//GSI4.5 09/15/2025 - Initial release
// Laurent "Buzzz" Buzzi - Copyright 2025
//#define DEBUG_INFO
//#define PROTO
#define FAN_ACTIVE
#include <EEPROM.h>
#include <RREFont.h>
#include "rre_gear.h"
#include "rre_bmwfont.h"
#include "rre_bmw.h"
#include "rre_icons.h"
#include <Adafruit_ILI9341.h>
#include <Adafruit_GFX.h>
#define TFT_DC 9
#define TFT_CS 10
#define TFT_RST   7
#define TFT_LED   8
#define FAN_PIN   2
  
const float light_mult = 1 ;
const uint8_t Gear_pin = A0;
const uint8_t Sensor_pin[] = {A1, A2, A7};
//  const uint8_t Vo_sensor = A7;
const float Voltcoeff = 0.01760;
const uint8_t TempHigh = 67;
const uint16_t TempLow = 860;
const uint8_t SCR_Siz = 130;
const uint8_t SCR_Max = SCR_Siz-1;
const uint8_t GEAR_X = 40;
const uint8_t GEAR_Y = 10;
const uint8_t TEMP_X[] = {126, 60};
const uint8_t TEMP_Y = 69;
const uint8_t VOLT_X = 108;
const uint8_t VOLT_Y = 97;
uint8_t celsius = 1;
uint8_t txt_color = 0;
const uint8_t roundeldiam[] = {53, 52, 27, 26};
const uint8_t tft_center = 65;
uint8_t light_lvl = 255;
const uint8_t fade_steps = 51;
const uint8_t fade_delay = 10;
bool blinker[] = {LOW, LOW, LOW};
bool blink_ON = HIGH;
bool Temp_ON[] = {LOW, LOW};
bool Temp_OFF[] = {LOW, LOW};
bool set_loop = LOW;
int16_t prevTemp[] = {200, 200};
uint16_t prevVolt = 0;
uint16_t SensorV[] = {1, 1, 1};
const float K = 273.15;
const uint16_t TempB = 3600;
const uint8_t TempVcoeff = 205;// 1024/5; 8184/5 for 13bits
const uint8_t TempVref = 5;
const uint16_t TempR2 = 1070;
const uint16_t TempRref = 2780;
const uint8_t TempCref = 19;
const uint8_t init_rot = 1;
const uint8_t FAN_temp_min = 115;
const uint8_t FAN_temp_max = 120;
const uint8_t FAN_Volt_min = 13.0;
const uint8_t FAN_Gear_max = 2;
const char degres [] = "<;";
uint8_t sens = 0;
float volt = 0.0;
uint8_t prevGear = 8;
uint8_t Gear = 8;
bool Gear_start = LOW;
uint16_t Gear_val = 0;
char vitesse [1];
long last_gear_change = 0;
long last_setting_loop = 0;
long last_blink = 0;
long timer_gear = 0;
long timer_sensors = 0;
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF
#define GREY   0x9999
#define DARKGREY 0x3186
const unsigned int blu_colors[] = {0x2bb3, 0x33d4, 0x33f4, 0x3c35, 0x4456, 0x4c77, 0x4c97, 0x54b8, 0x5cd8, 0x5cf9, 0x6519, 0x6539, 0x6d3a,};
const unsigned int txt_colors[3][9] = {{0xFFED,0xFFFF,0x9FED,0x77FA,0x6EDF,0xDE1F,0xFD34,0xFEED,0x0000},{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xFFFF},{0,0,0,0,0,0,0,0,1}};
RREFont font;
// needed for RREFont library initialization, define your fillRect
void customRect(int x, int y, int w, int h, int c) {return tft.fillRect(x, y, w, h, c); }
void setup()
{
  #ifdef FAN_ACTIVE
    pinMode(FAN_PIN, OUTPUT);
    digitalWrite (FAN_PIN, HIGH);
    delay(200);
    digitalWrite (FAN_PIN, LOW);
  #endif    
  pinMode(TFT_LED, OUTPUT);
  analogWrite(TFT_LED, 0);
  Read_sensor();
  Read_sensor();
  Read_sensor();
  Read_gear();
  if (Gear > 4) {Gear_start = HIGH;}
  #ifdef DEBUG_INFO
    Serial.begin(115200);
    Serial.println("DEBUG MODE ON");
  #endif
  pinMode(Gear_pin, INPUT);
  for (uint8_t i = 0; i < 3; i++) {pinMode(Sensor_pin[i], INPUT);}
  EEPROM.get(0, celsius);
  if (celsius != 0 && celsius != 1) {
    celsius = 1;
    EEPROM.put(0, celsius);
  }
  EEPROM.get( sizeof(int), txt_color );
  if (txt_color < 0 || txt_color > 8) {
    txt_color = 0;
    EEPROM.put( sizeof(int), txt_color );
  }
  font.init(customRect, SCR_Siz, SCR_Siz);
  tft.begin();
  tft.fillScreen(BLACK);
 //  splashscreen();
  if (Gear !=0 && Gear_start) Setting_loop();
  printlines();
  printicons();
//  printTemp();
}
void loop()
{
  if (millis() - last_blink > 300)
  {
//  tft.drawCircle(tft_center+1, tft_center, SCR_Siz/2+2, WHITE);
    blink_ON = !blink_ON;
    for (uint8_t i=0; i<2; i++){
      if (blinker[i] && blink_ON) Temp_ON[i]=HIGH;
      if (blinker[i] && !blink_ON) Temp_OFF[i]=HIGH;
    }
    last_blink = millis();
  }
  if (millis() - timer_gear > 200)
  {
    Read_gear();
    if (prevGear != Gear)
    {
      if (Gear != 7 ||(Gear == 7 && millis()-last_gear_change >1000)){
        printGear();
//        Serial.println(Gear);
        prevGear = Gear;
        last_gear_change = millis();
      }
    }
    timer_gear = millis();
  }
  if (millis() - timer_sensors > 300)
  {
    Read_sensor();
    #ifdef DEBUG_INFO
//    Serial.println(SensorV[sens]);
    #endif
    timer_sensors = millis();
  }				 
  printTemp();
  printvolt();
}
void splashscreen() {
  analogWrite(TFT_LED, 0);
//  Roundel
  font.setColor(WHITE);
  //  BMW characters
  tft.setRotation(init_rot + 2);
  font.setFont(&rre_bmw);
  font.setScale(1);
  font.setSpacing(0);
  font.printStr(26, 29,(char*)"0");
  font.printStr(57, 15,(char*)"1");
  font.printStr(86, 27,(char*)"2");
  for (uint8_t i = 0; i < 12; i++) {
    tft.fillCircle(tft_center+1, tft_center, roundeldiam[2] - i * 4, blu_colors[i]);
  }
  font.setFont(&rre_helice);
  font.printStr(tft_center-23, tft_center+1, "0");
  tft.setRotation(init_rot + 1);
  font.printStr(tft_center-25, tft_center+1, "0");
  //  White circles
  for (uint8_t i = 0; i < 4; i++) {
    tft.drawCircle(tft_center+1, tft_center, roundeldiam[i], WHITE);
    tft.drawCircle(tft_center, tft_center, roundeldiam[i], WHITE);
  }
  fade (0,5);
  delay(1000);
  fade(255,-5);
  tft.fillScreen(BLACK);
  delay(500);
  // tft.drawCircle(tft_center, tft_center, 64, WHITE);
 // R1100S logo
  tft.setRotation(init_rot + 2);
  font.setFont(&rre_R1100S);
  font.setScale(1);
  font.setSpacing(0);
  font.printStr(10, 55, "01234");
  fade (0,5);
  delay(1000);
  fade(255,-5);
  tft.fillScreen(BLACK);
  delay(500);
  
  tft.setRotation(init_rot + 2);
  printlines();
  printicons();
  printTemp();
  printvolt();
  Read_gear();
  printGear();
  delay(500);
  fade (0,5);
}
void Read_gear()
{
  Gear_val = analogRead (Gear_pin) / 10;
    switch(Gear_val){
    
    case 5 ... 9:
      Gear = 1;
    break;
    case 13 ... 19:
      Gear = 0;
    break;
    case 22 ... 26:
      Gear = 2;
    break;
    case 39 ... 43:
      Gear = 3;
    break;
    case 56 ... 60:
      Gear = 4;
    break;
    case 73 ... 77:
      Gear = 5;
    break;
    case 90 ... 94:
      Gear = 6;
    break;
    default:
      Gear = 7;
    break;
    }
}
void Read_sensor()
{
  delay(50);
  SensorV[sens] = analogRead(Sensor_pin[sens]);
  delay(50);
  SensorV[sens] = analogRead(Sensor_pin[sens]);
  if (SensorV[sens] <= TempHigh || SensorV[sens] >= TempLow) blinker[sens] = HIGH;
  else {
    if (blinker[sens]) Temp_ON[sens] = HIGH;
    blinker[sens] = LOW;
  }
  sens ++;
  if (sens == 3) {sens = 0;}
}
void printGear()
{
  font.setFont(&rre_gear);
  font.setBold(1);
  font.setScale(1);
  font.setCharMinWd(48);
  font.setSpacing(1);
  if (Gear == 0) {
    font.setColor(BLACK,GREEN);
    tft.fillRect(33, 0, 63, 64, GREEN);
//    tft.fillCircle(tft_center+1, tft_center, 33, GREEN);
  }
  else {
    font.setColor(txt_colors[0][txt_color], txt_colors[1][txt_color]);
    tft.fillRect(33, 0, 63, 64, txt_colors[1][txt_color]);
  }
  dtostrf(Gear, 0, 0, vitesse);
  font.printStr(GEAR_X, GEAR_Y, vitesse);
}
void printvolt()
{
  if (abs(SensorV[2] - prevVolt) >= 10)
  {
    volt = SensorV[2] * Voltcoeff; // + 16 - light_read / 20;
    char volte [10];
    font.setFont(&rre_bmwfont);
    font.setBold(0);
    font.setScale(1);
    font.setCharMinWd(5);
    font.setSpacing(2);
    font.setColor(txt_colors[0][txt_color], txt_colors[1][txt_color]);
    dtostrf(volt, 3, 1, volte);
    strcat (volte, ":");
	tft.fillRect(VOLT_X-55, VOLT_Y, 71, 23, txt_colors[1][txt_color]);
    font.printStr(VOLT_X - font.strWidth(volte), VOLT_Y, volte);
    prevVolt = SensorV[2];
  }
}
void printTemp()
{
  float TempR;
  int16_t TempF;
  int16_t TempC;
  for (uint8_t i=0; i<2; i++){
    if (SensorV[i] >= 25){
    //  TempC = (TempCref+K)/(1-(TempCref+K)/TempB*log(TempRref/TempR2*((float) TempVref/SensorV[i]*TempVcoeff-1)))-K;
      
      TempR= TempR2/((float) TempVref/SensorV[i]*TempVcoeff-1);
      TempC=(TempCref+K)/(1-(TempCref+K)/TempB*log(TempRref/TempR))-K;
  //    Serial.println(TempR);
    }
    else TempC = 200;
  //  Serial.print(i);  Serial.print(",");  Serial.println(TempC);
    
    if (abs(TempC - prevTemp[i])>= 2 && !blinker[i]){
      Temp_ON[i] = HIGH;
      prevTemp[i] = TempC;
    }
    if (Temp_OFF[i] || Temp_ON[i]){
      TempF = TempC;
      char tempe[10];
      font.setFont(&rre_bmwfont);
      font.setBold(0);
      font.setScale(1);
      font.setCharMinWd(5);
      font.setSpacing(2);
      if (celsius > 1) celsius = 1;
      if (celsius == 0) TempF = TempF * 1.8 + 32;
      dtostrf(TempF, 3, 0, tempe);
      strcat (tempe, "/");
      strncat (tempe, °res[celsius], 1);
      if (Temp_OFF[i]) font.setColor(txt_colors[1][txt_color], txt_colors[1][txt_color]);
      else font.setColor(txt_colors[0][txt_color], txt_colors[1][txt_color]);
      tft.fillRect(TEMP_X[i]-60, TEMP_Y, 60, 20,txt_colors[1][txt_color]);
      font.printStr(TEMP_X[i] - font.strWidth(tempe), TEMP_Y, tempe);
      Temp_OFF[i] = LOW;
      Temp_ON[i] = LOW;
    }
  
    if (i ==0) {
      #ifdef FAN_ACTIVE
        if ((TempC >= FAN_temp_max) && (Gear <= FAN_Gear_max) && (volt >= FAN_Volt_min))
        {
    //          #ifdef DEBUG_INFO
    //            Serial.print(FAN_temp_max);
    //            Serial.print(",");
    //            Serial.println(TempC);
    //          #endif
            digitalWrite (FAN_PIN, HIGH);
        }
        else if ((TempC <= FAN_temp_min) || (Gear > FAN_Gear_max) || (volt < FAN_Volt_min)) digitalWrite (FAN_PIN, LOW);
      #endif
    }
  }
  //  font.printStr(OTEMP_X - font.strWidth(tempe), OTEMP_Y, ";");
  //  Serial.println(OTEMP_X - font.strWidth(tempe));
}
void printlines()
{
  tft.fillRect(31, 0, 67, 66, txt_colors[0][txt_color]);
  tft.fillRect(64, 65, 2, 28, txt_colors[0][txt_color]);
  tft.fillRect(0, 92, 129, 2, txt_colors[0][txt_color]);
}
void printicons(){
  font.setFont(&rre_icons);
  font.setScale(1);
  font.setSpacing(0);
  font.setColor(txt_colors[0][txt_color], txt_colors[1][txt_color]);
//  font.printStr(6, 40,(char*) "2");
//  font.printStr(102,40,(char*) "0");
//  font.printStr(29, 96,(char*) "3");
}
void Setting_loop()
{
  set_loop=HIGH;
  uint8_t Gear_set = Gear;
  uint8_t celsius_init = celsius;
  uint8_t txt_color_init = txt_color;
  while (Gear == Gear_set)
//        Serial.println(txt_color);
  {
    if (millis() - last_setting_loop >= 2000)
    {
      if (Gear_set == 6) celsius = 1 - celsius;
      if (Gear_set == 5)
      {
        txt_color += 1;
        if (txt_color == 9 ) txt_color = 0;
//        Serial.println(txt_color);
        tft.fillScreen(txt_colors[1][txt_color]);
//        Serial.println(txt_color);
      }
      printlines();
      printicons();
      printGear();
      Temp_ON[0] = HIGH;
      Temp_ON[1] = HIGH;
      printTemp();
      printvolt();
      last_setting_loop = millis();
    }
    Read_gear();
//    Gear=2;
    delay (100);
  }
  if (celsius != celsius_init) EEPROM.update(0, celsius);
  if (txt_color != txt_color_init) EEPROM.update(sizeof(int), txt_color);
  set_loop=LOW;
}
void fade (uint8_t debut, int8_t fade_step) {
  uint8_t light_lvl = debut;
  uint8_t i = 0;
  while (i < fade_steps)
  {
    analogWrite(TFT_LED, light_lvl* light_mult);
    light_lvl += fade_step;
    delay(fade_delay);
    i += 1;
//    Serial.println(light_lvl);
  }
}