IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de Caxton
    Homme Profil pro
    Sans
    Inscrit en
    Janvier 2005
    Messages
    586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Corrèze (Limousin)

    Informations professionnelles :
    Activité : Sans

    Informations forums :
    Inscription : Janvier 2005
    Messages : 586
    Par défaut Communication radio mono directionnelle, RadioHead , Tableau de données traitement de l'émission et réception
    Bonsoir,
    Si je débarque ici, ce soir, c'est que toutes mes tentatives et sources ont été épurées. Je ne vais pas mettre la centaines de lien que j'ai consulté en vain.

    Je vais parler un peu radio en parlant de ma problématique et donc des solutions envisagées et problèmes rencontrées.

    Première étape, je dois faire quoi ? Envoyer des datas (une quantité assez importante si on regarde plus loin que le simple "Hello World"). A savoir une trame qui se composerais de plusieurs éléments :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Adresse(type hexadécimale ressemblant fort à l'IPV6) + Text + Ligne + Colonne + Texte
    Mais aussi d'autres possibilités tel que :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Adresse(type hexadécimale ressemblant fort à l'IPV6) + Clignotement + 1000 + 5000
    Bref autant de datas à transmettre.

    J'ai donc commencé par étudier un peu la solution full String (oui, pas beau) en me disant que "0010:0000:0000:0000:0000:0000:0000:0000,Text,0,0,Hello world" pouvais passer. Hélas, c'est déjà trop lourd. Voir donc méthode 2 : passer par tableau.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tbl[]={'0010','0000','0000','0000','0000','0000','0000','0000', 'Text', '0', '0', 'Hello World'}
    Déjà, c'est beaucoup plus intéressant car on pourra toujours appeler les éléments un par un et comme on le souhaite en réception. Je prendrais donc cela comme point de départ. Mais, il y a un premier mais. J'ai du texte et des chiffres mélangées. De mémoire, sur Arduino (par ce que je ne pratique pas tous les jours) n'aime pas du tout le mélange dans un tableau. Et la galère commence. Comment je peux m'affranchir de ce premier travers ?

    Et essayons enfin de sortir d'une première carte pour arriver dans la seconde en mode radio. Alors, dans ce domaine, j'ai vue plusieurs choses. Je vais commencé par celle qui me semble la plus évidente mais pas du tout compatible avec ce que j'ai évoquer plus haut dans la méthode 2. Je vais parler de Hamming + Manchester.

    Si je suis bien arrivé à faire fonctionner Manchester un coup sur deux, c'est que déjà la bibliothèque Githubienne est pas tout à fait au point. Pas fiable du tout!

    Au final, ce que je cherche à faire c'est transmettre le tableau, soit en entier, soit par infos quitte à borner les infos tel que l'ajout d'un start et d'un stop data (ben oué, faut faire comme en HTML, faut baliser) et transformer ça en modulation de 0/1 qui puissent être modulées par radio ou autre.

    J'ai commencé un bout de code m'appuyant finalement sur RadioHead qui fais pas trop mal le travail puisque je vois bien une trame à l'oscilloscope et que je vois bien un retrour sur écran à la réception.
    Pour l'émission :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    #include <RH_ASK.h>
    #include <SPI.h> // Not actually used but needed to compile
     
    #define speedTR 1000
    #define TX_PIN 4
     
    RH_ASK driver(speedTR, "", TX_PIN);
     
    void setup() {
      // put your setup code here, to run once:
      driver.init();
    }
     
    void loop() {
      // put your main code here, to run repeatedly:
      char data[20];
      data[0] = "<";
      data[1] = "00AB";
      data[2] = "CF2A";
      data[3] = "153D";
      data[4] = "2BAC";
      data[5] = "2384";
      data[6] = "A23D";
      data[7] = "F2FF";
      data[8] = "CA2D";
      data[9] = "TEXT";
      data[10] = "0";
      data[11] = "0";
      data[12] = "Hello world !!!!";
      data[13] = ">";
     
      driver.send((uint8_t*)data, 20);
      driver.waitPacketSent();
      delay(1000);
    }
    Pour le récepteur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    #include <RH_ASK.h>
    #include <SPI.h> // Not actually used but needed to compile
     
    #define speedTR 1000
    #define RX_PIN 5
     
    RH_ASK driver(speedTR, RX_PIN);
     
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600);
      driver.init();
    }
     
    void loop() {
      // put your main code here, to run repeatedly:
      char receivedData[20] = {0};
      uint8_t buflen = sizeof(receivedData);
     
      if (driver.recv((uint8_t*)receivedData, &buflen)) {
        for (byte i = 0; i < 20; i++) {
          Serial.print(receivedData[i]);
          Serial.print(" ");
        }
        Serial.println("");
      }
    }
    Et le résultat :
    r t y ~ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ * * * * 8 ,
    r t y ~ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ * * * * 8 ,
    r t y ~ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ * * * * 8 ,
    r t y ~ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ * * * * 8 ,
    r t y ~ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ * * * * 8 ,
    r t y ~ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ ⸮ * * * * 8 ,
    Bon, ben CQFD, j'ai bien mon retour mais les valeurs sont éronnées.

    Voilà, je m'en remet à des mains plus compétentes que les miennes étant dépassé pour le coup.

    Merci d'avoir pris le temps de me lire et de m'aider.

  2. #2
    Expert confirmé
    Avatar de Auteur
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    7 660
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 7 660
    Par défaut
    Bonsoir,

    Citation Envoyé par Caxton Voir le message
    Première étape, je dois faire quoi ? Envoyer des datas (une quantité assez importante si on regarde plus loin que le simple "Hello World"). A savoir une trame qui se composerais de plusieurs éléments :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Adresse(type hexadécimale ressemblant fort à l'IPV6) + Text + Ligne + Colonne + Texte
    Mais aussi d'autres possibilités tel que :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Adresse(type hexadécimale ressemblant fort à l'IPV6) + Clignotement + 1000 + 5000
    Bref autant de datas à transmettre.
    la première question me venant à l'esprit en lisant cette partie, est la suivante : quel est le caractère de fin de chaîne ? Utile pour signifier la fin de la transmission car tes données n'ont pas la même longueur.

    Citation Envoyé par Caxton Voir le message
    J'ai donc commencé par étudier un peu la solution full String (oui, pas beau) en me disant que "0010:0000:0000:0000:0000:0000:0000:0000,Text,0,0,Hello world" pouvais passer. Hélas, c'est déjà trop lourd. Voir donc méthode 2 : passer par tableau.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tbl[]={'0010','0000','0000','0000','0000','0000','0000','0000', 'Text', '0', '0', 'Hello World'}
    Attention : en C++, '0' n'a absolument pas la même signification que "0" !


    Citation Envoyé par Caxton Voir le message
    Déjà, c'est beaucoup plus intéressant car on pourra toujours appeler les éléments un par un et comme on le souhaite en réception. Je prendrais donc cela comme point de départ. Mais, il y a un premier mais. J'ai du texte et des chiffres mélangées. De mémoire, sur Arduino (par ce que je ne pratique pas tous les jours) n'aime pas du tout le mélange dans un tableau. Et la galère commence. Comment je peux m'affranchir de ce premier travers ?
    Avec des structures :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    struct message{
    int idMessage;
    int addrDest;
    int addrSrc;
    int val1;
    int val2;
    String text1;
    String text2;
    };
     
    message msg;

  3. #3
    Membre éclairé Avatar de Caxton
    Homme Profil pro
    Sans
    Inscrit en
    Janvier 2005
    Messages
    586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Corrèze (Limousin)

    Informations professionnelles :
    Activité : Sans

    Informations forums :
    Inscription : Janvier 2005
    Messages : 586
    Par défaut
    Salut Auteur content de te voir ici.

    Bon, oui, j'ai glissé pas mal d'erreur. Je suis un peu rouillé en ce moment niveau code et embarqué.

    Ok, pour le coup du '0' ou "0". Donc fut-t-il que je migre vers '0000' plutôt que tel que ?
    Je viens de tenter et y a une différence !

    TX
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    #include <RH_ASK.h>
    #include <SPI.h> // Not actually used but needed to compile
     
    #define speedTR 1000
    #define TX_PIN 4
     
    RH_ASK driver(speedTR, "", TX_PIN);
     
    void setup() {
      // put your setup code here, to run once:
      driver.init();
    }
     
    void loop() {
      // put your main code here, to run repeatedly:
      char data[20];
      data[0] = '<';
      data[1] = '00AB';
      data[2] = 'CF2A';
      data[3] = '153D';
      data[4] = '2BAC';
      data[5] = '2384';
      data[6] = 'A23D';
      data[7] = 'F2FF';
      data[8] = 'CA2D';
      data[9] = 'TEXT';
      data[10] = '0';
      data[11] = '0';
      data[12] = 'Hello world !!!!';
      data[13] = '>';
     
      driver.send((uint8_t*)data, 20);
      driver.waitPacketSent();
      delay(1000);
    }
    < B A D C 4 D F D T 0 0 ! > * * * * 8 ,
    < B A D C 4 D F D T 0 0 ! > * * * * 8 ,
    < B A D C 4 D F D T 0 0 ! > * * * * 8 ,
    < B A D C 4 D F D T 0 0 ! > * * * * 8 ,
    < B A D C 4 D F D T 0 0 ! > * * * * 8 ,
    < B A D C 4 D F D T 0 0 ! > * * * * 8 ,
    < B A D C 4 D F D T 0 0 ! > * * * * 8 ,
    Je n'ai pas toucher au code du récepteur RX.

    Par contre, les structures, je n'en ai jamais fait. Comment ça fonctionne cette bête. Je veux dire niveau pratique ? Par ce que pour le coup, ça m'intéresse si ça résoud le problème.

    Pour les caractères de début "<" et de fin ">" façon Hache Teu meu Leuh ! Mais on peut mettre autre chose si c'est trop coriace comme caractère.

    Merci pour le coup de pouce.

  4. #4
    Responsable Arduino et Systèmes Embarqués


    Avatar de f-leb
    Homme Profil pro
    Enseignant
    Inscrit en
    Janvier 2009
    Messages
    13 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 13 197
    Billets dans le blog
    47
    Par défaut
    Bonsoir,

    Citation Envoyé par Caxton Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // ...
      char data[20];
      data[0] = '<';
      data[1] = '00AB';
      data[2] = 'CF2A';
      data[3] = '153D';
      data[4] = '2BAC';
      data[5] = '2384';
      data[6] = 'A23D';
      data[7] = 'F2FF';
      data[8] = 'CA2D';
      data[9] = 'TEXT';
      data[10] = '0';
      data[11] = '0';
      data[12] = 'Hello world !!!!';
      data[13] = '>';
    // ...
    Je me trompe ou le type char est fait pour stocker 1 caractère ? Un tableau de chaînes de caractères est forcément un tableau 2D.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
      char data[][20] = {
      "<",
      "00AB",
      "CF2A",
      "153D",
      "2BAC",
      "2384",
      "A23D",
      "F2FF",
      "CA2D",
      "TEXT",
      "0",
      "0",
      "Hello world !!!!",
      ">"};

  5. #5
    Membre éclairé Avatar de Caxton
    Homme Profil pro
    Sans
    Inscrit en
    Janvier 2005
    Messages
    586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Corrèze (Limousin)

    Informations professionnelles :
    Activité : Sans

    Informations forums :
    Inscription : Janvier 2005
    Messages : 586
    Par défaut
    Bonjour,

    En effet, je comprends un peu mieux la différence entre "envoyer un seul caractère" ou "envoyer une chaine de caractère". J'avous que jusqu'ici, je n'avais jamais eu à m'en soucier directement.

    Du coup, si je comprends bien, le tableau est à 2 dimensions. Ce qui oblige à modifier le récepteur mais ça c'est pas grave.

    Je résume donc, côté émetteur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    char data[][20] = {
      "<",
      "00AB",
      "CF2A",
      "153D",
      "2BAC",
      "2384",
      "A23D",
      "F2FF",
      "CA2D",
      "TEXT",
      "0",
      "0",
      "Hello world !!!!",
      ">"
      };
     
      driver.send((uint8_t*)data, 20);
    Côté réception :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    < - - - - - - - - - - - - - - - - - - - -
    < - - - - - - - - - - - - - - - - - - - -
    < - - - - - - - - - - - - - - - - - - - -
    < - - - - - - - - - - - - - - - - - - - -
    < - - - - - - - - - - - - - - - - - - - -
    < - - - - - - - - - - - - - - - - - - - -
    Je comprends donc que je reçois bien quelque-chose mais le reste est vide. Je me dis donc 2 choses : "Que contient alors la donnée envoyée et que contient celle reçue ?".

    Pour ce qui est envoyé :
    data[0][0] : <
    data[1][0] : 0
    data[1][1] : 0
    data[1][2] : A...

    Donc, je vais modifier le récepteur pour voir ce que j'obtiens et l'automatiser. Et voilà le résultat :
    Nom : Capture-1.JPG
