Bluetooth Low Energy (BTH-LE)
« | 19 Mar 2019 | »Meine kostengünstige Armbanduhr
mit Herzschlag und Blutdrucksensor schickt tägliche ihre Daten zur Smartphone
App unter Android.
Harald Lesch nennt solche Geräte
zu Recht “digitale Diktatoren” die nicht gerade ein positives Beispiel
unserer Gesellschaft sind:
Weil wir zu faul sind, zu Fuß zur Arbeit zu marschieren und mit Öffis und Autos durch die Straßen brettern, brauchen wir am Abend die “Erinnerungsfunktion” am Handgelenk, dass noch X Schritte zu machen sind, damit wir uns als “gesund” titulieren können.
However … der spannendere Aspekt des “digitalen Diktators” ist, dass er über Bluetooth LE kommuniziert und so seine gesammelten Daten meldet und neue Konfigurationen abholt.
Das GATT Profile
(Generic Attribute Profile) ist in etwas das für Bluetooth, was
HID
(Human Interface Device) für
USB
(Universal Serial Bus) ist.
Anstatt dass jedes Gerät sein eigenes Datenprotokoll definiert, wird ein
generisches gewählt, das eine variable Sammlung von “Services” bereitstellen
kann, und jedes Service hat eigene “Characteristics” und “Attributes”, die
man entweder nur lesen, nur schreiben oder beides kann.
So etwas ist für die Programmierung super, weil man mit einer kleinen Anzahl von APIs jedes mögliche GATT / Bluetooth LE Gerät steuern und auslesen kann. Die Komplexität steckt dabei aber im Wissen, welches Service welche ID hat, und welche Eigenschaft (Characteristic) bzw. welche Eigenschaftskombinationen welche finalen Auswirkungen und Bedeutungen hat.
Es gibt natürlich das eine oder andere “generische” Service, das jedes Bluetooth-LE-Gerät bereit stellt um z.B. seinen Namen, Hersteller und die Version auszulesen, doch die Details zu vielen weiteren Services stehen nur in der Spezifikation des Herstellers oder … nirgends, weil sie nicht veröffentlicht sind.
Um so mehr Spaß macht es dann, diese Details herauszufinden.
Denn es gibt Tools, die alle Byteblöcke eines BTH-LE-Gerätes auslesen und
anzeigen.
Und daher sah ich mich schon fast gezwungen, diese APIs auch ins GATE
Projekt aufzunehmen um etwas damit “spielen” zu können.
Seit Windows 8 existieren die BluetoothGATT* Funktionen um eben genau diese Details auszulesen. Doch wie so oft unter Windows fehlt die zusammenhängende Dokumentation, wie man die Pfade für die Geräte kommt.
Hier die Zusammenfassung:
- Man sucht mit der SetupDI* API
nach allen BTH-LE Geräten über die Klasse
GUID_BLUETOOTHLE_DEVICE_INTERFACE
{781aee18-7733-4ce4-add0-91f41c67b592}
SetupDiGetClassDevs()
öffnet die Liste aller GeräteSetupDiEnumDeviceInterfaces()
lädt die Daten eines Geräts (per Index)SetupDiGetDeviceInterfaceDetail()
holt uns den Pfad zum Gerät
CreateFile()
öffnet das Gerät mittels des Geräte-PfadesBluetoothGATTGetServices()
holt uns eine Liste der Services und deren GUIDs eines BTH-LE-Geräts.
Will man die Characteristics eines BTH-LE-Services auf einem Gerät lesen oder schreiben, wird es etwas “tricky”:
- Wir suchen mit der SetupDI* API
nach allen BTH-LE Services über die Klassen-Guid des Services, die wir zuvor
mit
BluetoothGATTGetServices()
erhalten haben.- Hier gibt es noch den Fall, dass ein Service eine “Short-ID” hat, wo nur
die ersten Felder der GUID befüllt sind und die restlichen ausgenullt sind.
Bei der Such muss eine solche GUID aber immer auf:
XXXXXXXX-0000-1000-8000-00805f9b34fb
enden.
- Hier gibt es noch den Fall, dass ein Service eine “Short-ID” hat, wo nur
die ersten Felder der GUID befüllt sind und die restlichen ausgenullt sind.
Bei der Such muss eine solche GUID aber immer auf:
- Auch hier erhalten wir wieder einen Pfad zum “Service-Gerät”, den wir mit
CreateFile()
öffnen können. - Mit der geöffnet Gerätedatei können wir nun die anderen APIs
wie
BluetoothGATTGetCharacteristics
nutzen um jede Einstellung auszulesen oder zu schreiben.
Dieser Schritt war mir nämlich lange nicht klar, und so scheiterte ich stets
daran, dass das HANDLE
zum Bluetooth-Geräte mit den Characteristic-APIs immer
den Code ERROR_INVALID_FUNCTION
zurück gab.
Nur wenn man genau hinsieht, ist bei BluetoothGATTGetServices()
von
HANDLE hDevice
die Rede, während BluetoothGATTGetDescriptorValue()
von
einem “Service HANDLE” spricht.
Doch niemand sagt einem, dass das Service-HANDLE vom Device-HANDLE zu unterscheiden ist.
Daher nochmals:
BTH-LE-GUID -> Devices -> Device -> Service-Guids
Service->Guid -> Service-Path -> Service-Handle
So, jetzt kann ich alle Characteristics aller Services meiner Armbanduhr “sehen” … allein fehlt mir jetzt noch die Info, was die Bytes bedeuten sollen.
… also wird es Zeit für ein bisschen Herumprobieren.