Web_Switch: aggiungere pulsanti addizionali

ciao a tutti, dopo molte peripezie sono riuscito finalmente a far funzionare in maniera stabile nel tempo la mia scheda ethernet ENC28J60

ho usato come sketch quello intitolato “web_switch”, ossia digitando su una pagina web l’indirizzo IP della shield, accedo alla sua pagina e posso attivare o disattivare un pulsante che poi controllerà un LED presente su arduino.
Fino a qui tutto bene, ora vorrei semplicemente aumentare il numero dei pulsanti che posso gestire ( e quindi anche il numero delle relative uscite ), ma analizzando lo sketch non riesco davvero a capire il modo per farlo; trovo difficoltà soprattutto sul lato pagina web, ossia non capisco quali parametri dovrei aggiungere o modificare per ottenere quello che voglio.
Vi posto lo sketch:

#include "etherShield.h"

static uint8_t mymac[6] = {0x54,0x55,0x58,0x10,0x00,0x24}; // Indirizzo MAC della shield ENC28J60 
static uint8_t myip[4] = {192,168,1,20};                   // Indirizzo IP della shield ENC28J60 
static char baseurl[]="http://192.168.1.20/";              // URL della pagina dove verrano visualizzati i dati 
static uint16_t mywwwport =80;                             // Porta in ascolto 



#define BUFFER_SIZE 500
static uint8_t buf[BUFFER_SIZE+1];
#define STR_BUFFER_SIZE 22
static char strbuf[STR_BUFFER_SIZE+1];

EtherShield es=EtherShield();

// Preparazione della pagina web
uint16_t print_webpage(uint8_t *buf, byte on_off);
int8_t analyse_cmd(char *str);

// LED sul pin 4 usato come dispositivo da attivare o disattivare
#define LED_PIN  4


void setup(){
  
   /*inizializzazione enc28j60*/
	 es.ES_enc28j60Init(mymac);
   es.ES_enc28j60clkout(2); // cambio clkout da 6.25MHz a 12.5MHz
   delay(10);
        
	/* Configurazione dei LED del connettore ethernet della shield */
	// LEDA=verde LEDB=giallo
	//
	// 0x880 is PHLCON LEDB=on, LEDA=on
	// enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
	es.ES_enc28j60PhyWrite(PHLCON,0x880);
	delay(500);
	//
	// 0x990 is PHLCON LEDB=off, LEDA=off
	// enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
	es.ES_enc28j60PhyWrite(PHLCON,0x990);
	delay(500);
	//
	// 0x880 is PHLCON LEDB=on, LEDA=on
	// enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
	es.ES_enc28j60PhyWrite(PHLCON,0x880);
	delay(500);
	//
	// 0x990 is PHLCON LEDB=off, LEDA=off
	// enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
	es.ES_enc28j60PhyWrite(PHLCON,0x990);
	delay(500);
	//
  // 0x476 is PHLCON LEDA=links status, LEDB=receive/transmit
  // enc28j60PhyWrite(PHLCON,0b0000 0100 0111 01 10);
  es.ES_enc28j60PhyWrite(PHLCON,0x476);
	delay(100);
        
  //inizializzazione del layer ethernet/ip:
  es.ES_init_ip_arp_udp_tcp(mymac,myip,80);
  
 	pinMode(LED_PIN, OUTPUT); 
 	digitalWrite(LED_PIN, LOW);  // accendi il LED
}

