/*
 * This is a test sketch for a Arduino to allow the data received via its serialport
 * from the "TS2017 Raildriver And Joystick Interface" program to be used to control 
 * led's and LCD displays. The data is in the format
 * "<ControlGroup:ControlName:value>".
 * E.G. <Reverser:VirtualReverser:0.5>
 * we use < and > to indicate the start and end of the data and : to split the info.
 */
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
const byte AwsDRA_Pin = 13;
const byte Doors_Pin = 2;
const byte Dsd_Pin = 3;
const byte Emergency_Pin = 4;
const byte Engine_Pin = 5;
const byte Handbrake_Pin = 6;
const byte Sifa_Pin = 7;

//Here we add the details regarding the lcd screen width/height
const byte lcdWidth = 20;
const byte lcdRows = 4;

//Buffer to hold data from serialport
//data[0] = controlgroup
//data[1] = controlname
//data[2] = value
char data[3][80];

// byte data to hold the position of the current char in the data array.
byte cnt = 0;
byte pos = 0;

//Marker set when start of data received
boolean started = false;

//Marker set when all data received
boolean finished = false;

//Set I2C LCD Address
byte Lcd_Address = 0x27;

//Initialise the lcd.
LiquidCrystal_I2C lcd(Lcd_Address, 20, 4);

char ButtonMap[80];
char LocoName[80];


void setup() {
  // Set the pins
  pinMode(AwsDRA_Pin, OUTPUT);
  pinMode(Doors_Pin, OUTPUT);
  pinMode(Dsd_Pin, OUTPUT);
  pinMode(Emergency_Pin, OUTPUT);
  pinMode(Engine_Pin, OUTPUT);
  pinMode(Handbrake_Pin, OUTPUT);
  pinMode(Sifa_Pin, OUTPUT);
  Serial.begin(9600);

  //Setup lcd
  lcd.begin();
  lcd.backlight();
  lcd.clear();

  //Display a message to the user to show the code is working
  // and waiting for data.
  lcd.setCursor(0,0);
  lcd.print("Waiting for TS2019");
}

void loop() {
  // Check we have something in the serial buffer
  while(Serial.available() > 0) {
    char nextChar = Serial.read();
    if(nextChar == '<') { //Check for start of command marker
      started = true;
      finished = false;
      pos = 0;
      cnt = 0;

      //Reset data to nothing
      data[0][0] = '\0';
      data[1][0] = '\0';
      data[2][0] = '\0';
    }
    else if(nextChar == '>') { //End of command marker
      finished = true;
      break; //We have our data so exit the loop
    }
    else if(nextChar == ':') { //End of current string
      pos++;
      cnt = 0;
    }
    else {
      data[pos][cnt] = nextChar; //Store the incoming data one char at a time
      cnt++;
      data[pos][cnt] = '\0'; //Null terminate the data array;
    }
  } //End of While loop
  
  if(started && finished) { //All data for the current command received.
    UpdateHardware();//Activate switches/displays etc
  }
}

void UpdateHardware() {
   //Check if loco has changed, if so clear the display.
  if(!strcmp(data[0],"locochanged")){
    // Clear the lcd screen
    lcd.clear();
    //Turn all led's off
    digitalWrite(AwsDRA_Pin, LOW);
    digitalWrite(Doors_Pin, LOW);
    digitalWrite(Dsd_Pin, LOW);
    digitalWrite(Emergency_Pin, LOW);
    digitalWrite(Engine_Pin, LOW);
    digitalWrite(Handbrake_Pin, LOW);
    digitalWrite(Sifa_Pin, LOW);
	strcpy(ButtonMap, data[1]);
	strcpy(LocoName, data[2]);
    return;
  }
  
  //Convert value to an int.
  int value = atoi(data[2]);
  
  //Convert value to a float.
  float fvalue = atof(data[2]);

  //Used to hold how many spaces required at end of a line for the lcd
  byte padding = 0;
  
  //Temporary variable used when formatting output string for the display
  char tmp[30];
  
  //Although we have both sunflower and DRA set to the same pin, because in the program
  //I have them assigned to different serialports, only the command assigned to this
  //Arduinos port will be activated, this allows the same code to be used on multiple Arduinos.
  if( !strcmp(data[0],"Sunflower") || !strcmp(data[0], "DRA")) {
    if(value == 1) {
        digitalWrite(AwsDRA_Pin, HIGH);
      } else if(value == 0) {
        digitalWrite(AwsDRA_Pin, LOW);
      }
  }
  //Here we check to see if the controlgroup is "Speed", if it is, display it
  else if( !strcmp(data[0], "Speed")){
    lcd.setCursor(0,0);
    //The sprintf() function in the Arduino does not allow the use of float variables
    // so we need to use the dtostrf() function to convert the value to a string.
    char newVal[7];
    dtostrf(fvalue, 4, 1, newVal);
    sprintf(tmp,"%s = %s", data[0], newVal);
    padding = lcdWidth - strlen(tmp);
    lcd.print(tmp);
    for(int i = 0; i < padding; i++) {
      lcd.print(" ");
    }
  }
  //Here we move the cursor to line 1 and display the controlgroup "Gears"
  else if( !strcmp(data[0], "Gears")) {
    lcd.setCursor(0,1);
    sprintf(tmp, "%s = %d", data[0], value);
    padding = lcdWidth - strlen(tmp);
    lcd.print(tmp);
    for(int i = 0; i < padding; i++) {
      lcd.print(" ");
    }
  }
  //Here we move the cursor to line 2 and display the controlgroup "Reverser"
  //We use the float value and multiply it by 100 to get the % value. We then
  //add the % sign to the end.
  else if( !strcmp(data[0], "Reverser")) {
    lcd.setCursor(0,2);
    int i = fvalue * 100;
    sprintf(tmp, "%s = %d%%", data[0], i);
    padding = lcdWidth - strlen(tmp);
    lcd.print(tmp);
    for(int i = 0; i < padding; i++) {
      lcd.print(" ");
    }
  }
  //Here we display text to show if the doors are open/closed
  else if( !strcmp(data[0], "Doors")) {
    lcd.setCursor(0,3);
    if(value >= 1)
      sprintf(tmp, "%s Open", data[0]);
    else if(value == 0)
      sprintf(tmp, "%s Closed", data[0]);
    padding = lcdWidth - strlen(tmp);
    lcd.print(tmp);
    for(int i = 0; i < padding; i++) {
      lcd.print(" ");
    }
  }
}