/////////////////////////////////////////
// HXbot HXlcd firmware                 /
// EoF 2016 EoF@itphx.ru                /
/////////////////////////////////////////

#include <Wire.h>
#include <TroykaDHT11.h>
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>
#include "HXlcd2.h"


// DEBUG
#define DEBUG 1

// DEFINE
#define SLAVE_ADDRESS 0x06
#define XOR_SEQ 0xFF
#define EXT_COM 0xAA

#define R_LED 10
#define G_LED 9
#define B_LED 11
#define L_BTN A3
#define C_BTN A2
#define R_BTN A1

//clk 4, din 5, dc 6, cs 7, rst 8
#define TFT_BL   3
#define TFT_SCLK 4
#define TFT_MOSI 5
#define TFT_DC   6
#define TFT_CS   7
#define TFT_RST  8

// Sensors
#define LIGHT A6
#define LOUD A7
#define TEMP A0
#define BUZZ 13
#define FREE 12

#define LED_PIN 13

#define DELAY1 2000
#define DELAY2 500

// COMMANDS
// Util
#define COM_PING 0x01
#define COM_GET_TEMP 0x02

// Response
#define OK_RSP  0x00
#define NO_RSP  0xFF
#define ERR_RSP 0x01
#define BLK_RSP 0x02
#define CSE_RSP 0x03
#define IOE_RSP 0x04
#define TMO_RSP 0x05

// VAR

DHT11 dht(TEMP);
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);

// эту константу (typVbg) необходимо откалибровать индивидуально
const float typVbg = 1.08; // 1.0 -- 1.2

byte autoresponse = 0;
byte cmd = 0;
byte flg = 0;
byte ext = 0;

int temp, hum;

float p = 3.1415926;
float vcc;
bool l_pressed = false, c_pressed = false, r_pressed = false;
bool menu_drawed = false;
byte screen = 0, line = 1;

unsigned long t;

void setup() {
  
  if (DEBUG) {
    Serial.begin(9600);
    Serial.println("GO!");
  }
  
  // Initialize i2c as slave
  Wire.begin(SLAVE_ADDRESS);
 
  // Define callbacks for i2c communication
  Wire.onReceive(receiveData);
  Wire.onRequest(answer);
  
  // put your setup code here, to run once:
  pinMode(LED_PIN, OUTPUT);
 
  pinMode(R_LED, OUTPUT);
  pinMode(G_LED, OUTPUT);
  pinMode(B_LED, OUTPUT);

  pinMode(TFT_BL, OUTPUT);

  pinMode(L_BTN, INPUT_PULLUP);
  pinMode(C_BTN, INPUT_PULLUP);
  pinMode(R_BTN, INPUT_PULLUP);

  pinMode(LIGHT, INPUT);
  pinMode(LOUD, INPUT);
  pinMode(FREE, INPUT);
  pinMode(BUZZ, OUTPUT);

  randomSeed(millis());
  analogReference(DEFAULT);

  // Use this initializer if you're using a 1.8" TFT
  tft.initR(INITR_BLACKTAB);   // initialize a ST7735S chip, black tab
  tft.fillScreen(ST7735_BLACK);
  
  tft.drawRect(0, 0, 128, 160, ST7735_GREEN);
  tft.drawRect(1, 1, 126, 158, ST7735_WHITE);
  drawL();
  drawC();
  drawR();
  analogWrite(TFT_BL, 255);
     
  dht.begin();
}

void loop() {
  if (digitalRead(FREE) == HIGH) {
    analogWrite(G_LED, 128);
  }
  else {
    analogWrite(G_LED, 0);
  }

//  if (DEBUG) {
//    Serial.println(r_pressed);
//    Serial.println(c_pressed);
//    Serial.println(l_pressed);
//  }

  readButtons();
  drawMenu();  
  //displayALL();
}

