//    CONTROLS TESTER MARK II
//    V2.0.0

//    COPYRIGHT NOTICE: 
//    This code is the intellectual property of Zachary C. Filka © Sep 2024. All rights 
//    reserved. Unauthorized use, distribution, or modification of this code is prohibited.

//Refference
  // Libraries
  #include <SPI.h>
  #include <Wire.h>
  #include <Adafruit_GFX.h>
  #include <Adafruit_SSD1306.h>
  // Perameters
  #define SCREEN_WIDTH 128
  #define SCREEN_HEIGHT 64
  #define OLED_RESET    -1
  #define SCREEN_ADDRESS 0x3C //0x3D for 128x64, 0x3C for 128x32
  Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
  // Digital pin allocations
  #define Relay1Pin 2     //Relay. HIGH = Controls, LOW = Continuity
  #define LED1 8          //Green LED (Signal 1)
  #define LED2 9          //Amber LED (Signal 2)
  #define SwitchesEn 10   //Enables the output switches
  #define BuzzEnSw 11     //Enables the buzzer
  #define BuzzerPin 12    //Buzzer
  #define ChargeDet 13    //Detects a charger

  // Variables
  int Probe0;   //Analog value of A0
  int Probe1;   //Analog value of A1
  int Probe2;   //Analog value of A2
  float v0;     //Voltage on pin A0
  float v1;     //Voltage on pin A1
  float v2;     //Voltage on pin A2
  int Batt;     //Battery level read from pin A7
  int SelSw;    //Mode switch read from pin A6
  int EMOTrig;  //Int = 1 when EMO is triggered successfully
  int DeadBatt; //If battery is under an operatable voltage, int = 1
  int Buzzer;
  int LastBuzzSwState;
  int BuzzCount;
  int Blink0;
  int Blink1;
  int Blink2;
  int Count1;
  int Count2;
//

void setup() {
  //Don't delete
  Serial.begin(9600);
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    for(;;);
  }

  //Digital pin setups
  pinMode(ChargeDet, INPUT_PULLUP);
  pinMode(BuzzEnSw, INPUT_PULLUP);
  pinMode(BuzzerPin, OUTPUT);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(SwitchesEn, OUTPUT);

  digitalWrite(SwitchesEn, HIGH); //OFF

  //Start dead battery screen, R.I.P. battery ),:
  Batt=analogRead(A7);
  if(Batt<200) { 
    DeadBatt = 1;
  }

  //Welcome effect
  display.clearDisplay();
  display.setTextSize(2);        
  display.setTextColor(SSD1306_WHITE);  
  display.drawRect(30, 35, 68, 1, SSD1306_WHITE); 
  display.setCursor(24,18);             
  display.println(F("MARK II"));
  display.setTextSize(1);        
  display.setCursor(37,39);             
  display.println(F("FILKA KIM"));
  display.display();
  delay(200);  
  digitalWrite(LED1, HIGH);
  delay(200);
  digitalWrite(LED2, HIGH);
  delay(200);
  digitalWrite(LED1, LOW);
  delay(200);
  digitalWrite(LED2, LOW);
  delay(800);
}

void loop() {
 //Reset Screen
  display.clearDisplay();
  display.setTextSize(1);        
  display.setTextColor(SSD1306_WHITE);  
 //Convert analog values to real voltages
  Probe0=analogRead(A0);
  v0=(Probe0*0.06)*0.92;
  Probe1=analogRead(A1);
  v1=(Probe1*0.06)*0.92;
  Probe2=analogRead(A2);
  v2=(Probe2*0.06)*0.92;
 //Start charging battery screen
  if(digitalRead(ChargeDet) == LOW) {  //Pin that detects charger
  ChargingScreen();
  return;
  }
 //Start low battery screen
  if(DeadBatt == 1) {
  DeadBatteryScreen();
  return;
  }

 //Tab line
 display.drawRect(0, 14, 128, 1, SSD1306_WHITE); 

 //Battery Indicator
 Batt=analogRead(A7);
 if(Batt>800) {
  display.fillRect(108, 4, 3, 6, SSD1306_WHITE);
 }
 if(Batt>600) {
  display.fillRect(112, 4, 3, 6, SSD1306_WHITE);
 }
 if(Batt>400) {
  display.fillRect(116, 4, 3, 6, SSD1306_WHITE);
 }
 if(Batt>200) {
  display.fillRect(120, 4, 3, 6, SSD1306_WHITE);
  display.drawRect(106, 2, 19, 10, SSD1306_WHITE);
  display.fillRect(104, 4, 2, 6, SSD1306_WHITE);
 } else if(Blink0 == 0) {
  display.setCursor(69,55);             
  display.drawRect(106, 2, 19, 10, SSD1306_WHITE);
  display.fillRect(104, 4, 2, 6, SSD1306_WHITE);
  Blink0 = 1;
 } else {
  Blink0 = 0;
 }

 //Main buzzer enable indicator
 if(digitalRead(BuzzEnSw) == LOW) {
  display.fillRect(4, 4, 3, 6, SSD1306_WHITE);
  display.fillRect(7, 3, 1, 8, SSD1306_WHITE);
  display.fillRect(8, 2, 1, 10, SSD1306_WHITE);
  display.fillRect(11, 5, 1, 4, SSD1306_WHITE);
  display.fillRect(14, 4, 1, 6, SSD1306_WHITE);
  display.drawPixel(13, 3, SSD1306_WHITE);
  display.drawPixel(13, 10, SSD1306_WHITE);
 }

 //Selector Switch
 SelSw=analogRead(A6);
 if(SelSw < 256) {
  Controls();
 } else if(SelSw > 256 && SelSw < 512) {
  EMO();
 } else if(SelSw > 512 && SelSw < 768) {
  Continuity();
 } else if(SelSw > 768 && SelSw < 1024) {
  AuxPower();
 }

}

