Apertura file da SD fallito

Ciao a tutti! Sto realizzando uno sketch che servirà poi a controllare un climatizzatore da remoto.
La gestione delle pagine html salvate su SD avviene tramite lo sketch qui presente che tuttavia fallisce nel momento in cui

htmlFile = SD.open("index.htm")

ritorna un valore false.

Ho già preso spunto da:

e da altri articoli/blog che trattano di questo argomento..
Spero di non aver troppi casini..
Se poteste dargli un'occhiata ve ne sarei molto grato :slight_smile:
Grazie :slight_smile:

#include <SPI.h>        //Si inizia con la dichiarazione delle librerie
#include <Ethernet.h>   //utili allo scopo
#include <SD.h>

byte MAC[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };  //Si dichiara il MAC address
byte IP[] = { 192, 168, 1, 20 };                       //unico per ogni utente e l'IP
                                                      //che gli diamo noi
                                                      
EthernetClient client;   //Si definisce una variabile EthernetClient di nome client
EthernetServer server(80);    //Fa si che Arduino sia in ascolto sulla porta 80
String query = "";            //Definisco una variabile String per memorizzare la mia chiave
File htmlFile;            //Si definisce una variabile "File" della libreria SD.h
boolean currentLineIsBlank;
boolean index = true;

void setup()
 {
   query = String("");
   Serial.begin(9600);  //Scelgo di inizializzare la comunicazione seriale (facoltativo)
   Serial.println("Inizializzazione SD Card..."); //Scritta di "rito"
   if (!SD.begin(4))    //Inizializzo la SD card sul pin 4 (CS=Card Select)
    {                  //Se (SD.begin!=4) ovvero che non legge la SD sul pin 4 allora
                        // fallisce l'inizializzazione altrimenti riesce
      Serial.println("Inizializzazione SD fallita!");
      return;
    }
   else
    {
      Serial.println("Inizializzazione SD riuscita!");    
    }
   Ethernet.begin(MAC,IP);    //Inizializzo la comunicazione ethernet passando
   server.begin();            //MAC e IP e avvio il server
 }

void loop()
 {
   //Ascolto client in arrivo
  client = server.available(); // memorizzi la presenza di una richiesta da 
                               // parte di un Client Web in client, in pratica quando dal 
                               // tuo browser ti collegherai all’interfaccia web, 
                               // Arduino riceverà una richiesta di tipo Client che 
                               // puoi leggere con il metodo available() della 
                               // classe server
  if(client)  // leggi se la variabile client contiene una richiesta da parte di un browser 
              // allora esegue ciò che è indicato nelle linee successive;
    {
      Serial.println("Nuovo client"); //Dimmi che c'è il client
      currentLineIsBlank = true; //Utilizzata dopo
      while (client.connected()) // inizia un ciclo impostato sulla presenza di una connessione 
                                 // da parte di un browser web, tale verifica ti evita di far 
                                 // elaborazioni durante l’assenza di connessione;
        {
          if(client.available())  //verifica che la connessione oltre ad essere presente sia 
                                  // anche utilizzabile;
            {
              char c = client.read();  // leggi il valore inviato dal client con il metodo read() 
                                       // dell’oggetto client assegnalo ad una variabile di tipo char;
              query.concat(c);
              if(c=='\n' &&currentLineIsBlank)  // verifica che il carattere c letto sia un “\n” (new line) 
                                                // e che contemporaneamente la variabile current_line_is_blank  
                                                // sia settata a true
                {
                  // Invio header standard di risposta
                  client.println("HTTP/1.1 200 OK");
                  client.println("Content-Type: text/html");
                  client.println("Connnessione: close");
                  client.println();
                  Serial.println("Caricamento pagina sul server...");
                  Serial.print("Stringa query: ");
                  Serial.println(query);
                  if( index == true ){
                  Serial.println("Aperto index.htm");
                  htmlFile = SD.open("index.htm");  //Apro il file con il metodo 'open'
                  index = false;
                  }                                  // della classe SD
                  if(query == "index2.htm"){
                  Serial.println("Aperto index2.htm");
                  htmlFile = SD.open("index2.htm");  //Apro il file con il metodo 'open'
                  }                                  // della classe SD
                  if (htmlFile)                     // Se l'apertura è riuscita...
                    {
                      Serial.println("Apertura riuscita");
                      while (htmlFile.available())  //Finchè l'apertura del file è valida...
                        {  
                          Serial.println("File HTML valido e caricato");
                          client.write(htmlFile.read()); // Stampo sul server il file contenuto su SD
                                                         // tramite il metodo read (File.read())
                        }
                  htmlFile.close();  //chiudo il file su SD
                    }
                  else
                      {
                        Serial.println("Apertura fallita");
                      }        
                  query = String("");
                  break;   //fondamentale per evitare loop
                }
          if (c == '\n') 
          {
            currentLineIsBlank = true;
          }
          else if (c != '\r')   
          {
            currentLineIsBlank = false;
          }
       }
     }
     delay(100);
     client.stop();
     Serial.println("Client disconnesso");
     index = true;
    }
   }

Se provi gli esempi tipo ReadWrite funzionano senza problemi?

simonenascivera:
Se provi gli esempi tipo ReadWrite funzionano senza problemi?

Si funzionano quegli esempi :frowning:

Sbagli qui

if(query == "index2.htm")

hai fatto un serialprint di query in questa linea

Serial.println(query);

quindi avrai notato che è composta da una vasta quantità di caratteri simile a questa, anche se ci sono degli "a capo" (\n) la stringa è unica

GET /page2.htm HTTP/1.1
Host: 192.168.1.20
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:19.0) Gecko/20100101 Firefox/19.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-ZA,en-GB;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http:// 192.168.1.20/
Connection: keep-alive

perciò non potrà mai essere == "index2.htm"

se usi indexof e cerchi solo la stringa "index2.htm" il return della funzione restituisce un valore diveso da -1 se è presente l'intera stringa di ricerca.

non so perchè usi

boolean index = true;

ma se ti studi indexof puoi caricare il file senza troppe complicazioni true/false
ciao

pablos:
Sbagli qui

if(query == "index2.htm")

hai fatto un serialprint di query in questa linea

Serial.println(query);

quindi avrai notato che è composta da una vasta quantità di caratteri simile a questa, anche se ci sono degli "a capo" (\n) la stringa è unica

GET /page2.htm HTTP/1.1
Host: 192.168.1.20
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:19.0) Gecko/20100101 Firefox/19.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-ZA,en-GB;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http:// 192.168.1.20/
Connection: keep-alive

perciò non potrà mai essere == "index2.htm"

se usi indexof e cerchi solo la stringa "index2.htm" il return della funzione restituisce un valore diveso da -1 se è presente l'intera stringa di ricerca.

non so perchè usi

boolean index = true;

ma se ti studi indexof puoi caricare il file senza troppe complicazioni true/false
ciao

Eccola lì la cavolata... :frowning: domani provo e ti faccio sapere!
Grazie mille pablos!!!

Prego, figurati

Prima che cominci, non dimenticare di tener presente 2 cose

  1. siccome quella stringa è molto lunga e la memoria del 328 non è molto disponibile, intercetta lo "\n" per spezzare l'intera stringa
  2. ricordati di azzerare query alla fine della ricerca anche parziale
query ="" ;

es:
cerca in questa ... GET /page2.htm HTTP/1.1
azzera query
cerca in questa ... Host: 192.168.1.20
azzera query
cerca in questa ... User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:19.0) Gecko/20100101 Firefox/19.0
azzera query
...
...
...
Questo metodo, può nell'utilizzo avanzato delle query, permetterti di fare moltre altre cose come analizzare il sistema operativo che usa chi chiama arduino, credenziali criptate tipo username e password, paese ecc ecc

pablos:
Prego, figurati

Prima che cominci, non dimenticare di tener presente 2 cose

  1. siccome quella stringa è molto lunga e la memoria del 328 non è molto disponibile, intercetta lo "\n" per spezzare l'intera stringa
  2. ricordati di azzerare query alla fine della ricerca
query ="" ;

es:
cerca in questa GET /page2.htm HTTP/1.1
azzera query
cerca in questa Host: 192.168.1.20
azzera query
cerca in questa
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:19.0) Gecko/20100101 Firefox/19.0
azzera query
...
...
...

Però alla fine devo cercare solo nella prima riga giusto?
Nel mio sketch sostanzialmente elaboravo la stringa come unica e poi facevo la ricerca dell' "index.htm"...
Un altro metodo potrebbe essere utilizzare un array di char come indicato nel primo link che ho postato... a quel punto non dovrei avere problemi di over-RAM.. sbaglio?

si, esatto:)
però anche se hai trovato la stringa che ti interessa alla prima linea, devi lasciar andare la negoziazione, non puoi uscire quando ti pare altrimenti client e server non si capiranno.
Quello che voglio dire è .... alla fine la ricerca verrà fatta su tutte le linee, il query deve arrivare tutto, il termine è dato da \r\n ... se il pacchetto query non arriva completo il client se ne accorge e ti chiude in faccia la porta perchè non lo hai ascoltato
detto in modo molto grottesco :slight_smile:

Il tuo indexof lo puo fare anche nel blocco completo [query.concat(c);] però metti a rischio la stabilità del micro con problemi di over-RAM
Sta a te scegliere la migliore strada in base a quello che il micro deve fare oltre che a leggere le query nel tuo progetto

Una via, impegna meno RAM ma fa più calcoli
L'altra via impegna più RAM e fa meno calcoli

pablos:
si, esatto:)
però anche se hai trovato la stringa che ti interessa alla prima linea, devi lasciar andare la negoziazione, non puoi uscire quando ti pare altrimenti client e server non si capiranno.
Quello che voglio dire è .... alla fine la ricerca verrà fatta su tutte le linee, il query deve arrivare tutto, il termine è dato da \r\n ... se il pacchetto query non arriva completo il client se ne accorge e ti chiude in faccia la porta perchè non lo hai ascoltato
detto in modo molto grottesco :slight_smile:

Aaaaa capito!
Grazie per l'utile lezione serale :slight_smile: ti saluto e ti auguro una buona serata! Ci aggiorniamo domani :wink:

pablos:
si, esatto:)
però anche se hai trovato la stringa che ti interessa alla prima linea, devi lasciar andare la negoziazione, non puoi uscire quando ti pare altrimenti client e server non si capiranno.
Quello che voglio dire è .... alla fine la ricerca verrà fatta su tutte le linee, il query deve arrivare tutto, il termine è dato da \r\n ... se il pacchetto query non arriva completo il client se ne accorge e ti chiude in faccia la porta perchè non lo hai ascoltato
detto in modo molto grottesco :slight_smile:

Il tuo indexof lo puo fare anche nel blocco completo [query.concat(c);] però metti a rischio la stabilità del micro con problemi di over-RAM
Sta a te scegliere la migliore strada in base a quello che il micro deve fare oltre che a leggere le query nel tuo progetto

Una via, impegna meno RAM ma fa più calcoli
L'altra via impegna più RAM e fa meno calcoli

Aggiornamento in itinere:

Ho testato il codice SENZA analizzare la query riga per riga e il problema si ripresenta nello stesso modo.
A questo punto ho provato la RAM alloccata alla fine del processo e risulta intorno a 1270 kB... A questo punto penso ci sia un sovraccarico di RAM nella fase di ricerca della parola chiave e/o di memorizzazione della "query". Che ne dici?

if(query.indexOf(' GET / ')>0)
                  {
                  Serial.println("Caricato index.htm in htmlFile");
                  htmlFile = SD.open("index.htm");  //Apro il file con il metodo 'open'
                  index = false;
                  }                                  // della classe SD
                  if( query.indexOf(' GET/index2.htm ') >0 )
                  {
                  Serial.println("Caricato index2.htm in htmlFile");
                  htmlFile = SD.open("index2.htm");  //Apro il file con il metodo 'open'
                  }                                  // della classe SD
                  if (htmlFile)                     // Se l'apertura è riuscita...
                    {
                      Serial.println("Caricamento riuscito");
                      while (htmlFile.available())  //Finchè l'apertura del file è valida...
                        {  
                          Serial.println("File HTML valido e caricato");
                          client.write(htmlFile.read()); // Stampo sul server il file contenuto su SD
                                                         // tramite il metodo read (File.read())
                        }
                  htmlFile.close();  //chiudo il file su SD
                  Serial.println("File chiuso");
                    }
                  else
                      {
                        Serial.println("Caricamento fallito");
                      }

scusa, fammi capire cosa vuoi fare:

Vuoi caricare una pagina fissa quando ti colleghi al server o vuoi poter caricare qualsiasi file è scritto sulla GET query?
Nel secondo caso è un po' più complicato, va fatto un parse della GET per estrarre il nome del file e l'estensione, va poi preparato il client a ricevere quel tipo di file

client.println("Content-Type: text/html"); // per file tipo hml
client.println("Content-Type: image/jpeg"); // per immagini tipo jpeg
client.println("Content-Type: image/gif");// per immagini tipo gif
client.println("Content-Type: application/x-javascript");// per file tipo js
client.println("Content-Type: text"); //per file tipo text

Quello che vorrei fare è:

  • Avere a disposizione una pagina HTML che è la index.htm dell'allegato (molto simile a una pagina già presente su questo forum)
  • Quando clicco su una delle immagini deve aprirsi una seconda pagina HTML che mi dia la possibilità di selezionare la temperatura
  • Quando clicco sulla temperatura si dovrà aprire una terza pagina in cui seleziono la velocità della ventola

La terza pagina non la ho ancora realizzata mentre le prime due sì e sono diverse a seconda che io selezioni "cold" o "heat"
Secondo te qual'è il modo migliore per realizzare ciò? Tenendo conto che tutti i passaggi devono essere memorizzati in delle variabili così poi da selezionare il percorso corretto e inviare il segnale IR voluto :slight_smile:
Grazie
PS Non vedrai le immagini della index2.htm e index3.htm ma sono delle semplici scritte in Wordart :smiley:

index.htm (980 Bytes)

index2.htm (652 Bytes)

index3.htm (644 Bytes)

Risolto... era un problema di SRAM :frowning: ho eliminato l'uso della libreria "String.h" e ho utilizzato array di char e funzioni per azzerare array e funziona tutto :slight_smile: ora devo solamente hostare le immagini sul web perchè Arduino non riesce a caricarle dalla SD e ho risolto :slight_smile:

A chi dovesse interessare: La soluzione l'ho trovata sul primo link del primo post che ho pubblicato :slight_smile:

Grazie mille per l'aiuto! Buon appetito e buona domenica :slight_smile: