def program(self, args):
        from intelhex import IntelHex
        nrf = SetupCommand(args)

        if args.eraseall:
            nrf.api.erase_all()
        if args.sectorsanduicrerase:
            nrf.api.erase_uicr()

        hex_file = IntelHex(args.file)
        for segment in hex_file.segments():
            start_addr, end_addr = segment
            size = end_addr - start_addr

            if args.sectorserase or args.sectorsanduicrerase:
                start_page = int(start_addr / nrf.device.page_size)
                end_page = int(end_addr / nrf.device.page_size)
                for page in range(start_page, end_page + 1):
                    nrf.api.erase_page(page * nrf.device.page_size)

            data = hex_file.tobinarray(start=start_addr, size=(size))
            nrf.api.write(start_addr, data.tolist(), True)

            if args.verify:
                read_data = nrf.api.read(start_addr, len(data))
                assert (self.byte_lists_equal(data, read_data)), 'Verify failed. Data readback from memory does not match data written.'

        self._reset(nrf, args)

        nrf.cleanup()
    def verify(self, args):
        board = self._setup()

        hex_file = IntelHex(args.file)
        for segment in hex_file.segments():
            start_addr, end_addr = segment
            size = end_addr - start_addr

            data = hex_file.tobinarray(start=start_addr, size=size)
            read_data = board.target.readBlockMemoryUnaligned8(start_addr, size)

            assert (self.byte_lists_equal(data, read_data)), 'Verify failed. Data readback from memory does not match data written.'
Example #3
0
def get_firmware_object(sk_name, hex_file):
    from ecdsa import SigningKey, NIST256p

    sk = SigningKey.from_pem(open(sk_name).read())
    fw = open(hex_file, 'r').read()
    fw = base64.b64encode(fw.encode())
    fw = to_websafe(fw.decode())
    ih = IntelHex()
    ih.fromfile(hex_file, format='hex')
    # start of firmware and the size of the flash region allocated for it.
    # TODO put this somewhere else.
    START = ih.segments()[0][0]
    END = (0x08000000 + ((128 - 19) * 2048)) - 8

    ih = IntelHex(hex_file)
    segs = ih.segments()
    arr = ih.tobinarray(start=START, size=END - START)

    im_size = END - START

    print('im_size: ', im_size)
    print('firmware_size: ', len(arr))

    byts = (arr).tobytes() if hasattr(arr, 'tobytes') else (arr).tostring()
    h = sha256()
    h.update(byts)
    sig = binascii.unhexlify(h.hexdigest())
    print('hash', binascii.hexlify(sig))
    sig = sk.sign_digest(sig)

    print('sig', binascii.hexlify(sig))

    sig = base64.b64encode(sig)
    sig = to_websafe(sig.decode())

    # msg = {'data': read()}
    msg = {'firmware': fw, 'signature': sig}
    return msg
Example #4
0
def hexloader(hex_file, emu, verbose=False):
    """ Load a intel hex file into emu's memory using IntelHex """
    itx = IntelHex(hex_file)

    if verbose:
        print("[x] Loading HEX segments ...")

    for s_start, s_end in itx.segments():
        emu.map_space(s_start, s_end)
        if verbose:
            print(
                f"Writing : {s_start:x} - {len(itx.tobinstr(s_start, s_end-1)):x}"
            )
        emu.emu.mem_write(s_start, itx.tobinstr(s_start, s_end - 1))
Example #5
0
    def program_file(self, name):

        if name.lower().endswith(".json"):
            data = json.loads(open(name, "r").read())
            fw = base64.b64decode(
                helpers.from_websafe(data["firmware"]).encode())
            sig = base64.b64decode(
                helpers.from_websafe(data["signature"]).encode())
            ih = IntelHex()
            tmp = tempfile.NamedTemporaryFile(delete=False)
            tmp.write(fw)
            tmp.seek(0)
            tmp.close()
            ih.fromfile(tmp.name, format="hex")
        else:
            if not name.lower().endswith(".hex"):
                print('Warning, assuming "%s" is an Intel Hex file.' % name)
            sig = None
            ih = IntelHex()
            ih.fromfile(name, format="hex")

        if self.exchange == self.exchange_hid:
            chunk = 2048
        else:
            chunk = 240

        seg = ih.segments()[0]
        size = seg[1] - seg[0]
        total = 0
        t1 = time.time() * 1000
        print("erasing firmware...")
        for i in range(seg[0], seg[1], chunk):
            s = i
            e = min(i + chunk, seg[1])
            data = ih.tobinarray(start=i, size=e - s)
            self.write_flash(i, data)
            total += chunk
            progress = total / float(size) * 100
            sys.stdout.write("updating firmware %.2f%%...\r" % progress)
        sys.stdout.write("updated firmware 100%             \r\n")
        t2 = time.time() * 1000
        print("time: %.2f s" % ((t2 - t1) / 1000.0))

        if sig is None:
            sig = b"A" * 64

        if self.do_reboot:
            self.verify_flash(sig)

        return sig
Example #6
0
    def verify(self, args):
        board = self._setup()

        hex_file = IntelHex(args.file)
        for segment in hex_file.segments():
            start_addr, end_addr = segment
            size = end_addr - start_addr

            data = hex_file.tobinarray(start=start_addr, size=size)
            read_data = board.target.readBlockMemoryUnaligned8(
                start_addr, size)

            assert (self.byte_lists_equal(data, read_data)
                    ), 'Verify failed. Data readback from memory does not match data written.'
