Wie RADR Geräteinstanzen aus BLE-Dienst-UUIDs erkennt und erstellt
Die Geräteregistrierung ist das Kernsystem, das die UUIDs der Bluetooth-Low-Energy-(BLE-)Dienste den Gerätefabriken zuordnet. Wenn RADR nach Geräten sucht, verwendet es Dienst-UUIDs, um zu bestimmen, welche Factory die Geräteinstanz erstellen soll.
Architekturübersicht
RADR verwendet ein zweistufiges Registrierungssystem:
| Stufe | Beschreibung | Beispiel |
|---|---|---|
| Fest codiert | Geräte, die direkt im Code mit benutzerdefinierten Factorys registriert sind | OSSM |
| Dynamisch | Geräte, die mithilfe der ButtplugIO-Factory aus registry.json geladen werden | Lovense, Satisfyer, Kiiroo |
┌─────────────────────────────────────────────────────────────┐
│ Device Registry │
│ │
│ ┌─────────────────────┐ ┌─────────────────────────────┐│
│ │ Hardcoded Devices │ │ Dynamic Devices ││
│ │ (Custom Factory) │ │ (ButtplugIOFactory) ││
│ │ │ │ ││
│ │ Service UUID → │ │ registry.json → ││
│ │ Lambda → Device │ │ Service UUID → ││
│ │ │ │ Spec files → Device ││
│ └─────────────────────┘ └─────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘Die Registrierung wird beim Start des Geräts einmalig über initRegistry() gefüllt.
Registrierungsstruktur
Die Registrierung ist eine globale Map, die Dienst-UUIDs mit Factory-Funktionen verknüpft:
std::unordered_map<std::string, DeviceFactory> registry;Dabei ist DeviceFactory wie folgt definiert:
typedef Device *(*DeviceFactory)(const NimBLEAdvertisedDevice *advertisedDevice);Schlüsselfunktionen
| Funktion | Zweck |
|---|---|
initRegistry() | Füllt die Registrierung mit fest codierten und dynamischen Geräten |
getDeviceFactory() | Sucht eine Factory anhand der Dienst-UUID |
Fest codierte Geräte
Fest codierte Geräte werden direkt in initRegistry() mit einer Lambda-Factory registriert. Dieser Ansatz wird für Geräte mit benutzerdefinierten Protokollen verwendet, die eine spezielle Verarbeitung erfordern.
OSSM-Beispiel
registry.emplace(
OSSM_SERVICE_ID, // "522B443A-4F53-534D-0001-420BADBABE69"
[](const NimBLEAdvertisedDevice *advertisedDevice) -> Device * {
return new OSSM(advertisedDevice);
});OSSM verwendet ein benutzerdefiniertes BLE-Protokoll mit mehreren Characteristics zur Steuerung von Geschwindigkeit, Tiefe, Sensation und Hub. Daher ist eine eigene Geräteklasse statt der generischen ButtplugIO-Implementierung erforderlich.
Wann sollte die fest codierte Registrierung verwendet werden?
Verwenden Sie die fest codierte Registrierung, wenn:
- Das Gerät verwendet ein benutzerdefiniertes Protokoll, das nicht von Buttplug.io unterstützt wird
- Sie benötigen eine spezielle Benutzeroberfläche oder Steuerlogik
- Das Gerät erfordert eine spezielle Verarbeitung der Characteristics
Dynamische Geräte (ButtplugIO)
Dynamische Geräte werden aus der Datei data/registry.json im Dateisystem geladen. Dadurch kann Unterstützung für neue Geräte hinzugefügt werden, ohne den Code zu ändern.
registry.json-Struktur
Die Registrierung ordnet Dienst-UUIDs Arrays mit Protokollspezifikationsdateien zu:
{
"0000fff0-0000-1000-8000-00805f9b34fb": ["/protocols/lovense.json"],
"88f80580-0000-01e6-aace-0002a5d5c51b": ["/protocols/kiiroo-v2.json"],
"51361500-c5e7-47c7-8a6e-47ebc99d80e8": ["/protocols/satisfyer.json"]
}Jeder Eintrag ordnet eine BLE-Dienst-UUID (Schlüssel) einer oder mehreren Protokollspezifikationsdateien (Wertearray) zu.
Ablauf der Factory
Wenn ein Gerät mit einer registrierten Dienst-UUID erkannt wird:
ButtplugIODeviceFactoryliestregistry.jsonvon LittleFS- Ruft die Liste der Spezifikationsdateien für die Dienst-UUID ab
- Für jede Spezifikationsdatei:
- Lädt und analysiert die JSON-Konfiguration
- Vergleicht den beworbenen Gerätenamen mit den Mustern in
communication[0].btle.names - Extrahiert die TX/RX-Characteristics für die Dienst-UUID
- Erstellt eine
LovenseDevice-Instanz mit der passenden Konfiguration
Protokollspezifikationsdateiformat
Spezifikationsdateien folgen dem Buttplug.io v4-Format:
{
"defaults": {
"name": "Lovense Device",
"features": [...]
},
"configurations": [
{
"identifier": ["B"],
"name": "Max",
"features": [...]
}
],
"communication": [{
"btle": {
"names": ["LVS-*", "LOVE-*"],
"services": {
"0000fff0-0000-1000-8000-00805f9b34fb": {
"tx": "0000fff2-0000-1000-8000-00805f9b34fb",
"rx": "0000fff1-0000-1000-8000-00805f9b34fb"
}
}
}
}]
}| Feld | Zweck |
|---|---|
defaults | Standardgerätename und Funktionssatz |
configurations | Gerätespezifische Varianten und Identifikatoren |
communication[].btle.names | Gerätenamenmuster (unterstützt den Platzhalter *) |
communication[].btle.services | TX/RX-Characteristic-UUIDs pro Dienst |
Geräteerkennungsablauf
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ BLE Scan │────▶│ Get Service │────▶│ Lookup in │────▶│ Factory │
│ Discovers │ │ UUID │ │ Registry │ │ Creates │
│ Device │ │ │ │ │ │ Device │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘- Scan: RADR sucht nach BLE-Geräten
- UUID extrahieren: Ruft die UUID des beworbenen Dienstes ab
- Registrierungssuche:
getDeviceFactory(serviceUUID)findet die Fabrik - Gerät erstellen: Die Factory instanziiert die entsprechende Geräteklasse
Unterstützung für neue Geräte hinzufügen
Option A: Dynamisch (Buttplug.io-Registry)
Für Geräte, die mit dem Buttplug.io-Protokoll kompatibel sind:
Besorgen Sie sich die Spezifikationsdatei oder erstellen Sie sie
Holen Sie sich die Buttplug.io-v4-Protokollspezifikation für das Gerät. Diese ist im Konfigurations-Repository für Buttplug-Geräte verfügbar.
Spezifikationsdatei zu Protokollen hinzufügen
Platzieren Sie die JSON-Spezifikationsdatei in data/protocols/:
data/protocols/your-device.jsonregistry.json aktualisieren
Fügen Sie die Dienst-UUID-Zuordnung zu data/registry.json hinzu:
{
"your-service-uuid": ["/protocols/your-device.json"]
}Dateisystem hochladen
Verwenden Sie PlatformIO, um das Dateisystem auf das Gerät hochzuladen.
Option B: Fest codiert (benutzerdefiniertes Protokoll)
Für Geräte, die eine benutzerdefinierte Protokollverarbeitung erfordern:
Geräteklasse erstellen
Erstellen Sie eine neue Geräteklasse in src/devices/, die die Basisklasse Device erweitert.
Implementieren Sie die erforderlichen Methoden
Implementieren Sie getServiceUUID(), getName() und jede gerätespezifische Steuerlogik.
In initRegistry registrieren
Fügen Sie Registrierungscode in initRegistry() hinzu:
registry.emplace(
YOUR_SERVICE_UUID,
[](const NimBLEAdvertisedDevice *adv) -> Device * {
return new YourDevice(adv);
});Firmware neu kompilieren
Kompilieren und flashen Sie die aktualisierte Firmware.
Entwicklungsworkflow
Aktualisieren der Registrierung (Entwicklung)
Wenn Sie lokal entwickeln, verwenden Sie die Funktion „Upload Filesystem“ von PlatformIO, um das Verzeichnis data/ auf LittleFS zu flashen:
- Ändern Sie
data/registry.jsonoder fügen Sie Spezifikationsdateien zudata/protocols/hinzu - Klicken Sie in VS Code mit PlatformIO auf Upload Filesystem (oder führen Sie
pio run --target uploadfsaus). - Das Gerät verwendet beim nächsten Start die aktualisierte Registrierung
"Upload Filesystem" löscht die vorhandene LittleFS-Partition vor dem Schreiben. Alle Laufzeitänderungen gehen verloren.
Aktualisieren der Registrierung (Produktion)
OTA-Registrierungsaktualisierungen sind eine ausstehende Funktion. Derzeit ist für Registrierungsaktualisierungen ein Firmware-Flash erforderlich.
Der geplante Workflow für Produktionsgeräte:
- Navigieren Sie auf dem Gerät zu Settings > Look for updates
- RADR sucht nach Registrierungsaktualisierungen vom Server
- Aktualisierte
registry.json- und Protokolldateien werden OTA heruntergeladen - Die Unterstützung neuer Geräte ist ohne ein vollständiges Firmware-Update verfügbar
Wichtige Quelldateien
| Datei | Zweck |
|---|---|
src/devices/registry.h | Registrierungsschnittstelle und Typdefinitionen |
src/devices/registry.cpp | Implementierung und Initialisierung der Registrierung |
src/devices/buttplugio/buttplugIOFactory.cpp | Dynamische Gerätefabrik |
src/devices/device.h | Basisgeräteklasse |
data/registry.json | Dienst-UUID-Zuordnungen zu Spezifikationsdateien |
data/protocols/*.json | Buttplug.io-v4-Gerätespezifikationen |