Example #1
0
def read_data(com, page_nums) -> intelhex.Hexfile:
    """Read all pages and create a list"""

    data_list = read_pages(com, b'F', page_nums)

    pages = intelhex.Hexfile()

    for page_num, data in zip(page_nums, data_list):
        if data:
            page = intelhex.Page(data)

            # Remove NULL words and force unused high word to 00
            for offset in range(0, len(page)):
                if page[offset] == 0x00FF:
                    page[offset] = None

            if any(page):
                pages[page_num] = page

    return pages
Example #2
0
def read_program(com, page_nums) -> intelhex.Hexfile:
    """Read all pages and create a list"""

    prog_list = read_pages(com, b'R', page_nums)

    pages = intelhex.Hexfile()

    for page_num, data in zip(page_nums, prog_list):
        if data:
            page = intelhex.Page(data)

            # Remove NULL words
            for offset in range(0, len(page)):
                if page[offset] == 0x3FFF:
                    page[offset] = None

            if any(page):
                pages[page_num] = page

    return pages
Example #3
0
def read_data(com: comm.Comm, device):
    """read all data pages"""
    pages = intelhex.Hexfile()

    # if data region is not defined then return an empty list
    if device['min_data'] or device['max_data']:
        page_nums = range(device['min_data'], device['max_data'] + 1)
        data_list = read_pages(com, CMD_READ_DATA, page_nums)

        for page_num, data in zip(page_nums, data_list):
            if data:
                page = intelhex.Page(data)

                for offset in range(0, len(page)):
                    if page[offset] == 0x00FF:
                        page[offset] = None

                if any(page):
                    pages[page_num] = page

    return pages
Example #4
0
def read_program(com: comm.Comm, device) -> intelhex.Hexfile:
    """read all program pages"""
    page_nums = range(0, device['max_page'] + 1)
    page_list = read_pages(com, CMD_READ_PAGE, page_nums)

    pages = intelhex.Hexfile()

    # Read all pages and create a list
    for page_num, data in zip(page_nums, page_list):
        if data:
            page = intelhex.Page(data)

            # Remove NULL words
            for offset in range(0, len(page)):
                if page[offset] == 0x3FFF:
                    page[offset] = None

            if any(page):
                pages[page_num] = page

    return pages
Example #5
0
def main():
    """ main """
    parser = argparse.ArgumentParser(prog='gpmap', description='Intel hexfile memory mapper')
    parser.add_argument('-v', '--verbose', action='store_true', help='display long format memory map')
    parser.add_argument('--version', action='version', version='$Id: gpmap.py 893 2018-04-20 01:58:27Z rnee $')

    parser.add_argument('filename', default=None, nargs='?', action='store', help='HEX filename')

    args = parser.parse_args()

    # Check for commands that don't require a filename
    if args.filename is None:
        parser.print_help()
        sys.exit()

    with open(args.filename) as fp:
        file_firmware = hexfile.Hexfile()
        file_firmware.read(fp)
        if args.verbose:
            print(file_firmware.display())
        else:
            file_firmware.memory_map()
