¡Saludos, queridos!
En algún momento de su vida, ¡cada obstinada caja de bricolaje deja de extrañar al Kantian Arduino como "cosas en sí mismas"
que simplemente no pueden! : Parpadear el LED, tomar datos de los sensores y transferirlos por el cable a la PC es ciertamente divertido, pero el Santo Grial está en movilidad, en liberación de los "enlaces de cobre", en verdadera libertad entre las ondas del éter universal.
Aquí es donde se nos abre la dura realidad de los canales de comunicación inestables, los errores de transmisión y los mensajes no entregados.
Dios prohíbe reclamar originalidad en esta área: la humanidad ha usado durante mucho tiempo un montón de protocolos para todas las ocasiones.
Pero nuestro objetivo es aprender, y dado que soy un ferviente defensor del reconocimiento en combate, estudiaremos inventando nuestro propio protocolo "bicicleta".
Hoy propongo desarrollar un protocolo que garantice la entrega garantizada, la integridad y la secuencia de mensajes entre dos suscriptores (punto a punto, punto a punto), sepa cómo y aplica el algoritmo de
Nagle y la
canalización del protocolo , lo que sea que eso signifique. Al mismo tiempo, debería tener una
sobrecarga mínima y exprimirse incluso en el estrecho Arduino UNO.

Pregunto a todos los interesados a bordo, cerramos las escotillas, abrimos las piedras del rey, llenamos los tanques de lastre. ¡Tenemos una excursión al pasado, destino: año 1974!
Para los impacientes (¡yo mismo lo soy!)Aquí está el repositorio de github donde están las implementaciones:
Según la vieja tradición, al menos dos expertos reconocidos en este campo están involucrados en la descripción de algoritmos y protocolos criptográficos, si alguien más no los conoce, familiarícese:
Y
Primero describimos una tarea simple
Alice y Bob están sentados en trincheras adyacentes y no pueden levantar la cabeza para verse. Solo pueden hablar en voz, al lado de ellos silban las balas y los proyectiles explotan, ahogando sus gritos, y además, cuando uno de ellos habla, tienes que gritar para que no escuches nada.
La situación se complica por el hecho de que están siendo escuchados por los enemigos, y tienes que usar un lenguaje de código, por alguna razón que consiste en largas secuencias de números.
Dado que tanto Alice como Bob son personas, periódicamente tienen que salir a comer o ir al baño, ¡y están tan impacientes que pueden ser impacientes en el momento más inoportuno!
¿Cómo y por qué establecer una conexión?
¿Cómo podemos organizar una transferencia de datos confiable en una situación tan deprimente, cuando parece que todo está condenado al fracaso?
La primera solución que puede venir a la mente es usar frases de código de
palabras de detención para iniciar y finalizar la transferencia.
Bueno, digamos que si Alice quiere enviar un mensaje, entonces necesita gritar "¡Comience la transmisión!" Y espere hasta que Bob responda "¡Comience la recepción!".
Si Alice no espera la respuesta de Bob, simplemente repite su solicitud para comenzar la transferencia. Naturalmente, no debe hacer esto con demasiada frecuencia, de lo contrario, como sabemos, simplemente no escuchará la respuesta de Bob.
Genial Pero, ¿qué sucede si Alicia en respuesta escucha desde la siguiente trinchera, "Comenzar transmisión"?
Resulta que Bob también decidió transferir información importante en este momento. Alice tiene un carácter suave, y podría haber pensado: "Está bien, esperaré, mi mensaje es, en principio, no urgente, deja que Bob lo transmita primero". Pensando en esto, ella responde: "¡Comienza la recepción!".
Como
en tiempos de guerra el valor del seno puede alcanzar cuatro, la velocidad del sonido es finita, y lleva un tiempo comprender lo que Alice y Bob han escuchado, e incluso Bob, como un caballero, puede decidir ceder ante la dama, se encoge de hombros y grita: "¡Estoy comenzando la recepción!" ...
Para ilustrar la indignación, utilizaremos gráficos de tiempo. El tiempo se les acaba.
El caso cuando Alice y Bob no estuvieron de acuerdo a tiempo:

