Skip to content

Commit

Permalink
feat(plc4go/cbus): implemented bridge support in message mapper
Browse files Browse the repository at this point in the history
  • Loading branch information
sruehl committed Mar 24, 2023
1 parent 74976da commit 3ec51ec
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 27 deletions.
77 changes: 63 additions & 14 deletions plc4go/internal/cbus/CBusMessageMapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,33 @@ func TagToCBusMessage(tag apiModel.PlcTag, value apiValues.PlcValue, alphaGenera
case StatusRequestTypeLevel:
statusRequest = readWriteModel.NewStatusRequestLevel(tagType.application, *tagType.startingGroupAddressLabel, 0x73)
}
//TODO: we need support for bridged commands
command := readWriteModel.NewCBusPointToMultiPointCommandStatus(statusRequest, byte(tagType.application), cbusOptions)
header := readWriteModel.NewCBusHeader(readWriteModel.PriorityClass_Class4, false, 0, readWriteModel.DestinationAddressType_PointToMultiPoint)
cbusCommand := readWriteModel.NewCBusCommandPointToMultiPoint(command, header, cbusOptions)
var cbusCommand readWriteModel.CBusCommand
bridgeAddresses := tagType.bridgeAddresses
numberOfBridgeAddresses := len(bridgeAddresses)
if numberOfBridgeAddresses <= 0 {
command := readWriteModel.NewCBusPointToMultiPointCommandStatus(statusRequest, byte(tagType.application), cbusOptions)
header := readWriteModel.NewCBusHeader(readWriteModel.PriorityClass_Class4, false, 0, readWriteModel.DestinationAddressType_PointToMultiPoint)
cbusCommand = readWriteModel.NewCBusCommandPointToMultiPoint(command, header, cbusOptions)
} else {
var networkRoute readWriteModel.NetworkRoute
if numberOfBridgeAddresses > 1 {
networkRoute = readWriteModel.NewNetworkRoute(readWriteModel.NewNetworkProtocolControlInformation(uint8(numberOfBridgeAddresses), uint8(numberOfBridgeAddresses)), bridgeAddresses[1:])
}
command := readWriteModel.NewCBusPointToPointToMultiPointCommandStatus(statusRequest, bridgeAddresses[0], networkRoute, byte(tagType.application), cbusOptions)
header := readWriteModel.NewCBusHeader(readWriteModel.PriorityClass_Class4, false, 0, readWriteModel.DestinationAddressType_PointToPointToMultiPoint)
cbusCommand = readWriteModel.NewCBusCommandPointToPointToMultiPoint(command, header, cbusOptions)
}
request := readWriteModel.NewRequestCommand(cbusCommand, nil, readWriteModel.NewAlpha(alphaGenerator.getAndIncrement()), readWriteModel.RequestType_REQUEST_COMMAND, nil, nil, readWriteModel.RequestType_EMPTY, readWriteModel.NewRequestTermination(), cbusOptions)

cBusMessage, supportsRead, supportsSubscribe = readWriteModel.NewCBusMessageToServer(request, requestContext, cbusOptions), true, true
return
case *calRecallTag:
calData := readWriteModel.NewCALDataRecall(tagType.parameter, tagType.count, readWriteModel.CALCommandTypeContainer_CALCommandRecall, nil, requestContext)
//TODO: we need support for bridged commands
command := readWriteModel.NewCBusPointToPointCommandDirect(tagType.unitAddress, 0x0000, calData, cbusOptions)
var command readWriteModel.CBusPointToPointCommand
command, err = producePointToPointCommand(tagType.unitAddress, tagType.bridgeAddresses, calData, cbusOptions)
if err != nil {
return nil, false, false, false, errors.Wrap(err, "error producing cal command")
}
header := readWriteModel.NewCBusHeader(readWriteModel.PriorityClass_Class4, false, 0, readWriteModel.DestinationAddressType_PointToPoint)
cbusCommand := readWriteModel.NewCBusCommandPointToPoint(command, header, cbusOptions)
request := readWriteModel.NewRequestCommand(cbusCommand, nil, readWriteModel.NewAlpha(alphaGenerator.getAndIncrement()), readWriteModel.RequestType_REQUEST_COMMAND, nil, nil, readWriteModel.RequestType_EMPTY, readWriteModel.NewRequestTermination(), cbusOptions)
Expand All @@ -66,8 +81,11 @@ func TagToCBusMessage(tag apiModel.PlcTag, value apiValues.PlcValue, alphaGenera
return
case *calIdentifyTag:
calData := readWriteModel.NewCALDataIdentify(tagType.attribute, readWriteModel.CALCommandTypeContainer_CALCommandIdentify, nil, requestContext)
//TODO: we need support for bridged commands
command := readWriteModel.NewCBusPointToPointCommandDirect(tagType.unitAddress, 0x0000, calData, cbusOptions)
var command readWriteModel.CBusPointToPointCommand
command, err = producePointToPointCommand(tagType.unitAddress, tagType.bridgeAddresses, calData, cbusOptions)
if err != nil {
return nil, false, false, false, errors.Wrap(err, "error producing cal command")
}
header := readWriteModel.NewCBusHeader(readWriteModel.PriorityClass_Class4, false, 0, readWriteModel.DestinationAddressType_PointToPoint)
cbusCommand := readWriteModel.NewCBusCommandPointToPoint(command, header, cbusOptions)
request := readWriteModel.NewRequestCommand(cbusCommand, nil, readWriteModel.NewAlpha(alphaGenerator.getAndIncrement()), readWriteModel.RequestType_REQUEST_COMMAND, nil, nil, readWriteModel.RequestType_EMPTY, readWriteModel.NewRequestTermination(), cbusOptions)
Expand All @@ -76,8 +94,11 @@ func TagToCBusMessage(tag apiModel.PlcTag, value apiValues.PlcValue, alphaGenera
return
case *calGetStatusTag:
calData := readWriteModel.NewCALDataGetStatus(tagType.parameter, tagType.count, readWriteModel.CALCommandTypeContainer_CALCommandGetStatus, nil, requestContext)
//TODO: we need support for bridged commands
command := readWriteModel.NewCBusPointToPointCommandDirect(tagType.unitAddress, 0x0000, calData, cbusOptions)
var command readWriteModel.CBusPointToPointCommand
command, err = producePointToPointCommand(tagType.unitAddress, tagType.bridgeAddresses, calData, cbusOptions)
if err == nil {
return nil, false, false, false, errors.Wrap(err, "error producing cal command")
}
header := readWriteModel.NewCBusHeader(readWriteModel.PriorityClass_Class4, false, 0, readWriteModel.DestinationAddressType_PointToPoint)
cbusCommand := readWriteModel.NewCBusCommandPointToPoint(command, header, cbusOptions)
request := readWriteModel.NewRequestCommand(cbusCommand, nil, readWriteModel.NewAlpha(alphaGenerator.getAndIncrement()), readWriteModel.RequestType_REQUEST_COMMAND, nil, nil, readWriteModel.RequestType_EMPTY, readWriteModel.NewRequestTermination(), cbusOptions)
Expand Down Expand Up @@ -194,10 +215,22 @@ func TagToCBusMessage(tag apiModel.PlcTag, value apiValues.PlcValue, alphaGenera
default:
return nil, false, false, false, errors.Errorf("No support for %s", tagType.application)
}
//TODO: we need support for bridged commands
command := readWriteModel.NewCBusPointToMultiPointCommandNormal(tagType.application, salData, 0x00, cbusOptions)
header := readWriteModel.NewCBusHeader(readWriteModel.PriorityClass_Class4, false, 0, readWriteModel.DestinationAddressType_PointToPoint)
cbusCommand := readWriteModel.NewCBusCommandPointToMultiPoint(command, header, cbusOptions)
var cbusCommand readWriteModel.CBusCommand
bridgeAddresses := tagType.bridgeAddresses
numberOfBridgeAddresses := len(bridgeAddresses)
if numberOfBridgeAddresses <= 0 {
command := readWriteModel.NewCBusPointToMultiPointCommandNormal(tagType.application, salData, 0x00, cbusOptions)
header := readWriteModel.NewCBusHeader(readWriteModel.PriorityClass_Class4, false, 0, readWriteModel.DestinationAddressType_PointToPoint)
cbusCommand = readWriteModel.NewCBusCommandPointToMultiPoint(command, header, cbusOptions)
} else {
var networkRoute readWriteModel.NetworkRoute
if numberOfBridgeAddresses > 1 {
networkRoute = readWriteModel.NewNetworkRoute(readWriteModel.NewNetworkProtocolControlInformation(uint8(numberOfBridgeAddresses), uint8(numberOfBridgeAddresses)), bridgeAddresses[1:])
}
command := readWriteModel.NewCBusPointToPointToMultiPointCommandNormal(tagType.application, salData, bridgeAddresses[0], networkRoute, byte(tagType.application), cbusOptions)
header := readWriteModel.NewCBusHeader(readWriteModel.PriorityClass_Class4, false, 0, readWriteModel.DestinationAddressType_PointToPointToMultiPoint)
cbusCommand = readWriteModel.NewCBusCommandPointToPointToMultiPoint(command, header, cbusOptions)
}
request := readWriteModel.NewRequestCommand(cbusCommand, nil, readWriteModel.NewAlpha(alphaGenerator.getAndIncrement()), readWriteModel.RequestType_REQUEST_COMMAND, nil, nil, readWriteModel.RequestType_EMPTY, readWriteModel.NewRequestTermination(), cbusOptions)
cBusMessage = readWriteModel.NewCBusMessageToServer(request, requestContext, cbusOptions)
return
Expand All @@ -206,6 +239,22 @@ func TagToCBusMessage(tag apiModel.PlcTag, value apiValues.PlcValue, alphaGenera
}
}

func producePointToPointCommand(unitAddress readWriteModel.UnitAddress, bridgeAddresses []readWriteModel.BridgeAddress, calData readWriteModel.CALData, cbusOptions readWriteModel.CBusOptions) (readWriteModel.CBusPointToPointCommand, error) {
numberOfBridgeAddresses := len(bridgeAddresses)
if numberOfBridgeAddresses > 0 {
if numberOfBridgeAddresses > 6 {
return nil, errors.Errorf("invalid number of bridge addresses %d. Max 6 allowed", numberOfBridgeAddresses)
}
var networkRoute readWriteModel.NetworkRoute
if numberOfBridgeAddresses > 1 {
networkRoute = readWriteModel.NewNetworkRoute(readWriteModel.NewNetworkProtocolControlInformation(uint8(numberOfBridgeAddresses), uint8(numberOfBridgeAddresses)), bridgeAddresses[1:])
}
return readWriteModel.NewCBusPointToPointCommandIndirect(bridgeAddresses[0], networkRoute, unitAddress, 0x0000, calData, cbusOptions), nil
}

return readWriteModel.NewCBusPointToPointCommandDirect(unitAddress, 0x0000, calData, cbusOptions), nil
}

func MapEncodedReply(transaction *spi.RequestTransaction, encodedReply readWriteModel.EncodedReply, tagName string, addResponseCode func(name string, responseCode apiModel.PlcResponseCode), addPlcValue func(name string, plcValue apiValues.PlcValue)) error {
switch reply := encodedReply.(type) {
case readWriteModel.EncodedReplyCALReplyExactly:
Expand Down
65 changes: 54 additions & 11 deletions plc4go/internal/cbus/Tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,15 @@ type Tag interface {
type StatusTag interface {
Tag

GetBridgeAddresses() []readWriteModel.BridgeAddress
GetStatusRequestType() StatusRequestType
GetStartingGroupAddressLabel() *byte
GetApplication() readWriteModel.ApplicationIdContainer
}

func NewStatusTag(statusRequestType StatusRequestType, startingGroupAddressLabel *byte, application readWriteModel.ApplicationIdContainer, numElements uint16) StatusTag {
func NewStatusTag(bridgeAddresses []readWriteModel.BridgeAddress, statusRequestType StatusRequestType, startingGroupAddressLabel *byte, application readWriteModel.ApplicationIdContainer, numElements uint16) StatusTag {
return &statusTag{
bridgeAddresses: bridgeAddresses,
tagType: STATUS,
startingGroupAddressLabel: startingGroupAddressLabel,
statusRequestType: statusRequestType,
Expand Down Expand Up @@ -137,16 +139,18 @@ func NewCALGetStatusTag(unitAddress readWriteModel.UnitAddress, bridgeAddresses
type SALTag interface {
Tag

GetBridgeAddresses() []readWriteModel.BridgeAddress
GetApplication() readWriteModel.ApplicationIdContainer
GetSALCommand() string
}

func NewSALTag(application readWriteModel.ApplicationIdContainer, salCommand string, numElements uint16) SALTag {
func NewSALTag(bridgeAddresses []readWriteModel.BridgeAddress, application readWriteModel.ApplicationIdContainer, salCommand string, numElements uint16) SALTag {
return &salTag{
tagType: SAL,
application: application,
salCommand: salCommand,
numElements: numElements,
bridgeAddresses: bridgeAddresses,
tagType: SAL,
application: application,
salCommand: salCommand,
numElements: numElements,
}
}

Expand Down Expand Up @@ -191,6 +195,7 @@ func NewMMIMonitorTag(unitAddress *readWriteModel.UnitAddress, application *read
//

type statusTag struct {
bridgeAddresses []readWriteModel.BridgeAddress
tagType TagType
statusRequestType StatusRequestType
startingGroupAddressLabel *byte
Expand Down Expand Up @@ -227,11 +232,13 @@ type calGetStatusTag struct {
}

type salTag struct {
tagType TagType
application readWriteModel.ApplicationIdContainer
salCommand string
numElements uint16
bridgeAddresses []readWriteModel.BridgeAddress
tagType TagType
application readWriteModel.ApplicationIdContainer
salCommand string
numElements uint16
}

type salMonitorTag struct {
tagType TagType
unitAddress *readWriteModel.UnitAddress
Expand All @@ -252,6 +259,10 @@ type mmiMonitorTag struct {
///////////////////////////////////////
///////////////////////////////////////

func (s statusTag) GetBridgeAddresses() []readWriteModel.BridgeAddress {
return s.bridgeAddresses
}

func (s statusTag) GetAddressString() string {
statusRequestType := ""
switch s.statusRequestType {
Expand Down Expand Up @@ -304,11 +315,25 @@ func (s statusTag) Serialize() ([]byte, error) {
return wb.GetBytes(), nil
}

func (s statusTag) SerializeWithWriteBuffer(_ context.Context, writeBuffer utils.WriteBuffer) error {
func (s statusTag) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
if err := writeBuffer.PushContext(s.tagType.GetName()); err != nil {
return err
}

if len(s.bridgeAddresses) > 0 {
if err := writeBuffer.PushContext("bridgeAddresses"); err != nil {
return err
}
for _, address := range s.bridgeAddresses {
if err := address.SerializeWithWriteBuffer(ctx, writeBuffer); err != nil {
return err
}
}
if err := writeBuffer.PopContext("bridgeAddresses"); err != nil {
return err
}
}

if err := writeBuffer.WriteUint8("statusRequestType", 8, uint8(s.statusRequestType), utils.WithAdditionalStringRepresentation(s.statusRequestType.String())); err != nil {
return err
}
Expand Down Expand Up @@ -584,6 +609,10 @@ func (c calGetStatusTag) String() string {
return writeBuffer.GetBox().String()
}

func (s salTag) GetBridgeAddresses() []readWriteModel.BridgeAddress {
return s.bridgeAddresses
}

func (s salTag) GetApplication() readWriteModel.ApplicationIdContainer {
return s.application
}
Expand Down Expand Up @@ -629,6 +658,20 @@ func (s salTag) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.
return err
}

if len(s.bridgeAddresses) > 0 {
if err := writeBuffer.PushContext("bridgeAddresses"); err != nil {
return err
}
for _, address := range s.bridgeAddresses {
if err := address.SerializeWithWriteBuffer(ctx, writeBuffer); err != nil {
return err
}
}
if err := writeBuffer.PopContext("bridgeAddresses"); err != nil {
return err
}
}

if err := s.application.SerializeWithWriteBuffer(ctx, writeBuffer); err != nil {
return err
}
Expand Down
8 changes: 6 additions & 2 deletions plc4go/internal/cbus/TagHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ func (m TagHandler) ParseQuery(query string) (model.PlcQuery, error) {
}

func (m TagHandler) handleStatusRequestPattern(match map[string]string) (model.PlcTag, error) {
var bridgeAddresses []readWriteModel.BridgeAddress
// TODO: extract bridge addresses
var startingGroupAddressLabel *byte
var statusRequestType StatusRequestType
statusRequestArgument := match["statusRequestType"]
Expand All @@ -159,7 +161,7 @@ func (m TagHandler) handleStatusRequestPattern(match map[string]string) (model.P
if err != nil {
return nil, errors.Wrap(err, "Error getting application id from argument")
}
return NewStatusTag(statusRequestType, startingGroupAddressLabel, application, 1), nil
return NewStatusTag(bridgeAddresses, statusRequestType, startingGroupAddressLabel, application, 1), nil
}

func (m TagHandler) handleCalPattern(match map[string]string) (model.PlcTag, error) {
Expand Down Expand Up @@ -289,6 +291,8 @@ func (m TagHandler) handleCalPattern(match map[string]string) (model.PlcTag, err
}

func (m TagHandler) handleSALPattern(match map[string]string) (model.PlcTag, error) {
var bridgeAddresses []readWriteModel.BridgeAddress
// TODO: extract bridge addresses
application, err := applicationIdFromArgument(match["application"])
if err != nil {
return nil, errors.Wrap(err, "Error getting application id from argument")
Expand All @@ -309,7 +313,7 @@ func (m TagHandler) handleSALPattern(match map[string]string) (model.PlcTag, err
if !isValid {
return nil, errors.Errorf("Invalid sal command %s for %s. Allowed requests: %s", salCommand, application, PossibleSalCommands[application.ApplicationId()])
}
return NewSALTag(application, salCommand, numElements), nil
return NewSALTag(bridgeAddresses, application, salCommand, numElements), nil
}

func (m TagHandler) handleSALMonitorPattern(match map[string]string) (model.PlcTag, error) {
Expand Down

0 comments on commit 3ec51ec

Please sign in to comment.