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 2022/07/27 15:41:07 UTC

[plc4x] branch develop updated: fix(cbus): fixed several smaller issues

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 6dfa26e7e fix(cbus): fixed several smaller issues
6dfa26e7e is described below

commit 6dfa26e7e1f4bc544bc399cc2e3176574d5f02fa
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Wed Jul 27 17:40:59 2022 +0200

    fix(cbus): fixed several smaller issues
    
    - Extended the plc-simulator for new requests
    - fixed some issues decoding in plc4go
---
 plc4go/internal/cbus/Driver.go                     |  6 +-
 plc4go/internal/cbus/FieldHandler.go               |  3 +-
 plc4go/internal/cbus/MessageCodec.go               | 13 ++-
 plc4go/internal/cbus/Reader.go                     |  6 +-
 .../tests/drivers/tests/manual_cbus_driver_test.go |  9 ++-
 .../server/cbus/protocol/CBusServerAdapter.java    | 92 +++++++++++++++++++++-
 6 files changed, 113 insertions(+), 16 deletions(-)

diff --git a/plc4go/internal/cbus/Driver.go b/plc4go/internal/cbus/Driver.go
index 00ded8e73..c86d53800 100644
--- a/plc4go/internal/cbus/Driver.go
+++ b/plc4go/internal/cbus/Driver.go
@@ -72,9 +72,6 @@ func (m *Driver) GetConnection(transportUrl url.URL, transports map[string]trans
 		return ch
 	}
 
