2020-09-29 04:37:45 -04:00
|
|
|
# This file is part of the MicroPython project, http://micropython.org/
|
|
|
|
#
|
|
|
|
# The MIT License (MIT)
|
|
|
|
#
|
|
|
|
# Copyright (c) 2020 Damien P. George
|
|
|
|
# Copyright (c) 2020 Jim Mussared
|
|
|
|
#
|
|
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
|
|
# in the Software without restriction, including without limitation the rights
|
|
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
|
|
# furnished to do so, subject to the following conditions:
|
|
|
|
#
|
|
|
|
# The above copyright notice and this permission notice shall be included in
|
|
|
|
# all copies or substantial portions of the Software.
|
|
|
|
#
|
|
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
# THE SOFTWARE.
|
|
|
|
|
|
|
|
# This script provides helpers for working with the FUS/WS firmware on the WB55.
|
|
|
|
# It can be frozen into the MicroPython firmware (via manifest.py)
|
|
|
|
#
|
|
|
|
# The current FUS and WS firmware version and state can be queried via the
|
|
|
|
# `stm` module, e.g.
|
|
|
|
# stm.rfcore_status() (returns the first word of the device info table)
|
|
|
|
# stm.rfcore_fw_version(id) (returns a 5-tuple indicating fw version; id is: 0=FUS, 1=WS)
|
|
|
|
# stm.rfcore_sys_hci(ogf, ocf, cmd_buf) (synchronously execute HCI command on SYS channel)
|
|
|
|
#
|
|
|
|
# To perform a firmware update:
|
|
|
|
#
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
# 1. Generate "obfuscated" binary images using rfcore_makefirmware.py, eg.
|
|
|
|
# $ python3 ./boards/NUCLEO_WB55/rfcore_makefirmware.py ~/src/github.com/STMicroelectronics/STM32CubeWB/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x/ /tmp
|
2020-09-29 04:37:45 -04:00
|
|
|
# This will generate /tmp/{fus_102,fus_110,ws_ble_hci}.bin
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
# It may warn that stm32wb5x_FUS_fw_1_0_2.bin cannot be found, newer packs don't include this
|
|
|
|
# which can be ignored unless your currently flashed FUS is older than 1.0.2
|
2020-09-29 04:37:45 -04:00
|
|
|
#
|
|
|
|
# 2. Copy required files to the device filesystem.
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
# $ mpremote cp /tmp/fus_102.bin :
|
|
|
|
# $ mpremote cp /tmp/fus_110.bin :
|
|
|
|
# $ mpremote cp /tmp/ws_ble_hci.bin :
|
|
|
|
# $ mpremote cp ./boards/NUCLEO_WB55/rfcore_firmware.py :
|
|
|
|
# In general, it's always safe to copy all three files and the updater will
|
|
|
|
# figure out what needs to be done. This is the recommended option.
|
|
|
|
# However, if you already have the latest FUS (1.1.0) installed, then just the
|
|
|
|
# WS firmware is required.
|
|
|
|
# If a FUS binary is present, then the existing WS will be removed so it's a good
|
|
|
|
# idea to always include the WS binary if updating FUS.
|
|
|
|
# Note that a WS binary will not be installed unless FUS 1.1.0 is installed.
|
2020-09-29 04:37:45 -04:00
|
|
|
#
|
|
|
|
# 3. Ensure boot.py calls `rfcore_firmware.resume()`.
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
# $ mpremote exec "import rfcore_firmware; rfcore_firmware.install_boot()"
|
|
|
|
# The WB55 will reset several times during the firmware update process, so this
|
|
|
|
# script manages the update state using RTC backup registers.
|
|
|
|
# `rfcore_firmware.resume()` will continue the update operation on startup to
|
|
|
|
# resume any in-progress update operation, and either trigger another reset, or
|
|
|
|
# return 0 to indicate that the operation completed successfully, or a reason
|
|
|
|
# code (see REASON_* below) to indicate failure.
|
2020-09-29 04:37:45 -04:00
|
|
|
#
|
|
|
|
# 4. Call rfcore_firmware.check_for_updates() to start the update process.
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
# $ mpremote exec "import rfcore_firmware; rfcore_firmware.check_for_updates()"
|
|
|
|
# The device will then immediately reboot and when the firmware update completes,
|
|
|
|
# the status will be returned from rfcore_firmware.resume(). See the REASON_ codes below.
|
|
|
|
# You can use the built-in stm.rfcore_fw_version() to query the installed version
|
|
|
|
# from your application code.
|
2020-09-29 04:37:45 -04:00
|
|
|
|
|
|
|
import struct, os
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
|
|
|
|
try:
|
|
|
|
import machine, stm
|
|
|
|
from ubinascii import crc32
|
|
|
|
from micropython import const
|
|
|
|
except ImportError:
|
|
|
|
# cpython
|
|
|
|
from binascii import crc32
|
|
|
|
|
|
|
|
machine = stm = None
|
|
|
|
const = lambda x: x
|
|
|
|
|
2020-09-29 04:37:45 -04:00
|
|
|
|
|
|
|
_OGF_VENDOR = const(0x3F)
|
|
|
|
|
|
|
|
_OCF_FUS_GET_STATE = const(0x52)
|
|
|
|
_OCF_FUS_FW_UPGRADE = const(0x54)
|
|
|
|
_OCF_FUS_FW_DELETE = const(0x55)
|
|
|
|
_OCF_FUS_START_WS = const(0x5A)
|
|
|
|
_OCF_BLE_INIT = const(0x66)
|
|
|
|
|
|
|
|
_HCI_KIND_VENDOR_RESPONSE = const(0x11)
|
|
|
|
|
|
|
|
|
|
|
|
# The firmware updater will search all of flash for the image to install, so
|
|
|
|
# it's important that the file doesn't exist anywhere on the filesystem and
|
|
|
|
# that the updater only finds the version that we copy into the reserved area.
|
|
|
|
# Otherwise it will find matching headers/footers in the flash filesystem and
|
|
|
|
# get confused leading to either "FUS_STATE_IMG_NOT_AUTHENTIC" or (worse)
|
|
|
|
# corrupting the FUS.
|
|
|
|
# See footnote [1] referenced by Table 9 in AN5185 - Rev 4 -- the address
|
|
|
|
# passed to FUS_FW_UPGRADE is ignored (implying that it must be searching the
|
|
|
|
# flash). This requires that the firmware files have been pre-processed by
|
|
|
|
# rfcore_makefirmware.py and this key must match the one there.
|
|
|
|
_OBFUSCATION_KEY = const(0x0573B55AA)
|
|
|
|
|
|
|
|
# On boards using the internal flash filesystem, this must match the
|
2021-11-28 21:10:36 -05:00
|
|
|
# `_micropy_hw_internal_flash_storage_end` symbol defined by the linker script
|
|
|
|
# (see eg boards/stm32wb55xg.ld).
|
2020-09-29 04:37:45 -04:00
|
|
|
# We erase everything from here until the start of the secure area (defined by
|
|
|
|
# SFSA) just to ensure that no other fragments of firmware files are left
|
|
|
|
# behind. On boards with external flash, this just needs to ensure that it
|
|
|
|
# includes any regions that may contain partial firmware data.
|
|
|
|
# This is non-const so it can be override.
|
|
|
|
STAGING_AREA_START = 0x80C0000
|
|
|
|
|
|
|
|
# First word of device info table indicating FUS state (returned by `stm.rfcore_status()`).
|
|
|
|
_MAGIC_FUS_ACTIVE = const(0xA94656B9) # AN5185
|
|
|
|
_MAGIC_IPCC_MEM_INCORRECT = const(0x3DE96F61) # # AN5185
|
|
|
|
|
|
|
|
# Argument to `stm.rfcore_fw_version()`.
|
|
|
|
_FW_VERSION_FUS = const(0)
|
|
|
|
_FW_VERSION_WS = const(1)
|
|
|
|
|
|
|
|
# No firmware update in progress. Boot normally.
|
|
|
|
_STATE_IDLE = const(0)
|
|
|
|
|
|
|
|
# A previous firmware update failed. Will return reason code from resume().
|
|
|
|
_STATE_FAILED = const(1)
|
|
|
|
|
|
|
|
# Trying to get into the FUS. Keep issuing GET_STATE until the FUS is active.
|
|
|
|
_STATE_WAITING_FOR_FUS = const(2)
|
|
|
|
|
|
|
|
# Trying to get into the WS. Keep issuing START_WS until the WS is active (or fails).
|
|
|
|
_STATE_WAITING_FOR_WS = const(3)
|
|
|
|
|
|
|
|
# FW_DELETE has been issued. Waiting for the WS version to report zero.
|
|
|
|
_STATE_DELETING_WS = const(4)
|
|
|
|
|
|
|
|
# Flash copy has started for FUS/WS. If a reboot occurs, then fail.
|
|
|
|
_STATE_COPYING_FUS = const(5)
|
|
|
|
_STATE_COPYING_WS = const(6)
|
|
|
|
|
|
|
|
# Flash write fully completed, ready for install.
|
|
|
|
_STATE_COPIED_FUS = const(7)
|
|
|
|
_STATE_COPIED_WS = const(8)
|
|
|
|
|
|
|
|
# Check for next update to perform.
|
|
|
|
# Either we've just gotten into the FUS, or the first update in a sequence
|
|
|
|
# has completed. (e.g. FUS done, now do WS).
|
|
|
|
_STATE_CHECK_UPDATES = const(9)
|
|
|
|
|
|
|
|
# Installation has started, keep polling GET_STATE.
|
|
|
|
_STATE_INSTALLING_WS = const(10)
|
|
|
|
_STATE_INSTALLING_FUS = const(11)
|
|
|
|
|
|
|
|
# Update completed successfully.
|
|
|
|
REASON_OK = const(0)
|
|
|
|
# The device reset during flash copy. Possibly WS still installed.
|
|
|
|
REASON_FLASH_COPY_FAILED = const(1)
|
|
|
|
# Unable to start the WS after firmware update.
|
|
|
|
REASON_NO_WS = const(2)
|
|
|
|
# Copying FUS image to staging area caused FUS to fail.
|
|
|
|
REASON_FLASH_FUS_BAD_STATE = const(3)
|
|
|
|
# Copying WS image to staging area caused FUS to fail.
|
|
|
|
REASON_FLASH_WS_BAD_STATE = const(4)
|
|
|
|
# Cannot get into the FUS. Perhaps rfcore misconfigured.
|
|
|
|
REASON_FUS_NOT_RESPONDING = const(5)
|
|
|
|
# After a FUS install, unable to get back to the FUS.
|
|
|
|
REASON_FUS_NOT_RESPONDING_AFTER_FUS = const(6)
|
|
|
|
# After a WS install, unable to get back to the FUS.
|
|
|
|
REASON_FUS_NOT_RESPONDING_AFTER_WS = const(7)
|
|
|
|
# Unable to query rfcore version/active.
|
|
|
|
REASON_RFCORE_NOT_CONFIGURED = const(8)
|
|
|
|
# The WS deletion didn't have any effect.
|
|
|
|
REASON_WS_STILL_PRESENT = const(9)
|
|
|
|
# FUS refused to delete the WS.
|
|
|
|
REASON_WS_DELETION_FAILED = const(10)
|
|
|
|
# FUS returned a specific code for a FUS update.
|
|
|
|
# See AN5185 Rev 4, Table 12. Reason between 0x00-0x11 will be added.
|
|
|
|
REASON_FUS_VENDOR = const(0x10)
|
|
|
|
# FUS returned a specific code for a WS update. Values as for the FUS update.
|
|
|
|
REASON_WS_VENDOR = const(0x30)
|
|
|
|
|
|
|
|
# FUS 1.0.2 must be installed before FUS 1.1.0 can be installed.
|
|
|
|
# A factory Nucleo board has FUS (0, 5, 3, 0, 0) and WS (0, 5, 1, 0, 0).
|
|
|
|
_FUS_VERSION_102 = (1, 0, 2, 0, 0)
|
|
|
|
_FUS_VERSION_110 = (1, 1, 0, 0, 0)
|
|
|
|
_PATH_FUS_102 = "fus_102.bin"
|
|
|
|
_PATH_FUS_110 = "fus_110.bin"
|
|
|
|
_PATH_WS_BLE_HCI = "ws_ble_hci.bin"
|
|
|
|
|
2020-10-15 05:35:11 -04:00
|
|
|
# When installing the FUS/WS it can take a long time to return to the first
|
|
|
|
# GET_STATE HCI command.
|
|
|
|
# e.g. Installing stm32wb5x_BLE_Stack_full_fw.bin takes 3600ms to respond.
|
|
|
|
_INSTALLING_FUS_GET_STATE_TIMEOUT = const(1000)
|
|
|
|
_INSTALLING_WS_GET_STATE_TIMEOUT = const(6000)
|
|
|
|
|
2020-09-29 04:37:45 -04:00
|
|
|
|
|
|
|
def log(msg, *args, **kwargs):
|
|
|
|
print("[rfcore update]", msg.format(*args, **kwargs))
|
|
|
|
|
|
|
|
|
|
|
|
class _Flash:
|
|
|
|
_FLASH_KEY1 = 0x45670123
|
|
|
|
_FLASH_KEY2 = 0xCDEF89AB
|
|
|
|
|
2020-10-15 05:09:04 -04:00
|
|
|
_FLASH_CR_STRT_MASK = 1 << 16
|
|
|
|
_FLASH_CR_LOCK_MASK = 1 << 31
|
|
|
|
_FLASH_SR_BSY_MASK = 1 << 16
|
|
|
|
|
2020-09-29 04:37:45 -04:00
|
|
|
def wait_not_busy(self):
|
2020-10-15 05:09:04 -04:00
|
|
|
while machine.mem32[stm.FLASH + stm.FLASH_SR] & _Flash._FLASH_SR_BSY_MASK:
|
2020-09-29 04:37:45 -04:00
|
|
|
machine.idle()
|
|
|
|
|
|
|
|
def unlock(self):
|
2020-10-15 05:09:04 -04:00
|
|
|
if machine.mem32[stm.FLASH + stm.FLASH_CR] & _Flash._FLASH_CR_LOCK_MASK:
|
|
|
|
# Only unlock if already locked (i.e. FLASH_CR_LOCK is set).
|
|
|
|
machine.mem32[stm.FLASH + stm.FLASH_KEYR] = _Flash._FLASH_KEY1
|
|
|
|
machine.mem32[stm.FLASH + stm.FLASH_KEYR] = _Flash._FLASH_KEY2
|
|
|
|
else:
|
|
|
|
log("Flash was already unlocked.")
|
2020-09-29 04:37:45 -04:00
|
|
|
|
|
|
|
def lock(self):
|
2020-10-15 05:09:04 -04:00
|
|
|
machine.mem32[stm.FLASH + stm.FLASH_CR] = _Flash._FLASH_CR_LOCK_MASK
|
2020-09-29 04:37:45 -04:00
|
|
|
|
|
|
|
def erase_page(self, page):
|
|
|
|
assert 0 <= page <= 255 # 1MiB range (4k page)
|
|
|
|
self.wait_not_busy()
|
|
|
|
cr = page << 3 | 1 << 1 # PNB # PER
|
|
|
|
machine.mem32[stm.FLASH + stm.FLASH_CR] = cr
|
2020-10-15 05:09:04 -04:00
|
|
|
machine.mem32[stm.FLASH + stm.FLASH_CR] = cr | _Flash._FLASH_CR_STRT_MASK
|
2020-09-29 04:37:45 -04:00
|
|
|
self.wait_not_busy()
|
|
|
|
machine.mem32[stm.FLASH + stm.FLASH_CR] = 0
|
|
|
|
|
|
|
|
def write(self, addr, buf, sz, key=0):
|
|
|
|
assert sz % 4 == 0
|
|
|
|
self.wait_not_busy()
|
|
|
|
cr = 1 << 0 # PG
|
|
|
|
machine.mem32[stm.FLASH + stm.FLASH_CR] = cr
|
|
|
|
off = 0
|
|
|
|
while off < sz:
|
|
|
|
v = (buf[off]) | (buf[off + 1] << 8) | (buf[off + 2] << 16) | (buf[off + 3] << 24)
|
|
|
|
machine.mem32[addr + off] = v ^ key
|
|
|
|
off += 4
|
|
|
|
if off % 8 == 0:
|
|
|
|
self.wait_not_busy()
|
|
|
|
if off % 8:
|
|
|
|
machine.mem32[addr + off] = 0
|
|
|
|
self.wait_not_busy()
|
|
|
|
machine.mem32[stm.FLASH + stm.FLASH_CR] = 0
|
|
|
|
|
|
|
|
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
def validate_crc(f):
|
|
|
|
"""Should match copy of function in rfcore_makefirmware.py to confirm operation"""
|
|
|
|
f.seek(0)
|
|
|
|
file_crc = 0
|
|
|
|
chunk = 16 * 1024
|
|
|
|
buff = bytearray(chunk)
|
|
|
|
while True:
|
|
|
|
read = f.readinto(buff)
|
|
|
|
if read < chunk:
|
|
|
|
file_crc = crc32(buff[0:read], file_crc)
|
|
|
|
break
|
|
|
|
file_crc = crc32(buff, file_crc)
|
|
|
|
|
|
|
|
file_crc = 0xFFFFFFFF & -file_crc - 1
|
|
|
|
f.seek(0)
|
|
|
|
return file_crc == 0
|
|
|
|
|
|
|
|
|
|
|
|
def check_file_details(filename):
|
|
|
|
with open(filename, "rb") as f:
|
|
|
|
if not validate_crc(f):
|
|
|
|
raise ValueError("file validation failed: incorrect crc")
|
|
|
|
|
|
|
|
# Check the footer on the file
|
|
|
|
f.seek(-64, 2)
|
|
|
|
footer = f.read()
|
|
|
|
details = struct.unpack("<37sIIIIbbbII", footer)
|
|
|
|
(
|
|
|
|
src_filename,
|
|
|
|
addr_1m,
|
|
|
|
addr_640k,
|
|
|
|
addr_512k,
|
|
|
|
addr_256k,
|
|
|
|
vers_major,
|
|
|
|
vers_minor,
|
|
|
|
vers_patch,
|
|
|
|
KEY,
|
|
|
|
crc,
|
|
|
|
) = details
|
|
|
|
src_filename = src_filename.strip(b"\x00").decode()
|
|
|
|
if KEY != _OBFUSCATION_KEY:
|
|
|
|
raise ValueError("file validation failed: incorrect key")
|
|
|
|
|
|
|
|
return (
|
|
|
|
src_filename,
|
|
|
|
addr_1m,
|
|
|
|
addr_640k,
|
|
|
|
addr_512k,
|
|
|
|
addr_256k,
|
|
|
|
(vers_major, vers_minor, vers_patch),
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def _copy_file_to_flash(filename):
|
2020-09-29 04:37:45 -04:00
|
|
|
flash = _Flash()
|
|
|
|
flash.unlock()
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
# Reset any previously stored address
|
|
|
|
_write_target_addr(0)
|
2020-09-29 04:37:45 -04:00
|
|
|
try:
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
(
|
|
|
|
src_filename,
|
|
|
|
addr_1m,
|
|
|
|
addr_640k,
|
|
|
|
addr_512k,
|
|
|
|
addr_256k,
|
|
|
|
vers,
|
|
|
|
) = check_file_details(filename)
|
|
|
|
|
|
|
|
# TODO add support for querying the correct flash size on chip
|
|
|
|
addr = load_addr = addr_1m
|
|
|
|
|
|
|
|
log(f"Writing {src_filename} v{vers[0]}.{vers[1]}.{vers[2]} to addr: 0x{addr:x}")
|
|
|
|
|
2020-09-29 04:37:45 -04:00
|
|
|
# Erase the entire staging area in flash.
|
|
|
|
erase_addr = STAGING_AREA_START
|
|
|
|
sfr_sfsa = machine.mem32[stm.FLASH + stm.FLASH_SFR] & 0xFF
|
|
|
|
erase_limit = 0x08000000 + sfr_sfsa * 4096
|
|
|
|
while erase_addr < erase_limit:
|
|
|
|
flash.erase_page((erase_addr - 0x08000000) // 4096)
|
|
|
|
erase_addr += 4096
|
|
|
|
|
|
|
|
# Write the contents of the firmware (note flash.write will apply the
|
|
|
|
# XOR de-obfuscation).
|
|
|
|
with open(filename, "rb") as f:
|
|
|
|
buf = bytearray(4096)
|
|
|
|
|
|
|
|
while 1:
|
|
|
|
sz = f.readinto(buf)
|
|
|
|
if sz == 0:
|
|
|
|
break
|
|
|
|
flash.write(addr, buf, sz, _OBFUSCATION_KEY)
|
|
|
|
addr += 4096
|
|
|
|
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
# Cache the intended target load address
|
|
|
|
_write_target_addr(load_addr)
|
|
|
|
|
2020-09-29 04:37:45 -04:00
|
|
|
finally:
|
|
|
|
flash.lock()
|
|
|
|
|
|
|
|
|
|
|
|
def _parse_vendor_response(data):
|
|
|
|
assert len(data) >= 7
|
|
|
|
assert data[0] == _HCI_KIND_VENDOR_RESPONSE
|
|
|
|
assert data[1] == 0x0E
|
|
|
|
# assert data[3] == 0xff # "Num HCI" -- docs say 0xff, but we see 0x01
|
|
|
|
op = (data[5] << 8) | data[4]
|
|
|
|
return (op >> 10, op & 0x3FF, data[6], data[7] if len(data) > 7 else 0)
|
|
|
|
|
|
|
|
|
2020-10-15 05:35:11 -04:00
|
|
|
def _run_sys_hci_cmd(ogf, ocf, buf=b"", timeout=0):
|
2020-09-29 04:37:45 -04:00
|
|
|
try:
|
|
|
|
ogf_out, ocf_out, status, result = _parse_vendor_response(
|
2020-10-15 05:35:11 -04:00
|
|
|
stm.rfcore_sys_hci(ogf, ocf, buf, timeout)
|
2020-09-29 04:37:45 -04:00
|
|
|
)
|
|
|
|
except OSError:
|
|
|
|
# Timeout or FUS not active.
|
|
|
|
return (0xFF, 0xFF)
|
|
|
|
assert ogf_out == ogf
|
|
|
|
assert ocf_out == ocf
|
|
|
|
return (status, result)
|
|
|
|
|
|
|
|
|
2020-10-15 05:35:11 -04:00
|
|
|
def fus_get_state(timeout=0):
|
|
|
|
return _run_sys_hci_cmd(_OGF_VENDOR, _OCF_FUS_GET_STATE, timeout=timeout)
|
2020-09-29 04:37:45 -04:00
|
|
|
|
|
|
|
|
|
|
|
def fus_is_idle():
|
|
|
|
return fus_get_state() == (0, 0)
|
|
|
|
|
|
|
|
|
|
|
|
def fus_start_ws():
|
|
|
|
return _run_sys_hci_cmd(_OGF_VENDOR, _OCF_FUS_START_WS)
|
|
|
|
|
|
|
|
|
|
|
|
def _fus_fwdelete():
|
|
|
|
return _run_sys_hci_cmd(_OGF_VENDOR, _OCF_FUS_FW_DELETE)
|
|
|
|
|
|
|
|
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
def _fus_run_fwupgrade():
|
2020-09-29 04:37:45 -04:00
|
|
|
# Note: Address is ignored by the FUS (see comments above).
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
addr = _read_target_addr()
|
|
|
|
if not addr:
|
|
|
|
log(f"Update failed: Invalid load address: 0x{addr:x}")
|
|
|
|
return False
|
|
|
|
|
|
|
|
log(f"Loading to: 0x{addr:x}")
|
2020-09-29 04:37:45 -04:00
|
|
|
return _run_sys_hci_cmd(_OGF_VENDOR, _OCF_FUS_FW_UPGRADE, struct.pack("<I", addr))
|
|
|
|
|
|
|
|
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
if stm:
|
|
|
|
# Get/set current state/reason/addr to RTC Backup Domain.
|
|
|
|
# Using the second, third, and fourth-last registers (16, 17, 18) as
|
|
|
|
# the final one (19) is reserved by powerctrl.c for restoring the frequency.
|
|
|
|
# Can be overridden if necessary.
|
|
|
|
REG_RTC_STATE = stm.RTC + stm.RTC_BKP18R
|
|
|
|
REG_RTC_REASON = stm.RTC + stm.RTC_BKP17R
|
|
|
|
REG_RTC_ADDR = stm.RTC + stm.RTC_BKP16R
|
2020-09-29 04:37:45 -04:00
|
|
|
|
|
|
|
|
|
|
|
def _read_state():
|
|
|
|
return machine.mem32[REG_RTC_STATE]
|
|
|
|
|
|
|
|
|
|
|
|
def _write_state(state):
|
|
|
|
machine.mem32[REG_RTC_STATE] = state
|
|
|
|
|
|
|
|
|
|
|
|
def _read_failure_reason():
|
|
|
|
return machine.mem32[REG_RTC_REASON]
|
|
|
|
|
|
|
|
|
|
|
|
def _write_failure_state(reason):
|
|
|
|
machine.mem32[REG_RTC_REASON] = reason
|
|
|
|
_write_state(_STATE_FAILED)
|
|
|
|
return reason
|
|
|
|
|
|
|
|
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
def _read_target_addr():
|
|
|
|
return machine.mem32[REG_RTC_ADDR]
|
|
|
|
|
|
|
|
|
|
|
|
def _write_target_addr(addr):
|
|
|
|
machine.mem32[REG_RTC_ADDR] = addr
|
|
|
|
|
|
|
|
|
2020-09-29 04:37:45 -04:00
|
|
|
# Check for the presence of a given file and attempt to start installing it.
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
def _stat_and_start_copy(path, copying_state, copied_state):
|
2020-09-29 04:37:45 -04:00
|
|
|
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
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
_copy_file_to_flash(path)
|
2020-09-29 04:37:45 -04:00
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
# This should be called in boot.py to resume any in-progress update.
|
|
|
|
# If there's nothing to do, it will return 0 and the app can continue as normal.
|
|
|
|
# If a previous update has failed, then it will return the failure reason.
|
|
|
|
# Otherwise it will attempt to continue the update from where it left off.
|
|
|
|
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:
|
2020-10-15 05:11:43 -04:00
|
|
|
state = _read_state()
|
2020-09-29 04:37:45 -04:00
|
|
|
|
2020-10-15 05:11:43 -04:00
|
|
|
if state == _STATE_IDLE:
|
2020-09-29 04:37:45 -04:00
|
|
|
log("Firmware update complete")
|
|
|
|
return 0
|
|
|
|
|
2020-10-15 05:11:43 -04:00
|
|
|
elif state == _STATE_FAILED:
|
2020-09-29 04:37:45 -04:00
|
|
|
log("Firmware update failed")
|
|
|
|
return _read_failure_reason()
|
|
|
|
|
|
|
|
# Keep calling GET_STATE until error or FUS.
|
2020-10-15 05:11:43 -04:00
|
|
|
elif state == _STATE_WAITING_FOR_FUS:
|
2020-09-29 04:37:45 -04:00
|
|
|
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).
|
2020-10-15 05:11:43 -04:00
|
|
|
elif state == _STATE_WAITING_FOR_WS:
|
2020-09-29 04:37:45 -04:00
|
|
|
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).
|
2020-10-15 05:11:43 -04:00
|
|
|
elif state == _STATE_CHECK_UPDATES:
|
2020-09-29 04:37:45 -04:00
|
|
|
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")
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
if _stat_and_start_copy(_PATH_FUS_102, _STATE_COPYING_FUS, _STATE_COPIED_FUS):
|
2020-09-29 04:37:45 -04:00
|
|
|
continue
|
|
|
|
elif fus_version >= _FUS_VERSION_102 and fus_version < _FUS_VERSION_110:
|
|
|
|
log("FUS 1.0.2 detected")
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
if _stat_and_start_copy(_PATH_FUS_110, _STATE_COPYING_FUS, _STATE_COPIED_FUS):
|
2020-09-29 04:37:45 -04:00
|
|
|
continue
|
|
|
|
else:
|
|
|
|
log("FUS is up-to-date")
|
|
|
|
|
|
|
|
if fus_version >= _FUS_VERSION_110:
|
|
|
|
if _stat_and_start_copy(
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
_PATH_WS_BLE_HCI,
|
|
|
|
_STATE_COPYING_WS,
|
|
|
|
_STATE_COPIED_WS,
|
2020-09-29 04:37:45 -04:00
|
|
|
):
|
|
|
|
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.
|
2020-10-15 05:11:43 -04:00
|
|
|
elif state == _STATE_COPYING_FUS or state == _STATE_COPYING_WS:
|
2020-09-29 04:37:45 -04:00
|
|
|
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.
|
2020-10-15 05:11:43 -04:00
|
|
|
elif state == _STATE_COPIED_FUS:
|
2020-09-29 04:37:45 -04:00
|
|
|
if fus_is_idle():
|
|
|
|
log("FUS copy complete, installing")
|
|
|
|
_write_state(_STATE_INSTALLING_FUS)
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
_fus_run_fwupgrade()
|
2020-09-29 04:37:45 -04:00
|
|
|
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).
|
2020-10-15 05:11:43 -04:00
|
|
|
elif state == _STATE_INSTALLING_FUS:
|
2020-09-29 04:37:45 -04:00
|
|
|
log("Installing FUS...")
|
2020-10-15 05:35:11 -04:00
|
|
|
status, result = fus_get_state(_INSTALLING_FUS_GET_STATE_TIMEOUT)
|
2020-09-29 04:37:45 -04:00
|
|
|
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).
|
2020-10-15 05:11:43 -04:00
|
|
|
elif state == _STATE_DELETING_WS:
|
2020-09-29 04:37:45 -04:00
|
|
|
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.
|
2020-10-15 05:11:43 -04:00
|
|
|
elif state == _STATE_COPIED_WS:
|
2020-09-29 04:37:45 -04:00
|
|
|
if fus_is_idle():
|
|
|
|
log("WS copy complete, installing")
|
|
|
|
_write_state(_STATE_INSTALLING_WS)
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
_fus_run_fwupgrade()
|
2020-09-29 04:37:45 -04:00
|
|
|
else:
|
|
|
|
log("WS copy bad state")
|
|
|
|
_write_failure_state(REASON_FLASH_WS_BAD_STATE)
|
|
|
|
|
|
|
|
# As for _STATE_INSTALLING_FUS above.
|
2020-10-15 05:11:43 -04:00
|
|
|
elif state == _STATE_INSTALLING_WS:
|
2020-09-29 04:37:45 -04:00
|
|
|
log("Installing WS...")
|
2020-10-15 05:35:11 -04:00
|
|
|
status, result = fus_get_state(_INSTALLING_WS_GET_STATE_TIMEOUT)
|
2020-09-29 04:37:45 -04:00
|
|
|
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)
|
2021-10-11 21:07:02 -04:00
|
|
|
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.
|
2020-09-29 04:37:45 -04:00
|
|
|
# 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)
|
|
|
|
|
|
|
|
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
def install_boot():
|
|
|
|
boot_py = "/flash/boot.py"
|
|
|
|
header = ""
|
|
|
|
mode = "w"
|
|
|
|
try:
|
|
|
|
with open(boot_py, "r") as boot:
|
|
|
|
header = "\n"
|
|
|
|
mode = "a"
|
|
|
|
for line in boot:
|
|
|
|
if "rfcore_firmware.resume()" in line:
|
|
|
|
print("Already installed.")
|
|
|
|
return
|
|
|
|
|
|
|
|
print("boot.py exists, adding upgrade handler.")
|
|
|
|
except OSError:
|
|
|
|
print("boot.py doesn't exists, adding with upgrade handler.")
|
|
|
|
|
|
|
|
with open(boot_py, mode) as boot:
|
|
|
|
boot.write(header)
|
|
|
|
boot.write("# Handle rfcore updates.\n")
|
|
|
|
boot.write("import rfcore_firmware\n")
|
|
|
|
boot.write("rfcore_firmware.resume()\n")
|
|
|
|
|
|
|
|
|
2020-09-29 04:37:45 -04:00
|
|
|
# Start a firmware update.
|
|
|
|
# This will immediately trigger a reset and start the update process on boot.
|
stm32/boards/NUCLEO_WB55: Add error handling to firmware update scripts.
In-the-field use of these FUS/WS firmware update scripts has exposed some
weak points, causing corrupted FUS/WS firmware to be flashed to the unit.
The problems are mostly caused with the ST GUI application, but sometimes
from un-recognised failures during bin file transfer to the WB55 prior to
running the rfcore_firmware.py script. Other failures were caused by
incorrect load addresses being used, again both from user error copying the
address from the HTML release notes to the GUI tool, but also from
similarly not updating the address correctly in rfcore_firmware.py
To guard against these errors and make it easier to prepare different
versions, this commit adds a few features to the rfcore firmware update
tools:
- When creating the bin file, automatically parse the release note in the
folder to get the correct address.
- Add a footer to the bin file containing the name, version, CRC, address
etc.
- Before flashing rfcore, check if the same version is already installed.
- Verify the CRC and obfuscation key before flashing bin.
- Log the name and version of file being flashed.
2022-04-04 18:25:54 -04:00
|
|
|
def check_for_updates(force=False):
|
|
|
|
(
|
|
|
|
src_filename,
|
|
|
|
addr_1m,
|
|
|
|
addr_640k,
|
|
|
|
addr_512k,
|
|
|
|
addr_256k,
|
|
|
|
vers_fus,
|
|
|
|
) = check_file_details(_PATH_FUS_110)
|
|
|
|
(
|
|
|
|
src_filename,
|
|
|
|
addr_1m,
|
|
|
|
addr_640k,
|
|
|
|
addr_512k,
|
|
|
|
addr_256k,
|
|
|
|
vers_ws,
|
|
|
|
) = check_file_details(_PATH_WS_BLE_HCI)
|
|
|
|
current_version_fus = stm.rfcore_fw_version(_FW_VERSION_FUS)
|
|
|
|
fus_uptodate = current_version_fus[0:3] == vers_fus
|
|
|
|
|
|
|
|
current_version_ws = stm.rfcore_fw_version(_FW_VERSION_WS)
|
|
|
|
ws_uptodate = current_version_ws[0:3] == vers_ws
|
|
|
|
if fus_uptodate and ws_uptodate and not force:
|
|
|
|
log(f"Already up to date: fus: {current_version_fus}, ws: {current_version_ws}")
|
|
|
|
else:
|
|
|
|
log(f"Starting firmware update")
|
|
|
|
log(f" - fus: {current_version_fus} -> {vers_fus}")
|
|
|
|
log(f" - ws: {current_version_ws} -> {vers_ws}")
|
|
|
|
_write_state(_STATE_WAITING_FOR_FUS)
|
|
|
|
machine.reset()
|