Integrating Web Applications with Apache

When you deploy a web application, how do end users access it? Often web applications are set behind a gateway device through which end users can access it. One of the popular products to act as an application gateway on Linux is the Apache Web Server. Although it can function as a normal web server, it also has the ability to connect through it to other web servers. more>>

Nativ Vita

The motto "open to anything" underpins Nativ's development philosophy on all of its audio solutions, including its new Nativ Vita, "the world's first High-Resolution Music Player" and touchscreen control center that is designed to function as the central access point for one's entire music collection. more>>

Non-Linux FOSS: File Spelunking with WinDirStat

With Linux, it's fairy easy to find the large files on your system by doing something like this:

du -ahx / | sort -rh | head -20


Manipulate Images with ImageMagick

In my last article, I had some fun looking at the children's game of rock, paper, scissors, writing a simple simulator and finding out that some strategies are better than others. Yes, I used "strategy" and "rock, paper, scissors" in the same sentence! more>>

Updated bleeding edge toolchains on

Two months ago, we announced a new service from Free Electrons: free and ready-to-use Linux cross-compilation toolchains, for a large number of architectures and C libraries, available at

Bleeding edge toolchain updates

All our bleeding edge toolchains have been updated, with the latest version of the toolchain components:

  • gcc 7.2.0, which was released 2 days ago
  • glibc 2.26, which was released 2 weeks ago
  • binutils 2.29
  • gdb 8.0

Those bleeding edge toolchains are now based on Buildroot 2017.08-rc2, which brings a nice improvement: the host tools (gcc, binutils, etc.) are no longer linked statically against gmp, mpfr and other host libraries. They are dynamically linked against them with an appropriate rpath encoded into the gcc and binutils binaries to find those shared libraries regardless of the installation location of the toolchain.

However, due to gdb 8.0 requiring a C++11 compiler on the host machine (at least gcc 4.8), our bleeding edge toolchains are now built in a Debian Jessie system instead of Debian Squeeze, which means that at least glibc 2.14 is needed on the host system to use them.

The only toolchains for which the tests are not successful are the MIPS64R6 toolchains, due to the Linux kernel not building properly for this architecture with gcc 7.x. This issue has already been reported upstream.

Stable toolchain updates

We haven’t changed the component versions of our stable toolchains, but we made a number of fixes to them:

  • The armv7m and m68k-coldfire toolchains have been rebuilt with a fixed version of elf2flt that makes the toolchain linker directly usable. This fixes building the Linux kernel using those toolchains.
  • The mips32r5 toolchain has been rebuilt with NaN 2008 encoding (instead of NaN legacy), which makes the resulting userspace binaries actually executable by the Linux kernel, which expects NaN 2008 encoding on mips32r5 by default.
  • Most mips toolchains for musl have been rebuilt, with Buildroot fixes for the creation of the dynamic linker symbolic link. This has no effect on the toolchain itself, but also the tests under Qemu to work properly and validate the toolchains.

Other improvements

We made a number of small improvements to the site:

  • Each architecture now has a page that lists all toolchain versions available. This allows to easily find a toolchain that matches your requirements (in terms of gcc version, kernel headers version, etc.). See All aarch64 toolchains for an example.
  • We added a FAQ as well as a news page.

As usual, we welcome feedback about our toolchains, either on our bug tracker or by mail at

TeamViewer Linux Host

At last abandoning WINE and launching native Linux support, TeamViewer announced the availability of a new preview version of its Linux Host with native Linux support. more>>

Free Electrons proposes an I3C subsystem for the Linux kernel

MIPI I3C fact sheet, from the MIPI I3C white paper

MIPI I3C fact sheet, from the MIPI I3C white paper

At the end of 2016, the MIPI consortium has finalized the first version of its I3C specification, a new communication bus that aims at replacing older busses like I2C or SPI. According to the specification, I3C gets closer to SPI data rate while requiring less pins and adding interesting mechanisms like in-band interrupts, hotplug capability or automatic discovery of devices connected on the bus. In addition, I3C provides backward compatibility with I2C: I3C and legacy I2C devices can be connected on a common bus controlled by an I3C master.

For more details about I3C, we suggest reading the MIPI I3C Whitepaper, as unfortunately MIPI has not publicly released the specifications for this protocol.

For the last few months, Free Electrons engineer Boris Brezillon has been working with Cadence to develop a Linux kernel subsystem to support this new bus, as well as Cadence’s I3C master controller IP. We have now posted the first version of our patch series to the Linux kernel mailing list for review, and we already received a large number of very useful comments from the kernel community.

Free Electrons is proud to be pioneering the support for this new bus in the Linux kernel, and hopes to see other developers contribute to this subsystem in the near future!

Write for Us!

Summer is slowly coming to an end, schools are going into session, and we're all gathering projects and topics to get us through the winter. If you have any interesting topics or projects you're working on, we'd love to hear about them. more>>

The Post-TV Age?

The most basic cable package from Charter (Spectrum?) costs me more than $70 per month, and that's without any equipment other than a single cable card. It's very clear why people have been cutting the cord with cable TV companies. But, what options exist? Do the alternatives actually cost less? Are the alternatives as good? more>>

WPS Office 2016 for Linux

Promising the world's best office experience for the Linux community, WPS Software presents WPS Office 2016 for Linux: a high-performing yet considerably more affordable alternative to Microsoft Office that is fully compatible with and comparable to the constituent PowerPoint, Excel and Word applications. more>>

Utilisation du Bluetooth Low Energy avec bluez

Depuis sa sortie en 2010, le Bluetooth Low Energy s’affirme dans le domaine des protocoles de communications pour objets connectés. Cet article s’intéresse au fonctionnement de ce protocole et de son intégration dans un système embarqué sous Linux avec Bluez.


Introduction : le protocole Bluetooth

Logo Bluetooth

Le Bluetooth est un standard de communication radio opérant à courte distance. Son objectif est d’unifier les appareils électroniques autour d’un protocole commun et sans-fil. Le nom “Bluetooth” et son logo font référence au roi danois Harald Bluetooth qui avait su unifier les tribus de son peuple au sein d’un unique royaume. Le fabricant Ericsson est à l’origine du standard créé en 1994 et embarqué sur téléphone en 1996. Plusieurs grandes sociétés ont ensuite rejoint Ericsson pour former le Bluetooth Special Interest Group (SIG). Ce groupe s’occupe de l’évolution de la norme et la distribution des licenses aux fabricants. Le standard a évolué en plusieurs versions listées ci-dessous :

Version Date Améliorations majeures
1.0 1999
2.0 2004 Enhanced Data Rate, débit jusqu’à 2.1 Mbps
2.1 2007 Appairage sécurisé
3.0 2009
4.0 2010 Low Energy
4.1 2013 Amélioration du Low Energy
4.2 2014 Amélioration de la sécurtié du Low Energy
5.0 2016 Amélioration de la portée et débit radio

La version 4.0 du standard dévoile la spécification Bluetooth Low Energy qui évoluera jusqu’à la version 5.0. Cette spécification implique des changements importants sur les différentes couches du standard. Ce document se focalisera sur cette nouvelle spécification. La version 5.0, sortie en décembre 2016, apporte des améliorations considérables sur la portée et le débit du Bluetooth. Les principales nouveautés sont :

  • Slot Availability Mask (SAM) : Transmission entre deux appareils de leurs créneaux disponibles pour l’émission et la réception de données
  • 2 Msymboles/s sur la couche physique du BLE (x2)
  • Augmentation de la portée BLE
  • High Duty Cycle Non-Connectable Advertising
  • Extension de l’advertising BLE
  • Nouvel algorithme de sélection de canaux BLE

Dernièrement, le 13 juillet 2017, la spécification Bluetooth Mesh a été dévoilée par la Bluetooth SIG et permettra de créer des réseaux maillés entre appareils Bluetooth. La spécification a un grand potentiel pour la domotique et l’industrie car elle pourra unifier tous les appareils sous un même protocole.

Le Bluetooth Low Energy

Comme expliqué plus haut, le Bluetooth Low Energy apparaît avec le version 4.0 des spécifications Bluetooth. Bien que s’inspirant de l’architecture du Bluetooth Classic, le Low Energy est à voir comme un nouveau protocole, adapté à des systèmes contraints en énergie et ne nécessitant pas un débit élevé. Il a été conçu pour faire communiquer un système contraint – que l’on nomme périphérique – avec un système moins ou non contraint en énergie et en puissance de calcul, nommé le central.

Principes de base

Le standard est basé sur la spécification IEEE 802.15.1 qui définit les couches physiques et liaisons de modèle OSI pour des communications WPAN/Bluetooth. Le Bluetooth opère dans la bande de fréquence ISM 2.4 GHz ouverte sans licence à l’industrie, à la science et au médical. La plupart des appareils Bluetooth utilisent une puissance radio de 1 mW ce qui leur donne une portée de 5 à 10 m. Le standard permet de mettre en place des topologies de réseau en étoile ou maillé. Il faut noter que le réseau maillé est une possibilité, mais qu’elle n’est pas encore spécifiée. Des liens s’établissent entre un maître et des esclaves. Ces liens forment un piconet, nom du réseau selon la spécification Bluetooth. Un appareil Bluetooth ne peut être le maître que d’un seul piconet mais peut être l’esclave de plusieurs. Généralement, avec le Bluetooth Low Energy, le maître est un ordinateur ou un smartphone – nommé central – et l’esclave un objet connecté nommé périphérique.

Source : Spécification Bluetooth Core 5.0

Le Bluetooth spécifie des profils qui effectuent des opérations haut niveau entre le maître et l’esclave. Les plus connus sont l’Advanced Audio Distribution Profile (A2DP) pour le streaming audio ou le Dial-up Networking Profile (DUN) pour le partage de connexion internet par Bluetooth. Une liste des profils standards est disponible sur ce lien. Le standard impose deux profils par défaut pour le Bluetooth Low Energy (BLE), le Generic Access Profile (GAP) et le Generic Attribute Profile (GATT), qui seront décrits plus loin. Les périphériques utilisent l’advertising afin de signaler leur existence : des paquets sont envoyés sur des fréquences spécifiques écoutées par un central. Ces paquets contiennent des données fournissant des informations comme les services apportés par le périphérique ou son nom. Dans le cas d’une communication sans connexion (broadcast), les données sont transmises par les paquets d’advertising. Dans le cas d’une communication avec connexion, le central va initier la connexion avec le périphérique en lui dirigeant une requête sur les mêmes fréquences. Les deux appareils vont alors se synchroniser pour communiquer.

Architecture du Bluetooth Low Energy

Pile du Bluetooth Low Energy

Le schéma ci-dessus représente l’architecture du Bluetooth Low Energy. La partie blanche, bas niveau, est généralement implémentée dans un contrôleur. La partie haut niveau en gris foncé est implémentée à part dans un système plus puissant. Le Host Controller Interface permet d’interfacer ces deux éléments. Il est à savoir que la pile entière peut être implémentée entièrement dans le même microcontrôleur sans utiliser cette interface.

Couche Physique

Source : Argenox

Le Bluetooth Low Energy opère sur la bande de fréquences 2.4 GHz et utilise une modulation Gaussian Frequency Shift Keying (GFSK) ainsi que des séquences de Frequency Hopping afin d’éviter les interférences. Cette bande est découpée en 40 canaux numérotés de largeur 1 MHz séparés de 2 MHz. Trois d’entre eux – les 37, 38 et 39 – servent de canaux d’advertising primaire. Ceux-ci ont été placés sur des bandes de fréquences peu utilisées par les autres protocoles comme le Wi-Fi. Cela réduit le risque d’interférence et permet donc de réduire la fréquence des collisions des données d’advertising avec d’autres émissions radio. Les autres canaux servent à la donnée ou en canaux secondaires pour l’advertising.

Couche Liaison

Machine d’état de la couche Liaison

Comme expliqué brièvement plus haut, le processus de connexion se base sur un périphérique en mode advertising et un central en mode scanning. Le central envoie alors une requête de connexion par les canaux d’advertising qui lui donne un “rendez-vous” sur un canal de données spécifié et à un instant donné. Le périphérique et le central vont alors pouvoir communiquer durant ce qui est appelé une fenêtre de transmission (Transmit window) où la prochaine fenêtre sera définie et des données optionnellement transmises et ainsi de suite jusqu’à la déconnexion.

Host Controller Interface

Séparation de l’hôte et du contrôleur

Le Host Controller Interface (HCI) est un format de communication standardisé entre un système hôte et un contrôleur Bluetooth. En effet, la spécification Bluetooth permet de scinder son implémentation en un contrôleur qui gère les couches Physique et Liaison et un hôte qui gère les couches supérieures. Cela permet d’avoir une interopérabilité entre les différents composants Bluetooth. Cette communication peut être effectuée entre quatre types de transport :

  • USB : Permet par exemple l’existence des Dongle Bluetooth
  • UART 1 Wire
  • UART 3 Wires
  • SDIO

Le HCI permet à la fois la configuration de son contrôleur, la création d’une connexion, la réception et la transmission de données sur la couche physique.

La couche Transport

