Sunspec: serialize access to a shared device tree (#33014)
This commit is contained in:
parent
9f70a18501
commit
1b909edd9b
3 changed files with 73 additions and 8 deletions
|
|
@ -19,7 +19,7 @@ import (
|
|||
type ModbusSunspec struct {
|
||||
log *util.Logger
|
||||
conn *modbus.Connection
|
||||
device *sunsdev.SunSpec
|
||||
device *sunspecDevice
|
||||
op modbus.SunSpecOperation
|
||||
scale float64
|
||||
mask uint64
|
||||
|
|
@ -86,7 +86,7 @@ func NewModbusSunspecFromConfig(ctx context.Context, other map[string]any) (Plug
|
|||
device := sunspecSubDevices.Get(conn, cc.SubDevice)
|
||||
if device == nil {
|
||||
// silence KOSTAL implementation errors
|
||||
device = sunsdev.NewDevice("sunspec", cc.SubDevice)
|
||||
device = &sunspecDevice{SunSpec: sunsdev.NewDevice("sunspec", cc.SubDevice)}
|
||||
if err := device.InitializeWithTree(devices); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -111,6 +111,9 @@ func NewModbusSunspecFromConfig(ctx context.Context, other map[string]any) (Plug
|
|||
mask: mask,
|
||||
}
|
||||
|
||||
device.mu.Lock()
|
||||
defer device.mu.Unlock()
|
||||
|
||||
for _, op := range ops {
|
||||
if _, _, err := device.QueryPointAny(conn, op.Model, op.Block, op.Point); err == nil {
|
||||
mb.op = op
|
||||
|
|
@ -131,6 +134,9 @@ func recoverToError(err *error) {
|
|||
func (m *ModbusSunspec) floatGetter() (f float64, err error) {
|
||||
defer recoverToError(&err)
|
||||
|
||||
m.device.mu.Lock()
|
||||
defer m.device.mu.Unlock()
|
||||
|
||||
res, err := m.device.QueryPoint(
|
||||
m.conn,
|
||||
m.op.Model,
|
||||
|
|
@ -173,6 +179,9 @@ func (m *ModbusSunspec) BoolGetter() (func() (bool, error), error) {
|
|||
return func() (res bool, err error) {
|
||||
defer recoverToError(&err)
|
||||
|
||||
m.device.mu.Lock()
|
||||
defer m.device.mu.Unlock()
|
||||
|
||||
_, point, err := m.blockPoint()
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
|
@ -222,6 +231,8 @@ func sunspecBool(val int64, mask uint64) bool {
|
|||
return val != 0
|
||||
}
|
||||
|
||||
// blockPoint reads the block and returns its point. The device lock must be held
|
||||
// by the caller until the point value has been consumed or written.
|
||||
func (m *ModbusSunspec) blockPoint() (block sunspec.Block, point sunspec.Point, err error) {
|
||||
defer recoverToError(&err)
|
||||
|
||||
|
|
@ -242,7 +253,10 @@ var _ FloatSetter = (*Modbus)(nil)
|
|||
|
||||
// FloatSetter executes configured modbus write operation and implements FloatSetter
|
||||
func (m *ModbusSunspec) FloatSetter(_ string) (func(float64) error, error) {
|
||||
m.device.mu.Lock()
|
||||
block, point, err := m.blockPoint()
|
||||
m.device.mu.Unlock()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -252,6 +266,10 @@ func (m *ModbusSunspec) FloatSetter(_ string) (func(float64) error, error) {
|
|||
return func(val float64) (err error) {
|
||||
defer recoverToError(&err)
|
||||
|
||||
// setting the point and writing it must not interleave with a concurrent read
|
||||
m.device.mu.Lock()
|
||||
defer m.device.mu.Unlock()
|
||||
|
||||
val = val * m.scale
|
||||
switch typ {
|
||||
case typelabel.Float32:
|
||||
|
|
@ -268,7 +286,10 @@ var _ IntSetter = (*Modbus)(nil)
|
|||
|
||||
// IntSetter executes configured modbus write operation and implements IntSetter
|
||||
func (m *ModbusSunspec) IntSetter(_ string) (func(int64) error, error) {
|
||||
m.device.mu.Lock()
|
||||
block, point, err := m.blockPoint()
|
||||
m.device.mu.Unlock()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -278,6 +299,10 @@ func (m *ModbusSunspec) IntSetter(_ string) (func(int64) error, error) {
|
|||
return func(val int64) (err error) {
|
||||
defer recoverToError(&err)
|
||||
|
||||
// setting the point and writing it must not interleave with a concurrent read
|
||||
m.device.mu.Lock()
|
||||
defer m.device.mu.Unlock()
|
||||
|
||||
val = int64(float64(val) * m.scale)
|
||||
|
||||
// SetValue is used to include the scale factor when writing
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue