def convert_hex(basename): hex_name = basename + '.hex' print ('Reading %s' % hex_name) ih = IntelHex(hex_name) # f = open(basename + '.txt', 'w') # open file for writing # ih.dump(f) # dump to file object # f.close() # close file size = ih.maxaddr() - ih.minaddr() + 1 print '- Start: %x' % ih.minaddr() print '- End: %x' % ih.maxaddr() with open(basename + '.h', 'w') as fout: fout.write(header.replace('BASENAME',basename)); with open(basename + '.c', 'w') as fout: fout.write(code_start.replace('BASENAME',basename)); fout.write(' ') for i in range(0,size): if i % 1000 == 0: print ('- Write %05u/%05u' % (i, size)) byte = ih[ih.minaddr() + i] fout.write("0x{0:02x}, ".format(byte)) if (i & 0x0f) == 0x0f: fout.write('\n ') fout.write(code_end); print ('Done\n')
class Hex2BinConv: def __init__(self, out): self.hex = IntelHex() self.out = out def load(self, filename): print print "Loading application from hex" self.hex.loadfile(filename, "hex") size = self.hex.maxaddr() - self.hex.minaddr() print " size: %0.2f KiB (%d B)" % (size / 1024.0, size) def conv(self, label): done = False adr = self.hex.minaddr() max_adr = self.hex.maxaddr() out_file = open(self.out, "wb") lab_str = "" if label == "ee": f = open("../utils/build/build_number.txt", "r") number = int(f.readline()) f.close() # lab_str += struct.pack("<H", number) else: for i in range(32): if i >= len(label): c = chr(0) else: c = label[i] lab_str += c out_file.write(lab_str) print " label: %s" % lab_str print "Converting HEX 2 BIN ...", while adr <= max_adr: out_file.write(chr(self.hex[adr])) adr += 1 out_file.close() print "Done" def batch(self, filename, label): start = time.clock() self.load(filename) self.conv(label) end = time.clock() print print "That's all folks! (%.2f seconds)" % (end - start)
def main(): try: os.remove(RESULT) except OSError: pass ihx = IntelHex() ihx.fromfile(TARGET, format='hex') addr_min, addr_max = ihx.minaddr(), ihx.maxaddr() print hex(addr_min), hex(addr_max) ihx.tofile(TEST, format='hex') d = Disassembler() function = ihx.tobinarray()[FUNC_START:] blocks = d.parse(function, 0, FUNC_START) for b in blocks: print '-' * 40 print repr(b) print '-' * 40 blocks = sum(blocks) data = blocks.assemble(FUNC_START, externalize_labels=True) print 'Stream:', ' '.join('%02x' % b for b in bytearray(data)) data_length = len(data) print 'Writing %d bytes.' % data_length ihx.puts(FUNC_START, data) appendix = Block() label_nops = Label('look_mah_no_ops') appendix += Block(label_nops, nop, nop, nop, nop) appendix += Block(Data('\xef\xbe')) appendix += Block(Data(0xbeef)) appendix += Block(Data(label_nops)) end = ihx.maxaddr() + 1 data = appendix.assemble(end, externalize_labels=True) data_length = len(data) print 'Writing %d bytes.' % data_length ihx.puts(end, data) ihx.tofile(RESULT, format='hex') patched = IntelHex() patched.fromfile(RESULT, format='hex') check = ihx.tobinarray()[FUNC_START:FUNC_START + data_length] print 'Stream:', ' '.join('%02x' % b for b in bytearray(data)) print hex(patched.minaddr()), hex(patched.maxaddr())
class Hex2BinConv(): def __init__(self, out): self.hex = IntelHex() self.out = out def load(self, filename): print print "Loading application from hex" self.hex.loadfile(filename, "hex") size = self.hex.maxaddr() - self.hex.minaddr() print " size: %0.2f KiB (%d B)" % (size/1024, size) def conv(self, label): done = False adr = self.hex.minaddr() max_adr = self.hex.maxaddr() out_file = open(self.out, "wb"); lab_str = ''; for i in range(32): if i >= len(label): c = chr(0) else: c = label[i] lab_str += c print " label: %s" % lab_str print "Converting HEX 2 BIN ...", out_file.write(lab_str) while(adr <= max_adr): out_file.write(chr(self.hex[adr])) adr += 1 out_file.close() print "Done" def batch(self, filename, label): start = time.clock() self.load(filename) self.conv(label) end = time.clock() print print "That's all folks! (%.2f seconds)" % (end - start)
def _write_ihx(self, filename): ihx = IntelHex(filename) print "Erasing." min_sector = rounddown_multiple(ihx.minaddr(), SECTORSIZE) max_sector = roundup_multiple(ihx.maxaddr(), SECTORSIZE) for addr in range(min_sector, max_sector, SECTORSIZE): self._erase_sector(addr) print "Writing." min_page = rounddown_multiple(ihx.minaddr(), PAGESIZE) max_page = roundup_multiple(ihx.maxaddr(), PAGESIZE) for addr in range(min_page, max_page, PAGESIZE): self._write(addr, ihx.tobinstr(start=addr, size=PAGESIZE))
class Hex2BinConv(): def __init__(self, out): self.hex = IntelHex() self.out = out def load(self, filename): print print "Loading application from hex" self.hex.loadfile(filename, "hex") size = self.hex.maxaddr() - self.hex.minaddr() print " size: %0.2f KiB (%d B)" % (size/1024, size) def conv(self, label): done = False adr = self.hex.minaddr() max_adr = self.hex.maxaddr() tmp_file = open("tmp.bin", "wb") out_file = open(self.out, "w") print "Converting HEX 2 BIN ...", while(adr <= max_adr): tmp_file.write(chr(self.hex[adr])) adr += 1 tmp_file.close() tmp_file = open("tmp.bin", "r") base64.encode(tmp_file, out_file) out_file.close() print "Done" def batch(self, filename, label): start = time.clock() self.load(filename) self.conv(label) end = time.clock() print print "That's all folks! (%.2f seconds)" % (end - start)
def dfu_send_image(self): """ Send hex to peer in chunks of 20 bytes. """ if not self.connected: return padding = [0x00] * 12 # Open the hex file to be sent ih = IntelHex(self.hexfile_path) updating_sd = False updating_bl = False updating_app = False bl_start_address = 0x30000 bl_end_address = 0x40000 app_start_address = 0xFFFFFFFF if ih.minaddr() < 0x1004: updating_sd = True sd_end_address_str = ih.gets(0x3008, 4) sd_end_address = int(sd_end_address_str[::-1].encode('hex'), 16) if ih.minaddr() > 0x13FFC: if ih.minaddr() < 0x30000: updating_app = True app_start_address = ih.minaddr() if ih.maxaddr() > 0x30000: while bl_start_address < 0x40000: try: bl_loader_start = ih.gets(bl_start_address, 4) init_sp = int(bl_loader_start[::-1].encode('hex'), 16) if init_sp > 0x20000000: updating_bl = True break else: bl_start_address = bl_start_address + 0x1000 except Exception, e: bl_start_address = bl_start_address + 0x1000 while bl_start_address < bl_end_address: try: bl_loader_start = ih.gets(bl_end_address, 4) bl_end_address = bl_end_address + 0x04 break except Exception, e: bl_end_address = bl_end_address - 0x04
def merge_region_list(region_list, destination, padding=b'\xFF'): """Merege 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 gapps with """ merged = IntelHex() print("Merging Regions:") for region in region_list: if region.active and not region.filename: raise ToolException("Active region has no contents: No file found.") if region.filename: print(" Filling region %s with %s" % (region.name, region.filename)) part = intelhex_offset(region.filename, offset=region.start) part_size = (part.maxaddr() - part.minaddr()) + 1 if part_size > region.size: raise ToolException("Contents of region %s does not fit" % region.name) merged.merge(part) pad_size = region.size - part_size if pad_size > 0 and region != region_list[-1]: print(" Padding region %s with 0x%x bytes" % (region.name, pad_size)) merged.puts(merged.maxaddr() + 1, padding * pad_size) if not exists(dirname(destination)): makedirs(dirname(destination)) print("Space used after regions merged: 0x%x" % (merged.maxaddr() - merged.minaddr() + 1)) with open(destination, "wb+") as output: merged.tofile(output, format='bin')
class Driver(FirmwareBase): def __init__(self, filename): FirmwareBase.__init__(self) self.__ih = IntelHex() self.__ih.loadhex(filename) cs = crc.crc16() for each in range(self.__ih.minaddr(), self.__ih.maxaddr()+1): cs.addByte(self.__ih[each]) self.__size = self.__ih.maxaddr()+1 self.__checksum = cs.getResult() def download(self): progress = 0.0 self.sendStatus("Starting Download to Node " + str(self.destNode)) while True: if self.kill==True: self.sendProgress(0.0) self.sendStatus("Download Stopped") return time.sleep(0.1) self.sendProgress(progress) progress = progress + 0.01 if progress > 1: break self.sendProgress(1.0) self.sendStatus("Download Successful")
class FormatIntelHex(FormatReader, FormatWriter): def __init__(self): self.hexinstance = IntelHex() def load_file(self, filename=None): if filename is None: raise FormatError("Filename not specified.") file_extension = os.path.splitext(filename)[1][1 : ].lower() try: if file_extension == "bin": self.hexinstance.loadbin(filename) else: self.hexinstance.loadhex(filename) except: raise FormatError("Could not open %s file \"%s\"." % (file_extension.upper(), filename)) def save_file(self, filename): if filename is None: raise FormatError("Filename not specified.") file_extension = os.path.splitext(filename)[1][1 : ].lower() try: if file_extension == "bin": self.hexinstance.tofile(filename, format="bin") else: self.hexinstance.tofile(filename, format="hex") except: raise FormatError("Could not save %s file \"%s\"." % (file_extension.upper(), filename)) def add_section(self, start, data): self.hexinstance[start : start + len(data)] = data def get_sections(self): sections = dict() if self.hexinstance.minaddr() is not None: sections[None] = FormatIntelHex_Section(self.hexinstance) return sections @staticmethod def get_name(): return "Intel HEX File Parser" @staticmethod def get_extensions(): return ["hex", "eep"]
def post_process(self): logging.info("Processing binaries") # save original dir cwd = os.getcwd() # change to target dir os.chdir(self.target_dir) ih = IntelHex('main.hex') fwid = uuid.UUID('{' + self.settings["FWID"] + '}') size = ih.maxaddr() - ih.minaddr() + 1 # get os info os_project = get_project_builder(self.settings["OS_PROJECT"]) # create firmware info structure fw_info = struct.pack('<I16s128s16s128s16s', size, fwid.bytes, os_project.proj_name, os_project.version, self.proj_name, self.version) # insert fw info into hex ih.puts(0x120, fw_info) # compute crc crc_func = crcmod.predefined.mkCrcFun('crc-aug-ccitt') crc = crc_func(ih.tobinstr()) logging.info("size: %d" % (size)) logging.info("fwid: %s" % (fwid)) logging.info("crc: 0x%x" % (crc)) logging.info("os name: %s" % (os_project.proj_name)) logging.info("os version: %s" % (os_project.version)) logging.info("app name: %s" % (self.proj_name)) logging.info("app version: %s" % (self.version)) ih.puts(ih.maxaddr() + 1, struct.pack('>H', crc)) ih.write_hex_file('main.hex') ih.tobinfile('firmware.bin') # get loader info loader_project = get_project_builder(self.settings["LOADER_PROJECT"]) # create loader image loader_hex = os.path.join(loader_project.target_dir, "main.hex") self.merge_hex('main.hex', loader_hex, 'loader_image.hex') # change back to original dir os.chdir(cwd)
def burnHex(cmd, hexFileName, trampoline=False, blockSize=16) : hexFile = IntelHex(hexFileName) if (trampoline) : insertTrampoline(hexFile) print hexFile, hexFile.minaddr(), hexFile.maxaddr() end = hexFile.maxaddr()+1 if (end % 64 != 0) : end = end & ~63; end += 64; for i in range(hexFile.minaddr(), end, blockSize) : row = ["%s %04d %d" % (cmd, i, blockSize)] + [hexFile[x] for x in range(i,i+blockSize)] line = " ".join([str(x) for x in row]) + "\n" print 'Writing: ', line port.write(line) doRead()
def build_target_firmware(self, parent_test): """ Build test firmware for the board Login credentials must have been set with set_build_login. """ prebuilt = self._target_dir is not None build_login = (self._username is not None and self._password is not None) assert prebuilt or build_login if prebuilt: destdir = self._target_dir else: destdir = 'tmp' build_name = board_id_to_build_target[self.get_board_id()] name_base = os.path.normpath(destdir + os.sep + build_name) self._target_hex_path = name_base + '.hex' self._target_bin_path = name_base + '.bin' # Build target test image if a prebuild location is not specified if not prebuilt: test_info = parent_test.create_subtest('build_target_test_firmware') if not os.path.isdir(destdir): os.mkdir(destdir) # Remove previous build files if os.path.isfile(self._target_hex_path): os.remove(self._target_hex_path) if os.path.isfile(self._target_bin_path): os.remove(self._target_bin_path) test_info.info('Starting remote build') start = time.time() built_file = mbedapi.build_repo(self._username, self._password, TEST_REPO, build_name, destdir) stop = time.time() test_info.info("Build took %s seconds" % (stop - start)) extension = os.path.splitext(built_file)[1].lower() assert extension == '.hex' or extension == '.bin' if extension == '.hex': intel_hex = IntelHex(built_file) # Only supporting devices with the starting # address at 0 currently assert intel_hex.minaddr() == 0 intel_hex.tobinfile(self._target_bin_path) os.rename(built_file, self._target_hex_path) if extension == '.bin': intel_hex = IntelHex() intel_hex.loadbin(built_file, offset=0) intel_hex.tofile(self._target_hex_path, 'hex') os.rename(built_file, self._target_bin_path) # Assert that required files are present assert os.path.isfile(self._target_hex_path) assert os.path.isfile(self._target_bin_path) self._target_firmware_present = True
def build_target_bundle(directory, username, password, parent_test=None): """Build target firmware package""" if parent_test is None: parent_test = TestInfoStub() target_names = info.TARGET_NAME_TO_BOARD_ID.keys() for build_name in target_names: name_base = os.path.normpath(directory + os.sep + build_name) target_hex_path = name_base + '.hex' target_bin_path = name_base + '.bin' # Build target test image test_info = parent_test.create_subtest('Building target %s' % build_name) if not os.path.isdir(directory): os.mkdir(directory) # Remove previous build files if os.path.isfile(target_hex_path): os.remove(target_hex_path) if os.path.isfile(target_bin_path): os.remove(target_bin_path) test_info.info('Starting remote build') start = time.time() built_file = mbedapi.build_repo(username, password, TEST_REPO, build_name, directory) stop = time.time() test_info.info("Build took %s seconds" % (stop - start)) extension = os.path.splitext(built_file)[1].lower() assert extension == '.hex' or extension == '.bin' if extension == '.hex': intel_hex = IntelHex(built_file) # Only supporting devices with the starting # address at 0 currently assert intel_hex.minaddr() == 0 intel_hex.tobinfile(target_bin_path) os.rename(built_file, target_hex_path) if extension == '.bin': intel_hex = IntelHex() intel_hex.loadbin(built_file, offset=0) intel_hex.tofile(target_hex_path, 'hex') os.rename(built_file, target_bin_path) # Assert that required files are present assert os.path.isfile(target_hex_path) assert os.path.isfile(target_bin_path)
def add_firmware(self, filename_hex, fw_info): ihex = IntelHex(filename_hex) # We remove configuration data from TSB firmware (last 16 bytes) # beginnin with TSB ... fw_data = ihex.tobinstr() fw_info.tsb_fwconf = "" fw_parts = fw_data.rsplit("TSB", 1) if len(fw_parts) == 2: fw_data = fw_parts[0] fw_info.tsb_fwconf = fw_parts[1] fw_info.tsb_start = ihex.minaddr() fw_md5 = hashlib.md5(fw_data).hexdigest() if not self.tsbdb.has_key(fw_md5): self.tsbdb[fw_md5] = [ fw_data ] self.add_firmware_info(fw_md5, fw_info)
def load(self, path): """Load an image from a given file""" ext = os.path.splitext(path)[1][1:].lower() try: if ext == INTEL_HEX_EXT: ih = IntelHex(path) self.payload = ih.tobinarray() self.base_addr = ih.minaddr() else: with open(path, 'rb') as f: self.payload = f.read() except FileNotFoundError: raise click.UsageError("Input file not found") # Add the image header if needed. if self.pad_header and self.header_size > 0: if self.base_addr: # Adjust base_addr for new header self.base_addr -= self.header_size self.payload = bytes([self.erased_val] * self.header_size) + \ self.payload self.check_header()
def load_ihex(self, filename): """ Load from intel hex format """ self.logger.info("Loading from hexfile '{}'".format(filename)) from intelhex import IntelHex ih = IntelHex() ih.loadhex(filename) data = ih.tobinarray() start_address = ih.minaddr() self.logger.info("Loaded {0:d} bytes from ihex starting at address 0x{1:04X}".format(len(data), start_address)) # Size check if len(data) > self.device.flash_size: raise Exception("ihex too large for flash") # Offset to actual flash start if start_address < self.device.flash_start: self.logger.info("Adjusting flash offset to address 0x{:04X}".format(self.device.flash_start)) start_address += self.device.flash_start return data, start_address
def _build_record(slot_number, image_path, record_type, args): """Builds the appropriate record for the slot given the specified record type""" hex_data = IntelHex(image_path) hex_data.padding = 0xFF offset = hex_data.minaddr() bin_data = bytearray(hex_data.tobinarray(offset, hex_data.maxaddr())) if slot_number == 0: # If slot is controller if record_type == 2: # kReflashControllerTile return ReflashControllerRecord(bin_data, offset) elif record_type == 3: # kExecuteRPCWithoutCheck pass # Not implemented yet elif record_type == 4: # kExecuteRPCWithCheck pass # Not implemented yet elif record_type == 5: # kResetController pass # Not implemented yet elif record_type == 6: # kEnhancedReflashControllerTile if args['reboot'] == "True": skip_reboot_flag = 0 else: skip_reboot_flag = 1 return EnhancedReflashControllerRecord(bin_data, offset, flags=skip_reboot_flag) else: raise BuildError("Invalid record type for this slot.", slot=slot_number, record=record_type) else: # If slot is a tile if record_type == 1: # kReflashExternalTile return ReflashTileRecord(slot_number, bin_data, offset) else: raise BuildError("Invalid record type for this slot.", slot=slot_number, record=record_type)
show_help() sys.exit(1) if not os.path.exists(sys.argv[1]): sys.exit("Unable open build %s" % sys.argv[1]) if not os.path.exists(sys.argv[2]): sys.exit("Unable open build %s" % sys.argv[2]) build_filename = sys.argv[1] prog_filename = sys.argv[2] # open the build and prog # note open build via StringIO so we can add to it build = IntelHex(StringIO.StringIO(open(build_filename, "r").read())) prog = IntelHex(prog_filename) # merge program into build prog_header_addr = prog.minaddr() prog.start_addr = build.start_addr # we need this to make the merge work smoothly build.merge(prog) # add pointer to program header to the bootstrap header_tbl_addr = 0x08000204 header_tbl_len = 2 #@todo get this from 0x0800200 as uint32_t header_tbl_format = "<LL" header_tbl = list(struct.unpack(header_tbl_format, build.gets(header_tbl_addr, header_tbl_len * 4))) k = 0 while header_tbl[k] != 0xffffffff: if k > header_tbl_len: sys.exit("bootstrap program table full [you have too many programs]!"); k += 1 header_tbl[k] = prog_header_addr build.puts(header_tbl_addr, struct.pack(header_tbl_format, *header_tbl))
+ f.name) sys.exit(1) except: print("Fatal Error: -- FAILED parsing input hex file(s)") sys.exit(1) #print information about the input hex files print_args_info(inputFileNames, vargs.out, vargs.outbin, vargs.oadtype, vargs.imgtype, mergedHex) #Now that we have a merged hex image, lets do a bunch of arg checking #since mergedHex is an merge of all input hexes, it can be treated as an argument to the script argument_sanity_check(vargs, mergedHex) # Cut off / fill with --fill. startAddr = mergedHex.minaddr() endAddr = mergedHex.addresses()[-1] + 1 # Inclusive address if startAddr % OAD_BLOCK_SIZE: print( "Fatal Error: -- Start address 0x%X is not divisible by 16. Exiting" ) sys.exit(1) # DevMon rounds up to nearest sector. Why not, if they want to waste time and space. if vargs.round is not None: endAddr = ((endAddr + INT_FL_PG_SIZE) & ~(INT_FL_PG_SIZE - 1)) print('endAddr round', hex(endAddr)) if vargs.range is not None: if vargs.range[0] is not None: startAddr = vargs.range[0]
class Driver(FirmwareBase): def __init__(self, filename, node, vcode, conn): FirmwareBase.__init__(self, filename, node, vcode, conn) self.__ih = IntelHex() self.__ih.loadhex(filename) cs = crc.crc16() for each in range(self.__ih.minaddr(), self.__ih.maxaddr() + 1): cs.addByte(self.__ih[each]) self.__size = self.__ih.maxaddr() + 1 self.__checksum = cs.getResult() self.__progress = 0.0 self.blocksize = 128 self.__currentblock = 0 def setArg(self, argname, value): if argname == "blocksize": self.blocksize = value # .blocksize property def setBlocksize(self, value): self.__blocksize = value self.__blocks = self.__size // self.__blocksize if self.__size % self.__blocksize != 0: self.__blocks = self.__blocks + 1 #print("Block count = {}".format(self.__blocks)) def getBlocksize(self): return self.__blocksize blocksize = property(getBlocksize, setBlocksize) def __waitBufferResponse(self, channel, offset): endtime = time.time() + 0.5 while True: try: rframe = self.can.recv(0.5) except connection.Timeout: pass else: if rframe.arbitration_id == 0x7E0 + channel + 1: if (rframe.data[0] + (rframe.data[1] << 8)) == offset: break else: raise connection.BadOffset now = time.time() if now > endtime: raise connection.Timeout return True def __fillBuffer(self, ch, address, data): length = len(data) print("Address 0x{:08X} {}".format(address, address)) sframe = can.Message(arbitration_id=0x7E0 + ch, is_extended_id=False, data=[ 0x01, address & 0xFF, (address & 0xFF00) >> 8, (address & 0xFF0000) >> 16, (address & 0xFF000000) >> 24, 0, 1 ]) self.can.send(sframe) endtime = time.time() + 0.5 while True: # Channel wait loop try: rframe = self.can.recv(1) except connection.Timeout: pass else: if rframe.arbitration_id == sframe.arbitration_id+1 and \ rframe.data == sframe.data: break now = time.time() if now > endtime: raise connection.Timeout for n in range(length // 8): # print("[{:02}: ".format(n), end='') # for each in data[(8*n):(8*n) + 8]: # print("{:02X} ".format(each), end='') # print("]") sframe.data = data[(8 * n):(8 * n) + 8] sframe.dlc = 8 self.can.send(sframe) self.__waitBufferResponse(ch, (n + 1) * 8) #time.sleep(0.3) # TODO Need to deal with the abort from the uC somewhere return True def __erasePage(self, ch, address): sframe = can.Message(arbitration_id=0x7E0 + ch, is_extended_id=False, data=[ 0x02, address & 0xFF, (address & 0xFF00) >> 8, (address & 0xFF0000) >> 16, (address & 0xFF000000) >> 24 ]) self.can.send(sframe) endtime = time.time() + 0.5 while True: # Channel wait loop try: rframe = self.can.recv(0.1) except connection.Timeout: pass else: if rframe.arbitration_id == sframe.arbitration_id+1 and \ rframe.data == sframe.data: break now = time.time() if now > endtime: raise connection.Timeout return True def __writePage(self, ch, address): sframe = can.Message(arbitration_id=0x7E0 + ch, is_extended_id=False, data=[ 0x03, address & 0xFF, (address & 0xFF00) >> 8, (address & 0xFF0000) >> 16, (address & 0xFF000000) >> 24 ]) self.can.send(sframe) endtime = time.time() + 0.5 while True: # Channel wait loop try: rframe = self.can.recv(1) except connection.Timeout: pass else: if rframe.arbitration_id == sframe.arbitration_id+1 and \ rframe.data == sframe.data: break now = time.time() if now > endtime: raise connection.Timeout def __sendComplete(self, ch): sframe = can.Message(arbitration_id = 0x7E0 + ch, is_extended_id =False, data=[0x05, self.__checksum & 0xFF, (self.__checksum & 0xFF00) >> 8, \ self.__size & 0xFF, (self.__size & 0xFF00) >> 8, \ (self.__size & 0xFF0000) >> 16, (self.__size & 0xFF000000) >> 24]) self.can.send(sframe) endtime = time.time() + 0.5 while True: # Channel wait loop try: rframe = self.can.recv(1) except connection.Timeout: pass else: if rframe.arbitration_id == sframe.arbitration_id+1 and \ rframe.data == sframe.data: break now = time.time() if now > endtime: raise connection.Timeout # TODO Need to make sure this fails properly when something goes wrong and # it might be nice to have some retires on blocks that fail. Might # make this more robust. # TODO We are not sending partial frames. This probably isn't a big deal # but it's not exactly like the specification. Maybe change the spec, # that might simplify the bootloader def download(self): data = [] FirmwareBase.start_download(self) for n in range(self.__blocks * self.__blocksize): data.append(self.__ih[n]) for block in range(self.__blocks): try: address = block * self.__blocksize self.sendStatus("Writing Block %d of %d" % (block + 1, self.__blocks)) self.sendProgress(float(block) / float(self.__blocks)) self.__currentblock = block while (self.__fillBuffer( self.channel, address, data[address:address + self.blocksize]) == False): if self.kill: self.sendProgress(0.0) self.sendStatus("Download Stopped") return #raise firmware.FirmwareError("Canceled") # Erase Page #print( "Erase Page Address = {}".format(address)) self.__erasePage(self.channel, address) # Write Page #print("Write Page Address = {}".format(address)) self.__writePage(self.channel, address) except connection.Timeout: self.sendProgress(0.0) self.sendStatus("FAIL: Timeout Writing Data") return except connection.BadOffset: self.sendProgress(0.0) self.sendStatus("FAIL: Bad Block Offset Received") return #self.__progress = 1.0 #print("Download Complete Checksum".format(hex(self.__checksum), "Size", self.__size)) try: self.__sendComplete(self.channel) self.sendStatus("Download Complete Checksum 0x%X, Size %d" % (self.__checksum, self.__size)) self.sendProgress(1.0) except connection.Timeout: self.sendProgress(0.0) self.sendStatus("FAIL: Timeout While Finalizing Download")
def create_encrypted_image(self, hex_file, aes_key_file, aes_header, host_key_id, dev_key_id, out_file_encrypt, padding_value=0): """ Creates encrypted image for encrypted programming Format: Row 1 - keys ID (byte 1 - host key ID, byte 2 - dev key ID) Row 2 - AES header Other - encrypted image data """ # Write keys ID and AES header out_file_path = os.path.abspath(out_file_encrypt) with open(out_file_path, 'w') as f: f.write(str(host_key_id).zfill(2)) f.write(str(dev_key_id).zfill(2) + '\n') f.write(aes_header + '\n') ih = IntelHex(hex_file) hex_data_dict = ih.todict() if 'start_addr' in hex_data_dict: del hex_data_dict['start_addr'] logger.debug(f'hex_data_dict={hex_data_dict}') # Add padding ih.padding = padding_value data_to_program = dict() file_len = ih.maxaddr() - ih.minaddr() if file_len % FLASH_ROW_SIZE != 0: address_offset = (file_len // FLASH_ROW_SIZE + 1) * FLASH_ROW_SIZE max_address = ih.minaddr() + address_offset else: max_address = ih.maxaddr() for i in range(ih.minaddr(), max_address): data_to_program[i] = ih[i] sorted_address_keys = sorted(data_to_program) for key in sorted_address_keys: logger.debug('0x%08X: %02X' % (key, data_to_program[key])) logger.debug('Data bytes length: %s' % len(sorted_address_keys)) if len(sorted_address_keys) % FLASH_ROW_SIZE != 0: logger.error('Data bytes length is not multiple ' 'by FLASH_ROW_SIZE (%s)' % FLASH_ROW_SIZE) return sorted_bytes_values = [] for key in sorted_address_keys: sorted_bytes_values.append(data_to_program[key]) logger.debug('-' * 30 + ' Virgin rows ' + '-' * 30) address_row_bytes_dict = {} rows_of_bytes = list(AesHeaderStrategy.chunks_list(sorted_bytes_values, FLASH_ROW_SIZE)) flash_addresses = list(AesHeaderStrategy.chunks_list( sorted_address_keys, FLASH_ROW_SIZE)) for i in range(len(flash_addresses)): flash_addresses[i] = flash_addresses[i][0] address_row_bytes_dict[flash_addresses[i]] = rows_of_bytes[i] out_data = '0x%08X %s' % (flash_addresses[i], ''.join( map(AesHeaderStrategy.hex_str_wo_header, rows_of_bytes[i]))) logger.debug(out_data) logger.debug('-' * 30 + ' Encrypted rows ' + '-' * 30) addr_rows_bin = {} aes_key, aes_iv = read_key_from_file(aes_key_file) aes = AESCipherCBC(aes_key, aes_iv) with open(out_file_path, 'a') as encrypted_rows_out: for i in range(len(flash_addresses)): rows_in_binary_format = bytes(rows_of_bytes[i]) encrypted_row = aes.encrypt(rows_in_binary_format) encrypted_row = bytes(list(encrypted_row)) addr_rows_bin[flash_addresses[i]] = encrypted_row out_data = '%08X%s' % (flash_addresses[i], addr_rows_bin[flash_addresses[i]].hex()) logger.debug(out_data) encrypted_rows_out.write(out_data + '\n') logger.info(f'Created encrypted image \'{out_file_path}\'')
import hashlib import sys import argparse from intelhex import IntelHex def parse_args(): parser = argparse.ArgumentParser( description="Hash data from file.", formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("--infile", "-i", "--in", "-in", required=True, help="Hash the contents of the specified file. If a *.hex file is given, the contents will " "first be converted to binary. For all other file types, no conversion is done.") return parser.parse_args() if __name__ == "__main__": args = parse_args() if args.infile.endswith('.hex'): ih = IntelHex(args.infile) if len(ih) - 1 != (ih.maxaddr() - ih.minaddr()): raise RuntimeError("Non-contiguous hex file not supported.") to_hash = ih.tobinstr() else: to_hash = open(args.infile, 'rb').read() sys.stdout.buffer.write(hashlib.sha256(to_hash).digest())
else: c = 0 crc_out = crc_out >> 1 crc_out = crc_out ^ ((d ^ c) & crc_poly) return crc_out if __name__ == '__main__': args = get_args() ih = IntelHex() ih.padding = 0x00 print("-I Reading file {}...".format(args.ihex)) ih.fromfile(args.ihex, format='hex') # fromfile is the recommended way print("-I- Done") min_addr = ih.minaddr() max_addr = ih.maxaddr() print("-I- Start address : {}".format(min_addr)) print("-I- End address : {}".format(max_addr)) # See http://python-intelhex.readthedocs.io/en/latest/part2-5.html mem_array = OrderedDict() # Not sure if we need a +1 on the max_addr for i in range(min_addr, max_addr, 4): data = ih.tobinarray(start=i, size=4) mem_array[i] = (data[3] << 24) + (data[2] << 16) + (data[1] << 8) + ( data[0] << 0) # Just for debugging
mb = Microboot() info = mb.getDeviceInfo(device) if info is None: print "Unsupported device type '%s'." % device exit(1) # Set up logging if requested if g_logFile is not None: mb.logger = logFunction # Load the HEX file hexfile = IntelHex() hexfile.fromfile(filename, format='hex') if device == "attiny85": # Adjust the code to move the RESET vector hexfile = adjustStartup(info, hexfile) # Set up for the write start = hexfile.minaddr() length = (hexfile.maxaddr() - start) + 1 data = list() for index in range(length): data.append(hexfile[start + index]) print "Writing %d bytes (%04X:%04X) from file '%s'." % (length, start, start + length - 1, filename) print "Target is a '%s' on port '%s'." % (device, port) # Write the data try: mb.connect(device, port) except Exception, ex: print "Error: Could not connect to device, error message is:" print " " + str(ex) exit(1) mb.write(start, length, data) # Now verify
CRIS = 0x00 NNB = 0xFF if not selectNode(CRIS, NNB, connection, verbose): exit(1) #connected, now what? #first, verify that this is an AT90CAN128 # selectMemorySpace(SIGNATURE_SPACE, CRIS, connection, verbose) #first, select the Flash memory space # selectMemorySpace(FLASH_SPACE, CRIS, connection, verbose) # selectMemoryPage(0, CRIS, connection, verbose) #now, read the HEX file, and start writing ih = IntelHex(hexfile) address = ih.minaddr() max = ih.maxaddr() if (max > 0xFFFF): #have to do this in two pages max = 0xFFFF #now, start programming eraseMemory(CRIS, connection, verbose) writeMemory(ih, ih.minaddr(), ih.minaddr(), max, CRIS, connection, verbose) #and now, verify verifyMemory(ih, CRIS, connection, verbose) #finally, set bootloader flag, and start application selectMemorySpace(EEPROM_SPACE, CRIS, connection, verbose) writeMemory([0x00, 0x00], 0x00, 0x0FF8, 0x0FF9, CRIS, connection, verbose) frame = makeframestring(CRIS, CAN_DISPLAY_DATA, [0x00, 0x0F, 0xF7, 0x0F, 0xFF])
def post_process(self): logging.info("Processing binaries") fw_info_fmt = '<I16s128s16s128s16s' fw_info_addr = int(self.settings["FW_INFO_ADDR"], 16) # save original dir cwd = os.getcwd() # change to target dir os.chdir(self.target_dir) ih = IntelHex('main.hex') fwid = uuid.UUID('{' + self.settings["FWID"] + '}') # get KV meta start kv_meta_addr = fw_info_addr + struct.calcsize(fw_info_fmt) kv_meta_len = KVMetaField().size() bindata = ih.tobinstr() kv_meta_data = [] while True: kv_meta = KVMetaField().unpack(bindata[kv_meta_addr:kv_meta_addr + kv_meta_len]) kv_meta_addr += kv_meta_len if kv_meta.param_name == "kvstart": continue elif kv_meta.param_name == "kvend": break else: kv_meta_data.append(kv_meta) kv_meta_by_hash = {} logging.info("Hash type: FNV1A_32") # create lookups by 32 bit hash index = 0 for kv in kv_meta_data: hash32 = fnv1a_32(str(kv.param_name)) if hash32 in kv_meta_by_hash: raise Exception("Hash collision!") kv_meta_by_hash[hash32] = (kv, index) index += 1 # sort indexes sorted_hashes = sorted(kv_meta_by_hash.keys()) # create binary look up table kv_index = '' for a in sorted_hashes: kv_index += struct.pack('<LB', a, kv_meta_by_hash[a][1]) # write to end of hex file ih.puts(ih.maxaddr() + 1, kv_index) size = ih.maxaddr() - ih.minaddr() + 1 # get os info try: os_project = get_project_builder(self.settings["OS_PROJECT"], target=self.target_type) except KeyError: os_project = "" # create firmware info structure fw_info = struct.pack(fw_info_fmt, size, fwid.bytes, os_project.proj_name, os_project.version, str(self.settings['PROJ_NAME']), self.version) # insert fw info into hex ih.puts(fw_info_addr, fw_info) # compute crc crc_func = crcmod.predefined.mkCrcFun('crc-aug-ccitt') crc = crc_func(ih.tobinstr()) logging.info("size: %d" % (size)) logging.info("fwid: %s" % (fwid)) logging.info("fwinfo: %x" % (fw_info_addr)) logging.info("kv index len: %d" % (len(kv_index))) logging.info("crc: 0x%x" % (crc)) logging.info("os name: %s" % (os_project.proj_name)) logging.info("os version: %s" % (os_project.version)) logging.info("app name: %s" % (self.settings['PROJ_NAME'])) logging.info("app version: %s" % (self.version)) ih.puts(ih.maxaddr() + 1, struct.pack('>H', crc)) ih.write_hex_file('main.hex') ih.tobinfile('firmware.bin') # get loader info loader_project = get_project_builder(self.settings["LOADER_PROJECT"], target=self.target_type) # create loader image loader_hex = os.path.join(loader_project.target_dir, "main.hex") self.merge_hex('main.hex', loader_hex, 'loader_image.hex') # create sha256 of binary sha256 = hashlib.sha256(ih.tobinstr()) # create manifest file data = { 'name': self.settings['FULL_NAME'], 'timestamp': datetime.utcnow().isoformat(), 'sha256': sha256.hexdigest(), 'fwid': self.settings['FWID'], 'version': self.version } with open('manifest.txt', 'w+') as f: f.write(json.dumps(data)) # create firmware zip file zf = zipfile.ZipFile('chromatron_main_fw.zip', 'w') zf.write('manifest.txt') zf.write('firmware.bin') zf.close() # create second, project specific zip # we'll remove the first zip after # we update the firmware tools zf = zipfile.ZipFile('%s.zip' % (self.settings['PROJ_NAME']), 'w') zf.write('manifest.txt') zf.write('firmware.bin') zf.close() # change back to original dir os.chdir(cwd) logging.info("Package dir: %s" % (get_build_package_dir())) # make sure we have the firmware package dir try: os.makedirs(get_build_package_dir()) except OSError: pass # copy firmware zip try: shutil.copy( os.path.join(self.target_dir, '%s.zip' % (self.proj_name)), get_build_package_dir()) except IOError: raise AppZipNotFound # update build date with open( os.path.join(get_build_package_dir(), firmware_package.PUBLISHED_AT_FILENAME), 'w') as f: f.write(util.now().isoformat())
# Here's how easy it is to erase the memory, and then verify that it's blank print("Erasing the EEPROM...this may take 10s of seconds") programmer.erase() print("Erase Completed!") print("Now performing a blank check...") isBlank = programmer.blankCheck() print("isBlank = {}".format(isBlank)) print("Reading the entire EEPROM") data = programmer.read() print("Creating a .bin and .hex file with the data read from the EEPROM") ih.frombytes(data) print("Min Addr: {}, Max Addr: {}".format(str(ih.minaddr()), str(ih.maxaddr()))) print("Now saving the file to disk just to demo how easy it is") ih.tofile("testFileErased-00.hex", format="hex") ih.tofile("testFileErased-00.bin", format="bin") # Reading / Writing / Verifying EEPROMs from bin or hex files is also very # easy: print("Manually modifying the data file") dataFile = "testFile.bin" ih[0] = 0xDE ih[1] = 0xAD ih[2] = 0xBE ih[3] = 0xEF print("Now writing the modified file to EEPROM")
class StaxProg(): def __init__(self, port, speed): port = port speed = speed self.hex = IntelHex() self.port = port self.speed = speed def load(self, filename): print "Loading application from hex" self.hex.loadfile(filename, "hex") size = self.hex.maxaddr() - self.hex.minaddr() print " size: %0.2f KiB (%d B)" % (size/1024, size) def read(self): c = self.handle.read() return c def open(self): print "Programer ready connect SkyBean...", sys.stdout.flush() self.handle = serial.Serial(self.port, self.speed, timeout=.2) done = False i = 0 first = True while (not done): i += 1 time.sleep(0.1) self.handle.write("ebl") str = self.handle.read(10) if (str == 'bootloader'): done = True verh = ord(self.handle.read(1)) verl = ord(self.handle.read(1)) ver = (verh << 8) | verl else: if first: # print "Unable to reset automatically. Press reset now." sys.stdout.flush() first = False self.handle.flushInput(); time.sleep(.1) if (i > 1000): raise Exception("Unable to acquire bootloader control") print "done" print "Bootloader version %d" % ver self.handle.timeout=2 def erase(self): print "Erasing application...", sys.stdout.flush() self.handle.write('e') c = self.read() if c == 'd': print "done" else: raise Exception("Unexpected character (%c = %d)" % (c, ord(c))) def boot(self): print "Booting application..." self.handle.write('b') def prog(self): done = False adr = self.hex.minaddr() # self.handle.write('s') # adrh = (self.hex.maxaddr() & 0xFF0000) >> 16 # adrm = (self.hex.maxaddr() & 0x00FF00) >> 8 # adrl = (self.hex.maxaddr() & 0x0000FF) >> 0 # # self.handle.write(chr(adrl)) # self.handle.write(chr(adrm)) # self.handle.write(chr(adrh)) print "Programing application..." while(not done): self.handle.write('p') adrh = (adr & 0xFF0000) >> 16 adrm = (adr & 0x00FF00) >> 8 adrl = (adr & 0x0000FF) >> 0 self.handle.write(chr(adrl)) self.handle.write(chr(adrm)) self.handle.write(chr(adrh)) max_size = 64 size = self.hex.maxaddr() - adr if (size > max_size): size = max_size sizel = chr(size & 0x00FF) sizeh = chr((size & 0xFF00) >> 8) self.handle.write(sizel) self.handle.write(sizeh) for i in range(size): low = self.hex[adr + i*2] high = self.hex[adr + i*2 + 1] self.handle.write(chr(low)) self.handle.write(chr(high)) adr += size << 1 if adr >= self.hex.maxaddr(): adr = self.hex.maxaddr() done = True print " adr 0x%04X size %03X (%3.0f%%)" % (adr, size, (float(adr)/float(self.hex.maxaddr()))*100) sys.stdout.flush() c = self.read() if c != 'd': a = self.read() raise Exception("Unexpected character (%c = %d)" % (a, ord(a))) print "Done" def verify(self): print "Verifying application..." #atxmega128a3 app section size # max_adr = 0x20000 self.handle.write('s') adrh = (self.hex.maxaddr() & 0xFF0000) >> 16 adrm = (self.hex.maxaddr() & 0x00FF00) >> 8 adrl = (self.hex.maxaddr() & 0x0000FF) >> 0 self.handle.write(chr(adrl)) self.handle.write(chr(adrm)) self.handle.write(chr(adrh)) max_adr = self.hex.maxaddr() size = 512 done = False adr = 0 read_data = [] while (not done): self.handle.write('r') adrh = (adr & 0xFF0000) >> 16 adrm = (adr & 0x00FF00) >> 8 adrl = (adr & 0x0000FF) >> 0 self.handle.write(chr(adrl)) self.handle.write(chr(adrm)) self.handle.write(chr(adrh)) if (size > max_adr - adr): size = (max_adr - adr) * 2 sizel = chr(size & 0x00FF) sizeh = chr((size & 0xFF00) >> 8) self.handle.write(sizel) self.handle.write(sizeh) for i in range(size): cadr = adr + i data = ord(self.handle.read()) if (cadr >= self.hex.minaddr() and cadr <= self.hex.maxaddr()): read_data.append(data) else: if (data is not 0xFF): print "FF expected on %06X" % cadr adr += size if (adr >= max_adr): adr = max_adr done = True print " adr 0x%04X size %03X (%3.0f%%)" % (adr, size/2, (float(adr)/float(self.hex.maxaddr()))*100) sys.stdout.flush() if (self.hex.tobinarray() == read_data): print "Verification OK" else: print "Verification FAILED" print self.hex.tobinarray() print read_data wrong = 0 for i in range(self.hex.maxaddr() - self.hex.minaddr()): cadr = i + self.hex.minaddr() if (self.hex._buf[cadr] is not read_data[cadr]): wrong += 1 print "Wrong bytes %d/%d (%d %%)" % (wrong, self.hex.maxaddr(), (wrong*100)/self.hex.maxaddr()) def batch(self, filename): start = time.clock() self.load(filename) self.open() self.erase() self.prog() #self.verify() self.boot() end = time.clock() print print "That's all folks! (%.2f seconds)" % (end - start)
# check args def auto_int(x): return int(x,0) parser = ArgumentParser('add_header.py read a mos header, update it with given properties and length and checksum and write it back to stdout') parser.add_argument('-p', '--pid', type=auto_int, help='option to change the pid for this program') parser.add_argument('-k', '--key', type=auto_int, help='option to change the key for this program') parser.add_argument('--hw', type=auto_int, help='option to change the hardware id for this program') parser.add_argument('filename', nargs=1, help='mandatory hex file to read header data from') args = parser.parse_args() filename = args.filename[0] if not os.path.exists(filename): sys.exit("Unable open %s" % filename) # open the full program (open via StringIO so we can write back to filename if desired) prog = IntelHex(StringIO.StringIO(open(filename, "r").read())) header_addr = prog.minaddr() # all programs require there header to be located at the start # read out the header header = ih2header(prog) # optional updates if args.pid != None and args.pid >= 0 and args.pid < 256: header['pid'] = args.pid if args.key != None: header['key'] = args.key if args.hw != None: header['hw_id'] = args.hw # update the header len l = prog.maxaddr() - prog.minaddr() + 1 header['len'] = l
class Driver(FirmwareBase): def __init__(self, filename, can): FirmwareBase.__init__(self) self.__ih = IntelHex() self.__ih.loadhex(filename) self.can = can cs = crc.crc16() for each in range(self.__ih.minaddr(), self.__ih.maxaddr()+1): cs.addByte(self.__ih[each]) self.__size = self.__ih.maxaddr()+1 self.__checksum = cs.getResult() self.__progress = 0.0 self.__blocksize = 128 self.__blocks = self.__size / self.__blocksize + 1 self.__currentblock = 0 def __fillBuffer(self, ch, address, data): sframe = canbus.Frame(1760 + ch, [0x01, address & 0xFF, (address & 0xFF00) >> 8, 128]) self.can.sendFrame(sframe) endtime = time.time() + 0.5 while True: # Channel wait loop try: rframe = self.can.recvFrame() except canbus.DeviceTimeout: pass else: if rframe.id == sframe.id+1 and \ rframe.data == sframe.data: break now = time.time() if now > endtime: return False for n in range(self.__blocksize / 8): #print data[address + (8*n):address + (8*n) + 8] sframe.data = data[address + (8*n):address + (8*n) + 8] self.can.sendFrame(sframe) #time.sleep(0.3) # TODO Need to deal with the abort from the uC somewhere return True def __erasePage(self, ch, address): sframe = canbus.Frame(1760 + ch, [0x02, address & 0xFF, (address & 0xFF00) >> 8, 64]) self.can.sendFrame(sframe) endtime = time.time() + 0.5 while True: # Channel wait loop try: rframe = self.can.recvFrame() except canbus.DeviceTimeout: pass else: if rframe.id == sframe.id+1 and \ rframe.data == sframe.data: break now = time.time() if now > endtime: return False def __writePage(self, ch, address): sframe = canbus.Frame(1760 + ch, [0x03, address & 0xFF, (address & 0xFF00) >> 8]) self.can.sendFrame(sframe) endtime = time.time() + 0.5 while True: # Channel wait loop try: rframe = self.can.recvFrame() except canbus.DeviceTimeout: pass else: if rframe.id == sframe.id+1 and \ rframe.data == sframe.data: break now = time.time() if now > endtime: return False def __sendComplete(self, ch): sframe = canbus.Frame(1760 + ch, [0x05, self.__checksum & 0xFF, (self.__checksum & 0xFF00) >> 8, \ self.__size & 0xFF, (self.__size & 0xFF00) >> 8]) self.can.sendFrame(sframe) endtime = time.time() + 0.5 while True: # Channel wait loop try: rframe = self.can.recvFrame() except canbus.DeviceTimeout: pass else: if rframe.id == sframe.id+1 and \ rframe.data == sframe.data: break now = time.time() if now > endtime: return False def download(self, node): data=[] channel = FirmwareBase.start_download(self, node) for n in range(self.__blocks * self.__blocksize): data.append(self.__ih[n]) for block in range(self.__blocks): address = block * 128 #print "Buffer Fill at %d" % (address) self.sendStatus("Writing Block %d of %d" % (block, self.__blocks)) self.sendProgress(float(block) / float(self.__blocks)) self.__currentblock = block while(self.__fillBuffer(channel, address, data)==False): if self.kill: self.sendProgress(0.0) self.sendStatus("Download Stopped") return #raise firmware.FirmwareError("Canceled") # Erase Page #print "Erase Page Address =", address self.__erasePage(channel ,address) # Write Page #print "Write Page Address =", address self.__writePage(channel ,address) #self.__progress = 1.0 #print "Download Complete Checksum", hex(self.__checksum), "Size", self.__size self.__sendComplete(channel) self.sendStatus("Download Complete Checksum 0x%X, Size %d" % (self.__checksum, self.__size)) self.sendProgress(1.0) #FirmwareBase.end_download()
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)
def _build_reflash_script_action(target, source, env): """Create a TRUB script containing tile and controller reflashes and/or sensorgraph If the app_info is provided, then the final source file will be a sensorgraph. All subsequent files in source must be in intel hex format. This is guaranteed by the ensure_image_is_hex call in build_update_script. """ out_path = str(target[0]) source = [str(x) for x in source] records = [] if env['USE_SAFEUPDATE']: sgf_off = SendRPCRecord(8, 0x2005, bytearray([0])) # Disable Sensorgraph records.append(sgf_off) safemode_enable = SendRPCRecord(8, 0x1006, bytearray([1])) # Enable Safemode records.append(safemode_enable) # Update application firmwares if env['SLOTS'] is not None: for (controller, slot_id), image_path in zip(env['SLOTS'], source): hex_data = IntelHex(image_path) hex_data.padding = 0xFF offset = hex_data.minaddr() bin_data = bytearray( hex_data.tobinarray(offset, hex_data.maxaddr())) if controller: record = ReflashControllerRecord(bin_data, offset) else: record = ReflashTileRecord(slot_id, bin_data, offset) records.append(record) # Update sensorgraph if env['UPDATE_SENSORGRAPH']: sensor_graph_file = source[-1] sensor_graph = compile_sgf(sensor_graph_file) output = format_script(sensor_graph) records += UpdateScript.FromBinary(output).records # Update App and OS Tag os_info = env['OS_INFO'] app_info = env['APP_INFO'] if os_info is not None: os_tag, os_version = os_info records.append(SetDeviceTagRecord(os_tag=os_tag, os_version=os_version)) if app_info is not None: app_tag, app_version = app_info records.append( SetDeviceTagRecord(app_tag=app_tag, app_version=app_version)) if env['USE_SAFEUPDATE']: safemode_disable = SendRPCRecord(8, 0x1006, bytearray([0])) # Disable safemode records.append(safemode_disable) sgf_on = SendRPCRecord(8, 0x2005, bytearray([1])) # Enable Sensorgraph records.append(sgf_on) script = UpdateScript(records) with open(out_path, "wb") as outfile: outfile.write(script.encode())
""" import binascii, sys, struct from intelhex import IntelHex if len(sys.argv) != 3: print __doc__ % sys.argv[0] sys.exit(1) ih = IntelHex(sys.argv[1]) out = open(sys.argv[2], 'wb') # Sanity checks, very important if ih.maxaddr() < 0x1004 or ih.maxaddr() > 32767: print "Insane hexfile: min=0x%x max=0x%x" % (ih.minaddr(), ih.maxaddr()) sys.exit(2) print "Length: %d / 28672" % (ih.maxaddr() - 4096 + 1) print "Free: %d" % (28672 - (ih.maxaddr() - 4096 + 1)) # Hack to force tobinstr() to write data from addres 0. IntelHex will # only write data from the first location with initialized data, skipping # over any uninitialized data beforehand. This initializes address 0, # forcing IntelHex to do what I want. ih[0]=ih[0] sumdata = (ih.tobinstr())[0x1004:] sumdata += '\xff' * (0x6ffc - len(sumdata)) cksum = binascii.crc32(sumdata) & 0xffffffff print "Checksum: 0x%08x" % cksum ih.puts(0x1000, struct.pack('<L', cksum))
class StaxProg(): def __init__(self, port, speed): port = port speed = speed self.hex = IntelHex() self.port = port self.speed = speed def load(self, filename): # print "Loading application from hex" self.hex.loadfile(filename, "hex") size = self.hex.maxaddr() - self.hex.minaddr() # print " size: %0.2f KiB (%d B)" % (size/1024, size) def read(self): c = self.handle.read() return c def open(self): print(" * Power off and power on SkyBean") self.handle = serial.Serial(self.port, self.speed, timeout=2) done = False while (not done): c = self.handle.read(1) if c == b'b': break i = 0 first = True while (not done): i += 1 time.sleep(0.1) self.handle.write(b'ebl') str = self.handle.read(10) if (str == b'bootloader'): done = True verh = ord(self.handle.read(1)) verl = ord(self.handle.read(1)) ver = (verh << 8) | verl else: if first: # print "Unable to reset automatically. Press reset now." sys.stdout.flush() first = False self.handle.flushInput() time.sleep(.1) if (i > 1000): raise Exception("Unable to acquire bootloader control") print("Bootloader version %d" % ver) #self.handle.setTimeout(2) def erase(self): print("Erasing application...", end=' ') sys.stdout.flush() self.handle.write(b'e') c = self.read() if c == b'd': print("done") else: raise Exception("Unexpected character (%c = %d)" % (c, ord(c))) def boot(self): print("Booting application...") self.handle.write(b'b') def prog(self): done = False adr = self.hex.minaddr() print("Programing application...") while (not done): self.handle.write(b'p') adrh = (adr & 0xFF0000) >> 16 adrm = (adr & 0x00FF00) >> 8 adrl = (adr & 0x0000FF) >> 0 self.handle.write(bytes([adrl])) self.handle.write(bytes([adrm])) self.handle.write(bytes([adrh])) max_size = 64 size = self.hex.maxaddr() - adr if (size > max_size): size = max_size sizel = bytes([size & 0x00FF]) sizeh = bytes([(size & 0xFF00) >> 8]) self.handle.write(sizel) self.handle.write(sizeh) for i in range(size): low = self.hex[adr + i * 2] high = self.hex[adr + i * 2 + 1] self.handle.write(bytes([low])) self.handle.write(bytes([high])) adr += size << 1 if adr >= self.hex.maxaddr(): adr = self.hex.maxaddr() done = True # print " adr 0x%04X size %03X (%3.0f%%)" % (adr, size, (float(adr)/float(self.hex.maxaddr()))*100) print(".", end=' ') sys.stdout.flush() c = self.read() if c != b'd': a = self.read() raise Exception("Unexpected character (%c = %d)" % (a, ord(a))) print("Done") def verify(self): print("Verifying application...") #atxmega128a3 app section size # max_adr = 0x20000 self.handle.write('s') adrh = (self.hex.maxaddr() & 0xFF0000) >> 16 adrm = (self.hex.maxaddr() & 0x00FF00) >> 8 adrl = (self.hex.maxaddr() & 0x0000FF) >> 0 self.handle.write(chr(adrl)) self.handle.write(chr(adrm)) self.handle.write(chr(adrh)) max_adr = self.hex.maxaddr() size = 512 done = False adr = 0 read_data = [] while (not done): self.handle.write('r') adrh = (adr & 0xFF0000) >> 16 adrm = (adr & 0x00FF00) >> 8 adrl = (adr & 0x0000FF) >> 0 self.handle.write(chr(adrl)) self.handle.write(chr(adrm)) self.handle.write(chr(adrh)) if (size > max_adr - adr): size = (max_adr - adr) * 2 sizel = chr(size & 0x00FF) sizeh = chr((size & 0xFF00) >> 8) self.handle.write(sizel) self.handle.write(sizeh) for i in range(size): cadr = adr + i data = ord(self.handle.read()) if (cadr >= self.hex.minaddr() and cadr <= self.hex.maxaddr()): read_data.append(data) else: if (data is not 0xFF): print("FF expected on %06X" % cadr) adr += size if (adr >= max_adr): adr = max_adr done = True print(" adr 0x%04X size %03X (%3.0f%%)" % (adr, size / 2, (float(adr) / float(self.hex.maxaddr())) * 100)) sys.stdout.flush() if (self.hex.tobinarray() == read_data): print("Verification OK") else: print("Verification FAILED") print(self.hex.tobinarray()) print(read_data) wrong = 0 for i in range(self.hex.maxaddr() - self.hex.minaddr()): cadr = i + self.hex.minaddr() if (self.hex._buf[cadr] is not read_data[cadr]): wrong += 1 print("Wrong bytes %d/%d (%d %%)" % (wrong, self.hex.maxaddr(), (wrong * 100) / self.hex.maxaddr())) def batch(self, filename): start = time.clock() if hasattr(sys, "_MEIPASS"): filename = os.path.join(sys._MEIPASS, filename) self.load(filename) self.open() self.erase() self.prog() # self.verify() self.boot() end = time.clock() print() print("Programming done! (%.2f seconds)\n" % (end - start))
class Firmware(): """A Class that represents the firmware logic.""" def __init__(self, canbus, filename, srcnode=247): """canbus is a canbus.Connection() object and filename is a string that is the path to the Intel Hex file that we are downloading""" self.__canbus = canbus self.ih = IntelHex(filename) self.__srcnode = srcnode cs = crc.crc16() for each in range(self.ih.minaddr(), self.ih.maxaddr() + 1): cs.addByte(self.ih[each]) self.__size = self.ih.maxaddr() + 1 self.__checksum = cs.getResult() self.lock = threading.Lock() self.__progress = 0.0 self.__blocks = self.__size / 128 + 1 self.__currentblock = 0 self.__blocksize = 128 self.kill = False # Download support functions def __tryChannel(self, ch): """Waits for a half a second to see if there is any traffic on any of the channels""" result = self.__canbus.error() if result != 0x00: self.__canbus.close() self.__canbus.open() endtime = time.time() + 0.5 ch.ClearAll() while True: # Channel wait loop try: rframe = self.__canbus.recvFrame() except canbus.DeviceTimeout: pass else: ch.TestFrame(rframe) now = time.time() if now > endtime: break def __tryFirmwareReq(self, ch, node): """Requests a firmware load, waits for 1/2 a second and determines if the response is correct and if so returns True returns False on timeout""" channel = ch.GetFreeChannel() sframe = {} sframe["id"] = 1792 + self.__srcnode sframe["data"] = [] sframe["data"].append(node) sframe["data"].append(7) sframe["data"].append(1) sframe["data"].append(0xF7) sframe["data"].append(channel) self.__canbus.sendFrame(sframe) endtime = time.time() + 0.5 ch.ClearAll() while True: # Channel wait loop try: rframe = self.__canbus.recvFrame() except canbus.DeviceTimeout: pass else: if rframe["id"] == (1792 + node) and \ rframe["data"][0] == self.__srcnode: break now = time.time() if now > endtime: return False return True def __fillBuffer(self, ch, address, data): sframe = {} sframe["id"] = 1760 + ch sframe["data"] = [0x01, address & 0xFF, (address & 0xFF00) >> 8, 128] self.__canbus.sendFrame(sframe) endtime = time.time() + 0.5 while True: # Channel wait loop try: rframe = self.__canbus.recvFrame() except canbus.DeviceTimeout: pass else: if rframe["id"] == sframe["id"]+1 and \ rframe["data"] == sframe["data"]: break now = time.time() if now > endtime: return False for n in range(self.__blocksize / 8): print data[address + (8 * n):address + (8 * n) + 8] self.lock.acquire() self.__progress = float(address + 8 * n) / float(self.size) self.lock.release() sframe['data'] = data[address + (8 * n):address + (8 * n) + 8] print sframe self.__canbus.sendFrame(sframe) #time.sleep(0.3) # TODO Need to deal with the abort from the uC somewhere def __erasePage(self, ch, address): sframe = {} sframe["id"] = 1760 + ch sframe["data"] = [0x02, address & 0xFF, (address & 0xFF00) >> 8, 64] self.__canbus.sendFrame(sframe) endtime = time.time() + 0.5 while True: # Channel wait loop try: rframe = self.__canbus.recvFrame() except canbus.DeviceTimeout: pass else: if rframe["id"] == sframe["id"]+1 and \ rframe["data"] == sframe["data"]: break now = time.time() if now > endtime: return False def __writePage(self, ch, address): sframe = {} sframe["id"] = 1760 + ch sframe["data"] = [0x03, address & 0xFF, (address & 0xFF00) >> 8] self.__canbus.sendFrame(sframe) endtime = time.time() + 0.5 while True: # Channel wait loop try: rframe = self.__canbus.recvFrame() except canbus.DeviceTimeout: pass else: if rframe["id"] == sframe["id"]+1 and \ rframe["data"] == sframe["data"]: break now = time.time() if now > endtime: return False def __sendComplete(self, ch): sframe = {} sframe["id"] = 1760 + ch sframe["data"] = [0x05, self.__checksum & 0xFF, (self.__checksum & 0xFF00) >> 8, \ self.__size & 0xFF, (self.__size & 0xFF00) >> 8] self.__canbus.sendFrame(sframe) endtime = time.time() + 0.5 while True: # Channel wait loop try: rframe = self.__canbus.recvFrame() except canbus.DeviceTimeout: pass else: if rframe["id"] == sframe["id"]+1 and \ rframe["data"] == sframe["data"]: break now = time.time() if now > endtime: return False def Download(self, node): ch = Channels() data = [] while True: # Firmware load request loop self.__tryChannel(ch) # send firmware request if self.__tryFirmwareReq(ch, node): break if self.kill: exit(-1) # Here we are in the Firmware load mode of the node # Get our firmware bytes into a normal list channel = ch.GetFreeChannel() for n in range(self.__blocks * self.__blocksize): data.append(self.ih[n]) for block in range(self.__blocks): address = block * 128 print "Buffer Fill at %d" % (address) self.lock.acquire() self.__currentblock = block self.lock.release() self.__fillBuffer(channel, address, data) # TODO Deal with timeout of above # Erase Page print "Erase Page Address =", address self.__erasePage(channel, address) # Write Page print "Write Page Address =", address self.__writePage(channel, address) self.__progress = 1.0 print "Download Complete Checksum", hex( self.__checksum), "Size", self.__size self.__sendComplete(channel) def getProgress(self): self.lock.acquire() progress = self.__progress self.lock.release() return progress def getCurrentBlock(self): self.lock.acquire() progress = self.__currentblock self.lock.release() return progress def getBlocks(self): return self.__blocks def getSize(self): return self.__size def getChecksum(self): return self.__checksum def Connect(self): self.__canbus.connect() self.__canbus.init() self.__canbus.open() #time.sleep(3) #can.close() currentblock = property(getCurrentBlock) progress = property(getProgress) blocks = property(getBlocks) size = property(getSize) checksum = property(getChecksum)
def load(self, path): ih = IntelHex(path) return ih.tobinarray(), ih.minaddr()
class Firmware(): """A Class that represents the firmware logic.""" def __init__(self, canbus, filename, srcnode=247): """canbus is a canbus.Connection() object and filename is a string that is the path to the Intel Hex file that we are downloading""" self.__canbus = canbus self.ih = IntelHex(filename) self.__srcnode = srcnode cs = crc.crc16() for each in range(self.ih.minaddr(), self.ih.maxaddr()+1): cs.addByte(self.ih[each]) self.__size = self.ih.maxaddr()+1 self.__checksum = cs.getResult() self.lock = threading.Lock() self.__progress = 0.0 self.__blocks = self.__size / 128 + 1 self.__currentblock = 0 self.__blocksize = 128 self.kill = False # Download support functions def __tryChannel(self, ch): """Waits for a half a second to see if there is any traffic on any of the channels""" result = self.__canbus.error() if result != 0x00: self.__canbus.close() self.__canbus.open() endtime = time.time() + 0.5 ch.ClearAll() while True: # Channel wait loop try: rframe = self.__canbus.recvFrame() except canbus.DeviceTimeout: pass else: ch.TestFrame(rframe) now = time.time() if now > endtime: break def __tryFirmwareReq(self, ch, node): """Requests a firmware load, waits for 1/2 a second and determines if the response is correct and if so returns True returns False on timeout""" channel = ch.GetFreeChannel() sframe = {} sframe["id"] = 1792 + self.__srcnode sframe["data"] = [] sframe["data"].append(node) sframe["data"].append(7) sframe["data"].append(1) sframe["data"].append(0xF7) sframe["data"].append(channel) self.__canbus.sendFrame(sframe) endtime = time.time() + 0.5 ch.ClearAll() while True: # Channel wait loop try: rframe = self.__canbus.recvFrame() except canbus.DeviceTimeout: pass else: if rframe["id"] == (1792 + node) and \ rframe["data"][0] == self.__srcnode: break now = time.time() if now > endtime: return False return True def __fillBuffer(self, ch, address, data): sframe = {} sframe["id"] =1760 + ch sframe["data"] = [0x01, address & 0xFF, (address & 0xFF00) >> 8, 128] self.__canbus.sendFrame(sframe) endtime = time.time() + 0.5 while True: # Channel wait loop try: rframe = self.__canbus.recvFrame() except canbus.DeviceTimeout: pass else: if rframe["id"] == sframe["id"]+1 and \ rframe["data"] == sframe["data"]: break now = time.time() if now > endtime: return False for n in range(self.__blocksize / 8): print data[address + (8*n):address + (8*n) + 8] self.lock.acquire() self.__progress = float(address + 8*n) / float(self.size) self.lock.release() sframe['data'] = data[address + (8*n):address + (8*n) + 8] print sframe self.__canbus.sendFrame(sframe) #time.sleep(0.3) # TODO Need to deal with the abort from the uC somewhere def __erasePage(self, ch, address): sframe = {} sframe["id"] =1760 + ch sframe["data"] = [0x02, address & 0xFF, (address & 0xFF00) >> 8, 64] self.__canbus.sendFrame(sframe) endtime = time.time() + 0.5 while True: # Channel wait loop try: rframe = self.__canbus.recvFrame() except canbus.DeviceTimeout: pass else: if rframe["id"] == sframe["id"]+1 and \ rframe["data"] == sframe["data"]: break now = time.time() if now > endtime: return False def __writePage(self, ch, address): sframe = {} sframe["id"] =1760 + ch sframe["data"] = [0x03, address & 0xFF, (address & 0xFF00) >> 8] self.__canbus.sendFrame(sframe) endtime = time.time() + 0.5 while True: # Channel wait loop try: rframe = self.__canbus.recvFrame() except canbus.DeviceTimeout: pass else: if rframe["id"] == sframe["id"]+1 and \ rframe["data"] == sframe["data"]: break now = time.time() if now > endtime: return False def __sendComplete(self, ch): sframe = {} sframe["id"] =1760 + ch sframe["data"] = [0x05, self.__checksum & 0xFF, (self.__checksum & 0xFF00) >> 8, \ self.__size & 0xFF, (self.__size & 0xFF00) >> 8] self.__canbus.sendFrame(sframe) endtime = time.time() + 0.5 while True: # Channel wait loop try: rframe = self.__canbus.recvFrame() except canbus.DeviceTimeout: pass else: if rframe["id"] == sframe["id"]+1 and \ rframe["data"] == sframe["data"]: break now = time.time() if now > endtime: return False def Download(self, node): ch = Channels() data = [] while True: # Firmware load request loop self.__tryChannel(ch) # send firmware request if self.__tryFirmwareReq(ch, node): break if self.kill: exit(-1) # Here we are in the Firmware load mode of the node # Get our firmware bytes into a normal list channel = ch.GetFreeChannel() for n in range(self.__blocks * self.__blocksize): data.append(self.ih[n]) for block in range(self.__blocks): address = block * 128 print "Buffer Fill at %d" % (address) self.lock.acquire() self.__currentblock = block self.lock.release() self.__fillBuffer(channel, address, data) # TODO Deal with timeout of above # Erase Page print "Erase Page Address =", address self.__erasePage(channel ,address) # Write Page print "Write Page Address =", address self.__writePage(channel ,address) self.__progress = 1.0 print "Download Complete Checksum", hex(self.__checksum), "Size", self.__size self.__sendComplete(channel) def getProgress(self): self.lock.acquire() progress = self.__progress self.lock.release() return progress def getCurrentBlock(self): self.lock.acquire() progress = self.__currentblock self.lock.release() return progress def getBlocks(self): return self.__blocks def getSize(self): return self.__size def getChecksum(self): return self.__checksum def Connect(self): self.__canbus.connect() self.__canbus.init() self.__canbus.open() #time.sleep(3) #can.close() currentblock = property(getCurrentBlock) progress = property(getProgress) blocks = property(getBlocks) size = property(getSize) checksum = property(getChecksum)
def DoIP_Flash_Hex(componentID, ihexFP, hostECUAddr='1111', serverECUAddr='2004', targetIP='172.26.200.101', verbose=False, multiSegment=True): # get necessary dependencies import progressbar t_FlashStart = time.time() print '\nFlashing ' + ihexFP + ' to component ID : ' + componentID + '\n' # start a DoIP client DoIPClient = DoIP_Client(ECUAddr=hostECUAddr) DoIPClient.SetVerbosity(verbose) if DoIPClient._TCP_Socket: downloadErr = False DoIPClient.ConnectToDoIPServer(address=targetIP, port=13400, routingActivation=True, targetECUAddr=serverECUAddr) if DoIPClient._isTCPConnected and DoIPClient._isRoutingActivated: print "Switching to programming diagnostic session" if DoIPClient.DoIPSwitchDiagnosticSession(PyUDS.PRGS) == 0: print "Successfully switched to programming diagnostic session\n" #reset connection to server DoIPClient.DisconnectFromDoIPServer() DoIPClient.ConnectToDoIPServer(address=targetIP, port=13400, routingActivation=True, targetECUAddr=serverECUAddr) if DoIPClient._isTCPConnected and DoIPClient._isRoutingActivated: # # # initial seed key exchange # # # # to do : implement seed key exchange # read DIDs print "Starting pre-download checks..." print "\tReading old tester finger print" if DoIPClient.DoIPReadDID(PyUDS.DID_REFPRNT) == 0: print "\tRead success" print "\tWriting new tester finger print" # to do: we will need to replace the first line with the date if DoIPClient.DoIPWriteDID(PyUDS.DID_WRFPRNT, '180727' + \ '484F4E472D2D4849' + \ '4C2D544553542D54' + \ '45414D0304050607' + \ '08090A0B0C0D0E0F' + \ '0001020304050607' + \ '5858585858585858') == 0: print "\tWrite success" print "\tVerifying new tester finger print" # compare with the date here if DoIPClient.DoIPReadDID(PyUDS.DID_REFPRNT) == 0: # read and store old BL SW ID # to-do: decipher and store relevant info print "\tRead success" print "\tReading Bootloader SW ID" if DoIPClient.DoIPReadDID( PyUDS.DID_BOOTSID) == 0: # read and store old APP and CAL SW ID # to-do: decipher and store relevant info print "\tRead success" print "\tReading Application and Calibration SW ID" if DoIPClient.DoIPReadDID( PyUDS.DID_APCASID) == 0: print "\tRead success" print "Pre-download checks complete\n" # Erase component memory for target component if DoIPClient.DoIPEraseMemory( componentID) == 0: print "Erase memory success\n" else: downloadErr = True else: downloadErr = True else: downloadErr = True else: downloadErr = True else: downloadErr = True else: downloadErr = True if not downloadErr: print "Loading hex file: " + ihexFP from intelhex import IntelHex ih = IntelHex() ih.loadhex(ihexFP) if multiSegment: print "Downloading in multiple segments..." segments = ih.segments() else: print "Downloading in a single filled segment..." minAddr = ih.minaddr() maxAddr = ih.maxaddr() segments = [(ih.minaddr(), ih.maxaddr())] for (minAddr, maxAddr) in segments: if multiSegment: maxAddr -= 1 memSize = maxAddr - minAddr + 1 minAddrStr = "%.8X" % minAddr maxAddrStr = "%.8X" % maxAddr memSizeStr = "%.8X" % memSize print "\tStart Address: " + minAddrStr + " (%.10d)" % minAddr print "\tEnd Address: " + maxAddrStr + " (%.10d)" % maxAddr print "\tTotal Memory: " + memSizeStr + " (%.10d)\n" % memSize # request download here. Set maxBlockByteCount to valu from request download maxBlockByteCount = DoIPClient.DoIPRequestDownload( minAddrStr, memSizeStr) if maxBlockByteCount >= 2: maxBlockByteCount -= 2 # subtract 2 for SID and index else: print "Error while requesting download data. Exiting out of flash sequencing" downloadErr = True break blockByteCount = 0 hexDataStr = '' hexDataList = [] for address in range(minAddr, maxAddr + 1): # print '%.8X\t%.2X' % (address,ih[address]) hexDataStr = hexDataStr + '%.2X' % ih[address] blockByteCount += 1 if blockByteCount == maxBlockByteCount: hexDataList.append(hexDataStr) hexDataStr = '' blockByteCount = 0 hexDataList.append(hexDataStr) blockIndex = 1 # turn off verbosity, less you be spammed! if DoIPClient._isVerbose: DoIPClient.SetVerbosity(False) print "Transfering Data -- Max block size(bytes): 0x%.4X (%d)" % ( maxBlockByteCount, maxBlockByteCount) # start download progress bar bar = progressbar.ProgressBar( maxval=len(hexDataList), widgets=[ progressbar.Bar('=', '[', ']'), ' ', progressbar.Percentage() ]) bar.start() bar.update(blockIndex) t_Start = time.time() # begin transferring data for block in hexDataList: blockIndexStr = '%.2X' % (blockIndex & 0xFF) if DoIPClient.DoIPTransferData( blockIndexStr, block) != 0: downloadErr = True break bar.update(blockIndex) blockIndex += 1 bar.finish() if not downloadErr: if DoIPClient.DoIPRequestTransferExit() == 0: t_Finish = time.time() t_Download = int(t_Finish - t_Start) hr_Download = t_Download / 3600 min_Download = t_Download / 60 - hr_Download * 60 sec_Download = t_Download - hr_Download * 3600 - min_Download * 60 print "Download complete. Elapsed download time: %.0fdhr %.0fmin %.0fdsec" % ( hr_Download, min_Download, sec_Download) print 'Total Blocks sent: %d' % ( len(hexDataList)) print 'Block size(bytes): %d' % ( len(hexDataList[0]) / 2) print 'Final block size(bytes): %d\n' % ( len(hexDataList[len(hexDataList) - 1]) / 2) else: print "Request transfer exit failure. Exiting out of flash sequence" downloadErr = True break else: print "Transfer data failure. Exiting out of flash sequence" downloadErr = True break # reset verbosity if verbose: DoIPClient.SetVerbosity(True) if not downloadErr: # request check memory if DoIPClient.DoIPCheckMemory(componentID) == 0: if DoIPClient._RxDoIPMsg.payload[9] == '0': print "Check memory passed. Authorizing software update\n" # if pass, then authorize application . to do: application authorization else: print "Check memory failed. Software update is invalid. Exiting out of update sequence\n" print "Switching to default diagnostic session..." print "\tWarning :: ECU will reset" if DoIPClient._DoIPUDSSend(PyUDS.DSC + PyUDS.DS) == 0: print "Successfully switched to default diagnostic session\n" print "Software update success!!\n" t_FlashEnd = time.time() t_Flash = int(t_FlashEnd - t_FlashStart) hr_Flash = t_Flash / 3600 min_Flash = t_Flash / 60 - hr_Flash * 60 sec_Flash = t_Flash - hr_Flash * 3600 - min_Flash * 60 print "-----------------------------------------------------------------------------------" print "Flash sequence complete. Elapsed flash time: %.0fdhr %.0fmin %.0fdsec \n" % ( hr_Flash, min_Flash, sec_Flash) print "-----------------------------------------------------------------------------------" else: print "Error while checking memory. Exiting out of flash sequence." else: print "Error during post transfer operations.\n" # disconnect from the server gracefully please print "Exiting out of flash sequence...\n" DoIPClient.DisconnectFromDoIPServer() time.sleep(5) else: print "Error while performing pre-programming procedure. Exiting flash sequence." else: print "Error while reconnecting to ECU or during routing activation. Exiting flash sequence." else: print "Error while switching to programming diagnostic session. Exiting flash sequence." else: print "Error while connect to ECU and//or activate routing. Exiting flash sequence." else: print "Error while creating flash client. Unable to initiate flash sequence."
mb = Microboot() info = mb.getDeviceInfo(device) if info is None: print "Unsupported device type '%s'." % device exit(1) # Set up logging if requested if g_logFile is not None: mb.logger = logFunction # Load the HEX file hexfile = IntelHex() hexfile.fromfile(filename, format='hex') if device == "attiny85": # Adjust the code to move the RESET vector hexfile = adjustStartup(info, hexfile) # Set up for the write start = hexfile.minaddr() length = (hexfile.maxaddr() - start) + 1 data = list() for index in range(length): data.append(hexfile[start + index]) print "Writing %d bytes (%04X:%04X) from file '%s'." % ( length, start, start + length - 1, filename) print "Target is a '%s' on port '%s'." % (device, port) # Write the data try: mb.connect(device, port) except Exception, ex: print "Error: Could not connect to device, error message is:" print " " + str(ex) exit(1) beginProgress("Writing")
show_help() sys.exit(1) if not os.path.exists(sys.argv[1]): sys.exit("Unable open build %s" % sys.argv[1]) if not os.path.exists(sys.argv[2]): sys.exit("Unable open build %s" % sys.argv[2]) build_filename = sys.argv[1] prog_filename = sys.argv[2] # open the build and prog # note open build via StringIO so we can add to it build = IntelHex(StringIO.StringIO(open(build_filename, "r").read())) prog = IntelHex(prog_filename) # merge program into build prog_header_addr = prog.minaddr() prog.start_addr = build.start_addr # we need this to make the merge work smoothly build.merge(prog) # add pointer to program header to the bootstrap header_tbl_addr = 0x08000204 header_tbl_len = 2 #@todo get this from 0x0800200 as uint32_t header_tbl_format = "<LL" header_tbl = list( struct.unpack(header_tbl_format, build.gets(header_tbl_addr, header_tbl_len * 4))) k = 0 while header_tbl[k] != 0xffffffff: if k > header_tbl_len: sys.exit("bootstrap program table full [you have too many programs]!") k += 1
def main(): # Rather than at the beginning of the files, constants are here HASH_LENGH = 128/8 # Hash length (128 bits) AES_KEY_LENGTH = 256/8 # AES key length (256 bits) FW_MAX_LENGTH = 28672 # Maximum firmware length, depends on size allocated to bootloader FLASH_SECTOR_0_LENGTH = 264*8 # Length in bytes of sector 0a in external flash (to change for 16Mb & 32Mb flash!) STORAGE_SPACE = 65536 - FLASH_SECTOR_0_LENGTH # Uint16_t addressing space - sector 0a length (dedicated to other storage...) BUNDLE_MAX_LENGTH = STORAGE_SPACE - FW_MAX_LENGTH - HASH_LENGH - AES_KEY_LENGTH # Robust RNG rng = Random.new() # Check that all required files are here if isfile("bundle.img"): print "Bundle file found" else: print "Couldn't find bundle file" return if isfile("Mooltipass.hex"): print "Firmware file found" else: print "Couldn't find firmware file" return # Read bundle and firmware data firmware = IntelHex("Mooltipass.hex") fd = open("bundle.img", 'rb') bundle = fd.read() fd.close() # Check that the firmware data actually starts at address 0 if firmware.minaddr() != 0: print "Firmware start address isn't correct" return # Check that the bundle & firmware data aren't bigger than they should be if len(bundle) > BUNDLE_MAX_LENGTH: print "Bundle file too long:", len(bundle), "bytes long" return else: print "Bundle file is ", len(bundle), "bytes long" if len(firmware) > FW_MAX_LENGTH: print "Firmware file too long:", len(firmware), "bytes long" return else: print "Firmware file is ", len(firmware), "bytes long" # Generate new random AES key, encrypt it with the old one new_aes_key = rng.read(AES_KEY_LENGTH) new_aes_key = array('B',[0]*AES_KEY_LENGTH) # TO REMOVE! cipher = AES.new(getAesKeyForMooltipass(0), AES.MODE_ECB, array('B',[0]*AES.block_size)) # IV ignored in ECB enc_password = cipher.encrypt(new_aes_key) if len(enc_password) != AES_KEY_LENGTH: print "Encoded password is too long!" return # Generate beginning of update file data: bundle | padding | firmware | new aes key encoded update_file_data = array('B') update_file_data.extend(bytearray(bundle)) update_file_data.extend(array('B',[0]*(STORAGE_SPACE-HASH_LENGH-AES_KEY_LENGTH-FW_MAX_LENGTH-len(bundle)))) update_file_data.extend(firmware.tobinarray()) update_file_data.extend(array('B',[0]*(STORAGE_SPACE-HASH_LENGH-AES_KEY_LENGTH-len(update_file_data)))) update_file_data.extend(bytearray(enc_password)) # Check length if len(update_file_data) != (STORAGE_SPACE - HASH_LENGH): print "Problem with update file length!" return # Generate CBCMAC, IV is ZEROS cipher = AES.new(getAesKeyForMooltipass(0), AES.MODE_CBC, array('B',[0]*AES.block_size)) cbc_mac = cipher.encrypt(update_file_data)[-AES.block_size:] # Append it to update file data: bundle | padding | firmware | new aes key encoded | cbcmac update_file_data.extend(bytearray(cbc_mac)) # Check length if len(update_file_data) != STORAGE_SPACE: print "Problem with update file length!" return # Write our update image file data_fd = open("updatefile.img", 'wb') data_fd.write(update_file_data) data_fd.close() print "Update file written!"
class ShdlcFirmwareImage(object): """ This class represents a firmware image for an SHDLC device. It is used to load and verify Intel-Hex files for performing firmware updates over SHDLC. Since the different SHDLC devices use different memory layouts, this class needs to know the bootloader base address and application base address (see constructor parameters). Drivers for specific SHDLC devices should create a subclass to provide a new type which already contains the correct addresses, so users don't have to care about these details. .. note:: This class is intended only for devices which contain the SHDLC bootloader. Devices which support firmware updates with another system aren't supported by this class. .. note:: The package ``intelhex`` must be installed to use this class. See :ref:`firmware-updater-dependencies` for details. """ _PRODUCT_TYPE_SIZE = 4 # Product type size def __init__(self, hexfile, bl_start_addr, app_start_addr, signature=b'\x4A\x47\x4F\x4B', bl_version_offset=0x1004): """ Constructor which loads and parses the firmware from a hex file. :param str/file hexfile: The filename or file-like object containing the firmware in Intel-Hex format (\\*.hex). :param int bl_start_addr: The base address of the bootloader inside the firmware image. :param int app_start_addr: The base address of the application inside the firmware image. :param bytes signature: Signature bytes used for the application. :param int bl_version_offset: Bootloader version address offset. :raise ~sensirion_shdlc_driver.errors.ShdlcFirmwareImageSignatureError: If the signature of the image is invalid. """ # Import intelhex here to allow importing the firmware_image module # without having the intelhex package installed (it's an optional # dependency, so it might be missing). from intelhex import IntelHex self._bl_start_addr = int(bl_start_addr) self._app_start_addr = int(app_start_addr) self._signature = bytes(bytearray(signature)) self._bl_version_offset = int(bl_version_offset) self._app_data_index = 0 self._data = IntelHex(hexfile) self._data.padding = 0xFF # is returned when reading undefined regions log.debug( "Loaded hex file: {} [minaddr=0x{:08X}, maxaddr=0x{:08X}]".format( hexfile, self._data.minaddr(), self._data.maxaddr())) self._check_signature() log.debug("Signature: OK") self._product_type = self._read_product_type() log.debug("Product type: 0x{:08X}".format(self._product_type)) self._bootloader_version = self._read_bootloader_version() log.debug("Bootloader version: {}".format(self._bootloader_version)) self._application_version = self._read_application_version() log.debug("Application version: {}".format(self._application_version)) self._app_data = self._read_application_data() log.debug("Application size: {:.2f} kB".format(self.size / 1024)) self._checksum = self._calc_application_checksum() log.debug("Application checksum: 0x{:02X}".format(self._checksum)) @property def product_type(self): """ Get the product type for which the loaded firmware is made. :return: Product type as an integer. :rtype: int """ return self._product_type @property def bootloader_version(self): """ Get the bootloader version which is contained in the loaded image. :return: Bootloader version (note: debug flag is not supported, it's always False). :rtype: ~sensirion_shdlc_driver.types.FirmwareVersion """ return self._bootloader_version @property def application_version(self): """ Get the application firmware version which is contained in the loaded image. :return: Application firmware version (note: debug flag is not supported, it's always False). :rtype: ~sensirion_shdlc_driver.types.FirmwareVersion """ return self._application_version @property def checksum(self): """ Get the checksum over the application firmware part of the loaded image. This is the checksum which needs to be sent to the product bootloader. :return: Checksum as a byte. :rtype: byte """ return self._checksum @property def size(self): """ Get the size of the application firmware. :return: Size in bytes. :rtype: int """ return len(self._app_data) @property def available_bytes(self): """ Get the count of available bytes left. :return: Count of available bytes. :rtype: int """ return len(self._app_data) - self._app_data_index def read(self, size=-1): """ Read the next bytes of the application firmware. :param int size: Maximum count of bytes to read (-1 reads all available) :return: Firmware data block. :rtype: bytes """ if size < 0: size = self.available_bytes else: size = min(size, self.available_bytes) data = self._app_data[self._app_data_index:self._app_data_index + size] self._app_data_index += len(data) return bytes(data) # immutable type to avoid modifying image data def _check_signature(self): """ Check the signature of the loaded image and throw an exception if it's invalid. """ signature = self._read_bytes(self._app_start_addr, len(self._signature)) if signature != self._signature: raise ShdlcFirmwareImageSignatureError(signature) def _read_product_type(self): """ Read the product type from the loaded image. :return: The read product type. :rtype: int """ address = self._app_start_addr + len(self._signature) return self._read_uint32(address) def _read_bootloader_version(self): """ Read the bootloader version from the loaded image. :return: The read bootloader version. :rtype: ~sensirion_shdlc_driver.types.FirmwareVersion """ addr_major = self._bl_start_addr + self._bl_version_offset + 1 addr_minor = self._bl_start_addr + self._bl_version_offset return FirmwareVersion(major=self._data[addr_major], minor=self._data[addr_minor], debug=False) def _read_application_version(self): """ Read the application version from the loaded image. :return: The read application version. :rtype: ~sensirion_shdlc_driver.types.FirmwareVersion """ addr_major = self._app_start_addr + len(self._signature) + \ self._PRODUCT_TYPE_SIZE + 1 addr_minor = self._app_start_addr + len(self._signature) + \ self._PRODUCT_TYPE_SIZE return FirmwareVersion(major=self._data[addr_major], minor=self._data[addr_minor], debug=False) def _read_application_data(self): """ Read the application data block from the loaded image. :return: The read application data block. :rtype: bytearray """ # Skip the signature because it must not be sent to the bootloader! start_addr = self._app_start_addr + len(self._signature) if self._bl_start_addr > self._app_start_addr: end_addr = self._bl_start_addr - 1 # Don't include bootloader else: end_addr = self._data.maxaddr() return bytearray(self._data.tobinarray(start=start_addr, end=end_addr)) def _read_uint32(self, address): """ Read an uint32 at a specific image address. :param int address: The address to read from. :return: The integer at the specified address. :rtype: int """ return unpack("<I", self._data.tobinarray(start=address, size=4))[0] def _read_bytes(self, address, number_of_bytes): """ Read at a specific image address. :param int address: The address to read from. :param int number_of_bytes: Number of bytes to read :return: The bytes from the specified address. :rtype: bytes """ return self._data.tobinstr(start=address, size=number_of_bytes) def _calc_application_checksum(self): """ Calculate the checksum over the application data, as needed for the firmware download command. :return: Checksum of application data :rtype: byte """ return (sum(self._app_data) % 256) ^ 0xFF
address = int(address, 0) & 0xFFFFFFFF except ValueError: print("Address %s invalid." % address) sys.exit(1) if not os.path.isfile(binfile): print("Unreadable file '%s'." % binfile) sys.exit(1) target.append({ 'address': address, 'data': open(binfile, 'rb').read() }) if options.hexfiles: for hex in options.hexfiles: ih = IntelHex(hex) address = ih.minaddr() data = ih.tobinstr() try: address = address & 0xFFFFFFFF except ValueError: print("Address %s invalid." % address) sys.exit(1) target.append({'address': address, 'data': data}) 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:
def dumpHex(hexFileName) : hexFile = IntelHex(hexFileName) for i in range(hexFile.minaddr(), hexFile.maxaddr()+1, 16) : row = [str(i)] + [ str(hexFile[j]) for j in range(i, i+16)] print(" ".join(row))
if not selectNode(CRIS, NNB, connection, verbose): exit(1) #connected, now what? #first, verify that this is an AT90CAN128 # selectMemorySpace(SIGNATURE_SPACE, CRIS, connection, verbose) #first, select the Flash memory space # selectMemorySpace(FLASH_SPACE, CRIS, connection, verbose) # selectMemoryPage(0, CRIS, connection, verbose) #now, read the HEX file, and start writing ih = IntelHex(hexfile) address = ih.minaddr() max = ih.maxaddr() if(max > 0xFFFF): #have to do this in two pages max = 0xFFFF #now, start programming eraseMemory(CRIS, connection, verbose) writeMemory(ih, ih.minaddr(), ih.minaddr(), max, CRIS, connection, verbose) #and now, verify verifyMemory(ih, CRIS, connection, verbose) #finally, set bootloader flag, and start application selectMemorySpace(EEPROM_SPACE, CRIS, connection, verbose) writeMemory([0x00, 0x00], 0x00, 0x0FF8, 0x0FF9, CRIS, connection, verbose) frame = makeframestring(CRIS, CAN_DISPLAY_DATA, [0x00, 0x0F, 0xF7, 0x0F, 0xFF]) connection.network.send(frame)
class MainApp(MDApp): def __init__(self, **kwargs): super().__init__(**kwargs) self.ih = IntelHex() self.ab = ArduinoBootloader() self.working_thread = None self.progress_queue = Queue(100) self.protocol = "Stk500v1" self.baudrate = 115200 def build(self): return Builder.load_string(KV) def on_sel_programmer(self, baudrate, protocol): self.baudrate = baudrate self.protocol = protocol def on_flash(self): del self.ih try: self.ih = IntelHex() self.ih.fromfile(self.root.ids.file_name.text, format='hex') except FileNotFoundError: self.root.ids.file_info.text = "File not found" return except AddressOverlapError: self.root.ids.file_info.text = "File with address overlapped" return self.root.ids.file_info.text = "start address: {} size: {} bytes".format( self.ih.minaddr(), self.ih.maxaddr()) """The firmware update is done in a worker thread because the main thread in Kivy is in charge of updating the widgets.""" self.root.ids.progress.value = 0 self.working_thread = threading.Thread(target=self.thread_flash) self.working_thread.start() def thread_flash(self): """If the communication with the bootloader through the serial port could be established, obtains the information of the processor and the bootloader.""" res_val = False """First you have to select the communication protocol used by the bootloader of the Arduino board. The Stk500V1 is the one used by the Nano or Uno, and depending on the Old or New version, the communication speed varies, for the new one you have to use 115200 and for the old 57600. The communication protocol for boards based on Mega 2560 is Stk500v2 at 115200.""" prg = self.ab.select_programmer(self.protocol) if prg.open(speed=self.baudrate): if prg.board_request(): self.progress_queue.put(["board_request"]) Clock.schedule_once(self.progress_callback, 1 / 1000) if prg.cpu_signature(): self.progress_queue.put(["cpu_signature"]) Clock.schedule_once(self.progress_callback, 1 / 1000) """Iterate the firmware file into chunks of the page size in bytes, and use the write flash command to update the cpu.""" for address in range(0, self.ih.maxaddr(), self.ab.cpu_page_size): buffer = self.ih.tobinarray(start=address, size=self.ab.cpu_page_size) res_val = prg.write_memory(buffer, address) if not res_val: break self.progress_queue.put(["write", address / self.ih.maxaddr()]) Clock.schedule_once(self.progress_callback, 1 / 1000) """If the write was successful, re-iterate the firmware file, and use the read flash command to update and compare them.""" if res_val: for address in range(0, self.ih.maxaddr(), self.ab.cpu_page_size): buffer = self.ih.tobinarray(start=address, size=self.ab.cpu_page_size) read_buffer = prg.read_memory(address, self.ab.cpu_page_size) if not len(read_buffer) or (buffer != read_buffer): res_val = False break self.progress_queue.put( ["read", address / self.ih.maxaddr()]) Clock.schedule_once(self.progress_callback, 1 / 1000) self.progress_queue.put( ["result", "ok" if res_val else "error", address]) Clock.schedule_once(self.progress_callback, 1 / 1000) prg.leave_bootloader() prg.close() else: self.progress_queue.put(["open_error"]) Clock.schedule_once(self.progress_callback, 1 / 1000) def progress_callback(self, dt): """In kivy only the main thread can update the widgets. Schedule a clock event to read the message from the queue and update the progress.""" value = self.progress_queue.get() if value[0] == "open_error": self.root.ids.status.text = "Can't open bootloader {} at baudrate {}".format( self.protocol, self.baudrate) if value[0] == "board_request": self.root.ids.sw_version.text = self.ab.sw_version self.root.ids.hw_version.text = self.ab.hw_version self.root.ids.prg_name.text = self.ab.programmer_name if value[0] == "cpu_signature": self.root.ids.cpu_version.text = self.ab.cpu_name if value[0] == "write": self.root.ids.status.text = "Writing flash %{:.2f}".format( value[1] * 100) self.root.ids.progress.value = value[1] if value[0] == "read": self.root.ids.status.text = "Reading and verifying flash %{:.2f}".format( value[1] * 100) self.root.ids.progress.value = value[1] if value[0] == "result" and value[1] == "ok": self.root.ids.status.text = "Download done" self.root.ids.progress.value = 1 if value[0] == "result" and value[1] == "error": self.root.ids.status.text = "Error writing"
print("Fatal Error: -- FAILED merge due to overlap when merging " + f.name) sys.exit(1) except: print("Fatal Error: -- FAILED parsing input hex file(s)") sys.exit(1) #print information about the input hex files print_args_info(inputFileNames, vargs.out, vargs.outbin, vargs.oadtype, vargs.imgtype) #Now that we have a merged hex image, lets do a bunch of arg checking #since mergedHex is an merge of all input hexes, it can be treated as an argument to the script argument_sanity_check(vargs, mergedHex) # Cut off / fill with --fill. startAddr = mergedHex.minaddr() endAddr = mergedHex.addresses()[-1] + 1 # Inclusive address if startAddr % OAD_BLOCK_SIZE: print("Fatal Error: -- Start address 0x%X is not divisible by 16. Exiting") sys.exit(1) # DevMon rounds up to nearest sector. Why not, if they want to waste time and space. if vargs.round is not None: endAddr = ((endAddr + INT_FL_PG_SIZE) & ~(INT_FL_PG_SIZE-1)) print ('endAddr round', hex(endAddr)) if vargs.range is not None: if vargs.range[0] is not None: startAddr = vargs.range[0] if vargs.range[1] is not None: endAddr = vargs.range[1]
type=auto_int, help='option to change the key for this program') parser.add_argument('--hw', type=auto_int, help='option to change the hardware id for this program') parser.add_argument('filename', nargs=1, help='mandatory hex file to read header data from') args = parser.parse_args() filename = args.filename[0] if not os.path.exists(filename): sys.exit("Unable open %s" % filename) # open the full program (open via StringIO so we can write back to filename if desired) prog = IntelHex(StringIO.StringIO(open(filename, "r").read())) header_addr = prog.minaddr( ) # all programs require there header to be located at the start # read out the header header = ih2header(prog) # optional updates if args.pid != None and args.pid >= 0 and args.pid < 256: header['pid'] = args.pid if args.key != None: header['key'] = args.key if args.hw != None: header['hw_id'] = args.hw # update the header len l = prog.maxaddr() - prog.minaddr() + 1 header['len'] = l
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("."))
def sign_image(self, hex_file, image_id, image_type, encrypt_key=None, erased_val=None, boot_record='default'): """ Signs hex file with the key specified in the policy file. Converts binary file of the signed image. Creates copy of unsigned hex file. Encrypts UPGRADE image if the policy file contains encryption key :param hex_file: The hex file to sign. :param image_id: The ID of the firmware in policy file. :param image_type: The image type. :param encrypt_key: path to public key file for the image encryption :param erased_val: The value that is read back from erased flash :param boot_record: Create CBOR encoded boot record TLV. The sw_type represents the role of the software component (e.g. CoFM for coprocessor firmware). [max. 12 characters] :return: Path to the signed files. One file per slot. """ result = [] slot = self.parser.get_slot(image_id) if erased_val: self.erased_val = erased_val ih_padding = int(erased_val, 0) logger.warning(f'Custom value {erased_val} will be used as an ' f'erased value for all regions and memory types. ' f'Typical correct values for internal and ' f'external Flash memory are 0x00 and 0xFF ' f'respectively.') else: default_erased_val = self._default_erased_value(image_type, slot) ih_padding = int(default_erased_val, 0) if slot is None: logger.error( f'Image with ID {image_id} not found in \'{self.policy_file}\'' ) return None unsigned_hex = '{0}_{2}{1}'.format(*os.path.splitext(hex_file) + ('unsigned', )) copy2(hex_file, unsigned_hex) boot_ih = IntelHex() boot_ih.padding = ih_padding boot_ih.loadfile(hex_file, 'hex') base_addr = boot_ih.minaddr() boot_bin = f'{hex_file}.bin' hex2bin(boot_ih, boot_bin) encrypted_boot = False first_image_result = None # indicates first image signing success for image in slot['resources']: if image_type: if image['type'] != image_type.upper(): continue # skip generating hex file if sign type defined and not same as current image type if image['type'] == ImageType.UPGRADE.name: if 'upgrade' not in slot or not slot['upgrade']: continue # skip generating hex file for UPGRADE slot if it is disabled encryption = self.parser.encryption_enabled(slot['id']) if encryption: if encrypt_key is None: encrypt_key = self.parser.encrypt_key(slot['id']) if encrypt_key is None: raise ValueError('Encryption key not specified') else: if not os.path.isfile(encrypt_key): raise FileNotFoundError( f'Encryption key \'{encrypt_key}\' not found') else: encrypt_key = None if image['type'] == ImageType.BOOT.name: if first_image_result is False: continue hex_out = self.sign_single_hex(slot, image['type'], boot_bin, hex_file, start_addr=base_addr, boot_record=boot_record, encrypt_key=encrypt_key) encrypted_boot = encrypt_key is not None first_image_result = hex_out is not None os.remove(boot_bin) else: if first_image_result is False: continue output_name = '{0}_{2}{1}'.format(*os.path.splitext(hex_file) + ('upgrade', )) hex_out = self.sign_single_hex(slot, image['type'], unsigned_hex, output_name, encrypt_key, boot_record=boot_record) first_image_result = hex_out is not None if hex_out: bin_out = '{0}.bin'.format(os.path.splitext(hex_out)[0]) if not erased_val: default_erased_val = self._default_erased_value( image_type, slot) ih_padding = int(default_erased_val, 0) upgrade_ih = IntelHex() upgrade_ih.padding = ih_padding upgrade_ih.loadfile(hex_out, 'hex') hex2bin(upgrade_ih, bin_out) bin2hex(bin_out, output_name, offset=int(image['address'])) os.remove(bin_out) if hex_out: result.append(hex_out) if encrypted_boot: self.replace_image_body(hex_file, unsigned_hex, ih_padding) if image_type: if ImageType.UPGRADE.name == image_type.upper(): os.remove(hex_file) result = tuple(result) if len(result) > 0 else None return result
def main(): # Check if one input argument is provided if len(sys.argv) != 2: print "Usage:", sys.argv[0], "bootloader.hex" sys.exit(1) # Input arguments hexfile = sys.argv[1] # Check if file exists if not os.path.isfile(hexfile): print "Error: File does not exist." sys.exit(2) # Read bootloader data bootloader = IntelHex(hexfile) bootloader_bin = bootloader.tobinarray() #bootloader.dump() # Start address loaderStart = bootloader.minaddr() # Given a start address, deduce where the bootloader ends end_addresses = { 0x1000: 0x2000, 0x1C00: 0x2000, 0x1D00: 0x2000, 0x1E00: 0x2000, 0x3000: 0x4000, 0x3800: 0x4000, 0x3E00: 0x4000, 0x7000: 0x8000, 0x7800: 0x8000, 0x7E00: 0x8000, 0xF800: 0x10000, 0x1F000: 0x20000, 0x1FC00: 0x20000, 0x3E000: 0x40000, } if not loaderStart in end_addresses: print "Error: Unkown bootloader start address." sys.exit(3) loaderEnd = end_addresses[loaderStart] # Len loaderLen = loaderEnd - loaderStart if loaderLen < len(bootloader_bin): print "Error: Invalid bootloader length." sys.exit(4) # Calculate md5sum from hexfile and add padding bytes with 0xFF md5 = hashlib.md5() md5.update(bootloader_bin) padding = [0xFF] * (loaderLen - len(bootloader_bin)) md5.update(bytearray(padding)) # Calculatae md5sum from the original file so we know which disk file it came from filemd5 = hashlib.md5() fd = open(hexfile, 'rb') filemd5.update(fd.read()) fd.close() # Filename without full path and without ".hex" filename = os.path.splitext(os.path.basename(hexfile))[0] # Print header print '// File =', filename + ".hex" print '// Loader start:', hex(loaderStart), 'length', loaderLen print '// Bootloader MD5 sum =', md5.hexdigest() print '// Original file MD5 sum =', filemd5.hexdigest() print print 'const uint8_t', filename + '_hex [] PROGMEM = {' # Print data line = "" for i in range(len(bootloader_bin)): line += hex(bootloader_bin[i]) + ', ' if i % 16 == 15: print line line = '' if line: print line # Print footer print '}; // end of', filename + '_hex'
class StaxProg(): def __init__(self, port, speed): port = port speed = speed self.hex = IntelHex() self.port = port self.speed = speed def load(self, filename): print "Loading application from hex" self.hex.loadfile(filename, "hex") size = self.hex.maxaddr() - self.hex.minaddr() print " size: %0.2f KiB (%d B)" % (size/1024, size) def read(self): c = self.handle.read() return c def open(self): print "Programer ready connect SkyBean...", sys.stdout.flush() self.handle = serial.Serial(self.port, self.speed, timeout=.2) done = False i = 0 first = True while (not done): i += 1 time.sleep(0.1) self.handle.write("ebl") str = self.handle.read(10) if (str == 'bootloader'): done = True verh = ord(self.handle.read(1)) verl = ord(self.handle.read(1)) ver = (verh << 8) | verl else: if first: # print "Unable to reset automatically. Press reset now." sys.stdout.flush() first = False self.handle.flushInput(); time.sleep(.1) if (i > 1000): raise Exception("Unable to acquire bootloader control") print "done" print "Bootloader version %d" % ver self.handle.setTimeout(2) def erase(self): print "Erasing application...", sys.stdout.flush() self.handle.write('e') c = self.read() if c == 'd': print "done" else: raise Exception("Unexpected character (%c = %d)" % (c, ord(c))) def boot(self): print "Booting application..." self.handle.write('b') def prog(self): done = False adr = self.hex.minaddr() # self.handle.write('s') # adrh = (self.hex.maxaddr() & 0xFF0000) >> 16 # adrm = (self.hex.maxaddr() & 0x00FF00) >> 8 # adrl = (self.hex.maxaddr() & 0x0000FF) >> 0 # # self.handle.write(chr(adrl)) # self.handle.write(chr(adrm)) # self.handle.write(chr(adrh)) print "Programing application..." while(not done): self.handle.write('p') adrh = (adr & 0xFF0000) >> 16 adrm = (adr & 0x00FF00) >> 8 adrl = (adr & 0x0000FF) >> 0 self.handle.write(chr(adrl)) self.handle.write(chr(adrm)) self.handle.write(chr(adrh)) max_size = 64 size = self.hex.maxaddr() - adr if (size > max_size): size = max_size sizel = chr(size & 0x00FF) sizeh = chr((size & 0xFF00) >> 8) self.handle.write(sizel) self.handle.write(sizeh) for i in range(size): low = self.hex[adr + i*2] high = self.hex[adr + i*2 + 1] self.handle.write(chr(low)) self.handle.write(chr(high)) adr += size << 1 if adr >= self.hex.maxaddr(): adr = self.hex.maxaddr() done = True print " adr 0x%04X size %03X (%3.0f%%)" % (adr, size, (float(adr)/float(self.hex.maxaddr()))*100) sys.stdout.flush() c = self.read() if c != 'd': a = self.read() raise Exception("Unexpected character (%c = %d)" % (a, ord(a))) print "Done" def verify(self): print "Verifying application..." #atxmega128a3 app section size # max_adr = 0x20000 self.handle.write('s') adrh = (self.hex.maxaddr() & 0xFF0000) >> 16 adrm = (self.hex.maxaddr() & 0x00FF00) >> 8 adrl = (self.hex.maxaddr() & 0x0000FF) >> 0 self.handle.write(chr(adrl)) self.handle.write(chr(adrm)) self.handle.write(chr(adrh)) max_adr = self.hex.maxaddr() size = 512 done = False adr = 0 read_data = [] while (not done): self.handle.write('r') adrh = (adr & 0xFF0000) >> 16 adrm = (adr & 0x00FF00) >> 8 adrl = (adr & 0x0000FF) >> 0 self.handle.write(chr(adrl)) self.handle.write(chr(adrm)) self.handle.write(chr(adrh)) if (size > max_adr - adr): size = (max_adr - adr) * 2 sizel = chr(size & 0x00FF) sizeh = chr((size & 0xFF00) >> 8) self.handle.write(sizel) self.handle.write(sizeh) for i in range(size): cadr = adr + i data = ord(self.handle.read()) if (cadr >= self.hex.minaddr() and cadr <= self.hex.maxaddr()): read_data.append(data) else: if (data is not 0xFF): print "FF expected on %06X" % cadr adr += size if (adr >= max_adr): adr = max_adr done = True print " adr 0x%04X size %03X (%3.0f%%)" % (adr, size/2, (float(adr)/float(self.hex.maxaddr()))*100) sys.stdout.flush() if (self.hex.tobinarray() == read_data): print "Verification OK" else: print "Verification FAILED" print self.hex.tobinarray() print read_data wrong = 0 for i in range(self.hex.maxaddr() - self.hex.minaddr()): cadr = i + self.hex.minaddr() if (self.hex._buf[cadr] is not read_data[cadr]): wrong += 1 print "Wrong bytes %d/%d (%d %%)" % (wrong, self.hex.maxaddr(), (wrong*100)/self.hex.maxaddr()) def batch(self, filename): start = time.clock() self.load(filename) self.open() self.erase() self.prog() #self.verify() self.boot() end = time.clock() print print "That's all folks! (%.2f seconds)" % (end - start)
print("Address:file couple '%s' invalid." % arg) sys.exit(1) try: address = int(address,0) & 0xFFFFFFFF except ValueError: print("Address %s invalid." % address) sys.exit(1) if not os.path.isfile(binfile): print("Unreadable file '%s'." % binfile) sys.exit(1) target.append({ 'address': address, 'data': open(binfile,'rb').read() }) if options.hexfiles: for hex in options.hexfiles: ih = IntelHex(hex) address = ih.minaddr() data = ih.tobinstr() try: address = address & 0xFFFFFFFF except ValueError: print("Address %s invalid." % address) sys.exit(1) target.append({ 'address': address, 'data': data }) revision = DEFAULT_REVISION if options.revision: try: rev2byte(options.revision) revision = options.revision except ValueError: print("Invalid revision value.")
def bundlePackAndSign(bundleName, firmwareName, oldAesKey, newAesKey, updateFileName, verbose): # Rather than at the beginning of the files, constants are here VERSION_LENGTH = 4 # FW version length HASH_LENGH = 128/8 # Hash length (128 bits) AES_KEY_LENGTH = 256/8 # AES key length (256 bits) FW_VERSION_LENGTH = 4 # Length of the firmware version in the bundle AES_KEY_UPDATE_FLAG_LGTH = 1 # Length of the tag which specifies a firmware udpate FW_MAX_LENGTH = 28672 # Maximum firmware length, depends on size allocated to bootloader FLASH_SECTOR_0_LENGTH = 264*8 # Length in bytes of sector 0a in external flash (to change for 16Mb & 32Mb flash!) STORAGE_SPACE = 65536 - FLASH_SECTOR_0_LENGTH # Uint16_t addressing space - sector 0a length (dedicated to other storage...) BUNDLE_MAX_LENGTH = STORAGE_SPACE - FW_MAX_LENGTH - HASH_LENGH - AES_KEY_LENGTH - FW_VERSION_LENGTH - AES_KEY_UPDATE_FLAG_LGTH # Robust RNG rng = Random.new() # Extracted firmware version firmware_version = None # AES Key Update Bool aes_key_update_bool = True # Check that all required files are here if isfile(bundleName): if verbose == True: print "Bundle file found" else: print "Couldn't find bundle file" return False if isfile(firmwareName): if verbose == True: print "Firmware file found" else: print "Couldn't find firmware file" return False # Read bundle and firmware data firmware = IntelHex(firmwareName) firmware_bin = firmware.tobinarray() fd = open(bundleName, 'rb') bundle = fd.read() fd.close() # Check that the firmware data actually starts at address 0 if firmware.minaddr() != 0: print "Firmware start address isn't correct" return False # Check that the bundle & firmware data aren't bigger than they should be if len(bundle) > BUNDLE_MAX_LENGTH: print "Bundle file too long:", len(bundle), "bytes long" return False else: if verbose == True: print "Bundle file is", len(bundle), "bytes long" if len(firmware) > FW_MAX_LENGTH-VERSION_LENGTH: print "Firmware file too long:", len(firmware), "bytes long" return False else: if verbose == True: print "Firmware file is", len(firmware), "bytes long" if verbose == True: print "Remaining space in MCU flash:", FW_MAX_LENGTH - len(firmware), "bytes" if verbose == True: print "Remaining space in bundle:", STORAGE_SPACE - FW_MAX_LENGTH - HASH_LENGH - AES_KEY_LENGTH - FW_VERSION_LENGTH - AES_KEY_UPDATE_FLAG_LGTH - len(bundle), "bytes" # Beta testers devices have their aes key set to 00000... and the bootloader will always perform a key update if oldAesKey == "0000000000000000000000000000000000000000000000000000000000000000" and newAesKey == None: if verbose == True: print "Bundle update for beta testers unit, setting 00000... as new AES key" newAesKey = "0000000000000000000000000000000000000000000000000000000000000000" # If no new aes key is specified, don't set the aes key update flag if newAesKey == None: if verbose == True: print "No new AES key set" aes_key_update_bool = False else: if verbose == True: print "Encrypting new AES key" # If needed, check the new aes key if aes_key_update_bool == True: new_aes_key = array('B', newAesKey.decode("hex")) if len(new_aes_key) != AES_KEY_LENGTH: print "Wrong New AES Key Length:", len(new_aes_key) return False # Convert & check the old aes key old_aes_key = array('B', oldAesKey.decode("hex")) if len(old_aes_key) != AES_KEY_LENGTH: print "Wrong Old AES Key Length:", len(oldAesKey) return False # Get version number for i in range(len(firmware_bin) - 3): if chr(firmware_bin[i]) == 'v' and \ chr(firmware_bin[i + 1]) >= '1' and chr(firmware_bin[i + 1]) <= '9' and \ chr(firmware_bin[i + 2]) == '.' and \ chr(firmware_bin[i + 3]) >= '0' and chr(firmware_bin[i + 3]) <= '9': firmware_version = firmware_bin[i:i+4] if verbose == True: print "Extracted firmware version:", "".join(chr(firmware_version[j]) for j in range(0, 4)) break; # Write it in the last 4 bytes of the firmware hex firmware[FW_MAX_LENGTH-4] = firmware_version[0] firmware[FW_MAX_LENGTH-3] = firmware_version[1] firmware[FW_MAX_LENGTH-2] = firmware_version[2] firmware[FW_MAX_LENGTH-1] = firmware_version[3] # Check if we extracted the firmware version and it has the correct length if firmware_version == None or len(firmware_version) != FW_VERSION_LENGTH: print "Problem while extracting firmware version" return False # If needed, encrypt the new AES key with the old one if aes_key_update_bool == True: cipher = AES.new(old_aes_key, AES.MODE_ECB, array('B',[0]*AES.block_size)) # IV ignored in ECB enc_password = cipher.encrypt(new_aes_key) if len(enc_password) != AES_KEY_LENGTH: print "Encoded password is too long!" return False else: enc_password = [255]*AES_KEY_LENGTH # Generate beginning of update file data: bundle | padding | firmware version | new aes key bool | firmware | padding | new aes key encoded update_file_data = array('B') update_file_data.extend(bytearray(bundle)) update_file_data.extend(array('B',[0]*(STORAGE_SPACE-HASH_LENGH-AES_KEY_LENGTH-FW_MAX_LENGTH-FW_VERSION_LENGTH-AES_KEY_UPDATE_FLAG_LGTH-len(bundle)))) update_file_data.extend(firmware_version) if aes_key_update_bool == True: update_file_data.append(255) else: update_file_data.append(0) update_file_data.extend(firmware.tobinarray()) update_file_data.extend(array('B',[0]*(STORAGE_SPACE-HASH_LENGH-AES_KEY_LENGTH-len(update_file_data)))) update_file_data.extend(bytearray(enc_password)) # Check length if len(update_file_data) != (STORAGE_SPACE - HASH_LENGH): print "Problem with update file length!" return False # Generate CBCMAC, IV is ZEROS cipher = AES.new(old_aes_key, AES.MODE_CBC, array('B',[0]*AES.block_size)) cbc_mac = cipher.encrypt(update_file_data)[-AES.block_size:] # Append it to update file data: bundle | padding | firmware version | new aes key bool | firmware | padding | new aes key encoded | cbcmac update_file_data.extend(bytearray(cbc_mac)) # Check length if len(update_file_data) != STORAGE_SPACE: print "Problem with update file length!" return False # Write our update image file data_fd = open(updateFileName, 'wb') data_fd.write(update_file_data) data_fd.close() if verbose == True: print "Update file written!" return True
mergedHex.merge(ih, overlap='replace') except: print( "Fatal Error: -- FAILED merge due to overlap when merging " + f.name) sys.exit(1) except: print("Fatal Error: -- FAILED parsing input hex file(s)") sys.exit(1) #print information about the input hex files print_args_info(inputFileNames, vargs.out, vargs.outbin, vargs.oadtype, vargs.imgtype, mergedHex) # Cut off / fill with --fill. startAddr = mergedHex.minaddr() endAddr = mergedHex.addresses()[-1] + 1 # Inclusive address if startAddr % vargs.blockSize: print( "Fatal Error: -- Start address 0x%X is not divisible by 16. Exiting" % startAddr) sys.exit(1) if vargs.range is not None: if vargs.range[0] is not None: startAddr = vargs.range[0] if vargs.range[1] is not None: endAddr = vargs.range[1] # Make sure the last address is divisible by the block size remainder = endAddr % vargs.blockSize if remainder:
def get_file_buf(self, filename): fil = open(filename, 'r') hexfile = IntelHex(fil) glog.info('Min addr >> ', hexfile.minaddr()) assert hexfile.minaddr() == 0 return hexfile.tobinstr()