// CMainController.h // Zentraler Orchestrator des VersaPad v2. // Kennt alle Subsysteme und koordiniert den Datenfluss zwischen ihnen. // Einzige Instanz wird in main.cpp angelegt. #pragma once #include "CButton.h" #include "CEventQueue.h" #include "SEvent.h" #include "hal/matrix.h" #include "hal/encoder.h" #include "hal/usb_hid.h" #include "hal/usb_serial.h" #include "config/action.h" #include "config/nvm_config.h" #include "config/macro_config.h" class CMainController { public: CMainController(); void setup(); // Einmalig in Arduino setup() aufrufen void work(); // Jeden Loop-Durchlauf aufrufen private: // m_queue muss vor m_buttons deklariert sein: C++ initialisiert Member in // Deklarationsreihenfolge. Die static-Bridge-Funktion (matrix_cb) erhält // einen Pointer auf m_queue – der muss zum Zeitpunkt der Nutzung gültig sein. CEventQueue m_queue; // Alle 25 Matrix-Keys (0–24) als CButton-Array. // key_id 0–3: Encoder-SW (kein LED), key_id 4: NC, key_id 5–24: MX-Buttons mit LED. CButton m_buttons[MATRIX_KEYS]; // Encoder CW/CCW-Aktionen aus NVM – Encoder haben kein CButton-Objekt. SAction m_enc_cw[4]; SAction m_enc_ccw[4]; void init_buttons(); // Buttons aus NVM-Config initialisieren void poll_vendor(); // Eingehende Serial-Pakete (PC→Board) verarbeiten void processEvents(); // Queue leeren, Aktionen ausführen 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 execute_encoder_action(SAction action, uint8_t enc_id, uint8_t host_event); void updateLEDs(); // Dirty-LEDs in WS2812-Buffer schreiben enum : uint8_t { SERIAL_PAYLOAD_BYTES = 6, CONFIG_CHUNKS = (sizeof(SDeviceConfig) + SERIAL_PAYLOAD_BYTES - 1) / SERIAL_PAYLOAD_BYTES, MACRO_CHUNKS = (sizeof(SMacroTable) + SERIAL_PAYLOAD_BYTES - 1) / SERIAL_PAYLOAD_BYTES, }; // ── Config-Empfangspuffer ───────────────────────────────────────────────── uint8_t m_cfg_buf[sizeof(SDeviceConfig)]; // 740 Bytes uint8_t m_cfg_received[CONFIG_CHUNKS]; uint8_t m_cfg_chunks_expected; bool m_cfg_receiving; bool m_cfg_transfer_valid; // ── Makro-Empfangspuffer ────────────────────────────────────────────────── uint8_t m_macro_buf[sizeof(SMacroTable)]; // 512 Bytes uint8_t m_macro_received[MACRO_CHUNKS]; uint8_t m_macro_chunks_expected; bool m_macro_receiving; bool m_macro_transfer_valid; static bool all_chunks_received(const uint8_t* received, uint8_t count); // Geladene Makro-Tabelle (im RAM – wird beim Start aus NVM geladen) SMacroTable m_macros; // Werksreset per Long-Press-Kombination: // key_id 9 = unterster linker MX-Button (COL_1 / ROW_4) // key_id 24 = unterster rechter MX-Button (COL_4 / ROW_4) bool m_factory_left_held; bool m_factory_right_held; bool m_factory_reset_armed; bool m_factory_reset_done; uint32_t m_factory_hold_started_ms; bool is_factory_reset_key(uint8_t key_id) const; bool is_factory_reset_combo_active() const; void update_factory_reset_led_feedback(); void update_factory_reset_hold(uint8_t key_id, bool pressed); void check_factory_reset(); void perform_factory_reset(); void show_factory_reset_feedback(); };