/*
 * Title:   ESP32 RTC_WEB + ILI9341_SPI LCD 
 * Author: @red9030
 * 
 * References:  https://wokwi.com/projects/325324981270479442
*/

/*
 *****************************************************
 *    LIBRERIAS
 *****************************************************
*/
#include <Wire.h>               //Librería para uso de protocolo I2C
#include "SPI.h"                //Librería para uso de protocolo SPI
#include "Adafruit_GFX.h"       //Librería para gr´ficar en pantalla TFT
#include "Adafruit_ILI9341.h"   //Librería para control de pantalla TFT ILI9341
//#include "RTClib.h"             //Librería para conexión DS1307             
//#include <ESP32Time.h>          //Librería para uso del RTC interno ESP32

/*
 *****************************************************
 *    VARIABLES
 *****************************************************
*/
//Variables para TFT
#define TFT_DC 2       //azul TFT RST pin is connected to arduino pin 2
#define TFT_CS 15      //rosa TFT RST pin is connected to arduino pin 15
#define TFT_RST 4      //amarillo TFT RST pin is connected to arduino pin 4
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

//NOTA: Para usar los colores escribir el formato ILI9341_COLOR

//Variables uso RTC
//RTC_DS1307 rtc;

//Dimensiones  pantalla portrait
/*
const int TFT_Width  = 240;
const int TFT_Height = 320;
const int TFT_MINX   =   0;
const int TFT_MAXX   = 130;  // TFT_WIDTH - TFT_HEIGHT/3
const int TFT_MINY   =   0;
const int TFT_MAXY   = TFT_Height;
*/

//Botonres para cambio de parámetros
#define button1    25                       // Button B1 is connected to Arduino pin 25
#define button2    26                       // Button B2 is connected to Arduino pin 26


//Variables para reloj
char Time[]     = "  :  :  ";
char Calendar[] = "  /  /20  ";
char temperature[] = " 00.00";
char temperature_msb;
byte i, second, minute, hour, day, date, month, year, temperature_lsb;

/*
 *****************************************************
 *    SETUP
 *****************************************************
*/
void setup(void) {
  //Serial.begin(115200);
  //Serial.println("Loading...");
  pinMode(button1, INPUT_PULLUP);
  pinMode(button2, INPUT_PULLUP);
  tft.begin();
  tft.fillScreen(ILI9341_BLACK);   // initialize a ILI9341 chip, black tab
  tft.setRotation(0); //cambia la rotacion de la pantalla
  tft.fillScreen(ILI9341_BLACK);
  //Wire.begin();                                             // Join i2c bus
  tft.drawFastHLine(0, 53, tft.width(), ILI9341_BLUE);       // Draw horizontal blue line at position (0, 53)
  tft.drawFastHLine(0, 106, tft.width(), ILI9341_BLUE);      // Draw horizontal blue line at position (0, 106)
  draw_text(52, 64, "TIME", 1, ILI9341_MAGENTA);
  draw_text(30, 117, "TEMPERATURE", 1, ILI9341_RED);
}

