Envoi reception ESP-NOW

Bonjour,

j'utilise régulièrement le protocole NOW des ESP32 pour communiquer sur différents accessoires mais je suis tombé sur un problème qui m'arrache un peu les cheveux !

J'utilise une structure pour l'envoi de mes trames qui contient le TYPE et le MESSAGE qui sont toute deux des valeurs au format STRING.

Depuis une première carte j'envoi donc :

TYPE : "ACTION"
MESSAGE : "LEDON"

sur la seconde je reçois :

TYPE : "ACTION"
MESSAGE : "(8ѤN"

ma question est donc de comprendre pourquoi j'obtiens bien la String TYPE correctement mais pas la string MESSAGE.

A noté que (8ѤN reviens à chaque fois que je tape "LEDON" pour l'envoi ce n'est donc pas aléatoire. Cela doit être codé mais pourquoi ? Sachant également que le TYPE apparait comme il faut ...

Je précise aussi que mes deux structures sont identique dans les 2 codes et que les fonctions OnDataRecv() et OnDataSent() sont également identiques.

Merci de votre aide !

postez un code minimaliste démontrant le souci.

êtes vous sûr de bien imprimer la bonne chose ? le buffer est-il persistant ?

Mince j'ai pas eu la notification par mail qu'une réponse était publié ...
Désolé du coup pour le monstre retard pour répondre ...

Du coup pour la première carte voici les éléments utile pour mon problème :

uint8_t broadcastAddress[] = {};
char macStr[18];
String macStringToSend;

String success;

typedef struct struct_message {
  String Type;
  String Message;
} struct_message;


struct_message myData;


void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nLast Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");

  if (status ==0){
    success = "Delivery Success :)";
  }
  else{
    success = "fail";
  }
}


void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.print("Bytes received: ");
  Serial.println(len);
  Serial.print("Type: ");
  Serial.println(myData.Type);
  Serial.print("Message: ");
  Serial.println(myData.Message);
  Serial.println();

  snprintf(macStr, sizeof(macStr), "%02x%02x%02x%02x%02x%02x",//%02x:%02x:%02x:%02x:%02x:%02x
           mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

  macStringToSend = String(macStr);

  Serial.print("Received from: "); 
  Serial.println(macStr);
  Serial.println("");

void setup() {

// Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);
  
  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  // Once ESPNow is successfully Init, we will register for Send CB to
  // get the status of Trasnmitted packet
  esp_now_register_send_cb(OnDataSent);

    // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_register_recv_cb(OnDataRecv);
  
  // Register peer
  esp_now_peer_info_t peerInfo;
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;  
  peerInfo.encrypt = false;
  
  // Add peer        
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }

}

