embedded - sirve - ¿Cómo se diseña un protocolo de comando en serie para un sistema integrado?
protocolo http ejemplos (9)
Tengo un sistema integrado con el que me comunico en serie. La estructura de comandos en este momento está diseñada para ser operada de manera interactiva: muestra un aviso, acepta unos pocos comandos y muestra los resultados en una forma legible por humanos.
Estoy pensando en cambiar esto a un formato más utilizable por máquina, para poder hablar con él a través de una GUI de MATLAB sin demasiados problemas (en este momento está hipando en las indicaciones interactivas y variando la duración de los mensajes, etc.).
Entonces, ¿hay algún documento o norma en algún lugar que describa cómo diseñar un buen protocolo de comando en serie para su sistema integrado?
¿Has mirado a Modbus ( http://www.modbus.org/ )? Es un protocolo bastante simple que incluye una suma de comprobación en cada mensaje. También envía una respuesta a cada comando, incluso aquellos que no necesitan un "valor de retorno", para que sepa si su comando se recibió correctamente. La única opción que tendría después de elegir Modbus serían las direcciones de registro para almacenar sus datos y el formato de las funciones definidas por el usuario (que permite el protocolo MODBUS).
A menos que el ancho de banda o la latencia sea un gran problema, use ASCII donde pueda, facilita la depuración.
Me gustan los protocolos que envían un mensaje y luego un carácter claro de "fin de mensaje" (como "retorno de carro"). En general, no creo que el inicio de las señales de paquete sea tan útil (¿qué más hay en ese cable?) El uso de CR para el fin del mensaje también facilita la prueba a través del programa de terminal.
Actualización: Bruce señaló (en los comentarios) que el inicio del carácter del paquete le permite encontrar los paquetes un poco más rápido en caso de corrupción. Sin el inicio del carácter del paquete, tomaría hasta el final del siguiente paquete antes de que supiera dónde estaba y en ese momento estaría tirando 2 paquetes en lugar de uno.
Aquí hay muchas buenas sugerencias e ideas y observe que hay diferentes maneras de abordarlo para diferentes propósitos. Después de haber usado muchos protocolos seriales tanto buenos como malos, así como haber hecho varios de los míos (tanto buenos como malos ...) aquí hay algunas de mis sugerencias y comentarios.
Mantenlo simple. He encontrado el mayor éxito con simples "paquetes" de comando-respuesta basados en encabezados.
No se preocupe por ASCII legible por humanos. Solo es útil durante las pocas horas que realmente depura su protocolo. Después de eso, es restrictivo codificar siempre los datos como ASCII y muy ineficiente si transfiere una gran cantidad de datos.
Use la comprobación de errores. Prefiero un CRC de 16 bits, ya que proporciona órdenes de magnitud de protección sobre una suma de comprobación y sigue siendo simple y eficiente en algoritmos más pesados como MD5 o SHA1.
Use el mismo formato de paquete para los comandos que las respuestas.
Usa datos de 8 bits sin paridad. El bit de paridad serial no agrega ninguna protección si ya utiliza una CRC u otra verificación de integridad de datos y, en el mejor de los casos, una mala verificación de errores.
Entonces, en la forma más simple, el encabezado del paquete es el Comando o Respuesta, el tamaño del paquete, cero o más datos y el código de comprobación de errores (CRC).
Eche un vistazo a Firmata como un protocolo de ejemplo.
FTP es un ejemplo de protocolo que funciona razonablemente bien tanto de forma interactiva como con automatización. Una de las claves es que las respuestas comienzan con un código que indica si un cliente automático debería pagar o no. Del mismo modo para POP3.
Una cosa buena acerca de esos protocolos es que cuando se desarrolla / depura, se puede conducir razonablemente la comunicación desde un terminal regular o secuenciar la comunicación usando scripts de shell normales / archivos por lotes / lo que sea.
Sin embargo, una cosa que no hacen es proporcionar confiabilidad, que es proporcionada por una capa inferior de la pila de comunicaciones. Es algo que debería considerarse en la mayoría de los pahs de comunicación integrados.
Me gustan las respuestas de Bruce McGee. Después de haber trabajado con interfaces similares, puedo ofrecer muchos otros indicadores:
Al devolver tipos numéricos en un paquete de datos, por favor, intente que todo tenga el mismo formato. No tiene solo para algunos números y doble para otros. ¡Y no lo hagas arbitrario!
Proporcione ejemplos de paquetes de datos en su ICD. Es terriblemente frustrante tener que adivinar el orden de bytes o incluso el orden de bits (¿es MSByte primero o último? ¿Qué es el primero y el último?). Proporcione un diagrama que muestre los paquetes en función del tiempo (es decir, se envía 0x02 lo antes posible, luego el byte de la dirección, luego el id del mensaje, etc.).
No cambie entre formatos de datos si es posible. He trabajado en sistemas que usan ''números codificados en ASCII'' para algunos mensajes en los que debes quitar el ''3'' inicial de los bytes, luego júntalos para formar el número real. (Por lo general, la codificación ASCII se usa cuando tiene que evitar una secuencia de bytes, como 0x02, 0x04, etc. Los números codificados son 0x30, 0x32, 0x30, 0x34. Si es posible, utilice un campo de longitud para evitar esto, o en ¡al menos hazlo todo el tiempo!)
Definitivamente definitivamente documente la velocidad en baudios, la paridad, etc. Si está utilizando el documento RS-485, ¿el modo de bus (2 hilos? ¿4 hilos?) O los ajustes que aparecerán en la máquina en la que pretenda que se use esto . Da capturas de pantalla si es necesario.
Esta interfaz probablemente sea muy útil para la depuración. He trabajado con algunos sistemas que tenían funciones de depuración, como:
Un sistema donde el programador hizo una lista de ''parámetros registrados'' (variables internas). Le diría al sistema cuáles desea informar (hasta 8) y luego, cuando consulte el sistema para los parámetros registrados, los devolverá en un paquete de datos. Me gustó esto, pero dependiendo de la complejidad del sistema, puede o no ser capaz de especificarlos en tiempo de ejecución (o podría hacer algo simple y enviar al sistema una máscara que seleccionaría los que desea devolver).
Paquetes de datos que ''rompen'' el comportamiento y permiten que partes del sistema sean probadas independientemente (es decir, en un D / A poner este voltaje, en un puerto DIO estimula este byte, etc.)
¡Buena suerte!
Si debe tener su propio protocolo,
Por favor, por favor use el encuadre de paquetes.
SLIP Encuadre solo unas pocas líneas de código. Especificado en (RFC 1055)
Entonces, ahora todos los paquetes siempre se pueden ver así
<slip packet start>
message
message crc
<slip packet start>
No envíe una longitud de mensaje. Puede corromperse y los analizadores de mensajes del receptor se confunden.
Si su receptor tiene un pequeño buffer receptor y se desborda, simplemente siga leyendo hasta el límite del paquete. Ningún daño hecho.
Un montón de CRC simples de 2 bytes; el Xmodem uno es fácil. Puedes simplemente xor todos los bytes en el paquete que debes.
Si quería ser una persona realmente agradable, use PPP, DDNS y HTTP-REST para sus comandos reales. Encantador libro sobre cómo hacer esto en 16 series de procesadores PIC en C por Jeremy Bentham, TCP / IP Lean.
Luego puede usar un navegador web para hablar con él, o algo así como libcurl desde el código C. Como casi todos los lenguajes de programación tienen bibliotecas para hacer http, todos pueden hablar con su dispositivo.
Tengo algunas preferencias (y cosas malas) de escribir software para controlar medios y visualizar dispositivos usando RS232. Dependiendo de su hardware, algunos de estos pueden no aplicar:
Creo que es una buena idea hacer que su protocolo sea más amigable para la automatización. Si necesita una interfaz interactiva (línea de comando u otra), compile por separado y haga que use el protocolo de automatización. No me preocuparía demasiado hacer que sea legible para humanos, pero depende de ti.
Siempre devuelve una respuesta, incluso (especialmente) si recibes un comando no válido. Algo simple como $ 06 para ACK y $ 15 para NAK. O deletrearlo si quieres que sea un poco más legible para humanos.
Si puede establecer cualquier valor, asegúrese de que haya alguna forma de consultar ese mismo valor. Si tiene muchos valores, podría llevar un tiempo consultarlos a todos. Considere la posibilidad de tener una o algunas meta-consultas que devuelven varios valores a la vez.
Si tiene información que no se puede configurar, pero es importante (número de modelo, número de serie, versión, derechos de autor, etc.), asegúrese de que se puedan consultar en lugar de solo mostrarlos una vez que se inicie o reinicie.
Nunca responda con un error para un comando válido. Pensarías que este sería obvio ...
Hablando de obvio, documenta las configuraciones de serie que admite tu hardware. Especialmente si va a ser utilizado por alguien que no sea usted y no quiere que pasen los primeros 30 minutos tratando de averiguar si no pueden hablar con el dispositivo debido al puerto serie, las conexiones, el cable o su software. No es que sea amargo ...
Use comandos absolutos en lugar de alternar valores. Por ejemplo, tenga comandos separados para Encender y Apagar en lugar de enviar el mismo comando y encender y apagar la unidad.
Las respuestas deben incluir información sobre el comando al que responden. De esta forma, cualquier programa no necesita recordar lo último que solicitó para tratar la respuesta (ver la opción de crédito adicional a continuación).
Si su dispositivo admite un modo en espera (apagado, pero no apagado), asegúrese de que las consultas sigan funcionando mientras se encuentre en este estado.
Dependiendo de cuán paranoico sea con respecto a la integridad de los datos:
Envuelva su mensaje en un sobre. El encabezado podría incluir un carácter inicial, la lengeth del mensaje y un carácter de cierre. En caso de que recibas mensajes parciales o malformados. Quizás $ 02 para el comienzo y $ 03 para el final.
Si eres realmente paranoico sobre la integridad del mensaje, incluye una suma de comprobación. Aunque pueden ser un poco dolorosos.
Para crédito adicional:
- Si su configuración de hardware se puede cambiar manualmente, tal vez envíe este cambio al puerto serie como si el usuario lo hubiera consultado. Por ejemplo, es posible que no desee que el usuario pueda cambiar la fuente de entrada para un monitor de visualización público.
Espero que esto ayude.
Actualizar:
Olvidé algo importante. Antes de usar esto en serio y especialmente antes de dárselo a otra persona, pruébelo en algo trivial para asegurarse de que funcione de la manera que esperaba y (más importante aún) para asegurarse de que no haya dejado nada. Tomará más tiempo y esfuerzo arreglar las cosas si encuentra un problema en medio de un proyecto más grande.
Esta es una buena regla general ya sea que esté diseñando un protocolo de comando, un servicio web, un esquema de base de datos o una clase, etc.
Aquí hay un gran artículo de Eli Benderski sobre el encuadre del protocolo de serie. Sea cual sea el formato de paquete que elija, asegúrese de usar caracteres de escape. Le permite tener dichos caracteres dentro de los datos reales y facilita realmente la resincronización en caso de corrupción de paquetes.