El caso cuando se perdió el mensaje:

Este es un fiasco. Todo se vuelve demasiado confuso y se agrava por el hecho de que el destinatario puede escuchar o no escuchar cualquiera de las frases, y en cada caso el interlocutor no sabe si su mensaje fue escuchado por el destinatario.
Ahora tanto Alice como Bob esperan una bienvenida. Sería lógico darse cuenta de que se ha producido un conflicto y que alguien debe reanudar la transmisión. Pero, ¿qué pasa si todo vuelve a suceder de una manera nueva? Y aquí estamos nuevamente donde comenzamos.
Si cree que la situación es extremadamente rara, recuerde la última vez que habló con alguien por voz, cuando su suscriptor o usted (o ambos) tienen una conexión lenta a Internet. "Hola hola hola, desapareces". "No puedes escuchar hola hola".
Mientras tanto, en las trincheras, la situación se está calentando, los comandantes exigen la transmisión de informes.
Es hora
de recurrir a las fuentes principales: para estudiar a Marx, Engels regresará hace más de 40 años y verá cómo
los ingenieros de
DEC resolvieron tales problemas al diseñar el protocolo
DDCMP .
Según los desarrolladores de DDCMP, Alice y Bob deben rechazar las emociones y convertirse en
máquinas de estados finitos .
Esto significa que a partir de ahora, nuestros Alice y Bob tendrán solo unos pocos estados fijos, las transiciones entre estos estados pueden ocurrir estrictamente de acuerdo con ciertas reglas cuando ocurren ciertos eventos.
Primero, simplemente enumeramos los estados:
- Detenido
- COMIENZO INICIAL
- INICIO RECONOCIDO
- CORRIENDO
Como puede ver, solo hay cuatro de ellos. Y ahora, pase lo que pase, cada uno de los suscriptores al menos sabe con certeza que su visado solo se encuentra en uno de estos estados. De hecho, mirando un poco más adelante, diré que casi siempre un suscriptor sabrá en qué estado se encuentra el segundo suscriptor,
pero esto no es exacto .
Consideremos los estados por separado, en detalle
HALTED es el estado más simple, nadie va a ninguna parte, todos permanecen en sus lugares, nada se transmite y no se recibe, se ignora cualquier estímulo externo. Todos menos uno: la voluntad de las autoridades superiores. En el protocolo DDCMP original, la transición del estado
HALTED solo puede estar en el estado
INICIAL INICIAL a solicitud del usuario: Alice o Bob reciben una orden para establecer una conexión.
¿Qué sucede cuando Alice o Bob reciben tal orden?
Inmediatamente se advierten a sí mismos que el estado ha cambiado de
HALTED a
INICIAL START , esta transición, como cualquier otra, implica una secuencia de acciones estrictamente definida. En este caso, debe gritar "¡HAZLO!" Y poner el reloj en el reloj. Eso es todo.
Entonces, Alice gritó lo que se requería de ella y presionó un botón en el cronómetro. Ahora, para comprender qué esperar de Bob, descubriremos qué puede pasarle a Alice cuando está en el estado
INICIAL .
- Desde el momento en que Alice notó que el tiempo había pasado, digamos 10 segundos y no escuchó ninguna reacción de Bob (nota, no estoy diciendo que Bob no le gritó nada en respuesta, esto no se sabe, pero solo Alice no sabe nada escuchado durante este tiempo, Alice es una mujer sabia y racional y se basa únicamente en hechos). Llamamos a este evento un tiempo de espera: se ha excedido el intervalo de espera. En este caso, el protocolo nos dice que repitamos: grite "¡HAZLO UNA VEZ!" Y una y otra vez. Todavía no es grueso.
- Si Alice escuchó que Bob gritó lo mismo: “¡HAGA UNA VEZ!”, Entonces Alice ingresa de manera
no selectiva al estado
INICIO RECONOCIDO , sobre el cual debe gritar inmediatamente “¡HAGA DOS!” Y cronometra el reloj nuevamente.
- Una vez más, si Alice escuchó de Bob "DO DOO!", Entonces ella inmediatamente entra en el estado de
FUNCIONAMIENTO (!), Grita "¡NOOOOOL ACEPTADO!". Si su cronómetro se ha iniciado, lo apaga con precaución.
Es muy importante no hacer movimientos innecesarios que no estén previstos por el estado actual. Cualquier cosa que llore Bob, no importa cuán maldecida o suplicante, Alice solo reacciona según lo acordado.
Es conveniente presentar tales cosas en forma de tabla. Entonces, comencemos con los
estados HALTED e
INICIAL START ya descritos, y luego
repondremos más la tabla.
Conscientemente omito algunos puntos de la descripción original de DDCMP: no los necesitamos, queremos no solo repetir DDCMP, sino construir sobre la base
el mismo, solo otro protocolo nuevo.
Pero volvamos a la descripción de estados y transiciones. El siguiente estado es
INICIO RECONOCIDO .
Al estar en este estado, todo lo que puede preocupar a Alice o Bob es:
- como antes, la expiración del tiempo de espera, en este caso debe permanecer en el mismo estado, gritar "¡HAGA DOS!" y vuelva a iniciar el temporizador
- el "DO DOO!" escuchado se traduce al estado de
FUNCIONAMIENTO , mientras grita "NOOOOL ACEPTADO!" Y detiene el temporizador;
- el oído "¡HAZLO!" se va en el mismo estado, debes gritar "¡HAZ DOS!" e iniciar el temporizador;
- escuché "NOOOL ACEPTADO!" - transición al estado EN
EJECUCIÓN , detenga el temporizador.
Ponemos todo lo anterior en una mesa.
Con un apretón de manos, casi todo está listo: queda por considerar solo un estado
EN EJECUCIÓN , porque uno de los suscriptores ya puede entrar, y el segundo, correr urgentemente al baño, y cuando regrese, olvida todo e intenta establecer una nueva conexión.
Desde el punto de vista del procedimiento de protocolo de enlace (todavía no tratamos con la transferencia de datos, para lo cual todo se inició, esta es una historia separada) en el estado
EN EJECUCIÓN , estamos interesados en dos eventos:
- si nos gritan "¡HAZLO UNA VEZ!" - todo es muy malo, es una desincronización completa, todo debe comenzar de nuevo. El protocolo original le
indica que simplemente ingrese al estado
HALTED . Pero esto no nos ayudará de ninguna manera: si por alguna razón esto sucedió en un Arduino autónomo, que transmite algunos datos de algunos sensores, entonces para nosotros esto es un completo fracaso. Como sabemos, desde
HALTED puede ir al
INICIO INICIAL solo por orden de las autoridades.
Por lo tanto, estamos modificando el protocolo aquí: la recepción en el estado
HALTED del
comando "DO ONCE!" Debería funcionar como una orden de las autoridades, es decir
cambie al estado
INICIO INICIAL , grite "¡HAZLO UNA VEZ!", inicie el temporizador. Además, en algunos casos es conveniente dar una orden para establecer comunicación inmediatamente después de suministrarse energía.
Por lo tanto, ahora, en el caso más inconveniente, simplemente restableceremos la conexión.
- el segundo evento al que es necesario reaccionar en el estado
EN EJECUCIÓN - si escuchamos "DO DOO!" De una trinchera vecina. Esto ya es más interesante. En este caso, debe gritar "ER ACEPTADO!" Donde, por ER se entiende el número de mensajes recibidos con éxito en la sesión de comunicación actual. Este es un nuevo concepto. A continuación consideraremos todo con más detalle, pero por el momento traeremos todo lo que hemos aprendido al momento actual en una tabla:
Ahora, si Alice y Bob siguen estrictamente el protocolo, simplemente no tienen ninguna opción
para meterse en algo
incomprensible , excepto cómo establecer una conexión, cambiar conjuntamente al estado
EN EJECUCIÓN o, en un mal caso, tratar de establecerlo antes de que se
haga clic en la victoria.
Un lector agresivo puede intentar clasificar todas las opciones y llegar a la conclusión de que la serie de estados y transiciones resulta ser cerrada y estrictamente determinada. Nosotros (con la ayuda de las mentes de los ingenieros de DEC) ahora hemos vinculado a Alice y Bob con un conjunto de reglas que simplemente siguiendo las cuales establecerán una conexión, si en las condiciones actuales esto es generalmente posible en principio.
¿Cómo transferir datos ahora?
Bien, ese fue un buen entrenamiento. Período Candy-bouquet en la relación de dos nodos de red. Recuerde que comenzamos un negocio: ¡necesitamos transferir datos con entrega garantizada y prioridad! Con recuperación ante desastres. En la medida en que los recursos de hardware lo permitan (después de todo, ¡tanto Alice como Bob pueden probar ser controladores débiles de 8 bits con 2 kilobytes de RAM!).
Los ingenieros de DEC nos enseñan que los mensajes que necesitamos numerar, debemos contar cuánto enviamos, cuántos recibimos y cuántos de los mensajes que enviamos llegaron al destinatario.
¡Es hora de una digresión!Admítelo Cuando vi los nombres de las variables en la descripción del protocolo DDCMP, decidí que no fue un accidente: a los estadounidenses les encanta atraer hermosas abreviaturas de sus oídos.
Para nuestra conveniencia, hay incluso varios recursos donde los interesados pueden tocar lo bello.
Mi favorito es este:
sitio de acrónimos astronómicos tontos o demasiado forzados (o DOOFAAS)¡Cuánto valen estas fabricaciones!
Aquí hay un ejemplo:
WASP - Espectrómetro analógico de banda ancha (¡Pero no es lo que pensabas!)
SAURON - Unidad de área espectroscópica para la investigación de nebulosas ópticas
CISCO - Espectrógrafo infrarrojo refrigerado y cámara para OHS (¡Eso es lo que significa!)
Y aquí, solo dispara:
SQUIRT (¡oh sí, artículo 18+!) - Satettile QUick Research Testbed
MIERDA (¡Ni más ni menos!) - Telescopio interferométrico súper enorme, con la inscripción "búscate tú mismo", al que se adjunta el enlace al resumen al artículo del mismo nombre.
Por lo tanto, las variables que indican el número de paquetes recibidos, enviados y entregados en el nodo en la descripción original del protocolo se denominan
ARN .
Ah, ¿por qué no nombraron el protocolo de esa manera: ARN! Una especie de red de ARN. Los protocolos DECnet tenían todas las posibilidades de convertirse en protocolos de Internet si la historia hubiera resultado diferente.
Pero volviendo a nuestras trincheras
El estándar de protocolo original define que todos los contadores son de 8 bits e incrementan el módulo 256. Esto significa que puede haber un máximo de 256 mensajes enviados para los cuales aún no se ha recibido la confirmación.
Y si no se recibe la confirmación, es posible que necesiten retransmitirse, y si es necesario, deben almacenarse hasta la confirmación. Después de todo, ¡tenemos entrega garantizada!
Los parámetros físicos de nuestra Alice y Bob nos dictan diferentes condiciones. En Arduino de 8 bits, esta cantidad de datos simplemente no se puede almacenar y tenemos que comprometerla. Y no estoy hablando del hecho de que en el estándar la longitud de los paquetes (mensajes) en bytes está limitada a un número de 16 bits, es decir. ¡64 kilobytes es un lujo inadmisible!
Entonces, la conexión está establecida. Que sigue
En el momento en que Alice o Bob
ingresan al estado
EN EJECUCIÓN , los contadores se reinician.
Como ya mencioné, el protocolo original involucra la numeración de mensajes en el módulo 256, pero tenemos que reducir este número para adaptarlo a la pequeña cantidad de memoria en cosas similares a Arduino.
Para poder limitar de inmediato todos los incrementos de contadores, introduciremos una cierta UMCP_PACKETS_NUMBER constante, y ahora todos los incrementos ocurrirán en este módulo.
Si toma UMCP_PACKETS_NUMBER = 8, y el tamaño máximo del paquete es UMCP_PACKET_DATA_SIZE: las porciones de los datos transmitidos en un momento están limitadas a 64 bytes, entonces todo encajará en el Arduino UNO y permanecerá un poco para las necesidades del usuario.
Es importante recordar que ambos parámetros deben ser iguales para ambas partes.
Obviamente, ahora, si Alice y Bob han establecido con éxito una conexión, y uno de ellos necesita transferir datos, entonces los datos primero deben dividirse en porciones que no excedan los 64 bytes de tamaño, y en segundo lugar, cada paquete también debe contener un estado dos contadores de remitente: el número de mensajes recibidos y enviados (R y N).
Vea lo fácil que es ahora organizar el llamado ¡y qué fácil es manejar situaciones de error!
Si Alice envía 3 paquetes seguidos justo después de establecer la conexión, entonces todos ellos tendrán el contador R puesto a 0 (todavía no ha recibido ningún paquete), y el contador N aumentará en uno con cada paquete nuevo.
Si Bob los acepta con éxito, entonces, para confirmar la recepción de los tres paquetes, será suficiente para que envíe una confirmación solo para el último, de hecho, si simplemente devuelve el estado de sus contadores R = 3 y N = 0, entonces Alice comprenderá de inmediato que todos se enviaron sus mensajes llegaron al destinatario.
Fue un caso ideal cuando no se produjo fuerza mayor. Veamos ahora qué podría salir mal y cómo solucionarlo.
Si Bob por alguna razón omite el primer paquete y acepta uno de los siguientes, entonces inmediatamente llama la atención sobre el hecho de que el contador N en él (el número de paquetes transmitidos por Alice) claramente excede el contador R del lado de Bob y Bob se da cuenta fácilmente de que perdió el primer paquete . En este caso, solo necesita jugar al Capitán Evidence más plano y decirle a Alice el estado de su contador de paquetes recibidos (R = 0). Al mismo tiempo, Alice entiende que ella es N = 3, y Bob tiene R = 0, es decir, es necesario transferir paquetes de una nueva manera, comenzando desde el primero.
Si observa este esquema detenidamente, puede ver que cualquier transmisión del estado de sus contadores por parte de cualquier suscriptor le informa inmediatamente sobre el resultado de la transmisión de paquetes de datos, y la diferencia entre el contador transmitido por un lado y recibido por el otro indica cuántos paquetes se perdieron y de qué número comenzó.
Es decir, en el peor de los casos, hay una retransmisión completa de la transmisión, en el caso promedio, el contador A en el lado del transmisor aumenta al valor del contador R en el lado receptor y "envía" los paquetes perdidos.Es fácil entender que de esta manera se mantiene la continuidad del incremento de los contadores, lo que significa que la transmisión de mensajes (paquetes) está garantizada.Además de las variables de ARN, cada suscriptor tiene dos banderas SACK y SPEP. Si el primero está instalado, debe enviar una confirmación (Enviar confirmación), si es el segundo, debe enviar una solicitud de confirmación (Enviar REPly a un mensaje)., DDCMP — SNAK (Send Negative AcKnowledgement). - . , , , — .
, .
- . - . Y es verdad .
.
, — , . , , L, (, — R).
Ahora mira de cerca, recorre todo el circuito en la cabeza. Nos damos cuenta de lo que falta aquí.En la descripción original de DDCMP, de la cual nos hemos alejado bastante, esto se llama la bandera SELECCIONAR - un nodo (Alice o Bob) puede o no ser "elegido".Lo que nos confundió fue que ningún mecanismo estaba autorizado para permitir o prohibir la transferencia.Bueno, aquí está: esta es la bandera SELECCIONAR. Se aplica de manera muy simple: si se establece la bandera, entonces es posible transmitir, si no, es imposible.Todos los mensajes de control como ACK y REP deben contener este indicador. El último paquete en la cola también debe contener esta bandera. Si un nodo "cose" una bandera en un paquete, "la regala" y, en consecuencia, ya no está instalada. El nodo que detecta este indicador en el paquete, por el contrario, debe instalarlo por sí mismo. Esto es similar a pasar un bastón o jugar un picadillo (¿recuerdas eso?).Lo más importante al trabajar con este indicador es que uno de los nodos debe tener este indicador por defecto, y el otro no. Ese es otro temporizador muy importante: el temporizador de retorno de la bandera SELECT.Ahora tenemos un conjunto completo de reglas para establecer una conexión y transmitir datos a través de ella.No nos referimos solo a la implementación concreta de este conjunto de reglas.Bueno, arreglalo!Formación y formato de paquete
Message Framing — .
, .
1. , R N . Arduino 8 . , , 4-.
:
= (RL & 0x0F) | (NL << 4);
Y leeremos el estado de los contadores así:
NR = (c >> 4) & 0x0F; RR = c & 0x0F;
c - byte correspondiente del mensaje
2. También recordamos que cada mensaje debe contener el estado del indicador SELECT. Y los diferentes tipos de mensajes en sí serán:
Es decir, solo 6 tipos diferentes de mensajes. Todos los mensajes, excepto DTA, "liberan" el indicador SELECT; necesitan una respuesta inmediata del suscriptor remoto, y sin el indicador no podrá transmitirlo. El mensaje de DTA no devuelve una bandera para hacer posible la canalización.
En general, tenemos suficientes 3 bits para el tipo de mensaje, pero para no alterarlos, asignamos un byte completo al tipo; en caso de revisión, tendremos cierta libertad de acción.
Si el mensaje contiene datos, entonces necesitamos transferir su cantidad y suma de verificación. Como el tamaño máximo del paquete es de 64 bytes, también tomaremos un byte para la suma de comprobación y la longitud; de repente, tendrá que aumentar el tamaño del paquete.
3. También necesitamos alguna firma del comienzo del mensaje y una suma de verificación separada para el encabezado.
Con todo esto en mente, el encabezado (también conocido como mensajes de control) se ve así:
Y el bloque de datos es así:
Eso es todo Esta es una descripción completa del protocolo que obtuvimos de DDCMP.
Ahora puede pasar por la implementación.
¿Cómo está organizado y cómo usarlo?
Primero, un poco sobre la estructura del repositorio.
Como mencioné al principio, el código del proyecto se encuentra en el github:
uMCPInoPara ver cómo funciona todo, puede ejecutar una
aplicación de prueba en una PC.
En el archivo, ejecute uMCPIno_Test.exe, seleccione el puerto COM deseado e intente cómo funciona.
Puede verificar un par de puertos COM virtuales (generalmente hago esto).
¿Por qué puede ejecutar dos copias de la aplicación? Simplemente no olvide activar “SELECCIONADO POR DEFECTO” en una copia, esta será Master, y en la otra, desactívela. Por cierto, si está interesado, puede ver qué sucede si no cumple con esta regla =)
La opción EXTRAS le permite ver todos los movimientos de pensamientos dentro del cerebro del protocolo. Se mostrarán todos los cambios en el estado de las banderas SELECT, eventos de temporizadores, cambios en el estado del nodo y también los valores de las variables R y N en los mensajes transmitidos y recibidos.
Conecto mi Arduino UNO a mi computadora portátil a través de un convertidor UART <-> USB. Los conectores de clavija le permiten simular un salto de línea en cualquier momento:

