Skip to content

error: Invalidinput coming from a Buffered File #2210

@cvusb97

Description

@cvusb97

#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;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions