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 874e2b9565945d0a01bfbeeb3717df5d2ccfb43c Author: Sebastian Rühl <[email protected]> AuthorDate: Fri Mar 24 16:57:33 2023 +0100 refactor(plc4go/cbus): move map encoded reply to message mapper --- plc4go/internal/cbus/CBusMessageFactory.go | 202 ------------- .../cbus/{Reader.go => CBusMessageMapper.go} | 322 ++++++++++----------- plc4go/internal/cbus/Reader.go | 220 +------------- 3 files changed, 160 insertions(+), 584 deletions(-) diff --git a/plc4go/internal/cbus/CBusMessageFactory.go b/plc4go/internal/cbus/CBusMessageFactory.go deleted file mode 100644 index e162c27b28..0000000000 --- a/plc4go/internal/cbus/CBusMessageFactory.go +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package cbus - -import ( - "fmt" - "strings" - - "github.com/apache/plc4x/plc4go/pkg/api/model" - "github.com/apache/plc4x/plc4go/pkg/api/values" - readWriteModel "github.com/apache/plc4x/plc4go/protocols/cbus/readwrite/model" - "github.com/pkg/errors" -) - -func TagToCBusMessage(tag model.PlcTag, value values.PlcValue, alphaGenerator *AlphaGenerator, messageCodec *MessageCodec) (cBusMessage readWriteModel.CBusMessage, supportsRead, supportsWrite, supportsSubscribe bool, err error) { - cbusOptions := messageCodec.cbusOptions - requestContext := messageCodec.requestContext - switch tagType := tag.(type) { - case *statusTag: - var statusRequest readWriteModel.StatusRequest - switch tagType.statusRequestType { - case StatusRequestTypeBinaryState: - statusRequest = readWriteModel.NewStatusRequestBinaryState(tagType.application, 0x7A) - 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) - 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) - 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) - - cBusMessage, supportsRead = readWriteModel.NewCBusMessageToServer(request, requestContext, cbusOptions), true - 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) - 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) - - cBusMessage, supportsRead = readWriteModel.NewCBusMessageToServer(request, requestContext, cbusOptions), true - 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) - 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) - - cBusMessage, supportsRead = readWriteModel.NewCBusMessageToServer(request, requestContext, cbusOptions), true - return - case *salTag: - var salCommand = tagType.salCommand - if salCommand == "" { - return nil, false, false, false, errors.New("Empty sal command not supported") - } - var salData readWriteModel.SALData - switch tagType.application.ApplicationId() { - case readWriteModel.ApplicationId_FREE_USAGE: - panic("Not yet implemented") // TODO: implement - case readWriteModel.ApplicationId_TEMPERATURE_BROADCAST: - var temperatureBroadcastData readWriteModel.TemperatureBroadcastData - switch salCommand { - case readWriteModel.TemperatureBroadcastCommandType_BROADCAST_EVENT.PLC4XEnumName(): - if value == nil || !value.IsList() || len(value.GetList()) != 2 || !value.GetList()[0].IsByte() || !value.GetList()[1].IsByte() { - return nil, false, false, false, errors.Errorf("%s requires exactly 2 arguments [temperatureGroup,temperatureByte]", salCommand) - } - commandTypeContainer := readWriteModel.TemperatureBroadcastCommandTypeContainer_TemperatureBroadcastCommandSetBroadcastEvent1_2Bytes - temperatureGroup := value.GetList()[0].GetByte() - temperatureByte := value.GetList()[1].GetByte() - temperatureBroadcastData = readWriteModel.NewTemperatureBroadcastData(commandTypeContainer, temperatureGroup, temperatureByte) - supportsWrite = true - default: - return nil, false, false, false, errors.Errorf("Unsupported command %s for %s", salCommand, tagType.application.ApplicationId()) - } - salData = readWriteModel.NewSALDataTemperatureBroadcast(temperatureBroadcastData, nil) - case readWriteModel.ApplicationId_ROOM_CONTROL_SYSTEM: - panic("Implement me") - case - readWriteModel.ApplicationId_LIGHTING, - readWriteModel.ApplicationId_VENTILATION, - readWriteModel.ApplicationId_IRRIGATION_CONTROL, - readWriteModel.ApplicationId_POOLS_SPAS_PONDS_FOUNTAINS_CONTROL, - readWriteModel.ApplicationId_HEATING, - readWriteModel.ApplicationId_AUDIO_AND_VIDEO, - readWriteModel.ApplicationId_HVAC_ACTUATOR: - var lightingData readWriteModel.LightingData - switch salCommand { - case readWriteModel.LightingCommandType_OFF.PLC4XEnumName(): - commandTypeContainer := readWriteModel.LightingCommandTypeContainer_LightingCommandOff - if value == nil || !value.IsByte() { - return nil, false, false, false, errors.Errorf("%s requires exactly 1 arguments [group]", salCommand) - } - group := value.GetByte() - lightingData = readWriteModel.NewLightingDataOff(group, commandTypeContainer) - supportsWrite = true - case readWriteModel.LightingCommandType_ON.PLC4XEnumName(): - commandTypeContainer := readWriteModel.LightingCommandTypeContainer_LightingCommandOn - if value == nil || (!value.IsByte() && (!value.IsList() || len(value.GetList()) != 1 || value.GetList()[0].IsByte())) { - return nil, false, false, false, errors.Errorf("%s requires exactly 1 arguments [group]", salCommand) - } - group := value.GetByte() - lightingData = readWriteModel.NewLightingDataOn(group, commandTypeContainer) - supportsWrite = true - case readWriteModel.LightingCommandType_RAMP_TO_LEVEL.PLC4XEnumName(): - if value == nil || !value.IsList() || len(value.GetList()) != 3 || !value.GetList()[0].IsString() || !value.GetList()[1].IsByte() || !value.GetList()[2].IsByte() { - return nil, false, false, false, errors.Errorf("%s requires exactly 2 arguments [delay,group,level]", salCommand) - } - commandTypeContainer, ok := readWriteModel.LightingCommandTypeContainerByName(fmt.Sprintf("LightingCommandRampToLevel_%s", value.GetList()[0].GetString())) - if !ok { - var possibleValues []string - for _, v := range readWriteModel.LightingCommandTypeContainerValues { - possibleValues = append(possibleValues, strings.TrimPrefix(v.String(), "LightingCommandRampToLevel_")) - } - return nil, false, false, false, errors.Errorf("No level found for %s. Possible values %s", value.GetList()[0].GetString(), possibleValues) - } - group := value.GetList()[1].GetByte() - level := value.GetList()[2].GetByte() - lightingData = readWriteModel.NewLightingDataRampToLevel(group, level, commandTypeContainer) - supportsWrite = true - case readWriteModel.LightingCommandType_TERMINATE_RAMP.PLC4XEnumName(): - commandTypeContainer := readWriteModel.LightingCommandTypeContainer_LightingCommandTerminateRamp - if value == nil || !value.IsByte() { - return nil, false, false, false, errors.Errorf("%s requires exactly 1 arguments [group]", salCommand) - } - group := value.GetByte() - lightingData = readWriteModel.NewLightingDataTerminateRamp(group, commandTypeContainer) - supportsWrite = true - case readWriteModel.LightingCommandType_LABEL.PLC4XEnumName(): - panic("Implement me") - default: - return nil, false, false, false, errors.Errorf("Unsupported command %s for %s", salCommand, tagType.application.ApplicationId()) - } - salData = readWriteModel.NewSALDataLighting(lightingData, nil) - case readWriteModel.ApplicationId_AIR_CONDITIONING: - panic("Implement me") - case readWriteModel.ApplicationId_TRIGGER_CONTROL: - panic("Implement me") - case readWriteModel.ApplicationId_ENABLE_CONTROL: - panic("Implement me") - case readWriteModel.ApplicationId_SECURITY: - panic("Implement me") - case readWriteModel.ApplicationId_METERING: - panic("Implement me") - case readWriteModel.ApplicationId_ACCESS_CONTROL: - panic("Implement me") - case readWriteModel.ApplicationId_CLOCK_AND_TIMEKEEPING: - panic("Implement me") - case readWriteModel.ApplicationId_TELEPHONY_STATUS_AND_CONTROL: - panic("Implement me") - case readWriteModel.ApplicationId_MEASUREMENT: - panic("Implement me") - case readWriteModel.ApplicationId_TESTING: - panic("Implement me") - case readWriteModel.ApplicationId_MEDIA_TRANSPORT_CONTROL: - panic("Implement me") - case readWriteModel.ApplicationId_ERROR_REPORTING: - panic("Implement me") - 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) - 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 - default: - return nil, false, false, false, errors.Errorf("Unsupported type %T", tagType) - } -} diff --git a/plc4go/internal/cbus/Reader.go b/plc4go/internal/cbus/CBusMessageMapper.go similarity index 56% copy from plc4go/internal/cbus/Reader.go copy to plc4go/internal/cbus/CBusMessageMapper.go index 730a433186..6adb4bf4b4 100644 --- a/plc4go/internal/cbus/Reader.go +++ b/plc4go/internal/cbus/CBusMessageMapper.go @@ -22,195 +22,191 @@ package cbus import ( "context" "fmt" + "github.com/apache/plc4x/plc4go/spi" + spiValues "github.com/apache/plc4x/plc4go/spi/values" + "github.com/rs/zerolog/log" "strconv" - "sync" - "time" + "strings" apiModel "github.com/apache/plc4x/plc4go/pkg/api/model" apiValues "github.com/apache/plc4x/plc4go/pkg/api/values" readWriteModel "github.com/apache/plc4x/plc4go/protocols/cbus/readwrite/model" - "github.com/apache/plc4x/plc4go/spi" - spiModel "github.com/apache/plc4x/plc4go/spi/model" - spiValues "github.com/apache/plc4x/plc4go/spi/values" - "github.com/pkg/errors" - "github.com/rs/zerolog/log" ) -type Reader struct { - alphaGenerator *AlphaGenerator - messageCodec spi.MessageCodec - tm *spi.RequestTransactionManager -} +func TagToCBusMessage(tag apiModel.PlcTag, value apiValues.PlcValue, alphaGenerator *AlphaGenerator, messageCodec *MessageCodec) (cBusMessage readWriteModel.CBusMessage, supportsRead, supportsWrite, supportsSubscribe bool, err error) { + cbusOptions := messageCodec.cbusOptions + requestContext := messageCodec.requestContext + switch tagType := tag.(type) { + case *statusTag: + var statusRequest readWriteModel.StatusRequest + switch tagType.statusRequestType { + case StatusRequestTypeBinaryState: + statusRequest = readWriteModel.NewStatusRequestBinaryState(tagType.application, 0x7A) + 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) + request := readWriteModel.NewRequestCommand(cbusCommand, nil, readWriteModel.NewAlpha(alphaGenerator.getAndIncrement()), readWriteModel.RequestType_REQUEST_COMMAND, nil, nil, readWriteModel.RequestType_EMPTY, readWriteModel.NewRequestTermination(), cbusOptions) -func NewReader(tpduGenerator *AlphaGenerator, messageCodec spi.MessageCodec, tm *spi.RequestTransactionManager) *Reader { - return &Reader{ - alphaGenerator: tpduGenerator, - messageCodec: messageCodec, - tm: tm, - } -} + 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) + 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) -func (m *Reader) Read(ctx context.Context, readRequest apiModel.PlcReadRequest) <-chan apiModel.PlcReadRequestResult { - log.Trace().Msg("Reading") - result := make(chan apiModel.PlcReadRequestResult) - go m.readSync(ctx, readRequest, result) - return result -} + cBusMessage, supportsRead = readWriteModel.NewCBusMessageToServer(request, requestContext, cbusOptions), true + 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) + 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) -func (m *Reader) readSync(ctx context.Context, readRequest apiModel.PlcReadRequest, result chan apiModel.PlcReadRequestResult) { - numTags := len(readRequest.GetTagNames()) - if numTags > 20 { // letters g-z - result <- &spiModel.DefaultPlcReadRequestResult{ - Request: readRequest, - Response: nil, - Err: errors.New("Only 20 tags can be handled at once"), - } + cBusMessage, supportsRead = readWriteModel.NewCBusMessageToServer(request, requestContext, cbusOptions), true return - } - messages := make(map[string]readWriteModel.CBusMessage) - for _, tagName := range readRequest.GetTagNames() { - tag := readRequest.GetTag(tagName) - message, supportsRead, _, _, err := TagToCBusMessage(tag, nil, m.alphaGenerator, m.messageCodec.(*MessageCodec)) - if !supportsRead { - result <- &spiModel.DefaultPlcReadRequestResult{ - Request: readRequest, - Response: nil, - Err: errors.Wrapf(err, "Error encoding cbus message for tag %s. Tag is not meant to be read.", tagName), - } - return - } - if err != nil { - result <- &spiModel.DefaultPlcReadRequestResult{ - Request: readRequest, - Response: nil, - Err: errors.Wrapf(err, "Error encoding cbus message for tag %s", tagName), - } - 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) + 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) + + cBusMessage, supportsRead = readWriteModel.NewCBusMessageToServer(request, requestContext, cbusOptions), true + return + case *salTag: + var salCommand = tagType.salCommand + if salCommand == "" { + return nil, false, false, false, errors.New("Empty sal command not supported") } - messages[tagName] = message - } - responseMu := sync.Mutex{} - responseCodes := map[string]apiModel.PlcResponseCode{} - addResponseCode := func(name string, responseCode apiModel.PlcResponseCode) { - responseMu.Lock() - defer responseMu.Unlock() - responseCodes[name] = responseCode - } - valueMu := sync.Mutex{} - plcValues := map[string]apiValues.PlcValue{} - addPlcValue := func(name string, plcValue apiValues.PlcValue) { - valueMu.Lock() - defer valueMu.Unlock() - plcValues[name] = plcValue - } - for tagName, messageToSend := range messages { - if err := ctx.Err(); err != nil { - result <- &spiModel.DefaultPlcReadRequestResult{ - Request: readRequest, - Err: err, + var salData readWriteModel.SALData + switch tagType.application.ApplicationId() { + case readWriteModel.ApplicationId_FREE_USAGE: + panic("Not yet implemented") // TODO: implement + case readWriteModel.ApplicationId_TEMPERATURE_BROADCAST: + var temperatureBroadcastData readWriteModel.TemperatureBroadcastData + switch salCommand { + case readWriteModel.TemperatureBroadcastCommandType_BROADCAST_EVENT.PLC4XEnumName(): + if value == nil || !value.IsList() || len(value.GetList()) != 2 || !value.GetList()[0].IsByte() || !value.GetList()[1].IsByte() { + return nil, false, false, false, errors.Errorf("%s requires exactly 2 arguments [temperatureGroup,temperatureByte]", salCommand) + } + commandTypeContainer := readWriteModel.TemperatureBroadcastCommandTypeContainer_TemperatureBroadcastCommandSetBroadcastEvent1_2Bytes + temperatureGroup := value.GetList()[0].GetByte() + temperatureByte := value.GetList()[1].GetByte() + temperatureBroadcastData = readWriteModel.NewTemperatureBroadcastData(commandTypeContainer, temperatureGroup, temperatureByte) + supportsWrite = true + default: + return nil, false, false, false, errors.Errorf("Unsupported command %s for %s", salCommand, tagType.application.ApplicationId()) } - return - } - tagNameCopy := tagName - // Start a new request-transaction (Is ended in the response-handler) - transaction := m.tm.StartTransaction() - transaction.Submit(func() { - // Send the over the wire - log.Trace().Msg("Send ") - if err := m.messageCodec.SendRequest(ctx, messageToSend, func(receivedMessage spi.Message) bool { - cbusMessage, ok := receivedMessage.(readWriteModel.CBusMessageExactly) - if !ok { - return false + salData = readWriteModel.NewSALDataTemperatureBroadcast(temperatureBroadcastData, nil) + case readWriteModel.ApplicationId_ROOM_CONTROL_SYSTEM: + panic("Implement me") + case + readWriteModel.ApplicationId_LIGHTING, + readWriteModel.ApplicationId_VENTILATION, + readWriteModel.ApplicationId_IRRIGATION_CONTROL, + readWriteModel.ApplicationId_POOLS_SPAS_PONDS_FOUNTAINS_CONTROL, + readWriteModel.ApplicationId_HEATING, + readWriteModel.ApplicationId_AUDIO_AND_VIDEO, + readWriteModel.ApplicationId_HVAC_ACTUATOR: + var lightingData readWriteModel.LightingData + switch salCommand { + case readWriteModel.LightingCommandType_OFF.PLC4XEnumName(): + commandTypeContainer := readWriteModel.LightingCommandTypeContainer_LightingCommandOff + if value == nil || !value.IsByte() { + return nil, false, false, false, errors.Errorf("%s requires exactly 1 arguments [group]", salCommand) } - messageToClient, ok := cbusMessage.(readWriteModel.CBusMessageToClientExactly) - if !ok { - return false + group := value.GetByte() + lightingData = readWriteModel.NewLightingDataOff(group, commandTypeContainer) + supportsWrite = true + case readWriteModel.LightingCommandType_ON.PLC4XEnumName(): + commandTypeContainer := readWriteModel.LightingCommandTypeContainer_LightingCommandOn + if value == nil || (!value.IsByte() && (!value.IsList() || len(value.GetList()) != 1 || value.GetList()[0].IsByte())) { + return nil, false, false, false, errors.Errorf("%s requires exactly 1 arguments [group]", salCommand) } - // Check if this errored - if _, ok = messageToClient.GetReply().(readWriteModel.ServerErrorReplyExactly); ok { - // This means we must handle this below - return true + group := value.GetByte() + lightingData = readWriteModel.NewLightingDataOn(group, commandTypeContainer) + supportsWrite = true + case readWriteModel.LightingCommandType_RAMP_TO_LEVEL.PLC4XEnumName(): + if value == nil || !value.IsList() || len(value.GetList()) != 3 || !value.GetList()[0].IsString() || !value.GetList()[1].IsByte() || !value.GetList()[2].IsByte() { + return nil, false, false, false, errors.Errorf("%s requires exactly 2 arguments [delay,group,level]", salCommand) } - - confirmation, ok := messageToClient.GetReply().(readWriteModel.ReplyOrConfirmationConfirmationExactly) + commandTypeContainer, ok := readWriteModel.LightingCommandTypeContainerByName(fmt.Sprintf("LightingCommandRampToLevel_%s", value.GetList()[0].GetString())) if !ok { - return false - } - return confirmation.GetConfirmation().GetAlpha().GetCharacter() == messageToSend.(readWriteModel.CBusMessageToServer).GetRequest().(readWriteModel.RequestCommand).GetAlpha().GetCharacter() - }, func(receivedMessage spi.Message) error { - defer func(transaction *spi.RequestTransaction) { - // This is just to make sure we don't forget to close the transaction here - _ = transaction.EndRequest() - }(transaction) - // Convert the response into an - log.Trace().Msg("convert response to ") - cbusMessage := receivedMessage.(readWriteModel.CBusMessage) - messageToClient := cbusMessage.(readWriteModel.CBusMessageToClient) - if _, ok := messageToClient.GetReply().(readWriteModel.ServerErrorReplyExactly); ok { - log.Trace().Msg("We got a server failure") - addResponseCode(tagNameCopy, apiModel.PlcResponseCode_INVALID_DATA) - return transaction.EndRequest() - } - replyOrConfirmationConfirmation := messageToClient.GetReply().(readWriteModel.ReplyOrConfirmationConfirmationExactly) - if !replyOrConfirmationConfirmation.GetConfirmation().GetIsSuccess() { - var responseCode apiModel.PlcResponseCode - switch replyOrConfirmationConfirmation.GetConfirmation().GetConfirmationType() { - case readWriteModel.ConfirmationType_NOT_TRANSMITTED_TO_MANY_RE_TRANSMISSIONS: - responseCode = apiModel.PlcResponseCode_REMOTE_ERROR - case readWriteModel.ConfirmationType_NOT_TRANSMITTED_CORRUPTION: - responseCode = apiModel.PlcResponseCode_INVALID_DATA - case readWriteModel.ConfirmationType_NOT_TRANSMITTED_SYNC_LOSS: - responseCode = apiModel.PlcResponseCode_REMOTE_BUSY - case readWriteModel.ConfirmationType_NOT_TRANSMITTED_TOO_LONG: - responseCode = apiModel.PlcResponseCode_INVALID_DATA - default: - return transaction.FailRequest(errors.Errorf("Every code should be mapped here: %v", replyOrConfirmationConfirmation.GetConfirmation().GetConfirmationType())) + var possibleValues []string + for _, v := range readWriteModel.LightingCommandTypeContainerValues { + possibleValues = append(possibleValues, strings.TrimPrefix(v.String(), "LightingCommandRampToLevel_")) } - log.Trace().Msgf("Was no success %s:%v", tagNameCopy, responseCode) - addResponseCode(tagNameCopy, responseCode) - return transaction.EndRequest() + return nil, false, false, false, errors.Errorf("No level found for %s. Possible values %s", value.GetList()[0].GetString(), possibleValues) } - - alpha := replyOrConfirmationConfirmation.GetConfirmation().GetAlpha() - // TODO: it could be double confirmed but this is not implemented yet - embeddedReply, ok := replyOrConfirmationConfirmation.GetEmbeddedReply().(readWriteModel.ReplyOrConfirmationReplyExactly) - if !ok { - log.Trace().Msgf("Is a confirm only, no data. Alpha: %c", alpha.GetCharacter()) - addResponseCode(tagNameCopy, apiModel.PlcResponseCode_NOT_FOUND) - return transaction.EndRequest() - } - - log.Trace().Msg("Handling confirmed data") - // TODO: check if we can use a plcValueSerializer - encodedReply := embeddedReply.GetReply().(readWriteModel.ReplyEncodedReply).GetEncodedReply() - if err := m.mapEncodedReply(transaction, encodedReply, tagNameCopy, addResponseCode, addPlcValue); err != nil { - return errors.Wrap(err, "error encoding reply") - } - return transaction.EndRequest() - }, func(err error) error { - addResponseCode(tagNameCopy, apiModel.PlcResponseCode_REQUEST_TIMEOUT) - return transaction.FailRequest(err) - }, time.Second*1); err != nil { - log.Debug().Err(err).Msgf("Error sending message for tag %s", tagNameCopy) - addResponseCode(tagNameCopy, apiModel.PlcResponseCode_INTERNAL_ERROR) - if err := transaction.FailRequest(errors.Errorf("timeout after %ss", time.Second*1)); err != nil { - log.Debug().Err(err).Msg("Error failing request") + group := value.GetList()[1].GetByte() + level := value.GetList()[2].GetByte() + lightingData = readWriteModel.NewLightingDataRampToLevel(group, level, commandTypeContainer) + supportsWrite = true + case readWriteModel.LightingCommandType_TERMINATE_RAMP.PLC4XEnumName(): + commandTypeContainer := readWriteModel.LightingCommandTypeContainer_LightingCommandTerminateRamp + if value == nil || !value.IsByte() { + return nil, false, false, false, errors.Errorf("%s requires exactly 1 arguments [group]", salCommand) } + group := value.GetByte() + lightingData = readWriteModel.NewLightingDataTerminateRamp(group, commandTypeContainer) + supportsWrite = true + case readWriteModel.LightingCommandType_LABEL.PLC4XEnumName(): + panic("Implement me") + default: + return nil, false, false, false, errors.Errorf("Unsupported command %s for %s", salCommand, tagType.application.ApplicationId()) } - }) - if err := transaction.AwaitCompletion(ctx); err != nil { - log.Warn().Err(err).Msg("Error while awaiting completion") + salData = readWriteModel.NewSALDataLighting(lightingData, nil) + case readWriteModel.ApplicationId_AIR_CONDITIONING: + panic("Implement me") + case readWriteModel.ApplicationId_TRIGGER_CONTROL: + panic("Implement me") + case readWriteModel.ApplicationId_ENABLE_CONTROL: + panic("Implement me") + case readWriteModel.ApplicationId_SECURITY: + panic("Implement me") + case readWriteModel.ApplicationId_METERING: + panic("Implement me") + case readWriteModel.ApplicationId_ACCESS_CONTROL: + panic("Implement me") + case readWriteModel.ApplicationId_CLOCK_AND_TIMEKEEPING: + panic("Implement me") + case readWriteModel.ApplicationId_TELEPHONY_STATUS_AND_CONTROL: + panic("Implement me") + case readWriteModel.ApplicationId_MEASUREMENT: + panic("Implement me") + case readWriteModel.ApplicationId_TESTING: + panic("Implement me") + case readWriteModel.ApplicationId_MEDIA_TRANSPORT_CONTROL: + panic("Implement me") + case readWriteModel.ApplicationId_ERROR_REPORTING: + panic("Implement me") + default: + return nil, false, false, false, errors.Errorf("No support for %s", tagType.application) } - } - readResponse := spiModel.NewDefaultPlcReadResponse(readRequest, responseCodes, plcValues) - result <- &spiModel.DefaultPlcReadRequestResult{ - Request: readRequest, - Response: readResponse, + //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) + 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 + default: + return nil, false, false, false, errors.Errorf("Unsupported type %T", tagType) } } -func (m *Reader) mapEncodedReply(transaction *spi.RequestTransaction, encodedReply readWriteModel.EncodedReply, tagName string, addResponseCode func(name string, responseCode apiModel.PlcResponseCode), addPlcValue func(name string, plcValue apiValues.PlcValue)) error { +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: calData := reply.GetCalReply().GetCalData() diff --git a/plc4go/internal/cbus/Reader.go b/plc4go/internal/cbus/Reader.go index 730a433186..7b6cf2dfe6 100644 --- a/plc4go/internal/cbus/Reader.go +++ b/plc4go/internal/cbus/Reader.go @@ -21,8 +21,6 @@ package cbus import ( "context" - "fmt" - "strconv" "sync" "time" @@ -31,8 +29,6 @@ import ( readWriteModel "github.com/apache/plc4x/plc4go/protocols/cbus/readwrite/model" "github.com/apache/plc4x/plc4go/spi" spiModel "github.com/apache/plc4x/plc4go/spi/model" - spiValues "github.com/apache/plc4x/plc4go/spi/values" - "github.com/pkg/errors" "github.com/rs/zerolog/log" ) @@ -184,7 +180,7 @@ func (m *Reader) readSync(ctx context.Context, readRequest apiModel.PlcReadReque log.Trace().Msg("Handling confirmed data") // TODO: check if we can use a plcValueSerializer encodedReply := embeddedReply.GetReply().(readWriteModel.ReplyEncodedReply).GetEncodedReply() - if err := m.mapEncodedReply(transaction, encodedReply, tagNameCopy, addResponseCode, addPlcValue); err != nil { + if err := MapEncodedReply(transaction, encodedReply, tagNameCopy, addResponseCode, addPlcValue); err != nil { return errors.Wrap(err, "error encoding reply") } return transaction.EndRequest() @@ -209,217 +205,3 @@ func (m *Reader) readSync(ctx context.Context, readRequest apiModel.PlcReadReque Response: readResponse, } } - -func (m *Reader) 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: - calData := reply.GetCalReply().GetCalData() - addResponseCode(tagName, apiModel.PlcResponseCode_OK) - switch calData := calData.(type) { - case readWriteModel.CALDataStatusExactly: - application := calData.GetApplication() - // TODO: verify application... this should be the same - _ = application - blockStart := calData.GetBlockStart() - // TODO: verify application... this should be the same - _ = blockStart - statusBytes := calData.GetStatusBytes() - addResponseCode(tagName, apiModel.PlcResponseCode_OK) - plcListValues := make([]apiValues.PlcValue, len(statusBytes)*4) - for i, statusByte := range statusBytes { - plcListValues[i*4+0] = spiValues.NewPlcSTRING(statusByte.GetGav0().String()) - plcListValues[i*4+1] = spiValues.NewPlcSTRING(statusByte.GetGav1().String()) - plcListValues[i*4+2] = spiValues.NewPlcSTRING(statusByte.GetGav2().String()) - plcListValues[i*4+3] = spiValues.NewPlcSTRING(statusByte.GetGav3().String()) - } - addPlcValue(tagName, spiValues.NewPlcStruct(map[string]apiValues.PlcValue{ - "application": spiValues.NewPlcSTRING(application.PLC4XEnumName()), - "blockStart": spiValues.NewPlcBYTE(blockStart), - "values": spiValues.NewPlcList(plcListValues), - })) - case readWriteModel.CALDataStatusExtendedExactly: - coding := calData.GetCoding() - // TODO: verify coding... this should be the same - _ = coding - application := calData.GetApplication() - // TODO: verify application... this should be the same - _ = application - blockStart := calData.GetBlockStart() - // TODO: verify application... this should be the same - _ = blockStart - switch coding { - case readWriteModel.StatusCoding_BINARY_BY_THIS_SERIAL_INTERFACE: - fallthrough - case readWriteModel.StatusCoding_BINARY_BY_ELSEWHERE: - statusBytes := calData.GetStatusBytes() - addResponseCode(tagName, apiModel.PlcResponseCode_OK) - plcListValues := make([]apiValues.PlcValue, len(statusBytes)*4) - for i, statusByte := range statusBytes { - plcListValues[i*4+0] = spiValues.NewPlcSTRING(statusByte.GetGav0().String()) - plcListValues[i*4+1] = spiValues.NewPlcSTRING(statusByte.GetGav1().String()) - plcListValues[i*4+2] = spiValues.NewPlcSTRING(statusByte.GetGav2().String()) - plcListValues[i*4+3] = spiValues.NewPlcSTRING(statusByte.GetGav3().String()) - } - addPlcValue(tagName, spiValues.NewPlcStruct(map[string]apiValues.PlcValue{ - "application": spiValues.NewPlcSTRING(application.PLC4XEnumName()), - "blockStart": spiValues.NewPlcBYTE(blockStart), - "values": spiValues.NewPlcList(plcListValues), - })) - case readWriteModel.StatusCoding_LEVEL_BY_THIS_SERIAL_INTERFACE: - fallthrough - case readWriteModel.StatusCoding_LEVEL_BY_ELSEWHERE: - levelInformation := calData.GetLevelInformation() - addResponseCode(tagName, apiModel.PlcResponseCode_OK) - plcListValues := make([]apiValues.PlcValue, len(levelInformation)) - for i, levelInformation := range levelInformation { - switch levelInformation := levelInformation.(type) { - case readWriteModel.LevelInformationAbsentExactly: - plcListValues[i] = spiValues.NewPlcSTRING("is absent") - case readWriteModel.LevelInformationCorruptedExactly: - plcListValues[i] = spiValues.NewPlcSTRING("corrupted") - case readWriteModel.LevelInformationNormalExactly: - plcListValues[i] = spiValues.NewPlcUSINT(levelInformation.GetActualLevel()) - default: - return transaction.FailRequest(errors.Errorf("Impossible case %v", levelInformation)) - } - } - addPlcValue(tagName, spiValues.NewPlcList(plcListValues)) - } - case readWriteModel.CALDataIdentifyReplyExactly: - switch identifyReplyCommand := calData.GetIdentifyReplyCommand().(type) { - case readWriteModel.IdentifyReplyCommandCurrentSenseLevelsExactly: - addPlcValue(tagName, spiValues.NewPlcRawByteArray(identifyReplyCommand.GetCurrentSenseLevels())) - case readWriteModel.IdentifyReplyCommandDelaysExactly: - addPlcValue(tagName, spiValues.NewPlcStruct(map[string]apiValues.PlcValue{ - "reStrikeDelay": spiValues.NewPlcUSINT(identifyReplyCommand.GetReStrikeDelay()), - "terminalLevel": spiValues.NewPlcRawByteArray(identifyReplyCommand.GetTerminalLevels()), - })) - case readWriteModel.IdentifyReplyCommandDSIStatusExactly: - addPlcValue(tagName, spiValues.NewPlcStruct(map[string]apiValues.PlcValue{ - "channelStatus1": spiValues.NewPlcSTRING(identifyReplyCommand.GetChannelStatus1().String()), - "channelStatus2": spiValues.NewPlcSTRING(identifyReplyCommand.GetChannelStatus2().String()), - "channelStatus3": spiValues.NewPlcSTRING(identifyReplyCommand.GetChannelStatus3().String()), - "channelStatus4": spiValues.NewPlcSTRING(identifyReplyCommand.GetChannelStatus4().String()), - "channelStatus5": spiValues.NewPlcSTRING(identifyReplyCommand.GetChannelStatus5().String()), - "channelStatus6": spiValues.NewPlcSTRING(identifyReplyCommand.GetChannelStatus6().String()), - "channelStatus7": spiValues.NewPlcSTRING(identifyReplyCommand.GetChannelStatus7().String()), - "channelStatus8": spiValues.NewPlcSTRING(identifyReplyCommand.GetChannelStatus8().String()), - "unitStatus": spiValues.NewPlcSTRING(identifyReplyCommand.GetUnitStatus().String()), - "dimmingUCRevisionNumber": spiValues.NewPlcUSINT(identifyReplyCommand.GetDimmingUCRevisionNumber()), - })) - case readWriteModel.IdentifyReplyCommandExtendedDiagnosticSummaryExactly: - addPlcValue(tagName, spiValues.NewPlcStruct(map[string]apiValues.PlcValue{ - "lowApplication": spiValues.NewPlcSTRING(identifyReplyCommand.GetLowApplication().String()), - "highApplication": spiValues.NewPlcSTRING(identifyReplyCommand.GetHighApplication().String()), - "area": spiValues.NewPlcUSINT(identifyReplyCommand.GetArea()), - "crc": spiValues.NewPlcUINT(identifyReplyCommand.GetCrc()), - "serialNumber": spiValues.NewPlcUDINT(identifyReplyCommand.GetSerialNumber()), - "networkVoltage": spiValues.NewPlcUSINT(identifyReplyCommand.GetNetworkVoltage()), - "unitInLearnMode": spiValues.NewPlcBOOL(identifyReplyCommand.GetUnitInLearnMode()), - "networkVoltageLow": spiValues.NewPlcBOOL(identifyReplyCommand.GetNetworkVoltageLow()), - "networkVoltageMarginal": spiValues.NewPlcBOOL(identifyReplyCommand.GetNetworkVoltageMarginal()), - "enableChecksumAlarm": spiValues.NewPlcBOOL(identifyReplyCommand.GetEnableChecksumAlarm()), - "outputUnit": spiValues.NewPlcBOOL(identifyReplyCommand.GetOutputUnit()), - "installationMMIError": spiValues.NewPlcBOOL(identifyReplyCommand.GetInstallationMMIError()), - "EEWriteError": spiValues.NewPlcBOOL(identifyReplyCommand.GetEEWriteError()), - "EEChecksumError": spiValues.NewPlcBOOL(identifyReplyCommand.GetEEChecksumError()), - "EEDataError": spiValues.NewPlcBOOL(identifyReplyCommand.GetEEDataError()), - "microReset": spiValues.NewPlcBOOL(identifyReplyCommand.GetMicroReset()), - "commsTxError": spiValues.NewPlcBOOL(identifyReplyCommand.GetCommsTxError()), - "internalStackOverflow": spiValues.NewPlcBOOL(identifyReplyCommand.GetInternalStackOverflow()), - "microPowerReset": spiValues.NewPlcBOOL(identifyReplyCommand.GetMicroPowerReset()), - })) - case readWriteModel.IdentifyReplyCommandSummaryExactly: - addPlcValue(tagName, spiValues.NewPlcStruct(map[string]apiValues.PlcValue{ - "partName": spiValues.NewPlcSTRING(identifyReplyCommand.GetPartName()), - "unitServiceType": spiValues.NewPlcUSINT(identifyReplyCommand.GetUnitServiceType()), - "version": spiValues.NewPlcSTRING(identifyReplyCommand.GetVersion()), - })) - case readWriteModel.IdentifyReplyCommandFirmwareVersionExactly: - addPlcValue(tagName, spiValues.NewPlcSTRING(identifyReplyCommand.GetFirmwareVersion())) - case readWriteModel.IdentifyReplyCommandGAVPhysicalAddressesExactly: - addPlcValue(tagName, spiValues.NewPlcRawByteArray(identifyReplyCommand.GetValues())) - case readWriteModel.IdentifyReplyCommandGAVValuesCurrentExactly: - addPlcValue(tagName, spiValues.NewPlcRawByteArray(identifyReplyCommand.GetValues())) - case readWriteModel.IdentifyReplyCommandGAVValuesStoredExactly: - addPlcValue(tagName, spiValues.NewPlcRawByteArray(identifyReplyCommand.GetValues())) - case readWriteModel.IdentifyReplyCommandLogicalAssignmentExactly: - var plcValues []apiValues.PlcValue - for _, logicAssigment := range identifyReplyCommand.GetLogicAssigment() { - plcValues = append(plcValues, spiValues.NewPlcStruct(map[string]apiValues.PlcValue{ - "greaterOfOrLogic": spiValues.NewPlcBOOL(logicAssigment.GetGreaterOfOrLogic()), - "reStrikeDelay": spiValues.NewPlcBOOL(logicAssigment.GetReStrikeDelay()), - "assignedToGav16": spiValues.NewPlcBOOL(logicAssigment.GetAssignedToGav16()), - "assignedToGav15": spiValues.NewPlcBOOL(logicAssigment.GetAssignedToGav15()), - "assignedToGav14": spiValues.NewPlcBOOL(logicAssigment.GetAssignedToGav14()), - "assignedToGav13": spiValues.NewPlcBOOL(logicAssigment.GetAssignedToGav13()), - })) - } - addPlcValue(tagName, spiValues.NewPlcList(plcValues)) - case readWriteModel.IdentifyReplyCommandManufacturerExactly: - addPlcValue(tagName, spiValues.NewPlcSTRING(identifyReplyCommand.GetManufacturerName())) - case readWriteModel.IdentifyReplyCommandMaximumLevelsExactly: - addPlcValue(tagName, spiValues.NewPlcRawByteArray(identifyReplyCommand.GetMaximumLevels())) - case readWriteModel.IdentifyReplyCommandMinimumLevelsExactly: - addPlcValue(tagName, spiValues.NewPlcRawByteArray(identifyReplyCommand.GetMinimumLevels())) - case readWriteModel.IdentifyReplyCommandNetworkTerminalLevelsExactly: - addPlcValue(tagName, spiValues.NewPlcRawByteArray(identifyReplyCommand.GetNetworkTerminalLevels())) - case readWriteModel.IdentifyReplyCommandNetworkVoltageExactly: - volts := identifyReplyCommand.GetVolts() - voltsFloat, err := strconv.ParseFloat(volts, 0) - if err != nil { - addResponseCode(tagName, apiModel.PlcResponseCode_INTERNAL_ERROR) - return transaction.FailRequest(errors.Wrap(err, "Error parsing volts")) - } - voltsDecimalPlace := identifyReplyCommand.GetVoltsDecimalPlace() - voltsDecimalPlaceFloat, err := strconv.ParseFloat(voltsDecimalPlace, 0) - if err != nil { - addResponseCode(tagName, apiModel.PlcResponseCode_INTERNAL_ERROR) - return transaction.FailRequest(errors.Wrap(err, "Error parsing volts decimal place")) - } - voltsFloat += voltsDecimalPlaceFloat / 10 - addPlcValue(tagName, spiValues.NewPlcLREAL(voltsFloat)) - case readWriteModel.IdentifyReplyCommandOutputUnitSummaryExactly: - unitFlags := identifyReplyCommand.GetUnitFlags() - structContent := map[string]apiValues.PlcValue{ - "unitFlags": spiValues.NewPlcStruct(map[string]apiValues.PlcValue{ - "assertingNetworkBurden": spiValues.NewPlcBOOL(unitFlags.GetAssertingNetworkBurden()), - "restrikeTimingActive": spiValues.NewPlcBOOL(unitFlags.GetRestrikeTimingActive()), - "remoteOFFInputAsserted": spiValues.NewPlcBOOL(unitFlags.GetRemoteOFFInputAsserted()), - "remoteONInputAsserted": spiValues.NewPlcBOOL(unitFlags.GetRemoteONInputAsserted()), - "localToggleEnabled": spiValues.NewPlcBOOL(unitFlags.GetLocalToggleEnabled()), - "localToggleActiveState": spiValues.NewPlcBOOL(unitFlags.GetLocalToggleActiveState()), - "clockGenerationEnabled": spiValues.NewPlcBOOL(unitFlags.GetClockGenerationEnabled()), - "unitGeneratingClock": spiValues.NewPlcBOOL(unitFlags.GetUnitGeneratingClock()), - }), - "timeFromLastRecoverOfMainsInSeconds": spiValues.NewPlcUSINT(identifyReplyCommand.GetTimeFromLastRecoverOfMainsInSeconds()), - } - if gavStoreEnabledByte1 := identifyReplyCommand.GetGavStoreEnabledByte1(); gavStoreEnabledByte1 != nil { - structContent["gavStoreEnabledByte1"] = spiValues.NewPlcUSINT(*gavStoreEnabledByte1) - } - if gavStoreEnabledByte2 := identifyReplyCommand.GetGavStoreEnabledByte2(); gavStoreEnabledByte2 != nil { - structContent["gavStoreEnabledByte2"] = spiValues.NewPlcUSINT(*gavStoreEnabledByte2) - } - addPlcValue(tagName, spiValues.NewPlcStruct(structContent)) - case readWriteModel.IdentifyReplyCommandTerminalLevelsExactly: - addPlcValue(tagName, spiValues.NewPlcRawByteArray(identifyReplyCommand.GetTerminalLevels())) - case readWriteModel.IdentifyReplyCommandTypeExactly: - addPlcValue(tagName, spiValues.NewPlcSTRING(identifyReplyCommand.GetUnitType())) - default: - addResponseCode(tagName, apiModel.PlcResponseCode_INVALID_DATA) - return transaction.FailRequest(errors.Errorf("Unmapped type %T", identifyReplyCommand)) - } - default: - wbpcb := spiValues.NewWriteBufferPlcValueBased() - if err := calData.SerializeWithWriteBuffer(context.Background(), wbpcb); err != nil { - log.Warn().Err(err).Msgf("Unmapped cal data type %T. Returning raw to string", calData) - addPlcValue(tagName, spiValues.NewPlcSTRING(fmt.Sprintf("%s", calData))) - } else { - addPlcValue(tagName, wbpcb.GetPlcValue()) - } - } - default: - return transaction.FailRequest(errors.Errorf("All types should be mapped here. Not mapped: %T", reply)) - } - return nil -}
