Added hold function and updated doc
This commit is contained in:
parent
d6ed7cb81f
commit
3e83758f05
@ -1,6 +1,6 @@
|
|||||||
# Aktions-Engine
|
# Aktions-Engine
|
||||||
|
|
||||||
**Dateien:** `config/action.h`, `CMainController.cpp` (`processEvents`, `execute_action`)
|
**Dateien:** `config/action.h`, `CButton.h/.cpp`, `CMainController.cpp` (`processEvents`, `execute_action_down`, `execute_action_up`)
|
||||||
|
|
||||||
## SAction-Struct
|
## SAction-Struct
|
||||||
|
|
||||||
@ -24,47 +24,59 @@ struct __attribute__((packed)) SAction {
|
|||||||
| `HOST_COMMAND` | Event an VersaGUI senden, App führt aus | Command-ID (frei definiert) |
|
| `HOST_COMMAND` | Event an VersaGUI senden, App führt aus | Command-ID (frei definiert) |
|
||||||
| `MACRO` | Makro-Sequenz aus NVM-Tabelle | Slot-Index 0–31 |
|
| `MACRO` | Makro-Sequenz aus NVM-Tabelle | Slot-Index 0–31 |
|
||||||
|
|
||||||
## Ausführung (execute_action)
|
## execute_action_down() — Taste gedrückt (Hold-Start)
|
||||||
|
|
||||||
**HID_KEY:**
|
| ActionType | Verhalten |
|
||||||
```
|
|---|---|
|
||||||
usb_hid_send_key(keycode, modifier)
|
| `HID_KEY` | `usb_hid_send_key(keycode, modifier)` — Taste bleibt gedrückt bis `execute_action_up()` |
|
||||||
delay(10 ms)
|
| `HID_CONSUMER` | `usb_hid_send_consumer(usage_id)` — bleibt aktiv bis `execute_action_up()` |
|
||||||
usb_hid_release_key()
|
| `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) |
|
||||||
→ Tap-Only-Modell. Kein Hold-Support. KEY_UP löst kein HID-Release aus.
|
| `NONE` | nop |
|
||||||
|
|
||||||
**HID_CONSUMER:**
|
## execute_action_up() — Taste losgelassen (Hold-Ende)
|
||||||
```
|
|
||||||
usb_hid_send_consumer(usage_id)
|
|
||||||
usb_hid_release_consumer()
|
|
||||||
```
|
|
||||||
→ Kein Delay nötig (Consumer-Keys sind Edge-getriggert).
|
|
||||||
|
|
||||||
**HOST_COMMAND:**
|
| ActionType | Verhalten |
|
||||||
`execute_action()` macht nichts. `processEvents()` sendet zusätzlich `USB_EVT_KEY_DOWN` via CDC Serial an VersaGUI. Die App entscheidet was passiert (URL öffnen, Programm starten, …).
|
|---|---|
|
||||||
|
| `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**:
|
||||||
|
|
||||||
**MACRO:**
|
|
||||||
```
|
```
|
||||||
für jeden Step [0–3] im Slot:
|
KEY_DOWN-Event vom Board → execute_action_down() → HID Key-Down senden
|
||||||
if keycode == 0: abbrechen
|
[Taste bleibt physisch gedrückt...]
|
||||||
usb_hid_send_key(keycode, modifier)
|
KEY_UP-Event vom Board → execute_action_up() → HID Key-Up senden
|
||||||
delay(10 ms)
|
|
||||||
usb_hid_release_key()
|
|
||||||
delay(20 ms) // Pause damit der Host den Step verarbeiten kann
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Event-Verarbeitung
|
Das OS erkennt die gedrückte Taste und startet sein eigenes Key-Repeat nach ~500 ms — wie auf einer normalen Tastatur.
|
||||||
|
|
||||||
Events werden in `processEvents()` aus `CEventQueue` konsumiert (FIFO):
|
## Tap-Modell (Encoder CW/CCW)
|
||||||
|
|
||||||
- `KEY_DOWN` → `CButton.on_press()` (aktuell leer, Erweiterungspunkt) + `execute_action()`
|
Encoder-Bewegungen sind diskret (kein Halten möglich) und verwenden das **Tap-Modell**:
|
||||||
- `KEY_UP` → `CButton.on_release()` (aktuell leer)
|
|
||||||
- `ENC_CW/CCW` → `execute_action(m_enc_cw/ccw[enc_id])`
|
|
||||||
|
|
||||||
Encoder CW/CCW-Aktionen sind in `CMainController` direkt als `SAction`-Arrays gehalten (kein CButton-Objekt, da Encoder keine LED haben).
|
```
|
||||||
|
ENC_CW/ENC_CCW-Event → execute_action_down() + delay(10) + execute_action_up()
|
||||||
|
```
|
||||||
|
|
||||||
## Bekannte Einschränkungen
|
(Atomare Sequenz für jeden Encoder-Schritt.)
|
||||||
|
|
||||||
- **Kein Hold**: `execute_action` bei KEY_DOWN sendet sofort Key-Down + Key-Up. Halten der Taste löst keine Wiederholung aus.
|
## Work-Loop-Reihenfolge
|
||||||
- **HOST_COMMAND KEY_UP**: Board sendet derzeit kein `USB_EVT_KEY_UP` für KEY_UP-Events (nur KEY_DOWN wird gemeldet).
|
|
||||||
|
```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
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**processEvents() verarbeitet:**
|
||||||
|
- `KEY_DOWN` → `execute_action_down()`
|
||||||
|
- `KEY_UP` → `execute_action_up()`
|
||||||
|
- `ENC_CW` / `ENC_CCW` → `execute_action_down()` + `delay(10)` + `execute_action_up()`
|
||||||
|
|||||||
@ -32,7 +32,7 @@ Beide Rows sind im Linkerscript vom Code-Bereich ausgeschlossen.
|
|||||||
## CRC16-CCITT
|
## CRC16-CCITT
|
||||||
|
|
||||||
- Polynom: `0x1021`, Init: `0xFFFF`
|
- Polynom: `0x1021`, Init: `0xFFFF`
|
||||||
- Berechnet über Bytes 7–222 (ab `mx_actions`, nach dem `crc`-Feld selbst)
|
- Berechnet über Bytes 7–248 (ab `mx_actions`, nach dem `crc`-Feld selbst)
|
||||||
- Sichert Datenintegrität nach NVM-Schreiben und bei Versionswechsel
|
- Sichert Datenintegrität nach NVM-Schreiben und bei Versionswechsel
|
||||||
|
|
||||||
## Lese-Logik
|
## Lese-Logik
|
||||||
|
|||||||
@ -73,18 +73,6 @@ void CButton::init(uint8_t key_id, int8_t led_index, SAction action, RGB base)
|
|||||||
m_dirty = true; // Initialen Zustand beim ersten render_led() schreiben
|
m_dirty = true; // Initialen Zustand beim ersten render_led() schreiben
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Tastendruck-Hooks ─────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
void CButton::on_press()
|
|
||||||
{
|
|
||||||
// Reserviert für zukünftige Button-Logik (Hold, Toggle, Doppelklick …)
|
|
||||||
}
|
|
||||||
|
|
||||||
void CButton::on_release()
|
|
||||||
{
|
|
||||||
// Reserviert für zukünftige Button-Logik
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── LED Layer 1: base ─────────────────────────────────────────────────────────
|
// ── LED Layer 1: base ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
void CButton::set_base(RGB color)
|
void CButton::set_base(RGB color)
|
||||||
|
|||||||
@ -61,13 +61,8 @@ public:
|
|||||||
CButton();
|
CButton();
|
||||||
|
|
||||||
// Initialisierung (ersetzt Konstruktor-Parameter).
|
// Initialisierung (ersetzt Konstruktor-Parameter).
|
||||||
// led_index = -1 → kein LED (Encoder-SW-Buttons).
|
void init(uint8_t key_id, int8_t led_index, SAction action,
|
||||||
void init(uint8_t key_id, int8_t led_index, SAction action, RGB base = RGB());
|
RGB base = RGB());
|
||||||
|
|
||||||
// Hooks für Tastendruck/-loslassen.
|
|
||||||
// Reserviert für zukünftige Logik (Hold-Aktionen, Toggle-Modus, …).
|
|
||||||
void on_press();
|
|
||||||
void on_release();
|
|
||||||
|
|
||||||
// ── LED Layer 1: base ─────────────────────────────────────────────────────
|
// ── LED Layer 1: base ─────────────────────────────────────────────────────
|
||||||
// Idle-Farbe, aus NVM geladen oder von Windows-App gesetzt.
|
// Idle-Farbe, aus NVM geladen oder von Windows-App gesetzt.
|
||||||
|
|||||||
@ -103,7 +103,7 @@ void CMainController::init_buttons()
|
|||||||
|
|
||||||
// Encoder-SW-Buttons: nur SW-Aktion, kein LED (led_index = -1)
|
// Encoder-SW-Buttons: nur SW-Aktion, kein LED (led_index = -1)
|
||||||
for (uint8_t enc = 0; enc < 4; enc++) {
|
for (uint8_t enc = 0; enc < 4; enc++) {
|
||||||
m_buttons[enc].init(enc, -1, cfg.enc_actions[enc][ENC_ACTION_SW]);
|
m_buttons[enc].init(enc, -1, cfg.enc_actions[enc][ENC_ACTION_SW], RGB());
|
||||||
}
|
}
|
||||||
|
|
||||||
// MX-Buttons: LED-Index aus serpentiner Verdrahtung berechnen,
|
// MX-Buttons: LED-Index aus serpentiner Verdrahtung berechnen,
|
||||||
@ -144,7 +144,7 @@ void CMainController::work()
|
|||||||
{
|
{
|
||||||
matrix_scan(); // 1. Matrix scannen → Debounce → matrix_cb() → Queue
|
matrix_scan(); // 1. Matrix scannen → Debounce → matrix_cb() → Queue
|
||||||
poll_vendor(); // 2. Eingehende Serial-Pakete (PC→Board) verarbeiten
|
poll_vendor(); // 2. Eingehende Serial-Pakete (PC→Board) verarbeiten
|
||||||
processEvents(); // 3. Queue leeren: Aktionen ausführen, Buttons benachrichtigen
|
processEvents(); // 3. Queue leeren, Aktionen ausführen
|
||||||
updateLEDs(); // 4. Geänderte LED-Zustände in WS2812-Buffer schreiben + show()
|
updateLEDs(); // 4. Geänderte LED-Zustände in WS2812-Buffer schreiben + show()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,9 +212,9 @@ void CMainController::poll_vendor()
|
|||||||
SDeviceConfig cfg;
|
SDeviceConfig cfg;
|
||||||
nvm_config_load(cfg); // ungültige NVM → Defaults
|
nvm_config_load(cfg); // ungültige NVM → Defaults
|
||||||
const uint8_t* raw = reinterpret_cast<const uint8_t*>(&cfg);
|
const uint8_t* raw = reinterpret_cast<const uint8_t*>(&cfg);
|
||||||
const uint8_t sz = sizeof(SDeviceConfig); // 163
|
const uint8_t sz = sizeof(SDeviceConfig); // 223
|
||||||
const uint8_t payload = 6;
|
const uint8_t payload = 6;
|
||||||
uint8_t chunks = (sz + payload - 1) / payload; // 28
|
uint8_t chunks = (sz + payload - 1) / payload; // 38
|
||||||
|
|
||||||
usb_serial_send(USB_EVT_CONFIG_BEGIN, chunks);
|
usb_serial_send(USB_EVT_CONFIG_BEGIN, chunks);
|
||||||
|
|
||||||
@ -316,43 +316,40 @@ void CMainController::poll_vendor()
|
|||||||
// Verarbeitet alle Events in der Queue bis sie leer ist.
|
// Verarbeitet alle Events in der Queue bis sie leer ist.
|
||||||
// Reihenfolge: ältestes Event zuerst (FIFO).
|
// Reihenfolge: ältestes Event zuerst (FIFO).
|
||||||
//
|
//
|
||||||
// HOST_COMMAND-Aktionen werden zusätzlich über Serial an die Windows-App
|
// KEY_DOWN: execute_action_down() – HID-Taste wird gedrückt, bleibt aktiv bis KEY_UP.
|
||||||
// gemeldet – die App entscheidet dann was passiert (URL öffnen, Programm starten…).
|
// KEY_UP: execute_action_up() – HID-Taste wird losgelassen.
|
||||||
|
// Encoder CW/CCW: execute_action_down() + execute_action_up() für atomare TAP-Sequenz.
|
||||||
|
|
||||||
void CMainController::processEvents()
|
void CMainController::processEvents()
|
||||||
{
|
{
|
||||||
SEvent ev;
|
SEvent ev;
|
||||||
|
|
||||||
while (m_queue.pop(ev)) {
|
while (m_queue.pop(ev)) {
|
||||||
switch (ev.type) {
|
switch (ev.type) {
|
||||||
|
|
||||||
case EventType::KEY_DOWN:
|
case EventType::KEY_DOWN:
|
||||||
if (ev.key_id < MATRIX_KEYS) {
|
if (ev.key_id < MATRIX_KEYS)
|
||||||
m_buttons[ev.key_id].on_press();
|
execute_action_down(m_buttons[ev.key_id].action(), ev.key_id);
|
||||||
execute_action(m_buttons[ev.key_id].action());
|
|
||||||
// Bei HOST_COMMAND: Event-ID an Windows-App senden
|
|
||||||
if (m_buttons[ev.key_id].action().type == ActionType::HOST_COMMAND)
|
|
||||||
usb_serial_send(USB_EVT_KEY_DOWN, ev.key_id);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EventType::KEY_UP:
|
case EventType::KEY_UP:
|
||||||
if (ev.key_id < MATRIX_KEYS)
|
if (ev.key_id < MATRIX_KEYS)
|
||||||
m_buttons[ev.key_id].on_release();
|
execute_action_up(m_buttons[ev.key_id].action(), ev.key_id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EventType::ENC_CW:
|
case EventType::ENC_CW:
|
||||||
if (ev.key_id < 4) {
|
if (ev.key_id < 4) {
|
||||||
execute_action(m_enc_cw[ev.key_id]);
|
execute_action_down(m_enc_cw[ev.key_id], ev.key_id);
|
||||||
if (m_enc_cw[ev.key_id].type == ActionType::HOST_COMMAND)
|
delay(10);
|
||||||
usb_serial_send(USB_EVT_ENC_CW, ev.key_id);
|
execute_action_up(m_enc_cw[ev.key_id], ev.key_id);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EventType::ENC_CCW:
|
case EventType::ENC_CCW:
|
||||||
if (ev.key_id < 4) {
|
if (ev.key_id < 4) {
|
||||||
execute_action(m_enc_ccw[ev.key_id]);
|
execute_action_down(m_enc_ccw[ev.key_id], ev.key_id);
|
||||||
if (m_enc_ccw[ev.key_id].type == ActionType::HOST_COMMAND)
|
delay(10);
|
||||||
usb_serial_send(USB_EVT_ENC_CCW, ev.key_id);
|
execute_action_up(m_enc_ccw[ev.key_id], ev.key_id);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -362,35 +359,51 @@ void CMainController::processEvents()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Führt eine einzelne Aktion aus.
|
// ─── Aktions-Ausführung ───────────────────────────────────────────────────────
|
||||||
// HID_KEY / HID_CONSUMER: direkt über USB HID gesendet (funktioniert ohne Windows-App).
|
//
|
||||||
// HOST_COMMAND: kein direkter Aufruf hier – das Event wird in processEvents() via
|
// execute_action_down(): Taste wird gedrückt (Hold-Start).
|
||||||
// usb_serial_send() an die Windows-App weitergeleitet.
|
// HID_KEY: sendet Key-Down, bleibt aktiv.
|
||||||
void CMainController::execute_action(SAction action)
|
// HID_CONSUMER: sendet Consumer-Down, bleibt aktiv.
|
||||||
|
// HOST_COMMAND: sendet KEY_DOWN-Event an Windows-App.
|
||||||
|
// MACRO: führt volle Sequenz aus (Key-Down/Up jeweils mit Pause).
|
||||||
|
// NONE: keine Aktion.
|
||||||
|
//
|
||||||
|
// execute_action_up(): Taste wird losgelassen (Hold-Ende).
|
||||||
|
// HID_KEY: sendet Key-Up.
|
||||||
|
// HID_CONSUMER: sendet Consumer-Up.
|
||||||
|
// HOST_COMMAND: kann USB_EVT_KEY_UP senden.
|
||||||
|
// MACRO/NONE: keine Aktion.
|
||||||
|
|
||||||
|
void CMainController::execute_action_down(SAction action, uint8_t key_id)
|
||||||
{
|
{
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
|
||||||
case ActionType::HID_KEY:
|
case ActionType::HID_KEY:
|
||||||
|
{
|
||||||
// data-Encoding: Low-Byte = Keycode, High-Byte = Modifier
|
// data-Encoding: Low-Byte = Keycode, High-Byte = Modifier
|
||||||
usb_hid_send_key(static_cast<uint8_t>(action.data & 0xFF),
|
uint8_t keycode = static_cast<uint8_t>(action.data & 0xFF);
|
||||||
static_cast<uint8_t>(action.data >> 8));
|
uint8_t modifier = static_cast<uint8_t>(action.data >> 8);
|
||||||
delay(10); // Host braucht kurz Zeit zwischen Key-Down und Key-Up
|
usb_hid_send_key(keycode, modifier);
|
||||||
usb_hid_release_key();
|
// Taste bleibt gedrückt bis execute_action_up() aufgerufen wird
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ActionType::HID_CONSUMER:
|
case ActionType::HID_CONSUMER:
|
||||||
|
{
|
||||||
usb_hid_send_consumer(action.data);
|
usb_hid_send_consumer(action.data);
|
||||||
usb_hid_release_consumer();
|
// Consumer-Control bleibt aktiv bis execute_action_up() aufgerufen wird
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ActionType::HOST_COMMAND:
|
case ActionType::HOST_COMMAND:
|
||||||
// Wird in processEvents() über Serial gesendet
|
// Windows-App übernimmt Ausführung; KEY_DOWN-Event senden
|
||||||
|
usb_serial_send(USB_EVT_KEY_DOWN, key_id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ActionType::MACRO:
|
case ActionType::MACRO:
|
||||||
{
|
{
|
||||||
// Makro-Slot aus dem RAM ausführen (bei setup() aus NVM geladen).
|
// Makros sind Sequenzen – Steps mit keycode=0 werden übersprungen;
|
||||||
// Steps mit keycode=0 werden übersprungen; erstes leeres Step stoppt.
|
// erstes leeres Step stoppt.
|
||||||
uint8_t slot = static_cast<uint8_t>(action.data);
|
uint8_t slot = static_cast<uint8_t>(action.data);
|
||||||
if (slot >= MACRO_SLOTS) break;
|
if (slot >= MACRO_SLOTS) break;
|
||||||
for (uint8_t i = 0; i < MACRO_MAX_STEPS; i++) {
|
for (uint8_t i = 0; i < MACRO_MAX_STEPS; i++) {
|
||||||
@ -410,6 +423,31 @@ void CMainController::execute_action(SAction action)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CMainController::execute_action_up(SAction action, uint8_t key_id)
|
||||||
|
{
|
||||||
|
switch (action.type) {
|
||||||
|
|
||||||
|
case ActionType::HID_KEY:
|
||||||
|
usb_hid_release_key();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ActionType::HID_CONSUMER:
|
||||||
|
usb_hid_release_consumer();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ActionType::HOST_COMMAND:
|
||||||
|
// Optional: USB_EVT_KEY_UP senden (aktuell nicht implementiert)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ActionType::MACRO:
|
||||||
|
case ActionType::NONE:
|
||||||
|
default:
|
||||||
|
// MACRO: Sequenz ist in execute_action_down() komplett abgelaufen, nop hier
|
||||||
|
// NONE: keine Aktion
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ─── LED-Rendering ────────────────────────────────────────────────────────────
|
// ─── LED-Rendering ────────────────────────────────────────────────────────────
|
||||||
//
|
//
|
||||||
// Fragt alle CButton-Instanzen ab. Jede Instanz mit dirty-Flag schreibt
|
// Fragt alle CButton-Instanzen ab. Jede Instanz mit dirty-Flag schreibt
|
||||||
|
|||||||
@ -38,7 +38,8 @@ private:
|
|||||||
void init_buttons(); // Buttons aus NVM-Config initialisieren
|
void init_buttons(); // Buttons aus NVM-Config initialisieren
|
||||||
void poll_vendor(); // Eingehende Serial-Pakete (PC→Board) verarbeiten
|
void poll_vendor(); // Eingehende Serial-Pakete (PC→Board) verarbeiten
|
||||||
void processEvents(); // Queue leeren, Aktionen ausführen
|
void processEvents(); // Queue leeren, Aktionen ausführen
|
||||||
void execute_action(SAction); // Einzelne Aktion ausführen (HID / Serial)
|
void execute_action_down(SAction action, uint8_t key_id); // Taste drücken (Hold-Start)
|
||||||
|
void execute_action_up(SAction action, uint8_t key_id); // Taste losgelassen (Hold-Ende)
|
||||||
void updateLEDs(); // Dirty-LEDs in WS2812-Buffer schreiben
|
void updateLEDs(); // Dirty-LEDs in WS2812-Buffer schreiben
|
||||||
|
|
||||||
// ── Config-Empfangspuffer ─────────────────────────────────────────────────
|
// ── Config-Empfangspuffer ─────────────────────────────────────────────────
|
||||||
|
|||||||
@ -106,8 +106,10 @@ bool nvm_config_load(SDeviceConfig& cfg)
|
|||||||
// ── Speichern ─────────────────────────────────────────────────────────────────
|
// ── Speichern ─────────────────────────────────────────────────────────────────
|
||||||
void nvm_config_save(const SDeviceConfig& cfg)
|
void nvm_config_save(const SDeviceConfig& cfg)
|
||||||
{
|
{
|
||||||
// Config in temporären Buffer kopieren der auf 256B (Row) aufgefüllt ist
|
// Config in temporären Buffer kopieren der auf 256B (Row) aufgefüllt ist.
|
||||||
uint8_t row[256];
|
// __attribute__((aligned(4))) ist zwingend: nvm_write_page castet data zu
|
||||||
|
// const uint32_t*, und unaligned 32-Bit-Zugriffe sind HardFaults auf Cortex-M0+.
|
||||||
|
uint8_t row[256] __attribute__((aligned(4)));
|
||||||
memset(row, 0xFF, sizeof(row));
|
memset(row, 0xFF, sizeof(row));
|
||||||
memcpy(row, &cfg, sizeof(cfg));
|
memcpy(row, &cfg, sizeof(cfg));
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
// Gesamt genutzt: 223 Bytes (sizeof SDeviceConfig mit packed SAction)
|
// Gesamt genutzt: 223 Bytes (sizeof SDeviceConfig mit packed SAction)
|
||||||
|
|
||||||
#define NVM_CONFIG_MAGIC 0x56503202UL
|
#define NVM_CONFIG_MAGIC 0x56503202UL
|
||||||
#define NVM_CONFIG_VERSION 2 // Version 2: led_anim + led_period_ms hinzugefügt
|
#define NVM_CONFIG_VERSION 2 // Version 2
|
||||||
|
|
||||||
// Encoder-Aktions-Indizes (in SDeviceConfig.enc_actions[])
|
// Encoder-Aktions-Indizes (in SDeviceConfig.enc_actions[])
|
||||||
// Reihenfolge: [enc][0]=SW, [enc][1]=CW, [enc][2]=CCW
|
// Reihenfolge: [enc][0]=SW, [enc][1]=CW, [enc][2]=CCW
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user