Accès aux E/S Généralités Pour accéder aux E/S de la Raspberry Pi, on peut soit s’appuyer directement sur ce que propose Linux soit utiliser des librairies tierces. Les 2 approches possèdent des avantages mais aussi des inconvénients. Ici, on va s’intéresser à l’utilisation d’une librairie couramment utilisée lors des projets de 2ème année : la librairie bcm2835 . Cette librairie n’est pas disponible dans les dépôts logiciels de Raspberry Pi OS et ne peut donc pas être installée avec apt get install …. L’installation passera forcément par la compilation du code source de cette librairie. 🖮 Travail n° 1 Librairie bcm2835 Se rendre sur C library for Broadcom BCM 2835 as used in Raspberry Pi pour récupérer dans la description de la librairie le lien de téléchargement de son code source (quelque chose du genre http://www.airspayce.com/mikem/bcm2835/bcm2835-1.xx.tar.gz où “xx” correspond au n° de version) Procéder, depuis la ligne de commande, au téléchargement de la librairie sur la Raspberry Pi : Exemple pour la version v1.69 de la la librairie wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.69.tar.gz (1) Suite au téléchargement, suivre la procédure indiquée sur le site à savoir : tar zxvf bcm2835-1.xx.tar.gz (1) cd bcm2835-1.xx (2) ./configure (3) make (4) sudo make check (5) sudo make install (6) 1 extrait le fichier téléchargé 2 se rend dans le répertoire où la librairie a été extraite 3 exécute un script qui vérifie, entre autres, que la Raspberry Pi dispose de tous les outils pour compiler la librairie 4 génère la librairie 5 effectue des tests sur la librairie générée 6 procède à l’installation de la librairie Si tout s’est bien déroulé, la librairie doit alors être présente dans le répertoire /usr/local/lib/ sous le nom libbcm2835.a. Voir ce document pour plus de détails sur l’installation et l’utilisation de la librairie. Se rendre dans le répertoire de l’exemple d’utilisation de la librairie pour accéder aux GPIOs (→ General Purpose I/O) pour étudier son code source et l’exécuter cd bcm2835-1.69/examples/gpio/ (1) gcc -o gpio gpio.c -l bcm2835 (2) ./gpio (3) Running ... Insufficient command line arguments gpio Usage: gpio [options] [...] 1 adapter le chemin 2 génère le programme en le “linkant” avec la librairie (→ option -l bcm2835) 3 exécute le programme sans option afin d’afficher l’aide sur son utilisation Exécuter à nouveau l’exemple de façon à allumer et éteindre la LED située sur le hat de la Raspberry Pi. La librairie bcm2835 s’appuie sur les n° de broche (et non sur les n° de GPIO) des entrées/sorties à piloter. Voir documentation de la librairie bcm2835 (et plus particulièrement le paragraphe “Pin Numbering”) S’appuyer sur le schéma structurel du hat de la Raspberry Pi pour déterminer le n° de broche à spécifier au programme pour piloter la LED L’entête du fichier source de l’exemple contient quelques exemples d’invocation du programme Exécuter le même exemple pour lire l’état du bouton poussoir présent sur le hat. 🖮 Travail n° 2 Wrapper librairie bcm2835 La librairie bcm2835 est une librairie écrite en langage C. Or, vous allez être amenés à utiliser cette librairie dans un contexte C++ (→ Ex. : utilisation dans Qt). Une classe — dîte “Wrapper” — a donc été développée au lycée pour pouvoir l’exploiter comme si elle était codée en C++ (un peu à la manière d’une librairie Arduino). De manière générale, un Wrapper est simplement une interface vers une librairie existante visant à : permettre à plusieurs codes de fonctionner ensemble malgré certaines incompatibilités (ex. : formats de données) redéfinir l’API (→ Application Program Interface) d’une librairie existante parce qu’elle vous semble mal conçue ou trop compliquée. permettre l’interopérabilité avec d’autres langages ou environnements d’exécution (ex. : utiliser une librairie C/C++ depuis Python). La singularité de cette classe wrapper — nommée Bcm2835Wrapper — par rapport à ce que vous avez rencontré jusqu’ici réside dans la manière dont on va l’instancier pour pouvoir l’utiliser : vous ferez directement appel à la méthode statique getInstance() de cette classe plutôt qu’à son constructeur (car déclaré private). Cette façon d’instancier la classe est typique des classes qui codent le patron de conception Singleton. Un patron de conception ou design pattern est simplement une “recette de programmation orientée objet” qui permet de résoudre un problème de conception logicielle récurrent. Les objectifs du patron de conception Singleton sont : d’assurer qu’il n’existe qu’une seule instance de la classe de fournir un moyen d’obtenir cette instance unique De façon à vous approprier le fonctionnement de la classe Bcm2835Wrapper, vous allez la mettre en œuvre dans un programme C++ pour faire clignoter la DEL du hat de la Raspberry Pi. Cloner le dépôt Bcm2835LibWrapper de la forge logicielle Framagit dans lequel se trouve le code source du wrapper. git clone https://framagit.org/codebase-bts-sn/bcm2835libwrapper.git Renommer le répertoire bcm2835libwrapper/ dans lequel a été cloné le dépôt logiciel en MiseEnOeuvreBcm2835Wrapper/ Coder dans ce répertoire un fichier set-del-on.cpp qui utilise directement cette classe pour allumer la DEL du hat set-del-on.cpp // Compilation : // g++ -o set-del-on set-del-one.cpp bcm2835wrapper.cpp -lbcm2835 #include "bcm2835wrapper.h" int main(void) { const uint8_t LED_PIN = 27; // n° de GPIO pour la DEL // On récupère une référence sur l'instance du wrapper Bcm2835Wrapper& bcm = Bcm2835Wrapper::getInstance(); // On utilise le wrapper pour configurer la GPIO de la LED en sortie bcm.gpio_fsel(LED_PIN, Bcm2835Wrapper::OUTPUT); // On désactive les résistances de pull-up/pull-down sur la GPIO de la LED bcm.gpio_set_pud(LED_PIN, Bcm2835Wrapper::DOWN); // On allume la DEL bcm.gpio_set(LED_PIN); } Générer le programme g++ -o set-del-on set-del-on.cpp bcm2835wrapper.cpp -l bcm2835 Ce n’est pas parce qu’on utilise le wrapper de la librairie dans cet exemple qu’il ne faut pas le linker avec elle (→ option -l bcm2835) Exécuter le programme pour constater l’allumage de la DEL du hat sudo ./set-del-on Se baser sur cet exemple, pour coder un programme blink-del qui fait clignoter la DEL à 1Hz. Consignes/Astuces : Pour le clignotement à 1Hz, vous allumerez la DEL pendant 0.2s et l’éteindrez pendant 0.8s La méthode du wrapper qui positionne au O logique une GPIO est gpio_clr() La fonction standard usleep(useconds_t usec) déclarée dans l’entête <unistd.h> suspend l’exécution du programme pendant le nombre de microsecondes passé dans son argument. Elle pourra donc être utilisée dans une boucle pour réaliser le clignotement. 🖮 Travail n° 3 Application On vous demande maintenant de coder une application qui propose une IHM console qui permet à un utilisateur de piloter la DEL du hat. Cette application doit permettre : d’allumer la DEL d’éteindre la DEL de basculer l’état de la DEL d’afficher l’état courant de la DEL Le contrôle/commande de la DEL du hat se fera à travers une classe C++ nommée HatLed Le diagramme de classe simplifié de cette application est : Coder la classe HatLed conformément au modèle Consignes/Astuces: Le constructeur doit configurer la broche LED_PIN en sortie (→ OUTPUT), désactiver les résistances de pull-up/pull-down, éteindre la DEL et positionner l’attribut _state à false pour indiquer que la DEL est éteinte Le membre _bcm étant une référence C++, celle-ci doit obligatoirement être initialisée dans une liste d’initialisation du constructeur HatLed::HatLed() : _bcm(Bcm2835Wrapper::getInstance()) { (1) // ... } 1 Initialise l’attribut _bcm avec la référence C++ renvoyée par la méthode getInstance() de la classe Bcm2835Wrapper La méthode set() doit allumer la DEL et mettre à jour l’attribut _state avec la valeur true La méthode clr() doit éteindre la DEL et mettre à jour l’attribut _state avec la valeur false) la méthode getState() doit retourner la valeur actuelle de l’attribut _state la méthode toggle() doit basculer l’état de la DEL c.-à-d. l’allumer si elle est éteinte et l’éteindre si elle est allumée. Elle doit aussi, bien entendu, mettre à jour la valeur de l’attribut _state Coder une fonction main() provisoire dans un fichier drive-led.cpp qui instancie la classe HatLed afin de tester chacune de ses méthodes Coder la classe App Consignes/Astuces : la méthode exec() doit proposer un menu qui permet d’allumer/éteindre/basculer l’état de la DEL ainsi que récupérer son état courant Proposition d’IHM MENU : 1- Allumer la DEL 2- Eteindre la DEL 3- Basculer l'état de la DEL Etat courant de la DEL : DEL allumée <Appuyer sur 'q' pour quitter> la gestion se fera en mode non canonique (→ enableCanonicalMode() de la classe AnsiTerm) de façon à déclencher l’action du menu à chaque appui sur la touche qui lui est associée Quelle que soit l’action déclenchée (allumer, éteindre, basculer), l’IHM devra signaler l’état courant de la DEL à l’issue de l’action Modifier la fonction main() du fichier drive-led.cpp pour instancier dynamiquement la classe App et faire appel à sa méthode exec() 🞄 🞄 🞄 Environnement de développement Capteur SHT20