-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
#Hello,
i'm not an expert in this kind of advance using of Arduino. All the HTPP and network darkside of arduino is still a kinda unknown world for me. I asked to a friend and a lot of chat gpt to develop this code, so be patient with me :)
====== Issue in a few words ======
If i do:
DeserializationError error = deserializeJson(doc, client.readString(), DeserializationOption::Filter(filter));
everything works always fine but slowly.
if i do:
ReadBufferingStream bufferedFile(client, (contentLength+2048));
DeserializationError error = deserializeJson(doc, bufferedFile , DeserializationOption::Filter(filter));
for small responses it works fast and really well. For long responses it gives me " IncompleteInput"
====== Issue in a lot of words ======
I'm using an ESP32-Trinity board to control an led matrix (amazing check it out if you need a board to do this kind of projects https://esp32trinity.com/).
Basically i built this program to reproduce a bus stop screen to know exactly when a bus or a tram will arrive to a given bus stop, but when i'm at home.
https://giromilano.atm.it/proxy.tpportal/api/tpPortal/geodata/pois/stops/11491
The URL is above and 11491 is the choosen stop number. Obviously the json dimension depends a lot on how many Bus/Tram lines are passing via the stop and on what's happening in my city (Milan) as you can see in "TrafficBulletins" section. Sometimes more than 25k in total.
10708 is a "Small Stop"
11491 is a "Big Stop"
So for a faraway from the center bus stop it's always ok beacuse the json is small, but if it's a central bus stop the json is big and i think that the problem is because of that.
===What you should expect in serial output====
Conn. per fermata: 11491 - OK - Cont. Size: 10851 bytes - Deserializing... Success elapsedTime: 12688
Fermata: Via Orefici P.za Cordusio
Linea 2: in arrivo
Linea 12: ricalcolo
Linea 14: in arrivo
Linea 16: ricalcolo
Linea 19: ricalcolo
Linea 151: notturna
===What you receive with buffered file====
Conn. per fermata: 11491 - OK - Cont. Size: 10844 bytes - Deserializing... Errore parsing JSON IncompleteInput
As you can see without buffer it can take "elapsedTime: 12688" milliseconds to parse. with buffer it can get to around 1 or 2 seconds which is amazing. But with bus stops the above descripted problem comes out.
I think that the problem is in the buffered file that, for some reason, is incomplete. Is there a way to increase the buffered file dimension/chunks? is there something else that i'm doing wrong or that i can do better to increase speed without using a buffer? thanks in advice for the help and for your time spent reading :)
Below there's the code: the network and core part is in void showStopInfo(String stopId).
All the other functions are for controlling the LED Matrix.
P.S. The comments are in italian but i think that you can easily undestrand the showStopInfo part. but don't hesitate to ask
====== THE CODE ======
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#include <StreamUtils.h>
#include <Adafruit_GFX.h> //Core graphics library
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
// =========== INCLUSIONE FONTS =========
#include <Fonts/Org_01.h>
#include <Fonts/Picopixel.h>
#include <Fonts/Tiny3x3a2pt7b.h>
#include <Fonts/TomThumb.h>
//================================================================================================================================
//============================================== SETTAGGI ========================================================================
//================================================================================================================================
// === CONFIGURAZIONE WIFI ===
const char* ssid = "----";
const char* password = "----";
// === ID FERMATE ===
//const int stopIds[] = {10708, 10715, 10680, 12211, 10827, 15638, 11148, 13156}; //Inserire i numeri della fermata intervallati da una virgola
const int stopIds[] = {11491};
// === CONFIGURAZIONE DIMENSIONE PANNELLO ===
#define PANEL_RES_X 64
#define PANEL_RES_Y 32
#define PANEL_CHAIN 1
// === PULSANTI E SENSORI X ESP32 TRINITY ===
#define BUTTON_PIN 2 //GPIO2 per pulsante fisico
#define LDR_PIN 35 //GPIO35 per fotoresistore gia con resistenza e tutto
#define TOUCH_PIN1 32 //GPIO32 per touch capacitivo
#define TOUCH_PIN2 33 //GPIO32 per touch capacitivo
#define TOUCH_THRESHOLD 450 //soglia per attivazione touch piu alto più sensibile
// === LUMINOSITA' AUTOMATICA ======
#define USE_AUTO_BRIGHTNESS false //true usa luminosità automatica, false non la usa
#define DEFAULT_BRIGHTNESS 20 //valore di luminosità fissa nel caso non si voglia la luminosità automatica
//Selezione font: inserire il nome del font con & davanti (es: &Org_01;)
const GFXfont* stopNameFont = &Org_01;
const GFXfont* lineInfoFont = &TomThumb;
int lineNumReservedSpace = 15; //Numero di pixel riservati al numero della linea
// === TEMPI E VELOCITA' SCROLL ===
const unsigned long timeout = 60000; //Timeout dopo il quale il display si spegne se non viene premuto nessun tasto
const unsigned long updateInterval = 30000; //Tempo di update dei dati della fermata selezionata
const int scrollWait = 2000; //Tempo di attesa prima di scrollare in x e y
unsigned int refreshRate = 150; //Settaggio velocità scorrimenti + alto poù lento (ms per pixel di scroll)
//--------------------------------------------------------------------------------------------------------------------------------------
MatrixPanel_I2S_DMA *dma_display = nullptr;
int FONT_HEIGHT_STOP_NAME = 0; //Sarà calcolato
int FONT_HEIGHT_LINE_INFO = 0; //Sarà calcolato
uint16_t colorStopName, colorLineId, colorWaitMsg, sepLineColor, dimWhite, rectColor;
int initTimeWaitScrollX; //Variabili per attese scroll x
int initTimeWaitScrollY; //Variabili per attese scroll y
bool firstTimeScrollY = true; //Variabile che indica se sono all'inizio dello scroll y delle linee
bool firstTimeScrollX = true; //Variabile che indica se sono all'inizio dello scroll x del nome fermata
long initTimeWaitY;
long initTimeWaitX;
unsigned long scrollTimer = 0;
int stopScrollX = 0;
int lineScrollY = 0;
static const int lineMaxScroll= 10; //Supporto fino a 10 linee mostrabili
int waitMsgScrollX[lineMaxScroll] = {0};
const int numStops = sizeof(stopIds) / sizeof(stopIds[0]);
int currentStopIndex = numStops; //Partenza dal numero più alto perchè nelloop ci serve così
bool buttonState = HIGH;
bool displayOn = false;
unsigned long lastButtonPress = 0;
unsigned long lastUpdateTime = 0;
//--- Variabili per la memorizzazione dei dati della fermata ----
DynamicJsonDocument doc(30000);
//StaticJsonDocument<20000> doc;
const char* stopAddress = doc["Address"] | "---";
JsonArray lines = doc["Lines"];
//=================================================================================================================================================================
//==================================================================== SETUP ======================================================================================
//=================================================================================================================================================================
void setup() {
Serial.begin(115200);
delay(100); // Aspetta che il monitor seriale si agganci
pinMode(BUTTON_PIN, INPUT_PULLUP);
analogReadResolution(12);
//Calcolo altezze font
FONT_HEIGHT_STOP_NAME = getFontHeight(stopNameFont);
FONT_HEIGHT_LINE_INFO = getFontHeight(lineInfoFont); //+1 per tom Thumb
HUB75_I2S_CFG mxconfig (PANEL_RES_X, PANEL_RES_Y, PANEL_CHAIN);
// Display Setup
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
dma_display->begin();
dma_display->setBrightness8(DEFAULT_BRIGHTNESS);
dma_display->clearScreen();
dma_display->setTextWrap(false); // Disailito l'auto a capo
// === COLORI PERSONALIZZABILI (R-G-B) ===
colorStopName = dma_display->color565(250, 136, 69 );
colorLineId = dma_display->color565(250, 136, 69 );
colorWaitMsg = dma_display->color565(200, 200, 200);
sepLineColor = dma_display->color565(128 ,128, 128);
dimWhite = dma_display->color565(128, 128, 128);
rectColor = dma_display->color565( 40, 40 , 40 );
dma_display->setTextColor(dimWhite);
dma_display->setFont(stopNameFont);
WiFi.begin(ssid, password);
WiFi.setSleep(false);
while (WiFi.status() != WL_CONNECTED) {
dma_display->setCursor(2, 16);
dma_display->print("CONNECTING");
Serial.print(".");
delay(300);
dma_display->clearScreen();
}
Serial.print("\nWiFi CONNESSO! "); Serial.println(WiFi.localIP());
dma_display->setCursor(1, 12); dma_display->print("WiFi OK");
dma_display->setCursor(1, 20); dma_display->print(WiFi.localIP());
delay(1500);
dma_display->clearScreen();
}
//=================================================================================================================================================================
//=============================================================== LOOP ============================================================================================
//=================================================================================================================================================================
void loop() {
if(digitalRead(BUTTON_PIN) == LOW){ //LEGGO PRESSIONE PULSANTE
delay(40); //AntiBounce
buttonState=LOW; Serial.println("TASTO FISICO");
while(digitalRead(BUTTON_PIN)==LOW){} //Aspetto venga lasciato il tatso
}
if (Serial.available() > 0) { //SE MANDATA QUALSIASI COSA VIA TERMINALE SERIALE
while (Serial.available() > 0) Serial.read(); //Svuota buffer
buttonState = LOW;
Serial.println("TASTO SERIALE");
}
//Per qualche motivo se non li leggo tutti e due non funziona la lettura. è così anche su ghithub
int touchValue1 = touchRead(TOUCH_PIN1); //SE PREMUTO IL TOUCH BUTTON 1
int touchValue2 = touchRead(TOUCH_PIN2); //SE PREMUTO IL TOUCH BUTTON 1
if (touchValue1 < TOUCH_THRESHOLD || touchValue2 < TOUCH_THRESHOLD) { //SE PREMUTO uno dei due TOUCH BUTTON
if(touchValue1 != 0 && touchValue2 != 0){ //evita eventuali errori
buttonState = LOW;
Serial.print("TASTO TOUCH 1 "); Serial.print(touchValue1); Serial.print(" TASTO TOUCH 2 "); Serial.println(touchValue2);
}
}
if (buttonState == LOW) { //SE LA CONDIZIONE DI PULSANTE PREMUTO SI VERIFICA E L'ULTIMO STATO DEL PULSANTE ERA NON PREMUTO
displayOn = true;
currentStopIndex++;
if (currentStopIndex >= numStops){ currentStopIndex = 0; } //>= PERCHE' PARTE DA 0 L'INDEX
String stopId = String(stopIds[currentStopIndex]); //Conversione da int a string
showStopInfo(stopId);
lastButtonPress = millis();
buttonState = HIGH;
}
if (displayOn && (millis() - lastButtonPress > timeout)) { //Se il dipslay era acceso e sono passati più del tempo impostato dall'ultima pressione del tasto
displayOn = false;
Serial.println("Spengo schermo dopo inattività");
currentStopIndex = numStops;
dma_display->clearScreen();
}
if (displayOn) {
if (stopAddress != nullptr && !lines.isNull()) {updateDisplay();} //Controllo che i dati siano Validi
//SETTAGGIO LIMUNOSITA DEL DISPLAY
if (USE_AUTO_BRIGHTNESS) { //SE IMPOSTATO SU AUTOMATICA
int ldrValue = analogRead(LDR_PIN);
uint8_t brightness = map(ldrValue, 0, 4095, 40, 150);
dma_display->setBrightness8(brightness);
Serial.printf("LDR: %d -> Brightness: %d\n", ldrValue, brightness);
} else { dma_display->setBrightness8(DEFAULT_BRIGHTNESS); } //SE IMPOSTATO SU NON AUTOMATICA
//delay(refreshRate);
} else { initTimeWaitScrollY=millis(); initTimeWaitScrollX=millis(); } //Altrimenti aggiorno la variabile per il refresh. Resetto prima millis però
}
//=================================================================================================================================================================
//============================================ FETCHING DATI E SCORRIMENTI ========================================================================================
//=================================================================================================================================================================
void showStopInfo(String stopId) {
int elapsedTime = millis();
dma_display->clearScreen();
dma_display->setTextColor(sepLineColor);
dma_display->setCursor(30, 16);
dma_display->print("...");
rettanguloProgress(5); //Rettango a x percentuale
if (WiFi.status() != WL_CONNECTED){
dma_display->clearScreen();
Serial.println("WIFI NOT OK");
dma_display->setCursor(1, 16); dma_display->print("WiFi NOT OK");
displayOn = false;
return;
}
void resetbuffers(); //reset display buffers
delay(10);
WiFiClientSecure client;
//client.stop();
client.setInsecure();
client.setTimeout(10000);
client.setHandshakeTimeout(10000); // handshake timeout (Arduino-ESP32)
rettanguloProgress(10); //Rettango a x percentuale
if (!client.connect("giromilano.atm.it", 443)) {
Serial.println("Connessione giromilano fallita");
dma_display->clearScreen();
dma_display->setCursor(5, 11); dma_display->print("ATM SITE");
dma_display->setCursor(5, 21); dma_display->print("FAIL");
displayOn = false;
return;
} //else{ Serial.println("Connessione ATM OK"); }
rettanguloProgress(30); //Rettango a x percentuale
Serial.print("Conn. per fermata: "); Serial.print(stopId);
client.println("GET /proxy.tpportal/api/tpPortal/geodata/pois/stops/" + stopId + " HTTP/1.1");
client.println("Host: giromilano.atm.it");
client.println("User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
client.println("Accept: application/json, text/plain, */*");
client.println("Accept-Language: it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7");
client.println("Accept-Encoding: identity");
client.println("Referer: https://giromilano.atm.it/");
client.println("Origin: https://giromilano.atm.it");
client.println("Connection: close");
client.println();
Serial.print(" - OK ");
/*
while (client.connected()) {
String line = client.readStringUntil('\n');
if (line == "\r" || line.length() == 1) break;
}
*/
size_t contentLength = 0;
while (client.connected()) {
String line = client.readStringUntil('\n');
if (line.startsWith("Content-Length:")) {
contentLength = line.substring(15).toInt();
}
if (line == "\r") break; // fine header (\r\n\r\n)
}
rettanguloProgress(60); //Rettango a x percentuale
//Deserializzazione e filtraggio dati
Serial.print(" - Cont. Size: "); Serial.print(contentLength); Serial.print(" bytes - Deserializing... ");
JsonDocument filter;
filter["Address"] = true;
JsonObject filter_Lines_0 = filter["Lines"].add<JsonObject>();
filter_Lines_0["Line"]["LineId"] = true;
filter_Lines_0["WaitMessage"] = true;
ReadBufferingStream bufferedFile(client, (contentLength+2048));
DeserializationError error = deserializeJson(doc, bufferedFile , DeserializationOption::Filter(filter));
//ReadBufferingStream bufferedFile(client, (contentLength+2048));
//DeserializationError error = deserializeJson(doc, client.readString(), DeserializationOption::Filter(filter));
rettanguloProgress(90); //Rettango a x percentuale
if (!error) {
elapsedTime = millis() - elapsedTime;
Serial.print("Success "); Serial.print("elapsedTime: "); Serial.println(elapsedTime);
rettanguloProgress(100); //Rettango a x percentuale
delay(200);
stopAddress = doc["Address"].as<const char*>();
lines = doc["Lines"].as<JsonArray>();
//------------ serial print ----------------------------------------
Serial.println("==================================");
Serial.printf("Fermata: %s\n", stopAddress);
//---- stampa delle linee e memorizzazione dati line ---------------
for (JsonObject line : lines) {
const char* lineId = line["Line"]["LineId"]| "---";
const char* waitMsg = line["WaitMessage"]| "---";
Serial.printf("Linea %s: %s\n", lineId, waitMsg);
}
Serial.println("==================================");
//------------------------------------------------------------------
int totalLines = lines.size(); //Quante sono le linee da far vedere? analizza l'array
//Azzero le variabili di scroll
stopScrollX = PANEL_RES_X;
lineScrollY = 0;
//Setto tutte le x di scroll del messaggio d'attesa a zero
for (int i = 0; i < lineMaxScroll; i++) waitMsgScrollX[i] = 0;
lastUpdateTime = millis();
firstTimeScrollY = true;
firstTimeScrollX = true;
} else {
Serial.print("Errore parsing JSON "); Serial.println(error.c_str());
dma_display->clearScreen();
dma_display->setTextWrap(true);
dma_display->setCursor(0, 10); dma_display->print("ERRORE");
dma_display->setCursor(0, 21); dma_display->print(error.c_str());
dma_display->setTextWrap(false);
}
}
//==================================================================================================================================================================================
void updateDisplay() {
// --------------------Stampa ed eventuale scorrimento orizzontale del nome fermata-------------------------
dma_display->setFont(stopNameFont);
lineaStop();
int stopWidth = stringLenght(stopAddress); //Quanti pixel occupa il nome della fermata? lo calcolo
if (stopWidth > PANEL_RES_X) {
if (firstTimeScrollX) {
rettanguloStopName();
initTimeWaitX= millis(); //Setto il momento in cui è stato acceso il display
firstTimeScrollX = false; //Cambio la variabile per segnare che non è più la rima volta che accendo il display
}
dma_display->setCursor(PANEL_RES_X - stopScrollX + 1, FONT_HEIGHT_STOP_NAME -2); //Setto il cursore alla x di partenza (Che sarà a zero perchè l'abbiamo messa a 64) - la Y è la grandezza del font
dma_display->setTextColor(colorStopName);
dma_display->print(stopAddress);
if ((millis() - initTimeWaitX) > scrollWait && (millis() - initTimeWaitScrollX) > refreshRate - 70) { //Aspetto il tempo impostato per lo scroll wait, una volta raggiunto comicerò a scrollare
rettanguloStopName();
stopScrollX = (stopScrollX + 1) % (stopWidth + PANEL_RES_X); //Ogni Aumento di un pixel la x dello scroll. quando stopScrollX raggiunge il valore massimo (stopWidth + PANEL_RES_X), torna a 0
if (stopScrollX == 0) {firstTimeScrollX = true;} //Quando arriva azero imposto nuovamente la variabile che indica che sono a inizio scroll
initTimeWaitScrollX=millis(); //Resetto variabile per refreshrate
}
} else {
if (firstTimeScrollX) {
rettanguloStopName();
firstTimeScrollX = false; //Cambio la variabile per segnare che non è più la rima volta che accendo il display
}
dma_display->setCursor((PANEL_RES_X/2 - stopWidth/2) , FONT_HEIGHT_STOP_NAME - 2); //Setto la scritta al centro la Y è la grandezza del font
dma_display->setTextColor(colorStopName);
dma_display->print(stopAddress);
}
//----------------------------Stampa ed eventuale scorrimento verticale delle linee------------------------
int lineHeight = FONT_HEIGHT_LINE_INFO; //quanti pixel è alta la linea di testo?
int totalLines = lines.size(); //quante sono le linee da far vewere? analizza l'array
int maxScrollY = lineHeight * totalLines; //quanto devo scrollare per far scorrete tutte lelinee?
int availablePixelsY = PANEL_RES_Y - FONT_HEIGHT_STOP_NAME + 2; //quante sono i pixel disponibili per le linee
int stopCounter = 0; //Contatore numero fermata nell'array
int y;
int yStart = lineHeight + FONT_HEIGHT_STOP_NAME + 2 - lineScrollY; //a quale pixel devo comiciare a scrivere? Altezza pixel nome della fermata - contatore scroll Y
if (firstTimeScrollY) {
cleanLinesInfo();
rettanguloLineId();
lineaLines();
}
for (JsonObject line : lines) { //Faccio questa cosa per ogni linea dell'array
const char* lineId = line["Line"]["LineId"]| "---";
const char* waitMsg = line["WaitMessage"]| "---";
y = yStart + (stopCounter * lineHeight); //La y di scorrimento parte dalla y calcolata prima e ogni ciclo viene aumentata di 1. Nel caso della prima 0+1 * pixel altezza lineId
if (y > (FONT_HEIGHT_STOP_NAME + lineHeight)) { //Se la y calcolata è >= della altezza in pixel occupati comunque minore del numero di pixel in y del pannello
dma_display->setFont(lineInfoFont);
int lineIdWidth = stringLenght(lineId); //Calcolo numero di pixel occupati da lineId
int lineIdX = lineNumReservedSpace/2 - lineIdWidth/2; //Calcolo la x per scrivere al centro
dma_display->setCursor(lineIdX, y -1);
dma_display->setTextColor(colorLineId);
dma_display->print(lineId);
//===== CALCOLO VARIABILI SCORRIMENTO MESSAGGIOI DI ATTESA =======
int lineWidth = lineNumReservedSpace + 1; //Fisso lo spazio occupato dal numero della linea ad un valore arbitrario per far partire le attese tutte dallo stesso punto
int msgWidth = stringLenght(waitMsg); //larghezza del messaggio in pixel
int availableWidth = PANEL_RES_X - lineWidth; //spazio rimanente sul pannello.
//---------------------Scorrimento waitMsg se lungo--------------------------
if (msgWidth > availableWidth) {
int scrollX = lineWidth - waitMsgScrollX[stopCounter]; //Calcolo la x di scroll che all'inizio sarà 0 (azzerato all'inizio) + lo spazio riservato arbitrariamente
dma_display->setCursor(scrollX, y -1); //Setto il cursore a quella x e come y metto la y calcolata prima
dma_display->setTextColor(colorWaitMsg);
dma_display->print(waitMsg);
waitMsgScrollX[stopCounter] = (waitMsgScrollX[stopCounter] + 1) % (msgWidth + availableWidth); //Ogni Aumento di un pixel la x dello scroll. quando waitMsgScrollX raggiunge il valore massimo (msgWidth + availableWidth), torna a 0
} else {
dma_display->setCursor(lineWidth, y -1); //Setto il cursore a alla x calcolata e come y metto la y calcolata prima
dma_display->setTextColor(colorWaitMsg);
dma_display->print(waitMsg);
}
}else{ //Tutto la stessa cosa ma ripartendo da sotto a mo di rullo
y = yStart + (stopCounter * lineHeight) + (totalLines * lineHeight); //contatore + pixel occupati da numero di linee
if (y > (FONT_HEIGHT_STOP_NAME + lineHeight)) {
dma_display->setFont(lineInfoFont);
int lineIdWidth = stringLenght(lineId);
int lineIdX = lineNumReservedSpace/2 - lineIdWidth/2;
dma_display->setCursor(lineIdX, y -1);
//dma_display->setCursor(1, y -1);
dma_display->setTextColor(colorLineId);
dma_display->print(lineId);
//===== CALCOLO VARIABILI SCORRIMENTO MESSAGGIOI DI ATTESA =======
int lineWidth = lineNumReservedSpace + 1; //Fisso lo spazio occupato dal numero della linea ad un valore arbitrario per far partire le attese tutte dallo stesso punto
int msgWidth = stringLenght(waitMsg); //larghezza del messaggio in pixel
int availableWidth = PANEL_RES_X - lineWidth; //spazio rimanente sul pannello.
//---------------------Scorrimento waitMsg se lungo--------------------------
if (msgWidth > availableWidth) {
int scrollX = lineWidth - waitMsgScrollX[stopCounter]; //Calcolo la x di scroll che all'inizio sarà 0 (azzerato all'inizio) + lo spazio riservato arbitrariamente
dma_display->setCursor(scrollX, y -1); //Setto il cursore a quella x e come y metto la y calcolata prima
dma_display->setTextColor(colorWaitMsg);
dma_display->print(waitMsg);
waitMsgScrollX[stopCounter] = (waitMsgScrollX[stopCounter] + 1) % (msgWidth + availableWidth); //Ogni Aumento di un pixel la x dello scroll. quando waitMsgScrollX raggiunge il valore massimo (msgWidth + availableWidth), torna a 0
} else {
dma_display->setCursor(lineWidth, y -1); //Setto il cursore a alla x calcolata e come y metto la y calcolata prima
dma_display->setTextColor(colorWaitMsg);
dma_display->print(waitMsg);
}
}
}
stopCounter++;
}
//Se è la prima volta che viene acceso il display
if (firstTimeScrollY) {
initTimeWaitY= millis(); //Setto il momento in cui è stato acceso il display
firstTimeScrollY = false; //Cambio la variabile per segnare che non è più la rima volta che accendo il display
}
if (maxScrollY>availablePixelsY) { //Se devo scrollare
if ((millis() - initTimeWaitY) > scrollWait && (millis() - initTimeWaitScrollY) > refreshRate) { //Aspetto il tempo impostato per lo scroll wait e controllo refreshrate, una volta raggiunto comicerò a scrollare
cleanLinesInfo();
rettanguloLineId();
lineScrollY = (lineScrollY + 1) % (maxScrollY); //Ogni volta aumento il contatore dello scroll y. Quando la y dis croll raggiunge un valore pari maxScrollY
initTimeWaitScrollY=millis();
}
}
}
//==================================================================================================================================================================================
//FUNZIONE PER TROVARE L'ALTEZZA DI UN FONT
int getFontHeight(const GFXfont* font) { return font->yAdvance; } //1 pixel di margine superio ee inferiore calcolati
//Funzione per linea orizzontale di separazione tra nome fermata e linee
//x e y di partenza, per quanti pixel in x e colore
void lineaStop() { dma_display->drawFastHLine(0, FONT_HEIGHT_STOP_NAME + 1, PANEL_RES_X, sepLineColor); }
//Funzione per linea orizzontale di separazione tra line id e tempo attesa
//x e y di partenza, per quanti pixel in y e colore
void lineaLines() { dma_display->drawFastVLine((lineNumReservedSpace - 1), (FONT_HEIGHT_STOP_NAME +2), (PANEL_RES_Y - FONT_HEIGHT_STOP_NAME), sepLineColor); }
//Funzione per creare e ripulire il fondo del titolo linea (mettere nero per nessun fondo)
//x e y di partenza, per quanti pixel in x e per quanti pixel in y, colore nero epr pulire
void rettanguloStopName() { dma_display->fillRect(0, 0, PANEL_RES_X, FONT_HEIGHT_STOP_NAME + 1 , rectColor); }
//Funzione per creare e ripulire il fondo dei messaggi di attesa (mettere nero per nessun fondo)
void cleanLinesInfo() { dma_display->fillRect(lineNumReservedSpace, (FONT_HEIGHT_STOP_NAME +2), PANEL_RES_X, (PANEL_RES_Y - FONT_HEIGHT_STOP_NAME) , dma_display->color444(0, 0, 0)); }
//Funzione per creare e ripulire il fondo dei numeri linea (mettere nero per nessun fondo)
void rettanguloLineId() { dma_display->fillRect(0, (FONT_HEIGHT_STOP_NAME +2) , (lineNumReservedSpace - 1), (PANEL_RES_Y - FONT_HEIGHT_STOP_NAME+1) , rectColor); }
//Funzione per creare una progress bar
void rettanguloProgress(int prog) {
int bar = (PANEL_RES_X * prog)/100;
dma_display->fillRect(0, 20, bar, 2 , dimWhite);
}
int stringLenght(String text){
int16_t x = 0, y = 0; int16_t x1, y1; uint16_t w, h;
dma_display->getTextBounds(text, x, y, &x1, &y1, &w, &h);
return w;
}