From 197a405ec7279265822ccc7edae244e5b1c1102b Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Fri, 19 Apr 2019 09:54:22 -0400 Subject: [PATCH] merge #207 into stage for next release --- py25/bacpypes/apdu.py | 2 +- py25/bacpypes/constructeddata.py | 46 +++++++++- py27/bacpypes/apdu.py | 7 +- py27/bacpypes/constructeddata.py | 44 ++++++++- py34/bacpypes/apdu.py | 2 +- py34/bacpypes/constructeddata.py | 44 ++++++++- samples/ReadRange.py | 116 ++++++++++++++++++------ samples/ReadRangeServer.py | 148 +++++++++++++++++++++++++++++++ 8 files changed, 374 insertions(+), 35 deletions(-) create mode 100755 samples/ReadRangeServer.py diff --git a/py25/bacpypes/apdu.py b/py25/bacpypes/apdu.py index f67fab2..4fa8279 100755 --- a/py25/bacpypes/apdu.py +++ b/py25/bacpypes/apdu.py @@ -927,7 +927,7 @@ class RangeByPosition(Sequence): class RangeBySequenceNumber(Sequence): sequenceElements = \ - [ Element('referenceIndex', Unsigned) + [ Element('referenceSequenceNumber', Unsigned) , Element('count', Integer) ] diff --git a/py25/bacpypes/constructeddata.py b/py25/bacpypes/constructeddata.py index 6d04f93..d483cfc 100755 --- a/py25/bacpypes/constructeddata.py +++ b/py25/bacpypes/constructeddata.py @@ -7,7 +7,7 @@ Constructed Data import sys from copy import deepcopy as _deepcopy -from .errors import DecodingError, \ +from .errors import DecodingError, EncodingError, \ MissingRequiredParameter, InvalidParameterDatatype, InvalidTag from .debugging import ModuleLogger, bacpypes_debugging @@ -1461,3 +1461,47 @@ class AnyAtomic(Atomic): bacpypes_debugging(AnyAtomic) +# +# SequenceOfAny +# + +class SequenceOfAny(Any): + + def cast_in(self, element): + """encode the element into the internal tag list.""" + if _debug: SequenceOfAny._debug("cast_in %r", element) + + # make sure it is a list + if not isinstance(element, List): + raise EncodingError("%r is not a list" % (element,)) + + t = TagList() + element.encode(t) + + self.tagList.extend(t.tagList) + + def cast_out(self, klass): + """Interpret the content as a particular class.""" + if _debug: SequenceOfAny._debug("cast_out %r", klass) + + # make sure it is a list + if not issubclass(klass, List): + raise DecodingError("%r is not a list" % (klass,)) + + # build a helper + helper = klass() + + # make a copy of the tag list + t = TagList(self.tagList[:]) + + # let it decode itself + helper.decode(t) + + # make sure everything was consumed + if len(t) != 0: + raise DecodingError("incomplete cast") + + return helper.value + +bacpypes_debugging(AnyAtomic) + diff --git a/py27/bacpypes/apdu.py b/py27/bacpypes/apdu.py index c19a811..3062bd7 100755 --- a/py27/bacpypes/apdu.py +++ b/py27/bacpypes/apdu.py @@ -11,7 +11,8 @@ from .pdu import PCI, PDUData from .primitivedata import Boolean, CharacterString, Enumerated, Integer, \ ObjectIdentifier, ObjectType, OctetString, Real, TagList, Unsigned, \ expand_enumerations -from .constructeddata import Any, Choice, Element, Sequence, SequenceOf +from .constructeddata import Any, Choice, Element, Sequence, SequenceOf, \ + SequenceOfAny from .basetypes import ChannelValue, DateTime, DeviceAddress, ErrorType, \ EventState, EventTransitionBits, EventType, LifeSafetyOperation, \ NotificationParameters, NotifyType, ObjectPropertyReference, \ @@ -920,7 +921,7 @@ class RangeByPosition(Sequence): class RangeBySequenceNumber(Sequence): sequenceElements = \ - [ Element('referenceIndex', Unsigned) + [ Element('referenceSequenceNumber', Unsigned) , Element('count', Integer) ] @@ -956,7 +957,7 @@ class ReadRangeACK(ComplexAckSequence): , Element('propertyArrayIndex', Unsigned, 2, True) , Element('resultFlags', ResultFlags, 3) , Element('itemCount', Unsigned, 4) - , Element('itemData', SequenceOf(Any), 5) + , Element('itemData', SequenceOfAny, 5) , Element('firstSequenceNumber', Unsigned, 6, True) ] diff --git a/py27/bacpypes/constructeddata.py b/py27/bacpypes/constructeddata.py index 8dd27af..c343160 100755 --- a/py27/bacpypes/constructeddata.py +++ b/py27/bacpypes/constructeddata.py @@ -7,7 +7,7 @@ Constructed Data import sys from copy import deepcopy as _deepcopy -from .errors import DecodingError, \ +from .errors import DecodingError, EncodingError, \ MissingRequiredParameter, InvalidParameterDatatype, InvalidTag from .debugging import ModuleLogger, bacpypes_debugging @@ -1452,3 +1452,45 @@ class AnyAtomic(Atomic): return '<' + desc + ' instance at 0x%08x' % (id(self),) + '>' +# +# SequenceOfAny +# + +@bacpypes_debugging +class SequenceOfAny(Any): + + def cast_in(self, element): + """encode the element into the internal tag list.""" + if _debug: SequenceOfAny._debug("cast_in %r", element) + + # make sure it is a list + if not isinstance(element, List): + raise EncodingError("%r is not a list" % (element,)) + + t = TagList() + element.encode(t) + + self.tagList.extend(t.tagList) + + def cast_out(self, klass): + """Interpret the content as a particular class.""" + if _debug: SequenceOfAny._debug("cast_out %r", klass) + + # make sure it is a list + if not issubclass(klass, List): + raise DecodingError("%r is not a list" % (klass,)) + + # build a helper + helper = klass() + + # make a copy of the tag list + t = TagList(self.tagList[:]) + + # let it decode itself + helper.decode(t) + + # make sure everything was consumed + if len(t) != 0: + raise DecodingError("incomplete cast") + + return helper.value diff --git a/py34/bacpypes/apdu.py b/py34/bacpypes/apdu.py index c19a811..acf2c1a 100755 --- a/py34/bacpypes/apdu.py +++ b/py34/bacpypes/apdu.py @@ -920,7 +920,7 @@ class RangeByPosition(Sequence): class RangeBySequenceNumber(Sequence): sequenceElements = \ - [ Element('referenceIndex', Unsigned) + [ Element('referenceSequenceNumber', Unsigned) , Element('count', Integer) ] diff --git a/py34/bacpypes/constructeddata.py b/py34/bacpypes/constructeddata.py index 8dd27af..c343160 100755 --- a/py34/bacpypes/constructeddata.py +++ b/py34/bacpypes/constructeddata.py @@ -7,7 +7,7 @@ Constructed Data import sys from copy import deepcopy as _deepcopy -from .errors import DecodingError, \ +from .errors import DecodingError, EncodingError, \ MissingRequiredParameter, InvalidParameterDatatype, InvalidTag from .debugging import ModuleLogger, bacpypes_debugging @@ -1452,3 +1452,45 @@ class AnyAtomic(Atomic): return '<' + desc + ' instance at 0x%08x' % (id(self),) + '>' +# +# SequenceOfAny +# + +@bacpypes_debugging +class SequenceOfAny(Any): + + def cast_in(self, element): + """encode the element into the internal tag list.""" + if _debug: SequenceOfAny._debug("cast_in %r", element) + + # make sure it is a list + if not isinstance(element, List): + raise EncodingError("%r is not a list" % (element,)) + + t = TagList() + element.encode(t) + + self.tagList.extend(t.tagList) + + def cast_out(self, klass): + """Interpret the content as a particular class.""" + if _debug: SequenceOfAny._debug("cast_out %r", klass) + + # make sure it is a list + if not issubclass(klass, List): + raise DecodingError("%r is not a list" % (klass,)) + + # build a helper + helper = klass() + + # make a copy of the tag list + t = TagList(self.tagList[:]) + + # let it decode itself + helper.decode(t) + + # make sure everything was consumed + if len(t) != 0: + raise DecodingError("incomplete cast") + + return helper.value diff --git a/samples/ReadRange.py b/samples/ReadRange.py index 97f8211..b137327 100755 --- a/samples/ReadRange.py +++ b/samples/ReadRange.py @@ -1,9 +1,9 @@ #!/usr/bin/env python """ -This application presents a 'console' prompt to the user asking for readrange commands -which create ReadRangeRequest PDUs, then lines up the coorresponding ReadRangeACK -and prints the value. +This application presents a 'console' prompt to the user asking for readrange +commands which create ReadRangeRequest PDUs, then lines up the coorresponding +ReadRangeACK and prints the value. """ import sys @@ -17,10 +17,19 @@ from bacpypes.iocb import IOCB from bacpypes.pdu import Address from bacpypes.object import get_datatype -from bacpypes.apdu import ReadRangeRequest, ReadRangeACK +from bacpypes.apdu import ( + ReadRangeRequest, + Range, + RangeByPosition, + RangeBySequenceNumber, + RangeByTime, + ReadRangeACK, +) from bacpypes.app import BIPSimpleApplication -from bacpypes.primitivedata import ObjectIdentifier +from bacpypes.primitivedata import Date, Time, ObjectIdentifier +from bacpypes.constructeddata import Array, List +from bacpypes.basetypes import DateTime from bacpypes.local.device import LocalDeviceObject # some debugging @@ -34,17 +43,23 @@ this_application = None # ReadRangeConsoleCmd # + @bacpypes_debugging class ReadRangeConsoleCmd(ConsoleCmd): - def do_readrange(self, args): - """readrange [ ]""" + """readrange [ ] + [ p ] + [ s ] + [ t