  // Basic Version of Lightcomposer firmware
// 30/04/2026


#include <Arduino.h>

#include <Adafruit_NeoPixel.h>
#include <EEPROM.h>
#define NumberOfLEDs 32
#define LEDPIN 9
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NumberOfLEDs, LEDPIN, NEO_GRB + NEO_KHZ800); //use of RGB LEDs, not RGBW




int pulseCount; //rotation step count
int SIG_A = 0; //pin A output
int SIG_B = 0; //pin B output
int lastSIG_A = 0; //last state of SIG_A
int lastSIG_B = 0; //last state of SIG_B

// changed the turning direction by swapping pin a and pin b 
int Pin_A = 3; //interrupt pin (digital) for A (change your pins here) 
int Pin_B = 2; //interrupt pin (digital) for B
float angle = 0; 
int turningDirection; 

int turn;
int LEDCount;
bool PoliceActivated = false; // checks if the police light function is activated
bool RainbowActivated = false; // checks if the rainbow function is activated 
bool UserInput = false;
int InputChecker = 0;
int IdleChecker = 0;
int redReset = 100;
int greenReset = 100; 
int blueReset = 50; 
int redValue = 0;
int greenValue = 0;
int blueValue = 0; 
bool firstLight = true; 
int brightnessValue = 0; 
bool safeTurn = false; // if true the light values are stored in the eprom 
int OptionLED = 150; // brightness of the LEDs that are for options, the brightness of the lamp is not impacted 
int PoliceLED = 240; // brightness of the police light 




void colorMixer(){
  int colorLevel = LEDCount * 10;
  safeTurn = true; 
  
  if(turn == 2){
    redValue = colorLevel;
      if(firstLight == true){
        firstLight = false;
        greenValue = 0; 
        blueValue = 0;
      }
    }  else if(turn == 3){
    greenValue = colorLevel;
    if(firstLight == true){
      firstLight = false;
      redValue = 0; 
      blueValue = 0;
    }
  } else if(turn == 4){
    blueValue = colorLevel;
    if(firstLight == true){
      firstLight = false;
      greenValue = 0; 
      redValue = 0;
    }
  } 
//else if(turn == 0){
//    strip.setBrightness(colorLevel); 
//    strip.show(); 
//  }
//  Serial.print("Color Level: "); Serial.println(colorLevel); 
}


void PoliceLight(){
            int delayTime = 200; 
        strip.clear(); 
        strip.fill(strip.gamma32(strip.Color(PoliceLED,0,0)), 24, 4);
        strip.fill(strip.gamma32(strip.Color(PoliceLED,0,0)), 0, 12);
        strip.show();
        delay(delayTime);
        strip.clear(); 
        strip.fill(strip.gamma32(strip.Color(0,0,PoliceLED)), 28,4);
        strip.fill(strip.gamma32(strip.Color(0,0,PoliceLED)), 12,12);
        strip.show();
        delay(delayTime);
}



void turnPosition(){
  if(pulseCount < 0){
    turn = -1;
  } else if((pulseCount >= 0) && (pulseCount <= 48)){
    turn = 0;
  } else if((pulseCount >= 49) && (pulseCount <= 96)){
    turn = 1;
  } else if((pulseCount >= 97) && (pulseCount <= 144)){
    turn = 2;
  } else if((pulseCount >= 145) && (pulseCount <= 192)){
    turn = 3;
  } else if((pulseCount >= 193) && (pulseCount <= 240)){
    turn = 4;
  } else if((pulseCount >= 241) && (pulseCount <= 288)){
    turn = 5;
  } else if((pulseCount >= 289) && (pulseCount <= 336)){
    turn = 6;
  }  
 
//  Serial.print("Turn: "); Serial.println(turn);
}





void LEDPosition(){
  if(pulseCount < 0){ // cancel position 
    LEDCount = (pulseCount / -2);  //using the inner 8 LEDs, the outher ring is not being used, 48 pulses divided by 8 inner LEDs = 6
    
    if(LEDCount == 0){
      strip.clear();
      strip.show();
    } else {
    strip.clear(); 
    strip.setBrightness(120); 
    strip.fill(strip.gamma32(strip.Color(OptionLED,0,0)), 0, LEDCount);
    strip.show();
    }
  
  } else if((pulseCount >= 0) && (pulseCount <= 48)){ // light postion
    LEDCount = pulseCount / 2; // using the outer 24 LEDs
    
    if(LEDCount == 0){
      strip.clear();
      strip.show();
    } else {    
    strip.clear();
    strip.setBrightness(LEDCount *10);  
    strip.fill(strip.gamma32(strip.Color(redValue,greenValue,blueValue)), 0, LEDCount);
    strip.show();
    }
    
  } else if((pulseCount >= 49) && (pulseCount <= 96)){ // go into menue 
    LEDCount = ((pulseCount -48)/ 2);
    
    if(LEDCount == 0){
      strip.clear();
      strip.show();
    } else { 

//    strip.setPixelColor(
      
    strip.clear(); 
    strip.fill(strip.gamma32(strip.Color(OptionLED,0,OptionLED)), 0, LEDCount);
    strip.show();
    }
    
  } else if((pulseCount >= 97) && (pulseCount <= 144)){ // red positon
    LEDCount = ((pulseCount - 96)/ 2);
    
    if(LEDCount == 0){
      strip.clear();
      strip.show();
    } else { 
    strip.clear(); 
    strip.fill(strip.gamma32(strip.Color(OptionLED,0,0)), 0, LEDCount);
    strip.show();
    }
  } else if((pulseCount >= 145) && (pulseCount <= 192)){ // green position
     LEDCount = ((pulseCount - 144)/ 2);
    
    if(LEDCount == 0){
      strip.clear();
      strip.show();
    } else { 
    strip.clear(); 
    strip.fill(strip.gamma32(strip.Color(0,OptionLED,0)), 0, LEDCount);
    strip.show();
    }
  } else if((pulseCount >= 193) && (pulseCount <= 240)){
     LEDCount = ((pulseCount - 192)/ 2);
    PoliceActivated = false; 
    if(LEDCount == 0){
      strip.clear();
      strip.show();
    } else { 
    strip.clear(); 
    strip.fill(strip.gamma32(strip.Color(0,0,OptionLED)), 0, LEDCount);
    strip.show();
    }
  } else if((pulseCount >= 241) && (pulseCount <= 288)){ // police positon
    LEDCount = 0; 
    PoliceLight();
//    int delayTime = 200; 
//    int var = 0; 
//    RainbowActivated = false; 

//    if(PoliceActivated == false){
//      while(var < 20){
//       strip.clear(); 
//        strip.fill(strip.gamma32(strip.Color(PoliceLED,0,0)), 0, 12);
//        strip.show();
//        delay(delayTime);
//        strip.clear(); 
//        strip.fill(strip.gamma32(strip.Color(0,0,PoliceLED)), 12,12);
//        strip.show();
//        delay(delayTime);
//        var++; 
//    }
    

//    PoliceActivated = true; 
//    } else {
//      strip.clear();
//      strip.show();
//    }
   
  } else if((pulseCount >= 289) && (pulseCount <= 336)){ // psycodelic position
    LEDCount = 0; 
//    PoliceActivated = false; 
//    int var = 0; 

//    if(RainbowActivated == false){
//     while(var < 5){
//     while(pulseCount > 289){

      rainbowFade2White(1,1);
//      var++; 
//     }
//      RainbowActivated = true;
//    } else {
//      strip.clear();
//      strip.show();
//    }
    
  }  


//  Serial.print("LED Count: "); Serial.println(LEDCount); 
}



void Light(){
  brightnessValue = LEDCount*10;
  strip.clear(); 
  strip.setBrightness(brightnessValue); 
  strip.fill(strip.gamma32(strip.Color(redValue,greenValue,blueValue)), 0, 32);
  strip.show();
}




void boundaries(){
  if(pulseCount < -48){ // lower limit, with negative 1 turn, -48 impulses 
    pulseCount = -48;
  } else if(pulseCount > 336){ // upper limit, with 7 turns in the positive direction, 7*48 = 336
    pulseCount = 336;  
  }
}



// interrupt menue ---------------------------------------------------------------
void A_CHANGE() { //Interrupt Service Routine (ISR)
  detachInterrupt(0); //important
  SIG_A = digitalRead(Pin_A); //read state of A
  SIG_B = digitalRead(Pin_B); //read state of B

angle = (7.5)*pulseCount; // angle = (360/48)*pulseCount;, the number of pulses for 1 rotation is 48 
//Serial.print("Angle: "); Serial.println(angle); 
 
  if((SIG_B == SIG_A) && (lastSIG_B != SIG_B)) {
    pulseCount--; //anti-clockwise rotation
    lastSIG_B = SIG_B;
    turningDirection = 2; 
//    Serial.print(pulseCount);
//    Serial.println(" - Reverse");
    UserInput = true;
    InputChecker = 0; 
    IdleChecker = 0; 

  }
 
  else if((SIG_B != SIG_A) && (lastSIG_B == SIG_B)) {
    pulseCount++; //clockwise rotation
    lastSIG_B = SIG_B > 0 ? 0 : 1; //save last state of B
    turningDirection = 1; 
//    Serial.print(pulseCount);
//    Serial.println(" - Forward");
    UserInput = true;
    InputChecker = 0; 
    IdleChecker = 0; 
  }
  attachInterrupt(digitalPinToInterrupt(Pin_A), A_CHANGE, CHANGE);
  boundaries(); 
 
}





