//GSI5.0 10/8/2025 - Initial release
// Laurent "Buzzz" Buzzi - Copyright 2025
#define ADAFRUIT
#define FAN_ACTIVE
#include <RREFont.h>
#include "rre_bmwfont.h"
#include "rre_bmw.h"
#include "rre_icons.h"
#include <Adafruit_GFX.h>
#ifdef ADAFRUIT
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
#else
#include <Arduino_ST7789_Fast.h> //https://github.com/cbm80amiga/Arduino_ST7789_Fast
#endif
#include <SPI.h>
#define TFT_DC 9
#define TFT_CS 7
#define TFT_RST 8
#define TFT_MOSI 11 // Data out
#define TFT_SCLK 13 // Clock out
#define FAN_PIN 2
const float light_mult = 1 ;
const uint8_t Sensor_pin[] = {A0, A1, 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 = 240;
const uint8_t SCR_Max = SCR_Siz-1;
const uint8_t X_OFF = 0;
const uint8_t Y_OFF = 0;
const uint8_t X_center = SCR_Siz/2 + X_OFF;
const uint8_t Y_center = SCR_Siz/2 + Y_OFF;
const uint8_t TEMP_X[] = {233 + X_OFF, 111 + X_OFF};
const uint8_t TEMP_Y = 128 + Y_OFF;
const uint8_t VOLT_X = 200 + X_OFF;
const uint8_t VOLT_Y = 179 + Y_OFF;
uint8_t celsius = 1;
uint8_t txt_color = 0;
const uint8_t roundeldiam[] = {90, 89, 52, 51};
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 char degres [] = "<;";
uint8_t sens = 0;
float volt = 0.0;
long last_blink = 0;
long timer_sensors = 0;
#ifdef ADAFRUIT
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);
#else
Arduino_ST7789 tft = Arduino_ST7789(TFT_DC, TFT_RST);
#endif
#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
Read_sensor();
Read_sensor();
Read_sensor();
#ifdef DEBUG_INFO
Serial.begin(115200);
Serial.println("DEBUG MODE ON");
#endif
for (uint8_t i = 0; i < 3; i++) {pinMode(Sensor_pin[i], INPUT);}
font.init(customRect, SCR_Siz + X_OFF, SCR_Siz + Y_OFF);
tft.init(240, 280);
tft.fillScreen(BLACK);
splashscreen();
printlines();
printicons();
// printTemp();
}
void loop()
{
if (millis() - last_blink > 300)
{
// tft.drawCircle(X_center+1, Y_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_sensors > 300)
{
Read_sensor();
#ifdef DEBUG_INFO
// Serial.println(SensorV[sens]);
#endif
timer_sensors = millis();
}
printTemp();
printvolt();
}
void splashscreen() {
// Roundel
font.setColor(WHITE);
// BMW characters
tft.setRotation(init_rot + 2);
font.setFont(&rre_bmw);
font.setScale(1);
font.setSpacing(0);
font.printStr(48, 57,(char*)"0");
font.printStr(105, 28,(char*)"1");
font.printStr(159, 50,(char*)"2");
for (uint8_t i = 0; i < 12; i++) {
tft.fillCircle(X_center+1, Y_center, roundeldiam[2] - i * 4, blu_colors[i]);
}
font.setFont(&rre_helice);
font.printStr(X_center-23, Y_center+1, "0");
tft.setRotation(init_rot + 1);
font.printStr(X_center-25, Y_center+1, "0");
// White circles
for (uint8_t i = 0; i < 4; i++) {
tft.drawCircle(X_center, Y_center, roundeldiam[i], WHITE);
tft.drawCircle(X_center, Y_center, roundeldiam[i]+1, WHITE);
}
delay(10000);
tft.fillScreen(BLACK);
delay(500);
// tft.drawCircle(X_center, Y_center, 64, WHITE);
// R1100S logo
tft.setRotation(init_rot + 2);
font.setFont(&rre_R1100S);
font.setScale(1);
font.setSpacing(0);
font.printStr(18 + X_OFF, 102 + Y_OFF, "01234");
delay(1000);
tft.fillScreen(BLACK);
delay(500);
tft.setRotation(init_rot + 2);
printlines();
printicons();
printTemp();
printvolt();
delay(500);
}
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 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(2);
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) && (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) || (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");
}