En mi comunicación UART, necesito saber el byte de inicio y el byte de detención del mensaje enviado. El byte de inicio es fácil, pero el byte de parada, no tanto. He implementado dos bytes de detención al final de mi mensaje, es decir, \ n y \ r (10 y 13 decimales). UART solo funciona en valores de bytes 0-255, entonces, ¿qué tan seguro es esto? Puedo imaginar, aunque con baja probabilidad, que mi mensaje podría contener los valores "10 y 13" uno tras otro cuando no son los bytes de detención.
¿Hay una mejor manera de implementar esto?
"\x0D\x0A"
.\r\n\r\n
cuál contiene la\n\r
secuencia en el medio ...Respuestas:
Hay diferentes formas de prevenir esto:
Si sus mensajes tienen un máximo de 256 bytes, envíe:
Entonces sabes después de recibir 6 bytes de datos que es el final; no tienes que enviar un 10 13 después. Y puede enviar 10 13 dentro de un mensaje. Si sus mensajes pueden ser más largos, puede usar 2 bytes para el tamaño de los datos.
Actualización 1: otra forma de definir paquetes
Otra alternativa es enviar comandos que tienen una longitud específica y pueden tener muchas variaciones, p. Ej.
Actualización 2: Mala conexión / pérdida de bytes
Todo lo anterior solo funciona cuando la línea UART está enviando bytes correctamente. Si desea utilizar formas de envío más confiables, también hay muchas posibilidades. A continuación hay algunos:
Tenga en cuenta que todo el mecanismo anterior puede ser simple o tan complicado como desee (o necesite). En caso de reenviar mensajes, también se necesita un mecanismo para identificar mensajes (por ejemplo, agregar un número de secuencia al paquete).
fuente
Si envía, envíe datos arbitrarios -> probablemente no sea lo suficientemente seguro.
Una solución común es usar escape:
Definamos que los caracteres 0x02 (STX - inicio de trama) y 0x03 (ETX - final de trama) deben ser únicos dentro del flujo de datos transmitido. De esta manera, el inicio y el final de un mensaje se pueden detectar de forma segura.
Si uno de estos caracteres debe enviarse dentro del marco del mensaje, se reemplaza con el prefijo de un carácter de escape (ESC = 0x1b) y agregando 0x20 al carácter original.
Carácter original reemplazado por
El receptor invierte este proceso: cada vez que recibe un carácter de escape, este carácter se descarta y el siguiente carácter se resta 0x20.
Esto solo agrega un poco de sobrecarga de procesamiento, pero es 100% confiable (suponiendo que no ocurran errores de transmisión, lo que podría / debería verificar implementando adicionalmente un mecanismo de suma de verificación).
fuente
'\x10'
DLE (Data Link Escape). Algunas de las páginas de Wikipedia sugieren que DLE a menudo se usaba de manera opuesta: para decir que el siguiente byte era un carácter de control en lugar de un byte de datos. En mi experiencia, ese es generalmente el significado opuesto para un escape.Ya sabes, ASCII ya tiene bytes para estas funciones.
También tiene códigos para varios usos dentro de la carga útil.
Su protocolo debe especificar la granularidad más fina de ACK (0x06) y NAK (0x15), de modo que los datos negativos reconocidos puedan retransmitirse. Hasta esta granularidad más fina, es aconsejable tener un campo de longitud inmediatamente después de cualquier indicador de inicio (sin escape) y (como se explica en otras respuestas) es aconsejable seguir cualquier indicador de parada (sin escape) con un CRC.
fuente
UART no es a prueba de fallas por su propia naturaleza: aquí estamos hablando de la tecnología de la década de 1960.
La raíz del problema es que UART solo se sincroniza una vez cada 10 bits, lo que permite que pase un montón de galimatías entre esos períodos de sincronización. A diferencia de, por ejemplo, CAN, que muestrea cada bit individual varias veces.
Cualquier error de doble bit que ocurra dentro de los datos dañará una trama UART y pasará sin ser detectado. Los errores de bit en los bits de inicio / parada pueden o no detectarse en forma de errores de desbordamiento.
Por lo tanto, no importa si usa paquetes o datos sin procesar, siempre existe la probabilidad de que los cambios de bits causados por EMI den como resultado datos inesperados.
Existen numerosas formas de "charlatanería tradicional UART" para mejorar la situación muy ligeramente. Puede agregar bytes de sincronización, bits de sincronización, paridad, bits de doble parada. Podría agregar sumas de verificación que cuenten la suma de todos los bytes (y luego invertirla, porque por qué no) o podría contar la cantidad de binarios como una suma de verificación. Todo esto es ampliamente utilizado, muy poco científico y con una alta probabilidad de errores faltantes. Pero esto fue lo que hizo la gente desde 1960 hasta 1990 y muchas cosas extrañas como estas viven en la actualidad.
La forma más profesional de lidiar con una transmisión segura a través de UART es tener una suma de verificación CRC de 16 bits al final del paquete. Todo lo demás no es muy seguro y tiene una alta probabilidad de faltar errores.
Luego, en el nivel de hardware, puede usar el diferencial RS-422 / RS-485 para mejorar drásticamente la robustez de la transmisión. Esto es imprescindible para una transmisión segura a largas distancias. El nivel TTL UART solo debe usarse para la comunicación a bordo. RS-232 no debe usarse para ningún otro propósito, sino compatibilidad con versiones anteriores.
En general, cuanto más cerca del hardware esté su mecanismo de detección de errores, más efectivo será. En términos de efectividad, las señales diferenciales son las que más agregan, seguidas de la verificación de errores de encuadre / desbordamiento, etc. CRC16 agrega algo, y luego la "charlatanería tradicional UART" agrega un poco.
fuente
Se debe considerar una situación en la que una porción de datos es igual a la secuencia de terminación al diseñar el formato de un paquete de datos en serie. Otra cosa a considerar es que cualquier personaje puede corromperse o perderse durante la transmisión. Un carácter de inicio, un carácter de detención, un byte de carga útil de datos, una suma de verificación o un byte CRC, un byte de corrección de error directo no son inmunes a la corrupción. El mecanismo de trama debe poder detectar cuándo un paquete tiene datos corruptos.
Hay varias formas de abordar todo esto.
Estoy asumiendo que los paquetes están enmarcados solo con los bytes seriales. Las líneas de apretón de manos no se usan para enmarcar. Los retrasos de tiempo no se usan para enmarcar.
Enviar longitud del paquete
Envíe la longitud del paquete al principio, en lugar de [o además de] el carácter final al final.
Pros: la carga útil se envía en un formato binario eficiente.
Contras: necesita saber la longitud del paquete al comienzo de la transmisión.
Escapar de los personajes especiales
Escapar de los caracteres especiales al enviar los datos de carga. Esto ya se explicó en una respuesta anterior .
Pros: el remitente no necesita saber la longitud del paquete al comienzo de la transmisión.
Contras: Ligeramente menos eficiente, dependiendo de cuántos bytes de carga útil se deban escapar.
Datos de carga útil codificados de modo que no puedan contener caracteres de inicio y detención
La carga útil del paquete está codificada de modo que no puede contener los caracteres de inicio o detención. Por lo general, esto se hace enviando números como su representación ASCII o Hex-ASCII.
Pros: legible para humanos con programas terminales comunes. No hay necesidad de código para manejar el escape. No es necesario saber la longitud del paquete al comienzo de la transmisión.
Contras: menor eficiencia. Para un byte de datos de carga útil, se envían varios bytes.
fuente