Serveur web sur arduino mega+ethernet shield

Bonjour, je suis nouveau sur ce forum.
Je vous salue donc et vous remercie d'avance pour vos conseils et remarques.

Je m'interesse à l'informatique industrielle, j'ai acquis voila un mois une mega 2560, une ethernet shield et quelques composant DS18B20, des potars....

Maintenant je voudrais réaliser un petit serveur web sur la mega, mais là je commence à m'arracher les cheveux...
Mon programme ne fonctionne pas correctement enfin plutot pas à tous les coups...
Pire la gestion des requetes GET et POST devient un creve coeur , je n'obtiens pas les meme resultats entre Firefox et IE

Je parviens à ouvrir la page sur les navigateurs, la page contient des ressources javascript,css et image contenues dans la carte SD.
Les requetes POST et GET ne sont traités que partiellement, j'extrais les noms et valeurs des paramètres transmis par les formulaires.

Mais quand je commence à rajouter autre chose dans la loop genre lecture des DS18B20 le serveur web ne fonctionne plus du tout ]:slight_smile:

J'ai lue pas mal de topics, de page sur le sujet mais je ne progresse plus...
Aussi je m'en remets aux bonnes volontés que ce genre d'applications interressent.

Voila le code du projet en version 0.33, sans le code lecture des DS18B20
Je me doute que le code soit optimisable et perfectible.

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
#include <Server.h>
#include <Client.h>
const int chipSelect_SD = 4;
const int chipSelect_W5100 = 10;
const int chipSelect_SPISS = 53;
const byte HTTP_LenInfoReq = 3;
const boolean HTTP_DEBUG = true;
boolean SD_Ready = false;
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192,169,0,2 };
byte passerelle[] = { 192, 169, 0, 1 };
byte masque[] = { 255, 255, 255, 0 };
EthernetServer serveurHTTP(80);
String HTTP_ReqData;
char* HTTP_ReqTokens[3];
String HTTP_RequestAction;
String HTTP_ParamNameValue[10][2];
char HTTP_Buffer[160];byte HTTP_Sbuf = 0;
char HTTP_Buffer2[160];byte HTTP_Sbuf2 = 0;
String HTTP_HEADERS_Servername = "ServerLight 0.1";
String HTTP_HEADERS_ContentType ="";
unsigned long HTTP_HEADERS_RscSize;
boolean HTTP_HEADERS_IsReqProc;
boolean HTTP_HEADERS_IsReqAction;
boolean HTTP_HEADERS_IsReqActionGET;
boolean HTTP_HEADERS_IsReqActionPOST;
boolean HTTP_HEADERS_IsReqResc;
boolean HTTP_HEADERS_IsReqRescOk;

