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

// Set the LCD address to 0x27 for a 16x2 display
LiquidCrystal_I2C lcd(0x27, 16, 2);

#define BOUNCETIME 10
#define STARTINTERVAL 200 //mSec
#define TIMETODOUBLE 750 //mSec
#define pinSettings 4
#define pinAdjust 5

struct ButtonParameters {
  int parNum;
  int buttonPin;
  float Param;
  float minParam;
  float maxParam;
  float incSize;
  float curIncSize; //Current increment size - can get larger for faster changes
  unsigned long lastMillis;
  unsigned long interval; //Gets samaller when button held down
  bool Pressed;
  unsigned long PressedTime;

};


#define SETTINGS 2
//Names of the parameters
char  names[][21] = { "Voltage V\0", "Speed RPM\0"};
//Create storage for each button
ButtonParameters button1 = {0, 2, 0,    0,  1000, 0.5, 0, STARTINTERVAL, false, 0};
ButtonParameters button2 = {1, 3, 400, 100, 15000,  5, 0, STARTINTERVAL, false, 0};

int LastButtonPressed = 99;

bool adjustMode = false;

void setup() {
  pinMode(pinSettings, INPUT_PULLUP);
  pinMode(button1.buttonPin, INPUT_PULLUP);
  pinMode(button2.buttonPin, INPUT_PULLUP);

  Serial.begin(115200);

  int ButtonCount = sizeof(names) / sizeof(names[0]);
  Serial.print("Button Count:"); Serial.println(ButtonCount);

  // Initialize the LCD
  lcd.init();
  lcd.backlight();

  // Display a message on the LCD
  lcd.setCursor(0, 0); // Set the cursor to the first row
  lcd.print("Button Monitor");

}

void loop() {
  checkSettings(pinSettings);
  if (adjustMode) {


  } else {
    checkButton(button1);
    checkButton(button2);
  }
}

void checkSettings(int controlPin) {
  unsigned long currentMillis = millis();
  static int lastSetting = -1;
  static bool pressed = false;
  static unsigned long lastPress = 0;
  int reading = digitalRead(controlPin);

  if (reading == LOW && !pressed and millis() - lastPress > BOUNCETIME ) {
    Serial.println("Pressed");
    adjustMode = true;
    //Button has just been pressed
    pressed = true;
    lastPress = millis();
    lastSetting = ++lastSetting % SETTINGS;
    lcd.setCursor(0, 0);
    lcd.print("Setting ");
    lcd.print(names[lastSetting]);

  }

  if (reading == HIGH && pressed) {
    if (millis() - lastPress > BOUNCETIME) {
      pressed = false;
      lastPress = millis();
      Serial.println("Released");
    }
  }
}


void checkButton(ButtonParameters &button) {
  unsigned long currentMillis = millis();
  int reading = digitalRead(button.buttonPin);

  if (reading == LOW && !button.Pressed) {
    //Button has just been pressed
   Serial.println("New Button press");
    button.Pressed = true;
    button.PressedTime = currentMillis;
    button.interval = STARTINTERVAL;
    button.curIncSize = button.incSize;
    lcd.setCursor(0, 0);
    lcd.print("                "); //Overwrite any longer values
    lcd.setCursor(0, 0);
    lcd.print("Set ");
    lcd.print(names[button.parNum]);

  }

  if (button.Pressed) {
    if (currentMillis - button.PressedTime >= TIMETODOUBLE) {
      button.interval = button.interval / 2; //Halve the interval

      if (button.interval == 0) {
        button.interval = 1;
        button.curIncSize *=  2;
        Serial.print(" Increment size: "); Serial.println(button.curIncSize);
      }
      Serial.print(" Interval: "); Serial.println(button.interval);
      button.PressedTime = currentMillis;
    }

    if (currentMillis - button.lastMillis >= button.interval) {
      //ABout to increment
      if (LastButtonPressed != button.parNum) {
        //Just update the screen with the current value
        LastButtonPressed = button.parNum;
        Serial.println("Change of  Button pressed");
        lcd.setCursor(0, 1); // Set the cursor to the 2nd row
        lcd.print("              "); //Overwrite any longer values

      } else {
        button.Param += button.curIncSize;
      }

      button.lastMillis = currentMillis;
      long stepsLeft = (button.maxParam - button.Param) / button.curIncSize;

      long timeLeft = stepsLeft * button.interval;
      
      if (timeLeft < 10 ) {
        //Slow down before wrapping round
        Serial.println("===Slow down=== ");
 
        Serial.print(" Steps left: "); Serial.println( stepsLeft);
        Serial.print(" Time left: "); Serial.println( timeLeft);
        Serial.print(" Interval: "); Serial.println(button.interval);
        Serial.print(" Increment size: "); Serial.println(button.curIncSize);
   
        Serial.print(" Param: "); Serial.println( button.Param);

       button.interval = STARTINTERVAL;
      button.curIncSize =  button.incSize ;

      }

      if (button.Param > button.maxParam) {
        Serial.println("Wrap round");
        button.Param = button.minParam;
        button.curIncSize =  button.incSize ;
        button.interval = STARTINTERVAL; //Slow speed again
        lcd.setCursor(0, 1); // Set the cursor to the 2nd row
        lcd.print("              "); //Overwrite any longer values
        lcd.setCursor(0, 1); // Set the cursor to the 2nd row
        lcd.print(button.Param);
      }
      /*
        Serial.print(names[button.parNum]);
        Serial.print("=");
        Serial.println(button.Param);
        Serial.flush();
      */
      lcd.setCursor(0, 1); // Set the cursor to the 2nd row
      lcd.print(button.Param);
    }
  }

  if (reading == HIGH && button.Pressed) {
    if (currentMillis - button.PressedTime > BOUNCETIME) {
      Serial.println("Button release");
      button.Pressed = false;
      button.interval = STARTINTERVAL;

    } else {
      //Serial.print("B");
    }
  }
}