1
0
mirror of https://github.com/JoelBender/bacpypes synced 2025-09-28 22:15:23 +08:00
bacpypes/tests/test_service/helpers.py

343 lines
11 KiB
Python

#!/usr/bin/env python
"""
Service Helper Classes
"""
from bacpypes.debugging import bacpypes_debugging, ModuleLogger
from bacpypes.capability import Capability
from bacpypes.comm import Client, bind
from bacpypes.pdu import Address, LocalBroadcast
from bacpypes.npdu import NPDU
from bacpypes.apdu import apdu_types, APDU, SimpleAckPDU, RejectPDU, AbortPDU
from bacpypes.vlan import Network, Node
from bacpypes.app import ApplicationIOController
from bacpypes.appservice import StateMachineAccessPoint, ApplicationServiceAccessPoint
from bacpypes.netservice import NetworkServiceAccessPoint, NetworkServiceElement
from bacpypes.local.device import LocalDeviceObject
from ..state_machine import StateMachine, StateMachineGroup, TrafficLog
from ..time_machine import reset_time_machine, run_time_machine
# some debugging
_debug = 0
_log = ModuleLogger(globals())
#
# ApplicationNetwork
#
@bacpypes_debugging
class ApplicationNetwork(StateMachineGroup):
def __init__(self, test_name):
if _debug: ApplicationNetwork._debug("__init__ %r", test_name)
StateMachineGroup.__init__(self)
# reset the time machine
reset_time_machine()
if _debug: ApplicationNetwork._debug(" - time machine reset")
# create a traffic log
self.traffic_log = TrafficLog()
# make a little LAN
self.vlan = Network(broadcast_address=LocalBroadcast())
self.vlan.traffic_log = self.traffic_log
# test device object
self.td_device_object = LocalDeviceObject(
objectName="td",
objectIdentifier=("device", 10),
maxApduLengthAccepted=1024,
segmentationSupported='noSegmentation',
vendorIdentifier=999,
)
# test device
self.td = ApplicationStateMachine(self.td_device_object, self.vlan)
self.append(self.td)
# implementation under test device object
self.iut_device_object = LocalDeviceObject(
objectName="iut",
objectIdentifier=("device", 20),
maxApduLengthAccepted=1024,
segmentationSupported='noSegmentation',
vendorIdentifier=999,
)
# implementation under test
self.iut = ApplicationStateMachine(self.iut_device_object, self.vlan)
self.append(self.iut)
def run(self, time_limit=60.0):
if _debug: ApplicationNetwork._debug("run %r", time_limit)
# run the group
super(ApplicationNetwork, self).run()
if _debug: ApplicationNetwork._debug(" - group running")
# run it for some time
run_time_machine(time_limit)
if _debug:
ApplicationNetwork._debug(" - time machine finished")
for state_machine in self.state_machines:
ApplicationNetwork._debug(" - machine: %r", state_machine)
for direction, pdu in state_machine.transaction_log:
ApplicationNetwork._debug(" %s %s", direction, str(pdu))
# traffic log has what was processed on each vlan
self.traffic_log.dump(ApplicationNetwork._debug)
# check for success
all_success, some_failed = super(ApplicationNetwork, self).check_for_success()
ApplicationNetwork._debug(" - all_success, some_failed: %r, %r", all_success, some_failed)
assert all_success
#
# SnifferNode
#
class SnifferNode(Client):
def __init__(self, vlan):
if _debug: SnifferNode._debug("__init__ %r", vlan)
# save the name and give it a blank address
self.name = "sniffer"
self.address = Address()
# continue with initialization
Client.__init__(self)
# create a promiscuous node, added to the network
self.node = Node(self.address, vlan, promiscuous=True)
if _debug: SnifferNode._debug(" - node: %r", self.node)
# bind this to the node
bind(self, self.node)
def request(self, pdu):
if _debug: SnifferNode._debug("request(%s) %r", self.name, pdu)
raise RuntimeError("sniffers don't request")
def confirmation(self, pdu):
if _debug: SnifferNode._debug("confirmation(%s) %r", self.name, pdu)
# it's an NPDU
npdu = NPDU()
npdu.decode(pdu)
# filter out network layer traffic if there is any, probably not
if npdu.npduNetMessage is not None:
if _debug: SnifferNode._debug(" - network message: %r", npdu.npduNetMessage)
return
# decode as a generic APDU
apdu = APDU()
apdu.decode(npdu)
# "lift" the source and destination address
if npdu.npduSADR:
apdu.pduSource = npdu.npduSADR
else:
apdu.pduSource = npdu.pduSource
if npdu.npduDADR:
apdu.pduDestination = npdu.npduDADR
else:
apdu.pduDestination = npdu.pduDestination
# make a more focused interpretation
atype = apdu_types.get(apdu.apduType)
if _debug: SnifferNode._debug(" - atype: %r", atype)
xpdu = apdu
apdu = atype()
apdu.decode(xpdu)
print(repr(apdu))
apdu.debug_contents()
print("")
#
# SnifferStateMachine
#
@bacpypes_debugging
class SnifferStateMachine(Client, StateMachine):
def __init__(self, vlan):
if _debug: SnifferStateMachine._debug("__init__ %r", vlan)
# save the name and give it a blank address
self.name = "sniffer"
self.address = Address()
# continue with initialization
Client.__init__(self)
StateMachine.__init__(self)
# create a promiscuous node, added to the network
self.node = Node(self.address, vlan, promiscuous=True)
if _debug: SnifferStateMachine._debug(" - node: %r", self.node)
# bind this to the node
bind(self, self.node)
def send(self, pdu):
if _debug: SnifferStateMachine._debug("send(%s) %r", self.name, pdu)
raise RuntimeError("sniffers don't send")
def confirmation(self, pdu):
if _debug: SnifferStateMachine._debug("confirmation(%s) %r", self.name, pdu)
# it's an NPDU
npdu = NPDU()
npdu.decode(pdu)
# filter out network layer traffic if there is any, probably not
if npdu.npduNetMessage is not None:
if _debug: SnifferStateMachine._debug(" - network message: %r", npdu.npduNetMessage)
return
# decode as a generic APDU
apdu = APDU()
apdu.decode(npdu)
# "lift" the source and destination address
if npdu.npduSADR:
apdu.pduSource = npdu.npduSADR
else:
apdu.pduSource = npdu.pduSource
if npdu.npduDADR:
apdu.pduDestination = npdu.npduDADR
else:
apdu.pduDestination = npdu.pduDestination
# make a more focused interpretation
atype = apdu_types.get(apdu.apduType)
if _debug: SnifferStateMachine._debug(" - atype: %r", atype)
xpdu = apdu
apdu = atype()
apdu.decode(xpdu)
if _debug: SnifferStateMachine._debug(" - apdu: %r", apdu)
# pass to the state machine
self.receive(apdu)
#
# ApplicationStateMachine
#
@bacpypes_debugging
class ApplicationStateMachine(ApplicationIOController, StateMachine):
def __init__(self, localDevice, vlan):
if _debug: ApplicationStateMachine._debug("__init__ %r %r", localDevice, vlan)
# build an address and save it
self.address = Address(localDevice.objectIdentifier[1])
if _debug: ApplicationStateMachine._debug(" - address: %r", self.address)
# continue with initialization
ApplicationIOController.__init__(self, localDevice, self.address)
StateMachine.__init__(self, name=localDevice.objectName)
# include a application decoder
self.asap = ApplicationServiceAccessPoint()
# pass the device object to the state machine access point so it
# can know if it should support segmentation
self.smap = StateMachineAccessPoint(localDevice)
# the segmentation state machines need access to the same device
# information cache as the application
self.smap.deviceInfoCache = self.deviceInfoCache
# a network service access point will be needed
self.nsap = NetworkServiceAccessPoint()
# give the NSAP a generic network layer service element
self.nse = NetworkServiceElement()
bind(self.nse, self.nsap)
# bind the top layers
bind(self, self.asap, self.smap, self.nsap)
# create a node, added to the network
self.node = Node(self.address, vlan)
# bind the network service to the node, no network number
self.nsap.bind(self.node)
def send(self, apdu):
if _debug: ApplicationStateMachine._debug("send(%s) %r", self.name, apdu)
# send the apdu down the stack
self.request(apdu)
def indication(self, apdu):
if _debug: ApplicationStateMachine._debug("indication(%s) %r", self.name, apdu)
# let the state machine know the request was received
self.receive(apdu)
# allow the application to process it
super(ApplicationStateMachine, self).indication(apdu)
def confirmation(self, apdu):
if _debug: ApplicationStateMachine._debug("confirmation(%s) %r", self.name, apdu)
# forward the confirmation to the state machine
self.receive(apdu)
# allow the application to process it
super(ApplicationStateMachine, self).confirmation(apdu)
#
# COVTestClientServices
#
@bacpypes_debugging
class COVTestClientServices(Capability):
def do_ConfirmedCOVNotificationRequest(self, apdu):
if _debug: COVTestClientServices._debug("do_ConfirmedCOVNotificationRequest %r", apdu)
# the test device needs to set these
assert hasattr(self, 'test_ack')
assert hasattr(self, 'test_reject')
assert hasattr(self, 'test_abort')
if self.test_ack:
# success
response = SimpleAckPDU(context=apdu)
if _debug: COVTestClientServices._debug(" - simple_ack: %r", response)
elif self.test_reject:
# reject
response = RejectPDU(reason=self.test_reject, context=apdu)
if _debug: COVTestClientServices._debug(" - reject: %r", response)
elif self.test_abort:
# abort
response = AbortPDU(reason=self.test_abort, context=apdu)
if _debug: COVTestClientServices._debug(" - abort: %r", response)
# return the result
self.response(response)
def do_UnconfirmedCOVNotificationRequest(self, apdu):
if _debug: COVTestClientServices._debug("do_UnconfirmedCOVNotificationRequest %r", apdu)