Demostración de conexión compartida de coreMQTT - FreeRTOS

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

Demostración de conexión compartida de coreMQTT

importante

Esta es una versión archivada de la Guía del usuario de FreeRTOS para su uso con la versión 202012.00 de FreeRTOS. Para obtener la última versión de este documento, consulte la Guía del usuario de FreeRTOS.

Introducción

El proyecto de demostración de conexión compartida de CoreMQTT muestra cómo utilizar una aplicación multiproceso para establecer una conexión con el broker AWS MQTT mediante TLS con autenticación mutua entre el cliente y el servidor. Esta demostración utiliza una implementación de interfaz de transporte basada en mbedTLS para establecer una conexión TLS autenticada por el servidor y el cliente, y muestra el flujo de trabajo de suscripción-publicación de MQTT en el nivel de QoS 1. La demostración se suscribe a un filtro de temas, publica los temas que coinciden con el filtro y espera a que el servidor reciba esos mensajes en el nivel de QoS 1. Este ciclo de publicación en el agente y recepción del mismo mensaje por parte del agente se repite indefinidamente. Los mensajes de esta demostración se envían en QoS 1, lo que garantiza al menos una entrega de acuerdo con la especificación MQTT.

nota

Para configurar y ejecutar las demostraciones de FreeRTOS, siga los pasos que se indican en Introducción a FreeRTOS.

Esta demostración utiliza una cola segura para subprocesos para almacenar los comandos que interactúan con la API MQTT. En esta demostración, hay cuatro tareas que hay que tener en cuenta.

  • Una tarea de comandos (principal) toma los comandos de la cola de comandos y los procesa. Las demás tareas colocan los comandos en esta cola para procesarlos. Esta tarea entra en un bucle durante el cual procesa los comandos. Si se recibe un comando de terminación, esta tarea saldrá del bucle.

  • Una tarea de publicador sincrónica crea una serie de operaciones de publicación y las envía a la cola de comandos. A continuación, la tarea de comandos ejecuta estas operaciones. Esta tarea utiliza la publicación sincrónica, lo que significa que esperará a que se complete cada operación de publicación antes de programar la siguiente.

  • Una tarea de publicador sincrónica crea una serie de operaciones de publicación y las envía a la cola de comandos. A continuación, la tarea de comandos ejecuta estas operaciones. La diferencia entre esta tarea y la anterior es que no esperará a que se complete una operación de publicación para programar la siguiente. Comprueba el estado de cada operación de publicación una vez que todas sus operaciones de publicación se hayan agregado a la cola. Tenga en cuenta que la distinción entre publicación sincrónica y asincrónica reside únicamente en el comportamiento de estas tareas. No hay diferencias en los comandos de publicación reales.

  • Una tarea de suscriptor crea una suscripción MQTT a un filtro de temas que coincide con los temas de todos los mensajes que publican las dos tareas de publicador. Esta tarea entra en un bucle y espera a recibir los mensajes publicados por las demás tareas.

Las tareas pueden tener colas para almacenar los mensajes recibidos. La tarea de comandos colocará los mensajes entrantes en la cola de cualquier tarea que esté suscrita al tema entrante.

Esta demostración utiliza una conexión TLS con autenticación mutua para conectarse. AWS Si la red se desconecta inesperadamente durante la demostración, el cliente intenta volver a conectarse mediante una lógica de retroceso exponencial. Si el cliente se vuelve a conectar correctamente, pero el agente no puede reanudar la sesión anterior, el cliente volverá a suscribirse a los mismos temas que en la sesión anterior.

Un único subproceso frente a varios subprocesos

Hay dos modelos de uso de coreMQTT: subproceso único y varios subprocesos (multitarea). Esta demostración le muestra cómo crear su propio esquema de varios subprocesos. También hay otro ejemplo de varios subprocesos que ejecuta el protocolo MQTT en segundo plano dentro de una tarea de agente (o daemon). Para obtener más información, consulte Agente y demostraciones de MWTT con coreMQTT. Si ejecuta el protocolo MQTT en una tarea de agente, no es necesario gestionar explícitamente ningún estado de MQTT ni llamar a la función MQTT_ProcessLoop. Además, si utiliza una tarea de agente, varias tareas de la aplicación pueden compartir una única conexión MQTT sin necesidad de primitivas de sincronización, como mutex.

Código fuente

El archivo fuente de la demostración lleva un nombre mqtt_demo_connection_sharing.c y se encuentra en el directorio y en el sitio web. freertos/demos/coreMQTT/ GitHub

Funcionalidad

Esta demostración crea cuatro tareas en total: tres que solicitan llamadas a la API de MQTT y una que procesa esas solicitudes, que es la tarea principal. En esta demostración, la tarea principal entra en un bucle que crea las tres subtareas, llama al bucle de procesamiento y, después, se limpia. La tarea principal crea una única conexión MQTT con el agente que se comparte entre las subtareas. Dos de las subtareas publican los mensajes para el agente y la tercera los recibe de vuelta, mediante una suscripción de MQTT a un filtro de temas que coincide con todos los temas de los mensajes publicados.

Typedefs

La demostración define las siguientes estructuras, enumeraciones y punteros de función.

Comandos

En lugar de realizar llamadas a la API de MQTT directamente, las tareas utilizan estructuras Command_t para crear comandos que indiquen a la tarea principal que llame a la operación de API adecuada para ellas. Los comandos tienen los siguientes tipos:

  • PROCESSLOOP

  • PUBLISH

  • SUBSCRIBE

  • UNSUBSCRIBE

  • PING

  • DISCONNECT

  • RECONNECT

  • TERMINATE

