2 année STI - libpfb.so

2 e année STI
Réseaux non filaires
Communication & MANET
Communication dans un MANet basé sur des Raspberry Pi & radio nRF24L01
Gestion des interruptions sous Raspberry Pi
Le composant nRF24L01 est capable de déclencher une IRQ sur le matériel auquel il est connecté,
afin de l’avertir des 2 situations suivantes :
. envoi réussi ;
. trame reçue et disponible ;
. échec de l’envoi à l’issu du nombre total de réémission ;
Pour gérer ces interruptions, nous utiliserons la bibliothèque WiringPi, écrite par Gordon Henderson,
et nous l’installerons de la façon suivante :
$ git clone git://git.drogon.net/wiringPi
$ cd wiringPi
$ ./build
Au niveau connectique, nous connecterons la broche IRQ du composant nRF24L01 à la broche « GPIO
Pin 17 » du Raspberry.
L’IRQ sera détectée par un « front descendant » sur cette broche :
1
2
3
4
5
6
7
8
if (wiringPiSetup () < 0) {
fprintf (stderr, "Unable to setup wiringPi: %s\n", strerror (errno));
return 1;
...
if ( wiringPiISR (IRQ_PIN, INT_EDGE_FALLING, &interruption) < 0 ) {
fprintf (stderr, "Unable to setup ISR: %s\n", strerror (errno));
return 1;
}
Création d’un programme de « chat » entre Raspberry PI & nRF24L01
Nous allons écrire un programme de dialogue entre deux terminaux mobiles où chaque terminal pourra
communiquer avec l’autre de manière asynchrone.
Grâce à l’utilisation de l’IRQ, nous pouvons concevoir le programme de la manière suivante :
1. le composant radio nRF24L01 est configuré :
choix du canal de communication ;
de la puissance d’émission ;
du nombre de tentative de réémission en cas d’échec ;
des adresses source et destination (pour la bibliothèque RF24, le lien est un « pipe ») ;
// Setup for GPIO 22 CE and CE1 CSN with SPI Speed @ 8Mhz
RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_26, BCM2835_SPI_SPEED_8MHZ);
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
int main(int argc, char** argv)
{
// Setup and configure rf radio
radio.begin();
radio.setRetries(15,15);
radio.setChannel(0x4c);
radio.setPALevel(RF24_PA_LOW);
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
2. le traitement de l’IRQ est positionné sur une fonction ne traitant que de la réception d’un message ;
Resp. UE : P-F. Bonnefoi, http://libpfb.so/, « Communication & MANET » version du 13 mars 2014, rédigé avec ConTEXt – Don’t Panic !
1/4
3. le programme effectue une boucle sur l’entrée clavier pour lire un message en provenance de l’utilisateur :
bascule du composant radio nRF24L01 du mode écoute en mode envoi ;
paramètrage de la gestion de l’interruption : ignorer la gestion d’IRQ liée à la réception (impossible dans le mode émetteur) ;
envoi du message et gestion des acquittements/réémissions automatiques grâce au mode
« Shockburst TM » du composant ;
retour dans le mode réception ;
4. lors de la réception d’une IRQ liée à la réception d’un message :
affichage du message reçue ;
réinitialisation du mode de réception :
1
2
3
radio.read(message, sizeof(char)*32);
radio.startListening();
fprintf(stderr,"%s", message);
Encapsulation du « chat » dans Python
Il est possible de contrôler le programme de chat conçu précédemment dans un programme Python
pour lui permettre de contrôler les messages en entrée comme en sortie du module radio, grâce au code
suivant :
1
#!/usr/bin/python
3
import subprocess, os, pty
5
p = subprocess.Popen(["./chat_rf"],stderr=subprocess.PIPE,stdin=subprocess.PIPE,bufsize=0)
7
pid = os.fork()
9
if pid :
while(1):
ligne = p.stderr.readline()
print ligne.rstrip(’\n’)
else :
while(1):
ligne = raw_input()
p.stdin.write(ligne+’\n’)
10
11
12
13
14
15
16
On utilise le cacanl de sortie d’erreur qui est non bufferisé.
Resp. UE : P-F. Bonnefoi, http://libpfb.so/, « Communication & MANET » version du 13 mars 2014, rédigé avec ConTEXt – Don’t Panic !
2/4
Travail
1 – Vous étudierez :
a. l’utilisation du canal de communication : partage ou non entre tous les terminaux présents dans la
salle de TP ;
b. l’usage des adresses d’émission et de réception des messages :
possibilité de broadcast ?
gestion des collisions ?
L’acquittement automatique est associé au message émis par l’adresse destination qu’il contient.
c. La gestion de l’IRQ et des bascule « mode émetteur »/« mode récepteur » ;
d. les possibilités de routage :
réseau « single hop » vs « multi-hop » ;
portée radio/découverte des voisins/relais des échanges.
2 – Vous écrirez un programme Python permettant de faire des échanges sécurisés :
a. vous définierez un format de message (les messages sont limitées à 32 octets) contenant :
le nom de l’expéditeur : 6 octets ;
le nom du destinataire : 6 octets ;
le contenu du message sur au plus 20 octets ;
b. vous testerez l’envoi et la réception de vos messages avec le format indiqué en combinaison du
programme Python et du « chat ».
c. le contenu du message est chiffré maintenant.
Exemple de chiffrement :
limitation des messages à 15 octets à cause du codage en base64 (taille augmentatée de 30%)
avec une opération « xor » entre un HMAC basé sur SHA-1 (20 octets) utilisant un secret connu
des deux interlocuteurs ;
Attention : pour permettre l’échange du message entre le programme Python et le « chat », votre
message devra être encodé en base64 :
import base64
>>> a=base64.encodestring(’toto’)
>>> a
’dG90bw==\n’
>>> base64.decodestring(a)
’toto’
Exemple d’utilisation de la fonction de HMAC basé sur SHA-1 :
1
2
4
5
6
7
#!/usr/bin/python
import hmac, hashlib
secret=’super_secret’
generateur_hashmac = hmac.new(secret,’’, hashlib.sha1)
generateur_hashmac.update(’Texte quelconque’)
empreinte_securisee = generateur_hashmac.digest()
Modification du Makefile dans le répertoire ~/RF24/librf24-rpi/librf24-bcm/examples :
PROGRAMS = chat_rf #rpi-hub scanner pingtest pongtest pongtest_irq
SOURCES = ${PROGRAMS:=.cpp}
all: ${PROGRAMS}
${PROGRAMS}: ${SOURCES}
g++ ${CCFLAGS} -Wall -I../ -lrf24-bcm -lwiringPi [email protected] -o $@
Pour l’installation de la bibliothèque « PyCrypto » :
$ sudo apt-get install python-dev
$ sudo apt-get install python-setuptools
$ sudo easy_install pip
$ sudo pip install pycrypto
Resp. UE : P-F. Bonnefoi, http://libpfb.so/, « Communication & MANET » version du 13 mars 2014, rédigé avec ConTEXt – Don’t Panic !
3/4
1
2
3
4
5
#include
#include
#include
#include
#include
<cstdlib>
<iostream>
<errno.h>
<wiringPi.h>
"RF24.h"
7 #define A_VERS_B 1
9 // Use GPIO Pin 17, which is Pin 0 for wiringPi library
10 #define IRQ_PIN 0
12 // Radio pipe addresses for the 2 nodes to communicate.
13 const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
15 // Setup for GPIO 22 CE and CE1 CSN with SPI Speed @ 8Mhz
16 RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_26, BCM2835_SPI_SPEED_8MHZ);
18 bool en_ecoute = true;
20 void interruption(void)
21 { char message[33];
23
24
25
26
27 }
if (!en_ecoute) return;
radio.read(message, sizeof(char)*32);
radio.startListening();
fprintf(stderr,"%s", message);
29 int main(int argc, char** argv)
30 { // sets up the wiringPi library
31
if (wiringPiSetup () < 0) {
32
fprintf (stderr, "Unable to setup wiringPi: %s\n", strerror (errno));
33
return 1; }
34
// Setup and configure rf radio
35
radio.begin();
36
radio.setRetries(15,15);
37
radio.setChannel(0x4c);
38
radio.setPALevel(RF24_PA_LOW);
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// This simple sketch opens two pipes for these two nodes to communicate back and forth.
// Open ’our’ pipe for writing
// Open the ’other’ pipe for reading, in position #1
if ( A_VERS_B )
{ radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]); }
else
{ radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]); }
// set Pin 17/0 generate an interrupt on high-to-low transitions
if ( wiringPiISR (IRQ_PIN, INT_EDGE_FALLING, &interruption) < 0 ) {
fprintf (stderr, "Unable to setup ISR: %s\n", strerror (errno));
return 1;
}
// Start listening
en_ecoute = true;
radio.startListening();
// Dump the configuration of the rf unit for debugging
radio.printDetails();
60
61
62
while (1)
{
char ligne[256];
bool ok = false;
64
65
66
67
68
69
70
71
72
}
73 }
fgets(ligne, sizeof(char)*255, stdin);
// First, stop listening so we can talk.
radio.stopListening();
en_ecoute = false;
ok = radio.write( ligne, sizeof(char)*32 );
if (! ok) printf("Echec de l’envoi\n");
radio.startListening();
en_ecoute = true;
Resp. UE : P-F. Bonnefoi, http://libpfb.so/, « Communication & MANET » version du 13 mars 2014, rédigé avec ConTEXt – Don’t Panic !
4/4