Communication Ethernet TCP

Bonjour à vous tous

Je suis sur un projet d’un contrôleur pour mon installation Photovoltaïque.

J’ai réalisé cette carte « CPU_1284 » qui pour but de géré l’installation solaire et de transféré des données entre claques équipements.

J’utilise un ATMEGA1284 sur ce projet.

J’ai besoin des 5 bus de communication pour ce projet.

UART 0 pour la communication Modbus avec les 2 régulateurs de charge, et un module d’entrées sortie décentralisé.

UART 1 Pour la communication avec les onduleurs

UART 2 (SoftwareSerial) pour la communication avec un transmetteur de puissance.

ETHERNET (module W5500) pour la communication avec mon automate S7-300 Siemens de ma domotique

I2C pour l’affichage sur un LCD 20x4, un clavier, et un écran oled SSD1309 (qui ne fonctionne pas)

Je galère avec la communication Ethernet :

J’essaye de faire communiqué l’automate avec la CPU_1284 dans le but que l’automate lise un tableau de 64 mots (int) et qui écrive dans un tableau de 32 mots (int)

Du côté de l’automate, j’utilise les fonction AG_SEND pour envoyer une trame et AG_RECEIVE pour lire une trame.

J’’utilise c’et fonctions avec une passerelle Ethernet RS485 de Moxa, et la liaison série entre la passerelle et un Atmega, ça fonctionne.

Maintenant je souhaite que l’automate communique directement avec ma CPU_1284 en Ethernet.

L’automate et le client, et ma CPU_1284 et un serveur.

J’ai dû mal à comprendre les fonction client.read() , client.write() serveur.write(),…

// _________________________________________ Ethernet
// si  un client entrant se connecte, il y aura des octets disponibles à lire :
EthernetClient client = server.available();// crée un objet Client correspondant au client détecté par le serveur
if (client && client.connected())         // si l'objet client n'est pas vide
   {
    affC();                               // DM9368 AFFICHE C sur 7 SEGMENTS
           if (client.available()>0)
            { 
            EchangeEcritureSiemens[32] = client.read();
// ?????????
              server.write(EchangeLectureSiemens[64]);
            }       
           // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    aff1();                                               // DM9368 AFFICHE 1 sur 7 SEGMENTS
  }

J’espère d’être bien clair dans mon sujet.

Cordialement

Salut

En faisant comme cela tu écris uniquement dans le 33è élément du tableau.

En faisant comme cela tu envoies uniquement le 65è élément du tableau.
De plus, pour répondre à un client on utilise plutôt client.write() ou client.print().

Si tu veux recevoir une suite d'octets il faut le faire avec une boucle :

    int x = 0;
    while (client.connected()) {
      if (client.available()) {
        EchangeEcritureSiemens[x++] = client.read();
      }
    }
    delay(1);
    client.stop();

EchangeEcritureSiemens doit être correctement dimensionné. Côté Arduino un int = 2 bytes.

Si tu es persuadé que cette ligne permettra de recevoir 32 octets, il serait préférable d'appendre le langage, avec un tutoriel.

Salut
je dois faire une boucle pour l'envoie de plusieurs octet?

Pas forcément.
La classe EthernetClient possède une méthode :

size_t write(const uint8_t *buf, size_t size);
Mais elle possède également une méthode read() équivalente : 
int read(unsigned char* buffer, size_t len);
int read(char* buffer, size_t len);

Bonjour
Ma carte vois bien le client (Automate) est connecté: (La lettre "C" s"affiche sur mon afficheur 7 segments grace a "affC(); pendant 1/4 de secondes et revient a "1").
Ca me permet de savoir si le client est connecté.

Mon automate me renvoie un code erreur signifiant que la tache d'envoie (AG_SEND) ne s'est pas bien déroulé.

Dans ce cas:
Automate -----------> MOXA Npor Eth RS232 ---------> Arduino ca fonctionne.
MOXA Nport 5110 configuré en mode serveur TCP.

Dans ce cas:
Automate -------------------------> Arduino avec module W5500. ca ne fonctionne pas.

// _________________________________________ Ethernet
// si  un client entrant se connecte, il y aura des octets disponibles à lire :
EthernetClient client = server.available();// Regarde si un client est connecté et attend une réponse
if (client)                               // Un client est là ?
  { // 01 
   int y = 0;                             // on remet à zéro notre chaîne tampon
   int x = 0;
   affC();                                // DM9368 AFFICHE C sur 7 SEGMENTS
   while (client.connected())             // Tant que le client est connecté
      { // while
      if (client.available())             // A-t-il des choses à dire ?
         { 
          // traitement des infos du client
          EchangeEcritureSiemens[x++] = client.read();  //on lit ce qu'il raconte
         }  //else {
            //        client.write() =  EchangeLectureSiemens[y++]);  //on lui repond
            //     }

       delay(10);
      client.stop();                       // close the connection:
      aff1();                              // DM9368 AFFICHE 1 sur 7 SEGMENTS
      } // while
  } // 01