Affichages : 933
Taille : 67,1 Ko

    Y a comme un petit problème
    Retour au code du récepteur modifié:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    #include <RH_ASK.h>
    #include <SPI.h> // Not actually used but needed to compile
     
    #define speedTR 1000
    #define RX_PIN 5
     
    RH_ASK driver(speedTR, RX_PIN);
     
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600);
      driver.init();
    }
     
    void loop() {
      // put your main code here, to run repeatedly:
      char receivedData[][20] = {0};
      uint8_t buflen = sizeof(receivedData);
     
      if (driver.recv((uint8_t*)receivedData, &buflen)) {
        for (byte i = 0; i < 15; i++) {
          for (byte j = 0; j < 20; j++) {
            Serial.print(receivedData[i][j]);
          }
          Serial.print(" - ");
        }
        Serial.println("");
      }
    }

  6. #6
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 913
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 913
    Par défaut
    en déclarant votre tableau sous forme de vous allouez 20 caractères par lignes

    Rien que pour votre début d'adresse
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
      "00AB",
      "CF2A",
      "153D",
      "2BAC",
      "2384",
      "A23D",
      "F2FF",
      "CA2D",
    pour envoyer vos 8 codes, ça va vous coûter l'envoi de 8x20=160 octets. C'est déjà bien supérieur à ce que RH_ASK peut envoyer dans un message...

    Comment connaître la taille max du message possible ? Vous utilisez RH_ASK comme driver, et on l'obtient par l'appel à driver.maxMessageLength()

    c'est défini comme étant RH_ASK_MAX_MESSAGE_LEN qui est déclarée ainsi
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // Maximum message length (including the headers, byte count and FCS) we are willing to support
    // This is pretty arbitrary
    #define RH_ASK_MAX_PAYLOAD_LEN 67
     
    // The length of the headers we add (To, From, Id, Flags)
    // The headers are inside the payload and are therefore protected by the FCS
    #define RH_ASK_HEADER_LEN 4
     
    // This is the maximum message length that can be supported by this library. 
    // Can be pre-defined to a smaller size (to save SRAM) prior to including this header
    // Here we allow for 1 byte message length, 4 bytes headers, user data and 2 bytes of FCS
    #ifndef RH_ASK_MAX_MESSAGE_LEN
     #define RH_ASK_MAX_MESSAGE_LEN (RH_ASK_MAX_PAYLOAD_LEN - RH_ASK_HEADER_LEN - 3)
    #endif
    soit 67 - 4 - 3 = 60 octets pour TOUT le message --> bref, il faut être plus économe.

    je me dis que pour partie vous émettez des nombres codés sur 2 octets et représentés en ASCII. Chaque chaine va occuper 5 octets (si vous prenez soin de mettre des '0' devant) - les 4 pour l'hexadécimal puis un '\0' de fin de chaîne. c'est hyper bavard et la probabilité de perte de données en réseau sans fil est proportionnelle à la taille de la trame, si ça ne passe pas il faudra tout ré-émettre...

    est-ce que vous voulez un protocole "ASCII" - c'est à dire que tout est transmis textuellement, où un protocole binaire?

    Par exemple, envoyer vos 8 codes si vous tassez un peu, ça pourrait vous coûter l'envoi de 8x5=40 octets. c'est les 2 tiers des 60 octets dispos... Mais si vous envoyez en binaire, chaque nombre est sur 2 octets, vous n'aurez qu'à envoyer 8x2 = 16 octets, ça nous laisse plus de place pour le reste.

    Quand on travaille sur un protocole, il faut convenir d'un marquage de début de trame (fait pour vous par la librairie), puis on essaye de définir ce qui est commun à toutes les trames, ici on dirait que vous avez une adresse ressemblant à l'IPV6 - sans doute longue de 128 bits, soit 16 octets et ensuite il y a un "payload" pour vous qui est variable. Donc il faut lister les variations possibles. Vous pourriez réserver un octet pour les variantes décrivant le payload (255 variantes), puis généralement on a la taille du payload, comme ça on sait combien on doit lire d'octets côté réception, et souvent on ajoute un code de contrôle (CRC) pour s'assurer que la trame est bien arrivée (ce qui est fait pour vous dans la librairie aussi).

    plus d'info sur comment on code une fonction de somme de contrôle CRC ici

    Si vous ne voulez pas vous ennuyer à émettre des tailles variables, on peut mettre cela en dur et réserver la mémoire et comme ça pas besoin d'émettre la longueur. on va partir là dessus.

    On a vu qu'il faut s'assurer que le message au total ne dépasse pas ce que votre driver est capable de gérer soit 60 octets.

    On a 16 octets d'adresse, 1 octet pour la variante, donc reste pour le payload: 60 - 16 - 1 = 43 octets

    vous codez cela dans une struct.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    const uint16_t tailleMaxPayload = 43; // la taille totale de la structure doit être inférieure à driver.maxMessageLength()
    enum variante_t : uint8_t {VARIANTE_1, VARIANTE_2, VARIANTE_3, VARIANTE_4};  // donnez des noms parlants
    struct message_t {
      uint16_t  adresse[8]; // 16 octets 
      variante_t  variante; // 1 octet
      uint8_t   payload[tailleMaxPayload]; // 43 octets 
    } message;
    quand vous voulez émettre vous mettez un truc du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
      message.adresse[0] = 0x00AB ;
      message.adresse[1] = 0xCF2A ;
      message.adresse[2] = 0x153D ;
      message.adresse[3] = 0x2BAC ;
      message.adresse[4] = 0x2384 ;
      message.adresse[5] = 0xA23D ;
      message.adresse[6] = 0xF2FF ;
      message.adresse[7] = 0xCA2D ;
     
      message.variante = VARIANTE_3 ; // pour expliciter au récepteur ce qu'il doit décoder
     
     strncpy(message.payload, "Texte, 0, 0, Hello World", tailleMaxPayload-1); // http://www.cplusplus.com/reference/cstring/strncpy/
      message.payload[tailleMaxPayload-1] = '\0'; // pour s'assurer d'avoir une chaîne bien formée
     
      // reste plus qu'à émettre la structure
      driver.send((uint8_t *) &message, sizeof(message));
      driver.waitPacketSent();
    côté réception, vous recevez dans la même structure
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    driver.recv((uint8_t*) &message, &buflen);
    la partie qui ne change pas (adresse et variante) sera au début et vous pouvez utiliser les champs de la structure pour lire les différents éléments, puis vous utilisez le N° de variante pour décoder ce qu'il y dans le payload.

  7. #7
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 913
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 913
    Par défaut
    non on ne peut pas faire un == avec les cStrings, il faut utiliser strcmp() ou strstr() par exemple

    mais j'ai l'impression que vous repartez à l'envers, sur l'envoi en ASCII de votre adresse. on l'avait envoyé en binaire auparavant

    Si on part du principe que vous allez découper le message en petits paquets, il vous faudrait une structure décrivant le paquet 0 qui contiendrait une information particulière et une structure décrivant un paquet générique

    On sait qu'en tout on peut avoir 60 octets pour TOUT le paquet

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    struct paquetEntete {
      uint32_t sentinelle; // 4 octets magiques pour identifier un début de paquet par exemple 0xDEADBEEF
      uint16_t idMessage; // 2 octets pour un identifiant unique pour tout le message découpé en n paquets
      uint8_t nbPaquets; // 1 octet en combien de paquets le message a été découpé (0 si on ne l'a pas découpé et qu'il tient dans ce message)
      uint16_t addr[8]; // les 8 octets d'adresse cible
      uint8_t taillePayload; // 1 octet pour le nombre d'octets dans le payload principal
      uint8_t payload[44]; 
    };
    ce paquet fait donc 60 octets, il contient l'adresse de destination et un petit payload de 44 octets.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    struct paquetGenerique {
      uint32_t sentinelle; // 4 octets magiques pour identifier un paquet générique, par exemple 0xBADCAFFE
      uint16_t idMessage; // 2 octets pour un identifiant unique pour tout le message découpé en n paquets
      uint8_t idPaquet; // au maximum on a 255 paquets, si on dit que le paquet 0 est l'enTete, on compte à partir de 1 donc ici
      uint8_t taillePayload; // le nombre d'octets effectifs dans le payload
      uint8_t payload[52]; 
    };
    Ce second paquet fait 60 octets et contient un plus gros payload de 52 octets

    côté Tx vous recevez le message depuis le PC et fabriquez le paquetEntete et autant de paquetGenerique que nécessaire puis vous les balancez. Côté Rx vous écoutez en attendant d'avoir reçu un paquet qui contient comme sentinelle la valeur de paquetEntete (0xDEADBEEF). à partir de là vous vous mettez en mode reception de message. Si le nbPaquets est 0 vous avez tout votre message dans le premier paquet, sinon c'est qu'il a été envoyé par petits bouts et il faut les recevoir.


    avec cette approche vous Pourrez comparer l'adresse avec un memcmp() comme on l'avait déjà fait avant.

  8. #8
    Membre éclairé Avatar de Caxton
    Homme Profil pro
    Sans
    Inscrit en
    Janvier 2005
    Messages
    586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Corrèze (Limousin)

    Informations professionnelles :
    Activité : Sans

    Informations forums :
    Inscription : Janvier 2005
    Messages : 586
    Par défaut
    Ok, je comprends beaucoup mieux comment faire.

    Le projet à évolué entre temps. Bon, c'est un peu le problème entre ce que nous faisions au départ et ce qui sera réellement mis au point. Comme je travaille en avance de phase, je vais donc devoir repenser l'intégralité du projet.

    Ce que l'on garde dans le sens Pc -> RX :
    Une entête (voir ton dernier message)
    Une adresse
    Un message
    Ce que l'on ajoute dans le sens RX ->Pc :
    Un système de retour d'info
    Une entête
    Une valeur qui n'est autre que le message précédent)
    Une valeur Qté 0.

    Ce qui fait que :
    Le logiciel Pc dit :
    Addr;0x00AB:0xCF2A:0x153D:0x2ABC:0x2384:0xA23D:0xF2FF:0xCA2D
    Message;C0;L0;35262 5 B
    Quantite;10
    Rx reçois
    Addr;0x00AB:0xCF2A:0x153D:0x2ABC:0x2384:0xA23D:0xF2FF:0xCA2D
    -> Si c'est son adresse
    --> Afficher en Colonne 0, Ligne 0 : 35262 5 B
    --> Afficher la quantité 10
    -> Si appuie sur le bouton quantité 0
    --> Retourne au broadcast
    --> Addr;0x00AB:0xCF2A:0x153D:0x2ABC:0x2384:0xA23D:0xF2FF:0xCA2D
    --> Quantite;0
    Tx reçois
    Addr;0x00AB:0xCF2A:0x153D:0x2ABC:0x2384:0xA23D:0xF2FF:0xCA2D
    Quantite;0
    -> Il le transmet au PC

    L'échange devient bidirectionnel. Ce n'étais pas prévus au début !!! Bref, je vais donc passer à d'autres composants du style nRF24L01. Il me semble que tu avais évoquer le cas Jay. Mais je me trompe.

    Je dois m'absenter quelques jours pour raison de formation. Mais je vais bien vite, à mon retour me remettre à travailler sur ce sujet. Soit j'enterre le sujet tel que (je ferais le rappel dans un autre) et à ce moment là j'ouvrirais un nouveau sujet tout neuf. Soit je le garde ouvert et je reprendrais à mon retour.

    Voili voilà

  9. #9
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 913
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 913
    Par défaut
    votre émetteur Tx n'a aucun moyen de savoir si la réception s'est bien passée, sinon il faudrait un canal retour.
    le PC va donc balancer à son rythme à l'émetteur (Tx) des données à envoyer.

    l'émetteur (Tx) analyse ce qui vient du PC pour bâtir le message à envoyer. Il faut donc un protocole convenu entre le PC et l'émetteur. (marqueur début de message, fin de message).

    Comme ce message ne tient pas dans un seul paquet, l'émetteur met en forme les paquets et les balances les uns après les autres en croisant les doigts pour que le récepteur les voit bien arriver

    Le récepteur lui voit un flot de paquets et doit reconstituer le message

    un paquet pourrait être une structure avec

    - un octet pour le N° de paquet dans le message (paquet 0, paquet 1, paquet 2, ....)
    - un octet pour un identifiant de paquet (charge à l'émetteur de ne pas balancer deux paquets de suite avec le même identifiant)
    - un payload (une partie du message)

    dans le paquet N° 0, le payload pourrait dire combien de paquets attendre par exemple pour reconstituer le message et éventuellement un CRC ou autre information d'en-tête pertinente

    Si le PC parle trop vite à l'émetteur et que l'émetteur est occupé à envoyer le paquets, on risque de rater un message... l'émetteur verra un flot de données arriver mais aura raté le marqueur de début de message par exemple et pourra donc signaler au PC qu'il n'a pas compris.

    côté récepteur (Rx), il voit un flot continu de paquets. il attend celui dont le N° de paquet est 0 et sait que c'est un début de message, il lit dans le payload le nombre de paquets à attendre et se met en attente de tous ces paquets en vérifiant bien que le N° de paquet est bien croissant. une fois qu'il a re!u le bon nombre de paquets, il vérifie le CRC et remet en forme le message d'origine.

  10. #10
    Membre éclairé Avatar de Caxton
    Homme Profil pro
    Sans
    Inscrit en
    Janvier 2005
    Messages
    586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Corrèze (Limousin)

    Informations professionnelles :
    Activité : Sans

    Informations forums :
    Inscription : Janvier 2005
    Messages : 586
    Par défaut
    Reprenons !
    J'ai essayé d'envoyé toute la chaine "Addr;0x00AB:0xCF2A:0x153D:0x2ABC:0x2384:0xA23D:0xF2FF:0xCA2D". L'idée ici c'est d'avoir:
    Addr
    0x00AB
    0xCF2A
    0x153D
    0x2ABC
    0x2384
    0xA23D
    0xF2FF
    0xCA2D
    Pour ce faire j'ai cherché une solution pour que ça passe en entier. J'ai fini par y arrivé. Mais, il y a un mais !

    Niveau code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
     
    #include <RH_ASK.h>
    #include <SPI.h> // Not actually used but needed to compile
     
    #define speedTR 1000
    #define TX_PIN 4
     
    const uint16_t sizeMaxData = 43;  //Taille max du data à envoyer
     
    struct data_t {
      uint16_t addr[8];
      uint8_t dataSend[sizeMaxData];  //Nombre d'octets
    } data;
     
    RH_ASK driver(speedTR, "", TX_PIN);
     
    //char serData;
     
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600);
      driver.init();
    }
     
    char string[100];
     
    void loop() {
      // put your main code here, to run repeatedly:
     
      //Data reçu
      if(Serial.available() > 0) { 
        int availableBytes = Serial.available();
        for(int i=0; i<availableBytes; i++) {
          string[i] = Serial.read();
        }
        //Ici j'ai bien ma chaine entièrement reçu
        //On tente de parser
        char * pch;
        pch = strtok(string, ";:");
        while(pch != NULL) {
          Serial.println(pch);
          pch = strtok(NULL, ";:");
        }
     
       //If(pch == "Addr") {
             //Parser de nouveau
             //data.addr[0] = 0x00AB;
             //data.addr[1] = 0xCF2A;
             //data.addr[2] = 0x153D;
             //data.addr[3] = 0x2ABC;
             //data.addr[4] = 0x2384;
             //data.addr[5] = 0xA23D;
             //data.addr[6] = 0xF2FF;
             //data.addr[7] = 0xCA2D;
       //}
       //If(pch == "Message") {
             //Parser de nouveau
             //Colonne
             //Ligne
             //Message
       //}
       //Envoyer à RX
       Serial.flush();
      }
    }
    Des résultats encourageants

    Nom : Capture-1.JPG
