#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#include <Wire.h>


#define switch1  7
#define switch2  8 // change between calib and stations
#define switch3  9 // main station
#define switch4  10 // station 1
#define switch5  11 // station 2
#define switch6  12 // station 3

// led connections
#define led1  22 // main
#define led2  23 // station 1
#define led3  24 // station 2
#define led4  25 //station 3

// relays connection
#define led5  50 //station 3
#define led6  51 //station 3
// down
#define led7  52 //station 3
#define led8  53 //station 3

// button 1 change calibration
bool buttonstate1;
int num = 0;

// button 2 change between calib and stations
int buttonReading2;
int state2 = LOW;
int previous2 = LOW;

// button 3 Main station
int buttonReading3;
int state3 = LOW;
int previous3 = LOW;

// button 4 Staion 1
int buttonReading4;
int state4 = LOW;
int previous4 = LOW;

// button 5 station 2
int buttonReading5;
int state5 = LOW;
int previous5 = LOW;

// button 6 station 3
int buttonReading6;
int state6 = LOW;
int previous6 = LOW;

LiquidCrystal_I2C lcd(0x27, 20, 4);


// flags for each station

bool flag_1 = 0;
bool flag_2 = 0;
bool flag_3 = 0;
bool flag_m = 0;

// Joystick1 Variables
//*****************define your pins here***********************************************//
#define joystick_X A1    //joystick  X-as
#define joystick_Y A0    //joystick  Y-as
#define button_2 2       // button on d2

long range_X_min = 0;           //lowest X value
long range_X_max = 1023;          //highest X value
long range_X_center = 0;           //X center calue
unsigned long deadZone_X = 1;      //deadzone X, return center value for center +- deadzone(in steps of 1/1024)

float range_Y_min = 0;             //lowest Y value
float range_Y_max = 1023;          //highest Y value
float range_Y_center = 0;        //Y center value
unsigned long deadZone_Y = 1;      //deadzone Y, return center value for center +- deadzone(in steps of 1/1024)

int val_X, val_Y;

unsigned long X_CENTER; 
unsigned long X_MIN;
unsigned long X_MAX;
unsigned long Y_CENTER;
unsigned long Y_MIN;
unsigned long Y_MAX ;

unsigned long X_center = 0; 
unsigned long X_min = 0;
unsigned long X_max = 0;
unsigned long Y_center = 0;
unsigned long Y_min = 0;
unsigned long Y_max = 0;

unsigned long cal_X;
unsigned long cal_Y;

void setup()
{
  lcd.init();
  lcd.backlight();
  lcd.begin (20, 4);

  Serial.begin(9600);
  pinMode(switch1, INPUT_PULLUP);
  pinMode(switch2, INPUT_PULLUP);
  pinMode(switch3, INPUT_PULLUP);
  pinMode(switch4, INPUT_PULLUP);
  pinMode(switch5, INPUT_PULLUP);
  pinMode(switch6, INPUT_PULLUP);

  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(led4, OUTPUT);

  pinMode(led5, OUTPUT);
  pinMode(led6, OUTPUT);
  pinMode(led7, OUTPUT);
  pinMode(led8, OUTPUT);

  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
  digitalWrite(led3, LOW);
  digitalWrite(led4, LOW);

  //joystick1 variables
  pinMode(joystick_X, INPUT);
  pinMode(joystick_Y, INPUT);
  pinMode(button_2, INPUT_PULLUP);    //we pull this pin high to avoid a floating pin


  loadeeprom();

  lcd.setCursor (6, 0);
  lcd.print ("Please");
  lcd.setCursor (6, 1);
  lcd.print ("Select");
  lcd.setCursor (7, 2);
  lcd.print ("Station");

}

// important functions to callibrate joystick
long joy_X(long X)
{
  X += (X_center);   //should always be 512
  if (X <= 512)
  {
    X = mapfloat(X, X_min, X_center, range_X_min, range_X_center);   //min,center to range min, range center
    return X;
  }
  else if (X > 512) {
    X = mapfloat(X, 512, 1024 + X_center, range_X_center, range_X_max);
    return X;
  }
}

