Geräteregistrierung

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:

StufeBeschreibungBeispiel
Fest codiertGeräte, die direkt im Code mit benutzerdefinierten Factorys registriert sindOSSM
DynamischGeräte, die mithilfe der ButtplugIO-Factory aus registry.json geladen werdenLovense, 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

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

  1. ButtplugIODeviceFactory liest registry.json von LittleFS
  2. Ruft die Liste der Spezifikationsdateien für die Dienst-UUID ab
  3. 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
  4. 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"
        }
      }
    }
  }]
}
FeldZweck
defaultsStandardgerätename und Funktionssatz
configurationsGerätespezifische Varianten und Identifikatoren
communication[].btle.namesGerätenamenmuster (unterstützt den Platzhalter *)
communication[].btle.servicesTX/RX-Characteristic-UUIDs pro Dienst

Geräteerkennungsablauf

┌──────────────┐     ┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│  BLE Scan    │────▶│  Get Service │────▶│  Lookup in   │────▶│   Factory    │
│  Discovers   │     │    UUID      │     │   Registry   │     │   Creates    │
│   Device     │     │              │     │              │     │   Device     │
└──────────────┘     └──────────────┘     └──────────────┘     └──────────────┘
  1. Scan: RADR sucht nach BLE-Geräten
  2. UUID extrahieren: Ruft die UUID des beworbenen Dienstes ab
  3. Registrierungssuche: getDeviceFactory(serviceUUID) findet die Fabrik
  4. 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.json

registry.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:

  1. Ändern Sie data/registry.json oder fügen Sie Spezifikationsdateien zu data/protocols/ hinzu
  2. Klicken Sie in VS Code mit PlatformIO auf Upload Filesystem (oder führen Sie pio run --target uploadfs aus).
  3. 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:

  1. Navigieren Sie auf dem Gerät zu Settings > Look for updates
  2. RADR sucht nach Registrierungsaktualisierungen vom Server
  3. Aktualisierte registry.json- und Protokolldateien werden OTA heruntergeladen
  4. Die Unterstützung neuer Geräte ist ohne ein vollständiges Firmware-Update verfügbar

Wichtige Quelldateien

DateiZweck
src/devices/registry.hRegistrierungsschnittstelle und Typdefinitionen
src/devices/registry.cppImplementierung und Initialisierung der Registrierung
src/devices/buttplugio/buttplugIOFactory.cppDynamische Gerätefabrik
src/devices/device.hBasisgeräteklasse
data/registry.jsonDienst-UUID-Zuordnungen zu Spezifikationsdateien
data/protocols/*.jsonButtplug.io-v4-Gerätespezifikationen

Weiterführende Literatur

Auf dieser Seite