Example #7
0
def sign_firmware_for_version(sk_name,
                              hex_file,
                              APPLICATION_END_PAGE,
                              PAGES=128):
    # Maybe this is not the optimal module...

    import base64
    import binascii
    from hashlib import sha256

    from ecdsa import SigningKey
    from intelhex import IntelHex

    sk = SigningKey.from_pem(open(sk_name).read())
    fw = open(hex_file, "r").read()
    fw = base64.b64encode(fw.encode())
    fw = helpers.to_websafe(fw.decode())
    ih = IntelHex()
    ih.fromfile(hex_file, format="hex")
    # start of firmware and the size of the flash region allocated for it.
    # TODO put this somewhere else.
    START = ih.segments()[0][0]
    # keep in sync with targets/stm32l432/src/memory_layout.h
    PAGE_SIZE = 2048
    END = (0x08000000 + ((PAGES - APPLICATION_END_PAGE) * PAGE_SIZE)) - 8

    ih = IntelHex(hex_file)
    # segs = ih.segments()
    arr = ih.tobinarray(start=START, size=END - START)

    im_size = END - START

    print("im_size: ", im_size)
    print("firmware_size: ", len(arr))

    byts = (arr).tobytes() if hasattr(arr, "tobytes") else (arr).tostring()
    h = sha256()
    h.update(byts)
    sig = binascii.unhexlify(h.hexdigest())
    print("hash", binascii.hexlify(sig))
    sig = sk.sign_digest(sig)

    print("sig", binascii.hexlify(sig))

    sig = base64.b64encode(sig)
    sig = helpers.to_websafe(sig.decode())

    # msg = {'data': read()}
    msg = {"firmware": fw, "signature": sig}
    return msg
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--binary", required=True, type=pathlib.Path)
    parser.add_argument("--hex", required=True, type=pathlib.Path)
    parser.add_argument("--lzss_tool", required=True, type=pathlib.Path)

    option = parser.parse_args()

    intel_hex = IntelHex(str(option.hex))
    ds_segment, xs_segment = intel_hex.segments()[1:3]

    ds_header = intel_hex.tobinarray(
        start=ds_segment[0], end=ds_segment[0] + 0x10 - 1)
    ds_data = intel_hex.tobinarray(
        start=ds_segment[0] + 0x10, end=ds_segment[1] - 1)
    xs_data = intel_hex.tobinarray(start=xs_segment[0], end=xs_segment[1] - 1)

    # Align to 4 bytes
    ds_data = pad_data(ds_data, 4)
    xs_data = pad_data(xs_data, 4)

    # Pad XS data CRC to DS data
    xs_crc = zlib.crc32(xs_data)
    ds_data += pack("<L", xs_crc)

    # Compressed data
    cx_data = compress_data(option, xs_data, ".xs.bin")
    cx_crc = zlib.crc32(cx_data)

    # DS header
    ds_crc = zlib.crc32(ds_data)
    pack_into("<LL", ds_header, 0x08, ds_crc, len(ds_data))

    # XS header
    xs_header = ds_header.tobytes()
    xs_header += pack("<LL", xs_crc, len(xs_data))
    xs_header += pack("<LL", cx_crc, len(cx_data))

    print("DS: Length 0x{:08x}, CRC 0x{:08x}".format(len(ds_data), ds_crc))
    print("XS: Length 0x{:08x}, CRC 0x{:08x}".format(len(xs_data), xs_crc))
    print("CX: Length 0x{:08x}, CRC 0x{:08x}".format(len(cx_data), cx_crc))

    with open(str(option.binary), mode="wb") as binary:
        binary.write(ds_header)
        binary.write(ds_data)
        binary.write(xs_header)
        binary.write(cx_data)

    return 0
    def verify(self, args):
        from intelhex import IntelHex
        nrf = SetupCommand(args)

        hex_file = IntelHex(args.file)
        for segment in hex_file.segments():
            start_addr, end_addr = segment
            size = end_addr - start_addr

            data = hex_file.tobinarray(start=start_addr, size=size)
            read_data = nrf.api.read(start_addr, size)

            assert (self.byte_lists_equal(data, read_data)), 'Verify failed. Data readback from memory does not match data written.'

        nrf.cleanup()
Example #10
0
    def verify(self, args):
        from intelhex import IntelHex
        nrf = SetupCommand(args)

        hex_file = IntelHex(args.file)
        for segment in hex_file.segments():
            start_addr, end_addr = segment
            size = end_addr - start_addr

            data = hex_file.tobinarray(start=start_addr, size=size)
            read_data = nrf.api.read(start_addr, size)

            assert (self.byte_lists_equal(data, read_data)
                    ), 'Verify failed. Data readback from memory does not match data written.'

        nrf.cleanup()
Example #11
0
    def program_file(self, name):

        if name.lower().endswith('.json'):
            data = json.loads(open(name, 'r').read())
            fw = base64.b64decode(from_websafe(data['firmware']).encode())
            sig = base64.b64decode(from_websafe(data['signature']).encode())
            ih = IntelHex()
            tmp = tempfile.NamedTemporaryFile(delete=False)
            tmp.write(fw)
            tmp.seek(0)
            tmp.close()
            ih.fromfile(tmp.name, format='hex')
        else:
            if not name.lower().endswith('.hex'):
                print('Warning, assuming "%s" is an Intel Hex file.' % name)
            sig = None
            ih = IntelHex()
            ih.fromfile(name, format='hex')

        if self.exchange == self.exchange_hid:
            chunk = 2048
        else:
            chunk = 240

        seg = ih.segments()[0]
        size = seg[1] - seg[0]
        total = 0
        t1 = time.time() * 1000
        print('erasing...')
        for i in range(seg[0], seg[1], chunk):
            s = i
            e = min(i + chunk, seg[1])
            data = ih.tobinarray(start=i, size=e - s)
            self.write_flash(i, data)
            total += chunk
            progress = total / float(size) * 100
            sys.stdout.write('downloading %.2f%%...\r' % progress)
        sys.stdout.write('downloaded 100%             \r\n')
        t2 = time.time() * 1000
        print('time: %.2f s' % ((t2 - t1) / 1000.0))

        print('Verifying...')
        if self.do_reboot:
            if sig is not None:
                self.verify_flash(sig)
            else:
                self.verify_flash(b'A' * 64)
def read_hex_file(filename):
    """
    -Richter 2021
    Reads a hex file and generates flashable elements like with a dfu file
    """
    print("File: {}".format(filename))
    ih = IntelHex()
    ih.loadhex(filename)
    segments = ih.segments()
    print("Segments:", segments)
    elements = []
    for segId, segment in enumerate(segments):
        size = segment[1] - segment[0]
        dat = [ih[i] for i in range(segment[0], segment[1])]
        elem = {"addr": segment[0], "size": size, "num": segId, "data": dat}
        elements.append(elem)
    return elements
Example #13
0
def read_hexdata(hex_path):
    ih = IntelHex(hex_path)
    ih.padding = 0x00
    print(len(ih), MAX_BINLEN, ih.start_addr, ih.minaddr(), ih.maxaddr())
    print(ih.segments())
    print(ih[0], ih[1], ih[2])
    #print([x for x in ih[0:2]])
            
    if (ih[1] == 0x38 and ih[2] == 0x00):
        print(">>> Fixing hex file")
        ih[0] = ih[0x37FB]
        ih[1] = ih[0x37FC]
        ih[2] = ih[0x37FD]
        ih[0x37FB] = 0x00;
        ih[0x37FC] = 0x00
        ih[0x37FD] = 0x00
    print(ih[0], ih[1], ih[2])
    return ih.tobinarray(size=MAX_BINLEN)
Example #14
0
def summarize_yaml(fname):
    print("{:s}file: '{:s}'".format(INLIST, fname))
    from intelhex import IntelHex
    ih = IntelHex(fname)
    if ih.start_addr:
        keys = sorted(ih.start_addr.keys())
        if keys == ['CS','IP']:
            entry = ih.start_addr['CS'] * 65536 + ih.start_addr['IP']
        elif keys == ['EIP']:
            entry = ih.start_addr['EIP']
        else:
            raise RuntimeError("unknown 'IntelHex.start_addr' found")
        print("{:s}entry: 0x{:08X}".format(INDENT, entry))
    segments = ih.segments()
    if segments:
        print("{:s}data:".format(INDENT))
        for s in segments:
            print("{:s}{:s}{{ first: 0x{:08X}, last: 0x{:08X}, length: 0x{:08X} }}".format(INDENT, INLIST, s[0], s[1]-1, s[1]-s[0]))
    print("")
