ESP32 - LVGL - comportamento strano con style

Buongiorno a tutti,

sto usando una board ESP32 con schermo integrato e interfacce LVGL.

Ho un problema quando utilizzo lv_obj_add_style(label, style,0)

Parti del codice:

static lv_style_t style_red;
static lv_style_t style_green;
static lv_style_t style_white;
static lv_style_t style_purple;
static lv_style_t* colori[4];

dentro a setup, dopo lv_init() e ui_init();

  lv_style_set_text_color(&style_red, lv_color_make(0xFF, 0x00, 0x00));  // rosso
  colori[0] = &style_white;
  colori[1] = &style_purple;
  colori[2] = &style_green;
  colori[3] = &style_red;

Inizializzo tutti i colori allo stesso modo, per brevità ne ho messo solo uno, ho bisogno di inserirli dentro all'array perchè ricevo un messaggio via I2C con il numero colore

lv_obj_add_style(labels[lastPayload.msg], &style_purple, 0);

Funziona

lv_obj_add_style(labels[lastPayload.msg], colori[1], 0);

Funziona il colore, ma il testo viene modificato con caratteri 'a caso'

Sapete a cosa può essere dovuto?

Grazei

Da quel solo pezzo, ti concentri sul problema del colore ma è il testo che è errato.
Quindi cosa è lastPayload.msg ? E chi lo sa vedendo solo quel pezzo ? una stringa ? un intero ?

Secondo me poche info. Posta tutto il codice.

Ciao! Intanto grazie!

Ho evitato il codice perché è dispersivo e ha 5-6 file di dipendenze per la gui.
Ad ogni modo questa sera lo carico.

Non credo comunque sia quello il problema, perché la prima versione che avevo fatto del codice era senza colori e funzionava alla perfezione. Il problema è uscito quando aggiungo i colori. Ma solo se li richiamo attraverso l’array di puntatori. Se passo il puntatore direttamente funziona.

Ho caricato solo le aggiunte che hanno creato problemi ad un codice funzionante.

Quel .msg è valore numerico e l’array label è analogo a colori. Solo che le variabili degli elementi, a differenza degli stili, sono definiti già dalla gui come puntatori

La sensazione è che lo stile venga caricato su un registro precedente al testo e per qualche motivo la scrittura dello stile non si fermi andando a sovrapporsi al registro del testo nel driver.
Proverò a invertire e mettere lo stile prima del testo, anche se, nel caso, sarebbe un palliativo che risolve il risultato senza andare a capire realmente la causa.

Può essere secondo voi che passando l’array lui prenda gli indirizzi di tutto l’array e quindi scriva troppa roba andando a sforare su altri registri?. Sono abbastanza ignorante in merito ai puntatori (lavoro di più su Python che li gestisce in altro modo) Magari il puntatore dello stile ha una dimensione più lunga e quindi va a leggere più valori di ‘colori’ e sfora?

Quanto meno aggiungi le dichiarazioni degli oggetti che stai usando.

labels è un array ok, ma di cosa?
La funzione lv_obj_add_style() si aspetta come primo parametro un puntatore ad un oggetto di tipo lv_obj_t ovvero l'oggetto LVGL a cui vuoi applicare lo stile, mentre tu parli di valori numerici... c'è qualcosa che non torna.

Capito, quindi qui il problema. In apparenza non mi sembra errato.
Nella libreria:
void lv_obj_add_style(lv_obj_t * obj, const lv_style_t * style, lv_style_selector_t selector);
Perciò questo:
lv_obj_add_style(labels[lastPayload.msg], colori[1], 0);
visto che colori[1] = &style_purple dovrebbe equivalere a :
lv_obj_add_style(labels[lastPayload.msg], &style_purple, 0);

@cotestatnt effettivamente il suo problema è sul secondo parametro, sul primo gli funziona senza l'uso di array per lo style.

SI infatti io mi ero focalizzato più sul primo parametro.
Visto che manca la dichiarazione negli spezzoni di codice riportati e che lui parla di numeri mentre dovrebbe essere un puntatore a lv_obj_t .

@mastraa dice che la prima chiamata funziona, quindi si può presumere che il tipo dati sia corretto, però mi piacerebbe vederci più chiaro.

