Example #1
0
def _stat_and_start_copy(path, addr, copying_state, copied_state):
    try:
        os.stat(path)
    except OSError:
        log("{} not found", path)
        return False

    log("{} update is available", path)
    if sum(stm.rfcore_fw_version(_FW_VERSION_WS)):
        # There was some WS firmware already installed. Need to remove that
        # before copying to flash (both FUS or WS copy require this).
        log("Removing existing WS firmware")
        _write_state(_STATE_DELETING_WS)
        _fus_fwdelete()
    else:
        log("Copying {} to flash", path)
        # Mark that the flash write has started. Any failure should result in an overall failure.
        _write_state(
            copying_state)  # Either _STATE_COPYING_FUS or _STATE_COPYING_WS
        _copy_file_to_flash(path, addr)
        log("Copying complete")
        # The entire write has completed successfully, start the install.
        _write_state(
            copied_state)  # Either _STATE_COPIED_FUS or _STATE_COPIED_WS

    return True
Example #2
0
def resume():
    log("Checking firmware update progress...")

    if stm.rfcore_status() == _MAGIC_IPCC_MEM_INCORRECT:
        return _write_failure_state(REASON_RFCORE_NOT_CONFIGURED)

    while True:
        state = _read_state()

        if state == _STATE_IDLE:
            log("Firmware update complete")
            return 0

        elif state == _STATE_FAILED:
            log("Firmware update failed")
            return _read_failure_reason()

        # Keep calling GET_STATE until error or FUS.
        elif state == _STATE_WAITING_FOR_FUS:
            log("Querying FUS state")
            status, result = fus_get_state()
            log("FUS state: {} {}", status, result)

            if status == 0xFF and result == 0xFF:
                _write_failure_state(REASON_FUS_NOT_RESPONDING)
            elif status != 0:
                log("Operation in progress. Re-querying FUS state")
            elif stm.rfcore_status() == _MAGIC_FUS_ACTIVE:
                log("FUS active")
                _write_state(_STATE_CHECK_UPDATES)

        # Keep trying to start the WS until !fus_active() (or error).
        elif state == _STATE_WAITING_FOR_WS:
            if stm.rfcore_status() != _MAGIC_FUS_ACTIVE:
                log("WS active")
                _write_state(_STATE_IDLE)
                # Need to force a reset otherwise BLE will fail if FUS has changed.
                machine.reset()
            else:
                log("Starting WS")
                status, result = fus_start_ws()
                if status != 0:
                    log("Can't start WS")
                    log("WS version: {}",
                        stm.rfcore_fw_version(_FW_VERSION_WS))
                    _write_failure_state(REASON_NO_WS)

        # Sequence the FUS 1.0.2 -> FUS 1.1.0 -> WS (depending on what's available).
        elif state == _STATE_CHECK_UPDATES:
            log("Checking for updates")
            fus_version = stm.rfcore_fw_version(_FW_VERSION_FUS)
            log("FUS version {}", fus_version)
            if fus_version < _FUS_VERSION_102:
                log("Factory FUS detected")
                if _stat_and_start_copy(_PATH_FUS_102, _ADDR_FUS,
                                        _STATE_COPYING_FUS, _STATE_COPIED_FUS):
                    continue
            elif fus_version >= _FUS_VERSION_102 and fus_version < _FUS_VERSION_110:
                log("FUS 1.0.2 detected")
                if _stat_and_start_copy(_PATH_FUS_110, _ADDR_FUS,
                                        _STATE_COPYING_FUS, _STATE_COPIED_FUS):
                    continue
            else:
                log("FUS is up-to-date")

            if fus_version >= _FUS_VERSION_110:
                if _stat_and_start_copy(_PATH_WS_BLE_HCI, _ADDR_WS_BLE_HCI,
                                        _STATE_COPYING_WS, _STATE_COPIED_WS):
                    continue
                else:
                    log("No WS updates available")
            else:
                # Don't attempt to install WS if we're running an old FUS.
                log("Need latest FUS to install WS")

            # Attempt to go back to WS.
            # Either this will fail (because WS was removed due to FUS install), or
            # this whole thing was a no-op and we should be fine to restart WS.
            _write_state(_STATE_WAITING_FOR_WS)

        # This shouldn't happen - the flash write should always complete and
        # move straight onto the COPIED state. Failure here indicates that
        # the rfcore is misconfigured or the WS firmware was not deleted first.
        elif state == _STATE_COPYING_FUS or state == _STATE_COPYING_WS:
            log("Flash copy failed mid-write")
            _write_failure_state(REASON_FLASH_COPY_FAILED)

        # Flash write completed, we should immediately see GET_STATE return 0,0
        # so we can start the FUS install.
        elif state == _STATE_COPIED_FUS:
            if fus_is_idle():
                log("FUS copy complete, installing")
                _write_state(_STATE_INSTALLING_FUS)
                _fus_run_fwupgrade(_ADDR_FUS)
            else:
                log("FUS copy bad state")
                _write_failure_state(REASON_FLASH_FUS_BAD_STATE)

        # Keep polling the state until we see a 0,0 (success) or non-transient
        # error. In general we should expect to see (16,0) several times,
        # followed by a (255,0), followed by (0, 0).
        elif state == _STATE_INSTALLING_FUS:
            log("Installing FUS...")
            status, result = fus_get_state(_INSTALLING_FUS_GET_STATE_TIMEOUT)
            log("FUS state: {} {}", status, result)
            if 0x20 <= status <= 0x2F and result == 0:
                # FUS_STATE_FUS_UPGRD_ONGOING
                log("FUS still in progress...")
            elif 0x10 <= status <= 0x1F and result == 0x11:
                # FUS_STATE_FW_UPGRD_ONGOING and FUS_FW_ROLLBACK_ERROR
                # Confusingly this is a "FW_UPGRD" (0x10) not "FUS_UPRD" (0x20).
                log("Attempted to install same FUS version... re-querying FUS state to resume."
                    )
            elif status == 0:
                log("FUS update successful")
                _write_state(_STATE_CHECK_UPDATES)
            elif result == 0:
                # See below (for equivalent path for WS install -- we
                # sometimes see (255,0) right at the end).
                log("Re-querying FUS state...")
            elif result == 0xFF:
                _write_failure_state(REASON_FUS_NOT_RESPONDING_AFTER_FUS)
            else:
                _write_failure_state(REASON_FUS_VENDOR + result)

        # Keep polling the state until we see 0,0 or failure (1,0). Any other
        # result means retry (but the docs say that 0 and 1 are the only
        # status values).
        elif state == _STATE_DELETING_WS:
            log("Deleting WS...")
            status, result = fus_get_state()
            log("FUS state: {} {}", status, result)
            if status == 0:
                if sum(stm.rfcore_fw_version(_FW_VERSION_WS)) == 0:
                    log("WS deletion complete")
                    _write_state(_STATE_CHECK_UPDATES)
                else:
                    log("WS deletion no effect")
                    _write_failure_state(REASON_WS_STILL_PRESENT)
            elif status == 1:
                log("WS deletion failed")
                _write_failure_state(REASON_WS_DELETION_FAILED)

        # As for _STATE_COPIED_FUS above. We should immediately see 0,0.
        elif state == _STATE_COPIED_WS:
            if fus_is_idle():
                log("WS copy complete, installing")
                _write_state(_STATE_INSTALLING_WS)
                _fus_run_fwupgrade(_ADDR_WS_BLE_HCI)
            else:
                log("WS copy bad state")
                _write_failure_state(REASON_FLASH_WS_BAD_STATE)

        # As for _STATE_INSTALLING_FUS above.
        elif state == _STATE_INSTALLING_WS:
            log("Installing WS...")
            status, result = fus_get_state(_INSTALLING_WS_GET_STATE_TIMEOUT)
            log("FUS state: {} {}", status, result)
            if 0x10 <= status <= 0x1F and result == 0:
                # FUS_STATE_FW_UPGRD_ONGOING
                log("WS still in progress...")
            elif 0x10 <= status <= 0x1F and result == 0x11:
                # FUS_FW_ROLLBACK_ERROR
                log("Attempted to install same WS version... re-querying FUS state to resume."
                    )
            elif status == 0:
                log("WS update successful")
                _write_state(_STATE_WAITING_FOR_WS)
            elif result in (0, 0xFE):
                # We get an error response with no payload sometimes at the end
                # of the update (this is not in AN5185). Additionally during
                # WS update, newer WS reports (status, result) of (255, 254)
                # before eventually reporting the correct state of
                # _STATE_INSTALLING_WS once again. In these cases, re-try the
                # GET_STATE.
                # The same thing happens transitioning from WS to FUS mode.
                # The actual HCI response has no payload, the result=0 comes from
                # _parse_vendor_response above when len=7.
                log("Re-querying FUS state...")
            elif result == 0xFF:
                # This is specifically a failure sending the HCI command.
                _write_failure_state(REASON_FUS_NOT_RESPONDING_AFTER_WS)
            else:
                _write_failure_state(REASON_WS_VENDOR + result)