Example #15
0
def ihexsize(ihexf, granularity=1):
    ih = IntelHex()
    ih.loadhex(ihexf)
    all_sections = ih.segments()
    low_addr = all_sections[0][0]
    high_addr = all_sections[0][1]
    logging.debug("input hex file sections:")
    for sec in all_sections:
        logging.debug("0x%08X 0x%08X" % (sec[0], sec[1] - 1))
        low_addr = min(low_addr, sec[0])
        high_addr = max(high_addr, sec[1])

    logging.debug("low_addr =0x%x" % low_addr)
    logging.debug("high_addr=0x%x" % high_addr)
    size = high_addr - low_addr
    part = size % granularity
    if 0 != part:
        size += granularity - part
    return size
Example #16
0
def load_state(filename):
    reg_regex = re.compile(r"^([^=]{2,4})=0x([0-9a-f]+)$")

    with open(filename, "r") as file:
        reg_vals = {}

        for _ in uc_reg_consts:
            line = file.readline()
            name, val_str = reg_regex.match(line).groups()
            val = int(val_str, 16)
            reg_vals[name] = val

        mem_segments = {}
        ih = IntelHex(file)
        for addr, end in ih.segments():
            contents = ih.gets(addr, end - addr)
            mem_segments[addr] = contents

        return reg_vals, mem_segments
Example #17
0
def summarize_yaml(fname):
    print("{:s}file: '{:s}'".format(INLIST, fname))
    from intelhex import IntelHex
    ih = IntelHex(fname)
    if ih.start_addr:
        keys = ih.start_addr.keys()
        keys.sort()
        if keys == ['CS','IP']:
            entry = ih.start_addr['CS'] * 65536 + ih.start_addr['IP']
        elif keys == ['EIP']:
            entry = ih.start_addr['EIP']
        else:
            raise RuntimeError("unknown 'IntelHex.start_addr' found")
        print("{:s}entry: 0x{:08X}".format(INDENT, entry))
    segments = ih.segments()
    if segments:
        print("{:s}data:".format(INDENT))
        for s in segments:
            print("{:s}{:s}{{ first: 0x{:08X}, last: 0x{:08X}, length: 0x{:08X} }}".format(INDENT, INLIST, s[0], s[1]-1, s[1]-s[0]))
    print("")
Example #18
0
def load_firmware_update(fw_update_file):
    print('loading firmware update ...')
    # the update file has multiple End Of File records (which is invalid)
    # so we split the intel hex update file into multiple files
    hex_strs = []
    s = ""
    with open(fw_update_file, 'r') as f:
        for l in f.readlines():
            s += l
            # end of file record
            if l.rstrip() == ':00000001FF':
                hex_strs.append(s)
                s = ""
    assert len(hex_strs) > 0, 'firmware update file has no firmware!'

    # IntelHex library doesn't like multiple Start Address records
    # so we only load the boot loader since that is what we need
    ih = IntelHex(io.StringIO(hex_strs[0]))
    for s, e in ih.segments():
        print(f'  {hex(s)}-{hex(e)}')
    return ih
def verify_flash_from_hex(hex_filename, backend):
    """
    Verify the contents of flash against a hex-file

    :param filename: Name/path of hex-file to verify
    :param device_memory_info: DeviceMemoryInfo instance for the device the hex file should be verified against
    :param backend: Reference to the Backend class of pymcuprog
    :returns: Boolean value indicating success or failure of the operation
    """
    hexfile = IntelHex(hex_filename)
    segments = hexfile.segments()

    for i in range(len(segments)):
        segment_data = []
        for j in range(segments[i][1]-segments[i][0]):
            segment_data.append(hexfile[segments[i][0]+j])

        verify_status = backend.verify_memory(segment_data, 'flash', segments[i][0])
        if verify_status is False:
            return False
    return True
Example #20
0
    def install_app(self, app_manifest: AppManifest):
        hex_file = IntelHex(app_manifest.get_binary())
        code_length = hex_file.maxaddr() - hex_file.minaddr() + 1
        data_length = app_manifest.data_size

        code_length -= data_length
        assert code_length % 64 == 0  # code length must be aligned

        flags = app_manifest.get_application_flags()  # not handled yet

        params = app_manifest.serialize_parameters()
        main_address = hex_file.start_addr["EIP"] - hex_file.minaddr()

        data = struct.pack(">IIIII", code_length, data_length, len(params),
                           flags, main_address)
        self.apdu_secure_exchange(LedgerSecureIns.CREATE_APP, data)

        hex_file.puts(hex_file.maxaddr() + 1, params)

        for segment in hex_file.segments():
            self._load_segment(hex_file, segment)
        self.apdu_secure_exchange(LedgerSecureIns.COMMIT)
Example #21
0
async def file_service():  # config r/w
    for cfg in os.listdir('configs'):
        if cfg.endswith('.json'):
            csa['cfgs'].append(cfg)

    sock = CDWebSocket(ws_ns, 'file')
    while True:
        dat, src = await sock.recvfrom()
        logger.debug(f'file ser: {dat}')

        if dat['action'] == 'get_cfgs':
            await sock.sendto(csa['cfgs'], src)

        elif dat['action'] == 'get_cfg':
            with open(os.path.join('configs', dat['cfg'])) as c_file:
                c = json5.load(c_file)
                await sock.sendto(c, src)

        elif dat['action'] == 'get_ihex':
            ret = []
            ih = IntelHex()
            try:
                ih.loadhex(dat['path'])
                segs = ih.segments()
                logger.info(
                    f'parse ihex file, segments: {[list(map(hex, l)) for l in segs]} (end addr inclusive)'
                )
                for seg in segs:
                    s = [seg[0], ih.tobinstr(seg[0], size=seg[1] - seg[0])]
                    ret.append(s)
            except Exception as err:
                logger.error(f'parse ihex file error: {err}')
            await sock.sendto(ret, src)

        else:
            await sock.sendto('err: file: unknown cmd', src)
Example #22
0
                except ValueError:
                    print("Address %s invalid." % address)
                    sys.exit(1)
                if not os.path.isfile(binfile):
                    print("Unreadable file '%s'." % binfile)
                    sys.exit(1)
                checkbin(binfile)
                target.append({
                    'address': address,
                    'data': open(binfile, 'rb').read()
                })

        if options.hexfiles:
            for hex in options.hexfiles:
                ih = IntelHex(hex)
                for (address, end) in ih.segments():
                    try:
                        address = address & 0xFFFFFFFF
                    except ValueError:
                        print "Address %s invalid." % address
                        sys.exit(1)
                    target.append({
                        'address':
                        address,
                        'data':
                        ih.tobinstr(start=address, end=end - 1)
                    })

        outfile = args[0]
        device = DEFAULT_DEVICE
        if options.device:
