You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2021/03/31 10:02:05 UTC
[plc4x] branch develop updated: plc4go: ads first draft of symbolic
addressing implemented + Test currently doesn't run due to issues on xml
(un)marshalling
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
The following commit(s) were added to refs/heads/develop by this push:
new 49337d9 plc4go: ads first draft of symbolic addressing implemented + Test currently doesn't run due to issues on xml (un)marshalling
49337d9 is described below
commit 49337d9140e2b794f2708e94d77124277b8b2f88
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Wed Mar 31 12:01:47 2021 +0200
plc4go: ads first draft of symbolic addressing implemented
+ Test currently doesn't run due to issues on xml (un)marshalling
---
go.mod | 2 +-
go.sum | 7 +
plc4go/cmd/main/drivers/tests/ads_driver_test.go | 2 +-
plc4go/internal/plc4go/ads/Field.go | 125 ++++++++++++----
plc4go/internal/plc4go/ads/FieldHandler.go | 13 +-
plc4go/internal/plc4go/ads/Reader.go | 180 ++++++++++++++++-------
plc4go/internal/plc4go/ads/Writer.go | 2 +-
7 files changed, 239 insertions(+), 92 deletions(-)
diff --git a/go.mod b/go.mod
index de83014..bad7f35 100644
--- a/go.mod
+++ b/go.mod
@@ -21,6 +21,6 @@ module github.com/apache/plc4x
go 1.15
require (
- github.com/apache/plc4x/plc4go v0.0.0-20210323102244-4bca718b85a1 // indirect
+ github.com/apache/plc4x/plc4go v0.0.0-20210331081511-003c50ba4f7e // indirect
github.com/sirupsen/logrus v1.7.0 // indirect
)
diff --git a/go.sum b/go.sum
index 35506dc..11e6fe6 100644
--- a/go.sum
+++ b/go.sum
@@ -16,20 +16,26 @@ github.com/apache/plc4x/plc4go v0.0.0-20210319203815-34cd8e7cee37 h1:v6058YVP+Cs
github.com/apache/plc4x/plc4go v0.0.0-20210319203815-34cd8e7cee37/go.mod h1:1mws7SPHWDbyheFlOoxKystKWmq5m4itv1uf/rvMzzQ=
github.com/apache/plc4x/plc4go v0.0.0-20210323102244-4bca718b85a1 h1:s2kHU276v57Y1t2IeC90g2/Wr5vkEKzliWoGLbndmvU=
github.com/apache/plc4x/plc4go v0.0.0-20210323102244-4bca718b85a1/go.mod h1:9m7z5psLsDpPfcVPIdd/L9qmn1lCojPLxfhTrvhQwjw=
+github.com/apache/plc4x/plc4go v0.0.0-20210331081511-003c50ba4f7e h1:LFclJ70mgE7gU4ZGLHub4LwBA9TCULXObHlRdrye+2Q=
+github.com/apache/plc4x/plc4go v0.0.0-20210331081511-003c50ba4f7e/go.mod h1:NfO8uGKPGwDxn1GqOb4oNhAtPF7St1A9LRk1J/qSlWU=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE=
github.com/elastic/go-licenser v0.3.1/go.mod h1:D8eNQk70FOCVBl3smCGQt/lv7meBeQno2eI1S5apiHQ=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
+github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/icza/bitio v1.0.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A=
github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
@@ -76,4 +82,5 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gotest.tools/gotestsum v1.6.2/go.mod h1:H74H1IvjJE+E/1INpsn2P4+QW0uLDgL/T2sVajPHmTM=
+gotest.tools/gotestsum v1.6.3/go.mod h1:fTR9ZhxC/TLAAx2/WMk/m3TkMB9eEI89gdEzhiRVJT8=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
diff --git a/plc4go/cmd/main/drivers/tests/ads_driver_test.go b/plc4go/cmd/main/drivers/tests/ads_driver_test.go
index 15da0f0..002aefb 100644
--- a/plc4go/cmd/main/drivers/tests/ads_driver_test.go
+++ b/plc4go/cmd/main/drivers/tests/ads_driver_test.go
@@ -30,7 +30,7 @@ func TestAdsDriver(t *testing.T) {
testutils.RunDriverTestsuite(t, ads.NewDriver(), "assets/testing/protocols/ads/DriverTestsuite.xml",
// TODO: tests assumes proper multi requests which is currently not implemented yet
"Multi-element direct read request",
- // TODO: symbolic addressing not implemented yet
+ // TODO: xml marshaller/unmarshaler produces empty elements which break the tests
"Single element symbolic read request",
// TODO: symbolic addressing not implemented yet
"Single element symbolic read request (Address previously resolved)",
diff --git a/plc4go/internal/plc4go/ads/Field.go b/plc4go/internal/plc4go/ads/Field.go
index c79f746..7b878ca 100644
--- a/plc4go/internal/plc4go/ads/Field.go
+++ b/plc4go/internal/plc4go/ads/Field.go
@@ -30,18 +30,11 @@ import (
type PlcField struct {
FieldType FieldType
- IndexGroup uint32
- IndexOffset uint32
- SymbolicAddress string
StringLength int32
NumberOfElements int64
Datatype model2.AdsDataType
}
-func (m PlcField) GetAddressString() string {
- return fmt.Sprintf("%dx%05d%05d%s%05d%05d:%s", m.FieldType, m.IndexGroup, m.IndexOffset, m.SymbolicAddress, m.StringLength, m.NumberOfElements, m.Datatype.String())
-}
-
func (m PlcField) GetTypeName() string {
return m.FieldType.GetName()
}
@@ -50,38 +43,41 @@ func (m PlcField) GetQuantity() uint16 {
return 1
}
-func NewAdsPlcField(fieldType FieldType, indexGroup uint32, indexOffset uint32, adsDataType model2.AdsDataType, stringLength int32, numberOfElements int64) (model.PlcField, error) {
- return PlcField{
- FieldType: fieldType,
- IndexGroup: indexGroup,
- IndexOffset: indexOffset,
- SymbolicAddress: "",
- StringLength: stringLength,
- NumberOfElements: numberOfElements,
- Datatype: adsDataType,
- }, nil
+type DirectPlcField struct {
+ IndexGroup uint32
+ IndexOffset uint32
+ PlcField
}
-func NewAdsSymbolicPlcField(fieldType FieldType, symbolicAddress string, adsDataType model2.AdsDataType, stringLength int32, numberOfElements int64) (model.PlcField, error) {
- return PlcField{
- FieldType: fieldType,
- IndexGroup: 0,
- IndexOffset: 0,
- SymbolicAddress: symbolicAddress,
- StringLength: stringLength,
- NumberOfElements: numberOfElements,
- Datatype: adsDataType,
+func (m DirectPlcField) GetAddressString() string {
+ return fmt.Sprintf("%dx%05d%05d%05d%05d:%s", m.FieldType, m.IndexGroup, m.IndexOffset, m.StringLength, m.NumberOfElements, m.Datatype.String())
+}
+
+func newDirectAdsPlcField(indexGroup uint32, indexOffset uint32, adsDataType model2.AdsDataType, stringLength int32, numberOfElements int64) (model.PlcField, error) {
+ fieldType := DirectAdsField
+ if stringLength > 0 {
+ fieldType = DirectAdsStringField
+ }
+ return DirectPlcField{
+ IndexGroup: indexGroup,
+ IndexOffset: indexOffset,
+ PlcField: PlcField{
+ FieldType: fieldType,
+ StringLength: stringLength,
+ NumberOfElements: numberOfElements,
+ Datatype: adsDataType,
+ },
}, nil
}
-func CastToAdsFieldFromPlcField(plcField model.PlcField) (PlcField, error) {
- if adsField, ok := plcField.(PlcField); ok {
+func castToDirectAdsFieldFromPlcField(plcField model.PlcField) (DirectPlcField, error) {
+ if adsField, ok := plcField.(DirectPlcField); ok {
return adsField, nil
}
- return PlcField{}, errors.New("couldn't cast to AdsPlcField")
+ return DirectPlcField{}, errors.New("couldn't cast to AdsPlcField")
}
-func (m PlcField) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
+func (m DirectPlcField) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
log.Trace().Msg("MarshalXML")
if err := e.EncodeToken(xml.StartElement{Name: xml.Name{Local: m.FieldType.GetName()}}); err != nil {
return err
@@ -93,11 +89,76 @@ func (m PlcField) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
if err := e.EncodeElement(m.IndexOffset, xml.StartElement{Name: xml.Name{Local: "indexOffset"}}); err != nil {
return err
}
- if m.SymbolicAddress != "" {
- if err := e.EncodeElement(m.SymbolicAddress, xml.StartElement{Name: xml.Name{Local: "symbolicAddress"}}); err != nil {
+ if m.StringLength > 0 {
+ if err := e.EncodeElement(m.StringLength, xml.StartElement{Name: xml.Name{Local: "stringLength"}}); err != nil {
return err
}
}
+ if err := e.EncodeElement(m.NumberOfElements, xml.StartElement{Name: xml.Name{Local: "numberOfElements"}}); err != nil {
+ return err
+ }
+ if err := e.EncodeElement(m.Datatype.String(), xml.StartElement{Name: xml.Name{Local: "dataType"}}); err != nil {
+ return err
+ }
+
+ if err := e.EncodeToken(xml.EndElement{Name: xml.Name{Local: m.FieldType.GetName()}}); err != nil {
+ return err
+ }
+ return nil
+}
+
+type SymbolicPlcField struct {
+ SymbolicAddress string
+ PlcField
+}
+
+func (m SymbolicPlcField) GetAddressString() string {
+ return fmt.Sprintf("%dx%s%05d%05d:%s", m.FieldType, m.SymbolicAddress, m.StringLength, m.NumberOfElements, m.Datatype.String())
+}
+
+func newAdsSymbolicPlcField(symbolicAddress string, adsDataType model2.AdsDataType, stringLength int32, numberOfElements int64) (model.PlcField, error) {
+ fieldType := SymbolicField
+ if stringLength > 0 {
+ fieldType = SymbolicStringField
+ }
+ return SymbolicPlcField{
+ SymbolicAddress: symbolicAddress,
+ PlcField: PlcField{
+ FieldType: fieldType,
+ StringLength: stringLength,
+ NumberOfElements: numberOfElements,
+ Datatype: adsDataType,
+ },
+ }, nil
+}
+
+func needsResolving(plcField model.PlcField) bool {
+ switch plcField.(type) {
+ case SymbolicPlcField:
+ return true
+ case DirectPlcField:
+ return false
+ default:
+ return false
+ }
+}
+
+func castToSymbolicPlcFieldFromPlcField(plcField model.PlcField) (SymbolicPlcField, error) {
+ if adsField, ok := plcField.(SymbolicPlcField); ok {
+ return adsField, nil
+ }
+ return SymbolicPlcField{}, errors.New("couldn't cast to AdsPlcField")
+}
+
+func (m SymbolicPlcField) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
+ log.Trace().Msg("MarshalXML")
+ if err := e.EncodeToken(xml.StartElement{Name: xml.Name{Local: m.FieldType.GetName()}}); err != nil {
+ return err
+ }
+
+ if err := e.EncodeElement(m.SymbolicAddress, xml.StartElement{Name: xml.Name{Local: "symbolicAddress"}}); err != nil {
+ return err
+ }
if m.StringLength > 0 {
if err := e.EncodeElement(m.StringLength, xml.StartElement{Name: xml.Name{Local: "stringLength"}}); err != nil {
return err
diff --git a/plc4go/internal/plc4go/ads/FieldHandler.go b/plc4go/internal/plc4go/ads/FieldHandler.go
index 1825a62..3bfe85d 100644
--- a/plc4go/internal/plc4go/ads/FieldHandler.go
+++ b/plc4go/internal/plc4go/ads/FieldHandler.go
@@ -100,7 +100,7 @@ func (m FieldHandler) ParseQuery(query string) (apiModel.PlcField, error) {
numberOfElements = 1
}
- return NewAdsPlcField(DirectAdsStringField, indexGroup, indexOffset, model2.AdsDataTypeByName(match["adsDataType"]), int32(stringLength), int64(numberOfElements))
+ return newDirectAdsPlcField(indexGroup, indexOffset, model2.AdsDataTypeByName(match["adsDataType"]), int32(stringLength), int64(numberOfElements))
} else if match := utils.GetSubgroupMatches(m.directAdsField, query); match != nil {
var indexGroup uint32
if indexGroupHexString := match["indexGroupHex"]; indexGroupHexString != "" {
@@ -137,7 +137,7 @@ func (m FieldHandler) ParseQuery(query string) (apiModel.PlcField, error) {
log.Trace().Msg("Falling back to number of elements 1")
numberOfElements = 1
}
- return NewAdsPlcField(DirectAdsField, indexGroup, indexOffset, adsDataType, int32(0), int64(numberOfElements))
+ return newDirectAdsPlcField(indexGroup, indexOffset, adsDataType, int32(0), int64(numberOfElements))
} else if match := utils.GetSubgroupMatches(m.symbolicAdsStringField, query); match != nil {
stringLength, err := strconv.Atoi(match["stringLength"])
if err != nil {
@@ -147,13 +147,14 @@ func (m FieldHandler) ParseQuery(query string) (apiModel.PlcField, error) {
if err != nil {
return nil, errors.Wrap(err, "Error decoding number of elements")
}
- return NewAdsSymbolicPlcField(SymbolicStringField, match["symbolicAddress"], model2.AdsDataTypeByName(match["adsDataType"]), int32(stringLength), int64(numberOfElements))
- } else if match := utils.GetSubgroupMatches(m.symbolicAdsStringField, query); match != nil {
+ return newAdsSymbolicPlcField(match["symbolicAddress"], model2.AdsDataTypeByName(match["adsDataType"]), int32(stringLength), int64(numberOfElements))
+ } else if match := utils.GetSubgroupMatches(m.symbolicAdsField, query); match != nil {
numberOfElements, err := strconv.Atoi(match["numberOfElements"])
if err != nil {
- return nil, errors.Wrap(err, "Error decoding number of elements")
+ log.Trace().Msg("Falling back to number of elements 1")
+ numberOfElements = 1
}
- return NewAdsSymbolicPlcField(SymbolicField, match["symbolicAddress"], model2.AdsDataTypeByName(match["adsDataType"]), int32(0), int64(numberOfElements))
+ return newAdsSymbolicPlcField(match["symbolicAddress"], model2.AdsDataTypeByName(match["adsDataType"]), int32(0), int64(numberOfElements))
} else {
return nil, errors.Errorf("Invalid address format for address '%s'", query)
}
diff --git a/plc4go/internal/plc4go/ads/Reader.go b/plc4go/internal/plc4go/ads/Reader.go
index de73688..a177762 100644
--- a/plc4go/internal/plc4go/ads/Reader.go
+++ b/plc4go/internal/plc4go/ads/Reader.go
@@ -28,6 +28,7 @@ import (
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"math"
+ "sync"
"sync/atomic"
"time"
)
@@ -39,6 +40,8 @@ type Reader struct {
sourceAmsNetId readWriteModel.AmsNetId
sourceAmsPort uint16
messageCodec spi.MessageCodec
+ fieldMapping map[SymbolicPlcField]DirectPlcField
+ mappingLock sync.Mutex
}
func NewReader(messageCodec spi.MessageCodec, targetAmsNetId readWriteModel.AmsNetId, targetAmsPort uint16, sourceAmsNetId readWriteModel.AmsNetId, sourceAmsPort uint16) *Reader {
@@ -49,6 +52,7 @@ func NewReader(messageCodec spi.MessageCodec, targetAmsNetId readWriteModel.AmsN
sourceAmsNetId: sourceAmsNetId,
sourceAmsPort: sourceAmsPort,
messageCodec: messageCodec,
+ fieldMapping: make(map[SymbolicPlcField]DirectPlcField),
}
}
@@ -68,7 +72,30 @@ func (m *Reader) Read(readRequest model.PlcReadRequest) <-chan model.PlcReadRequ
// If we are requesting only one field, use a
fieldName := readRequest.GetFieldNames()[0]
field := readRequest.GetField(fieldName)
- adsField, err := CastToAdsFieldFromPlcField(field)
+ if needsResolving(field) {
+ // TODO: resolve field
+ adsField, err := castToSymbolicPlcFieldFromPlcField(field)
+ if err != nil {
+ result <- model.PlcReadRequestResult{
+ Request: readRequest,
+ Response: nil,
+ Err: errors.Wrap(err, "invalid field item type"),
+ }
+ log.Debug().Msgf("Invalid field item type %T", field)
+ return
+ }
+ field, err = m.resolveField(adsField)
+ if err != nil {
+ result <- model.PlcReadRequestResult{
+ Request: readRequest,
+ Response: nil,
+ Err: errors.Wrap(err, "invalid field item type"),
+ }
+ log.Debug().Msgf("Invalid field item type %T", field)
+ return
+ }
+ }
+ adsField, err := castToDirectAdsFieldFromPlcField(field)
if err != nil {
result <- model.PlcReadRequestResult{
Request: readRequest,
@@ -108,67 +135,118 @@ func (m *Reader) Read(readRequest model.PlcReadRequest) <-chan model.PlcReadRequ
return
}
- // Calculate a new transaction identifier
- transactionIdentifier := atomic.AddUint32(&m.transactionIdentifier, 1)
- if transactionIdentifier > math.MaxUint8 {
- transactionIdentifier = 1
- atomic.StoreUint32(&m.transactionIdentifier, 1)
- }
- log.Debug().Msgf("Calculated transaction identifier %x", transactionIdentifier)
- userdata.InvokeId = transactionIdentifier
+ m.sendOverTheWire(userdata, readRequest, result)
+ }()
+ return result
+}
- // Assemble the finished tcp paket
- log.Trace().Msg("Assemble tcp paket")
- amsTcpPaket := readWriteModel.AmsTCPPacket{
- Userdata: &userdata,
- }
+func (m *Reader) sendOverTheWire(userdata readWriteModel.AmsPacket, readRequest model.PlcReadRequest, result chan model.PlcReadRequestResult) {
+ // Calculate a new transaction identifier
+ transactionIdentifier := atomic.AddUint32(&m.transactionIdentifier, 1)
+ if transactionIdentifier > math.MaxUint8 {
+ transactionIdentifier = 1
+ atomic.StoreUint32(&m.transactionIdentifier, 1)
+ }
+ log.Debug().Msgf("Calculated transaction identifier %x", transactionIdentifier)
+ userdata.InvokeId = transactionIdentifier
- // Send the TCP Paket over the wire
- log.Trace().Msg("Send TCP Paket")
- if err = m.messageCodec.SendRequest(
- amsTcpPaket,
- func(message interface{}) bool {
- paket := readWriteModel.CastAmsTCPPacket(message)
- return paket.Userdata.InvokeId == transactionIdentifier
- },
- func(message interface{}) error {
- // Convert the response into an amsTcpPaket
- log.Trace().Msg("convert response to amsTcpPaket")
- amsTcpPaket := readWriteModel.CastAmsTCPPacket(message)
- // Convert the ads response into a PLC4X response
- log.Trace().Msg("convert response to PLC4X response")
- readResponse, err := m.ToPlc4xReadResponse(*amsTcpPaket, readRequest)
+ // Assemble the finished tcp paket
+ log.Trace().Msg("Assemble tcp paket")
+ amsTcpPaket := readWriteModel.AmsTCPPacket{
+ Userdata: &userdata,
+ }
- if err != nil {
- result <- model.PlcReadRequestResult{
- Request: readRequest,
- Err: errors.Wrap(err, "Error decoding response"),
- }
- // TODO: should we return the error here?
- return nil
- }
- result <- model.PlcReadRequestResult{
- Request: readRequest,
- Response: readResponse,
- }
- return nil
- },
- func(err error) error {
+ // Send the TCP Paket over the wire
+ log.Trace().Msg("Send TCP Paket")
+ if err := m.messageCodec.SendRequest(
+ amsTcpPaket,
+ func(message interface{}) bool {
+ paket := readWriteModel.CastAmsTCPPacket(message)
+ return paket.Userdata.InvokeId == transactionIdentifier
+ },
+ func(message interface{}) error {
+ // Convert the response into an amsTcpPaket
+ log.Trace().Msg("convert response to amsTcpPaket")
+ amsTcpPaket := readWriteModel.CastAmsTCPPacket(message)
+ // Convert the ads response into a PLC4X response
+ log.Trace().Msg("convert response to PLC4X response")
+ readResponse, err := m.ToPlc4xReadResponse(*amsTcpPaket, readRequest)
+
+ if err != nil {
result <- model.PlcReadRequestResult{
Request: readRequest,
- Err: errors.Wrap(err, "got timeout while waiting for response"),
+ Err: errors.Wrap(err, "Error decoding response"),
}
+ // TODO: should we return the error here?
return nil
- },
- time.Second*1); err != nil {
+ }
result <- model.PlcReadRequestResult{
Request: readRequest,
- Response: nil,
- Err: errors.Wrap(err, "error sending message"),
+ Response: readResponse,
}
+ return nil
+ },
+ func(err error) error {
+ result <- model.PlcReadRequestResult{
+ Request: readRequest,
+ Err: errors.Wrap(err, "got timeout while waiting for response"),
+ }
+ return nil
+ },
+ time.Second*1); err != nil {
+ result <- model.PlcReadRequestResult{
+ Request: readRequest,
+ Response: nil,
+ Err: errors.Wrap(err, "error sending message"),
}
+ }
+}
+
+func (m *Reader) resolveField(symbolicField SymbolicPlcField) (DirectPlcField, error) {
+ if directPlcField, ok := m.fieldMapping[symbolicField]; ok {
+ return directPlcField, nil
+ }
+ m.mappingLock.Lock()
+ defer m.mappingLock.Unlock()
+ // In case a previous one has already
+ if directPlcField, ok := m.fieldMapping[symbolicField]; ok {
+ return directPlcField, nil
+ }
+ userdata := readWriteModel.AmsPacket{
+ TargetAmsNetId: &m.targetAmsNetId,
+ TargetAmsPort: m.targetAmsPort,
+ SourceAmsNetId: &m.sourceAmsNetId,
+ SourceAmsPort: m.sourceAmsPort,
+ CommandId: readWriteModel.CommandId_ADS_READ_WRITE,
+ State: readWriteModel.NewState(false, false, false, false, false, true, false, false, false),
+ ErrorCode: 0,
+ InvokeId: 0,
+ Data: nil,
+ }
+ userdata.Data = readWriteModel.NewAdsReadWriteRequest(
+ uint32(readWriteModel.ReservedIndexGroups_ADSIGRP_SYM_HNDBYNAME),
+ 0,
+ 4,
+ nil,
+ utils.ByteArrayToInt8Array([]byte(symbolicField.SymbolicAddress+"\000")),
+ )
+ result := make(chan model.PlcReadRequestResult)
+ go func() {
+ m.sendOverTheWire(userdata, nil, result)
}()
- return result
+ response := <-result
+ if response.Err != nil {
+ log.Debug().Err(response.Err).Msg("Error during resolve")
+ return DirectPlcField{}, response.Err
+ }
+ handle := response.Response.GetValue(response.Response.GetFieldNames()[0]).GetUint32()
+ directPlcField := DirectPlcField{
+ IndexGroup: uint32(readWriteModel.ReservedIndexGroups_ADSIGRP_SYM_VALBYHND),
+ IndexOffset: handle,
+ PlcField: symbolicField.PlcField,
+ }
+ m.fieldMapping[symbolicField] = directPlcField
+ return directPlcField, nil
}
func (m *Reader) ToPlc4xReadResponse(amsTcpPaket readWriteModel.AmsTCPPacket, readRequest model.PlcReadRequest) (model.PlcReadResponse, error) {
@@ -185,7 +263,7 @@ func (m *Reader) ToPlc4xReadResponse(amsTcpPaket readWriteModel.AmsTCPPacket, re
// Get the field from the request
log.Trace().Msg("get a field from request")
fieldName := readRequest.GetFieldNames()[0]
- field, err := CastToAdsFieldFromPlcField(readRequest.GetField(fieldName))
+ field, err := castToDirectAdsFieldFromPlcField(readRequest.GetField(fieldName))
if err != nil {
return nil, errors.Wrap(err, "error casting to ads-field")
}
diff --git a/plc4go/internal/plc4go/ads/Writer.go b/plc4go/internal/plc4go/ads/Writer.go
index 253d91c..3525e7b 100644
--- a/plc4go/internal/plc4go/ads/Writer.go
+++ b/plc4go/internal/plc4go/ads/Writer.go
@@ -67,7 +67,7 @@ func (m Writer) Write(writeRequest model.PlcWriteRequest) <-chan model.PlcWriteR
// Get the ads field instance from the request
field := writeRequest.GetField(fieldName)
- adsField, err := CastToAdsFieldFromPlcField(field)
+ adsField, err := castToDirectAdsFieldFromPlcField(field)
if err != nil {
result <- model.PlcWriteRequestResult{
Request: writeRequest,