VersaMCU/doc/03_action_engine.md

2.9 KiB
Raw Blame History

Aktions-Engine

Dateien: config/action.h, CButton.h/.cpp, CMainController.cpp (processEvents, execute_action_down, execute_action_up)

SAction-Struct

struct __attribute__((packed)) SAction {
    ActionType type;   // 1 Byte
    uint16_t   data;   // 2 Bytes (Keycode, Consumer-Code, Command-ID oder Slot-Index)
};
// Gesamt: 3 Bytes (packed! ohne packed wären es 4 durch Alignment)

packed ist zwingend damit sizeof(SDeviceConfig) == 223 mit der C#-Serialisierung in VersaGUI übereinstimmt.

ActionType

Typ Bedeutung data-Inhalt
NONE Keine Aktion
HID_KEY Tastendruck via USB HID Keyboard Low-Byte = HID Keycode, High-Byte = Modifier
HID_CONSUMER Consumer Control (Volume, Media, …) Consumer Usage ID
HOST_COMMAND Event an VersaGUI senden, App führt aus Command-ID (frei definiert)
MACRO Makro-Sequenz aus NVM-Tabelle Slot-Index 031

execute_action_down() — Taste gedrückt (Hold-Start)

ActionType Verhalten
HID_KEY usb_hid_send_key(keycode, modifier) — Taste bleibt gedrückt bis execute_action_up()
HID_CONSUMER usb_hid_send_consumer(usage_id) — bleibt aktiv bis execute_action_up()
HOST_COMMAND usb_serial_send(USB_EVT_KEY_DOWN, key_id)
MACRO Volle Sequenz ausführen (Steps[slot], keycode==0 = Ende, delay 10+20 ms)
NONE nop

execute_action_up() — Taste losgelassen (Hold-Ende)

ActionType Verhalten
HID_KEY usb_hid_release_key()
HID_CONSUMER usb_hid_release_consumer()
HOST_COMMAND — (optional: könnte USB_EVT_KEY_UP senden)
MACRO/NONE nop

Hold-Modell (HID-Keys und Consumer Controls)

Normale Tasten- und Media-Aktionen folgen dem Hold-Modell:

KEY_DOWN-Event vom Board → execute_action_down() → HID Key-Down senden
[Taste bleibt physisch gedrückt...]
KEY_UP-Event vom Board → execute_action_up() → HID Key-Up senden

Das OS erkennt die gedrückte Taste und startet sein eigenes Key-Repeat nach ~500 ms — wie auf einer normalen Tastatur.

Tap-Modell (Encoder CW/CCW)

Encoder-Bewegungen sind diskret (kein Halten möglich) und verwenden das Tap-Modell:

ENC_CW/ENC_CCW-Event → execute_action_down() + delay(10) + execute_action_up()

(Atomare Sequenz für jeden Encoder-Schritt.)

Work-Loop-Reihenfolge

void work() {
    matrix_scan();        // → Events in Queue (KEY_DOWN, KEY_UP, ENC_CW, ENC_CCW)
    poll_vendor();        // Serial-Pakete verarbeiten (PC↔Board Kommandos)
    processEvents();      // → execute_action_down/up() aufrufen
    updateLEDs();         // Dirty-LEDs aktualisieren
}

processEvents() verarbeitet:

  • KEY_DOWNexecute_action_down()
  • KEY_UPexecute_action_up()
  • ENC_CW / ENC_CCWexecute_action_down() + delay(10) + execute_action_up()