web-dev-qa-db-fra.com

Comment concevez-vous un protocole de commande série pour un système embarqué?

J'ai un système intégré avec lequel je communique en série. À l'heure actuelle, la structure de commandes est conçue pour fonctionner de manière interactive: elle affiche une invite, accepte quelques commandes et affiche les résultats sous une forme lisible par l'homme.

Je pense à changer cela en un format plus utilisable par la machine, donc je peux lui parler via une interface graphique MATLAB sans trop de problèmes (en ce moment, il y a un hoquet sur les invites interactives et des longueurs de message variables, etc.).

Existe-t-il un document ou une norme quelque part décrivant comment concevoir un bon protocole de commande série pour votre système embarqué?

40
jparker

J'ai des préférences (et des bêtes noires) concernant l'écriture de logiciels pour contrôler les médias et les périphériques d'affichage à l'aide de RS232. Selon votre matériel, certains d'entre eux peuvent ne pas s'appliquer:

  • Je pense que c'est une bonne idée de rendre votre protocole plus convivial pour l'automatisation. Si vous avez besoin d'une interface interactive (ligne de commande ou autre), créez-la séparément et faites-la utiliser le protocole d'automatisation. Je ne m'inquiéterais pas trop de le rendre lisible par l'homme, mais cela dépend de vous.

  • Renvoyez toujours une réponse, même (surtout) si vous obtenez une commande invalide. Quelque chose de simple comme 06 $ pour ACK et 15 $ pour NAK. Ou expliquez-le si vous voulez qu'il soit légèrement plus lisible par l'homme.

  • Si vous pouvez définir n'importe quelle valeur, assurez-vous qu'il existe un moyen d'interroger cette même valeur. Si vous avez beaucoup de valeurs, cela peut prendre un certain temps pour les interroger toutes. Pensez à avoir une ou quelques méta-requêtes qui retournent plusieurs valeurs à la fois.

  • Si vous avez des informations qui ne peuvent pas être définies, mais qui sont importantes (numéro de modèle, numéro de série, version, copyright, etc.), assurez-vous qu'elles peuvent être consultées au lieu de les afficher une seule fois au démarrage ou à la réinitialisation.

  • Ne répondez jamais avec une erreur pour une commande valide. On pourrait penser que celui-ci serait évident ...

  • En parlant d'évident, documentez les paramètres série pris en charge par votre matériel. Surtout s'il va être utilisé par quelqu'un d'autre que vous et que vous ne voulez pas qu'ils passent les 30 premières minutes à essayer de comprendre s'ils ne peuvent pas parler à l'appareil à cause du port série, des connexions, du câble ou leur logiciel. Pas que je sois amer ...

  • Utilisez des commandes absolues au lieu de basculer les valeurs. Par exemple, ayez des commandes distinctes pour la mise sous tension et hors tension au lieu d'envoyer la même commande et d'activer et de désactiver la mise sous tension.

  • Les réponses doivent inclure des informations sur la commande à laquelle elles répondent. De cette façon, aucun programme n'a besoin de se souvenir de la dernière chose qu'il a demandée pour traiter la réponse (voir l'option de crédit supplémentaire ci-dessous).

  • Si votre appareil prend en charge un mode veille (désactivé, mais pas vraiment désactivé), assurez-vous que les requêtes fonctionnent toujours lorsque vous êtes dans cet état.

Selon la façon dont vous êtes paranoïaque quant à l'exhaustivité des données:

  • Enveloppez votre message dans une enveloppe. L'en-tête peut inclure un caractère de départ, la longueur du message et un caractère de fermeture. Juste au cas où vous recevez des messages partiels ou malformés. Peut-être 02 $ pour le début et 03 $ pour la fin.

  • Si vous êtes vraiment paranoïaque à propos de l'intégrité des messages, incluez une somme de contrôle. Ils peuvent cependant être un peu pénibles.

Pour un crédit supplémentaire:

  • Si vos paramètres matériels peuvent être modifiés manuellement, envoyez peut-être cette modification sur le port série comme si l'utilisateur l'avait interrogé. Par exemple, vous ne souhaiterez peut-être pas que l'utilisateur puisse modifier la source d'entrée d'un moniteur d'affichage public.

J'espère que ça aide.

Mise à jour:

J'ai oublié quelque chose d'important. Avant de l'utiliser sérieusement et surtout avant de le donner à quelqu'un d'autre, essayez-le sur quelque chose de trivial pour vous assurer qu'il fonctionne comme vous le souhaitez et (plus important encore) pour vous assurer que vous n'avez rien oublié. Il faudra plus de temps et d'efforts pour résoudre les problèmes si vous rencontrez un problème au milieu d'un projet plus important.

C'est une bonne règle de base, que vous conceviez un protocole de commande, un service Web, un schéma de base de données ou une classe, etc.

51
Bruce McGee

Ici est un excellent article d'Eli Benderski sur le cadrage du protocole série. Quel que soit le format de paquet que vous avez choisi, assurez-vous d'utiliser des caractères d'échappement. Il vous permet d'avoir de tels caractères dans les données réelles et facilite la resynchronisation en cas de corruption de paquets.

15
Marcelo MD

Sauf si la bande passante ou la latence est un gros problème, utilisez ASCII où vous le pouvez - cela facilite le débogage.

J'aime les protocoles qui envoient un message, puis un caractère clair de "fin de message" (tel que "retour chariot"). Je ne trouve généralement pas que le début des signaux de paquets soit aussi utile (quoi d'autre sur ce fil?) L'utilisation de CR pour la fin du message facilite également le test via le programme du terminal.

