// LessonG.ino
// Program with servo, potentiometer, led flashes, switch buttons, question and response
// 
// See @Robin2's https://forum.arduino.cc/t/planning-and-implementing-an-arduino-program/252364/9
// and https://forum.arduino.cc/t/best-first-5-topics-to-read-to-reach-trust-level-1/1287592
// DaveX: slight mod: change endMarker to '\n'

//======for the servo==========
#include <Servo.h>
Servo myServo;
const byte servoPin = 5;
const byte servoMin = 20;
const byte servoMax = 160;
byte servoPosition = servoMin;

//======for the potentiometer===
const byte potPin = A0;
int potValue;

//======for the LEDs============
const unsigned long ledOnMillis = 300;
const unsigned long ledAbaseInterval = 500;
const unsigned long ledBbaseInterval = 1000;
unsigned long ledAInterval = ledAbaseInterval;
unsigned long ledBInterval = ledBbaseInterval;
byte ledAstate = HIGH;
byte ledBstate = HIGH;
unsigned long prevLedAMillis;
unsigned long prevLedBMillis;
unsigned long currentMillis;
const byte ledApin = 13;
const byte ledBpin = 12;
unsigned long ledAoffMillis = ledAbaseInterval;
unsigned long ledBoffMillis = ledBbaseInterval;


//======for the switch buttons===
const byte button0pin = 8;
const byte button1pin = 9;
byte button0state;
byte button1state;

//======for user question========
const char question[] = "Please type some text and press ENTER";
const unsigned long questionInterval = 5000;
unsigned long prevResponseMillis = 0;
boolean waitingForResponse = false;

//=====for user response=========
const byte buffSize = 31;
char userResponse[buffSize];
const char endMarker = '\n'; // \r or \n as your system works.
byte bytesRecvd = 0;
boolean ackResponse = false;


void setup() {
  myServo.attach(servoPin);
  myServo.write(servoPosition);
  
  pinMode(ledApin, OUTPUT);
  pinMode(ledBpin, OUTPUT);
  digitalWrite(ledApin, HIGH);
  digitalWrite(ledBpin, HIGH);
  
  pinMode(button0pin, INPUT_PULLUP);
  pinMode(button1pin, INPUT_PULLUP);
  
  Serial.begin(9600);
  Serial.println("Starting LessonG.ino");
  
  delay(5000);
}

void loop() {
 
    currentMillis = millis();

    checkButtons();
    setFlashPeriod();
    flashLedA();
    flashLedB();
    
    askForUserInput();
    getUserResponse();
    acknowledgeResponse();
    
    readPotentiometer();
    setServoPosition();
    moveServo();
}

void flashLedA() {
  if (currentMillis - prevLedAMillis >= ledAInterval) {
    prevLedAMillis += ledAInterval;
    ledAstate = ! ledAstate;
    if (ledAstate == HIGH) {
      ledAInterval = ledOnMillis;
    }
    else {
      ledAInterval = ledAoffMillis;
    }
    digitalWrite(ledApin, ledAstate);
  }
}

void flashLedB() {
  if (currentMillis - prevLedBMillis >= ledBInterval) {
    prevLedBMillis += ledBInterval;
    ledBstate = ! ledBstate;
    if (ledBstate == HIGH) {
      ledBInterval = ledOnMillis;
    }
    else {
      ledBInterval = ledBoffMillis;
    }
    digitalWrite(ledBpin, ledBstate);
  }
}

void checkButtons() {
  button0state = digitalRead(button0pin);
  button1state = digitalRead(button1pin);
}

void setFlashPeriod() {

  if (button0state == LOW && button1state == LOW) {
    return; // if both buttons are pressed do nothing
  }

  if (button0state == LOW) { // LOW means button is pressed
     ledAoffMillis = ledAbaseInterval;
     ledBoffMillis = ledAbaseInterval;
  }

  if (button1state == LOW) {
     ledAoffMillis = ledAbaseInterval >> 1;
     ledBoffMillis = ledAbaseInterval >> 1;
  }
}

void askForUserInput() {
  if (waitingForResponse == true) {
    return;
  }
  
  if (currentMillis - prevResponseMillis >= questionInterval) {
    Serial.println(question);
    waitingForResponse = true;
    bytesRecvd = 0;
  }
}

void getUserResponse() {
  if (waitingForResponse == false) {
    return;
  }

  if(Serial.available() == 0) {
    return;
  }

  char inChar = Serial.read();
   
  if (inChar != endMarker) {
    userResponse[bytesRecvd] = inChar;
    bytesRecvd ++;
    if (bytesRecvd == buffSize) {
      bytesRecvd = buffSize - 1;
    }

  }
  else { // inChar is the endMarker
    waitingForResponse = false;
    userResponse[bytesRecvd] = 0;
    prevResponseMillis = currentMillis;
    ackResponse = true;
  }
}

void moveServo() {
  myServo.write(servoPosition);
}

void readPotentiometer() {
  potValue = analogRead(potPin);
}

void setServoPosition() {
  servoPosition = (servoMax - servoMin) * (long) potValue / 1023 + servoMin;
}

void acknowledgeResponse() {
  if (ackResponse == false) {
    return;
  }
  Serial.println();
  Serial.println("Thank you");
  Serial.print("You entered the following ");
  Serial.print(bytesRecvd);
  Serial.println(" bytes ");
  Serial.print(" --- ");
  Serial.println(userResponse);
  Serial.println();
  
  ackResponse = false;
}