/*******************************************************************************
 * Program..: idCloset.ino Control curtain
 * Author...: Jan-marie Newton
 * Date.....: 2018-02-12
 * History..: 2020-09-17 - adjust cause solid state relay is inverted
 * Notes....:
 *******************************************************************************/
char VERSION[] = "Ver 3.5;";
#include "U8glib.h"
#define TXBEG '['
#define TXFIN ']'
#define RELAY  4
#define SELECT 2
#define FLIP   3

char serialdata[4];             // incoming buffer
char allRelays[]    = "000000000;";
unsigned int inx    = 9;        // incoming buffer index
unsigned int inByte = 0;        // incoming serial byte
unsigned long int debounce = 0;
unsigned long int debdelay = 500;
volatile unsigned int rlay = 2; // Current relay on LCD
volatile bool redraw = true;
char cmd    = 0;
char opt    = 0;
char sp     = 'Z';
bool debug  = false;
bool useSSR = true;


// SPI Com: SCK = en = 14, MOSID = rw = 16, CS = di = 15
U8GLIB_ST7920_128X64 u8g(14, 16, 15, U8G_PIN_NONE);

//--------------------------------------------------------------
void draw(void) {
   // update screen
   u8g.firstPage();
   do {
      drawBrds(rlay);
      drawStat();
   } while( u8g.nextPage() );
   redraw = false;
}
//--------------------------------------------------------------

//--------------------------------------------------------------
void drawBrds(unsigned int c) {
   char n[] = "0";
   u8g.setFont(u8g_font_ncenB14);
   for(int i=1; i<=4; ++i) {
      n[0] = 48+i;
      u8g.drawStr(0, i*16, n);
      n[0] = 48+i+4;
      u8g.drawStr(116, i*16, n);
   }
   u8g.drawRFrame(44, 9, 37, 42, 7);
   u8g.drawRFrame(43, 8, 39, 44, 7);
   u8g.setFont(u8g_font_gdr25);
   n[0] = 48+c;
   u8g.drawStr(53,41, n);
  //u8g.drawHLine(2+d, 35+d, 47);
  //u8g.drawVLine(45+d, 32+d, 12);
}
//--------------------------------------------------------------

//--------------------------------------------------------------
void drawStat() {
   int rad = 6;
   int l = 0;
   int r = 0;
   for(int i=1; i<=4; ++i) {
      l = digitalRead(i + RELAY - 1);
      if (useSSR and i == 1) l = 1 - l;  // solid state relay is inverted
      r = digitalRead(i + RELAY + 3);
      int y = i * 2*(rad+2) - 8;

      if (false) {
         Serial.print("pins: ");
         Serial.print(i + RELAY - 1);
         Serial.print(" : ");
         Serial.print(i + RELAY + 3);
         Serial.print(" left: ");
         Serial.print(l);
         Serial.print(" right: ");
         Serial.println(r);
      }
      if (l == 1)
         u8g.drawCircle(18,y, rad);
      else
         u8g.drawDisc(18,y, rad);

      if (r == 1)
         u8g.drawCircle(106,y, rad);
      else
         u8g.drawDisc(106,y, rad);
   }
   if (false)
      Serial.println(" ---------- ");
}
//--------------------------------------------------------------

//-----------------------------------------------------------
void setup() {
   // Turns all Relays Off
   pinMode(RELAY, OUTPUT);
   digitalWrite(RELAY, useSSR ? LOW : HIGH);
   for(int i=RELAY+1; i<RELAY+8; i++) {
      pinMode(i, OUTPUT);
      digitalWrite(i,HIGH);
   }

   // setup buttons
   pinMode(SELECT, INPUT_PULLUP);
   pinMode(FLIP, INPUT_PULLUP);

   // start serial port at 115200 bps and wait for port to open:
   Serial.begin(115200);
   if (debug) Serial.println("Begin program");

   // buttons
   attachInterrupt(digitalPinToInterrupt(SELECT), setrelay, CHANGE);
   attachInterrupt(digitalPinToInterrupt(FLIP), fliprelay, CHANGE);
}
//------------------------------------------------------------

//============================================================
void loop() {
   // reset debounce
   if (debounce and (millis() - debounce) > debdelay)
      debounce = 0;

   // Listen for serial data from host computer
   //---------------------------------------------------------
   if (Serial.available() <= 0) {
      if (redraw) draw();
      return;
   }

   inByte = Serial.read();
   //Serial.println(inByte, DEC);

   if (inByte == TXBEG) {
      inx = 0;
      cmd = 0;
      for (int i=0; i < 4; i++)
          serialdata[i] = 0;

   } else if (inx < 3) {
      serialdata[inx++] = inByte;
      if (serialdata[2] == TXFIN) {
         doCommand();
      }
   }

  // update screen
  draw();
}
//============================================================

//---------------------------------------------------------
void doCommand() {
   if (debug)
      Serial.println(serialdata);

   if (serialdata[0] == 'i' and serialdata[1] == 'd') {
      Serial.write("ITcloset;");
      delay(5);
      return;
   }
   if (serialdata[0] == 'v' and serialdata[1] == 'e') {
      Serial.write(VERSION);
      delay(5);
      return;
   }

   if (serialdata[0] >= '1' and serialdata[0] <= '8') {
      int pin = serialdata[0] - 49 + RELAY; // convert to int and zero based index
      int opt = serialdata[1] - '0';        // convert to int
      if (useSSR and pin == RELAY and opt < 2) // for Solid-State Relay
         opt = 1 - opt;                        // invert command for Solid-State Relay

      switch (opt) {
      case 2:
          opt = digitalRead(pin);
      case 0:
      case 1:
          digitalWrite(pin, (1 - opt));
      }

   } else if (serialdata[0] == 'r' and serialdata[1] == 'e') {
      digitalWrite(RELAY, useSSR ? LOW : HIGH);
      for(int i=1; i<8; i++) {
         digitalWrite(i+RELAY, HIGH);
      }
   }

   if (useSSR)
      allRelays[0] = digitalRead(RELAY) + 48;  // for Solid-State Relay
   else
      allRelays[0] = 49 - digitalRead(RELAY); // for opto-coupler relay

   for(int i=1; i<8; i++)
      allRelays[i] = (49 - digitalRead(i+RELAY));

   Serial.print(allRelays);
   delay(5);
}
//---------------------------------------------------------

//---------------------------------------------------------
void setrelay() {
   if (debounce) return;
   ++rlay;
   if (rlay > 8) rlay = 1;
   redraw   = true;
   debounce = millis();
}
//---------------------------------------------------------

//---------------------------------------------------------
void fliprelay() {
   if (debounce) return;
   int pin  = rlay + RELAY - 1;
   int opt  = 1 - digitalRead(pin);
   redraw   = true;
   debounce = millis();
   digitalWrite(pin, opt);
}
//---------------------------------------------------------
