def test_get_softdevice_variant(self): nrf = nrfhex.nRFHex("firmwares/foo.hex") self.assertEqual(nrf.get_softdevice_variant(), "unknown") nrf = nrfhex.nRFHex("firmwares/s130_nrf51_mini.hex") self.assertEqual(nrf.get_softdevice_variant(), "s1x0") nrf = nrfhex.nRFHex("firmwares/s132_nrf52_mini.hex") self.assertEqual(nrf.get_softdevice_variant(), "s132")
def test_sizes(self): nrf = nrfhex.nRFHex("firmwares/foo.hex", "firmwares/bar.hex") self.assertEqual(nrf.get_mbr_end_address(), 0x1000) self.assertEqual(nrf.minaddr(), 0x1000) self.assertEqual(nrf.size(), 73152) self.assertEqual(nrf.bootloadersize(), 13192) nrf = nrfhex.nRFHex("firmwares/s132_nrf52_mini.hex") self.assertEqual(nrf.get_mbr_end_address(), 0x3000) self.assertEqual(nrf.minaddr(), 0x3000) self.assertEqual(nrf.size(), 12288) self.assertEqual(nrf.bootloadersize(), 0)
def test_tobinfile_two_bin(self): nrf = nrfhex.nRFHex("firmwares/foo_wanted.bin", "firmwares/bar_wanted.bin") nrf.tobinfile("firmwares/foobar.bin") self.comparefiles("firmwares/foobar.bin", "firmwares/foobar_wanted.bin")
def normalize_firmware_to_bin(work_dir, firmware_path): firmware_filename = os.path.basename(firmware_path) new_filename = firmware_filename.replace(".hex", ".bin") new_filepath = os.path.join(work_dir, new_filename) if not os.path.exists(new_filepath): temp = nRFHex(firmware_path) temp.tobinfile(new_filepath) return new_filepath
def generate_package(self, filename, preserve_work_dir=False): """ Generates a Nordic DFU package. The package is a zip file containing firmware(s) and metadata required for Nordic DFU applications to perform DFU onn nRF5X devices. :param str filename: Filename for generated package. :param bool preserve_work_dir: True to preserve the temporary working directory. Useful for debugging of a package, and if the user wants to look at the generated package without having to unzip it. :return: None """ self.zip_file = filename self.work_dir = self.__create_temp_workspace() sd_bin_created = False if Package._is_bootloader_softdevice_combination(self.firmwares_data): # Removing softdevice and bootloader data from dictionary and adding the combined later softdevice_fw_data = self.firmwares_data.pop(HexType.SOFTDEVICE) bootloader_fw_data = self.firmwares_data.pop(HexType.BOOTLOADER) softdevice_fw_name = softdevice_fw_data[ FirmwareKeys.FIRMWARE_FILENAME] bootloader_fw_name = bootloader_fw_data[ FirmwareKeys.FIRMWARE_FILENAME] new_filename = "sd_bl.bin" sd_bl_file_path = os.path.join(self.work_dir, new_filename) nrf_hex = nRFHex(softdevice_fw_name, bootloader_fw_name) nrf_hex.tobinfile(sd_bl_file_path) softdevice_size = nrf_hex.size() bootloader_size = nrf_hex.bootloadersize() boot_validation_type = [] boot_validation_type.extend( softdevice_fw_data[FirmwareKeys.BOOT_VALIDATION_TYPE]) boot_validation_type.extend( bootloader_fw_data[FirmwareKeys.BOOT_VALIDATION_TYPE]) self.__add_firmware_info( firmware_type=HexType.SD_BL, firmware_version=bootloader_fw_data[ FirmwareKeys.INIT_PACKET_DATA] [PacketField. FW_VERSION], # use bootloader version in combination with SD filename=sd_bl_file_path, init_packet_data=softdevice_fw_data[ FirmwareKeys.INIT_PACKET_DATA], boot_validation_type=boot_validation_type, sd_size=softdevice_size, bl_size=bootloader_size) # Need to generate SD only bin for boot validation signature sd_bin = Package.normalize_firmware_to_bin( self.work_dir, softdevice_fw_data[FirmwareKeys.FIRMWARE_FILENAME]) sd_bin_path = os.path.join(self.work_dir, sd_bin) sd_bin_created = True for key, firmware_data in self.firmwares_data.items(): # Normalize the firmware file and store it in the work directory firmware_data[FirmwareKeys.BIN_FILENAME] = \ Package.normalize_firmware_to_bin(self.work_dir, firmware_data[FirmwareKeys.FIRMWARE_FILENAME]) # Calculate the hash for the .bin file located in the work directory bin_file_path = os.path.join( self.work_dir, firmware_data[FirmwareKeys.BIN_FILENAME]) firmware_hash = Package.calculate_sha256_hash(bin_file_path) bin_length = int(Package.calculate_file_size(bin_file_path)) sd_size = 0 bl_size = 0 app_size = 0 if key in [HexType.APPLICATION, HexType.EXTERNAL_APPLICATION]: app_size = bin_length elif key == HexType.SOFTDEVICE: sd_size = bin_length elif key == HexType.BOOTLOADER: bl_size = bin_length elif key == HexType.SD_BL: bl_size = firmware_data[FirmwareKeys.BL_SIZE] sd_size = firmware_data[FirmwareKeys.SD_SIZE] boot_validation_type_array = firmware_data[ FirmwareKeys.BOOT_VALIDATION_TYPE] boot_validation_bytes_array = [] for x in boot_validation_type_array: if x == ValidationTypes.VALIDATE_ECDSA_P256_SHA256: if key == HexType.SD_BL: boot_validation_bytes_array.append( Package.sign_firmware(self.key_file, sd_bin_path)) else: boot_validation_bytes_array.append( Package.sign_firmware(self.key_file, bin_file_path)) else: boot_validation_bytes_array.append(b'') init_packet = InitPacketPB( from_bytes=None, hash_bytes=firmware_hash, hash_type=HashTypes.SHA256, boot_validation_type=boot_validation_type_array, boot_validation_bytes=boot_validation_bytes_array, dfu_type=HexTypeToInitPacketFwTypemap[key], is_debug=firmware_data[FirmwareKeys.INIT_PACKET_DATA][ PacketField.DEBUG_MODE], fw_version=firmware_data[FirmwareKeys.INIT_PACKET_DATA][ PacketField.FW_VERSION], hw_version=firmware_data[FirmwareKeys.INIT_PACKET_DATA][ PacketField.HW_VERSION], sd_size=sd_size, app_size=app_size, bl_size=bl_size, sd_req=firmware_data[FirmwareKeys.INIT_PACKET_DATA][ PacketField.REQUIRED_SOFTDEVICES_ARRAY]) if (self.key_file is not None): signer = Signing() signer.load_key(self.key_file) signature = signer.sign(init_packet.get_init_command_bytes()) init_packet.set_signature(signature, SigningTypes.ECDSA_P256_SHA256) # Store the .dat file in the work directory init_packet_filename = firmware_data[ FirmwareKeys.BIN_FILENAME].replace(".bin", ".dat") with open(os.path.join(self.work_dir, init_packet_filename), 'wb') as init_packet_file: init_packet_file.write(init_packet.get_init_packet_pb_bytes()) firmware_data[FirmwareKeys.DAT_FILENAME] = \ init_packet_filename if self.is_zigbee: firmware_version = firmware_data[ FirmwareKeys.INIT_PACKET_DATA][PacketField.FW_VERSION] file_name = firmware_data[FirmwareKeys.BIN_FILENAME] self.zigbee_ota_file = OTA_file( firmware_version, len(init_packet.get_init_packet_pb_bytes()), binascii.crc32(init_packet.get_init_packet_pb_bytes()) & 0xFFFFFFFF, init_packet.get_init_packet_pb_bytes(), os.path.getsize(file_name), self.calculate_crc(32, file_name) & 0xFFFFFFFF, bytes(open(file_name, 'rb').read()), self.manufacturer_id, self.image_type, 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) ota_file_handle.close() # Remove SD binary file created for boot validation if sd_bin_created: os.remove(sd_bin_path) # Store the manifest to manifest.json manifest = self.create_manifest() with open(os.path.join(self.work_dir, Package.MANIFEST_FILENAME), "w") as manifest_file: manifest_file.write(manifest) # Package the work_dir to a zip file Package.create_zip_package(self.work_dir, filename) # Delete the temporary directory self.rm_work_dir(preserve_work_dir)
def test_tobinfile_single_bin_file(self): nrf = nrfhex.nRFHex("firmwares/bar_wanted.bin") nrf.tobinfile("firmwares/bar.bin") self.comparefiles("firmwares/bar.bin", "firmwares/bar_wanted.bin")
def test_tobinfile_single_file_with_uicr_content(self): nrf = nrfhex.nRFHex("firmwares/foo.hex") nrf.tobinfile("firmwares/foo.bin") self.comparefiles("firmwares/foo.bin", "firmwares/foo_wanted.bin")