Affichages : 282
Taille : 14,8 Ko

    J'espère que je ne perd pas tout le monde. J'i mis en pseudo code ce que je compte faire ensuite. Mais avant, j'aimerais quand même savoir quelle est la meilleure façon de traiter tout ça. Car en l'état, j'ai pas l'impression que ça soit correct pour tester avec un if.

  11. #11
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 913
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 913
    Par défaut
    Salut

    Tout à fait en général mais ici comme il envoie des données brutes on devrait retrouver nos petits octets même s’ils sont mélangés

    Pour cela il ne faut pas imprimer des char (ça donne les petits carrés quand c’est pas de l’ascii) mais la valeur binaire (utile pour les 16 premiers octets) Et surtout il faut donner un buffer approprié

    La méthode recv du driver RHASK attend 2 paramètres, un pointeur sur le buffer mémoire où écrire et un pointeur vers un uint8_t (1 octet) qui sera initialisé avant l’appel à la taille du buffer et qui vaudra après l’appel le nombre exact d’octets reçus

    en réception donc il faut faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    ...
     
    const uint16_t sizeMaxData = 43;  //Taille max du message textuel 60 - le reste de la structure, ici on pourrait donc avoir 44
     
    struct data_t {
      uint16_t addr[8];
      uint8_t dataSend[sizeMaxData];  //Nombre d'octets
    } data;
     
    ...
     
    void loop() {
      uint8_t buflen = sizeof(data); // on initialise avec la place totale dispo
     
      if (driver.recv((uint8_t*) &data, &buflen)) { // a-t-on reçu quelque chose ?
        for (uint8_t i = 0; i < buflen; i++) { // on a reçu buflen octets
          uint8_t octet = *(((uint8_t*) &data)+ i); // l’octet en position i du buffer
          Serial.print(i);
          Serial.print(F(\t0x”));
          Serial.print(octet, HEX); // impression en hexa
          if ((octet >= ‘ ‘) && (octet <= ‘~’)) { // est-ce un caractère affichable ?
            Serial.print(F(\t));
            Serial.print((char) octet); // impression Du caractère 
          }
           Serial.println();
        }
      }
    }
    (code tapé ici depuis ma tablette donc il se peut qu’il y ait des fautes)


    Ensuite effectivement si vous jouez avec 2 plateformes différentes il faut bien utiliser les uint8_t ou uint16_t etc pour garantir la taille mémoire utilisée et marquer la structure comme devant être compacte et ordonnée telle que définie (cf mon post pointé par jpbricole) et donc déclarer la structure des 2 cotés au minimum comme (voire avec alignement mais dans ce cas vérifier les tailles réelles pour ne pas dépasser les 60 octets)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct __attribute__((packed)) data_t {
      uint16_t addr[8];
      uint8_t dataSend[sizeMaxData];  //Nombre d'octets
    } data;
    (et perso j’appellerais dataSend autrement, l’habitude c’est payload ou dataBuffer ou juste contenu, bref sans notion de send car d’un côté c’est envoyé mais de l’autre c’est reçu )

    Pour être aussi tranquille c’est parfois bien de ne pas mettre un nombre impair d’octets dans la structure sur une architecture 32 bits et idéalement mettre un multiple de 4, ici on a 16 octets pour l’adresse on pourrait prendre 40 ou 44 octets pour le message (faut rester en dessous de 60 au total)

  12. #12
    Membre éclairé Avatar de Caxton
    Homme Profil pro
    Sans
    Inscrit en
    Janvier 2005
    Messages
    586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Corrèze (Limousin)

    Informations professionnelles :
    Activité : Sans

    Informations forums :
    Inscription : Janvier 2005
    Messages : 586
    Par défaut
    Ah oui, en effet, je suis sur de bons rails (HO ou même Net O ).

    Je rebondit sur ce que dit Auteur. Dans mon cas, il y aura du cross développement. Environnement windows (Windev) -> USB -> FTDI et la chaine Arduino. Donc il faudra veiller à ce que les datas rentrent au format structure pour être traités. Je suis tout à fait d'accord avec ce qui a été dit plus haut.

    Maintenant, revenons à l'actualité, ne partons pas trop loin en besognes et recentrons-nous sur le sujet.

    J'ai testé une modification du RX, comme nous venons parfaitement de l'expliquer un peu plus haut. Je remercie au passage toute l'aide que vous prenez le temps de donner afin de faire avancer les choses. C'est un régal de vous lire et moi d'apprendre aussi de nouvelles façons de programmer. Je suis arrivé à un résultat pas trop moche :

    Nom : Capture-3.JPG
Affichages : 881
Taille : 55,2 Ko

    Je suis content que le code fonctionne et de ne plus voir de carrés disgracieux.

    Je ne m'attendais pas à voir à chaque lignes un caractère... Là, j'essaie maintenant d'imaginer comment modifier pour que ça soit parsé et traité. Ne serais-ce que pour en extraire l'adresse. Car je me dis le fonctionnement suivant (en pseudo code) :
    Loop()
    Data reçu ?
    Oui -> nombre de bits reçus ?
    Oui -> adresse correspondante à la carte ?
    Oui -> Lcd ?
    Oui -> Ligne, Colone
    Message = Message reçue
    Non -> Erreur
    Message = "Erreur : Ligne / Colonne"
    Oui -> Options ?
    Traitement options
    Non -> Erreur
    Message = "Erreur : L'erreur..."
    Non -> Ne rien faire
    Non -> Ne rien faire

    Si Message > 1
    Appeler aficheur I2C adresse connue
    Afficher message
    Message = "";
    //Fin loop
    Ne me faites pas tout, je voudrais comprendre déjà pour l'adresse et je me charge de la partie LCD puisque j'ai déjà ma bibliothèque qui tourne et que je vais améliorer (ben oué, je me suis essayés avec des classes et ça rends super bien). En gros, ce que je cherche c'est le parsage correct et le traitement de l'IP.

    Je vais essayer maintenant de commenter mon RX afin de comprendre comment je peux modifier mon code pour recevoir en une ligne. Mais avant, j'aimerais quand même que ça soit correct afin d'éviter de partir dans le vide.

    RX :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
     
    #include <RH_ASK.h>
    #include <SPI.h> // Not actually used but needed to compile
     
    #define speedTR 1000
    #define RX_PIN 5
     
    const uint16_t sizeMaxData = 43;  //Taille max du data à envoyer
     
    struct data_t {
      uint16_t addr[8];
      uint8_t dataSend[sizeMaxData];  //Nombre d'octets
    } data;
     
    RH_ASK driver(speedTR, RX_PIN); //Librairie RadioHead
     
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600); //Liaison série pour le Débug
      driver.init();  //Initialisation de RH_ASK
    }
     
    void loop() {
      // put your main code here, to run repeatedly:
      uint8_t buflen = sizeof(data);  //Longueur du buffer
     
      //Si des datas sont reçues au tarvers de RH_ASK
      if (driver.recv((uint8_t*) &data, &buflen)) {
     
        //De 0 à Longueur du buffer
        for(uint8_t i = 0; i < buflen; i++) {
     
          uint8_t octet = *(((uint8_t*) &data)+i);  //Un octet
          Serial.print(i);                          //Numéro d'index
          Serial.print(F("\t0x"));                  //Je connais pas ce code ???
          Serial.print(octet, HEX);                 //Affichage en HEXA de la valeur de l'octet
     
          //Si l'octet n'est pas un caractère vide ou un ~
          if((octet >= ' ') && (octet <= '~')) {
            Serial.print(F("\t"));                  //Je connais pas ce code ???
            Serial.print((char)octet);              //Afficher l'octet sous forme de character
     
            //C'est ici que je pense recomposer en datas style data.ADDR[0] -> 00AB...
          }
          Serial.println();
        }
     
        //C'est ici que je compte tester mon adresse
          //C'est ici que je fais mon traitement
      }
    }
    Qu'en pensez-vous ? Est-ce que je commet des erreurs ? Est-ce que mes commentaires sont bons ? Là, il faut que je m'améliore de toute façon !

    Merci,

  13. #13
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 913
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 913
    Par défaut
    on progresse à grands pas

    Si on regarde ce que vous avez reçu:
    Nom : CaptureOK.JPG
