forked from jappel/VersaMCU
Added hold function and updated doc
This commit is contained in:
parent
d6ed7cb81f
commit
3e83758f05
8 changed files with 141 additions and 105 deletions
|
|
@ -103,7 +103,7 @@ void CMainController::init_buttons()
|
|||
|
||||
// Encoder-SW-Buttons: nur SW-Aktion, kein LED (led_index = -1)
|
||||
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,
|
||||
|
|
@ -115,7 +115,7 @@ void CMainController::init_buttons()
|
|||
uint8_t row = key % MATRIX_ROWS;
|
||||
int8_t led = static_cast<int8_t>(LED_INDEX(col, row));
|
||||
uint8_t mx_idx = key - 5;
|
||||
RGB base(cfg.led_r[mx_idx], cfg.led_g[mx_idx], cfg.led_b[mx_idx]);
|
||||
RGB base(cfg.led_r[mx_idx], cfg.led_g[mx_idx], cfg.led_b[mx_idx]);
|
||||
m_buttons[key].init(key, led, cfg.mx_actions[mx_idx], base);
|
||||
|
||||
LEDAnim anim = static_cast<LEDAnim>(cfg.led_anim[mx_idx]);
|
||||
|
|
@ -142,10 +142,10 @@ void CMainController::init_buttons()
|
|||
|
||||
void CMainController::work()
|
||||
{
|
||||
matrix_scan(); // 1. Matrix scannen → Debounce → matrix_cb() → Queue
|
||||
poll_vendor(); // 2. Eingehende Serial-Pakete (PC→Board) verarbeiten
|
||||
processEvents(); // 3. Queue leeren: Aktionen ausführen, Buttons benachrichtigen
|
||||
updateLEDs(); // 4. Geänderte LED-Zustände in WS2812-Buffer schreiben + show()
|
||||
matrix_scan(); // 1. Matrix scannen → Debounce → matrix_cb() → Queue
|
||||
poll_vendor(); // 2. Eingehende Serial-Pakete (PC→Board) verarbeiten
|
||||
processEvents(); // 3. Queue leeren, Aktionen ausführen
|
||||
updateLEDs(); // 4. Geänderte LED-Zustände in WS2812-Buffer schreiben + show()
|
||||
}
|
||||
|
||||
// ─── Vendor-Kommunikation (PC → Board) ───────────────────────────────────────
|
||||
|
|
@ -212,9 +212,9 @@ void CMainController::poll_vendor()
|
|||
SDeviceConfig cfg;
|
||||
nvm_config_load(cfg); // ungültige NVM → Defaults
|
||||
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;
|
||||
uint8_t chunks = (sz + payload - 1) / payload; // 28
|
||||
uint8_t chunks = (sz + payload - 1) / payload; // 38
|
||||
|
||||
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.
|
||||
// Reihenfolge: ältestes Event zuerst (FIFO).
|
||||
//
|
||||
// HOST_COMMAND-Aktionen werden zusätzlich über Serial an die Windows-App
|
||||
// gemeldet – die App entscheidet dann was passiert (URL öffnen, Programm starten…).
|
||||
// KEY_DOWN: execute_action_down() – HID-Taste wird gedrückt, bleibt aktiv bis KEY_UP.
|
||||
// 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()
|
||||
{
|
||||
SEvent ev;
|
||||
|
||||
while (m_queue.pop(ev)) {
|
||||
switch (ev.type) {
|
||||
|
||||
case EventType::KEY_DOWN:
|
||||
if (ev.key_id < MATRIX_KEYS) {
|
||||
m_buttons[ev.key_id].on_press();
|
||||
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);
|
||||
}
|
||||
if (ev.key_id < MATRIX_KEYS)
|
||||
execute_action_down(m_buttons[ev.key_id].action(), ev.key_id);
|
||||
break;
|
||||
|
||||
case EventType::KEY_UP:
|
||||
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;
|
||||
|
||||
case EventType::ENC_CW:
|
||||
if (ev.key_id < 4) {
|
||||
execute_action(m_enc_cw[ev.key_id]);
|
||||
if (m_enc_cw[ev.key_id].type == ActionType::HOST_COMMAND)
|
||||
usb_serial_send(USB_EVT_ENC_CW, ev.key_id);
|
||||
execute_action_down(m_enc_cw[ev.key_id], ev.key_id);
|
||||
delay(10);
|
||||
execute_action_up(m_enc_cw[ev.key_id], ev.key_id);
|
||||
}
|
||||
break;
|
||||
|
||||
case EventType::ENC_CCW:
|
||||
if (ev.key_id < 4) {
|
||||
execute_action(m_enc_ccw[ev.key_id]);
|
||||
if (m_enc_ccw[ev.key_id].type == ActionType::HOST_COMMAND)
|
||||
usb_serial_send(USB_EVT_ENC_CCW, ev.key_id);
|
||||
execute_action_down(m_enc_ccw[ev.key_id], ev.key_id);
|
||||
delay(10);
|
||||
execute_action_up(m_enc_ccw[ev.key_id], ev.key_id);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -362,35 +359,51 @@ void CMainController::processEvents()
|
|||
}
|
||||
}
|
||||
|
||||
// Führt eine einzelne Aktion aus.
|
||||
// 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
|
||||
// usb_serial_send() an die Windows-App weitergeleitet.
|
||||
void CMainController::execute_action(SAction action)
|
||||
// ─── Aktions-Ausführung ───────────────────────────────────────────────────────
|
||||
//
|
||||
// execute_action_down(): Taste wird gedrückt (Hold-Start).
|
||||
// HID_KEY: sendet Key-Down, bleibt aktiv.
|
||||
// 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) {
|
||||
|
||||
case ActionType::HID_KEY:
|
||||
{
|
||||
// data-Encoding: Low-Byte = Keycode, High-Byte = Modifier
|
||||
usb_hid_send_key(static_cast<uint8_t>(action.data & 0xFF),
|
||||
static_cast<uint8_t>(action.data >> 8));
|
||||
delay(10); // Host braucht kurz Zeit zwischen Key-Down und Key-Up
|
||||
usb_hid_release_key();
|
||||
uint8_t keycode = static_cast<uint8_t>(action.data & 0xFF);
|
||||
uint8_t modifier = static_cast<uint8_t>(action.data >> 8);
|
||||
usb_hid_send_key(keycode, modifier);
|
||||
// Taste bleibt gedrückt bis execute_action_up() aufgerufen wird
|
||||
break;
|
||||
}
|
||||
|
||||
case ActionType::HID_CONSUMER:
|
||||
{
|
||||
usb_hid_send_consumer(action.data);
|
||||
usb_hid_release_consumer();
|
||||
// Consumer-Control bleibt aktiv bis execute_action_up() aufgerufen wird
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
case ActionType::MACRO:
|
||||
{
|
||||
// Makro-Slot aus dem RAM ausführen (bei setup() aus NVM geladen).
|
||||
// Steps mit keycode=0 werden übersprungen; erstes leeres Step stoppt.
|
||||
// Makros sind Sequenzen – Steps mit keycode=0 werden übersprungen;
|
||||
// erstes leeres Step stoppt.
|
||||
uint8_t slot = static_cast<uint8_t>(action.data);
|
||||
if (slot >= MACRO_SLOTS) break;
|
||||
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 ────────────────────────────────────────────────────────────
|
||||
//
|
||||
// Fragt alle CButton-Instanzen ab. Jede Instanz mit dirty-Flag schreibt
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue