def convert_ihex_syx(source, byte_width: int = 32) -> bytearray: ihex = IntelHex(source) syx = bytearray() # HEADER syx.extend(reset_bytes()) syx.extend(b'\x00\x51') # id syx.extend(b'\x00' + ihex.gets(ihex.minaddr() + 0x102, 1)) syx.extend(b'\x00' + ihex.gets(ihex.minaddr() + 0x101, 1)) syx.extend(b'\x00' + ihex.gets(ihex.minaddr() + 0x100, 1)) syx.append(0xF7) # PAYLOAD for i in range(ihex.minaddr() + byte_width, ihex.maxaddr(), byte_width): syx.extend(reset_bytes(eol=b'\x72')) syx.extend(block(ihex, i, byte_width)) syx.append(0xF7) syx.extend(reset_bytes(eol=b'\x73')) syx.extend(block(ihex, ihex.minaddr(), byte_width)) syx.append(0xF7) # CHECKSUM syx.extend(reset_bytes(eol=b'\x76')) syx.extend(b'\x00' + b'Firmware') syx.extend(b'\x00\x00\x00\x00\x00\x00\x00\x00') syx.append(0xF7) return syx
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 load_hexfile(self, hexfile: str) -> None: ih = IntelHex() ih.loadhex(hexfile) for (beg, end) in ih.segments(): try: mem = bytes(ih.gets(beg, end - beg)) self.emu.mem_write(beg, mem) except: print('Error loading %s at 0x%08x (%d bytes):' % (hexfile, beg, len(mem))) raise
def _main(): """Append credentials to a prebuilt hex file, download it via a J-Link debug probe, allow the hex file to run, verify the result code, and then erase the hex file. """ args = _add_and_parse_args() nrfjprog_api = None nrfjprog_probe = None try: hex_path = HEX_PATH if args.in_file: hex_path = args.in_file intel_hex = IntelHex(hex_path) if intel_hex.maxaddr() >= CRED_PAGE_ADDR: if hex_path == HEX_PATH: print("error: Prebuilt hex file is too large.") _close_and_exit(nrfjprog_api, -3) elif (intel_hex.maxaddr() < FW_RESULT_CODE_ADDR or intel_hex.gets(CRED_PAGE_ADDR, 4) != MAGIC_NUMBER_BYTES): print("error: Magic number not found in hex file.") _close_and_exit(nrfjprog_api, -2) else: intel_hex.puts(CRED_PAGE_ADDR, MAGIC_NUMBER_BYTES) intel_hex.puts(CRED_COUNT_ADDR, struct.pack('B', 0x00)) if not args.out_file or args.program_app: nrfjprog_api, nrfjprog_probe = _connect_to_jlink(args) _append_creds(intel_hex, args) if args.out_file: intel_hex.tofile(args.out_file, "hex") else: # Create a temporary file to pass to pynrfjprog and then delete it when finished. tmp_file = os.path.sep.join((tempfile.mkdtemp(), TMP_FILE_NAME)) intel_hex.tofile(tmp_file, "hex") _write_firmware(nrfjprog_probe, tmp_file) time.sleep(args.fw_delay) result_code = nrfjprog_probe.read(FW_RESULT_CODE_ADDR) if result_code: print("error: Firmware result is 0x{:X}".format(result_code)) _close_and_exit(nrfjprog_api, -4) imei_bytes = nrfjprog_probe.read(IMEI_ADDR, IMEI_LEN + 1) if (IMEI_LEN != imei_bytes.find(BLANK_FLASH_VALUE) or not imei_bytes[:IMEI_LEN].isdigit()): print("error: IMEI does not look valid.") _close_and_exit(nrfjprog_api, -5) print(imei_bytes[:-1].decode()) nrfjprog_probe.erase(HighLevel.EraseAction.ERASE_ALL) os.remove(tmp_file) os.removedirs(os.path.dirname(tmp_file)) if args.program_app: _write_firmware(nrfjprog_probe, args.program_app) _close_and_exit(nrfjprog_api, 0) except Exception as ex: print("error: " + str(ex)) _close_and_exit(nrfjprog_api, -2)
def load_hexfile(self, hexfile: str) -> None: ih = IntelHex() ih.loadhex(hexfile) beg = ih.minaddr() end = ih.maxaddr() + 1 mem = bytes(ih.gets(beg, end - beg)) try: self.emu.mem_write(beg, mem) except: print('Error loading %s at 0x%08x (%d bytes):' % (hexfile, beg, len(mem))) raise
def from_eep_file(cls, eep_file_name): """Create an ErrorLog instance with the content from the EEPROM-file.""" hex_file = IntelHex() hex_file.fromfile(eep_file_name, format='hex') log = cls() for addr in range(ErrorLog._START_ADDRESS, ErrorLog._END_ADDRESS, ErrorMessage.size()): data = hex_file.gets(addr, ErrorMessage.size()) error_message = ErrorMessage.from_bytes(data) if error_message: log.append(error_message) return log
def _load_segment(self, hex_file: IntelHex, segment): start_addr, end_addr = segment segment_load_address = start_addr - hex_file.minaddr() self.apdu_secure_exchange(LedgerSecureIns.SET_LOAD_OFFSET, struct.pack(">I", segment_load_address)) load_size = end_addr - start_addr # max_load_size = 0xf0 - LOAD_SEGMENT_CHUNK_HEADER_LENGTH - MIN_PADDING_LENGTH - SCP_MAC_LENGTH max_load_size = 0x80 load_address = start_addr while load_size > 0: chunk_size = min(load_size, max_load_size) data = hex_file.gets(load_address, chunk_size) data = struct.pack(">H", load_address - start_addr) + data self.apdu_secure_exchange(LedgerSecureIns.LOAD, data) load_address += chunk_size load_size -= chunk_size
def from_eep_file(cls, eep_file_name): """Create an Config instance with data from an EEPROM-file.""" hex_file = IntelHex() hex_file.fromfile(eep_file_name, format='hex') data = hex_file.gets(Config.START_ADDRESS, Config.size()) parameters = struct.unpack(Config._FMT_CRC, data) stored_crc = parameters[-1] # Remove the two last bytes to exclude the stored CRC value from the # CRC calculation. calculated_crc = Config.calculate_crc(data[:-2]) if stored_crc != calculated_crc: raise ConfigCrcException('CRC mismatch') # Remove last element with the stored CRC since it's only used for # validation. return cls(*parameters[:-1])
def load_state(filename): reg_regex = re.compile(r"^([^=]{2,4})=0x([0-9a-f]+)$") with open(filename, "r") as file: reg_vals = {} for _ in uc_reg_consts: line = file.readline() name, val_str = reg_regex.match(line).groups() val = int(val_str, 16) reg_vals[name] = val mem_segments = {} ih = IntelHex(file) for addr, end in ih.segments(): contents = ih.gets(addr, end - addr) mem_segments[addr] = contents return reg_vals, mem_segments
def read_from_file(file_path): if file_path.lower().endswith('.hex'): try: from intelhex import IntelHex except ImportError: print( 'To open HEX files install IntelHex library:\npip install IntelHex\npip3 install IntelHex' ) sys.exit(3) ih = IntelHex() ih.loadhex(file_path) logging.info('Was readed 0x{0:X} ({0}) byte(s): 0x{1:X}..{2:X}'.format( ih.maxaddr() - ih.minaddr() + 1, ih.minaddr(), ih.maxaddr())) return bytearray(ih.gets(ih.minaddr(), ih.maxaddr() - ih.minaddr() + 1)) logging.info('Read from binary file "{0}"'.format(file_path)) f = BinFormat() f.read(file_path) logging.info('Was readed 0x{0:X} ({0}) byte(s)'.format(len(f.data))) return f.data
class Flash(): def __init__(self, link, flash_type, sbp_version, max_queued_ops=1): """ Object representing either of the two flashes (STM/M25) on the Piksi, including methods to erase, program, and read. Parameters ---------- link : sbp.client.handler.Handler Handler to send messages to Piksi over and register callbacks with. flash_type : string Which Piksi flash to interact with ("M25" or "STM"). sbp_version : (int, int) SBP protocol version, used to select messages to send. max_queued_ops : int Maximum number of Flash read/program operations to queue in device flash. (0.5 * ADDRS_PER_OP + SBP packet overhead) * max_queued_ops is how much of the device UART RX buffer will be filled by the program/read callback messages. A higher value will significantly speed up flashing, but can result in RX buffer overflows in other UARTs if the device is receiving data on other UARTs. Returns ------- out : Flash instance """ self._n_queued_ops = 0 self.max_queued_ops = max_queued_ops self.nqo_lock = Lock() self.stopped = False self.status = '' self.link = link self.flash_type = flash_type self.sbp_version = sbp_version # IntelHex object to store read flash data in that was read from device. self._read_callback_ihx = IntelHex() self.link.add_callback(self._done_callback, SBP_MSG_FLASH_DONE) self.link.add_callback(self._read_callback, SBP_MSG_FLASH_READ_RESP) self.ihx_elapsed_ops = 0 # N operations finished in self.write_ihx if self.flash_type == "STM": self.flash_type_byte = 0 self.addr_sector_map = stm_addr_sector_map # Add STM-specific functions. self.__dict__['lock_sector'] = \ new.instancemethod(_stm_lock_sector, self, Flash) self.__dict__['unlock_sector'] = \ new.instancemethod(_stm_unlock_sector, self, Flash) self.n_sectors = STM_N_SECTORS self.restricted_sectors = STM_RESTRICTED_SECTORS elif self.flash_type == "M25": self.flash_type_byte = 1 self.addr_sector_map = m25_addr_sector_map # Add M25-specific functions. self.__dict__['write_status'] = \ new.instancemethod(_m25_write_status, self, Flash) self.n_sectors = M25_N_SECTORS self.restricted_sectors = M25_RESTRICTED_SECTORS else: raise ValueError("flash_type must be \"STM\" or \"M25\", got \"%s\"" \ % flash_type) def __enter__(self): return self def __exit__(self, type, value, traceback): """ Calls self.stop() before instance is deleted. """ if not self.stopped: self.stop() def ihx_n_ops(self, ihx, erase=True): """ Find the number of sent SBP messages (erase, program, read) self.write_ihx will require to write a particular intelhex.IntelHex for this instance's flash type. Parameters ---------- ihx : intelhex.Intelhex intelhex.IntelHex to be written. erase : bool Include number of erase operations required in total. Returns ------- out : int Number of sent SBP messages (erase, program, read) self.write_ihx will require to write ihx. """ return ihx_n_ops(ihx, self.addr_sector_map, erase) def inc_n_queued_ops(self): """ Increment the count of queued flash operation SBP messages in the STM's flash in a thread safe way. """ self.nqo_lock.acquire() self._n_queued_ops += 1 self.nqo_lock.release() def dec_n_queued_ops(self): """ Decrement the count of queued flash operation SBP messages in the STM's flash in a thread safe way. """ self.nqo_lock.acquire() self._n_queued_ops -= 1 self.nqo_lock.release() def get_n_queued_ops(self): """ Get the current count of queued flash operation SBP messages. Returns ------- out : int Get the current count of queued flash operation SBP messages. """ return self._n_queued_ops def stop(self): """ Remove instance callbacks from sbp.client.handler.Handler. """ self.stopped = True self.link.remove_callback(self._done_callback, SBP_MSG_FLASH_DONE) self.link.remove_callback(self._read_callback, SBP_MSG_FLASH_READ_RESP) def __str__(self): """ Return flashing status. """ return self.status def erase_sector(self, sector, warn=True): """ Erase a sector of the flash. Parameters ---------- sector : int Sector to be erased. warn : bool Warn if sector is restricted and should most likely not be erased. """ if warn and sector in self.restricted_sectors: text = 'Attempting to erase %s flash restricted sector %d' % \ (self.flash_type, sector) raise Warning(text) msg_buf = struct.pack("BB", self.flash_type_byte, sector) self.inc_n_queued_ops() self.link(MsgFlashErase(target=self.flash_type_byte, sector_num=sector)) while self.get_n_queued_ops() > 0: time.sleep(0.001) def program(self, address, data): """ Program a set of addresses of the flash. Parameters ---------- address : int Starting address of set of addresses to program with data. data : string String of bytes to program to flash starting at address. """ msg_buf = struct.pack("B", self.flash_type_byte) msg_buf += struct.pack("<I", address) msg_buf += struct.pack("B", len(data)) self.inc_n_queued_ops() # < 0.45 of SBP protocol, reuse single flash message. if self.sbp_version < (0, 45): self.link(SBP(SBP_MSG_FLASH_DONE, payload=msg_buf + data)) else: self.link( MsgFlashProgram(target=self.flash_type_byte, addr_start=address, addr_len=len(data), data=data)) def read(self, address, length, block=False): """ Read a set of addresses of the flash. Parameters ---------- address : int Starting address of length addresses to read. length : int Number of addresses to read. block : bool Block until addresses are read and return them. Returns ======= out : str String of bytes (big endian) read from address. """ msg_buf = struct.pack("B", self.flash_type_byte) msg_buf += struct.pack("<I", address) msg_buf += struct.pack("B", length) self.inc_n_queued_ops() # < 0.45 of SBP protocol, reuse single read message. if self.sbp_version < (0, 45): self.link(SBP(SBP_MSG_FLASH_READ_RESP, payload=msg_buf)) else: self.link( MsgFlashReadReq(target=self.flash_type_byte, addr_start=address, addr_len=length)) if block: while self.get_n_queued_ops() > 0: time.sleep(0.001) return self._read_callback_ihx.gets(address, length) def _done_callback(self, sbp_msg, **metadata): """ Handles flash done message sent from device. Parameters ---------- data : string Binary data sent from device. """ ret = ord(sbp_msg.payload) if (ret != 0): print(("Flash operation returned error (%d)" % ret)) self.dec_n_queued_ops() assert self.get_n_queued_ops() >= 0, \ "Number of queued flash operations is negative" def _read_callback(self, sbp_msg, **metadata): """ Handles flash read message sent from device. Parameters ---------- data : string Binary data sent from device. """ # 4 bytes addr, 1 byte length, length bytes data address = struct.unpack('<I', sbp_msg.payload[0:4])[0] length = struct.unpack('B', sbp_msg.payload[4])[0] self._read_callback_ihx.puts(address, sbp_msg.payload[5:]) self.dec_n_queued_ops() assert self.get_n_queued_ops() >= 0, \ "Number of queued flash operations is negative" def write_ihx(self, ihx, stream=None, mod_print=0, elapsed_ops_cb=None, erase=True): """ Perform all operations to write an intelhex.IntelHex to the flash and verify. Parameters ---------- ihx : intelhex.IntelHex intelhex.IntelHex to write to the flash. stream : stream Object implementing write and flush methods to write status updates to. mod_print : int How many loops to run through before writing to stream. elapsed_ops_cb : function Callback to execute every mod_print loops. erase : bool Erase sectors before writing. """ self.ihx_elapsed_ops = 0 self.print_count = 0 start_time = time.time() ihx_addrs = ihx_ranges(ihx) # Erase sectors if erase: for sector in sectors_used(ihx_addrs, self.addr_sector_map): self.status = self.flash_type + " Flash: Erasing sector %d" % sector if stream: stream.write('\r' + self.status) stream.flush() self.erase_sector(sector) self.ihx_elapsed_ops += 1 if elapsed_ops_cb != None: elapsed_ops_cb(self.ihx_elapsed_ops) if stream: stream.write('\n') # Write data to flash and read back to later validate. STM's lowest address # is used by bootloader to check that the application is valid, so program # from high to low to ensure this address is programmed last. for start, end in reversed(ihx_addrs): for addr in reversed(list(range(start, end, ADDRS_PER_OP))): self.status = self.flash_type + " Flash: Programming address" + \ " 0x%08X" % addr if mod_print == 0 or mod_print != 0 and self.print_count % mod_print == 0: if stream: stream.write('\r' + self.status) stream.flush() self.print_count = 1 if elapsed_ops_cb != None: elapsed_ops_cb(self.ihx_elapsed_ops) else: self.print_count += 1 binary = ihx.tobinstr(start=addr, size=ADDRS_PER_OP) # Program ADDRS_PER_OP addresses while self.get_n_queued_ops() >= self.max_queued_ops: time.sleep(0.001) self.program(addr, binary) self.ihx_elapsed_ops += 1 # Read ADDRS_PER_OP addresses while self.get_n_queued_ops() >= self.max_queued_ops: time.sleep(0.001) self.read(addr, ADDRS_PER_OP) self.ihx_elapsed_ops += 1 # Verify that data written to flash matches data read from flash. while self.get_n_queued_ops() > 0: time.sleep(0.001) for start, end in reversed(ihx_addrs): if self._read_callback_ihx.gets(start, end-start+1) != \ ihx.gets(start, end-start+1): for i in range(start, end): r = self._read_callback_ihx.gets(i, 1) p = ihx.gets(i, 1) if r != p: raise Exception( 'Data read from flash != Data programmed to flash' ( 'Addr: %x, Programmed: %x, Read: %x' % (i, r, p)).upper()) self.status = self.flash_type + " Flash: Successfully programmed and " + \ "verified, total time = %d seconds" % \ int(time.time()-start_time) if stream: stream.write('\n\r' + self.status + '\n')
INT_FL_OAD_IMG_A_META_BEGIN + 15))) else: residentHdr = OadHdr._make( struct.unpack(OAD_HDR_FMT, mergedHex.tobinstr(startAddr, startAddr + 15))) metaAddr = vargs.meta if metaAddr is None: # Try first address, ideally there should be free space at the beginning of the image #in the reserved image metadata sector #if onchip production image, we must start at imgA start with is 0x600 if vargs.oadtype == 'onchip' and vargs.imgtype == 'production': attemptedMetaStart = INT_FL_OAD_IMG_A_META_BEGIN else: attemptedMetaStart = mergedHex.minaddr() beginning = mergedHex.gets(attemptedMetaStart, OAD_METADATA_SIZE) blank16 = struct.pack('B', 0xff) * OAD_METADATA_SIZE if beginning == blank16: metaAddr = attemptedMetaStart print( "Found free area at start of address range, metalocation: 0x%08X" % metaAddr) else: # there are two cases to be checked by this else: # 1.Is there already metadata embedded in the image # - we verify this by checking if imgLen <= actual size and if crc == crc # 2.There is no metadata in the image, and no metadata addr is specified # - We will look to see if there room for metadata based on start addr # - remember that for current on OAD solution metadata must reside
# Place metadata, onchip production image expects header at 0x600 if vargs.oadtype == 'onchip' and vargs.imgtype == 'production': residentHdr = OadHdr._make(struct.unpack(OAD_HDR_FMT, mergedHex.tobinstr(INT_FL_OAD_IMG_A_META_BEGIN, INT_FL_OAD_IMG_A_META_BEGIN+15))) else: residentHdr = OadHdr._make(struct.unpack(OAD_HDR_FMT, mergedHex.tobinstr(startAddr, startAddr+15))) metaAddr = vargs.meta if metaAddr is None: # Try first address, ideally there should be free space at the beginning of the image #in the reserved image metadata sector #if onchip production image, we must start at imgA start with is 0x600 if vargs.oadtype == 'onchip' and vargs.imgtype == 'production': attemptedMetaStart = INT_FL_OAD_IMG_A_META_BEGIN else: attemptedMetaStart = mergedHex.minaddr() beginning = mergedHex.gets(attemptedMetaStart, OAD_METADATA_SIZE) blank16 = struct.pack('B', 0xff)*OAD_METADATA_SIZE if beginning == blank16: metaAddr = attemptedMetaStart print ("Found free area at start of address range, metalocation: 0x%08X" % metaAddr) else: # there are two cases to be checked by this else: # 1.Is there already metadata embedded in the image # - we verify this by checking if imgLen <= actual size and if crc == crc # 2.There is no metadata in the image, and no metadata addr is specified # - We will look to see if there room for metadata based on start addr # - remember that for current on OAD solution metadata must reside # - in one of two places defined by EXT_FL_OAD_META_BEGIN, INT_FL_OAD_META_BEGIN
class Flash(): def __init__(self, link, flash_type, sbp_version): """ Object representing either of the two flashes (STM/M25) on the Piksi, including methods to erase, program, and read. Parameters ---------- link : sbp.client.handler.Handler Handler to send messages to Piksi over and register callbacks with. flash_type : string Which Piksi flash to interact with ("M25" or "STM"). sbp_version : (int, int) SBP protocol version, used to select messages to send. Returns ------- out : Flash instance """ self._n_queued_ops = 0 self.nqo_lock = Lock() self.stopped = False self.status = '' self.link = link self.flash_type = flash_type self.sbp_version = sbp_version # IntelHex object to store read flash data in that was read from device. self._read_callback_ihx = IntelHex() self.link.add_callback(self._done_callback, SBP_MSG_FLASH_DONE) self.link.add_callback(self._read_callback, SBP_MSG_FLASH_READ_DEVICE) self.ihx_elapsed_ops = 0 # N operations finished in self.write_ihx if self.flash_type == "STM": self.flash_type_byte = 0 self.addr_sector_map = stm_addr_sector_map # Add STM-specific functions. self.__dict__['lock_sector'] = \ new.instancemethod(_stm_lock_sector, self, Flash) self.__dict__['unlock_sector'] = \ new.instancemethod(_stm_unlock_sector, self, Flash) self.n_sectors = STM_N_SECTORS self.restricted_sectors = STM_RESTRICTED_SECTORS elif self.flash_type == "M25": self.flash_type_byte = 1 self.addr_sector_map = m25_addr_sector_map # Add M25-specific functions. self.__dict__['write_status'] = \ new.instancemethod(_m25_write_status, self, Flash) self.n_sectors = M25_N_SECTORS self.restricted_sectors = M25_RESTRICTED_SECTORS else: raise ValueError("flash_type must be \"STM\" or \"M25\", got \"%s\"" \ % flash_type) def __enter__(self): return self def __exit__(self, type, value, traceback): """ Calls self.stop() before instance is deleted. """ if not self.stopped: self.stop() def ihx_n_ops(self, ihx, erase=True): """ Find the number of sent SBP messages (erase, program, read) self.write_ihx will require to write a particular intelhex.IntelHex for this instance's flash type. Parameters ---------- ihx : intelhex.Intelhex intelhex.IntelHex to be written. erase : bool Include number of erase operations required in total. Returns ------- out : int Number of sent SBP messages (erase, program, read) self.write_ihx will require to write ihx. """ return ihx_n_ops(ihx, self.addr_sector_map, erase) def inc_n_queued_ops(self): """ Increment the count of queued flash operation SBP messages in the STM's flash in a thread safe way. """ self.nqo_lock.acquire() self._n_queued_ops += 1 self.nqo_lock.release() def dec_n_queued_ops(self): """ Decrement the count of queued flash operation SBP messages in the STM's flash in a thread safe way. """ self.nqo_lock.acquire() self._n_queued_ops -= 1 self.nqo_lock.release() def get_n_queued_ops(self): """ Get the current count of queued flash operation SBP messages. Returns ------- out : int Get the current count of queued flash operation SBP messages. """ return self._n_queued_ops def stop(self): """ Remove instance callbacks from sbp.client.handler.Handler. """ self.stopped = True self.link.remove_callback(self._done_callback, SBP_MSG_FLASH_DONE) self.link.remove_callback(self._read_callback, SBP_MSG_FLASH_READ_DEVICE) def __str__(self): """ Return flashing status. """ return self.status def erase_sector(self, sector, warn=True): """ Erase a sector of the flash. Parameters ---------- sector : int Sector to be erased. warn : bool Warn if sector is restricted and should most likely not be erased. """ if warn and sector in self.restricted_sectors: text = 'Attempting to erase %s flash restricted sector %d' % \ (self.flash_type, sector) raise Warning(text) msg_buf = struct.pack("BB", self.flash_type_byte, sector) self.inc_n_queued_ops() self.link.send(SBP_MSG_FLASH_ERASE, msg_buf) while self.get_n_queued_ops() > 0: time.sleep(0.001) def program(self, address, data): """ Program a set of addresses of the flash. Parameters ---------- address : int Starting address of set of addresses to program with data. data : string String of bytes to program to flash starting at address. """ msg_buf = struct.pack("B", self.flash_type_byte) msg_buf += struct.pack("<I", address) msg_buf += struct.pack("B", len(data)) self.inc_n_queued_ops() # < 0.45 of SBP protocol, reuse single flash message. if self.sbp_version < (0, 45): self.link.send(SBP_MSG_FLASH_DONE, msg_buf + data) else: self.link.send(SBP_MSG_FLASH_PROGRAM, msg_buf + data) def read(self, address, length): """ Read a set of addresses of the flash. Parameters ---------- address : int Starting address of length addresses to read. length : int Number of addresses to read. """ msg_buf = struct.pack("B", self.flash_type_byte) msg_buf += struct.pack("<I", address) msg_buf += struct.pack("B", length) self.inc_n_queued_ops() # < 0.45 of SBP protocol, reuse single read message. if self.sbp_version < (0, 45): self.link.send(SBP_MSG_FLASH_READ_DEVICE, msg_buf) else: self.link.send(SBP_MSG_FLASH_READ_HOST, msg_buf) def _done_callback(self, sbp_msg): """ Handles flash done message sent from device. Parameters ---------- data : string Binary data sent from device. """ ret = ord(sbp_msg.payload) if (ret != 0): print "Flash operation returned error (%d)" % ret self.dec_n_queued_ops() assert self.get_n_queued_ops() >= 0, \ "Number of queued flash operations is negative" def _read_callback(self, sbp_msg): """ Handles flash read message sent from device. Parameters ---------- data : string Binary data sent from device. """ # 4 bytes addr, 1 byte length, length bytes data address = struct.unpack('<I', sbp_msg.payload[0:4])[0] length = struct.unpack('B', sbp_msg.payload[4])[0] self._read_callback_ihx.puts(address, sbp_msg.payload[5:]) self.dec_n_queued_ops() assert self.get_n_queued_ops() >= 0, \ "Number of queued flash operations is negative" def write_ihx(self, ihx, stream=None, mod_print=0, elapsed_ops_cb=None, erase=True): """ Perform all operations to write an intelhex.IntelHex to the flash and verify. Parameters ---------- ihx : intelhex.IntelHex intelhex.IntelHex to write to the flash. stream : stream Object implementing write and flush methods to write status updates to. mod_print : int How many loops to run through before writing to stream. elapsed_ops_cb : function Callback to execute every mod_print loops. erase : bool Erase sectors before writing. """ self.ihx_elapsed_ops = 0 self.print_count = 0 start_time = time.time() ihx_addrs = ihx_ranges(ihx) # Erase sectors if erase: for sector in sectors_used(ihx_addrs, self.addr_sector_map): self.status = self.flash_type + " Flash: Erasing sector %d" % sector if stream: stream.write('\r' + self.status) stream.flush() self.erase_sector(sector) self.ihx_elapsed_ops += 1 if elapsed_ops_cb != None: elapsed_ops_cb(self.ihx_elapsed_ops) if stream: stream.write('\n') # Write data to flash and read back to later validate. STM's lowest address # is used by bootloader to check that the application is valid, so program # from high to low to ensure this address is programmed last. for start, end in reversed(ihx_addrs): for addr in reversed(range(start, end, ADDRS_PER_OP)): self.status = self.flash_type + " Flash: Programming address" + \ " 0x%08X" % addr if mod_print == 0 or mod_print != 0 and self.print_count % mod_print == 0: if stream: stream.write('\r' + self.status) stream.flush() self.print_count = 1 if elapsed_ops_cb != None: elapsed_ops_cb(self.ihx_elapsed_ops) else: self.print_count += 1 binary = ihx.tobinstr(start=addr, size=ADDRS_PER_OP) # Program ADDRS_PER_OP addresses while self.get_n_queued_ops() >= MAX_QUEUED_OPS: time.sleep(0.001) self.program(addr, binary) self.ihx_elapsed_ops += 1 # Read ADDRS_PER_OP addresses while self.get_n_queued_ops() >= MAX_QUEUED_OPS: time.sleep(0.001) self.read(addr, ADDRS_PER_OP) self.ihx_elapsed_ops += 1 # Verify that data written to flash matches data read from flash. while self.get_n_queued_ops() > 0: time.sleep(0.001) for start, end in reversed(ihx_addrs): if self._read_callback_ihx.gets(start, end-start+1) != \ ihx.gets(start, end-start+1): for i in range(start, end): r = self._read_callback_ihx.gets(i,1) p = ihx.gets(i,1) if r != p: raise Exception('Data read from flash != Data programmed to flash' ('Addr: %x, Programmed: %x, Read: %x' % (i,r,p)).upper()) self.status = self.flash_type + " Flash: Successfully programmed and " + \ "verified, total time = %d seconds" % \ int(time.time()-start_time) if stream: stream.write('\n\r' + self.status + '\n')
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)) # done build.write_hex_file(build_filename)
"Last address was 0x%0X. Expanded to 0x%0X to be divisible by OAD block size" % (endAddr, endAddr + (vargs.blockSize - remainder))) endAddr += vargs.blockSize - remainder #if specified, the script will pad the image with the pad value fillHex = IntelHex() fillHex.puts(startAddr, struct.pack('B', vargs.fill) * (endAddr)) mergedHex.merge(fillHex, 'ignore') mergedHex = mergedHex[ startAddr:endAddr] # +1 since the last address is not inclusive mergedHex.padding = vargs.fill # User provided metadata location # Test that this location is free within the image blankMeta = struct.pack('B', 0xff) * OAD_METADATA_SIZE if vargs.meta in mergedHex.addresses(): currentMeta = mergedHex.gets(vargs.meta, OAD_METADATA_SIZE) else: currentMeta = blankMeta # Check to ensure there is no useful application data at the meta address if currentMeta == blankMeta: metaAddr = vargs.meta print("Placing metadata at 0x%08X" % metaAddr) startAddr = metaAddr else: print( "Fatal Error: -- The provided metadata location (0x%08X) is not empty. Exiting." % vargs.meta) sys.exit(1) # Calculate metadata if vargs.oadtype == 'onchip' and vargs.imgtype == 'production':
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)) # done build.write_hex_file(build_filename)