//#define DEBUG_INFO
#define FAN_ACTIVE
#define TFT_DC 9
#define TFT_CS 10
#define TFT_RST 7
#define TFT_LED 8
#define FAN_PIN 1
#define SCR_Siz 130
#define SCR_Max SCR_Siz-1
#include <Adafruit_ILI9341.h>
#include <Adafruit_GFX.h>
#include <EEPROM.h>
#include <RREFont.h>
//#include <fast_math.h>
#include "rre_gear.h"
#include "rre_bmwfont.h"
#include "rre_bmw.h"
#include "scale.h"
#define GEAR_X 41
#define GEAR_Y 42
#define GEAR_BIG_X 17
#define GEAR_BIG_Y 17
//#define ATEMP_X 180
//#define ATEMP_Y 215
#define OTEMP_X 92
#define OTEMP_Y 101
#define VOLT_X 90
#define VOLT_Y 10
#define DEG2RAD 0.0174532925
const int To_sensor = A0;
//const int Ta_sensor = A0;
const int Vo_sensor = A7;
int celsius = 1;
int txt_color = 0;
const int blu_colors[] = {0x2bb3, 0x33d4, 0x33f4, 0x3c35, 0x4456, 0x4c77, 0x4c97, 0x54b8, 0x5cd8, 0x5cf9, 0x6519, 0x6539, 0x6d3a,};
const 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}};
const unsigned int roundeldiam[] = {53, 52, 28, 27};
const unsigned int tft_center = 65;
bool start = HIGH;
bool geared = LOW;
int light_lvl = 255;
float light_mult = 1 ;
const int mean_count = 40;
const unsigned int fade_time = 500;
const unsigned int fade_steps = 50;
const unsigned int fade_delay = fade_time / fade_steps;
bool blinker = LOW;
bool blink_ON = HIGH;
bool blink_CH = HIGH;
bool blink_prev = HIGH;
const unsigned int warnOtemp = 120;
unsigned int prevOTemp = 0;
const float K = 273.15;
const unsigned int OtempB = 3600;
const float OtempVcoeff = 5./1024; //8184 for 13bits
const unsigned int OtempVref = 5;
const unsigned int OtempR2 = 1070;
float OtempR = 2200;
const unsigned int OtempRref = 2780;
const unsigned int OtempCref = 19;
float OtempV = 11.0;
int OtempC = -31;
const unsigned int init_rot = 1;
int sens = 0;
const unsigned int cursor_offset = 3;
const unsigned int cursor_margin = 20;
const unsigned int graph_ymin = cursor_margin;
const unsigned int graph_ymax = SCR_Max - cursor_margin;
const unsigned int graphh = graph_ymax-graph_ymin;
const unsigned int bar_larg = 28;
const unsigned int temp_xmin = 103;
const unsigned int volt_xmin = 0;
const unsigned int volt_min = 110;
const unsigned int volt_max = 170;
const unsigned int temp_min = 30;
const unsigned int temp_max = 150;
unsigned int index = 0;
unsigned int prev_volt_index = 64;
unsigned int prev_temp_index = 64;
const unsigned int FAN_temp_min = 100;
const unsigned int FAN_temp_max = 110;
const unsigned int FAN_Volt_min = 13.0;
const unsigned int FAN_Gear_max = 2;
const char degres [] = "<;";
float prevvolt = -1.0;
float volt = 0.0;
const float Voltcoeff = 0.01735;
int prevGear = 8;
int Gear = 8;
bool Gear_start = LOW;
bool Gear_bits[3];
const int Gear_pins [] = {2, 3, 4};
char vitesse [2];
long last_gear_change = 0;
long last_setting_loop = 0;
long last_update = 0;
long last_blink = 0;
long timer_gear = 0;
long timer_sensors = 0;
#define BLACK 0x0000
#define WHITE 0xFFFF
#define GREEN 0x07E0
#define GREY 0x9999
#define DARKGREY 0x3186
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
//SSD1283A tft(/*CS=10*/ SS, /*DC=*/ TFT_DC, /*RST=*/ TFT_RST, /*LED=*/ TFT_LED); //hardware spi,cs,cd,reset,led
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() {
Read_gear();
// Gear = 0;
if (Gear != 0) {Gear_start = HIGH;}
// txt_color = 0;
#ifdef FAN_ACTIVE
pinMode(FAN_PIN, OUTPUT);
digitalWrite (FAN_PIN, LOW);
#endif
#ifdef DEBUG_INFO
Serial.begin(9600);
Serial.println("DEBUG MODE ON");
#endif
analogWrite(TFT_LED, 0);
for (int i = 0; i < 3; i++) {
pinMode(Gear_pins[i], INPUT);
}
pinMode(To_sensor, INPUT);
// pinMode(Ta_sensor, INPUT);
pinMode(Vo_sensor, INPUT);
// Serial.begin(9600);
EEPROM.get(0, celsius);
// Serial.println( celsius);
if (celsius != 0 && celsius != 1) {
celsius = 1;
EEPROM.put(0, celsius);
}
EEPROM.get( sizeof(int), txt_color );
// Serial.println( txt_color);
if (txt_color < 0 || txt_color > 8) {
txt_color = 0;
EEPROM.put( sizeof(int), txt_color );
}
// txt_color = ;
font.init(customRect, SCR_Siz, SCR_Siz);
// tft.init();
tft.begin();
analogWrite(TFT_LED, 0);
tft.setRotation(init_rot + 2);
tft.fillScreen(BLACK);
// tft.drawCircle(tft_center, tft_center, 64, WHITE);
splashscreen();
// printlines();
// draw_scale (0, SCR_Max, 1, 0, SCR_Max);
// draw_scale (SCR_Siz - bar_larg + 1, SCR_Max, 1, 0, SCR_Max);
}
void loop() {
if (start)
{
int fade_lvl = 255;
fade (0,fade_lvl);
Read_sensors();
Read_gear();
// Gear = 2;
if (Gear != 0 && !Gear_start) Setting_loop();
start = !start;
}
if (millis() - last_blink > 500)
{
blink_ON = !blink_ON;
blink_prev = !blink_ON;
blink_CH=HIGH;
last_blink = millis();
}
if (millis() - timer_gear > 100)
{
Read_gear();
// Gear = 2;
if (prevGear != Gear)
{
if (Gear != 7 ||(Gear == 7 && millis()-last_gear_change >1000)){
printGear_big();
//Serial.println( txt_color);
geared = HIGH;
prevGear = Gear;
last_gear_change = millis();
}
}
timer_gear = millis();
}
if (millis() - timer_sensors > 500) {
Read_sensors();
#ifdef FAN_ACTIVE
if ((OtempC <= FAN_temp_min) || (Gear > FAN_Gear_max) || (volt < FAN_Volt_min)) digitalWrite (FAN_PIN, LOW);
else if ((OtempC >= FAN_temp_max) && (Gear <= FAN_Gear_max) && (volt >= FAN_Volt_min)) digitalWrite (FAN_PIN, HIGH);
#endif
sens = 1 - sens;
timer_sensors = millis();
}
if(millis() - last_gear_change > 2000 && millis() - last_update > 50){
if (geared == HIGH ){
tft.fillScreen(txt_colors[1][txt_color]);
draw_scale (0, SCR_Max, 1, 0, SCR_Max);
draw_scale (SCR_Siz - bar_larg + 1, SCR_Max, 1, 0, SCR_Max);
printlines();
printGear();
prevOTemp += 5;
prevvolt += 1;
prev_temp_index += 1;
prev_volt_index += 1;
geared = LOW;
}
if (abs(OtempC - prevOTemp)> 1 || (blinker & blink_CH)) printOTemp();
if (abs(volt - prevvolt) > 0.1) printvolt();
draw_cursor (SCR_Siz-bar_larg + 1 , 1, OtempC, temp_min, temp_max, prev_temp_index);
prev_temp_index = index;
// Serial.print("indexO= ");
// Serial.println(index);
draw_cursor (bar_larg , -1, volt * 10 , volt_min , volt_max, prev_volt_index);
prev_volt_index = index;
// Serial.print("indexV= ");
// Serial.println(index);
blink_CH=LOW;
last_update = millis();
}
blink_prev = blink_ON;
tft.drawCircle(tft_center, tft_center, 64, WHITE);
// delay(50);
}
void draw_cursor(int pos_x, int sens, int valeur, int mini, int maxi , int previndex)
{
// index = constrain(graph_ymax - map(constrain( valeur, mini, maxi), mini, maxi, graph_ymin, graph_ymax),previndex - 2, previndex + 2);
index = constrain(SCR_Max - constrain(map( valeur, mini, maxi, graph_ymin, graph_ymax), graph_ymin, graph_ymax),previndex - 2, previndex + 2);
if (index != previndex )
{
draw_scale(pos_x, SCR_Max, sens, SCR_Max-previndex - 8 , SCR_Max - previndex + 8);
tft.fillTriangle(pos_x + (cursor_offset -4) * sens , index, pos_x + (bar_larg + cursor_offset -4) * sens , index - 8, pos_x + (bar_larg + cursor_offset -4) * sens, index + 8, txt_colors[1][txt_color]);
tft.fillTriangle(pos_x + cursor_offset * sens , index, pos_x + (bar_larg + cursor_offset) * sens , index , pos_x + (bar_larg + cursor_offset) * sens, index - 8, txt_colors[0][txt_color]);
tft.fillTriangle(pos_x + cursor_offset * sens , index+1, pos_x + (bar_larg + cursor_offset) * sens , index + 1, pos_x + (bar_larg + cursor_offset) * sens, index +8, txt_colors[0][txt_color] - DARKGREY);
}
}
void draw_scale(int x, int y, int sens, int mini, int maxi) {
for (int i = mini; i < maxi ; i++) {
// if ( i % 10 == 0) {tft.drawFastHLine(x , y - i , bar_larg * sens , txt_colors[0][txt_color]);}
// else {tft.drawFastHLine(x , y - i , bar_larg * sens , echelle[txt_colors[2][txt_color]][129 - i]);}
if ( i % 10 == 0) {tft.writeFastHLine(x , y - i , bar_larg * sens , BLACK);}
else {tft.writeFastHLine(x , y - i , bar_larg * sens , BLACK);}
}
}
void splashscreen() {
// Roundel
// BMW characters
font.setFont(&rre_bmw);
font.setScale(1);
font.setSpacing(0);
font.setColor(WHITE);
font.printStr(23, 28,"0");
font.printStr(54, 14, "1");
font.printStr(83, 26, "2");
for (int i = 0; i < 13; i++) {
tft.fillCircle(tft_center, tft_center, roundeldiam[2] - i * 4, blu_colors[i]);
}
font.setFont(&rre_helice);
tft.setRotation(init_rot + 0);
font.printStr(38, tft_center+1, "0");
tft.setRotation(init_rot + 2);
font.printStr(38, tft_center+1, "0");
// White circles
for (int i = 0; i < 4; i++) {
tft.drawCircle(tft_center, tft_center, roundeldiam[i], WHITE);
tft.drawCircle(tft_center, tft_center+1, roundeldiam[i], WHITE);
}
int fade_lvl = 255;
fade (0,fade_lvl);
delay(1000);
fade(fade_lvl,0);
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_lvl = 255;
fade (0,fade_lvl);
delay(1000);
fade(fade_lvl,0);
tft.fillScreen(BLACK);
delay(500);
}
void Read_gear()
{
for (int i = 0; i < 3; i++) {
Gear_bits[i] = digitalRead(Gear_pins[i]);
}
Gear = Gear_bits[0] + Gear_bits[1] * 2 + Gear_bits[2] * 4;
}
void Read_sensors()
{
// Serial.print("sensor: ");
// Serial.println(timer_sensors);
if (sens == 0){
volt = analogRead(Vo_sensor);
delay(50);
volt = analogRead(Vo_sensor)* Voltcoeff ; // + 16 - light_read / 20;
// volt += 13.2;
// Serial.print("volt : "); Serial.println(volt);
}
if (sens == 1 || start) {
OtempV = analogRead(To_sensor);
delay(50);
OtempV = analogRead(To_sensor)*OtempVcoeff;
// Serial.print("OtempV= ");
// Serial.println(OtempV);
if (OtempV != 0){
OtempR= OtempR2/((float) OtempVref/OtempV-1);
// Serial.print("OtempR= ");
// Serial.println(OtempR);
OtempC=(OtempCref+K)/(1-(OtempCref+K)/OtempB*log(OtempRref/OtempR))-K;
}
else {OtempC = prevOTemp;}
if (OtempC >= warnOtemp) {blinker = HIGH;}
else { blinker = LOW;}
}
// OtempC= 130;
// Serial.print("OtempC=");
// Serial.println(OtempC);
}
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, 37, 65, 58, 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, 37, 65, 58, txt_colors[1][txt_color]);
// tft.fillCircle(tft_center+1, tft_center, 33, txt_colors[1][txt_color]);
}
dtostrf(Gear, 0, 1, vitesse);
font.printStr(GEAR_X, GEAR_Y, vitesse);
}
void printGear_big()
{
font.setFont(&rre_gear);
font.setBold(1);
font.setScale(2);
font.setCharMinWd(48);
font.setSpacing(1);
if (Gear == 0) {
font.setColor(BLACK, GREEN);
tft.fillRect(0, 0, SCR_Max, SCR_Max, GREEN);
}
else {
font.setColor(txt_colors[0][txt_color], txt_colors[1][txt_color]);
tft.fillScreen(txt_colors[1][txt_color]);
}
dtostrf(Gear, 0, 1, vitesse);
font.printStr(GEAR_BIG_X, GEAR_BIG_Y, vitesse);
}
void printvolt()
{
char volte [10];
tft.fillRect(VOLT_X-50, VOLT_Y, 50, 20, txt_colors[1][txt_color]);
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, ":");
font.printStr(VOLT_X - font.strWidth(volte), VOLT_Y, volte);
prevvolt = volt;
}
void printOTemp()
{
float Otemp_f = OtempC;
char tempe[10];
tft.fillRect(OTEMP_X-50, OTEMP_Y, 50, 20, txt_colors[1][txt_color]);
font.setFont(&rre_bmwfont);
font.setBold(0);
font.setScale(1);
font.setCharMinWd(5);
font.setSpacing(2);
if (blinker && blink_ON){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]);}
// Serial.print("celsius=");
// Serial.println(celsius);
if (celsius > 1) {celsius = 1;}
if (celsius == 0) {Otemp_f = Otemp_f * 1.8 + 32;}
dtostrf(Otemp_f, 3, 0, tempe);
strcat (tempe, "/");
strncat (tempe, °res[celsius], 1);
// Serial.println(degres);
// Serial.println(tempe);
font.printStr(OTEMP_X - font.strWidth(tempe), OTEMP_Y, tempe);
// font.printStr(OTEMP_X - font.strWidth(tempe), OTEMP_Y, ";");
// Serial.println(OTEMP_X - font.strWidth(tempe));
prevOTemp = OtempC;
}
void printlines()
{
// tft.drawCircle(tft_center, tft_center, 33, txt_colors[0][txt_color]);
// tft.drawCircle(tft_center, tft_center, 34, txt_colors[0][txt_color]);
// tft.drawCircle(tft_center+1, tft_center, 34, txt_colors[0][txt_color]);
// tft.drawCircle(tft_center+1, tft_center, 33, txt_colors[0][txt_color]);
for (int i = 0; i < 3; i++)
{
tft.drawRect(30+i, 34+i, 71-(2*i), 64-(2*i), txt_colors[0][txt_color]);
}
tft.fillRect(30, tft_center, 3, tft_center, txt_colors[0][txt_color]);
tft.fillRect(98, 0, 3, tft_center, txt_colors[0][txt_color]);
}
void Setting_loop()
{
int Gear_set = Gear;
int celsius_init = celsius;
int txt_color_init = txt_color;
printGear();
printOTemp();
printvolt();
while (Gear !=0)
// Serial.println(txt_color);
{
if (millis() - last_setting_loop >= 2000)
{
if (Gear_set == 1)
{
celsius = 1 - celsius;
}
else
{
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();
printGear();
printOTemp();
printvolt();
draw_scale (0, SCR_Max, 1, 0, SCR_Max);
draw_scale (SCR_Siz - bar_larg + 1, SCR_Max, 1, 0, SCR_Max);
draw_cursor (SCR_Siz-bar_larg + 1 , 1, OtempC, temp_min, temp_max, prev_temp_index);
draw_cursor (bar_larg , -1, volt , volt_min , volt_max, prev_volt_index);
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);}
}
void fade (int debut, int cible) {
int range = abs (cible - debut);
int fade_step = (cible - debut)/fade_steps;
int fade_step_abs = abs(fade_step);
light_lvl = debut;
int i = 0;
while (i < range)
{
analogWrite(TFT_LED, light_lvl* light_mult);
light_lvl += fade_step;
delay(fade_delay);
i = i + fade_step_abs;
}
analogWrite(TFT_LED, cible * light_mult);
}