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

commit 232b6645e2c7dc3d5210ab29bb4c277a355196a4
Author: Sebastian Rühl <[email protected]>
AuthorDate: Wed Aug 21 22:35:21 2024 +0200

    feat(plc4go/bacnet): InitializeRoutingTable
---
 plc4go/internal/bacnetip/comp.go                   |   1 +
 plc4go/internal/bacnetip/npdu.go                   | 151 ++++++++++++++++++++-
 plc4go/internal/bacnetip/tests/state_machine.go    |  13 ++
 .../bacnetip/tests/test_npdu/test_codec_test.go    |  97 +++++++++++++
 4 files changed, 258 insertions(+), 4 deletions(-)

diff --git a/plc4go/internal/bacnetip/comp.go b/plc4go/internal/bacnetip/comp.go
index 98a9174baa..7df264e855 100644
--- a/plc4go/internal/bacnetip/comp.go
+++ b/plc4go/internal/bacnetip/comp.go
@@ -130,6 +130,7 @@ const (
        KWRmtnDNET               = KnownKey("rmtnDNET")
        KWRbtnNetworkList        = KnownKey("rbtnNetworkList")
        KWRatnNetworkList        = KnownKey("ratnNetworkList")
+       KWIrtTable               = KnownKey("irtTable")
 )
 
 type MessageBridge struct {
diff --git a/plc4go/internal/bacnetip/npdu.go b/plc4go/internal/bacnetip/npdu.go
index 330bd196cf..b6e8d59477 100644
--- a/plc4go/internal/bacnetip/npdu.go
+++ b/plc4go/internal/bacnetip/npdu.go
@@ -727,16 +727,159 @@ func (r *RouterAvailableToNetwork) String() string {
        return fmt.Sprintf("RouterAvailableToNetwork{%s, ratnNetworkList: %v}", 
r._NPDU, r.ratnNetworkList)
 }
 
-func NewRoutingTableEntry() (*RoutingTableEntry, error) {
-       panic("implement me")
+type RoutingTableEntry struct {
+       *DebugContents
+       rtDNET     uint16
+       rtPortId   uint8
+       rtPortInfo []byte
+}
+
+func NewRoutingTableEntry(opts ...func(*RoutingTableEntry)) *RoutingTableEntry 
{
+       r := &RoutingTableEntry{}
+       for _, opt := range opts {
+               opt(r)
+       }
+       return r
+}
+
+func WithRoutingTableEntryDestinationNetworkAddress(dnet uint16) 
func(*RoutingTableEntry) {
+       return func(r *RoutingTableEntry) {
+               r.rtDNET = dnet
+       }
+}
+
+func WithRoutingTableEntryPortId(id uint8) func(*RoutingTableEntry) {
+       return func(r *RoutingTableEntry) {
+               r.rtPortId = id
+       }
+}
+
+func WithRoutingTableEntryPortInfo(portInfo []byte) func(*RoutingTableEntry) {
+       return func(r *RoutingTableEntry) {
+               r.rtPortInfo = portInfo
+       }
+}
+
+func (r *RoutingTableEntry) tuple() (destinationNetworkAddress uint16, portId 
uint8, portInfoLength uint8, portInfo []byte) {
+       return r.rtDNET, r.rtPortId, uint8(len(r.rtPortInfo)), r.rtPortInfo
+}
+
+func (r *RoutingTableEntry) Equals(other any) bool {
+       if r == nil && other == nil {
+               return true
+       }
+       if r == nil {
+               return false
+       }
+       otherEntry, ok := other.(*RoutingTableEntry)
+       if !ok {
+               return false
+       }
+       return r.rtDNET == otherEntry.rtDNET &&
+               r.rtPortId == otherEntry.rtPortId &&
+               bytes.Equal(r.rtPortInfo, otherEntry.rtPortInfo)
+}
+
+func (r *RoutingTableEntry) String() string {
+       return fmt.Sprintf("RoutingTableEntry{rtDNET: %d, rtPortId: %d, 
rtPortInfo: %d}", r.rtDNET, r.rtPortId, r.rtPortInfo)
 }
 
 type InitializeRoutingTable struct {
        *_NPDU
+       irtTable []*RoutingTableEntry
+
+       readWriteModel.NLMInitializeRoutingTable
 }
 
-func NewInitializeRoutingTable() (*InitializeRoutingTable, error) {
-       panic("implement me")
+func NewInitializeRoutingTable(opts ...func(*InitializeRoutingTable)) 
(*InitializeRoutingTable, error) {
+       i := &InitializeRoutingTable{}
+       for _, opt := range opts {
+               opt(i)
+       }
+       i.NLMInitializeRoutingTable = 
readWriteModel.NewNLMInitializeRoutingTable(i.produceNLMInitializeRoutingTablePortMapping())
+       npdu, err := NewNPDU(i.NLMInitializeRoutingTable, nil)
+       if err != nil {
+               return nil, errors.Wrap(err, "error creating NPDU")
+       }
+       i._NPDU = npdu.(*_NPDU)
+       return i, nil
+}
+
+func WithInitializeRoutingTableIrtTable(irtTable ...*RoutingTableEntry) 
func(*InitializeRoutingTable) {
+       return func(r *InitializeRoutingTable) {
+               r.irtTable = irtTable
+       }
+}
+
+func (r *InitializeRoutingTable) GetIrtTable() []*RoutingTableEntry {
+       return r.irtTable
+}
+
+func (r *InitializeRoutingTable) produceNLMInitializeRoutingTablePortMapping() 
(numberOfPorts uint8, mappings 
[]readWriteModel.NLMInitializeRoutingTablePortMapping, _ uint16) {
+       numberOfPorts = uint8(len(r.irtTable))
+       mappings = make([]readWriteModel.NLMInitializeRoutingTablePortMapping, 
numberOfPorts)
+       for i, entry := range r.irtTable {
+               mappings[i] = 
readWriteModel.NewNLMInitializeRoutingTablePortMapping(entry.tuple())
+       }
+       return
+}
+
+func (r *InitializeRoutingTable) produceIRTTable(mappings 
[]readWriteModel.NLMInitializeRoutingTablePortMapping) (irtTable 
[]*RoutingTableEntry) {
+       irtTable = make([]*RoutingTableEntry, len(mappings))
+       for i, entry := range mappings {
+               irtTable[i] = NewRoutingTableEntry(
+                       
WithRoutingTableEntryDestinationNetworkAddress(entry.GetDestinationNetworkAddress()),
+                       WithRoutingTableEntryPortId(entry.GetPortId()),
+                       WithRoutingTableEntryPortInfo(entry.GetPortInfo()),
+               )
+       }
+       return
+}
+
+func (r *InitializeRoutingTable) Encode(npdu Arg) error {
+       switch npdu := npdu.(type) {
+       case NPDU:
+               if err := npdu.Update(r); err != nil {
+                       return errors.Wrap(err, "error updating _NPCI")
+               }
+               for _, rte := range r.irtTable {
+                       npdu.PutShort(int16(rte.rtDNET))
+                       npdu.Put(rte.rtPortId)
+                       npdu.Put(byte(len(rte.rtPortInfo)))
+                       npdu.PutData(rte.rtPortInfo...)
+               }
+               npdu.setNPDU(r.npdu)
+               npdu.setNLM(r.nlm)
+               npdu.setAPDU(r.apdu)
+               return nil
+       default:
+               return errors.Errorf("invalid NPDU type %T", npdu)
+       }
+}
+
+func (r *InitializeRoutingTable) Decode(npdu Arg) error {
+       switch npdu := npdu.(type) {
+       case NPDU:
+               if err := r.Update(npdu); err != nil {
+                       return errors.Wrap(err, "error updating _NPCI")
+               }
+               switch pduUserData := npdu.GetPDUUserData().(type) {
+               case readWriteModel.NPDUExactly:
+                       switch nlm := pduUserData.GetNlm().(type) {
+                       case readWriteModel.NLMInitializeRoutingTable:
+                               r.setNLM(nlm)
+                               r.NLMInitializeRoutingTable = nlm
+                               r.irtTable = 
r.produceIRTTable(nlm.GetPortMappings())
+                       }
+               }
+               return nil
+       default:
+               return errors.Errorf("invalid NPDU type %T", npdu)
+       }
+}
+
+func (r *InitializeRoutingTable) String() string {
+       return fmt.Sprintf("InitializeRoutingTable{%s, irtTable: %v}", r._NPDU, 
r.irtTable)
 }
 
 type InitializeRoutingTableAck struct {
diff --git a/plc4go/internal/bacnetip/tests/state_machine.go 
b/plc4go/internal/bacnetip/tests/state_machine.go
index b51f893a69..d1382e5aeb 100644
--- a/plc4go/internal/bacnetip/tests/state_machine.go
+++ b/plc4go/internal/bacnetip/tests/state_machine.go
@@ -219,6 +219,19 @@ func MatchPdu(localLog zerolog.Logger, pdu bacnetip.PDU, 
pduType any, pduAttrs m
                                return false
                        }
                        return slices.Equal(net, uint16s)
+               case bacnetip.KWIrtTable:
+                       irt, ok := pdu.(*bacnetip.InitializeRoutingTable)
+                       if !ok {
+                               return false
+                       }
+                       irts := irt.GetIrtTable()
+                       oirts, ok := attrValue.([]*bacnetip.RoutingTableEntry)
+                       if !ok {
+                               return false
+                       }
+                       return slices.EqualFunc(irts, oirts, func(entry 
*bacnetip.RoutingTableEntry, entry2 *bacnetip.RoutingTableEntry) bool {
+                               return entry.Equals(entry2)
+                       })
                default:
                        panic("implement " + attrName)
                }
diff --git a/plc4go/internal/bacnetip/tests/test_npdu/test_codec_test.go 
b/plc4go/internal/bacnetip/tests/test_npdu/test_codec_test.go
index a13b8794d6..07ed9e924a 100644
--- a/plc4go/internal/bacnetip/tests/test_npdu/test_codec_test.go
+++ b/plc4go/internal/bacnetip/tests/test_npdu/test_codec_test.go
@@ -79,6 +79,14 @@ func RouterAvailableToNetwork(netList ...uint16) 
*bacnetip.RouterAvailableToNetw
        return network
 }
 
+func InitializeRoutingTable(irtTable ...*bacnetip.RoutingTableEntry) 
*bacnetip.InitializeRoutingTable {
+       network, err := 
bacnetip.NewInitializeRoutingTable(bacnetip.WithInitializeRoutingTableIrtTable(irtTable...))
+       if err != nil {
+               panic(err)
+       }
+       return network
+}
+
 type TestNPDUCodecSuite struct {
        suite.Suite
 
@@ -374,6 +382,95 @@ func (suite *TestNPDUCodecSuite) 
TestRouterAvailableToNetworkNetworks() { // Tes
        err = 
suite.Confirmation(bacnetip.NewArgs(&bacnetip.RouterAvailableToNetwork{}), 
bacnetip.NewKWArgs(bacnetip.KWRatnNetworkList, networkList))
 }
 
+func (suite *TestNPDUCodecSuite) TestInitializeRoutingTableEmpty() { // Test 
the Result encoding and decoding.
+       // Request successful
+       pduBytes, err := bacnetip.Xtob(
+               "01.80" + // version, network layer message
+                       "06 00", // message type and list length
+       )
+       suite.Require().NoError(err)
+       { // Parse with plc4x parser to validate
+               parse, err := 
readWriteModel.NPDUParse(testutils.TestContext(suite.T()), pduBytes, 
uint16(len(pduBytes)))
+               suite.Assert().NoError(err)
+               if parse != nil {
+                       suite.T().Log("\n" + parse.String())
+               }
+       }
+
+       err = suite.Request(bacnetip.NewArgs(InitializeRoutingTable()), 
bacnetip.NoKWArgs)
+       suite.Assert().NoError(err)
+       err = suite.Indication(bacnetip.NoArgs, 
bacnetip.NewKWArgs(bacnetip.KWPDUData, pduBytes))
+       suite.Assert().NoError(err)
+
+       err = 
suite.Response(bacnetip.NewArgs(bacnetip.NewPDU(&bacnetip.MessageBridge{Bytes: 
pduBytes})), bacnetip.NoKWArgs)
+       suite.Assert().NoError(err)
+       err = 
suite.Confirmation(bacnetip.NewArgs(&bacnetip.InitializeRoutingTable{}), 
bacnetip.NewKWArgs(bacnetip.KWIrtTable, []*bacnetip.RoutingTableEntry{}))
+}
+
+func (suite *TestNPDUCodecSuite) TestInitializeRoutingTable01() { // Test the 
Result encoding and decoding.
+       // Request successful
+       xtob, err := bacnetip.Xtob("")
+       suite.Require().NoError(err)
+       rte := RoutingTableEntry(1, 2, xtob)
+       rtEntries := []*bacnetip.RoutingTableEntry{rte}
+
+       // Request successful
+       pduBytes, err := bacnetip.Xtob(
+               "01.80" + // version, network layer message
+                       "06 01" + // message type and list length
+                       "0001 02 00", // network, port number, port info
+       )
+       suite.Require().NoError(err)
+       { // Parse with plc4x parser to validate
+               parse, err := 
readWriteModel.NPDUParse(testutils.TestContext(suite.T()), pduBytes, 
uint16(len(pduBytes)))
+               suite.Assert().NoError(err)
+               if parse != nil {
+                       suite.T().Log("\n" + parse.String())
+               }
+       }
+
+       err = 
suite.Request(bacnetip.NewArgs(InitializeRoutingTable(rtEntries...)), 
bacnetip.NoKWArgs)
+       suite.Assert().NoError(err)
+       err = suite.Indication(bacnetip.NoArgs, 
bacnetip.NewKWArgs(bacnetip.KWPDUData, pduBytes))
+       suite.Assert().NoError(err)
+
+       err = 
suite.Response(bacnetip.NewArgs(bacnetip.NewPDU(&bacnetip.MessageBridge{Bytes: 
pduBytes})), bacnetip.NoKWArgs)
+       suite.Assert().NoError(err)
+       err = 
suite.Confirmation(bacnetip.NewArgs(&bacnetip.InitializeRoutingTable{}), 
bacnetip.NewKWArgs(bacnetip.KWIrtTable, rtEntries))
+}
+
+func (suite *TestNPDUCodecSuite) TestInitializeRoutingTable02() { // Test the 
Result encoding and decoding.
+       // Request successful
+       xtob, err := bacnetip.Xtob("deadbeef")
+       suite.Require().NoError(err)
+       rte := RoutingTableEntry(3, 4, xtob)
+       rtEntries := []*bacnetip.RoutingTableEntry{rte}
+
+       // Request successful
+       pduBytes, err := bacnetip.Xtob(
+               "01.80" + // version, network layer message
+                       "06 01" + // message type and list length
+                       "0003 04 04 DEADBEEF", // network, port number, port 
info
+       )
+       suite.Require().NoError(err)
+       { // Parse with plc4x parser to validate
+               parse, err := 
readWriteModel.NPDUParse(testutils.TestContext(suite.T()), pduBytes, 
uint16(len(pduBytes)))
+               suite.Assert().NoError(err)
+               if parse != nil {
+                       suite.T().Log("\n" + parse.String())
+               }
+       }
+
+       err = 
suite.Request(bacnetip.NewArgs(InitializeRoutingTable(rtEntries...)), 
bacnetip.NoKWArgs)
+       suite.Assert().NoError(err)
+       err = suite.Indication(bacnetip.NoArgs, 
bacnetip.NewKWArgs(bacnetip.KWPDUData, pduBytes))
+       suite.Assert().NoError(err)
+
+       err = 
suite.Response(bacnetip.NewArgs(bacnetip.NewPDU(&bacnetip.MessageBridge{Bytes: 
pduBytes})), bacnetip.NoKWArgs)
+       suite.Assert().NoError(err)
+       err = 
suite.Confirmation(bacnetip.NewArgs(&bacnetip.InitializeRoutingTable{}), 
bacnetip.NewKWArgs(bacnetip.KWIrtTable, rtEntries))
+}
+
 func TestNPDUCodec(t *testing.T) {
        suite.Run(t, new(TestNPDUCodecSuite))
 }

Reply via email to