You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by ho...@apache.org on 2023/01/07 02:32:29 UTC
[plc4x] branch develop updated: feat(plc4go/modbus): Implementing the correct reading of BOOL type
This is an automated email from the ASF dual-hosted git repository.
hongjinlin pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/develop by this push:
new 17d7f765c6 feat(plc4go/modbus): Implementing the correct reading of BOOL type
17d7f765c6 is described below
commit 17d7f765c670f86c3fd110f010a3faafe8ee1c5a
Author: Jinlin Hong <89...@qq.com>
AuthorDate: Sat Jan 7 10:31:49 2023 +0800
feat(plc4go/modbus): Implementing the correct reading of BOOL type
---
plc4go/examples/read/hello_world_plc4go_read.go | 16 ++++----
plc4go/internal/modbus/Reader.go | 6 ++-
plc4go/internal/modbus/Tag.go | 17 +++++++--
plc4go/internal/modbus/TagHandler.go | 24 ++++++------
plc4go/protocols/modbus/readwrite/ParserHelper.go | 2 +-
.../protocols/modbus/readwrite/XmlParserHelper.go | 2 +-
.../protocols/modbus/readwrite/model/DataItem.go | 44 +++++++++++++++-------
7 files changed, 71 insertions(+), 40 deletions(-)
diff --git a/plc4go/examples/read/hello_world_plc4go_read.go b/plc4go/examples/read/hello_world_plc4go_read.go
index 465a7ff6c7..4ab56f6d54 100644
--- a/plc4go/examples/read/hello_world_plc4go_read.go
+++ b/plc4go/examples/read/hello_world_plc4go_read.go
@@ -24,7 +24,6 @@ import (
"github.com/apache/plc4x/plc4go/pkg/api"
"github.com/apache/plc4x/plc4go/pkg/api/drivers"
- "github.com/apache/plc4x/plc4go/pkg/api/model"
)
func main() {
@@ -47,7 +46,9 @@ func main() {
// Prepare a read-request
readRequest, err := connection.ReadRequestBuilder().
- AddTagAddress("tag", "holding-register:26:REAL").
+ AddTagAddress("field", "holding-register:26:INT").
+ AddTagAddress("field_bool_single", "holding-register:1:BOOL[1]").
+ AddTagAddress("field_bool_list", "holding-register:1.10:BOOL[20]").
Build()
if err != nil {
fmt.Printf("error preparing read-request: %s", connectionResult.GetErr().Error())
@@ -64,12 +65,9 @@ func main() {
return
}
- // Do something with the response
- if rrr.GetResponse().GetResponseCode("tag") != model.PlcResponseCode_OK {
- fmt.Printf("error an non-ok return code: %s", rrr.GetResponse().GetResponseCode("tag").GetName())
- return
+ readResponse := rrr.GetResponse()
+ for _, tagName := range readResponse.GetTagNames() {
+ plcValue := readResponse.GetValue(tagName)
+ fmt.Printf("%v\n", plcValue)
}
-
- value := rrr.GetResponse().GetValue("tag")
- fmt.Printf("Got result %f", value.GetFloat32())
}
diff --git a/plc4go/internal/modbus/Reader.go b/plc4go/internal/modbus/Reader.go
index 482cc30750..b29c772fc9 100644
--- a/plc4go/internal/modbus/Reader.go
+++ b/plc4go/internal/modbus/Reader.go
@@ -76,6 +76,10 @@ func (m *Reader) Read(ctx context.Context, readRequest model.PlcReadRequest) <-c
return
}
numWords := uint16(math.Ceil(float64(modbusTagVar.Quantity*uint16(modbusTagVar.Datatype.DataTypeSize())) / float64(2)))
+ // BOOL type numWords = Ceil((Offset + Quantity) / 16)
+ if modbusTagVar.Datatype == readWriteModel.ModbusDataType_BOOL {
+ numWords = uint16(math.Ceil(float64(modbusTagVar.Offset+modbusTagVar.Quantity) / float64(16)))
+ }
log.Debug().Msgf("Working with %d words", numWords)
var pdu readWriteModel.ModbusPDU = nil
switch modbusTagVar.TagType {
@@ -190,7 +194,7 @@ func (m *Reader) ToPlc4xReadResponse(responseAdu readWriteModel.ModbusTcpADU, re
// Decode the data according to the information from the request
log.Trace().Msg("decode data")
- value, err := readWriteModel.DataItemParse(data, tag.Datatype, tag.Quantity)
+ value, err := readWriteModel.DataItemParse(data, tag.Datatype, tag.Quantity, tag.Offset)
if err != nil {
return nil, errors.Wrap(err, "Error parsing data item")
}
diff --git a/plc4go/internal/modbus/Tag.go b/plc4go/internal/modbus/Tag.go
index 8958d18c4f..76cd1859be 100644
--- a/plc4go/internal/modbus/Tag.go
+++ b/plc4go/internal/modbus/Tag.go
@@ -42,24 +42,35 @@ type modbusTag struct {
TagType TagType
Address uint16
+ Offset uint16
Quantity uint16
Datatype model2.ModbusDataType
}
-func NewTag(tagType TagType, address uint16, quantity uint16, datatype model2.ModbusDataType) modbusTag {
+func NewTag(tagType TagType, address uint16, offset uint16, quantity uint16, datatype model2.ModbusDataType) modbusTag {
return modbusTag{
TagType: tagType,
Address: address - AddressOffset,
+ Offset: offset,
Quantity: quantity,
Datatype: datatype,
}
}
-func NewModbusPlcTagFromStrings(tagType TagType, addressString string, quantityString string, datatype model2.ModbusDataType) (model.PlcTag, error) {
+func NewModbusPlcTagFromStrings(tagType TagType, addressString string, offsetString string, quantityString string, datatype model2.ModbusDataType) (model.PlcTag, error) {
address, err := strconv.ParseUint(addressString, 10, 16)
if err != nil {
return nil, errors.Errorf("Couldn't parse address string '%s' into an int", addressString)
}
+ if offsetString == "" {
+ log.Debug().Msg("No offset supplied, assuming 0")
+ offsetString = "0"
+ }
+ offset, err := strconv.ParseUint(offsetString, 10, 16)
+ if err != nil {
+ log.Warn().Err(err).Msgf("Error during parsing for %s. Falling back to 1", offsetString)
+ offset = 0
+ }
if quantityString == "" {
log.Debug().Msg("No quantity supplied, assuming 1")
quantityString = "1"
@@ -69,7 +80,7 @@ func NewModbusPlcTagFromStrings(tagType TagType, addressString string, quantityS
log.Warn().Err(err).Msgf("Error during parsing for %s. Falling back to 1", quantityString)
quantity = 1
}
- return NewTag(tagType, uint16(address), uint16(quantity), datatype), nil
+ return NewTag(tagType, uint16(address), uint16(offset), uint16(quantity), datatype), nil
}
func (m modbusTag) GetAddressString() string {
diff --git a/plc4go/internal/modbus/TagHandler.go b/plc4go/internal/modbus/TagHandler.go
index 9fa496e7e7..aac0bc0e70 100644
--- a/plc4go/internal/modbus/TagHandler.go
+++ b/plc4go/internal/modbus/TagHandler.go
@@ -58,8 +58,8 @@ type TagHandler struct {
}
func NewTagHandler() TagHandler {
- generalAddressPattern := `(?P<address>\d+)(:(?P<datatype>[a-zA-Z_]+))?(\[(?P<quantity>\d+)])?$`
- generalFixedDigitAddressPattern := `(?P<address>\d{4,5})?(:(?P<datatype>[a-zA-Z_]+))?(\[(?P<quantity>\d+)])?$`
+ generalAddressPattern := `(?P<address>\d+)\.?(?P<offset>\d+)?(:(?P<datatype>[a-zA-Z_]+))?(\[(?P<quantity>\d+)])?$`
+ generalFixedDigitAddressPattern := `(?P<address>\d{4,5})?\.?(?P<offset>\d+)?(:(?P<datatype>[a-zA-Z_]+))?(\[(?P<quantity>\d+)])?$`
return TagHandler{
plc4xCoilPattern: regexp.MustCompile("^coil:" + generalAddressPattern),
numericCoilPattern: regexp.MustCompile("^0[xX]?" + generalFixedDigitAddressPattern),
@@ -80,61 +80,61 @@ func (m TagHandler) ParseTag(tagAddress string) (model.PlcTag, error) {
if !ok {
return nil, errors.Errorf("Unknown type %s", match["datatype"])
}
- return NewModbusPlcTagFromStrings(Coil, match["address"], match["quantity"], typeByName)
+ return NewModbusPlcTagFromStrings(Coil, match["address"], match["offset"], match["quantity"], typeByName)
} else if match := utils.GetSubgroupMatches(m.numericCoilPattern, tagAddress); match != nil {
typeByName, ok := model2.ModbusDataTypeByName(match["datatype"])
if !ok {
return nil, errors.Errorf("Unknown type %s", match["datatype"])
}
- return NewModbusPlcTagFromStrings(Coil, match["address"], match["quantity"], typeByName)
+ return NewModbusPlcTagFromStrings(Coil, match["address"], match["offset"], match["quantity"], typeByName)
} else if match := utils.GetSubgroupMatches(m.plc4xDiscreteInputPattern, tagAddress); match != nil {
typeByName, ok := model2.ModbusDataTypeByName(match["datatype"])
if !ok {
return nil, errors.Errorf("Unknown type %s", match["datatype"])
}
- return NewModbusPlcTagFromStrings(DiscreteInput, match["address"], match["quantity"], typeByName)
+ return NewModbusPlcTagFromStrings(DiscreteInput, match["address"], match["offset"], match["quantity"], typeByName)
} else if match := utils.GetSubgroupMatches(m.numericDiscreteInputPattern, tagAddress); match != nil {
typeByName, ok := model2.ModbusDataTypeByName(match["datatype"])
if !ok {
return nil, errors.Errorf("Unknown type %s", match["datatype"])
}
- return NewModbusPlcTagFromStrings(DiscreteInput, match["address"], match["quantity"], typeByName)
+ return NewModbusPlcTagFromStrings(DiscreteInput, match["address"], match["offset"], match["quantity"], typeByName)
} else if match := utils.GetSubgroupMatches(m.plc4xInputRegisterPattern, tagAddress); match != nil {
typeByName, ok := model2.ModbusDataTypeByName(match["datatype"])
if !ok {
return nil, errors.Errorf("Unknown type %s", match["datatype"])
}
- return NewModbusPlcTagFromStrings(InputRegister, match["address"], match["quantity"], typeByName)
+ return NewModbusPlcTagFromStrings(InputRegister, match["address"], match["offset"], match["quantity"], typeByName)
} else if match := utils.GetSubgroupMatches(m.numericInputRegisterPattern, tagAddress); match != nil {
typeByName, ok := model2.ModbusDataTypeByName(match["datatype"])
if !ok {
return nil, errors.Errorf("Unknown type %s", match["datatype"])
}
- return NewModbusPlcTagFromStrings(InputRegister, match["address"], match["quantity"], typeByName)
+ return NewModbusPlcTagFromStrings(InputRegister, match["address"], match["offset"], match["quantity"], typeByName)
} else if match := utils.GetSubgroupMatches(m.plc4xHoldingRegisterPattern, tagAddress); match != nil {
typeByName, ok := model2.ModbusDataTypeByName(match["datatype"])
if !ok {
return nil, errors.Errorf("Unknown type %s", match["datatype"])
}
- return NewModbusPlcTagFromStrings(HoldingRegister, match["address"], match["quantity"], typeByName)
+ return NewModbusPlcTagFromStrings(HoldingRegister, match["address"], match["offset"], match["quantity"], typeByName)
} else if match := utils.GetSubgroupMatches(m.numericHoldingRegisterPattern, tagAddress); match != nil {
typeByName, ok := model2.ModbusDataTypeByName(match["datatype"])
if !ok {
return nil, errors.Errorf("Unknown type %s", match["datatype"])
}
- return NewModbusPlcTagFromStrings(HoldingRegister, match["address"], match["quantity"], typeByName)
+ return NewModbusPlcTagFromStrings(HoldingRegister, match["address"], match["offset"], match["quantity"], typeByName)
} else if match := utils.GetSubgroupMatches(m.plc4xExtendedRegisterPattern, tagAddress); match != nil {
typeByName, ok := model2.ModbusDataTypeByName(match["datatype"])
if !ok {
return nil, errors.Errorf("Unknown type %s", match["datatype"])
}
- return NewModbusPlcTagFromStrings(ExtendedRegister, match["address"], match["quantity"], typeByName)
+ return NewModbusPlcTagFromStrings(ExtendedRegister, match["address"], match["offset"], match["quantity"], typeByName)
} else if match := utils.GetSubgroupMatches(m.numericExtendedRegisterPattern, tagAddress); match != nil {
typeByName, ok := model2.ModbusDataTypeByName(match["datatype"])
if !ok {
return nil, errors.Errorf("Unknown type %s", match["datatype"])
}
- return NewModbusPlcTagFromStrings(ExtendedRegister, match["address"], match["quantity"], typeByName)
+ return NewModbusPlcTagFromStrings(ExtendedRegister, match["address"], match["offset"], match["quantity"], typeByName)
}
return nil, errors.Errorf("Invalid address format for address '%s'", tagAddress)
}
diff --git a/plc4go/protocols/modbus/readwrite/ParserHelper.go b/plc4go/protocols/modbus/readwrite/ParserHelper.go
index 83ccafbbd4..38bb3f1994 100644
--- a/plc4go/protocols/modbus/readwrite/ParserHelper.go
+++ b/plc4go/protocols/modbus/readwrite/ParserHelper.go
@@ -40,7 +40,7 @@ func (m ModbusParserHelper) Parse(typeName string, arguments []string, io utils.
if err != nil {
return nil, errors.Wrap(err, "Error parsing")
}
- return model.DataItemParseWithBuffer(io, dataType, numberOfValues)
+ return model.DataItemParseWithBuffer(io, dataType, numberOfValues, 0)
case "ModbusPDUReadFileRecordResponseItem":
return model.ModbusPDUReadFileRecordResponseItemParseWithBuffer(io)
case "ModbusDeviceInformationObject":
diff --git a/plc4go/protocols/modbus/readwrite/XmlParserHelper.go b/plc4go/protocols/modbus/readwrite/XmlParserHelper.go
index 9790ce62ef..19ccbfdd73 100644
--- a/plc4go/protocols/modbus/readwrite/XmlParserHelper.go
+++ b/plc4go/protocols/modbus/readwrite/XmlParserHelper.go
@@ -51,7 +51,7 @@ func (m ModbusXmlParserHelper) Parse(typeName string, xmlString string, parserAr
return nil, err
}
numberOfValues := uint16(parsedUint1)
- return model.DataItemParseWithBuffer(utils.NewXmlReadBuffer(strings.NewReader(xmlString)), dataType, numberOfValues)
+ return model.DataItemParseWithBuffer(utils.NewXmlReadBuffer(strings.NewReader(xmlString)), dataType, numberOfValues, 0)
case "ModbusPDUReadFileRecordResponseItem":
return model.ModbusPDUReadFileRecordResponseItemParseWithBuffer(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
case "ModbusDeviceInformationObject":
diff --git a/plc4go/protocols/modbus/readwrite/model/DataItem.go b/plc4go/protocols/modbus/readwrite/model/DataItem.go
index 135c89fdc6..2742c8ac1b 100644
--- a/plc4go/protocols/modbus/readwrite/model/DataItem.go
+++ b/plc4go/protocols/modbus/readwrite/model/DataItem.go
@@ -24,34 +24,52 @@ import (
"github.com/apache/plc4x/plc4go/spi/utils"
"github.com/apache/plc4x/plc4go/spi/values"
"github.com/pkg/errors"
+ "math"
)
// Code generated by code-generation. DO NOT EDIT.
-func DataItemParse(theBytes []byte, dataType ModbusDataType, numberOfValues uint16) (api.PlcValue, error) {
- return DataItemParseWithBuffer(utils.NewReadBufferByteBased(theBytes), dataType, numberOfValues)
+func DataItemParse(theBytes []byte, dataType ModbusDataType, numberOfValues uint16, offset uint16) (api.PlcValue, error) {
+ return DataItemParseWithBuffer(utils.NewReadBufferByteBased(theBytes), dataType, numberOfValues, offset)
}
-func DataItemParseWithBuffer(readBuffer utils.ReadBuffer, dataType ModbusDataType, numberOfValues uint16) (api.PlcValue, error) {
+func DataItemParseWithBuffer(readBuffer utils.ReadBuffer, dataType ModbusDataType, numberOfValues uint16, offset uint16) (api.PlcValue, error) {
readBuffer.PullContext("DataItem")
switch {
case dataType == ModbusDataType_BOOL && numberOfValues == uint16(1): // BOOL
- // Reserved Field (Just skip the bytes)
- if _, _err := readBuffer.ReadUint16("reserved", 15); _err != nil {
- return nil, errors.Wrap(_err, "Error parsing reserved field")
- }
-
- // Simple Field (value)
- value, _valueErr := readBuffer.ReadBit("value")
- if _valueErr != nil {
- return nil, errors.Wrap(_valueErr, "Error parsing 'value' field")
+ _numberOfValues := uint16(math.Ceil(float64((offset + numberOfValues)) / float64(16)))
+ var value bool
+ var _valueErr error
+ // find the offset bit
+ for i := 0; i < int(_numberOfValues*16); i++ {
+ // skip offset
+ if i != int(offset) {
+ readBuffer.ReadBit("value")
+ continue
+ }
+ // Simple Field (value)
+ value, _valueErr = readBuffer.ReadBit("value")
+ if _valueErr != nil {
+ return nil, errors.Wrap(_valueErr, "Error parsing 'value' field")
+ }
+ break
}
readBuffer.CloseContext("DataItem")
return values.NewPlcBOOL(value), nil
case dataType == ModbusDataType_BOOL: // List
+ _numberOfValues := uint16(math.Ceil(float64((offset + numberOfValues)) / float64(16)))
// Array Field (value)
var value []api.PlcValue
- for i := 0; i < int(numberOfValues); i++ {
+ for i := 0; i < int(_numberOfValues*16); i++ {
+ // skip offset
+ if i < int(offset) {
+ readBuffer.ReadBit("value")
+ continue
+ }
+ // read end
+ if i == int(offset+numberOfValues) {
+ break
+ }
_item, _itemErr := readBuffer.ReadBit("value")
if _itemErr != nil {
return nil, errors.Wrap(_itemErr, "Error parsing 'value' field")