El comando TERMINATE no tiene una operación de API MQTT correspondiente. Se utiliza en la demostración para indicar a la tarea principal que deje de procesar los comandos y comience las operaciones de limpieza. Dado que algunos comandos de MQTT, como, por ejemplo, MQTT_Publish, MQTT_Subscribe y MQTT_Unsubscribe, requieren cierta información adicional, por ejemplo, información de publicación o suscripción, utilizamos el campo CommandContext_t. Este campo es obligatorio para estos tres comandos y es opcional para los demás.

Como este contexto es obligatorio para estos comandos, no cambie este valor una vez que el comando se haya colocado en la cola, hasta que se complete. Cuando se completa un comando, se puede invocar una devolución de llamada opcional. En esta demostración, utilizamos una devolución de llamada que crea una notificación de tarea para informar a la tarea de llamada de que el comando se ha completado. Para las operaciones de MQTT que requieren acuses de recibo (se suscribe, cancela la suscripción y publica con un QoS superior a 0), el comando se considera completado una vez recibido el acuse de recibo. De lo contrario, el comando se completa cuando se devuelve la correspondiente llamada a la API de MQTT.

En el archivo mqtt_demo_connection_sharing.c se encuentran las siguientes definiciones:

Acuses de recibo

Como algunas operaciones de MQTT requieren un acuse de recibo, utilizan una matriz de AckInfo_t que contiene el identificador de paquete del acuse de recibo esperado y el comando original que lo espera, de modo que se pueda invocar su devolución de llamada de finalización.

Suscripciones

Esta demostración puede realizar un seguimiento de las suscripciones para cada tarea. Para ello, cada tarea que solicite una suscripción debe proporcionar una cola de mensajes en la que recibirá los mensajes publicados (_t). SubscriptionElement Se pueden suscribir varias tareas al mismo filtro de temas, ya que se espera que usen colas de respuesta independientes.

Mensajes publicados recibidos

Como las tareas se ejecutan en paralelo con la tarea principal, sería difícil y llevaría mucho tiempo que la tarea principal tuviera que esperar a que cada tarea suscrita lea un mensaje publicado recibido. Por lo tanto, cada mensaje recibido se copia en la cola de respuestas de cualquier tarea que esté suscrita al tema del mensaje publicado (_t). PublishElement Como los paquetes de publicación recibidos del cliente MQTT contienen punteros al búfer de red del cliente, la carga útil y el nombre del tema del mensaje entrante se copian en búferes independientes antes de insertarlos en una cola de respuestas. De esta forma, la tarea suscrita puede seguir leyendo la información recibida una vez que el cliente MQTT haya borrado su búfer de red.

Tarea principal

La tarea principal de la aplicación RunCoreMQTTConnectionSharingDemo, establece una sesión MQTT persistente, crea tres subtareas y ejecuta el ciclo de procesamiento hasta que se recibe una orden de finalización. Se utiliza una sesión persistente, por lo que, si la red se desconecta inesperadamente, la demostración volverá a conectarse al agente en segundo plano, sin perder las suscripciones ni los mensajes entrantes publicados por el agente. Para crear una nueva sesión persistente para cada ejecución, la demostración se conecta con el agente que tiene el indicador clean session activado y, a continuación, se desconecta y se vuelve a conectar con el indicador desactivado. Una vez finalizado el bucle de procesamiento, se desconecta del agente y vuelve a realizar el bucle desde el punto en el que se reconectó a la red.

Si se completa correctamente la demostración, se generará una salida similar a la de la siguiente imagen.

Salida del terminal de demostración de conexión compartida de MQTT tras una finalización correcta
Bucle de comandos

El bucle de comandos prvCommandLoop, espera a que los comandos se coloquen en la cola de comandos y, a continuación, llama a la API de MQTT correspondiente. Todos los comandos, excepto DISCONNECT y TERMINATE hacen que se llame también a MQTT_ProcessLoop. Esta demostración configura una devolución de llamada de activación del socket para añadir un comando PROCESSLOOP a la cola cuando hay datos disponibles en el socket. Sin embargo, es posible que haya muchos comandos por delante en la cola en ese momento. Para asegurarnos de no descuidar los datos entrantes mientras se procesan otros comandos, se llama a MQTT_ProcessLoop para que realice una única iteración después de cada comando.

Procesamiento de comandos

Consulte la función. prvProcessCommand

Tarea de publicación sincrónica

La tarea de publicación sincrónica, prvSyncPublishTask, crea PUBLISH operaciones de forma sincrónica y espera a que se complete cada operación antes de programar la siguiente. Esta demostración usa QoS 1 para publicar mensajes, lo que significa que estas operaciones no se consideran completadas hasta que se reciba el paquete de acuse de recibo de publicación.

Tarea de publicador asíncrona

La tarea de publicación asíncrona, llamada prvAsyncPublishTask, no espera a que se complete una publicación para colocar la siguiente en la cola. Esto demuestra que no siempre es necesario que una tarea espere a que se complete una operación de MQTT para poder reanudarla. Como cada comando de publicación requiere su propia estructura de contexto, esta tarea no puede reutilizar una sola estructura de contexto como lo hace la tarea de publicador sincrónica, ya que es posible que un comando anterior aún la necesite. Por lo tanto, asigna memoria para cada estructura de contexto y, a continuación, espera a liberar toda la memoria asignada una vez que todos los mensajes que se van a publicar se hayan colocado en la cola.

Tarea de suscriptor

La tarea de suscriptor, prvSubscribeTask, se suscribe a un filtro de temas que coincide con todos los temas de los mensajes publicados en las tareas sincrónicas y asincrónicas. A continuación, espera a recibir todos los mensajes publicados antes de cancelar la suscripción. Esta tarea también es responsable de crear la operación TERMINATE que indica a la tarea principal que debe finalizar el bucle de comandos.