Le contrôle de flux, la fragmentation et le réassemblage des données sont assurés par le Logical Link Control and Adaptation Layer Protocol (L2CAP). Celui-ci utilise un système de canaux associés à une application : GATT ou IP sur BLE par exemple. Après l’établissement d’une connexion par la couche liaison, le maître peut se connecter aux canaux écoutés par l’esclave. Chaque canal gère indépendamment le flux, la fragmentation et le réassemblage. Le L2CAP gère aussi la qualité du service (QoS) afin de prioriser certaines applications sur d’autres. Le L2CAP peut être considéré comme la base pour la création de nouvelles fonctionnalités pour le Bluetooth. L’IETF a, par exemple, décrit la possibilité de transmettre des paquets en 6LoWPAN à travers le canal IP du L2CAP (cf. Sources en fin d’article).

Generic Access Profile

Le GAP est le profil de base autant pour le Bluetooth Classic que pour le Low Energy. Il définit les prérequis minimum d’un appareil Bluetooth. Avec le Low Energy, il permet d’accéder aux fonctionnalités de paramétrage, d’advertising, de scanning et connexion du contrôleur. Il définit aussi le rôle de l’appareil : Broadcaster, Observer, Peripheral ou Central. En BLE, le GAP impose l’existence du GATT dans la pile logicielle de l’appareil Bluetooth. Ainsi, tout dispositif dit Bluetooth Low Energy implémente obligatoirement ce profil.

Generic Attribute Protocol

Hiérarchie du GATT

Le GATT se base sur le format de données de l’Attribute Protocol (ATT) pour fournir une sorte de base de donnée. Le GATT utilise un système d’interaction serveur-client entre les deux appareils connectés. Le serveur est hébergé sur le périphérique qui met à disposition du central des informations (température, humidité, etc) rangées en services et caractéristiques. Certains services et certaines caractéristiques sont prédéfinis par la spécification Bluetooth comme les services Battery Service ou Heart Rate. Les caractéristiques sont des valeurs représentant une donnée quelconque associée à des métadonnées, dites descripteurs, définissant des permissions et d’autres informations. Celles-ci sont regroupées en services dont l’identifiant peut être intégré à la donnée d’advertising. Ainsi, un smartphone pourra se connecter automatiquement à un compteur de pulsation cardiaque juste en reconnaissant l’identifiant de ce service dans la trame d’advertising. Les caractéristiques peuvent, en fonction des permissions, être lues, écrites ou peuvent  notifier ou indiquer au central un changement de valeur. La notification permet l’envoi direct de la nouvelle valeur au central alors que l’indication lui signale que celle-ci est prête à être lue. Ce système permet une économie d’énergie, car le central n’a plus besoin de requêter régulièrement le serveur GATT.

Intégration sur Linux

Architecture de bluez

BlueZ est la pile Bluetooth officielle de Linux sous licence GNU GPL. Elle s’appuie sur des composants logiciels en espace noyau et utilisateur. BlueZ est intégré au noyau Linux à partir de la version 2.4. La partie noyau contient les pilotes HCI et la couche Transport de la spécification Bluetooth : le L2CAP, expliqué plus haut, et le RFCOMM, un protocole émulant une liaison série via Bluetooth. Le noyau met à disposition des sockets pour interagir avec le bus HCI, le L2CAP ou le RFCOMM. Les profils Bluetooth sont implémentés en espace utilisateur dans un service appelé bluetoothd à l’exception du profil OBEX (transfert de fichiers) qui a son propre service obexd. Le service bluetoothd fournit une interface D-Bus pour créer ou interagir avec des profils.

Utilisation de bluetoothd

Le service bluetoothd implémente tous les profils de la spécification : A2DP, GATT, etc. Il est possible de désactiver certains profils inutilisés par le système avant de compiler pour alléger l’empreinte mémoire de bluetoothd. L’interaction avec le service s’effectue via une interface D-Bus. Il est possible, à l’aide de cette interface, d’accéder à toutes les fonctionnalités nécessaires pour ajouter des profils, découvrir des périphériques, interagir avec le profil GATT, etc.

Ce qui nous intéresse dans le cas du Bluetooth Low Energy, c’est la capacité à scanner, se connecter, s’appairer et à utiliser le profil GATT. Cette section explique comment utiliser l’interface D-Bus pour du Bluetooth Low Energy. La connaissance de D-Bus est prérequise pour la bonne compréhension des explications qui suivent. Ces explications se basent sur la documentation de BlueZ.

Vue générale

Capture sur d-feet du bus org.bluez

L’interface D-Bus est accessible via le bus org.bluez. BlueZ présente plusieurs types d’objets accessibles via les chemins d’accès suivants :

  • / : L’objet root permet l’accès aux interfaces standards ObjetsManager et Introspectable.
  • /org/bluez : Permet d’ajouter un profil Bluetooth ou configurer le système d’appairage de BlueZ.
  • /org/bluez/adapter : Représente un contrôleur Bluetooth nommé sous la forme hci0, hci1, etc.
  • /org/bluez/adapter/device : Représente un périphérique Bluetooth découvert nommé sous la forme dev_XX_XX_XX_XX_XX
  • /org/bluez/adapter/device/service : Service GATT
  • /org/bluez/adapter/device/service/characteristic : Caractéristique GATT
  • /org/bluez/adapter/device/service/characteristic/descriptor : Descripteur GATT

BlueZ permet d’utiliser le Bluetooth Classic et Low Energy. L’API peut prêter à confusion car elle est homogénéisée et il est donc difficile de savoir si l’on utilise l’un ou l’autre. Afin de clarifier les choses, les sections suivantes mettent en avant les fonctionnalités utilisées pour le Low Energy.


Dans les objets adapters, on retrouve plusieurs interfaces :

  • Adapter1 : Fournit les contrôles pour lancer/arrêter la découverte de périphériques. Présente aussi les propriétés du contrôleur.
  • GattManager1 : Permet soit une connexion automatisée du contrôleur à des périphériques en fonction des services fournis, soit de générer un client GATT.
  • Media1 : Utilisé pour l’A2DP ou les kits mains libres.
  • NetworkServer1 : Utilisé pour se connecter à internet via le Bluetooth.
  • Introspectable : Permet une introspection de l’objet.
  • Properties : Permet de lire et d’écrire des propriétés.

L’interface Adapter1 est essentielle pour l’utilisation du Low Energy et en voici les éléments principaux :

  • Powered : Cette propriété est utilisée pour activer/désactiver le contrôleur. La méthode Set de l’interface Properties permet de changer l’état du contrôleur. Le signal PropertiesChanged sera envoyé par bluetoothd lorsque cet état aura été changé.
  • StartDiscovery() : Cette méthode permet d’activer la découverte de périphérique. La propriété Discovering passe à true lorsque la découverte a été activée. Lorsqu’un périphérique est découvert, l’interface ObjetsManager envoie le signal InterfacesAdded. Il faut garder en tête que certains périphériques ont pu être découverts auparavant ou enregistrés par BlueZ. Dans ce cas, ces périphériques sont retrouvés grâce à la méthode GetManagedObjets() qui permet d’obtenir toute l’arborescence du bus org.bluez.
  • SetDiscoveryFilters(filters) : Il est possible d’appliquer des filtres sur les périphériques à découvrir. Quatre paramètres sont disponibles : Services fournis, transport, RSSI et pathloss. Dans notre cas, on peut être intéressé pour restreindre le transport au Low Energy.
  • StopDiscovery() : Cette méthode stoppe la découverte de périphérique.


Dans les objets périphériques, on retrouve ces interfaces :

  • Device1 : Représente le périphérique.
  • Introspectable : Permet une introspection de l’objet.
  • Properties : Permet de lire et d’écrire des propriétés.

Dans l’interface Device1, ces éléments sont utilisés :

  • Connect() : Le contrôleur lance une connexion sur ce périphérique. Le signal PropertiesChanged est envoyé sur la propriété Connected si la connexion a abouti. Les périphériques connectés sont enregistrés par bluetoothd dans la liste des objets, qu’ils soient disponibles ou non. Il est possible de retirer un périphérique avec la méthode RemoveDevice().
  • Disconnect() : Le contrôleur se déconnecte du périphérique.
  • Pair() : Le contrôleur lance un appairage. La connexion se sécurise alors en fonction les capacités du master et du slave. BlueZ utilise un système d’agent que l’on peut configurer dans /org/bluez en utilisant l’interface AgentManager1. Un agent par défaut est fourni et répond à la plupart des cas d’application. Utiliser un agent personnalisé peut servir si l’on souhaite créer son propre wizard d’appairage. Enfin, la propriété Paired passe à true si l’appairage a réussi.
  • ServicesResolved : La connexion à un périphérique Low Energy est automatiquement suivie par les découvertes de sa hierachie GATT. Lorsque cette propriété passe à true, après que la connexion soit établie, tous les services, caractéristiques et descripteurs du périphérique ont été découverts et ajoutés au bus. Il faut savoir que ceux-ci sont placés en cache pour les prochaines connexions.
  • Name : Nom du périphérique.
  • AdvertisingFlags: Flags d’advertising du périphérique.
  • UUIDS : Services fournis par le périphérique.

Profil GATT

bluetoothd implémente le profil GATT client et serveur. L’utilisation d’un système Linux en tant que serveur GATT est moins courant qu’en tant que client, mais celle-ci est nécessaire pour la certification du Bluetooth SIG. Lorsque le contrôleur se connecte à un périphérique, il découvre tous ses services, caractéristiques et descripteurs. Les objets associés sont créés sur le bus, fournissant les interfaces GattService1, GattCharacteristic1 et GattDescriptor1

  • GattService1 : Contient l’UUID du service ainsi que la liste des services qu’il inclus
  • GattCharacteristic1 : L’interface de caractéristique est plus complexe. Elle permet d’écrire (WriteValue()), de lire (ReadValue()), ou de souscrire aux notifications et indications (StartNotify()/StopNotify()). Les propriétés donnent accès à la liste des usages avec Flags. Value représente la valeur de la caractérisque qui change une fois l’écriture effectuée ou une indication/notification reçue. Ce changement de valeur peut bien évidemment être récupéré par le signal PropertiesChanged.
  • GattDescriptor1 : Cette interface permet de la même façon que la caractéristique, de lire et d’écrire la valeur en respectant les propriétés du descripteur données dans Flags.

Utilisation des sockets

bluetoothd peut être considéré comme trop volumineux pour certains cas d’applications simples. Il est important de rappeler que ce service est dépendant de la glib et de libdbus. Il est alors possible d’utiliser les sockets qui permettent de s’interfacer avec la pile Bluetooth du noyau en espace utilisateur. Il est alors nécessaire d’implémenter soi-même ses propres profils et applications. Le noyau fournit trois sockets :

  • Socket HCI : Permet d’interagir avec le contrôleur en utilisation directement le protocole HCI.
  • Socket MGMT : Permet le contrôle par plusieurs processus du contrôleur Bluetooth.
  • Socket L2CAP : Permet l’envoi de données via le L2CAP implémenté dans le noyau.

Le dossier src/shared du dépôt Git de BlueZ donne accès aux composants logiciels développés pour bluetoothd. Le code est sous licence LGPL (et non GPL) ce qui permet l’utilisation dans une application sous licence non libre. Certaines bibliothèque en NodeJs, Go ou d’autres langages implémentent directement toute la pile logicielle du Bluetooth Low Energy sur le HCI pour le portage multiplateforme. Le choix du socket est à associer au nombre de processus utilisant le contrôleur et à la volonté ou non de porter la solution en dehors de Linux.

Socket HCI

Les sockets HCI sont utilisés pour interagir directement avec le contrôleur. Le noyau s’occupe de la gestion du transport HCI et échange les paquets HCI entre le socket et ce transport. Il existe deux types de canaux pour ce socket : raw channel et user channel. Le mode “user channel” permet un accès exclusif au bus HCI alors que le “raw channel” permet à toute application en espace utilisateur d’accéder en écriture.

En C, les fonctions socket et bind sont utilisées pour ouvrir la socket. Le code suivant montre comment :

