Tutorat système & Station météorologique TCP/IPXavier Redon & Thomas Vantroys |
L’objectif est de concevoir une station météorologique avec des capteurs de pression et de température connectés à un réseau TCP/IP et un serveur Web permettant d’afficher ergonomiquement les valeurs des capteurs.
Les capteurs sont réalisés à l’aide d’un Arduino complété par un capteur de température et d’humidité ainsi que par un bouclier Ethernet à base de circuit WIZnet W5100. Ces capteurs diffusent leurs valeurs sur le réseau TCP/IP local.
La collecte des valeurs météorologiques est assurée par un processus Unix qui joue aussi le rôle de serveur Web pour permettre un accès par les utilisateurs aux données. Une page affiche les valeurs instantanées et une autre les graphiques de valeurs au cours du temps. Les éléments graphiques sont implantés en utilisant la technologie canvas de la norme HTML5.
Les Arduino diffusent les valeurs des capteurs en utilisant le protocole UDP. Les processus Unix doivent récupérer et archiver ces valeurs de façon permanente. Les capteurs pourraient être repérés à leur adresse IP mais il est demandé qu’ils diffusent un identifiant sous la forme d’une chaîne de caractères avec leurs valeurs. Le format des messages UDP est laissé à votre bon soin. Il est évident qu’un format unique doit être adopté par la promotion.
Pour afficher les données de l’ensemble des capteurs connectés, votre processus Unix doit se comporter comme un serveur Web. Le port d’écoute du serveur doit pouvoir être passé en paramètre. Il vous faut décoder les requêtes HTTP envoyées à votre processus. Vous avez juste besoin de trouver le nom de la page demandée mais il faut quand même lire toutes les entêtes des requêtes. Vous devez gérer les entêtes de réponse Server, Date et Content-Type.
La page d’affichage des valeurs instantanées peut être une simple page HTML avec un dispositif de rafraichissement périodique. Prenez soin d’identifier les valeurs en utilisant les chaînes envoyés par les Arduino. Vous pouvez agrémenter l’affichage en utilisant des routines javascript pour simuler des afficheurs 7 ou 14 segments disponibles sur Internet.
La page d’affichage des graphiques doit être à base de javascript utilisant la technologie canvas d’HTML5 (vous pouvez utiliser une bibliothèque). Les données sont récupérées dans les fichiers de sauvegarde et transcrites sous forme de tableaux javascript. Les graphes sont tracés par une routine javascript. Un plus est de permettre de spécifier la plage d’affichage (jour, semaine, mois ou année).
Chaque binôme reçoit un Arduino avec un bouclier Ethernet et un capteur à base de BMP180 pour récupérer la pression et la température. Il vous est demandé de concevoir un bouclier pour porter le capteur ainsi que quelques LEDs indicatives. Personne ne vous empêche de réaliser une carte intégrant le micro-contrôleur ATMega328p, le contrôleur Ethernet W5100 et le capteur BMP180.
La programmation du micro-contrôleur se fait en utilisant le compilateur avr-gcc. L’algorithme à implanter sur le micro-contrôleur consiste en la lecture des valeurs des capteurs et en leur envoi dans des datagrammes UDP.
Il est fortement conseillé de suivre les étapes proposées ci-après pour réaliser le travail.
Le projet est constitué du programme pour le micro-contrôleur, de 2 bibliothèques et du programme tournant sous Unix. Chacune de ces entités est développée dans un répertoire propre. On gère donc les quatre répertoires suivants :
Cette arborescence et quelques squelettes de fichiers sont disponibles sous forme d’un fichier au format tar et compressé à l’URL http://www.plil.net/~rex/Enseignement/Systeme/Tutorat.IMA2a4.StationMeteo/meteo.tgz. Transférez ce fichier dans votre compte Polytech’Lille et décompressez-le avec la commande tar xvzf meteo.tgz. Vous pouvez constater que très peu de code est fourni, principalement quelques bibliothèques et le squelette du code pour le micro-contrôleur.
Cependant, le répertoire créé contient déjà un fichier Makefile global et des Makefile annexes dans chaque sous-répertoire. Vous avez un exemple de Makefile permettant de générer un exécutable et un exemple de Makefile permettant de construire une bibliothèque. Appuyez vous sur ces deux exemples pour compléter les autres Makefile. Le projet doit pouvoir être généré par la simple commande make exécutée dans le répertoire principal du projet. Il doit être aussi possible de regénérer complètement le projet par la commande make clean all lancée du même répertoire.
On prévoira de pouvoir compiler les différents sources avec un drapeau DEBUG (option -DDEBUG de gcc), permettant un affichage conditionnel d’informations de déverminage des programmes.
Les deux principales difficultés pour la programmation d’un capteur Arduino sont décrites ci-après.
Il s’agit dans cette étape de réaliser un serveur TCP basique à l’aide de l’interface de programmation des sockets.
Ecrivez dans le module libcom.c (répertoire Communication), les deux fonctions suivantes :
Testez cette bibliothèque en écrivant un programme station.c (répertoire Station) qui l’utilise et dont la fonction de traitement des connexions (celle appelée par boucleServeur) effectue juste une écriture de message dans la socket et clôt la connexion. Pour écrire, et plus tard lire, sur la connexion utilisez les fonctions classiques comme fgets ou fprintf. Pour y arriver vous devez transformer le descripteur de socket en une structure de fichier par la primitive fdopen.
Ce programme peut prendre des arguments : -p <port> ou --port <port> pour spécifier un numéro de port différent de celui par défaut (port 80). Pour traiter les arguments, utilisez la fonction getopt_long (voir la page de manuel correspondante). Si les arguments sont incorrects, on doit afficher un message qui précise la syntaxe. Pour plus de clarté, l’analyse des arguments et l’affichage de la syntaxe seront écrits dans des fonctions séparées.
Modifiez la fonction de traitement des connexions afin qu’elle ne ferme la connexion qu’après avoir lu une commande en provenance du client. Testez votre serveur avec plusieurs commandes nc simultanées. Conclusion ?
Pour que votre serveur Web puisse traiter plusieurs connexions simultanément, vous allez lancer un processus léger (thread) par connexion. Pour cela, implémentez la fonction publique de libthrd (répertoire Threads) :
int lanceThread(void (*)(void *),void *,int);
Cette fonction doit avoir comme action de lancer un thread dans le mode détaché. Ce thread doit exécuter la fonction passée en paramètre. La dite fonction prenant elle même comme paramètre le second paramètre de lanceThread dont la taille mémoire est donnée par le troisième paramètre. Il vous est conseillé d’utiliser une fonction intermédiaire récupérant un pointeur vers une structure comprenant les deux paramètres de lanceThread.
Testez votre fonction lanceThread en créant une nouvelle fonction dans station.c qui appelle votre fonction de traitement des connexions via lanceThread. Utilisez la nouvelle fonction comme paramètre de boucleServeur. Pour plus de clarté, ce serait une bonne idée de déplacer les fonctions de traitement des commandes des clients TCP du fichier station.c vers le fichier http.c.
Vérifiez que votre serveur est maintenant capable de gérer plusieurs connexions simultanément (toujours avec l’utilitaire nc).
La fonction lanceThread est utilisée dans plusieurs situations différentes. Tout d’abord comme expliqué plus haut pour gérer plusieurs clients Web simultanément ; dans ce cas la donnée passée à la fonction paramètre est un descripteur de socket de dialogue. La fonction lanceThread est aussi utilisée pour gérer simultanément les messages UDP envoyés par les capteurs ; dans ce cas la donnée passée à la fonction paramètre est le message UDP. Enfin, la fonction lanceThread est aussi utilisée pour démarrer le processus léger de gestion des messages UDP ; ici il n’y a pas de donnée à passer à la fonction paramètre (appelez lanceThread avec NULL en second paramètre et 0 en troisième paramètre).
Dans la description de l’architecture générale il est indiqué que les valeurs météorologiques arrivent par diffusion UDP. Vous allez donc ajouter dans la bibliothèque Communication les fonctions suivantes :
Testez vos fonctions en créant un fichier capteurs.c. Vous y écrirez une fonction messages permettant de lancer un processus léger réalisant principalement un appel à la fonction serveurMessages. La fonction de traitement associée se bornera à afficher le contenu des messages reçus en considérant qu’il s’agit d’une chaîne de caractères.
Créez un exécutable annexe de test utilisant la fonction d’envoi de message de façon périodique. Vérifiez avec cet exécutable de test que votre exécutable principal reçoit bien les diffusions UDP.
Pour l’affichage des valeurs instantanées des capteurs vous utiliserez une liste contigüe de structures stockant les valeurs des capteurs.
Pour l’affichage des courbes des valeurs, vous utiliserez les données stockées dans des fichiers binaires. Il est conseillé d’utiliser un fichier par capteur et un fichier listant le nom de tous les capteurs.
Définissez les structures de données nécessaires dans le fichier entête station.h.
Déterminez quelles opérations nécessitent l’utilisation de sémaphores.
Implantez dans votre bibliothèque libthrd les deux fonctions publiques :
void P(int) ; void V(int) ;
Ces fonctions cachent totalement le fait que vous utilisez des verrous d’exclusion mutelle pour threads POSIX. En particulier, les verrous sont représentés par une constante.
En implantant dans les divers fichiers, les fonctions nécessaires au fonctionnement du processus Unix, prenez soin d’y ajouter les poses et levées de verrous nécessaires.
Vous pouvez maintenant vous attaquer à l’écriture du code concernant le serveur Web. Il vous est rappelé qu’il vous a été conseillé d’utiliser les fichiers suivants :
Pour normaliser le serveur Web, il est demandé que la page d’affichage des valeurs instantanées soit nommée valeurs.html et que celle d’affichage des graphes soit nommée graphes.html. Une page principale doit être prévue pour renvoyer l’utilisateur sur une des deux pages décrites plus haut.
Ce document a été traduit de LATEX par HEVEA