Démo de partage de connexion CoreMQTT - FreeRTOS

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Démo de partage de connexion CoreMQTT

Important

Il s'agit d'une version archivée du guide de l'utilisateur de FreeRTOS à utiliser avec la version 202012.00 de FreeRTOS. Pour obtenir la dernière version de ce document, consultez le guide de l'utilisateur de FreeRTOS.

Introduction

Le projet de démonstration du partage de connexion CoreMQTT vous montre comment utiliser une application multithread pour établir une connexion au broker AWS MQTT à l'aide du protocole TLS avec authentification mutuelle entre le client et le serveur. Cette démonstration utilise une implémentation d'interface de transport basée sur MBEDTLS pour établir une connexion TLS authentifiée par le serveur et le client, et illustre le flux de travail d'abonnement/publication de MQTT au niveau QoS 1. La démo s'abonne à un filtre de rubrique, publie les rubriques correspondant au filtre, puis attend de recevoir ces messages du serveur au niveau QoS 1. Ce cycle de publication auprès du courtier et de réception du même message de la part du courtier se répète indéfiniment. Les messages de cette démo sont envoyés à QoS 1, ce qui garantit au moins une livraison conformément à la spécification MQTT.

Note

Pour configurer et exécuter les démos de FreeRTOS, suivez les étapes décrites dans. Débuter avec FreeRTOS

Cette démonstration utilise une file d'attente sécurisée par thread pour contenir les commandes permettant d'interagir avec l'API MQTT. Il y a quatre tâches à prendre en compte dans cette démonstration.

  • Une tâche de commande (principale) prend des commandes de la file de commandes et les traite. Les autres tâches placent les commandes dans cette file d'attente pour être traitées. Cette tâche entre dans une boucle au cours de laquelle elle traite les commandes. Si une commande de fin est reçue, cette tâche sera interrompue.

  • Une tâche d'éditeur synchrone crée une série d'opérations de publication et les envoie vers la file de commandes. Ces opérations sont ensuite exécutées par la tâche de commande. Cette tâche utilise la publication synchrone, ce qui signifie qu'elle attendra la fin de chaque opération de publication avant de planifier la suivante.

  • Une tâche d'éditeur asynchrone crée une série d'opérations de publication et les envoie vers la file de commandes. Ces opérations sont ensuite exécutées par la tâche de commande. La différence entre cette tâche et la précédente est qu'elle n'attendra pas la fin d'une opération de publication pour planifier la suivante. Il vérifie le statut de chaque opération de publication une fois que toutes ses opérations de publication ont été ajoutées à la file d'attente. Notez que la distinction entre publication synchrone et publication asynchrone réside uniquement dans le comportement de ces tâches. Il n'y a aucune différence entre les commandes de publication réelles.

  • Une tâche d'abonné crée un abonnement MQTT à un filtre de sujet qui correspond aux sujets de tous les messages publiés par les deux tâches d'éditeur. Cette tâche entre dans une boucle et attend de recevoir les messages publiés par les autres tâches.

Les tâches peuvent comporter des files d'attente pour contenir les messages reçus. La tâche de commande redirige les messages entrants vers la file d'attente de toute tâche abonnée au sujet entrant.

Cette démonstration utilise une connexion TLS avec authentification mutuelle pour se connecter AWS. Si le réseau se déconnecte de façon inattendue pendant la démonstration, le client tente de se reconnecter en utilisant une logique d'interruption exponentielle. Si le client se reconnecte avec succès, mais que le courtier ne parvient pas à reprendre la session précédente, le client se réabonnera aux mêmes sujets que lors de la session précédente.

Monothread ou multithread

Il existe deux modèles d'utilisation de CoreMQTT, monothread et multithread (multitâche). Cette démo vous montre comment créer votre propre schéma de multithreading. Il existe également un autre exemple multithread qui exécute le protocole MQTT en arrière-plan dans une tâche d'agent (ou de démon). Pour plus d'informations, consultez Agent MWTT et démos utilisant CoreMQTT. Si vous exécutez le protocole MQTT dans une tâche d'agent, il n'est pas nécessaire de gérer explicitement un état MQTT ou d'appeler la MQTT_ProcessLoop fonction. En outre, si vous utilisez une tâche d'agent, plusieurs tâches d'application peuvent partager une même connexion MQTT sans avoir besoin de primitives de synchronisation, telles que des mutex.

Code source

Le fichier source de démonstration est nommé mqtt_demo_connection_sharing.c et se trouve dans le freertos/demos/coreMQTT/ répertoire et GitHubsur le site Web.

Fonctionnalité

Cette démonstration crée quatre tâches au total : trois qui demandent des appels d'API MQTT et une qui traite ces demandes, qui est la tâche principale. Dans cette démonstration, la tâche principale entre dans une boucle qui crée les trois sous-tâches, appelle la boucle de traitement et nettoie ensuite. La tâche principale crée une connexion MQTT unique avec le broker, qui est partagée entre les sous-tâches. Deux des sous-tâches publient des messages destinés au courtier, et la troisième reçoit les messages en retour, en utilisant un abonnement MQTT à un filtre de sujets qui correspond à tous les sujets des messages publiés.

Définitions typographiques

La démo définit les structures, les énumérations et les pointeurs de fonction suivants.

Commandes

Plutôt que d'effectuer des appels d'API MQTT directement, les tâches utilisent Command_t des structures pour créer des commandes qui demandent à la tâche principale d'appeler l'opération d'API appropriée pour elles. Les types de commandes sont les suivants :

  • PROCESSLOOP

  • PUBLISH

  • SUBSCRIBE

  • UNSUBSCRIBE

  • PING

  • DISCONNECT

  • RECONNECT

  • TERMINATE

La TERMINATE commande n'a pas d'opération d'API MQTT correspondante. Il est utilisé dans la démo pour demander à la tâche principale d'arrêter le traitement des commandes et de commencer les opérations de nettoyage. Parce que certaines informations supplémentaires, par exemple des informations de publication ou d'abonnement, sont requises pour certaines commandes MQTT telles que MQTT_PublishMQTT_Subscribe, etMQTT_Unsubscribe, nous utilisons le CommandContext_t champ. Ce champ est obligatoire pour ces trois commandes, mais il est facultatif pour les autres.

Ce contexte étant requis pour ces commandes, ne modifiez pas cette valeur une fois que la commande a été placée dans la file d'attente, tant qu'elle n'est pas terminée. Lorsqu'une commande est terminée, un rappel facultatif peut être invoqué. Dans cette démo, nous utilisons un rappel qui crée une notification de tâche pour informer la tâche appelante que la commande est terminée. Pour les opérations MQTT qui nécessitent des accusés de réception (abonnement, désabonnement et publication avec une QoS supérieure à 0), la commande est considérée comme terminée une fois que l'accusé de réception a été reçu. Dans le cas contraire, la commande est terminée une fois que l'appel d'API MQTT correspondant est renvoyé.

Les définitions suivantes se trouvent dans le mqtt_demo_connection_sharing.c fichier :

Remerciements

Comme certaines opérations MQTT nécessitent un accusé de réception, elles utilisent un tableau de AckInfo_t qui contient l'identifiant de paquet de l'accusé de réception attendu et la commande d'origine qui l'attend, afin que son rappel de fin puisse être invoqué.

Abonnements

Cette démo permet de suivre les abonnements pour chaque tâche. Pour ce faire, chaque tâche demandant un abonnement doit fournir une file de messages dans laquelle elle recevra en retour les messages publiés (SubscriptionElement_t). Plusieurs tâches peuvent s'abonner au même filtre de rubrique, car elles sont censées utiliser des files de réponses distinctes.

Messages publiés reçus

Comme les tâches s'exécutent en parallèle avec la tâche principale, il serait difficile et fastidieux pour celle-ci d'attendre que chaque tâche abonnée lise un message publié reçu. Par conséquent, chaque message reçu est copié dans la file de réponses de toute tâche abonnée au sujet du message publié (PublishElement_t). Étant donné que les paquets de publication reçus du client MQTT contiennent des pointeurs vers la mémoire tampon réseau du client, la charge utile et le nom du sujet du message entrant sont copiés dans des tampons distincts avant d'être insérés dans une file de réponses. Ainsi, la tâche abonnée peut toujours lire les informations reçues une fois que le client MQTT a vidé sa mémoire tampon réseau.

Tâche principale

La tâche principale de l'application établit une session MQTT persistante, crée trois sous-tâches et exécute la boucle de traitement jusqu'à ce qu'une commande de fin soit reçue. RunCoreMQTTConnectionSharingDemo Une session permanente est utilisée. Ainsi, si le réseau se déconnecte de manière inattendue, la démo se reconnecte au courtier en arrière-plan, sans perdre les abonnements ni les messages publiés entrants provenant du courtier. Pour créer une nouvelle session persistante pour chaque exécution, la démo se connecte au broker avec le clean session drapeau activé, puis se déconnecte et se reconnecte avec le drapeau non activé. Une fois la boucle de traitement terminée, elle se déconnecte du broker, puis recommence à fonctionner à partir du point où elle a effectué la reconnexion au réseau.

Si la démonstration est terminée avec succès, un résultat similaire à l'image suivante sera généré.

Sortie du terminal de démonstration du partage de connexion MQTT en cas de réussite
Boucle de commande

La boucle de commande attend que les commandes soient placées dans la file d'attente de commandes, puis appelle l'API MQTT appropriée. prvCommandLoop Toutes les commandes, à DISCONNECT l'TERMINATEexception de et, MQTT_ProcessLoop sont également appelées. Cette démo définit un rappel de réveil du socket pour ajouter une PROCESSLOOP commande à la file d'attente lorsque des données sont disponibles sur le socket. Cependant, il se peut qu'il y ait de nombreuses commandes devant lui dans la file d'attente à ce stade. Pour s'assurer que nous ne négligeons pas les données entrantes lorsque d'autres commandes sont traitées, une seule itération MQTT_ProcessLoop est requise après chaque commande.

Commandes de traitement

Voir la prvProcessCommandfonction.

Tâche d'éditeur synchrone

La tâche d'éditeur synchrone, prvSyncPublishTask, crée PUBLISH des opérations de manière synchrone et attend que chaque opération soit terminée avant de planifier la suivante. Cette démonstration utilise QoS 1 pour publier des messages, ce qui signifie que ces opérations ne sont pas considérées comme terminées tant que le paquet d'accusé de réception de publication n'a pas été reçu.

Tâche d'éditeur asynchrone

La tâche d'éditeur asynchrone, prvAsyncPublishTask, n'attend pas la fin d'une publication pour placer la suivante dans la file d'attente. Cela montre qu'il n'est pas toujours nécessaire pour une tâche d'attendre la fin d'une opération MQTT avant de pouvoir reprendre. Comme chaque commande de publication nécessite sa propre structure de contexte, cette tâche ne peut pas réutiliser une seule structure de contexte comme le fait la tâche d'éditeur synchrone, car une commande précédente peut toujours en avoir besoin. Par conséquent, il alloue de la mémoire à chaque structure de contexte, puis attend de libérer toute la mémoire allouée une fois que tous les messages à publier ont été placés dans la file d'attente.

Tâche d'abonné

La tâche d'abonné s'abonne à un filtre de sujets qui correspond à tous les sujets des messages publiés à partir des tâches synchrones et asynchrones. prvSubscribeTask Il attend ensuite de recevoir en retour tous les messages publiés avant de se désabonner. Cette tâche est également chargée de créer l'TERMINATEopération qui indique à la tâche principale de mettre fin à la boucle de commande.