Skip to content

Commit c4a4c65

Browse files
committed
fix #28: return an unknown XBee packet when the received packet is not
supported by the library instead of raising an exception Signed-off-by: Ruben Moral <ruben.moral@digi.com>
1 parent 55570cd commit c4a4c65

File tree

3 files changed

+106
-9
lines changed

3 files changed

+106
-9
lines changed

digi/xbee/packets/aft.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class ApiFrameType(Enum):
5858
DEVICE_RESPONSE_STATUS = (0xBA, "Device Response Status")
5959
FRAME_ERROR = (0xFE, "Frame Error")
6060
GENERIC = (0xFF, "Generic")
61+
UNKNOWN = (-1, "Unknown Packet")
6162

6263
def __init__(self, code, description):
6364
self.__code = code
@@ -90,13 +91,13 @@ def get(cls, code):
9091
code (Integer): the code of the API frame type to get.
9192
9293
Returns:
93-
:class:`.ApiFrameType`: the API frame type associated to the given code or ``None`` if
94+
:class:`.ApiFrameType`: the API frame type associated to the given code or ``UNKNOWN`` if
9495
the given code is not a valid ApiFrameType code.
9596
"""
9697
try:
9798
return cls.lookupTable[code]
9899
except KeyError:
99-
return None
100+
return ApiFrameType.UNKNOWN
100101

101102
code = property(__get_code)
102103
"""Integer. The API frame type code."""

digi/xbee/packets/base.py

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,14 +284,20 @@ def __init__(self, api_frame_type):
284284
Class constructor. Instantiates a new :class:`.XBeeAPIPacket` object with the provided parameters.
285285
286286
Args:
287-
api_frame_type (:class:`.ApiFrameType`): The API frame type.
287+
api_frame_type (:class:`.ApiFrameType` or Integer): The API frame type.
288288
289289
.. seealso::
290290
| :class:`.ApiFrameType`
291291
| :class:`.XBeePacket`
292292
"""
293293
super().__init__()
294-
self._frame_type = api_frame_type
294+
# Check the type of the API frame type.
295+
if isinstance(api_frame_type, ApiFrameType):
296+
self._frame_type = api_frame_type
297+
self._frame_type_value = api_frame_type.code
298+
else:
299+
self._frame_type = ApiFrameType.get(api_frame_type)
300+
self._frame_type_value = api_frame_type
295301
self._frame_id = 0
296302

297303
def get_frame_spec_data(self):
@@ -304,7 +310,7 @@ def get_frame_spec_data(self):
304310
data = self._get_api_packet_spec_data()
305311
if self.needs_id():
306312
data.insert(0, self._frame_id)
307-
data.insert(0, self._frame_type.code)
313+
data.insert(0, self._frame_type_value)
308314
return data
309315

310316
def get_frame_type(self):
@@ -319,6 +325,18 @@ def get_frame_type(self):
319325
"""
320326
return self._frame_type
321327

328+
def get_frame_type_value(self):
329+
"""
330+
Returns the frame type integer value of this packet.
331+
332+
Returns:
333+
Integer: the frame type integer value of this packet.
334+
335+
.. seealso::
336+
| :class:`.ApiFrameType`
337+
"""
338+
return self._frame_type_value
339+
322340
def _get_frame_spec_data_dict(self):
323341
"""
324342
Override method.
@@ -516,3 +534,84 @@ def _get_api_packet_spec_data_dict(self):
516534
| :meth:`.XBeeAPIPacket._get_api_packet_spec_data_dict`
517535
"""
518536
return {DictKeys.RF_DATA: self.__rf_data}
537+
538+
539+
class UnknownXBeePacket(XBeeAPIPacket):
540+
"""
541+
This class represents an unknown XBee packet.
542+
543+
.. seealso::
544+
| :class:`.XBeeAPIPacket`
545+
"""
546+
547+
__MIN_PACKET_LENGTH = 5
548+
549+
def __init__(self, api_frame, rf_data):
550+
"""
551+
Class constructor. Instantiates a :class:`.UnknownXBeePacket` object with the provided parameters.
552+
553+
Args:
554+
api_frame (Integer): the API frame integer value of this packet.
555+
rf_data (bytearray): the frame specific data without frame type and frame ID.
556+
557+
.. seealso::
558+
| :mod:`.factory`
559+
| :class:`.XBeeAPIPacket`
560+
"""
561+
super().__init__(api_frame_type=api_frame)
562+
self.__rf_data = rf_data
563+
564+
@staticmethod
565+
def create_packet(raw, operating_mode=OperatingMode.API_MODE):
566+
"""
567+
Override method.
568+
569+
Returns:
570+
:class:`.UnknownXBeePacket`: the UnknownXBeePacket generated.
571+
572+
Raises:
573+
InvalidPacketException: if the bytearray length is less than 5. (start delim. + length (2 bytes) +
574+
frame type + checksum = 5 bytes).
575+
InvalidPacketException: if the length field of 'raw' is different than its real length. (length field: bytes
576+
2 and 3)
577+
InvalidPacketException: if the first byte of 'raw' is not the header byte. See :class:`.SpecialByte`.
578+
InvalidPacketException: if the calculated checksum is different than the checksum field value (last byte).
579+
InvalidOperatingModeException: if ``operating_mode`` is not supported.
580+
581+
.. seealso::
582+
| :meth:`.XBeePacket.create_packet`
583+
| :meth:`.XBeeAPIPacket._check_api_packet`
584+
"""
585+
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
586+
raise InvalidOperatingModeException(operating_mode + " is not supported.")
587+
588+
XBeeAPIPacket._check_api_packet(raw, min_length=UnknownXBeePacket.__MIN_PACKET_LENGTH)
589+
590+
return UnknownXBeePacket(raw[3], raw[4:-1])
591+
592+
def _get_api_packet_spec_data(self):
593+
"""
594+
Override method.
595+
596+
.. seealso::
597+
| :meth:`.XBeeAPIPacket._get_api_packet_spec_data`
598+
"""
599+
return bytearray(self.__rf_data)
600+
601+
def needs_id(self):
602+
"""
603+
Override method.
604+
605+
.. seealso::
606+
| :meth:`.XBeeAPIPacket.needs_id`
607+
"""
608+
return False
609+
610+
def _get_api_packet_spec_data_dict(self):
611+
"""
612+
Override method.
613+
614+
.. seealso::
615+
| :meth:`.XBeeAPIPacket._get_api_packet_spec_data_dict`
616+
"""
617+
return {DictKeys.RF_DATA: self.__rf_data}

digi/xbee/packets/factory.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,6 @@ def build_frame(packet_bytearray, operating_mode=OperatingMode.API_MODE):
108108
Args:
109109
packet_bytearray (Bytearray): the raw data of the packet to build.
110110
operating_mode (:class:`.OperatingMode`): the operating mode in which the raw data has been captured.
111-
112-
Raises:
113-
NotImplementedError: if the packet defined by the bytearray is not supported.
114111
115112
.. seealso::
116113
| :class:`.OperatingMode`
@@ -208,4 +205,4 @@ def build_frame(packet_bytearray, operating_mode=OperatingMode.API_MODE):
208205
return FrameErrorPacket.create_packet(packet_bytearray, operating_mode)
209206

210207
else:
211-
raise NotImplementedError("Frame type " + str(frame_type) + " is not supported.")
208+
return UnknownXBeePacket.create_packet(packet_bytearray, operating_mode)

0 commit comments

Comments
 (0)