Skip to content

Commit d2c8a4a

Browse files
mikewadstentatianaleon
authored andcommitted
firmware: add support for XBee XR modules
* The ATVH command on XR returns the value differently than other XBee 3 or RR devices. * _XBEE3_BOOTLOADER_FILE_PREFIX was missing an entry for XR. * Profile code now will treat a .gbl file as a possible OTA firmware image. https://onedigi.atlassian.net/browse/LCG-631
1 parent 9c51c56 commit d2c8a4a

File tree

5 files changed

+98
-33
lines changed

5 files changed

+98
-33
lines changed

CHANGELOG.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ v1.4.2 - XX/XX/202X
1717
* Support to retrieve XBee statistics.
1818
* Send/receive explicit data in 802.15.4.
1919
(XBee 3 modules support this feature)
20+
* Support for local and remote firmware update of XBee XR 868 and 900.
2021
* Bug fixing:
2122

2223
* Fix order of nodes when creating a Zigbee source route (#278)
@@ -29,8 +30,8 @@ v1.4.1 - 12/22/2021
2930
* XBee 3 Cellular LTE-M/NB-IoT (Telit)
3031
* XBee 3 Reduced RAM
3132
* S2C P5
32-
* XB3-DMLR
33-
* XB3-DMLR868
33+
* XBee XR 900
34+
* XBee XR 868
3435
* OTA firmware update:
3536

3637
* Implementation of considerations for versions 1009, 300A, 200A or prior

digi/xbee/firmware.py

Lines changed: 68 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
from digi.xbee.models.hw import HardwareVersion
4040
from digi.xbee.models.mode import APIOutputModeBit
4141
from digi.xbee.models.options import RemoteATCmdOptions
42-
from digi.xbee.models.protocol import XBeeProtocol, Role, Region
42+
from digi.xbee.models.protocol import XBeeProtocol, Role, Region, OTAMethod
4343
from digi.xbee.models.status import TransmitStatus, ATCommandStatus, \
4444
EmberBootloaderMessageType, ModemStatus, UpdateProgressStatus, NodeUpdateType
4545
from digi.xbee.packets.aft import ApiFrameType
@@ -81,12 +81,17 @@
8181

8282
_XBEE3_BL_DEF_PREFIX = "xb3-boot-rf_"
8383
_XBEE3_RR_BL_DEF_PREFIX = "xb3-boot-rr_"
84+
_XBEE3_XR_BL_DEF_PREFIX = "xb3-boot-lr_"
8485
_XBEE3_BOOTLOADER_FILE_PREFIX = {
8586
HardwareVersion.XBEE3.code: _XBEE3_BL_DEF_PREFIX,
8687
HardwareVersion.XBEE3_SMT.code: _XBEE3_BL_DEF_PREFIX,
8788
HardwareVersion.XBEE3_TH.code: _XBEE3_BL_DEF_PREFIX,
8889
HardwareVersion.XBEE3_RR.code: _XBEE3_RR_BL_DEF_PREFIX,
89-
HardwareVersion.XBEE3_RR_TH.code: _XBEE3_RR_BL_DEF_PREFIX
90+
HardwareVersion.XBEE3_RR_TH.code: _XBEE3_RR_BL_DEF_PREFIX,
91+
HardwareVersion.XBEE3_DM_LR.code: _XBEE3_XR_BL_DEF_PREFIX,
92+
HardwareVersion.XBEE3_DM_LR_868.code: _XBEE3_XR_BL_DEF_PREFIX,
93+
HardwareVersion.XBEE_XR_900_TH.code: _XBEE3_XR_BL_DEF_PREFIX,
94+
HardwareVersion.XBEE_XR_868_TH.code: _XBEE3_XR_BL_DEF_PREFIX,
9095
}
9196

9297
_GEN3_BOOTLOADER_ERROR_CHECKSUM = 0x12
@@ -297,14 +302,15 @@
297302
HardwareVersion.XBEE3_SMT.code,
298303
HardwareVersion.XBEE3_TH.code,
299304
HardwareVersion.XBEE3_RR.code,
300-
HardwareVersion.XBEE3_RR_TH.code,
301-
HardwareVersion.XBEE3_DM_LR.code,
302-
HardwareVersion.XBEE3_DM_LR_868.code,
303-
HardwareVersion.XBEE_XR_900_TH.code,
304-
HardwareVersion.XBEE_XR_868_TH.code)
305+
HardwareVersion.XBEE3_RR_TH.code)
305306

