This is an automated email from the ASF dual-hosted git repository. sruehl pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit 04a37a2d699525dff68fb426248e577d2fb3a730 Author: Sebastian Rühl <[email protected]> AuthorDate: Mon Jul 6 11:37:56 2026 +0200 fix(plc4go): serial transport deadline and connected-state follow-ups - Write: clear the write deadline when the context has none, so a lapsed deadline from a previous call no longer fails later writes with a spurious i/o timeout - IsConnected: key on the connected flag (like the TCP transport) instead of a lock-free read of the port field --- plc4go/spi/transports/serial/TransportInstance.go | 4 +++- .../spi/transports/serial/TransportInstance_pty_test.go | 16 ++++++++++++++++ plc4go/spi/transports/serial/TransportInstance_test.go | 17 +++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/plc4go/spi/transports/serial/TransportInstance.go b/plc4go/spi/transports/serial/TransportInstance.go index 5868efbc25..772ae3b9f4 100644 --- a/plc4go/spi/transports/serial/TransportInstance.go +++ b/plc4go/spi/transports/serial/TransportInstance.go @@ -113,7 +113,7 @@ func (m *TransportInstance) Close() error { } func (m *TransportInstance) IsConnected() bool { - return m.serialPort != nil + return m.connected.Load() } func (m *TransportInstance) Write(ctx context.Context, data []byte) error { @@ -127,6 +127,8 @@ func (m *TransportInstance) Write(ctx context.Context, data []byte) error { if err := m.serialPort.SetWriteDeadline(deadline); err != nil { return errors.Wrap(err, "error setting write deadline") } + } else if err := m.serialPort.SetWriteDeadline(time.Time{}); err != nil { + return errors.Wrap(err, "error clearing write deadline") } num, err := m.serialPort.Write(data) if err != nil { diff --git a/plc4go/spi/transports/serial/TransportInstance_pty_test.go b/plc4go/spi/transports/serial/TransportInstance_pty_test.go index b33456eaa3..04b3255e9a 100644 --- a/plc4go/spi/transports/serial/TransportInstance_pty_test.go +++ b/plc4go/spi/transports/serial/TransportInstance_pty_test.go @@ -89,3 +89,19 @@ func TestTransportInstance_CloseIsIdempotentOnPTY(t *testing.T) { assert.False(t, instance.IsConnected()) require.NoError(t, instance.Close(), "second close must be a no-op") } + +func TestTransportInstance_WriteDeadlineDoesNotStick(t *testing.T) { + _, slavePath := openPTY(t) + instance := NewTransportInstance(slavePath, 9600, 1, NewTransport()) + require.NoError(t, instance.Connect(context.Background())) + t.Cleanup(func() { _ = instance.Close() }) + + shortCtx, cancel := context.WithTimeout(context.Background(), 30*time.Millisecond) + defer cancel() + require.NoError(t, instance.Write(shortCtx, []byte{0x01})) + + time.Sleep(60 * time.Millisecond) // let the first write's deadline lapse + + // A deadline-less write must not inherit the lapsed deadline. + require.NoError(t, instance.Write(context.Background(), []byte{0x02})) +} diff --git a/plc4go/spi/transports/serial/TransportInstance_test.go b/plc4go/spi/transports/serial/TransportInstance_test.go index e3f5f76145..6690958468 100644 --- a/plc4go/spi/transports/serial/TransportInstance_test.go +++ b/plc4go/spi/transports/serial/TransportInstance_test.go @@ -267,3 +267,20 @@ func TestTransportInstance_Write(t *testing.T) { }) } } + +// stubPort is a minimal serialport.Port for white-box state tests. +type stubPort struct{} + +func (stubPort) Read([]byte) (int, error) { return 0, nil } +func (stubPort) Write(p []byte) (int, error) { return len(p), nil } +func (stubPort) Close() error { return nil } +func (stubPort) SetReadDeadline(time.Time) error { return nil } +func (stubPort) SetWriteDeadline(time.Time) error { return nil } + +func TestTransportInstance_IsConnected_keysOnConnectedFlag(t *testing.T) { + m := &TransportInstance{} + m.serialPort = stubPort{} + assert.False(t, m.IsConnected(), "a port that never connected must not report connected") + m.connected.Store(true) + assert.True(t, m.IsConnected()) +}
