/*
WK Arduino Software version 1-15-2015
By: WATERKARMA 
Takes commands via serial port in this form: <S=_:Z=___:T=___:N=___>
Sprinkler systems supported: Hunter, RainBird
*/

#include <LiquidCrystal.h>
//********************************************************
const int pinSerialOut = 12;
const int pinSerialIn = 13;
const int BuzzerPos = A5;
const int BuzzerNeg = A2;

int varZone = 1;
int varTimeOn = 1;
int varTemp_int;
char varCharRecover_char;
unsigned long varMillisSave_ulong;
byte varTemp_byte = 0;
char varCharSerialRead;
char charMessageSys;
int intMessageZone;
int intMessageTime;
int intMessageNote;
String varString = "";

// Hunter fx Variables
String varP0_String = "11111111010000000000000";
String varP1_String = "00000000000010000000000000";
String varP2_String = "00000000000010000000000000";
String varP3_String = "00000000000010000000000000";
String varP4_String = "001101110000011111110";

// RB fx Variables
const int timetiltrans = 215; //manchester encoding stuff time in uS
const int timeaftertrans = 150; //manchester encoding stuff time in uS
byte arrayOn_Byte[] = {245,245,245,28,4,57,0,1,5,67,B00011100};  //on command zone info in arrayOn_Byte[7]=zone and arrayOn_Byte[9]=zone+66
byte arrayOff_Byte[] = {245,245,245,28,1,64,65,B00011100};  //off command regardles of zone

