I have been trying for weeks to do the following: When entering the IP address of the arduino board, release a login form and if the entered data is correct, then list files inside the micro SD card. It is worth noting that the listed files can be opened in the browser (all are text type).
The login page, first try to create it in an html file saved on the SD card, but it did not work to the end. I had to use basic authentication via HTTP:
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 1, 117);
EthernetServer server(80);
char header[300];
int bufferSize = 0;
void setup() {
Serial.begin(9600);
Ethernet.begin(mac, ip);
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
}
void loop() {
EthernetClient client = server.available();
if (client) {
Serial.println("new client");
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
if(bufferSize < 300) header[bufferSize++] = c;
if (c == '\n' && currentLineIsBlank) {
//'arduino:admin' (user:password)
Serial.println(header);
if(strstr(header, "YXJkdWlubzphZG1pbg==") != NULL) {
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
if(strstr(header, "GET / HTTP/1.1")) {
Serial.println("Lo has ingresado great");
client.println("<html>");
client.println("<h2>Felicidades Qlo</h2>");
client.println("</html>");
}
} else {
client.println("HTTP/1.1 401 Unauthorized");
client.println("WWW-Authenticate: Basic realm=\"Secure\"");
client.println("Content-Type: text/html");
client.println();
client.println("<html>REJECTED</html>");
}
bufferSize = 0;
StrClear(header, 300);
break;
}
if (c == '\n') {
currentLineIsBlank = true;
}
else if (c != '\r') {
currentLineIsBlank = false;
}
}
}
delay(1);
client.stop();
Serial.println("client disconnected");
}
}
void StrClear(char *str, char length)
{
for (int i = 0; i < length; i++) {
str[i] = 0;
}
}
To list and view files within the SD, I follow the tutorial on this page:Arduino Tutorials - Ethernet+SD
#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 1, 117);
EthernetServer server(80);
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;
#define error(s) error_P(PSTR(s))
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);
}
struct Millis{
unsigned long offset = 0;
unsigned long get(){return millis() - offset;}
void reset(){offset = millis();}
void set(unsigned long value){offset - millis() - value;}
};
void setup() {
Serial.begin(9600);
pinMode( 8, OUTPUT );
digitalWrite( 9, HIGH );
if( !card.init( SPI_HALF_SPEED, 4 ) ) error( "card.init failed!" );
if( !volume.init( &card ) ) error( "vol.init failed!" );
if( !root.openRoot( &volume ) ) error( "openRoot failed" );
Ethernet.begin(mac, ip);
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
}
#define BUFSIZ 100
Millis lol;
void loop()
{
char clientline[BUFSIZ];
int index = 0;
LEDCunt();
EthernetClient client = server.available();
if (client) {
boolean current_line_is_blank = true;
index = 0;
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (c != '\n' && c != '\r') {
clientline[index] = c;
index++;
//Se comprueba si el tamaño del Buffer es demasiado grande
if (index >= BUFSIZ)
index = BUFSIZ -1;
//Si no es grande, se continua normalmente el codigo
continue;
}
// Si esta linea se cumple, significa que ya salio el bucle de la condicion anterior.
// Osea.... ya se encontro el espacio en blanco final (\n,\t)
clientline[index] = 0;
// Insertamos el array para proseguir con la solicitacion de directorios de la tarjeta SD (ROOT)
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();
client.println("<h2>Archivos:</h2>");
//Listamos archivos
ListFiles(client, 0);
} else if (strstr (clientline, "GET /") != 0) {
char *filename;
filename = clientline + 5;
//Limpiamos el array igualando elementos a 0
(strstr (clientline, " HTTP"))[0] = 0;
// Cuando demos click al archivo que vamos abrir, imprime el nombre por consola.
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("<h2>File Not Found!</h2>");
break;
}
Serial.println("Opened!");
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/plain");
client.println();
int16_t c;
while ((c = file.read()) > 0) {
client.print((char)c);
}
file.close();
} else {
//Si no encuentra el archivo o no puede abrirlo
client.println("HTTP/1.1 404 Not Found");
client.println("Content-Type: text/html");
client.println();
client.println("<h2>File Not Found!</h2>");
}
break;
}
}
delay(1);
client.stop();
}
}
void StrClear(char *str, char length)
{
for (int i = 0; i < length; i++) {
str[i] = 0;
}
}
void ListFiles(EthernetClient client, uint8_t flags) {
dir_t p;
root.rewind();
client.println("<ul>");
while (root.readDir(p) > 0) {
if (p.name[0] == DIR_NAME_FREE) break;
// omite entradas (archivos) eliminadas
if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue;
// enlista subdirectorios y archivos(solamente)
if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;
// imprime espacios en blanco para extension del archivo
client.print("<li><a href=\"");
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("\">");
// imprime el nombre del archivo
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("</a>");
if (DIR_IS_SUBDIR(&p)) {
client.print('/');
}
// imprime la fecha de ultima modificacion si se solicita
if (flags & LS_DATE) {
root.printFatDate(p.lastWriteDate);
client.print(' ');
root.printFatTime(p.lastWriteTime);
}
// imprime el tamaño del archivo si se solicita
if (!DIR_IS_SUBDIR(&p) && (flags & LS_SIZE)) {
client.print(' ');
client.print(p.fileSize);
}
client.println("</li>");
}
client.println("</ul>");
}
void LEDCunt(){
if(lol.get() < 700){
digitalWrite(9,HIGH);
}
if(lol.get() > 700){
digitalWrite(9,LOW);
}
if(lol.get() == 1400){
lol.reset();
}
}
I added those comments to understand the code. Now what I am struggling to achieve, is to be able to combine the Login (first code) and the list of files (second code). I do not know why sometimes I think that is impossible, because in my tests, my memory is very limited (91%). I would like to know alternatives if they exist? Or is it possible to combine these two codes?