void drawMenu() {

  if (millis() - t < BTN_TIMEOUT) return;
  
  if (screen == 0) {
    if (l_pressed) {
      line++;    
      if (line > SCR1_MAX) line = 1;
      drawPointer();
      t = millis();
    }
    if (r_pressed) {
      line--;
      if (line < 1) line = SCR1_MAX;
      drawPointer();
      t = millis();
    }

    if (! menu_drawed) {
      tft.setTextSize(1);      
      tft.setCursor(52, 8);
      tft.print("MAIN");
    
      tft.setTextSize(1);
      tft.setCursor(20, 20);
      tft.print("HXbot");
      tft.setCursor(20, 30);
      tft.print("REflex");
      tft.setCursor(20, 40);
      tft.print("HXpower");
      tft.setCursor(20, 50);
      tft.print("HXlcd");
      tft.setCursor(20, 60);
      tft.print("HXcamera");

      drawPointer();

      menu_drawed = true;
    }

    if (c_pressed) {
      screen = line;
      line = 0;
      clearMenu();
      t = millis();
      return;
    }
  }

  if (screen == 1) {
    if (! menu_drawed) {
      tft.setTextSize(1);
      tft.setCursor(49, 8);
      tft.print("HXbot");
  
      tft.setTextSize(1);
      tft.setCursor(52, 130);
      tft.print("back");

      drawPointer();

      menu_drawed = true;
    }

    if (c_pressed) {
      screen = 0;
      line = 1;
      clearMenu();
      t = millis();
      return;
    }
  }

  if (screen == 2) {
    if (! menu_drawed) {
      tft.setTextSize(1);
      tft.setCursor(49, 8);
      tft.print("REflex");
  
      tft.setTextSize(1);
      tft.setCursor(52, 130);
      tft.print("back");

      drawPointer();

      menu_drawed = true;
    }

    if (c_pressed) {
      screen = 0;
      line = 1;
      clearMenu();
      t = millis();
      return;
    }
  }

  if (screen == 3) {
    if (! menu_drawed) {
      tft.setTextSize(1);
      tft.setCursor(49, 8);
      tft.print("HXpower");
  
      tft.setTextSize(1);
      tft.setCursor(52, 130);
      tft.print("back");

      drawPointer();

      menu_drawed = true;
    }

    if (c_pressed) {
      screen = 0;
      line = 1;
      clearMenu();
      t = millis();
      return;
    }
  }

  if (screen == 4) {
    if (! menu_drawed) {
      tft.setTextSize(1);
      tft.setCursor(49, 8);
      tft.print("HXlcd");
  
      tft.setTextSize(1);
      tft.setCursor(52, 130);
      tft.print("back");

      drawPointer();

      menu_drawed = true;
    }

    if (c_pressed) {
      screen = 0;
      line = 1;
      clearMenu();
      t = millis();
      return;
    }
  }

  if (screen == 5) {
    if (! menu_drawed) {
      tft.setTextSize(1);
      tft.setCursor(49, 8);
      tft.print("HXcamera");
  
      tft.setTextSize(1);
      tft.setCursor(52, 130);
      tft.print("back");

      drawPointer();

      menu_drawed = true;
    }

    if (c_pressed) {
      screen = 0;
      line = 1;
      clearMenu();
      t = millis();
      return;
    }
  }
  
}

void clearMenu() {
  tft.fillRect(2, 2, 123, 140, BLACK);
  menu_drawed = false;
}

void drawPointer() {
  byte x1, y1, x2, y2, x3, y3;

  if (line != 0) {
    x1 = 10;
    y1 = 11 + line * 10;
    x2 = 10;
    y2 = 15 + line * 10;
    x3 = 15;
    y3 = 13 + line * 10;
  }
  else {  
    x1 = 42;
    y1 = 131;
    x2 = 42;
    y2 = 135;
    x3 = 47;
    y3 = 133;
  }

  tft.fillRect(10, 20, 6, 100, BLACK);  
  tft.fillTriangle(x1, y1, x2, y2, x3, y3, WHITE);
}

void displayALL() {
  // Vcc
  vcc = readvcc();

  tft.setCursor(10, 10);
  tft.setTextColor(ST7735_WHITE, ST7735_BLACK);
  tft.print("Vcc=");
  if (vcc < 4.8 || vcc > 5.2)
    tft.setTextColor(ST7735_RED, ST7735_BLACK);
  else
    tft.setTextColor(ST7735_GREEN, ST7735_BLACK);

  tft.print(vcc);
  tft.setTextColor(ST7735_WHITE, ST7735_BLACK);
  tft.print(" V  ");

  // Light
  tft.setCursor(10, 20);
  tft.setTextColor(ST7735_WHITE, ST7735_BLACK);
  tft.print("Lightness=");
  tft.setTextColor(ST7735_YELLOW, ST7735_BLACK);
  tft.print(analogRead(LIGHT));
  tft.setTextColor(ST7735_WHITE, ST7735_BLACK);
  tft.print(" UE  ");

  // Loud
  tft.setCursor(10, 30);
  tft.setTextColor(ST7735_WHITE, ST7735_BLACK);
  tft.print("Loud=");
  tft.setTextColor(ST7735_MAGENTA, ST7735_BLACK);
  tft.print(analogRead(LOUD));
  tft.setTextColor(ST7735_WHITE, ST7735_BLACK);
  tft.print(" UE  ");

  // TH
  int result;
  result = dht.read();
    
  tft.setCursor(10, 40);
  tft.setTextColor(ST7735_WHITE, ST7735_BLACK);
  tft.print("Temp=");
  tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
  if (result == DHT_OK) tft.print(dht.getTemperatureC()); else tft.print("ERR");
  tft.setTextColor(ST7735_WHITE, ST7735_BLACK);
  tft.print(" C  ");
      
  tft.setCursor(10, 50);
  tft.setTextColor(ST7735_WHITE, ST7735_BLACK);
  tft.print("Hum=");
  tft.setTextColor(ST7735_BLUE, ST7735_BLACK);
  if (result == DHT_OK) tft.print(dht.getHumidity()); else tft.print("ERR");
  tft.setTextColor(ST7735_WHITE, ST7735_BLACK);
  tft.print(" %  ");
}

void readButtons() {
  if ((digitalRead(L_BTN) == LOW) && ! l_pressed) {
    l_pressed = true;
    drawL();
  }  
  else {
    if ((digitalRead(L_BTN) == HIGH) && l_pressed) {
      l_pressed = false;
      drawL();
    }
  }
  
  if ((digitalRead(C_BTN) == LOW) && ! c_pressed) {
    c_pressed = true;
    drawC();
  }
  else {
    if ((digitalRead(C_BTN) == HIGH) && c_pressed) {
      c_pressed = false;
      drawC();
    }
  }
  
  if ((digitalRead(R_BTN) == LOW) && ! r_pressed) {
    r_pressed = true;
    drawR();
  }  
  else {
    if ((digitalRead(R_BTN) == HIGH) && r_pressed) {
      r_pressed = false;
      drawR();
    }
  }
}

void drawL() {
  tft.fillRoundRect(4, 145, 37, 12, 3, YELLOW);
  if (! l_pressed) {
    tft.drawRoundRect(4, 145, 37, 12, 3, LYELLOW);
    tft.drawLine(6, 156, 38, 156, DYELLOW);
    tft.drawLine(40, 147, 40, 154, DYELLOW);
    tft.drawPixel(5, 155, DYELLOW);
    tft.drawPixel(39, 155, DYELLOW);
    tft.fillTriangle(15, 147, 29, 147, 22, 154, GRAY);
    tft.drawTriangle(15, 147, 29, 147, 22, 154, DGRAY);
  }
  else {  
    tft.drawRoundRect(4, 145, 37, 12, 3, DYELLOW);
    tft.drawLine(6, 156, 38, 156, LYELLOW);
    tft.drawLine(40, 147, 40, 154, LYELLOW);
    tft.drawPixel(5, 155, LYELLOW);
    tft.drawPixel(39, 155, LYELLOW);
    tft.fillTriangle(15, 147, 29, 147, 22, 154, WHITE);
    tft.drawTriangle(15, 147, 29, 147, 22, 154, DGRAY);
  }
}