/*
 *****************************************************
 *    LOOP
 *****************************************************
*/
void loop() {
  //DateTime now = rtc.now();
  if(!digitalRead(button1)){                         // If button B1 is pressed
      i = 0;
      while(!digitalRead(button1));                    // Wait for button B1 release
      while(true){
        while(!digitalRead(button2)){                  // While button B2 pressed
          day++;                                       // Increment day
          if(day > 7) day = 1;
          display_day();                               // Call display_day function
          delay(200);                                  // Wait 200 ms
        }
        tft.fillRect(40, 10, 54, 8, ILI9341_BLACK);     // Draw rectangle (earase day from the display)
        blink_parameter();                             // Call blink_parameter function
        display_day();                                 // Call display_day function
        blink_parameter();                             // Call blink_parameter function
        if(!digitalRead(button1))                      // If button B1 is pressed
          break;
      }
      date   = edit(4, 27, date);                      // Edit date
      month  = edit(40, 27, month);                    // Edit month
      year   = edit(100, 27, year);                    // Edit year
      hour   = edit(16, 81, hour);                     // Edit hours
      minute = edit(52, 81, minute);                   // Edit minutes
      // Convert decimal to BCD
      minute = ((minute / 10) << 4) + (minute % 10);
      hour = ((hour / 10) << 4) + (hour % 10);
      date = ((date / 10) << 4) + (date % 10);
      month = ((month / 10) << 4) + (month % 10);
      year = ((year / 10) << 4) + (year % 10);
      // End conversion
      // Write data to DS3231 RTC
      Wire.beginTransmission(0x68);               // Start I2C protocol with DS3231 address
      Wire.write(0);                              // Send register address
      Wire.write(0);                              // Reset sesonds and start oscillator
      Wire.write(minute);                         // Write minute
      Wire.write(hour);                           // Write hour
      Wire.write(day);                            // Write day
      Wire.write(date);                           // Write date
      Wire.write(month);                          // Write month
      Wire.write(year);                           // Write year
      Wire.endTransmission();                     // Stop transmission and release the I2C bus
      delay(200);                                 // Wait 200ms
    }
    Wire.beginTransmission(0x68);                 // Start I2C protocol with DS3231 address
    Wire.write(0);                                // Send register address
    Wire.endTransmission(false);                  // I2C restart
    Wire.requestFrom(0x68, 7);                    // Request 7 bytes from DS3231 and release I2C bus at end of reading
    second = Wire.read();                         // Read seconds from register 0
    minute = Wire.read();                         // Read minuts from register 1
    hour   = Wire.read();                         // Read hour from register 2
    day    = Wire.read();                         // Read day from register 3
    date   = Wire.read();                         // Read date from register 4
    month  = Wire.read();                         // Read month from register 5
    year   = Wire.read();                         // Read year from register 6
    Wire.beginTransmission(0x68);                 // Start I2C protocol with DS3231 address
    Wire.write(0x11);                             // Send register address
    Wire.endTransmission(false);                  // I2C restart
    Wire.requestFrom(0x68, 2);                    // Request 2 bytes from DS3231 and release I2C bus at end of reading
    temperature_msb = Wire.read();                // Read temperature MSB
    temperature_lsb = Wire.read();                // Read temperature LSB
    display_day();
    DS3231_display();                             // Diaplay time & calendar
    delay(50);                                    // Wait 50ms 
}

/*
 *****************************************************
 *    FUNCIONES
 *****************************************************
*/

//====================================================
//  Función para hacer TEST
//====================================================
void hola_mundo(){
    tft.setCursor(20, 120);
    tft.setTextColor(ILI9341_RED);
    tft.setTextSize(3);
    tft.println("Hello ESP32");

    tft.setCursor(24, 160);
    tft.setTextColor(ILI9341_GREEN);
    tft.setTextSize(2);
    tft.println("I can do SPI :-)");
}

