Skip to content

Commit

Permalink
feat(plc4go/cbus): progress on field handling
Browse files Browse the repository at this point in the history
  • Loading branch information
sruehl committed Jul 26, 2022
1 parent cf5407f commit 38a8bdf
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 33 deletions.
87 changes: 68 additions & 19 deletions plc4go/internal/cbus/Field.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,47 +22,96 @@ package cbus
import (
"fmt"
"github.com/apache/plc4x/plc4go/internal/spi/utils"
"github.com/apache/plc4x/plc4go/pkg/api/model"
readWriteModel "github.com/apache/plc4x/plc4go/protocols/cbus/readwrite/model"
)

type PlcField interface {
type StatusRequestType uint8

const (
StatusRequestTypeBinaryState StatusRequestType = iota
StatusRequestTypeLevel
)

// StatusField can be used to query status using a P-to-MP-StatusRequest command
type StatusField interface {
model.PlcField
GetStatusRequestType() StatusRequestType
GetApplicationId() readWriteModel.ApplicationId
}

type plcField struct {
NumElements uint16
func NewStatusField(statusRequestType StatusRequestType, level *byte, applicationId readWriteModel.ApplicationId, numElements uint16) StatusField {
return &statusField{
fieldType: STATUS,
statusRequestType: statusRequestType,
applicationId: applicationId,
numElements: numElements,
}
}

func NewField(numElements uint16) PlcField {
return &plcField{
NumElements: numElements,
// CALField can be used to get device/network management fields
type CALField interface {
model.PlcField
}

func NewCALField(numElements uint16) CALField {
return &calField{
fieldType: CAL,
numElements: numElements,
}
}

func (m plcField) GetAddressString() string {
// TODO: implement me
return fmt.Sprintf("TODO[%d]", m.NumElements)
type statusField struct {
fieldType FieldType
statusRequestType StatusRequestType
level *byte
applicationId readWriteModel.ApplicationId
numElements uint16
}

func (m statusField) GetAddressString() string {
return fmt.Sprintf("%d[%d]", m.fieldType, m.numElements)
}

func (m statusField) GetStatusRequestType() StatusRequestType {
return m.statusRequestType
}

func (m statusField) GetApplicationId() readWriteModel.ApplicationId {
return m.applicationId
}

func (m statusField) GetTypeName() string {
return STATUS.GetName()
}

func (m statusField) GetQuantity() uint16 {
return m.numElements
}

type calField struct {
fieldType FieldType
numElements uint16
}

func (m plcField) GetTypeName() string {
return "TODO"
func (m calField) GetAddressString() string {
return fmt.Sprintf("%d[%d]", m.fieldType, m.numElements)
}

func (m plcField) GetApplicationId() readWriteModel.ApplicationId {
//TODO implement me
panic("implement me")
func (m calField) GetTypeName() string {
return CAL.GetName()
}

func (m plcField) GetQuantity() uint16 {
return m.NumElements
func (m calField) GetQuantity() uint16 {
return m.numElements
}

func (m plcField) Serialize(writeBuffer utils.WriteBuffer) error {
if err := writeBuffer.PushContext("TODO"); err != nil {
func (m calField) Serialize(writeBuffer utils.WriteBuffer) error {
if err := writeBuffer.PushContext(m.fieldType.GetName()); err != nil {
return err
}

if err := writeBuffer.PopContext("TODO"); err != nil {
if err := writeBuffer.PopContext(m.fieldType.GetName()); err != nil {
return err
}
return nil
Expand Down
74 changes: 71 additions & 3 deletions plc4go/internal/cbus/FieldHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,96 @@
package cbus

import (
"encoding/hex"
"github.com/apache/plc4x/plc4go/internal/spi/utils"
"github.com/apache/plc4x/plc4go/pkg/api/model"
readWriteModel "github.com/apache/plc4x/plc4go/protocols/cbus/readwrite/model"
"github.com/pkg/errors"
"regexp"
"strconv"
"strings"
)

type FieldType uint8

//go:generate stringer -type FieldType
const (
TODO FieldType = 0x00
STATUS FieldType = iota
CAL
)

func (i FieldType) GetName() string {
return i.String()
}

type FieldHandler struct {
statusRequestPattern *regexp.Regexp
calPattern *regexp.Regexp
}

func NewFieldHandler() FieldHandler {
return FieldHandler{}
return FieldHandler{
statusRequestPattern: regexp.MustCompile(`^status/(?P<statusRequestType>(?P<binary>binary)|level=0x(?P<level>00|20|40|60|80|A0|C0|E0))/(?P<applicationId>.*)`),
calPattern: regexp.MustCompile(`^cal/(?P<calType>recall=\[(?P<recallParamNo>[\w\d]+),(?P<recallCount>\d+)]|identify=\[(?P<identifyAttribute>[\w\d]+)]|getstatus=\[(?P<getstatusParamNo>[\w\d]+),(?P<getstatusCount>\d+)])`),
}
}

func (m FieldHandler) ParseQuery(query string) (model.PlcField, error) {
return nil, errors.Errorf("Unable to parse %s", query)
if match := utils.GetSubgroupMatches(m.statusRequestPattern, query); match != nil {
var level *byte
var statusRequestType StatusRequestType
statusRequestArgument := match["statusRequestType"]
if statusRequestArgument != "" {
if match["binary"] != "" {
statusRequestType = StatusRequestTypeBinaryState
} else if levelArgument := match["level"]; levelArgument != "" {
statusRequestType = StatusRequestTypeLevel
decodedHex, _ := hex.DecodeString(match["level"])
if len(decodedHex) != 1 {
panic("invalid state. Should have exactly 1")
}
level = &decodedHex[0]
} else {
return nil, errors.Errorf("Unknown statusRequestType%s", statusRequestArgument)
}
}
var applicationId readWriteModel.ApplicationId
applicationIdArgument := match["applicationId"]
if strings.HasPrefix(applicationIdArgument, "0x") {
decodedHex, err := hex.DecodeString(applicationIdArgument[2:])
if err != nil {
return nil, errors.Wrap(err, "Not a valid hex")
}
if len(decodedHex) != 1 {
return nil, errors.Errorf("Hex must be exatly one byte")
}
applicationId = readWriteModel.ApplicationId(decodedHex[0])
} else {
atoi, err := strconv.ParseUint(applicationIdArgument, 10, 8)
if err != nil {
applicationId = readWriteModel.ApplicationId(atoi)
} else {
applicationIdByName, ok := readWriteModel.ApplicationIdByName(applicationIdArgument)
if !ok {
return nil, errors.Errorf("Unknown applicationId%s", applicationIdArgument)
}
applicationId = applicationIdByName
}
}
return NewStatusField(statusRequestType, level, applicationId, 1), nil
} else if match := utils.GetSubgroupMatches(m.calPattern, query); match != nil {
calTypeArgument := match["calType"]
switch {
case strings.HasPrefix(calTypeArgument, "recall="):
panic("Implement me ")
case strings.HasPrefix(calTypeArgument, "identify="):
panic("Implement me ")
case strings.HasPrefix(calTypeArgument, "getstatus="):
panic("Implement me ")
default:
return nil, errors.Errorf("Invalid cal type %s", calTypeArgument)
}
} else {
return nil, errors.Errorf("Unable to parse %s", query)
}
}
7 changes: 4 additions & 3 deletions plc4go/internal/cbus/fieldtype_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 44 additions & 0 deletions plc4go/tests/drivers/tests/manual_cbus_driver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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
*
* https://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 tests

import (
"github.com/apache/plc4x/plc4go/internal/cbus"
"github.com/apache/plc4x/plc4go/internal/spi/testutils"
"github.com/apache/plc4x/plc4go/pkg/api"
"github.com/apache/plc4x/plc4go/pkg/api/transports"
_ "github.com/apache/plc4x/plc4go/tests/initializetest"
"testing"
)

func TestManualCBusDriver(t *testing.T) {
t.Skip()

connectionString := "c-bus://192.168.178.101"
driverManager := plc4go.NewPlcDriverManager()
driverManager.RegisterDriver(cbus.NewDriver())
transports.RegisterTcpTransport(driverManager)
test := testutils.NewManualTestSuite(connectionString, driverManager, t)

test.AddTestCase("status/binary/0x04", true)
test.AddTestCase("status/level=0x40/0x04", true)

test.Run()
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ void setUp() {
void whatEverThisIs() throws Exception {
byte[] bytes = "\\3436303230303231303167\r".getBytes(StandardCharsets.UTF_8);
ReadBufferByteBased readBufferByteBased = new ReadBufferByteBased(bytes);
cBusOptions = C_BUS_OPTIONS_WITH_SRCHK;
CBusMessage msg = CBusMessage.staticParse(readBufferByteBased, false, requestContext, cBusOptions, bytes.length);
assertThat(msg).isNotNull();
System.out.println(msg);
Expand Down Expand Up @@ -244,19 +243,14 @@ void statusRequestBinaryState() throws Exception {
void wat() throws Exception {
byte[] bytes = "D8FF0024000002000000000000000008000000000000000000\r\n".getBytes(StandardCharsets.UTF_8);
ReadBufferByteBased readBufferByteBased = new ReadBufferByteBased(bytes);
cBusOptions = C_BUS_OPTIONS_WITH_SRCHK;
requestContext = new RequestContext(true, false, false);
CBusMessage msg = CBusMessage.staticParse(readBufferByteBased, true, requestContext, cBusOptions, bytes.length);
assertThat(msg).isNotNull();
System.out.println(msg);
CBusMessageToClient messageToClient = (CBusMessageToClient) msg;
ReplyOrConfirmationReply reply = (ReplyOrConfirmationReply) messageToClient.getReply();
/*
MonitoredSALReply monitoredSALReply = (MonitoredSALReply) reply.getReply();
System.out.println(monitoredSALReply.getMonitoredSAL());
*/
EncodedReplyCALReply encodedReplyCALReply = (EncodedReplyCALReply) ((ReplyEncodedReply) reply.getReply()).getEncodedReply();
System.out.println(encodedReplyCALReply.getCalReply());
EncodedReplyStandardFormatStatusReply encodedReplyCALReply = (EncodedReplyStandardFormatStatusReply) ((ReplyEncodedReply) reply.getReply()).getEncodedReply();
System.out.println(encodedReplyCALReply.getReply());
assertMessageMatches(bytes, msg);
}

Expand Down

0 comments on commit 38a8bdf

Please sign in to comment.