void drawC() {
  tft.fillRoundRect(44, 144, 40, 12, 3, BLUE);
  if (! c_pressed) {
    tft.drawRoundRect(44, 144, 40, 12, 3, LBLUE);
    tft.drawLine(46, 155, 81, 155, DBLUE);
    tft.drawLine(83, 146, 83, 153, DBLUE);
    tft.drawPixel(45, 154, DBLUE);
    tft.drawPixel(82, 154, DBLUE);
    tft.fillRoundRect(60, 146, 8, 8, 3, GRAY);
    tft.drawRoundRect(60, 146, 8, 8, 3, DGRAY);
  }
  else {
    tft.drawRoundRect(44, 144, 40, 12, 3, DBLUE);
    tft.drawLine(46, 155, 81, 155, LBLUE);
    tft.drawLine(83, 146, 83, 153, LBLUE);
    tft.drawPixel(45, 154, LBLUE);
    tft.drawPixel(82, 154, LBLUE);
    tft.fillRoundRect(60, 146, 8, 8, 3, WHITE);
    tft.drawRoundRect(60, 146, 8, 8, 3, DGRAY);
  }
}

void drawR() {
  tft.fillRoundRect(86, 145, 37, 12, 3, YELLOW);
  if (! r_pressed) {
    tft.drawRoundRect(86, 145, 37, 12, 3, LYELLOW);
    tft.drawLine(88, 156, 120, 156, DYELLOW);
    tft.drawLine(122, 147, 122, 154, DYELLOW);
    tft.drawPixel(87, 155, DYELLOW);
    tft.drawPixel(121, 155, DYELLOW);
    tft.fillTriangle(97, 154, 111, 154, 104, 147, GRAY);
    tft.drawTriangle(97, 154, 111, 154, 104, 147, DGRAY);
  }
  else {  
    tft.drawRoundRect(86, 145, 37, 12, 3, DYELLOW);
    tft.drawLine(88, 156, 120, 156, LYELLOW);
    tft.drawLine(122, 147, 122, 154, LYELLOW);
    tft.drawPixel(87, 155, LYELLOW);
    tft.drawPixel(121, 155, LYELLOW);
    tft.fillTriangle(97, 154, 111, 154, 104, 147, WHITE);
    tft.drawTriangle(97, 154, 111, 154, 104, 147, DGRAY);
  }
}

void rgb_control() {
  //int tmp1;
  //tmp1 = Read(L_BTN);
  if (digitalRead(L_BTN) == LOW) { 
    analogWrite(R_LED, 255);
    //Serial.println(analogRead(L_BTN));
  }
  else {
    analogWrite(R_LED,0);
  }

  if (digitalRead(C_BTN) == LOW) {
    analogWrite(G_LED, 255);
  }
  else {
    analogWrite(G_LED,0);
  }
  
  if (digitalRead(R_BTN) == LOW) {
    analogWrite(B_LED, 255);
  }
  else {
    analogWrite(B_LED,0);
  }
}

// Callback for received data
void receiveData(int byteCount) {
  
  while(Wire.available()) {
    // Get command
    cmd = Wire.read();
    if (cmd == EXT_COM && byteCount == 3) {
      flg = 0x00;
      ext = 0x00;
      
      if (Wire.available()) ext = Wire.read();
      if (Wire.available()) flg = Wire.read();
    }
    else {
      // Cleanup I2C bus
      while(Wire.available()) {
        ext = Wire.read();
      }
    }
      
    switch (cmd) {
      case COM_PING:
        autoresponse = OK_RSP;
        blink_red();
        break;
      case COM_GET_TEMP:
        autoresponse = getInternalTemp();
        break;
      default:
        autoresponse = ERR_RSP;
        break;
    }
  }
}

