diff options
Diffstat (limited to '')
-rw-r--r-- | circuitpython/lib/nrfutil/nordicsemi/dfu/manifest.py | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/manifest.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/manifest.py new file mode 100644 index 0000000..c65e7dd --- /dev/null +++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/manifest.py @@ -0,0 +1,239 @@ +# Copyright (c) 2015, Nordic Semiconductor +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of Nordic Semiconductor ASA nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Python libraries +import json +import binascii +import os + +# Nordic libraries +from nordicsemi.exceptions import NotImplementedException +from nordicsemi.dfu.init_packet import PacketField +from nordicsemi.dfu.model import HexType, FirmwareKeys + + +class ManifestGenerator(object): + def __init__(self, dfu_version, firmwares_data): + """ + The Manifest Generator constructor. Needs a data structure to generate a manifest from. + + :type float dfu_version: The dfu version number to state in manifest + :type dict firmwares_data: The firmwares data structure describing the Nordic DFU package + """ + self.dfu_version = dfu_version + self.firmwares_data = firmwares_data + self.manifest = None + + def generate_manifest(self): + self.manifest = Manifest() + self.manifest.dfu_version = self.dfu_version + + for key in self.firmwares_data: + firmware_dict = self.firmwares_data[key] + + if key == HexType.SD_BL: + _firmware = SoftdeviceBootloaderFirmware() + _firmware.bl_size = firmware_dict[FirmwareKeys.BL_SIZE] + _firmware.sd_size = firmware_dict[FirmwareKeys.SD_SIZE] + else: + _firmware = Firmware() + + # Strip path, add only filename + _firmware.bin_file = os.path.basename(firmware_dict[FirmwareKeys.BIN_FILENAME]) + _firmware.dat_file = os.path.basename(firmware_dict[FirmwareKeys.DAT_FILENAME]) + + init_packet_data = InitPacketData() + + for init_packet_data_key in firmware_dict[FirmwareKeys.INIT_PACKET_DATA]: + field = firmware_dict[FirmwareKeys.INIT_PACKET_DATA][init_packet_data_key] + + if init_packet_data_key == PacketField.APP_VERSION: + init_packet_data.application_version = field + elif init_packet_data_key == PacketField.DEVICE_TYPE: + init_packet_data.device_type = field + elif init_packet_data_key == PacketField.DEVICE_REVISION: + init_packet_data.device_revision = field + elif init_packet_data_key == PacketField.REQUIRED_SOFTDEVICES_ARRAY: + init_packet_data.softdevice_req = field + elif init_packet_data_key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID: + init_packet_data.ext_packet_id = field + elif init_packet_data_key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_LENGTH: + init_packet_data.firmware_length = field + elif init_packet_data_key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH: + init_packet_data.firmware_hash = binascii.hexlify(field) + elif init_packet_data_key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16: + init_packet_data.firmware_crc16 = field + elif init_packet_data_key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_INIT_PACKET_ECDS: + init_packet_data.init_packet_ecds = binascii.hexlify(field) + else: + raise NotImplementedException( + "Support for init packet data type {0} not implemented yet.".format(init_packet_data_key)) + + _firmware.init_packet_data = init_packet_data + + if key == HexType.APPLICATION: + self.manifest.application = _firmware + elif key == HexType.BOOTLOADER: + self.manifest.bootloader = _firmware + elif key == HexType.SOFTDEVICE: + self.manifest.softdevice = _firmware + elif key == HexType.SD_BL: + self.manifest.softdevice_bootloader = _firmware + else: + raise NotImplementedException("Support for firmware type {0} not implemented yet.".format(key)) + + return self.to_json() + + def to_json(self): + def remove_none_entries(d): + if not isinstance(d, dict): + return d + + return dict((k, remove_none_entries(v)) for k, v in d.iteritems() if v is not None) + + return json.dumps({'manifest': self.manifest}, + default=lambda o: remove_none_entries(o.__dict__), + sort_keys=True, indent=4, + separators=(',', ': ')) + + +class InitPacketData(object): + def __init__(self, + device_type=None, + device_revision=None, + application_version=None, + softdevice_req=None, + ext_packet_id=None, + firmware_length=None, + firmware_hash=None, + firmware_crc16=None, + init_packet_ecds=None + ): + """ + The InitPacketData data model. + + :param int device_type: device type + :param int device_revision: device revision + :param int application_version: application version + :param list softdevice_req: softdevice requirements + :param int ext_packet_id: packet extension id + :param int firmware_length: firmware length + :param str firmware_hash: firmware hash + :param int firmware_crc16: firmware CRC-16 calculated value + :param str init_packet_ecds: Init packet signature + :return: InitPacketData + """ + self.device_type = device_type + self.device_revision = device_revision + self.application_version = application_version + self.softdevice_req = softdevice_req + self.ext_packet_id = ext_packet_id + self.firmware_length = firmware_length + self.firmware_hash = firmware_hash + self.firmware_crc16 = firmware_crc16 + self.init_packet_ecds = init_packet_ecds + + +class Firmware(object): + def __init__(self, + bin_file=None, + dat_file=None, + init_packet_data=None): + """ + The firmware datamodel + + :param str bin_file: Firmware binary file + :param str dat_file: Firmware .dat file (init packet for Nordic DFU) + :param dict init_packet_data: Initial packet data + :return: + """ + self.dat_file = dat_file + self.bin_file = bin_file + + if init_packet_data: + self.init_packet_data = InitPacketData(**init_packet_data) + + +class SoftdeviceBootloaderFirmware(Firmware): + def __init__(self, + bin_file=None, + dat_file=None, + init_packet_data=None, + sd_size=None, + bl_size=None): + """ + The SoftdeviceBootloaderFirmware data model + + :param str bin_file: Firmware binary file + :param str dat_file: Firmware .dat file (init packet for Nordic DFU) + :param int sd_size: The softdevice size + :param int bl_size: The bootloader size + :return: SoftdeviceBootloaderFirmware + """ + super(SoftdeviceBootloaderFirmware, self).__init__( + bin_file, + dat_file, + init_packet_data) + self.sd_size = sd_size + self.bl_size = bl_size + + +class Manifest: + def __init__(self, + application=None, + bootloader=None, + softdevice=None, + softdevice_bootloader=None, + dfu_version=None): + """ + The Manifest data model. + + :param dict application: Application firmware in package + :param dict bootloader: Bootloader firmware in package + :param dict softdevice: Softdevice firmware in package + :param dict softdevice_bootloader: Combined softdevice and bootloader firmware in package + :return: Manifest + """ + self.softdevice_bootloader = \ + SoftdeviceBootloaderFirmware(**softdevice_bootloader) if softdevice_bootloader else None + + self.softdevice = Firmware(**softdevice) if softdevice else None + self.bootloader = Firmware(**bootloader) if bootloader else None + self.application = Firmware(**application) if application else None + self.dfu_version = dfu_version + + @staticmethod + def from_json(data): + """ + Parses a manifest according to Nordic DFU package specification. + + :param str data: The manifest in string format + :return: Manifest + """ + kwargs = json.loads(data) + return Manifest(**kwargs['manifest']) |