We used nRF5_SDK_15.0.0_a53641a and nrf5_SDK_for_Mesh_v2.0.0_src.
We are following DFU quick start guide http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.meshsdk.v0.10.0%2Findex.html
For nRF52:
We used nRF5_SDK_15.0.0_a53641a and nrf5_SDK_for_Mesh_v2.0.0_src.
We are following DFU quick start guide http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.meshsdk.v0.10.0%2Findex.html
For nRF52:
I have tested the DFU quick start guide using both Mesh SDK v2.0.0 & v2.0.1 & I receive the exact same TypeError as you do. I will mention this to the developers of nrfutil & see if they have any suggestions.
Update:
There was an issue with the python device_page_generator.py file. Should work if you download this file & copy it into the tools/dfu folder. I do not get any errors with step 4, but have not had time yet to test the rest. Could you please let me know if everything else works fine? If it does not, I will test a bit later.
# Copyright (c) 2010 - 2018, Nordic Semiconductor ASA # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # 2. 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. # # 3. 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 NORDIC SEMICONDUCTOR ASA 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. import argparse import enum import struct import intelhex import sys import json import os PACKAGE_PARENT = '..' SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__)))) sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT))) from deviceutil.deviceutil import \ get_application_limits, \ make_bootloader_for_platforms, \ set_softdevices_for_platforms, \ load_softdevies, \ load_platforms WORD_SIZE = 4 class BLInfoType(enum.IntEnum): INVALID = 0x00 ECDSA_PUBLIC_KEY = 0x01 VERSION = 0x02 JOURNAL = 0x03 FLAGS = 0x04 SEGMENT_SD = 0x10 SEGMENT_BL = 0x11 SEGMENT_APP = 0x12 LAST = 0x7FFF class DevicePageEntry(object): def __init__(self, bl_info_type, data): #print("Type: ", type(data).__name__) if not (isinstance(bl_info_type, BLInfoType) and (isinstance(data, bytearray) or isinstance(data, str))): raise TypeError("Invalid type %r" % (type(data))) self.bl_info_type = bl_info_type if (isinstance(data, str)): data = bytearray.fromhex(data) self.data = self.pad(data) @property def word_count(self): return (len(self.data) + WORD_SIZE) // WORD_SIZE def pad(self, data): pad_byte_count = (WORD_SIZE - len(data) % WORD_SIZE) % WORD_SIZE if pad_byte_count > 0: data += bytearray([0xFF] * pad_byte_count) return data def serialize(self): return (bytearray(struct.pack('<HH', self.word_count, self.bl_info_type) + self.data)) class DevicePage(object): def __init__(self, platform, softdevice, bootloader_config): self.entries = [] self.generate_entries(platform, softdevice, bootloader_config) self.platform = platform self.softdevice = softdevice def generate_entries(self, platform, softdevice, bootloader_config): public_key = bytearray.fromhex(bootloader_config["public_key"]) \ if "public_key" in bootloader_config else None if public_key: self.entries.append( DevicePageEntry(BLInfoType.ECDSA_PUBLIC_KEY, public_key)) app_limits = get_application_limits(platform, softdevice) app_segment = bytearray(struct.pack("<II", app_limits["flash_start"], app_limits["flash_size"])) sd_segment = bytearray(struct.pack("<II", softdevice["flash_start"], softdevice["flash_size"])) bl_segment = bytearray(struct.pack("<II", platform["bootloader"]["flash_start"], platform["bootloader"]["flash_size"])) self.entries.append( DevicePageEntry(BLInfoType.SEGMENT_APP, app_segment)) self.entries.append( DevicePageEntry(BLInfoType.SEGMENT_SD, sd_segment)) self.entries.append( DevicePageEntry(BLInfoType.SEGMENT_BL, bl_segment)) version_data = bytearray(struct.pack("<HBBIHI", int(softdevice["version"], 16), bootloader_config["bootloader_id"], bootloader_config["bootloader_version"], bootloader_config["company_id"], bootloader_config["application_id"], bootloader_config["application_version"])) #print(version_data) self.entries.append(DevicePageEntry(BLInfoType.VERSION, version_data)) self.entries.append(DevicePageEntry(BLInfoType.FLAGS, bytearray(struct.pack('I', 0xFFFFFFFF)))) def write_hex(self, hexfile): # Info page metadata raw_data = bytearray(struct.pack("<BBBB", 4, 1, 8, 8)) raw_data += bytearray().join(map(DevicePageEntry.serialize, self.entries)) raw_data += bytearray(struct.pack("<HH", 0xFFFF, BLInfoType.LAST)) hex_output = intelhex.IntelHex() hex_output.frombytes(raw_data, self.platform["flash_size"] - self.platform["page_size"]) hex_output.tofile(hexfile, "hex") def write_specific_page(platforms, softdevices, args): platform = next((p for p in platforms if args.device == p["name"]), None) if not platform: print("Unknown device: \"%s\" in list %r" % (args.device, [p["name"] for p in platforms])) sys.exit(1) softdevice = next((s for s in softdevices if args.softdevice == s["name"]), None) if not softdevice: print("Unknown SoftDevice: \"%s\"" % (args.softdevice)) sys.exit(1) if args.softdevice not in platform["softdevices"]: print("Unknown SoftDevice \"%s\" for platform \"%s\"" % (args.softdevice, args.device)) sys.exit(1) # Filter out the others... platforms = [p for p in platforms if args.device.lower() in p["name"].lower()] make_bootloader_for_platforms(platforms) set_softdevices_for_platforms(platforms, softdevices) # Dict is updated by reference # platform = platforms[args.device] # softdevice = softdevices[args.softdevice] with open(args.bootloader_config, "r") as f: bootloader_config = json.load(f)["bootloader_config"] device_page = DevicePage(platform, softdevice, bootloader_config) if not args.output_file: args.output_file = "_".join(["device_page", self.platform["name"], self.softdevice["name"]]) + ".hex" device_page.write_hex(args.output_file) def write_all(platforms, softdevices, args): make_bootloader_for_platforms(platforms) set_softdevices_for_platforms(platforms, softdevices) with open(args.bootloader_config, "r") as f: bootloader_config = json.load(f)["bootloader_config"] for platform in platforms: for softdevice in platform["softdevices"]: device_page = DevicePage(platform, softdevice, bootloader_config) device_page.write_hex(args.output_file) def main(): softdevices = load_softdevies("../configuration/softdevices.json") platforms = load_platforms("../configuration/platforms.json") sd_str = '' for sd in softdevices: sd_str += ''.join(sd["name"]) + "\n" plt_str = '' for plt in platforms: plt_str += ''.join(plt["name"]) + '\n' SOFTDEVICE = "s132_5.0.0" DEVICE = "nrf52832_xxAA" parser = argparse.ArgumentParser(description="Device Page Generator") parser.add_argument("-d", "--device", help="Select device: " + ''.join(plt_str), default=DEVICE) parser.add_argument("-sd", "--softdevice", help="Select SoftDevice: " + ''.join(sd_str), default=SOFTDEVICE) parser.add_argument("-c", "--bootloader-config", default="bootloader_config_default.json", help="Bootloader configuration file") parser.add_argument("-o", "--output-file", help="Output hex file", default="bin/device_page_%s_%s.hex" % (DEVICE, SOFTDEVICE)) parser.add_argument("--all", default=False, action="store_true", help=("Writes all known device page combinations to " + "\'bin/\'")) args = parser.parse_args() dirname = os.path.dirname(args.output_file) if not os.path.exists(dirname): os.mkdir(dirname) if args.all: write_all(platforms, softdevices, args) print("Wrote for device pages for all devices.") elif args.softdevice and args.device: write_specific_page(platforms, softdevices, args) print("Wrote device page for %s with the %s SoftDevice to %s." % (args.device, args.softdevice, args.output_file)) if __name__ == "__main__": main()
I have tested the DFU quick start guide using both Mesh SDK v2.0.0 & v2.0.1 & I receive the exact same TypeError as you do. I will mention this to the developers of nrfutil & see if they have any suggestions.
Update:
There was an issue with the python device_page_generator.py file. Should work if you download this file & copy it into the tools/dfu folder. I do not get any errors with step 4, but have not had time yet to test the rest. Could you please let me know if everything else works fine? If it does not, I will test a bit later.
# Copyright (c) 2010 - 2018, Nordic Semiconductor ASA # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # 2. 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. # # 3. 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 NORDIC SEMICONDUCTOR ASA 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. import argparse import enum import struct import intelhex import sys import json import os PACKAGE_PARENT = '..' SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__)))) sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT))) from deviceutil.deviceutil import \ get_application_limits, \ make_bootloader_for_platforms, \ set_softdevices_for_platforms, \ load_softdevies, \ load_platforms WORD_SIZE = 4 class BLInfoType(enum.IntEnum): INVALID = 0x00 ECDSA_PUBLIC_KEY = 0x01 VERSION = 0x02 JOURNAL = 0x03 FLAGS = 0x04 SEGMENT_SD = 0x10 SEGMENT_BL = 0x11 SEGMENT_APP = 0x12 LAST = 0x7FFF class DevicePageEntry(object): def __init__(self, bl_info_type, data): #print("Type: ", type(data).__name__) if not (isinstance(bl_info_type, BLInfoType) and (isinstance(data, bytearray) or isinstance(data, str))): raise TypeError("Invalid type %r" % (type(data))) self.bl_info_type = bl_info_type if (isinstance(data, str)): data = bytearray.fromhex(data) self.data = self.pad(data) @property def word_count(self): return (len(self.data) + WORD_SIZE) // WORD_SIZE def pad(self, data): pad_byte_count = (WORD_SIZE - len(data) % WORD_SIZE) % WORD_SIZE if pad_byte_count > 0: data += bytearray([0xFF] * pad_byte_count) return data def serialize(self): return (bytearray(struct.pack('<HH', self.word_count, self.bl_info_type) + self.data)) class DevicePage(object): def __init__(self, platform, softdevice, bootloader_config): self.entries = [] self.generate_entries(platform, softdevice, bootloader_config) self.platform = platform self.softdevice = softdevice def generate_entries(self, platform, softdevice, bootloader_config): public_key = bytearray.fromhex(bootloader_config["public_key"]) \ if "public_key" in bootloader_config else None if public_key: self.entries.append( DevicePageEntry(BLInfoType.ECDSA_PUBLIC_KEY, public_key)) app_limits = get_application_limits(platform, softdevice) app_segment = bytearray(struct.pack("<II", app_limits["flash_start"], app_limits["flash_size"])) sd_segment = bytearray(struct.pack("<II", softdevice["flash_start"], softdevice["flash_size"])) bl_segment = bytearray(struct.pack("<II", platform["bootloader"]["flash_start"], platform["bootloader"]["flash_size"])) self.entries.append( DevicePageEntry(BLInfoType.SEGMENT_APP, app_segment)) self.entries.append( DevicePageEntry(BLInfoType.SEGMENT_SD, sd_segment)) self.entries.append( DevicePageEntry(BLInfoType.SEGMENT_BL, bl_segment)) version_data = bytearray(struct.pack("<HBBIHI", int(softdevice["version"], 16), bootloader_config["bootloader_id"], bootloader_config["bootloader_version"], bootloader_config["company_id"], bootloader_config["application_id"], bootloader_config["application_version"])) #print(version_data) self.entries.append(DevicePageEntry(BLInfoType.VERSION, version_data)) self.entries.append(DevicePageEntry(BLInfoType.FLAGS, bytearray(struct.pack('I', 0xFFFFFFFF)))) def write_hex(self, hexfile): # Info page metadata raw_data = bytearray(struct.pack("<BBBB", 4, 1, 8, 8)) raw_data += bytearray().join(map(DevicePageEntry.serialize, self.entries)) raw_data += bytearray(struct.pack("<HH", 0xFFFF, BLInfoType.LAST)) hex_output = intelhex.IntelHex() hex_output.frombytes(raw_data, self.platform["flash_size"] - self.platform["page_size"]) hex_output.tofile(hexfile, "hex") def write_specific_page(platforms, softdevices, args): platform = next((p for p in platforms if args.device == p["name"]), None) if not platform: print("Unknown device: \"%s\" in list %r" % (args.device, [p["name"] for p in platforms])) sys.exit(1) softdevice = next((s for s in softdevices if args.softdevice == s["name"]), None) if not softdevice: print("Unknown SoftDevice: \"%s\"" % (args.softdevice)) sys.exit(1) if args.softdevice not in platform["softdevices"]: print("Unknown SoftDevice \"%s\" for platform \"%s\"" % (args.softdevice, args.device)) sys.exit(1) # Filter out the others... platforms = [p for p in platforms if args.device.lower() in p["name"].lower()] make_bootloader_for_platforms(platforms) set_softdevices_for_platforms(platforms, softdevices) # Dict is updated by reference # platform = platforms[args.device] # softdevice = softdevices[args.softdevice] with open(args.bootloader_config, "r") as f: bootloader_config = json.load(f)["bootloader_config"] device_page = DevicePage(platform, softdevice, bootloader_config) if not args.output_file: args.output_file = "_".join(["device_page", self.platform["name"], self.softdevice["name"]]) + ".hex" device_page.write_hex(args.output_file) def write_all(platforms, softdevices, args): make_bootloader_for_platforms(platforms) set_softdevices_for_platforms(platforms, softdevices) with open(args.bootloader_config, "r") as f: bootloader_config = json.load(f)["bootloader_config"] for platform in platforms: for softdevice in platform["softdevices"]: device_page = DevicePage(platform, softdevice, bootloader_config) device_page.write_hex(args.output_file) def main(): softdevices = load_softdevies("../configuration/softdevices.json") platforms = load_platforms("../configuration/platforms.json") sd_str = '' for sd in softdevices: sd_str += ''.join(sd["name"]) + "\n" plt_str = '' for plt in platforms: plt_str += ''.join(plt["name"]) + '\n' SOFTDEVICE = "s132_5.0.0" DEVICE = "nrf52832_xxAA" parser = argparse.ArgumentParser(description="Device Page Generator") parser.add_argument("-d", "--device", help="Select device: " + ''.join(plt_str), default=DEVICE) parser.add_argument("-sd", "--softdevice", help="Select SoftDevice: " + ''.join(sd_str), default=SOFTDEVICE) parser.add_argument("-c", "--bootloader-config", default="bootloader_config_default.json", help="Bootloader configuration file") parser.add_argument("-o", "--output-file", help="Output hex file", default="bin/device_page_%s_%s.hex" % (DEVICE, SOFTDEVICE)) parser.add_argument("--all", default=False, action="store_true", help=("Writes all known device page combinations to " + "\'bin/\'")) args = parser.parse_args() dirname = os.path.dirname(args.output_file) if not os.path.exists(dirname): os.mkdir(dirname) if args.all: write_all(platforms, softdevices, args) print("Wrote for device pages for all devices.") elif args.softdevice and args.device: write_specific_page(platforms, softdevices, args) print("Wrote device page for %s with the %s SoftDevice to %s." % (args.device, args.softdevice, args.output_file)) if __name__ == "__main__": main()