Example #6
0
def program(com):
    """main programming routine"""

    # Check for a filename
    if args.filename is None:
        parser.print_help()
        return

    # unless we are reading out the chip firmware read a new file to load
    if not args.read:
        with open(args.filename) as fp:
            file_firmware = intelhex.Hexfile()
            file_firmware.read(fp)
            if not args.quiet:
                print(args.filename)
                print(file_firmware.display())
    else:
        file_firmware = None

    # Bring target out of reset
    print('Reset...')
    time.sleep(0.050)
    com.pulse_dtr(0.250)
    time.sleep(0.050)
    # is this flush needed?  it clears the prompt char that is waiting to be
    # read that was produced by the reset.  Maybe it belongs prior to the dtr
    # pulse to clean up garbage from open the serial port
    # com.flush()

    # Trigger and look for prompt
    while True:
        (count, value) = com.read(1)
        if count == 0 or value != b'\x00':
            break

    if count == 0 or value != b'K':
        print(f'[{count}, {value}] Could not find ICSP on {args.port}\n')
        return

    print('Connected...')

    # flush input buffer so that we can start out synchronized
    com.flush()

    # Get host controller version
    print('Getting Version...')
    ver = icsp.get_version(com)
    print('Hardware version:', ver)

    print('Start...')
    start(com)

    print("\nDevice Info:")
    chip_rev, chip_id, cfg1, cfg2, cal1, cal2 = read_info(com)

    # enhanced and midrange have different id/rev bits
    for mask, shift in ((0x00, 0), (0x00F, 4), (0x01F, 5)):
        if 0x00 < chip_rev < 0x3FFF:
            device_rev = chip_rev
        else:
            device_rev = chip_id & mask

        device_id = chip_id >> shift
        if device_id in picdevice.PARAM:
            break
    else:
        print(" ID: %04X not in device list" % chip_id)

        print("End...")
        icsp.release(com)

        return

    device_param = picdevice.PARAM[device_id]
    device_name = device_param['name']

    print(f" ID: {device_id:04X} {device_name} rev {device_rev:02X}")
    print(f"CFG: {cfg1:04X} {cfg2:04X}")
    print(f"CAL: {cal1:04X} {cal2:04X}")

    if device_name is None:
        raise RuntimeError("Unknown device")

    # Set ranges and addresses based on the bootloader config and device information
    min_page = 0
    max_page = device_param['max_page']
    min_data = device_param['min_data']
    max_data = device_param['max_data']
    conf_page_num = device_param['conf_page']

    if args.read:
        print("Reset Address...")
        icsp.reset_address(com)

        print("Reading Firmware...")
        chip_firmware = read_firmware(com, device_param)
        print()

        # Hex files always have DOS encoding
        with open(args.filename, mode='w', newline='\r\n') as fp:
            chip_firmware.write(fp)

        if not args.quiet:
            print(chip_firmware.display())
    else:
        # Erase entire device including userid locations
        print("Erase Program...")
        icsp.load_config(com)
        icsp.erase_program(com)

        print("Reset Address...")
        icsp.reset_address(com)

        print("Writing Program 0x%X .. 0x%X ..." % (0, max_page))
        icsp.write_program_pages(com, file_firmware, device_param)

        if min_data < max_data:
            print("Erase Data...")
            icsp.erase_data(com)
            print("Writing Data 0x%X .. 0x%X ..." % (min_data, max_data))
            icsp.write_data_pages(com, file_firmware, device_param)

        print("Reset Address...")
        icsp.reset_address(com)

        print("Writing Config 0x%X ..." % conf_page_num)
        icsp.write_config(com, file_firmware, device_param)

        print("Reset Address...")
        icsp.reset_address(com)

        print("Reading Firmware...")
        verify_firmware = read_firmware(com, device_param)
        print()

        # Compare protected regions to ensure they are compatible
        print("Comparing firmware pages 0x%X .. 0x%X, 0x%X .. 0x%X, 0x%X..." %
              (min_page, max_page, min_data, max_data, conf_page_num))
        check_list = list(range(min_page, max_page + 1)) + list(
            range(min_data, max_data)) + [conf_page_num]
        error_list = file_firmware.compare(verify_firmware, check_list)

        if error_list:
            print("\nWARNING!\nError verifying firmware.")

            for page_num in error_list:
                print("File:")
                if file_firmware[page_num]:
                    print(file_firmware[page_num].display(page_num))
                print("Chip:")
                if verify_firmware[page_num]:
                    print(verify_firmware[page_num].display(page_num))
        else:
            print(" OK")

    print("End...")
    icsp.release(com)
Example #7
0
        if os.path.exists(args.log):
            os.unlink(args.log)
        logf = open(args.log, 'a')
    else:
        logf = None

    start_time = time.time()

    print('Initializing communications on {} {} ...'.format(
        args.port, args.baud))
    if args.port.upper() == 'MOCK':
        import mock

        # unless we are reading out the chip firmware read a new file to load
        with open('mock.hex') as fp:
            mock_firmware = intelhex.Hexfile()
            mock_firmware.read(fp)

        ser = mock.ICSPHost('12F1822', mock_firmware)
    else:
        import serial

        ser = serial.Serial(args.port,
                            baudrate=args.baud,
                            bytesize=DATA,
                            timeout=TOUT)

    # create wrapper
    with comm.Comm(ser, logf) as ser_com:
        print(ser_com)
        program(ser_com)
