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

Arduino Discussion :

Traitement RS422 - Arduino


Sujet :

Arduino

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Juillet 2012
    Messages
    275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2012
    Messages : 275
    Par défaut Traitement RS422 - Arduino
    Bonjour,

    Je me permet de venir vers vous afin de vous demander un peu d'aide. je suis bloqué

    Je récupère des données en continu depuis un appareil électronique en port série sur un shield RS485/RS422 en 38400baud, 8bits, 1 bits de stop.

    Les données sont bien réceptionnées, je les récupère bien octet par octet avec Serial1.read();

    Voici la structure des données :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    00 30 
    00 30 
    03 21 c0 05 03 21 c0 06 02 00 00 02 00 01
    03 20 10 09 03 20 11 0d 03 20 11 20 03 10 1b 0d 
    04 00 16 00 1f 03 0a 1b 0d etc....
    L'octet de couleur rouge correspond au nombre d'octet suivant la commande, par ex 03 soit 03 01 02 03 ou 05 01 02 03 04 05, le 00 30 est un ping de test et attend en réponse 84 84.
    Il n'y a pas de caractère de fin.

    Je dois lui envoyer une réponse dans les 10ms, voici un type de réponse d'exemple :

    Requête = 00 30 -> Réponse = 84 84
    Requête = 03 21 c0 05 -> Réponse = aucune
    Requête = 03 20 10 09 -> Réponse =03 00 80 92
    etc....


    Avez-vous une aidée de comment faire le traitement, pour l'envoi de la réponse, je pense partir sur un switch case.

    Je vous dépose un début de code dans la matinée de ce que j'ai déjà fait.

    Merci d'avance.

    Cordialement,

    Vincent.

  2. #2
    Expert confirmé

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

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 914
    Par défaut
    0030 est donc un signal de début de communication / synchronisation ? Et ensuite après avoir répondu 84 84 vous recevez un octet qui vous dit combien en attendre pour la commande suivante et il n’y a plus de 0030 ? (Sinon le 00 devra être traité comme un cas à part cart ce n’est pas un nombre d’octets et il faut consommer le 30 qui suit.)

    Un protocole sans point de synchro ni checksum c’est assez fragile. Si vous vous décalez par perte d’un octet il faut pouvoir se recaler et ce n’est pas super simple. C’est curieux que ce ne soit pas prévu. Quel est donc cet appareil ?

    Un switch est envisageable si les commandes font moins de 4 octets, vous les rangez dans un unsigned long pour faire la comparaison avec les commandes connues. (Faudrait tester avec des unsigned long long sur 64 buts, ça devrait marcher aussi pour un switch).

    S’il y a de nombreuses commandes ça va faire un gros switch. Une approche par tableau et boucle peut aussi s’envisager.

    Si les commandes dépassent ce qui est représentable dans une constante reconnue par un switch la fonction memcmp() permet de comparer octet or octet deux zones mémoires.

    les réponses sont elles câblées en dur où il y a envoi de valeurs «*dynamiques*» ?


    une première approche d'un gestionnaire de ce type où on attend un ping avant de débuter les commandes
    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
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    #define externalDevice Serial1
     
    enum t_state : uint8_t {WAITING_00, WAITING_30, WAITING_LENGTH, WAITING_COMMAND} state = WAITING_00;
     
    const uint32_t maxCommandLength = 4;
     
    struct t_command {
      uint8_t length;
      uint8_t bytes[maxCommandLength];
    };
     
    const t_command commandList[] = {   // don't forget to pad with 0x00 to the left
      {0x03, {0x00, 0x21, 0xc0, 0x05}}, // command Comm_0
      {0x03, {0x00, 0x21, 0xc0, 0x06}}, // command Comm_1
      {0x02, {0x00, 0x00, 0x00, 0x00}}, // command Comm_2
      {0x02, {0x00, 0x00, 0x00, 0x01}}, // command Comm_3
      {0x03, {0x00, 0x20, 0x10, 0x09}}, // command Comm_4
      {0x03, {0x00, 0x20, 0x11, 0x0d}}, // command Comm_5
      {0x03, {0x00, 0x20, 0x11, 0x20}}, // command Comm_6
      {0x03, {0x00, 0x10, 0x1b, 0x0d}}, // command Comm_7
      {0x04, {0x00, 0x16, 0x00, 0x1f}}, // command Comm_8
      {0x03, {0x00, 0x0a, 0x1b, 0x0d}}, // command Comm_9
    };
    const uint8_t numberOfCommands = sizeof commandList / sizeof commandList[0];
     
    // we assign symbolic names to the indexes to make it easier to read the code
    enum : uint8_t {Comm_0 = 0, Comm_1, Comm_2, Comm_3, Comm_4, Comm_5, Comm_6, Comm_7, Comm_8, Comm_9, Comm_Unknown = 0xFF};
     
    // define static answers if you know them
    const uint8_t answerComm_4[] = {0x03, 0x00, 0x80, 0x92}; // hardwire answer to Comm_4
     
    bool receiveCommand(t_command& aCommand)
    {
      bool commandComplete = false;
      int r = externalDevice.read();
      if (r == -1) return false;
     
      uint8_t byteReceived = (uint8_t) r;
      static uint8_t bytePosition;
     
      switch (state) {
        case WAITING_00: // handle ping
          if (r == 0x00) state = WAITING_30;
          break;
     
        case WAITING_30:
          if (r == 0x30) {
              Serial.println(F("Got PING"));
            // got ping, provide answer
            externalDevice.write(0x84);
            externalDevice.write(0x84);
            state = WAITING_LENGTH;
          } else if (r != 0x00) state = WAITING_00; // handle 00 00 30 ... by recognizing the 2 last bytes
          break;
     
        case WAITING_LENGTH:
          if (byteReceived == 0x00) { // length can't be 0. Handle possible ping
            state = WAITING_30;
          } else {
            if (byteReceived <= maxCommandLength) {
              aCommand.length = byteReceived;
              bytePosition = byteReceived;
              memset(aCommand.bytes, 0x00, maxCommandLength); // empty the previous command cf https://en.cppreference.com/w/cpp/string/byte/memset
              state = WAITING_COMMAND;
            } else {
              // handle error, this can't be a command.
              Serial.println(F("error: Command length too long"));
              externalDevice.end();                     // close the connection
              delay(100);                               // wait a bit
              externalDevice.begin(38400, SERIAL_8N1);  // open a fresh connection
              state = WAITING_00;                       //  wait for a new ping
            }
          }
          break;
     
        case WAITING_COMMAND:
          aCommand.bytes[--bytePosition] = byteReceived;
          if (bytePosition == 0) {
            commandComplete = true;
            state = WAITING_COMMAND;
          }
          break;
      }
     
      return commandComplete;
    }
     
    bool handleCommand(t_command& aCommand)
    {
      uint8_t commandIndex = Comm_Unknown;
     
      // Do we know this command?
      for (uint8_t i = 0; i < numberOfCommands; i++) {
        // check if we have the right length and matching bytes for the command
        if ((aCommand.length == commandList[i].length) && (!memcmp(aCommand.bytes, commandList[i].bytes, maxCommandLength))) { // cf memcmp() doc: https://en.cppreference.com/w/cpp/string/byte/memcmp
          commandIndex = i; // found our command
          break;
        }
      }
     
      // did we find our command?
      if (commandIndex == Comm_Unknown) return false;
     
      // we have a known command
      switch (commandIndex) {
        case Comm_0: Serial.println(F("Command 0")); /* send answer */; break;
        case Comm_1: Serial.println(F("Command 1")); /* send answer */; break;
        case Comm_2: Serial.println(F("Command 2")); /* send answer */; break;
        case Comm_3: Serial.println(F("Command 3")); /* send answer */; break;
        case Comm_4: Serial.println(F("Command 4")); externalDevice.write(answerComm_4, sizeof answerComm_4); break;
        case Comm_5: Serial.println(F("Command 5")); /* send answer */; break;
        case Comm_6: Serial.println(F("Command 6")); /* send answer */; break;
        case Comm_7: Serial.println(F("Command 7")); /* send answer */; break;
        case Comm_8: Serial.println(F("Command 8")); /* send answer */; break;
        case Comm_9: Serial.println(F("Command 9")); /* send answer */; break;
      }
      return true;
    }
     
    void setup() {
      Serial.begin(115200);
      externalDevice.begin(38400, SERIAL_8N1);
    }
     
    void loop() {
      t_command aCommand;
      if (receiveCommand(aCommand)) handleCommand(aCommand);
      // you can do other non blocking stuff here
    }
    (tapé ici, non testé - c'est plus pour vous donner une idée du principe)

  3. #3
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Juillet 2012
    Messages
    275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2012
    Messages : 275
    Par défaut
    Bonjour Jay M,

    Merci pour ta réponse.

    Alors tant que je ne répond pas 84 84, je reçois 00 30.

    Effectivement, il ne semble pas y avoir de moyen de contrôle. C'est un switcher avec un protocole propriétaire.

    Il y a de nombreuses commandes et de tailles différentes.

    Voici une commande de la doc :

    READ: 02, EFF, byte2
    WRITE: 03, EFF, byte2, byte3
    Il y a des valeurs en dur et des valeurs dynamiques par exemple (byte2, byte3).

    Je peut également essayer de jouer sur les timers.

    J'espère avoir été clair.

  4. #4
    Expert confirmé

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

    Informations professionnelles :
    Activité : mad scientist :)

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

    OK - la structure du code que je propose ci dessous permet de traiter des commandes de longueur différentes et donne un exemple d'une réponse "câblée en dur" (Requête = 03 20 10 09 -> Réponse =03 00 80 92)

    il y a un switch qui permet de reconnaître la commande reçue et donc c'est là que vous devez rajouter du code spécifique à chaque commande.

    jouer sur les timers ne présente pas grand intérêt pour coder cela, un simple traitement asynchrone permet de gérer le tout, la communication à 38400 bauds étant "super lente" il y a pas mal de temps mort entre deux caractères pour faire tous les traitements que l'on veut et le buffer de 64 octets en réception doit être très largement suffisant même si certaines de vos réponses sont un peu plus lentes

    s'il y a des trucs que vous ne comprenez pas dans le code, n'hésitez pas. (il se peut aussi qu'il y ait des bugs, c'est non testé, même pas compilé - je suis sur mon iPad)

  5. #5
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Juillet 2012
    Messages
    275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2012
    Messages : 275
    Par défaut
    Salut,

    Merci pour votre réponse.

    Il n'y pas de code dans votre message. Je vais essayer de vous envoyer un code, il est fait en nodeJS, mais nodejs n'est pas assez rapide donc je me dirige vers un arduino.

    Vincent.

  6. #6
    Expert confirmé

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

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 914
    Par défaut
    Salut Vincent
    Citation Envoyé par vins86 Voir le message
    Il n'y pas de code dans votre message
    je ne comprends pas... moi je vois bien du code dans ma première réponse

    (SerialPort de nodeJS devrait être largement assez rapide sur un ordinateur pour traiter une communication à 38400 bauds... )

  7. #7
    Expert confirmé

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

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 914
    Par défaut
    Si l'Arduino est une option - c'est plus adapté à une gestion bas niveau mais nodeJS devrait être tout à fait capable de gérer cela.

    Votre passage par une représentation ASCII des octets de commande (le parser ASCII Readline) alourdit le traitement cependant. il faudrait rester au niveau binaire.
    ensuite votre usage du timer (setInterval(Response, 0);) ne fait pas ce que vous pensez, on ne peut pas passer 0, il prend 1 par défaut dans ce cas et en 1ms vous pouvez avoir reçu quasiment 4 octets...

    Il faut traiter en permanence le flux entrant et réagir quand la commande est reconnue - un peu comme je le fais avec la machine à état dans la fonction de réception sur Arduino.

  8. #8
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Juillet 2012
    Messages
    275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2012
    Messages : 275
    Par défaut
    Bonjour,

    Je me permet de revenir vers vous après avoir eu le temps de faire quelques essais.

    Je passe bien l'étape 00 30, mais malheureusement, je ne passe pas du tout aux commandes suivantes. Voici le code 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
    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
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
     
    #define externalDevice Serial1
     
    enum t_state : uint8_t {WAITING_00, WAITING_30, WAITING_LENGTH, WAITING_COMMAND} state = WAITING_00;
     
    const uint32_t maxCommandLength = 4;
     
    struct t_command {
      uint8_t length;
      uint8_t bytes[maxCommandLength];
    };
     
    const t_command commandList[] = {   // don't forget to pad with 0x00 to the left
      {0x03, {0x00, 0x21, 0xc0, 0x05}}, // command Comm_0
      {0x03, {0x00, 0x21, 0xc0, 0x06}}, // command Comm_1
      {0x02, {0x00, 0x00, 0x00, 0x00}}, // command Comm_2
      {0x02, {0x00, 0x00, 0x00, 0x01}}, // command Comm_3
      {0x03, {0x00, 0x20, 0x10, 0x09}}, // command Comm_4
      {0x03, {0x00, 0x20, 0x11, 0x0d}}, // command Comm_5
      {0x03, {0x00, 0x20, 0x11, 0x20}}, // command Comm_6
      {0x03, {0x00, 0x10, 0x1b, 0x0d}}, // command Comm_7
      {0x03, {0x00, 0x0a, 0x1b, 0x0d}}, // command Comm_8
      {0x03, {0x00, 0x0c, 0x1b, 0x0d}}, // command Comm_9
      {0x03, {0x00, 0x20, 0x10, 0x19}}, // command Comm_10
    };
    const uint8_t numberOfCommands = sizeof commandList / sizeof commandList[0];
     
    // we assign symbolic names to the indexes to make it easier to read the code
    enum : uint8_t {Comm_0 = 0, Comm_1, Comm_2, Comm_3, Comm_4, Comm_5, Comm_6, Comm_7, Comm_8, Comm_9, Comm_10, Comm_Unknown = 0xFF};
     
    // define static answers if you know them
    const uint8_t answerComm_2[] = {0x03, 0x00, 0x80, 0x92}; // hardwire answer to Comm_2
    const uint8_t answerComm_3[] = {0x03, 0x00, 0x81, 0x17}; // hardwire answer to Comm_3
    const uint8_t answerComm_4[] = {0x04, 0x20, 0x90, 0x09, 0x01}; // hardwire answer to Comm_4
    const uint8_t answerComm_5[] = {0x04, 0x20, 0x91, 0x0d, 0x01}; // hardwire answer to Comm_5
    const uint8_t answerComm_6[] = {0x04, 0x20, 0x91, 0x20, 0x00}; // hardwire answer to Comm_6
    const uint8_t answerComm_7[] = {0x04, 0x10, 0x9b, 0x0d, 0x00}; // hardwire answer to Comm_7
    const uint8_t answerComm_8[] = {0x04, 0x0a, 0x9b, 0x0d, 0x00}; // hardwire answer to Comm_8
    const uint8_t answerComm_9[] = {0x04, 0x0c, 0x9b, 0x0d, 0x00}; // hardwire answer to Comm_9
    const uint8_t answerComm_10[] = {0x05, 0x20, 0x90, 0x19, 0x00, 0x07}; // hardwire answer to Comm_10
     
    bool receiveCommand(t_command& aCommand)
    {
      bool commandComplete = false;
      int r = externalDevice.read();
      if (r == -1) return false;
     
      uint8_t byteReceived = (uint8_t) r;
      static uint8_t bytePosition;
     
      switch (state) {
        case WAITING_00: // handle ping
          if (r == 0x00) state = WAITING_30;
          break;
     
        case WAITING_30:
          if (r == 0x30) {
              Serial.println(F("Got PING"));
            // got ping, provide answer
            externalDevice.write(0x84);
            externalDevice.write(0x84);
            state = WAITING_LENGTH;
          } else if (r != 0x00) state = WAITING_00; // handle 00 00 30 ... by recognizing the 2 last bytes
          break;
     
        case WAITING_LENGTH:
          if (byteReceived == 0x00) { // length can't be 0. Handle possible ping
            state = WAITING_30;
          } else {
            if (byteReceived <= maxCommandLength) {
              aCommand.length = byteReceived;
              bytePosition = byteReceived;
              memset(aCommand.bytes, 0x00, maxCommandLength); // empty the previous command cf https://en.cppreference.com/w/cpp/string/byte/memset
              state = WAITING_COMMAND;
            } else {
              // handle error, this can't be a command.
              Serial.println(F("error: Command length too long"));
              externalDevice.end();                     // close the connection
              delay(100);                               // wait a bit
              externalDevice.begin(38400, SERIAL_8N1);  // open a fresh connection
              state = WAITING_00;                       //  wait for a new ping
            }
          }
          break;
     
        case WAITING_COMMAND:
          aCommand.bytes[--bytePosition] = byteReceived;
          Serial.println(byteReceived, HEX);
          if (bytePosition == 0) {
            commandComplete = true;
            state = WAITING_COMMAND;
          }
          break;
      }
     
      return commandComplete;
    }
     
    bool handleCommand(t_command& aCommand)
    {
      uint8_t commandIndex = Comm_Unknown;
     
      // Do we know this command?
      for (uint8_t i = 0; i < numberOfCommands; i++) {
     
     
        // check if we have the right length and matching bytes for the command
        if ((aCommand.length == commandList[i].length) && (!memcmp(aCommand.bytes, commandList[i].bytes, maxCommandLength))) { // cf memcmp() doc: https://en.cppreference.com/w/cpp/string/byte/memcmp
          Serial.print("commands: ");
          Serial.println(i);
          commandIndex = i; // found our command
          break;
        }
      }
     
      // did we find our command?
      if (commandIndex == Comm_Unknown) return false;
     
      // we have a known command
      switch (commandIndex) {
        case Comm_0: Serial.println(F("Command 0")); /* send answer */; break;
        case Comm_1: Serial.println(F("Command 1")); /* send answer */; break;
        case Comm_2: Serial.println(F("Command 2")); externalDevice.write(answerComm_2, sizeof answerComm_2); break;
        case Comm_3: Serial.println(F("Command 3")); externalDevice.write(answerComm_3, sizeof answerComm_3); break;
        case Comm_4: Serial.println(F("Command 4")); externalDevice.write(answerComm_4, sizeof answerComm_4); break;
        case Comm_5: Serial.println(F("Command 5")); externalDevice.write(answerComm_5, sizeof answerComm_5); break;
        case Comm_6: Serial.println(F("Command 6")); externalDevice.write(answerComm_6, sizeof answerComm_6); break;
        case Comm_7: Serial.println(F("Command 7")); externalDevice.write(answerComm_7, sizeof answerComm_7); break;
        case Comm_8: Serial.println(F("Command 8")); externalDevice.write(answerComm_8, sizeof answerComm_8); break;
        case Comm_9: Serial.println(F("Command 9")); externalDevice.write(answerComm_9, sizeof answerComm_9); break;
        case Comm_10: Serial.println(F("Command 10")); externalDevice.write(answerComm_10, sizeof answerComm_10); break;
      }
      return true;
    }
     
    void setup() {
      pinMode(7, OUTPUT);
      digitalWrite(7, HIGH);
      Serial.begin(115200);
      externalDevice.begin(38400, SERIAL_8N1);
    }
     
    void loop() {
      t_command aCommand;
      if (receiveCommand(aCommand)) handleCommand(aCommand);
    }
    Je n'arrive pas à comprendre pourquoi. Vous avez peut-être l'explication.

    Merci d'avance.

    Cordialement,

    Vincent.

  9. #9
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Juillet 2012
    Messages
    275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2012
    Messages : 275
    Par défaut
    Bonjour JAY M,

    Merci pour votre retour.

    Je réceptionne bien les octets en faisant des serials. Mais je ne rentre toujours pas dans les étapes suivantes :


    Voici ce que je réceptionne :

    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
    00
    11:48:17.139 -> Got PING
    11:48:17.842 -> length :3
    11:48:17.842 -> 21
    11:48:17.842 -> C0
    11:48:17.842 -> 5
    11:48:17.842 -> 3
    11:48:17.842 -> 21
    11:48:17.842 -> C0
    11:48:17.842 -> 6
    11:48:17.842 -> 2
    11:48:17.842 -> 0
    11:48:17.842 -> 0
    11:48:17.842 -> 2
    11:48:17.842 -> 0
    11:48:17.842 -> 1
    11:48:17.842 -> 2
    11:48:17.842 -> 0
    11:48:17.842 -> F
    voici le code avec 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
    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
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    #define externalDevice Serial1
     
    enum t_state : uint8_t {WAITING_00, WAITING_30, WAITING_LENGTH, WAITING_COMMAND} state = WAITING_00;
     
    const uint32_t maxCommandLength = 4;
     
    struct t_command {
      uint8_t length;
      uint8_t bytes[maxCommandLength];
    };
     
    const t_command commandList[] = {   // don't forget to pad with 0x00 to the left
      {0x03, {0x00, 0x21, 0xc0, 0x05}}, // command Comm_0
      {0x03, {0x00, 0x21, 0xc0, 0x06}}, // command Comm_1
      {0x02, {0x00, 0x00, 0x00, 0x00}}, // command Comm_2
      {0x02, {0x00, 0x00, 0x00, 0x01}}, // command Comm_3
      {0x03, {0x00, 0x20, 0x10, 0x09}}, // command Comm_4
      {0x03, {0x00, 0x20, 0x11, 0x0d}}, // command Comm_5
      {0x03, {0x00, 0x20, 0x11, 0x20}}, // command Comm_6
      {0x03, {0x00, 0x10, 0x1b, 0x0d}}, // command Comm_7
      {0x03, {0x00, 0x0a, 0x1b, 0x0d}}, // command Comm_8
      {0x03, {0x00, 0x0c, 0x1b, 0x0d}}, // command Comm_9
      {0x03, {0x00, 0x20, 0x10, 0x19}}, // command Comm_10
    };
    const uint8_t numberOfCommands = sizeof commandList / sizeof commandList[0];
     
    // we assign symbolic names to the indexes to make it easier to read the code
    enum : uint8_t {Comm_0 = 0, Comm_1, Comm_2, Comm_3, Comm_4, Comm_5, Comm_6, Comm_7, Comm_8, Comm_9, Comm_10, Comm_Unknown = 0xFF};
     
    // define static answers if you know them
    const uint8_t answerComm_2[] = {0x03, 0x00, 0x80, 0x92}; // hardwire answer to Comm_2
    const uint8_t answerComm_3[] = {0x03, 0x00, 0x81, 0x17}; // hardwire answer to Comm_3
    const uint8_t answerComm_4[] = {0x04, 0x20, 0x90, 0x09, 0x01}; // hardwire answer to Comm_4
    const uint8_t answerComm_5[] = {0x04, 0x20, 0x91, 0x0d, 0x01}; // hardwire answer to Comm_5
    const uint8_t answerComm_6[] = {0x04, 0x20, 0x91, 0x20, 0x00}; // hardwire answer to Comm_6
    const uint8_t answerComm_7[] = {0x04, 0x10, 0x9b, 0x0d, 0x00}; // hardwire answer to Comm_7
    const uint8_t answerComm_8[] = {0x04, 0x0a, 0x9b, 0x0d, 0x00}; // hardwire answer to Comm_8
    const uint8_t answerComm_9[] = {0x04, 0x0c, 0x9b, 0x0d, 0x00}; // hardwire answer to Comm_9
    const uint8_t answerComm_10[] = {0x05, 0x20, 0x90, 0x19, 0x00, 0x07}; // hardwire answer to Comm_10
     
    bool receiveCommand(t_command& aCommand)
    {
      bool commandComplete = false;
      int r = externalDevice.read();
      if (r == -1) return false;
     
      uint8_t byteReceived = (uint8_t) r;
      static uint8_t bytePosition;
     
      switch (state) {
        case WAITING_00: // handle ping
          if (r == 0x00) state = WAITING_30;
          Serial.println(F("00"));
          break;
     
        case WAITING_30:
          if (r == 0x30) {
              Serial.println(F("Got PING"));
            // got ping, provide answer
            externalDevice.write(0x84);
            externalDevice.write(0x84);
            state = WAITING_LENGTH;
          } else if (r != 0x00) state = WAITING_00; // handle 00 00 30 ... by recognizing the 2 last bytes
          break;
     
        case WAITING_LENGTH:
          if (byteReceived == 0x00) { // length can't be 0. Handle possible ping
            state = WAITING_30;
          } else {
            if (byteReceived <= maxCommandLength) {
              aCommand.length = byteReceived;
              bytePosition = byteReceived;
              Serial.print(F("length :"));
              Serial.println(byteReceived);
              memset(aCommand.bytes, 0x00, maxCommandLength); // empty the previous command cf https://en.cppreference.com/w/cpp/string/byte/memset
              state = WAITING_COMMAND;
            } else {
              // handle error, this can't be a command.
              Serial.println(F("error: Command length too long"));
              externalDevice.end();                     // close the connection
              delay(100);                               // wait a bit
              externalDevice.begin(38400, SERIAL_8N1);  // open a fresh connection
              state = WAITING_00;                       //  wait for a new ping
            }
          }
          break;
     
        case WAITING_COMMAND:
          aCommand.bytes[--bytePosition] = byteReceived;
          Serial.println(byteReceived, HEX);
          if (bytePosition == 0) {
            commandComplete = true;
            state = WAITING_COMMAND;
          }
          break;
      }
     
      return commandComplete;
    }
     
    bool handleCommand(t_command& aCommand)
    {
      uint8_t commandIndex = Comm_Unknown;
     
      // Do we know this command?
      for (uint8_t i = 0; i < numberOfCommands; i++) {
     
     
        // check if we have the right length and matching bytes for the command
        if ((aCommand.length == commandList[i].length) && (!memcmp(aCommand.bytes, commandList[i].bytes, maxCommandLength))) { // cf memcmp() doc: https://en.cppreference.com/w/cpp/string/byte/memcmp
          Serial.print(F("commands: "));
          Serial.println(i);
          commandIndex = i; // found our command
          break;
        }
      }
     
      // did we find our command?
      if (commandIndex == Comm_Unknown) return false;
     
      // we have a known command
      switch (commandIndex) {
        case Comm_0: Serial.println(F("Command 0")); /* send answer */; break;
        case Comm_1: Serial.println(F("Command 1")); /* send answer */; break;
        case Comm_2: Serial.println(F("Command 2")); externalDevice.write(answerComm_2, sizeof answerComm_2); break;
        case Comm_3: Serial.println(F("Command 3")); externalDevice.write(answerComm_3, sizeof answerComm_3); break;
        case Comm_4: Serial.println(F("Command 4")); externalDevice.write(answerComm_4, sizeof answerComm_4); break;
        case Comm_5: Serial.println(F("Command 5")); externalDevice.write(answerComm_5, sizeof answerComm_5); break;
        case Comm_6: Serial.println(F("Command 6")); externalDevice.write(answerComm_6, sizeof answerComm_6); break;
        case Comm_7: Serial.println(F("Command 7")); externalDevice.write(answerComm_7, sizeof answerComm_7); break;
        case Comm_8: Serial.println(F("Command 8")); externalDevice.write(answerComm_8, sizeof answerComm_8); break;
        case Comm_9: Serial.println(F("Command 9")); externalDevice.write(answerComm_9, sizeof answerComm_9); break;
        case Comm_10: Serial.println(F("Command 10")); externalDevice.write(answerComm_10, sizeof answerComm_10); break;
      }
      return true;
    }
     
    void setup() {
      pinMode(7, OUTPUT);
      digitalWrite(7, HIGH);
      Serial.begin(115200);
      externalDevice.begin(38400, SERIAL_8N1);
    }
     
    void loop() {
      static t_command aCommand;
      if (receiveCommand(aCommand)) handleCommand(aCommand);
      // you can do other non blocking stuff here
    }
    Merci d'avance pour ton aide.

    Cordialement,

    Vincent.

  10. #10
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Juillet 2012
    Messages
    275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2012
    Messages : 275
    Par défaut
    Bonjour jay M,

    Je me permet de revenir vers vous sur l'avancement du projet.

    Nous sommes partie sur une autre façon de faire. Nous avons branché les appareils d'origines et nous avons fait un pont pour intercepter les commandes par un programme NodeJS.

    Nous avons fait le test sur une commande et le résultat est plutôt concluant même s'il nous arrive d'avoir quelques loupés de temps en temps. Nous essayerons de remplacer l'appareil de réponse quand on aura bien compris le fonctionnement.

    Je me permet de transmettre le code, puis-je continuer sur ce sujet ou dois-je créer un nouveau sujet sur la rubrique NodeJS?

    Code JavaScript : 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
    87
    88
    89
    90
    91
    var Atem = require('dpclive-atem') // Load the atem module
    const SerialPort = require('serialport')
     
    let array = new Array();
     
    const atem = new Atem();
    const port = new SerialPort('COM7', {
        baudRate: 38400,
        dataBits: 8,
        parity: 'none',
        stopBits: 1,
        flowControl: false
    })
     
    port.open(function (err) {
      if (err) {
        return console.log('Error opening port: ', err.message)
      }
    })
     
    let scratch = [];
     
    function isCommand(byte) {
        if ((byte == 2) || (byte == 3) || (byte == 4) || (byte == 5) || (byte == 6)) {
            return true;
        } else {
            return false;
        }
    }
     
    function analyseCmd(cmd)
    {
        if ((cmd[0] == 3) && (cmd[1] == 0)) {
            console.log("BUS: " + cmd[2] + " BTN: " + cmd[3]);
            var input = cmd[3];
            //console.log(input-128);
            atem.setProgram(input-127, 0);
        }
    }
     
    port.on('data', function (data) {
        //array.push(data);
        // console.table(data);
        // console.table("---------");
        let i = 0;
        let lastIndex = 0;
     
        for (let j = 0; j < data.length; j++) {
            scratch.push(data[j]);
        }
     
        let foundFrame = false;
        if (scratch.length >= 10) {
         //   console.log("Scratch size: " + scratch.length);
            for (i = 0; i < scratch.length;) {
                let nbCar = scratch[i];
                if (isCommand(nbCar)) {
                    // un potentiel début de trame
                    let remainingSize = scratch.length - (i+1);
                    if (remainingSize > nbCar) {
                        // On est ici si on a la place pour stocker les données + l'octet de la commande suivante
                        if (isCommand(scratch[i + nbCar + 1])) {
                          //  console.log("Found frame: " + nbCar.toString(16));
                            // FIXME : analyser la commande, les données
                            foundFrame = true;
                            analyseCmd(scratch.slice(i, i + nbCar + 1));
                            i += (nbCar + 1);
                            lastIndex = i;
     
                        } else {
                            i++; // c'est pas une commande, on continue le scan ...
                        }
                    } else if (foundFrame) {
                        // Si la trame précédente était bonne, alors on est en bout de buffer
                        scratch.splice(0, lastIndex);
                        return; // on quitte l'analyse
                    } else {
                        i++;
                    }
                } else {
                    i++;
                }
     
            } // for ()
        }
     
     
    })
     
    atem.ip = '192.168.1.111';
    atem.connect();

    Merci pour votre aide très précieux.

    Cordialement,

    Vincent.

  11. #11
    Expert confirmé

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

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 914
    Par défaut
    j'ai un bug dans la loop()

    il faut déclarer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static  t_command aCommand;
    pour que la longueur soit bien conservée quand on fait tourner la machine à états

    Si ça ne fonctionne pas, rajoutez des print dans tous les case pour dire où vous êtes et l’octet reçu

    Ça aidera le debugging

  12. #12
    Expert confirmé

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

    Informations professionnelles :
    Activité : mad scientist :)

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


    j'ai laissé un bug (pour voir si vous suiviez bien sûr .... )

    je vous laisse trouver, c'est dans
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        case WAITING_COMMAND:
          aCommand.bytes[--bytePosition] = byteReceived;
          Serial.println(byteReceived, HEX);
          if (bytePosition == 0) {
            commandComplete = true;
            state = WAITING_COMMAND;
          }
          break;
    ==> une fois qu'on a reçu la commande complète, quel devrait être le prochain état? (qu'attendez vous en début de prochaine commande?)

  13. #13
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Juillet 2012
    Messages
    275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2012
    Messages : 275
    Par défaut
    Ah oui, je ne comprend pas tout le code, désolé.

    Donc si j'ai bien compris, c'est ceci pour passer à l'étape suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        case WAITING_COMMAND:
          aCommand.bytes[--bytePosition] = byteReceived;
          Serial.println(byteReceived, HEX);
          if (bytePosition == 0) {
            commandComplete = true;
            state = WAITING_LENGTH;
          }
          break;
    Cordialement,

    Vincent.

  14. #14
    Expert confirmé

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

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 914
    Par défaut
    BRAVO !!


    notez aussi qu'avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
          aCommand.bytes[--bytePosition] = byteReceived;
    on range les octets reçus à partir de la fin du tableau. Donc si la commande est émise dans le même ordre que la définition du tableau il ne faut pas ranger dans ce sens mais de manière croissante, donc définir bytePosition qui commence à 0 et croissant jusqu'à avoir reçu le bon nombre d'octets
    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
    case WAITING_LENGTH:
          if (byteReceived == 0x00) { // length can't be 0. Handle possible ping
            state = WAITING_30;
          } else {
            if (byteReceived <= maxCommandLength) {
              aCommand.length = byteReceived;
              bytePosition = 0;
              Serial.print(F("length :"));
              Serial.println(byteReceived);
              memset(aCommand.bytes, 0x00, maxCommandLength); // empty the previous command cf https://en.cppreference.com/w/cpp/string/byte/memset
              state = WAITING_COMMAND;
            } else {
              // handle error, this can't be a command.
              Serial.println(F("error: Command length too long"));
              externalDevice.end();                     // close the connection
              delay(100);                               // wait a bit
              externalDevice.begin(38400, SERIAL_8N1);  // open a fresh connection
              state = WAITING_00;                       //  wait for a new ping
            }
          }
          break;
    
        case WAITING_COMMAND:
          aCommand.bytes[bytePosition++] = byteReceived;
          Serial.println(byteReceived, HEX);
          if (bytePosition >= aCommand.length) {
            commandComplete = true;
            state = WAITING_LENGTH; // BRAVO !
          }
          break;

  15. #15
    Expert confirmé

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

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 914
    Par défaut
    Je ne suis pas un des modérateurs ici, mais il me semble que comme ce n’est plus vraiment dans ce cas un post pour le monde arduino, vaudrait mieux effectivement choisir un forum plus approprié si vous avez d’autres questions

Discussions similaires

  1. Traitement d'images : quel langage?
    Par belasri dans le forum Langages de programmation
    Réponses: 19
    Dernier message: 07/10/2005, 09h59
  2. Durée d'un traitement temps réel
    Par Almex dans le forum C
    Réponses: 5
    Dernier message: 29/03/2003, 14h15
  3. [directsound] boucle de traitement de son
    Par gargle dans le forum DirectX
    Réponses: 5
    Dernier message: 24/03/2003, 10h47
  4. Traitement d'un char* renvoyé par une DLL en C++
    Par LuluTchab dans le forum Langage
    Réponses: 4
    Dernier message: 22/03/2003, 21h48
  5. Rafraichissement de la fenetre pendant le traitement
    Par Bobx dans le forum Composants VCL
    Réponses: 5
    Dernier message: 20/02/2003, 15h13

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