void loop(){
  uint16_t plen, dat_p;
  int8_t cmd;
  byte on_off = 1;

  plen = es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf);

	/* plen sarà diverso da zero se vi è un pacchetto valido (senza errore CRC) */
  if(plen!=0){
	           
    // arp è trasmesso se sconosciuto, ma un host può comunque verificare l'indirizzo MAC inviandogli un indirizzo unicast //
    if(es.ES_eth_type_is_arp_and_my_ip(buf,plen)){
      es.ES_make_arp_answer_from_request(buf);
      return;
    }

    // Controlla se i pacchetti IP sono per noi //
    if(es.ES_eth_type_is_ip_and_my_ip(buf,plen)==0){
      return;
    }
    
    if(buf[IP_PROTO_P]==IP_PROTO_ICMP_V && buf[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V){
      es.ES_make_echo_reply_from_request(buf,plen);
      return;
    }
    
    // la porta tcp www si avvia, confronto solo il byte più basso // 
    if (buf[IP_PROTO_P]==IP_PROTO_TCP_V&&buf[TCP_DST_PORT_H_P]==0&&buf[TCP_DST_PORT_L_P]==mywwwport){
      if (buf[TCP_FLAGS_P] & TCP_FLAGS_SYN_V){
         es.ES_make_tcp_synack_from_syn(buf); // make_tcp_synack_from_syn ha già inviato il syn,ack
         return;     
      }
      if (buf[TCP_FLAGS_P] & TCP_FLAGS_ACK_V){
        es.ES_init_len_info(buf); //  inizializzo alcune strutture dati
        dat_p=es.ES_get_tcp_data_pointer();
        if (dat_p==0){ // possiamo non avere nessun dato, solo ack:
          if (buf[TCP_FLAGS_P] & TCP_FLAGS_FIN_V){
            es.ES_make_tcp_ack_from_any(buf);
          }
          return;
        }
        if (strncmp("GET ",(char *)&(buf[dat_p]),4)!=0){
            plen=es.ES_fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<h1>200 OK</h1>"));
            goto SENDTCP;
        }
 	if (strncmp("/ ",(char *)&(buf[dat_p+4]),2)==0){
                plen=print_webpage(buf, on_off);
            goto SENDTCP;
         }
        cmd=analyse_cmd((char *)&(buf[dat_p+5]));
        
        if (cmd==2){
                on_off=1;
        	digitalWrite(LED_PIN, LOW);  // Accendi il LED
        }
        else if (cmd==3){
                on_off=0;
        	digitalWrite(LED_PIN, HIGH);  // Spegni il LED
        }
        plen=print_webpage(buf, on_off);
        	
        	   plen=print_webpage(buf, on_off);
SENDTCP:  es.ES_make_tcp_ack_from_any(buf); // Manda ack per ottenere l'http 
           es.ES_make_tcp_ack_with_data(buf,plen); // manda i dati       
      }
    }
  }
        
}
// I valori di ritorno sono contenuti nella variabile globale strbuf
uint8_t find_key_val(char *str,char *key)
{
        uint8_t found=0;
        uint8_t i=0;
        char *kp;
        kp=key;
        while(*str &&  *str!=' ' && found==0){
                if (*str == *kp){
                        kp++;
                        if (*kp == '\0'){
                                str++;
                                kp=key;
                                if (*str == '='){
                                        found=1;
                                }
                        }
                }else{
                        kp=key;
                }
                str++;
        }
        if (found==1){
                // Copia il valore su un buffer e lo termino con '\0'
                while(*str &&  *str!=' ' && *str!='&' && i<STR_BUFFER_SIZE){
                        strbuf[i]=*str;
                        i++;
                        str++;
                }
                strbuf[i]='\0';
        }
        return(found);
}

int8_t analyse_cmd(char *str)
{
        int8_t r=-1;
     
        if (find_key_val(str,"cmd")){
                if (*strbuf < 0x3a && *strbuf > 0x2f){
                        // è un numero ASCII, lo restituisco
                        r=(*strbuf-0x30);
                }
        }
        return r;
}


uint16_t print_webpage(uint8_t *buf, byte on_off)
{

       int i=0;
    
        
        uint16_t plen;
        
 
        
        plen=es.ES_fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"));
        plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<center><p><h1>Welcome to Arduino Ethernet Shield V1.0  </h1></p> "));
         
        plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<hr>
<form METHOD=get action=\""));
        plen=es.ES_fill_tcp_data(buf,plen,baseurl);
        plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("\">"));
        plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<h2> REMOTE LED is  </h2> "));
 				plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<h1><font color=\"#00FF00\"> "));
         
        if(on_off)
        	plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("ON"));
        else 
        	plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("OFF"));
        
        plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("  </font></h1>
 ") );
        
        if(on_off){
        	plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<input type=hidden name=cmd value=3>"));
        	plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<input type=submit value=\"Switch off\"></form>"));
        }
        else {
        	plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<input type=hidden name=cmd value=2>"));
        	plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<input type=submit value=\"Switch on\"></form>"));
        }
        
        plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</center><hr> <p> V1.0 <a href=\"http://www.nuelectronics.com\">www.nuelectronics.com<a>"));
  
        return(plen);
}

quello che vi chiedo è magari di dirmi quale parte dovrei copiare e incollare ( se è così che si deve fare ) per poi cambiare qualche parametro, oppure se devo aggiungere da zero alcune cose, o ancora se la mia modifica implica anche la modifica di alcuni parametri ( per esempio, di default il pulsante me lo ritrovo al centro della pagina…se ne voglio aggiungere un altro, ne metterò uno accanto all’altro quindi credo che i parametri per la “disposizione” del vecchio pulsante andranno cambiati ), ecc.
mi interessa capire il metodo insomma per aggiungere pulsanti, come posizionarli e come agganciarli alle uscite di arduino…vi ringrazio in anticipo.
il collegamento hardware è così disposto: PC - Router - ethernet shield - arduino - led
l’ide usato è lo 0.21 ( per motivi di compatibilità con questa shield ) e il sistema operativo è WIN7 ultimate 64bit

ciao
Non ho possibilità di provartelo per 2 ragioni, non ho quella eth shield e non ho arduino, però posso indicarti dove modificare lo sketch.

Ti ritrovi al centro perchè qui:
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("

Welcome to Arduino Ethernet Shield V1.0

"));
e stato aperto un per il titolo e non è stato chiuso, se vuoi il pulsante di lato, prova sostituendo la linea con:
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("

Welcome to Arduino Ethernet Shield V1.0

"));

la tua paginetta web la scrive questo pezzo di sketch

plen=es.ES_fill_tcp_data_p(buf,0,PSTR(“HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n”));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("

Welcome to Arduino Ethernet Shield V1.0

"));

plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("


")); plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("

REMOTE LED is

")); plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("

"));

if(on_off)
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“ON”));
else
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“OFF”));

plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("


") );

if(on_off){
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(""));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<input type=submit value=“Switch off”>"));
}
else {
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(""));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<input type=submit value=“Switch on”>"));
}

plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("


V1.0 <a href=“http://www.nuelectronics.com”>www.nuelectronics.com"));

come vedi c’e’ un if(on_off)
se on_off è vero ti fa apparire il tasto con su scritto switch off con queste 2 righe
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(""));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<input type=submit value=“Switch off”>"));
altrimenti ti sostituisce il tasto con su scritto accendi “Switch on”

questo pezzo legge i caratteri in arrivo dal client quando premi il tasto sulla pagina
es plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(""));
qui invii cmd=3

cmd=analyse_cmd((char *)&(buf[dat_p+5]));

if (cmd==2){
on_off=1;
digitalWrite(LED_PIN, LOW); // Accendi il LED
}
else if (cmd==3){
on_off=0;
digitalWrite(LED_PIN, HIGH); // Spegni il LED
}

dovresti aggiungere più righe che stampano i tasti e dovresti aggiungere più controlli,
dichiarare altre variabili led_pin e ovviamente nei nuovi tasti mettere altri valori
name=cmd value=4
name=cmd value=5

name=cmd value=6
name=cmd value=7

anche se io lo avrei fatto in un altro modo, assegnando al cmd direttamente il numero del pin da comandare. In tal modo leggo il valore e lo copio nel digitalwrite direttamente, non dovendo mettere così una sfilza di righe di confronto

esempio:
cmd=30 separo la stringa il primo byte è la porta (pin 3) e il secondo il comando “0”
cmd=31 separo la stringa il primo byte è la porta (pin 3) e il secondo il comando “1”

cmd=40
cmd=41

cmd=50
cmd=51


anche la variabile byte on_off va moltiplicata per il numero dei tasti devi aggiungerne altre
byte on_off_2
byte on_off_3

altrimenti ti sostituisce tutti i tasti anche cliccandone uno solo

Ripeto non posso provarlo altrimenti ti avrei aggiunto dei tasti io
ciao

Ti ringrazio tantissimo per il tuo aiuto, a grandi linee ho capito dove devo andare a modificare lo sketch per aggiungere pulsanti e per comandarci le uscite di arduino; ho fatto una prova, aggiungendo un pulsante:
ho definito un’altra uscita per un altro led

#define LED_PIN  4
#define LED_PIN2 5

saltando un pò di righe:

pinMode(LED_PIN, OUTPUT);
pinMode(LED_PIN2, OUTPUT);
digitalWrite(LED_PIN, LOW);  // accendi il LED
digitalWrite(LED_PIN2, LOW);  // accendi il LED_2

insomma, niente di che…ho solo aggiunto quello che mancava; nel loop, all’inizio, ho messo on_off2 per il secondo pulsante:

uint16_t plen, dat_p;
  int8_t cmd;
  byte on_off = 1;
  byte on_off2 = 1;

qui ho copiato e incollato il pezzo che già c’era, modificando solo il valore di CMD e aggancandoci l’uscita del LED_PIN2, e mettendo alla fine quel comando già presente, mettendoci però on_off2:

cmd=analyse_cmd((char *)&(buf[dat_p+5]));
        
        if (cmd==2){
                on_off=1;
        	digitalWrite(LED_PIN, LOW);  // Accendi il LED
        }
        else if (cmd==3){
                on_off=0;
        	digitalWrite(LED_PIN, HIGH);  // Spegni il LED
        }
        
       

cmd=analyse_cmd((char *)&(buf[dat_p+5]));
        
        if (cmd==4){
                on_off2=1;
           digitalWrite(LED_PIN2, LOW);  // Accendi il LED
        }
        else if (cmd==5){
                on_off2=0;
           digitalWrite(LED_PIN2, HIGH);  // Spegni il LED
        }      
        
        plen=print_webpage(buf, on_off2);
        plen=print_webpage(buf, on_off);

qui ho fatto come hai detto te ( il fatto di stare a centro pagina ):

uint16_t print_webpage(uint8_t *buf, byte on_off)
{

       int i=0;
    
        
        uint16_t plen;
        
 
        
        plen=es.ES_fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"));
        plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<center><p><h1>Welcome to Arduino Ethernet Shield V1.0  </h1></p></center> "));
         
        plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<hr>
<form METHOD=get action=\""));
        plen=es.ES_fill_tcp_data(buf,plen,baseurl);
        plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("\">"));
        plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<h2> REMOTE LED is  </h2> "));
 				plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<h1><font color=\"#00FF00\"> "));
         
        if(on_off)
        	plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("ON"));
        else 
        	plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("OFF"));
        
        plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("  </font></h1>
 ") );
        
        if(on_off){
        	plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<input type=hidden name=cmd value=3>"));
        	plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<input type=submit value=\"Switch off\"></form>"));
        }
        else {
        	plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<input type=hidden name=cmd value=2>"));
        	plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<input type=submit value=\"Switch on\"></form>"));
        }
        
        plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</center><hr> <p> V1.0 <a href=\"http://www.nuelectronics.com\">www.nuelectronics.com<a>"));
  
        return(plen);
}

poi mi sono accorto che, sempre su questo pezzo di programma, sulla prima riga:
uint16_t print_webpage(uint8_t *buf, byte on_off)
mancasse il riferimento a on_off2; così l’ho aggiunto all’interno in questo modo:
uint16_t print_webpage(uint8_t *buf, byte on_off, byte on_off2)
ricontrollando, ho visto inoltre che anche all’inizio mancava questo riferimento, esattamente qui:

// Preparazione della pagina web
uint16_t print_webpage(uint8_t *buf, byte on_off);
int8_t analyse_cmd(char *str);

e l’ho aggiunto allo stesso modo; quando però ho fatto la verifica mi ha dato errore, e da quello che ho capito è inerente al fatto che erano presenti troppi paramenti nella funzione “uint16_t print_webpage”.
come posso fare per aggiungere il riferimento a on_off2 ( senza di questo, non posso gestire la sua uscita su arduino )?
grazie!!!