Je ne reçois toujours rien.

je ne comprend pas bien a quel moment la boucle x++ se termine, car la fonction while se termine après la fonction client.stop() ?
Quand le client a tout dit , il dois lire les 64 variable int avant de se déconnecter.

Coté automate, il y a une cadence. j'envoie mes variables a ma carte ave AG_SEND, et a la fin de l'execution de la fonction, j’appelle a fonction AG_RECEIVE pour recuperé les données de ma carte.

https://support.industry.siemens.com/cs/document/8707570/transfert-de-donn%C3%A9es-(avec-fc5-ag_send-et-fc6-ag_recv-)-avec-des-t%C3%A9l%C3%A9grammes-de-longueur-variable-et-en-utilisant-le-protocole-tcp?dti=0&lc=fr-WW

Dans ma table d’échange, l'automate envoie un mot d’état sur le 1 er mot et la date et heure sue les 6 mots suivant. le mot 7 a 32 sont a 0.
L'envoie de données ver ma Carte n'est pas le plus important, c'est juste pour du réglage de seuil.
En revanche, la lecture des données de ma carte et importante, c'est pour l'affichage vers un IHM.

Si tu t'inspirais de l'exemple donné plus haut :
https://github.com/arduino-libraries/Ethernet/blob/master/examples/WebServer/WebServer.ino
Tu verrais que delay(1) et client.stop() sont en dehors de la boucle while().

Forcément, tu n'envoies rien. Le serveur de l'exemple répond : client.println()
Dans cet exemple, il s'agit d'une réponse du type HTTP, mais cela ne change pas grand chose.

Salut.
Je ne pige pas bien la communication Ethernet. je dois répondre quoi au client? simplement un client.println() et après ca, je peux récupéré les infos envoyer par l'automate.

Qu'et est la fonction de la variable boolean "currentLineIsBlank" dan votre exemple?

Avec ce code, il la connection client s’établit pendan approximativement 25 secondes, ce qui est trop long pour mon projet.
mai ma carte reboote a chaque fin de connexion. pour commencé j'envoie juste l'horloge et un mot d’état ou je recupere un bit pour synchronisé l’horloge. celle ci affiche 00/00/2058 00:57:24. je ne sait pas ci j'ai reçu une trame éroné, ou ci l'horloge c'est déréglé suite au reboot de la carte.
L'automate ne reçois rien de la table d’échange "EchangeLectureSiemens"

EthernetClient client = server.available();// Regarde si un client est connecté et attend une réponse
if (client)                               // Un client est là ?
  { // 01 
   int y = 0;                             // on remet à zéro notre chaîne tampon
   int x = 0;
   affC();                                // DM9368 AFFICHE C sur 7 SEGMENTS
   bool currentLineIsBlank = true;
   while (client.connected())             // Tant que le client est connecté
      { // while
      if (client.available())             // A-t-il des choses à dire ?
         { 
          // traitement des infos du client
          //char c = client.read();
          EchangeEcritureSiemens[x++] = client.read();  //on lit ce qu'il raconte
          char c = EchangeEcritureSiemens[x];
          if (c == '\n' && currentLineIsBlank)
             {
              // send a standard HTTP response header
              
              client.println("HTTP/1.1 200 OK");          // Tout d'abord le code de réponse 200 = réussite
              client.println("Content-Type: application/json");  // Puis le type mime du contenu renvoyé, du json
              client.println();                             // On envoie une ligne vide pour signaler la fin du header
            
              for (int y = 0; y < 64; y++) 
                  {
                  client.print(EchangeLectureSiemens[y]);
                  client.println("<br />");
                  }
             break;
             } 
             
          if (c == '\n') 
              {
              currentLineIsBlank = true;              // vous démarrez une nouvelle ligne
              } else if (c != '\r') 
                        {
                        currentLineIsBlank = false;   // vous avez un caractère sur la ligne courante
                        }  
                        
         }   
    } // while
    delay(10);              // Attente
    client.stop();          // close the connection:
    aff1();                 // DM9368 AFFICHE 1 sur 7 SEGMENTS
  } // 01

Tout dépend de la réponse qu'attend le client.

Cela fait partie de la réponse classique HTTP, inutile si tu utilises TCP seul.

j'utilise une conexión TCP pas de HTTP.
Pour répondre au client, je ne sait pas du tout ce qu'il attend. j'utilise des fonction AG-SEND et AG_RECEIVE pour échanger des données. c'est fonction son propre a Siemens, je ne sait pas comment elle son traité.
Je configure une liaison TCP dan ma config materiel, cette configuration me génère un ID et une adresse de liaison, qui correspond a l'IP du serveur et son port.
Je rentre c'et ID dans mes blocks de fonction, ainsi le pointeur de destination dan lequel je recupere mes données. Apelle la fonction et le tour et joué.

en utilisant cette passerelle RS485 ver un Arduino, ca fonctionne.
https://www.moxa.com/Moxa/media/PDIM/S100000213/moxa-nport-ia5000-series-manual-v4.0.pdf

Dans ce cas, l'ARDUINO renvoie bien une réponse, que tu as toi-même définie ?
Il suffit peut-être de renvoyer la même ?

bonjour hbachetti
la passerelle est un serveur serie. dans ce cas, j'utilise simplement "Serial.Write(xx) et serial.read(xx). c'est le moxa qui gére la connection TCP.

je fouille les trames avec Wireshark entre la moxa et l'automate, pour vois ci ca peux m'aidé. ca me donne ceci:

je vais continué a creusé. mais plutôt sur le transfert de donné de ma carte ves l'automate, il est plus important dan mon projet.

Bonjour
Je ne reçois toujours rien en provenance de l’automate ?

// _________________________________________ Ethernet
// si  un client entrant se connecte, il y aura des octets disponibles à lire :
EthernetClient client = server.available();// Regarde si un client est connecté et attend une réponse
if (client)                               // Un client est là ?
  { // Client 
   //int y = 0;                             // on remet à zéro notre chaîne tampon
   int x = 0;
   affC();                                // DM9368 AFFICHE C sur 7 SEGMENTS
   while (client.connected())             // Tant que le client est connecté
      { // while
      if (client.available())             // A-t-il des choses à dire ?
         { 
          // traitement des infos du client
          EchangeEcritureSiemens[x++] = client.read();    //on lit ce qu'il raconte
          client.println();                               // On envoie une ligne vide pour signaler la fin du header

          for (int y = 0; y < 128; y++) 
              {
               client.print(EchangeLectureSiemens[y]);
              }
          break;
         }   
    } // while
    delay(10);              // Attente
    client.stop();          // close the connection:
    aff1();                 // DM9368 AFFICHE 1 sur 7 SEGMENTS
  } // Client

En revanche, l’automate récupère bien les 128 byte de ma carte, mais je reçois n’importe quoi.

Mon 1er mot affiche :3338 et reste fixe, alors qui devrais affiché le mot de vie de ma carte.
Les 3 mots suivant affiche une valeur qui change à chaque transfert avec ma carte.
Cette valeur ne veux rien dire. je devrai avoir des 0.
Les mots suivant affiche : 12336 alors que je devrais avoir 0

Mon tableaux d’envoi EchangeLectureSiemens : les 2 premier byte corresponde à un mot de vie qui s’incrémente par pas de 100 jusqu'à 5000 et reviens a 0.

if (BoucleR == 10)
  {
    MotdeVie = MotdeVie + 100;
    if (MotdeVie > 5000)
        {
        MotdeVie = 0;
        }
  // Le transfert d'un int comme deux octets
  //char MotdeVieMSB = (char)highByte(MotdeVie);
  //char MotdeVieLSB = (char)lowByte(MotdeVie);
  EchangeLectureSiemens[0] = MotdeVie & 0b11111111;
  EchangeLectureSiemens[1] = MotdeVie >> 8;
  }

Dans l’automate, ça me permet de surveillé la communication. Si celle valeur se fige, il n’y a plus de communication.

Le reste du tableau, sont des valeurs. Elle son a 0 actuellement.
Je sèche

EchangeEcritureSiemens reçoit des bytes de ton client. Combien ?
Ensuite tu renvoies au client, (pour chaque byte reçu !), 128 bytes du même buffer.

Et que fait ce break après l'envoi ?

Le client envoie 64 Bytes, que je veux stocké dan mon tableaux "EchangeEcritureSiemens"
Fonction AG_SEND
une foi qu'il a fini d'envoyer ces bytes, le client viens lire les 128 bytes d'un autre tableaux "EchangeLectureSiemens"
Fonction AG_RECEIVE

Coté automate: voir le lien dan mon post #7

Tel que je vois le code, après le premier octet reçu, le serveur envoie une ligne blanche (println), puis 128 octets, ensuite break, ce qui empêche de recevoir le reste.

Je vous envoi mon code complet en PJ.
Celui-ci n'est pas terminé
Automate_Solaire_REV0.zip (24,4 Ko)

Je commence a mieux comprendre:

EthernetClient client = server.available();// Regarde si un client est connecté et attend une réponse
if (client)                               // Un client est là ?
  { // Client 
   //int y = 0;                             // on remet à zéro notre chaîne tampon
   int x = 0;
   affC();                                // DM9368 AFFICHE C sur 7 SEGMENTS
   while (client.connected())             // Tant que le client est connecté
      { // while
      if (client.available())             // A-t-il des choses à dire ?
         { 
          // traitement des infos du client
          EchangeEcritureSiemens[x++] = client.read();    //on lit ce qu'il raconte
          break;

          client.println();                               // On envoie une ligne vide pour signaler la fin du header
          for (int y = 0; y < 128; y++) 
              {
               client.print(EchangeLectureSiemens[y]);
              }
          
         }   
    } // while
    delay(10);              // Attente
    client.stop();          // close the connection:
    aff1();                 // DM9368 AFFICHE 1 sur 7 SEGMENTS
  } // Client