Mise à jour: Bruce a souligné (dans les commentaires) qu'un début de caractère de paquet vous permet de trouver les paquets un peu plus rapidement en cas de corruption. Sans le début du caractère de paquet, il faudrait jusqu'à la fin du paquet suivant avant de savoir où vous étiez et à ce moment-là, vous lanceriez 2 paquets au lieu d'un.

7
Michael Kohne

J'aime les réponses de Bruce McGee. Ayant travaillé avec des interfaces similaires, je peux proposer plusieurs autres pointeurs:

  • Lorsque vous retournez des types numériques dans un paquet de données, veuillez essayer de tout faire au même format. Ne pas avoir simple pour certains nombres et double pour d'autres. Et ne le rendez pas arbitraire!

  • Fournissez des exemples de paquets de données dans votre CIM. C'est terriblement frustrant de devoir deviner l'ordre des octets ou même l'ordre des bits (MSByte est-il premier ou dernier? Qu'est-ce qui est premier et dernier?). Fournissez un diagramme qui montre les paquets en fonction du temps (c'est-à-dire que 0x02 est envoyé au plus tôt, puis l'octet d'adresse, puis l'identifiant du message, etc.).

  • Ne permutez pas entre les formats de données si possible. J'ai travaillé dans des systèmes qui utilisent des "nombres codés ASCII" pour certains messages où vous devez supprimer le "3" principal des octets, puis les rassembler pour former le vrai nombre. (Le codage ASCII est généralement utilisé lorsque vous avez une séquence d'octets que vous devez éviter, comme 0x02, 0x04, etc. moins le faire tout le temps!)

  • Certainement, définitivement, documentez le débit en bauds, la parité, etc. . Donnez des captures d'écran si vous le devez.

Cette interface sera probablement très utile pour le débogage. J'ai travaillé avec certains systèmes qui avaient des fonctionnalités de débogage telles que:

  • Un système où le programmeur a fait une liste de "paramètres enregistrés" (variables internes). Vous indiqueriez au système ceux que vous vouliez signaler (jusqu'à 8), puis lorsque vous interrogiez le système pour les paramètres enregistrés, il les renvoyait dans un seul paquet de données. J'ai aimé cela, mais selon la complexité du système, vous pouvez ou non être en mesure de les spécifier au moment de l'exécution (ou vous pouvez faire quelque chose de simple et envoyer au système un masque qui sélectionnerait ceux que vous souhaitez renvoyer).

  • Paquets de données qui "cassent" le comportement et permettent à des parties du système d'être testées indépendamment (c'est-à-dire, sur un D/A éteindre cette tension, sur un port DIO stimulant cet octet, etc.)

Bonne chance!

6
Stephen Friederichs

Si vous devez avoir votre propre protocole,

Veuillez s'il vous plaît s'il vous plaît utiliser le cadrage des paquets.

SLIP Framing seulement quelques lignes de code. Spécifié dans (RFC 1055)

Alors maintenant, tous les paquets peuvent toujours ressembler à ceci

 <slip packet start>
 message
 message crc
 <slip packet start>

N'envoyez pas de longueur de message. Il peut être corrompu, puis les analyseurs de messages du récepteur sont confus.

Si votre récepteur a un petit tampon de récepteur et qu'il déborde, vous continuez à lire jusqu'à la limite du paquet. Pas de mal.

Beaucoup de CRC simples de 2 octets; le Xmodem est simple. Vous pouvez juste xor tous les octets dans le paquet dont vous avez besoin.

Si vous vouliez être une personne vraiment sympa, utilisez PPP, DDNS et HTTP-REST pour vos commandes réelles. Beau livre sur le faire sur le processeur PIC série 16 en C par Jeremy Bentham, TCP/IP Lean.

Ensuite, vous pouvez utiliser un navigateur Web pour lui parler, ou quelque chose comme libcurl à partir du code C. Comme presque tous les langages de programmation ont des bibliothèques pour faire http, tout le monde peut parler à votre appareil.

5
Tim Williscroft

Il y a beaucoup de bonnes suggestions et idées ici et notez qu'il existe différentes façons de s'y attaquer à des fins différentes. Après avoir utilisé de nombreux protocoles série à la fois bons et mauvais et en avoir fait plusieurs (bons ou mauvais ...) voici quelques-unes de mes suggestions et commentaires.

  • Rester simple. J'ai trouvé le plus grand succès avec des "paquets" de réponse de commande basés sur un en-tête simple.

  • Ne vous inquiétez pas de l'ASCII lisible par l'homme. Il n'est utile que pendant les quelques heures pendant lesquelles vous déboguez réellement votre protocole. Après cela, il est restrictif de toujours coder les données en tant que ASCII et très inefficace si vous transférez beaucoup de données.

  • Utilisez la vérification des erreurs. Je préfère un CRC 16 bits car il fournit des ordres de grandeur de protection sur une somme de contrôle et est toujours simple et efficace sur des algorithmes plus lourds comme MD5 ou SHA1.

  • Utilisez le même format de paquet pour les commandes que les réponses.

  • Utilisez des données 8 bits sans parité. Le bit de parité série n'ajoute aucune protection si vous utilisez déjà un autre contrôle d'intégrité des données CRC ou un mauvais contrôle d'erreur au mieux.

  • Donc, dans la forme la plus simple, l'en-tête du paquet est la commande ou la réponse, la taille du paquet, zéro ou plusieurs données et le code de vérification d'erreur (CRC).

4
newts

FTP est un exemple de protocole qui fonctionne raisonnablement bien à la fois de manière interactive et avec l'automatisation. L'une des clés est que les réponses commencent par un code qui indique si un client automatisé doit payer attnetion ou non. De même pour POP3.

Une bonne chose à propos de ces protocoles est que lorsque vous développez/déboguez, vous pouvez raisonnablement conduire la communication à partir d'un terminal normal ou scripter la communication en utilisant des scripts Shell/fichiers batch/quoi que ce soit.

Cependant, une chose qu'ils ne font pas est de fournir la fiabilité - qui est fournie par une couche inférieure de la pile de communication. C'est quelque chose qui devrait être pris en compte dans la plupart des communications intégrées.

2
Michael Burr

Avez-vous regardé Modbus ( http://www.modbus.org/ )? C'est un protocole assez simple qui inclut une somme de contrôle sur chaque message. Il envoie également une réponse à chaque commande, même celles qui n'ont pas besoin d'une "valeur de retour", donc vous savez si votre commande a été reçue correctement. Le seul choix que vous auriez après avoir choisi Modbus serait les adresses de registre pour stocker vos données et le format de toutes les fonctions définies par l'utilisateur (que le protocole MODBUS autorise).

2
Sam Skuce

Jetez un œil à Firmata comme exemple de protocole.

1
Matthew Murdoch