Il existe de nombreuses façons d'écrire un protocole série en fonction des fonctionnalités que vous souhaitez et du niveau de vérification des erreurs dont vous avez besoin.
Certaines des choses courantes que vous voyez dans les protocoles point à point sont:
Fin du message
Les protocoles ASCII les plus simples ont juste une séquence de caractères de fin de message, souvent \r
ou \n
comme c'est ce qui est imprimé lorsque la touche Entrée est enfoncée. Les protocoles binaires peuvent utiliser 0x03
ou un autre octet commun.
Début du message
Le problème avec la fin du message est que vous ne savez pas quels autres octets ont déjà été reçus lorsque vous envoyez votre message. Ces octets seraient alors préfixés au message et provoqueraient une mauvaise interprétation. Par exemple, si l'Arduino vient de se réveiller, il peut y avoir des ordures dans le tampon série. Pour contourner cela, vous avez un début de séquence de messages. Dans votre exemple ^
, dans les protocoles binaires, souvent0x02
Vérification des erreurs
Si le message peut être corrompu, nous avons besoin d'une vérification d'erreur. Cela pourrait être une somme de contrôle ou une erreur CRC ou autre chose.
Caractères d'échappement
Il se peut que la somme de contrôle s'ajoute à un caractère de contrôle, tel que l'octet «début de message» ou «fin de message», ou que le message contienne une valeur égale à un caractère de contrôle. La solution est d'introduire un caractère d'échappement. Le caractère d'échappement est placé avant un caractère de contrôle modifié afin que le caractère de contrôle réel ne soit pas présent. Par exemple, si un caractère de début est 0x02, en utilisant le caractère d'échappement 0x10, nous pouvons envoyer la valeur 0x02 dans le message comme paire d'octets 0x10 0x12 (caractère de contrôle XOR octet)
Numéro de paquet
Si un message est corrompu, nous pourrions demander un renvoi avec un message nack ou retry, mais si plusieurs messages ont été envoyés, seul le dernier message peut être renvoyé. Au lieu de cela, le paquet peut recevoir un numéro qui se renouvelle après un certain nombre de messages. Par exemple, si ce nombre est 16, le périphérique émetteur peut stocker les 16 derniers messages envoyés et s'il y en a un endommagé, le périphérique récepteur peut demander un renvoi en utilisant le numéro de paquet.
Longueur
Souvent, dans les protocoles binaires, vous voyez un octet de longueur qui indique au périphérique récepteur le nombre de caractères dans le message. Cela ajoute un autre niveau de vérification d'erreur comme si le nombre correct d'octets n'était pas reçu, il y avait alors une erreur.
Spécifique à l'Arduino
Lors de l'élaboration d'un protocole pour Arduino, la première considération est la fiabilité du canal de communication. Si vous envoyez sur la plupart des supports sans fil, XBee, WiFi, etc., la vérification des erreurs et les tentatives sont déjà intégrées et donc inutile de les mettre dans votre protocole. Si vous envoyez un RS422 sur quelques kilomètres, cela sera nécessaire. Les choses que j'inclurais sont le début du message et la fin des caractères du message, comme vous l'avez fait. Mon implémentation typique ressemble à ceci:
>messageType,data1,data2,…,dataN\n
La délimitation des parties de données par une virgule permet une analyse facile et le message est envoyé en ASCII. Les protocoles ASCII sont excellents car vous pouvez taper des messages dans le moniteur série.
Si vous voulez un protocole binaire, peut-être pour raccourcir la taille des messages, vous devrez implémenter l'échappement si un octet de données peut être le même qu'un octet de contrôle. Les caractères de contrôle binaire sont meilleurs pour les systèmes où le spectre complet de vérification d'erreur et de nouvelles tentatives est souhaité. La charge utile peut toujours être ASCII si vous le souhaitez.
Je n'ai aucune expertise formelle sur les protocoles série, mais je les ai utilisés pas mal de fois, et plus ou moins installés sur ce schéma:
(En-tête de paquet) (octet ID) (données) (somme de contrôle fletcher16) (pied de page de paquet)
Je fais d'habitude l'en-tête 2 octets et le pied de page 1 octet. Mon analyseur va tout vider quand il voit un nouvel en-tête de paquet et tenter d'analyser le message s'il voit un pied de page. Si la somme de contrôle échoue, elle n'abandonnera pas le message, mais continuera d'ajouter jusqu'à ce que le caractère de pied de page soit trouvé et qu'une somme de contrôle réussisse. De cette façon, le pied de page n'a besoin que d'un octet, car les collisions ne perturbent pas le message.
L'ID est arbitraire, parfois avec la longueur de la section de données étant le quartet inférieur (4 bits). Un deuxième bit de longueur pourrait être utilisé, mais je ne me dérange pas normalement car la longueur n'a pas besoin d'être connue pour être analysée correctement, donc voir la bonne longueur passer pour un ID donné est juste une confirmation supplémentaire que le message était correct.
La somme de contrôle fletcher16 est une somme de contrôle de 2 octets avec presque la même qualité que CRC mais est beaucoup plus facile à implémenter. quelques détails ici . Le code peut être aussi simple que cela:
J'ai également utilisé un système d'appel et de réponse pour les messages critiques, où le PC enverra un message toutes les 500 ms environ jusqu'à ce qu'il obtienne un message OK avec une somme de contrôle de tout le message d'origine en tant que données (y compris la somme de contrôle d'origine).
Ce schéma n'est bien sûr pas bien adapté pour être tapé dans un terminal comme le serait votre exemple. Votre protocole semble assez bon pour être limité à ASCII et je suis sûr qu'il est plus facile pour un projet rapide que vous souhaitez pouvoir lire et envoyer directement des messages. Pour les grands projets, il est agréable d'avoir la densité d'un protocole binaire et la sécurité d'une somme de contrôle.
la source
Si vous êtes dans les normes, vous pouvez jeter un œil au codage ASN.1 / BER TLV. ASN.1 est un langage utilisé pour décrire les structures de données, conçu spécifiquement pour la communication. BER est une méthode TLV de codage des données structurées en utilisant ASN.1. Le problème est que le codage ASN.1 peut être difficile au mieux. La création d'un compilateur ASN.1 à part entière est un projet en soi (et particulièrement délicat à cela, pensez-y des mois ).
Il est probablement préférable de ne conserver que la structure TLV. TLV se compose essentiellement de trois éléments: une balise, une longueur et un champ de valeur. La balise définit le type des données (chaîne de texte, chaîne d'octets, entier, etc.) et la longueur la longueur de la valeur .
Dans BER, le T indique également si la valeur est un ensemble de structures TLV lui-même (un nœud construit) ou directement une valeur (un nœud primitif). De cette façon, vous pouvez créer un arbre en binaire, un peu comme XML (mais sans la surcharge XML).
Exemple:
est un entier (balise
02
) d'une longueur de la valeur de 1 (longueur01
) et de la valeur -1 (valeurFF
). Dans ASN.1 / BER, les entiers sont de grands nombres endiens, mais vous pouvez bien sûr utiliser votre propre format.est une séquence (une liste) de longueur 7 contenant deux entiers, un avec la valeur -1 et l'autre avec la valeur 255. Les deux codages entiers constituent ensemble la valeur de la séquence.
Vous pouvez également simplement jeter cela dans un décodeur en ligne, n'est-ce pas sympa?
Vous pouvez également utiliser une longueur indéfinie dans BER qui vous permettra de diffuser des données. Dans ce cas, vous devez cependant analyser correctement votre arbre. Je considérerais que c'est un sujet avancé, vous devez connaître d'abord l'analyse en largeur et en profondeur, pour commencer.
L'utilisation d'un schéma TLV vous permet de penser à n'importe quel type de structure de données et de l'encoder. ASN.1 va beaucoup plus loin que cela, vous donnant des identifiants uniques (OID), des choix (un peu comme les unions C), des inclusions d'autres structures ASN.1, etc., etc., mais cela peut être exagéré pour votre projet. Les structures les plus connues définies par ASN.1 sont probablement les certificats utilisés par votre navigateur.
la source
Sinon, vous avez couvert les bases. Vos commandes peuvent être créées et lues par des humains et des machines, ce qui est un gros plus. Vous pouvez ajouter une somme de contrôle pour détecter une commande mal formée ou endommagée pendant le transport, en particulier si votre chaîne comprend un long câble ou une liaison radio.
Si vous avez besoin d'une puissance industrielle (votre appareil ne doit pas causer ou blesser quelqu'un ou mourir; vous avez besoin de débits de données élevés, de la récupération des pannes, de la détection de paquets manquants, etc.), consultez certains des protocoles et pratiques de conception standard.
la source