//====================================================
//  Función para mostrar pantalla de carga
//====================================================
void display_day(){
  switch(day){
    case 1:  draw_text(40, 10, " SUNDAY  ", 1, ILI9341_CYAN); break;
    case 2:  draw_text(40, 10, " MONDAY  ", 1, ILI9341_CYAN); break;
    case 3:  draw_text(40, 10, " TUESDAY ", 1, ILI9341_CYAN); break;
    case 4:  draw_text(40, 10, "WEDNESDAY", 1, ILI9341_CYAN); break;
    case 5:  draw_text(40, 10, "THURSDAY ", 1, ILI9341_CYAN); break;
    case 6:  draw_text(40, 10, " FRIDAY  ", 1, ILI9341_CYAN); break;
    default: draw_text(40, 10, "SATURDAY ", 1, ILI9341_CYAN);
  }
}
void DS3231_display(){
  // Convert BCD to decimal
  second = (second >> 4) * 10 + (second & 0x0F);
  minute = (minute >> 4) * 10 + (minute & 0x0F);
  hour   = (hour >> 4)   * 10 + (hour & 0x0F);
  date   = (date >> 4)   * 10 + (date & 0x0F);
  month  = (month >> 4)  * 10 + (month & 0x0F);
  year   = (year >> 4)   * 10 + (year & 0x0F);
  // End conversion
  Time[7]     = second % 10 + 48;
  Time[6]     = second / 10 + 48;
  Time[4]     = minute % 10 + 48;
  Time[3]     = minute / 10 + 48;
  Time[1]     = hour   % 10 + 48;
  Time[0]     = hour   / 10 + 48;
  Calendar[9] = year   % 10 + 48;
  Calendar[8] = year   / 10 + 48;
  Calendar[4] = month  % 10 + 48;
  Calendar[3] = month  / 10 + 48;
  Calendar[1] = date   % 10 + 48;
  Calendar[0] = date   / 10 + 48;
  if(temperature_msb < 0){
    temperature_msb = abs(temperature_msb);
    temperature[0] = '-';
  }
  else
    temperature[0] = ' ';
  temperature_lsb >>= 6;
  temperature[2] = temperature_msb % 10  + 48;
  temperature[1] = temperature_msb / 10  + 48;
  if(temperature_lsb == 0 || temperature_lsb == 2){
    temperature[5] = '0';
    if(temperature_lsb == 0) temperature[4] = '0';
    else                     temperature[4] = '5';
  }
  if(temperature_lsb == 1 || temperature_lsb == 3){
    temperature[5] = '5';
    if(temperature_lsb == 1) temperature[4] = '2';
    else                     temperature[4] = '7';
  }
  draw_text(4,  27, Calendar, 3, ILI9341_YELLOW);
  draw_text(16, 81, Time, 3, ILI9341_GREEN);
  draw_text(14, 134, temperature, 2, ILI9341_WHITE);
  tft.drawCircle(90, 134, 3, ILI9341_WHITE);                // Degree symbol (°)
  draw_text(96, 134, "C", 3, ILI9341_WHITE);
}

void blink_parameter(){
  byte j = 0;
  while(j < 10 && digitalRead(button1) && digitalRead(button2)){
    j++;
    delay(25);
  }
}
byte edit(byte x_pos, byte y_pos, byte parameter){
  char text[3];
  uint16_t color = ILI9341_YELLOW;
  sprintf(text,"%02u", parameter);
  if(i == 3 || i == 4)
    color = ILI9341_GREEN;
  while(!digitalRead(button1));                      // Wait until button B1 released
  while(true){
    while(!digitalRead(button2)){                    // If button (pin #9) is pressed
      parameter++;
      if(i == 0 && parameter > 31)                   // If date > 31 ==> date = 1
        parameter = 1;
      if(i == 1 && parameter > 12)                   // If month > 12 ==> month = 1
        parameter = 1;
      if(i == 2 && parameter > 99)                   // If year > 99 ==> year = 0
        parameter = 0;
      if(i == 3 && parameter > 23)                   // If hours > 23 ==> hours = 0
        parameter = 0;
      if(i == 4 && parameter > 59)                   // If minutes > 59 ==> minutes = 0
        parameter = 0;
      sprintf(text,"%02u", parameter);
      draw_text(x_pos, y_pos, text, 2, color);
      delay(200);                                    // Wait 200ms
    }
    tft.fillRect(x_pos, y_pos, 22, 16, ILI9341_BLACK);
    blink_parameter();
    draw_text(x_pos, y_pos, text, 2, color);
    blink_parameter();
    if(!digitalRead(button1)){                       // If button (pin #8) is pressed
      i++;                                           // Increament 'i' for the next parameter
      return parameter;                              // Return parameter value and exit
    }
  }
}

void draw_text(byte x_pos, byte y_pos, char *text, byte text_size, uint16_t text_color) {
  tft.setCursor(x_pos, y_pos);
  tft.setTextSize(text_size);
  tft.setTextColor(text_color, ILI9341_BLACK);
  tft.print(text);
}
GND5VSDASCLSQWRTCDS1307+