void setup() 
{
  if(HTTP_DEBUG){ Serial.begin(9600); }
  pinMode (chipSelect_W5100, OUTPUT);digitalWrite(chipSelect_W5100,HIGH);
  pinMode(53, OUTPUT);
  if(SD.begin(chipSelect_SD)){ SD_Ready = true; }
  Ethernet.begin(mac, ip, passerelle, masque);
 serveurHTTP.begin();
  HTTP_HEADERS_Reset();
}
void loop()
{
  boolean test = false;
  
  EthernetClient client = serveurHTTP.available();

  if (client) 
  {
    while (client.connected()) {
        if(ReceptionRequeteClient(client))
        {
          if(HTTP_DEBUG){ Dbg_Afficher_Requete(); }
          HTTP_HEADERS_IsReqProc = true;
          ExtraireInfoRequete();
          GestionRequete(client);
        }
        else 
        { 
          HTTP_HEADERS_IsReqProc = false;		  
          HTTP_HEADERS_Send(client); 
        }
        delay(1);client.stop();
    }

  }
  delay(1000);
Serial.println("Winting for connection");
}
boolean ReceptionRequeteClient( EthernetClient& eclient)
{
	
  int i = 0;int j=0;
  int sizebuff = sizeof(HTTP_Buffer) - 1;
  int sizebuff2 = sizeof(HTTP_Buffer) - 1;
  char ch;char lastch;
  boolean firstline = false;
  HTTP_ReqData="";

  memset( HTTP_Buffer, 0, sizeof(HTTP_Buffer) );
  
   while (eclient.available()) {
     
	ch = eclient.read();
	HTTP_ReqData = HTTP_ReqData + ch;
        if(!firstline)
        {
			HTTP_Buffer[i] = ch;i++;
			if(i>sizebuff) { HTTP_HEADERS_IsReqProc=false;return false; }       
			if (ch == '\n') { HTTP_Buffer[i] = ch;firstline = true; }
        }
		else
		{
			if (lastch == '\n')
			{
				memset( HTTP_Buffer2, 0, sizeof(HTTP_Buffer2) );
				j = 0;
				HTTP_Buffer2[j] = ch;j++;
			}
			else
			{
				HTTP_Buffer2[j] = ch;j++;
			}
		}
		lastch = ch;
  }
  HTTP_HEADERS_IsReqProc = true;
  return true;  

}
void GestionRequete( EthernetClient& eclient )
{
  String ReqTokens0 = HTTP_ReqTokens[0];
  String ReqTokens1;
  String ExtractReq1;
  int iTemp = -1;
	            
  if(ReqTokens0 == "GET")
  {
    ReqTokens1 = HTTP_ReqTokens[1];iTemp = ReqTokens1.indexOf('?');
    if (iTemp != -1)
    {
      if(HTTP_DEBUG){ Serial.println("Req = GET avec parametre"); }
      HTTP_HEADERS_IsReqAction = true;              
      ExtractReq1 = ReqTokens1.substring(1);
      iTemp = ExtractReq1.indexOf('?');
      HTTP_RequestAction = ExtractReq1.substring(0 , iTemp);
      ExtractReq1= ExtractReq1.substring(iTemp+1);
      ExtractReq1.toCharArray(HTTP_Buffer2 ,160 );
      
      if(HTTP_DEBUG)
      {
        Serial.print("GET method = ");Serial.print(HTTP_RequestAction);Serial.println();
        Serial.print("GET param+value = ");Serial.print(ExtractReq1);Serial.println();
      }
      
      ExtraireParamValueRequete();
      HTTP_HEADERS_IsReqAction = true;
      HTTP_HEADERS_IsReqActionGET =true;
      HTTP_HEADERS_Send(eclient);
    }
    else
    {
      if(ReqTokens1 == "/" )
      {
        String sTempIndexHtml = HTTP_Index();
        char HTTP_FileBuffer[1024];
        sTempIndexHtml.toCharArray(HTTP_FileBuffer ,1024 );
	HTTP_HEADERS_Send(eclient);
	eclient.write(HTTP_FileBuffer);
        //if(HTTP_DEBUG) { Serial.println("Req = GET racine du serveur");Serial.println(HTTP_FileBuffer); }
      }
      else
      {
        if(HTTP_DEBUG){ Serial.println("Req = GET demande ressource "); }
        ExtractReq1 = ReqTokens1.substring(1); // supprime le premier slash
	HTTP_EnvoieRessource( eclient , ExtractReq1 );
      }
    }
  }
  else
  {
    if(ReqTokens0 == "POST")
    {
      if(HTTP_DEBUG){ Serial.println("Req = POST avec parametre"); }
      //HTTP_HEADERS_IsReqAction = true;
      ExtractReq1 = HTTP_ReqTokens[1];
      HTTP_RequestAction = ExtractReq1.substring(1);
      ExtraireParamValueRequete();
      HTTP_HEADERS_IsReqAction = true;
      HTTP_HEADERS_IsReqActionPOST=true; 
      HTTP_HEADERS_Send(eclient);
    }
    else 
    {
      if(HTTP_DEBUG){ Serial.println("Req = UNKNOW erreur 500"); }
      HTTP_HEADERS_Send(eclient);
    }
  }	
}
[code]
void ExtraireParamValueRequete()
{
	char *pcharPV;
	byte bPVIdx = 0;
	byte bPVIdx2 = 0;
	String Param;

	pcharPV = strtok(HTTP_Buffer2, "&");
	bPVIdx = 0;
        if(HTTP_DEBUG) { Serial.println("-------    PARAM VALUE VERS TOKEN  (loop)   --------");}
        		      
	while (pcharPV != NULL)
	{
		Param =  pcharPV;
		bPVIdx2 = Param.indexOf('=');
		HTTP_ParamNameValue[bPVIdx][0] = Param.substring( 0 , bPVIdx2 );
		HTTP_ParamNameValue[bPVIdx][1] = Param.substring( bPVIdx2 + 1 );
		if(HTTP_DEBUG) 
                { 
                  Serial.print(HTTP_ParamNameValue[bPVIdx][0]);Serial.print(" vaut  ");Serial.print(HTTP_ParamNameValue[bPVIdx][1]);Serial.println();
                }
		bPVIdx++;
		pcharPV = strtok(NULL, "&");
	}
}
String HTTP_Index()
{
  String sIndex ="<html>";
  sIndex +="<head>";
  sIndex +="<title>Connexion au Serveur Arduino</title>";
  sIndex +="<SCRIPT type=\"text/javascript\" src=\"./web/libjs.js\"></SCRIPT>";
  sIndex +="<link rel=\"stylesheet\" media=\"all\" href=\"./web/style.css\" type=\"text/css\" />";
  //sIndex +="<META HTTP-EQUIV=\"Refresh\" CONTENT=\"60\">";
  sIndex +="</head>";
  sIndex +="<body onclick=\"testjs()\">";
  sIndex +="<h1>INDEX DU SERVEUR ARDUINO</h1>";
  sIndex +="<img src=\"./web/logo.gif\" width=\"250\"/>";
  sIndex +="<h3>Carte SD</h3>";
  sIndex +="Carte SD : ";
  if(SD_Ready) { sIndex +="OK"; } else {  sIndex +="DEFAUT"; }
  sIndex +="<h3>Formulaire post</h3>";
  sIndex +="<form METHOD=\"POST\" ACTION=\"\\action\">";
  sIndex +="nom : <INPUT type=text name=\"nom\">";
  sIndex +="prenom <INPUT type=text name=\"prenom\">";
  sIndex +="<INPUT type=\"submit\" value=\"POST\">
";
  sIndex +="</form>";
  sIndex +="<h3>Formulaire get</h3>";
  sIndex +="<form METHOD=\"GET\" ACTION=\"\\action\">";
  sIndex +="nom <INPUT type=text name=\"nom\">";
  sIndex +="prenom <INPUT type=text name=\"prenom\">";
  sIndex +="<INPUT type=\"submit\" value=\"GET\">
";
  sIndex +="</form>";    
  sIndex +="</body>";
  sIndex +="</html>";
  HTTP_HEADERS_IsReqResc = true;	
  HTTP_HEADERS_IsReqRescOk = true;
  HTTP_HEADERS_ContentType = SelectContentType("index.html");//on force contenu
  HTTP_HEADERS_RscSize = sIndex.length();
  return sIndex;
}
String SelectContentType( String PathFile )
{
  // Extraction extension fichier
  byte iTemp = PathFile.indexOf('.');
  String FilEx = PathFile.substring(iTemp+1);
  byte bCT = -1;
  String sCT="";
  
  if( FilEx.equals("JS")  || FilEx.equals("js") ) {bCT = 0;}
  if( FilEx.equals("JPEG")  || FilEx.equals("jpeg") || FilEx.equals("JPG") || FilEx.equals("jpg") ) {bCT = 1;}
  if( FilEx.equals("PNG")  || FilEx.equals("png") ) {bCT = 2;}
  if( FilEx.equals("GIF")  || FilEx.equals("gif") ) {bCT = 3;}
  if( FilEx.equals("CSS")  || FilEx.equals("css") ) {bCT = 4;}
  if( FilEx.equals("HTML")  || FilEx.equals("html") || FilEx.equals("HTM") || FilEx.equals("htm") ) {bCT = 5;}
  
  switch(bCT)
  {
  case 0 : sCT = "Content-Type:application/javascript;";break;
  case 1 : sCT = "Content-Type:image/jpeg;";break;
  case 2 : sCT = "Content-Type:image/png;";break;
  case 3 : sCT = "Content-Type:image/gif;";break;
  case 4 : sCT = "Content-Type:text/css;";break;
  case 5 : sCT = "Content-Type:text/html;";break;
  default : sCT = "Content-Type:text/plain;";
  }
  return sCT;
}

