#include <Arduino.h>
#include "A4988.h"
#include "EEPROM.h"
#include "HX711_ADC.h"

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

int PIN_SCK = 8;
int PIN_DT = 9;
HX711_ADC LoadCell(PIN_DT, PIN_SCK);


int Step = 3;   //GPIO3 in Arduino UNO --- Step of stepper motor driver
int Dire  = 2;  //GPIO2 in Arduino UNO --- Direction of stepper motor driver
int Sleep = 4;  //GPIO4 in Arduino UNO --- Control Sleep Mode on A4988
int MS3 = 5;    //GPIO5 in Arduino UNO --- MS3 for A4988
int MS2 = 6;    //GPIO6 in Arduino UNO --- MS2 for A4988
int MS1 = 7;    //GPIO7 in Arduino UNO --- MS1 for A4988

//Motor Specs
const int spr = 200;  //Steps per revolution
int RPM = 1;         //Motor Speed in revolutions per minute
int Microsteps = 2;   //Stepsize (1 for full steps, 2 for half steps, 4 for quarter steps, etc)

//Providing parameters for motor control
A4988 stepper(spr, Dire, Step, MS1, MS2, MS3);

int eeprom_idx = 0;

int btn_tare = 13;
int btn_ready = 12;
void taring_fn() {
  if (digitalRead (btn_tare) == LOW ) {
    Serial.println("Taring Sensor ...");
    lcd.clear();
    delay(150);
    lcd.setCursor(3, 0);
    lcd.print("Taring");
    delay(200);
    LoadCell.start(1000);
    delay(400);
    Serial.println("Ready!!!");
    weigth_display(0);
  }
}



/* Start Function */


void lcd_show(String txt) {
  // lcd.clear();
  lcd.setCursor(1, 0);
  lcd.print(txt);
}

void eeprom_write(int addr, String str) {
  byte len = str.length();
  EEPROM.put(addr, len);
  for (int i = 0; i < len; i++) {
    EEPROM.put(addr + 1 + i, str[i]);
  }
}
String eeprom_read(int addr) {
  int len = EEPROM.read(addr);
  // char data[len + 1];
  char data[len];

  for (int i = 0; i < len; i++) {
    data[i] = EEPROM.read(addr + 1 + i);
  }
  // data[len] = '\0';
  return String(data);
}

void EEPROM_process() {
  Serial.println("EEPROM idx:" + String(eeprom_idx) + ", ready to used.!");
  if (Serial.available() > 0) {
    String read_str = Serial.readString();
    if (read_str.indexOf("SAVE:") > -1) {
      read_str.replace("SAVE:", "");
      eeprom_write(eeprom_idx, read_str);
      Serial.println("Saved..");
    } else if (read_str.indexOf("READ") > -1) {
      String read_saved_str = eeprom_read(eeprom_idx);
      Serial.println(String("Read from EEPROM :\"") + read_saved_str + String("\""));
    } else if (read_str.indexOf("IDX") > -1) {
      read_str.replace("IDX:", "");
      eeprom_idx = read_str.toInt();
      Serial.println("eeprom_idx changed to:" + read_str);
    } else {
      Serial.println("-----------");
    }
  }
}
/* End Function */


void weigth_display(float current_weight) {
  lcd.setCursor(2, 0);
  lcd.print("Weighing Scale");
  lcd.setCursor(0, 1);
  lcd.print(current_weight, 0);
  lcd.print("g");
  if (current_weight < 0) {
    delay(200);
    LoadCell.start(1000);
    delay(400);
    lcd.clear();
  }
}
void setup() {
  // Serial.begin(9600);
  Serial.begin(115200);
  Serial.setTimeout(10);
  pinMode(Step, OUTPUT);    // Step pin as output
  pinMode(Dire,  OUTPUT);   // Direcction pin as output
  pinMode(Sleep,  OUTPUT);  // Set Sleep OUTPUT Control button as output
  digitalWrite(Step, LOW);  // Currently no stepper motor movement
  digitalWrite(Dire, LOW);

  pinMode(A0, OUTPUT);    // LED

  // Set target motor RPM to and microstepping setting
  stepper.begin(RPM, Microsteps);

  pinMode(btn_tare,  INPUT_PULLUP);
  pinMode(btn_ready,  INPUT_PULLUP);

  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(1, 0);
  lcd.print("Weighing Scale");
  delay(850);
  lcd.clear();
  delay(150);
  lcd.setCursor(3, 0);
  lcd.print("Taring");
  delay(200);
  lcd.setCursor(9, 0);
  lcd.print(".");
  delay(200);
  lcd.setCursor(10, 0);
  lcd.print(".");
  delay(200);
  lcd.setCursor(11, 0);
  lcd.print(".");
  delay(200);
  lcd.setCursor(12, 0);
  lcd.print(".");
  delay(200);

  LoadCell.begin();
  LoadCell.start(1000);
  LoadCell.setCalFactor(0.42);
  lcd.clear();
  Serial.println("Setup done.");
  digitalWrite(Sleep, HIGH);
  weigth_display(0);
}

int feeding = 0;
float current_weight = 0.0;
float target_weight = 1000.0;
void motor_sensor() {
  if (current_weight < target_weight) {
    //A logic high allows normal operation of the A4988 by removing from sleep
    if (target_weight - current_weight > 100) {
      RPM = 1000;      
    } else if (target_weight - current_weight > 50) {
      RPM = 750;      
    } else if (target_weight - current_weight > 20) {
      RPM = 250;
    } else if (target_weight - current_weight > 10) {
      RPM = 150;
    } else if (target_weight - current_weight > 5) {
      RPM = 10;
    }
    stepper.begin(RPM, Microsteps);
    stepper.rotate(1);
  } else {
    RPM = 1000;
    feeding = 0;
  }
}
void led_sensor() {
  if (current_weight < target_weight) {
    digitalWrite(A0, LOW);
  } else {
    digitalWrite(A0, HIGH);
  }
}



void weight_sensor_fn() {
  LoadCell.update();
  current_weight = LoadCell.getData();

  // Serial.println(String("Weight :") + String(current_weight, 2) + String("g."));
  weigth_display(current_weight);
}
void loop() {
  // EEPROM_process();

  // lcd_show("Ready...");
  // updateCursor();
  taring_fn();
  if (feeding == 1) {
    motor_sensor();
    led_sensor();
    weight_sensor_fn();
  }
  // lcd.clear();

  if (digitalRead(btn_ready) == LOW) {
    Serial.println("Ready!!!");
    feeding = 1;
  }
  // delay(100);
}
A4988