Example #23
0
    def program_hex_nrf53(self, erase_arg, program_commands):
        # program_hex() helper for nRF53.

        # *********************** NOTE *******************************
        # self.hex_ can contain code for both the application core and
        # the network core.
        #
        # We can't assume, for example, that
        # CONFIG_SOC_NRF5340_CPUAPP=y means self.hex_ only contains
        # data for the app core's flash: the user can put arbitrary
        # addresses into one of the files in HEX_FILES_TO_MERGE.
        #
        # Therefore, on this family, we may need to generate two new
        # hex files, one for each core, and flash them individually
        # with the correct '--coprocessor' arguments.
        #
        # Kind of hacky, but it works, and nrfjprog is not capable of
        # flashing to both cores at once. If self.hex_ only affects
        # one core's flash, then we skip the extra work to save time.
        # ************************************************************

        def add_program_cmd(hex_file, coprocessor):
            program_commands.append([
                'nrfjprog', '--program', hex_file, erase_arg, '-f', 'NRF53',
                '--snr', self.dev_id, '--coprocessor', coprocessor
            ] + self.tool_opt)

        full_hex = IntelHex()
        full_hex.loadfile(self.hex_, format='hex')
        min_addr, max_addr = full_hex.minaddr(), full_hex.maxaddr()

        # Base address of network coprocessor's flash. From nRF5340
        # OPS. We should get this from DTS instead if multiple values
        # are possible, but this is fine for now.
        net_base = 0x01000000

        if min_addr < net_base <= max_addr:
            net_hex, app_hex = IntelHex(), IntelHex()

            for start, stop in full_hex.segments():
                segment_hex = net_hex if start >= net_base else app_hex
                segment_hex.merge(full_hex[start:stop])

            hex_path = Path(self.hex_)
            hex_dir, hex_name = hex_path.parent, hex_path.name

            net_hex_file = os.fspath(hex_dir /
                                     f'GENERATED_CP_NETWORK_{hex_name}')
            app_hex_file = os.fspath(hex_dir /
                                     f'GENERATED_CP_APPLICATION_{hex_name}')

            self.logger.info(
                f'{self.hex_} targets both nRF53 coprocessors; '
                f'splitting it into: {net_hex_file} and {app_hex_file}')

            net_hex.write_hex_file(net_hex_file)
            app_hex.write_hex_file(app_hex_file)

            add_program_cmd(net_hex_file, 'CP_NETWORK')
            add_program_cmd(app_hex_file, 'CP_APPLICATION')
        else:
            coprocessor = 'CP_NETWORK' if max_addr >= net_base else 'CP_APPLICATION'
            add_program_cmd(self.hex_, coprocessor)
Example #24
0
    def program_file(self, name):
        def parseField(f):
            return base64.b64decode(helpers.from_websafe(f).encode())

        def isCorrectVersion(current, target):
            """ current is tuple (x,y,z).  target is string '>=x.y.z'.
                Return True if current satisfies the target expression.
            """
            if "=" in target:
                target = target.split("=")
                assert target[0] in [">", "<"]
                target_num = [int(x) for x in target[1].split(".")]
                assert len(target_num) == 3
                comp = target[0] + "="
            else:
                assert target[0] in [">", "<"]
                target_num = [int(x) for x in target[1:].split(".")]
                comp = target[0]
            target_num = ((target_num[0] << 16) | (target_num[1] << 8) |
                          (target_num[2] << 0))
            current_num = (current[0] << 16) | (current[1] << 8) | (
                current[2] << 0)
            return eval(str(current_num) + comp + str(target_num))

        if name.lower().endswith(".json"):
            data = json.loads(open(name, "r").read())
            fw = parseField(data["firmware"])
            sig = None

            if "versions" in data:
                current = (0, 0, 0)
                try:
                    current = self.bootloader_version()
                except CtapError as e:
                    if e.code == CtapError.ERR.INVALID_COMMAND:
                        pass
                    else:
                        raise (e)
                for v in data["versions"]:
                    if isCorrectVersion(current, v):
                        print("using signature version", v)
                        sig = parseField(data["versions"][v]["signature"])
                        break

                if sig is None:
                    raise RuntimeError(
                        "Improperly formatted firmware file.  Could not match version."
                    )
            else:
                sig = parseField(data["signature"])

            ih = IntelHex()
            tmp = tempfile.NamedTemporaryFile(delete=False)
            tmp.write(fw)
            tmp.seek(0)
            tmp.close()
            ih.fromfile(tmp.name, format="hex")
        else:
            if not name.lower().endswith(".hex"):
                print('Warning, assuming "%s" is an Intel Hex file.' % name)
            sig = None
            ih = IntelHex()
            ih.fromfile(name, format="hex")

        if self.exchange == self.exchange_hid:
            chunk = 2048
        else:
            chunk = 240

        seg = ih.segments()[0]
        size = seg[1] - seg[0]
        total = 0
        t1 = time.time() * 1000
        print("erasing firmware...")
        for i in range(seg[0], seg[1], chunk):
            s = i
            e = min(i + chunk, seg[1])
            data = ih.tobinarray(start=i, size=e - s)
            self.write_flash(i, data)
            total += chunk
            progress = total / float(size) * 100
            sys.stdout.write("updating firmware %.2f%%...\r" % progress)
        sys.stdout.write("updated firmware 100%             \r\n")
        t2 = time.time() * 1000
        print("time: %.2f s" % ((t2 - t1) / 1000.0))

        if sig is None:
            sig = b"A" * 64

        if self.do_reboot:
            self.verify_flash(sig)

        return sig
