Tutorat système & Capteur de pollution TCP/IP

Xavier Redon & Thomas Vantroys

1  Description générale du projet

1.1  Objectif

L’objectif est de concevoir une station de vérification de la qualité environnementale avec des capteurs de particules et des gaz connectés à un réseau TCP/IP et un serveur Web permettant d’afficher ergonomiquement les valeurs des capteurs.

2  Description des composants du projet

2.1  Architecture générale

Les capteurs sont réalisés à l’aide d’un Arduino complété par un capteur du taux de particules ainsi que par un bouclier Ethernet à base de circuit WIZnet W5100. Ces capteurs diffusent leurs valeurs sur le réseau TCP/IP local.

Il est aussi possible de concevoir une carte électronique à base de micro-contrôleur ATMega328p intégrant une puce W5100.

La collecte des valeurs des capteurs 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.

2.2  Diffusions UDP

Les dispositifs à base d’ATMega328p envoient les valeurs des capteurs en utilisant le protocole UDP. Les processus Unix doivent récupérer et archiver ces valeurs de façon permanente. Il est demandé que les dispositifs 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.

Les valeurs sont envoyées lorsqu’un message UDP de sollicitation est reçu. Cela permet aux processus Unix de découvrir les capteurs à l’aide d’une diffusion UDP pour ensuite solliciter les dispositifs en unicast. Ces derniers ne générent donc que des paquets UDP unicast.

2.3  L’affichage des données

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 dispositifs micro-contrôleur. 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).

2.4  Le matériel

Chaque binôme reçoit un Arduino mini avec un breakout Ethernet et un capteur GP2Y1010AU0F pour récupérer le taux de particules. Il vous est demandé de concevoir un circuit imprimé pour porter l’Arduino, le breakout, 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.

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.

3  Organisation du travail

3.1  Généralités

Il est fortement conseillé de suivre les étapes proposées ci-après pour réaliser le travail.

3.2  Organisation modulaire

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 :

Capteur -
pour les sources du programme chargé sur la plate-forme ATMega328p ;
Communication -
pour les sources de la bibliothèque contenant les fonctions de gestion réseau libcom ;
Threads -
pour les sources de la bibliothèque contenant les fonctions de gestion des threads libthrd ;
Station -
pour l’application de récupération et d’affichage des données météorologiques.

Cette arborescence et quelques squelettes de fichiers sont disponibles sous forme d’un fichier au format tar et compressé à l’URL http://rex.plil.fr/Enseignement/Systeme/Tutorat.IMA2a4.CapteurPollution/pollution.tgz. Transférez ce fichier dans votre compte Polytech’Lille et décompressez-le avec la commande tar xvzf pollution.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.

3.3  Programmation du micro-contrôleur

Les deux principales difficultés pour la programmation d’un dispositif micro-contrôleur sont décrites ci-après.

3.4  Sockets et serveur TCP

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 ?

3.5  Un serveur Web à base de processus légers

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).

3.6  Diffusion de messages par UDP

Dans la description de l’architecture générale il est indiqué que le processus Unix effectue une diffusion UDP pour découvrir les capteurs puis sollicite des valeurs par envoi de paquets UDP unicast. 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.

3.7  Structure de données et fichiers

Pour l’affichage des valeurs instantanées des capteurs vous utiliserez une liste contigüe de structures stockant les adresses des capteurs et leurs valeurs.

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.

3.8  Le serveur Web

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