Affichages : 974
Taille : 82,0 Ko

    pour les commentaires:

    dans code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    uint8_t octet = *(((uint8_t*) &data)+i);  //Un octet
    ce n'est pas n'importe quel octet, mais le i-ème du buffer. On parcourt chaque octet de la structure pour affichage.

    dans ce code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Serial.print(F("\t0x"));                  //Je connais pas ce code ???
    ainsi que ce code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Serial.print(F("\t"));                  //Je connais pas ce code ???
    le \t représente une tabulation, ce qui permet d'aligner bien en colonnes l'impression. C'est ce qu'on appelle une Séquence d'échappement, il y en a un certain nombre à connaître qui sont bien pratiques pour imprimer un guillemet par exemple avec le \"

    (et le 0x c'est pour qu'il soit écrit directement à l'affichage juste avant la valeur de l'octet en binaire comme vous le voyez à l'affichage


    Ne me faites pas tout, je voudrais comprendre déjà pour l'adresse et je me charge de la partie LCD puisque j'ai déjà ma bibliothèque qui tourne et que je vais améliorer (ben oué, je me suis essayés avec des classes et ça rends super bien). En gros, ce que je cherche c'est le parsage correct et le traitement de l'IP.
    En pratique vous recevez bien la structure et l'avantage de la structure c'est que vous n'avez pas besoin de lire octet par octet, tout est déjà rangé dans les variables pour vous (du moment qu'on a bien aligné entre l'émetteur et le récepteur).

    Par exemple étudiez ce code et regardez ce que ça imprime:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    #include <RH_ASK.h>
    #include <SPI.h> // Not actually used but needed to compile
    
    #define speedTR 1000
    #define RX_PIN 5
    
    const uint16_t sizeMaxData = 43;  //Taille max du data à envoyer
    
    struct data_t {
      uint16_t addr[8];
      uint8_t dataSend[sizeMaxData];  //Nombre d'octets
    } data;
    
    RH_ASK driver(speedTR, RX_PIN); //Librairie RadioHead
    
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600); //Liaison série pour le Débug
      driver.init();  //Initialisation de RH_ASK
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      uint8_t buflen = sizeof(data);  //Longueur du buffer
    
      //Si des data sont reçues au tarvers de RH_ASK
      if (driver.recv((uint8_t*) &data, &buflen)) {
        // on imprime les 8 adresses
        for (uint8_t i = 0; i < 8; i++) {
          Serial.print(F("data.addr["));
          Serial.print(i);
          Serial.print(F("] = 0x"));
          Serial.println(data.addr[i], HEX);
        }
        // puis on imprime le message textuel
        Serial.print(F("Message: "));
        Serial.println((char*) data.dataSend);
      }
    }
    je vous conseille de changer le débit en bauds de votre liaison série de debug Serial.begin(9600); de 9600 en 115200 (et bien sûr ajuster dans la console série à 115200 avec le popup en bas)

  14. #14
    Membre éclairé Avatar de Caxton
    Homme Profil pro
    Sans
    Inscrit en
    Janvier 2005
    Messages
    586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Corrèze (Limousin)

    Informations professionnelles :
    Activité : Sans

    Informations forums :
    Inscription : Janvier 2005
    Messages : 586
    Par défaut
    Oh punaise

    Je commence à voir mes trames

    Nom : Capture-4.JPG