Questa sera vi posto il codice, ora sono col cell e non accedo.

Comunque parlavo di numero per la variabile .msg che viene usata come indice per l’array label

label[payload.msg]

No, in entrambe i modi tu passi la label come "label[payload.msg]" quindi non puo' essere li l'inghippo.
C'e' qualcosa con i puntatori del parametro style.

KartScreen.ino (6.6 KB)
Ecco il codice, ho provato anche a invertire le righe di impostazione style col cambio della label, ma comunque visualizzo testi strani. punti di domanda, numeri casuali, chiocciole ecc.

mi pare anche strano che il problema sia che passo variabili di tipo sbagliato, perchè non essendo avvezzo di puntatori ho provato a vedere se stavo facendo confusione tra &, * ecc, ma qualunque altra cosa abbia scritto mi dava espressamente errore che si aspettava un tipo differente...

Delle due righe con cambio colore la prima con il puntatore diretto va, la seconda in cui provo a passarlo via array no. O meglio: il colore lo cambia correttamente, ma poi il testo non è quello che dovrei vedere...

Per spararle proprio tutte ho anche provato a mettere un delay (che non ha alcun senso visto che l'aggiornamento funziona con l'handler...) tra le due impostazioni. Ma nulla.

Poco male perchè alla fine basta aggiunfere una condizione switch/case, però avrei velocizzato e semplificato il codice...

Se vedete che mi sono perso qualcosa

Grazie

No, non è cosi;
Stai passando le variabili nel modo corretto poiché hai definito labels come un array di puntatori lv_obj_t che è esattamente ciò che si aspetta la funzione.

lv_obj_t* labels[4]; // Array globale

Il dubbio a questo punto è proprio sulla modalità con cui applichi gli stili ai widget LVGL.

Come prima cosa, usi 0 come selettore nella seconda chiamata: LV_PART_MAIN è definita come 0x0000 quindi in teoria non dovrebbe cambiare nulla, però il framework LVGL fa molto uso di macro che magari hanno problemi in questo modo.
Prova ad usare LV_PART_MAIN in modo esplicito anche nel secondo caso.

Inoltre tu continui ad aggiungere lo stile allo stesso widget anche se magari è stato già assegnato, non dovrebbe essere un problema però nel dubbio prima di assegnare il nuovo stile al widget, prova a rimuovere tutti quelli assegnati in precedenza per evitare sovrapposizioni usando la funzione lv_obj_remove_style_all()

dtostrf(lastPayload.time/1000.0, 0, 3, indata);
lv_obj_remove_style_all();
lv_obj_add_style(labels[lastPayload.msg], colori[1], LV_PART_MAIN );
lv_label_set_text(labels[lastPayload.msg], indata);

Infine, siamo sicuri che sia proprio l'istruzione lv_obj_add_style() a creare problemi e che invece non sia l'array di caratteri char indata[] a contenere dati "strani"?
Aggiungi un Serial.println(indata) di verifica.

Inoltre, LVGL dispone della funzione lv_label_set_text_fmt() che ti consente di formattare il testo direttamente senza usare dei buffer temporanei e l'istruzione dtostrf()

if(lastPayload.delta) {  // è un delta
    lv_label_set_text_fmt(ui_delta, "%.3f", lastPayload.time/1000.0);
    lv_obj_remove_style_all(ui_delta);
    lv_obj_add_style(ui_delta, &style_purple, LV_PART_MAIN);
}
else {  // è un time
    lv_label_set_text_fmt(labels[lastPayload.msg], "%.3f", lastPayload.time/1000.0);
    lv_obj_remove_style_all(labels[lastPayload.msg]);
    lv_obj_add_style(labels[lastPayload.msg], colori[1], LV_PART_MAIN);
}

Buonasera,

scusate in questi giorni non sono riuscito a fare nulla e ho ripreso in mano oggi.

LV_PART_MAIN e 0 sono alternati proprio perchè ho provato a fare la prova che dicevi e quando ho allegato il codice non avevo resettato. Ma non cambia nulla.

MISTERO
Ho fatto altre prove: definito una variabile 'stile' come puntatore. Stessa definizione dell'array di prima, ma variabile 'semplice'.
Assegnata ad ogni iterazione a uno dei colori.
Funziona...

SOLUZIONE
In ogni caso, seguendo il tuo consiglio di verificare cosa ci fosse su 'indata' ho notato che in effetti ha un errore.
dtostrf mi passa in ogni caso una stringa che riempie tutti gli spazi senza terminatore.
Ho quindi provato ad aumentare di un carattere e imporre manualmente 0 l'ultimo carattere...e funziona tutto o almeno così sembra dalla prova veloce che ho fatto :star_struck:

Non mi è chiaro però perchè la funzione dtostrf non ritorni un array di char con terminatore come dovrebbe essere standard...

Mi pare strano. Su Avr non mi da problemi un semplice

double d = 123.123;
char buf[10];
void setup() { Serial.begin(9600); }
void loop() {
  dtostrf(d, 5, 2, buf);
  Serial.println(buf);
}

visto che poi usa println che cerca il terminatore.
Il codice del core x Esp32 è ampiamente testato.
Questo il codice che risulta sul mio pc:

char *dtostrf(double number, signed int width, unsigned int prec, char *s) {
  bool negative = false;
  if (isnan(number)) {
    strcpy(s, "nan");
    return s;
  }
  if (isinf(number)) {
    strcpy(s, "inf");
    return s;
  }
  char *out = s;
  int fillme = width;  // how many cells to fill for the integer part
  if (prec > 0) {
    fillme -= (prec + 1);
  }
  // Handle negative numbers
  if (number < 0.0) {
    negative = true;
    fillme--;
    number = -number;
  }
  // Round correctly so that print(1.999, 2) prints as "2.00"
  // I optimized out most of the divisions
  double rounding = 2.0;
  for (unsigned int i = 0; i < prec; ++i) {
    rounding *= 10.0;
  }
  rounding = 1.0 / rounding;
  number += rounding;
  // Figure out how big our number really is
  double tenpow = 1.0;
  unsigned int digitcount = 1;
  while (number >= 10.0 * tenpow) {
    tenpow *= 10.0;
    digitcount++;
  }
  number /= tenpow;
  fillme -= digitcount;
  // Pad unused cells with spaces
  while (fillme-- > 0) {
    *out++ = ' ';
  }
  // Handle negative sign
  if (negative)  *out++ = '-';
  // Print the digits, and if necessary, the decimal point
  digitcount += prec;
  int8_t digit = 0;
  while (digitcount-- > 0) {
    digit = (int8_t)number;
    if (digit > 9) {
      digit = 9;  // insurance
    }
    *out++ = (char)('0' | digit);
    if ((digitcount == prec) && (prec > 0)) {
      *out++ = '.';
    }
    number -= digit;
    number *= 10.0;
  }
  // make sure the string is terminated
  *out = 0;
  return s;
}

ed al fondo scrive lo 0 (// make sure the string is terminated)

Su esp32 dovrebbe funzionare snprintf() con i double (non funziona su avr per la grande occupazione di memoria codice la gestione dei double nella printf, perciò han creato la dtostrf)
snprintf(buf, sizeof(buf), "%5.2f", d); //max 10 con terminatore

Non saprei dire, purtroppo C/Arduino ultimamente li sto usando molto poco quindi sono arrugginito.

In ogni caso io mando un payload e lo divido per mille e lo inserisco in indata

dtostrf(lastPayload.time/1000.0, 0, 3, indata);

In ogni caso (che lo inizializzi con 6 o 7 char) se faccio un print di indata vedo un carattere strano in coda e se lo uso per lvgl così com’è, in combinazione alla scelta dello stile con array, mi printa cose strane.

In effetti se uso semplicemente il puntatore di stile o una variabile contenente esso nessun problema.

Se però vado a forzare il terminatore sovrascrivendo l’ultimo carattere, il quadratino vuoto che vedevo con print sparisce e funziona in tutti i casi con lvgl…

La sensazione, che avevo fin dall’inizio, è che per qualche motivo finisca a scrivere su registri limitrofi in qualche condizione.
Perché con questa ‘combinazione’ di casistiche non lo so dire