Chapitre 2 Les fonctions réseau d Arduino 2.1 Matériel nécessaire Dans cette section, nous aurons besoin soit d un Arduino Uno et d une carte Wi-Fi, soit d un arduino Ethernet. Il existe plusieurs sortes d Arduino, parmi lesquels : Arduino UNO est le plus simple, il vaut une vingtaine d euro. Il est composé (cf. Figure 2.1 page suivante) d un processeur ATmega328 de la société ATmel. Il s agit d un processeur RISC 8 bits avec 32 Koctets de mémoire flash, des interfaces séries comme I2C, SPI. 23 broches d entrées sorties et la possibilité d échantillonner des signaux analogiques. La fréquence d horloge est de 16 Mhz conduisant à une puissance de traitement d environ 16 MIPS. 6 entrées analogiques pour échantillonage du signal. A noter que sur les anciennes versions les broches A4 et A5 peuvent servir pour les communications numériques via un bus I2C. Dans la dernière révision, des broches spécifiques sont apparues au niveau des broches d entrées/sorties numériques. une alimentation électrique comprise entre 9 et 12 volts. Elle n est pas nécessaire quand l Arduino est connecté à un port USB. un port USB qui permet d alimenter l Arduino, de téléverser le code compilé sur un ordinateur et de suivre l exécution d un programme si celui-ci envoie des informations sur la liaison série. Deux LED permettent de suivre l évolution des échanges de données en émission et en réception. L Arduino Ethernet vaut une cinquantaine d euro et a à peu près les mêmes caractéristiques que l Arduino UNO. Il se distingue par un port Ethernet à la place du port USB et un connecteur 6 broches qui permet de connecter un connecteur série connectable à de l USB. La carte dispose également d un emplacement mémoire dans le cas où l équipement est utilisé comme serveur et doit stocker des données. A noter que les broches 10 à 13 sont inutilisables car réservées à la communication avec le module Ethernet. D autres Arduino comme le Mega ou le DUE sont basés sur des processeurs ATmega plus puissants et possèdent plus de place en mémoire pour stocker les programmes, plus de broches d entrées/sorties et parfois une fréquence d horloge plus rapide. 11
Port USB (alimentation électrique, transfert de données, monitor) LED données port USB 13 Entrées/Sortie Numériques LED Alimenté Bouton RESET Alimentation électrique 9V à 12 V continu (+ au centre) Tensions et Masse Processeur ATmega328 6 entrées Analogiques (0 à 1023) FIGURE 2.1 Arduino UNO 2.2 Premières Applications en réseau Nous allons écrire des applications simples qui permettent d envoyer des informations vers un serveur. Dans un premier temps utiliser le protocole UDP qui est la manière la plus simple de communiquer avec l extérieur. Nous allons utiliser deux types de cartes Arduino. La première Arduino Ethernet contient une pile Ethernet intégrée, la seconde sera composée d un Arduino Uno et d une carte supplémentaire WiFi 1. Il faut aller télécharger sur la page suivante http://arduino.cc/en/main/ Software l application Arduino qui contient les bibliothèques nécessaire pour communiquer avec les différents modules, permet de compiler le code et de le télécharger le binaire obtenu via un port USB sur l équipement. Les exemples de ce livre sont basés sur la version 1.0.5. 2.2.1 Format d un programme Nous supposerons dans la suite que le lecteur possède quelques notions du langage C. Quand on en connaît les rudiments, la programmation en Arduino est très simple, deux 1. Il n est pas nécessaire d avoir les deux pour mettre en œuvre la suite des exemples. Ce chapitre explique comment facilement d une configuration vers une autre. 12
fonctions sont nécessaires pour tout programme Arduino : 2 la fonction setup est appelée une seule fois au démarrage du programme pour initialiser des variables. la fonction loop contient le programme principal. Elle est appelée continuellement donc il n est pas nécessaire qu elle contienne une boucle. Bien entendu, comme C, d autres fonctions appelées par setup ou loop peuvent être créées. De même qu il sera possible de créer des variables globales ou inclure les descriptions des types de données, des variables et des fonctions contenues dans des bibliothèques. La figure 2.2 montre l environnement de programmation pour le programme le plus simple (et qui ne fait rien). On y retrouve les deux fonctions setup ou loop. FIGURE 2.2 Interface de programmation Le bouton permet de compiler le programme pour vérifier qu il est syntaxiquement correct. Les erreurs de compilation (ou le message de succès) apparaît dans la fenêtre noire située en bas. Le bouton permet de compiler le code et, en bon québécois, de le téléverser, c est-à-dire de le copier sur l arduino et de l exécuter. En bas de l écran le port série est 2. voir également la très bonne introduction sur http://www.craslab.org/arduino/ LivretArduinoFr06.pdf. 13
indiqué (dans notre exemple /dev/tty.usbmodem411). Cette information est importante dans le cas où l on développe sur plusieurs Arduinos connectés par USB pour ne pas téléverser le code sur le mauvais équipement. Les boutons permettent de manipuler les fichiers. Le premier crée une nouvelle fenêtre vide dans laquelle on pourra développer un nouveau code. La flèche vers le haut ouvre dans l éditeur un code déjà écrit ou un modèle que l on pourra adapter à ses besoins. La flèche vers le bas sauvegarde le programme écrit. Enfin, le bouton permet, quand le code s exécute, de suivre les messages envoyés par l Arduino, via le port série. 2.2.2 Premier programme : Adresse MAC Comme il s agit d un livre sur les réseaux, nous n allons pas faire clignoter bêtement une LED en guise de premier programme. Nous allons plutôt commencer par un programme simple lisant l adresse d un module Wi-Fi (cf. Listing 2.1). 1 # i n c l u d e <SPI. h> 2 # i n c l u d e <WiFi. h> 3 4 b y t e mac [ 6 ] ; / / a d r e s s e MAC 5 6 void setup ( ) 7 { 8 S e r i a l. b e g i n ( 9 6 0 0 ) ; / / i n i t i a l i s e l a communication s e r i e 9 10 WiFi. macaddress ( mac ) ; / / r e c u p e r e l a d r e s s e MAC du module WiFi 11 S e r i a l. p r i n t ( MAC: ) ; / / l a f f i c h e s u r l e l i e n s e r i e 12 S e r i a l. p r i n t ( mac [ 5 ],HEX ) ; 13 S e r i a l. p r i n t ( : ) ; 14 S e r i a l. p r i n t ( mac [ 4 ],HEX ) ; 15 S e r i a l. p r i n t ( : ) ; 16 S e r i a l. p r i n t ( mac [ 3 ],HEX ) ; 17 S e r i a l. p r i n t ( : ) ; 18 S e r i a l. p r i n t ( mac [ 2 ],HEX ) ; 19 S e r i a l. p r i n t ( : ) ; 20 S e r i a l. p r i n t ( mac [ 1 ],HEX ) ; 21 S e r i a l. p r i n t ( : ) ; 22 S e r i a l. p r i n t l n ( mac [ 0 ],HEX ) ; 23 24 } 25 26 void loop ( ) {} Listing 2.1 Lecture de l adresse MAC Les 2 premières lignes définissent les variables et fonctions utilisées pour ce programme : SPI.h concerne les communications entre la carte Arduino et les périphériques, ici la carte Wi-Fi. WiFi.h définit les commandes permettant de piloter la carte Wi-Fi. 14
Ligne 4, le programme définit une structure globale de 6 octets appelée mac. Cette structure servira à stocker l adresse de la carte Wi-Fi. Ligne 6, la fonction d initialisation setup commence par définir la vitesse du bus serie USB pour communiquer avec le moniteur de l ordinateur. Ligne 10 un objet WiFi est déjà créé lors de l inclusion du fichier WiFi.h. La méthode macaddress retourne l adresse de la carte Wi-Fi. Cette adresses se retrouve également dans les carte Ethernet, on l appelle adresse MAC (Medium Access Control) Les lignes 11 à 22 envoyent le résultat sur le lien série pour qu il soit affiché par le moniteur de l ordinateur ayant servi à compiler le code (il faut sélectionner l icone ). Enfin, on peut remarquer que la fonction loop ligne 26 est vide car notre programme se déroule uniquement durant la phase d initialisation. Le résultat est donné dans le listing suivant : MAC: 7A: C4 : E : 9 2 : EB: 0 2.3 Comprendre les adresses MAC Le programme précédent a retourné une valeur sur 6 octets qui correspond à l adresse MAC de la carte Wi-Fi. L IEEE qui standardise les protocoles des réseaux locaux (Ethernet et Wi-Fi) a défini une structure commune pour tous les types de réseaux locaux. Cela permet leur interconnexion au niveau 2, c est-à-dire au niveau des trames. Le but d une adresse de niveau 2 est d identifier sans ambiguïté un équipement sur le réseau local (Ethernet, Wi-Fi,...). Techniquement parlant, l unicité de l adresse doit être garantie que sur ce réseau local, mais en pratique un réseau est amené à évoluer n importe qu elle machine dans le monde peut potentiellement s y connecter. Il est donc plus facile de garantir l unicité de l adresse au niveau mondial, de cette manière, il n y aura jamais de conflit d adresses quelque soit la configuration du réseau. EUI 48 I / G U / L OUI Vendor ID U=0 : Universal L=1 : Local I=0 : Individual G=1 : Group EUI 64 I / G U / L OUI Vendor ID MAC 16 I / G Local FIGURE 2.3 Adresses IEEE La figure 2.3 reprend les différents formats que l on retrouve dans les réseaux et dont le format est standardisé par l IEEE. Ce qui a été retourné par la carte Wi-Fi est appelée plus 15
formellement un EUI-48 (Extended Unique Identifier). Cet identificateur est décomposée en trois parties. Au centre se trouvent les 22 bits de l OUI (Organizationally Unique Identifier). L IEEE les attribue aux entreprises qui en font la demande (contre 1 885 $). Cette partie étant unique et les entreprises numérotant de manière unique les 24 bits restants (Vendor ID) la valeur est par construction unique dans le monde. Le deux premiers bits transmis ont un rôle particulier : le premier bit appelé I quand il est à 0 et G quand il est à 1 indique la nature de l adresse. Quand il est à 0, il s agit d une adresse unicast ou individuelle, c est-àdire destinée à un seul équipement sur le réseau. Quand il est à 1, il s agit d une adresse de groupe, on distingue : les adresses de broadcast dans laquelle tous les bits sont à 1, dans ce cas toutes les cartes réseaux recevant ces trames avec cette adresse de destination doivent la traiter. Elle est notée FF-FF-FF-FF-FF-FF. les adresses de multicast où tous les bits ne sont pas à 1, dans ce cas les machines qui veulent recevoir ce trafic, doivent l indiquer à leur carte réseau qui va s abonner. Les autres rejetteront les paquets qui ne leur sont pas destiné. Le deuxième bit est appelé U quand il est à 0 et L quand il est à 1. Quand il est à 0 il s agit d une adresse universelle c est-à-dire attribuée à partir de OUI de l IEEE et unique dans le monde. Ce bit mis à 1 devrait indiquer que l adresse a été modifiée ou créée par l administrateur de la machine 3. Dans notre notre exemple précédent, nous avions eu la valeur 7A-C4-0E-92-EB-00. Si l on regarde le premier octet transmis, c est à dire celui de gauche, il s écrit en binaire 0111 1100. Nous avons ici un piège lié à la représentation d un nombre sur le papier ou sur un écran, car il faut lire cette valeur de droite à gauche, le bit le moins significatif étant à droite. Nous avons donc une adresse individuelle (c est à-dire de l adresse d un seul équipement) et une adresse universelle. La figure 2.3 page précédente montre aussi deux autres types d adresses. Les EUI-64 sont une extension des EUI-48, la partie Vendor ID a été étendue sur 5 octets. Il existe également une forme d adressage sur 16 bits. Dans ce cas, bien entendu, il ne peut exister que des adresses locales, il est impossible de garantir leur unicité à l échelon mondial. On retrouvera ces deux types d adresses quand nous regarderons la norme IEEE 802.15.4 pour les réseaux de capteurs. 2.3.1 Carte Ethernet Une particularité de l Arduino avec une carte Ethernet embarquée est de ne pas avoir l adresse MAC stockée dans les composants. Sur les modèles récents, elle est imprimée sur une étiquette collée sur la face arrière de la carte. Il faut donc rentrer la valeur au début de la phase d initialisation, comme le montre le programme 2.2. 1 # i n c l u d e <SPI. h> 2 # i n c l u d e <E t h e r n e t. h> 3 3. Dans les fait, il n y a aucun contrôle possible, il ne faut donc pas baser une sécurité sur un EUI car ils sont modifiables et par conséquent facilement usurpables. 16
4 b y t e mac [ ] = { 0x90, 0xA2, 0xDA, 0x0D, 0x6F, 0x30 } ; 5 6 void setup ( ) 7 { 8 E t h e r n e t. b e g i n ( mac ) ; 9 } 10 11 void loop ( ) {} Listing 2.2 Affectation de l adresse MAC On y retrouve ligne 4, la structure mac à laquelle on affecte 6 valeurs qui correspondent à l adresse inscrite sur le dos de la carte. La méthode begin permet de l affecter à la carte Ethernet. Question 1 Le site web http://standards.ieee.org/develop/regauth/oui/public. html permet de connaître les affectations publiques des OUI par l IEEE. Qui possède l OUI des Arduino Ethernet? Cette solution si elle est simple d un point de vue matériel, peut poser des problèmes si l on doit déployer plusieurs cartes arduino tournant le même code. Il faudra à chaque fois le modifier pour prendre en compte une adresse MAC différente. 2.3.2 Pile protocolaire Arduino Si l on se réfère au modèle en couche présenté à la figure 3.14 page 68, la carte Arduino se place au niveau applicatif (7) et elle va communiquer avec la carte réseau qui se charge de mettre en place l ensemble de la pile protocolaire du niveau transport (4) au niveau physique (1). La communication entre l arduino et la carte se fait par le bus SPI (Serial Peripheral Interface) synchrone et bi-directionnel via les broches 10 à 13. Depuis l arduino, il n est pas possible de modifier les piles réseaux, en particulier comme les cartes Wi-Fi et Ethernet n incluent pas de pile IPv6, les communications se feront qu en IPv4. Comme le montre le programme 2.1 page 14 et le programme 2.2 page ci-contre un objet (au sens langage de progrmmation) est utilisé pour permettre la communication avec la carte réseau adéquate (respectivement WiFi et Ethernet). Ces noms sont assez trompeur car ils définissent des méthodes permettant d accéder également aux protocoles des couches 2 à 4 comme TCP/IP ou UDP. 2.4 Connexion à un réseau WiFi Si la connexion à un réseau Ethernet est généralement très simple, il suffit de brancher la prise Ethernet RJ-45 pour s y connecter physiquement, avec les réseaux sans fil le processus est un petit peu plus complexe. En effet, plusieurs réseaux peuvent être disponibles à un instant donné, et l utilisateur doit pouvoir sélectionner celui qu il désire utiliser. Il faut également empêcher qu un utilisateur non autorisé s y connecte ou puisse écouter les données émises. 17
2.4.1 Découverte des points d accès La carte Wi-Fi d Arduino met en œuvre le mode avec point d accès (AP : Access Point). Ce point d accès va diffuser toutes les 100 ms le nom du réseau (formellement SSID : Service Set Identifier). Ce message appelé beacon en anglais permet aux stations que le reçoivent de faire le choix d AP en fonction du nom et aussi de la qualité du signal (RSSI : Received Signal Strength Indication). Le programme 2.3 fortement inspiré d un programme que l on trouve sur le site web d Arduino permet de scanner et d afficher les réseaux présents. 1 / 2 c r e a t e d 13 J u l y 2010 by d l f ( Metodo2 s r l ) 3 m o d i f i e d 21 Junn 2012 by Tom Igoe and Jaymes Dec 4 / 5 # i n c l u d e <SPI. h> 6 # i n c l u d e <WiFi. h> 7 8 b y t e mac [ 6 ] ; 9 10 void setup ( ) { / / I n i t i a l i z e s e r i a l and w a i t f o r p o r t t o open : 11 S e r i a l. b e g i n ( 9 6 0 0 ) ; 12 w h i l e (! S e r i a l ) {} / / w a i t f o r s e r i a l p o r t t o c o n n e c t. 13 / / Needed f o r Leonardo only 14 i f ( WiFi. s t a t u s ( ) == WL NO SHIELD ) { / / check f o r s h i e l d p r e s e n c e 15 S e r i a l. p r i n t l n ( WiFi s h i e l d n o t p r e s e n t ) ; 16 w h i l e ( t r u e ) ; 17 } 18 WiFi. macaddress ( mac ) ; p r i n t M a c A d d r e s s ( mac ) ; / / P r i n t WiFi MAC a d d r e s s : 19 } 20 21 void loop ( ) { 22 l i s t N e t w o r k s ( ) ; / / Scan 23 d e l a y ( 1 0 0 0 0 ) ; / / w a i t 10 s e c 24 } 25 26 void p r i n t M a c A d d r e s s ( b y t e macaddr ) { 27 S e r i a l. p r i n t ( MAC: ) ; 28 S e r i a l. p r i n t ( macaddr [ 5 ],HEX ) ; S e r i a l. p r i n t ( : ) ; 29 S e r i a l. p r i n t ( macaddr [ 4 ],HEX ) ; S e r i a l. p r i n t ( : ) ; 30 S e r i a l. p r i n t ( macaddr [ 3 ],HEX ) ; S e r i a l. p r i n t ( : ) ; 31 S e r i a l. p r i n t ( macaddr [ 2 ],HEX ) ; S e r i a l. p r i n t ( : ) ; 32 S e r i a l. p r i n t ( macaddr [ 1 ],HEX ) ; S e r i a l. p r i n t ( : ) ; 33 S e r i a l. p r i n t l n ( macaddr [ 0 ],HEX ) ; 34 } 35 36 void l i s t N e t w o r k s ( ) { 37 S e r i a l. p r i n t l n ( Scan Networks ) ; 38 i n t numssid = WiFi. scannetworks ( ) ; 39 i f ( numssid == 1) { 40 S e r i a l. p r i n t l n ( Couldn t g e t a w i f i c o n n e c t i o n ) ; 41 w h i l e ( t r u e ) ; 42 } 43 / / p r i n t t h e l i s t of n e t w o r k s seen : 44 S e r i a l. p r i n t ( number of a v a i l a b l e n e t w o r k s : ) ; 45 S e r i a l. p r i n t l n ( numssid ) ; 18
46 47 f o r ( i n t t h i s N e t = 0 ; t h i s N e t <numssid ; t h i s N e t ++) { 48 S e r i a l. p r i n t ( t h i s N e t ) ; S e r i a l. p r i n t ( ) ) ; 49 S e r i a l. p r i n t ( WiFi. SSID ( t h i s N e t ) ) ; 50 S e r i a l. p r i n t ( \ t S i g n a l : ) ; S e r i a l. p r i n t ( WiFi. RSSI ( t h i s N e t ) ) ; 51 S e r i a l. p r i n t ( dbm ) ; 52 S e r i a l. p r i n t ( \ t E n c r y p t i o n : ) ; 53 p r i n t E n c r y p t i o n T y p e ( WiFi. e n c r y p t i o n T y p e ( t h i s N e t ) ) ; 54 } 55 } 56 57 void p r i n t E n c r y p t i o n T y p e ( i n t t h i s T y p e ) { 58 S e r i a l. p r i n t ( ( ) ; S e r i a l. p r i n t ( t h i s T y p e ) ; S e r i a l. p r i n t ( ) ) ; 59 s w i t c h ( t h i s T y p e ) { 60 c a s e ENC TYPE WEP : S e r i a l. p r i n t l n ( WEP ) ; b r e a k ; 61 c a s e ENC TYPE TKIP : S e r i a l. p r i n t l n ( WPA ) ; b r e a k ; 62 c a s e ENC TYPE CCMP : S e r i a l. p r i n t l n ( WPA2 ) ; b r e a k ; 63 c a s e ENC TYPE NONE : S e r i a l. p r i n t l n ( None ) ; b r e a k ; 64 c a s e ENC TYPE AUTO : S e r i a l. p r i n t l n ( Auto ) ; b r e a k ; 65 } 66 } Listing 2.3 Scanning des réseaux Wi-Fi disponibles La partie initialisation lignes 10 à 21 ressemble au premier programme que nous avons vu, un test supplémentaire vérifie que la carte Wi-Fi est bien présente. Dans le cas contraire le programme se bloque en exécutant une boucle sans fin (ligne 16). La partie boucle va appeler la fonction de scan (listnetworks) puis attendre 10 secondes. La fonction listnetworks (lignes 38 à 57) appelle ligne 40 la méthode scannetworks de la classe WiFi qui retourne soit le nombre de points d accès trouvé, soit une erreur (-1) qui provoque l arrêt du programme (ligne 43). Une boucle permet de parcourir et d afficher les caractéristiques des points d accès trouvés, à savoir, leur nom (SSID), la puissance du signal (RSSI) et la méthode de chiffrement. La fonction printencryptiontype indique l algorithme associé à la valeur. Le chiffrage WEP (Wired Equivalent Privacy) a été la première méthode utilisée pour chiffrer les connexions, mais elle est peu fiable pour deux raisons, la première est que la clé de chiffrement peut être facilement trouvée, la seconde est que comme son nom l indique ce mécanisme de chiffrement offre l équivalent d un réseau filaire de type Ethernet : tout équipement entré dans le réseau peut écouter les trafics venant des autres équipements. WPA (Wi-Fi Protected Access) offre des mécanismes de chiffrement plus robustes TKIP (Temporal Key Integrity Protocol) dans les premières versions et CCMP (Counter Cipher Mode with Block Chaining Message Authentication Code Protocol) pour la version WPA2 4. 4. Il existe un mode entreprise, dans lequel l authentification des utilisateurs se fait par un serveur centralisé. La carte Wi-Fi ne prend pas en compte ce mode de fonctionnement. 19
2.4.2 Connexion à un point d accès Pour se connecter à un point d accès, la méthode begin de l objet WiFi est utilisée, suivant la nature du réseau, elle prend plus ou moins d arguments : WiFi.begin(ssid) où ssid est une chaîne de caractères contenant le nom d un réseau ouvert c est-à-dire sans mécanisme de chiffrement. WiFi.begin(ssid, keyindex, key) où keyindex est un entier indiquant l index de la clé WEP et key une chaîne de caractère contenant la séquence hexadécimale. WiFi.begin(ssid, key) où keyindex est un entier indiquant l index de la clé WEP et key une chaîne de caractère contenant la séquence hexadécimale. Le programme 2.4 permet de se connecter à un réseau Wi-Fi protégé par WPA. Une fois connecté, il affiche periodiquement la force du signal. 1 / c r e a t e d 13 J u l y 2010 by d l f ( Metodo2 s r l ) 2 m o d i f i e d 31 May 2012 by Tom Igoe / 3 # i n c l u d e <SPI. h> 4 # i n c l u d e <WiFi. h> 5 6 c h a r s s i d [ ] = MyPlace ; / / your network SSID ( name ) 7 c h a r p a s s [ ] = 1234567890 ; / / your network password 8 i n t s t a t u s = WL IDLE STATUS ; / / t h e Wifi r a d i o s s t a t u s 9 10 void setup ( ) { / / I n i t i a l i z e s e r i a l and w a i t f o r p o r t t o open : 11 b y t e b s s i d [ 6 ] ; 12 13 S e r i a l. b e g i n ( 9 6 0 0 ) ; 14 w h i l e (! S e r i a l ) {} 15 16 i f ( WiFi. s t a t u s ( ) == WL NO SHIELD ) { 17 S e r i a l. p r i n t l n ( WiFi s h i e l d n o t p r e s e n t ) ; 18 w h i l e ( t r u e ) ; 19 } 20 21 w h i l e ( s t a t u s!= WL CONNECTED) { 22 S e r i a l. p r i n t ( A t t e m p t i n g t o c o n n e c t t o WPA SSID : ) ; 23 S e r i a l. p r i n t l n ( s s i d ) ; / / Connect t o WPA/WPA2 network : 24 s t a t u s = WiFi. b e g i n ( s s i d, p a s s ) ; 25 d e l a y ( 1 0 0 0 0 ) ; / / w a i t 10 s e c o n d s f o r c o n n e c t i o n : 26 } 27 28 S e r i a l. p r i n t ( You r e c o n n e c t e d t o t h e network ) ; 29 30 WiFi. BSSID ( b s s i d ) ; 31 S e r i a l. p r i n t ( BSSID : ) ; 32 S e r i a l. p r i n t ( b s s i d [ 5 ],HEX ) ; S e r i a l. p r i n t ( : ) ; 33 S e r i a l. p r i n t ( b s s i d [ 4 ],HEX ) ; S e r i a l. p r i n t ( : ) ; 34 S e r i a l. p r i n t ( b s s i d [ 3 ],HEX ) ; S e r i a l. p r i n t ( : ) ; 35 S e r i a l. p r i n t ( b s s i d [ 2 ],HEX ) ; S e r i a l. p r i n t ( : ) ; 36 S e r i a l. p r i n t ( b s s i d [ 1 ],HEX ) ; S e r i a l. p r i n t ( : ) ; 37 S e r i a l. p r i n t l n ( b s s i d [ 0 ],HEX ) ; 38 } 39 20
40 void loop ( ) { 41 p r i n t C u r r e n t N e t ( ) ; 42 d e l a y ( 1 0 0 0 0 ) ; 43 } 44 45 void p r i n t C u r r e n t N e t ( ) { / / p r i n t t h e r e c e i v e d s i g n a l s t r e n g t h : 46 long r s s i = WiFi. RSSI ( ) ; 47 S e r i a l. p r i n t ( s i g n a l s t r e n g t h ( RSSI ) : ) ; S e r i a l. p r i n t l n ( r s s i ) ; 48 } Listing 2.4 Connexion à un réseau Wi-Fi WPA 2.5 Comprendre IPv4 Au dessus du niveau 2, se trouve la couche IP. Il existe actuellement deux versions du protocole. L historique et la plus déployée est IPv4, mais la taille des adresses utilisées est trop petite et l espace d adressage sera bientôt saturé. Pour faire face à la pénurie, l IETF (Internet Engineering Task Force) travaille depuis une vingtaine d années sur un successeur, appelé IPv6, qui reprend les principes qui ont fait le succès d IPv4. Mais cette version peine à se déployer car la plupart des contenus se trouve encore uniquement accessible en IPv4. Pour l Internet des Objets, IPv6 offre plus de potentiel qu IPv4 grâce à une capacité d adresse quasi-illimitée et aux mécanismes d auto-configuration, mais dans une première approche nous nous intéresserons qu au protocole IPv4 puisqu il est le seul disponible pour les cartes Wi-Fi et Ethernet. Nous aborderons IPv6 dans le chapitre consacré à XBee, et un certain nombre de principes vu pour IPv4 seront conservés. 2.5.1 L adressage IPv4 Si le format d adresses est resté le même depuis la création du protocole en 1983, la manière de gérer l affectation des adresses a évoluée au cours de temps. Une adresse IPv4 est un mot de 32 bits. Pour simplifier la représentation, on utilise une notation utilisant 4 mots de 8 bits séparés par un point. préfixe identifiant d interface 0101 1011 1101 0011 0100 1001 0011 0100 91.211.73.52/21 FIGURE 2.4 Adresse IPv4 Dans les faits une adresse est divisée en 2 parties, une partie préfixe qui sert au routage et une partie identifiant d interface qui sert à repérer la machine sur le dernier lien. La 21
frontière entre ces deux parties varie d un réseau à un autre et est fixée par l ingénieur réseau en fonction du nombre de réseaux dont il a besoin et du nombre de machines qu il veut y placer. Toutes les machines sur un même réseau partage la même valeur de préfixe (et par conséquent la même longueur), par contre l identifiant d interface doit être unique. Comme il est impossible connaître la longueur du préfixe en lisant une adresse IPv4, cette information est indiquée après un /. La représentation d une adresse en décimal n aide pas à la lecture de la valeur du préfixe, ainsi sur l exemple figure 2.4 page précédente, le préfixe est 91.211.72.0/21. Pour le calculer, il faut mettre tous les bits de l identifiant d interface à 0. Comme les adresses sont de taille fixe, il n est pas nécessaire de représenter les octets à 0 situés à droite, le préfixe peut aussi se noter : 91.211.72/21 Cette représentation permet de rendre l adressage hiérarchique, ainsi si une société se voit attribuer le préfixe 91.211.72.0/21, elle peut assigner 8 préfixes de longueur 24 pour ses réseaux en interne. De même un opérateur peut représenter l ensemble de ses clients par un préfixe plus court, par exemple, 91.211/16. L identifiant d interface peut prendre toutes les valeurs possibles, sauf celles ou : tous les bits sont à 0 puisque ceci est la représentation d un préfixe tous les bits sont à 1 car cela correspond à l adresse de diffusion pour joindre l ensemble des machines connectées au réseau. Historiquement, la notion de longueur de préfixe était définie par un netmask. Comme son nom l indique, il s agissait de masquer la partie préfixe (net) de l identifiant d interface, en définissant un mot de la longueur de l adresse (32 bits) où les bits à 1 indiquaient un bit de préfixe dans l adresse et un bit à 0 un bit d identifiant d interface. Même si cela était théoriquement possible, la zone où les bits était à 1 devaient être contigüe. Par exemple, le netmask correspondant à un préfixe de longueur 24 est 255.255.255.0 car 255 s écrit en binaire 1111 1111. Le concept de netmask est plus difficile à manier que la longueur de préfixe, ainsi le netmask correspondant au préfixe de longueur 21 de notre exemple est 255.255.248.0. 2.5.2 Plan d adressage ADSL Wi-Fi SSID : Chezmoi box 1 câble Ethernet commutateur câble Ethernet Wi-Fi SSID : Test 5PC2 6PC3 4PC1 routeur 2 3 7PC4 câble Ethernet DHCP Réseau 1 192.168.1/24 Réseau 2 192.168.2/24 FIGURE 2.5 Topologie IP 22
La figure 2.5 page ci-contre représente schématiquement un réseau un peu plus complexe que ce que l on retrouve habituellement dans une maison. Ce réseau se compose d un routeur d accès connecté au réseau d opérateur (appelé en France Box). Elle peut être vu comme un routeur avec dans la maisons des ports Ethernet et un réseau Wi-Fi. L interconnexion entre le réseau Ethernet et le Wi-Fi est faite au niveau 2, c est-à-dire qu au niveau IP il s agit d un même réseau. Le commutateur, qui dans cet exemple, a été connecté à la box est également de niveau 2, donc tous les éléments qui y sont connectés appartiendront également à ce réseau. Pour connecter les équipements, l IETF propose, dans le document RFC1819 5, 3 plans d adressages privés (10/8, 172.16/12, 192.168/16). Ces préfixes sont utilisables librement et ils ne rentrent pas en conflit avec des préfixes officiellement attribués à d autres site. En contre partie, le trafic ne peut pas sortir du site avec ces adresses. On suppose que la box de l opérateur est configurée pour utiliser le préfixe 192.168/16. La box peut affecter au réseau Wi-Fi et Ethernet le préfixe 192.168.1/24. Ainsi le PC1 pourra avoir l adresse 192.168.1.10/24 et le PC2 l adresse 192.168.1.11/24. Le routeur sera également vu comme un équipement et pourra avoir l adresse 192.168.1.12/24. La box qui aura aussi une adresse en interne pour se connecter au réseau peut prendre la valeur 192.168.1.1/24 Le routeur va définir un second réseau auquel est connecte le réseaux Wi-Fi et ses propres ports Ethernet. L administrateur peut utiliser le préfixe 192.168.2/24. Le PC3 aura l adresse 192.168.2.1/24 et le PC4 192.168.2.2/24. L adresse interne assignée à ce réseau sera 192.168.2.254/24. 2.5.3 DHCP L utilisation du protocole DHCP Dynamic Host Configuration Protocol est la méthode la plus simple pour affecter les paramètres nécessaires pour qu un nœud puisse s insérer dans le réseau. Le programme 2.5 montre comment configurer le port Ethernet d un Arduino. 1 # i n c l u d e <SPI. h> 2 # i n c l u d e <E t h e r n e t. h> 3 4 b y t e mac [ ] = { 0x90, 0xA2, 0xDA, 0x0D, 0x6F, 0x30 } ; 5 6 void setup ( ) 7 { 8 S e r i a l. b e g i n ( 9 6 0 0 ) ; 9 10 E t h e r n e t. b e g i n ( mac ) ; 11 12 S e r i a l. p r i n t ( IP a d d r e s s : ) ; S e r i a l. p r i n t l n ( E t h e r n e t. l o c a l I P ( ) ) ; 13 S e r i a l. p r i n t ( netmas : ) ; S e r i a l. p r i n t l n ( E t h e r n e t. subnetmask ( ) ) ; 14 S e r i a l. p r i n t ( D e f a u l t r o u t e r : ) ; S e r i a l. p r i n t l n ( E t h e r n e t. gatewayip ( ) ) ; 15 S e r i a l. p r i n t ( DNS s e r v e r : ) ; S e r i a l. p r i n t l n ( E t h e r n e t. d n s S e r v e r I P ( ) ) ; 16 } 17 18 void loop ( ) {} 5. http://www.ietf.org/rfc/rfc1918.txt 23
Listing 2.5 Récupération des paramètres via DHCP Comme nous l avons indiqué précédemment, les cartes Ethernet des Arduino n ont pas d adresse MAC stockée dans leur ROM. Il est essentiel, ligne 4, de bien préciser l adresse MAC de l Arduino. En effet DHCP si deux équipements font une requête avec la même adresse MAC, le serveur DHCP retournera la même adresse IP. Ligne 10, la méthode begin permet d assigner l adresse MAC à la carte et comme aucun n autre paramètre n est précisé, la carte Ethernet va dérouler le protocole DHCP pour récupérer les paramètres. les lignes 12 à 15 permettent d afficher les résultats. Le résultat obtenu sur le port console est le suivant : IP a d d r e s s : 1 9 2. 1 6 8. 2. 1 0 netmask : 2 5 5. 2 5 5. 2 5 5. 0 D e f a u l t r o u t e r : 1 9 2. 1 6 8. 2. 1 DNS s e r v e r : 1 9 2. 1 6 8. 2. 1 le serveur DHCP a attribué l adresse IP 192.168.2.10/24 puisque le netmask est 255.255.255.0. Le routeur par défaut, c est-à-dire le routeur vers lequel sera envoyé le trafic qui n est pas à destination du préfixe de l Arduino (192.168.2.0/24, est 192.168.2.1. C est également l adresse du résolveur DNS, c est-à-dire l équipement qui pourra transformer un nom de machine du genre www.arduino.cc en adresse IP. Exemple de trafic Un analyseur réseau sur l ordinateur, comme wireshark 6 ou tcpdump 7, placé sur le réseau Ethernet permet de voir le trafic engendré pour l attribution des paramètres par DHCP. E t h e r n e t I I, Src : GheoSa 0d : 6 f : 3 0 ( 9 0 : a2 : da : 0 d : 6 f : 3 0 ), Dst : B r o a d c a s t ( f f : f f : f f : f f : f f : f f ) Type : IP (0 x0800 ) I n t e r n e t P r o t o c o l, Src : 0. 0. 0. 0 ( 0. 0. 0. 0 ), Dst : 2 5 5. 2 5 5. 2 5 5. 2 5 5 ( 2 5 5. 2 5 5. 2 5 5. 2 5 5 ) User Datagram Protocol, Src Port : bootpc ( 6 8 ), Dst Port : bootps ( 67) B o o t s t r a p P r o t o c o l Transaction ID : 0x00000332 C l i e n t IP a d d r e s s : 0. 0. 0. 0 ( 0. 0. 0. 0 ) Your ( c l i e n t ) IP a d d r e s s : 0. 0. 0. 0 ( 0. 0. 0. 0 ) Next s e r v e r IP a d d r e s s : 0. 0. 0. 0 ( 0. 0. 0. 0 ) Relay a g e n t IP a d d r e s s : 0. 0. 0. 0 ( 0. 0. 0. 0 ) C l i e n t MAC a d d r e s s : GheoSa 0d : 6 f : 3 0 ( 9 0 : a2 : da : 0 d : 6 f : 3 0 ) C l i e n t hardware a d d r e s s padding : 00000000000000000000 S e r v e r h o s t name n o t g i v e n Boot f i l e name n o t g i v e n Magic cookie : DHCP Option : ( t =53, l =1) DHCP Message Type = DHCP D i s c o v e r Option : ( t =61, l =7) C l i e n t i d e n t i f i e r Value : 0190 a2da0d6f30 Hardware t y p e : E t h e r n e t Option : ( t =12, l =12) Host Name = WIZnet0D6F30 Option : ( t =55, l =6) P a r a m e t e r Request L i s t Option : ( 55) Parameter Request L i s t Length : 6 Value : 0103060 f3a3b 1 = Subnet Mask 3 = R o u ter 6 = Domain Name S e r v e r 15 = Domain Name 58 = Renewal Time Value 59 = Rebinding Time Value End Option Comme il peut exister plusieurs serveurs DHCP dans un réseau, l Arduino va envoyer une requête DISCOVER en diffusion sur le réseau local. 6. http://www.wireshark.org/ 7. http://www.tcpdump.org/ 24
Au niveau Ethernet, on retrouve en adresse source l adresse qui a été configurée dans le programme 2.5 page 23. On peut remarquer que l analyseur à partir de l OUI identifie le fabriquant comme GheoSa. L adresse de destination est celle réservée à la diffusion généralisée (tout les bits sont à 1). Le champ type de la trame Ethernet indique le protocole de niveau supérieur ; 0x800 est la valeur désignant le protocole IPv4. Il est paradoxal d utiliser le protocole IP vue que l arduino ne dispose pas encore d adresse IP pour envoyer une requête DHCP. En fait comme le montre le listing, l adresse source est 0.0.0.0 et l adresse de destination est 255.255.255.255 c est-à-dire l ensemble des équipements du réseau local. Le protocole de niveau supérieur est UDP. UDP sert uniquement à identifier les applications. Dans ce cas spécial, les numéros de ports restent constants ; 67 pour le serveur et 68 pour le client DHCP. Le protocole DHCP est une extension du protocole bootstrap qui permet en particulier d allouer des adresses dynamiquement. Comme les adresses IP ne permettent pas d identifier l émetteur du message, un champ Transaction ID permet d identifier la transaction. Un certain nombre de champs permettent ensuite de transporter les adresses à allouer, dans notre cas elles sont toutes à 0.0.0.0. Le champ Magic Coockie : DHCP indique les paramètres supplémentaires définis pour étendre le protocole bootstrap : le premier paramètre décrit le type de message DHCP, ici une découverte des serveurs DHCP présent sur le réseau. un identificateur du client qui est basé sur l adresse Ethernet MAC de l arduino. le nom de l équipement ; Arduino utilise le mot clé WIZnet auquel il concatène les 3 derniers octets de l adresse MAC. et finalement la liste des paramètres qu il attend du serveur en plus de l adresse IP (le netmask, le routeur par défaut, le résolveur DNS, le nom de domaine et la durée pendant laquelle l Arduino pourra garder l adresse attribuée). Les serveurs DHCP répondent, dans notre exemple, il n y en a qu un d où une seule réponse : E t h e r n e t I I, Src : Apple a9 : f7 : ac ( 0 0 : 2 3 : df : a9 : f7 : ac ), Dst : B r o a d c a s t ( f f : f f : f f : f f : f f : f f ) Type : IP (0 x0800 ) I n t e r n e t P r o t o c o l, Src : 1 9 2. 1 6 8. 2. 1 ( 1 9 2. 1 6 8. 2. 1 ), Dst : 2 5 5. 2 5 5. 2 5 5. 2 5 5 ( 2 5 5. 2 5 5. 2 5 5. 2 5 5 ) User Datagram Protocol, Src Port : bootps ( 6 7 ), Dst Port : bootpc ( 68) B o o t s t r a p P r o t o c o l Transaction ID : 0x00000332 C l i e n t IP a d d r e s s : 0. 0. 0. 0 ( 0. 0. 0. 0 ) Your ( c l i e n t ) IP a d d r e s s : 1 9 2. 1 6 8. 2. 1 0 ( 1 9 2. 1 6 8. 2. 1 0 ) Next s e r v e r IP a d d r e s s : 1 9 2. 1 6 8. 2. 1 ( 1 9 2. 1 6 8. 2. 1 ) Relay a g e n t IP a d d r e s s : 0. 0. 0. 0 ( 0. 0. 0. 0 ) C l i e n t MAC a d d r e s s : GheoSa 0d : 6 f : 3 0 ( 9 0 : a2 : da : 0 d : 6 f : 3 0 ) C l i e n t hardware a d d r e s s padding : 00000000000000000000 Server host name : coba. lan Boot f i l e name n o t g i v e n Magic cookie : DHCP Option : ( t =53, l =1) DHCP Message Type = DHCP O f f e r Option : ( t =54, l =4) DHCP S e r v e r I d e n t i f i e r = 1 9 2. 1 6 8. 2. 1 Option : ( t =51, l =4) IP Address Lease Time = 23 hours, 45 minutes, 36 seconds Option : ( t =1, l =4) Subnet Mask = 255. 255. 255. 0 Option : ( t =3, l =4) Router = 192. 168. 2. 1 Option : ( t =6, l =4) Domain Name Server = 192. 168. 2. 1 Option : ( t =15, l =3) Domain Name = l a n End Option Les niveaux 2 à 4 ne changent fondamentalement par rapport à la précédente trame. On peut remarquer que l émetteur de la trame Ethernet est le serveur DHCP et qu il a mis son adresse comme adresse source du paquet IP (192.168.2.1). Au niveau DHCP, il répond montrant les paramètres qu il offre (OFFER) : Dans le corps du message l adresse IP qui pourra être affecté à l Arduino :192.168.2.10 et dans les options : la durée du bail (Lease Time), précisemment 23 heures 45 minutes et 36 secondes, le netmask associé à l adresse précédente 255.255.255.0, 25
le routeur par défaut 192.168.2.1. On peut remarquer que le serveur DHCP est localisé sur le routeur, le résolveur DNS qui est également sur le routeur, le nom du domaine lan. Le nom de l équipement sera donc WIZnet0D6F30.lan. Le client a reçu toutes les offres, il sélectionne celle qui lui convient le mieux, dans notre cas, il n a pas trop le choix : E t h e r n e t I I, Src : GheoSa 0d : 6 f : 3 0 ( 9 0 : a2 : da : 0 d : 6 f : 3 0 ), Dst : B r o a d c a s t ( f f : f f : f f : f f : f f : f f ) Type : IP (0 x0800 ) I n t e r n e t P r o t o c o l, Src : 0. 0. 0. 0 ( 0. 0. 0. 0 ), Dst : 2 5 5. 2 5 5. 2 5 5. 2 5 5 ( 2 5 5. 2 5 5. 2 5 5. 2 5 5 ) User Datagram Protocol, Src Port : bootpc ( 6 8 ), Dst Port : bootps ( 67) B o o t s t r a p P r o t o c o l Transaction ID : 0x00000332 C l i e n t IP a d d r e s s : 0. 0. 0. 0 ( 0. 0. 0. 0 ) Your ( c l i e n t ) IP a d d r e s s : 0. 0. 0. 0 ( 0. 0. 0. 0 ) Next s e r v e r IP a d d r e s s : 0. 0. 0. 0 ( 0. 0. 0. 0 ) Relay a g e n t IP a d d r e s s : 0. 0. 0. 0 ( 0. 0. 0. 0 ) C l i e n t MAC a d d r e s s : GheoSa 0d : 6 f : 3 0 ( 9 0 : a2 : da : 0 d : 6 f : 3 0 ) C l i e n t hardware a d d r e s s padding : 00000000000000000000 S e r v e r h o s t name n o t g i v e n Boot f i l e name n o t g i v e n Magic cookie : DHCP Option : ( t =53, l =1) DHCP Message Type = DHCP Request Option : ( t =61, l =7) C l i e n t i d e n t i f i e r Value : 0190 a2da0d6f30 Hardware t y p e : E t h e r n e t Option : ( t =12, l =12) Host Name = WIZnet0D6F30 Option : ( t =50, l =4) Requested IP Address = 192. 168. 2. 10 Option : ( t =54, l =4) DHCP S e r v e r I d e n t i f i e r = 1 9 2. 1 6 8. 2. 1 Option : ( t =55, l =6) P a r a m e t e r Request L i s t Option : ( 55) Parameter Request L i s t Length : 6 Value : 0103060 f3a3b 1 = Subnet Mask 3 = R o u ter 6 = Domain Name S e r v e r 15 = Domain Name 58 = Renewal Time Value 59 = Rebinding Time Value End Option Dans les options, on peut voir qu il a sélectionné le serveur DHCP 192.168.2.1 et qu il lui demande officiellement les paramètres. Le serveur acquitte la demande. L adresse sera attribuée pour un peu moins qu une journée. Il faudra que l arduino renouvelle se demande pour ne pas qu après ce laps de temps cette adresse soit attribuée à un autre équipement E t h e r n e t I I, Src : Apple a9 : f7 : ac ( 0 0 : 2 3 : df : a9 : f7 : ac ), Dst : B r o a d c a s t ( f f : f f : f f : f f : f f : f f ) Type : IP (0 x0800 ) I n t e r n e t P r o t o c o l, Src : 1 9 2. 1 6 8. 2. 1 ( 1 9 2. 1 6 8. 2. 1 ), Dst : 2 5 5. 2 5 5. 2 5 5. 2 5 5 ( 2 5 5. 2 5 5. 2 5 5. 2 5 5 ) User Datagram Protocol, Src Port : bootps ( 6 7 ), Dst Port : bootpc ( 68) B o o t s t r a p P r o t o c o l Transaction ID : 0x00000332 C l i e n t IP a d d r e s s : 0. 0. 0. 0 ( 0. 0. 0. 0 ) Your ( c l i e n t ) IP a d d r e s s : 1 9 2. 1 6 8. 2. 1 0 ( 1 9 2. 1 6 8. 2. 1 0 ) Next s e r v e r IP a d d r e s s : 1 9 2. 1 6 8. 2. 1 ( 1 9 2. 1 6 8. 2. 1 ) Relay a g e n t IP a d d r e s s : 0. 0. 0. 0 ( 0. 0. 0. 0 ) C l i e n t MAC a d d r e s s : GheoSa 0d : 6 f : 3 0 ( 9 0 : a2 : da : 0 d : 6 f : 3 0 ) C l i e n t hardware a d d r e s s padding : 00000000000000000000 Server host name : coba. lan Boot f i l e name n o t g i v e n Magic cookie : DHCP Option : ( t =53, l =1) DHCP Message Type = DHCP ACK Option : ( t =54, l =4) DHCP S e r v e r I d e n t i f i e r = 1 9 2. 1 6 8. 2. 1 Option : ( t =51, l =4) IP Address Lease Time = 23 hours, 45 minutes, 36 seconds Option : ( t =1, l =4) Subnet Mask = 255. 255. 255. 0 Option : ( t =3, l =4) Router = 192. 168. 2. 1 Option : ( t =6, l =4) Domain Name Server = 192. 168. 2. 1 Option : ( t =15, l =3) Domain Name = l a n End Option La figure 2.6 page suivante représente graphiquement l échange précédent. 2.6 Trafic TCP Nous allons étudier le fonctionnement en mode client/serveur de TCP. Une première définition d un serveur est un équipement qui attend des connexions venant de clients qui 26
WIZnet0D6F30 WIZnetaaaaaa WIZnetbbbbbb WIZnetcccccc DHCP Serveur OFFER DISCOVER REQUEST ACK FIGURE 2.6 Echange DHCP les initient. 2.6.1 Mise en place d un serveur apache Nous allons utiliser une machine Lunix Ubuntu chez un hébergeur, du type KimSufi d OVH. La premère étape est d installer un serveur Apache sur cette machine. Apache est le serveur Web le plus populaire, pour l installer sur une machine Linux, il suffit de taper : 1 >sudo apt-get install apache2 2 [sudo] password for toutain: 3 Reading package lists... Done 4 Building dependency tree 5 Reading state information... Done 6 The following NEW packages will be installed: 7 apache2 8 0 upgraded, 1 newly installed, 0 to remove and 15 not upgraded. 9 Need to get 0 B/1,492 B of archives. 10 After this operation, 29.7 kb of additional disk space will be used. 11 Selecting previously unselected package apache2. 12 (Reading database... 54742 files and directories currently installed.) 13 Unpacking apache2 (from.../apache2_2.2.22-1ubuntu1.3_amd64.deb)... 14 Setting up apache2 (2.2.22-1ubuntu1.3)... En se connectant via un navigateur sur le serveur ainsi créé, nous avons la page représentée figure 2.7 page suivante. Noter l adresse IP de votre serveur en tapant la commande ifconfig eth0 8. 1 >sudo ifconfig eth0 2 eth0 Link encap:ethernet HWaddr 00:22:4d:86:84:8a 3 inet addr:5.135.181.196 Bcast:5.135.181.255 Mask:255.255.255.0 4 inet6 addr: fe80::222:4dff:fe86:848a/64 Scope:Link 5 inet6 addr: 2001:41d0:8:bcc4::1/64 Scope:Global 6 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 7 RX packets:2447243 errors:0 dropped:0 overruns:0 frame:0 8 TX packets:1927771 errors:0 dropped:0 overruns:0 carrier:0 9 collisions:0 txqueuelen:1000 8. Vous pouvez devoir être super-utilisateur pour lancer cette commande 27
FIGURE 2.7 Page par défaut du server web 10 RX bytes:1155284677 (1.1 GB) TX bytes:461249596 (461.2 MB) 11 Interrupt:16 Memory:80400000-80420000 12 La ligne inet donne l adresse IP du serveur, ici 5.135.181.196. 2.6.2 Mise en place du client Arduino Nous allons poursuivre l écriture du programme 2.5 page 23 qui ne faisait que demander une adresse IP. Le programme 2.6 va ouvrir une connexion avec le serveur et afficher le résultat de la requête. 1 # i n c l u d e <SPI. h> 2 # i n c l u d e <E t h e r n e t. h> 3 4 b y t e mac [ ] = { 0x90, 0xA2, 0xDA, 0x0D, 0x6F, 0x30 } ; 5 6 E t h e r n e t C l i e n t c l i e n t ; 7 IPAddress i p ( 5, 1 3 5, 1 8 1, 1 9 6 ) ; 8 9 void setup ( ) 10 { 11 S e r i a l. b e g i n ( 9 6 0 0 ) ; 12 13 E t h e r n e t. b e g i n ( mac ) ; 14 15 S e r i a l. p r i n t ( IP a d d r e s s : ) ; S e r i a l. p r i n t l n ( E t h e r n e t. l o c a l I P ( ) ) ; 16 S e r i a l. p r i n t ( netmask : ) ; S e r i a l. p r i n t l n ( E t h e r n e t. subnetmask ( ) ) ; 17 S e r i a l. p r i n t ( D e f a u l t r o u t e r : ) ; S e r i a l. p r i n t l n ( E t h e r n e t. gatewayip ( ) ) ; 18 S e r i a l. p r i n t ( DNS s e r v e r : ) ; S e r i a l. p r i n t l n ( E t h e r n e t. d n s S e r v e r I P ( ) ) ; 19 20 d e l a y ( 1 0 0 0 ) ; 28
21 22 S e r i a l. p r i n t l n ( c o n n e c t i n g... ) ; 23 24 i f ( c l i e n t. c o n n e c t ( ip, 8 0 ) ) { 25 S e r i a l. p r i n t l n ( c o n n e c t e d ) ; 26 c l i e n t. p r i n t l n ( GET / HTTP / 1. 0 ) ; 27 c l i e n t. p r i n t l n ( ) ; 28 } e l s e { 29 S e r i a l. p r i n t l n ( c o n n e c t i o n f a i l e d ) ; 30 } 31 } 32 33 34 void loop ( ) { 35 i f ( c l i e n t. a v a i l a b l e ( ) ) { 36 c h a r c = c l i e n t. r e a d ( ) ; 37 S e r i a l. p r i n t ( c ) ; 38 } 39 40 i f (! c l i e n t. c o n n e c t e d ( ) ) { 41 S e r i a l. p r i n t l n ( ) ; 42 S e r i a l. p r i n t l n ( d i s c o n n e c t i n g. ) ; 43 c l i e n t. s t o p ( ) ; 44 f o r ( ; ; ) 45 ; 46 } 47 48 } Listing 2.6 Client HTTP Ligne 6, un objet client de la classe EthernetClient 9 est déclaré. Ligne 7, un objet ip de la classe IPAddress est déclaré, il est vu comme un tableau de 4 entiers, il est initialisé avec les octets de l adresse IP du serveur web installé au paragraphe précédent. Comme il s agit d une structure de données, et non pas d une adresse IP, les octets sont séparés par des virgules. Ligne 22 commence par l envoi d un message de trace sur la liaison série indiquant la phase d initialisation. Ligne 24, la méthode connect de l objet client permet une ouverture de connexion vers l adresse IP précédemment indiquée et sur le port 80 qui correspond au protocole HTTP (Hypertext Transfer Protocol) utilisé par le serveur Web 10. Si la connexion est un succès, le programme envoie la commande HTTP GET / HTTP1.0 (ligne 26) qui demande au serveur Web d envoyer la ressource située à la racine du serveur en utilisant la version 1.0 du protocole. En cas d échec de la connexion, un message d erreur est retourné (ligne 29). La boucle (loop), à partir de la ligne 34, va permettre d afficher le texte retourné par le serveur. Deux états vont être utilisés : la méthode client.available() (ligne 35) indique le nombre d octets disponibles à la lecture. Ils sont lus et affichés sur le port série un par un par le 9. WifiClient en cas d utilisation du module Wi-Fi. 10. Elle aurait pu être remplacée par client.connect("ks.touta.in", 80) où "ks.touta.in" correspond au nom de la machine, dans ce cas le résolveur DNS aurait été appelé. 29
programme. la méthode client.connected() (ligne 40) indique si la connexion est toujours établie avec le serveur. Dans le cas, on elle ne l est plus, le programme client libère les ressources locales utilisées pour gérer cette connexion grâce à la méthode client.stop() (ligne 43). En exécutant le programme on obtient le résultat donné au listing 2.7. 1 IP a d d r e s s : 1 9 2. 1 6 8. 2. 1 0 2 netmask : 2 5 5. 2 5 5. 2 5 5. 0 3 D e f a u l t r o u t e r : 1 9 2. 1 6 8. 2. 1 4 DNS s e r v e r : 1 9 2. 1 6 8. 2. 1 5 c o n n e c t i n g... 6 c o n n e c t e d 7 HTTP / 1. 1 200 OK 8 Date : F r i, 26 Apr 2013 1 2 : 5 4 : 5 0 GMT 9 S e r v e r : Apache / 2. 2. 2 2 ( Ubuntu ) 10 Last Modified : Sat, 20 Apr 2013 1 4 : 3 0 : 0 7 GMT 11 ETag : 201 ce b1 4d a c b a c 1 f a f 3 4 12 Accept Ranges : b y t e s 13 Content Length : 177 14 Vary : Accept Encoding 15 C o n n e c t i o n : c l o s e 16 Content Type : t e x t / html 17 18 <html><body><h1> I t works! </ h1> 19 <p>this i s t h e d e f a u l t web page f o r t h i s s e r v e r. </ p> 20 <p>the web s e r v e r s o f t w a r e i s r u n n i n g b u t no c o n t e n t has been added, y e t. </ p> 21 </ body ></ html> 22 23 d i s c o n n e c t i n g. Listing 2.7 Résultat de l interrogation du serveur Web La réponse du serveur commence ligne 7 où est donné le status de la requête : la version du protocole utilisé est HTTP/1.1. La valeur 200 indique que le serveur a accepté la demande, cette valeur est normalisée et peut être interprétée par les applications clientes, pour les humains, le status est aussi indiqué par OK. Les lignes qui suivent contiennent les champs de l en-tête HTTP qui se termine par une ligne vide (ligne 17). Ensuite de la ligne 18 à 22 viennent les données. Ces données sont structurées suivante le protocole HTML (HyperText Markup Language) comme indiqué ligne 16 dans le champ Content-Type de l en-tête. Un document HTML est structuré par des balises de la forme <balise>... </balise>. Ici tout le document est sous la balise <html> puis sous celle de <body>. la balise <h1> permet d afficher un texte en grand et les balises <p> permettent de délimiter les paragraphes. 2.6.3 Analyse du trafic Les échanges suivants ont eu lieu sur le câble Ethernet, après l échange DHCP étudié précédemment. 30
E t h e r n e t I I, Src : GheoSa 0d : 6 f : 3 0 ( 9 0 : a2 : da : 0 d : 6 f : 3 0 ), Dst : B r o a d c a s t ( f f : f f : f f : f f : f f : f f ) Type : ARP (0 x0806 ) Address R e s o l u t i o n P r o t o c o l ( r e q u e s t ) Hardware type : Ethernet (0 x0001 ) Protocol type : IP (0 x0800 ) Hardware s i z e : 6 P r o t o c o l s i z e : 4 Opcode : request (0 x0001 ) [ I s g r a t u i t o u s : F a l s e ] Sender MAC a d d r e s s : GheoSa 0d : 6 f : 3 0 ( 9 0 : a2 : da : 0 d : 6 f : 3 0 ) Sender IP address : 192. 168. 2. 10 ( 1 9 2. 1 6 8. 2. 1 0 ) T a r g e t MAC a d d r e s s : 0 0 : 0 0 : 0 0 00 : 0 0 : 0 0 ( 0 0 : 0 0 : 0 0 : 0 0 : 0 0 : 0 0 ) T a r g e t IP a d d r e s s : 1 9 2. 1 6 8. 2. 1 ( 1 9 2. 1 6 8. 2. 1 ) L Arduino envoie une requête ARP (Address Resolution Protocol). Il recherche l adresse MAC du routeur (192.168.2.1) pour lui envoyer les paquets à destination du serveur Web. En effet, comme la destination ne partage pas le préfixe de la source, l utilisation du routeur par défaut configuré par DHCP s impose. E t h e r n e t I I, Src : Apple a9 : f7 : ac ( 0 0 : 2 3 : df : a9 : f7 : ac ), Dst : GheoSa 0d : 6 f : 3 0 ( 9 0 : a2 : da : 0 d : 6 f : 3 0 ) Type : ARP (0 x0806 ) Address R e s o l u t i o n P r o t o c o l ( r e p l y ) Hardware type : Ethernet (0 x0001 ) Protocol type : IP (0 x0800 ) Hardware s i z e : 6 P r o t o c o l s i z e : 4 Opcode : reply (0 x0002 ) [ I s g r a t u i t o u s : F a l s e ] Sender MAC a d d r e s s : Apple a9 : f7 : ac ( 0 0 : 2 3 : df : a9 : f7 : ac ) Sender IP a d d r e s s : 1 9 2. 1 6 8. 2. 1 ( 1 9 2. 1 6 8. 2. 1 ) T a r g e t MAC a d d r e s s : GheoSa 0d : 6 f : 3 0 ( 9 0 : a2 : da : 0 d : 6 f : 3 0 ) Target IP address : 192. 168. 2. 10 ( 1 9 2. 1 6 8. 2. 1 0 ) Le routeur retourne son adresse MAC (00:23:df:a9:f7:ac), l arduino la met dans une table pour éviter de faire cette requête à chaque envoi de paquet. Le client Arduino peut ouvrir la connexion avec le serveur Web. I n t e r n e t P r o t o c o l, Src : 1 9 2. 1 6 8. 2. 1 0, Dst : 5. 1 3 5. 1 8 1. 1 9 6 Transmission Control Protocol, Src Port : 1025, Dst Port : h t t p ( 80), Seq : 0, Len : 0 Flags : 0x02 (SYN) L arduino envoie un message TCP avec un bit SYN mis à 1. Ce bit indique au serveur la volonté du client d ouvrir une connexion. Le client a choisi un numéro de port (1025) comme port source, designant localement l application qui ouvre la connexion, et envoi au port destination (80) qui correspond au protocole HTTP. I n t e r n e t P r o t o c o l, Src : 5. 1 3 5. 1 8 1. 1 9 6, Dst : 1 9 2. 1 6 8. 2. 1 0 Transmission Control Protocol, Src Port : h t t p ( 80), Dst Port : 1025, Seq : 0, Ack : 1, Len : 0 Flags : 0x12 (SYN, ACK) Le serveur acquitte la demande d ouverture de connexion en envoyant un message TCP contenant les bits SYN et ACK positionnés. I n t e r n e t P r o t o c o l, Src : 1 9 2. 1 6 8. 2. 1 0 ( 1 9 2. 1 6 8. 2. 1 0 ), Dst : 5. 1 3 5. 1 8 1. 1 9 6 ( 5. 1 3 5. 1 8 1. 1 9 6 ) Transmission Control Protocol, Src Port : blackjack ( 1025), Dst Port : h t t p ( 80), Seq : 1, Ack : 1, Len : 0 Flags : 0x10 (ACK) Le client acquitte le message précédent en positionnant le bit ACK. A partir de ce moment, la connexion est ouverte sur le client, elle le sera sur le serveur quand il recevra ce message. Le transfert de données peut commencer. I n t e r n e t P r o t o c o l, Src : 1 9 2. 1 6 8. 2. 1 0, Dst : 5. 1 3 5. 1 8 1. 1 9 6 Transmission Control Protocol, Src Port : 1025, Dst Port : h t t p ( 80), Seq : 1, Ack : 1, Len : 14 TCP segment data (14 bytes ) GET / HTTP / 1. 0 Le client envoie la requêtre HTTP I n t e r n e t P r o t o c o l, Src : 1 9 2. 1 6 8. 2. 1 0, Dst : 5. 1 3 5. 1 8 1. 1 9 6 Transmission Control Protocol, Src Port : 1025, Dst Port : h t t p ( 80), Seq : 15, Ack : 1, Len : 1 TCP segment data (1 byte ) \ r pour le caractère de contrôle \r correspondant au retour chariot I n t e r n e t P r o t o c o l, Src : 1 9 2. 1 6 8. 2. 1 0, Dst : 5. 1 3 5. 1 8 1. 1 9 6 Transmission Control Protocol, Src Port : 1025, Dst Port : h t t p ( 80), Seq : 16, Ack : 1, Len : 1 TCP segment d a t a (1 b y t e ) \n 31
et le caractère \n qui correspond à un saut de ligne. Ceci correspond à l envoi de caractère de la ligne 26 du programme 2.6 page 28. I n t e r n e t P r o t o c o l, Src : 1 9 2. 1 6 8. 2. 1 0, Dst : 5. 1 3 5. 1 8 1. 1 9 6 Transmission Control Protocol, Src Port : 1025, Dst Port : h t t p ( 80), Seq : 17, Ack : 1, Len : 1 TCP segment data (1 byte ) \ r I n t e r n e t P r o t o c o l, Src : 1 9 2. 1 6 8. 2. 1 0, Dst : 5. 1 3 5. 1 8 1. 1 9 6 Transmission Control Protocol, Src Port : 1025, Dst Port : h t t p ( 80), Seq : 18, Ack : 1, Len : 1 TCP segment d a t a (1 b y t e ) Encore un retour chariot - saut de ligne qui correspond à la ligne 27 du programme 2.6 page 28. Le serveur acquitte les données qu il a reçues. I n t e r n e t P r o t o c o l, Src : 5. 1 3 5. 1 8 1. 1 9 6, Dst : 1 9 2. 1 6 8. 2. 1 0 Transmission Control Protocol, Src Port : h t t p ( 80), Dst Port : 1025, Seq : 1, Ack : 15, Len : 0 I n t e r n e t P r o t o c o l, Src : 5. 1 3 5. 1 8 1. 1 9 6, Dst : 1 9 2. 1 6 8. 2. 1 0 Transmission Control Protocol, Src Port : h t t p ( 80), Dst Port : 1025, Seq : 1, Ack : 16, Len : 0 I n t e r n e t P r o t o c o l, Src : 5. 1 3 5. 1 8 1. 1 9 6, Dst : 1 9 2. 1 6 8. 2. 1 0 Transmission Control Protocol, Src Port : h t t p ( 80), Dst Port : 1025, Seq : 1, Ack : 17, Len : 0 I n t e r n e t P r o t o c o l, Src : 5. 1 3 5. 1 8 1. 1 9 6, Dst : 1 9 2. 1 6 8. 2. 1 0 Transmission Control Protocol, Src Port : h t t p ( 80), Dst Port : 1025, Seq : 1, Ack : 18, Len : 0 I n t e r n e t P r o t o c o l, Src : 5. 1 3 5. 1 8 1. 1 9 6, Dst : 1 9 2. 1 6 8. 2. 1 0 Transmission Control Protocol, Src Port : h t t p ( 80), Dst Port : 1025, Seq : 1, Ack : 19, Len : 0 Pour chaque message TCP émis, un message d acquittement est retourné, comme on peut le voir avec l évolution du champ Ack. I n t e r n e t P r o t o c o l, Src : 5. 1 3 5. 1 8 1. 1 9 6, Dst : 1 9 2. 1 6 8. 2. 1 0 Transmission Control Protocol, Src Port : h t t p ( 80), Dst Port : 1025, Seq : 1, Ack : 19, Len : 453 TCP segment data (453 bytes ) : HTTP / 1. 1 200 OK\r\n Date : Fri, 26 Apr 2013 1 5 : 2 5 : 2 9 GMT\r\n S e r v e r : Apache / 2. 2. 2 2 ( Ubuntu )\ r\n Last Modified : Sat, 20 Apr 2013 14:30:07 GMT\r\n ETag : 201 ce b1 4dacbac1faf34 \ r\n Accept Ranges : b y t e s \r\n Content Length : 177\ r\n [ Content length : 177] Vary : Accept Encoding\r\n Connection : c l o s e \r\n Content Type : t e x t / html\r\n \r\n <html><body><h1>i t works!</h1>\n <p>this i s t h e d e f a u l t web page f o r t h i s s e r v e r.</p>\n <p>the web server software i s running but no content has been added, yet.</p>\n </body></html>\n Le serveur envoie la réponse correspondant à la requête GET. On retrouve le texte qui avait été affiché par l arduino (c.f. Listing 2.7 page 30). I n t e r n e t P r o t o c o l, Src : 5. 1 3 5. 1 8 1. 1 9 6, Dst : 1 9 2. 1 6 8. 2. 1 0 Transmission Control Protocol, Src Port : h t t p ( 80), Dst Port : 1025, Seq : 454, Ack : 19, Len : 0 L arduino acquitte les données reçues. I n t e r n e t P r o t o c o l, Src : 5. 1 3 5. 1 8 1. 1 9 6, Dst : 1 9 2. 1 6 8. 2. 1 0 Transmission Control Protocol, Src Port : h t t p ( 80), Dst Port : 1025, Seq : 454, Ack : 19, Len : 0 Header length : 20 bytes Flags : 0x11 ( FIN, ACK) I n t e r n e t P r o t o c o l, Src : 1 9 2. 1 6 8. 2. 1 0, Dst : 5. 1 3 5. 1 8 1. 1 9 6 Transmission Control Protocol, Src Port : 1025, Dst Port : h t t p ( 80), Seq : 19, Ack : 455, Len : 0 Flags : 0x10 (ACK) I n t e r n e t P r o t o c o l, Src : 1 9 2. 1 6 8. 2. 1 0, Dst : 5. 1 3 5. 1 8 1. 1 9 6 Transmission Control Protocol, Src Port : 1025, Dst Port : h t t p ( 80), Seq : 19, Ack : 455, Len : 0 Flags : 0x11 ( FIN, ACK) I n t e r n e t P r o t o c o l, Src : 5. 1 3 5. 1 8 1. 1 9 6, Dst : 1 9 2. 1 6 8. 2. 1 0 Transmission Control Protocol, Src Port : h t t p ( 80), Dst Port : 1025, Seq : 455, Ack : 20, Len : 0 Flags : 0x10 (ACK) Le serveur met fin à la connexion en envoyant un paquet avec le bit FIN de positionné que l Arduino acquitte. Puis l Arduino envoie à son tour un paquet avec le bit FIN de 32
positionné que le serveur acquitte. A ce stade, la connexion est terminée et les ressources utilisées pour la contrôler sont libérées sur les deux équipements. La figure 2.8 retrace l échange. Le nombre de paquets échangés (21) pour ce simple échange est relativement important. Dans des mises en oeuvres plus complètes, des algorithmes auraient limité le nombre de paquets échangés, mais l implémentation dans la carte Ethernet du protocole TCP est limitée par la taille, ce qui pour effet d augmenter le nombre de paquets échangés. Client 192.168.2.10 Serveur 5.135.181.196 SYN SYN ACK ACK ACK : 15 ACK : 16 ACK : 17 ACK : 18 ACK : 19 GET / HTTP/1.0 \r \n \r \n HTTP/1.1 200 OK... ACK : 454 FIN ACK FIN ACK ACK FIGURE 2.8 Diagramme temporel des échanges entre le client et le serveur Question 2 Relancer le programme 2.6 page 28 en supprimant le println vide ligne 27. Qu obtienton comme résultat? Au bout de combien de temps? Comment interpréter cette réponse? 2.7 Traduction d adresses Si l on regarde le trafic du coté du serveur, le premier paquet émis par le client pour ouvrir la connexion (paquet SYN), on trouve : I n t e r n e t P r o t o c o l, Src : 1 8 9. 2 2 5. 4 7. 5 7, Dst : 5. 1 3 5. 1 8 1. 1 9 6 Transmission Control Protocol, Src Port : 50814, Dst Port : h t t p ( 80), Seq : 0, Len : 0 Flags : 0x02 (SYN) On remarque que l adresse IP source a été changée de 192.168.2.10 à 189.225.47.57. En effet le préfixe 192.168/16 est un préfixe privé et ne peut donc être utilisé dans le 33
réseau du site (domicile, entreprise) et ne doit pas être vu à l extérieur sur Internet. Si l on reprend le schéma figure 2.5 page 22, l opérateur va fournir à la box une adresse IP publique, la box offrira une fonction de traduction et changera l adresse privée en adresse publique. Mais cela ne suffit pas de changer d adresse car cela risque de créer des ambiguités. Toujours sur le schéma figure 2.5 page 22, supposons que PC1 et PC2 aillent sur le même serveur Web. En IP on identifie un flux à partir de 5 valeurs tirées des paquets : F lux =< adresse source, adresse destination, port source, port destination, proto > Dans notre exemple on aura : F lux 1 =< 192.168.1.10, IP serveur, P S 1, 80, T CP > F lux 1 =< 192.168.1.11, IP serveur, P S 2, 80, T CP > Il n y a pas d ambiguïtés car même si les numéros de ports sont identique (P S 1 = P S 2 ) les adresses IP étant différentes, les flux sont bien identifiés. Le choix des numéros de ports source étant local au client, il se peut que deux machines choisissent le même. Or après la phase de traduction d adresse, les adresses sources deviendront les mêmes. Pour éviter que l on ne puisse plus identifier les flux, le NAT devra veiller à l unicité des numéros de ports. On peut noter que dans la trace précédente, le numéro de port source est passé de 1025 à 50814. En fait le numéro de port devient, en quelque sorte, l identifiant du flux localement. Le NAT va associer aux numéros de ports extérieurs, les adresses et numéros de ports internes. De cette manière, quand un paquet revient, le NAT regarde le port destination et peut le remplacer, ainsi que l adresse destination par les valeurs mémorisées. S il elle n existe dans aucun contexte associé à un numéro de port externe, une machine est inaccessible depuis l extérieur. En d autres termes les connexions entrantes (c est-à-dire à l initiative de machines situées sur Internet) sont bloquées, le NAT ne permet que les connexion sortantes à l initiative des machines situées sur le réseau privé. Cela donne un sentiment de sécurité, puiqu une machine n est accessible que pour des flux ayant déjà créés des contextes au niveau du NAT. Si on veut qu une machine, ou qu un serveur, soit accessible depuis l extérieur, deux possibilités s offrent : créer un contexte permanent sur le routeur d accès. Généralement, en se connectant sur la box via son interface web de configuration, il est possible de définir un port externe et d indiquer vers quel machine et quel port en interne le trafic devra être traduit et dirigé. Ainsi dans l exemple figure 2.5 page 22, si l on veut que PC4 offre un service web accessible depuis l extérieur, il faudra configurer le NAT pour que le trafic entrant avec le port 80 soit dirigé vers PC4, le port 80 pouvant être conservé. Si le site privé dispose de plusieurs serveurs web, ils devront être accessible depuis l extérieur sur un numéro de port différent. La création de contexte peut être automatisée par l utilisation de protocole comme UPnP (Universal Plug and Play) permettant aux applications d ouvrir des ports sur le NAT. Si cela simplifie la mise en œuvre, cela rend les machines plus vulnérables. 34
Définir une zone démilitarisée (DMZ : Demilitarized Zone. Ceci n est pas valable sur tous les équipements, mais le principe est simple, tout les paquets entrant dont le numéro de port destination n est pas dans le contexte du NAT seront dirigé vers un machine particulière. Evidemment cette machine est beaucoup plus sensible aux attaques vu qu elle peut être considérée comme directement connectée sur Internet. Un inconvénient du NAT est que l on change au niveau 3 d espace de nommage, mais que cela reste transparent pour les applications. Ainsi si une application envoie dans les données son adresse IP (par exemple, pour être jointe ultérieurement) le récepteur ne pourra pas la contacter car il peut s agir s une adresse privée. Une règle d ingénierie des protocoles pour être le plus transparent possible au NAT est de prendre l adresse IP contenue dans l en-tête du paquet et de ne pas envoyer l adresse dans les données. 2.8 Compteur distant Puisqu une des forces d Arduino est de pouvoir interagir avec le monde extérieur, nous allons écrire un programme qui enverra une requête HTTP vers un serveur quand un interrupteur sera activé relié à la broche A0. Nous allons utiliser sur le serveur un petit programme PHP qui compte le nombre de requêtes sur une page donnée (cf Listing 2.8). Ce programme est à mettre dans le répertoire où se trouvent les pages du serveur, typiquement /var/www sous Ubuntu. 1 <?php 2 $count my page = ( h i t c o u n t e r. t x t ) ; 3 $ h i t s = f i l e ( $count my page ) ; 4 $ h i t s [ 0 ] = $ h i t s [ 0 ] + 1 ; ; 5 $fp = fopen ( $count my page, w ) ; 6 f p u t s ( $fp, $ h i t s [ 0 ] ) ; 7 f c l o s e ( $fp ) ; 8 echo $ h i t s [ 0 ] ; 9?> Listing 2.8 Script PHP de comptage d accès aux pages Un script PHP commence par la séquence <?php (ligne 1) et se termine par?>. Ligne 2, le nom du fichier hitcounter.txt contenant la dernière valeur du compteur est stockée dans la variable $count my page. Ce fichier doit se trouver dans le même répertoire que le script et être accessible en lecture écriture pour le serveur web, typiquemet accessible pour l utilisateur www-data pour Ubuntu. Ligne 3, le contenu du fichier précédemment nommé est stocké dans la variable $hits. Comme ce fichier ne comporte qu un seul élément correspondant au nombre de requêtes, cette valeur sera accessible en utilisant le premier élément $hits[0]. La valeur est incrémentée ligne 4 puis le fichier est ouvert en lecture (ligne 5) et le résultat y est stocké (ligne 6) avant d être fermé (ligne 7). Ligne 8 le résultat est affiché, ce sera la réponse aux requêtes HTTP. Bien qu il reprenne une grande partie des concepts vu dans au programme 2.6 page 28, ce programme Arduino (cf. Listing 2.9 page suivante) est plus complexe car plusieurs 35
événements peuvent arriver simultanément, soit un changement d état de la broche A0, soit une réponse du serveur web distant. Pour gérer ce parallélisme d événements, une variable permettra de réagir en fonction des événements et de l état dans lequel se trouve le programme. Ainsi, 3 états peuvent être définis : 1. Attente que l utilisateur appuie sur l interrupteur. Quand cet événement est détecté, une connexion est établie avec le serveur et l on passe dans le deuxième état. 2. Attente que le serveur distant envoie la réponse. Tant que la connexion reste ouverte avec le serveur distant, le programme attend la réponse et l affiche. Lorsque la connexion se perd, le programme retourne dans l état 1 si l interrupteur n est plus appuyé ou dans l état 3 sinon. 3. Attente que l utilisateur relâche l interrupteur. Le programme reste dans cet état tant que l interrupteur est appuyé puis revient dans l état 1. La figure 2.9 représente l automate à états finis décrivant le programme. Les états sont représenté par des rectangles aux cotés arrondis. Les transitions par des flèches. Les événements qui vont déclencher les changements d état sont représentés en blanc sur fond noir avec les actions associées lors de ce changement d état. réponse du serveur Afficher le résultat sur le port série Attente que le serveur distant envoie la réponse fermeture de la connexion et Interrupteur appuyé libérer ressources Interrupteur appuyé ouvrir connexion avec le serveur, envoyer requête Attente que l utilisateur relâche l interrupteur fermeture de la connexion et Interrupteur relaché libérer ressources Attente que l utilisateur appuie sur l interrupteur Interrupteur relaché FIGURE 2.9 Automate à états finis représentant le programme 2.9 1 # i n c l u d e <SPI. h> 2 # i n c l u d e <E t h e r n e t. h> 3 4 b y t e mac [ ] = { 0x90, 0xA2, 0xDA, 0x0D, 0x6F, 0x30 } ; 5 6 E t h e r n e t C l i e n t c l i e n t ; 7 8 c o n s t i n t a n a l o g I n P i n = A0 ; 9 10 enum C l i e n t S t a t e { waitup, waitdown, waitresp } CS ; 11 12 void setup ( ) { 36
13 S e r i a l. b e g i n ( 9 6 0 0 ) ; 14 E t h e r n e t. b e g i n ( mac ) ; 15 CS= waitup ; 16 } 17 18 void loop ( ) { 19 i n t v a l u e = analogread ( a n a l o g I n P i n ) ; 20 21 s w i t c h ( CS ) { 22 c a s e waitup : 23 S e r i a l. p r i n t ( v a l u e ) ; S e r i a l. p r i n t l n ( waitup ) ; 24 25 i f ( v a l u e == 1023) { 26 i f ( c l i e n t. c o n n e c t ( ks. t o u t a. i n, 8 0 ) ) { 27 S e r i a l. p r i n t l n ( c o n n e c t e d ) ; 28 c l i e n t. p r i n t l n ( GET / compteur HTTP / 1. 0 ) ; 29 c l i e n t. p r i n t l n ( ) ; 30 31 CS= waitresp ; 32 33 } e l s e { 34 S e r i a l. p r i n t l n ( c o n n e c t i o n f a i l e d ) ; 35 } 36 } 37 b r e a k ; 38 39 c a s e waitresp : 40 i f ( c l i e n t. a v a i l a b l e ( ) ) { 41 c h a r c = c l i e n t. r e a d ( ) ; 42 S e r i a l. p r i n t ( c ) ; 43 } 44 45 i f (! c l i e n t. c o n n e c t e d ( ) ) { 46 S e r i a l. p r i n t l n ( d i s c o n n e c t i n g. ) ; 47 c l i e n t. s t o p ( ) ; 48 49 i f ( v a l u e == 1023) CS = waitdown ; e l s e CS = waitup ; 50 } 51 b r e a k ; 52 53 c a s e waitdown : 54 S e r i a l. p r i n t ( v a l u e ) ; S e r i a l. p r i n t l n ( waitdown ) ; 55 i f ( v a l u e < 1023) CS =waitup ; 56 b r e a k ; 57 } 58 } Listing 2.9 Appel de la page compteur Le programme commence comme le programme 2.6 page 28 en décrivant l adresse Ethernet et la création de l objet client. La ligne 8 crée l entier analoginpin et lui affecte la valeur A0. Cette variable permettra de lire l entrée analogique 0 et dira si l interrupteur est appuyé ou non. Pour décrire l automate, les différents états sont définis dans une structure enum dont CS contiendra une des trois valeurs possibles (ligne 10). Dans la procédure d initialisation, 37
CS sera mis dans l état d attente d un appuis de l interrupteur (ligne 15). Dans la boucle, la valeur de l entrée analogique A0 est lue. Cela correspond à une valeur comprise entre 0 (l entrée est à la masse) à 1023 (l entrée est connecté à une tension de 3.3 V). Quand l interrupteur est appuyé la valeur est donc de 1023. Ligne 21 commence le switch qui va permettre de décrire tous les états de l automate et dans chacune des entrées les événements seront testés. Lignes 22 à 37, l appuis sur l interrupteur est testé, si la valeur de l entrée passe à 1023 alors la connexion est ouverte avec le serveur et la requête est envoyée vers http://ks.touta.in/compteur. Le programme passe dans l état d attente de réponse. En cas d échec de la connexion, le programme reste dans le même état. Dans l état attente de données, si des données sont présentes, elles sont affichées (lignes 40 à 43), Si la connexion est coupée, l état de l entrée analogique est testée, si la valeur est de 1023 on passe dans l état waitdown sinon le programme revient dans l état waitup. Le listing suivant donne le résultat de l exécution du programme 2.9 page 36. Pour mieux montrer le fonctionnement de l automate, les états waitup et waitdown sont indiqués avec la valeur collectée sur la broche A0. 467 waitup 460 waitup 458 waitup 463 waitup 1023 waitup c o n n e c t e d HTTP / 1. 1 200 OK Date : Sat, 04 May 2013 1 6 : 2 3 : 1 2 GMT S e r v e r : Apache / 2. 2. 2 2 ( Ubuntu ) Content L o c a t i o n : compteur. php Vary : n e g o t i a t e, Accept Encoding TCN: c h o i c e X Powered By : PHP/5.3.10 1 ubuntu3. 6 Content Length : 4 C o n n e c t i o n : c l o s e Content Type : t e x t / html 96 d i s c o n n e c t i n g. 1023 waitdown... 1023 waitdown 1015 waitdown 1011 waitup 1011 waitup 1006 waitup 998 waitup 993 waitup... 1023 waitup c o n n e c t e d HTTP / 1. 1 200 OK 38
Date : Sat, 04 May 2013 1 6 : 2 3 : 1 8 GMT S e r v e r : Apache / 2. 2. 2 2 ( Ubuntu ) Content L o c a t i o n : compteur. php Vary : n e g o t i a t e, Accept Encoding TCN: c h o i c e X Powered By : PHP/5.3.10 1 ubuntu3. 6 Content Length : 4 C o n n e c t i o n : c l o s e Content Type : t e x t / html 97 d i s c o n n e c t i n g. 1023 waitdown... 2.9 Thermomètre Traditionnellement, un programme pour Arduino doit pouvoir faire clignoter des LED. Nous avions pour le moment résisté, mais pour finir ce chapitre, nous allons écrire un programme plus complexe qui va allumer une LED d une certaine couleur en fonction de la température d un lieu. Pour se faire nous allons réaliser le montage représenté sur la photo figure 2.10. FIGURE 2.10 Montage d un Arduino Ethernet Comme la lisibilité sur une photo est médiocre, il est préférable d utiliser une représentation schématique. Il existe une convention pour la représentation des fils électrique : le noir représente la masse, le rouge une tension continue. Les autres couleurs peuvent être utilisées sans contraintes. Ici elles sont en relation avec la couleur des LED. 39
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Ethernet SCL SDA AREF GND 13 12 11 10 9 8 7 6 5 4 Digital (PWM ) 3 2 T X 1 RX 0 ICSP RESET RX TX +5 GND USB power Power IOREF RESET 3.3V 5V GND GND Vin Analog IN A0 A1 A2 A3 A4 A5 FIGURE 2.11 Représentation schématique du montage 2.10 Ce montage représenté 2.11 ne comporte aucune difficulté particulière en particulier grâce à l utilisation d une plaque sans soudure (breadboard). L espacement permet de mettre des composants standards. Les connecteurs placées sur les deux rangées extérieures sont connectées horizontalement, ce qui permet d avoir une alimentation en courant continu et la masse. Les colonnes du milieu sont connectées verticalement. La seule difficulté du montage concerne la polarité des LED. Comme toutes diodes, elles ne laissent passer le courant que dans un sens. La figure 2.12 représente une LED, le pôle négatif (la cathode) peut être repéré par un plat sur la surface bombée, un connecteur plus court et en regardant en transparence par la plus grande partie intérieure. Dans notre cas, la cathode doit donc être connecté à la masse. Cathode (-) Anode (+) FIGURE 2.12 Format d une LED Pour connaître la température pour une ville donnée, nous allons utiliser les services de Yahoo!. La page web http://developer.yahoo.com/weather/ explique son fonctionnement. Il faut demander l URL http://weather.yahooapis.com/forecastrss 40
en précisant deux paramètres w=localisation et u=unité, où localisation est le code de la ville dont on veut connaître la météo. Pour obtenir facilement cet valeur, il suffit d aller sur la page weather.yahoo.com, de rentrer le nom d une ville et d analyser l URL retournée. Par exemple, pour Rennes, la valeur est 619163, comme le montre la figure 2.13. Les unités sont soit f pour Fahrenheit et c pour Celsius. FIGURE 2.13 Détermination du code de la ville Le résultat suivant est retourné par un navigateur quand l URL http://weather. yahooapis.com/forecastrss?w=619163&u=c : 1 <r s s xmlns : y w e a t h e r = h t t p : / / xml. w e a t h e r. yahoo. com / ns / r s s / 1. 0 2 xmlns : geo= h t t p : / / www. w3. org / 2 0 0 3 / 0 1 / geo / wgs84 pos # v e r s i o n = 2. 0 > 3 <channel> 4 <t i t l e >Yahoo! Weather Rennes, FR</ t i t l e > 5 <l i n k> 6 h t t p : / / us. rd. yahoo. com / d a i l y n e w s / r s s / w e a t h e r / Rennes FR / h t t p : / / w e a t h e r. yahoo. com / f o r e c a s t / FRXX0114 c. html 7 </ l i n k> 8 <description>yahoo! Weather for Rennes, FR</ description> 9 <language>en us </language> 10 <lastbuilddate>sat, 01 Jun 2013 12:59 pm CEST</ lastbuilddate> 11 <t t l >60</ t t l > 12 <y w e a t h e r : l o c a t i o n c i t y = Rennes r e g i o n = c o u n t r y = F r a n c e /> 13 <y w e a t h e r : u n i t s t e m p e r a t u r e = C d i s t a n c e = km p r e s s u r e = mb speed = km / h /> 14 <y w e a t h e r : wind c h i l l = 17 d i r e c t i o n = 340 speed = 1 6. 0 9 /> 15 <y w e a t h e r : a t m o s p h e r e h u m i d i t y = 68 v i s i b i l i t y = 9. 9 9 p r e s s u r e = 1015.92 r i s i n g = 1 /> 16 <y w e a t h e r : astronomy s u n r i s e = 6:10 am s u n s e t = 9:57 pm /> 17 <image> 18 <t i t l e >Yahoo! Weather </ t i t l e > 19 <width >142</width> 20 <h e i g h t >18</h e i g h t> 21 <l i n k>h t t p : / / w e a t h e r. yahoo. com</ l i n k> 22 <u r l> 23 h t t p : / / l. yimg. com / a / i / brand / p u r p l e l o g o / / uh / us / news wea. g i f 24 </ u r l> 25 </image> 26 <item> 27 <t i t l e >C o n d i t i o n s f o r Rennes, FR a t 12:59 pm CEST</ t i t l e > 28 <geo : lat >48.11</geo : lat> 29 <geo : long > 1.68</geo : long> 30 <l i n k> 31 h t t p : / / us. rd. yahoo. com / d a i l y n e w s / r s s / w e a t h e r / Rennes FR / h t t p : / / w e a t h e r. yahoo. com / f o r e c a s t / FRXX0114 c. html 32 </ l i n k> 33 <pubdate>sat, 01 Jun 2013 12:59 pm CEST</pubDate> 34 <yweather : condition t e x t = Mostly Cloudy code= 28 temp= 17 date= Sat, 01 Jun 2013 12:59 pm CEST /> 35 <d e s c r i p t i o n > 36 <![CDATA[ 37 <img s r c = h t t p : / / l. yimg. com / a / i / us / we / 5 2 / 2 8. g i f /><br /> <b>c u r r e n t C o n d i t i o n s :</b><br /> Mostly Cloudy, 17 C 38 <BR /> 39 <BR /><b>forecast :</b><br /> Sat Mostly Sunny. High : 17 Low : 8<br /> 40 Sun P a r t l y Cloudy. High : 19 Low : 7<br /> <br /> 41 <a h r e f = h t t p : / / us. rd. yahoo. com / d a i l y n e w s / r s s / w e a t h e r / Rennes FR / h t t p : / / w e a t h e r. yahoo. com / f o r e c a s t / FRXX0114 c. html > 42 Full Forecast at Yahoo! Weather</a><BR/><BR/> ( provided by <a href = h t t p : / / www. weather. com >The Weather Channel </a>) 43 <br/> 44 ]]> 45 </ d e s c r i p t i o n > 46 <y w e a t h e r : f o r e c a s t day= S a t d a t e = 1 Jun 2013 low= 8 h igh = 17 t e x t = Mostly Sunny code= 34 /> 47 <y w e a t h e r : f o r e c a s t day= Sun d a t e = 2 Jun 2013 low= 7 h igh = 19 t e x t = P a r t l y Cloudy code= 30 /> 48 <guid ispermalink= f a l s e >FRXX0114 2013 06 02 7 00 CEST</guid> 49 </item> 50 </channel> 41
51 </ r s s> 52 <! 53 a p i 5. weather. ch1. yahoo. com Sat Jun 1 1 1 :3 5 :4 5 PST 2013 54 > Listing 2.10 Réponse codée en XML Les informations retournées ne sont pas au format HTML comme nous l avions vu dans les exemples précédents (par exemple Listing 2.7 page 30). Ici la réponse est structurée suivant le format XML qui permet une représentation universelle des valeurs échangées car basée sur les caractère ASCII. Comme pour HTML dont il est dérivé, un format XML contient un ensemble de balises (tags) identifié par le nom de la balise entre les symboles < et > et terminé par la même séquence, mais la balise est précédée du caractère /. Les balises peuvent s emboîter comme le montre, par exemple, les lignes 17 à 25 du listing 2.10 page précédente qui définissent les valeurs de la balise image, qui est elle-même composée de balises title, width, height, link et url. Une autre méthode pour transporter des valeurs est d utiliser des champs dans les description de la balise, comme ligne 15 du listing 2.10 page précédente. Pour rendre la notation plus compacte, il est possible de terminer par le caractère / au lieu de répéter deux fois le nom de la balise. L information qui nous intéresse se trouve à la ligne 34 du listing 2.10 page précédente, le champ temp="17" donne la température qu il faisait à Rennes au moment de la requête. Il va falloir l extraire pour pouvoir la traiter dansle programme Arduino. Suivant sa valeur, une des LED sera allumée. Sous Linux, il existe des bibliothèques qui à partir des valeurs contenues dans un réponse XML peuvent reconstruire une structure de données utilisable par l ordinateur. Malheureusement ces bibliothèques sont assez volumineuses et ne peuvent pas tenir dans la mémoire d un Arduino. De plus, il faut stocker la réponse en mémoire ce qui réduit encore plus l espace disponible. Nous allons traiter à la volée l information, c est-à-dire que nous allons rechercher caractère par caractère la chaîne temp=", puis prendre les chiffres qui suivent pour les transformer en une valeur numérique. Le programme est basé également sur un automate à états finis qui représente les différentes étapes du programme : Le client envoie une requête HTTP vers le serveur (état CFREQ) le client analyse la réponse pour trouver la chaîne de caractères souhaitée (état CFTAG) le client prend la valeur numérique qui suit pour l afficher (état CVVALUE) le client finit de traiter les données reçues pour fermer la connexion. (état CFSKIP) le client attend 60 secondes avant de recommencer la procédure. (état CFTEMPO) Auquel s ajoute un état de traitement d erreurs (état CFERROR) qui va faire clignoter les LEDs avant de retenter d envoyer une requête. La figure 2.14 page suivante décrit cet automate. Pour faciliter la visualisation des états, les LEDS seront allumées différemment à chaque étape. Le programme se décompose en deux fichiers. Le fichier d include Comp temp.h (cf. listing 2.11 page ci-contre) contient l énumération qui va servir à représenter les états de l automate, ceci pour contourner un problème qui empêche de déclarer directement des fonctions dans le fichier principal qui manipulent ces énumérations. 42
SETUP CFTEMPO fin du timer fin du timer CFREQ fin de connexion CFSKIP CFERROR fin de connexion fin de connexion erreur ouverture CFTAG Envoie URL réussi. Valeur trouvée et affiché sur les LED CFVALUE Tag trouvé dans la réponse FIGURE 2.14 Automate du traitement d une page XML 1 enum S e a r c h F o r {CFREQ, / / d o i t envoyer une r e q u e t e 2 CFTAG, / / en r e c h e r c h e de l a c h a i n e de c a r. 3 CFVALUE, / / t a g t r o u v e, r e c u p e r e l a v a l e u r 4 CFSKIP, / / f i n i de l i r e l e r e s t e de l a r e p o n s e 5 CFERROR, / / Quelque chose va de t r a v e r s 6 CFTEMPO / / a t t e n t e a v a n t n o u v e l l e r e q u e t e 7 } ; / / E t a t 8 9 void changecf ( S e a r c h F o r newcf ) ; Listing 2.11 Comp temp.h Le programme principal est décrit listing 2.12. 1 # i n c l u d e <SPI. h> 2 # i n c l u d e <E t h e r n e t. h> 3 # i n c l u d e Comp temp. h 4 5 S e a r c h F o r CF = CFREQ; / / e t a t du programme dans l a u t o m a t e 6 7 # d e f i n e RLED 0 x01 8 # d e f i n e OLED 0 x02 9 # d e f i n e GLED 0 x04 10 11 b y t e mac [ ] = { 0x90, 0xA2, 0xDA, 0x0D, 0x6F, 0x30 } ; 12 13 E t h e r n e t C l i e n t c l i e n t ; 14 15 c h a r l o o k f o r = temp =\ ; / / c h a i n e r e c h e r c h e e 16 i n t i d x =0; / / nombre de c a r a c t e r e s t r o u v e s 17 i n t t e m p e r a t u r e =0; / / s t o c k e l a temp. r e t o u r n e e dans l e XML 18 i n t s t r i n g S i z e ; 43
19 20 / / d e f i n i l e PIN a s s o c i e a l a LED 21 i n t redled = 2 ; 22 i n t orangeled =3; 23 i n t greenled =4; 24 25 void switchled ( i n t LEDS) { 26 i f (LEDS & RLED) { d i g i t a l W r i t e ( redled, HIGH ) ; } 27 e l s e { d i g i t a l W r i t e ( redled, LOW) ; } 28 29 i f (LEDS & OLED) { d i g i t a l W r i t e ( orangeled, HIGH ) ; } 30 e l s e { d i g i t a l W r i t e ( orangeled, LOW) ; } 31 32 i f (LEDS & GLED) { d i g i t a l W r i t e ( greenled, HIGH ) ; } 33 e l s e { d i g i t a l W r i t e ( greenled, LOW) ; } 34 } 35 36 void p r i n t C F ( ) { 37 s w i t c h ( CF ) { 38 c a s e CFREQ : S e r i a l. p r i n t ( CFREQ ) ; b r e a k ; 39 c a s e CFTAG : S e r i a l. p r i n t ( CFTAG ) ; b r e a k ; 40 c a s e CFVALUE : S e r i a l. p r i n t ( CFVALUE ) ; b r e a k ; 41 c a s e CFSKIP : S e r i a l. p r i n t ( CFSKIP ) ; b r e a k ; 42 c a s e CFERROR : S e r i a l. p r i n t ( CFERROR ) ; b r e a k ; 43 c a s e CFTEMPO : S e r i a l. p r i n t ( CFTEMPO ) ; b r e a k ; 44 } 45 S e r i a l. p r i n t ( ) ; 46 } 47 48 void changecf ( S e a r c h F o r newcf ) { 49 p r i n t C F ( ) ; S e r i a l. p r i n t ( => ) ; 50 CF = newcf ; 51 p r i n t C F ( ) ; 52 S e r i a l. p r i n t l n ( ) ; 53 } 54 55 void setup ( ) { 56 S e r i a l. b e g i n ( 9 6 0 0 ) ; 57 58 pinmode ( redled, OUTPUT ) ; 59 pinmode ( orangeled, OUTPUT ) ; 60 pinmode ( greenled, OUTPUT ) ; 61 62 switchled (RLED OLED GLED ) ; 63 64 E t h e r n e t. b e g i n ( mac ) ; 65 S e r i a l. p r i n t l n ( E t h e r n e t. l o c a l I P ( ) ) ; 66 67 s t r i n g S i z e = s t r l e n ( l o o k f o r ) ; 68 } 69 70 void loop ( ) { 71 c h a r c ; 72 73 s w i t c h ( CF ) { 44
74 c a s e CFREQ: 75 t e m p e r a t u r e =0; 76 switchled (RLED OLED ) ; 77 78 i f ( c l i e n t. c o n n e c t ( w e a t h e r. y a h o o a p i s. com, 8 0 ) ) { 79 S e r i a l. p r i n t l n ( c o n n e c t e d ) ; 80 c l i e n t. p r i n t l n ( GET / f o r e c a s t r s s?w=12724564&u=c HTTP / 1. 0 ) ; 81 c l i e n t. p r i n t l n ( Host : w e a t h e r. y a h o o a p i s. com ) ; 82 83 c l i e n t. p r i n t l n ( ) ; 84 85 changecf (CFTAG ) ; 86 switchled (RLED ) ; 87 88 } e l s e { 89 S e r i a l. p r i n t l n ( c o n n e c t i o n f a i l e d ) ; 90 CF = CFERROR; 91 } 92 b r e a k ; 93 94 c a s e CFTAG: / / on r e c h e r c h e l e s c a r a c t e r e s 95 i f (! c l i e n t. a v a i l a b l e ( ) ) b r e a k ; 96 97 c = c l i e n t. r e a d ( ) ; 98 S e r i a l. p r i n t ( c ) ; S e r i a l. p r i n t ( i d x ) ; 99 100 i f ( c == l o o k f o r [ i d x ] ) { / / s i un c a r a c t e r e e s t t r o u v e 101 i d x ++; / / on r e c h e r c h e l e s u i v a n t 102 i f ( i d x == s t r i n g S i z e ) { / / s i on a t o u t t r o u v e 103 changecf (CFVALUE ) ; / / change d e t a t pour p r e n d r e l a v a l e u r 104 105 switchled (0 x00 ) ; / / i n d i q u e l e TAG e s t t r o u v e 106 } 107 } e l s e { 108 i d x =0; / / s i n o n on r e v i e n t a c h e r c h e r l e 109 } / / p r e m i e r c a r a c t e r e. 110 b r e a k ; 111 112 c a s e CFVALUE: 113 i f (! c l i e n t. a v a i l a b l e ( ) ) b r e a k ; 114 115 c = c l i e n t. r e a d ( ) ; 116 S e r i a l. p r i n t ( c ) ; S e r i a l. p r i n t ( + ) ; 117 118 i f ( ( c >= 0 x30 ) & ( c <= 0x39 ) ) { / / code ASCII d un c h i f f r e 119 t e m p e r a t u r e = 1 0 ; / / on d e c a l e d une d i z a i n e 120 t e m p e r a t u r e += ( c 0x30 ) ; / / on a d d i t i o n n e l e c h i f f r e 121 } e l s e { / / pas un c h i f f r e on a f i n i 122 S e r i a l. p r i n t ( T emperature = ) ; S e r i a l. p r i n t l n ( t e m p e r a t u r e ) ; 123 124 i f ( t e m p e r a t u r e < 0) switchled (RLED ) ; 125 i f ( ( t e m p e r a t u r e >= 0) & ( t e m p e r a t u r e <10)) switchled (OLED ) ; 126 i f ( t e m p e r a t u r e >= 10) switchled (GLED ) ; 127 128 changecf ( CFSKIP ) ; 45
129 } 130 b r e a k ; 131 132 c a s e CFSKIP : 133 i f (! c l i e n t. a v a i l a b l e ( ) ) b r e a k ; 134 135 c = c l i e n t. r e a d ( ) ; 136 S e r i a l. p r i n t ( c ) ; S e r i a l. p r i n t ( X ) ; 137 b r e a k ; 138 139 c a s e CFERROR: 140 c l i e n t. s t o p ( ) ; 141 f o r ( i n t i =0; i < 100; i ++) { 142 switchled ( i ) ; 143 d e l a y ( 1 0 0 ) ; 144 } 145 changecf (CFREQ ) ; 146 b r e a k ; 147 148 c a s e CFTEMPO: 149 c l i e n t. s t o p ( ) ; 150 d e l a y ( 6 0 0 0 0 ) ; 151 changecf (CFREQ ) ; 152 b r e a k ; 153 } 154 155 i f (! c l i e n t. c o n n e c t e d ( ) ) { 156 S e r i a l. p r i n t l n ( Not Connected ) ; 157 158 i f ( CF==CFTAG) changecf ( CFERROR ) ; 159 i f ( CF==CFVALUE) changecf ( CFERROR ) ; 160 i f ( CF==CFSKIP ) changecf (CFTEMPO ) ; 161 } 162 } Listing 2.12 Affichage de la température Les LEDs sont réprésentées de deux manières dans le programme : par une valeur binaire comme l indique les #define lignes 7 à 9. Chaque LED est représenté par un bit, cela permettra d utiliser la fonction switchled, lignes 25 à 34 pour les allumer et les éteindre. Avoir utilisé une fonction permet de réduire la taille du code compilé car il pourra être appelé génériquement à plusieurs étapes du programme. Pour indiquer la LED à allumer, un ou logique est utilisé (opérateur ). Ainsi switchled (RLED OLED) allume les LEDS rouge et orange. en associant la broche de sortie (pin) à une LED, lines 21 à 23. La fonction arduino digitalwrite permet de les allumer ou de les éteindre suivant que son second argument est HIGH ou LOW. Les broches sont initialisées pour être utilisées en sortie dans la fonction d initialisation (setup) lignes 58 à 60. Pour permettre de comprendre le fonctionnement du programme, le port série (USB) est utilisé pour afficher des messages de débogage. En particulier, les changements d états de l automate sont indiqués. Deux fonctions sont nécessaire : void printcf() indique dans quel état se trouve l automate (i.e. la valeur de la variable globale CF. 46
void changecf(searchfor) qui prend en argument le nouvel état dans lequel doit passer l automate. L initialisation est classique, les broches dédiées aux LED sont déclarées utilisées pour des sorties, les 3 LEDs sont allumées et l initialisation de la pile réseau est réalisée. La LED verte s éteint quand le programme quitte la phase d initialisation et entre dans la boucle, puisque l automate est au démarrage du programme est dans l état CFREQ (ligne 76). La variable stringsize est initialisée à la longueur de la chaîne de caractère recherchée. Cette initialisation doit se faire ici, car strlen est une fonction. La boucle contient les actions à réaliser pour chaque étapes de l automate : dans l état CFREQ, la connexion est ouverte avec la machine weather.yahooapis.com. A noter que la requête est un peu plus complète que dans les exemples précédents. En effet, un serveur peut être virtualisé, c est-à-dire servir plusieurs sites différents à partir de la même adresse IP (que l on obtient par résolution via le DNS du nom). Pour pouvoir distinguer les serveurs, la ligne Host: weather.yahooapis.com est nécessaire (ligne 81). dans l état CFTAG. Il faudrait dans l absolu analyser tout le fichier XML, comprendre sa structure et recherche la variable dans le tag yweather:condition, mais ceci serait relativement coûteux, vu le peu de mémoire dont dispose d arduino Uno. L approche adoptée est beaucoup plus simpliste, mais est adapté à ce type de page XML. La séquence de caractères temp=" est recherchée dans toute la réponse, comme elle n apparaît qu à l endroit souhaité, cela fonctionne correctement. Sur le terminal, la recherche est décrite, après chaque caractère reçu, l indice du caractère recherché est indiqué. Le listing 2.13 page suivante montre l effet de l algorithme sur la ligne 13 de la réponse XML (cf. listing 2.10 page 41) où le mot temperature apparaît. Quand le t apparaît l indice est incrémenté, mais quand un e est trouvé à la place d un caractère = celui-ci repasse à 0. 11. dans l état CFVALUE, puisque l on a recherché la chaîne jusqu au caractère ", les caractères qui suivent sont des chiffres. Il suffit de les additionner jusqu à ce que l on trouve une valeur non numérique. Les chiffres sont codés en ASCII, pour trouver leur vrai valeur numérique, il suffit de leur retrancher la valeur hexadécimale 0x30. En fonction de la valeur trouvée, une des LED est allumée. dans l état CFSKIP le reste des caractères est lu pour arriver en fin de réponse. Sur la liaison série, cela se traduit par des X à la place des valeurs numérique. Le listing 2.14 page suivante montre le moment où la chaîne temp=" est trouvée. Le fait de lire tout le texte va faire qu à la fin le client ne sera plus connecté (lignes 158 à 161). Suivant l état dans lequel était l automate cela va conduire à un comportement différent. Si cela arrive dans l état CFSKIP, il s agit d un comportement normal, dans tous les autres cas, il s agit d une erreur parque soit la séquence n a pas été trouvée, ou il y a une erreur dans la valeur numérique. dans l état CFTEMPO, les LED ne sont pas modifiées ce qui permet de conserver 11. Pour être plus générique, il faudrait autoriser des espaces autour du caractère =, mais dans ce cas ce n est pas nécessaire. 47
l affichage pour 60 000 millisecondes grâce à la fonction arduino delay. dans l état CFERROR, l allumage des LEDs est piloté par la variable i de la boucle for. Cela permet d avoir un clignotement caractéristique. 1 0<0y0w0e0a0t0h1e0r0 : 0 u0n0i0t0s1 0 t0e1m2p3e4r0a0t0u1r0e0 =0.... 1 t0e1m2p3=4 5CFTAG =>CFVALUE 2 1+6+ + Temperature = 16 3 CFVALUE =>CFSKIP 4 X XdXaXtXeX=X XSXuXnX,X Listing 2.13 Recherche de temp Listing 2.14 temp Question 3 Peut-on chercher plusieurs chaînes de caractères simultanément? Quelles modifications doit-on apporter à l automate? Modifier le programme pour qu il affiche sur le port série le taux d humidité. 48