Example #8
0
def main():
    parser = argparse.ArgumentParser(prog='flash',
                                     description='icsp programming tool.')
    parser.add_argument('-p',
                        '--port',
                        default=DEFAULT_PORT,
                        help='serial device')
    parser.add_argument('-b', '--baud', default=DEFAULT_BAUD, help='baud rate')

    group = parser.add_mutually_exclusive_group()
    group.add_argument('-i',
                       '--id',
                       action='store_true',
                       help='read chip id info from target')
    group.add_argument('-w',
                       '--write',
                       action='store_true',
                       help='write firmware to target')
    group.add_argument('-r',
                       '--read',
                       action='store_true',
                       help='Read target and save to file')

    parser.add_argument('-1',
                        '--mclr1',
                        action='store_true',
                        help="use mclr1 for 28 pin chips")
    parser.add_argument('-q',
                        '--quiet',
                        action='store_true',
                        help="quiet mode. don't dump hex files")
    parser.add_argument('-e',
                        '--enh',
                        action='store_true',
                        help='Enhanced midrange programming method')
    parser.add_argument('-f',
                        '--fast',
                        action='store_true',
                        help='Fast mode.  Do minimal verification')
    parser.add_argument('-l',
                        '--log',
                        nargs='?',
                        const='bload.log',
                        default=None,
                        help='Log all I/O to file')
    parser.add_argument('-t', '--test', action='store_true', help='Test')
    parser.add_argument(
        '--version',
        action='version',
        version='$Id: flash.py 740 2017-11-25 02:25:22Z rnee $')
    parser.add_argument('filename',
                        default=None,
                        nargs='?',
                        action='store',
                        help='HEX filename')

    args = parser.parse_args()

    args.write = not args.read and not args.id

    if args.log:
        if os.path.exists(args.log):
            os.unlink(args.log)
        logf = open(args.log, 'a')
    else:
        logf = None
    # logf = sys.stdout

    # Check for a filename
    if not args.id and args.filename is None:
        parser.print_help()
        sys.exit()

    # unless we are reading out the chip firmware read a new file to load
    if not args.read and not args.id:
        with open(args.filename) as fp:
            file_firmware = intelhex.Hexfile()
            file_firmware.read(fp)
            if not args.quiet:
                print(args.filename)
                print(file_firmware.display())
    else:
        file_firmware = None

    # Init comm (holds target in reset)
    print(f'Initializing communications on {args.port} at {args.baud} ...')
    if MOCK:
        # read firmware to simulate target and load and create mock target
        firmware = intelhex.Hexfile()
        with open(TMP + 'icsp.hex') as fp:
            firmware.read(fp)

        ser = mock.ICSPHost(firmware)
    else:
        ser = serial.Serial(args.port,
                            baudrate=args.baud,
                            bytesize=DATA,
                            timeout=TOUT)

    # Create wrapper
    com = comm.Comm(ser, logf)

    # Bring target out of reset
    print('Reset...')
    time.sleep(0.050)
    com.pulse_dtr(0.250)
    time.sleep(0.050)

    # Trigger and look for prompt
    for _ in range(5):
        com.flush()
        com.write(b'K')
        (count, value) = com.read(1)
        if value == b'K':
            break
    else:
        com.close()

        print(f'[{count}, {value}] Could not find ICSP on {args.port}\n')
        sys.exit()

    print('Connected...')

    # flush input buffer so that we can start out synchronized
    com.flush()

    # Get host controller version
    print('Getting Version...')
    ver = icsp.get_version(com)
    print('KT150 firmware version:', ver)

    display_status(com)

    if args.mclr1:
        print('Start using MCLR1...')
        send_start1(com)
    else:
        print('Start using MCLR2...')
        send_start2(com)

    icsp.sync(com)
    display_status(com)

    print("\nDevice Info:")
    chip_id, cfg1, cfg2, cal1, cal2 = read_info(com)

    # enhanced and midrange have different id/rev bits
    for mask, shift in ((0x00F, 4), (0x01F, 5)):
        device_id = chip_id >> shift
        device_rev = chip_id & mask

        if device_id in picdevice.PARAM:
            break
    else:
        print(" ID: %04X not in device list" % chip_id)

        print("End...")
        icsp.release(com)

        sys.exit()

    device_param = picdevice.PARAM[device_id]
    device_name = device_param['name']

    print(f" ID: {device_id:04X} {device_name} rev {device_rev:02X}")
    print(f"CFG: {cfg1:04X} {cfg2:04X}")
    print(f"CAL: {cal1:04X} {cal2:04X}")

    # Set ranges and addresses based on the bootloader config and device information
    min_page = 0
    max_page = device_param['max_page']
    min_data = device_param['min_data']
    max_data = device_param['max_data']
    conf_page_num = device_param['conf_page']

    if args.read:
        print("Reset Address...")
        icsp.reset_address(com)

        print("Reading Firmware...")
        chip_firmware = read_firmware(com, device_param)
        print()

        with open(args.filename, mode='w') as fp:
            chip_firmware.write(fp)

        if not args.quiet:
            print(chip_firmware.display())
    elif args.write:
        # Erase entire device including userid locations
        print("Erase Device...")
        icsp.load_config(com)
        icsp.erase_program(com)
        icsp.erase_data(com)

        icsp.reset_address(com)

        sys.stderr.flush()
        print(f"Writing Program 0x0 .. 0x{max_page:#0X} ...")
        icsp.write_program_pages(com, file_firmware, device_param)

        print(f"Writing Data {min_data:#0X} .. {max_data:#0X} ...")
        icsp.write_data_pages(com, file_firmware, device_param)

        print("Writing Config 0x%X ..." % conf_page_num)
        icsp.reset_address(com)
        icsp.write_config(com, file_firmware, device_param)

        print("Reading Firmware...")
        icsp.reset_address(com)
        verify_firmware = read_firmware(com, device_param)
        print()

        # Compare protected regions to ensure they are compatible
        print("Comparing firmware pages 0x%X .. 0x%X, 0x%X .. 0x%X, 0x%X..." %
              (min_page, max_page, min_data, max_data, conf_page_num))
        check_list = list(range(min_page, max_page + 1)) + list(
            range(min_data, max_data)) + [conf_page_num]
        error_list = file_firmware.compare(verify_firmware, check_list)

        if error_list:
            print("\nWARNING!\nError verifying firmware.")

            for page_num in error_list:
                if file_firmware[page_num]:
                    print("File:")
                    print(file_firmware[page_num].display(page_num))
                if verify_firmware[page_num]:
                    print("Chip:")
                    print(verify_firmware[page_num].display(page_num))
        else:
            print(" OK")

    print("End...")
    icsp.release(com)

    com.close()