306-
LOCAL_SUPPORTED_HW_VERSIONS = SX_HW_VERSIONS + XBEE3_HW_VERSIONS
307-
REMOTE_SUPPORTED_HW_VERSIONS = SX_HW_VERSIONS + XBEE3_HW_VERSIONS + S2C_HW_VERSIONS
307+
XR_HW_VERSIONS = (HardwareVersion.XBEE3_DM_LR.code,
308+
HardwareVersion.XBEE3_DM_LR_868.code,
309+
HardwareVersion.XBEE_XR_900_TH.code,
310+
HardwareVersion.XBEE_XR_868_TH.code)
311+
312+
LOCAL_SUPPORTED_HW_VERSIONS = SX_HW_VERSIONS + XBEE3_HW_VERSIONS + XR_HW_VERSIONS
313+
REMOTE_SUPPORTED_HW_VERSIONS = SX_HW_VERSIONS + XBEE3_HW_VERSIONS + S2C_HW_VERSIONS + XR_HW_VERSIONS
308314

309315
_log = logging.getLogger(__name__)
310316

@@ -1118,13 +1124,15 @@ class _BootloaderType(Enum):
11181124
| **name** (String): The name of this _BootloaderType.
11191125
| **value** (Integer): The ID of this _BootloaderType.
11201126
"""
1121-
GEN3_BOOTLOADER = (0x01, "Generation 3 bootloader")
1122-
GECKO_BOOTLOADER = (0x02, "Gecko bootloader")
1123-
EMBER_BOOTLOADER = (0x03, "Ember bootloader")
1127+
GEN3_BOOTLOADER = (0x01, "Generation 3 bootloader", OTAMethod.GPM)
1128+
GECKO_BOOTLOADER = (0x02, "Gecko bootloader", OTAMethod.ZCL)
1129+
EMBER_BOOTLOADER = (0x03, "Ember bootloader", OTAMethod.EMBER)
1130+
GECKO_BOOTLOADER_XR = (0x04, "Gecko bootloader with GPM OTA", OTAMethod.GPM)
11241131

1125-
def __init__(self, identifier, description):
1132+
def __init__(self, identifier, description, ota_method):
11261133
self.__id = identifier
11271134
self.__desc = description
1135+
self.__ota_method = ota_method
11281136

11291137
@classmethod
11301138
def get(cls, identifier):
@@ -1160,6 +1168,8 @@ def determine_bootloader_type(cls, hw_version):
11601168
return _BootloaderType.GEN3_BOOTLOADER
11611169
if hw_version in XBEE3_HW_VERSIONS:
11621170
return _BootloaderType.GECKO_BOOTLOADER
1171+
if hw_version in XR_HW_VERSIONS:
1172+
return _BootloaderType.GECKO_BOOTLOADER_XR
11631173
if hw_version in S2C_HW_VERSIONS:
11641174
return _BootloaderType.EMBER_BOOTLOADER
11651175

@@ -1185,6 +1195,16 @@ def description(self):
11851195
"""
11861196
return self.__desc
11871197

1198+
@property
1199+
def ota_method(self):
1200+
"""
1201+
Returns the over-the-air update method for this bootloader type.
1202+
1203+
Returns:
1204+
:class:`OTAMethod`: OTA method to use with this bootloader.
1205+
"""
1206+
return self.__ota_method
1207+
11881208

