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

LiquidCrystal_I2C lcd(0x27, 16, 2);

byte up_button = 16;
byte dn_button = 2;
byte ent_button = 17;
byte jog_left = 4;
byte jog_right = 15;

byte move_state = 0;
byte move_state_last = 0;
byte ent_state = 0;
byte ent_state_last = 0;
byte jog_state = 0;

byte program_state = 0;
byte program_state_last = 0;

int n_turns = 100;
long hold_start_time = 0;
int hold_duration = 0;
double pitch = 0;

int coil_length = 25;
int turns_per_layer = 0;
long pulse_time = 0;
int time_since_pulse = 0;

int total_counter = 0;
int layer_counter = 0;
int layer_number = 1;
int wind_direction = 1;

byte wire_step_divisor[] = {
    255, 255, 255, 255, 15, 18,
    255, 255, 255, 255, 255}; // 255 means i havent calibrated the number yet
byte awg_sizes[] = {16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36};

// added for stepper rotor variant

byte switch_state = 0;
byte switch_state_last = 1;
byte follower_direction = 0;
byte follower_steps_index = 1;

void setup() {
  pinMode(up_button, INPUT_PULLUP);
  pinMode(dn_button, INPUT_PULLUP);
  pinMode(ent_button, INPUT_PULLUP);
  pinMode(jog_left, INPUT_PULLUP);
  pinMode(jog_right, INPUT_PULLUP);

  pinMode(4, INPUT_PULLUP); // LEFT LIMIT
  pinMode(9, INPUT_PULLUP); // RIGHT LIMIT

  pinMode(8, OUTPUT); // Rotor Step
  pinMode(7, OUTPUT); // Rotor direction

  pinMode(10, OUTPUT); // Follower direction
  pinMode(11, OUTPUT); // Follower step
  pinMode(13, OUTPUT); // Follower & Rotor RST

  // Pulse the sleep / reset on the stepper driver (doesn't work without this on
  // A4988 boards)
  digitalWrite(13, LOW);
  delay(50);
  digitalWrite(13, HIGH);
  Serial.begin(9600);
  digitalWrite(7, HIGH);

  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Number of turns:");
}

void loop() {
  move_state = (1 - digitalRead(up_button)) + (1 - digitalRead(dn_button)) * 2;
  ent_state = 1 - digitalRead(ent_button);
  jog_state = (1 - digitalRead(jog_left)) +
              (1 - digitalRead(jog_right)) *
                  2; // 2 = Right button press,  1 = Left button press

  switch (program_state) {
  ///==========================================STATE 0: TURN COUNT
  /// SELECTION=======================================================================
  case 0:
    lcd.setCursor(0, 1);
    lcd.print("      ");
    lcd.setCursor(0, 1);
    lcd.print(n_turns);

    if (move_state == 1) {
      if (hold_duration > 5000) {
        n_turns = n_turns + 50;
      } else if (hold_duration > 2000) {
        n_turns = n_turns + 10;
      } else {
        n_turns++;
      }

      if (n_turns > 9999) {
        n_turns = 9999;
      }
      if (move_state_last != move_state) {
        hold_start_time = millis();
      }
      hold_duration = millis() - hold_start_time;
      lcd.print("     ");
    }

    else if (move_state == 2 && n_turns > 0) {
      if (hold_duration > 5000) {
        n_turns = n_turns - 50;
      } else if (hold_duration > 2000) {
        n_turns = n_turns - 10;
      } else {
        n_turns--;
      }
      if (move_state_last != move_state) {
        hold_start_time = millis();
      }
      if (n_turns < 0) {
        n_turns = 0;
      }
      hold_duration = millis() - hold_start_time;
      lcd.print("     ");
    }

    else {
      hold_start_time = 0;
      hold_duration = 0;
    }

    if (ent_state == 1 && move_state == 0) {
      if (n_turns > 0) {
        program_state++;
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("....");
        delay(250);
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Pitch");
      } else {
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Invalid number");
        lcd.setCursor(0, 1);
        lcd.print("of turns!");
        delay(2000);
      }
    }

    move_state_last = move_state;
    delay(100);
    break;

  ///==========================================STATE 1: AWG
  /// SELECTION=======================================================================
  case 1:
    lcd.setCursor(0, 1);
    lcd.print("pitch");

    if (move_state == 1) {
      pitch + 0.1;
      if (pitch > 10) {
        pitch = 10;
      }
    } else if (move_state == 2) {
      if (pitch > 0) {
        pitch - 0.1;
      }
      if (move_state_last != move_state) {
        hold_start_time = millis();
      }
      hold_duration = millis() - hold_start_time;
    } else {
      hold_start_time = 0;
      hold_duration = 0;
    }

    if (hold_duration > 1500) {
      program_state--;
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Going back...");
      delay(1000);
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Number of turns:");
    }

    if (ent_state == 1 && move_state == 0) {
      program_state++;
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print(n_turns);
      lcd.setCursor(5, 0);
      lcd.print("Turns");
      lcd.setCursor(11, 0);
      lcd.print(pitch);
      lcd.setCursor(14, 0);
      lcd.print("mm");
      lcd.setCursor(0, 1);
      lcd.print(coil_length);
      lcd.setCursor(6, 1);
      lcd.print("mm");
      lcd.setCursor(10, 1);
      lcd.print("OK?");
    }
    move_state_last = move_state;
    delay(200);
    break;

  ///==========================================STATE 2:
  /// VERIFICATION===========================================================================
  case 2:

    delay(250);

    if (move_state == 2) {
      if (move_state_last != move_state) {
        hold_start_time = millis();
      }
      hold_duration = millis() - hold_start_time;
    } else {
      hold_start_time = 0;
      hold_duration = 0;
    }
    if (hold_duration > 1500) {
      program_state--;
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Going back...");
      delay(250);
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Coil Length(mm):");
    }

    if (ent_state == 1 && move_state == 0) {
      program_state++;
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("....");
      delay(250);
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Please position");
      lcd.setCursor(0, 1);
      lcd.print("wire guide...");
    }
    move_state_last = move_state;
    break;

  ///==========================================STATE 3: MANUAL JOG BEFORE
  /// START===============================================================
  case 3:

    if (move_state == 2) {
      if (move_state_last != move_state) {
        hold_start_time = millis();
      }
      hold_duration = millis() - hold_start_time;
      // Serial.println(hold_duration);
    } else {
      hold_start_time = 0;
      hold_duration = 0;
    }

    if (hold_duration > 2000) {
      program_state--;
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Going back...");
      delay(500);
      lcd.clear();
    }

    if (ent_state == 1 && move_state == 0) {
      program_state++;
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Starting coil...");
      delay(150);
      for (byte i = 0; i < 16; i++) {
        lcd.setCursor(i, 1);
        lcd.print(".");
        delay(20);
      }
      delay(250);
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Winding in");
      lcd.setCursor(0, 1);
      lcd.print("progress...");
    }
    move_state_last = move_state;
    break;

  ///==========================================STATE 4: Automated
  /// winding====================================================================
  case 4:

    if (total_counter < n_turns) {
      for (int j = 0; j < n_turns; j++) {
        switch_state =
            (1 - digitalRead(4)) +
            (1 - digitalRead(9)) * 2; // 1 = left switch, 2 = right switch
      }

      if (switch_state == 2 && switch_state_last == 1) {
        digitalWrite(10, HIGH);
        follower_direction = 1 - follower_direction;
        switch_state_last = switch_state;
      }

      if (switch_state == 1 && switch_state_last == 2) {
        digitalWrite(10, LOW);
        follower_direction = 1 - follower_direction;
        switch_state_last = switch_state;
      }
      for (int i = 0; i < 1600; i++) {

        follower_steps_index++;

        if (follower_steps_index == pitch) {
          digitalWrite(11, HIGH);
          digitalWrite(8, HIGH);
          delayMicroseconds(100);
          digitalWrite(11, LOW);
          digitalWrite(8, LOW);
          delayMicroseconds(100);
          follower_steps_index = 1;
        }

        else {
          digitalWrite(8, HIGH);
          delayMicroseconds(100);
          digitalWrite(8, LOW);
          delayMicroseconds(100);
        }
      }
      total_counter++;
    }

    else {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print(n_turns);
      lcd.print(" Turns");
      lcd.setCursor(0, 1);
      lcd.print("Complete");
      program_state++;
      layer_counter = 0;
      layer_number = 1;
      total_counter = 0;
      wind_direction = 1;
    }
    break;
  ///==========================================STATE 6: Waiting for return to
  /// start====================================================================
  case 5:
    if (ent_state == 1 && move_state == 0) {
      program_state = 0;
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Returning...");
      delay(500);
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Number of turns:");
    }
    break;
  }

  if (program_state != 4) // Lock out manual controls when winding is in process
  {
    if (jog_state == 1) {
      // manual jog
    } else if (jog_state == 2) {
      // manual jog
    }
  }

  ent_state_last = ent_state;
  program_state_last = program_state;
  delayMicroseconds(10);
}
esp:VIN
esp:GND.2
esp:D13
esp:D12
esp:D14
esp:D27
esp:D26
esp:D25
esp:D33
esp:D32
esp:D35
esp:D34
esp:VN
esp:VP
esp:EN
esp:3V3
esp:GND.1
esp:D15
esp:D2
esp:D4
esp:RX2
esp:TX2
esp:D5
esp:D18
esp:D19
esp:D21
esp:RX0
esp:TX0
esp:D22
esp:D23
lcd1:GND
lcd1:VCC
lcd1:SDA
lcd1:SCL
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
btn2:1.l
btn2:2.l
btn2:1.r
btn2:2.r
btn3:1.l
btn3:2.l
btn3:1.r
btn3:2.r
btn4:1.l
btn4:2.l
btn4:1.r
btn4:2.r
btn5:1.l
btn5:2.l
btn5:1.r
btn5:2.r
A4988
drv1:ENABLE
drv1:MS1
drv1:MS2
drv1:MS3
drv1:RESET
drv1:SLEEP
drv1:STEP
drv1:DIR
drv1:GND.1
drv1:VDD
drv1:1B
drv1:1A
drv1:2A
drv1:2B
drv1:GND.2
drv1:VMOT
A4988
drv2:ENABLE
drv2:MS1
drv2:MS2
drv2:MS3
drv2:RESET
drv2:SLEEP
drv2:STEP
drv2:DIR
drv2:GND.1
drv2:VDD
drv2:1B
drv2:1A
drv2:2A
drv2:2B
drv2:GND.2
drv2:VMOT
stepper1:A-
stepper1:A+
stepper1:B+
stepper1:B-
stepper2:A-
stepper2:A+
stepper2:B+
stepper2:B-