Example #9
0
def run(argv=None):
    parser = argparse.ArgumentParser(
        prog='pyload', description='pyload Bload bootloader tool.')
    parser.add_argument('-p',
                        '--port',
                        default=DEFAULT_PORT,
                        help=f'serial device ({DEFAULT_PORT})')
    parser.add_argument('-b', '--baud', default=DEFAULT_BAUD, help='baud rate')
    parser.add_argument('-q',
                        '--quiet',
                        action='store_true',
                        help='quiet mode. dont dump hex files')
    parser.add_argument('-c',
                        '--cdef',
                        action='store_true',
                        help='Convert filename to C definition statements')
    parser.add_argument('-f',
                        '--fast',
                        action='store_true',
                        help='Fast mode.  Do minimal verification')
    parser.add_argument('-r',
                        '--read',
                        action='store_true',
                        help='Read target and save to filename')
    parser.add_argument('-x',
                        '--reset',
                        action='store_true',
                        help='Reset target and exit')
    parser.add_argument('-t',
                        '--term',
                        action='store_true',
                        help='Start terminal mode after processing')
    parser.add_argument('-l',
                        '--log',
                        nargs='?',
                        const='bload.log',
                        default=None,
                        help='Log all I/O to file')
    parser.add_argument(
        '--version',
        action='version',
        version='$Id: pyload.py 901 2018-04-28 21:44:56Z rnee $')

    parser.add_argument('filename',
                        default=None,
                        nargs='?',
                        action='store',
                        help='HEX filename')

    args = parser.parse_args(args=argv if argv else sys.argv[1:])

    # reading and fast mode are incompatible
    if args.read and args.fast:
        parser.print_help()
        sys.exit()

    if args.log:
        if os.path.exists(args.log):
            os.unlink(args.log)
        logf = open(args.log, 'a')
    else:
        logf = None

    print('Initializing communications on {} {} ...'.format(
        args.port, args.baud))
    if args.port.upper() == 'MOCK':
        import mock

        # unless we are reading out the chip firmware read a new file to load
        with open('mock.hex') as fp:
            mock_firmware = intelhex.Hexfile()
            mock_firmware.read(fp)

        ser = mock.BLoadHost('12F1822', mock_firmware)
    else:
        import serial

        ser = serial.Serial(args.port,
                            baudrate=args.baud,
                            bytesize=DATA,
                            timeout=TOUT)

    # create wrapper
    with comm.Comm(ser, logf) as ser_com:
        if args.reset:
            ser_com.pulse_dtr(0.250)
            if args.term:
                term.terminal(ser_com)

        # Check for commands that require a filename
        if args.filename is not None:
            program(ser_com, args)

        if args.term:
            ser_com.pulse_dtr(0.250)
            term.terminal(ser_com)