11891209
@unique
11901210
class _Gen3BootloaderCmd(Enum):
@@ -1225,7 +1245,7 @@ def get(cls, identifier):
12251245
:class:`._Gen3BootloaderCommand`: _Gen3BootloaderCommand with the
12261246
given identifier, `None` if not found.
12271247
"""
1228-
for value in _BootloaderType:
1248+
for value in _Gen3BootloaderCmd:
12291249
if value.identifier == identifier:
12301250
return value
12311251

@@ -5760,7 +5780,8 @@ class _RemoteGPMFirmwareUpdater(_RemoteFirmwareUpdater):
57605780
__DEFAULT_TIMEOUT = 20 # Seconds.
57615781

57625782
def __init__(self, remote, xml_fw_file, xbee_fw_file=None,
5763-
timeout=__DEFAULT_TIMEOUT, progress_cb=None):
5783+
timeout=__DEFAULT_TIMEOUT, progress_cb=None,
5784+
bootloader_type=_BootloaderType.GEN3_BOOTLOADER):
57645785
"""
57655786
Class constructor. Instantiates a new
57665787
:class:`._RemoteGPMFirmwareUpdater` with the given parameters.
@@ -5776,6 +5797,9 @@ def __init__(self, remote, xml_fw_file, xbee_fw_file=None,
57765797
* The current update task as a String
57775798
* The current update task percentage as an Integer
57785799
5800+
bootloader_type (:class:`_BootloaderType`): Bootloader type of the
5801+
remote node.
5802+
57795803
Raises:
57805804
FirmwareUpdateException: If there is any error performing the
57815805
remote firmware update.
@@ -5787,6 +5811,7 @@ def __init__(self, remote, xml_fw_file, xbee_fw_file=None,
57875811
self._gpm_frame_sent = False
57885812
self._gpm_frame_received = False
57895813
self._num_bytes_per_blocks = 0
5814+
self._bootloader_type = bootloader_type
57905815

57915816
def _get_default_reset_timeout(self):
57925817
"""
@@ -5808,7 +5833,15 @@ def _check_fw_binary_file(self):
58085833
# same folder as the XML firmware file.
58095834
if self._fw_file is None:
58105835
path = Path(self._xml_fw_file)
5811-
self._fw_file = str(Path(path.parent).joinpath(path.stem + EXTENSION_EBIN))
5836+
self._fw_file = str(
5837+
Path(path.parent).joinpath(
5838+
path.stem + (
5839+
EXTENSION_EBIN
5840+
if self._bootloader_type == _BootloaderType.GEN3_BOOTLOADER
5841+
else EXTENSION_GBL
5842+
)
5843+
)
5844+
)
58125845

58135846
if not _file_exists(self._fw_file):
58145847
self._exit_with_error(_ERROR_FILE_XBEE_FW_NOT_FOUND
@@ -7103,7 +7136,9 @@ def update_local_firmware(target, xml_fw_file, xbee_firmware_file=None,
71037136
hw_version = target.get_hardware_version()
71047137
if hw_version and hw_version.code not in LOCAL_SUPPORTED_HW_VERSIONS:
71057138
raise OperationNotSupportedException(
7106-
"Firmware update only supported in XBee 3 and XBee SX 868/900")
7139+
"Firmware update only supported in XBee 3, XBee SX 868/900, "
7140+
"and XBee XR 868/900"
7141+
)
71077142

71087143
# Launch the update process.
71097144
if not timeout:
@@ -7120,7 +7155,10 @@ def update_local_firmware(target, xml_fw_file, xbee_firmware_file=None,
71207155
if isinstance(target, XBeeDevice) and not target._active_update_type:
71217156
target._active_update_type = NodeUpdateType.FIRMWARE
71227157
bootloader_type = _determine_bootloader_type(target)
7123-
if bootloader_type == _BootloaderType.GECKO_BOOTLOADER:
7158+
if bootloader_type in (
7159+
_BootloaderType.GECKO_BOOTLOADER,
7160+
_BootloaderType.GECKO_BOOTLOADER_XR,
7161+
):
71247162
update_process = _LocalXBee3FirmwareUpdater(
71257163
target, xml_fw_file, xbee_fw_file=xbee_firmware_file,
71267164
bootloader_fw_file=bootloader_firmware_file,
@@ -7196,7 +7234,9 @@ def update_remote_firmware(remote, xml_fw_file, firmware_file=None, bootloader_f
71967234
hw_version = remote.get_hardware_version()
71977235
if hw_version and hw_version.code not in REMOTE_SUPPORTED_HW_VERSIONS:
71987236
raise OperationNotSupportedException(
7199-
"Firmware update only supported in XBee 3, XBee SX 868/900, and XBee S2C devices")
7237+
"Firmware update only supported in XBee 3, XBee SX 868/900, "
7238+
"XBee S2C, and XBee XR 868/900 devices"
7239+
)
72007240

72017241
# Launch the update process.
72027242
if not timeout:
@@ -7217,16 +7257,17 @@ def update_remote_firmware(remote, xml_fw_file, firmware_file=None, bootloader_f
72177257
remote.set_sync_ops_timeout(max(orig_op_timeout, timeout))
72187258
bootloader_type = _determine_bootloader_type(remote)
72197259
remote.set_sync_ops_timeout(orig_op_timeout)
7220-
if bootloader_type == _BootloaderType.GECKO_BOOTLOADER:
7260+
if bootloader_type.ota_method == OTAMethod.ZCL:
72217261
update_process = _RemoteXBee3FirmwareUpdater(
72227262
remote, xml_fw_file, ota_fw_file=firmware_file,
72237263
otb_fw_file=bootloader_file, timeout=timeout,
72247264
max_block_size=max_block_size, progress_cb=progress_callback)
7225-
elif bootloader_type == _BootloaderType.GEN3_BOOTLOADER:
7265+
elif bootloader_type.ota_method == OTAMethod.GPM:
72267266
update_process = _RemoteGPMFirmwareUpdater(
72277267
remote, xml_fw_file, xbee_fw_file=firmware_file,
7228-
timeout=timeout, progress_cb=progress_callback)
7229-
elif bootloader_type == _BootloaderType.EMBER_BOOTLOADER:
7268+
timeout=timeout, progress_cb=progress_callback,
7269+
bootloader_type=bootloader_type)
7270+
elif bootloader_type.ota_method == OTAMethod.EMBER:
72307271
update_process = _RemoteEmberFirmwareUpdater(
72317272
remote, xml_fw_file, xbee_fw_file=firmware_file,
72327273
timeout=timeout, force_update=True, progress_cb=progress_callback)
@@ -7474,6 +7515,10 @@ def _get_bootloader_version(xbee):
74747515
_PARAM_READ_RETRIES)
74757516
if bootloader_version is None or len(bootloader_version) < 2:
74767517
return None
7518+
if len(bootloader_version) == 3:
7519+
# XR returns VH value as three bytes: 0XYYZZ.
7520+
return bootloader_version
7521+
74777522
bootloader_version_array[0] = bootloader_version[0] & 0x0F
74787523
bootloader_version_array[1] = (bootloader_version[1] & 0xF0) >> 4
74797524
bootloader_version_array[2] = bootloader_version[1] & 0x0F

digi/xbee/models/protocol.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1313
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1414

15-
from enum import Enum, unique
15+
from enum import Enum, unique, auto
1616
from digi.xbee.models.hw import HardwareVersion
1717
from digi.xbee.util import utils
1818

@@ -521,3 +521,15 @@ def allows_any(self):
521521

522522

523523
Region.__doc__ += utils.doc_enum(Region)
524+
525+
526+
@unique
527+
class OTAMethod(Enum):
528+
"""
529+
Enumerates the over-the-air firmware update mechanisms of XBee modules.
530+
"""
531+
532+
UNDEFINED = auto()
533+
EMBER = auto()
534+
GPM = auto()
535+
ZCL = auto()

digi/xbee/profile.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,9 @@
115115
_WILDCARD_CELLULAR_BOOTLOADER = "bl_.*"
116116
_WILDCARD_XML = "*%s" % EXTENSION_XML
117117
_WILDCARDS_FW_LOCAL_BINARY_FILES = (EXTENSION_EBIN, EXTENSION_EHX2, EXTENSION_GBL)
118-
_WILDCARDS_FW_REMOTE_BINARY_FILES = (EXTENSION_OTA, EXTENSION_OTB, EXTENSION_EBL, EXTENSION_EBIN)
118+
_WILDCARDS_FW_REMOTE_BINARY_FILES = (
119+
EXTENSION_OTA, EXTENSION_OTB, EXTENSION_EBL, EXTENSION_EBIN, EXTENSION_GBL,
120+
)
119121

120122
_XML_COMMAND = "command"
121123
_XML_CONTROL_TYPE = "control_type"

doc/user_doc/update_the_xbee.rst

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ profiles:
2222
* **XBee S2C**
2323
* Remote firmware updates
2424
* Remote profile updates
25+
* **XBee XR 868/900**
26+
* Local and remote firmware updates
27+
* Local and remote profile updates
2528

2629

2730
.. _updateFirmware:
@@ -44,6 +47,7 @@ and remote devices:
4447
* **XBee 3**: Local and remote firmware updates
4548
* **XBee SX 868/900 MHz**: Local and remote firmware updates
4649
* **XBee S2C**: Remote firmware updates
50+
* **XBee XR 868/900**: Local and remote firmware updates
4751

4852

4953
.. _updateFirmwareLocal:
@@ -66,8 +70,8 @@ connection. For this operation, you need the following components:
6670
not provided.
6771

6872
.. warning::
69-
At the moment, local firmware update is only supported in **XBee 3** and
70-
**XBee SX 868/900 MHz** devices.
73+
At the moment, local firmware update is only supported in **XBee 3**,
74+
**XBee SX 868/900 MHz** and **XBee XR 868/900** devices.
7175

7276

7377
+------------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -221,7 +225,7 @@ components:
221225

222226
.. warning::
223227
At the moment, remote firmware update is only supported in **XBee 3**,
224-
**XBee SX 868/900 MHz**, and **XBee S2C** devices.
228+
**XBee SX 868/900 MHz**, **XBee S2C**, and **XBee XR 868/900** devices.
225229

226230
To perform the remote firmware update, call the ``update_firmware()`` method of
227231
the ``RemoteXBeeDevice`` class providing the required parameters:
@@ -489,6 +493,7 @@ To configure individual settings see :ref:`configureXBee`.
489493
* **XBee 3**: Local and remote profile updates
490494
* **XBee SX 868/900 MHz**: Local and remote profile updates
491495
* **XBee S2C**: Remote profile updates
496+
* **XBee XR 868/900**: Local and remote profile updates
492497

493498

494499
.. _readXBeeProfile:
@@ -641,8 +646,8 @@ Applying a profile to a local XBee requires the following components:
641646
Use `XCTU <http://www.digi.com/xctu>`_ to create configuration profiles.
642647

643648
.. warning::
644-
At the moment, local profile update is only supported in **XBee 3** and
645-
**XBee SX 868/900 MHz** devices.
649+
At the moment, local profile update is only supported in **XBee 3**,
650+
**XBee SX 868/900 MHz**, and **XBee XR 868/900** devices.
646651

647652
To apply the XBee profile to a local XBee, call the ``apply_profile()`` method
648653
of the ``XBeeDevice`` class providing the required parameters:
@@ -716,7 +721,7 @@ Applying a profile to a remote XBee requires the following components:
716721

717722
.. warning::
718723
At the moment, remote profile update is only supported in **XBee 3**,
719-
**XBee SX 868/900 MHz**, and **XBee S2C** devices.
724+
**XBee SX 868/900 MHz**, **XBee S2C**, and **XBee XR 868/900** devices.
720725

721726
To apply the XBee profile to a remote XBee, call the ``apply_profile()`` method
722727
of the ``RemoteXBeeDevice`` class providing the required parameters:

0 commit comments

Comments
 (0)