test(plc4go/bacnetip): work on network tests
diff --git a/plc4go/internal/bacnetip/constructors/npdu.go b/plc4go/internal/bacnetip/constructors/npdu.go
new file mode 100644
index 0000000..ba9679ae
--- /dev/null
+++ b/plc4go/internal/bacnetip/constructors/npdu.go
@@ -0,0 +1,129 @@
+/*
+ * 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 constructors
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/bacnetip"
+	readWriteModel "github.com/apache/plc4x/plc4go/protocols/bacnetip/readwrite/model"
+)
+
+func WhoIsRouterToNetwork(net uint16) *bacnetip.WhoIsRouterToNetwork {
+	network, err := bacnetip.NewWhoIsRouterToNetwork(bacnetip.WithWhoIsRouterToNetworkNet(net))
+	if err != nil {
+		panic(err)
+	}
+	return network
+}
+
+func IAmRouterToNetwork(netList ...uint16) *bacnetip.IAmRouterToNetwork {
+	network, err := bacnetip.NewIAmRouterToNetwork(bacnetip.WithIAmRouterToNetworkNetworkList(netList...))
+	if err != nil {
+		panic(err)
+	}
+	return network
+}
+
+func ICouldBeRouterToNetwork(net uint16, perf uint8) *bacnetip.ICouldBeRouterToNetwork {
+	network, err := bacnetip.NewICouldBeRouterToNetwork(bacnetip.WithICouldBeRouterToNetworkNetwork(net), bacnetip.WithICouldBeRouterToNetworkPerformanceIndex(perf))
+	if err != nil {
+		panic(err)
+	}
+	return network
+}
+
+func RejectMessageToNetwork(reason uint8, dnet uint16) *bacnetip.RejectMessageToNetwork {
+	network, err := bacnetip.NewRejectMessageToNetwork(bacnetip.WithRejectMessageToNetworkRejectionReason(readWriteModel.NLMRejectMessageToNetworkRejectReason(reason)), bacnetip.WithRejectMessageToNetworkDnet(dnet))
+	if err != nil {
+		panic(err)
+	}
+	return network
+}
+
+func RouterBusyToNetwork(netList ...uint16) *bacnetip.RouterBusyToNetwork {
+	network, err := bacnetip.NewRouterBusyToNetwork(bacnetip.WithRouterBusyToNetworkDnet(netList))
+	if err != nil {
+		panic(err)
+	}
+	return network
+}
+
+func RouterAvailableToNetwork(netList ...uint16) *bacnetip.RouterAvailableToNetwork {
+	network, err := bacnetip.NewRouterAvailableToNetwork(bacnetip.WithRouterAvailableToNetworkDnet(netList))
+	if err != nil {
+		panic(err)
+	}
+	return network
+}
+
+func InitializeRoutingTable(irtTable ...*bacnetip.RoutingTableEntry) *bacnetip.InitializeRoutingTable {
+	network, err := bacnetip.NewInitializeRoutingTable(bacnetip.WithInitializeRoutingTableIrtTable(irtTable...))
+	if err != nil {
+		panic(err)
+	}
+	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
+}
+
+func EstablishConnectionToNetwork(dnet uint16, terminationTime uint8) *bacnetip.EstablishConnectionToNetwork {
+	network, err := bacnetip.NewEstablishConnectionToNetwork(bacnetip.WithEstablishConnectionToNetworkDNET(dnet), bacnetip.WithEstablishConnectionToNetworkTerminationTime(terminationTime))
+	if err != nil {
+		panic(err)
+	}
+	return network
+}
+
+func DisconnectConnectionToNetwork(dnet uint16) *bacnetip.DisconnectConnectionToNetwork {
+	network, err := bacnetip.NewDisconnectConnectionToNetwork(bacnetip.WithDisconnectConnectionToNetworkDNET(dnet))
+	if err != nil {
+		panic(err)
+	}
+	return network
+}
+
+func WhatIsNetworkNumber(dnet uint16) *bacnetip.WhatIsNetworkNumber {
+	network, err := bacnetip.NewWhatIsNetworkNumber()
+	if err != nil {
+		panic(err)
+	}
+	return network
+}
+
+func NetworkNumberIs(net uint16, flag bool) *bacnetip.NetworkNumberIs {
+	network, err := bacnetip.NewNetworkNumberIs(bacnetip.WithNetworkNumberIsNET(net), bacnetip.WithNetworkNumberIsTerminationConfigured(flag))
+	if err != nil {
+		panic(err)
+	}
+	return network
+}
diff --git a/plc4go/internal/bacnetip/npdu.go b/plc4go/internal/bacnetip/npdu.go
index 17095ec..1962377 100644
--- a/plc4go/internal/bacnetip/npdu.go
+++ b/plc4go/internal/bacnetip/npdu.go
@@ -189,7 +189,7 @@
 			sourceAddress = nil
 		}
 	}
-	destinationSpecified := destination != nil
+	destinationSpecified := destination != nil && destination.AddrType != LOCAL_BROADCAST_ADDRESS // TODO: check if this is right... (exclude local broadcast)
 	var destinationNetworkAddress *uint16
 	var destinationLength *uint8
 	var destinationAddress []uint8
diff --git a/plc4go/internal/bacnetip/tests/test_network/helpers.go b/plc4go/internal/bacnetip/tests/test_network/helpers.go
index 0bf42f5..0658803 100644
--- a/plc4go/internal/bacnetip/tests/test_network/helpers.go
+++ b/plc4go/internal/bacnetip/tests/test_network/helpers.go
@@ -138,7 +138,7 @@
 	log zerolog.Logger
 }
 
-func NewSnifferStateMachine(localLog zerolog.Logger, address string, vlan *bacnetip.IPNetwork) (*SnifferStateMachine, error) {
+func NewSnifferStateMachine(localLog zerolog.Logger, address string, vlan *bacnetip.Network) (*SnifferStateMachine, error) {
 	s := &SnifferStateMachine{
 		log: localLog,
 	}
@@ -156,7 +156,7 @@
 	}
 
 	// create a promiscuous node, added to the network
-	s.node, err = bacnetip.NewNode(s.log, s.address, bacnetip.WithNodePromiscuous(true))
+	s.node, err = bacnetip.NewNode(s.log, s.address, bacnetip.WithNodePromiscuous(true), bacnetip.WithNodeLan(vlan))
 	if err != nil {
 		return nil, errors.Wrap(err, "error creating node")
 	}
@@ -185,7 +185,7 @@
 	node  *bacnetip.Node
 }
 
-func NewNetworkLayerStateMachine(localLog zerolog.Logger, address string, vlan *bacnetip.IPNetwork) (*NetworkLayerStateMachine, error) {
+func NewNetworkLayerStateMachine(localLog zerolog.Logger, address string, vlan *bacnetip.Network) (*NetworkLayerStateMachine, error) {
 	n := &NetworkLayerStateMachine{
 		log: localLog,
 	}
@@ -220,4 +220,282 @@
 	return n, nil
 }
 
-//
+type RouterNode struct {
+	nsap *bacnetip.NetworkServiceAccessPoint
+	nse  *_NetworkServiceElement
+
+	log zerolog.Logger
+}
+
+func NewRouterNode(localLog zerolog.Logger) (*RouterNode, error) {
+	r := &RouterNode{log: localLog}
+	var err error
+	// a network service access point will be needed
+	r.nsap, err = bacnetip.NewNetworkServiceAccessPoint(localLog)
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating network service access point")
+	}
+	// give the NSAP a generic network layer service element
+	r.nse, err = new_NetworkServiceElement(localLog)
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating network service element")
+	}
+	err = bacnetip.Bind(localLog, r.nse, r.nsap)
+	if err != nil {
+		return nil, errors.Wrap(err, "error binding")
+	}
+	return r, nil
+}
+
+func (r *RouterNode) AddNetwork(address string, vlan *bacnetip.Network, net uint16) error {
+	r.log.Debug().Str("address", address).Stringer("vlan", vlan).Uint16("net", net).Msg("AddNetwork")
+
+	// convert the address to an Address
+	addr := Address(address)
+
+	// create a node, add to the network
+	node, err := bacnetip.NewNode(r.log, addr, bacnetip.WithNodeLan(vlan))
+	if err != nil {
+		return errors.Wrap(err, "error creating node")
+	}
+
+	// bind the BIP stack to the local network
+	return r.nsap.Bind(node, &net, addr)
+}
+
+func (r *RouterNode) String() string {
+	return fmt.Sprintf("RouterNode")
+}
+
+type RouterStateMachine struct {
+	*RouterNode
+	tests.StateMachine
+}
+
+func NewRouterStateMachine(localLog zerolog.Logger) (*RouterStateMachine, error) {
+	r := &RouterStateMachine{}
+	var err error
+	r.RouterNode, err = NewRouterNode(localLog)
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating router node")
+	}
+	var initFunc func()
+	r.StateMachine, initFunc = tests.NewStateMachine(localLog, r)
+	initFunc()
+	return r, nil
+}
+
+type TestDeviceObject struct {
+	*bacnetip.LocalDeviceObject
+}
+
+type ApplicationLayerStateMachine struct {
+	*bacnetip.ApplicationServiceElement
+	*tests.ClientStateMachine
+
+	name    string
+	address *bacnetip.Address
+
+	asap *bacnetip.ApplicationServiceAccessPoint
+	smap *bacnetip.StateMachineAccessPoint
+	nsap *bacnetip.NetworkServiceAccessPoint
+	nse  *_NetworkServiceElement
+	node *bacnetip.Node
+
+	log zerolog.Logger
+}
+
+func NewApplicationLayerStateMachine(localLog zerolog.Logger, address string, vlan *bacnetip.IPNetwork) (*ApplicationLayerStateMachine, error) {
+	a := &ApplicationLayerStateMachine{
+		log: localLog,
+	}
+
+	// save the name and address
+	a.name = fmt.Sprintf("app @ %s", address)
+	a.address = Address(address)
+
+	// build a local device object
+	localDevice := TestDeviceObject{
+		&bacnetip.LocalDeviceObject{
+			ObjectName:       a.name,
+			ObjectIdentifier: "device:" + address,
+			VendorIdentifier: 999,
+		},
+	}
+
+	a.log.Debug().Stringer("address", a.address).Msg("address")
+
+	var err error
+	// continue with initialization
+	a.ApplicationServiceElement, err = bacnetip.NewApplicationServiceElement(a.log, a)
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating application service")
+	}
+	a.ClientStateMachine, err = tests.NewClientStateMachine(a.log, tests.WithClientStateMachineName(localDevice.ObjectName))
+	if err != nil {
+		return nil, errors.Wrap(err, "error building client state machine")
+	}
+
+	// include a application decoder
+	a.asap, err = bacnetip.NewApplicationServiceAccessPoint(a.log)
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating application service access point")
+	}
+
+	// pass the device object to the state machine access point so it
+	// can know if it should support segmentation
+	// the segmentation state machines need access to some device
+	// information cache, usually shared with the application
+	a.smap, err = bacnetip.NewStateMachineAccessPoint(a.log, localDevice.LocalDeviceObject, bacnetip.WithStateMachineAccessPointDeviceInfoCache(bacnetip.NewDeviceInfoCache(a.log))) // TODO: this is not quite right as we unwrap here
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating state machine access point")
+	}
+
+	//  a network service access point will be needed
+	a.nsap, err = bacnetip.NewNetworkServiceAccessPoint(a.log)
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating network service access point")
+	}
+
+	//  give the NSAP a generic network layer service element
+	a.nse, err = new_NetworkServiceElement(a.log)
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating network service element")
+	}
+	err = bacnetip.Bind(a.log, a.nse, a.nsap)
+	if err != nil {
+		return nil, errors.Wrap(err, "error binding")
+	}
+
+	//  bind the top layers
+	err = bacnetip.Bind(a.log, a, a.asap, a.smap, a.nsap)
+	if err != nil {
+		return nil, errors.Wrap(err, "error binding")
+	}
+
+	//  create a node, added to the network
+	a.node, err = bacnetip.NewNode(a.log, a.address, bacnetip.WithNodeLan(vlan))
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating node")
+	}
+	a.log.Debug().Stringer("node", a.node).Msg("node")
+
+	//  bind the stack to the local network
+	err = a.nsap.Bind(a.node, nil, nil)
+	if err != nil {
+		return nil, errors.Wrap(err, "error binding")
+	}
+
+	return a, nil
+}
+
+func (a *ApplicationLayerStateMachine) Indication(args bacnetip.Args, kwargs bacnetip.KWArgs) error {
+	a.log.Debug().Stringer("Args", args).Stringer("KWArgs", kwargs).Msg("Indication")
+	return a.Receive(args, bacnetip.NoKWArgs)
+}
+
+func (a *ApplicationLayerStateMachine) Confirmation(args bacnetip.Args, kwargs bacnetip.KWArgs) error {
+	a.log.Debug().Stringer("Args", args).Stringer("KWArgs", kwargs).Msg("Confirmation")
+	return a.Receive(args, bacnetip.NoKWArgs)
+}
+
+type ApplicationNode struct {
+	*bacnetip.Application
+	*bacnetip.WhoIsIAmServices
+	*bacnetip.ReadWritePropertyServices
+
+	name    string
+	address *bacnetip.Address
+	asap    *bacnetip.ApplicationServiceAccessPoint
+	smap    *bacnetip.StateMachineAccessPoint
+	nsap    *bacnetip.NetworkServiceAccessPoint
+	nse     *_NetworkServiceElement
+	node    *bacnetip.Node
+
+	log zerolog.Logger
+}
+
+func NewApplicationNode(localLog zerolog.Logger, address string, vlan *bacnetip.IPNetwork) (*ApplicationNode, error) {
+	a := &ApplicationNode{
+		log: localLog,
+	}
+
+	// build a name, save the address
+	a.name = fmt.Sprintf("app @ %s", address)
+	a.address = Address(address)
+
+	// build a local device object
+	localDevice := &TestDeviceObject{
+		LocalDeviceObject: &bacnetip.LocalDeviceObject{
+			ObjectName:       a.name,
+			ObjectIdentifier: "device:999",
+			VendorIdentifier: 999,
+		},
+	}
+
+	var err error
+	// continue with initialization
+	a.Application, err = bacnetip.NewApplication(localLog, localDevice.LocalDeviceObject) //TODO: this is a indirection that wasn't intended... we don't use the annotation yet so that might be fine
+	if err != nil {
+		return nil, errors.Wrap(err, "error building application")
+	}
+
+	// include a application decoder
+	a.asap, err = bacnetip.NewApplicationServiceAccessPoint(localLog)
+	if err != nil {
+		return nil, errors.Wrap(err, "error building application service access point")
+	}
+
+	// pass the device object to the state machine access point so it
+	// can know if it should support segmentation
+	// the segmentation state machines need access to the same device
+	// information cache as the application
+	a.smap, err = bacnetip.NewStateMachineAccessPoint(localLog, localDevice.LocalDeviceObject, bacnetip.WithStateMachineAccessPointDeviceInfoCache(a.GetDeviceInfoCache())) //TODO: this is a indirection that wasn't intended... we don't use the annotation yet so that might be fine
+	if err != nil {
+		return nil, errors.Wrap(err, "error building state machine access point")
+	}
+
+	// a network service access point will be needed
+	a.nsap, err = bacnetip.NewNetworkServiceAccessPoint(localLog)
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating network service access point")
+	}
+
+	// give the NSAP a generic network layer service element
+	a.nse, err = new_NetworkServiceElement(localLog)
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating network service element")
+	}
+	err = bacnetip.Bind(localLog, a.nse, a.nsap)
+	if err != nil {
+		return nil, errors.Wrap(err, "error binding")
+	}
+
+	// bind the top layers
+	err = bacnetip.Bind(localLog, a, a.asap, a.smap, a.nsap)
+	if err != nil {
+		return nil, errors.Wrap(err, "error binding")
+	}
+
+	// create a node, added to the network
+	a.node, err = bacnetip.NewNode(a.log, a.address, bacnetip.WithNodeLan(vlan))
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating node")
+	}
+
+	// bind the stack to the local network
+	err = a.nsap.Bind(a.node, nil, nil)
+	if err != nil {
+		return nil, errors.Wrap(err, "error binding")
+	}
+
+	return a, nil
+}
+
+func xtob(s string) []byte {
+	bytes, err := bacnetip.Xtob(s)
+	if err != nil {
+		panic(err)
+	}
+	return bytes
+}
diff --git a/plc4go/internal/bacnetip/tests/test_network/test_net_1_test.go b/plc4go/internal/bacnetip/tests/test_network/test_net_1_test.go
index d4a0497..22c877d 100644
--- a/plc4go/internal/bacnetip/tests/test_network/test_net_1_test.go
+++ b/plc4go/internal/bacnetip/tests/test_network/test_net_1_test.go
@@ -19,4 +19,187 @@
 
 package test_network
 
-// TODO: implement me
+import (
+	"testing"
+	"time"
+
+	"github.com/rs/zerolog"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"github.com/apache/plc4x/plc4go/internal/bacnetip"
+	"github.com/apache/plc4x/plc4go/internal/bacnetip/tests"
+	"github.com/apache/plc4x/plc4go/spi/testutils"
+)
+
+type TNetwork1 struct {
+	*tests.StateMachineGroup
+
+	vlan1    *bacnetip.Network
+	iut      *RouterNode
+	td       *NetworkLayerStateMachine
+	sniffer1 *SnifferStateMachine
+	vlan2    *bacnetip.Network
+	sniffer2 *SnifferStateMachine
+	vlan3    *bacnetip.Network
+	sniffer3 *SnifferStateMachine
+
+	t *testing.T
+
+	log zerolog.Logger
+}
+
+func NewTNetwork1(t *testing.T) *TNetwork1 {
+	localLog := testutils.ProduceTestingLogger(t)
+	tn := &TNetwork1{
+		t:   t,
+		log: localLog,
+	}
+	tn.StateMachineGroup = tests.NewStateMachineGroup(localLog)
+
+	// reset the time machine
+	tests.ResetTimeMachine(tests.StartTime)
+	localLog.Trace().Msg("time machine reset")
+
+	var err error
+	// implementation under test
+	tn.iut, err = NewRouterNode(tn.log)
+	require.NoError(t, err)
+
+	// make a little LAN
+	tn.vlan1 = bacnetip.NewNetwork(localLog)
+
+	// Test devices
+	tn.td, err = NewNetworkLayerStateMachine(localLog, "1", tn.vlan1)
+	require.NoError(t, err)
+	tn.Append(tn.td)
+
+	// sniffer node
+	tn.sniffer1, err = NewSnifferStateMachine(localLog, "2", tn.vlan1)
+	require.NoError(t, err)
+	tn.Append(tn.sniffer1)
+
+	// add the network
+	err = tn.iut.AddNetwork("3", tn.vlan1, 1)
+	require.NoError(t, err)
+
+	//  make another little LAN
+	tn.vlan2 = bacnetip.NewNetwork(tn.log, bacnetip.WithNetworkName("vlan2"), bacnetip.WithNetworkBroadcastAddress(bacnetip.NewLocalBroadcast(nil)))
+
+	//  sniffer node
+	tn.sniffer2, err = NewSnifferStateMachine(localLog, "4", tn.vlan2)
+	require.NoError(t, err)
+	tn.Append(tn.sniffer2)
+
+	//  add the network
+	err = tn.iut.AddNetwork("5", tn.vlan2, 2)
+	require.NoError(t, err)
+
+	//  make another little LAN
+	tn.vlan3 = bacnetip.NewNetwork(tn.log, bacnetip.WithNetworkName("vlan23"), bacnetip.WithNetworkBroadcastAddress(bacnetip.NewLocalBroadcast(nil)))
+
+	//  sniffer node
+	tn.sniffer3, err = NewSnifferStateMachine(localLog, "6", tn.vlan2)
+	require.NoError(t, err)
+	tn.Append(tn.sniffer3)
+
+	//  add the network
+	err = tn.iut.AddNetwork("7", tn.vlan3, 3)
+	require.NoError(t, err)
+
+	return tn
+}
+
+func (t *TNetwork1) Run(timeLimit time.Duration) {
+	if timeLimit == 0 {
+		timeLimit = 60 * time.Second
+	}
+	t.log.Debug().Dur("time_limit", timeLimit).Msg("run")
+
+	// run the group
+	err := t.StateMachineGroup.Run()
+	require.NoError(t.t, err)
+
+	// run it some time
+	tests.RunTimeMachine(t.log, timeLimit, time.Time{})
+	t.log.Trace().Msg("time machine finished")
+	for _, machine := range t.StateMachineGroup.GetStateMachines() {
+		t.log.Debug().Stringer("machine", machine).Msg("Machine:")
+		for _, s := range machine.GetTransactionLog() {
+			t.log.Debug().Str("logEntry", s).Msg("logEntry")
+		}
+	}
+
+	// check for success
+	success, failed := t.CheckForSuccess()
+	assert.True(t.t, success)
+	assert.False(t.t, failed)
+}
+
+func TestSimple1(t *testing.T) {
+	tests.ExclusiveGlobalTimeMachine(t)
+
+	t.Run("testIdle", func(t *testing.T) {
+		// create a network
+		tnet := NewTNetwork1(t)
+
+		// all start states are successful
+		tnet.td.GetStartState().Success("")
+		tnet.sniffer1.GetStartState().Success("")
+		tnet.sniffer2.GetStartState().Success("")
+		tnet.sniffer3.GetStartState().Success("")
+
+		// run the group
+		tnet.Run(0)
+	})
+}
+
+func TestWhoIsRouterToNetwork(t *testing.T) {
+	t.Skip("Not yet ready") // TODO: finish me
+	tests.ExclusiveGlobalTimeMachine(t)
+
+	t.Run("test_01", func(t *testing.T) {
+		// create a network
+		tnet := NewTNetwork1(t)
+
+		// test device sends request, sees response
+		whois, err := bacnetip.NewWhoIsRouterToNetwork()
+		require.NoError(t, err)
+		whois.SetPDUDestination(bacnetip.NewLocalBroadcast(nil)) // TODO: upstream does this inline
+		tnet.td.GetStartState().Doc("1-1-0").
+			Send(whois, nil).Doc("1-1-1").
+			Receive(bacnetip.NewArgs((*bacnetip.IAmRouterToNetwork)(nil)), bacnetip.NewKWArgs(bacnetip.KWIartnNetworkList, []uint16{2, 3})).Doc("1-1-2").
+			Success("")
+
+		// sniffer on network 1 sees the request and the response
+		tnet.sniffer1.GetStartState().Doc("1-2-0").
+			Receive(bacnetip.NewArgs((bacnetip.PDU)(nil)),
+				bacnetip.NewKWArgs(bacnetip.KWPDUData, xtob(
+					"01.80"+ //version, network layer
+						"00", //message type, no network
+				),
+				),
+			).Doc("1-2-1").
+			Receive(bacnetip.NewArgs((bacnetip.PDU)(nil)),
+				bacnetip.NewKWArgs(bacnetip.KWPDUData, xtob(
+					"01.80"+ //version, network layer
+						"01 0002 0003", //message type and network list
+				),
+				),
+			).Doc("1-2-2").
+			Success("")
+
+		// nothing received on network 2
+		tnet.sniffer2.GetStartState().Doc("1-3-0").
+			Timeout(3*time.Second, nil).Doc("1-3-1").
+			Success("")
+
+		// nothing received on network 3
+		tnet.sniffer3.GetStartState().Doc("1-4-0").
+			Timeout(3*time.Second, nil).Doc("1-4-1").
+			Success("")
+
+		// run the group
+		tnet.Run(0)
+	})
+}
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 a8bab0f..36a81c6 100644
--- a/plc4go/internal/bacnetip/tests/test_npdu/test_codec_test.go
+++ b/plc4go/internal/bacnetip/tests/test_npdu/test_codec_test.go
@@ -26,115 +26,12 @@
 	"github.com/stretchr/testify/suite"
 
 	"github.com/apache/plc4x/plc4go/internal/bacnetip"
+	. "github.com/apache/plc4x/plc4go/internal/bacnetip/constructors"
 	"github.com/apache/plc4x/plc4go/internal/bacnetip/tests"
 	readWriteModel "github.com/apache/plc4x/plc4go/protocols/bacnetip/readwrite/model"
 	"github.com/apache/plc4x/plc4go/spi/testutils"
 )
 
-func WhoIsRouterToNetwork(net uint16) *bacnetip.WhoIsRouterToNetwork {
-	network, err := bacnetip.NewWhoIsRouterToNetwork(bacnetip.WithWhoIsRouterToNetworkNet(net))
-	if err != nil {
-		panic(err)
-	}
-	return network
-}
-
-func IAmRouterToNetwork(netList ...uint16) *bacnetip.IAmRouterToNetwork {
-	network, err := bacnetip.NewIAmRouterToNetwork(bacnetip.WithIAmRouterToNetworkNetworkList(netList...))
-	if err != nil {
-		panic(err)
-	}
-	return network
-}
-
-func ICouldBeRouterToNetwork(net uint16, perf uint8) *bacnetip.ICouldBeRouterToNetwork {
-	network, err := bacnetip.NewICouldBeRouterToNetwork(bacnetip.WithICouldBeRouterToNetworkNetwork(net), bacnetip.WithICouldBeRouterToNetworkPerformanceIndex(perf))
-	if err != nil {
-		panic(err)
-	}
-	return network
-}
-
-func RejectMessageToNetwork(reason uint8, dnet uint16) *bacnetip.RejectMessageToNetwork {
-	network, err := bacnetip.NewRejectMessageToNetwork(bacnetip.WithRejectMessageToNetworkRejectionReason(readWriteModel.NLMRejectMessageToNetworkRejectReason(reason)), bacnetip.WithRejectMessageToNetworkDnet(dnet))
-	if err != nil {
-		panic(err)
-	}
-	return network
-}
-
-func RouterBusyToNetwork(netList ...uint16) *bacnetip.RouterBusyToNetwork {
-	network, err := bacnetip.NewRouterBusyToNetwork(bacnetip.WithRouterBusyToNetworkDnet(netList))
-	if err != nil {
-		panic(err)
-	}
-	return network
-}
-
-func RouterAvailableToNetwork(netList ...uint16) *bacnetip.RouterAvailableToNetwork {
-	network, err := bacnetip.NewRouterAvailableToNetwork(bacnetip.WithRouterAvailableToNetworkDnet(netList))
-	if err != nil {
-		panic(err)
-	}
-	return network
-}
-
-func InitializeRoutingTable(irtTable ...*bacnetip.RoutingTableEntry) *bacnetip.InitializeRoutingTable {
-	network, err := bacnetip.NewInitializeRoutingTable(bacnetip.WithInitializeRoutingTableIrtTable(irtTable...))
-	if err != nil {
-		panic(err)
-	}
-	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
-}
-
-func EstablishConnectionToNetwork(dnet uint16, terminationTime uint8) *bacnetip.EstablishConnectionToNetwork {
-	network, err := bacnetip.NewEstablishConnectionToNetwork(bacnetip.WithEstablishConnectionToNetworkDNET(dnet), bacnetip.WithEstablishConnectionToNetworkTerminationTime(terminationTime))
-	if err != nil {
-		panic(err)
-	}
-	return network
-}
-
-func DisconnectConnectionToNetwork(dnet uint16) *bacnetip.DisconnectConnectionToNetwork {
-	network, err := bacnetip.NewDisconnectConnectionToNetwork(bacnetip.WithDisconnectConnectionToNetworkDNET(dnet))
-	if err != nil {
-		panic(err)
-	}
-	return network
-}
-
-func WhatIsNetworkNumber(dnet uint16) *bacnetip.WhatIsNetworkNumber {
-	network, err := bacnetip.NewWhatIsNetworkNumber()
-	if err != nil {
-		panic(err)
-	}
-	return network
-}
-
-func NetworkNumberIs(net uint16, flag bool) *bacnetip.NetworkNumberIs {
-	network, err := bacnetip.NewNetworkNumberIs(bacnetip.WithNetworkNumberIsNET(net), bacnetip.WithNetworkNumberIsTerminationConfigured(flag))
-	if err != nil {
-		panic(err)
-	}
-	return network
-}
-
 type TestNPDUCodecSuite struct {
 	suite.Suite