Previous Up

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.


Previous Up