From c0bcc783f2066547c8ae8d6630271ff572fcd58d Mon Sep 17 00:00:00 2001 From: iain MacDonnell Date: Sat, 18 Apr 2026 15:47:57 +0100 Subject: [PATCH] fix(serial) keep serial console mux closed when not needed Only open the serial console mux and broker when the extension is actually in use, otherwise the mux gets in a fight with the ATX or DC control extension in reading from the serial port. Closes: #1420 --- jsonrpc.go | 4 ++++ serial.go | 19 +++++++++++++++++++ serial_console_helpers.go | 18 ++++++++++++++++-- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/jsonrpc.go b/jsonrpc.go index 4b9376bef..eb126abbd 100644 --- a/jsonrpc.go +++ b/jsonrpc.go @@ -770,6 +770,8 @@ func rpcSetActiveExtension(extensionId string) error { _ = unmountATXControl() case "dc-power": _ = unmountDCControl() + case "serial-console": + _ = unmountSerialConsole() } config.ActiveExtension = extensionId if err := SaveConfig(); err != nil { @@ -780,6 +782,8 @@ func rpcSetActiveExtension(extensionId string) error { _ = mountATXControl() case "dc-power": _ = mountDCControl() + case "serial-console": + _ = mountSerialConsole() } // Re-publish MQTT HA Discovery for the new extension diff --git a/serial.go b/serial.go index 6189c1e03..fa4c23b6a 100644 --- a/serial.go +++ b/serial.go @@ -580,10 +580,20 @@ func initSerialPort() { _ = mountATXControl() case "dc-power": _ = mountDCControl() + case "serial-console": + _ = mountSerialConsole() } } func reopenSerialPort() error { + if serialMux != nil { + serialMux.Close() + serialMux = nil + } + if consoleBroker != nil { + consoleBroker.Close() + consoleBroker = nil + } if port != nil { port.Close() } @@ -598,6 +608,10 @@ func reopenSerialPort() error { return err } + return nil +} + +func mountSerialConsole() error { // new broker (no sink yet—set it in handleSerialChannel.OnOpen) norm := NormalizationOptions{ Mode: ModeNames, LineEnding: LineEnding_LF, TabRender: "", PreserveANSI: true, @@ -619,6 +633,11 @@ func reopenSerialPort() error { return nil } +func unmountSerialConsole() error { + _ = reopenSerialPort() + return nil +} + func handleSerialChannel(dataChannel *webrtc.DataChannel) { scopedLogger := serialLogger.With(). Uint16("data_channel_id", *dataChannel.ID()).Str("service", "serial terminal channel").Logger() diff --git a/serial_console_helpers.go b/serial_console_helpers.go index 8a45879b4..f2d09715f 100644 --- a/serial_console_helpers.go +++ b/serial_console_helpers.go @@ -273,9 +273,16 @@ func NewConsoleBroker(s Sink, norm NormalizationOptions) *ConsoleBroker { } func (b *ConsoleBroker) Start() { go b.loop() } -func (b *ConsoleBroker) Close() { close(b.done) } func (b *ConsoleBroker) SetSink(s Sink) { b.sink = s } func (b *ConsoleBroker) SetNormOptions(norm NormalizationOptions) { b.norm = norm } +func (b *ConsoleBroker) Close() { + select { + case <-b.done: + return + default: + close(b.done) + } +} func (b *ConsoleBroker) SetTerminalPaused(v bool) { if b == nil { return @@ -626,7 +633,14 @@ func (m *SerialMux) Start() { go m.writer() } -func (m *SerialMux) Close() { close(m.done) } +func (m *SerialMux) Close() { + select { + case <-m.done: + return + default: + close(m.done) + } +} func (m *SerialMux) SetEchoEnabled(v bool) { m.echoEnabled.Store(v) }