void Controls() {
  //Static Text
  display.setCursor(40,4);             
  display.println(F("CONTROLS"));
  //IO
  digitalWrite(SwitchesEn, LOW); //ON
  digitalWrite(Relay1Pin, LOW);
  if(v1 > 22) {
    digitalWrite(LED1, HIGH);
  } else {
    digitalWrite(LED1, LOW);    
  }
  if(v2 > 22) {
    digitalWrite(LED2, HIGH);
  } else {
    digitalWrite(LED2, LOW);    
  }
  //Power voltage meter
  display.setCursor(20,24);             
  display.println(F("POWER:"));
  display.setCursor(110,24);             
  display.println(F("V"));
  display.setCursor(75,24);             
  display.println(v0);
  //Signal 1 voltage meter
  display.setCursor(10,36);             
  display.println(F("SIGNAL 1:"));
  display.setCursor(110,36);            
  display.println(F("V"));
  display.setCursor(75,36);            
  display.println(v1);
  //Signal 2 voltage meter
  display.setCursor(10,48);             
  display.println(F("SIGNAL 2:"));
  display.setCursor(110,48);            
  display.println(F("V"));
  display.setCursor(75,48);            
  display.println(v2);

  //Buzzer
  if(digitalRead(BuzzEnSw) == LOW) {
    if (LastBuzzSwState == HIGH) {
      BuzzCount = (BuzzCount + 1) % 3;
    }
    if(BuzzCount == 0 || BuzzCount == 2) { //Signal 1 Buzzer
      display.fillRect(0, 38, 3, 3, SSD1306_WHITE);
      display.fillRect(3, 36, 1, 7, SSD1306_WHITE);
      display.drawPixel(2, 37, SSD1306_WHITE);
      display.drawPixel(2, 41, SSD1306_WHITE);
      display.drawPixel(5, 37, SSD1306_WHITE);
      display.drawPixel(5, 41, SSD1306_WHITE);
      display.drawRect(6, 38, 1, 3, SSD1306_WHITE);
      if(v1 > 22) {
        BuzzerLoop();
      }
    }
    if(BuzzCount == 1 || BuzzCount == 2) {  //Signal 2 Buzzer
      display.fillRect(0, 50, 3, 3, SSD1306_WHITE);
      display.fillRect(3, 48, 1, 7, SSD1306_WHITE);
      display.drawPixel(2, 49, SSD1306_WHITE);
      display.drawPixel(2, 53, SSD1306_WHITE);
      display.drawPixel(5, 49, SSD1306_WHITE);
      display.drawPixel(5, 53, SSD1306_WHITE);
      display.drawRect(6, 50, 1, 3, SSD1306_WHITE);
      if(v2 > 22) {
        BuzzerLoop();
      }
    }
  }
  LastBuzzSwState = digitalRead(BuzzEnSw);


  //Draw screen
  display.display();
  delay(300);
}

void EMO() {
  //Static Text
  display.setCursor(38,4);             
  display.println(F("EMO TEST"));
  display.setCursor(24,42);             
  display.println(F("SAFETY 1:"));
  display.setCursor(24,54);             
  display.println(F("SAFETY 2:"));
  //IO
  digitalWrite(SwitchesEn, HIGH); //OFF
  digitalWrite(Relay1Pin, LOW);

  //Check signal 1
  if(v1 > 22) {
  display.setCursor(86,42);             
  display.println(F("OK"));
  digitalWrite(LED1, HIGH);
  } else {
  display.setCursor(83,42);             
  display.println(F("N/A"));
  digitalWrite(LED1, LOW);
  }
  //Check signal 2
  if(v2 > 22) {
  display.setCursor(86,54);             
  display.println(F("OK"));
  digitalWrite(LED2, HIGH);
  } else {
  display.setCursor(83,54);             
  display.println(F("N/A"));
  digitalWrite(LED2, LOW);
  }
  //EMO overall status
  if(v1 > 22 && v2 > 22) { 
    display.setTextSize(2);  
    display.setCursor(12,19);             
    display.println(F("TENSIONED"));
    EMOTrig = 1;
  } else if((v1 > 22 && v2 < 22) || (v1 < 22 && v2 >22)) {
    display.setTextSize(2);  
    display.setCursor(28,19);             
    display.println(F("FAULTY"));
  } else if(EMOTrig == 1) {
    EMOtriggered(); //Send to triggered sub routine
    EMOTrig = 0;
  } else {
    display.setTextSize(2);  
    display.setCursor(28,19);             
    display.println(F("NO EMO"));
  }
  //Draw screen
  display.display();
  delay(300);
}

void Continuity() {
  //Static text
  display.setCursor(34,4);             
  display.println(F("CONTINUITY"));
  //IO
  digitalWrite(SwitchesEn, HIGH);
  digitalWrite(Relay1Pin, HIGH);
  //Draw screen
  display.display();
  delay(300);

}

void AuxPower() {
  //Static text
  display.setCursor(39,4);             
  display.println(F("AUX TEST"));
  //IO
  digitalWrite(SwitchesEn, HIGH);
  digitalWrite(Relay1Pin, LOW);
  //Check circuit A
  display.setCursor(10,19);             
  display.println(F("CIRCUIT A:")); //Probe from pin A0
  display.setCursor(110,19);
  display.println(F("V"));
  display.setCursor(75,19);
  display.println(v0);
  //Check circuit B
  display.setCursor(10,31);             
  display.println(F("CIRCUIT B:")); //Probe from pin A1
  display.setCursor(110,31);            
  display.println(F("V"));
  display.setCursor(75,31);
  display.println(v1);

  display.setCursor(8,43);             
  display.println(F("BLK: WHT: RED: GRN:"));
  
  if(v0 < 18 && v1 < 18) {
  display.setCursor(8,55);             
  display.println(F("N/A  N/A  N/A  N/A"));
  } else {

   //Check red conductor
   if(v0 > 18) {
     display.setCursor(72,55);             
     display.println(F("OK"));
   } else if(Blink1 == 0) {
     display.setCursor(69,55);             
     display.println(F("BAD"));
     Blink1 = 1;
   } else {
     Blink1 = 0;    
   }
  
    //Check green conductor
   if(v1 > 18) {
     display.setCursor(102,55);             
     display.println(F("OK"));
   } else if(Blink2 == 0) {
     display.setCursor(99,55);             
     display.println(F("BAD"));
     Blink2 = 1;
    } else {
     Blink2 = 0;    
    }
  }
  //Draw screen
  display.display();
  delay(300);
}

void ChargingScreen() {
  //IO
  digitalWrite(SwitchesEn, HIGH);
  digitalWrite(Relay1Pin, LOW);
  //Battery indicator
  display.fillRect(27, 15, 81, 35, SSD1306_WHITE);
  display.fillRect(20, 22, 7, 21, SSD1306_WHITE);
  display.fillRect(30, 18, 75, 29, SSD1306_INVERSE);
  display.fillRect(88, 22, 12, 21, SSD1306_WHITE); 
  //Filling Battery animation
  Count1++; 
  if(Count1 >= 2) {
    display.fillRect(71, 22, 12, 21, SSD1306_WHITE);  
  }
  if(Count1 >= 3) {
    display.fillRect(54, 22, 12, 21, SSD1306_WHITE);  
  }
  if(Count1 >= 4) {
    display.fillRect(37, 22, 12, 21, SSD1306_WHITE);  
  Count1 = 0;
  }
  //Draw screen
  display.display();
  delay(500);
}

void DeadBatteryScreen() {
  digitalWrite(Relay1Pin, LOW);
  //Battery indicator
  display.fillRect(27, 15, 81, 35, SSD1306_WHITE);
  display.fillRect(20, 22, 7, 21, SSD1306_WHITE);
  display.fillRect(30, 18, 75, 29, SSD1306_INVERSE);
  //Flashing battery bar
  if(Blink1 == 0) {
  display.fillRect(93, 22, 7, 21, SSD1306_WHITE);  
  Blink1 = 1;
  } else {
  Blink1 = 0;    
  }
  //Draw screen
  display.display();
  delay(500);

}

void EMOtriggered() {
  for(int Count1 = 0; Count1 < 2; Count1++) {
  display.setTextSize(2);  
  display.setCursor(12,19);             
  display.println(F("TRIGGERED"));
  display.display();

  if(digitalRead(BuzzEnSw) == LOW) {
  BuzzerLoop();
  } else {
  delay(1300);
  }

  display.setTextColor(SSD1306_INVERSE);  
  display.setCursor(12,19);             
  display.println(F("TRIGGERED"));
  display.setTextColor(SSD1306_WHITE);  
  display.setCursor(12,19);             
  display.println(F("CORRECTLY"));
  display.display();
  delay(1000);
  display.setTextColor(SSD1306_INVERSE);  
  display.setCursor(12,19);             
  display.println(F("CORRECTLY"));
  display.display();
  }
}

void BuzzerLoop() {
  tone(BuzzerPin, 1000);
  delay(800);
  noTone(BuzzerPin);
  for(int Count2 = 0; Count2 < 3; Count2++) {
  delay(100);
  tone(BuzzerPin, 1000);
  delay(50);
  noTone(BuzzerPin);
  }
}