272 lines
7.9 KiB
C++
272 lines
7.9 KiB
C++
/*
|
|
* SDWebBrowse.ino
|
|
*
|
|
* This sketch uses the microSD card slot on the a WIZ5500 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 and the rest is from Limor Fried
|
|
* (Adafruit) so its probably under GPL
|
|
*
|
|
* Tutorial is at https://learn.adafruit.com/arduino-ethernet-sd-card/serving-files-over-ethernet
|
|
*
|
|
*/
|
|
|
|
#include <SPI.h>
|
|
#include <SD.h>
|
|
#include <Ethernet2.h>
|
|
|
|
/************ ETHERNET STUFF ************/
|
|
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // change if necessary
|
|
byte ip[] = { 192, 168, 1, 177 }; // change if necessary
|
|
EthernetServer server(80);
|
|
|
|
/************ SDCARD STUFF ************/
|
|
#define SDCARD_CS 4
|
|
File root;
|
|
|
|
#if defined(ESP8266)
|
|
// default for ESPressif
|
|
#define WIZ_CS 15
|
|
#elif defined(ESP32)
|
|
#define WIZ_CS 33
|
|
#elif defined(ARDUINO_STM32_FEATHER)
|
|
// default for WICED
|
|
#define WIZ_CS PB4
|
|
#elif defined(TEENSYDUINO)
|
|
#define WIZ_CS 10
|
|
#elif defined(ARDUINO_FEATHER52)
|
|
#define WIZ_CS 11
|
|
#else // default for 328p, 32u4 and m0
|
|
#define WIZ_CS 10
|
|
#endif
|
|
|
|
// store error strings in flash to save RAM
|
|
#define error(s) error_P(PSTR(s))
|
|
|
|
void error_P(const char* str) {
|
|
Serial.print(F("error: "));
|
|
Serial.println(str);
|
|
|
|
while(1);
|
|
}
|
|
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
while (!Serial); // For 32u4 based microcontrollers like 32u4 Adalogger Feather
|
|
|
|
//Serial.print(F("Free RAM: ")); Serial.println(FreeRam());
|
|
|
|
if (!SD.begin(SDCARD_CS)) {
|
|
error("card.init failed!");
|
|
}
|
|
|
|
root = SD.open("/");
|
|
printDirectory(root, 0);
|
|
|
|
// Recursive list of all directories
|
|
Serial.println(F("Files found in all dirs:"));
|
|
printDirectory(root, 0);
|
|
|
|
Serial.println();
|
|
Serial.println(F("Done"));
|
|
|
|
// Debugging complete, we start the server!
|
|
Serial.println(F("Initializing WizNet"));
|
|
Ethernet.init(WIZ_CS);
|
|
// give the ethernet module time to boot up
|
|
delay(1000);
|
|
// start the Ethernet connection
|
|
// Use the fixed IP specified. If you want to use DHCP first
|
|
// then switch the Ethernet.begin statements
|
|
Ethernet.begin(mac, ip);
|
|
// try to congifure using DHCP address instead of IP:
|
|
// Ethernet.begin(mac);
|
|
|
|
// print the Ethernet board/shield's IP address to Serial monitor
|
|
Serial.print(F("My IP address: "));
|
|
Serial.println(Ethernet.localIP());
|
|
|
|
server.begin();
|
|
}
|
|
|
|
void ListFiles(EthernetClient client, uint8_t flags, File dir) {
|
|
client.println("<ul>");
|
|
while (true) {
|
|
File entry = dir.openNextFile();
|
|
|
|
// done if past last used entry
|
|
if (! entry) {
|
|
// no more files
|
|
break;
|
|
}
|
|
|
|
// print any indent spaces
|
|
client.print("<li><a href=\"");
|
|
client.print(entry.name());
|
|
if (entry.isDirectory()) {
|
|
client.println("/");
|
|
}
|
|
client.print("\">");
|
|
|
|
// print file name with possible blank fill
|
|
client.print(entry.name());
|
|
if (entry.isDirectory()) {
|
|
client.println("/");
|
|
}
|
|
|
|
client.print("</a>");
|
|
/*
|
|
// print modify date/time if requested
|
|
if (flags & LS_DATE) {
|
|
dir.printFatDate(p.lastWriteDate);
|
|
client.print(' ');
|
|
dir.printFatTime(p.lastWriteTime);
|
|
}
|
|
// print size if requested
|
|
if (!DIR_IS_SUBDIR(&p) && (flags & LS_SIZE)) {
|
|
client.print(' ');
|
|
client.print(p.fileSize);
|
|
}
|
|
*/
|
|
client.println("</li>");
|
|
entry.close();
|
|
}
|
|
client.println("</ul>");
|
|
}
|
|
|
|
// How big our line buffer should be. 100 is plenty!
|
|
#define BUFSIZ 100
|
|
|
|
void loop()
|
|
{
|
|
char clientline[BUFSIZ];
|
|
char name[17];
|
|
int index = 0;
|
|
|
|
EthernetClient client = server.available();
|
|
if (client) {
|
|
// 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 file
|
|
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;
|
|
|
|
if(filename[strlen(filename)-1] == '/') { // Trim a directory filename
|
|
filename[strlen(filename)-1] = 0; // as Open throws error with trailing /
|
|
}
|
|
|
|
Serial.print(F("Web request for: ")); Serial.println(filename); // print the file we want
|
|
|
|
File file = SD.open(filename, O_READ);
|
|
if ( file == 0 ) { // Opening the file with return code of 0 is an error in SDFile.open
|
|
client.println("HTTP/1.1 404 Not Found");
|
|
client.println("Content-Type: text/html");
|
|
client.println();
|
|
client.println("<h2>File Not Found!</h2>");
|
|
client.println("<br><h3>Couldn't open the File!</h3>");
|
|
break;
|
|
}
|
|
|
|
Serial.println("File Opened!");
|
|
|
|
client.println("HTTP/1.1 200 OK");
|
|
if (file.isDirectory()) {
|
|
Serial.println("is a directory");
|
|
//file.close();
|
|
client.println("Content-Type: text/html");
|
|
client.println();
|
|
client.print("<h2>Files in /");
|
|
client.print(filename);
|
|
client.println(":</h2>");
|
|
ListFiles(client,LS_SIZE,file);
|
|
file.close();
|
|
} else { // Any non-directory clicked, server will send file to client for download
|
|
client.println("Content-Type: application/octet-stream");
|
|
client.println();
|
|
|
|
char file_buffer[16];
|
|
int avail;
|
|
while (avail = file.available()) {
|
|
int to_read = min(avail, 16);
|
|
if (to_read != file.read(file_buffer, to_read)) {
|
|
break;
|
|
}
|
|
// uncomment the serial to debug (slow!)
|
|
//Serial.write((char)c);
|
|
client.write(file_buffer, to_read);
|
|
}
|
|
file.close();
|
|
}
|
|
} else {
|
|
// everything else is a 404
|
|
client.println("HTTP/1.1 404 Not Found");
|
|
client.println("Content-Type: text/html");
|
|
client.println();
|
|
client.println("<h2>File Not Found!</h2>");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
// give the web browser time to receive the data
|
|
delay(1);
|
|
client.stop();
|
|
}
|
|
}
|
|
|
|
|
|
void printDirectory(File dir, int numTabs) {
|
|
while(true) {
|
|
File entry = dir.openNextFile();
|
|
if (! entry) {
|
|
// no more files
|
|
break;
|
|
}
|
|
for (uint8_t i=0; i<numTabs; i++) {
|
|
Serial.print('\t');
|
|
}
|
|
Serial.print(entry.name());
|
|
if (entry.isDirectory()) {
|
|
Serial.println("/");
|
|
printDirectory(entry, numTabs+1);
|
|
} else {
|
|
// files have sizes, directories do not
|
|
Serial.print("\t\t");
|
|
Serial.println(entry.size(), DEC);
|
|
}
|
|
entry.close();
|
|
}
|
|
}
|