-	codec := NewMessageCodec(transportInstance)
-	log.Debug().Msgf("working with codec %#v", codec)
-
 	configuration, err := ParseFromOptions(options)
 	if err != nil {
 		log.Error().Err(err).Msgf("Invalid options")
@@ -85,6 +82,9 @@ func (m *Driver) GetConnection(transportUrl url.URL, transports map[string]trans
 		return ch
 	}
 
+	codec := NewMessageCodec(transportInstance, configuration.srchk)
+	log.Debug().Msgf("working with codec %#v", codec)
+
 	driverContext, err := NewDriverContext(configuration)
 	if err != nil {
 		log.Error().Err(err).Msgf("Invalid options")
diff --git a/plc4go/internal/cbus/FieldHandler.go b/plc4go/internal/cbus/FieldHandler.go
index d4192fe78..f210d4afd 100644
--- a/plc4go/internal/cbus/FieldHandler.go
+++ b/plc4go/internal/cbus/FieldHandler.go
@@ -66,7 +66,8 @@ func (m FieldHandler) ParseQuery(query string) (model.PlcField, error) {
 				statusRequestType = StatusRequestTypeBinaryState
 			} else if levelArgument := match["startingGroupAddressLabel"]; levelArgument != "" {
 				statusRequestType = StatusRequestTypeLevel
-				decodedHex, _ := hex.DecodeString(match["level"])
+				startingGroupAddressLabelArgument := match["startingGroupAddressLabel"]
+				decodedHex, _ := hex.DecodeString(startingGroupAddressLabelArgument)
 				if len(decodedHex) != 1 {
 					panic("invalid state. Should have exactly 1")
 				}
diff --git a/plc4go/internal/cbus/MessageCodec.go b/plc4go/internal/cbus/MessageCodec.go
index 895d451b0..1a2bb0306 100644
--- a/plc4go/internal/cbus/MessageCodec.go
+++ b/plc4go/internal/cbus/MessageCodec.go
@@ -39,10 +39,10 @@ type MessageCodec struct {
 	hashEncountered uint
 }
 
-func NewMessageCodec(transportInstance transports.TransportInstance) *MessageCodec {
+func NewMessageCodec(transportInstance transports.TransportInstance, srchk bool) *MessageCodec {
 	codec := &MessageCodec{
 		requestContext: readwriteModel.NewRequestContext(false, false, false),
-		cbusOptions:    readwriteModel.NewCBusOptions(false, false, false, false, false, false, false, false, false),
+		cbusOptions:    readwriteModel.NewCBusOptions(false, false, false, false, false, false, false, false, srchk),
 	}
 	codec.DefaultCodec = _default.NewDefaultCodec(codec, transportInstance)
 	return codec
@@ -132,17 +132,22 @@ lookingForTheEnd:
 			m.lastPackageHash, m.hashEncountered = 0, 0
 		}
 	}
-	if !pciResponse || !requestToPci {
+	if !pciResponse && !requestToPci {
 		// Apparently we have not found any message yet
 		return nil, nil
 	}
 
+	packetLength := indexOfCR + 1
+	if pciResponse {
+		packetLength = indexOfLF + 1
+	}
+
 	// Sanity check
 	if pciResponse && requestToPci {
 		panic("Invalid state... Can not be response and request at the same time")
 	}
 
-	read, err := ti.Read(uint32(indexOfCR + 1))
+	read, err := ti.Read(uint32(packetLength))
 	if err != nil {
 		panic("Invalid state... If we have peeked that before we should be able to read that now")
 	}
diff --git a/plc4go/internal/cbus/Reader.go b/plc4go/internal/cbus/Reader.go
index c590127bb..6eaa35c20 100644
--- a/plc4go/internal/cbus/Reader.go
+++ b/plc4go/internal/cbus/Reader.go
@@ -141,7 +141,7 @@ func (m *Reader) Read(readRequest model.PlcReadRequest) <-chan model.PlcReadRequ
 						// TODO: it could be double confirmed but this is not implemented yet
 						embeddedReply := confirmation.GetEmbeddedReply().(readWriteModel.ReplyOrConfirmationReplyExactly)
 
-						switch reply := embeddedReply.(readWriteModel.ReplyEncodedReply).GetEncodedReply().(type) {
+						switch reply := embeddedReply.GetReply().(readWriteModel.ReplyEncodedReply).GetEncodedReply().(type) {
 						case readWriteModel.EncodedReplyStandardFormatStatusReplyExactly:
 							application := reply.GetReply().GetApplication()
 							// TODO: verify application... this should be the same
@@ -173,17 +173,21 @@ func (m *Reader) Read(readRequest model.PlcReadRequest) <-chan model.PlcReadRequ
 							// TODO: how should we serialize that???
 							addPlcValue(fieldNameCopy, values2.NewPlcSTRING(fmt.Sprintf("%s", calData)))
 						}
+						requestWasOk <- true
 						return transaction.EndRequest()
 					},
 					func(err error) error {
 						log.Debug().Msgf("Error waiting for field %s", fieldNameCopy)
 						addResponseCode(fieldNameCopy, model.PlcResponseCode_REQUEST_TIMEOUT)
+						// TODO: ok or not ok?
+						requestWasOk <- true
 						return transaction.EndRequest()
 					},
 					time.Second*1); err != nil {
 					log.Debug().Err(err).Msgf("Error sending message for field %s", fieldNameCopy)
 					addResponseCode(fieldNameCopy, model.PlcResponseCode_INTERNAL_ERROR)
 					_ = transaction.EndRequest()
+					requestWasOk <- false
 				}
 			})
 			if !<-requestWasOk {
diff --git a/plc4go/tests/drivers/tests/manual_cbus_driver_test.go b/plc4go/tests/drivers/tests/manual_cbus_driver_test.go
index ce907fad2..43fa084a3 100644
--- a/plc4go/tests/drivers/tests/manual_cbus_driver_test.go
+++ b/plc4go/tests/drivers/tests/manual_cbus_driver_test.go
@@ -31,17 +31,18 @@ import (
 func TestManualCBusDriver(t *testing.T) {
 	t.Skip()
 
-	connectionString := "c-bus://192.168.178.101"
+	connectionString := "c-bus://192.168.178.101?srchk=true"
 	driverManager := plc4go.NewPlcDriverManager()
 	driverManager.RegisterDriver(cbus.NewDriver())
 	transports.RegisterTcpTransport(driverManager)
 	test := testutils.NewManualTestSuite(connectionString, driverManager, t)
 
 	test.AddTestCase("status/binary/0x04", true)
+	// TODO: apparently a level means that we get a extended status reply but at the moment it is guarded by exstat
 	test.AddTestCase("status/level=0x40/0x04", true)
-	test.AddTestCase("cal/0/recall=[INTERFACE_OPTIONS_1, 1]", true)
-	test.AddTestCase("cal/0/identify=[FirmwareVersion]", true)
-	test.AddTestCase("cal/0/gestatus=[0xFF, 1]", true)
+	//test.AddTestCase("cal/0/recall=[INTERFACE_OPTIONS_1, 1]", true)
+	//test.AddTestCase("cal/0/identify=[FirmwareVersion]", true)
+	//test.AddTestCase("cal/0/gestatus=[0xFF, 1]", true)
 
 	test.Run()
 }
diff --git a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/cbus/protocol/CBusServerAdapter.java b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/cbus/protocol/CBusServerAdapter.java
index 87c73d19f..74f98ad01 100644
--- a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/cbus/protocol/CBusServerAdapter.java
+++ b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/cbus/protocol/CBusServerAdapter.java
@@ -25,6 +25,8 @@ import org.apache.plc4x.simulator.model.Context;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.List;
+
 public class CBusServerAdapter extends ChannelInboundHandlerAdapter {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(CBusServerAdapter.class);
@@ -32,7 +34,7 @@ public class CBusServerAdapter extends ChannelInboundHandlerAdapter {
     private Context context;
 
     private static final RequestContext requestContext = new RequestContext(false, false, false);
-    private static final CBusOptions cBusOptions = new CBusOptions(false, false, false, false, false, false, false, false, false);
+    private static final CBusOptions cBusOptions = new CBusOptions(false, false, false, false, false, false, false, false, true);
 
     public CBusServerAdapter(Context context) {
         this.context = context;
@@ -56,31 +58,115 @@ public class CBusServerAdapter extends ChannelInboundHandlerAdapter {
         }
         if (request instanceof RequestDirectCommandAccess) {
             RequestDirectCommandAccess requestDirectCommandAccess = (RequestDirectCommandAccess) request;
+            LOGGER.info("Handling RequestDirectCommandAccess\n{}", requestDirectCommandAccess);
             // TODO: handle this
             return;
         }
         if (request instanceof RequestCommand) {
             RequestCommand requestCommand = (RequestCommand) request;
-            // TODO: handle this
+            LOGGER.info("Handling RequestCommand\n{}", requestCommand);
+            CBusCommand cbusCommand = requestCommand.getCbusCommand();
+            LOGGER.info("Handling CBusCommand\n{}", cbusCommand);
+            if (cbusCommand instanceof CBusCommandPointToPoint) {
+                // TODO: handle this
+                return;
+            }
+            if (cbusCommand instanceof CBusCommandPointToMultiPoint) {
+                CBusCommandPointToMultiPoint cBusCommandPointToMultiPoint = (CBusCommandPointToMultiPoint) cbusCommand;
+                CBusPointToMultiPointCommand command = cBusCommandPointToMultiPoint.getCommand();
+                if (command instanceof CBusPointToMultiPointCommandStatus) {
+                    CBusPointToMultiPointCommandStatus cBusPointToMultiPointCommandStatus = (CBusPointToMultiPointCommandStatus) command;
+                    StatusRequest statusRequest = cBusPointToMultiPointCommandStatus.getStatusRequest();
+                    if (statusRequest instanceof StatusRequestBinaryState) {
+                        StatusRequestBinaryState statusRequestBinaryState = (StatusRequestBinaryState) statusRequest;
+                        StatusHeader statusHeader = new StatusHeader((short) (2 + 1)); // 2 we have always + 1 as we got one status byte
+                        // TODO: map actuall values from simulator
+                        byte blockStart = 0x0;
+                        List<StatusByte> statusBytes = List.of(new StatusByte(GAVState.ON, GAVState.ERROR, GAVState.OFF, GAVState.DOES_NOT_EXIST));
+                        // TODO: this might be extended or standard depeding on exstat
+                        StandardFormatStatusReply standardFormatStatusReply = new StandardFormatStatusReply(statusHeader, statusRequestBinaryState.getApplication(), blockStart, statusBytes);
+                        EncodedReply encodedReply = new EncodedReplyStandardFormatStatusReply((byte) 0xC0, standardFormatStatusReply, cBusOptions, requestContext);
+                        ReplyEncodedReply replyEncodedReply = new ReplyEncodedReply((byte) 0xC0, encodedReply, null, cBusOptions, requestContext);
+                        ReplyOrConfirmation replyOrConfirmation = new ReplyOrConfirmationReply((byte) 0xFF, replyEncodedReply, new ResponseTermination(), cBusOptions, requestContext);
+                        Alpha alpha = requestCommand.getAlpha();
+                        if (alpha != null) {
+                            Confirmation confirmation = new Confirmation(alpha, null, ConfirmationType.CONFIRMATION_SUCCESSFUL);
+                            replyOrConfirmation = new ReplyOrConfirmationConfirmation(alpha.getCharacter(), confirmation, replyOrConfirmation, cBusOptions, requestContext);
+                        }
+                        CBusMessage response = new CBusMessageToClient(replyOrConfirmation, requestContext, cBusOptions);
+                        LOGGER.info("Send binary status response\n{}", response);
+                        ctx.writeAndFlush(response);
+                        return;
+                    }
+                    if (statusRequest instanceof StatusRequestBinaryStateDeprecated) {
+                        // TODO: handle this
+                        return;
+                    }
+                    if (statusRequest instanceof StatusRequestLevel) {
+                        StatusRequestLevel statusRequestLevel = (StatusRequestLevel) statusRequest;
+                        ExtendedStatusHeader statusHeader = new ExtendedStatusHeader((short) (3 + 1)); // 2 we have always + 1 as we got one status byte
+                        StatusCoding coding = StatusCoding.LEVEL_BY_THIS_SERIAL_INTERFACE;
+                        // TODO: map actuall values from simulator
+                        byte blockStart = statusRequestLevel.getStartingGroupAddressLabel();
+                        List<StatusByte> statusBytes = List.of(new StatusByte(GAVState.ON, GAVState.ERROR, GAVState.OFF, GAVState.DOES_NOT_EXIST));
+                        ExtendedFormatStatusReply extendedFormatStatusReply = new ExtendedFormatStatusReply(statusHeader, coding, statusRequestLevel.getApplication(), blockStart, statusBytes);
+                        EncodedReply encodedReply = new EncodedReplyExtendedFormatStatusReply((byte) 0xC0, extendedFormatStatusReply, cBusOptions, requestContext);
+                        ReplyEncodedReply replyEncodedReply = new ReplyEncodedReply((byte) 0xC0, encodedReply, null, cBusOptions, requestContext);
+                        ReplyOrConfirmation replyOrConfirmation = new ReplyOrConfirmationReply((byte) 0xFF, replyEncodedReply, new ResponseTermination(), cBusOptions, requestContext);
+                        Alpha alpha = requestCommand.getAlpha();
+                        if (alpha != null) {
+                            Confirmation confirmation = new Confirmation(alpha, null, ConfirmationType.CONFIRMATION_SUCCESSFUL);
+                            replyOrConfirmation = new ReplyOrConfirmationConfirmation(alpha.getCharacter(), confirmation, replyOrConfirmation, cBusOptions, requestContext);
+                        }
+                        CBusMessage response = new CBusMessageToClient(replyOrConfirmation, requestContext, cBusOptions);
+                        LOGGER.info("Send level status response\n{}", response);
+                        ctx.writeAndFlush(response);
+                        return;
+                    }
+                    // TODO: handle this
+                    return;
+                }
+                if (command instanceof Normal) {
+                    // TODO: handle this
+                    return;
+                }
+                // TODO: handle this
+                return;
+            }
+            if (cbusCommand instanceof CBusCommandPointToPointToMultiPoint) {
+                // TODO: handle this
+                return;
+            }
+            if (cbusCommand instanceof CBusCommandDeviceManagement) {
+                // TODO: handle this
+                return;
+            }
+
             Alpha alpha = requestCommand.getAlpha();
             if (alpha != null) {
-                Confirmation confirmation = new Confirmation(alpha, null, ConfirmationType.CONFIRMATION_SUCCESSFUL);
+                Confirmation confirmation = new Confirmation(alpha, null, ConfirmationType.NOT_TRANSMITTED_CORRUPTION);
                 ReplyOrConfirmationConfirmation replyOrConfirmationConfirmation = new ReplyOrConfirmationConfirmation(alpha.getCharacter(), confirmation, null, cBusOptions, requestContext);
                 CBusMessage response = new CBusMessageToClient(replyOrConfirmationConfirmation, requestContext, cBusOptions);
+                LOGGER.info("Send response\n{}", response);
                 ctx.writeAndFlush(response);
             }
             return;
         }
         if (request instanceof RequestObsolete) {
             RequestObsolete requestObsolete = (RequestObsolete) request;
+            LOGGER.info("Handling RequestObsolete\n{}", requestObsolete);
             // TODO: handle this
             return;
         }
         if (request instanceof RequestReset) {
+            RequestReset requestReset = (RequestReset) request;
+            LOGGER.info("Handling RequestReset\n{}", requestReset);
             // TODO: handle this
             return;
         }
         if (request instanceof RequestSmartConnectShortcut) {
+            RequestSmartConnectShortcut requestSmartConnectShortcut = (RequestSmartConnectShortcut) request;
+            LOGGER.info("Handling RequestSmartConnectShortcut\n{}", requestSmartConnectShortcut);
             // TODO: handle this
             return;
         }