You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2020/10/30 13:42:01 UTC
[plc4x] branch feature/plc4go updated: - Ported the
SingleFieldOptimizer to go (SingleItemRequestItemInterceptor)
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a commit to branch feature/plc4go
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/feature/plc4go by this push:
new a0b7c0d - Ported the SingleFieldOptimizer to go (SingleItemRequestItemInterceptor)
a0b7c0d is described below
commit a0b7c0dc131b808fdda03c296d3415966ee18060
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Fri Oct 30 14:41:53 2020 +0100
- Ported the SingleFieldOptimizer to go (SingleItemRequestItemInterceptor)
---
.../java/spi/optimizer/SingleFieldOptimizer.java | 2 +-
.../main/resources/protocols/modbus/modbus.mspec | 2 +-
sandbox/plc4go/cmd/main/drivers/modbus_test.go | 47 +++---
.../internal/plc4go/modbus/ModbusConnection.go | 55 ++++---
.../plc4go/internal/plc4go/modbus/ModbusDriver.go | 110 +++++++------
.../plc4go/internal/plc4go/modbus/ModbusReader.go | 2 +
.../plc4go/internal/plc4go/modbus/ModbusWriter.go | 8 +-
.../modbus/readwrite/model/ModbusPDUError.go | 179 ++++++++++-----------
.../internal/plc4go/model/DefaultPlcReadRequest.go | 88 ++++++++--
.../plc4go/model/DefaultPlcWriteRequest.go | 4 +-
.../RequestInterceptor.go} | 18 ++-
.../interceptors/SingleItemRequestInterceptor.go | 85 ++++++++++
.../plc4go/pkg/plc4go/model/plc_write_response.go | 2 +-
13 files changed, 375 insertions(+), 227 deletions(-)
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/optimizer/SingleFieldOptimizer.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/optimizer/SingleFieldOptimizer.java
index a1fc1fa..5038479 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/optimizer/SingleFieldOptimizer.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/optimizer/SingleFieldOptimizer.java
@@ -62,7 +62,7 @@ public class SingleFieldOptimizer extends BaseOptimizer {
List<PlcRequest> subRequests = new ArrayList<>(writeRequest.getNumberOfFields());
for (String fieldName : writeRequest.getFieldNames()) {
PlcField field = writeRequest.getField(fieldName);
- PlcValue value = ((DefaultPlcWriteRequest) writeRequest).getPlcValue(fieldName);
+ PlcValue value = writeRequest.getPlcValue(fieldName);
PlcWriteRequest subRequest = new DefaultPlcWriteRequest(
((DefaultPlcWriteRequest) writeRequest).getWriter(),
new LinkedHashMap<>(Collections.singletonMap(fieldName, new FieldValueItem(field, value))));
diff --git a/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec b/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
index 412bd2b..6b28d84 100644
--- a/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
+++ b/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
@@ -60,7 +60,7 @@
[discriminator uint 7 'functionFlag']
[typeSwitch 'errorFlag','functionFlag','response'
['true' ModbusPDUError
- [simple uint 8 'exceptionCode']
+ [enum ModbusErrorCode 'exceptionCode']
]
// Bit Access
diff --git a/sandbox/plc4go/cmd/main/drivers/modbus_test.go b/sandbox/plc4go/cmd/main/drivers/modbus_test.go
index 905b4b6..4eae9d0 100644
--- a/sandbox/plc4go/cmd/main/drivers/modbus_test.go
+++ b/sandbox/plc4go/cmd/main/drivers/modbus_test.go
@@ -19,18 +19,18 @@
package drivers
import (
- "encoding/hex"
- "encoding/xml"
- "fmt"
- "net"
- "os"
- "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/modbus"
- "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/modbus/readwrite/model"
- "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/transports/tcp"
- "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/utils"
- "plc4x.apache.org/plc4go-modbus-driver/v0/pkg/plc4go"
- "strings"
- "testing"
+ "encoding/hex"
+ "encoding/xml"
+ "fmt"
+ "net"
+ "os"
+ "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/modbus"
+ "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/modbus/readwrite/model"
+ "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/transports/tcp"
+ "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/utils"
+ "plc4x.apache.org/plc4go-modbus-driver/v0/pkg/plc4go"
+ "strings"
+ "testing"
)
func TestModbus(t *testing.T) {
@@ -55,14 +55,14 @@ func test(t *testing.T, rawMessage string, response bool) {
t.Errorf("Error parsing: %s", err)
}
if adu != nil {
- serialized, err := xml.Marshal(adu)
- if err != nil {
- fmt.Println("Hurz!" + err.Error())
- return
- }
- fmt.Println(string(serialized))
- var deserializedAdu *model.ModbusTcpADU
- xml.Unmarshal(serialized, &deserializedAdu)
+ serialized, err := xml.Marshal(adu)
+ if err != nil {
+ fmt.Println("Hurz!" + err.Error())
+ return
+ }
+ fmt.Println(string(serialized))
+ var deserializedAdu *model.ModbusTcpADU
+ xml.Unmarshal(serialized, &deserializedAdu)
wb := utils.WriteBufferNew()
val := model.CastIModbusTcpADU(deserializedAdu)
@@ -151,7 +151,8 @@ func TestPlc4goDriver(t *testing.T) {
// Prepare a read-request
rrb := connection.ReadRequestBuilder()
- rrb.AddItem("field", "holding-register:0:REAL")
+ rrb.AddItem("field1", "holding-register:1:REAL")
+ rrb.AddItem("field2", "holding-register:3:REAL")
readRequest, err := rrb.Build()
if err != nil {
t.Errorf("error preparing read-request: %s", connectionResult.Err.Error())
@@ -169,7 +170,7 @@ func TestPlc4goDriver(t *testing.T) {
}
// Do something with the response
- value := rrr.Response.GetValue("field")
+ value := rrr.Response.GetValue("field")
- fmt.Printf("\n\nResult: %f\n", value.GetFloat32())
+ fmt.Printf("\n\nResult: %f\n", value)
}
diff --git a/sandbox/plc4go/internal/plc4go/modbus/ModbusConnection.go b/sandbox/plc4go/internal/plc4go/modbus/ModbusConnection.go
index 90c474c..607f4f3 100644
--- a/sandbox/plc4go/internal/plc4go/modbus/ModbusConnection.go
+++ b/sandbox/plc4go/internal/plc4go/modbus/ModbusConnection.go
@@ -19,11 +19,12 @@
package modbus
import (
- internalModel "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/model"
- "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/spi"
- "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/transports"
- "plc4x.apache.org/plc4go-modbus-driver/v0/pkg/plc4go"
- "plc4x.apache.org/plc4go-modbus-driver/v0/pkg/plc4go/model"
+ internalModel "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/model"
+ "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/spi"
+ "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/spi/interceptors"
+ "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/transports"
+ "plc4x.apache.org/plc4go-modbus-driver/v0/pkg/plc4go"
+ "plc4x.apache.org/plc4go-modbus-driver/v0/pkg/plc4go/model"
)
type ConnectionMetadata struct {
@@ -43,29 +44,31 @@ func (m ConnectionMetadata) CanSubscribe() bool {
}
type ModbusConnection struct {
- transactionIdentifier uint16
- messageCodec spi.MessageCodec
- options map[string][]string
- fieldHandler spi.PlcFieldHandler
- valueHandler spi.PlcValueHandler
+ transactionIdentifier uint16
+ messageCodec spi.MessageCodec
+ options map[string][]string
+ fieldHandler spi.PlcFieldHandler
+ valueHandler spi.PlcValueHandler
+ requestInterceptor internalModel.RequestInterceptor
plc4go.PlcConnection
}
-func NewModbusConnection(transactionIdentifier uint16, messageCodec spi.MessageCodec, options map[string][]string, fieldHandler spi.PlcFieldHandler, valueHandler spi.PlcValueHandler) ModbusConnection {
+func NewModbusConnection(transactionIdentifier uint16, messageCodec spi.MessageCodec, options map[string][]string, fieldHandler spi.PlcFieldHandler) ModbusConnection {
return ModbusConnection{
- transactionIdentifier: transactionIdentifier,
- messageCodec: messageCodec,
- options: options,
- fieldHandler: fieldHandler,
- valueHandler: valueHandler,
+ transactionIdentifier: transactionIdentifier,
+ messageCodec: messageCodec,
+ options: options,
+ fieldHandler: fieldHandler,
+ valueHandler: NewValueHandler(),
+ requestInterceptor: interceptors.NewSingleItemRequestInterceptor(),
}
}
func (m ModbusConnection) Connect() <-chan plc4go.PlcConnectionConnectResult {
ch := make(chan plc4go.PlcConnectionConnectResult)
go func() {
- err := m.messageCodec.Connect()
- ch <- plc4go.NewPlcConnectionConnectResult(m, err)
+ err := m.messageCodec.Connect()
+ ch <- plc4go.NewPlcConnectionConnectResult(m, err)
}()
return ch
}
@@ -92,12 +95,13 @@ func (m ModbusConnection) GetMetadata() model.PlcConnectionMetadata {
}
func (m ModbusConnection) ReadRequestBuilder() model.PlcReadRequestBuilder {
- return internalModel.NewDefaultPlcReadRequestBuilder(m.fieldHandler,
- NewModbusReader(m.transactionIdentifier, m.messageCodec))
+ return internalModel.NewDefaultPlcReadRequestBuilderWithInterceptor(m.fieldHandler,
+ NewModbusReader(m.transactionIdentifier, m.messageCodec), m.requestInterceptor)
}
func (m ModbusConnection) WriteRequestBuilder() model.PlcWriteRequestBuilder {
- return internalModel.NewDefaultPlcWriteRequestBuilder(m.fieldHandler, m.valueHandler, NewModbusWriter())
+ return internalModel.NewDefaultPlcWriteRequestBuilder(
+ m.fieldHandler, m.valueHandler, NewModbusWriter(m.requestInterceptor))
}
func (m ModbusConnection) SubscriptionRequestBuilder() model.PlcSubscriptionRequestBuilder {
@@ -109,9 +113,8 @@ func (m ModbusConnection) UnsubscriptionRequestBuilder() model.PlcUnsubscription
}
func (m ModbusConnection) GetTransportInstance() transports.TransportInstance {
- if mc, ok := m.messageCodec.(spi.TransportInstanceExposer); ok {
- return mc.GetTransportInstance()
- }
- return nil
+ if mc, ok := m.messageCodec.(spi.TransportInstanceExposer); ok {
+ return mc.GetTransportInstance()
+ }
+ return nil
}
-
diff --git a/sandbox/plc4go/internal/plc4go/modbus/ModbusDriver.go b/sandbox/plc4go/internal/plc4go/modbus/ModbusDriver.go
index bb68052..529ae30 100644
--- a/sandbox/plc4go/internal/plc4go/modbus/ModbusDriver.go
+++ b/sandbox/plc4go/internal/plc4go/modbus/ModbusDriver.go
@@ -19,30 +19,28 @@
package modbus
import (
- "encoding/json"
- "errors"
- "fmt"
- "math"
- "net/url"
- "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/modbus/readwrite/model"
- "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/spi"
- "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/transports"
- "plc4x.apache.org/plc4go-modbus-driver/v0/pkg/plc4go"
- "sync/atomic"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "math"
+ "net/url"
+ "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/modbus/readwrite/model"
+ "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/spi"
+ "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/transports"
+ "plc4x.apache.org/plc4go-modbus-driver/v0/pkg/plc4go"
+ "sync/atomic"
)
type ModbusDriver struct {
- transactionIdCounter int32
- fieldHandler spi.PlcFieldHandler
- valueHandler spi.PlcValueHandler
+ transactionIdCounter int32
+ fieldHandler spi.PlcFieldHandler
plc4go.PlcDriver
}
func NewModbusDriver() *ModbusDriver {
return &ModbusDriver{
- transactionIdCounter: 0,
- fieldHandler: NewFieldHandler(),
- valueHandler: NewValueHandler(),
+ transactionIdCounter: 0,
+ fieldHandler: NewFieldHandler(),
}
}
@@ -55,7 +53,7 @@ func (m ModbusDriver) GetProtocolName() string {
}
func (m ModbusDriver) GetDefaultTransport() string {
- return "tcp"
+ return "tcp"
}
func (m ModbusDriver) CheckQuery(query string) error {
@@ -64,46 +62,46 @@ func (m ModbusDriver) CheckQuery(query string) error {
}
func (m ModbusDriver) GetConnection(transportUrl url.URL, transports map[string]transports.Transport, options map[string][]string) <-chan plc4go.PlcConnectionConnectResult {
- // Get an the transport specified in the url
- transport, ok := transports[transportUrl.Scheme]
- if !ok {
- ch := make(chan plc4go.PlcConnectionConnectResult)
- ch <- plc4go.NewPlcConnectionConnectResult(nil, errors.New("couldn't find transport for given transport url " + transportUrl.String()))
- return ch
- }
- // Provide a default-port to the transport, which is used, if the user doesn't provide on in the connection string.
- options["defaultTcpPort"] = []string{"502"}
- // Have the transport create a new transport-instance.
- transportInstance, err := transport.CreateTransportInstance(transportUrl, options)
- if err != nil {
- ch := make(chan plc4go.PlcConnectionConnectResult)
- ch <- plc4go.NewPlcConnectionConnectResult(nil, errors.New("couldn't initialize transport configuration for given transport url " + transportUrl.String()))
- return ch
- }
- // Generate a new transaction id
- transactionId := atomic.AddInt32(&m.transactionIdCounter, 1)
- if transactionId > math.MaxUint16 {
- transactionId = 1
- atomic.StoreInt32(&m.transactionIdCounter, 1)
- }
+ // Get an the transport specified in the url
+ transport, ok := transports[transportUrl.Scheme]
+ if !ok {
+ ch := make(chan plc4go.PlcConnectionConnectResult)
+ ch <- plc4go.NewPlcConnectionConnectResult(nil, errors.New("couldn't find transport for given transport url "+transportUrl.String()))
+ return ch
+ }
+ // Provide a default-port to the transport, which is used, if the user doesn't provide on in the connection string.
+ options["defaultTcpPort"] = []string{"502"}
+ // Have the transport create a new transport-instance.
+ transportInstance, err := transport.CreateTransportInstance(transportUrl, options)
+ if err != nil {
+ ch := make(chan plc4go.PlcConnectionConnectResult)
+ ch <- plc4go.NewPlcConnectionConnectResult(nil, errors.New("couldn't initialize transport configuration for given transport url "+transportUrl.String()))
+ return ch
+ }
+ // Generate a new transaction id
+ transactionId := atomic.AddInt32(&m.transactionIdCounter, 1)
+ if transactionId > math.MaxUint16 {
+ transactionId = 1
+ atomic.StoreInt32(&m.transactionIdCounter, 1)
+ }
- // Create a new codec for taking care of encoding/decoding of messages
- defaultChanel := make(chan interface{})
- go func() {
- for {
- msg := <-defaultChanel
- adu := model.CastModbusTcpADU(msg)
- serialized, err := json.Marshal(adu)
- if err != nil {
- fmt.Errorf("got error serializing adu: %s\n", err.Error())
- } else {
- fmt.Printf("got message in the default handler %s\n", serialized)
- }
- }
- }()
- codec := NewModbusMessageCodec(transportInstance, nil)
+ // Create a new codec for taking care of encoding/decoding of messages
+ defaultChanel := make(chan interface{})
+ go func() {
+ for {
+ msg := <-defaultChanel
+ adu := model.CastModbusTcpADU(msg)
+ serialized, err := json.Marshal(adu)
+ if err != nil {
+ fmt.Errorf("got error serializing adu: %s\n", err.Error())
+ } else {
+ fmt.Printf("got message in the default handler %s\n", serialized)
+ }
+ }
+ }()
+ codec := NewModbusMessageCodec(transportInstance, nil)
- // Create the new connection
- connection := NewModbusConnection(uint16(transactionId), codec, options, m.fieldHandler, m.valueHandler)
+ // Create the new connection
+ connection := NewModbusConnection(uint16(transactionId), codec, options, m.fieldHandler)
return connection.Connect()
}
diff --git a/sandbox/plc4go/internal/plc4go/modbus/ModbusReader.go b/sandbox/plc4go/internal/plc4go/modbus/ModbusReader.go
index fcf3edd..d8ad0a8 100644
--- a/sandbox/plc4go/internal/plc4go/modbus/ModbusReader.go
+++ b/sandbox/plc4go/internal/plc4go/modbus/ModbusReader.go
@@ -180,6 +180,8 @@ func toPlc4xResponse(requestAdu modbusModel.ModbusTcpADU, responseAdu modbusMode
case modbusModel.ModbusPDUReadHoldingRegistersResponse:
pdu := modbusModel.CastModbusPDUReadHoldingRegistersResponse(responseAdu.Pdu)
data = utils.Int8ToUint8(pdu.Value)
+ case modbusModel.ModbusPDUError:
+ return nil, errors.New("got an error from remote")
default:
return nil, errors.New("unsupported response type")
}
diff --git a/sandbox/plc4go/internal/plc4go/modbus/ModbusWriter.go b/sandbox/plc4go/internal/plc4go/modbus/ModbusWriter.go
index 897d5a0..0a6b8f3 100644
--- a/sandbox/plc4go/internal/plc4go/modbus/ModbusWriter.go
+++ b/sandbox/plc4go/internal/plc4go/modbus/ModbusWriter.go
@@ -19,16 +19,20 @@
package modbus
import (
+ model2 "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/model"
"plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/spi"
"plc4x.apache.org/plc4go-modbus-driver/v0/pkg/plc4go/model"
)
type ModbusWriter struct {
+ writeRequestInterceptor model2.WriteRequestInterceptor
spi.PlcWriter
}
-func NewModbusWriter() ModbusWriter {
- return ModbusWriter{}
+func NewModbusWriter(writeRequestInterceptor model2.WriteRequestInterceptor) ModbusWriter {
+ return ModbusWriter{
+ writeRequestInterceptor: writeRequestInterceptor,
+ }
}
func (m ModbusWriter) Write(writeRequest model.PlcWriteRequest) <-chan model.PlcWriteRequestResult {
diff --git a/sandbox/plc4go/internal/plc4go/modbus/readwrite/model/ModbusPDUError.go b/sandbox/plc4go/internal/plc4go/modbus/readwrite/model/ModbusPDUError.go
index b5f4d18..72d1b57 100644
--- a/sandbox/plc4go/internal/plc4go/modbus/readwrite/model/ModbusPDUError.go
+++ b/sandbox/plc4go/internal/plc4go/modbus/readwrite/model/ModbusPDUError.go
@@ -19,145 +19,144 @@
package model
import (
- "encoding/xml"
- "errors"
- "io"
- "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/spi"
- "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/utils"
+ "encoding/xml"
+ "errors"
+ "io"
+ "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/spi"
+ "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/utils"
)
// The data-structure of this message
type ModbusPDUError struct {
- ExceptionCode uint8
- ModbusPDU
+ ExceptionCode IModbusErrorCode
+ ModbusPDU
}
// The corresponding interface
type IModbusPDUError interface {
- IModbusPDU
- Serialize(io utils.WriteBuffer) error
+ IModbusPDU
+ Serialize(io utils.WriteBuffer) error
}
// Accessors for discriminator values.
func (m ModbusPDUError) ErrorFlag() bool {
- return true
+ return true
}
func (m ModbusPDUError) FunctionFlag() uint8 {
- return 0
+ return 0
}
func (m ModbusPDUError) Response() bool {
- return false
+ return false
}
func (m ModbusPDUError) initialize() spi.Message {
- return m
+ return m
}
-func NewModbusPDUError(exceptionCode uint8) ModbusPDUInitializer {
- return &ModbusPDUError{ExceptionCode: exceptionCode}
+func NewModbusPDUError(exceptionCode IModbusErrorCode) ModbusPDUInitializer {
+ return &ModbusPDUError{ExceptionCode: exceptionCode}
}
func CastIModbusPDUError(structType interface{}) IModbusPDUError {
- castFunc := func(typ interface{}) IModbusPDUError {
- if iModbusPDUError, ok := typ.(IModbusPDUError); ok {
- return iModbusPDUError
- }
- return nil
- }
- return castFunc(structType)
+ castFunc := func(typ interface{}) IModbusPDUError {
+ if iModbusPDUError, ok := typ.(IModbusPDUError); ok {
+ return iModbusPDUError
+ }
+ return nil
+ }
+ return castFunc(structType)
}
func CastModbusPDUError(structType interface{}) ModbusPDUError {
- castFunc := func(typ interface{}) ModbusPDUError {
- if sModbusPDUError, ok := typ.(ModbusPDUError); ok {
- return sModbusPDUError
- }
- if sModbusPDUError, ok := typ.(*ModbusPDUError); ok {
- return *sModbusPDUError
- }
- return ModbusPDUError{}
- }
- return castFunc(structType)
+ castFunc := func(typ interface{}) ModbusPDUError {
+ if sModbusPDUError, ok := typ.(ModbusPDUError); ok {
+ return sModbusPDUError
+ }
+ if sModbusPDUError, ok := typ.(*ModbusPDUError); ok {
+ return *sModbusPDUError
+ }
+ return ModbusPDUError{}
+ }
+ return castFunc(structType)
}
func (m ModbusPDUError) LengthInBits() uint16 {
- var lengthInBits uint16 = m.ModbusPDU.LengthInBits()
+ var lengthInBits uint16 = m.ModbusPDU.LengthInBits()
- // Simple field (exceptionCode)
- lengthInBits += 8
+ // Enum Field (exceptionCode)
+ lengthInBits += 8
- return lengthInBits
+ return lengthInBits
}
func (m ModbusPDUError) LengthInBytes() uint16 {
- return m.LengthInBits() / 8
+ return m.LengthInBits() / 8
}
func ModbusPDUErrorParse(io *utils.ReadBuffer) (ModbusPDUInitializer, error) {
- // Simple Field (exceptionCode)
- exceptionCode, _exceptionCodeErr := io.ReadUint8(8)
- if _exceptionCodeErr != nil {
- return nil, errors.New("Error parsing 'exceptionCode' field " + _exceptionCodeErr.Error())
- }
+ // Enum field (exceptionCode)
+ exceptionCode, _exceptionCodeErr := ModbusErrorCodeParse(io)
+ if _exceptionCodeErr != nil {
+ return nil, errors.New("Error parsing 'exceptionCode' field " + _exceptionCodeErr.Error())
+ }
- // Create the instance
- return NewModbusPDUError(exceptionCode), nil
+ // Create the instance
+ return NewModbusPDUError(exceptionCode), nil
}
func (m ModbusPDUError) Serialize(io utils.WriteBuffer) error {
- ser := func() error {
-
- // Simple Field (exceptionCode)
- exceptionCode := uint8(m.ExceptionCode)
- _exceptionCodeErr := io.WriteUint8(8, (exceptionCode))
- if _exceptionCodeErr != nil {
- return errors.New("Error serializing 'exceptionCode' field " + _exceptionCodeErr.Error())
- }
-
- return nil
- }
- return ModbusPDUSerialize(io, m.ModbusPDU, CastIModbusPDU(m), ser)
+ ser := func() error {
+
+ // Enum field (exceptionCode)
+ exceptionCode := CastModbusErrorCode(m.ExceptionCode)
+ _exceptionCodeErr := exceptionCode.Serialize(io)
+ if _exceptionCodeErr != nil {
+ return errors.New("Error serializing 'exceptionCode' field " + _exceptionCodeErr.Error())
+ }
+
+ return nil
+ }
+ return ModbusPDUSerialize(io, m.ModbusPDU, CastIModbusPDU(m), ser)
}
func (m *ModbusPDUError) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
- for {
- token, err := d.Token()
- if err != nil {
- if err == io.EOF {
- return nil
- }
- return err
- }
- switch token.(type) {
- case xml.StartElement:
- tok := token.(xml.StartElement)
- switch tok.Name.Local {
- case "exceptionCode":
- var data uint8
- if err := d.DecodeElement(&data, &tok); err != nil {
- return err
- }
- m.ExceptionCode = data
- }
- }
- }
+ for {
+ token, err := d.Token()
+ if err != nil {
+ if err == io.EOF {
+ return nil
+ }
+ return err
+ }
+ switch token.(type) {
+ case xml.StartElement:
+ tok := token.(xml.StartElement)
+ switch tok.Name.Local {
+ case "exceptionCode":
+ var data *ModbusErrorCode
+ if err := d.DecodeElement(&data, &tok); err != nil {
+ return err
+ }
+ m.ExceptionCode = data
+ }
+ }
+ }
}
func (m ModbusPDUError) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
- if err := e.EncodeToken(xml.StartElement{Name: start.Name, Attr: []xml.Attr{
- {Name: xml.Name{Local: "className"}, Value: "org.apache.plc4x.java.modbus.readwrite.ModbusPDUError"},
- }}); err != nil {
- return err
- }
- if err := e.EncodeElement(m.ExceptionCode, xml.StartElement{Name: xml.Name{Local: "exceptionCode"}}); err != nil {
- return err
- }
- if err := e.EncodeToken(xml.EndElement{Name: start.Name}); err != nil {
- return err
- }
- return nil
+ if err := e.EncodeToken(xml.StartElement{Name: start.Name, Attr: []xml.Attr{
+ {Name: xml.Name{Local: "className"}, Value: "org.apache.plc4x.java.modbus.readwrite.ModbusPDUError"},
+ }}); err != nil {
+ return err
+ }
+ if err := e.EncodeElement(m.ExceptionCode, xml.StartElement{Name: xml.Name{Local: "exceptionCode"}}); err != nil {
+ return err
+ }
+ if err := e.EncodeToken(xml.EndElement{Name: start.Name}); err != nil {
+ return err
+ }
+ return nil
}
-
diff --git a/sandbox/plc4go/internal/plc4go/model/DefaultPlcReadRequest.go b/sandbox/plc4go/internal/plc4go/model/DefaultPlcReadRequest.go
index 5a747be..afbd09f 100644
--- a/sandbox/plc4go/internal/plc4go/model/DefaultPlcReadRequest.go
+++ b/sandbox/plc4go/internal/plc4go/model/DefaultPlcReadRequest.go
@@ -23,20 +23,27 @@ import (
"errors"
"plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/spi"
"plc4x.apache.org/plc4go-modbus-driver/v0/pkg/plc4go/model"
+ "time"
)
type DefaultPlcReadRequestBuilder struct {
- reader spi.PlcReader
- fieldHandler spi.PlcFieldHandler
- queries map[string]string
+ reader spi.PlcReader
+ fieldHandler spi.PlcFieldHandler
+ queries map[string]string
+ readRequestInterceptor ReadRequestInterceptor
model.PlcReadRequestBuilder
}
func NewDefaultPlcReadRequestBuilder(fieldHandler spi.PlcFieldHandler, reader spi.PlcReader) *DefaultPlcReadRequestBuilder {
+ return NewDefaultPlcReadRequestBuilderWithInterceptor(fieldHandler, reader, nil)
+}
+
+func NewDefaultPlcReadRequestBuilderWithInterceptor(fieldHandler spi.PlcFieldHandler, reader spi.PlcReader, readRequestInterceptor ReadRequestInterceptor) *DefaultPlcReadRequestBuilder {
return &DefaultPlcReadRequestBuilder{
- reader: reader,
- fieldHandler: fieldHandler,
- queries: map[string]string{},
+ reader: reader,
+ fieldHandler: fieldHandler,
+ queries: map[string]string{},
+ readRequestInterceptor: readRequestInterceptor,
}
}
@@ -55,31 +62,78 @@ func (m *DefaultPlcReadRequestBuilder) Build() (model.PlcReadRequest, error) {
fields[name] = field
}
return DefaultPlcReadRequest{
- fields: fields,
- reader: m.reader,
+ Fields: fields,
+ Reader: m.reader,
+ ReadRequestInterceptor: m.readRequestInterceptor,
}, nil
}
type DefaultPlcReadRequest struct {
- fields map[string]model.PlcField
- reader spi.PlcReader
+ Fields map[string]model.PlcField
+ Reader spi.PlcReader
+ ReadRequestInterceptor ReadRequestInterceptor
model.PlcReadRequest
}
+func NewDefaultPlcReadRequest(fields map[string]model.PlcField, reader spi.PlcReader, readRequestInterceptor ReadRequestInterceptor) DefaultPlcReadRequest {
+ return DefaultPlcReadRequest{
+ Fields: fields,
+ Reader: reader,
+ ReadRequestInterceptor: readRequestInterceptor,
+ }
+}
+
func (m DefaultPlcReadRequest) Execute() <-chan model.PlcReadRequestResult {
- return m.reader.Read(m)
+ // Shortcut, if no interceptor is defined
+ if m.ReadRequestInterceptor == nil {
+ return m.Reader.Read(m)
+ }
+
+ // Split the requests up into multiple ones.
+ readRequests := m.ReadRequestInterceptor.InterceptReadRequest(m)
+ // Shortcut for single-request-requests
+ if len(readRequests) == 1 {
+ return m.Reader.Read(readRequests[0])
+ } else {
+ // Create a sub-result-channel slice
+ var subResultChannels []<-chan model.PlcReadRequestResult
+
+ // Iterate over all requests and add the result-channels to the list
+ for _, subRequest := range readRequests {
+ subResultChannels = append(subResultChannels, m.Reader.Read(subRequest))
+ // TODO: Replace this with a real queueing of requests.
+ time.Sleep(time.Millisecond * 20)
+ }
+
+ // Create a new result-channel, which completes as soon as all sub-result-channels have returned
+ resultChannel := make(chan model.PlcReadRequestResult)
+ go func() {
+ var subResults []model.PlcReadRequestResult
+ // Iterate over all sub-results
+ for _, subResultChannel := range subResultChannels {
+ subResult := <-subResultChannel
+ subResults = append(subResults, subResult)
+ }
+ // As soon as all are done, process the results
+ result := m.ReadRequestInterceptor.ProcessReadResponses(m, subResults)
+ // Return the final result
+ resultChannel <- result
+ }()
+
+ return resultChannel
+ }
}
func (m DefaultPlcReadRequest) GetFieldNames() []string {
- fieldNames := []string{}
- for name := range m.fields {
+ var fieldNames []string
+ for name := range m.Fields {
fieldNames = append(fieldNames, name)
}
return fieldNames
}
func (m DefaultPlcReadRequest) GetField(name string) model.PlcField {
- if field, ok := m.fields[name]; ok {
+ if field, ok := m.Fields[name]; ok {
return field
}
return nil
@@ -90,10 +144,10 @@ func (m DefaultPlcReadRequest) MarshalXML(e *xml.Encoder, start xml.StartElement
return err
}
- if err := e.EncodeToken(xml.StartElement{Name: xml.Name{Local: "fields"}}); err != nil {
+ if err := e.EncodeToken(xml.StartElement{Name: xml.Name{Local: "Fields"}}); err != nil {
return err
}
- for fieldName, field := range m.fields {
+ for fieldName, field := range m.Fields {
if err := e.EncodeToken(xml.StartElement{Name: xml.Name{Local: fieldName}}); err != nil {
return err
}
@@ -104,7 +158,7 @@ func (m DefaultPlcReadRequest) MarshalXML(e *xml.Encoder, start xml.StartElement
return err
}
}
- if err := e.EncodeToken(xml.EndElement{Name: xml.Name{Local: "fields"}}); err != nil {
+ if err := e.EncodeToken(xml.EndElement{Name: xml.Name{Local: "Fields"}}); err != nil {
return err
}
diff --git a/sandbox/plc4go/internal/plc4go/model/DefaultPlcWriteRequest.go b/sandbox/plc4go/internal/plc4go/model/DefaultPlcWriteRequest.go
index 91e5a63..5c90853 100644
--- a/sandbox/plc4go/internal/plc4go/model/DefaultPlcWriteRequest.go
+++ b/sandbox/plc4go/internal/plc4go/model/DefaultPlcWriteRequest.go
@@ -88,7 +88,7 @@ func (m DefaultPlcWriteRequest) MarshalXML(e *xml.Encoder, start xml.StartElemen
return err
}
- if err := e.EncodeToken(xml.StartElement{Name: xml.Name{Local: "fields"}}); err != nil {
+ if err := e.EncodeToken(xml.StartElement{Name: xml.Name{Local: "Fields"}}); err != nil {
return err
}
for fieldName, field := range m.fields {
@@ -102,7 +102,7 @@ func (m DefaultPlcWriteRequest) MarshalXML(e *xml.Encoder, start xml.StartElemen
return err
}
}
- if err := e.EncodeToken(xml.EndElement{Name: xml.Name{Local: "fields"}}); err != nil {
+ if err := e.EncodeToken(xml.EndElement{Name: xml.Name{Local: "Fields"}}); err != nil {
return err
}
diff --git a/sandbox/plc4go/internal/plc4go/modbus/ModbusWriter.go b/sandbox/plc4go/internal/plc4go/model/RequestInterceptor.go
similarity index 59%
copy from sandbox/plc4go/internal/plc4go/modbus/ModbusWriter.go
copy to sandbox/plc4go/internal/plc4go/model/RequestInterceptor.go
index 897d5a0..614057b 100644
--- a/sandbox/plc4go/internal/plc4go/modbus/ModbusWriter.go
+++ b/sandbox/plc4go/internal/plc4go/model/RequestInterceptor.go
@@ -16,21 +16,23 @@
// specific language governing permissions and limitations
// under the License.
//
-package modbus
+package model
import (
- "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/spi"
"plc4x.apache.org/plc4go-modbus-driver/v0/pkg/plc4go/model"
)
-type ModbusWriter struct {
- spi.PlcWriter
+type ReadRequestInterceptor interface {
+ InterceptReadRequest(readRequest model.PlcReadRequest) []model.PlcReadRequest
+ ProcessReadResponses(readRequest model.PlcReadRequest, readResults []model.PlcReadRequestResult) model.PlcReadRequestResult
}
-func NewModbusWriter() ModbusWriter {
- return ModbusWriter{}
+type WriteRequestInterceptor interface {
+ InterceptWriteRequest(writeRequest model.PlcWriteRequest) []model.PlcWriteRequest
+ ProcessWriteResponses(writeRequest model.PlcWriteRequest, writeResults []model.PlcWriteRequestResult) model.PlcWriteRequestResult
}
-func (m ModbusWriter) Write(writeRequest model.PlcWriteRequest) <-chan model.PlcWriteRequestResult {
- return make(chan model.PlcWriteRequestResult)
+type RequestInterceptor interface {
+ ReadRequestInterceptor
+ WriteRequestInterceptor
}
diff --git a/sandbox/plc4go/internal/plc4go/spi/interceptors/SingleItemRequestInterceptor.go b/sandbox/plc4go/internal/plc4go/spi/interceptors/SingleItemRequestInterceptor.go
new file mode 100644
index 0000000..6027e62
--- /dev/null
+++ b/sandbox/plc4go/internal/plc4go/spi/interceptors/SingleItemRequestInterceptor.go
@@ -0,0 +1,85 @@
+//
+// 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
+//
+// http://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 interceptors
+
+import (
+ "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/model"
+ apiModel "plc4x.apache.org/plc4go-modbus-driver/v0/pkg/plc4go/model"
+ "plc4x.apache.org/plc4go-modbus-driver/v0/pkg/plc4go/values"
+)
+
+type SingleItemRequestInterceptor struct {
+}
+
+func NewSingleItemRequestInterceptor() SingleItemRequestInterceptor {
+ return SingleItemRequestInterceptor{}
+}
+
+func (m SingleItemRequestInterceptor) InterceptReadRequest(readRequest apiModel.PlcReadRequest) []apiModel.PlcReadRequest {
+ // If this request just has one field, go the shortcut
+ if len(readRequest.GetFieldNames()) == 1 {
+ return []apiModel.PlcReadRequest{readRequest}
+ }
+ // In all other cases, create a new read request containing only one item
+ defaultReadRequest := readRequest.(model.DefaultPlcReadRequest)
+ var readRequests []apiModel.PlcReadRequest
+ for _, fieldName := range readRequest.GetFieldNames() {
+ field := readRequest.GetField(fieldName)
+ subReadRequest := model.NewDefaultPlcReadRequest(
+ map[string]apiModel.PlcField{fieldName: field},
+ defaultReadRequest.Reader,
+ defaultReadRequest.ReadRequestInterceptor)
+ readRequests = append(readRequests, subReadRequest)
+ }
+ return readRequests
+}
+
+func (m SingleItemRequestInterceptor) ProcessReadResponses(readRequest apiModel.PlcReadRequest, readResults []apiModel.PlcReadRequestResult) apiModel.PlcReadRequestResult {
+ if len(readResults) == 1 {
+ return readResults[0]
+ }
+
+ responseCodes := map[string]apiModel.PlcResponseCode{}
+ val := map[string]values.PlcValue{}
+ var err error
+ for _, readResult := range readResults {
+ if readResult.Err != nil {
+ // TODO: Handle the case that multiple requests had errors that are different
+ err = readResult.Err
+ } else if readResult.Response != nil {
+ for _, fieldName := range readResult.Response.GetRequest().GetFieldNames() {
+ responseCodes[fieldName] = readResult.Response.GetResponseCode(fieldName)
+ val[fieldName] = readResult.Response.GetValue(fieldName)
+ }
+ }
+ }
+ return apiModel.PlcReadRequestResult{
+ Request: readRequest,
+ Response: model.NewDefaultPlcReadResponse(readRequest, responseCodes, val),
+ Err: err,
+ }
+}
+
+func (m SingleItemRequestInterceptor) InterceptWriteRequest(writeRequest apiModel.PlcWriteRequest) []apiModel.PlcWriteRequest {
+ return []apiModel.PlcWriteRequest{writeRequest}
+}
+
+func (m SingleItemRequestInterceptor) ProcessWriteResponses(writeRequest apiModel.PlcWriteRequest, writeResponses []apiModel.PlcWriteRequestResult) apiModel.PlcWriteRequestResult {
+ return apiModel.PlcWriteRequestResult{}
+}
diff --git a/sandbox/plc4go/pkg/plc4go/model/plc_write_response.go b/sandbox/plc4go/pkg/plc4go/model/plc_write_response.go
index a3c57da..db3abbe 100644
--- a/sandbox/plc4go/pkg/plc4go/model/plc_write_response.go
+++ b/sandbox/plc4go/pkg/plc4go/model/plc_write_response.go
@@ -18,5 +18,5 @@
//
package model
-type PlcWriteResponse struct {
+type PlcWriteResponse interface {
}