Skip to content

Commit

Permalink
feat(plc4go/bacnetip): first bvlc draft
Browse files Browse the repository at this point in the history
  • Loading branch information
sruehl committed Aug 22, 2024
1 parent d4aca36 commit dd1e22d
Show file tree
Hide file tree
Showing 17 changed files with 916 additions and 141 deletions.
9 changes: 5 additions & 4 deletions plc4go/internal/bacnetip/ApplicationLayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ package bacnetip
import (
"context"
"fmt"
"github.com/apache/plc4x/plc4go/spi/options"
"github.com/rs/zerolog"
"time"

readWriteModel "github.com/apache/plc4x/plc4go/protocols/bacnetip/readwrite/model"
"github.com/apache/plc4x/plc4go/spi/options"

"github.com/pkg/errors"
"github.com/rs/zerolog"
)

type SSMState uint8
Expand Down Expand Up @@ -444,7 +445,7 @@ func (c *ClientSSM) Request(args Args, kwargs KWArgs) error {
apdu := args.Get0PDU()

// make sure it has a good source and destination
apdu = NewPDUFromPDU(apdu, WithPDUSource(nil), WithPDUDestination(c.pduAddress))
apdu = NewPDU(apdu, WithPDUSource(nil), WithPDUDestination(c.pduAddress))

// send it via the device
return c.ssmSAP.Request(NewArgs(apdu), kwargs)
Expand Down Expand Up @@ -563,7 +564,7 @@ func (c *ClientSSM) Response(args Args, kwargs KWArgs) error {
apdu := args.Get0PDU()

// make sure it has a good source and destination
apdu = NewPDUFromPDU(apdu, WithPDUSource(c.pduAddress), WithPDUDestination(nil))
apdu = NewPDU(apdu, WithPDUSource(c.pduAddress), WithPDUDestination(nil))

// send it to the application
return c.ssmSAP.SapResponse(NewArgs(apdu), kwargs)
Expand Down
21 changes: 14 additions & 7 deletions plc4go/internal/bacnetip/BACnetVirtualLinkLayerService.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ func (m *UDPMultiplexer) Indication(args Args, kwargs KWArgs) error {
return errors.New("invalid destination address type")
}

return m.directPort.Indication(NewArgs(NewPDUFromPDU(pdu, WithPDUDestination(dest))), NoKWArgs)
return m.directPort.Indication(NewArgs(NewPDU(pdu, WithPDUDestination(dest))), NoKWArgs)
}

func (m *UDPMultiplexer) Confirmation(args Args, kwargs KWArgs) error {
Expand Down Expand Up @@ -445,7 +445,7 @@ func (b *BIPSimple) String() string {

func (b *BIPSimple) Indication(args Args, kwargs KWArgs) error {
b.log.Debug().Stringer("Args", args).Stringer("KWArgs", kwargs).Msg("Indication")
pdu := args.Get0PDU()
pdu := args.Get0NPDU()
if pdu == nil {
return errors.New("no pdu")
}
Expand All @@ -457,19 +457,26 @@ func (b *BIPSimple) Indication(args Args, kwargs KWArgs) error {
switch pdu.GetPDUDestination().AddrType {
case LOCAL_STATION_ADDRESS:
// make an original unicast _PDU
xpdu := readWriteModel.NewBVLCOriginalUnicastNPDU(pdu.GetMessage().(readWriteModel.NPDU), 0)
xpdu, err := NewOriginalUnicastNPDU(pdu, WithOriginalUnicastNPDUDestination(pdu.GetPDUDestination()), WithOriginalUnicastNPDUUserData(pdu.GetPDUUserData()))
if err != nil {
return errors.Wrap(err, "error creating original unicastNPDU")
}
// TODO: route aware stuff missing here
b.log.Debug().Stringer("xpdu", xpdu).Msg("xpdu")

// send it downstream
return b.Request(NewArgs(NewPDUFromPDUWithNewMessage(pdu, xpdu)), NoKWArgs)
return b.Request(NewArgs(xpdu), NoKWArgs)
case LOCAL_BROADCAST_ADDRESS:
// make an original broadcast _PDU
xpdu := readWriteModel.NewBVLCOriginalBroadcastNPDU(pdu.GetMessage().(readWriteModel.NPDU), 0)

xpdu, err := NewOriginalBroadcastNPDU(pdu, WithOriginalBroadcastNPDUDestination(pdu.GetPDUDestination()), WithOriginalBroadcastNPDUUserData(pdu.GetPDUUserData()))
if err != nil {
return errors.Wrap(err, "error creating original BroadcastNPDU")
}
// TODO: route aware stuff missing here
b.log.Debug().Stringer("xpdu", xpdu).Msg("xpdu")

// send it downstream
return b.Request(NewArgs(NewPDUFromPDUWithNewMessage(pdu, xpdu)), NoKWArgs)
return b.Request(NewArgs(xpdu), NoKWArgs)
default:
return errors.Errorf("invalid destination address: %s", pdu.GetPDUDestination())
}
Expand Down
34 changes: 32 additions & 2 deletions plc4go/internal/bacnetip/CommunicationsModule.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
package bacnetip

import (
"context"
"fmt"
"strconv"
"strings"

"github.com/apache/plc4x/plc4go/spi"
"github.com/apache/plc4x/plc4go/spi/utils"

"github.com/pkg/errors"
"github.com/rs/zerolog"
Expand All @@ -46,7 +48,7 @@ func init() {
}

type IPCI interface {
fmt.Stringer
spi.Message
SetPDUUserData(spi.Message)
GetPDUUserData() spi.Message
GetPDUSource() *Address
Expand All @@ -57,7 +59,7 @@ type IPCI interface {
}

type __PCI struct {
pduUserData spi.Message // TODO: should that be PDUUserData rater than spi.Message and do we need another field... lets see...
pduUserData spi.Message
pduSource *Address
pduDestination *Address
}
Expand Down Expand Up @@ -119,6 +121,34 @@ func (p *__PCI) deepCopy() *__PCI {
return &__PCI{pduUserData, pduSource, pduDestination}
}

func (p *__PCI) Serialize() ([]byte, error) {
if p.pduUserData == nil {
return nil, errors.New("no pdu userdata")
}
return p.pduUserData.Serialize()
}

func (p *__PCI) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
if p.pduUserData == nil {
return errors.New("no pdu userdata")
}
return p.pduUserData.SerializeWithWriteBuffer(ctx, writeBuffer)
}

func (p *__PCI) GetLengthInBytes(ctx context.Context) uint16 {
if p.pduUserData == nil {
return 0
}
return p.pduUserData.GetLengthInBytes(ctx)
}

func (p *__PCI) GetLengthInBits(ctx context.Context) uint16 {
if p.pduUserData == nil {
return 0
}
return p.pduUserData.GetLengthInBits(ctx)
}

func (p *__PCI) String() string {
pduUserDataString := ""
if p.pduUserData != nil {
Expand Down
11 changes: 7 additions & 4 deletions plc4go/internal/bacnetip/NetworkService.go
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,7 @@ func (n *NetworkServiceAccessPoint) ProcessNPDU(adapter *NetworkAdapter, pdu PDU
}

// build a new NPDU to send to other adapters
newpdu := NewPDUFromPDU(pdu).(*_PDU)
newpdu := NewPDU(pdu).(*_PDU)

// decrease the hop count
newNpduHopCount := *npdu.GetHopCount() - 1
Expand Down Expand Up @@ -804,7 +804,7 @@ func (n *NetworkServiceAccessPoint) ProcessNPDU(adapter *NetworkAdapter, pdu PDU

for _, xadapter := range n.adapters {
if xadapter != adapter {
if err := xadapter.ProcessNPDU(NewPDUFromPDU(newpdu)); err != nil {
if err := xadapter.ProcessNPDU(NewPDU(newpdu)); err != nil {
n.log.Warn().Err(err).Msg("Error processing npdu")
}
}
Expand Down Expand Up @@ -861,7 +861,7 @@ func (n *NetworkServiceAccessPoint) ProcessNPDU(adapter *NetworkAdapter, pdu PDU
0,
)

return xadapter.ProcessNPDU(NewPDUFromPDU(newpdu))
return xadapter.ProcessNPDU(NewPDU(newpdu))
}

// look for routing information from the network of one of our adapters to the destination network
Expand All @@ -883,7 +883,10 @@ func (n *NetworkServiceAccessPoint) ProcessNPDU(adapter *NetworkAdapter, pdu PDU
pduDestination := routerInfo.address

// send the packet downstream
return snetAdapter.ProcessNPDU(NewPDUFromPDU(newpdu, WithPDUDestination(&pduDestination)))
if snetAdapter == nil {
return errors.New("snetAdapter nil")
}
return snetAdapter.ProcessNPDU(NewPDU(newpdu, WithPDUDestination(&pduDestination)))
}

n.log.Debug().Msg("No router info found")
Expand Down
54 changes: 25 additions & 29 deletions plc4go/internal/bacnetip/PDU.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"strconv"
"strings"

"github.com/apache/plc4x/plc4go/internal/bacnetip/globals"
readWriteModel "github.com/apache/plc4x/plc4go/protocols/bacnetip/readwrite/model"
"github.com/apache/plc4x/plc4go/spi"
"github.com/apache/plc4x/plc4go/spi/utils"
Expand Down Expand Up @@ -887,9 +888,9 @@ type _PCI struct {

var _ PCI = (*_PCI)(nil)

func newPCI(msg spi.Message, pduSource *Address, pduDestination *Address, expectingReply bool, networkPriority readWriteModel.NPDUNetworkPriority) *_PCI {
func newPCI(pduUserData spi.Message, pduSource *Address, pduDestination *Address, expectingReply bool, networkPriority readWriteModel.NPDUNetworkPriority) *_PCI {
return &_PCI{
new__PCI(msg, pduSource, pduDestination),
new__PCI(pduUserData, pduSource, pduDestination),
expectingReply,
networkPriority,
}
Expand Down Expand Up @@ -1064,9 +1065,9 @@ type _APCI struct {
*_PCI
}

func newAPCI(msg spi.Message, pduSource *Address, pduDestination *Address, expectingReply bool, networkPriority readWriteModel.NPDUNetworkPriority) *_APCI {
func newAPCI(pduUserData spi.Message, pduSource *Address, pduDestination *Address, expectingReply bool, networkPriority readWriteModel.NPDUNetworkPriority) *_APCI {
return &_APCI{
_PCI: newPCI(msg, pduSource, pduDestination, expectingReply, networkPriority),
_PCI: newPCI(pduUserData, pduSource, pduDestination, expectingReply, networkPriority),
}
}

Expand Down Expand Up @@ -1099,53 +1100,41 @@ type PDU interface {
DeepCopy() PDU
}

// PDUContract provides a set of functions which can be overwritten by a sub struct
type PDUContract interface {
GetName() string
}

type _PDU struct {
*_APCI
*_PDUData
PDUContract
}

func NewPDU(msg spi.Message, pduOptions ...PDUOption) PDU {
p := &_PDU{
_APCI: newAPCI(msg, nil, nil, false, readWriteModel.NPDUNetworkPriority_NORMAL_MESSAGE),
}
for _, option := range pduOptions {
option(p)
}
p._PDUData = newPDUData(p)
return p
}

func NewPDUFromPDU(pdu PDU, pduOptions ...PDUOption) PDU {
msg := pdu.(*_PDU).pduUserData
func NewPDU(pduUserData spi.Message, pduOptions ...PDUOption) PDU {
p := &_PDU{
_APCI: newAPCI(msg, pdu.GetPDUSource(), pdu.GetPDUDestination(), pdu.GetExpectingReply(), pdu.GetNetworkPriority()),
_APCI: newAPCI(pduUserData, nil, nil, false, readWriteModel.NPDUNetworkPriority_NORMAL_MESSAGE),
}
p.PDUContract = p
for _, option := range pduOptions {
option(p)
}
p._PDUData = newPDUData(p)
return p
}

func NewPDUFromPDUWithNewMessage(pdu PDU, msg spi.Message, pduOptions ...PDUOption) PDU {
func NewPDUFromPDUWithNewMessage(pdu PDU, pduUserData spi.Message, pduOptions ...PDUOption) PDU {
p := &_PDU{
_APCI: newAPCI(msg, pdu.GetPDUSource(), pdu.GetPDUDestination(), pdu.GetExpectingReply(), pdu.GetNetworkPriority()),
_APCI: newAPCI(pduUserData, pdu.GetPDUSource(), pdu.GetPDUDestination(), pdu.GetExpectingReply(), pdu.GetNetworkPriority()),
}
p.PDUContract = p
for _, option := range pduOptions {
option(p)
}
p._PDUData = newPDUData(p)
return p
}

func NewPDUWithAllOptions(msg spi.Message, pduSource *Address, pduDestination *Address, expectingReply bool, networkPriority readWriteModel.NPDUNetworkPriority) *_PDU {
p := &_PDU{
_APCI: newAPCI(msg, pduSource, pduDestination, expectingReply, networkPriority),
}
p._PDUData = newPDUData(p)
return p
}

type PDUOption func(pdu *_PDU)

func WithPDUSource(pduSource *Address) PDUOption {
Expand Down Expand Up @@ -1195,6 +1184,13 @@ func (p *_PDU) DeepCopy() PDU {
return p.deepCopy()
}

func (p *_PDU) GetName() string {
return "PDU"
}

func (p *_PDU) String() string {
return fmt.Sprintf("_PDU{%s}", p._PCI)
if globals.ExtendedPDUOutput {
return fmt.Sprintf("_PDU{%s}", p._PCI)
}
return fmt.Sprintf("<%s %s -> %s : %s>", p.PDUContract.GetName(), p.GetPDUSource(), p.GetPDUDestination(), Btox(p.GetPduData(), "."))
}
Loading

0 comments on commit dd1e22d

Please sign in to comment.