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.