Example #10
0
def program(com: comm.Comm, args):
    """ main """

    start_time = time.time()

    # unless we are reading out the chip firmware read a new file to load
    if not args.read:
        # Read, parse and display image to load
        with open(args.filename) as fp:
            file_firmware = intelhex.Hexfile()
            file_firmware.read(fp)
            if not args.quiet:
                print(args.filename)
                print(file_firmware.display())
    else:
        file_firmware = None

    if args.cdef:
        for page_num in range(64):
            if file_firmware[page_num]:
                print('page_list[%d] = "%s";' %
                      (page_num, file_firmware[page_num]))

        return

    if not connect(com):
        print('[{count}, {value}] Could not find boot loader on {com.port}\n')
        return

    print('Connected...')

    # Get info about the bootloader
    (boot_version, boot_pagesize, boot_start, boot_size, data_start, data_end,
     code_end) = bload.get_info(com)

    # Recompute word addresses as page addresses
    boot_start = (boot_start & 0x7FFF) // boot_pagesize
    boot_end = boot_start + (boot_size // boot_pagesize) - 1
    code_end //= boot_pagesize
    data_start //= boot_pagesize
    data_end //= boot_pagesize

    # Get config info
    config = bload.read_config(com)

    user_id = ""
    for word in config[0:4 * 2:2]:
        user_id += '{:X}'.format(word & 0x0F)

    chip_id = int.from_bytes(config[6 * 2:7 * 2], 'little')
    chip_rev = int.from_bytes(config[6 * 2:7 * 2], 'little')
    config_words = [
        int.from_bytes(config[7 * 2:8 * 2], 'little'),
        int.from_bytes(config[8 * 2:9 * 2], 'little')
    ]

    # enhanced and midrange have different id/rev bits
    for mask, shift in ((0x00, 0), (0x00F, 4), (0x01F, 5)):
        if 0x00 < chip_rev < 0x3FFF:
            device_rev = chip_rev
        else:
            device_rev = chip_id & mask

        device_id = chip_id >> shift
        if device_id in picdevice.PARAM:
            break
    else:
        print(" ID: %04X not in device list" % chip_id)
        reset(com)
        sys.exit()

    device_param = picdevice.PARAM[device_id]
    device_name = device_param['name']

    print("\nBootloader Version: %02X\n"
          "Page Size:          0x%02X\n"
          "Bootloader Region:  0x%03X - 0x%03X\n"
          "Program Region:     0x%03X - 0x%03X\n"
          "EEPROM Data Region: 0x%03X - 0x%03X\n" %
          (boot_version, boot_pagesize, boot_start, boot_end, 0, code_end,
           data_start, data_end))

    print(
        "CONFIG User ID: %s  Device ID: %04X %s Rev: %1X  Config Words: %x %x"
        % (user_id, device_id, device_name, device_rev, config_words[0],
           config_words[1]))

    # Set ranges and addresses based on the bootloader config and device information
    min_user = 1
    max_user = boot_start - 1
    conf_page = picdevice.PARAM[device_id]['conf_page']
    min_data = picdevice.PARAM[device_id]['min_data']
    max_data = picdevice.PARAM[device_id]['max_data']

    if min_data != data_start or max_data != data_end:
        print("Error:")
        print("min_data=", min_data, 'max_data=', max_data)
        print("data_start=", data_start, 'data_end=', data_end)

        return

    prog_list = list(range(0, code_end + 1))
    user_list = list(range(min_user, max_user + 1))
    boot_list = list(range(boot_start, boot_end + 1))
    data_list = list(range(min_data, max_data + 1))

    #
    # Test routine for bootloader range check
    #
    # run_range_test(com)

    # Read existing firmware
    if args.fast:
        sys.stdout.write("Reading Bootloader  ")
        chip_firmware = bload.read_program(com, [0] + boot_list)
        print()
    else:
        sys.stdout.write("Reading Firmware    ")
        chip_firmware = read_firmware(com, conf_page, prog_list, data_list)
        if not args.quiet:
            print()
            print(chip_firmware.display())

    if args.read:
        print('Saving firmware to', args.filename, '...')
        with open(args.filename, mode='w') as fp:
            chip_firmware.write(fp)
    else:
        if not args.fast:
            print('Saving firmware to previous.hex ...')
            with open("previous.hex", mode='w') as fp:
                chip_firmware.write(fp)

        # Compare protected regions to ensure they are compatible
        # noinspection PyUnboundLocalVariable
        errors = chip_firmware.compare(file_firmware, boot_list)
        if errors:
            # Reset the target
            com.pulse_dtr(0.250)

            print(
                "\nError!\n",
                "The reserved bootloader portions of the new and existing program images\n",
                "are different.  Attempting to load this image using the bootloader may\n",
                "result in damage to the firmware and may require reflashing the chip\n",
                "Diff pages: ", errors)

            for page_num in errors:
                print("File:")
                print(file_firmware[page_num].display(page_num))
                print("Chip:")
                print(chip_firmware[page_num].display(page_num))

            return

        page_zero = chip_firmware.compare(file_firmware, [0])

        # Compute write list based on hex file and existing firmware if available.
        # Compute check list for verify step.  Either all pages or abbreviated list
        prog_write_list = []
        data_write_list = []
        prog_check_list = []
        data_check_list = []
        if args.fast:
            # we don't have the existing firmware to compare to so write all pages
            # in the input file and erase all others
            prog_write_list = user_list
            data_write_list = data_list

            for page_num in user_list:
                if file_firmware[page_num]:
                    prog_check_list.append(page_num)
            for page_num in data_list:
                if file_firmware[page_num]:
                    data_check_list.append(page_num)
        else:
            # don't write pages if input and existing are both already blank
            for page_num in user_list:
                if file_firmware[page_num] or chip_firmware[page_num]:
                    prog_write_list.append(page_num)
            for page_num in data_list:
                if file_firmware[page_num] or chip_firmware[page_num]:
                    data_write_list.append(page_num)

            prog_check_list = user_list
            data_check_list = data_list

        # Write the new firmware.  Use a loop in case multiple attempts are necessary
        while True:
            sys.stdout.write("Writing Firmware    ")
            bload.write_pages(com, b'W', file_firmware, prog_write_list)
            bload.write_pages(com, b'D', file_firmware, data_write_list)

            print()

            # Verify what was just written
            if not args.fast:
                sys.stdout.write("Checking Firmware    ")

                prog_pages = bload.read_program(com, prog_check_list)
                data_pages = bload.read_data(com, data_check_list)
                sys.stdout.write('\n')

                check_firmware = prog_pages + data_pages
                check_list = prog_check_list + data_check_list

                errors = check_firmware.compare(file_firmware, check_list)
                if errors:
                    for page_num in errors:
                        print("File:")
                        print(file_firmware[page_num].display(page_num))
                        print("Chip:")
                        print(check_firmware[page_num].display(page_num))

                    print(
                        "\nWARNING!\n",
                        "Error verifying firmware.  Do not power down target.\n",
                        "Press Enter to attempt reflash.")

                    # Wait for confirmation
                    input()
                    continue

            # Done
            break

        # if the first page is different then update it last
        if page_zero:
            sys.stdout.write("Writing Page Zero    ")
            bload.write_pages(com, b'W', file_firmware, [0])
            print()

        sys.stdout.flush()
        print("Update successful.")

    print("Reseting target...")
    reset(com)

    print(f"elapsed time: {time.time() - start_time:0.2f} seconds")