Web server e comandi seriali

Eccomi di nuovo con i miei dubbi sull'Ethernet shield. Negli esempi che ho trovato in rete ho capito come settare e resettare un'uscita attraverso il browser, ma come posso fare in modo che l'arduino invii una determinata sequenza di byte sulla seriale (sempre creando il solito pulsantino dal browser) ?

il tuo arduino fa da server giusto?
bene, quando clicchi il pulsantino, il browser invia una richiesta post o get a seconda di come hai scritto l'html della pagina. In questo post/get vengono inclusi anche i dati inseriti in un'eventuale form comprendente il pulsante. prendi questo input e stampatelo al pc via seriale, non è difficile da comprendere, è tutto in chiaro.

attenzione, perchè il pulsante funzioni deve essere assegnato ad un form, altrimenti è solo un'elemento decorativo. Per esempio questo crea un pulsante+un'area di testo, quando premi il pulsante il testo viene inviato con una GET alla pagina index.html

Testo di input:

Sto vedendo l'esempio proposto da Lesto perchè anche io ho delle difficoltà a comunicare con lo shield. Ho provato ad inviare una variabile ad arduino sia con il metodo get che con il metodo post, inserisco lo sketch e gli output da seriale:

#include <Ethernet.h>
byte mac[] = { 0x37, 0xA8, 0xD5, 0x00, 0x00, 0x53 };
byte ip[] = { 192, 168, 1, 145 };
Server server(80);

void setup(){
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.begin(9600);
}

void loop(){
  Client client = server.available();
  if (client) {
    boolean current_line_is_blank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.print(c);
        if (c == '\n' && current_line_is_blank) {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          client.println("<html><head><title>Prova ethernet</title>");
          client.println("</head><body>");
          client.println("<form name=\"input\" method=\"get\">");
          client.println("Testo di input: <input type=\"text\" name=\"variabile\" />");
          client.println("<input type=\"submit\" value=\"Invia\" />");
          client.println("</form></body></html> ");
          break;
        }
        if (c == '\n') {
          current_line_is_blank = true;
        } else if (c != '\r') {
          current_line_is_blank = false;
        }
      }
    }
    delay(1);
    client.stop();
  }
}
// OUTPUT con metodo GET
GET /?variabile=arduino HTTP/1.1
Host: 192.168.1.145
bla bla bla
Referer: http://192.168.1.145/?variabile=arduino
// questo invece è ciò che compare nella barra degli indirizzi del browser:
http://192.168.1.145/?variabile=arduino

// OUTPUT con metodo POST
POST / HTTP/1.1
Host: 192.168.1.145
bla bla bla
Referer: http://192.168.1.145/
Content-Length: 17

Usando il metodo POST non ricevo esplicitamente la variabile, ma da come si vede nell'ultima riga dell'output aggiunge "Content-Length: 17". Volevo usare il metodo POST per non avere la variabile visibile nell'indirizzo, dove è l'errore?
Mi scuso con Ambrogio per aver sfruttato il suo post ma credo sia pertinente al topic e chissà magari abbiamo gli stessi dubbi.

non è un'errore, tutto funziona alla perfezione!
Il problema è che tu stai usando l'HTTP 1.1 che prevede la disconnessione e riconnessione del client, probabilmente, se accettassi ancora connessioni, vedresti che il browser si ricollega e ti invia il resto dei dati.
per evitare il casino usa l'HTTP 1.0, che non supporta questo sbatti di disconnessione e riconnessione e ti arriva tutto insieme :smiley:

Scusa la domanda forse stupida, ma cosa dovrei cambiare per usare l'HTML 1.0 invece del 1.1?
Per me è un mondo nuovo l'html, cercando su internet spiegazioni nei vari forum ti fa venire voglia di buttare via tutto, si mescola tutto tra php, asp, ajax, javascript e la confusione aumenta.
C'è da mettere qualche tag specifico nell'head della pagina, bisogna usare una sintassi particolare o è un'impostazione che si setta nel browser?

nonono fermo. l'HTTP è il protocollo di trasmissione dati (che a sua volta si appoggia sul tcp che a sua volta... Open Systems Interconnection - Wikipedia)
l'HTML invece è un linguaggio per "disegnare" la pagina

semplicemente cambia client.println("HTTP/1.1 200 OK"); in client.println("HTTP/1.0 200 OK");
e di conseguenza anche le risposte del browser dovrebbero cambiare... da GET /?variabile=arduino HTTP/1.1 a GET /?variabile=arduino HTTP/1.0, altrimenti rispondi con un'errore 505(HTTP Version Not Supported) e il browser dovrebbe rifare la richiesta in HTTP1.0

E' la prima prova che ho fatto, ma nell'output seriale rileva sempre HTTP1.1

ciò può dipendere dal fatto che la prima pagina viene richiesta in http1.1, e tu rispondi però dicendo 1.0, ma il browser se ne frega. dovresti subito rispondere 505 finchè il browser non ti risponde in http1.0

altrimenti ti tocca implementare http1.1, cerca http su wkipedia e in fondo segui i link sulle RFC (se non sai cosa sono le RFC, sono le regole standard dei vari protocolli come http, ftp, tcp, html, etc..)

Allora, sono riuscito a farmi riconoscere la pagina come HTTP 1.0 cambiando un'impostazione nel browser, ecco l'output che ricevo dalla seriale:
POST / HTTP/1.0

bla bla bla
Content-Length: 20

Ancora non ricevo la variabile col metodo post mentre col metodo get funziona normalmente.
Sto diventando noioso mi sa, scusatemi.

