Go Down

Topic: [Résolu] Problème de connexion Shield Ethernet + Arduino MEGA (Read 1 time) previous topic - next topic

Rduino2D

Bonjour à tous !

Si je viens ici, vous l'aurez deviné, c'est que j'ai besoin de votre savoir ^^

Je vous présente mon projet : j'ai une Arduino MEGA 2560 + Shield Ethernet (avec port µSD).
J'ai un site web avec plusieurs pages qui sont stockées sur la carte µSD du Shield Ethernet.
J'ai également 2 bacs d'eau et je fais des mesures de débit et de niveau sur ces derniers. Les données récoltées vont directement dans un fichier .txt sur la carte µSD.

Mon site doit afficher les valeurs du fichier txt sur la page php et l'utilisateur peut rafraîchir la page pour rafraîchir les données de niveau et de débit.

La communication entre mon Shield Ethernet et mon Arduino MEGA se fait par câble RJ45
Pour afficher la code PHP correctement, je veux dire, pour simuler que c'est un serveur qui traite le code, je passe par ce logiciel : WampServer

Mon site HTML-CSS-PHP est parfaitement fonctionnel.

Venons-en à mon problème : mon site web (IP 192.168.0.100) ne m'affiche pas les autres page de mon site, mais à chaque fois il me redirige sur la page d'accueil, alors que si j'affiche mon site sans passer par l'Arduino (j'ouvre directement les fichiers avec mon navigateur) je n'ai aucun problème.

Petit exemple, parce que j'an tendance à mal expliquer :

Quand je passe par l'Arduino + IP du site : Je suis sur ma page index.htm (Accueil) et je clic sur "Qui sommes nous ?" par exemple, et il me redirige vers la page "Accueil". Idem si je clic sur un autre lien

Quand je ne passe pas par Aduino (mais ouverture du fichier directement > Ouvrir avec ... > Google Chrome) : Je suis sur la page "Accueil" et je clic sur "Qui sommes-nous ?" et il m'affiche la page "Qui sommes-nous ?". Idem pour les autres lien.

=> Le problème ne vient donc pas de mon code HTML, mais de l'arduino.

Après plusieurs heures de recherches, j'ai enfin trouvé d'où vient mon problème : la connexion entre le client (moi depuis mon PC qui veut accéder à mon site web via l'IP du Shield) s'arrête dès l'affichage de la page d'accueil, et donc, comme mon code l'indique, à chaque nouvelle connexion, il envoie la page d'accueil ...
Le problème vient donc soit de l'Arduino, soit de mon code, que voici :

Code: [Select]
#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>

byte mac[] = {0x90, 0xA2, 0xDA, 0x0D, 0xB0, 0xBF} ;       // Adresse MAC Shield
IPAddress ip(192,168,0,100);                              // IP
byte passerelle[] = { 192, 168, 0, 100 };                 // Passerelle par défaut
byte masque[] = { 255, 255, 255, 0 };                     // Masque sous-réseau

EthernetServer server(80);  // Créé un serveur sur le port 80

File accueil;
File qui;
//boolean pageaccueil;
const int chipSelect = 10;   // Utilise le shield Ethernet  

void setup()
{
    //pageaccueil=false;
    Ethernet.begin(mac, ip);  // Initialise le module Ethernet
    server.begin();           // Commence à vérifier si des clients sont dispo
    Serial.begin(115200);     // Moniteur série
    pinMode(chipSelect, OUTPUT);      // Indique que l'esclave avec qui communiquer à partir de ce moment est sur la pin 53
    digitalWrite(chipSelect, HIGH);
    
    Serial.println("Initialisation de la carte SD ..."); // Initialise la carte SD
    if (!SD.begin(4))
    {
        Serial.println("L'initialisation de la carte SD a echoue");
        return;    // Initialisation échouée
    }
    Serial.println("La carte SD a ete initialisee");  

    
    if (SD.exists("index.htm"))
    {
    Serial.println("Le fichier index.htm a ete trouve");
    }
    
    else
    {
    Serial.println("Impossible de trouver le fichier index.htm");  
    }

}

void loop()
{
    EthernetClient client = server.available();  // Cherche si un client est disponible

    if (client) // Si il y a un client
    {
        Serial.println("Nouveau client connecte au site web");
        boolean currentLineIsBlank = true;
        while (client.connected())
        {
            if (client.available())     // Les données venant du client peuvent être lues
            {
                char c = client.read(); // Analyse chaque caractère de la requête du client
                                        // On ne peut répondre au client qu'une fois qu'il a envoyé la dernière ligne de sa requête : "\n"
                                        
                if (c == '\n' && currentLineIsBlank) // Si le client a fini d'envoyer sa requête
                {
                    // Envoi d'une réponse connexion OK
                    client.println("HTTP/1.1 200 OK");
                    client.println("Content-Type: text/html");
                    client.println("Connection: keep-alive");
                    client.println();
                    
                    Serial.println("HTTP/1.1 200 OK");
                    Serial.println("Content-Type: text/html");
                    Serial.println("Connection: keep-alive");
                    Serial.println();
                    
                    // Envoi de la page WEB depuis la carte SD
                    accueil = SD.open("index.htm");        // Ouvre le fichier index.htm
                    qui = SD.open("qui.htm");
                    
                    if (accueil)//&&pageaccueil==false)
                    {
                        while(accueil.available())
                        {
                            client.write(accueil.read()); // Envoi de la page d'accueil
                            //pageaccueil==true;
                        }
                        accueil.close();
                    }
                    
                    else if (qui)
                    {
                        while(qui.available())
                        {
                            client.write(qui.read()); // Envoi de la page d'accueil
                            //pageaccueil==true;
                        }
                        qui.close();
                    }
                    break;
                }
                
                // Toutes les lignes de texte envoyées par le client finissent par \r\n
                
                if (c == '\n') // Si un des caractères reçus est "\n" alors le client a fini d'envoyer des données
                {
                    currentLineIsBlank = true; // Commence une nouvelle ligne et analyse son contenu > si la ligne est vide, le client a fini d'envoyer des données
                }
                else if (c != '\r') // Si un des caractères reçus est "\r" ou différent alors le client n'a pas fini d'envoyer des données
                {
                    currentLineIsBlank = false; // Le client continue d'envoyer des données
                }
            } // Fin if (client.available())
        } // Fin while (client.connected())
        delay(1);      // Laisse le temps au navigateur de recevoir les données
        //client.stop(); // Arrête la connexion
    } // Fin if (client)
} // Fin void loop()


Je précise que le code est tiré du site Starting Electronics et que je l'ai modifié + commenté pour mon cas.

Je vous donne également les pages de mon site web, au cas où : Pages site web


Si j'ai oublié des infos, demandez les moi je vous les fournirait ;)

Merci d'avance pour votre aide !

bricoleau

Je pense que le problème provient de ton code arduino.
Ton arduino est un serveur web.
Il retourne une et une seule page à chaque connection client.

Si je lis bien ton code, tu ne cherches pas à savoir quelle page est demandée par le client.
Tu retournes systématiquement le contenu du fichier index.htm présent sur ta carte SD.

L'enchaînement des pages ne va pas se faire tout seul.
A mon sens, il manque une analyse de la demande client reçue, pour savoir quel fichier de la carte SD ouvrir et retourner.

Si tu affiches la demande reçue, tu verras qu'elle contient le "GET /index.htm" ou "GET /qui.htm" qui te donne le nom du fichier à ouvrir et à retourner.
Tutoriels arduino : http://forum.arduino.cc/index.php?topic=398112.0

Rduino2D

Si je lis bien ton code, tu ne cherches pas à savoir quelle page est demandée par le client.
Tu retournes systématiquement le contenu du fichier index.htm présent sur ta carte SD.
En effet, c'est bien cela, oui.

Donc ce que tu me propose de faire c'est quelque chose dans ce genre :
Code: [Select]
void loop()
{
  // if there are incoming bytes available
  // from the server, read them and print them:
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }


Et ensuite, j'analyse la GET en faisant quelque chose du genre if(GET=index.htm) j'affiche index.htm ainsi de suite ?
Il faudrait donc que je me positionne dans la requête juste après le GET et j'analyse quel fichier est demandé, c'est bien cela ?

bricoleau

Oui

Mais sans gérer le nom des fichiers de la carte SD, en dur dans ton code arduino.

Tu charges dans une chaîne de caractères NOMFIC ce qui est reçu à la suite du GET, et tu passes ce NOMFIC en paramètre d'appel de SD.open()

Et si open() est en erreur, tu retournes par défaut le contenu de "index.htm"
Tutoriels arduino : http://forum.arduino.cc/index.php?topic=398112.0

Rduino2D

D'accord, je vais essayer de faire cela.

Par contre, petite question : à quoi correspond le "NOMFIC" ? C'est le nom de la chaîne de caractères ou une "fonction spéciale" ?

bricoleau

à rien du tout
c'était juste un nom de variable au pif pour essayer d'être plus clair
C'est raté !  :smiley-roll-sweat:

char NOMFIC[30];
Tutoriels arduino : http://forum.arduino.cc/index.php?topic=398112.0

Rduino2D

D'accord !
Et à quoi correspond le [30] ?
C'est le nombre de caractères max de la variable ?

bricoleau

oui, c'est-à-dire au nom de fichier le plus long parmi ceux présents sur ta carte SD
Tutoriels arduino : http://forum.arduino.cc/index.php?topic=398112.0

Rduino2D

Donc, j'ai essayé de faire de 2 façons différentes :

La première, j'ai analysé le premier caractère de la page demandée dans le GET car vu que aucune de mes pages ne commence par la même lettre, je peux facilement savoir quelle page est demandée en analysant le premier caractère du fichier demandé.

La 2e façon, c'est celle qui tu m'a proposée bricoleau, mais j'ai une petite question :
Selon toi, est-ce-qu'il serait plus simple que je mette la même taille de nom de fichier (exemple 6 caractères ; le point ; l'extention) ou est-ce-que j'analyse le nom du fichier caractère par caractère et dès que je tombe sur un blanc (un espace) j'arrête l'analyse du nom de fichier ?

Edit : J'ai défini char NOMFIC[10]; pour qu'il contienne le nom du fichier demandé, mais quand j'essaie de compiler, j'ai cette erreur :

Code_Ethernet_GET_NOMFIC.ino: In function 'void loop()':
Code_Ethernet_GET_NOMFIC:176: error: incompatible types in assignment of 'File' to 'String [10]'
Code_Ethernet_GET_NOMFIC:180: error: request for member 'available' in 'NOMFIC', which is of non-class type 'String [10]'
Code_Ethernet_GET_NOMFIC:182: error: request for member 'read' in 'NOMFIC', which is of non-class type 'String [10]'
Code_Ethernet_GET_NOMFIC:184: error: request for member 'close' in 'NOMFIC', which is of non-class type 'String [10]'
Code_Ethernet_GET_NOMFIC.ino: At global scope:
Code_Ethernet_GET_NOMFIC:203: error: expected declaration before '}' token


Et la partie du code mise en cause :

Code: [Select]
175                    // Envoi de la page WEB depuis la carte SD
176                    NOMFIC = SD.open("NOMFIC"); // Ouvre le fichier demandé
177                   
178                    if (NOMFIC)
179                    {
180                        while(NOMFIC.available())
181                        {
182                            client.write(NOMFIC.read()); // Envoi de la page d'accueil
183                        }
184                        NOMFIC.close();
185                    }


Vous avez du le voir, dans le code d'erreur, il y a marqué String NOMFIC[10]; c'est tout simplement parce que j'ai essayé avec String, mais j'ai la même erreur qu'avec char.

Rduino2D

Bonjour !

Je reviens à la charge avec du nouveau :

Donc, avec mon programme qui analyse la GET et qui analyse la première lettre du fichier demandé, mon programme marche, à un point près : je me DDoS tout seul ... En clair, je reçois des centaines et des centaines de requêtes, indéfiniment ...
Mon programme passe à la suite une fois qu'il ne reçoit plus de requêtes, or là il en reçoit indéfiniment et donc ne passe jamais à la suite ...

Je vous donne le nouveau code à télécharger car en copier/coller je dépassais les 9000 caractères max : cliquez ici

Le problème est situé vers la ligne 136 (ce qui est normal vu que dans cette situation, le client envoie en continu une requête et donc mon programme ne peut pas passer à la suite :/

Si vous avez des solutions à me proposer, cela ne serait pas de refus !

Merci d'avance !
Rduino2D

Rduino2D

Bonjour à tous !

J'ai réussi à régler mon problème !
Si d'autres personnes auraient le même problème que moi, je vais expliquer ici comment je m'y suis prit :

Donc, pour mon problème d'auto-DDoS, j'ai dû forcer le programme à faire passer la variable boolean currentLineIsBlank en true pour que le programme puisse passer à l'étape suivante.

Ensuite, j'avais un problème avec le trame que j'analysais pour savoir quel fichier renvoyer.
Au premier lancement du programme, tout marchait bien, mais dès que la boucle revenait une 2e fois, la valeur du string gardait en mémoire la première requête.
J'ai donc là aussi dû forcer la remise à zéro de la variable d'analyse juste avant le commencement de l'analyse de la GET.

Une fois ces 2 problèmes réglés, tout fonctionne parfaitement !

Encore merci à bricoleau pour ton aide précieuse ;)

Go Up