Example #25
0
def dfu(serial, connect_attempts, detach, dry_run, firmware):
    """Program via STMicroelectronics DFU interface.


    Enter dfu mode using `solo program aux enter-dfu` first.
    """

    import time

    import usb.core
    from intelhex import IntelHex

    dfu = solo.dfu.find(serial, attempts=connect_attempts)

    if dfu is None:
        print("No STU DFU device found.")
        if serial is not None:
            print("Serial number used: ", serial)
        sys.exit(1)

    dfu.init()

    if not dry_run:
        # The actual programming
        # TODO: move to `operations.py` or elsewhere
        ih = IntelHex()
        ih.fromfile(firmware, format="hex")

        chunk = 2048
        # Why is this unused
        # seg = ih.segments()[0]
        size = sum([max(x[1] - x[0], chunk) for x in ih.segments()])
        total = 0
        t1 = time.time() * 1000

        print("erasing...")
        try:
            dfu.mass_erase()
        except usb.core.USBError:
            # garbage write, sometimes needed before mass_erase
            dfu.write_page(0x08000000 + 2048 * 10, "ZZFF" * (2048 // 4))
            dfu.mass_erase()

        page = 0
        for start, end in ih.segments():
            for i in range(start, end, chunk):
                page += 1
                data = ih.tobinarray(start=i, size=chunk)
                dfu.write_page(i, data)
                total += chunk
                # here and below, progress would overshoot 100% otherwise
                progress = min(100, total / float(size) * 100)

                sys.stdout.write(
                    "downloading %.2f%%  %08x - %08x ...         \r" %
                    (progress, i, i + page))
                # time.sleep(0.100)

            # print('done')
            # print(dfu.read_mem(i,16))

        t2 = time.time() * 1000
        print()
        print("time: %d ms" % (t2 - t1))
        print("verifying...")
        progress = 0
        for start, end in ih.segments():
            for i in range(start, end, chunk):
                data1 = dfu.read_mem(i, 2048)
                data2 = ih.tobinarray(start=i, size=chunk)
                total += chunk
                progress = min(100, total / float(size) * 100)
                sys.stdout.write("reading %.2f%%  %08x - %08x ...         \r" %
                                 (progress, i, i + page))
                if (end - start) == chunk:
                    assert data1 == data2
        print()
        print("firmware readback verified.")

    if detach:
        dfu.prepare_options_bytes_detach()
        dfu.detach()
        print("Please powercycle the device (pull out, plug in again)")

    hot_patch_windows_libusb()
Example #26
0
    # System registers
    #
    # PEEK_ROM_COMMAND = 6
    #
    # COMMAND 10125
    # RESULT_DATA 10126   This is the base address to read peek results from

    #######################################
    #
    # This is very slow but shows an example of how to peek into the Smartbox ROM and compare result to hex file
    print("Reading rom hex file")
    ih = IntelHex("test_rom1.hex")

    print("Segments found:")
    print(ih.segments())

    numWrites = 0  # number of write chunks.  This is used for verifying

    for segment in ih.segments():
        start = segment[0]
        end = segment[1]
        if start < 0x1003000:  # this is the magic dual partition boot config that should never be changed FBOOT
            print("Segment: " + str(start) + " - " + str(end))  # in bytes
            address = start
            while address < end:
                fileValue = ih[address] | (ih[address + 1] << 8) | (
                    ih[address + 2] << 16)

                # peek in bank 0 (active boot) ROM
                romAddress = address >> 1
Example #27
0
  usage = """
%prog {-i|--ihex} file.hex [-i file.hex ...] [{-D|--device}=vendor:device] outfile.dfu"""

  parser = OptionParser(usage=usage)
  parser.add_option("-i", "--ihex", action="append", dest="hexfiles",
    help="build a DFU file from given HEXFILES", metavar="HEXFILES")
  parser.add_option("-D", "--device", action="store", dest="device",
    help="build for DEVICE, defaults to %s" % DEFAULT_DEVICE, metavar="DEVICE")
  (options, args) = parser.parse_args()

  if options.hexfiles and len(args)==1:
    target = []
    
    for h in options.hexfiles:
      ih = IntelHex(h)
      for (s,e) in ih.segments():
        target.append({ 'address': s, 'data': ih.tobinstr(s,e-1) })
    
    outfile = args[0]
    device = DEFAULT_DEVICE
    if options.device:
      device=options.device
    try:
      v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1))
    except:
      print("Invalid device '%s'." % device)
      sys.exit(1)
    build(outfile,[target],device)
  else:
    parser.print_help()
    sys.exit(1)
Example #28
0
def update_device(device, firmware, logger, cancellation_token):
    """
    Updates the specified device with the specified firmware.
    The device passed to this function can either be in
    normal mode or in DFU mode.
    The firmware should be an instance of Firmware or None.
    If firmware is None, the newest firmware for the device is
    downloaded from GitHub releases.
    """

    if isinstance(device, usb.core.Device):
        serial_number = device.serial_number
        dfudev = DfuDevice(device)
        if (logger._verbose):
            logger.debug("OTP:")
            dump_otp(dfudev)

        # Read hardware version from one-time-programmable memory
        otp_sector = [s for s in dfudev.sectors if s['name'] == 'OTP Memory' and s['addr'] == 0x1fff7800][0]
        otp_data = dfudev.read_sector(otp_sector)
        if otp_data[0] == 0:
            otp_data = otp_data[16:]
        if otp_data[0] == 0xfe:
            hw_version = (otp_data[3], otp_data[4], otp_data[5])
        else:
            hw_version = (0, 0, 0)
    else:
        serial_number = device.__channel__.usb_device.serial_number
        dfudev = None

        # Read hardware version as reported from firmware
        hw_version_major = device.hw_version_major if hasattr(device, 'hw_version_major') else 0
        hw_version_minor = device.hw_version_minor if hasattr(device, 'hw_version_minor') else 0
        hw_version_variant = device.hw_version_variant if hasattr(device, 'hw_version_variant') else 0
        hw_version = (hw_version_major, hw_version_minor, hw_version_variant)

    if hw_version < (3, 5, 0):
        print("  DFU mode is not supported on board version 3.4 or earlier.")
        print("  This is because entering DFU mode on such a device would")
        print("  break the brake resistor FETs under some circumstances.")
        print("Warning: DFU mode is not supported on ODrives earlier than v3.5 unless you perform a hardware mod.")
        if not odrive.utils.yes_no_prompt("Do you still want to continue?", False):
            raise OperationAbortedException()

    fw_version_major = device.fw_version_major if hasattr(device, 'fw_version_major') else 0
    fw_version_minor = device.fw_version_minor if hasattr(device, 'fw_version_minor') else 0
    fw_version_revision = device.fw_version_revision if hasattr(device, 'fw_version_revision') else 0
    fw_version_prerelease = device.fw_version_prerelease if hasattr(device, 'fw_version_prerelease') else True
    fw_version = (fw_version_major, fw_version_minor, fw_version_revision, fw_version_prerelease)

    print("Found ODrive {} ({}) with firmware {}{}".format(
                serial_number,
                get_hw_version_string(hw_version),
                get_fw_version_string(fw_version),
                " in DFU mode" if dfudev is not None else ""))

    if firmware is None:
        if hw_version == (0, 0, 0):
            if dfudev is None:
                suggestion = 'You have to manually flash an up-to-date firmware to make automatic checks work. Run `odrivetool dfu --help` for more info.'
            else:
                suggestion = 'Run "make write_otp" to program the board version.'
            raise Exception('Cannot check online for new firmware because the board version is unknown. ' + suggestion)
        print("Checking online for newest firmware...", end='')
        firmware = get_newest_firmware(hw_version)
        if firmware is None:
            raise Exception("could not find any firmware release for this board version")
        print(" found {}".format(get_fw_version_string(firmware.fw_version)))

    if firmware.fw_version <= fw_version:
        print()
        if firmware.fw_version < fw_version:
            print("Warning: you are about to flash firmware {} which is older than the firmware on the device ({}).".format(
                    get_fw_version_string(firmware.fw_version),
                    get_fw_version_string(fw_version)))
        else:
            print("You are about to flash firmware {} which is the same version as the firmware on the device ({}).".format(
                    get_fw_version_string(firmware.fw_version),
                    get_fw_version_string(fw_version)))
        if not odrive.utils.yes_no_prompt("Do you want to flash this firmware anyway?", False):
            raise OperationAbortedException()

    # load hex file
    # TODO: Either use the elf format or pack a custom format with a manifest.
    # This way we can for instance verify the target board version and only
    # have to publish one file for every board (instead of elf AND hex files).
    hexfile = IntelHex(firmware.get_as_hex())

    logger.debug("Contiguous segments in hex file:")
    for start, end in hexfile.segments():
        logger.debug(" {:08X} to {:08X}".format(start, end - 1))

    # Back up configuration
    if dfudev is None:
        do_backup_config = device.user_config_loaded if hasattr(device, 'user_config_loaded') else False
        if do_backup_config:
            odrive.configuration.backup_config(device, None, logger)
    elif not odrive.utils.yes_no_prompt("The configuration cannot be backed up because the device is already in DFU mode. The configuration may be lost after updating. Do you want to continue anyway?", True):
        raise OperationAbortedException()

    # Put the device into DFU mode if it's not already in DFU mode
    if dfudev is None:
        find_odrive_cancellation_token = Event(cancellation_token)
        put_into_dfu_mode(device, find_odrive_cancellation_token)
        stm_device = find_device_in_dfu_mode(serial_number, cancellation_token)
        find_odrive_cancellation_token.set()
        dfudev = DfuDevice(stm_device)

    logger.debug("Sectors on device: ")
    for sector in dfudev.sectors:
        logger.debug(" {:08X} to {:08X} ({})".format(
            sector['addr'],
            sector['addr'] + sector['len'] - 1,
            sector['name']))

    # fill sectors with data
    touched_sectors = list(populate_sectors(dfudev.sectors, hexfile))

    logger.debug("The following sectors will be flashed: ")
    for sector,_ in touched_sectors:
        logger.debug(" {:08X} to {:08X}".format(sector['addr'], sector['addr'] + sector['len'] - 1))

    # Erase
    try:
        for i, (sector, data) in enumerate(touched_sectors):
            print("Erasing... (sector {}/{})  \r".format(i, len(touched_sectors)), end='', flush=True)
            dfudev.erase_sector(sector)
        print('Erasing... done            \r', end='', flush=True)
    finally:
        print('', flush=True)

    # Flash
    try:
        for i, (sector, data) in enumerate(touched_sectors):
            print("Flashing... (sector {}/{})  \r".format(i, len(touched_sectors)), end='', flush=True)
            dfudev.write_sector(sector, data)
        print('Flashing... done            \r', end='', flush=True)
    finally:
        print('', flush=True)

    # Verify
    try:
        for i, (sector, expected_data) in enumerate(touched_sectors):
            print("Verifying... (sector {}/{})  \r".format(i, len(touched_sectors)), end='', flush=True)
            observed_data = dfudev.read_sector(sector)
            mismatch_pos = get_first_mismatch_index(observed_data, expected_data)
            if not mismatch_pos is None:
                mismatch_pos -= mismatch_pos % 16
                observed_snippet = ' '.join('{:02X}'.format(x) for x in observed_data[mismatch_pos:mismatch_pos+16])
                expected_snippet = ' '.join('{:02X}'.format(x) for x in expected_data[mismatch_pos:mismatch_pos+16])
                raise RuntimeError("Verification failed around address 0x{:08X}:\n".format(sector['addr'] + mismatch_pos) +
                                   "  expected: " + expected_snippet + "\n"
                                   "  observed: " + observed_snippet)
        print('Verifying... done            \r', end='', flush=True)
    finally:
        print('', flush=True)


    # If the flash operation failed for some reason, your device is bricked now.
    # You can unbrick it as long as the device remains powered on.
    # (or always with an STLink)
    # So for debugging you should comment this last part out.

    # Jump to application
    dfudev.jump_to_application(0x08000000)

    logger.info("Waiting for the device to reappear...")
    device = odrive.find_any("usb", serial_number,
                    cancellation_token, cancellation_token, timeout=30)

    if do_backup_config:
        odrive.configuration.restore_config(device, None, logger)
        os.remove(odrive.configuration.get_temp_config_filename(device))

    logger.success("Device firmware update successful.")
Example #29
0
def use_dfu(args):
    fw = args.__dict__["[firmware]"]

    for i in range(0, 8):
        dfu = DFUDevice()
        try:
            dfu.find(ser=args.dfu_serial)
        except RuntimeError:
            time.sleep(0.25)
            dfu = None

    if dfu is None:
        print("No STU DFU device found. ")
        if args.dfu_serial:
            print("Serial number used: ", args.dfu_serial)
        sys.exit(1)
    dfu.init()

    if fw:
        ih = IntelHex()
        ih.fromfile(fw, format="hex")

        chunk = 2048
        seg = ih.segments()[0]
        size = sum([max(x[1] - x[0], chunk) for x in ih.segments()])
        total = 0
        t1 = time.time() * 1000

        print("erasing...")
        try:
            dfu.mass_erase()
        except usb.core.USBError:
            dfu.write_page(0x08000000 + 2048 * 10, "ZZFF" * (2048 // 4))
            dfu.mass_erase()

        page = 0
        for start, end in ih.segments():
            for i in range(start, end, chunk):
                page += 1
                s = i
                data = ih.tobinarray(start=i, size=chunk)
                dfu.write_page(i, data)
                total += chunk
                progress = total / float(size) * 100

                sys.stdout.write(
                    "downloading %.2f%%  %08x - %08x ...         \r" %
                    (progress, i, i + page))
                # time.sleep(0.100)

            # print('done')
            # print(dfu.read_mem(i,16))
        t2 = time.time() * 1000
        print()
        print("time: %d ms" % (t2 - t1))
        print("verifying...")
        progress = 0
        for start, end in ih.segments():
            for i in range(start, end, chunk):
                data1 = dfu.read_mem(i, 2048)
                data2 = ih.tobinarray(start=i, size=chunk)
                total += chunk
                progress = total / float(size) * 100
                sys.stdout.write("reading %.2f%%  %08x - %08x ...         \r" %
                                 (progress, i, i + page))
                if (end - start) == chunk:
                    assert data1 == data2
        print()
        print("firmware readback verified.")
    if args.detach:
        dfu.detach()
Example #30
0
def merge_region_list(region_list,
                      destination,
                      notify,
                      config,
                      padding=b'\xFF'):
    """Merge the region_list into a single image

    Positional Arguments:
    region_list - list of regions, which should contain filenames
    destination - file name to write all regions to
    padding - bytes to fill gaps with
    """
    merged = IntelHex()
    _, format = splitext(destination)
    notify.info("Merging Regions")
    # Merged file list: Keep track of binary/hex files that we have already
    # merged. e.g In some cases, bootloader may be split into multiple parts,
    # but all internally referring to the same bootloader file.
    merged_list = []

    for region in region_list:
        if region.active and not region.filename:
            raise ToolException(
                "Active region has no contents: No file found.")
        if isinstance(region.filename, list):
            header_basename, _ = splitext(destination)
            header_filename = header_basename + "_header.hex"
            _fill_header(region_list, region).tofile(header_filename,
                                                     format='hex')
            region = region._replace(filename=header_filename)
        if region.filename and (region.filename not in merged_list):
            notify.info("  Filling region %s with %s" %
                        (region.name, region.filename))
            part = intelhex_offset(region.filename, offset=region.start)
            part.start_addr = None
            # Normally, we assume that part.maxddr() can be beyond
            # end of rom. If the size is restricted with config, don't
            # allow this.
            if config.target.restrict_size is not None:
                part_size = (part.maxaddr() - part.minaddr()) + 1
                if part_size > region.size:
                    raise ToolException("Contents of region %s does not fit" %
                                        region.name)
            merged_list.append(region.filename)
            merged.merge(part)
        elif region.filename in merged_list:
            notify.info("  Skipping %s as it is merged previously" %
                        (region.name))

    # Hex file can have gaps, so no padding needed. While other formats may
    # need padding. Iterate through segments and pad the gaps.
    if format != ".hex":
        # begin patching from the end of the first segment
        _, begin = merged.segments()[0]
        for start, stop in merged.segments()[1:]:
            pad_size = start - begin
            merged.puts(begin, padding * pad_size)
            begin = stop + 1

    if not exists(dirname(destination)):
        makedirs(dirname(destination))
    notify.info("Space used after regions merged: 0x%x" %
                (merged.maxaddr() - merged.minaddr() + 1))
    merged.tofile(destination, format=format.strip("."))
class nRF5MultiFlash(object):
    def __init__(self, args):
        self.nRF5_instances = {}
        self.erase_all = args.eraseall
        self.family = args.family
        self.file = args.file
        self.sectors_erase = args.sectorserase
        self.sectors_and_uicr_erase = args.sectorsanduicrerase
        self.snrs = args.snrs
        self.systemreset = args.systemreset
        self.verify = args.verify

        if not self.family:
            self.family = 'NRF51'

        if not self.snrs:
            with MultiAPI.MultiAPI('NRF51') as nrf:
                self.snrs = nrf.enum_emu_snr()

        if self.family is 'NRF51':
            self.PAGE_SIZE = 0x400
        else:
            self.PAGE_SIZE = 0x1000

        self.hex_file = IntelHex(self.file)

    def _byte_lists_equal(self, data, read_data):
        for i in xrange(len(data)):
            if data[i] != read_data[i]:
                return False
        return True

    def _connect_to_device(self, device):
        self.nRF5_instances[device] = MultiAPI.MultiAPI(self.family)
        self.nRF5_instances[device].open()
        self.nRF5_instances[device].connect_to_emu_with_snr(device)

    def _program_device(self, device):
        if self.erase_all:
            self.nRF5_instances[device].recover() # NOTE: using recover() instead of erase_all().
        if self.sectors_and_uicr_erase:
            self.nRF5_instances[device].erase_uicr()

        for segment in self.hex_file.segments():
            start_addr, end_addr = segment
            size = end_addr - start_addr

            if self.sectors_erase or self.sectors_and_uicr_erase:
                start_page = int(start_addr / self.PAGE_SIZE)
                end_page = int(end_addr / self.PAGE_SIZE)
                for page in range(start_page, end_page + 1):
                    self.nRF5_instances[device].erase_page(page * self.PAGE_SIZE)

            data = self.hex_file.tobinarray(start=start_addr, size=(size)) # TODO: this can be optimized.
            self.nRF5_instances[device].write(start_addr, data.tolist(), True)

            if self.verify:
                read_data = self.nRF5_instances[device].read(start_addr, len(data))
                assert (self._byte_lists_equal(data, read_data)), 'Verify failed. Data readback from memory does not match data written.'

        if self.systemreset:
            self.nRF5_instances[device].sys_reset()
            self.nRF5_instances[device].go()


    def _cleanup(self, device):
        self.nRF5_instances[device].disconnect_from_emu()
        self.nRF5_instances[device].close()

    # Public methods.

    def perform_command(self, device):
        self._connect_to_device(device)
        self._program_device(device)
        self._cleanup(device)
Example #32
0
def send_hex(conn, filename, modbus_address, logger=logging):
    """
    Takes the name of a file in Intel hex format, and sends it to the specified Modbus address, then commands the
    microcontroller to swap to the new ROM bank. The caller must issue a reset command using the reset_microcontroller()
    function after this function exits, to boot into the new firmware.

    Note that it's up to the caller to make sure that the firmware in the file matches the hardware on the specified
    modbus address - otherwise the device will be 'bricked', and need a manual firmware upload in the lab.

    :param conn: A pasd.transport.Connection() object
    :param filename: The name of a file containing and Intel Hex format firmware binary
    :param modbus_address: Modbus address
    :param logger: A logging.logger object, or defaults to the logging module with basicConfig() called
    :return:
    """
    logger.info('Writing %s to modbus address %d' % (filename, modbus_address))
    if IntelHex is None:
        logger.critical('intelhex library no available, exiting.')
        return False

    # this is a pain.  In order to calculate CRC32 we need to give zlib.crc32() an array of bytes
    # The CRC is calculated for registers ADDRESS_LOW to COMMAND and these are stored in these
    # 246 bytes least significant byte first.
    registerBytes = bytearray(246)

    #######################################

    # start by erasing the EEPROM
    print("Issuing erase command...")
    registerBytes[244] = ERASE_COMMAND  # least sig byte of COMMAND register
    crc32 = zlib.crc32(registerBytes)
    for i in range(0, 246):  # clear for next calc
        registerBytes[i] = 0

    # write CRC separately to command
    conn.writeMultReg(modbus_address=modbus_address, regnum=10001, valuelist=[crc32 & 0xffff, crc32 >> 16])
    conn.writeReg(modbus_address=modbus_address, regnum=10125, value=ERASE_COMMAND)  # , timeout=10.0)
    logger.debug("Erase return code: " + str(conn.readReg(modbus_address=modbus_address, regnum=10126)[0][1]))  # least sig byte

    # a rom hex file consists of segments which are start/end marker of addresses of bytes to write
    # PIC24 has 24-bit instructions but addressing is compatible with 16-bit data presumably so increments of
    # 2 for addressed instructions.
    #
    # So, every 4th byte is zero in the hex file
    logger.info("Reading file %s" % filename)
    ih = IntelHex(filename)

    logger.info("Segments found:")
    logger.info(ih.segments())

    numWrites = 0  # number of write chunks.  This is used for verifying

    for segment in ih.segments():
        start = segment[0]
        end = segment[1]
        if start < 0x1003000:  # this is the magic dual partition boot config that should never be changed
            logger.info("Segment: " + str(start) + " - " + str(end))  # in bytes
            address = start
            addressWords = start >> 1  # addresses are in bytes = 4 bytes per instruction.  But as far as PIC24 addressing goes this has to be halved
            while address < end:
                length = end - address
                if length > 320:  # 320 = 80 "4 byte" instructions which is 240 bytes packed into SEGMENT_DATA
                    length = 320

                logger.info("Chunk: " + str(address) + " - " + str(length))

                i = 0
                j = 4  # there are 2 address registers below here
                while i < length:
                    registerBytes[j] = ih[address + i]
                    registerBytes[j + 1] = ih[address + i + 1]
                    registerBytes[j + 2] = ih[address + i + 2]
                    i = i + 4
                    j = j + 3

                # word count and set into highcount reg
                numWords = j // 2

                if j & 1 > 0:
                    numWords = numWords + 1

                addressLow = addressWords & 0xffff
                addressHighCount = (addressWords >> 16) | ((numWords - 2) << 8)  # the -2 is because we don't count address

                # mirror address registers in registerBytes
                registerBytes[0] = addressLow & 0xff
                registerBytes[1] = addressLow >> 8
                registerBytes[2] = addressHighCount & 0xff
                registerBytes[3] = addressHighCount >> 8

                # and the write command
                registerBytes[244] = WRITE_SEGMENT_COMMAND  # least sig byte of COMMAND register

                # now, calc crc
                crc32 = zlib.crc32(registerBytes)

                # and build a list for multiwrite
                regValues = [crc32 & 0xffff, crc32 >> 16]
                for i in range(0, numWords):
                    regValues.append(registerBytes[i * 2] + (registerBytes[i * 2 + 1] << 8))

                if length < 320:
                    # partial write
                    logger.info("writing partial chunk...")
                    conn.writeMultReg(modbus_address=modbus_address, regnum=10001, valuelist=regValues)
                    conn.writeReg(modbus_address=modbus_address, regnum=10125, value=WRITE_SEGMENT_COMMAND)  # write command
                else:
                    # full write, add on command
                    print("writing chunk... " + str(len(regValues)))
                    #                    regValues.append(2)
                    conn.writeMultReg(modbus_address=modbus_address, regnum=10001, valuelist=regValues)
                    # ideally, should just append 2 to regValues above but for some reason transport.py hangs with 125 registers
                    # so split into 2 writes - 124 registers and the separate command.
                    conn.writeReg(modbus_address=modbus_address, regnum=10125, value=WRITE_SEGMENT_COMMAND)  # write command

                logger.debug("write return code: " + str(conn.readReg(modbus_address=modbus_address, regnum=10126)))  # [0][1]))  # least sig byte

                # one more
                numWrites = numWrites + 1

                # clear for next lop
                for i in range(0, 246):  # clear for next calc
                    registerBytes[i] = 0

                # and do the next block
                address = address + 320
                addressWords = addressWords + 160

    logger.info(str(numWrites) + " chunks written.  Verifying...")

    # to verify, put numWrites as a 32-bit unsigned int into the first two SEGMENT_DATA registers
    registerBytes[4] = numWrites & 0xff
    registerBytes[5] = (numWrites >> 8) & 0xff
    registerBytes[6] = (numWrites >> 16) & 0xff
    registerBytes[7] = (numWrites >> 24) & 0xff

    # set address to zero
    registerBytes[0] = 0
    registerBytes[1] = 0
    registerBytes[2] = 0
    registerBytes[3] = 0

    # and the verify command
    registerBytes[244] = VERIFY_COMMAND  # least sig byte of COMMAND register

    # now, calc crc
    crc32 = zlib.crc32(registerBytes)
    for i in range(0, 246):  # clear for next calc
        registerBytes[i] = 0

    # and build a list for multiwrite
    regValues = [crc32 & 0xffff, crc32 >> 16]
    regValues.append(0)  # empty address x 2
    regValues.append(0)
    regValues.append(numWrites & 0xffff)
    regValues.append(numWrites >> 16)

    conn.writeMultReg(modbus_address=modbus_address, regnum=10001, valuelist=regValues)
    conn.writeReg(modbus_address=modbus_address, regnum=10125, value=VERIFY_COMMAND)  # trust but verify

    verifyResult = conn.readReg(modbus_address=modbus_address, regnum=10126)[0][1]
    if verifyResult == 0:
        logger.info("verify ok.  Updating.")

        # the update command
        registerBytes[244] = UPDATE_COMMAND  # least sig byte of COMMAND register
        # now, calc crc
        crc32 = zlib.crc32(registerBytes)
        for i in range(0, 246):  # clear for next calc
            registerBytes[i] = 0
        regValues = [crc32 & 0xffff, crc32 >> 16]
        conn.writeMultReg(modbus_address=modbus_address, regnum=10001, valuelist=regValues)
        conn.writeReg(modbus_address=modbus_address, regnum=10125, value=UPDATE_COMMAND)  # update
        updateResult = conn.readReg(modbus_address=modbus_address, regnum=10126)[0][1]
        if updateResult == 0:
            logger.info("Update ok.  Call reset_microcontroller to boot into new firmware.")
            return True
        else:
            logger.info("Update FAILED, new firmware NOT swapped in!: " + str(updateResult))
            return False
    else:
        logger.info("Verify FAILED, new firmware NOT written!: " + str(verifyResult))
        return False
Example #33
0

def chunks(seq, size):
    return (seq[pos:pos + size] for pos in range(0, len(seq), size))


hex = IntelHex(sys.argv[1])

print('READY')

fails = 0

write_bytes(0x0000, [0x76])
reset()

for (start, stop) in hex.segments():
    for chunk in chunks(range(start, stop), 1024):
        address = chunk[0]
        data = [hex[a] for a in chunk]
        print(f'WRITING {len(data)} BYTES AT ADDRESS ${address:0{4}x}')
        while True:
            check = write_bytes(address, data)
            if check == data:
                break
            if check is None:
                print(f"--- COMMAND ERROR - RETRYING ---")
            elif len(check) != len(data):
                print(f"--- LENGTH ERROR ({len(check)}) - RETRYING ---")
            else:
                print(f"--- VERIFICATION ERROR - RETRYING ---")
Example #34
0
    )
    print("Usage:")
    print("phyihex.py <ihex> <start> <end> [<start> <end>]*")
    exit()

ihexf = sys.argv[1]
sections = []
for i in range(2, len(sys.argv), 2):
    start = int(sys.argv[i], 0)
    end = int(sys.argv[i + 1], 0)
    sections.append([start, end + 1])

ih = IntelHex()
iho = IntelHex()
ih.loadhex(ihexf)
all_sections = ih.segments()
print("input hex file sections:")
for sec in all_sections:
    print("0x%08X 0x%08X" % (sec[0], sec[1] - 1))

#copy all regular sections
for sec in sections:
    for i in range(sec[0], sec[1]):
        iho[i] = ih[i]

#copy start address
#print("start address: ",ih.start_addr)
iho.start_addr = ih.start_addr

iho.write_hex_file(ihexf + ".phy.ihex")
Example #35
0
def dump_header(infile, image, header):
    inhex = IntelHex(infile)
    (start, end) = inhex.segments()[0]
    inhex.tobinfile(image, start=start, end=end - 1)
    (start, end) = inhex.segments()[-1]
    inhex.tobinfile(header, start=start, end=end - 1)
Example #36
0
from intelhex import IntelHex

ih = IntelHex()
ih.padding = 0
ih.fromfile("sbos.hex", format="hex")
start = ih.segments()[0][0]
ih.tobinfile("sbos.bin", start=start, size=8192)