Organizzare dati: cicli while e funzioni stringa

Ciao,
Finora sono riuscito a memorizzarmi i dati nella SD, scrivendo più file organizzati per contenuti.
Ora il problema è ciclarli e organizzarli a mio piacimento.
Ovviamente scrivo perchè dopo qualche prova, non riesco ad ottenere risultati! Posto un blocco del codice per capire

 FileProg = SD.open(nomeFile.txt);
  if (FileProg) {
    while (FileProg.available()) {
      Serial.write(FileProg.read());
    }
  
    FileProg.close();
  }

Fino a questo punto ci saimo, ottengo sul monitor seriale il contenuto del file, ma se io voglio verificare che all'interno del file ci siano degli argomenti specifici? Facciamo un esempio concreto.
All'interno del nomeFile.txt ci sono memorizzate le seguenti righe:
SB20X600X1200,
AD40X1000X1200,
PLUS60X3000X1200,

FileProg.read() mi restituisce correttamente il contenuto ma se io voglio rilevare tramite appositi sensori le caratteristiche del prodotto che transita nella linea di produzione, senza entrare in merito ai controlli dei sensori, uno di questi mi rileva ad esempio "SB", devo confrontare se nel programma scritto dall'operatore (contenuto nella SD quindi nel file nomeFile.txt) il prodotto sia presente tradotto nel codice:

Sring type;
type = "SB"; //questa variabile viene valorizzata dal sensore
 FileProg = SD.open(nomeFile.txt);
  if (FileProg) {
    while (FileProg.available()) {
      Serial.write(FileProg.read());
if((strpos(FileProg.read(),type)) !== FALSE) {
//se trovo corrispondenza faccio altri controlli
}
else{tft.print("messaggio di errore");}

    }
  
    FileProg.close();
  }

Questo uno dei tentativi, un'alto ho provato con un ciclo while in questa maniera:

Sring type;
type = "SB"; //questa variabile viene valorizzata dal sensore
 FileProg = SD.open(nomeFile.txt);
  if (FileProg) {
    while (FileProg.available()) {
      Serial.write(FileProg.read());
while(FileProg.read()==type){
//se trovo corrispondenza faccio altri controlli
}
else{tft.print("messaggio di errore");}
    }
  
    FileProg.close();
  }

Attendo cordiale riscontro.
Maurizio Filomeni

Aspetta, vediamo se ho capito
Tu hai un file, che contiene, ad esempio delle righe, con scritto un identificatore
Ti arriva da un sensore una stringa
Vuoi vedere se quella stringa c'è tra gli identificatori
Magari se c'è vuoi sapere cosa c'è scritto nel resto della riga?
Alcuni mesi fa avevo scritto un post su un argomento simile
Credo si intitolasse "ti cerco ti trovo ma non riesco a toglierti" o qualcosa del genere
Prova a vedere lì se trovi ispirazione

filomeni:
uno di questi mi rileva ad esempio "SB", devo confrontare se nel programma scritto dall'operatore (contenuto nella SD quindi nel file nomeFile.txt) il prodotto sia presente