//--------------------------------------------------------------------------------------------
void setup()
{ 
  // Open Serial port
  Serial.begin(9600); 
  Serial.println("<Initialized>");
  
  // Pin 13 has an LED connected on most Arduino boards:
  //  pinMode(0, INPUT);
  //  pinMode(1, INPUT);
  //  pinMode(2, INPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(11, INPUT);
  pinMode(12, OUTPUT);
  digitalWrite(12, HIGH);
  pinMode(13, INPUT);
  //digitalWrite(13, HIGH); // Pull up

  pinMode(BuzzerNeg, OUTPUT);
  digitalWrite(BuzzerNeg, LOW);
  pinMode(BuzzerPos, OUTPUT);
  digitalWrite(BuzzerPos, LOW);

  digitalWrite(BuzzerPos, 1);
  delay(100);
  digitalWrite(BuzzerPos, 0);
  delay(200);
  digitalWrite(BuzzerPos, 1);
  delay(100);
  digitalWrite(BuzzerPos, 0);
  delay(200);
  digitalWrite(BuzzerPos, 1);
  delay(100);
  digitalWrite(BuzzerPos, 0);
  delay(1000);
}
//--------------------------------------------------------------------------------------------
void loop()  { 
  while (Serial.available() > 0) Serial.read(); // Flush the serial receive buffer
  while (Serial.available() == 0)  delay(1);
  
  if (Serial.available() > 0)  {
    varMillisSave_ulong = millis();
    while ((Serial.available() < 23) && (millis() - varMillisSave_ulong < 250))  delay(1);
    if (Serial.available() < 23)  {
      Serial.println("<Timed Out - Message Short>");
    }
    else  {
      varString = "";
      for (int i=0; i < 23; i++)  {
        varCharSerialRead = Serial.read();
        varString += varCharSerialRead;
      }
      //Parse Message
      if (varString.indexOf('<') != 0)  Serial.println("Message Error - Begin Sentinel");
      else if (varString.indexOf('>') != 22)  Serial.println("Message Error - End Sentinel");
      else if (varString.charAt(1) != 'S')  Serial.println("Message Error - System Parameter");
      else if (varString.charAt(5) != 'Z')  Serial.println("Message Error - Zone Parameter");
      else if (varString.charAt(11) != 'T')  Serial.println("Message Error - Time Parameter");
      else if (varString.charAt(17) != 'N')  Serial.println("Message Error - Note Parameter");
      else  {
        //Passed all parameter checks
        charMessageSys = varString.charAt(3);
        intMessageZone = varString.substring(7,10).toInt();
        intMessageTime = varString.substring(13,16).toInt();
        intMessageNote = varString.substring(19,22).toInt();
        Serial.print("<Valid Message:S=");
        Serial.print(charMessageSys);
        Serial.print(":Z=");
        Serial.print(intMessageZone);
        Serial.print(":T=");
        Serial.print(intMessageTime);
        Serial.print(":N=");
        Serial.print(intMessageNote);
        Serial.println(">");
       
        if (charMessageSys == 'H')  {
          if (intMessageZone < 1)  varZone = 1;
          else if (intMessageZone > 48)  varZone = 48;
          else varZone = intMessageZone;
          
          if (intMessageTime < 0)  varTimeOn = 0;
          else if (intMessageTime > 90)  varTimeOn = 90;
          else varTimeOn = intMessageTime;
          
          fxPlayHunter();
        }
          
        if (charMessageSys == 'R')  {
          if (intMessageZone < 1)  varZone = 1;
          else if (intMessageZone > 48)  varZone = 48;
          else varZone = intMessageZone;
          
          if (intMessageTime < 0)  varTimeOn = 0;
          else if (intMessageTime > 1)  varTimeOn = 1;
          else varTimeOn = intMessageTime;
          
          fxPlayRB();
        }
        Serial.print("<Message Sent:S=");
        Serial.print(charMessageSys);
        Serial.print(":Z=");
        Serial.print(varZone);
        Serial.print(":T=");
        Serial.print(varTimeOn);
        Serial.println(">");
      }
    }
  }
  digitalWrite(A5, HIGH);
  delay(100);
  digitalWrite(A5, LOW);
}
//--------------------------------------------------------------------------------------------
void fxPlayHunter()  {
  //Build message from the front starting with P0
  if (varZone < 13)  {  //Weird change in P0 but it only happens at the zone 12 to 13 transition, phew!
    varP0_String.setCharAt(9,'1');
    varP0_String.setCharAt(10,'0');
  }
  else  {
    varP0_String.setCharAt(9,'0');
    varP0_String.setCharAt(10,'1');
  }
  //P1 here
  varTemp_byte = varZone + 23;
  for (int i=0; i <= 6; i++)  {
    if (bitRead(varTemp_byte,i) == 0)  varP1_String.setCharAt(i,'0');
    else  varP1_String.setCharAt(i,'1');
  }
  for (int i=0; i <= 6; i++)  {
    if (bitRead(varTemp_byte,i) == 0)  varP1_String.setCharAt(i + 13,'0');
    else  varP1_String.setCharAt(i + 13,'1');
  }
  varTemp_byte = varTimeOn;
  for (int i=0; i <= 3; i++)  {
    if (bitRead(varTemp_byte,i) == 0)  varP1_String.setCharAt(i + 8,'0');
    else  varP1_String.setCharAt(i + 8,'1');
  }
  for (int i=4; i <= 6; i++)  {
    if (bitRead(varTemp_byte,i) == 0)  varP1_String.setCharAt(i + 21 - 4,'0');
    else  varP1_String.setCharAt(i + 21 - 4,'1');
  }
  
  //P2 here
  varTemp_byte = varZone + 35;
  for (int i=0; i <= 6; i++)  {
    if (bitRead(varTemp_byte,i) == 0)  varP2_String.setCharAt(i,'0');
    else  varP2_String.setCharAt(i,'1');
  }
  for (int i=0; i <= 6; i++)  {
    if (bitRead(varTemp_byte,i) == 0)  varP2_String.setCharAt(i + 13,'0');
    else  varP2_String.setCharAt(i + 13,'1');
  }
  varTemp_byte = varTimeOn;
  for (int i=0; i <= 3; i++)  {
    if (bitRead(varTemp_byte,i) == 0)  varP2_String.setCharAt(i + 8,'0');
    else  varP2_String.setCharAt(i + 8,'1');
  }
  for (int i=4; i <= 6; i++)  {
    if (bitRead(varTemp_byte,i) == 0)  varP2_String.setCharAt(i + 21 - 4,'0');
    else  varP2_String.setCharAt(i + 21 - 4,'1');
  }
  
  //P3 here
  varTemp_byte = varZone + 47;
  for (int i=0; i <= 6; i++)  {
    if (bitRead(varTemp_byte,i) == 0)  varP3_String.setCharAt(i,'0');
    else  varP3_String.setCharAt(i,'1');
  }
  for (int i=0; i <= 6; i++)  {
    if (bitRead(varTemp_byte,i) == 0)  varP3_String.setCharAt(i + 13,'0');
    else  varP3_String.setCharAt(i + 13,'1');
  }
  varTemp_byte = varTimeOn;
  for (int i=0; i <= 3; i++)  {
    if (bitRead(varTemp_byte,i) == 0)  varP3_String.setCharAt(i + 8,'0');
    else  varP3_String.setCharAt(i + 8,'1');
  }
  for (int i=4; i <= 6; i++)  {
    if (bitRead(varTemp_byte,i) == 0)  varP3_String.setCharAt(i + 21 - 4,'0');
    else  varP3_String.setCharAt(i + 21 - 4,'1');
  }
  
  //P4 here
  varTemp_byte = varZone - 1;
  for (int i=0; i <= 3; i++)  {
    if (bitRead(varTemp_byte,i) == 0)  varP4_String.setCharAt(i + 8,'0');
    else  varP4_String.setCharAt(i + 8,'1');
  }
  
  varString = "";
  varString = varP0_String + varP1_String + varP2_String + varP3_String + varP4_String;
  
  delay(150);
  digitalWrite(A5, HIGH);
  delay(100);
  digitalWrite(A5, LOW);
  
  digitalWrite(pinSerialOut, LOW);
  //Serial.print("L");
  delay(320);
  digitalWrite(pinSerialOut, HIGH);
  //Serial.print("H");
  delay(65);
  digitalWrite(pinSerialOut, LOW);
  //Serial.println("L");
  delayMicroseconds(900);
  
  varTemp_int = varString.length() - 1;
  for (int i=0; i <= varTemp_int; i++)  {
    varCharRecover_char = varString.charAt(i);
    //Serial.write(varCharRecover_char);
    
    digitalWrite(pinSerialOut, HIGH);
    delayMicroseconds(225);
    digitalWrite(pinSerialOut, LOW);
    delayMicroseconds(225);
    
    if (varCharRecover_char == '0')  digitalWrite(pinSerialOut, HIGH);
    delayMicroseconds(1800);
  }
  digitalWrite(pinSerialOut, HIGH);
  //Serial.println("");
  //Serial.println("End");
}

