Added config, added factory reset functionality

This commit is contained in:
2026-04-18 23:59:48 +02:00
parent 433d61c29f
commit 802ab858e1
9 changed files with 718 additions and 778 deletions
+68 -65
View File
@@ -1,100 +1,103 @@
# Aktions-Engine
**Dateien:** `config/action.h`, `CButton.h/.cpp`, `CMainController.cpp` (`processEvents`, `execute_action_down`, `execute_action_up`)
Dateien:
## SAction-Struct
- `config/action.h`
- `CMainController.h/.cpp`
- `CButton.h/.cpp`
## `SAction`
```cpp
struct __attribute__((packed)) SAction {
ActionType type; // 1 Byte
uint16_t data; // 2 Bytes (Keycode, Consumer-Code, Command-ID oder Slot-Index)
ActionType type;
uint16_t data;
};
// Gesamt: 3 Bytes (packed! ohne packed wären es 4 durch Alignment)
```
`packed` ist zwingend damit `sizeof(SDeviceConfig) == 740` mit der C#-Serialisierung in VersaGUI übereinstimmt.
Groesse: 3 Byte.
Das `packed` ist zwingend, weil Config v3 bytegenau zwischen Firmware und GUI uebereinstimmen muss.
## ActionType
## `ActionType`
| Typ | Wert | Bedeutung | data-Inhalt |
|---|---|---|---|
| `NONE` | 0 | Keine Aktion | |
| `HID_KEY` | 1 | Tastendruck via USB HID Keyboard | Low-Byte = HID Keycode, High-Byte = Modifier |
| `HID_CONSUMER` | 2 | Consumer Control (Volume, Media, …) | Consumer Usage ID |
| `HOST_COMMAND` | 3 | Event an VersaGUI senden, App führt aus | Command-ID (frei definiert) |
| `MACRO` | 4 | Makro-Sequenz aus NVM-Tabelle | Slot-Index 031 |
| `PROFILE_SWITCH` | 5 | Aktives Profil wechseln | 02 = Ziel-Profil, 0xFF = nächstes Profil (Zyklus 0→1→2→0) |
| Typ | Bedeutung | `data` |
|---|---|---|
| `NONE` | keine Aktion | - |
| `HID_KEY` | Tastaturtaste ueber USB HID | low byte = keycode, high byte = modifier |
| `HID_CONSUMER` | Media/Consumer-HID | usage id |
| `HOST_COMMAND` | Event an die GUI | command id |
| `MACRO` | Makro aus `SMacroTable` | slot 0..31 |
| `PROFILE_SWITCH` | Profilwechsel | 0..2 oder `0xFF` fuer naechstes Profil |
## execute_action_down() — Taste gedrückt (Hold-Start)
## Verhalten bei `KEY_DOWN`
| ActionType | Verhalten |
| Typ | Effekt |
|---|---|
| `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) |
| `PROFILE_SWITCH` | NVM laden → `active_profile` setzen → CRC neu berechnen → NVM speichern`init_buttons()` |
| `NONE` | nop |
| `HID_KEY` | `usb_hid_send_key()` |
| `HID_CONSUMER` | `usb_hid_send_consumer()` |
| `HOST_COMMAND` | `usb_serial_send(KEY_DOWN/ENC_*)` |
| `MACRO` | komplette Sequenz sofort abspielen |
| `PROFILE_SWITCH` | Config aus NVM laden, Profil aendern, CRC neu berechnen, speichern, Buttons neu initialisieren |
| `NONE` | nichts |
## execute_action_up() — Taste losgelassen (Hold-Ende)
## Verhalten bei `KEY_UP`
| ActionType | Verhalten |
| Typ | Effekt |
|---|---|
| `HID_KEY` | `usb_hid_release_key()` |
| `HID_CONSUMER` | `usb_hid_release_consumer()` |
| `HOST_COMMAND` | — (optional: könnte `USB_EVT_KEY_UP` senden) |
| `MACRO`/`PROFILE_SWITCH`/`NONE` | nop |
| `HOST_COMMAND` | optionaler Up-Pfad, derzeit praktisch ohne Nutzlast |
| `MACRO` | nichts |
| `PROFILE_SWITCH` | nichts |
| `NONE` | nichts |
## PROFILE_SWITCH — Ablauf
## Hold- und Tap-Modell
```cpp
SDeviceConfig cfg;
nvm_config_load(cfg); // komplette Config aus NVM
uint8_t target = (uint8_t)action.data;
if (target == 0xFF)
target = (cfg.active_profile + 1) % 3; // Zyklus
cfg.active_profile = target;
cfg.crc = nvm_config_crc(cfg); // CRC MUSS nach Änderung neu berechnet werden!
if (nvm_config_save(cfg)) // bool: false = NVM-Timeout
init_buttons();
- MX-Buttons und Encoder-SW benutzen fuer HID und Consumer das Hold-Modell.
- Encoder `CW` und `CCW` sind immer diskrete Tap-Events:
```text
down -> delay(10 ms) -> up
```
> **Wichtig:** `active_profile` liegt im CRC-geschützten Bereich (ab Byte 7). Wird die CRC nicht aktualisiert, findet das nächste `nvm_config_load()` einen CRC-Fehler und lädt die Defaults (alle Aktionen NONE, alle LEDs Regenbogen).
- Makros laufen komplett synchron in der Firmware.
## Hold-Modell (HID-Keys und Consumer Controls)
## Makro-Ausfuehrung
Normale Tasten- und Media-Aktionen folgen dem **Hold-Modell**:
Bei `ActionType::MACRO` wird `action.data` als Slot interpretiert.
Die Firmware laeuft dann durch bis zu 8 Steps:
```
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
```text
step.keycode == 0 -> Ende
Key-Down
10 ms warten
Key-Up
20 ms warten
```
Das OS erkennt die gedrückte Taste und startet sein eigenes Key-Repeat nach ~500 ms — wie auf einer normalen Tastatur.
## Profilwechsel
## Tap-Modell (Encoder CW/CCW)
`PROFILE_SWITCH` arbeitet direkt auf der gespeicherten Config:
Encoder-Bewegungen sind diskret (kein Halten möglich) und verwenden das **Tap-Modell**:
1. Config aus NVM laden
2. `active_profile` aendern
3. CRC neu berechnen
4. wieder speichern
5. `init_buttons()`
```
ENC_CW/ENC_CCW-Event → execute_action_down() + delay(10) + execute_action_up()
```
Wichtig:
`active_profile` liegt im CRC-geschuetzten Bereich. Ohne neue CRC wuerde die Config beim naechsten Laden verworfen.
(Atomare Sequenz für jeden Encoder-Schritt.)
## Sonderfall Werksreset
## Work-Loop-Reihenfolge
Die Reset-Kombination uebersteuert das normale Action-System fuer genau zwei Tasten:
```cpp
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
}
```
- `key_id 9`
- `key_id 24`
**processEvents() verarbeitet:**
- `KEY_DOWN``execute_action_down()`
- `KEY_UP``execute_action_up()`
- `ENC_CW` / `ENC_CCW``execute_action_down()` + `delay(10)` + `execute_action_up()`
Sobald beide gleichzeitig gehalten werden:
- ihre normalen Actions werden nicht weiter ausgefuehrt
- eventuell bereits gestartete HID-Holds werden sofort freigegeben
- die LEDs der beiden Tasten leuchten rot
- nach 5 Sekunden wird `perform_factory_reset()` ausgefuehrt