Skip to content
This repository was archived by the owner on Jan 17, 2023. It is now read-only.

Commit

Permalink
Allow zigbee image generation to use min_max_hw_ver (#227)
Browse files Browse the repository at this point in the history
* Allow zigbee image generation to use min_max_hw_ver

* Refactor Zigbee OTA header generating

* Change message type to error
  • Loading branch information
sebastiandraus authored and bihanssen committed Jun 14, 2019
1 parent b82d8ba commit c566ad6
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 19 deletions.
40 changes: 38 additions & 2 deletions nordicsemi/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,14 @@ def pkg():
help='The zigbee OTA fw version.',
required=False,
type=BASED_INT_OR_NONE)
@click.option('--zigbee-ota-min-hw-version',
help='The zigbee OTA minimum hw version of Zigbee OTA Client.',
required=False,
type=BASED_INT_OR_NONE)
@click.option('--zigbee-ota-max-hw-version',
help='The zigbee OTA maximum hw version of Zigbee OTA Client.',
required=False,
type=BASED_INT_OR_NONE)
def generate(zipfile,
debug_mode,
application,
Expand All @@ -629,7 +637,9 @@ def generate(zipfile,
zigbee_image_type,
zigbee_comment,
zigbee_ota_hw_version,
zigbee_ota_fw_version):
zigbee_ota_fw_version,
zigbee_ota_min_hw_version,
zigbee_ota_max_hw_version):
"""
Generate a zip package for distribution to apps that support Nordic DFU OTA.
The application, bootloader, and SoftDevice files are converted to .bin if supplied as .hex files.
Expand Down Expand Up @@ -844,6 +854,30 @@ def generate(zipfile,
if zigbee:
inner_external_app = False

if zigbee_ota_min_hw_version > 0xFFFF:
click.echo('Error: zigbee-ota-min-hw-version exceeds 2-byte long integer.')
return

if zigbee_ota_max_hw_version > 0xFFFF:
click.echo('Error: zigbee-ota-max-hw-version exceeds 2-byte long integer.')
return

if zigbee and (hw_version > 0xFFFF):
click.echo('Error: hw-version exceeds 2-byte long integer.')
return

# Warn user if minimal/maximum zigbee ota hardware version are not correct:
# * only one of them is given
# * minimum version is higher than maximum version
# * hw_version is inside the range specified by minimum and maximum hardware version
if (type(zigbee_ota_min_hw_version) is int) != (type(zigbee_ota_max_hw_version) is int):
click.echo('Warning: min/max zigbee ota hardware version is missing. Discarding min/max hardware version.')
elif type(zigbee_ota_min_hw_version) is int:
if zigbee_ota_min_hw_version > zigbee_ota_max_hw_version:
click.echo('Warning: zigbee-ota-min-hw-version is higher than zigbee-ota-max-hw-version.')
if (hw_version > zigbee_ota_max_hw_version) or (hw_version < zigbee_ota_min_hw_version):
click.echo('Warning: hw-version is outside the specified range specified by zigbee_ota_min_hw_version and zigbee_ota_max_hw_version.')

# Generate a DFU package. If --zigbee is set this is the inner DFU package
# which will be used as a binary input to the outter DFU package
package = Package(debug_mode,
Expand All @@ -862,7 +896,9 @@ def generate(zipfile,
zigbee,
zigbee_manufacturer_id,
zigbee_image_type,
zigbee_comment)
zigbee_comment,
zigbee_ota_min_hw_version,
zigbee_ota_max_hw_version)

package.generate_package(zipfile_path)

Expand Down
12 changes: 10 additions & 2 deletions nordicsemi/dfu/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ def __init__(self,
zigbee_format=False,
manufacturer_id=0,
image_type=0,
comment=''):
comment='',
zigbee_ota_min_hw_version=None,
zigbee_ota_max_hw_version=None):

"""
Constructor that requires values used for generating a Nordic DFU package.
Expand All @@ -146,6 +148,8 @@ def __init__(self,
:param str bootloader_fw: Path to bootloader firmware file
:param str softdevice_fw: Path to softdevice firmware file
:param str key_file: Path to Signing key file (PEM)
:param int zigbee_ota_min_hw_version: Minimal zigbee ota hardware version
:param int zigbee_ota_max_hw_version: Maximum zigbee ota hardware version
:return: None
"""

Expand Down Expand Up @@ -206,6 +210,8 @@ def __init__(self,
self.image_type = image_type
self.manufacturer_id = manufacturer_id
self.comment = comment
self.zigbee_ota_min_hw_version = zigbee_ota_min_hw_version
self.zigbee_ota_max_hw_version = zigbee_ota_max_hw_version
else:
self.is_zigbee = False
self.image_type = None
Expand Down Expand Up @@ -479,7 +485,9 @@ def generate_package(self, filename, preserve_work_dir=False):
bytes(open(file_name, 'rb').read()),
self.manufacturer_id,
self.image_type,
self.comment)
self.comment,
self.zigbee_ota_min_hw_version,
self.zigbee_ota_max_hw_version)

ota_file_handle = open(self.zigbee_ota_file.filename, 'wb')
ota_file_handle.write(self.zigbee_ota_file.binary)
Expand Down
93 changes: 78 additions & 15 deletions nordicsemi/zigbee/ota_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
OTA_UPGRADE_SUBELEMENT_HEADER_SIZE = 2 + 4 # Tag ID + Length Field
OTA_UPGRADE_SUBELEMENT_TRIGGER_TYPE = 0xCDEF
OTA_UPGRADE_SUBELEMENT_TRIGGER_LENGTH = 1 + 4 + 4 + 4 + 4 # See background_dfu_trigger_t in the nRF5 SDK for explanation

OTA_UPGRADE_FIELD_CONTROL_BIT_MASK_HW_VER = (1 << 2)
OTA_UPGRADE_MIN_HW_VERSION_LENGTH = 2
OTA_UPGRADE_MAX_HW_VERSION_LENGTH = 2
'''
background_dfu_trigger_t type defined in components/iot/background_dfu/background_dfu_state.h of nRF5 SDK:
Expand All @@ -74,25 +78,28 @@ def __init__(self,
firmware,
manufacturer_code = OTA_UPGRADE_MANUFACTURER_WILDCARD,
image_type = OTA_UPGRADE_IMAGE_TYPE_WILDCARD,
comment = ''):
comment = '',
min_hw_version=None,
max_hw_version=None):
'''A constructor for the OTA file class, see Zigbee ZCL spec 11.4.2 (Zigbee Document 07-5123-06)
see: http://www.zigbee.org/~zigbeeor/wp-content/uploads/2014/10/07-5123-06-zigbee-cluster-library-specification.pdf
(access verified as of 2018-08-06)
'''

total_len = OTA_UPGRADE_FILE_HEADER_LENGTH + 3 * OTA_UPGRADE_SUBELEMENT_HEADER_SIZE + OTA_UPGRADE_SUBELEMENT_TRIGGER_LENGTH + init_cmd_len + firmware_len
ota_header_pack_format = '<LHHHHHLHc31sL'
ota_header = struct.pack(ota_header_pack_format,
OTA_UPGRADE_FILE_HEADER_FILE_ID,
OTA_UPGRADE_FILE_HEADER_FILE_VERSION,
OTA_UPGRADE_FILE_HEADER_LENGTH,
OTA_UPGRADE_FIELD_CONTROL,
manufacturer_code,
image_type,
file_version,
OTA_UPGRADE_FILE_HEADER_STACK_PRO,
chr(len(comment)),
bytes(comment.encode('ascii')),
total_len)

ota_header = OTA_header(OTA_UPGRADE_FILE_HEADER_FILE_ID,
OTA_UPGRADE_FILE_HEADER_FILE_VERSION,
OTA_UPGRADE_FILE_HEADER_LENGTH,
OTA_UPGRADE_FIELD_CONTROL,
manufacturer_code,
image_type,
file_version,
OTA_UPGRADE_FILE_HEADER_STACK_PRO,
comment,
total_len,
min_hw_version,
max_hw_version)

subelement_header_pack_format = '<HL'
subelement_trigger_pack_format = '>cLLLL'
Expand All @@ -110,8 +117,64 @@ def __init__(self,
subelement_init_cmd = struct.pack(subelement_header_pack_format, 0x0000, init_cmd_len) # Subelement tags are not really needed in case of Init Cmd and Firmware subelements
subelement_firmware = struct.pack(subelement_header_pack_format, 0x0000, firmware_len)

self.binary = ota_header + subelement_trigger + subelement_trigger_payload + subelement_init_cmd + init_cmd + subelement_firmware + firmware
self.binary = ota_header.header + subelement_trigger + subelement_trigger_payload + subelement_init_cmd + init_cmd + subelement_firmware + firmware
self.filename = '-'.join(['{:04X}'.format(manufacturer_code),
'{:04X}'.format(image_type),
'{:08X}'.format(file_version),
comment]) + '.zigbee'


class OTA_header(object):
def __init__(self,
file_id,
header_version,
header_length,
header_field_control,
manufacturer_code,
image_type,
file_version,
zigbee_stack_version,
header_string,
total_image_size,
min_hw_version=None,
max_hw_version=None):

self.__pack_format = '<LHHHHHLHc31sL'
self.__header_length = header_length
self.__total_size = total_image_size
self.__field_control = header_field_control
self.__additional_fields = []

# If min and max hardware version are present add optional fields to the header
if (type(min_hw_version) is int) and (type(max_hw_version) is int):
self.__add_optional_fields((OTA_UPGRADE_MIN_HW_VERSION_LENGTH + OTA_UPGRADE_MAX_HW_VERSION_LENGTH),
OTA_UPGRADE_FIELD_CONTROL_BIT_MASK_HW_VER,
'HH',
[min_hw_version, max_hw_version])

self.__pack_args = [file_id,
header_version,
self.__header_length,
self.__field_control,
manufacturer_code,
image_type,
file_version,
zigbee_stack_version,
chr(len(header_string)),
bytes(header_string.encode('ascii')),
self.__total_size]
self.__pack_args.extend(self.__additional_fields)

@property
def header(self):
return struct.pack(self.__pack_format, *self.__pack_args)

def __add_optional_fields(self, fields_length, field_control_bit_mask, fields_formatting, fields_values):
self.__total_size += fields_length
self.__header_length += fields_length
self.__field_control += field_control_bit_mask
self.__pack_format += fields_formatting
if type(fields_values) in (tuple, list):
self.__additional_fields.extend(fields_values)
else:
self.__additional_fields.append(fields_values)

0 comments on commit c566ad6

Please sign in to comment.