void rainbowFade2White(int wait, int rainbowLoops) {
  int fadeVal = 100, fadeMax = 100;

  for (uint32_t firstPixelHue = 0; firstPixelHue < rainbowLoops * 65536;
       firstPixelHue += 128) {

    for (int i = 0; i < strip.numPixels(); i++) { // For each pixel in strip...

      uint32_t pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());

      strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue, 255,
                                           255 * fadeVal / fadeMax)));
    }
    strip.show();
    delay(wait);
  }
}


// setup menu ---------------------------------------------------------------
void setup() {
  SIG_B = digitalRead(Pin_B); //current state of B
  SIG_A = SIG_B > 0 ? 0 : 1; //let them be different
  //attach iterrupt for state change, not rising or falling edges
  attachInterrupt(digitalPinToInterrupt(Pin_A), A_CHANGE, CHANGE);
  Serial.begin(9600);


  strip.begin();        //initialize LED protocol
  strip.setBrightness(120); 
  rainbowFade2White(1,1); 
//  strip.fill(strip.Color(255,255,255), 0, 32);
//  strip.show();         //Initialize all pixels to 'off'
//  delay(500);
//  strip.fill();
//  strip.show(); 

  // set the inital color values 
  redValue = EEPROM.read(0);
  greenValue = EEPROM.read(3);
  blueValue = EEPROM.read(5);

  strip.clear(); 
  strip.setBrightness(brightnessValue); 
  strip.fill(strip.gamma32(strip.Color(redValue,greenValue,blueValue)), 0, 32);
  strip.show(); 

  Serial.println("Ready jeffe!");
//  Serial.println(); 
}





// loop menue ---------------------------------------------------------------
void loop() {

if(UserInput == true){
  turnPosition(); 
  LEDPosition(); 
  InputChecker++; 

  if(InputChecker >= 50){
    UserInput = false; 
  }
} else if((UserInput == false) && (IdleChecker < 50)) {
   if(turn == 0){
   Light();
   
   } else if(turn == -1){
    if(LEDCount >= 22){ // at least 22 LEDs must be in the count before the lamp is reset
      strip.fill(strip.gamma32(strip.Color(0,OptionLED,0)), 24, 8);
    strip.show();
    redValue = redReset; 
    greenValue = greenReset;
    blueValue = blueReset;
    firstLight = true; 
    }
   } else if(turn == 2){
    strip.fill(strip.gamma32(strip.Color(0,OptionLED,0)), 24, 8);
    strip.show();
    colorMixer();
   } else if(turn == 3){
    strip.fill(strip.gamma32(strip.Color(0,OptionLED,0)), 24, 8);
    strip.show();
    colorMixer();
   } else if(turn == 4){
    strip.fill(strip.gamma32(strip.Color(0,OptionLED,0)), 24, 8);
    strip.show();
    colorMixer();
   } else if(turn == 1){
    Light();
   } else if(turn == 5){
    PoliceLight();
   } else if(turn == 6){
    rainbowFade2White(1,1);
   }

  IdleChecker++; 
} else if((IdleChecker >= 50) && (IdleChecker <= 6000)){
  IdleChecker++; 
  if(turn == 5){
    PoliceLight();
   } else if(turn == 6){
    rainbowFade2White(1,1);
   } 
}


  else if((IdleChecker > 6000) && (safeTurn == true) && (turn == 0)){
  safeTurn = false; 
  EEPROM.write(0, redValue);
  EEPROM.write(3, greenValue);
  EEPROM.write(5, blueValue);
  
//  Serial.println(); 
//  Serial.println("Was saved, NOT");
//  Serial.println(); 
}

//
//  else {
//  Serial.println("Doing notin"); 
//}

//Serial.print("Input Checker: "); Serial.println(InputChecker); 
//Serial.print("Idle Checker: "); Serial.println(IdleChecker); 


 delay(5); 
}