Affichages : 916
Taille : 66,8 Ko

    J'ai modifié deux lignes par rapport à l'exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    uint8_t dataRecv[sizeMaxData];  //Nombre d'octets en réception
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Serial.println((char*) data.dataRecv);
    Donc, à ce stade je retrouve bien mon adresse et le message. A moi maintenant de trouver comment parser. Mais avant de partir dans tous les sens, si ça ne vous ennuie pas de poursuivre un peu ce tread (ou j'en ouvre un autre, vous me direz bien), j'aimerais savoir quelle est la meilleure façon de parser le retour pour son traitement.

  15. #15
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 913
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 913
    Par défaut
    Citation Envoyé par Caxton Voir le message
    Oh punaise
    Je commence à voir mes trames .
    Magique

    Citation Envoyé par Caxton Voir le message
    J'ai modifié deux lignes par rapport à l'exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    uint8_t dataRecv[sizeMaxData];  //Nombre d'octets en réception
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Serial.println((char*) data.dataRecv);
    OK oui, généralement on essaye de définir la structure exactement de la même façon des 2 côtés, ça permet de partager un .h par exemple... (et c'est pour cela qu'on appelle le contenu payload ou autre truc générique)

    Citation Envoyé par Caxton Voir le message
    A moi maintenant de trouver comment parser. Mais avant de partir dans tous les sens, si ça ne vous ennuie pas de poursuivre un peu ce tread (ou j'en ouvre un autre, vous me direz bien), j'aimerais savoir quelle est la meilleure façon de parser le retour pour son traitement
    vu que vous recevez un cString (un buffer de texte), explorez les fonctions des librairies standard dans stdlib.h et aussi dans string.h
    On peut extraire des tokens avec strtok() (attention cette fonction va modifier le buffer)

    Par exemple si vous avez des séparateurs bien définis - ici on dirait que vous optez pour la virgule comme séparateur de champs, ça pourrait ressembler à cela (à condition qu'il n'y ait pas de virgule dans le texte final). (attention j'ai mis la console Série à 115200 bauds)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    char message[] = "LCD, 0, 0, Hello World!!!!!!!";
     
    void analyseMessage(char* texte)
    {
      char * pointeur;
      Serial.print(F("Analyse de ["));
      Serial.print(texte);
      Serial.println(F("]"));
     
      pointeur = strtok (texte, ",");
      while (pointeur) {
        Serial.print(F("["));
        if (*pointeur == ' ') // on saute l'espace si on en a un au début
          Serial.print(pointeur + 1);
        else
          Serial.print(pointeur);
        Serial.println(F("]"));
        pointeur = strtok (NULL, ","); // on passe au token suivant
      }
    }
     
     
    void setup()
    {
      Serial.begin(115200);
      analyseMessage(message);
    }
     
    void loop() {}
    et jetez un oeil à la fonction atoi() pour convertir un entier écrit en ASCII dans une chaîne de caractères vers un entier "mathématique".

  16. #16
    Membre éclairé Avatar de Caxton
    Homme Profil pro
    Sans
    Inscrit en
    Janvier 2005
    Messages
    586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Corrèze (Limousin)

    Informations professionnelles :
    Activité : Sans

    Informations forums :
    Inscription : Janvier 2005
    Messages : 586
    Par défaut
    Je comprends un peu. Pour parser, il faut s'orienter strtok() et les tokens. Ok !

    Bon, je travaille aussi pour recomposer l'adresse. Je suis bien arrivé à compiler quelque-chose mais le résultat ne me plait pas. J'ai du oublier quelque-chose. Je connais mal les cstrings. Il faudra que je m'y fasse.

    Voilà la modification du Loop(). Je synthétise pour me concentrer sur la modification.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
     // put your main code here, to run repeatedly:
      uint8_t buflen = sizeof(data);  //Longueur du buffer
      uint8_t addrRecv = "";
     
      //Si des datas sont reçues au tarvers de RH_ASK
      if (driver.recv((uint8_t*) &data, &buflen)) {
        //Nous imprimons les 8 adresses
        for(uint8_t i = 0; i < 8; i++) {
          /*Serial.print(F("data.addr["));
          Serial.print(i);
          Serial.print(F("] = 0x"));
          Serial.println(data.addr[i], HEX);*/
          if(i != 8) {
            addrRecv += data.addr[i]+':';
          }
          else {
            addrRecv += data.addr[i];
          }
        }
     
        Serial.println(addrRecv);
     
        //Nous imprimons le message contextuel
        Serial.print(F("Message: "));
        Serial.println((char*) data.dataRecv);
      }
    Si ça semble bien assembler correctement la chaine, son contenu m'interpèle quand je regarde le retour sur le Serial.

    Nom : Capture-5.JPG
Affichages : 837
Taille : 13,5 Ko

    Dans l'idée, si c'est < à 8, on cumule la chaine avec, successivement 00AB:, 00AB:CF2A:, 00AB:CF2A:153D:, 00AB:CF2A:153D:0x2ABC:, 00AB:CF2A:153D:0x2ABC:2384:, 00AB:CF2A:153D:0x2ABC:2384:A23D:, 00AB:CF2A:153D:0x2ABC:2384:A23D:F2FF: et enfin, car c'est = à 8, 00AB:CF2A:153D:0x2ABC:2384:A23D:F2FF:CA2D

    Mais voilà je trouve 255.

    Bon, j'essaie, je fais surement des erreurs et j'avoue que j'ai tester quelques solutions avant de répondre. Mais ça m'amuse de voir aussi ce qui se passe. D'ailleurs, si ça se trouve on peut certainement utiliser les pointeurs pour faire ça. Enfin, bon, là, je m'avance, c'est une piste. Y a peut-être moyen de faire plus simple.

  17. #17
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 913
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 913
    Par défaut
    Citation Envoyé par Caxton Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
      uint8_t addrRecv = ""; // un uint8_t n’est qu’un seul octet...
    ...
        for(uint8_t i = 0; i < 8; i++) {
          /*Serial.print(F("data.addr["));
          Serial.print(i);
          Serial.print(F("] = 0x"));
          Serial.println(data.addr[i], HEX);*/
          if(i != 8) { // i ne vaudra jamais 8 dans cette boucle...
            addrRecv += data.addr[i]+':'; // ici vous additionnez un uint16_t (entier sur 2 octets) et le code ascii du caractère
          }
          else {
            addrRecv += data.addr[i];
          }
     ...
    Les adresses reçues sont des nombres, en c++ on ne fabrique pas une chaîne en concaténation comme cela...
    Pour bâtir une chaîne il faut un tableau avec assez de caractères pour tout stocker et itoa() et strcact() ou sprintf()... ou alors prendre la classe String mais vous risquez d’aller au devant de soucis mémoire

    Pourquoi souhaitez vous rebâtir une string avec l’adresse ? si c’est juste pour l’afficher, affichez là par petits bouts comme on a fait précédemment



    sinon, voici quelque chose à étudier:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    const uint16_t sizeMaxData = 43;
    struct data_t {
      uint16_t addr[8];
      uint8_t payload[sizeMaxData];  //Nombre d'octets
    } ;
     
    data_t data[] = {
      {
        0x00AB, 0xCF2A, 0x153D, 0x2BAC, 0x2384, 0xA23D, 0xF2FF, 0xCA2D,
        "LCD, 23, 35, Hello LCD!!!!!!!"
      },
      {
        0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888,
        "TFT, 125, 350, Hello TFT!!!!!!!"
      }
    };
     
     
    void analyseMessage(char* texte)
    {
      char * pointeur;
      Serial.print(F("Analyse de ["));
      Serial.print(texte);
      Serial.println(F("]"));
     
      pointeur = strtok (texte, ",");
      while (pointeur) {
        char* debut;
        Serial.print(F("["));
     
        if (*pointeur == ' ') // on saute l'espace si on en a un au début
          debut = pointeur + 1;
        else
          debut = pointeur;
     
        Serial.print(debut);
        Serial.print(F("]"));
     
        if (isdigit(*debut)) {
          long valeur = atol(debut);
          Serial.print(F("  J'ai reconnu le nombre -> 0x"));
          Serial.print(valeur, HEX);
          Serial.print(F(" (en base 10 -> "));
          Serial.print(valeur, DEC);
          Serial.print(F(")"));
        } else {
          Serial.print(F(" (pas un nombre)"));
        }
        Serial.println();
        pointeur = strtok (NULL, ","); // on passe au token suivant
      }
    }
     
    void information(data_t& dataStruct)
    {
      // on imprime les 8 adresses
      for (uint8_t i = 0; i < 8; i++) {
        Serial.print(F("data.addr["));
        Serial.print(i);
        Serial.print(F("] = 0x"));
        Serial.println(dataStruct.addr[i], HEX);
      }
     
      // puis on imprime le message textuel
      Serial.print(F("Message: "));
      Serial.println((char*) dataStruct.payload);
     
      // on fabrique l'adresse en ASCII avec sprintf (ça prend plein de mémoire)
      char adresseASCII[40]; // "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx" -> 39 caractères + '\0' final
      sprintf(adresseASCII, "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X", dataStruct.addr[0], dataStruct.addr[1], dataStruct.addr[2], dataStruct.addr[3], dataStruct.addr[4], dataStruct.addr[5], dataStruct.addr[6], dataStruct.addr[7]); // http://www.cplusplus.com/reference/cstdio/sprintf/
     
      Serial.print(F("Adresse en ASCII: "));
      Serial.println(adresseASCII);
      Serial.println();
      analyseMessage((char*) dataStruct.payload);
    }
     
    void setup() {
      Serial.begin(115200); //Liaison série pour le Débug
     
      information(data[0]);
      Serial.println(F("\n-------------"));
      information(data[1]);
    }
     
    void loop() {}

  18. #18
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 913
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 913
    Par défaut
    Bravo

    Notez que pour comparer l’adresse il n’y a pas besoin de fabriquer la chaîne de caractère et comparer en ascii, vous pouvez juste comparer les 8 éléments 2 à 2 ou en étant un peu smart puisque les octets sont contigus dans la structure avec un memcmp()

  19. #19
    Membre éclairé Avatar de Caxton
    Homme Profil pro
    Sans
    Inscrit en
    Janvier 2005
    Messages
    586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Corrèze (Limousin)

    Informations professionnelles :
    Activité : Sans

    Informations forums :
    Inscription : Janvier 2005
    Messages : 586
    Par défaut
    J'avoue qu'au départ, je n'avez pas songé à cette solution

    Mais du coup, ça m'a donné une idée. Pourquoi ne pas travailler sur un token. Ben oui, come ça on ne teste plus qu'un booléen pour effectuer l'affichage. C'est beaucoup plus rapide et ça évite de se perdre. Du coup, j'ai mis en place une technique qui fait qu'au premier groupe de caractère faux ça break !

    Voilà donc ce que ça donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
     
    #include <RH_ASK.h>
    #include <SPI.h> // Not actually used but needed to compile
     
    #define speedTR 1000
    #define RX_PIN 5
     
    const uint16_t sizeMaxData = 43;  //Taille max du data à envoyer
     
    struct data_t {
      uint16_t addr[8];
      uint8_t dataRecv[sizeMaxData];  //Nombre d'octets en réception
    } data;
     
    uint16_t tblAddr[8]{0x00AB,0xCF2A,0x153D,0x2ABC,0x2384,0xA23D,0xF2FF,0xCA2D};
    boolean tokenValid = false;
     
    RH_ASK driver(speedTR, RX_PIN); //Librairie RadioHead
     
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600); //Liaison série pour le Débug
      driver.init();  //Initialisation de RH_ASK
    }
     
    void loop() {
      // put your main code here, to run repeatedly:
      uint8_t buflen = sizeof(data);  //Longueur du buffer
     
      //Si des datas sont reçues au tarvers de RH_ASK
      if (driver.recv((uint8_t*) &data, &buflen)) {
        //Nous imprimons les 8 adresses
        for(uint8_t i = 0; i < 8; i++) {
          Serial.print(F("data.addr["));
          Serial.print(i);
          Serial.print(F("] = 0x"));
          Serial.println(data.addr[i], HEX);
        }
     
        //Nous imprimons le message contextuel
        Serial.print(F("Message: "));
        Serial.println((char*) data.dataRecv);
     
        //Lister au travers de la mémoire chaque valeur de l'adresse
        for(uint8_t i = 0; i < 8; i++) {
     
          //Comparaison par emplacement mémoire
          if(memcmp(tblAddr[i], data.addr[i], sizeof(tblAddr)) == 0) {
            tokenValid = true;
          }
          else {
            tokenValid = false;
            break; // Forcer la sortie de la recherche d'adresse car c'est pas la bonne
          }
        }
     
        if(tokenValid) {
          Serial.print(F("Addresse OK -> Traitement"));
          Serial.println();
        }
      }
    }
    Bien sûr, c'est bien mieux ainsi. Qu'en pensez vous ?
    Si c'est bon, la prochaine étape sera donc d'extraire le message, de prévoir une pile (on en parlera ensuite)

  20. #20
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 913
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 913
    Par défaut
    y'a de l'idée mais c'est pas tout à fait cela !!


    si vous voulez comparer deux à deux avec votre boucle for, on peut simplement comparer avec == entre deux entiers
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    const uint16_t sizeMaxData = 43;  //Taille max du data à envoyer
    const uint16_t tblAddr[8] = {0x00AB,0xCF2A,0x153D,0x2ABC,0x2384,0xA23D,0xF2FF,0xCA2D}; // mettez le en const, c'est mieux
    ...
    bool tokenValid = true;
    for(uint8_t i = 0; i < 8; i++) {
      if (tblAddr[i] != data.addr[i]) {
        tokenValid = false;
        break; // Forcer la sortie de la recherche d'adresse car c'est pas la bonne
      }
    }
    
    if (tokenValid) {
      // bonne adresse
    } else {
      // mauvaise adresse
    }
    Cependant la fonction memcmp() est assez intelligente pour arrêter de comparer dès qu'un octet ne correspond pas, donc elle fait l'équivalent de votre break. donc si vous utilisez memcmp() c'est sur tout le buffer d'un coup qu'il faut le faire, pas besoin de la boucle for.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    const uint16_t sizeMaxData = 43;  //Taille max du data à envoyer
    const uint16_t tblAddr[8] = {0x00AB,0xCF2A,0x153D,0x2ABC,0x2384,0xA23D,0xF2FF,0xCA2D}; // mettez le en const, c'est mieux
    ...
    
    if (!memcmp(data.addr, tblAddr, sizeMaxData)) {
      // bonne adresse
    } else {
      // mauvaise adresse
    }
    --> c'est encore plus compact

Discussions similaires

  1. [Toutes versions] tableau qui donne les dates communes (ligne) de 3 noms choisis(colonne)
    Par camad dans le forum Macros et VBA Excel
    Réponses: 12
    Dernier message: 27/10/2011, 18h57
  2. exporter un tableau de donnée vers un document word
    Par demerzel0 dans le forum Access
    Réponses: 2
    Dernier message: 04/11/2005, 11h57
  3. Filtrer un tableau de données
    Par Yux dans le forum Langage
    Réponses: 12
    Dernier message: 13/10/2005, 22h21
  4. [Collections] Transformer un tableau de données en une chaîne
    Par NATHW dans le forum Collection et Stream
    Réponses: 12
    Dernier message: 03/06/2004, 16h44
  5. [Choix SGBD] Application mono-poste mais beaucoup de données
    Par Wavyx dans le forum Décisions SGBD
    Réponses: 5
    Dernier message: 16/03/2003, 18h24

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo