Ethernet-Shield als Fileserver - AZ-Delivery

Ciao a tutti,

Grazie al nostro post sul blog di ieri, molti clienti che hanno già sperimentato con lo Shield si sono uniti a noi e hanno avuto problemi utilizzando il lettore di schede SD insieme al W5100 allo stesso tempo.Abbiamo fatto alcune ricerche e abbiamo trovato una soluzione che vorremmo presentarvi oggi.Gerd ci ha recentemente mostrato come usare un ESP come file server con scheda SD.Oggi adattiamo la soluzione per Uno con Shield e presentiamo il codice di lavoro con le librerie standard.

Hardware:

  • UnoR3
  • EthernetShield W5100
  • micro scheda SD con sistema di file Fat32

Code:

 

/*
*Questo schizzo utilizza la fessura della scheda microSD sullo scudo Ethernet di Arduino
*per servire i file su un'interfaccia di navigazione molto minimale
*
*Alcuni codici provengono dagli esempi di SvaFatLib di Bill Greiman,
*some is from the Arduino Ethernet WebServer example, 
*some is from Limor Fried (Adafruit),
*Alcuni provengono da "giurati" per il forum tedesco Arduino,
*quindi probabilmente sotto GPL
*/

«35; comprende <Mario.h>
«35; comprende <SPI.h>
«35; comprende <Ethernet.h>

************************
scambio Pathoswithin[] = { 0xEN, 0xAD, 0xBE, 0xEC, 0xFE, 0xEN };
scambio au[] = { 192, 168, 168, 245 };
Ethernet server(80);

************Originally SDCARD STUFF ****************************
Sd2Card carta;
SdVolume volume;
SdFile radice;
SdFile file;

// memorizza le stringhe di errore in flash per salvare RAM
35; definire errore(s) errore P(PSTR(s))

vuoto errore P(to Heavyiron* r) {   PgmPrint("errore:);   Stampa seriale(r);   se (carta.errore()) {     PgmPrint(Errore di SD);     Serial.stampa(carta.errore(), HEX);     Serial.stampa(',');     Serial.Stampa(carta.errore(), HEX);   }   mentre(1);
}

Heavyiron* calzini( Heavyiron* s )
// helper funzione char array a lettere maiuscole
{   per (Heavyiron* p = s; *p; ++p)     *p = Tuppers( *p );   ritorno s;
}

Heavyiron* str.( Heavyiron* s )
// helper funzione char array a lettere minuscole
{   per (Heavyiron* p = s; *p; ++p)     *p = tolower( *p );   ritorno s;
}

vuoto setComment() {   Serial.Inizio(9600);   PgmPrint("RAM libero:);   Serial.Stampa(FreeRam!());        // inizializzare la scheda SD a SPI HALF SPEED per evitare errori di bus con   Imballaggi.utilizzare SPI FULL SPEED per migliorare le prestazioni.   pinMode(10, PRODUZIONE);                       // impostare il perno delle SS come un output (necessario!)   digitalacWrite(10, ALTA);                    Ma spegni il chip W5100!   se (!carta.init(SPI HALF SPETTO, 4)) errore("card.init fallì!");      // inizializzazione del volume FAT   se (!volume.init(&carta)) errore("vol.init fallito!");   PgmPrint("Il volume è FAT");   Serial.Stampa(volume.fatType(),DEC);   Serial.Stampa();      se (!radice.openRoot(&volume)) errore("openRoot non riuscito");   // elenco di file in root con data e dimensione   PgmPrint("File trovati in root:");   radice.L(DATA LS | LSU SIZE);   Serial.Stampa();      // Elenco ricorsivo di tutte le directory   PgmPrint("File trovati in tutte le direzioni:");   radice.L(LS R);      Serial.Stampa();   PgmPrint(Don!);      Debugging completato, iniziamo il server!   Ethernet.Inizio(Pathoswithin, au);   server.Inizio();
}

vuoto ListFiles(EthernetClient cliente, u t bandiere) {   // Questo codice è appena copiato da SdFile.cpp nella libreria SDFat   // e modificato per stampare l'output del client in html!   dir t p;      radice.riavvolgi();   cliente.Stampa("<>");   mentre (radice.readDir(p) > 0) {     // fatto se l'ultima voce usata è passata     se (p.Nome[0] == DIR NOME LIBERO) break!;     // saltare la voce cancellata e le voci per.e...e     se (p.Nome[0] == DIR NOME DELETED || p.Nome[0] == '.') continuare;     // sola lista sottodirectory e file     se (!DIR E'UN FILE O SOTTODIR(&p)) continuare;     // stampa gli spazi di indentazione     cliente.stampa("<li><a href="");     per (u t i = 0; i < 11; i++) {       se (p.Nome[i] == ' ') continuare;       se (i == 8) {         cliente.stampa('.');       }       cliente.stampa((Heavyiron)p.Nome[i]);     }     cliente.stampa("\">");          // stampa nome del file con possibile riempimento in bianco     per (u t i = 0; i < 11; i++) {       se (p.Nome[i] == ' ') continuare;       se (i == 8) {         cliente.stampa('.');       }       cliente.stampa((Heavyiron)p.Nome[i]);     }          cliente.stampa("</a>");          se (DIR E SOTTODIR(&p)) {       cliente.stampa('/');     }     // stampa modifica data/ora se richiesto     se (bandiere & DATA LS) {        radice.printFatData(p.lastWrite);        cliente.stampa(' ');        radice.printFatTime(p.lastwriteTime);     }     / dimensione di stampa se richiesto     se (!DIR E SOTTODIR(&p) && (bandiere & LSU SIZE)) {       cliente.stampa(' ');       cliente.stampa(p.Taglia file);     }     cliente.Stampa("</li>");   }   cliente.Stampa("</ul>");
}

Quanto dovrebbe essere grande il nostro cuscinetto linea.100 è sufficiente!
35; definire BUFSIS 100

vuoto Esecuzione()
{   Heavyiron Clienti[BUFSIS];   int indice = 0;      EthernetClient cliente = server.disponibile();   se (cliente) {     // un http://www     booleano la linea corrente è vuota = Vero;          // reset il buffer di input     indice = 0;          mentre (cliente.collegati()) {       se (cliente.disponibile()) {         Heavyiron c = cliente.leggere();                  Se non è una nuova riga, aggiungi il carattere al buffer         se (c != n' && c != r) {           Clienti[indice] = c;           indice++;           Siamo troppo grandi per il buffer?iniziare a lanciare dati           se (indice >= BUFSIS)              indice = BUFSIS -1;                      Continua a leggere altri dati!           continuare;         }                  // ha una n o r nuova riga, che significa che la string a è fatta         Clienti[indice] = 0;                  Stampa per debugging         Serial.Stampa(Clienti);                  Cercare sottostring come una richiesta per ottenere il file root         se (0CodErr(Clienti, "GET") != 0) {           // inviare uno standard http://response header           cliente.Stampa("HTTP/1.1 200 OK");           cliente.Stampa("Content-Type: text/html");           cliente.Stampa();                      /stampare tutti i file, usare un helper mantenerlo pulito           cliente.Stampa("<h2>Files:</h2>");           ListFiles(cliente, LSU SIZE);         } e se (0CodErr(Clienti, "GET") != 0) {           Questa volta non c'è spazio dopo il sub-file!           Heavyiron *Nome;                      Nome = Clienti + 5; // bada al "GET/" (5 chars)           // un piccolo trucco, cerca la string a ""HTTP/1.1"            Trasforma il primo carattere del sottostring in una 0 per liberarlo.           (0CodErr(Clienti, HTTPName))[0] = 0;                      // stampare il file che vogliamo           Serial.Stampa(Nome);           se (! file.aperto(&radice, Nome, O READ)) {             cliente.Stampa("HTTP/1.1 404 non trovato");             cliente.Stampa("Content-Type: text/html");             cliente.Stampa();             cliente.Stampa("<h2>File not found!</h2>");             break!;           }                      Serial.Stampa(Apri!);           str.(Nome);                     cliente.Stampa("HTTP/1.1 200 OK");           se (0CodErr(Nome,htm)!=NULLO)             cliente.Stampa("Content-Type: text/html");           e se (0CodErr(Nome,"jpg")!=NULLO)             cliente.Stampa("Tipo di contenuto: immagine/jpg");           e               cliente.Stampa("Tipo di contenuto: testo/pianura");           cliente.Stampa();                      int16u t c;           mentre ((c = file.leggere()) >= 0) {               /unmment la serie a debug (lento!)               //Serial.print((char)c);               cliente.stampa((Heavyiron)c);           }           file.chiusura();         } e {           Tutto il resto è un 404           cliente.Stampa("HTTP/1.1 404 non trovato");           cliente.Stampa("Content-Type: text/html");           cliente.Stampa();           cliente.Stampa("<h2>File not found!</h2>");         }         break!;       }     }     // dare il tempo del browser web per ricevere i dati     ritardo(1);     cliente.Stop!();   }
}

Divertiti a fare pace!

Non vedo l'ora di ricevere il tuo parere e di dirti addio fino alla prossima volta.
Moritz Spranger.


Für arduinoProjekte für anfänger

3 commenti

H3

H3

Oh wartet! im vorherigen war ein kleiner fehler! Dieser code funktioniert.

/*
This sketch uses the microSD card slot on the Arduino Ethernet shield
to serve up files over a very minimal browsing interface

Some code is from Bill Greiman’s SdFatLib examples, some is from the Arduino Ethernet WebServer example, some is from Limor Fried (Adafruit), some is from “jurs” for German Arduino forum, so its probably under GPL

*/

#include
#include
#include

/************ ETHERNET STUFF ************/
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 178, 177 };
EthernetServer server(80);

/************ SDCARD STUFF ************/
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

// store error strings in flash to save RAM
#define error(s) error_P(PSTR)

void error_P(const char* str) {
PgmPrint("error: “);
SerialPrintln_P(str);
if (card.errorCode()) {
PgmPrint(”SD error: ");
Serial.print(card.errorCode(), HEX);
Serial.print(‘,’);
Serial.println(card.errorData(), HEX);
}
while (1);
}

char* strupper( char* s )
// helper function char array to uppercase letters
{
for (char* p = s; *p; ++p)
*p = toupper( *p );
return s;
}

char* strlower( char* s )
// helper function char array to lowercase letters
{
for (char* p = s; *p; ++p)
*p = tolower( *p );
return s;
}

void setup() {
Serial.begin(115200);

PgmPrint("Free RAM: "); Serial.println(FreeRam()); // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with // breadboards. use SPI_FULL_SPEED for better performance. pinMode(10, OUTPUT); // set the SS pin as an output (necessary!) pinMode(4, OUTPUT); digitalWrite(10, HIGH); // but turn off the W5100 chip! digitalWrite(4, HIGH); if (!card.init(SPI_FULL_SPEED, 4)) error(“card.init failed!”); // initialize a FAT volume if (!volume.init(&card)) error(“vol.init failed!”); PgmPrint(“Volume is FAT”); Serial.println(volume.fatType(), DEC); Serial.println(); if (!root.openRoot(&volume)) error(“openRoot failed”); // list file in root with date and size PgmPrintln(“Files found in root:”); root.ls(LS_DATE | LS_SIZE); Serial.println(); // Recursive list of all directories PgmPrintln(“Files found in all dirs:”); root.ls(LS_R); Serial.println(); PgmPrintln(“Done”); // Debugging complete, we start the server! Ethernet.begin(mac, ip); server.begin(); delay(1000); digitalWrite(8, LOW);

}

void ListFiles(EthernetClient client, uint8_t flags) {
// This code is just copied from SdFile.cpp in the SDFat library
// and tweaked to print to the client output in html!
dir_t p;

root.rewind(); client.println(“”); while (root.readDir(p) > 0) { // done if past last used entry if (p.name0 == DIR_NAME_FREE) break; // skip deleted entry and entries for . and .. if (p.name0 == DIR_NAME_DELETED || p.name0 == ‘.’) continue; // only list subdirectories and files if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue; // print any indent spaces client.print( for (uint8_t i = 0; i < 11; i++) { if (p.name[i] == ’ ’) continue; if (i == 8) { client.print(‘.’); } client.print((char)p.name[i]); } client.print(“\”>"); // print file name with possible blank fill for (uint8_t i = 0; i < 11; i++) { if (p.name[i] == ’ ’) continue; if (i == 8) { client.print(‘.’); } client.print((char)p.name[i]); } client.print(“”); if (DIR_IS_SUBDIR(&p)) { client.print(‘/’); } // print modify date/time if requested if (flags & LS_DATE) { root.printFatDate(p.lastWriteDate); client.print(’ ’); root.printFatTime(p.lastWriteTime); } // print size if requested if (!DIR_IS_SUBDIR(&p) && (flags & LS_SIZE)) { client.print(’ ’); client.print(p.fileSize); } client.println(“”); } client.println(“”);

}

// How big our line buffer should be. 100 is plenty!
#define BUFSIZ 100

void loop()
{
char clientline[BUFSIZ];
int index = 0;

EthernetClient client = server.available(); if (client) { digitalWrite(8, HIGH); // an http request ends with a blank line boolean current_line_is_blank = true; // reset the input buffer index = 0; while (client.connected()) { if (client.available()) { char c = client.read(); // If it isn’t a new line, add the character to the buffer if (c != ‘\n’ && c != ‘\r’) { clientline[index] = c; index++; // are we too big for the buffer? start tossing out data if (index >= BUFSIZ) index = BUFSIZ – 1; // continue to read more data! continue; } // got a \n or \r new line, which means the string is done clientline[index] = 0; // Print it out for debugging Serial.println(clientline); // Look for substring such as a request to get the root file if (strstr(clientline, "GET / ") != 0) { // send a standard http response header client.println(“HTTP/1.1 200 OK”); client.println(“Content-Type: text/html”); client.println(); // print all the files, use a helper to keep it clean client.println(“Files:”); ListFiles(client, LS_SIZE); } else if (strstr(clientline, “GET /”) != 0) { // this time no space after the /, so a sub-file! char *filename; filename = clientline + 5; // look after the “GET /” (5 chars) // a little trick, look for the " HTTP/1.1" string and // turn the first character of the substring into a 0 to clear it out. (strstr(clientline, " HTTP"))0 = 0; // print the file we want Serial.println(filename); if (! file.open(&root, filename, O_READ)) { client.println(“HTTP/1.1 404 Not Found”); client.println(“Content-Type: text/html”); client.println(); client.println(“File Not Found!”); break; } Serial.println(“Opened!”); strlower(filename); client.println(“HTTP/1.1 200 OK”); if (strstr(filename, “.html”) != NULL) client.println(“Content-Type: text/html”); else if (strstr(filename, “.jpg”) != NULL) client.println(“Content-Type: image/jpg”); else if (strstr(filename, “.png”) != NULL) client.println(“Content-Type: image/png”); else if (strstr(filename, “.mp3”) != NULL) client.println(“Content-Type: audio/mpeg”); else if (strstr(filename, “.ogg”) != NULL) client.println(“Content-Type: audio/ogg”); else if (strstr(filename, “.wav”) != NULL) client.println(“Content-Type: audio/wav”); else if (strstr(filename, “.m4a”) != NULL) client.println(“Content-Type: audio/mp4”); else if (strstr(filename, “.mp4”) != NULL) client.println(“Content-Type: video/mp4”); else client.println(“Content-Type: text/plain”); client.println(); int16_t c; while ((c = file.read()) >= 0) { // uncomment the serial to debug (slow!) //Serial.print((char)c); client.print((char)c); digitalWrite(8, !digitalRead(8)); if (!client.connected()) { break; } if (!client.available()) { break; } } file.close(); Serial.println(F(“Closed.”)); } else { // everything else is a 404 client.println(“HTTP/1.1 404 Not Found”); client.println(“Content-Type: text/html”); client.println(); client.println(“File Not Found!”); } break; } } // give the web browser time to receive the data delay(1); client.stop(); digitalWrite(8, LOW); }

}

H3

H3

Hab ein paar verbesserungen getätigt.
u.a. stoppt die übertragung jetzt wenn der client disconnected. außerdem gibt es jetzt eine Info LED auf pin 8 die aktivität anzeigt.

/*
This sketch uses the microSD card slot on the Arduino Ethernet shield
to serve up files over a very minimal browsing interface

Some code is from Bill Greiman’s SdFatLib examples, some is from the Arduino Ethernet WebServer example, some is from Limor Fried (Adafruit), some is from “jurs” for German Arduino forum, so its probably under GPL

*/

#include
#include
#include

/************ ETHERNET STUFF ************/
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 178, 177 };
EthernetServer server(80);

/************ SDCARD STUFF ************/
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

// store error strings in flash to save RAM
#define error(s) error_P(PSTR)

void error_P(const char* str) {
PgmPrint("error: “);
SerialPrintln_P(str);
if (card.errorCode()) {
PgmPrint(”SD error: ");
Serial.print(card.errorCode(), HEX);
Serial.print(‘,’);
Serial.println(card.errorData(), HEX);
}
while (1);
}

char* strupper( char* s )
// helper function char array to uppercase letters
{
for (char* p = s; *p; ++p)
*p = toupper( *p );
return s;
}

char* strlower( char* s )
// helper function char array to lowercase letters
{
for (char* p = s; *p; ++p)
*p = tolower( *p );
return s;
}

void setup() {
Serial.begin(115200);

PgmPrint("Free RAM: "); Serial.println(FreeRam()); // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with // breadboards. use SPI_FULL_SPEED for better performance. pinMode(10, OUTPUT); // set the SS pin as an output (necessary!) pinMode(4, OUTPUT); digitalWrite(10, HIGH); // but turn off the W5100 chip! digitalWrite(4, HIGH); if (!card.init(SPI_FULL_SPEED, 4)) error(“card.init failed!”); // initialize a FAT volume if (!volume.init(&card)) error(“vol.init failed!”); PgmPrint(“Volume is FAT”); Serial.println(volume.fatType(), DEC); Serial.println(); if (!root.openRoot(&volume)) error(“openRoot failed”); // list file in root with date and size PgmPrintln(“Files found in root:”); root.ls(LS_DATE | LS_SIZE); Serial.println(); // Recursive list of all directories PgmPrintln(“Files found in all dirs:”); root.ls(LS_R); Serial.println(); PgmPrintln(“Done”); // Debugging complete, we start the server! Ethernet.begin(mac, ip); server.begin(); delay(1000); digitalWrite(8, LOW);

}

void ListFiles(EthernetClient client, uint8_t flags) {
// This code is just copied from SdFile.cpp in the SDFat library
// and tweaked to print to the client output in html!
dir_t p;

root.rewind(); client.println(“”); while (root.readDir(p) > 0) { // done if past last used entry if (p.name0 == DIR_NAME_FREE) break; // skip deleted entry and entries for . and .. if (p.name0 == DIR_NAME_DELETED || p.name0 == ‘.’) continue; // only list subdirectories and files if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue; // print any indent spaces client.print( for (uint8_t i = 0; i < 11; i++) { if (p.name[i] == ’ ’) continue; if (i == 8) { client.print(‘.’); } client.print((char)p.name[i]); } client.print(“\”>"); // print file name with possible blank fill for (uint8_t i = 0; i < 11; i++) { if (p.name[i] == ’ ’) continue; if (i == 8) { client.print(‘.’); } client.print((char)p.name[i]); } client.print(“”); if (DIR_IS_SUBDIR(&p)) { client.print(‘/’); } // print modify date/time if requested if (flags & LS_DATE) { root.printFatDate(p.lastWriteDate); client.print(’ ’); root.printFatTime(p.lastWriteTime); } // print size if requested if (!DIR_IS_SUBDIR(&p) && (flags & LS_SIZE)) { client.print(’ ’); client.print(p.fileSize); } client.println(“”); } client.println(“”);

}

// How big our line buffer should be. 100 is plenty!
#define BUFSIZ 100

void loop()
{
char clientline[BUFSIZ];
int index = 0;

EthernetClient client = server.available(); if (client) { digitalWrite(8, HIGH); // an http request ends with a blank line boolean current_line_is_blank = true; // reset the input buffer index = 0; while (client.connected()) { if (client.available()) { char c = client.read(); // If it isn’t a new line, add the character to the buffer if (c != ‘\n’ && c != ‘\r’) { clientline[index] = c; index++; // are we too big for the buffer? start tossing out data if (index >= BUFSIZ) index = BUFSIZ – 1; // continue to read more data! continue; } // got a \n or \r new line, which means the string is done clientline[index] = 0; // Print it out for debugging Serial.println(clientline); // Look for substring such as a request to get the root file if (strstr(clientline, "GET / ") != 0) { // send a standard http response header client.println(“HTTP/1.1 200 OK”); client.println(“Content-Type: text/html”); client.println(); // print all the files, use a helper to keep it clean client.println(“Files:”); ListFiles(client, LS_SIZE); } else if (strstr(clientline, “GET /”) != 0) { // this time no space after the /, so a sub-file! char *filename; filename = clientline + 5; // look after the “GET /” (5 chars) // a little trick, look for the " HTTP/1.1" string and // turn the first character of the substring into a 0 to clear it out. (strstr(clientline, " HTTP"))0 = 0; // print the file we want Serial.println(filename); if (! file.open(&root, filename, O_READ)) { client.println(“HTTP/1.1 404 Not Found”); client.println(“Content-Type: text/html”); client.println(); client.println(“File Not Found!”); break; } Serial.println(“Opened!”); strlower(filename); client.println(“HTTP/1.1 200 OK”); if (strstr(filename, “.html”) != NULL) client.println(“Content-Type: text/html”); else if (strstr(filename, “.jpg”) != NULL) client.println(“Content-Type: image/jpg”); else if (strstr(filename, “.png”) != NULL) client.println(“Content-Type: image/png”); else if (strstr(filename, “.mp3”) != NULL) client.println(“Content-Type: audio/mpeg”); else if (strstr(filename, “.ogg”) != NULL) client.println(“Content-Type: audio/ogg”); else if (strstr(filename, “.wav”) != NULL) client.println(“Content-Type: audio/wav”); else if (strstr(filename, “.m4a”) != NULL) client.println(“Content-Type: audio/mp4”); else if (strstr(filename, “.mp4”) != NULL) client.println(“Content-Type: video/mp4”); else client.println(“Content-Type: text/plain”); client.println(); int16_t c; while ((c = file.read()) >= 0) { // uncomment the serial to debug (slow!) //Serial.print((char)c); client.print((char)c); digitalWrite(8, !digitalRead(8)); if (!client.connected()) { return; } if (!client.available()) { return; } } file.close(); Serial.println(F(“Closed.”)); } else { // everything else is a 404 client.println(“HTTP/1.1 404 Not Found”); client.println(“Content-Type: text/html”); client.println(); client.println(“File Not Found!”); } break; } } // give the web browser time to receive the data delay(1); client.stop(); digitalWrite(8, LOW); }

}

Magnus

Magnus

I just bought from you a EthernetShield W5100 and wanted to test it with your code but I always get SD error: 1, FF with the code in the blog.
I have tried the code in the eBook. The WebServer example code works well, but the “Serving the web page from SD card, with AJAX” gives always a SD error.
Any clue to sort this out ?

Lascia un commento

Tutti i commenti vengono moderati prima della pubblicazione