long joy_Y(long Y)
{
  Y += (Y_center);
  if (Y <= range_Y_center)
  {
    Y = mapfloat(Y, Y_min, Y_center, range_Y_min, range_Y_center);
    return Y;
  }
  else if (Y > range_Y_center)
  {
    Y = mapfloat(Y, 512, 1024 + Y_center, range_Y_center, range_Y_max);
    return Y;
  }
}

void set_range_X(float min, float max, float center) {
  range_X_min = min;
  range_X_max = max;
  range_X_center = center;
}

void set_range_Y(float min, float max, float center) {
  range_Y_min = min;
  range_Y_max = max;
  range_Y_center = center;
}

float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

void loadeeprom()
{
  EEPROM.get(0, X_center);
  delay(10);
  EEPROM.get(10, Y_center);
  delay(10);
  EEPROM.get(20, X_min);
  delay(10);
  EEPROM.get(30, Y_min);
  delay(10);
  EEPROM.get(40, X_max);
  delay(10);
  EEPROM.get(50, Y_max);
  delay(10);
}
void joycalabcenter1()
{
  delay(500);
  lcd.clear();
  lcd.setCursor (2, 0);
  lcd.print ("Calibration mode");
  lcd.setCursor (6, 1);
  lcd.print ("JoyStick 1");
  lcd.setCursor (7, 2);
  lcd.print ("Place"); //and another load of these from A0 to A10
  lcd.setCursor (1, 3);
  lcd.print ("It in the Center");

  Serial.println("\n---calibrating joystick---\n");
  Serial.println("place the joystick in the center position");
  cal_X = 0;
  cal_Y = 0;
  delay(2500);
  Serial.print("calibrating center");
  for (int i = 0; i < 100; i++) {
    Serial.print(".");
    cal_X += analogRead(joystick_X);
    delay(5);
    cal_Y += analogRead(joystick_Y);
    delay(5);
  }
  X_CENTER = (cal_X / 100);
  Y_CENTER = (cal_Y / 100);
  Serial.print("\nCorrection X: ");
  Serial.print(X_CENTER);
  Serial.print("\nCorrection Y: ");
  Serial.println(Y_CENTER);

  EEPROM.put(0, 0);
  delay(10);
  EEPROM.put(10, 0);
  delay(10);

  EEPROM.put(0, X_CENTER);
  delay(10);
  EEPROM.put(10, Y_CENTER);
  delay(10);
}
void joycalabmin1()
{
  delay(500);
  lcd.clear();
  lcd.setCursor (2, 0);
  lcd.print ("Calibration mode");
  lcd.setCursor (6, 1);
  lcd.print ("JoyStick 1");
  lcd.setCursor (7, 2);
  lcd.print ("Place it in"); //and another load of these from A0 to A10
  lcd.setCursor (1, 3);
  lcd.print ("Bottom Right Corner");

  X_MIN = 0;    //reset the values
  Y_MIN = 0;
  delay(2500);
  Serial.print("calibrating position");
  for (int i = 0; i < 100; i++)        //take 100 readings
  {
    Serial.print(".");
    X_MIN += analogRead(joystick_X);
    delay(5);
    Y_MIN += analogRead(joystick_Y);
    delay(5);
  }
  X_MIN /= 100;
  Y_MIN /= 100;
  Serial.println();
  Serial.print("X: ");
  Serial.println(X_MIN);
  Serial.print("Y: ");
  Serial.println(Y_MIN);

  EEPROM.put(20, 0);
  delay(10);
  EEPROM.put(30, 0);
  delay(10);

  EEPROM.put(20, X_MIN);
  delay(10);
  EEPROM.put(30, Y_MIN);
  delay(10);
}

void joycalabmax1()
{
  delay(500);
  lcd.clear();
  lcd.setCursor (2, 0);
  lcd.print ("Calibration mode");
  lcd.setCursor (6, 1);
  lcd.print ("JoyStick 1");
  lcd.setCursor (7, 2);
  lcd.print ("Place it in"); //and another load of these from A0 to A10
  lcd.setCursor (1, 3);
  lcd.print ("Top Right Corner");

  Serial.println("\nplace the joystick in the top-right corner");
  X_MAX = 0;    //reset the values
  Y_MAX = 0;
  delay(2500);
  Serial.print("calibrating position");
  for (int i = 0; i < 100; i++)
  {
    X_MAX += analogRead(joystick_X);
    delay(5);
    Y_MAX += analogRead(joystick_Y);
    delay(5);
  }
  X_MAX /=  100;
  Y_MAX /=  100;
  Serial.println();
  Serial.print("X: "); Serial.println(X_MAX);
  Serial.print("Y: "); Serial.println(Y_MAX);

  EEPROM.put(40, 0);
  delay(10);
  EEPROM.put(50, 0);
  delay(10);

  EEPROM.put(40, X_MAX);
  delay(10);
  EEPROM.put(50, Y_MAX);
  delay(10);
}

void callib()
{
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
  digitalWrite(led3, LOW);
  digitalWrite(led4, LOW);
  buttonstate1 = digitalRead(switch1);
  if (buttonstate1 == LOW)
  {
    if (num < 4 )
    {
      num++;
    }
    else
    {
      num = 0;
    }
  }

  switch (num)
  {
    case 1 :
      {
        joycalabcenter1();
        break;
      }
    case 2:
      {
        joycalabmin1();
        break;
      }
    case 3 :
      {
        joycalabmax1();
        break;
      }
    default:
      {
        lcd.setCursor (2, 0);
        lcd.print ("Calibration mode");
        delay(500);
        lcd.clear();
        break;
      }
  }
}

void stationmain()
{
  buttonReading3 = digitalRead(switch3);
  if (buttonReading3 == LOW && previous3 == HIGH )
  {
    flag_m = 1;
    if (state3 == LOW)
    {
      state3 = HIGH;
    }
    else
    {
      state3 = LOW;
    }
  }
  previous3 = buttonReading3;

  if (state3 == HIGH && flag_m == 1)
  {
    delay(500);
    lcd.clear();
    flag_2 = 0;
    flag_3 = 0;
    flag_1 = 0;


    state4 = LOW;
    state5 = LOW;
    state6 = LOW;

    digitalWrite(led1, HIGH);
    digitalWrite(led2, LOW);
    digitalWrite(led3, LOW);
    digitalWrite(led4, LOW);

    lcd.setCursor (3, 0);
    lcd.print(" Main Station");
    lcd.setCursor (6, 1);
    lcd.print("Operational");


    val_X = analogRead(joystick_X);
    Serial.print(joy_X(val_X));
    Serial.print(" : ");
    delay(50);
    val_Y = analogRead(joystick_Y);
    Serial.println(joy_Y(val_Y));
    delay(50);

    if (val_X >= 500 && val_X <= 512 && val_Y >= 500 && val_Y <= 512 )
    {
      digitalWrite(led5, LOW);
      digitalWrite(led6, LOW);
      digitalWrite(led7, LOW);
      digitalWrite(led8, LOW);
    }

    if (val_X <= 10 && val_X >= 0 && val_Y >= 500 && val_Y <= 512)
    {
      digitalWrite(led5, LOW);
      digitalWrite(led6, HIGH);
      digitalWrite(led7, HIGH);
      digitalWrite(led8, LOW);
    }
    if (val_Y <= 10 && val_Y >= 0 && val_X >= 500 && val_X <= 512)
    {
      digitalWrite(led5, HIGH);
      digitalWrite(led6, LOW);
      digitalWrite(led7, HIGH);
      digitalWrite(led8, LOW );
    }
    if (val_X >= 500 && val_X <= 512 && val_Y >= 1005 && val_Y <= 1023)
    {
      digitalWrite(led5, LOW);
      digitalWrite(led6, HIGH);
      digitalWrite(led7, LOW);
      digitalWrite(led8, HIGH);
    }
    if (val_Y >= 500 && val_Y >= 512 && val_X >= 1005 && val_X <= 1023)
    {
      digitalWrite(led5, HIGH);
      digitalWrite(led6, LOW);
      digitalWrite(led7, LOW);
      digitalWrite(led8, HIGH);
    }


  }
  else
  {
    state3 = HIGH;
  }
}


void loop()
{
  buttonReading2 = digitalRead(switch2);
  if (buttonReading2 == LOW && previous2 == HIGH)
  {
    if (state2 == LOW)
    {
      state2 = HIGH;
    }
    else
    {
      state2 = LOW;
    }
  }
  previous2 = buttonReading2;
  if (state2 == HIGH)
  {

    callib();
  }
  else
  {
    stationmain();
  }
}