Beh intanto da questa prima occhiata, non essendoci alcun separatore tra codice prodotto e caratteristiche (ricordo l'altro thread dove cercavi di usare nomi di file lunghi...), la prima domanda è: sei sicuro che i codici prodotto non siano in sovrapposizione? Ossia, se esiste "SB" non è che i caratteri "SB" sono contenuti anche in altri prodotti, come "SBPIPPO" o "SBY"?
Perché se tu verifichi solamente se in ogni riga è presente, corri questo rischio di interpretare una cosa per l'altra...

Visto che parliamo quindi di dati, perché non usi un semplice separatore per i vari campi (che sono comunque posizionali)? Di fatto per le caratteristiche (dimensioni) hai già la "X", aggiungi un separatore anche dopo il codice prodotto e stai più al riparo da errori, ad esempio una virgola (e magari a questo punto usata per tutti gli altri campi del record, di fatto un "comma delimited" o CSV...).

Inoltre tu lì fai 2 volte la .read(), ed il secondo è quello che confronti, per cui consideri un carattere si ed uno no...

La .read() legge un carattere, quindi devi accumulare i caratteri dentro ad un buffer, fino a che non incontri il terminatore (solitamente LF ossia 0x10).

Poi resta anche il solito consiglio: MAI usare la classe String!

Per cui il file dovrebbe contenere semplicemente:

SB,20,600,1200
AD,40,1000,1200
PLUS,60,3000,1200

e con un semplice parse (strtok) estrai i campi, o quantomeno inizi dal primo.
Il codice diventa una cosa del genere (scritto al volo, non ti assicuro che funzioni ma è la base per leggere i file dalla SD):

  char type[20];
  type = "SB"; //questa variabile viene valorizzata dal sensore

  char buf[128]; // buffer di linea
  
  File FileProg = SD.open("nomeFile.txt");
  if (FileProg) {
    int i=0;
    char c;
    while (FileProg.available()) {
      c = FileProg.read();
      if ( c == '\r' )
        break;
      buf[i++] = c;
    }
    Serial.println(buf);
    char * code = strtok(buf,",");
    if( strcmp(code, type) == 0) {
        //se trovo corrispondenza faccio altri controlli
    }
    FileProg.close();
  else {
    // errore!!!
  }
}

Io concordo con docdoc, nella teoria in pieno
Nella pratica poco meno, io separerei l'estrazione dei dati dal loro riconoscimento
Inoltre io preferisco trattare flussi, non blocchi precostituiti
Farei una funzione che apre il file e restituisce l'intera riga cercata
Una seconda funzione, che a file chiuso tratta le informazioni della riga

Standardoil:
Farei una funzione che apre il file e restituisce l'intera riga cercata
Una seconda funzione, che a file chiuso tratta le informazioni della riga

Beh in pratica è quello che facevo :wink: ossia il codice che ho messo legge il file e "si ferma" non appena rileva il codice cercato, quindi basta farne una funzione che, dopo aver trovato la riga col codice (passato a parametro) ne restituisce la riga con i dati (o stringa nulla per dire che non ha trovato il codice nel file). Il chiamante poi elabora la cosa come meglio crede.

Io e te siamo spesso d'accordo...
Anche adesso

Dunque, ora sono arrivato ad ottenere il file nella SD come consigliato:

SB,20,600,1200
AD,40,1000,1200
PLUS,60,3000,1200

Però seguendo poi il codice mi retituisce errore alla compilazione:
incompatible types in assignment of 'const char [3]' to 'char [20]'
Riferito a:
type = "SB"; //questa variabile viene valorizzata dal sensore

Ho provato a smanettare un pò con scarsi risultati!
Faccio una gran fatica a seguire la "filosofia" del MAI usare le stringhe proveniendo da programmazione php...
Abbi pazienza :wink:

Non puoi usare così una stringa, devi modificarla elemento per elemento, sempre (tranne, unica eccezione, in fase di creazione). Per il resto devi sempre chiamare un elemento alla volta, con relativo numero.
Esempio:

//dichuarazione di stringa
char nomestringa [lunghezzastringa]="contenuto iniziale stringa";
//richiamare un elemento
nomestringa [numeroelemento]
//usare questa forma in ogni punto in cui serve usare la stringa
//mumeroelemento può essere anche una variabile, e per ciò si consiglia di usare cicli for
//ricordarsi che alla creazione di una stringa é stato allocato lo spazio richiesto, e gli spazi successivi sono in uso.
//ma non é possibile (almeno non in modo sicuro) coniscere la lunghezza di tale spazio da programma.
//quindi ricordarsela, prima di andare a leggere (o a scrivere) dove non si dovrebbe.
//il primo carattere della stringa é il numero 0

Silente:
//ricordarsi che alla creazione di una stringa é stato allocato lo spazio richiesto, e gli spazi successivi sono in uso.
//ma non é possibile (almeno non in modo sicuro) coniscere la lunghezza di tale spazio da programma.

... ne sei sicuro? ... e secondo te la funzione strlen() a cosa serve? :smiling_imp:

Guglielmo

Il tipo 'stringa di c' non esiste, quindi non si possono fare comparazioni, eguaglianze, assegnazioni etc etc
Stringa di c è un array di caratteri, lo devi trattare elemento per elemento
Se devi scriverci "ab" devi mettere a in casella 0, b in casella 1 e via così
Per questo sono state create funzioni che ti semplificano la vita, in particolare
strcpy(type,"ab")
copia carattere per carattere da "ab" dentro in type

Cari miei! Benedetto PHP... Pian piano mi sto rendendo conto senza averne avuto esplicita spiegazione quanto il c++ non digerisca le "lettere".
Beh! imparerò pian piano la struttura del c++ e cosa debba fare per gestire piccoli dati stringa.
Certo, come mi è stato consigliato in un'altro post (anche da Guglielmo), e capisco sempre più il motivo, di utilizzare altro hardware per il mio scopo, dovessi intraprendere un'altro progetto simile sicuramente non mi rivolgerò ad Arduino...
Comunque la mia natura mi porta ora a risovere comunque il problema e portare a compimento il progetto con il meraviglioso mondo di Arduino...
Credo che a questo punto dovrei aprire un'altro post per chiedere delle lezioni sulle stringhe per Arduino... :wink:
Grazie comunque a tutti coloro che sono intervenuti.
Filomeni Maurizio

filomeni:
Credo che a questo punto dovrei aprire un’altro post per chiedere delle lezioni sulle stringhe per Arduino… :wink:

Non credo … :smiling_imp:

… le stringhe classiche del ‘C’ sono solo dei semplici array di char terminati dal carattere null (0x00) gestibili facilmente con le funzioni che trovi nella libreria standard (… che, oltretutto, è automaticamente inclusa dal IDE) AVR libc ed, in particolare, quanto è in <string.h> :wink:

Guglielmo

Il problema non è il C++, è che stai lavorando su una piattaforma embedded ridotta ai minimi termini nella quale le risorse sono estremamente preziose, e l'allocazione dinamica è un lusso che non ti puoi permettere.

Infatti in C ci sono tutte le funzioni per manipolare le stringhe che trovi anche nella classe String del C++, per quanto mi sembri che questo non sia chiaro a tutti quelli a cui consigliamo di orientarsi verso le prime. L'unica grande differenza è che, essendo sconsigliato fare allocazione dinamica su Arduino, devi stabilire a priori la dimensione massima di ogni stringa, cosa che sembra sconvolgere totalmente i più.

gpb01:
Non credo … :smiling_imp:

… le stringhe classiche del ‘C’ sono solo dei semplici array di char terminati dal carattere null (0x00) gestibili facilmente con le funzioni che trovi nella libreria standard (… che, oltretutto, è automaticamente inclusa dal IDE) AVR libc ed, in particolare, quanto è in <string.h> :wink:

Guglielmo

nel mio IDE non c’è 1.8.7

accipicchia, un problema piuttosto grave,
comunque non è difficile ri-scriversi tutte le funzioni che ti servono, basta cercare sulla grande rete "string.h", e vedere come sono fatte
comunque: una volta scritta una.... le altre sono sempre la stessa minestra....

(... che, oltretutto, è automaticamente inclusa dal IDE)

se è inclusa automaticamente, c'è senza bisogno di... "includerla" :wink:

filomeni:
nel mio IDE non c'è 1.8.7

Aggiorna l'IDE all'ultima versione 1.8.7. Le librerie (core) sono un'altra cosa. Mi pare sia 1.6.22

Ok, allora non apro un nuovo post e continuo qui…
Essndomi “incaponito” con le Stringhe, ho fatto delle prove con la funzione indexOf() che mi sembra quella che si avvicina più alle mie esigenze e ho scritto:

//apro il file
FileProg = SD.open(nomeFile + ext);
          if (FileProg) {
            while (FileProg.available()) {
              String c;
              c = FileProg.read();
              String t;
              String type;
              type="CC";//la variabile viene valorizzata da un sensore
              t=c.indexOf(type);
              //controllo il valore restituito dalla funzione
              Serial.print(t);
            }
           FileProg.close();
          }

La funzione indexOf() mi restituisce sempre -1 quindi non trova il valore “CC” nel file. Ma in realtà il valore è presente, comunque ho fatto svariate prove e il risultato è sempre -1.
Boh!!!

nid69ita:
Aggiorna l'IDE all'ultima versione 1.8.7. Le librerie (core) sono un'altra cosa. Mi pare sia 1.6.22

ho l'ultima 1.8.7

'scolta me...
che tu "voglia" usare la classe String, pur essendoti stata sconsigliata, già è strano
ma che tu lo voglia fare "senza" studiare quello che stai facendo è pure "storto"
Lo sai cosa stai facendo?
secondo te questa riga:

c = FileProg.read();

cosa fa?
giusto per non rischiare che tu faccia come quell'altro, che alla domanda di cosa stava facendo mi rispondeva cosa "voleva" fare: lo hai letto il reference della read?
questa poi è pura poesia:

              String t;
              t=c.indexOf(type);

cioè: ottieni un indirizzo (si, vabbe' dai, un indice) e lo converti in stringa?
e come lo useresti dopo, giusto per saperlo?
a proposito, ma sei andato a vedere come io faccio le stesse cose nel "ti metto, ti trovo, ti cerco"...
insomma quel post che ti ho consigliato di leggere?