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
Example #2
0
    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
Example #3
0
    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
Example #4
0
 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
Example #5
0
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)
Example #6
0
 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
Example #7
0
    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
Example #8
0
    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
Example #9
0
    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])
Example #10
0
def load_state(filename):
    reg_regex = re.compile(r"^([^=]{2,4})=0x([0-9a-f]+)$")

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

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

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

        return reg_vals, mem_segments
Example #11
0
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
Example #12
0
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')
Example #13
0
                                       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
Example #14
0
        # 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
Example #15
0
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')
Example #16
0
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)
Example #17
0
            "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':
Example #18
0
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)