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 4c27bf44652d1cd4068b5b027e932af90964730d Author: Sebastian Rühl <[email protected]> AuthorDate: Wed Aug 21 22:36:30 2024 +0200 feat(plc4go/bacnet): InitializeRoutingTableAck --- plc4go/internal/bacnetip/comp.go | 1 + plc4go/internal/bacnetip/npdu.go | 94 +++++++++++++++++++++- plc4go/internal/bacnetip/tests/state_machine.go | 13 +++ .../bacnetip/tests/test_npdu/test_codec_test.go | 80 ++++++++++++++++++ 4 files changed, 186 insertions(+), 2 deletions(-) diff --git a/plc4go/internal/bacnetip/comp.go b/plc4go/internal/bacnetip/comp.go index 7df264e855..3c28148b0c 100644 --- a/plc4go/internal/bacnetip/comp.go +++ b/plc4go/internal/bacnetip/comp.go @@ -131,6 +131,7 @@ const ( KWRbtnNetworkList = KnownKey("rbtnNetworkList") KWRatnNetworkList = KnownKey("ratnNetworkList") KWIrtTable = KnownKey("irtTable") + KWIrtaTable = KnownKey("irtaTable") ) type MessageBridge struct { diff --git a/plc4go/internal/bacnetip/npdu.go b/plc4go/internal/bacnetip/npdu.go index b6e8d59477..de6791f359 100644 --- a/plc4go/internal/bacnetip/npdu.go +++ b/plc4go/internal/bacnetip/npdu.go @@ -884,10 +884,100 @@ func (r *InitializeRoutingTable) String() string { type InitializeRoutingTableAck struct { *_NPDU + irtaTable []*RoutingTableEntry + + readWriteModel.NLMInitializeRoutingTableAck } -func NewInitializeRoutingTableAck() (*InitializeRoutingTableAck, error) { - panic("implement me") +func NewInitializeRoutingTableAck(opts ...func(*InitializeRoutingTableAck)) (*InitializeRoutingTableAck, error) { + i := &InitializeRoutingTableAck{} + for _, opt := range opts { + opt(i) + } + i.NLMInitializeRoutingTableAck = readWriteModel.NewNLMInitializeRoutingTableAck(i.produceNLMInitializeRoutingTableAckPortMapping()) + npdu, err := NewNPDU(i.NLMInitializeRoutingTableAck, nil) + if err != nil { + return nil, errors.Wrap(err, "error creating NPDU") + } + i._NPDU = npdu.(*_NPDU) + return i, nil +} + +func WithInitializeRoutingTableAckIrtaTable(irtaTable ...*RoutingTableEntry) func(*InitializeRoutingTableAck) { + return func(r *InitializeRoutingTableAck) { + r.irtaTable = irtaTable + } +} + +func (r *InitializeRoutingTableAck) GetIrtaTable() []*RoutingTableEntry { + return r.irtaTable +} + +func (r *InitializeRoutingTableAck) produceNLMInitializeRoutingTableAckPortMapping() (numberOfPorts uint8, mappings []readWriteModel.NLMInitializeRoutingTablePortMapping, _ uint16) { + numberOfPorts = uint8(len(r.irtaTable)) + mappings = make([]readWriteModel.NLMInitializeRoutingTablePortMapping, numberOfPorts) + for i, entry := range r.irtaTable { + mappings[i] = readWriteModel.NewNLMInitializeRoutingTablePortMapping(entry.tuple()) + } + return +} + +func (r *InitializeRoutingTableAck) 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 *InitializeRoutingTableAck) 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.irtaTable { + 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 *InitializeRoutingTableAck) 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.NLMInitializeRoutingTableAck: + r.setNLM(nlm) + r.NLMInitializeRoutingTableAck = nlm + r.irtaTable = r.produceIRTTable(nlm.GetPortMappings()) + } + } + return nil + default: + return errors.Errorf("invalid NPDU type %T", npdu) + } +} + +func (r *InitializeRoutingTableAck) String() string { + return fmt.Sprintf("InitializeRoutingTableAck{%s, irtaTable: %v}", r._NPDU, r.irtaTable) } type EstablishConnectionToNetwork struct { diff --git a/plc4go/internal/bacnetip/tests/state_machine.go b/plc4go/internal/bacnetip/tests/state_machine.go index d1382e5aeb..0d957e1765 100644 --- a/plc4go/internal/bacnetip/tests/state_machine.go +++ b/plc4go/internal/bacnetip/tests/state_machine.go @@ -232,6 +232,19 @@ func MatchPdu(localLog zerolog.Logger, pdu bacnetip.PDU, pduType any, pduAttrs m return slices.EqualFunc(irts, oirts, func(entry *bacnetip.RoutingTableEntry, entry2 *bacnetip.RoutingTableEntry) bool { return entry.Equals(entry2) }) + case bacnetip.KWIrtaTable: + irta, ok := pdu.(*bacnetip.InitializeRoutingTableAck) + if !ok { + return false + } + irts := irta.GetIrtaTable() + 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 07ed9e924a..b53bcb9d48 100644 --- a/plc4go/internal/bacnetip/tests/test_npdu/test_codec_test.go +++ b/plc4go/internal/bacnetip/tests/test_npdu/test_codec_test.go @@ -87,6 +87,22 @@ func InitializeRoutingTable(irtTable ...*bacnetip.RoutingTableEntry) *bacnetip.I return network } +func RoutingTableEntry(address uint16, portId uint8, portInfo []byte) *bacnetip.RoutingTableEntry { + return bacnetip.NewRoutingTableEntry( + bacnetip.WithRoutingTableEntryDestinationNetworkAddress(address), + bacnetip.WithRoutingTableEntryPortId(portId), + bacnetip.WithRoutingTableEntryPortInfo(portInfo), + ) +} + +func InitializeRoutingTableAck(irtaTable ...*bacnetip.RoutingTableEntry) *bacnetip.InitializeRoutingTableAck { + network, err := bacnetip.NewInitializeRoutingTableAck(bacnetip.WithInitializeRoutingTableAckIrtaTable(irtaTable...)) + if err != nil { + panic(err) + } + return network +} + type TestNPDUCodecSuite struct { suite.Suite @@ -471,6 +487,70 @@ func (suite *TestNPDUCodecSuite) TestInitializeRoutingTable02() { // Test the Re err = suite.Confirmation(bacnetip.NewArgs(&bacnetip.InitializeRoutingTable{}), bacnetip.NewKWArgs(bacnetip.KWIrtTable, rtEntries)) } +func (suite *TestNPDUCodecSuite) TestInitializeRoutingTableAck01() { // 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 + "07 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(InitializeRoutingTableAck(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.InitializeRoutingTableAck{}), bacnetip.NewKWArgs(bacnetip.KWIrtaTable, rtEntries)) +} + +func (suite *TestNPDUCodecSuite) TestInitializeRoutingTableAck02() { // 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 + "07 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(InitializeRoutingTableAck(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.InitializeRoutingTableAck{}), bacnetip.NewKWArgs(bacnetip.KWIrtaTable, rtEntries)) +} + func TestNPDUCodec(t *testing.T) { suite.Run(t, new(TestNPDUCodecSuite)) }
