Update firmware documentation and agent guidance
This commit is contained in:
+2
-2
@@ -45,7 +45,7 @@ struct RGB
|
||||
enum class LEDAnim : uint8_t
|
||||
{
|
||||
STATIC = 0, // Sofort, keine Animation (Standardzustand)
|
||||
BLINK, // Binäres An/Aus – period_ms = Halbperiode (An-Zeit = Aus-Zeit)
|
||||
BLINK, // Binäres An/Aus – period_ms = Vollperiode (50 % an, 50 % aus)
|
||||
PULSE, // Lineares Fade-In/Fade-Out in Schleife – period_ms = Vollperiode
|
||||
FADE_IN, // Einmalig: schwarz → volle Helligkeit über period_ms
|
||||
FADE_OUT, // Einmalig: volle Helligkeit → schwarz über period_ms
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
|
||||
// ── LED-Animation ─────────────────────────────────────────────────────────
|
||||
// set_anim(): für STATIC, BLINK, PULSE, FADE_IN, FADE_OUT, COLOR_CYCLE.
|
||||
// period_ms: Halbperiode (BLINK), Vollperiode (PULSE/COLOR_CYCLE), Dauer (FADE_*).
|
||||
// period_ms: Vollperiode (BLINK/PULSE/COLOR_CYCLE), Dauer (FADE_*).
|
||||
// phase_offset_ms: Zeitversatz in die Vergangenheit – verschiebt den Startpunkt der
|
||||
// Animation. Nützlich für COLOR_CYCLE um LEDs versetzt starten zu
|
||||
// lassen (Regenbogen-Wellen-Effekt über mehrere Buttons).
|
||||
|
||||
+4
-5
@@ -7,11 +7,10 @@
|
||||
// Leer: m_head == m_tail
|
||||
// Voll: (m_tail + 1) % SIZE == m_head → ein Slot bleibt immer frei
|
||||
//
|
||||
// Interrupt-Sicherheit (Cortex-M0+):
|
||||
// push() wird aus Encoder-ISR aufgerufen, pop() aus dem Loop.
|
||||
// Auf M0+ sind uint8_t-Lese/Schreibzugriffe atomar (single-cycle LDR/STR) –
|
||||
// solange nur ein Producer (ISR) und ein Consumer (Loop) existieren, ist kein
|
||||
// Mutex nötig. Bei mehreren Producern müsste noInterrupts() verwendet werden.
|
||||
// Nebenläufigkeit:
|
||||
// Encoder-ISRs und der Matrixcallback im Loop können beide push() aufrufen.
|
||||
// Dieser gemischte Producerfall ist aktuell nicht durch eine Critical
|
||||
// Section geschützt; siehe doc/09_known_limitations.md.
|
||||
|
||||
#include "CEventQueue.h"
|
||||
|
||||
|
||||
+4
-5
@@ -7,11 +7,10 @@
|
||||
// Kapazität: QUEUE_SIZE - 1 = 16 Events (ein Slot bleibt leer damit
|
||||
// is_full() und is_empty() ohne extra Zähler unterscheidbar sind).
|
||||
//
|
||||
// Thread-Sicherheit:
|
||||
// push() wird aus ISR-Kontext aufgerufen (encoder_cb).
|
||||
// pop() wird aus Loop-Kontext aufgerufen (processEvents).
|
||||
// Auf Cortex-M0+ sind 8-Bit-Lese/Schreibzugriffe atomar → kein Mutex nötig
|
||||
// solange nur ein Producer (ISR) und ein Consumer (Loop) existieren.
|
||||
// Nebenläufigkeit:
|
||||
// push() wird aus Encoder-ISRs und aus dem Matrixcallback im Loop aufgerufen.
|
||||
// pop() läuft ebenfalls im Loop. Es gibt aktuell keine Critical Section für
|
||||
// den Fall, dass ein Encoderinterrupt einen Matrix-Push unterbricht.
|
||||
|
||||
#pragma once
|
||||
#include "SEvent.h"
|
||||
|
||||
@@ -58,7 +58,8 @@ static void matrix_cb(uint8_t key, bool pressed)
|
||||
}
|
||||
|
||||
// Wird von handle_encoder() aufgerufen – läuft im ISR-Kontext (EIC-Interrupt).
|
||||
// CEventQueue::push() ist interrupt-sicher (kein Heap, atomare Indizes auf M0+).
|
||||
// Die Queue vermeidet den Heap, schützt den gemischten Matrix-/ISR-Producerfall
|
||||
// aber aktuell nicht mit einer Critical Section.
|
||||
static void encoder_cb(uint8_t enc, int8_t dir)
|
||||
{
|
||||
if (!s_queue) return;
|
||||
@@ -168,7 +169,7 @@ void CMainController::work()
|
||||
poll_vendor(); // 2. Eingehende Serial-Pakete (PC→Board) verarbeiten
|
||||
processEvents(); // 3. Queue leeren, Aktionen ausführen
|
||||
check_factory_reset();// 4. Long-Press-Kombination für Werksreset prüfen
|
||||
updateLEDs(); // 4. Geänderte LED-Zustände in WS2812-Buffer schreiben + show()
|
||||
updateLEDs(); // 5. Geänderte LED-Zustände in WS2812-Buffer schreiben + show()
|
||||
}
|
||||
|
||||
// ─── Vendor-Kommunikation (PC → Board) ───────────────────────────────────────
|
||||
@@ -525,7 +526,7 @@ void CMainController::show_factory_reset_feedback()
|
||||
// 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.
|
||||
// HOST_COMMAND: aktuell keine Ausgabe auf Release.
|
||||
// MACRO/NONE: keine Aktion.
|
||||
|
||||
void CMainController::execute_action_down(SAction action, uint8_t key_id)
|
||||
@@ -606,7 +607,7 @@ void CMainController::execute_action_up(SAction action, uint8_t key_id)
|
||||
break;
|
||||
|
||||
case ActionType::HOST_COMMAND:
|
||||
// Optional: USB_EVT_KEY_UP senden (aktuell nicht implementiert)
|
||||
// USB_EVT_KEY_UP ist definiert, wird aktuell aber nicht gesendet.
|
||||
break;
|
||||
|
||||
case ActionType::MACRO:
|
||||
|
||||
+5
-4
@@ -6,15 +6,16 @@ enum class ActionType : uint8_t
|
||||
NONE, // Keine Aktion
|
||||
HID_KEY, // Standard-Keyboard-Keycode (direkt in Firmware gesendet)
|
||||
HID_CONSUMER, // Consumer-Control-Keycode (Volume, Media, …)
|
||||
HOST_COMMAND, // Command-ID → Windows-App führt aus (URL, Programm, …)
|
||||
HOST_COMMAND, // Host-Event; data wird vom aktuellen Controller nicht übertragen
|
||||
MACRO, // Makro-Slot (data = Slot-Index 0–31) → bis zu 8 HID-Keys sequenziell
|
||||
PROFILE_SWITCH, // Profil wechseln (data = Profil-Index 0–2); speichert in NVM
|
||||
PROFILE_SWITCH, // Profil 0–2 oder 0xFF = nächstes Profil; speichert in NVM
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) SAction
|
||||
{
|
||||
ActionType type;
|
||||
uint16_t data; // Keycode (HID_KEY / HID_CONSUMER) oder Command-ID (HOST_COMMAND)
|
||||
uint16_t data; // Typabhängige Nutzdaten; für HOST_COMMAND aktuell ungenutzt
|
||||
// packed: 1B type + 2B data = 3B (kein Alignment-Padding)
|
||||
// Muss packed sein damit sizeof(SDeviceConfig)==163 == C#-Serialisierung
|
||||
// Muss packed sein, damit sizeof(SDeviceConfig)==740 und die
|
||||
// hostseitige Serialisierung bytegenau übereinstimmen.
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//
|
||||
// Slot-Zuweisung (vom Windows-App vergeben, Board speichert blind):
|
||||
// Slot 0–19 : MX-Buttons (mx_idx)
|
||||
// Slot 20–31 : Encoder-Aktionen (enc*3 + act_idx, 0=SW/1=CW/2=CCW)
|
||||
// Slot 20–31 : Encoder-Aktionen (20 + enc*3 + act_idx, 0=SW/1=CW/2=CCW)
|
||||
//
|
||||
// Ein Step mit keycode=0 gilt als leer → Ausführung stoppt dort.
|
||||
// Delay zwischen Steps: 20 ms (hardcoded).
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@
|
||||
#define BTN_COL_COUNT 5
|
||||
#define BTN_ROW_COUNT 5
|
||||
|
||||
// Column pins: driven OUTPUT LOW during scan, otherwise INPUT (high-Z or HIGH)
|
||||
// Column pins: INPUT; external 10k pull-ups hold them HIGH.
|
||||
static const uint8_t BTN_COLS[BTN_COL_COUNT] = {
|
||||
PIN_COL0, // PB10 – encoder SW column
|
||||
PIN_COL1, // PA11 – Cherry MX col 1 (leftmost)
|
||||
@@ -28,7 +28,7 @@ static const uint8_t BTN_COLS[BTN_COL_COUNT] = {
|
||||
PIN_COL4, // PA08 – Cherry MX col 4 (rightmost)
|
||||
};
|
||||
|
||||
// Row pins: INPUT_PULLUP, read LOW when button pressed
|
||||
// Row pins: idle INPUT (high-Z), driven OUTPUT LOW one at a time during scan.
|
||||
static const uint8_t BTN_ROWS[BTN_ROW_COUNT] = {
|
||||
PIN_ROW0, // PB11
|
||||
PIN_ROW1, // PA12
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
#include <HID.h>
|
||||
|
||||
// ── HID Report Descriptor: Keyboard + Consumer Control ───────────────────────
|
||||
// Vendor-Kommunikation läuft über CVendorHID (eigenes PluggableUSBModule).
|
||||
// Host-Kommunikation außerhalb von HID läuft separat über USB CDC (SerialUSB).
|
||||
|
||||
static const uint8_t k_hid_descriptor[] = {
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// alle verfügbaren Bytes in einen internen Ring-Buffer und gibt ein vollständiges
|
||||
// 8-Byte-Paket zurück sobald genug Bytes akkumuliert sind.
|
||||
// Der Ring-Buffer (256 Bytes = 32 Pakete) verhindert Datenverlust wenn mehrere
|
||||
// Pakete auf einmal ankommen (Config-Transfer: 30 Pakete).
|
||||
// Pakete auf einmal ankommen. Größere Transfers werden fortlaufend geleert.
|
||||
//
|
||||
// Senden (Board → PC):
|
||||
// Direkt via SerialUSB.write() – kein eigener Puffer nötig, da der Arduino-CDC-
|
||||
@@ -16,8 +16,9 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
// Ring-Buffer für eingehende Bytes – CDC kann jederzeit Bytes liefern.
|
||||
// Größe: 32 Pakete × 8 Bytes = 256 Bytes – reicht für eine vollständige
|
||||
// Config-Übertragung (30 Pakete) ohne Überlauf.
|
||||
// Größe: 32 Pakete × 8 Bytes = 256 Bytes. Der Puffer ist nur ein
|
||||
// Zwischenpuffer; ein vollständiger Config-Transfer umfasst 126 Pakete
|
||||
// einschließlich BEGIN und COMMIT.
|
||||
static uint8_t s_buf[SERIAL_PKT_SIZE * 32];
|
||||
static uint16_t s_head = 0;
|
||||
static uint16_t s_count = 0;
|
||||
|
||||
@@ -8,10 +8,8 @@
|
||||
// Byte-Layout aller Pakete:
|
||||
// [0] Command/Event-ID
|
||||
// [1] key_id (Button 0–24 oder Encoder 0–3)
|
||||
// [2] r / Daten-Byte A
|
||||
// [3] g / Daten-Byte B
|
||||
// [4] b
|
||||
// [5..7] reserviert (0x00)
|
||||
// [2..7] kommandospezifische Daten
|
||||
// LED-Kommandos nutzen [2..4] als RGB; Config-/Makro-DATA nutzt [2..7].
|
||||
//
|
||||
// Richtungen:
|
||||
// PC → Board (Commands, 0x01–0x7F): poll_vendor() in CMainController
|
||||
@@ -44,9 +42,9 @@
|
||||
|
||||
// ── Events: Board → PC ────────────────────────────────────────────────────────
|
||||
#define USB_EVT_KEY_DOWN 0x81 // key_id → HOST_COMMAND-Button gedrückt
|
||||
#define USB_EVT_KEY_UP 0x82 // key_id → HOST_COMMAND-Button losgelassen
|
||||
#define USB_EVT_ENC_CW 0x83 // enc_id → Encoder Schritt CW (HOST_COMMAND)
|
||||
#define USB_EVT_ENC_CCW 0x84 // enc_id → Encoder Schritt CCW (HOST_COMMAND)
|
||||
#define USB_EVT_KEY_UP 0x82 // Reserviert; vom Controller aktuell nicht gesendet
|
||||
#define USB_EVT_ENC_CW 0x83 // Reserviert; vom Controller aktuell nicht gesendet
|
||||
#define USB_EVT_ENC_CCW 0x84 // Reserviert; vom Controller aktuell nicht gesendet
|
||||
#define USB_EVT_PONG 0x85 // Antwort auf USB_CMD_PING
|
||||
#define USB_EVT_CONFIG_ACK 0x90 // Config erfolgreich in NVM geschrieben
|
||||
#define USB_EVT_CONFIG_NACK 0x91 // Config CRC/Magic ungültig – nicht geschrieben
|
||||
|
||||
Reference in New Issue
Block a user