//UPDATED: Mar 07 2022, 04:53

/*
BLACK   ===   GND
RED     ===   NIGHT
GRAY    ===   BRAKE
WHITE   ===   BLINK

5.87Vf @ 210mA == 2 LEDS in series -|>|- -|>|-
2.52Vf
Active = 2.9Vf @ 210mA

D-Latch will be used for driving MOSFETs [ 74LVC373AT20-13 ]
MOSFET TIMING SPEC = 24mA for 3.5us = 84nC max Gate Charge
*/

//======================   Arduino Nano config   ======================
const int PWM = 5;                        //PWM MOSFET Control Output, Nano Pin ~D5 (Port D5), Timer1 = 16-bit Timer/Counter
const int mos[6] = {6, 7, 8, 9, 10, 11};  //6-bit MOSFET Control Output
const int swPin[4] = {14, 15, 16, 17};    //Nano 4-bit DIP Switch Input


/*
//======================   ATtiny824 config   ======================
const int pwmMOS = 6;                     //PWM MOSFET Control Output, ATtiny824 ~D6 (Port PB1) Timer1 = 16-bit Timer/Counter
const int ledMOS[6] = {0, 1, 2, 3, 4, 5}; //6-bit MOSFET Control Output
const int swPin[4] = {7, 8, 9, 10};       //4-bit DIP Switch Input

*/

//======================   Global Variables   ======================
const int LEDS = 6;           //# of LEDS
const int pwmRes = 255;       //PWM Resolution 255 (8-bit) or 65535 (16-bit)
const int pwmIntervals = 100; //Number of steps for PWNM fading {1-100}
const int t = 500;            //Standard delay interval
const int FPS = 60;           //Frames per seconds, used for Mode[8..15]
const int delaySW = 100;      //Delay for switching LED MOSFET and PWM MOSFET, microseconds

int b[6];                     //PWM value placeholders for each individual LED
bool swVal[4];                //Switch Value Placeholders
float R;                      //Logarithmic PWM value placeholder


void setup() {
  R = (pwmIntervals * log10(2))/(log10(pwmRes));

  for (int i = 0; i < 5; i++) { pinMode(swPin[i], INPUT_PULLUP); }  //Initialize Input Pins

  for (int i = 0; i < 6; i++) { pinMode(mos[i], OUTPUT); digitalWrite(mos[i], LOW); } //Initialize Output Pins

  pinMode(PWM, OUTPUT);
}

void loop() {
  
  //-----temp spot. Place in setup() on finalization.
  for (int i = 0; i < 6; i++) { digitalWrite(mos[i], LOW); }
  digitalWrite(PWM, LOW);
  delay(t);

  for (int i = 0; i < 4; i++) { swVal[i] = digitalRead(swPin[i]); }

  LightMode();  
}

void LightMode() {
  int bcd = 0;                      //Reset BCD value to '0'

  if (swVal[0] == 0) { bcd += 1; }
  if (swVal[1] == 0) { bcd += 2; }
  if (swVal[2] == 0) { bcd += 4; }
  if (swVal[3] == 0) { bcd += 8; }


  if (bcd ==  0)  {   Mode0();    } //OEM Blink
  if (bcd ==  1)  {   Mode1();    } //Multi Blink
  if (bcd ==  2)  {   Mode2();    } //Basic Sequential
  if (bcd ==  3)  {   Mode3();    } //Inverted Basic Sequential 
  if (bcd ==  4)  {   Mode4();    } //In N' Out
  if (bcd ==  5)  {   Mode5();    } //Singles
  if (bcd ==  6)  {   Mode6();    } //Doubles
  if (bcd ==  7)  {   Mode7();    } //Hammer
  
  if (bcd ==  8)  {   Mode8(1);   } //Fade OEM Blink, (reps)
  if (bcd ==  9)  {   Mode9(2);   } //Fade Double Blink, (reps)
  if (bcd ==  10) {   Mode10();   } //Fade Basic Sequential
  if (bcd ==  11) {   Mode11();   } //Fade Inverted Basic Sequential
  if (bcd ==  12) {   Mode12();   } //Fade In N' Out
  if (bcd ==  13) {   Mode13();   } //Fade Singles
  if (bcd ==  14) {   Mode14();   } //Fade Doubles
  //if (bcd ==  15) {   Mode15();   } //Comet
}

void Mode0() {  //OEM Blink
  for (int i = 0; i < LEDS; i++) { digitalWrite(mos[i], HIGH); } //Turn ON all LED MOSFETs

  delayMicroseconds(delaySW);

  digitalWrite(PWM, HIGH);  //Activate Light

  delay(t);
}

void Mode1() {  //Multi Blink
  //Sequence: (3 frames)
  //ON | OFF | ON
  //|* * * * * *|0
  //|           |1
  //|* * * * * *|2

  int frames = 3;
  unsigned long dSplit = t / frames; 

  for (int i = 0; i < LEDS; i++) { digitalWrite(mos[i], HIGH); } //Turn ON all LED MOSFETs

  delayMicroseconds(delaySW);

  digitalWrite(PWM, HIGH);  //Activate Light
  delay(dSplit);
  digitalWrite(PWM, LOW);   //Deactivate Light
  delay(dSplit);
  digitalWrite(PWM, HIGH);  //Activate Light, remain ON until power cuts
  delay(dSplit);
}

void Mode2() {  //Basic Sequential
  //Sequence: (6 frames)
  //|*          |0
  //|* *        |1
  //|* * *      |2
  //|* * * *    |3
  //|* * * * *  |4
  //|* * * * * *|5

  int frames = 6;
  unsigned long dSplit = t / frames;

  digitalWrite(PWM, HIGH);

  delayMicroseconds(delaySW);

  for (int i = 0; i < LEDS; i++) {
    digitalWrite(mos[i], HIGH);
    delay(dSplit);
  }
}

void Mode3() {  //Inverted Basic Sequential
  //Sequence: (6 frames)
  //|* * * * * *|0
  //|  * * * * *|1
  //|    * * * *|2
  //|      * * *|3
  //|        * *|4
  //|          *|5

  int frames = 6;
  unsigned long dSplit = t / frames;

  for (int i = 0; i < LEDS; i++) {
    digitalWrite(mos[i], HIGH);
  }

  delayMicroseconds(delaySW);
  
  digitalWrite(PWM, HIGH);

  for (int i = 0; i < LEDS; i++) {
    delay(dSplit);
    digitalWrite(mos[i], LOW);
  }
}

void Mode4() {  //In n' Out
  //Sequence: (11 frames)
  //|*          |0
  //|* *        |1
  //|* * *      |2
  //|* * * *    |3
  //|* * * * *  |4
  //|* * * * * *|5
  //|  * * * * *|6
  //|    * * * *|7
  //|      * * *|8
  //|        * *|9
  //|          *|10

  unsigned long dSplit = t / 11;

  digitalWrite(PWM, HIGH);

  delayMicroseconds(delaySW);

  for (int i = 0; i < LEDS; i++) {
    digitalWrite(mos[i], HIGH);
    
    if (i < 5) {
      delay(dSplit);
    } 
    else {
      for (int j = 0; j < LEDS; j++) {
      delay(dSplit);
      digitalWrite(mos[j], LOW);
      }
    }
  }
}

void Mode5() {  //Singles
  //Sequence: (6 frames)
  //|*          |0
  //|  *        |1
  //|    *      |2
  //|      *    |3
  //|        *  |4
  //|          *|5

  int frames = 6;
  unsigned long dSplit = t / frames;

  digitalWrite(PWM, HIGH);

  delayMicroseconds(delaySW);

  for (int i = 0; i < frames; i++) {
    digitalWrite(mos[i], HIGH);
    digitalWrite(mos[i-1], LOW);
    delay(dSplit);
  }
}

void Mode6() {  //Doubles
  //Sequence: (7 frames)
  //|*          |0
  //|* *        |1
  //|  * *      |2
  //|    * *    |3
  //|      * *  |4
  //|        * *|5
  //|          *|6

  int frames = 7;
  unsigned long dSplit = t / frames;

  digitalWrite(PWM, HIGH);

  delayMicroseconds(delaySW);

  for (int i = 0; i < frames; i++) {
    digitalWrite(mos[i], HIGH);
    digitalWrite(mos[i-2], LOW);
    delay(dSplit);
  }
}

void Mode7() {  //Hammer
  //Sequence: (2x11 frames)
  //|*          |0
  //|* *        |1
  //|* * *      |2
  //|* * * *    |3
  //|* * * * *  |4
  //|* * * * * *|5
  //|* * * * *  |6
  //|* * * *    |7
  //|* * *      |8
  //|* *        |9
  //|*          |10
  //   REPEAT

  int frames = 22;
  unsigned long dSplit = t / frames;

  digitalWrite(PWM, HIGH);

  delayMicroseconds(delaySW);

  for (int a = 0; a < 2; a++) {
    for (int i = 0; i < LEDS; i++) {
      digitalWrite(mos[i], HIGH);
      delay(dSplit);
    }
    for (int i = LEDS; i > 0; i--) {
      digitalWrite(mos[i], LOW);
      delay(dSplit);
    }
  }
}

void Mode8(int reps) {  //Fade OEM Blink
  int b = 0; //Brightness level
  unsigned int dSplit = ((t / reps) / (pwmIntervals * 2)) * 1000;

  for (int i = 0; i < LEDS; i++) { digitalWrite(mos[i], HIGH); } //Turn ON all LED MOSFETs

  delayMicroseconds(delaySW);

  for (int i = 0; i < reps; i++) {
    for (int interval = 1; interval <= pwmIntervals; interval++) 
    {
      b = pow(2, (interval / R)) - 1;
      b = pwmRes - b;                 //Exclude if using N-MOSFET control
      analogWrite(PWM, b);
      delayMicroseconds(dSplit);

      if (interval < pwmIntervals) { 
        continue; 
      } 
      else 
      {
        for (int interval = pwmIntervals; interval >= 1; interval--) {
          b = pow(2, (interval / R)) - 1;
          b = pwmRes - b;                 //Exclude if using N-MOSFET control
          analogWrite(PWM, b);
          delayMicroseconds(dSplit);
        }
      }
    }
  }
}

void Mode9(int reps) {  //Fade Double Blink
  Mode8(reps);
}

void Mode10() { //Fade Basic Sequential
  //Sequence: (6 frames * 100 pwmIntervals * 60Hz = )
  //|*          |0
  //|* *        |1
  //|* * *      |2
  //|* * * *    |3
  //|* * * * *  |4
  //|* * * * * *|5

  int frames = LEDS * pwmIntervals * FPS;
  unsigned int dSplit = (t / frames) * 1000;

  for (int i = 0; i < LEDS; i++) {  
    b[i] = 0;  //Set starting brightness levels
  }
  
  for (int bulb = 0; bulb < LEDS; bulb++) {
    for (int interval = 1; interval <= pwmIntervals; interval++) {
      b[bulb] = pow(2, (interval / R)) - 1;
      b[bulb] = pwmRes - b[bulb];           //Exclude if using N-MOSFET control
      
      for (int f = 0; f < FPS; f++) {
        for (int l = 0; l < LEDS; l++) {
          digitalWrite(mos[l], HIGH);
          analogWrite(PWM, b[l]);
          delayMicroseconds(dSplit);
          digitalWrite(mos[l], LOW);
        }
      }
    }
  }
}

void Mode11() { //Fade Inverted Basic Sequential
  //Sequence: (6 frames * 100 pwmIntervals * 60Hz = 36000 frames)
  //|* * * * * *|0
  //|  * * * * *|1
  //|    * * * *|2
  //|      * * *|3
  //|        * *|4
  //|          *|5

  int frames = LEDS * pwmIntervals * FPS;
  unsigned int dSplit = (t / frames) * 1000;

  for (int i = 0; i < LEDS; i++) {  
    b[i] = pwmRes;  //Set starting brightness levels to '255'
  }

  for (int bulb = 0; bulb < LEDS; bulb++) {
    for (int interval = pwmIntervals; interval <= 1; interval--) {
      b[bulb] = pow(2, (interval / R)) - 1;
      b[bulb] = pwmRes - b[bulb];           //Exclude if using N-MOSFET control
      
      for (int f = 0; f < FPS; f++) {
        for (int l = 0; l < LEDS; l++) {
          digitalWrite(mos[l], HIGH);
          analogWrite(PWM, b[l]);
          delayMicroseconds(dSplit);
          digitalWrite(mos[l], LOW);
        }
      }
    }
  }
}

void Mode12() { //Fade Inverted Basic Sequential
  //Sequence: (11 frames * 100 pwmIntervals * 60Hz = 66000 frames)
  //|*          |0
  //|* *        |1
  //|* * *      |2
  //|* * * *    |3
  //|* * * * *  |4
  //|* * * * * *|5
  //|  * * * * *|6
  //|    * * * *|7
  //|      * * *|8
  //|        * *|9
  //|          *|10

  int frames = 11 * pwmIntervals * FPS;
  unsigned int dSplit = (t / frames) * 1000;

  for (int i = 0; i < LEDS; i++) {  
    b[i] = 0;  //Set starting brightness levels to '0'
  }
  
  for (int bulb = 0; bulb < LEDS; bulb++) {
    for (int interval = 1; interval <= pwmIntervals; interval++) {
      b[bulb] = pow(2, (interval / R)) - 1;
      b[bulb] = pwmRes - b[bulb];           //Exclude if using N-MOSFET control
      
      for (int f = 0; f < FPS; f++) {
        for (int l = 0; l < LEDS; l++) {
          digitalWrite(mos[l], HIGH);
          analogWrite(PWM, b[l]);
          delayMicroseconds(dSplit);
          digitalWrite(mos[l], LOW);
        }
      }
    }
  }

  for (int bulb = 0; bulb < LEDS; bulb++) {
    for (int interval = pwmIntervals; interval <= 1; interval--) {
      b[bulb] = pow(2, (interval / R)) - 1;
      b[bulb] = pwmRes - b[bulb];           //Exclude if using N-MOSFET control

      for (int f = 0; f < FPS; f++) {
        for (int l = 0; l < LEDS; l++) {
          digitalWrite(mos[l], HIGH);
          analogWrite(PWM, b[l]);
          delayMicroseconds(dSplit);
          digitalWrite(mos[l], LOW);
        }
      }
    }
  }
}

void Mode13() { //Fade Singles
  //Sequence: (6 [frames] * 2 [fade stages] * 100 [pwmIntervals] = 1200 frames)
  //|*          |0
  //|  *        |1
  //|    *      |2
  //|      *    |3
  //|        *  |4
  //|          *|5

  int frames = LEDS * 2 * pwmIntervals;
  unsigned int dSplit = (t / frames) * 1000;

  //Set starting brightness levels
  for (int i = 0; i < LEDS; i++) { b[i] = 0; }

  for (int i = 0; i < LEDS; i++) {
    digitalWrite(mos[i], HIGH);

    for (int interval = 1; interval <= pwmIntervals; interval++) {
      b[i] = pow(2, (interval / R)) - 1;
      b[i] = pwmRes - b[i];             //Exclude if using N-MOSFET control

      analogWrite(PWM, b[i]);
      delayMicroseconds(dSplit);
    }

    for (int interval = pwmIntervals; interval <= 1; interval--) {
      b[i] = pow(2, (interval / R)) - 1;
      b[i] = pwmRes - b[i];             //Exclude if using N-MOSFET control

      analogWrite(PWM, b[i]);
      delayMicroseconds(dSplit);
    }
    digitalWrite(mos[i], LOW);
  }
}

void Mode14() { //Fade Doubles
  //Sequence: (7 [frames] * 2 [fade stages] * 100 [pwmIntervals] = 1400 frames)
  //|*          |0
  //|* *        |1
  //|  * *      |2
  //|    * *    |3
  //|      * *  |4
  //|        * *|5
  //|          *|6

  int frames = 7 * 2 * pwmIntervals;
  unsigned int dSplit = (t / frames) * 1000;

  //Set starting brightness levels
  for (int i = 0; i < LEDS; i++) { b[i] = 0; }

  for (int i = 0; i < LEDS; i++) {
    digitalWrite(mos[i], HIGH);
    digitalWrite(mos[i-1], HIGH);

    for (int interval = 1; interval <= pwmIntervals; interval++) {
      b[i] = pow(2, (interval / R)) - 1;
      b[i] = pwmRes - b[i];             //Exclude if using N-MOSFET control

      analogWrite(PWM, b[i]);
      delayMicroseconds(dSplit);
    }

    for (int interval = pwmIntervals; interval <= 1; interval--) {
      b[i] = pow(2, (interval / R)) - 1;
      b[i] = pwmRes - b[i];             //Exclude if using N-MOSFET control

      analogWrite(PWM, b[i]);
      delayMicroseconds(dSplit);
    }
    digitalWrite(mos[i], LOW);
  }
}

void Mode15() { //Comet

}