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
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
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
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
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()
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)
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)
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()
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)
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")