Implémentation d'un dispositif Bluetooth Low Energy périphérique sous Yocto : Configuration, connectivité et transfert de données

Cet article détaille les étapes techniques pour configurer et faire fonctionner un appareil Bluetooth sous Yocto, en se concentrant sur le rôle de périphérique (Peripheral). L'objectif est de fournir un guide opérationnel pour obtenir un système fonctionnel.

Compréhension des rôles dans l'architecture Bluetooth

Un système BLE repose sur deux rôles distincts. L'appareil central (Central), comme un smartphone, initie les connexions. Le périphérique (Peripheral), typiquement un capteur ou une carte embarquée, diffuse sa présence et fournit des services de données. Dans notre contexte, l'appareil basé sur Yocto agira ecxlusivement en tant que Peripheral.

Structure logicielle cible

La pile logicielle pour un Peripheral sous Yocto se décompose ainsi :


Application
└── Interface D-Bus, socket, ou GATT

BlueZ (service bluetoothd)
├── GAP (Découverte et gestion des connexions)
├── Serveur GATT (Définition des services de données)
└── Gestion de la sécurité

Noyau Linux
└── Pilote HCI (UART, USB)

Contrôleur Bluetooth matériel

La majorité du développement se situe dans l'espace utilisateur, au niveau de BlueZ et de l'application.

Configuration initiale du rôle Peripheral

La définition du comportement initial de l'appareil se fait principalement via le fichier de configuration de BlueZ, situé dans /etc/bluetooth/main.conf.

Exemple de configuration pertinente pour un Peripheral :


[General]
DeviceName = Senseur-Environnement
DiscoverableTimeout = 0
PairableTimeout = 0
AutoEnable = true

Ces paramètres garantissent que l'appareil est permanentement découvrable et que le contrôleur Bluetooth est activé automatiquement au démarrage du service.

Assurer la disponibilité au démarrage

Pour garantir la fiabilité, il est conseillé d'utiliser un service systemd pour consolider l'état initial du Bluetooth après le démarrage des services principaux.


[Unit]
Description=Initialisation Bluetooth Peripheral
After=bluetooth.service

[Service]
Type=oneshot
ExecStart=/usr/bin/bluetoothctl power on
ExecStart=/usr/bin/bluetoothctl discoverable on
ExecStart=/usr/bin/bluetoothctl pairable on
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

Ce service force l'activation et la découverte, compensant tout problème d'ordre d'initialisation des drivers ou du firmware.

Découverte et établissement de la connexion

Un Peripheral non connecté diffuse périodiquement des paquets d'annonce (advertising) contenant son nom et ses services. Un Central scanne, identifie l'appareil, puis initie une connexion. L'état de connexion peut être vérifié avec l'outil bluetoothctl.

Gestion des données avec GATT

Le protocole GATT (Generic Attribute Profile) est fondamental. Il structure l'échange de données via des services, eux-mêmes composés de caractéristiques. Chaque caractéristique a une valeur (la donnée) et des propriétés (Lecture, Écriture, Notification).

Un Central interagit avec un serveur GATT de trois manières : lire, écrire, ou s'abonner aux notifications d'une caractéristique.

Exemple d'implémentation d'un serveur GATT minimal

Voici une classe Python simplifiée, utilisant l'API D-Bus de BlueZ, qui définit une caractéristique pouvant être lue, écrite et notifier.


from gi.repository import GLib
import dbus
import dbus.service
import dbus.mainloop.glib

# ... (autres imports et définitions de base)

class CapteurCharacteristic(dbus.service.Object):
    IFACE = "org.bluez.GattCharacteristic1"

    def __init__(self, bus, path_base, index, service_uuid):
        self.path = f"{path_base}/char{index}"
        self.bus = bus
        self.value = []
        self.notifying = False
        super().__init__(bus, self.path)

    @dbus.service.method(IFACE, in_signature="", out_signature="ay")
    def ReadValue(self):
        return self.value

    @dbus.service.method(IFACE, in_signature="ay", out_signature="")
    def WriteValue(self, data):
        self.value = data
        print(f"Données reçues : {[hex(b) for b in data]}")

    @dbus.service.method(IFACE)
    def StartNotify(self):
        self.notifying = True

    @dbus.service.method(IFACE)
    def StopNotify(self):
        self.notifying = False

    def envoyer_notification(self, new_data):
        if not self.notifying:
            return
        self.value = new_data
        self.PropertiesChanged(self.IFACE, {"Value": self.value}, [])

Un Central peut ainsi écrire des données dans la caractéristique via WriteValue ou s'abonner pour recevoir des mises à jour via StartNotify et la méthode envoyer_notification.

Protocoles et outils de débogage

Les protocoles clés sont GAP (pour la connexion) et GATT (pour les données). L'outil bluetoothctl sur le périphérique et l'application mobile nRF Connect sur le central sont indispensables pour vérifier les services exposés et tester les lectures/écritures/notifications.

Références techniques

Se référer à la documentation officielle de BlueZ, notamment la section sur le GATT (doc/gatt-api.txt), et au volume 3 du Bluetooth Core Specification pour les détails des profils GATT et GAP. Les exemples inclus dans la source de BlueZ (test/example-gatt-server) sont également une ressource précieuse.

Étiquettes: BlueZ Yocto Project Bluetooth Low Energy GATT D-Bus

Publié le 20 juin à 21h42