void ExtraireInfoRequete()
{
  char *pcharInfo;
  byte bInfoIdx = 0;
    
  pcharInfo = strtok(HTTP_Buffer, " ");
  
  while ( (pcharInfo != NULL) && (bInfoIdx < HTTP_LenInfoReq )) 
  {
    HTTP_ReqTokens[bInfoIdx] = pcharInfo;
    bInfoIdx++;
    pcharInfo = strtok(NULL, " ");
  }
}
boolean HTTP_EnvoieRessource( EthernetClient& eclient , String PathFile )
{
  File SD_Datafile;
  size_t size;
  char CharPathFile[50];
  char FileBuffer2[1024];
  HTTP_HEADERS_IsReqResc = true;
  HTTP_HEADERS_IsReqRescOk = false;
	
  if(SD_Ready)
  {
    PathFile.toCharArray( CharPathFile , sizeof(CharPathFile) );
    SD_Datafile = SD.open( CharPathFile , FILE_READ);
    if(SD_Datafile)
    {
      HTTP_HEADERS_IsReqRescOk = true;
      HTTP_HEADERS_ContentType = SelectContentType(PathFile);
      HTTP_HEADERS_RscSize = SD_Datafile.size();
      HTTP_HEADERS_Send(eclient);

      while ((size = SD_Datafile.read(FileBuffer2, sizeof(FileBuffer2))) > 0) 
      {
        eclient.write((uint8_t*)FileBuffer2, size);
        if(HTTP_DEBUG)  {Serial.println("-------    Boucle lecture fichier   --------");}
      }
      SD_Datafile.close();// close the file:
      //if(HTTP_DEBUG)  {    Serial.println("-------    ENVOI RESSOURCE reussi   --------");Serial.println(CharPathFile);}
    }
    else
    {
      HTTP_HEADERS_IsReqRescOk = false;
      HTTP_HEADERS_Send(eclient);
      //if(HTTP_DEBUG)  {    Serial.println("-------    ENVOI RESSOURCE echec   --------");Serial.println(CharPathFile);}
    }
  }
  	
}
void HTTP_HEADERS_Reset()
{
	HTTP_HEADERS_Servername = "ServerLight 0.1";
	HTTP_HEADERS_ContentType ="";
	HTTP_HEADERS_RscSize = 0;
	HTTP_HEADERS_IsReqProc = false ; //requete client gerable
	HTTP_HEADERS_IsReqAction = false ; //requete client FORM ou POST
        HTTP_HEADERS_IsReqActionPOST = false ;
        HTTP_HEADERS_IsReqActionGET = false ;
	HTTP_HEADERS_IsReqResc = false ; //requete client ressource
	HTTP_HEADERS_IsReqRescOk = false ; //requete client ressource ok

}
//----------------------------------------------------------------------------------
void HTTP_HEADERS_Send( EthernetClient& eclient )
{
	int HCode = 0;
	char tampon[32];

  if ( !HTTP_HEADERS_IsReqProc ){ HCode = 413; }		
  if ( !HTTP_HEADERS_IsReqAction && !HTTP_HEADERS_IsReqResc ){ HCode = 500; }	
  if ( (HTTP_HEADERS_IsReqResc && HTTP_HEADERS_IsReqRescOk) || HTTP_HEADERS_IsReqAction ){ HCode = 200; }
  if ( HTTP_HEADERS_IsReqResc && !HTTP_HEADERS_IsReqRescOk ){ HCode = 404; }
/*	
  if(HTTP_DEBUG)  
  {    
    Serial.println("-------   HTTP_HEADERS_Send   --------");
    Serial.println(HCode);
    Serial.println("--- HEADERS----");
    Serial.print("HTTP_HEADERS_Servername : ");Serial.print(HTTP_HEADERS_Servername);Serial.println();
    Serial.print("HTTP_HEADERS_ContentType : ");Serial.print(HTTP_HEADERS_ContentType);Serial.println();
    Serial.print("HTTP_HEADERS_RscSize : ");Serial.print(HTTP_HEADERS_RscSize);Serial.println();
    Serial.print("HTTP_HEADERS_IsReqProc : ");Serial.print(HTTP_HEADERS_IsReqProc);Serial.println();
    Serial.print("HTTP_HEADERS_IsReqAction : ");Serial.print(HTTP_HEADERS_IsReqAction);Serial.println();
    Serial.print("HTTP_HEADERS_IsReqResc : ");Serial.print(HTTP_HEADERS_IsReqResc);Serial.println();
    Serial.print("HTTP_HEADERS_IsReqRescOk :");Serial.print(HTTP_HEADERS_IsReqRescOk);Serial.println();
    
  }
  */
	switch(HCode)
	{
	case 200:
                if( HTTP_HEADERS_IsReqAction )
                {
                  if(HTTP_HEADERS_IsReqActionGET) { eclient.println("HTTP/1.1 204 No Content");eclient.println("Connection: close");eclient.println(); }
                  if(HTTP_HEADERS_IsReqActionPOST) { eclient.println("HTTP/1.1 204 No Content");eclient.println("Connection: close");eclient.println(); }
                }
                else
                {
                  eclient.println("HTTP/1.1 200 OK");
		  eclient.println(HTTP_HEADERS_Servername);
		  eclient.println(HTTP_HEADERS_ContentType);
		  sprintf(tampon,"Content-Length:%d", HTTP_HEADERS_RscSize);
		  eclient.println(tampon);
		  eclient.println("Connection: close");
		  eclient.println();
                }
		break;
	case 404:
		eclient.println("HTTP/1.1 404 Not Found");
		eclient.println("Connection: close");
		eclient.println();
		break;
	case 413:
		eclient.println("HTTP/1.1 413 Request Entity Too Large");
		eclient.println("Connection: close");
		eclient.println();
		break;
	case 500:
	        eclient.println("HTTP/1.1 500 Internal Server Error");
	        eclient.println("Connection: close");
	        eclient.println();	
	default:
	    eclient.println("HTTP/1.1 500 Internal Server Error");
	    eclient.println("Connection: close");
	    eclient.println();
	}
	
  HTTP_HEADERS_Reset();
	
}
void Dbg_Afficher_Requete()
{
	Serial.println("-------    REQUETE CLIENT  --------");
	Serial.println(HTTP_ReqData);
}

[/code]

J'avais eu un peu le meme problème pour mixer de la réception XBee, publication ethernet et gestion de l'intensité d'éclairage d'un LCD + lecture de températures.

Il ne faut pas boucler en permanence ce qui n'est pas indispensable. C'est pourquoi j'avais utilisé un CASE+SWITCH pour chaque "fonction" de l'arduino avec un déclenchement à certains moments seulement pour certains.

Un extrait du code:

//// START MAIN ////
void loop()
{   
    t = now(); // get local unix time
    
    // change LCD display every five seconds
  
    switch(valeur)
    {
        case 1: // reading tmp102&LM35 internal temperatures
              tmp102();
              //lm35dz();
            valeur=2;
            break;
            
        case 2: // reading Stalker v2 external data communicating with XBEE radio module
              xbee();
            valeur=3;
            break;
            
        case 3: // cut received data into separate strings and setup min max temperatures
              if(second(t) %  5 == 0) {// refresh
              stringTostring();
              minmaxtemp();
              }
               
            valeur=4;
            break;
            
        case 4: // publish results on webserver        
              ether();
            valeur=5;
            break;
            
        case 5: // publish results on lcd screen  
              time=millis();
              time2=millis();
              
              // print current temperatures
              if (time-lastTime>DISPLAY_INTERVAL)  // if at least DISPLAY_INTERVAL ms have passed
              {
                currenttemperatures();  // update display
                lastTime=time;  // reset timer
              }
              // print min max temperatures
              if (time2-lastTime2>DISPLAY_INTERVAL2)  // if at least DISPLAY_INTERVAL2 have passed
              {
                minmaxtemperatures();  // update display
                lastTime2=time2;  // reset timer
                lastTime=time;
              }
            valeur=6;
            break;
            
            case 6: // Backlight control of the LCD Screen with a LDR
              backlightcontrol();
              //if(second(t) %  15 == 0) {// refresh
              
              //}

            
            valeur=1;
            break;
        default: //problem in the program
            problem();
            break;
    }   

}
//// END MAIN ////