void loop() {

 //if(Serial2.available()){
if(Serial.available()){
  Serial.println("Recpetion en cours");

    c = Serial.readString();
    sixFirstChar = c.substring(0, 6);
    Serial.println(c);
    Serial.println(sixFirstChar);
    if (sixFirstChar == "ACTION" || sixFirstChar == "SAVING" || sixFirstChar == "MASTER"){
      ActionAccRqst = c.substring(7,24);
      ActionToSend = c.substring(25,c.length());
      Serial.println("Une action est à envoyer à : ");
      Serial.print(ActionAccRqst);
      Serial.print(" -> ");
      Serial.println(ActionToSend);
      String Code1 = ActionAccRqst.substring(0, 2);
      String Code2 = ActionAccRqst.substring(3, 5);
      String Code3 = ActionAccRqst.substring(6, 8);
      String Code4 = ActionAccRqst.substring(9, 11);
      String Code5 = ActionAccRqst.substring(12, 14);
      String Code6 = ActionAccRqst.substring(15, 17);

       broadcastAddress[0] = strtol(Code1.c_str(), 0, 16);
       broadcastAddress[1] = strtol(Code2.c_str(), 0, 16);
       broadcastAddress[2] = strtol(Code3.c_str(), 0, 16);
       broadcastAddress[3] = strtol(Code4.c_str(), 0, 16);
       broadcastAddress[4] = strtol(Code5.c_str(), 0, 16);
       broadcastAddress[5] = strtol(Code6.c_str(), 0, 16);
      
      myData.Type = sixFirstChar;
      //myData.Destinataire = ActionAccRqst;
      myData.Message = String(ActionToSend);
      Serial.println(myData.Type);
      Serial.println(myData.Message);

        // Register peer
        esp_now_peer_info_t peerInfo;
        memcpy(peerInfo.peer_addr, broadcastAddress, 6);
        peerInfo.channel = 0;  
        peerInfo.encrypt = false;
        
        // Add peer        
        if (esp_now_add_peer(&peerInfo) != ESP_OK){
          Serial.println("Failed to add peer");
            digitalWrite(LedBlue, HIGH),
            delay(200);
            digitalWrite(LedBlue, LOW);

          return;
        }


      // Send message via ESP-NOW
      esp_err_t result2 = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));

      if (result2 == ESP_OK) {
        Serial.println("Sent with success");
        digitalWrite(LedGreen, HIGH),
        delay(200);
        digitalWrite(LedGreen, LOW);
      }
      else {
        Serial.println("Error sending the data");
        Serial.println(result2, 16);
        //const char MyError *esp_err_to_name_r(result2);
        Serial.println(esp_err_to_name(result2));
            digitalWrite(LedRed, HIGH),
            delay(200);
            digitalWrite(LedRed, LOW);
      }
      if (esp_now_del_peer(broadcastAddress) != ESP_OK){
          Serial.println("Failed to del peer");
          return;
        }
    }
 }
  

}


}

Et pour la seconde carte :

uint8_t broadcastAddress[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};


typedef struct struct_message {
    String Type;
    String Message;
} struct_message;


struct_message myData;

void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nLast Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
    if (status ==0){
    success = "Delivery Success :)";
    Serial.println("Youpi");
  }
  else{
    success = "fail";
    Serial.println("fail");
  }
}

// callback function that will be executed when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.print("Bytes received: ");
  Serial.println(len);
  Serial.print("Type: ");
  Serial.println(myData.Type);

  Serial.print("Message: ");
  Serial.println(myData.Message);
  Serial.println();

  ActionIsAlreadyPerfomed = false;


  snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
           mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

  Serial.print("Received from: "); 
  Serial.println(macStr);
  Serial.println("");
  
}

void setup() {


  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  //MASTER NOW SETTING 

  File file2 = SPIFFS.open("/MyMaster.txt", "r");
 
  if (!file2) {
    Serial.println("Failed to open file for reading");
    return;
  }
  uint16_t i = 0;
      while(file2.available()){
        //Serial.write(file.read());
        MyMasterChar [i] = file2.read();
        i++;
      }
      MyMasterChar [i] ='\0';
       Serial.println(MyMasterChar);
 
  file2.close();

      MyMasterString = String(MyMasterChar);

      String Code1 = MyMasterString.substring(0, 2);
      String Code2 = MyMasterString.substring(3, 5);
      String Code3 = MyMasterString.substring(6, 8);
      String Code4 = MyMasterString.substring(9, 11);
      String Code5 = MyMasterString.substring(12, 14);
      String Code6 = MyMasterString.substring(15, 17);

      /*byte Code1b = strtol(Code1.c_str(), 0, 16);
      byte Code2b = strtol(Code2.c_str(), 0, 16);
      byte Code3b = strtol(Code3.c_str(), 0, 16);
      byte Code4b = strtol(Code4.c_str(), 0, 16);
      byte Code5b = strtol(Code5.c_str(), 0, 16);
      byte Code6b = strtol(Code6.c_str(), 0, 16);*/

       broadcastAddress[0] = strtol(Code1.c_str(), 0, 16);
       broadcastAddress[1] = strtol(Code2.c_str(), 0, 16);
       broadcastAddress[2] = strtol(Code3.c_str(), 0, 16);
       broadcastAddress[3] = strtol(Code4.c_str(), 0, 16);
       broadcastAddress[4] = strtol(Code5.c_str(), 0, 16);
       broadcastAddress[5] = strtol(Code6.c_str(), 0, 16);

      //uint8_t SbroadcastAddress[] = {Code1b, Code2b, Code3b, Code4b, Code5b, Code6b};
      //broadcastAddress[0] = SbroadcastAddress[0];
      Serial.print("BroadcastAddress is");
      Serial.print(broadcastAddress[0]);
      Serial.print(broadcastAddress[1]);
      Serial.print(broadcastAddress[2]);
      Serial.print(broadcastAddress[3]);
      Serial.print(broadcastAddress[4]);
      Serial.println(broadcastAddress[5]);

  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }else{
    Serial.println("initializing ESP-NOW DONE");
  }

  // Once ESPNow is successfully Init, we will register for Send CB to
  // get the status of Trasnmitted packet
  esp_now_register_send_cb(OnDataSent);

  // Register peer
  esp_now_peer_info_t peerInfo;
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;  
  peerInfo.encrypt = false;
  
  // Add peer        
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }

  
  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_register_recv_cb(OnDataRecv);
}