void fxPlayRB()  {
  //Serial.print("Building ON message with zone: ");
  //Serial.println(varZone);
  
  arrayOn_Byte[7] = varZone;
  arrayOn_Byte[9] = varZone + 66;
  
  delay(150);
  digitalWrite(A5, HIGH);
  delay(100);
  digitalWrite(A5, LOW);
  
  if (varTimeOn == 1)  {  // Send ON message
    for (int ii=0; ii <= 9; ii++)  {
      for (int i=7; i >= 0; i--)  {
        if (bitRead(arrayOn_Byte[ii],i) == 1)  {
          digitalWrite(pinSerialOut, HIGH);
          delayMicroseconds(timetiltrans);
          digitalWrite(pinSerialOut, LOW);
          delayMicroseconds(timeaftertrans);
          //Serial.print("1");
        }
        else  {
          digitalWrite(pinSerialOut, LOW);
          delayMicroseconds(timetiltrans);
          digitalWrite(pinSerialOut, HIGH);
          delayMicroseconds(timeaftertrans);
          //Serial.print("0");
        }
      }
      //Serial.print(" ");
    }
    for (int i=7; i >= 1; i--)  {
      if (bitRead(arrayOn_Byte[10],i) == 1)  {
        digitalWrite(pinSerialOut, HIGH);
        delayMicroseconds(timetiltrans);
        digitalWrite(pinSerialOut, LOW);
        delayMicroseconds(timeaftertrans);
        //Serial.print("1");
      }
      else  {
        digitalWrite(pinSerialOut, LOW);
        delayMicroseconds(timetiltrans);
        digitalWrite(pinSerialOut, HIGH);
        delayMicroseconds(timeaftertrans);
        //Serial.print("0");
      }
    }
  }
  
  else  {  // Send OFF Message
    for (int ii=0; ii <= 6; ii++)  {
      for (int i=7; i >= 0; i--)  {
        if (bitRead(arrayOff_Byte[ii],i) == 1)  {
          digitalWrite(pinSerialOut, HIGH);
          delayMicroseconds(timetiltrans);
          digitalWrite(pinSerialOut, LOW);
          delayMicroseconds(timeaftertrans);
          //Serial.print("1");
        }
        else  {
          digitalWrite(pinSerialOut, LOW);
          delayMicroseconds(timetiltrans);
          digitalWrite(pinSerialOut, HIGH);
          delayMicroseconds(timeaftertrans);
          //Serial.print("0");
        }
      }
      //Serial.print(" ");
    }
    for (int i=7; i >= 1; i--)  {
      if (bitRead(arrayOff_Byte[7],i) == 1)  {
        digitalWrite(pinSerialOut, HIGH);
        delayMicroseconds(timetiltrans);
        digitalWrite(pinSerialOut, LOW);
        delayMicroseconds(timeaftertrans);
        //Serial.print("1");
      }
      else  {
        digitalWrite(pinSerialOut, LOW);
        delayMicroseconds(timetiltrans);
        digitalWrite(pinSerialOut, HIGH);
        delayMicroseconds(timeaftertrans);
        //Serial.print("0");
      }
    }
  }
  delayMicroseconds(timeaftertrans);
  digitalWrite(pinSerialOut, LOW);
  //Serial.println();
  //Serial.println("End");
}