Mais ce n'est surement pas la meilleure solution, on doit aussi pouvoir utiliser les interruptions pour ça.

Bonjour,

Pourquoi vouloir réinventer la roue quand des parser HTTP complets existent déja :wink:
http://code.google.com/p/webduino/
http://www.webweavertech.com/ovidiu/weblog/archives/000484.html

Because i 've alaready try...perso j'ai pas reussi a le faire fonctionner :astonished: As tu reussi ,toi, a le faire fonctionner ?

J'ai essaye de comprende le code qui me semble aussi imbitable que la doc fourni mais cela m'est permie d'avancer un peu

Mais bon on est entetete aussi on perserve, dans l'erreur ? telle est la question ?!

Arnaud56410:
Because i 've alaready try…perso j’ai pas reussi a le faire fonctionner :astonished: As tu reussi ,toi, a le faire fonctionner ?

Oui … les deux même.
Je préfère webduino pour sa syntaxe un peu plus simple mais TinyWebserver est quasiment identique …

Arnaud56410:
J’ai essaye de comprendre le code qui me semble aussi imbitable que la doc fourni mais cela m’est permie d’avancer un peu

Regarde les exemples, les deux librairie sont basées sur un système de callback + handler (programmation événementielle)
https://github.com/sirleech/Webduino/blob/master/examples/Web_HelloWorld/Web_HelloWorld.ino
https://github.com/ovidiucp/TinyWebServer/blob/master/examples/SimpleWebServer/SimpleWebServer.ino