// Callback for sending data
void answer() {
  Wire.write(autoresponse);
}

void blink_red() {
  digitalWrite(R_LED, HIGH);
  delay(100);
  digitalWrite(R_LED, LOW);
}

// Get the internal temperature of the arduino
double getInternalTemp(void) {
  unsigned int wADC;
  double t;
  ADMUX = (_BV(REFS1) | _BV(REFS0) | _BV(MUX3));
  ADCSRA |= _BV(ADEN); // enable the ADC
  delay(20); // wait for voltages to become stable.
  ADCSRA |= _BV(ADSC); // Start the ADC
  while (bit_is_set(ADCSRA,ADSC));
  wADC = ADCW;
  t = (wADC - 324.31 ) / 1.22;
  return (t);
}

float readvcc() {
  float tmp = 0.0;

  // Read 1.1V reference against Avcc
  // set the reference to vcc and the measurement to the internal 1.1V reference
  #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
      ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
      ADMUX = _BV(MUX5) | _BV(MUX0);
  #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
      ADMUX = _BV(MUX3) | _BV(MUX2);
  #else
      // works on an Arduino 168 or 328
      ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #endif

  delay(3); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring

  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
  uint8_t high = ADCH; // unlocks both

  tmp = (high<<8) | low;
  tmp = (typVbg * 1023.0) / tmp;

  return tmp;
}

void tftPrintTest() {
  tft.setTextWrap(false);
  tft.fillScreen(ST7735_GREEN);
  tft.setCursor(0, 30);
  tft.setTextColor(ST7735_RED);
  tft.setTextSize(1);
  tft.println("Hello World!");
  tft.setTextColor(ST7735_YELLOW);
  tft.setTextSize(2);
  tft.println("Hello World!");
  tft.setTextColor(ST7735_GREEN);
  tft.setTextSize(3);
  tft.println("Hello World!");
  tft.setTextColor(ST7735_BLUE);
  tft.setTextSize(4);
  tft.print(1234.567);
  delay(1500);
  tft.setCursor(0, 0);
  tft.fillScreen(ST7735_BLACK);
  tft.setTextColor(ST7735_WHITE);
  tft.setTextSize(0);
  tft.println("Hello World!");
  tft.setTextSize(1);
  tft.setTextColor(ST7735_GREEN);
  tft.print(p, 6);
  tft.println(" Want pi?");
  tft.println(" ");
  tft.print(8675309, HEX); // print 8,675,309 out in HEX!
  tft.println(" Print HEX!");
  tft.println(" ");
  tft.setTextColor(ST7735_WHITE);
  tft.println("Sketch has been");
  tft.println("running for: ");
  tft.setTextColor(ST7735_MAGENTA);
  tft.print(millis() / 1000);
  tft.setTextColor(ST7735_WHITE);
  tft.print(" seconds.");
}

void tftTest() {
  //
  tft.fillScreen(ST7735_BLACK);
  tft.drawRect(0, 0, 128, 160, ST7735_GREEN);
  tft.drawRect(1, 1, 126, 158, ST7735_WHITE);

  // Smile
  tft.fillCircle(64, 80, 40, ST7735_YELLOW);
  //tft.drawCircle(64, 80, 40, ST7735_BLUE);

  tft.fillRoundRect(45, 63, 10, 15, 3, ST7735_BLACK);
  tft.fillRoundRect(73, 63, 10, 15, 3, ST7735_BLACK);

  tft.fillTriangle(50, 95, 78, 95, 70, 105, ST7735_BLACK);

  tft.setCursor(33, 132);
  tft.setTextColor(ST7735_YELLOW);
  tft.setTextSize(2);
  tft.print("HELLO!");

//  for (byte i = 1; i <= 31; i++) {
//    tft.drawRect(i * 2, i * 3, 128 - i * 4, 160 - i * 5, ST7735_WHITE);
//    delay(100);
//    //tft.drawRect(i * 2, i * 2, 128 - i * 4, 160 - i * 4, ST7735_BLACK);
//  }
}

