Skip to content

Commit

Permalink
operating_mode: fix packet reader function to correctly escape the bytes
Browse files Browse the repository at this point in the history
- Transformed _unescape_data() method to public.
- Removed all unnecesary calls to unescape_data() from create_packet methods.
- Replaced __read_next_packet() method by a search in the xbee packet queue.

Signed-off-by: Héctor González <[email protected]>
Signed-off-by: Diego Escalona <[email protected]>
  • Loading branch information
hgonzaleDigi authored and diescalo committed Jan 18, 2018
1 parent e102693 commit 17e21a3
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 128 deletions.
51 changes: 13 additions & 38 deletions digi/xbee/devices.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2017, Digi International Inc.
# Copyright 2017, 2018, Digi International Inc.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
Expand All @@ -24,7 +24,6 @@

from digi.xbee.packets.cellular import TXSMSPacket
from digi.xbee.models.accesspoint import AccessPoint, WiFiEncryptionType
from digi.xbee.models.atcomm import SpecialByte
from digi.xbee.models.hw import HardwareVersion
from digi.xbee.models.mode import OperatingMode, APIOutputMode, IPAddressingMode
from digi.xbee.models.address import XBee64BitAddress, XBee16BitAddress, XBeeIMEIAddress
Expand All @@ -34,7 +33,6 @@
from digi.xbee.models.status import ATCommandStatus, TransmitStatus, PowerLevel, \
ModemStatus, CellularAssociationIndicationStatus, WiFiAssociationIndicationStatus, AssociationIndicationStatus,\
NetworkDiscoveryStatus
from digi.xbee.packets import factory
from digi.xbee.packets.aft import ApiFrameType
from digi.xbee.packets.common import ATCommPacket, TransmitPacket, RemoteATCommandPacket, ExplicitAddressingPacket
from digi.xbee.packets.network import TXIPv4Packet
Expand Down Expand Up @@ -108,6 +106,8 @@ def __init__(self, local_xbee_device=None, serial_port=None, sync_ops_timeout=_D
self._protocol = None
self._node_id = None

self._packet_listener = None

self._log.addHandler(logging.NullHandler())

self.__generic_lock = threading.Lock()
Expand Down Expand Up @@ -1055,13 +1055,14 @@ def _get_packet_by_id(self, frame_id):
ValueError: if ``frame_id`` is less than 0 or greater than 255.
TimeoutException: if there was not any XBee packet matching the provided frame ID that could be read.
"""
operating_mode = OperatingMode.API_MODE if self.is_remote() else self._operating_mode
if not (0 <= frame_id <= 255):
raise ValueError("Frame ID must be between 0 and 255.")
packet_read = factory.build_frame(self.__read_next_packet(), operating_mode)
while not packet_read.needs_id() or packet_read.frame_id != frame_id:
packet_read = factory.build_frame(self.__read_next_packet(), operating_mode)
return packet_read

queue = self._packet_listener.get_queue()

packet = queue.get_by_id(frame_id, XBeeDevice.TIMEOUT_READ_PACKET)

return packet

@staticmethod
def __is_api_packet(xbee_packet):
Expand All @@ -1079,31 +1080,6 @@ def __is_api_packet(xbee_packet):
return False
return True

def __read_next_packet(self):
"""
Reads the next XBee packet. Starts to read when finds the start delimiter.
The last byte read is the checksum.
If there is something in the COM port buffer before the
start delimiter, this method discards it.
Returns:
:class:XBeePacket: the next XBee packet read.
Raises:
TimeoutException: if it could not read any new XBee packet.
"""
xbee_packet = bytearray(1)
xbee_packet[0] = self._serial_port.read_byte()
while xbee_packet[0] != SpecialByte.HEADER_BYTE.code:
xbee_packet[0] = self._serial_port.read_byte()
packet_length = self._serial_port.read_bytes(2)
xbee_packet += packet_length
length = utils.length_to_int(packet_length)
xbee_packet += self._serial_port.read_bytes(length)
xbee_packet.append(self._serial_port.read_byte())
return xbee_packet

def __get_log(self):
"""
Returns the XBee device log.
Expand Down Expand Up @@ -1147,7 +1123,7 @@ class XBeeDevice(AbstractXBeeDevice):
Timeout to wait when resetting the module.
"""

_TIMEOUT_READ_PACKET = 3 # seconds
TIMEOUT_READ_PACKET = 3 # seconds
"""
Timeout to read packets.
"""
Expand Down Expand Up @@ -1203,7 +1179,6 @@ def __init__(self, port, baud_rate, data_bits=serial.EIGHTBITS, stop_bits=serial

self._network = XBeeNetwork(self)

self._packet_listener = None
self.__packet_queue = None
self.__data_queue = None
self.__explicit_queue = None
Expand Down Expand Up @@ -2463,7 +2438,7 @@ def send_packet(self, packet, sync=False):
This method can be synchronous or asynchronous.
If is synchronous, this method will discards all response
If is synchronous, this method will discard all response
packets until it finds the one that has the appropriate frame ID,
that is, the sent packet's frame ID.
Expand Down Expand Up @@ -3481,7 +3456,7 @@ def send_ip_data_broadcast(self, dest_port, data):
return self.send_ip_data(IPv4Address(self.BROADCAST_IP), dest_port, IPProtocol.UDP, data)

@AbstractXBeeDevice._before_send_method
def read_ip_data(self, timeout=XBeeDevice._TIMEOUT_READ_PACKET):
def read_ip_data(self, timeout=XBeeDevice.TIMEOUT_READ_PACKET):
"""
Reads new IP data received by this XBee device during the
provided timeout.
Expand Down Expand Up @@ -3512,7 +3487,7 @@ def read_ip_data(self, timeout=XBeeDevice._TIMEOUT_READ_PACKET):
return self.__read_ip_data_packet(timeout)

@AbstractXBeeDevice._before_send_method
def read_ip_data_from(self, ip_addr, timeout=XBeeDevice._TIMEOUT_READ_PACKET):
def read_ip_data_from(self, ip_addr, timeout=XBeeDevice.TIMEOUT_READ_PACKET):
"""
Reads new IP data received from the given IP address during the
provided timeout.
Expand Down
12 changes: 5 additions & 7 deletions digi/xbee/packets/base.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2017, Digi International Inc.
# Copyright 2017, 2018, Digi International Inc.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
Expand Down Expand Up @@ -229,7 +229,7 @@ def _escape_data(data):
return esc_data

@staticmethod
def _unescape_data(data):
def unescape_data(data):
"""
Un-escapes the provided bytearray data.
Expand Down Expand Up @@ -482,15 +482,13 @@ def create_packet(raw, operating_mode=OperatingMode.API_MODE):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode + " is not supported.")

unesc_raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw
XBeeAPIPacket._check_api_packet(raw, min_length=GenericXBeePacket.__MIN_PACKET_LENGTH)

XBeeAPIPacket._check_api_packet(unesc_raw, min_length=GenericXBeePacket.__MIN_PACKET_LENGTH)

if unesc_raw[3] != ApiFrameType.GENERIC.code:
if raw[3] != ApiFrameType.GENERIC.code:
raise InvalidPacketException("Wrong frame type, expected: " + ApiFrameType.GENERIC.description +
". Value: " + ApiFrameType.GENERIC.code)

return GenericXBeePacket(unesc_raw[4:-1])
return GenericXBeePacket(raw[4:-1])

def _get_api_packet_spec_data(self):
"""
Expand Down
18 changes: 8 additions & 10 deletions digi/xbee/packets/cellular.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2017, Digi International Inc.
# Copyright 2017, 2018, Digi International Inc.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
Expand Down Expand Up @@ -83,13 +83,12 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

_raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw

XBeeAPIPacket._check_api_packet(_raw, min_length=RXSMSPacket.__MIN_PACKET_LENGTH)
if _raw[3] != ApiFrameType.RX_SMS.code:
XBeeAPIPacket._check_api_packet(raw, min_length=RXSMSPacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.RX_SMS.code:
raise InvalidPacketException("This packet is not an RXSMSPacket")

return RXSMSPacket(_raw[4:23].decode("utf8").replace("\0", ""), _raw[24:-1].decode("utf8"))
return RXSMSPacket(raw[4:23].decode("utf8").replace("\0", ""), raw[24:-1].decode("utf8"))

def needs_id(self):
"""
Expand Down Expand Up @@ -252,13 +251,12 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

_raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw

XBeeAPIPacket._check_api_packet(raw, min_length=TXSMSPacket.__MIN_PACKET_LENGTH)
if _raw[3] != ApiFrameType.TX_SMS.code:

if raw[3] != ApiFrameType.TX_SMS.code:
raise InvalidPacketException("This packet is not a TXSMSPacket")

return TXSMSPacket(_raw[4], _raw[6:25].decode("utf8").replace("\0", ""), _raw[26:-1].decode("utf8"))
return TXSMSPacket(raw[4], raw[6:25].decode("utf8").replace("\0", ""), raw[26:-1].decode("utf8"))

def needs_id(self):
"""
Expand Down
21 changes: 1 addition & 20 deletions digi/xbee/packets/common.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2017, Digi International Inc.
# Copyright 2017, 2018, Digi International Inc.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
Expand Down Expand Up @@ -91,7 +91,6 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw
XBeeAPIPacket._check_api_packet(raw, min_length=ATCommPacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.AT_COMMAND.code:
Expand Down Expand Up @@ -253,8 +252,6 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw

XBeeAPIPacket._check_api_packet(raw, min_length=ATCommResponsePacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.AT_COMMAND_RESPONSE.code:
Expand Down Expand Up @@ -441,8 +438,6 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw

XBeeAPIPacket._check_api_packet(raw, min_length=ReceivePacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.RECEIVE_PACKET.code:
Expand Down Expand Up @@ -678,8 +673,6 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw

XBeeAPIPacket._check_api_packet(raw, min_length=RemoteATCommandPacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.REMOTE_AT_COMMAND_REQUEST.code:
Expand Down Expand Up @@ -937,8 +930,6 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw

XBeeAPIPacket._check_api_packet(raw, min_length=RemoteATCommandResponsePacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.REMOTE_AT_COMMAND_RESPONSE.code:
Expand Down Expand Up @@ -1211,8 +1202,6 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw

XBeeAPIPacket._check_api_packet(raw, min_length=TransmitPacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.TRANSMIT_REQUEST.code:
Expand Down Expand Up @@ -1463,8 +1452,6 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw

XBeeAPIPacket._check_api_packet(raw, min_length=TransmitStatusPacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.TRANSMIT_STATUS.code:
Expand Down Expand Up @@ -1663,8 +1650,6 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw

XBeeAPIPacket._check_api_packet(raw, min_length=ModemStatusPacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.MODEM_STATUS.code:
Expand Down Expand Up @@ -1799,8 +1784,6 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw

XBeeAPIPacket._check_api_packet(raw, min_length=IODataSampleRxIndicatorPacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.IO_DATA_SAMPLE_RX_INDICATOR.code:
Expand Down Expand Up @@ -2150,7 +2133,6 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw
XBeeAPIPacket._check_api_packet(raw, min_length=ExplicitAddressingPacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.EXPLICIT_ADDRESSING.code:
Expand Down Expand Up @@ -2511,7 +2493,6 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw
XBeeAPIPacket._check_api_packet(raw, min_length=ExplicitRXIndicatorPacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.EXPLICIT_RX_INDICATOR.code:
Expand Down
8 changes: 1 addition & 7 deletions digi/xbee/packets/devicecloud.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2017, Digi International Inc.
# Copyright 2017, 2018, Digi International Inc.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
Expand Down Expand Up @@ -90,7 +90,6 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw
XBeeAPIPacket._check_api_packet(raw, min_length=DeviceRequestPacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.DEVICE_REQUEST.code:
Expand Down Expand Up @@ -312,7 +311,6 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw
XBeeAPIPacket._check_api_packet(raw, min_length=DeviceResponsePacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.DEVICE_RESPONSE.code:
Expand Down Expand Up @@ -469,7 +467,6 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw
XBeeAPIPacket._check_api_packet(raw, min_length=DeviceResponseStatusPacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.DEVICE_RESPONSE_STATUS.code:
Expand Down Expand Up @@ -585,7 +582,6 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw
XBeeAPIPacket._check_api_packet(raw, min_length=FrameErrorPacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.FRAME_ERROR.code:
Expand Down Expand Up @@ -719,7 +715,6 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw
XBeeAPIPacket._check_api_packet(raw, min_length=SendDataRequestPacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.SEND_DATA_REQUEST.code:
Expand Down Expand Up @@ -939,7 +934,6 @@ def create_packet(raw, operating_mode):
if operating_mode != OperatingMode.ESCAPED_API_MODE and operating_mode != OperatingMode.API_MODE:
raise InvalidOperatingModeException(operating_mode.name + " is not supported.")

raw = XBeeAPIPacket._unescape_data(raw) if operating_mode == OperatingMode.ESCAPED_API_MODE else raw
XBeeAPIPacket._check_api_packet(raw, min_length=SendDataResponsePacket.__MIN_PACKET_LENGTH)

if raw[3] != ApiFrameType.SEND_DATA_RESPONSE.code:
Expand Down
Loading

0 comments on commit 17e21a3

Please sign in to comment.