Skip to content

Commit 285b01f

Browse files
authored
Modbus: fix missing template delay and timeout defaults (#32694)
1 parent 34024cb commit 285b01f

4 files changed

Lines changed: 91 additions & 16 deletions

File tree

util/modbus/connection.go

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import (
1111
type Connection struct {
1212
*logger
1313
meters.Connection
14-
slaveID uint8 // duplicated from meters.Connection
15-
logical meters.Logger
16-
delay time.Duration
14+
physical *meterConnection
15+
slaveID uint8 // duplicated from meters.Connection
16+
logical meters.Logger
1717
}
1818

1919
func (c *Connection) Addr() string {
@@ -24,35 +24,33 @@ func (c *Connection) Logger(logger meters.Logger) {
2424
c.logical = logger
2525
}
2626

27+
// Delay applies the delay to the shared physical connection
2728
func (c *Connection) Delay(delay time.Duration) {
28-
c.delay = delay
29+
c.physical.setDelay(delay)
2930
}
3031

3132
func (c *Connection) Clone(slaveID uint8) *Connection {
3233
return &Connection{
3334
slaveID: slaveID,
3435
Connection: c.Connection.Clone(slaveID),
3536
logger: c.logger,
37+
physical: c.physical,
3638
}
3739
}
3840

39-
// TODO resolve conflicts
41+
// ConnectDelay applies the connect delay to the shared physical connection
4042
func (c *Connection) ConnectDelay(delay time.Duration) {
41-
if delay > 0 {
42-
c.Connection.ConnectDelay(delay)
43-
}
43+
c.physical.setConnectDelay(delay)
4444
}
4545

46-
// TODO resolve conflicts
46+
// Timeout applies the timeout to the shared physical connection
4747
func (c *Connection) Timeout(timeout time.Duration) {
48-
if timeout > 0 {
49-
_ = c.Connection.Timeout(timeout)
50-
}
48+
c.physical.setTimeout(timeout)
5149
}
5250

5351
func (c *Connection) exec(fun func() ([]byte, error)) ([]byte, error) {
5452
return c.WithLogger(c.logical, func() ([]byte, error) {
55-
time.Sleep(c.delay)
53+
time.Sleep(c.physical.getDelay())
5654

5755
b, err := fun()
5856
if err != nil {

util/modbus/modbus.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,52 @@ type meterConnection struct {
103103
meters.Connection
104104
proto Protocol
105105
refs int // count of references; first connection has ref count 0
106+
107+
// largest value requested by any of the sharing logical connections
108+
delay time.Duration
109+
connectDelay time.Duration
110+
timeout time.Duration
111+
106112
*logger
107113
}
108114

115+
// setDelay applies the delay if larger than the current value
116+
func (c *meterConnection) setDelay(delay time.Duration) {
117+
mu.Lock()
118+
defer mu.Unlock()
119+
120+
c.delay = max(c.delay, delay)
121+
}
122+
123+
func (c *meterConnection) getDelay() time.Duration {
124+
mu.Lock()
125+
defer mu.Unlock()
126+
127+
return c.delay
128+
}
129+
130+
// setConnectDelay applies the connect delay if larger than the current value
131+
func (c *meterConnection) setConnectDelay(delay time.Duration) {
132+
mu.Lock()
133+
defer mu.Unlock()
134+
135+
if delay > c.connectDelay {
136+
c.connectDelay = delay
137+
c.Connection.ConnectDelay(delay)
138+
}
139+
}
140+
141+
// setTimeout applies the timeout if larger than the current value
142+
func (c *meterConnection) setTimeout(timeout time.Duration) {
143+
mu.Lock()
144+
defer mu.Unlock()
145+
146+
if timeout > c.timeout {
147+
c.timeout = timeout
148+
_ = c.Connection.Timeout(timeout)
149+
}
150+
}
151+
109152
var (
110153
connections = make(map[string]*meterConnection)
111154
mu sync.Mutex
@@ -176,6 +219,7 @@ func NewConnection(ctx context.Context, uri, device, comset string, baudrate int
176219
slaveID: slaveID,
177220
Connection: conn.Clone(slaveID),
178221
logger: conn.logger,
222+
physical: conn,
179223
}
180224

181225
return res, nil

util/modbus/modbus_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,40 @@ package modbus
22

33
import (
44
"testing"
5+
"time"
56

67
"github.com/stretchr/testify/require"
78
)
89

10+
// TestSharedSettings ensures the largest delay and timeout wins for all
11+
// connections sharing the same physical connection
12+
func TestSharedSettings(t *testing.T) {
13+
ctx := t.Context()
14+
uri := "localhost:15020"
15+
16+
c1, err := Settings{URI: uri, ID: 1, Delay: 2 * time.Second, Timeout: time.Second}.Connection(ctx)
17+
require.NoError(t, err)
18+
19+
c2, err := Settings{URI: uri, ID: 2, Delay: time.Second, Timeout: 3 * time.Second}.Connection(ctx)
20+
require.NoError(t, err)
21+
22+
// unset settings don't reset the shared values
23+
c3, err := Settings{URI: uri, ID: 3}.Connection(ctx)
24+
require.NoError(t, err)
25+
26+
require.Same(t, c1.physical, c2.physical)
27+
require.Same(t, c1.physical, c3.physical)
28+
require.Same(t, c1.physical, c1.Clone(4).physical)
29+
30+
for _, c := range []*Connection{c1, c2, c3} {
31+
require.Equal(t, 2*time.Second, c.physical.getDelay())
32+
require.Equal(t, 3*time.Second, c.physical.timeout)
33+
}
34+
35+
// timeout has been applied to the physical connection
36+
require.Equal(t, 3*time.Second, c1.physical.Connection.Timeout(3*time.Second))
37+
}
38+
939
func TestParsePoint(t *testing.T) {
1040
tc := []struct {
1141
in string

util/templates/template_modbus.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,12 @@ func (t *Template) ModbusValues(renderMode int, values map[string]any) {
6969
typeParams := modbusConfig.Types[iface].Params
7070

7171
for _, p := range typeParams {
72-
// don't overwrite custom values
73-
if values[p.Name] != nil {
74-
continue
72+
// don't overwrite custom values. Params the template deprecated in favour
73+
// of the modbus definition are pre-populated with an empty string default.
74+
if v := values[p.Name]; v != nil {
75+
if s, ok := v.(string); !ok || s != "" {
76+
continue
77+
}
7578
}
7679

7780
values[p.Name] = p.DefaultValue(renderMode)

0 commit comments

Comments
 (0)