Si ahora ejecuta la aplicación en la computadora portátil, luego de presionar el botón "CONECTAR", la arduina establecerá una conexión:

Y así es como el sistema reacciona a un intento de enviar a través de una línea "desgarrada":

Para incrustar uMCPIno en su aplicación para PC:
- El repositorio tiene una biblioteca uMCPIno. Conéctelo a las referencias de su proyecto.
- Contiene la clase uMCPInoPort. Declaramos su instancia:
uMCPInoPort port; port = new uMCPInoPort("COM1", UCNLDrivers.BaudRate.baudRate9600, true, 8100, 2000, 64, 8);
Parámetros en orden: nombre del puerto, luego velocidad del puerto, estado SELECT predeterminado, intervalo para SELECT, intervalo de tiempo de espera, tamaño de paquete y la cantidad máxima de mensajes no reconocidos.
- Suscríbase a eventos:
cuando el indicador SELECT - port.Select cambia:
OnSelectChangedEventHandler
cuando el estado cambia - puerto. Estado:
OnStateChangedEventHandler
El host remoto confirma la recepción del código:
OnDataBlockAcknowledgedEventHandler
cuando llega el paquete de datos:
OnDataBlockReceivedEventHandler
- Antes del trabajo, abra el puerto.
port.Open();
- Para enviar datos, llamamos al método:
port.Send(byte[] data);
- Al finalizar, cierre el puerto:
port.Close();
¡Solo envíe dos bytes!
Ahora pasemos a la implementación de Arduino. Hay dos ejemplos en la carpeta
github.com/AlekUnderwater/uMCPIno/tree/master/ArduinoEl primero es solo un convertidor desde y hacia uMCP. El primer Serial sirve para comunicarse con el Host, y Serial1 (si está en su placa) o SoftwareSerial en los pines 2 y 3, para comunicarse con otro nodo uMCPIno. Puede conectar Bluetooth o un módulo de radio aquí.
El segundo es una plantilla de proyecto con soporte para el protocolo uMCPIno
Ambos proyectos tienen configuraciones donde puedes y debes escalar. Aquí están:
El estado predeterminado del indicador SELECT. Si se establece en (verdadero), incluso si el nodo remoto no devuelve el indicador, el temporizador lo establecerá en verdadero.
#define CFG_SELECT_DEFAULT_STATE (false)
Para establecer el período de este temporizador, existe la siguiente configuración: intervalo para devolver el indicador SELECT en milisegundos
#define CFG_SELECT_DEFAULT_INTERVAL_MS (4000)
El intervalo para esperar una respuesta en milisegundos, es mejor dejarlo un poco menos que el intervalo para devolver el indicador SELECT.
#define CFG_TIMEOUT_INTERVAL_MS (3000)
La velocidad de transmisión real de la línea. Este parámetro es necesario para determinar cuándo finalizará la transferencia.
#define CFG_LINE_BAUDRATE_BPS (9600)
Intervalo de acumulación de datos para el algoritmo de Nagle. Insolentemente tómalo igual a 100 milisegundos. Durante este tiempo, estamos esperando un conjunto de paquetes, si no está escrito, lo enviamos tal cual. La tarea del algoritmo de Nagle es librar a la red de un montón de paquetes pequeños de uno a varios bytes de tamaño.
#define CFG_NAGLE_DELAY_MS (100)
Esta configuración establece las velocidades del puerto para la comunicación con el sistema de control (Host) y la línea. No confunda la velocidad del puerto con una línea con una velocidad de transferencia física.
#define CFG_HOST_CONNECTION_BAUDRATE_BPS (9600)
Si esta configuración está habilitada, cuando se suministre energía al controlador, el protocolo mismo se ordenará a sí mismo comenzar a establecer una conexión.
#define CFG_IS_AUTOSTART_ON_POWERON (true)
Este es el tamaño en bytes del búfer para los paquetes de datos entrantes.
#define CFG_IL_RING_SIZE (255)
A continuación, veamos cómo se ve el bucle de boceto principal:
void loop() { uMCP_ITimers_Process(); DC_Input_Process(); DC_Output_Process();
Ahora veamos cómo funciona el protocolo. La lógica principal está contenida en la función uMCP_Protocol_Perform (); Aquí está su código:
void uMCP_Protocol_Perform() { if (state == uMCP_STATE_RUNNING) {
Un analizador de paquetes que vive en una función.
On_NewByte_From_Line
también organizado por el principio de una máquina de estados finitos y funciona "byte por byte". Esto se hace para ahorrar memoria.
El resto de la implementación no es de particular interés. Analizaremos mejor cómo interactúa el usuario con el protocolo. En este ejemplo, hay cuatro "puntos de contacto".
La primera es la función de enviar datos en la línea uMCPIno:
bool uMCPIno_SendData(byte* dataToSend, byte dataSize);
Aquí todo es simple: tiene un búfer de datos dataToSend, su tamaño es dataSize. La función devuelve verdadero si el envío es posible (hay espacio para agregar datos) y falso de lo contrario.
Para no conducir en vano, puede verificar de inmediato la disponibilidad de espacio suficiente utilizando la función:
bool uMCP_IsCanSend(byte dataSize);
Para analizar los paquetes de datos entrantes, debe agregar su código al cuerpo de la función
void USER_uMCPIno_DataPacketReceived();
Los datos entrantes se escriben en el búfer de anillo il_ring. Leer desde él se puede organizar en bytes de esta manera:
while (il_Cnt > 0) { c = il_ring[il_rPos]; il_rPos = (il_rPos + 1) % CFG_IL_RING_SIZE; il_Cnt--;
Para placeres sofisticados hay una función
void USER_uMCP_OnTxBufferEmptry();
Que se llama cuando todos los datos se envían con éxito. También es posible y necesario poner algún tipo de código en él.
¿Por qué es todo esto y dónde?
Trate principalmente con Solo por diversión. Además, necesitaba un protocolo simple y, lo más importante, "ligero" para enviar datos a través de nuestros módems de sonda
uWAVE . Dado que transmiten datos a través del agua a una velocidad de solo 80 bps, y con su rango de comunicación máximo de 1000 metros y la velocidad del sonido en el agua de aproximadamente 1500 m / s, la transmisión está asociada con retrasos notables, y solo hay un canal de sonda (si no la mayoría) !) de los más ruidosos, lentos e inestables.
En gran parte debido a esto, tuve que abandonar el mecanismo de reconocimiento negativo (NAK), si es posible no transmitir, en agua es mejor no transmitir al 100%.
En realidad, el protocolo fue útil al transmitir datos a través de un canal de radio utilizando módulos
DORJI y el
NS-012 conocido por los arduinoes.
Que sigue
Si hay tiempo, planeo agregar la posibilidad de direccionamiento (que, por cierto, estaba en DDCMP). Dado que la tarea principal de este protocolo ahora es proporcionar comodidad para todo tipo de pruebas de nuestros módems de sonda y otras redes de sensores, entonces hay (¡literalmente!) Trampas allí. Solo puedo decir que el problema no se puede resolver simplemente agregando los campos "Remitente" y "Destino".
Quizás llegue a
Enrutamiento geográfico y todo ese jazz.
PS
Tradicionalmente, estaré muy agradecido por las críticas constructivas, los deseos y las sugerencias. Siempre es importante comprender si está haciendo algo útil para las personas o está perdiendo el tiempo.
Quizás, al tratar de evitar la transición de este largo hilo a la novela "Guerra y paz", me he perdido algunos detalles. No dude en preguntar.
PPS
Muchas gracias a la vergüenza de mi analfabetismo, señalando errores (gramaticales y lógicos):
El proyecto fue originalmente de código abierto, pero ahora el artículo también es de código abierto.