Le Relais 2 x 5 V … dans l’IoT ou l’art de piloter en BLE les périphériques de la WaRP7 – Partie 2/2

3.3 Activation du driver Kernel

La partie device tree étant faite, il nous reste à activer le support du driver gpio-exporter au sein de notre image Kernel (zImage). Pour ce faire, nous passerons une fois de plus par l’environnement Yocto/OE, en invoquant la commande suivante :

Puis dans Devices Drivers > GPIO Support il nous faudra activer l’option comme le montre la figure 8.

Fig. 8: CONFIG_GPIO_EXPORTER au sein de menuconfig

 

Remarque
L’ensemble des patchs relatifs au kernel (gpio-exporter, dts et fichier defconfig), sont directement intégrés au sein de la couche distribution mis à disposition par les auteurs : https://github.com/bdx-iot/meta-iot/tree/master/recipes-kernel (au travers une recette dérivée)

Nous pourrons dès à présent relancer une phase de compilation pour générer le fichier zImage et notre nouveau fichier dtb (transformation en un fichier binaire du fichier dts), qui sera donc imx7s-warp-relay.dtb :

3.4 Intégration

Nous allons, dans cette sous-partie, mettre à jour le fichier zImage ainsi que le fichier imx7s-warp-relay.dtb sur notre cible. Pour ce faire, il sera question, ici aussi, de monter la partition eMMC en mode mass storage via u-boot. Nous finirons naturellement cette sous-partie par une phase de test sur cible.

3.4.1 zImage et .dtb

Pour la copie de la zImage :

Pour la copie du fichier dtb spécifique à la gestion du relais :

Plaçons-nous maintenant côté cible et spécifions à notre chargeur d’amorçage (u-boot dans notre cas) que nous souhaitons utiliser le nouveau fichier dtb fraichement généré (imx7s-warp-relay.dtb) intégrant la partie gpio-exporter pour la gestion de nos relais, mais nous souhaitons, dans une moindre mesure, que celui-ci soit pris en compte par défaut, ceci afin d’éviter l’obligation d’une connexion série à chaque démarrage de la cible, il nous suffit donc de faire :

Ceci surcharge la variable fdt_file, variable qui contient la référence vers le fichier dtb à utiliser (de base, imx7s-warp.dtb dans les sources de u-boot). Sauvegardons maintenant notre environnement :

Il nous est maintenant possible de démarrer notre cible via l’exécution de la commande bootcmd (qui contient une suite de commandes à exécuter au démarrage) :

3.4.2 Test en espace utilisateur

Afin de simplifier (encore plus) l’accès aux GPIO (via gpio-exporter), les auteurs auront préféré mettre en place la notion de lien symbolique afin de se créer un point d’accès dans /dev/mikrobus/*. En temps normal l’accès aux GPIO s’effectue dans /sys/devices/platform/gpio-exporter//out_RL*. Cette technique nous donnera donc le résultat suivant sur notre plateforme :

Liens Symboliques
Le script concernant la génération des liens symboliques est entièrement consultable sur le github des auteurs : https://github.com/bdx-iot/meta-iot/blob/master/recipes-iot/clicks-board-init/clicks-board-init/mikrobus.sh.

Tout comme en section précédente, nous pouvons de façon très simple, et ceci sans connaître le numéro de la GPIO, piloter nos relais (plutôt pas mal non ?) :

4. Mise en situation …

Nous clôturerons cet article sur un mini-projet (par simple habitude des auteurs) permettant ainsi au lecteur de mettre en pratique les notions évoquées tout au long de l’article. Celui-ci nous permettra d’aborder quelques nouvelles techniques, comme par exemple l’introduction au QML.

4.1 Présentation du projet

Nous nous servirons du travail effectué durant cette première partie de l’ article, qui de ce fait, nous servira de base pour notre application « connectée ». Nous proposons ici de faire une évolution du serveur BLE du précédent article.

L’idée sera donc de créer :

  • une application « serveur BLE », permettant le pilotage de notre carte « relay click », application qui sera sur la WaRP7.
  • un client associé, qui, lui, sera sous forme d’application Android et qui enverra les données au serveur BLE (commande des relais).

La figure 9 (ci-après) illustre l’architecture globale que l’on se propose de mettre en œuvre durant cette dernière partie de l’article :

Fig. 9: structure du projet

4.2 Le Serveur

Interaction avec nos GPIO

La première étape consistera à créer une fonction nous permettant d’écrire sur les GPIO. Il suffit d’utiliser la classe QFile[12] qui permet la gestion de fichiers (et oui, sous Linux tout est fichier) :

Ceci étant fait, il ne reste plus qu’à ouvrir (via l’appel open()) le fichier (avec la permission d’écriture !), écrire la valeur souhaitée (0 ou 1) puis le refermer via l’appel close() :

Dans le cas présent, « data » est de type QByteArray (simple tableau d’octets) contenant la valeur à envoyer sur notre GPIO. Nous verrons plus tard comment cette dernière est envoyée.

Et la partie BLE ?

Dans cet exemple, nous avons décidé de ne pas utiliser les services[13]/caractéristiques[14] standards proposés par le protocole Bluetooth, et de ce fait, nous avons créé les nôtres pour les besoins de cet article, c’est bien plus ludique quand même !

La figure 10 indique comment nous allons architecturer nos données.

Fig. 10: Architecture du serveur BLE

 

Il faut donc d’abord avoir nos propres UUID (Service + Caractéristiques) :

Que nous allons ensuite « caster » en QBluetoothUuid :

Les présentations étant faites, nous pouvons rentrer dans le vif du sujet, la création du serveur. Et bien, pour ce faire, rien de plus simple avec l’API proposé par Qt :

Nous déclarons dans un premier temps un « advertiser » qui définit la configuration de base de notre serveur, ceci grâce à la classe suivante :

Configurons son mode, son nom (GLMF_200_BLE) et nous y ajoutons un nouveau service (serviceRelay dans notre exemple) :

Nous créons ensuite les caractéristiques voulues (charRelay1). Le descripteur va définir la gamme de fonctionnalités de la caractéristique associée.

Puis nous les associons au service préalablement configuré. Nous définissons son type comme « Primaire » car il donne accès aux fonctionnalités standard des services :

La dernière étape arrive. Il ne reste plus qu’à créer le contrôleur, qui est, entre autres, le point d’entrée des périphériques Bluetooth. On ajoute alors le service relais à celui-ci et on démarre le serveur. Ainsi on rend la connexion possible :

Il ne reste donc plus qu’à implémenter la fonction qui traite la réception d’une donnée afin de savoir à quel relais elle s’applique et dans quel état nous devons le mettre. Il suffit assez simplement de lire l’UUID de la caractéristique reçue et de commuter celui concerné en fonction :

Le travail est fini et le serveur est ainsi prêt à fonctionner. Si le lecteur veut s’y tenter, il pourra d’ores et déjà compiler l’application pour la déployer sur la cible (bitbake ServiceRelay). Pour de plus amples informations sur la gestion des paquets/déploiement, les auteurs renverront le lecteur sur un excellent article de Pierre Ficheux[15]).

Température
Dans l’exemple complet proposé sur le Github des auteurs, nous avons rajouté la lecture de la température présente sur la Warp7 afin de donner un peu de vie à l’interface.

4.3 « Dans la peau du client »

Création de notre environnement

Le serveur est fonctionnel, donc prêt à être piloté. Il ne manque plus qu’à lui associer un client. L’idée ici est de proposer une application Android avec le framework Qt en QML.

QML
QML (pour Qt Meta Language) est un langage de programmation graphique qui ressemble beaucoup au JSON. Il a été créé principalement pour les applications mobiles, son utilisation étant bien plus simple que le Designer standard pour plateforme mobile.

Avant de pouvoir démarrer le projet, il faut mettre en place notre environnement. Pour cela, il est suggéré ici, de suivre le tutoriel Qt pour Android qui est très bien documenté (http://doc.qt.io/qt-5/android-support.html), qui consiste en l’installation de la chaîne de compilation Qt pour Android ainsi que le NDK et le SDK fournis par Google. Il faudra bien entendu installer Java !

Afin de ne pas sacrifier de nombreuses pages, les auteurs renverront le lecteur sur le GitHub en ce qui concerne l’ensemble des sources à télécharger. A la suite de cela, nous pouvons alors ouvrir Qt Creator et :

  • – Dans Tool > Options > Android, il faudra ici remplir correctement les arborescences (JDK, NDK et SDK) comme le montre la figure 11.

Fig. 11: Configuration de notre environnement

 

  • Puis dans Tool > Options > Build & Run > Kits, il faudra créer le Kit associé (voir figure 12).

Fig. 12: Configuration de notre Kit

Un premier projet

En premier lieu, créons notre premier projet QML (Qt Quick Application) tout en sélectionnant le Kit Android pour le futur déploiement (smartphone).

Une application QML se scinde toujours en deux parties :

  • une partie C++
  • une partie script QML.

Il existe donc plusieurs outils pour communiquer entre les deux couches que nous expliciterons au cours de cette partie.

La partie C++

Dans cette partie, nous décrirons le client Bluetooth Low Energy. Et surtout, comment envoyer une donnée au serveur.

Dans un souci de simplicité, nous avons retiré les méthodes de découverte des périphériques présents. Partons du postulat que nous connaissons déjà l’adresse (MAC) de notre serveur. Nous chercherons simplement à nous y connecter de façon directe.


Identifier l’adresse mac de l’interface BLE
Pour connaître l’adresse physique de l’interface bluetooth de notre WaRP7, il suffira d’exécuter la commande suivante :


Voici donc l’introduction des premières lignes de code. Le type d’adresse peut être soit « Public » soit « Random ». Le premier définit un mode de fonctionnement standard avec une adresse « statique » et le second définit un mode dans lequel l’adressage peut évoluer, c’est une sécurité dont nous n’avons pas besoin pour la suite :

La connexion n’est pas instantanée, mais une fois faite, on lance alors la découverte des services associés au périphérique :

Puis, à la réception des services, il est possible de lancer la découverte des caractéristiques associées au service via la fonction « discoverDetails() » :

Et enfin, à la réception des caractéristiques, on conserve la valeur contenue dans celles-ci et on met à jour l’interface en fonction. Les caractéristiques se reconnaîtront grâce à leurs UUID :

Le plus dur est fait et, afin d’envoyer une nouvelle valeur au serveur en vue de changer l’état d’un des deux relais, il suffira d’utiliser la fonction suivante :

A partir de là, il ne reste plus qu’à créer notre interface !

La partie QML

Lorsque l’on crée un fichier QML, on peut soit le modifier sous la forme d’un script, soit via le designer QML de Qt. Il existe donc deux types de fichiers qml :

  • Fichier.ui.qml qui pourra être édité via l’éditeur et/ou par script,
  • Fichier.qml qui pourra être modifié uniquement par script

Généralement, les fichiers.ui.qml sont associés à un fichier.qml afin de créer les connexions vers le C++. Dans l’exemple, nous avons créé deux fichiers .qml (associés chacun à un fichier.ui.qml) :

  • main.qml : qui consiste en un simple bouton permettant d’enclencher la connexion directement avec le serveur dont l’adresse est celle spécifiée dans le code principal.
  • Relay.qml : permet de piloter les deux relais.

Pour que le QML puisse communiquer avec notre classe, il faut pour ce faire, passer celle-ci en paramètre. Nous pouvons alors charger la page main.qml :

Au chargement de l’application, nous aurons donc la page main.qml qui s’affichera constituée d’un simple bouton. Pour gérer l’évènement du clique, il suffit d’utiliser le script suivant :

Afin que la fonction start soit appelée, il est nécessaire qu’elle soit invocable[16] depuis le C++ :

L’objet pageLoader permet de charger une nouvelle page QML et est défini par :

La page Relay.qml est alors chargée. Elle est composée de deux switchs qui permettront de piloter les deux relais. De la même manière, le changement d’état des switchs se gère de la façon suivante :

L’application est bientôt terminée. Nous avons vu comment insérer et appeler une fonction depuis le QML vers le C++. Il ne reste plus qu’à expliquer comment mettre à jour la parité QML avec le C++. Pour réaliser le lien, Qt propose l’utilisation des Q_PROPERTY[17] qui seront liées à des signaux de mise à jour. Par exemple, si nous voulons mettre à jour l’état d’un relais nous définirons la Q_PROPERTY suivante :

Et côté QML, la connexion au signal se fait de la manière suivante :

4.4 Le rendu final

Pour avoir un aperçu du projet réalisé, voici ci-après le fruit du travail réalisé durant cet article. La première étape consiste au lancement de l’application (.apk disponible ici : https://github.com/bdx-iot/RelayGUI/blob/master/GLMF_200_GUI_BLE.apk)

Fig. 13: Démarrage de l’application


L’étape suivante nous indique de nous connecter à notre périphérique (figure 14) :

Fig. 14: Connexion


Une fois connectés, nous avons la satisfaction de pouvoir interagir avec nos relais, lire la température du capteur Altimètre (MPL3115), mais surtout, de pouvoir jouer avec une simple ampoule comme le montre notre environnement sur la figure 15.

Fig. 15: IoT : L’environnement de test


Agissons maintenant sur le relais 1 (figure 16) :

Fig. 16: IoT : Rendu globale avec RL1 activé


Puis activons le 2ème relais (figure 17) :

Fig. 17: IoT : Rendu globale


Rappelons une fois de plus que le lecteur pourra retrouver l’ensemble des sources sur le référentiel git suivant : https://github.com/bdx-iot. Se trouvera sur celui-ci :

Conclusion

Dans cet article, nous avons découvert le standard MikroBUS et nous avons ainsi pu le mettre en application sur notre plateforme cible. De par l’intégration, nous avons d’autre part, découvert des notions comme le device tree ou encore le langage QML.

Finalement, nous avons mis en pratique l’ensemble des notions pour créer un véritable objet connecté (jusqu’à la création de la partie client pour la gestion de celui-ci), le tout basé sur du Bluetooth Low Energy. Ceci n’étant qu’une introduction au vu du potentiel, le lecteur pourra s’inspirer et imaginer d’autres applications (domotique) via les modules Mikrobus de MikroElektronika.

En parlant de domotique, n’oublions pas que cette plateforme dispose d’une interface caméra, autre périphérique qu’il serait intéressant de mettre en œuvre afin de créer un environnement connecté pour la surveillance de nos enfants (vidéo/température/gestion de la veilleuse), ceci en ne négligeant pas l’aspect low energy de notre objet bien entendu.

Références

[1] Article « A la découverte de la WaRP7 » par Pierre-Jean TEXIER et Jean CHABRERIE, Open Silicium n°20
[2] Site d’Element14 :
https://www.element14.com/community/docs/DOC-79058/l/warp7-the-next-generation-iot-and-wearable-development-platform
[3] Page NXP présentant l’architecture du i.MX7 :
http://www.nxp.com/products/microcontrollers-and-processors/arm-processors/i.mx-applications-processors/i.mx-7-processors/i.mx-7solo-processors-heterogeneous-processing-with-arm-cortex-a7-and-cortex-m4-cores:i.MX7S
[4] Documentatio du projet Yocto (version 2.1 : krogoth) :
http://www.yoctoproject.org/docs/2.1/mega-manual/mega-manual.html
[5] Documentation relative à l’outil repo : https://source.android.com/source/using-repo.html
[6] Couche distribution des auteurs : https://github.com/bdx-iot/meta-iot
[7] Ensemble des cartes « click » par MikroElektronika : http://www.mikroe.com/click/
[8] Documentation dans les sources du Noyau Linux sur l’utilisation des GPIO en espace utilisateur : https://www.kernel.org/doc/Documentation/gpio/sysfs.txt
[9] Driver gpio-exporter : https://patchwork.kernel.org/patch/6207321/
[10] Article « Périphériques découvrables, découverts ou à découvrir » par Pierre FICHEUX, Open Silicium n°20
[11] Article « Introduction au « device Tree »sur ARM » par Thomas PETAZZONI, Open Silicium n°17
[12] Documentation de la classe Qfile :
http://doc.qt.io/qt-5/qfile.htmlhttp://doc.qt.io/qt-5/qfile.html
[13] Spécifications des services bluetooth :
https://www.bluetooth.com/specifications/gatt/services
[14] Spécifications des caractéristiques bluetooth :
https://www.bluetooth.com/specifications/gatt/characteristics
[15] Article « IoT sous Yocto, un cas d’utilisation » par Pierre FICHEUX, Open Silicium n°20
[16] Explication de la macro Q_INVOKABLE :
http://doc.qt.io/qt-5/qobject.html#Q_INVOKABLE
[17] Explication de la macro Q_PROPERTY :
http://doc.qt.io/qt-5/qobject.html#Q_PROPERTY

Retrouvez cet article (et bien d’autres) dans GNU/Linux Magazine n°200, disponible sur la boutique et sur la plateforme de lecture en ligne Connect !

Laisser un commentaire