non ti preoccupare e posta tutto l'output che hai adesso.
poi prova ad accettare nuove connessioni, e veedere se per caso il client prova a riconnettersi anche usando l'http1.0

ahhh mi pare che prima di inviare i dati post il client va a capo 2 volte per dividere l'header dai dati... magari è per questo motivo?
posti il tuo codice server completo pls?

#include <Ethernet.h>

byte mac[] = { 0x37, 0xA8, 0xD5, 0x00, 0x00, 0x53 };
byte ip[] = { 192, 168, 1, 145 };

Server server(80);

void setup()
{
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.begin(9600);
}

void loop()
{
  Client client = server.available();
  if (client) {
    // an http request ends with a blank line
    boolean current_line_is_blank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        // if we've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so we can send a reply
        Serial.print(c);
        if (c == '\n' && current_line_is_blank) {
          // send a standard http response header
          client.println("HTTP/1.0 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          client.println("<html><head><title>Prova ethernet</title>");
          client.println("</head><body>");
          client.println("<form name=\"input\" method=\"POST\">");
          client.println("Testo di input: <input type=\"text\" name=\"variabile\" />");
          client.println("<input type=\"submit\" value=\"Invia\" />");
          client.println("</form></body></html> ");
          break;
        }
        if (c == '\n') {
          // we're starting a new line
          current_line_is_blank = true;
        } else if (c != '\r') {
          // we've gotten a character on the current line
          current_line_is_blank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    client.stop();
  }
}
POST / HTTP/1.0

Host: 192.168.1.145

User-Agent: Mozilla/5.0 (X11; U; Linux i686; it; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.10 (maverick) Firefox/3.6.13

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: it-it,it;q=0.8,en-us;q=0.5,en;q=0.3

Accept-Encoding: gzip,deflate

Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7

Keep-Alive: 115

Connection: keep-alive

Referer: http://192.168.1.145/

Content-Type: application/x-www-form-urlencoded

Content-Length: 17

esatto, credo che l'errore sia nella tua gestione degli '\n', infatti la post risponde in questo modo:

POST /path/script.cgi HTTP/1.0
From: frog@jmarshall.com
User-Agent: HTTPTool/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 32

home=Cosby&favorite+flavor=flies

come puoi vedere va a capo 2 volte prima di darti i dati, e invece nel tuo codice al secondo a capo disconnetti il povero client... XD

Non riesco ancora a farlo andare, sembrerò ritardato :roll_eyes:
Non è che avresti un esempio anche banale con il codice funzionante almeno la pianto di rompere....

umhh ok, anche se non dovrei ]:slight_smile:

allora, i caratteri di fine connessione sono 2: \n\r
tu invece disconnetti all'arrivo di \n\n, e quindi ti perdi il post. il codice diventa:

#include <Ethernet.h>

byte mac[] = { 0x37, 0xA8, 0xD5, 0x00, 0x00, 0x53 };
byte ip[] = { 192, 168, 1, 145 };

Server server(80);

void setup()
{
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.begin(9600);
}

void loop()
{
  Client client = server.available();
  if (client) {
    // an http request ends with \n\r so:
    boolean nWasLastCar = false;

    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.print(c);
        // if we've have a \n followed by a \r the request has ended
        if (c == '\r' && nWasLastCar) {
          // send a standard http response header
          client.println("HTTP/1.0 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          client.println("<html><head><title>Prova ethernet</title>");
          client.println("</head><body>");
          client.println("<form name=\"input\" method=\"POST\">");
          client.println("Testo di input: <input type=\"text\" name=\"variabile\" />");
          client.println("<input type=\"submit\" value=\"Invia\" />");
          client.println("</form></body></html> ");
          break;
        }
        if (c != '\n') {
          nWasLastCar = true;
        }else{
          nWasLastCar = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    client.stop();
  }
}

Oggi ti faccio arrabbiare Lesto :blush:
Col codice che hai postato nell'output seriale esce solo
POST / HTTP/1.0

okok, mea culpa, vuol dire che SEMPRE quando va a capo manda i segnale \n\r

#include <Ethernet.h>

byte mac[] = { 0x37, 0xA8, 0xD5, 0x00, 0x00, 0x53 };
byte ip[] = { 192, 168, 1, 145 };

Server server(80);

void setup()
{
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.begin(9600);
}

void loop()
{
  Client client = server.available();
  if (client) {
    // an http request ends with \n\r so:
    boolean nWasLastCar = false;
    int numeroDiACapo = 0;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.print(c);
        // if we've have a \n followed by a \r the request has ended
        if (c == '\r' && nWasLastCar) {
            numeroDiACapo++;
        }
        if (c != '\n') {
          nWasLastCar = true;
        }else{
          nWasLastCar = false;
        }
      }else{
          if (numeroDiACapo>1){
             // send a standard http response header
             client.println("HTTP/1.0 200 OK");
             client.println("Content-Type: text/html");
             client.println();
             client.println("<html><head><title>Prova ethernet</title>");
             client.println("</head><body>");
             client.println("<form name=\"input\" method=\"POST\">");
             client.println("Testo di input: <input type=\"text\" name=\"variabile\" />");
             client.println("<input type=\"submit\" value=\"Invia\" />");
             client.println("</form></body></html> ");
             break;
          }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    client.stop();
  }
}

ti avviso subito che la struttura del codice deve essere rivista, se il client appena finito di inviare si disconnette da solo c'è il rischio che non elabori parte dei dati via serial...