VersaGUI/doc/01_serial_manager.md

3.5 KiB
Raw Blame History

SerialManager

Datei: SerialManager.cs

Verantwortung

  • COM-Port-Erkennung per WMI (VID/PID)
  • Verbindungsaufbau und automatischer Reconnect
  • Hintergrund-Lese-Thread mit Paket-Assembler
  • Sende-Methoden für alle Protokoll-Operationen
  • ACK/NACK-Synchronisation zwischen ReadLoop-Thread und SendConfig/SendMacros-Task

COM-Port-Erkennung

VidPid = "VID_239A&PID_0042"   // muss mit platformio.ini übereinstimmen

SELECT Name, DeviceID FROM Win32_PnPEntity WHERE DeviceID LIKE '%VID_239A&PID_0042%'
// Name enthält z.B. "USB Serial Device (COM3)" → extrahiert "COM3"

Erkennt das Board auch bei wechselnder COM-Nummer. Funktioniert auch nach USB-Reinitialisierung (Kabel abziehen/stecken nach SWD-Flash).

Verbindungsaufbau (TryConnect)

Monitor.TryEnter(_connectLock)    nur ein gleichzeitiger Versuch
FindPort() per WMI
SerialPort erstellen:
    ReadTimeout  = 500 ms
    WriteTimeout = 500 ms
    DtrEnable    = true   ← VOR Open() setzen! (SAMD21 CDC-Constraint)
port.Open()
Thread.Sleep(200)          CDC stabilisieren
ReadLoop-Thread starten
Connected-Event → UI-Thread

Reconnect-Timer: alle 3 s, Start nach 500 ms. 5 s Backoff (_waitingAfterDisconnect) nach Verbindungsverlust damit Board vollständig re-enumerieren kann.

ReadLoop (Hintergrund-Thread)

while (port.IsOpen):
    b = port.ReadByte()       blockiert 500 ms (ReadTimeout)
    buf[bufFill++] = b
    if bufFill < 8: continue
    → SerialPacket fertig → SynchronizationContext.Post → PacketReceived auf UI-Thread
    bufFill = 0

Bei IOException:
    if port.IsOpen: ignorieren  ← .NET 7: IOException = normaler Timeout (kein Fehler!)
    else: break → Disconnect

ACK/NACK-Synchronisation

SendConfig und SendMacros blockieren nach COMMIT auf ein SemaphoreSlim-Gate bis das Board antwortet:

_configAckGate / _macroAckGate    SemaphoreSlim(0, 1)
_configAckOk   / _macroAckOk      volatile bool (true = ACK, false = NACK)
Methode Aufruf durch Wirkung
SignalConfigAck() TrayApp bei EvtConfigAck _configAckOk = true, Gate freigeben
SignalConfigNack() TrayApp bei EvtConfigNack _configAckOk = false, Gate freigeben
SignalMacroAck() TrayApp bei EvtMacroAck _macroAckOk = true, Gate freigeben
SignalMacroNack() TrayApp bei EvtMacroNack _macroAckOk = false, Gate freigeben

SendConfig() und SendMacros() geben bool zurück (true = ACK erhalten, false = NACK oder Timeout nach 3 s).

Sende-Methoden

Methode Rückgabe Funktion
Send(pkt) void Rohe 8-Byte-Übertragung (fire-and-forget)
SetLedOverride(keyId, r, g, b) void CMD 0x01
ClearLedOverride(keyId) void CMD 0x02
SetLedBase(keyId, r, g, b) void CMD 0x03
RequestConfig() void CMD 0x13 Board antwortet mit Config-Dump
RequestMacros() void CMD 0x23 Board antwortet mit Makro-Dump
SendConfig(cfg) bool BEGIN(0x10) → 124×DATA(0x11) → COMMIT(0x12), 5 ms zwischen Chunks, wartet auf ACK/NACK
SendMacros(macros) bool BEGIN(0x20) → 86×DATA(0x21) → COMMIT(0x22), 5 ms zwischen Chunks, wartet auf ACK/NACK

SendConfig und SendMacros blockieren ~1,5 s (Chunks + NVM-Zeit) → werden in Task.Run() aus ConfigForm.OnSave() aufgerufen.

Events

Event Gefeuert wenn
Connected Verbindung erfolgreich hergestellt (auf UI-Thread)
Disconnected Verbindung verloren (auf UI-Thread)
PacketReceived Vollständiges 8-Byte-Paket empfangen (auf UI-Thread)