int hci_create(void) {

    struct sockaddr_hci addr;
    int fd;

    if (fd < 0)
        return -errno;

    memset(&addr, 0, sizeof(addr));

    addr.hci_family = AF_BLUETOOTH;
    addr.hci_dev = HCI_DEV_NONE;
    addr.hci_channel = HCI_CHANNEL_USER;

    if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
        int err = -errno;
        return err;

    return fd;

Socket MGMT

Le MGMT est une interface de management du Bluetooth propre au noyau Linux depuis la version 3.4. Il permet d’effectuer des opérations de pilotage du contrôleur : des fonctionnalités du GAP comme l’appairage ou la connexion. Sa création a été motivée par la volonté que plusieurs applications en espace utilisateur puissent utiliser le contrôleur en même temps. L’interface est documentée dans le fichier doc/mgmt-api.txt du dépôt Git de bluez.

int mgmt_create(void) {

    struct sockaddr_hci addr;
    int fd;

    if (fd < 0)
        return -errno;

    memset(&addr, 0, sizeof(addr));

    addr.hci_family = AF_BLUETOOTH;
    addr.hci_dev = HCI_DEV_NONE;
    addr.hci_channel = HCI_CHANNEL_CONTROL;

    if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
        int err = -errno;
        return err;

    return fd;

Socket L2CAP

La couche L2CAP est implémentée dans le noyau. Le code ci-dessous montre comment connecter deux L2CAP, l’un local (ex : hci0) et l’autre distant (ex: un périphérique découvert). Il faut bien comprendre que ce sont les L2CAP qui se connectent et non pas les contrôleurs. Si la connexion au niveau de la couche liaison n’est pas établie, la connexion L2CAP échouera. Les sockets L2CAP s’utilisent donc en complément du MGMT. Des exemples d’utilisation du L2CAP peuvent être trouvés dans le dossier tools du dépôt Git comme l2ping ou l2test.

// localdevice : local device (hci0, hci1, ...) bluetooth address as string. ex : "AA:DE:AD:BE:EF"
// remotedevice : remote device bluetooth address

int l2cap_create(const char* localdevice, const char* remotedevice) {

    struct sockaddr_l2 addr;
    int sk;

    /* Create socket */

    if (sk < 0)
        return -errno;

    /* Bind to local address */
    memset(&addr, 0, sizeof(addr));
    addr.l2_family = AF_BLUETOOTH;
    str2ba(localdevice, &addr.l2_bdaddr);

    if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0)
        return -errno;

    /* Connect to remote device */
    memset(&addr, 0, sizeof(addr));
    addr.l2_family = AF_BLUETOOTH;
    str2ba(remotedevice, &addr.l2_bdaddr);

    if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0)
        return -errno;

    return sk;


Le Bluetooth Low Energy est un protocole complexe qui évolue constamment pour apporter des solutions au plus grand nombre de cas d’usage possible. La présence du standard dans les différents secteurs de l’industrie démontre son intérêt. Son implémentation logicielle dans Linux est complète malgré une architecture logicielle qui peut prêter à confusion. Les ressources pour comprendre le fonctionnement de BlueZ sont présentes mais peu explicites. Cet article avait pour objectif de réduire la barrière d’appréhension de BlueZ.


À nouveau disponible en kiosque : le guide dédié à la programmation de scripts shell !

Vous l’avez manqué ? Sachez que notre guide dédié à la programmation de scripts shell est actuellement de retour en kiosque ! Au menu : une première partie qui vous permettra de mettre le pied à l’étrier en programmant votre premier script shell, vous passerez ensuite aux choses sérieuses en vous frottant aux structures de contrôle et à la gestion de processus, et pour finir vous découvrirez les fonctions avancées du shell Bash et les bonnes techniques à adopter. Un cas pratique vous attend en bonus de ce hors-série. Retrouvez ce numéro spécial chez votre marchand de journaux, sur notre boutique en ligne ainsi que sur notre plateforme de lecture en ligne Connect !

Au sommaire


p. 08 Écrivez votre premier script « Shell »


p. 44 Utilisez les structures de contrôle et autres mécanismes de la programmation « Shell »

p. 76 Gérez vos processus et sous-processus


p. 90 Découvrez les fonctionnalités avancées du « Bash » et les bonnes pratiques


p. 112 Mise en pratique : réalisation d’un outil de contrôle de qualité de scripts « Shell »

À nouveau disponible en kiosque : le guide dédié à la programmation de scripts shell !

Vous l’avez manqué ? Sachez que notre guide dédié à la programmation de scripts shell est actuellement de retour en kiosque ! Au menu : une première partie qui vous permettra de mettre le pied à l’étrier en programmant votre premier script shell, vous passerez ensuite aux choses sérieuses en vous frottant aux structures de contrôle et à la gestion de processus, et pour finir vous découvrirez les fonctions avancées du shell Bash et les bonnes techniques à adopter. Un cas pratique vous attend en bonus de ce hors-série. Retrouvez ce numéro spécial chez votre marchand de journaux, sur notre boutique en ligne ainsi que sur notre plateforme de lecture en ligne Connect !

Au sommaire


p. 08 Écrivez votre premier script « Shell »


p. 44 Utilisez les structures de contrôle et autres mécanismes de la programmation « Shell »

p. 76 Gérez vos processus et sous-processus


p. 90 Découvrez les fonctionnalités avancées du « Bash » et les bonnes pratiques


p. 112 Mise en pratique : réalisation d’un outil de contrôle de qualité de scripts « Shell »

Unsupervised Learning

In my last few articles, I've looked into machine learning and how you can build a model that describes the world in some way. All of the examples I looked at were of "supervised learning", meaning that you loaded data that already had been categorized or classified in some way, and then created a model that "learned" the ways the inputs mapped to the outputs. more>>

JMR SiloStor NVMe SSD Drives

Compute-intensive workflows are the environments in which the newly developed JMR SiloStor NVMe family of SSD drives is designed to show its colors. more>>

The Actually Distributed Web

I thought my mind was through getting blown until I heard in mid-June 2017 that Brave raised $35 million in less than 30 seconds, though an ICO (Initial Coin Offering). I did know IC more>>

Read a Book in the Blink of an Eye!

I love reading. Sadly, the 24 hours I get per day seems to be inadequate for the tasks I need to accomplish. That might change as my teenagers turn into college kids and then begin to start families of their own. For now, however, between drama class and basketball practice, it seems like it takes about 30 hours to accomplish a 24-hour day. more>>

Kodiak Data's MemCloud

Scientists working with big data regularly confront the high cost of acquiring the computational power needed to push the boundaries and innovate in data science. more>>

Android Candy: My World, in a Lock Screen

It feels weird to mention a Microsoft product in Linux Journal. But to be honest, there are some cool things coming out of the Microsoft Garage One of those things is "Next Lock Screen", which is an Android app that brings interactive tools to the lock screen. more>>

Les LED, aujourd'hui, c'est quoi ? - Caen (14) Le 17 octobre 2017

Le Dôme, en partenariat avec CAP'TRONIC, vous invite à découvrir les ressources insoupçonnées de la technologie LED, depuis l'affichage en trichromie jusqu'à la transmission de donnée sans-fil.

"Le domaine des Diodes Électroluminescentes connaît une véritable révolution, de simples indicateurs lumineux, les LED se sont transformées en sources de lumière multicolores, puissantes et compactes.

Présentes dans de nombreuses applications comme les enseignes lumineuses, la signalisation, les phares d'automobile ou le rétro éclairage d'écrans, leur très faible consommation électrique, leur durée de vie élevée, et leur robustesse permettent aussi aux LED d'apparaitre dans les objets connectés et pour le transfert de données par la lumière des éclairages, le LiFi."

Cette rencontre organisée par le Dôme, en partenariat avec CAP'TRONIC et le Pôle ATENa pour objectif de présenter les domaines d'utilisation des LEDs, de l'éclairage à la transmission de données.

Au programme

- La Technologie LED
- Energie, Eco consommation
- La Diode LED Bleue (DLEB)
- Le Lifi, Light Fidelity comme moyen de communication

Monsieur Julien LAUDY, LUCIBEL

Informations pratiques :

Inscription en ligne

Tarif :
8 € par personne

Date :
Le 17 octobre 2017 à 18h

Lieu :
Le Dôme
Esplanade Stéphane Heissel
14000 CAEN

Contact :
CAP'TRONIC - Hugues SAINT-PAUL - 06 89 56 62 40

Linux Journal August 2017

The Wacky World of Linux

One of the nifty things about being a Linux user is how bizarre life can get. more>>

À nouveau disponible en kiosque : le guide pour débuter avec la Raspberry Pi !

Si vous l’avez manqué chez votre marchand de journaux, sachez que le hors-série n°38 de Linux Pratique est actuellement de retour en kiosque ! Pour rappel, ce guide vous fournira tout ce qu’il faut savoir pour démarrer facilement avec la Raspberry Pi : découverte de ses divers modèles, tour d’horizon et prise en main de son système phare et divers cas pratiques d’utilisation en bonus. Ce numéro spécial est évidemment toujours disponible sur notre boutique ainsi que sur notre plateforme de lecture en ligne Connect

Au sommaire


p. 08 Qu’est-ce que la Raspberry Pi ?

p. 14 Une famille, plusieurs modèles et des accessoires

Mise en route

p. 24 Préparez tout le nécessaire avant de vous lancer

p. 30 Mettez en route votre Raspberry Pi


p. 40 Tour d’horizon de votre environnement de travail

p. 48 Faisons connaissance avec la logithèque disponible


p. 66 Gérez vos paquets logiciels avec Synaptic

p. 72 Ajoutez et gérez des utilisateurs

p. 76 Contrôlez à distance votre Raspberry Pi avec VNC

p. 80 Faites de votre Raspberry Pi un media center


p. 86 Découvrez Ubuntu MATE, une alternative à Raspbian

p. 100 Hébergez un cloud personnel sur votre Raspberry Pi

p. 110 Transformez votre Raspberry Pi en console de retrogaming

p. 126 L’aventure continue…

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 :

$ bitbake linux-fslc-imx -c menuconfig

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


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 : (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 :

$ bitbake linux-fslc-imx

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 :

$ sudo cp tmp/work/imx7s_warp-poky-linux-gnueabi/linux-fslc-imx/4.1-1.0.x+gitAUTOINC+9d3f7f9343-r0/build/arch/arm/boot/zImage /media/<username>/Boot imx7s-/

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

$ sudo cp tmp/work/imx7s_warp-poky-linux-gnueabi/linux-fslc-imx/4.1-1.0.x+gitAUTOINC+9d3f7f9343-r0/build/arch/arm/boot/dts/imx7s-warp-dtb /media/<username>/Boot imx7s-/

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 :

=> setenv fdt_file imx7s-warp-relay.dtb

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 :

=> save
Saving Environment to MMC...
Writing to MMC(0)... done

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) :

=> run bootcmd
switch to partitions #0, OK
6390056 bytes read in 94 ms (64.8 MiB/s)
Booting from mmc ...
reading imx7s-warp-relay.dtb
37834 bytes read in 12 ms (3 MiB/s)
Kernel image @ 0x80800000 [ 0x000000 - 0x618128 ]
## Flattened Device Tree blob at 83000000
Starting kernel ...

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 :

root@iot:~# ls -l /dev/mikrobus/out_RL*
lrwxrwxrwx 1 root root 50 Nov 18 10:26 /dev/mikrobus/out_RL1 -> /sys/devices/platform/gpio-exporter//out_RL1/value
lrwxrwxrwx 1 root root 50 Nov 18 10:26 /dev/mikrobus/out_RL2 -> /sys/devices/platform/gpio-exporter//out_RL2/value

Liens Symboliques
Le script concernant la génération des liens symboliques est entièrement consultable sur le github des auteurs :

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 ?) :

root@iot:~# echo 1 > /dev/mikrobus/out_RL1 // Pour activer le relais
root@iot:~# echo 0 > /dev/mikrobus/out_RL2 // Pour désactiver le relais

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) :

m_relay1File = new QFile("/dev/mikrobus/out_RL1");
m_relay2File = new QFile("/dev/mikrobus/out_RL2");

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) :

#define SERVICE_UUID 0x1820
#define CHAR_UUID_RELAY1 0x2aa4
#define CHAR_UUID_RELAY2 0x2aa5

Que nous allons ensuite « caster » en QBluetoothUuid :

QBluetoothUuid serviceRelayUuid((quint32)SERVICE_UUID);
QBluetoothUuid charRelay1Uuid((quint32)CHAR_UUID_RELAY1);
QBluetoothUuid charRelay2Uuid((quint32)CHAR_UUID_RELAY2);

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 :

QLowEnergyAdvertisingData m_advertisingData;

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

//Mode d'accessibilité
//Nom du serveur
//Ajout du service Relais
m_advertisingData.setServices(QList<QBluetoothUuid>() <<

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.

QLowEnergyCharacteristicData charRelay1;
charRelay1.setUuid(charRelay1Uuid); //uuid définie de la caractéristique
charRelay1.setValue(QByteArray(2, 0));
charRelay1.setProperties(type); //précise le type de la propriété
const QLowEnergyDescriptorData clientConfig( //Descripteur standard
      QByteArray(2, 0));

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 :

//Couplage du service avec la caractéristique créée.
QLowEnergyServiceData serviceRelayData;
serviceRelayData.addCharacteristic(charRelay1); //Ajout relai 1
serviceRelayData.addCharacteristic(charRelay2); //Ajout relai 2

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 :

//création du controlleur BLE
m_bleController = QLowEnergyController::createPeripheral();
//Permettra de savoir si un client se déconnecte afin de relancer l’”advertising”
this, SLOT(controllerStateChanged(QLowEnergyController::ControllerState)));
//ajout du service
m_serviceRelay = m_bleController->addService(serviceRelayData);
//permettra de récupérer les données reçues
   this, SLOT(characteristicChanged(QLowEnergyCharacteristic,QByteArray)));
//démarrage "advertising"
m_bleController->startAdvertising(QLowEnergyAdvertisingParameters(),m _advertisingData, m_advertisingData);

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 :

void CServerBLE::characteristicChanged(QLowEnergyCharacteristic c, QByteArray data)


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]).

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 (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é (, 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 :

root@iot:~# hciconfig
hci0: Type: BR/EDR Bus: UART
      BD Address: 43:43:A1:12:1F:AC ACL MTU: 1021:8 SCO MTU: 64:1
      RX bytes:766 acl:0 sco:0 events:52 errors:0
      TX bytes:1766 acl:0 sco:0 commands:52 errors:0

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 :

//création du contrôleur avec l'addresse du serveur en paramètre
m_controller = new QLowEnergyController(QBluetoothAddress(address), this);
//on crée les connections
//Pour récupérer les services présents
//Pour savoir quand la connection est faite
//on se connecte

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() » :

//on stock l'addresse du pointeur
m_connectedService = service;
if (m_connectedService->state() == QLowEnergyService::DiscoveryRequired)
//permet de récupérer une mise à jour des caractéristiques venant du serveur
//Permet de découvrir les caractéristiques associées au service
//démarrer la découverte des caractéristiques

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 :

//on récupère le service
   QLowEnergyService *service = qobject_cast<QLowEnergyService *>(sender());
   //on récupère ses caractéristiques
   const QList<QLowEnergyCharacteristic> chars = service->characteristics();
   //on les parcours pour les traiter
   foreach (const QLowEnergyCharacteristic &ch, chars)
      //relay1, on met à jour relay1
      if (ch.uuid().toUInt32() == CHAR_UUID_RELAY1)
      m_relay1Characteristic = ch;
      m_relay1Changed = ch.value().toInt();
      Q_EMIT relay1Changed();
   //Si uuid relay2, on met à jour relay2
   if (ch.uuid().toUInt32() == CHAR_UUID_RELAY2)
      m_relay2Characteristic = ch;
      m_relay2Changed = ch.value().toInt();
      Q_EMIT relay2Changed();

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 :

void CBLEDiscover::switchRelay1(bool value)

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 :

QQmlApplicationEngine engine;
//Charger la classe
CBLEDiscover *bleDiscover = new CBLEDiscover();
engine.rootContext()->setContextProperty("BLEDiscover", bleDiscover);
//Charger le 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 :

connectButton.onClicked: {
   pageLoader.source = "Relay.qml"

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

Q_INVOKABLE void start();

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

Loader { id: pageLoader }

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 :

   if (relay1.checked == true)

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 :

Q_PROPERTY(bool relay1State MEMBER m_relay1Changed NOTIFY relay1Changed)
//valeur membre
bool m_relay1Changed;
//signal à émettre lors d’une mise à jour
Q_SIGNAL void relay1Changed();

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

relay1 {
   checked: BLEDiscover.relay1State;
   font.pointSize: 7;

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 :

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 : Se trouvera sur celui-ci :


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.


[1] Article « A la découverte de la WaRP7 » par Pierre-Jean TEXIER et Jean CHABRERIE, Open Silicium n°20
[2] Site d’Element14 :
[3] Page NXP présentant l’architecture du i.MX7 :
[4] Documentatio du projet Yocto (version 2.1 : krogoth) :
[5] Documentation relative à l’outil repo :
[6] Couche distribution des auteurs :
[7] Ensemble des cartes « click » par MikroElektronika :
[8] Documentation dans les sources du Noyau Linux sur l’utilisation des GPIO en espace utilisateur :
[9] Driver gpio-exporter :
[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 :
[13] Spécifications des services bluetooth :
[14] Spécifications des caractéristiques bluetooth :
[15] Article « IoT sous Yocto, un cas d’utilisation » par Pierre FICHEUX, Open Silicium n°20
[16] Explication de la macro Q_INVOKABLE :
[17] Explication de la macro 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 !

CAP'TRONIC vous invite à une visite showroom CEA Tech - Grenoble (38) Le 22 septembre 2017

Aux PME qui développent des produits intégrant de l'électronique et désireuses de découvrir les innovations & technologies du CEA Tech, CAP'TRONIC organise une visite du showroom (dans le cadre du dispositif EASYTECH)

Sur les 400 m² du showroom plusieurs dizaines de maquettes fonctionnelles présentent des technologies et des systèmes issus des laboratoires. Objectif : stimuler la créativité des visiteurs industriels pour faire émerger de nouvelles idées ou adapter des résultats de recherche à de nouveaux domaines applicatifs.
Les quelques 150 démonstrateurs présentés illustrent notamment les recherches menées dans les domaines variés : santé, habitat, transport, logistique, informatique, énergie, matériaux, loisirs numériques…, etc.
De nouveaux démonstrateurs issus des programmes de R&D viennent régulièrement nourrir cette vitrine technologique.

La visite en groupe (20 personnes maximum) sera suivi d'une présentation des activités du département DSYS (Département Systèmes) du CEA Leti et des dispositifs d'aide aux PME EASYTECH & CAP'TRONIC.

Inscription en ligne

Swan GEROME - CEA Leti & Marc DONIKIAN - CEA Leti,
Damien COHEN - Minalogic/Easytech,


  • 9H00-9h15 Accueil-café
  • 9h30- 11h00 Visite du showroom
  • 11H15-12H00 Présentations & networking


Personnes concernées : Ingénieurs, techniciens, chefs d'entreprises issus de TPE/PME/ETI qui développent des produits intégrant de l'électronique

Date : Le vendredi 22 septembre 2017 matin

CEA Grenoble
17 avenue des martyrs

=> Privilégier Entrée 4 côté Minatec/Phelma si vous êtes à pied.
Dans tous les cas, vous présenter à l'accueil pour retirer votre badge (prévoir un peu de marge pour arriver jusqu'au showroom).

Contact inscription : Vincent LAGNIER - 04 38 78 37 36


Carte Nationale d'Identité ou Passeport obligatoire à nous fournir scanné lors de votre inscription ( et à amener le jour même pour entrer sur le site (permis de conduire non accepté)

Prix : Gratuit.

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

L’important choix de cartes intégrant des capteurs/actionneurs, en fait aujourd’hui, un choix difficile pour l’utilisateur final. C’est pour ces raisons que MikroElektronika a créé un standard : MikroBUS. Il facilite l’interaction entre microcontrôleur ou microprocesseur et les cartes d’extensions, appelées « add-ons », utilisant cette connectique. Cet article se propose d’explorer la partie MikroBUS d’un des tous derniers SBC (Single Board Computer) du marché : la WaRP7 (« WearAble Reference Platform »). On commencera dans un premier temps par une succincte présentation de la WaRP7 et d’une partie « board bring-up » (via Yocto/OE). Puis, viendra la partie MikroBUS qui sera mise en avant à travers un mini projet architecturé autour du Bluetooth Low Energy et du framework Qt5 pour Android tout en y intégrant une carte add-ons, carte qui se base sur le standard MikroBUS.

Le présent article s’inscrit dans la continuité des manipulations ayant permis la rédaction d’un article précédent paru dans le n°20 d’Open Silicium [1], les auteurs renverront vers celui-ci les lecteurs qui désirent avoir de plus amples connaissances sur la diversité que propose la cible utilisé dans ce numéro de Linux Magazine. Dans le premier article, il était question de découvrir la WaRP7 et ses capteurs au travers une application « IoT » minimaliste (récupération d’une température, la pression atmosphérique ainsi qu’une valeur représentant le rythme cardiaque), ceci en utilisant la connectivité Bluetooth et le framework Qt5, le tout basé sur une distribution Yocto/OE mis à disposition par les auteurs.

Que le lecteur ne pouvant pas se procurer le premier article soit rassuré, on se permettra tout de même ici de faire des rappels (ouf !) quant aux éléments essentiels (présentation de la cible, génération et installation de l’image sur notre cible, une partie Bluetooth, puis quelques mots sur le SDK Yocto/Qt5).

1. Introduction

1.1 La cible : « WaRP7 », petit rappel

La plateforme cible [2] est composée de 2 cartes :

  • Une carte « fille », qui est construite autour d’un System on Chip NXP i.MX7 Solo [3] (avec un coeur Cortex A7 + un coeur Cortex M4). De plus, cette carte embarquera la gestion de la connectivité (Wifi/BLE) ;
  • Une carte « mère », qui contiendra l’ensemble des capteurs (Gyroscope, Altimètre, etc.), ainsi que l’extension MikroBUS (qui nous intéresse particulièrement dans cet article).

Fig. 1: Non, la WaRP7 n’est pas timide

1.2 Construction de notre distribution « IoT »

La génération de la distribution pour notre cible, repose sur l’utilisation du BSP (Board Support Package) NXP articulé autour du projet Yocto [4] et de deux couches supplémentaires (nous ne ferons pas ici, de détails quant à l’utilisation de Yocto/OE, le lecteur pourra en outre, se référer aux différents articles parus dans les précédents numéros d’open silicium).

La première étape consiste donc à récupérer l’ensemble des sources contenues dans le BSP. Pour ce faire, NXP utilise l’utilitaire repo (outil Python développé par Google [5]), ceci afin de permettre une meilleure gestion des référentiels Git compris dans celui-ci :

$ mkdir ~/bin
$ curl > ~/bin/repo
$ chmod a+x ~/bin/repo
$ PATH=${PATH}:~/bin
$ mkdir warp7_glmf200
$ cd warp7_glmf200
$ repo init -u -b krogoth
$ repo sync

Comme prévu, après récupération de notre base logicielle, nous pouvons maintenant télécharger les deux couches supplémentaires essentielles à la bonne construction de notre image.

Téléchargeons dans un premier temps la couche distribution mis à disposition par les auteurs [6], pour rappel, cette couche spécifique est intimement liée à l’article (ceci afin de ne pas se perdre dans le framework qu’est Yocto/OE) :

$ cd sources/
$ git clone

Dans un second temps, récupérons la couche permettant d’intégrer l’environnement Qt5 à notre distribution :

$ cd sources/
$ git clone

Nous voilà maintenant en possession de l’ensemble des sources. L’étape d’après consiste en la création de l’environnement, on retrouve ci-après les différentes étapes :

  • création du dossier de construction warp7-build/,
  • appel du script oe-init-build-env,
  • mise à jour de la variable MACHINE,
  • puis un prompt concernant la licence FSL EULA (à accepter).

La commande suivante s’occupera donc de nous placer dans un environnement de travail spécifique à notre plateforme de développement :

$ MACHINE=imx7s-warp source setup-environment warp7-build/

Il reste maintenant à définir les chemins vers les couches précédemment téléchargées, pour ce faire, modifions le fichier conf/bblayers.conf pour y rajouter les deux lignes suivantes :

${BSPDIR}/sources/meta-iot \
${BSPDIR}/sources/meta-qt5 \

Dernière étape avant de pouvoir lancer la construction de l’image, il nous faut spécifier la distribution utilisée (dans notre cas une distribution spécifique à l’article dérivé de la distribution poky) dans conf/local.conf, en mettant à jour la variable DISTRO :

DISTRO ?= 'iot'

Lançons maintenant la construction de notre image par le biais de la commande bitbake :

$ bitbake iot-qt-image

Après cette longue étape qu’est la construction, l’utilisateur pourra retrouver très facilement l’ensemble des fichiers utiles au bon démarrage de la plateforme (Bootloader, Kernel, RootFileSystem) dans tmp/deploy/images/imx7s-warp.


1.3 Premier Flash, premier Boot, …

Rappelons qu’afin de mettre à jour le système avec l’ensemble des binaires compilés, les étapes se déroulent comme suit :

  • Connexion en liaison série (via un émulateur de terminal comme microcom), puis arrêt de l’auto-boot au niveau du bootloader (u-boot) :

$ microcom --speed 115200 --port /dev/ttyUSB0
U-Boot 2016.07+fslc+ge6b4241 (Sep 14 2016 - 11:21:52 +0200)
CPU: Freescale i.MX7S rev1.2 at 792MHz
Hit any key to stop autoboot: 0

  • Montage de la partition eMMC côté bootloader :

=> ums 0 mmc 0

  • Décompression et opération de copie coté système hôte sur le device spécifique :

$ cd tmp/deploy/images/imx7s-warp
$ gunzip qt-image-imx7s-warp-20161118195314.rootfs.sdcard.gz
$ sudo dd if=qt-image-imx7s-warp-20161118195314.rootfs.sdcard of=/dev/sdX (où X représente le device)

Une fois la copie terminée, l’utilisateur pourra redémarrer la carte pour voir apparaître la séquence de démarrage :

Starting kernel ...
Booting Linux on physical CPU 0x0
Linux version 4.1.32-fslc+g9d3f7f9 (pjtexier@bdxiot) (gcc version 5.3.0 (GCC) ) #1 SMP PREEMPT
IOT powered by Yocto/OE (Welcome to Bordeaux) 2.1.1 iot /dev/ttymxc0
iot login: root
Password: iot
___ ___ _____
|_ _/ _ \_ _|
| | | | || |
| | |_| || |
|___\___/ |_|


1.4 Activation de l’interface Bluetooth

Rappelons ici, comment attacher, initialiser et activer notre interface Bluetooth, afin que celle-ci soit accessible par les autres périphériques compatibles :

root@iot:~# hciattach ttymxc2 bcm43xx 3000000 flow -t 20
root@iot:~# hciconfig hci0 up
root@iot:~# hciconfig hci0 name 'Hello GLMF200' // Nom de l'interface visible depuis n'importe quel périphérique bluetooth
root@iot:~# hciconfig hci0 piscan

1.5 SDK Qt5

1.5.1 Génération

Nous avons évoqué lors de l’article précédent la notion de SDK et chaîne de compilation croisée (mais pas que). Ceci afin de pouvoir générer du code Qt5 sur notre cible. La commande ci-dessous permettra la génération d’un SDK générique et compatible Qt5 :

$ bitbake meta-toolchain-qt5

Une fois la génération terminée, le script d’installation du SDK se trouvera dans tmp/deploy/sdk.

1.5.2 Installation

Elle se fera tout simplement en exécutant le script suivant où il conviendra de spécifier le chemin d’installation (/opt/iot/sdk dans cet exemple) :

$ cd tmp/deploy/sdk
IOT powered by Yocto/OE (Welcome to Bordeaux) SDK installer version 2.1.1
Enter target directory for SDK (default: /opt/iot/2.1.1): /opt/iot/sdk

1.5.3 Intégration à l’IDE Qt creator

Afin de se voir l’environnement de compilation croisée, intégré à notre IDE préféré, il nous faudra :

  • Dans Outils > Options > Compiler et Exécuter
  • Puis dans la section Compilateurs > Ajouter , choisir « GCC »
  • On donnera un nom à notre GCC spécifique (par exemple WaRP7_GLMF200),
  • Puis nous spécifierons le chemin du compilateur : /opt/iot/sdk/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-gcc
  • Dans Versions de Qt, Qt est normalement automatiquement détecté. Sinon le lecteur devra ajouter le chemin vers qmake : /opt/iot/sdk/sysroots/x86_64-pokysdk-linux/usr/bin/qt5/qmake
  • Dans Kits, il ne reste plus qu’à choisir les éléments précédemment mis en place (Compilateur et version), il sera aussi recommandé de spécifier le mkspecs « linux-oe-g++ » :

2. MikroBUS

Dans cette partie nous aborderons, dans un premier temps, le standard MikroBUS, nous présenterons autant les aspects matériels que les aspects logiciels que propose celui-ci. Nous ferons ensuite un bref tour d’horizon sur les modules que propose MikroElektronika.

2.1 Le standard : introduction

Le standard MikroBUS définit les connectiques des cartes principales (on parle souvent de carte mère) ainsi que celles des cartes additionnelles (add-on) utilisées pour l’interfaçage du microcontrôleur ou du microprocesseur avec les circuits et modules complémentaires. De plus, il spécifie la disposition physique du brochage, les broches de communication et les broches d’alimentation utilisées.

On remarque, bien évidemment, que l‘objectif de mikroBUS est de jouer sur la flexibilité matérielle, permettant ainsi un interfaçage plus facile avec un grand nombre de cartes complètes, qui plus est, standardisées (plus de 200 modèles commercialisés par MikroElektronika tout de même !), chacune avec un simple capteur (humidistance), un module radio (RFID), un écran (OLED), une connectique (RS232), ou tout autre module électronique[7].

A noter que mikroBUS est un standard ouvert et donc n’importe qui peut prétendre implémenter mikroBUS dans sa conception matérielle, à condition bien sûr de respecter les conditions de MikroElektronika.

2.2 Le standard : Description du connecteur MikroBUS

Le connecteur MikroBUS est composé de 16 broches (2×8). L’ensemble de celles-ci est toujours positionné de la même manière comme le montre la figure 2.

Fig. 2: pinout du standard MikroBUS

On retrouvera sur chaque module :

  • Des broches par type de bus de communication : SPI, UART, I2C.
  • 4 broches complémentaires : PWM (ou MLI en français), interruption matérielle (INT), entrée analogique (AN) et reset (RST).
  • Puis un couple pour les alimentations :
  • 3,3V / GND
  • 5V / GND

2.3 Quelques Examples :

Il est bien évidemment compliqué de présenter ici l’ensemble des modules proposés par la firme MikroElektronika. Afin de donner au lecteur un bref aperçu des cartes disponibles, les auteurs auront choisi d’en exposer 2 au travers de cet article :

2.3.1 La « Relay Click Board » :

Fig. 3: La Relay Click sous les projecteurs

Cette carte embarque deux relais de puissance (G6D1AASI-5DC de référence Omron). Le pilotage vers la carte principale (dans notre cas la WaRP7) s’effectue via les broches suivantes du connecteur MikroBUS :

  • Broche PWM pour le Relais 1 (RL1),
  • Broche CS pour le Relais 2 (RL2).

De notre point de vue, ce ne sera ni plus ni moins que l’activation (état haut ou état bas) d’une broche GPIO (ouverture ou fermeture du relais).

2.3.2 La « custom » :

Fig. 4: L’inconnu au bataillon

Comme remarqué précédemment, il est possible de réaliser sa propre carte autour du standard MikroBUS. Dans cet exemple, le module est composé d’un gpio expander (microchip mcp23s08) pilotable au travers d’une interface SPI (mais aussi via le bus i2c). Cette option permet d’étendre les capacités de la carte principale quand celle-ci arrive à ses limites (ou si aucune GPIO physique n’est présente sur la carte mère).

3. Jouons un peu avec la « relay click board »

Viens maintenant le temps de jouer un peu avec notre module MikroBUS, celui-ci permettant d’étendre les capacités de notre WaRP7, nous mettant ainsi des relais à disposition (ceci afin de commander par exemple une lampe, ou tout autre objet …). Dans ce chapitre nous verrons comment les piloter de façon simpliste en accédant aux GPIO depuis l’espace utilisateur. Nous aborderons ensuite le sujet du device tree et l’accès à la configuration des GPIO depuis celui-ci.

3.1 Plug !

Insérons notre module relais et constatons qu’il est très facile d’intégration entre notre plateforme cible et les modules MikroBUS (WaRP7 <-> Relay Click Board), ceci grâce à la standardisation :

Fig. 5 : La WaRP7 en position !

3.2 And Play !

Sous GNU/Linux, l’accès aux GPIO [8] s’effectue dans /sys/class/gpio/gpioN où N représente le numéro de la GPIO (à condition que le driver associé soit présent → GPIO_SYSFS).

Nous savons par le biais de la schématique (disponible en [2]), que le relais 1 et sur la broche CPU « GPIO7_IO8 », qui, en espace utilisateur devient gpio200.

Comment calculer le numéro de gpio utilisé en mode userspace ?
Le calcul est sous la forme :
((port_GPIO – 1)*32) + n°gpio.
Exemple pour le relais 1 : ((7-1)*32) + 8 = 200

La première étape consistera à exporter cette GPIO pour la rendre accessible depuis le système de fichier virtuel /sys, la commande si après créera donc un point d’accès gpio200 :

root@iot:~# echo 200 > /sys/class/gpio/export

L’interface étant disponible, il nous faut la paramétrer en tant que broche de sortie :

root@iot:~# echo out > /sys/class/gpio/gpio200/direction

Une fois configurée, il nous est possible de la piloter, ceci en agissant simplement sur la tension de sortie de la broche, via la commande suivante :

root@iot:~# echo 1 > /sys/class/gpio/gpio200/value

La broche de sortie passée à l’état haut, il nous est facile de constater le résultat sur la carte relais (led REL1), comme nous le montre la figure 6 :

Fig. 6: Relais 1 en fonctionnement

Nous ferons de même pour le relais numéro 2 (RL2 sur la « relay click ») qui lui est sur « GPIO4_IO23 » :

root@iot:~# echo 119 > /sys/class/gpio/export
root@iot:~# echo out > /sys/class/gpio/gpio119/direction
root@iot:~# echo 1 > /sys/class/gpio/gpio119/value

Fig. 7 : Relais 2 en fonctionnement

3.2 Intégration au device-tree : « gpio-exporter & pin-muxing »

L’inconvénient des étapes (export/direction) précédentes réside dans le fait qu’il nous est obligatoire de les réexécuter à chaque démarrage de la WaRP7, car non statique au sein de la configuration matérielle. Il serait donc intéressant d’avoir une entrée statique. Nous irons un peu plus loin que la simple configuration des GPIO.

En effet, il serait aussi plaisant de pouvoir associer un nom à nos GPIO lors de la configuration de celles-ci, pour ce faire, nous intégrerons le travail de Martin FUZZEY[9] (qu’on ne manquera pas de remercier pour le travail effectué), qui a en effet développé un driver Kernel permettant d’avoir au sein de l’espace utilisateur, un lien nom/numéro de GPIO. L’avantage de cette solution est que finalement, l’utilisateur ne se soucie plus du numéro de la GPIO, de ce fait, la configuration est beaucoup plus portable et maintenable.

3.2.1 Device tree : une petite introduction

L’arbre de périphériques (device tree ou encore DT) est une structure de données permettant de décrire le matériel d’un système, dérivée du format utilisé par Open Firmware pour encapsuler les informations de plateforme et les transmettre au noyau, qui utilise alors les données du DT pour trouver et enregistrer les périphériques du système.

La structure de données elle-même est un arbre de nœuds nommés et de propriétés. Chaque nœud contient des propriétés de simples paires « nom-valeur » et des nœuds fils. Afin d’être interprétée correctement par le noyau, l’arborescence doit suivre une structure prédéfinie. Une « liaison » (en anglais, binding) est une description de la façon dont un périphérique est décrit dans le DT. Un grand nombre de périphériques disposent de liaisons bien établies et documentées.

3.2.2 Anatomie de notre fichier dts « imx7s-warp-relay.dts »

Afin de ne pas surcharger le fichier dts (device tree source) principal (imx7s-warp.dts), les auteurs auront choisi de créer un fichier dts spécifique à l’intégration du module « relay click », en voici sa constitution :

#include "imx7s-warp.dts"

/ {

      gpio_exporter: gpio-exporter {
         compatible = "linux,gpio-exporter";
         pinctrl-names = "default";
         pinctrl-0 = <&pinctrl_gpioexporter_relay>;

         out_RL1 {
            gpios = <&gpio7 8 GPIO_ACTIVE_HIGH>;
            initial-state = <0>;

         out_RL2 {
            gpios = <&gpio4 23 GPIO_ACTIVE_HIGH>;
            initial-state = <0>;

&iomuxc {
      pinctrl-names = "default";
      imx7s-warp {
         pinctrl_gpioexporter_relay: gpioexportergrp {
            fsl,pins = <
               MX7D_PAD_ENET1_RGMII_TD2__GPIO7_IO8 0x14
               MX7D_PAD_ECSPI2_SS0__GPIO4_IO23 0x14

Essayons de détailler celui-ci :

  • #include « imx7s-warp.dts » fera référence au fichier principal la WaRP7 (définition de la carte), qui lui-même inclus la définition du SoC (System on Chip) i.MX7 (imx7d.dtsi).
  • Au niveau du contenu du fichier :
  • La création d’un nœud (node) avec son label associé, que l’on appellera gpio-exporter :

gpio_exporter: gpio-exporter {
   compatible = "linux,gpio-exporter";

  • Le mot clé compatible est une propriété qui permettra de faire le lien avec la partie driver (respectant la règle du plateform driver comme présenté par Pierre Ficheux en [10]). Ceci via la structure of_device_id qui sera utilisée avec le tableau gpio_exporter_dt_ids[]. Le lecteur curieux pourra jeter un coup d’oeil au code source dans tmp/work/imx7s_warp-polky-linux-gnueabi/linux-fslc-imx/4.1-1.0.x+gitAUTOINC+9d3f7f9343-r0/git/drivers/gpio/gpio-exporter.c :

static const struct of_device_id gpio_exporter_dt_ids[] = {
   { .compatible = "linux,gpio-exporter", },
} ;

  • La propriété pinctrl-0 permet de donner la liste des broches qui seront soumises à une définition spécifique de leur état, ceci grâce au sous-système pinctrl qui permet de gérer le multiplexage des broches. Dans notre cas, la configuration s’effectuera dans le nœud fils pinctrl_gpioexporter_relay

pinctrl-0 = <&pinctrl_gpioexporter_relay>;

  • Il convient ensuite de créer un nœud fils (child node), le nom de celui-ci représentera le nom exposé au sein de l’espace utilisateur, nous garderons la même syntaxe que la carte « relay click », à savoir RL1 pour le pilotage du relais 1 :

out_RL1 {
      gpios = <&gpio7 8 GPIO_ACTIVE_HIGH>;
      initial-state = <0>;

Il nous faudra aussi renseigner les propriétés à notre nœud fils :

  • gpios : Référence vers la GPIO à exporter (binding standard défini dans les sources du Noyau Linux : Documentation/devicetree/bindings/gpio/gpio.txt). En plus du phandle (nœud vers le contrôleur associé), nous retrouverons le numéro de GPIO, 8 pour notre application. Puis le second argument signifie que celle-ci est active sur un niveau haut (GPIO_ACTIVE_HIGH).
  • output : pour spécifier que l’on désire la positionner en sortie,
  • initial-state : où on fixera sont état initial (état bas dans notre cas)

Il en sera de même pour le relais numéro deux, où seul le nom du sous-nœud et de la GPIO associé seront donc à modifier pour le piloter :

out_RL2 {
      gpios = <&gpio4 23 GPIO_ACTIVE_HIGH>;
      initial-state = <0>;

Nous en resterons là quant à la présentation du fichier device tree, le lecteur pourra se référer au très bon article écrit par Thomas Petazzoni paru dans le n°17 d’Open Silicium [11].

Pierre-Jean TEXIER
[Ingénieur Linux Embarqué, Intervenant Linux Embarqué à ESTEI Bordeaux ,
Co-auteur de l’ouvrage « Yocto For Raspberry-pi »]

[Ingénieur Systèmes Embarqués, Qt Enthousiaste]

La seconde partie de cet article sera publiée prochainement sur le blog, restez connectés 😉

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 !

Dissémination de données géoréférencées – qgis-server et OpenLayers – Partie 2/2

4. À la pointe de la technologie : OpenLayers 3

Dans la course aux fonctionnalités, nous ne cessons de casser ce qui marche pour mettre à jour les nouvelles fonctionnalités. Pourquoi donc casser ce bel exemple OpenLayers2 pour le remplacer par OpenLayers3 ? La déformation excessive des cartes aux latitudes élevées est un défaut bien connu de la projection de Mercator utilisée par défaut par tous les environnements cartographiques de la toile (projection de code 900913 – l’écriture leet de Google – puisque la norme choisie n’a pas été validée par l’instance qu’est l’EPSG). Étant conscients des déficiences de la projection de Mercator, nous voudrions pouvoir sélectionner un mode de projection localement tangent à la région considérée – à savoir Universal Transverse Mercator (UTM). Et nous en arrivons à l’excuse pour passer de OpenLayers 2 à 3 : la version actuelle d’OpenLayers ne permet pas la projection au vol des images, et impose donc une sortie déformée, particulièrement gênante lorsque nous nous éloignons de l’équateur.

Nous reprenons donc toutes nos investigations, mais cette fois dans le contexte d’OpenLayers 3, avec la nécessité pour chaque nouvelle couche de préciser le mode de projection d’entrée (toutes nos données sont stockées en coordonnées sphériques, donc WGS84 de code EPSG:4326. OpenLayers ne connaît pas tous les modes de projection de sortie : nous devons les définir selon nos besoins (voir figure 5).

Fig. 5: Gauche : le passage à une projection locale WGS84/UTM33N résout la déformation observée auparavant dans OpenLayers 2 et son Google Mercator. Cependant, cette projection n’a pas prétention de s’étendre à tout le globe, et réduire le grossissement met en évidence la déformation sur les régions adjacentes, ici le nord Canada et la Sibérie (droite). Cet exemple est disponible sur


Heureusement, proj4 se charge de cette opération pour nous, et nous informe de la façon de définir WGS84/UTM33N (la bande qui couvre la Norvège – nous aurions choisi UTM31N pour la France). Ainsi, le mode de projection qui va nous intéresser se définit par :

proj4.defs('EPSG:32633','+proj=utm +zone=33 +ellps=WGS84 +datum=WGS84 +units=m +towgs84=0,0,0 +no_defs');

Et nous pouvons faire appel aux outils de conversion de la forme :

var osmLayer = new ol.layer.Tile({ source: new ol.source.OSM() });
var map = new ol.Map({
   controls: ol.control.defaults().extend([new ol.control.ScaleLine()]),
   target: 'map',
   view: new ol.View({projection: 'EPSG:32633',center: ol.proj.fromLonLat([10, 79], 'EPSG:32633'),zoom: 9})
var dm_wms2013 = new ol.layer.Tile({
   preload: Infinity,
   visible: true,
   source: new ol.source.TileWMS(({
      url: '',
      params: {'LAYERS': '2013_0830utm33n', 'TILED': true, 'VERSION': '1.3.0',
      'FORMAT': 'image/png8', 'WIDTH': 256, 'HEIGHT': 256, 'CRS': 'EPSG:4326'},
      serverType: 'geoserver'


Ici la projection de la carte respecte la norme EPSG (WGS84/UTM33N s’appelle EPSG:32633) que nous avons défini par proj4 auparavant, tandis que les données en entrée (ici issues de la fonction WM(T)S du serveur) sont au format WGS84 en coordonnées sphériques (aussi nommée EPSG:4326).

5. Ajout automatique de toutes les couches WMS d’un projet qgis-server dans OpenLayers2

Une dernière question que nous pouvons nous poser, dans le contexte d’un travail collaboratif où chaque utilisateur est susceptible d’ajouter ses propres couches, tient en la capacité à automatiser la génération d’une page Web contenant toutes les couches fournies par un serveur QGis. Cela signifie donc récupérer la description XML des capacités du serveur, découper cette description pour extraire le nom des couches disponibles, et finalement générer automatique le script JavaScript affichant toutes ces couches. De telles fonctionnalités sont fournies (paquet php-xml dans la distribution Debian) par simplexml. Ainsi, un premier script qui se contente de lister toutes les couches disponibles en recherchant d’abord les fonctionnalités WMS du serveur, puis en étudiant [5] la liste des propriétés (FeatureTypeList) et finalement les propriétés de chacun de ces objets (FeatureType) pour en extraire le nom (FeatureTypeList->FeatureType->Name) ressemble à :

<html><head><title>XML depuis PHP</title></head><body>
   if (extension_loaded(’simplexml’)) {
      echo "extension installed:<hr>";
      $mypix = simplexml_load_file(urlencode(
         ’ SERVICE=WFS&VERSION=1.0.0&REQUEST=GetCapabilities’));
         foreach ($mypix->FeatureTypeList as $pixinfo):
            foreach ($pixinfo->FeatureType as $nam):
               if ($nam->Name!=’’) echo $nam->Name,"<br>";
   else echo "missing extension<br>";


Ayant compris ce mécanisme, il devient simple de générer les champs décrivant chaque couche WMS affichée, en lui attribuant le même nom de couche que celui utilisé dans QGis. Le résultat est :

<html><head><title>Toutes les couches WMS depuis openlayers</title>
   <script src=""></script>
   <div style="width:100%;height:100%" id="map"></div>
   <script defer="defer" type="text/javascript">
      var map=new OpenLayers.Map(’map’);
      ls=new OpenLayers.Control.LayerSwitcher({’div’:OpenLayers.Util.getElement(’layerswitcher’)});
      var wms=new OpenLayers.Layer.WMS("Basic map",
         "",{layers: ’basic’} );
   if (extension_loaded(’simplexml’)) {
      $mypix = simplexml_load_file(urlencode(
      foreach ($mypix->FeatureTypeList as $pixinfo):
         foreach ($pixinfo->FeatureType as $nam):
            if ($nam->Name!=’’)
               {echo "var dm_",$k,"=new OpenLayers.Layer.WMS(\"",$nam->Name,"\",";
                echo "\"\",";
                echo "{layers: \"",$nam->Name,"\",";
                echo "transparent:\"true\", format:\"image/png\"},{isBaseLayer: false});\n";
      echo "map.addLayer(wms);\n";
      echo "map.setCenter(new OpenLayers.LonLat(12,79),9);\n";
      for ($x=1;$x<$k;$x++) {echo "map.addLayer(dm_$x);\n";}
   } else echo "missing extension<br>";

Ce qui donne la figure 6. Il serait d’une part très fastidieux d’ajouter à la main toutes les couches de ce projet, mais surtout dans cet exemple l’affichage s’adapte automatiquement aux nouvelles couches ajoutées par les divers contributeurs au projet.

Fig. 6: Ajout automatique de toutes les couches fournies par un serveur WMS sur dans un contexte d’OpenLayers2. Le script d’exemple /opt/qgis-server/plugins/HelloServer qui affiche le logo de QGis a été volontairement laissé en place pour distinguer le serveur en production ( du serveur de tests (


6. Ajout d’images orthorectifiées produites par microdrone

Nous avions présenté le flux de traitement permettant de générer une série d’images orthorectifiées et de modèles numériques d’élévation associés avec le souci de comparer ces jeux de données entre eux, mais sans prétention de les positionner dans un référentiel absolu partagé par convention entre plusieurs utilisateurs. Il s’avère [6] que la solution de simplement translater un jeu de données par rapport à l’autre ne suffit plus lorsque la zone considérée s’étend sur plusieurs hectares. Nous avons observé que dans ce cas, le positionnement par GPS (mono-fréquence, telle que fournie sur microdrone DJI Phantom3 Professional) n’est exact qu’à une dizaine de mètres, alors que nous visons un positionnement au décimètre près pour des comparaisons de vols successifs. Il s’avère que vouloir corriger les défauts d’échelle et de position du modèle numérique d’élévation en lui appliquant les corrections permettant de superposer les images orthorectifiées est une approche peu judicieuse, et qu’il vaut mieux insérer dans le flot de traitement l’étape d’exploitation des points de contrôle au sol pour corriger les défauts du modèle de caméra et de leur position ( Pour notre part, les points de contrôle au sol (GCP) sont acquis a posteriori dans Google Earth – les coordonnées sphériques fournies avec 6 décimales sont précises à 11 cm à l’équateur : 7 points aisément reconnaissables dans les jeux de données sont d’une part identifiée dans Google Earth (bandes de parking, barrière, coin à la base de bâtiments) avec des coordonnées converties de coordonnées sphériques (WGS84) vers un référentiel projeté localement tangent à la Terre (WGS84/UTM31N), et d’autre part leur position (en pixel) identifiée sur les images acquises par drone. Ce couple de fichiers (coordonnées dans l’espace v.s coordonnées sur les photographies) alimente l’outil Campari de Micmac. Après traitement dans ces conditions, nous observons une exactitude de position par rapport aux couches vectorielles de Openstreetmaps mais surtout par rapport à une image aérienne de l’IGN (BD ORTHO, convertie de Lambert93 à WGS84/UTM31N puisque nous avons vu que OpenLayers 2 ne sait pas le faire à la volée) meilleure qu’une vingtaine de centimètres – erreur attribuable à notre manque d’assiduité à pointer les points de contrôle. Ce jeu de données est disponible sur

Fig. 7: Résultat de l’insertion de trois images orthorectifiées, en comparaison de données de référence que sont les images aériennes de la BD ORTHO de l’IGN et les données vectorielles de Opensteetmaps. En haut à gauche : deux images orthorectifiées acquises à 30 minutes d’intervalle positionnées au moyen de 7 GCPs. En haut à droite : le même jeu de données, positionné uniquement par les positions GPS du drone au moment de la prise de vue. Le trait rouge, indiquant la différence de position, est long de 9,8 m. En bas à gauche : superposition d’une image produite par drone (moitié gauche) avec une image IGN (moitié droite). En bas à droite : comparaison de deux orthophotos produites à un mois d’intervalle.


Nous avons proposé un environnement de travail permettant de disséminer des informations géoréférencées soit vers des utilisateurs de logiciels dédiés de gestion de systèmes d’informations géographiques (SIG) ou vers les API Web associées (OpenLayers). Est-ce que ce mode de dissémination est réellement utilisé en pratique ? L’institut polaire norvégien (NPI) propose ses informations dans ce format tel que décrit sur Ainsi, sous QGis, configurer l’onglet WM(T)S vers donne accès aux informations bitmap que sont les photographies aériennes de très haute résolution (jusquà 16 cm/pixel !) tandis que l’url dans l’onglet WFS donne accès aux informations vectorielles que sont les limites des glaciers extraites des images satellitaires SPOT.

Le lecteur est encouragé à reproduire ces expériences sur ses propres zones d’intérêt. Compte tenu de la résolution médiocre de Landsat, le résultat est peu convaincant pour la vallée de Chamonix, mais les glaciers groenlandais (Illulisat près de la baie de Disco) ou la banquise antarctique sont parfaitement appropriés à cette démonstration, voir la mer d’Aral sur (un peu pénible à assembler car de superficie supérieure à ce que le site de l’USGS permet d’analyser) ou la mer morte sur et pour laquelle l’extension des bassins d’exploitation du sel est particulièrement visible. Le lecteur saura-t-il calculer la surface ainsi affectée ? Indice : tracer un polygone avec l’outil New Shapefile puis dans la table des attributs, créer un nouveau champ pour chaque polygone avec la variable $area.

Une autre voie d’étude qui semble intéressante dans le cadre de la diffusion sur le Web de données géoréférencées est qgis2web, greffon de QGis actuellement inexploitable sous Debian testing/sid compte tenu d’une dépendance cassée. Finalement, étant donné que toutes les informations pertinentes à une utilisation en surface sont disponibles sur OpenStreetMaps, ne serait-il pas temps de commencer à considérer la cartographie des services sous terrains (eau, gaz, électricité), qui même s’ils sont propriété de leurs exploitants respectifs, sont devenus des services nécessaires au quotidien d’un habitant d’Europe occidentale actuel : chaque kilomètre de route contient plusieurs dizaines de kilomètres de services sous terrains [7] qui ne demandent qu’à être cartographiés à l’occasion des ouvertures de routes.

Jean-Michel FRIEDT
[Institut FEMTO-ST, dpt. Temps-fréquence, Besançon]

Émile Carry
[Institut FEMTO-ST, dpt. Temps-fréquence, Besançon]

Références et Notes

[1] PIERROT-DESEILLIGNY M. et FRIEDT J.-M, « La photogrammétrie pour tous : MicMac pour la reconstruction 3D de scènes géoréférencées à partir de photographies numériques », tutorial à FOSS4G-fr 2016, décrit sur
[2] FRIEDT J.-M. Friedt, TOLLE F., et BERNARD É., « Utilisation de Micmac pour la génération de modèle numérique d’élévation par traitement d’images acquises par microdrone », GNU/Linux Magazine France 191, pp.48–57 (Mars 2016)
[3] ERLE S., GIBSON R., et WALSCH J., « Building the geospatial web », dans « Mapping Hacks – Tips & Tools for Electronic Cartography », O’Reilly (2005)

[4] GIBSON R. et ERLE S., « Google Maps Hacks – Tips & Tools for Geographic Searching and Remixing », O’Reilly (2006)
[5] Les divers champs se déduisent de l’analyse de la sortie de wget -O – « »
« Détection de l’érosion dans un bassin versant agricole par comparaison d’images multidates acquises par drone », Colloque Drones et moyens légers aéroportés d’observation, 26/06/2014 (Montpellier), disponible sur
Chaque kilomètre de route à Hong-Kong recouvre 47 km de services enterrés, ou, ou en d’autres termes il existe 47 câbles, tuyaux, fibres optiques et autres modes de transmission de fluides et d’informations sous chaque route.


J.-P Culas (CM-Drones, Besançon) a effectué les vols au-dessus du parking de FEMTO-ST. Les membres du forum Micmac ( ont une fois de plus partagé leurs connaissances pour corriger les défaillances dans les traitements que nous proposions initialement.

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 !

Nouvelle réglementation européenne des DM : Quel impact pour votre entreprise ? - Nantes (44) Le 12 octobre 2017

L'ANSM, le SNITEM et le G-MED se réuniront le 12 octobre à la CCI de Nantes pour vous présenter les nouvelles exigences et les modalités de mise en œuvre de cette nouvelle réglementation.

Pré-Programme :

- 8h30-9h : accueil des participants

- 9h : Introduction par les organisateurs

- 9H00 – 12h45 :

  • Actualité sur les nouveaux règlements européenne des DM – Intervenant à confirmer, ANSM
  • Rôle du SNITEM et présentation des organismes notifiés - Pascale Cousin, SNITEM
  • La mise en place des tests produits et du système qualité dans l'entreprise - Corinne DELORME, LNE G-MED

- 12h45 : Clôture et mot des organisateurs

L'accès à cette matinée est gratuit et l'inscription obligatoire.

Inscription en ligne

Lieu :
CCI Nantes St-Nazaire - Centre des Salorges, Nantes
16 Quai Ernest Renaud
44100 Nantes

Une retransmission sera proposée à Rennes, précisions à venir.



"Innovations du Grand Ouest" sur les composants et fonctions électroniques intégrables - Tours (37) Le 23 novembre 2017

Le 23 novembre à Tours, de 9h à 16h00, CAP'TRONIC s'associe au Pôle S2E2 et vous invite à la quatrième édition des "Innovations du Grand Ouest" sur la thématique des composants et fonctions électroniques intégrables.

A cette occasion, venez rencontrer, sur le site de STMicroélectronics Tours une dizaine d'entreprises leaders sur leur marché et découvrir les dernières solutions technologiques sur la thématique des composants et fonctions électroniques intégrables au service de l'autonomie énergétique, de la connectivité et du stockage d'énergie pour des applications stationnaires ou embarquées.

Inscriptions ouvertes très prochainement

Intervenants & thématiques traitées

Pour les intervenants de cette nouvelle édition, participer aux "Innovations du Grand Ouest", c'est :

Promouvoir vos produits et services innovants
Rencontrer de nouveaux clients, distributeurs et fournisseurs
montrer votre capacité d'innovation
Faire émerger de nouvelles idées
Bénéficier d'une visibilité unique sur la thématique du stockage de l'énergie

Programme prévisionnel

Cibles de l'événement :

- Electroniciens,
- Intégrateurs de solutions,
- Industriels,
- Utilisateurs potentiels...

Contacts :

Nicolas POUSSET, Responsable technique & pilote des IGO - 02 47 42 49 83
Frédéric CABAS, Marketing & communication - 02 47 42 49 82

Dissémination de données géoréférencées – qgis-server et OpenLayers – Partie 1/2

Les données géoréférencées, générées par l’auteur ou distribuées par les agences telles que l’ESA ( ou l’USGS (, sont disséminées au travers d’un service accessible par le Web selon les formats WFS ou WMTS. Ces données sont alors exploitables au travers de logiciels spécialisés tels que QGis, ou de l’API OpenLayers pour être intégrées dans des pages Web.

Tout possesseur de téléphone portable devient en mesure aujourd’hui de produire de la donnée géoréférencée, qu’il s’agisse de photographies numériques ou de traces de parcours pour les données brutes, ou des données issues d’informations géoréférencées acquises. Nous avons par exemple présenté au FOSS4G-fr [1] et dans ces pages [2] la génération de modèles de bâtiments par les photographies géoréférencées prises par téléphone, et leur intégration dans QGis sur fond de carte OpenStreetMaps (OSM).

Obtenir de telles données est bien, mais les partager avec une communauté d’utilisateurs, c’est mieux. Le mode de transmission le plus pratique pour les volumes de données dont il est question est évidemment internet, ne serait-ce que pour centraliser les données partagées en vue de garantir leur cohérence si plusieurs utilisateurs les manipulent.

Trois protocoles de dissémination ont été mis en place à cet effet [3][4] : WM(T)S, WFS et WCS. Le premier dissémine des images représentant les données traitées, avec une résolution adaptée à l’échelle de la carte de l’utilisateur. Ne fournissant qu’une image des informations transmises, il n’est plus possible pour l’utilisateur de s’approprier ou retraiter lui-même des informations. Les deux autres protocoles disséminent les données brutes, vectorielles ou matricielles. Nous nous proposons d’aborder séquentiellement trois problèmes : un serveur de données pour disséminer les informations qui auront été traitées dans QGis (qgis-server) ; la récupération des informations sur un logiciel dédié tel que Qgis pour le traitement des informations ; et finalement la récupération des données dans un client Web pour affichage comme couche OpenLayers. Afin de ne pas faire durer le suspens plus longtemps, le lecteur est encouragé à consulter et pour se faire une idée du résultat recherché.

Le contexte de notre étude porte sur le retrait de glaciers à front marin en milieu arctique. Les images des satellites Landsat sont acquises depuis les années 1970 et mises à disposition par l’USGS, par exemple sur Elles sont plus ou moins bien géoréférencées (une petite correction est parfois nécessaire, surtout pour les plus anciennes), mais surtout souffrent d’une résolution médiocre (de l’ordre de 30 m/pixel) compte tenu des standards actuels. Plus de 40 ans d’histoire d’images satellites en font néanmoins une source irremplaçable pour appréhender l’évolution des régions qui vont nous intéresser. Notre travail initial sous QGis a été d’importer toutes ces images, les reprojeter dans un référentiel localement plan (WGS84/UTM33N, le référentiel projeté approprié pour le nord de la Norvège tel que nous en informe, s’assurer par quelques points de référence que les images sont convenablement positionnées, et dans le cas contraire les repositionner au moyen de 4 ou 5 points de référence sur le pourtour de la région considérée (presqu’île de Brøgger, Svalbard). Ces informations matricielles sont alors utilisées pour tracer manuellement (création d’un shapefile comprenant des lignes) les fronts marins des glaciers, créant ainsi un jeu de données vectorielles. Par ailleurs, un trajet en avion a été enregistré au moyen du récepteur GPS d’un téléphone portable (logiciel OSMTracker sous Android) et nous désirons insérer la séquence de points au format GPX dans nos cartes. Sous QGis, l’opération est triviale (Vector > GPS Tools > Load GPX File) mais pourrons-nous exporter cette information par le Web et l’inclure dans les pages affichées par un navigateur ? Nous verrons que la réponse n’est pas aussi triviale qu’il pourrait paraître.

Fig. 1 :Projet QGis que nous désirons partager au travers d’internet, avec toutes les images sans nuages acquises par Landsat de la presqu’île de Brøgger au Svalbard, et la mesure de position des fronts, illustrant le recul de 4 km en 40 ans du Kongsbreen.

1. Le serveur : qgis-server

QGis a tout prévu pour nous : un projet QGis s’exporte dans un format accessible par le Web au travers de qgis-server. Le principal exercice va donc porter sur l’installation de cet outil, puisqu’exporter le projet se résume à Project > Projet Properties et activer WMS, WFS et WCS en cochant toutes les couches (Select All) dans les deux derniers cas.

L’installation de qgis-server ne présente aucune difficulté et est décrite parfaitement sur On notera cependant que bien que le service WM(T)S fonctionne convenablement avec des versions plus anciennes de qgis-server, l’export des couches vectorielles (formats WFS et WCS) ne semble pas opérationnel pour les versions précédent 2.12. Nous expérimenterons donc avec une version au moins supérieure à 2.14 de QGis et de son serveur qgis-server. Sous Debian GNU/Linux, cela signifie éviter Wheezy mais travailler dans la version stable à la date de cette rédaction.

À l’issue de l’installation du serveur comme service d’Apache2 (nécessitant le support FCGI fourni par libapache2-mod-fcgid), le bon fonctionnement du service est validé (dans le cas d’une installation locale) par :

$ wget -O - ""

La réponse doit être du type :

   <!-- Human-readable title for pick lists -->
   <Title>QGIS mapserver</Title>
   <!-- Narrative description providing additional information -->
   <Abstract>A WMS service with QGIS mapserver</Abstract>

Le service étant fonctionnel, divers projets QGis (fichier .qgs) sont placés, avec toutes les données associées aux diverses couches du projet, dans des sous-répertoires de /usr/lib/cgi-bin, en complétant avec une copie du serveur Fast-CGI (qgis_mapserv.fcgi).

Attention !
Les liens symboliques entre /usr/lib/cgi-bin et, par exemple, un répertoire utilisateur, ne sont autorisés qu’en modifiant la configuration par défaut de Apache2 sous Debian dans /etc/apache2/conf-available/serve-cgi-bin.conf en remplaçant le + par un de l’option SymLinksIfOwnerMatch.

Si le projet QGis autorise l’export des couches au format WM(T)S ou WFS, nous validons la capacité à rapatrier ces couches (dans notre cas le projet et ses fichiers se trouvent dans /usr/lib/cgi-bin/project/landsat de par :

$ wget -O - "\

La réponse est la liste des couches accessibles sous la forme :

<WFS_Capabilities xmlns:xsi="" ...
<LatLongBoundingBox maxx="12.2424" minx="12.103" maxy="79.0268" miny="78.9989"/>

Nous voyons donc que la projection dans laquelle les coordonnées des points formant la couche (ici vectorielle) est renseignée (EPSG:4326 signifie WGS84 en coordonnées sphériques tel que nous l’indique le CRS sous QGis), et l’extension de la couche (autour de 12°E et 79°N).

Ces points sont récupérés – au format GML – par une requête WFS de la forme :

$ wget -O - "\

La réponse est :

<gml:LineString srsName="EPSG:4326">
<gml:coordinates cs="," ts=" ">12.11525618,79.02193675 12.1224397,79.02118041 12.11728195,
79.01669523 12.11808149,79.0123295 12.12970628,79.00850923 12.14676275,79.00549989 12.16023071,79.00480137
12.16426326,79.00331772 12.16469826,79.00161054 12.17939472,78.99997196 12.18340417,79.00381158 12.20189733,
79.00556583 12.21455655,79.00542793 12.2268052,79.00560265 12.2366082,79.00626179 12.24175315,79.00561112

Nous avons ici les diverses coordonnées qui forment la ligne d’une des couches vectorielles de notre projet QGis, accessible au travers d’une requête HTML. Ces données sont donc accessibles par la communauté, il reste à en faire un bon usage avec les divers outils à notre disposition. Nous présentons quelques exemples ci-dessous.

2. Le client : Qgis

Le premier environnement le plus simple pour accéder à ces données est QGis lui même. Dans la barre des icônes de gauche de QGis, les trois icônes en forme de globe proposent l’accès respectivement aux données au format WM(T)S, WCS et WFS. Dans tous les cas, il nous faut renseigner l’url du serveur, par exemple Lors de la connexion, la liste des couches accessibles est proposée, et cliquer sur une couche suivi de Add donne accès au jeu de données. La seule subtilité dans cette application tient à ne pas utiliser un serveur trop ancien (avant 2.12) sous peine de voir la liste des couches s’afficher, mais une liste vide de points être retournée par les requêtes WFS. WM(T)S semble avoir toujours bien fonctionné (voir figure 2).

Fig. 2: Obtention de couches WM(T)S – images au format bitmap des données (“fronts4”) – et WFS – informations vectorielles (“fronts3”), depuis QGis. Noter le logo de QGis qui est un effet de bord du serveur de test installé par le site web décrivant l’installation de QGis. Effacer /opt/qgis-server/plugins/HelloServer ou tout au moins /opt/qgis-server/plugins/HelloServer/icons/icon.png pour s’affranchir de cet effet.

3. Intégration dans une page web : OpenLayers 2

La portée de notre serveur se retreint encore à un public relativement averti puisque utilisateur de QGis. Nombreuses sont les cartes sur le Web qui ne sont pas destinées à un auditoire de géographes mais simplement pour illustrer un concept à des utilisateurs probablement spécialistes dans d’autres domaines. Afin d’insérer des cartes et les couches générées sous QGis, l’environnement de développement en JavaScript OpenLayers semble idéal puisque fournissant la capacité à charger des couches dans tous les formats qui nous intéressent – WM(T)S, WFS ou GPX pour les traces GPS. Nous avons initialement été sensibilisés à OpenLayers comme environnement de développement pour accéder aux couches fournies par l’IGN au travers de Géoportail. Nous allons dans un premier temps nous intéresser à la version stable d’OpenLayers (version 2) qui semble mature, mais verrons que la nouvelle mouture (version 3) offre des fonctionnalités précieuses qui justifient la migration vers l’environnement en cours de développement.

Une carte OpenLayers est formée d’un appel aux bibliothèques JavaScript (<script>…</script>), la création d’une carte remplie d’un fond par défaut – nous choisissons le fond vectoriel OpenStreeMaps (OSM) – et recouvert de diverses couches additionnelles que nous fournirons depuis qgis-server.

Dans son expression la plus simple, une page OpenLayers ressemble à :

      <title>Essai de lecture de WMS depuis openlayers</title>
      <script src=""></script>
      <div style="width:100%;height:100%" id="map"></div>
      <script defer="defer" type="text/javascript">
         var map=new OpenLayers.Map(’map’);
         var wms=new OpenLayers.Layer.WMS("Basic map","",{layers: ’basic’} );
         map.setCenter(new OpenLayers.LonLat(12,79),9);

Et tant que nous n’insérons que des couches WMS – donc des images (puisque les données, même vectorielles, sont transmises sous forme d’images avec une résolution adaptée au facteur de grossissement), tout se passe bien. Nous pouvons ainsi ajouter une image Landsat accessible sous forme WMS, voir même un des fronts de glacier :

      <title>Essai de lecture de WMS depuis openlayers</title>
      <script src=""></script>
      <div style="width:100%;height:100%" id="map"></div>
      <script defer="defer" type="text/javascript">
         var map=new OpenLayers.Map(’map’);
         var wms=new OpenLayers.Layer.WMS("Basic map","",{layers: ’basic’} );
         var dm_wms2013=new OpenLayers.Layer.WMS(
            "Landsat image 2013",
            {layers: "2013_0830utm33n", transparent:"true", format:"image/png" },
            {isBaseLayer: false}
         var fronts1=new OpenLayers.Layer.WMS(
            "Glacier fronts1",
            {layers: "fronts4", transparent:"true", format:"image/png"},
            {isBaseLayer: false}
         map.setCenter(new OpenLayers.LonLat(12,79),9);

Le lecteur est encouragé à compléter cet exemple en ajoutant un front additionnel, par exemple la couche nommée fronts5, et observer la conséquence d’échanger l’ordre d’affichage des couches. Ces exemples sont fortement inspirés des excellents tutoriaux fournis par

Pour WFS, le problème se corse : le principe de Same Origin impose que le serveur de données soit sur le même site que le serveur Web. Ceci est valable pour toute donnée vectorielle. Afin d’illustrer ce problème, nous proposons trois sources de données : un même fichier GPX stocké sur,, puis Le serveur qgis-serveur fournissant les couches WFS est exécuté comme service Apache2 sur, tandis que la page Web qui fait appel à ce service peut être placée sur chacun de ces trois serveurs. La figure 3 illustre les interdictions d’accès rencontrées, tel qu’indiqué par Firebug : le fichier GPX stocké sur peut être lu par la page mais est rejeté par la même page stockée sur Cette dernière n’a accès qu’au même fichier GPX placé dans le répertoire du serveur

Fig. 3: Trois illustrations du problème de Same Origin pour se convaincre de la source du problème.


Les exemples de la figure 3 sont obtenus, après la définition de la carte, par l’appel aux couches vectorielles aux formats GPX ou WFS, de la forme :

var lgpxfree = new OpenLayers.Layer.Vector("GPX track free", {
   strategies: [new OpenLayers.Strategy.Fixed()],
   protocol: new OpenLayers.Protocol.HTTP({
      url: ",_2016_11;20;10_2016-05-06_11-20-10.gpx",
      format: new OpenLayers.Format.GPX()
   style: {strokeColor: "red", strokeWidth: 5, strokeOpacity: 0.8}
var lgpxsqnx = new OpenLayers.Layer.Vector("GPX track sqnx", {
   strategies: [new OpenLayers.Strategy.Fixed()],
   protocol: new OpenLayers.Protocol.HTTP({
      url: ",_2016_11;20;10_2016-05-06_11-20-10.gpx",
      format: new OpenLayers.Format.GPX()
   style: {strokeColor: "green", strokeWidth: 5, strokeOpacity: 0.8}
var fronts=new OpenLayers.Layer.Vector("Test WFS", { // WFS
   strategies: [new OpenLayers.Strategy.BBOX()],
   protocol: new OpenLayers.Protocol.WFS({
      url : "",
      featureType : "fronts5",

map.addLayer(wms); map.setCenter(new OpenLayers.LonLat(12,79),9);

Ce code fait appel au même fichier GPX stocké sur deux serveurs (afin de valider que seule la couche située sur le même serveur que la page Web appelante est acceptable), et la couche nommée fronts5 fournie au format WFS par

Fig. 4: En local (, tout se passe bien, les données et le serveur sont au même endroit. L’intérêt en terme de diffusion reste limité : placer toutes ses données sur le même site que le serveur résout les problèmes de Same Origin (l’exemple de droite est accessible sur


Ayant dépassé tous les écueils de configuration, nous avons finalement la satisfaction de voir toutes les couches s’afficher sur la même carte, en ajoutant l’onglet de commandes qui permet d’activer ou désactiver chaque couche afin d’aisément comparer la position des fronts des glaciers et leur évolution dans le temps :

var map=new OpenLayers.Map('map');
ls=new OpenLayers.Control.LayerSwitcher({'div':OpenLayers.Util.getElement('layerswitcher')});

Il n’aura cependant pas échappé au lecteur que nos images satellites semblent fortement déformées (comparer les figures 1 et 4). Il s’agit ici de la conséquence de la projection de Mercator, qui tend à considérablement grossir l’axe des abscisses lorsque la zone considérée s’éloigne de l’équateur. Quoiqu’acceptable jusqu’à des latitudes de ±60°, l’effet devient vraiment significatif au-delà et carrément désagréable par 79°N. C’est pourquoi les projections locales, tentant de trouver un plan localement tangent à la sphère représentant le globe terrestre, ne prétendent pas à s’appliquer à l’ensemble de la Terre mais uniquement à un petit segment de longitude. Malheureusement, OpenLayers 2 ne supporte pas la reprojection à la volée des données bitmap, nous sommes coincés avec la projection imposée depuis Google Maps qui continue à déformer les pôles. Nous allons remédier à ce problème en passant sous OpenLayers 3 et retrouver ainsi les belles cartes de Qgis.

Jean-Michel FRIEDT
[Institut FEMTO-ST, dpt. Temps-fréquence, Besançon]

Émile Carry
[Institut FEMTO-ST, dpt. Temps-fréquence, Besançon]

La seconde partie de cet article sera publiée prochainement sur le blog, restez connectés 😉

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 !

Comprendre l'industrialisation : un impératif pour vos produits ! - Paris Le 6 novembre 2017

Créateur d'objets électroniques connectés ou non, venez comprendre les contraintes liées à l'industrialisation et à la conception.

Cette formation sera centrée sur la conception et l'industrialisation des produits électroniques et vous permettra de comprendre clairement les enjeux qui y sont liés afin d'appliquer les bonnes pratiques.

Partie sur le Cycle de vie

- développement produit
- la faisabilité technico-économique

Partie Conception

- la méthodologie de travail, le phasage des étapes, les bonnes pratiques
(et les mauvaises à éviter), les process techniques/technologiques selon les différents métiers (mécanique, électronique, tests, logiciel)
- les points à considérer (banc de test, assemblage,...), le design "To cost", les aspects normatifs, le design du boîtier

Partie Industrialisation

- les process de fabrication, les étapes nécessaires pour garantir la qualité (câblage, tests, bancs de test etc.)
- la méthodologie de travail, le phasage des étapes, les bonnes pratiques
(et les mauvaises à éviter) associés à la conception produit
- les maquettes, prototypes, les essais associés, la préparation et réalisation des préséries et séries, les aspects SAV et qualité


Lundi 6 novembre : 8h30-18h00


- Cycle de vie d'un projet (phasage, délais etc.)
- L'Innovation
- Définition du besoin Client
- Exemples


- Synoptique, méthodologie, outils de faisabilité
- Faisabilité technico-économique (état de l'art, risques etc.)
- Cahier des charges technico-fonctionnel (réponse au CDC Client,
compétences requises)
- Preuve de concept (validation par démonstrateur, Fab Labs)
- Sourcing prestataires/partenaires (R&D, industrialisation)
- Qualification et choix prestataires/partenaires (considérations qualitatives)
- Proposition technico-économique R&D/industrialisation (métriques)
- Budget R&D/industrialisation/outillages
- Prix de revient produit
- Planning R&D/industrialisation/outillages
- ROI (retour sur investissements)
- GO - NO GO
- Exemples

(mécanique/plasturgie) :
- Process d'industrialisation mécanique/plasturgie (conception/réalisation outillage, directives, paramètres, tests, retouches, validations, coûts, délais)

Mardi 7 novembre : 8h30-18h00

(électronique, assemblage, tests) :

- Process d'industrialisation des cartes électroniques
(appros, conception/réalisation outillage, directives, paramètres, tests, retouches, validations, coûts, délais)
- Process d'Industrialisation assemblage/tests (conception/réalisation outillage, directives, paramètres, tests, validations, coûts, délais)

(démarrer la conception vers les prototypes) :

- Ingénierie simultanée (bien du 1er coup, penser process dès la conception)
- Contrats de prestation R&D/Industrialisation
- Synoptique, Méthodologie, Outils de conception
- Conception générale multi-métiers (mécanique/plasturgie,
électronique, logiciel embarqué et applicatif, tests)
- Design To cost (conception à coût objectif - prix de revient cible)
- Les choix (technologiques, composants, assemblage, tests)
- Les directives de conception par métiers
- Design To manufacturing (contraintes de fabrication)
- Design To test (contraintes de test)
- Les contraintes normatives, certification
- Conception détaillée par métiers (mécanique/plasturgie, électronique,
logiciel embarqué) : les outils, méthodologie, documents, ...
- Maquettes (run 1 hardware/mécanique, code source)
- Evaluation technique (mesures, fonctions, essais , CEM, ...)
- Exemples

(intégrer les process/technos dès la conception) :

- Ingénierie simultanée (bien du 1er coup, penser process dès la conception)
- Choix technologiques et Conception
- Méthodologie
- Prototypes (run 2 hardware/mécanique, logiciel embarqué, assemblage,
intégration, mises au point, tests)
- Qualification/certifications (validations techniques/normatives par
rapport au CDC)
- Lancement présérie industrielle (validation process, outillages, prix de
- Lancement fabrication série (stratégie industrielle et logistique)
- Le SAV (REX,…)


- Projet d'ensemble, analyse fonctionnelle
- Choix et directives technologiques
- Choix et validation prestataires
- Validations de phases avec les prestataires
- Validation de prototypes
- validation de process en Présérie

Lieu de l'événement :

Maison de la Salle
78A Rue de Sèvres
75007 Paris

Participation aux frais

- Prix préférentiel pour les adhérents CAP'TRONIC : 700 € HT par personne pour les 2 jours
- Pour les grandes entreprises et les PME qui ne souhaitent pas adhérer : 900 € HT par personne pour les 2 jours

Si vous êtes une PME non adhérente :
Vous pouvez adhérer à l'association JESSICA France. Pour cela contacter Florence CAGNARD
Modalités d'adhésion

Remarque : Jessica France est titulaire d'un numéro d'agrément de formation continue. La prise en charge de cette formation est donc possible par les Organismes Paritaires Collecteurs Agréés (OPCA) mais attention, l'étude de votre dossier peut prendre plusieurs semaines, renseignez-vous dès maintenant et inscrivez-vous au plus tôt.

Places limitées à 10 personnes

Contact :
Christophe Bricout - 09 52 73 77 88

crédit image Designed by Freepik