Et je ne parviens pas a trouver pourquoi la variable TYPE passe sans problèmes et la variable MESSAGE non ...

Merci

La structure que tu envoies est constitué de 2 Strings.
Les objets String sont des objets très complexes : en interne, ils contiennent un pointeur vers un buffet où sont stockés les caractères.
Les caractères ne sont donc pas dans la String, mais qque part en mémoire, et la String contient un pointeur vers ce buffet.

Quand tu envoies l'objet String (comme partie de ta structure), tu ne transfères pas les caractères du buffet. Tu transmets seulement ce qui est à l'intérieur de l'objet String, c-à-d le pointeur.

Une fois arrivé sur la machine réceptrice, ce pointeur pointe vers ... n'importe où ! Il n'y a aucune raison que sur cette machine-là, les bons caractères (qui n'ont pas été passé par la ligne série) se retrouvent à la même adresse que sur la machine qui émet.

Conclusion : tu ne peux pas passer un String sur la ligne série.
Comment faire ?

  • dans le cas général, les objets bien écrits en C+++ peuvent être sérialisés (c'est le terme), c-à-d qu'ils possèdent une méthode pour fabriquer un paquet d'octets qui le représente, et une autre qui reconvertit ce paquet d'octets en un vrai objet fonctionnel. Pas sûr que la String de l"Arduino sache faire ça
  • dans le cas particulier, il suffit de transmettre le texte ( en prévoyant la taille maxi du texte)
    Par exemple
const int TAILLE_MAX_TEXTE = 128;
struct Trame {
  char chaine1[TAILLE_MAX_TEXTE];
  char chaine2[TAILLE_MAX_TEXTE]
};

De plus dans ton cas;, c'est du gaspillage de passer le champ TYPE comme un chaîne de caractères. Il vaut mieux utiliser un entier énuméré.

Et bah dit donc depuis toutes ces années que je code pour le plaisir et je viens seulement maintenant de comprendre le fonctionnement des STRING ::slight_smile:

L'idée de passer le type par un INT était mon idée de base mais j'étais revenu sur du STRING pour des fin de debug !

Pour la partie message, j'ai bien modifié ma structure avec un tableau CHAR. mais j'ai toujours le problème qui persiste... Seulement dans un sens maintenant ...

J'explique, depuis la Première carte j'envoi TYPE = 1 et MESSAGE = SETMAST la Seconde carte reçois TYPE = 1 et MESSAGE = (8ѤAST

Pour info le (8ѤAST est bien générer par la première carte car j'ai mis un SerialPrint avant l'envoi de la trame et cela sort de cette façon ...

J'en conclus que le soucis vient de la première carte ...

Le code est le suivant :

if(Serial.available()){
  Serial.println("Recpetion en cours");
    c = Serial.readString();
    sixFirstChar = c.substring(0, 6);
    Serial.println(c);
    Serial.println(sixFirstChar);
    if (sixFirstChar == "ACTION" || sixFirstChar == "SAVING" || sixFirstChar == "MASTER"){
      ActionAccRqst = c.substring(7,24);
      ActionToSend = c.substring(25,c.length());
      Serial.println("Une action est à envoyer à : ");
      Serial.print(ActionAccRqst);
      Serial.print(" -> ");
      Serial.println(ActionToSend);
      String Code1 = ActionAccRqst.substring(0, 2);
      String Code2 = ActionAccRqst.substring(3, 5);
      String Code3 = ActionAccRqst.substring(6, 8);
      String Code4 = ActionAccRqst.substring(9, 11);
      String Code5 = ActionAccRqst.substring(12, 14);
      String Code6 = ActionAccRqst.substring(15, 17);

       broadcastAddress[0] = strtol(Code1.c_str(), 0, 16);
       broadcastAddress[1] = strtol(Code2.c_str(), 0, 16);
       broadcastAddress[2] = strtol(Code3.c_str(), 0, 16);
       broadcastAddress[3] = strtol(Code4.c_str(), 0, 16);
       broadcastAddress[4] = strtol(Code5.c_str(), 0, 16);
       broadcastAddress[5] = strtol(Code6.c_str(), 0, 16);

      if (sixFirstChar == "ACTION"){
        myData.Type = 1;
      }else if (sixFirstChar == "SAVING"){
        myData.Type = 2;
      }else if (sixFirstChar == "MASTER"){
        myData.Type = 10;
      }

      ActionToSend.toCharArray(myData.Message, TAILLE_MAX_TEXTE);
      Serial.println(myData.Type);
      Serial.println(myData.Message);

        // Register peer
        esp_now_peer_info_t peerInfo;
        memcpy(peerInfo.peer_addr, broadcastAddress, 6);
        peerInfo.channel = 0;  
        peerInfo.encrypt = false;
        
        // Add peer        
        if (esp_now_add_peer(&peerInfo) != ESP_OK){
          Serial.println("Failed to add peer");
            digitalWrite(LedBlue, HIGH),
            delay(200);
            digitalWrite(LedBlue, LOW);
          return;
        }


      // Send message via ESP-NOW
      esp_err_t result2 = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));

      if (result2 == ESP_OK) {
        Serial.println("Sent with success");
        digitalWrite(LedGreen, HIGH),
        delay(200);
        digitalWrite(LedGreen, LOW);
      }
      else {
        Serial.println("Error sending the data");
        Serial.println(result2, 16);
        Serial.println(esp_err_to_name(result2));
            digitalWrite(LedRed, HIGH),
            delay(200);
            digitalWrite(LedRed, LOW);
      }
      if (esp_now_del_peer(broadcastAddress) != ESP_OK){
          Serial.println("Failed to del peer");
          return;
        }
    }
 }

Flyer-74:
Pour la partie message, j'ai bien modifié ma structure avec un tableau CHAR. mais j'ai toujours le problème qui persiste... Seulement dans un sens maintenant ...

J'explique, depuis la Première carte j'envoi TYPE = 1 et MESSAGE = SETMAST la Seconde carte reçois TYPE = 1 et MESSAGE = (8ѤAST

Pour info le (8ѤAST est bien générer par la première carte car j'ai mis un SerialPrint avant l'envoi de la trame et cela sort de cette façon ...

On appelle cela

    ActionToSend.toCharArray(myData.Message, TAILLE_MAX_TEXTE);
    Serial.println(myData.Type);
    Serial.println(myData.Message);

'SISO' (Shit In, Shit out) ou 'GIGO' (Garbage In, Garbage Out)...

Postez un code où vous nous montrez comment vous construisez et envoyez vraiment des cString.

Tout ce que je vois ci dessus c'est encore des instances de la classe String et une gestion approximative du port série. (éventuellement vous pouvez jeter un oeil à mon petit tuto sur la gestion du port série)