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/11/12 17:25:37 UTC

[plc4x] branch feature/plc4go updated: - Fixed a bug in the "update change" detection mechanism - Implemented the active read support

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 9365eb8  - Fixed a bug in the "update change" detection mechanism - Implemented the active read support
9365eb8 is described below

commit 9365eb841cda2c0a0d603d2d58b15873a9f9a085
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Thu Nov 12 18:25:28 2020 +0100

    - Fixed a bug in the "update change" detection mechanism
    - Implemented the active read support
---
 plc4go/cmd/main/drivers/knxnetip_test.go           |  2 +-
 .../internal/plc4go/knxnetip/KncNetIpConnection.go | 12 ++-
 plc4go/internal/plc4go/knxnetip/KnxNetIpField.go   | 58 +++++++++++++
 plc4go/internal/plc4go/knxnetip/KnxNetIpReader.go  | 99 ++++++++++++++++++++++
 4 files changed, 166 insertions(+), 5 deletions(-)

diff --git a/plc4go/cmd/main/drivers/knxnetip_test.go b/plc4go/cmd/main/drivers/knxnetip_test.go
index db4c12f..dbf2a4c 100644
--- a/plc4go/cmd/main/drivers/knxnetip_test.go
+++ b/plc4go/cmd/main/drivers/knxnetip_test.go
@@ -109,7 +109,7 @@ func TestKnxNetIpPlc4goDriver(t *testing.T) {
     }
 
     // Wait 2 minutes
-    time.Sleep(120 * time.Second)
+    time.Sleep(1200 * time.Second)
 
     // Do something with the response
     /*value1 := rrr.Response.GetValue("field1")
diff --git a/plc4go/internal/plc4go/knxnetip/KncNetIpConnection.go b/plc4go/internal/plc4go/knxnetip/KncNetIpConnection.go
index 07ad4e5..7e2eb64 100644
--- a/plc4go/internal/plc4go/knxnetip/KncNetIpConnection.go
+++ b/plc4go/internal/plc4go/knxnetip/KncNetIpConnection.go
@@ -41,7 +41,7 @@ type ConnectionMetadata struct {
 }
 
 func (m ConnectionMetadata) CanRead() bool {
-    return false
+    return true
 }
 
 func (m ConnectionMetadata) CanWrite() bool {
@@ -314,7 +314,8 @@ func (m *KnxNetIpConnection) GetMetadata() apiModel.PlcConnectionMetadata {
 }
 
 func (m *KnxNetIpConnection) ReadRequestBuilder() apiModel.PlcReadRequestBuilder {
-    panic("this connection doesn't support reading")
+    return internalModel.NewDefaultPlcReadRequestBuilder(
+        m.fieldHandler, NewKnxNetIpReader(m))
 }
 
 func (m *KnxNetIpConnection) WriteRequestBuilder() apiModel.PlcWriteRequestBuilder {
@@ -371,8 +372,11 @@ func (m *KnxNetIpConnection) handleIncomingTunnelingRequest(tunnelingRequestChan
                 addressData := uint16(cemiDataInd.CemiDataFrame.DestinationAddress[0])<<8 | (uint16(cemiDataInd.CemiDataFrame.DestinationAddress[1]) & 0xFF)
                 val, ok := m.valueCache[addressData]
                 changed := false
-                if !ok || !m.sliceEqual(val, cemiDataInd.CemiDataFrame.Data) {
-                    m.valueCache[addressData] = cemiDataInd.CemiDataFrame.Data
+                var payload []int8
+                payload = append(payload, cemiDataInd.CemiDataFrame.DataFirstByte)
+                payload = append(payload, cemiDataInd.CemiDataFrame.Data...)
+                if !ok || !m.sliceEqual(val, payload) {
+                    m.valueCache[addressData] = payload
                     changed = true
                 }
                 for _, subscriber := range m.subscribers {
diff --git a/plc4go/internal/plc4go/knxnetip/KnxNetIpField.go b/plc4go/internal/plc4go/knxnetip/KnxNetIpField.go
index 5224580..3d9ee16 100644
--- a/plc4go/internal/plc4go/knxnetip/KnxNetIpField.go
+++ b/plc4go/internal/plc4go/knxnetip/KnxNetIpField.go
@@ -29,6 +29,7 @@ import (
 
 type KnxNetIpField interface {
     matches(knxGroupAddress driverModel.KnxGroupAddress) bool
+    toGroupAddress() *driverModel.KnxGroupAddress
     apiModel.PlcField
 }
 
@@ -70,6 +71,30 @@ func (k KnxNetIpGroupAddress3LevelPlcField) matches(knxGroupAddress driverModel.
         matches(k.SubGroup, strconv.Itoa(int(level3KnxGroupAddress.SubGroup)))
 }
 
+func (k KnxNetIpGroupAddress3LevelPlcField) toGroupAddress() *driverModel.KnxGroupAddress {
+    mainGroup, err := strconv.Atoi(k.MainGroup)
+    if err != nil {
+        return nil
+    }
+    midleGroup, err := strconv.Atoi(k.MiddleGroup)
+    if err != nil {
+        return nil
+    }
+    subGroup, err := strconv.Atoi(k.SubGroup)
+    if err != nil {
+        return nil
+    }
+    ga := &driverModel.KnxGroupAddress {}
+    l3 := &driverModel.KnxGroupAddress3Level{
+        MainGroup: uint8(mainGroup),
+        MiddleGroup: uint8(midleGroup),
+        SubGroup: uint8(subGroup),
+        Parent: ga,
+    }
+    ga.Child = l3
+    return ga
+}
+
 type KnxNetIpGroupAddress2LevelPlcField struct {
     FieldType   *model.KnxDatapointType
     // 5 Bits: Values 0-31
@@ -104,6 +129,25 @@ func (k KnxNetIpGroupAddress2LevelPlcField) matches(knxGroupAddress driverModel.
         matches(k.SubGroup, strconv.Itoa(int(level2KnxGroupAddress.SubGroup)))
 }
 
+func (k KnxNetIpGroupAddress2LevelPlcField) toGroupAddress() *driverModel.KnxGroupAddress {
+    mainGroup, err := strconv.Atoi(k.MainGroup)
+    if err != nil {
+        return nil
+    }
+    subGroup, err := strconv.Atoi(k.SubGroup)
+    if err != nil {
+        return nil
+    }
+    ga := &driverModel.KnxGroupAddress {}
+    l3 := &driverModel.KnxGroupAddress2Level{
+        MainGroup: uint8(mainGroup),
+        SubGroup: uint16(subGroup),
+        Parent: ga,
+    }
+    ga.Child = l3
+    return ga
+}
+
 type KnxNetIpGroupAddress1LevelPlcField struct {
     FieldType   *model.KnxDatapointType
     // 16 Bits
@@ -134,6 +178,20 @@ func (k KnxNetIpGroupAddress1LevelPlcField) matches(knxGroupAddress driverModel.
     return matches(k.MainGroup, strconv.Itoa(int(level1KnxGroupAddress.SubGroup)))
 }
 
+func (k KnxNetIpGroupAddress1LevelPlcField) toGroupAddress() *driverModel.KnxGroupAddress {
+    mainGroup, err := strconv.Atoi(k.MainGroup)
+    if err != nil {
+        return nil
+    }
+    ga := &driverModel.KnxGroupAddress {}
+    l3 := &driverModel.KnxGroupAddressFreeLevel{
+        SubGroup: uint16(mainGroup),
+        Parent: ga,
+    }
+    ga.Child = l3
+    return ga
+}
+
 func CastToKnxNetIpFieldFromPlcField(plcField apiModel.PlcField) (KnxNetIpField, error) {
     if knxNetIpField, ok := plcField.(KnxNetIpField); ok {
         return knxNetIpField, nil
diff --git a/plc4go/internal/plc4go/knxnetip/KnxNetIpReader.go b/plc4go/internal/plc4go/knxnetip/KnxNetIpReader.go
new file mode 100644
index 0000000..a5ae873
--- /dev/null
+++ b/plc4go/internal/plc4go/knxnetip/KnxNetIpReader.go
@@ -0,0 +1,99 @@
+//
+// 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 knxnetip
+
+import (
+    driverModel "github.com/apache/plc4x/plc4go/internal/plc4go/knxnetip/readwrite/model"
+    internalModel "github.com/apache/plc4x/plc4go/internal/plc4go/model"
+    "github.com/apache/plc4x/plc4go/internal/plc4go/spi"
+    "github.com/apache/plc4x/plc4go/internal/plc4go/utils"
+    "github.com/apache/plc4x/plc4go/pkg/plc4go/model"
+    "github.com/apache/plc4x/plc4go/pkg/plc4go/values"
+)
+
+type KnxNetIpReader struct {
+    connection *KnxNetIpConnection
+    spi.PlcReader
+}
+
+func NewKnxNetIpReader(connection *KnxNetIpConnection) *KnxNetIpReader {
+    return &KnxNetIpReader{
+        connection: connection,
+    }
+}
+
+func (m KnxNetIpReader) Read(readRequest model.PlcReadRequest) <-chan model.PlcReadRequestResult {
+    resultChan := make(chan model.PlcReadRequestResult)
+    go func() {
+        responseCodes := map[string]model.PlcResponseCode{}
+        plcValues := map[string]values.PlcValue{}
+        for _, fieldName := range readRequest.GetFieldNames() {
+            field, err := CastToKnxNetIpFieldFromPlcField(readRequest.GetField(fieldName))
+            if err != nil {
+                responseCodes[fieldName] = model.PlcResponseCode_INVALID_ADDRESS
+                plcValues[fieldName] = nil
+                continue
+            }
+
+            // Serialize the field to an uint16
+            wb := utils.NewWriteBuffer()
+            err = field.toGroupAddress().Serialize(*wb)
+            if err != nil {
+                responseCodes[fieldName] = model.PlcResponseCode_INVALID_ADDRESS
+                plcValues[fieldName] = nil
+                continue
+            }
+            rawAddress := wb.GetBytes()
+            address := (uint16(rawAddress[0]) << 8) | uint16(rawAddress[1] & 0xFF)
+
+            // Get the value form the cache
+            int8s, ok := m.connection.valueCache[address]
+            if !ok {
+                responseCodes[fieldName] = model.PlcResponseCode_NOT_FOUND
+                plcValues[fieldName] = nil
+                continue
+            }
+
+            // Decode the data according to the fields type
+            rb := utils.NewReadBuffer(utils.Int8ToUint8(int8s))
+            plcValue, err := driverModel.KnxDatapointParse(rb, field.GetTypeName())
+            if err != nil {
+                responseCodes[fieldName] = model.PlcResponseCode_INVALID_DATA
+                plcValues[fieldName] = nil
+                continue
+            }
+
+            // Add it to the result
+            responseCodes[fieldName] = model.PlcResponseCode_OK
+            plcValues[fieldName] = plcValue
+        }
+        result := internalModel.NewDefaultPlcReadResponse(readRequest, responseCodes, plcValues)
+        resultChan <- model.PlcReadRequestResult{
+            Request:  readRequest,
+            Response: result,
+            Err:      nil,
+        }
+    }()
+    return resultChan
+}
+
+
+
+
+