Skip to content

Support new v3 devinfo and separate CLI tool#4

Open
tridge wants to merge 7 commits into
am32-firmware:mainfrom
tridge:cli-and-deviceinfo-magic
Open

Support new v3 devinfo and separate CLI tool#4
tridge wants to merge 7 commits into
am32-firmware:mainfrom
tridge:cli-and-deviceinfo-magic

Conversation

@tridge
Copy link
Copy Markdown
Member

@tridge tridge commented May 27, 2026

This adds support for the new v3 devinfo from this bootloader PR:
am32-firmware/AM32-bootloader#68
it also adds a new SerialPortConnector_CLI which makes rapid testing a lot easier.
With the new v3 devinfo we no longer have an issue with new flash layouts as we are not dependent on the pin code.

tridge and others added 3 commits May 23, 2026 19:34
Use the bootloader protocol version and magic flash addresses so the
configurator no longer needs hardcoded per-MCU/per-variant flash layout:

- EEPROM read/write use the magic addresses (0x20/0x21) when the
  bootloader reports protocol version >= 2.
- the firmware flash start comes from the deviceInfo instead of being
  guessed from the flash-size code (the CAN G431 reserves 16KB for the
  bootloader but reports the same 0x2b code as G071), via
  firmwareChunkAddress().
- over the 4-way passthrough the FC only forwards a 4-byte InitFlash
  signature, so the version / firmware-start are fetched with a 4-way
  READ at ADDRESS_MAGIC_DEVINFO (0x23), which returns the devinfo block
  (magic1/magic2 + deviceInfo). Falls back to flash-size-code defaults on
  older bootloaders.

The protocol-decision logic (deviceInfo parsing, CRC/ACK handling,
magic/firmware addressing, Intel-HEX parsing) is moved into FourWayIF and
a new hexfile module so the GUI and the CLI share it and cannot diverge.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A command-line build (QtCore + serialport, no GUI) with "settings" and
"flash" commands that drives the same shared protocol code as the GUI, so
protocol changes can be tested against hardware without the GUI. The flash
command also writes flash_image.bin (the exact bytes flashed) so a flash
read-back can be compared against it.

Build:
  qmake SerialPortConnector_CLI.pro -o Makefile.cli && make -f Makefile.cli

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The bootloader's v3 devinfo (read via ADDRESS_MAGIC_DEVINFO) is now a packed
struct: 9-byte deviceInfo, then length, address_shift, and the
firmware/filename/eeprom/tune CMD_SET_ADDRESS values (already >> address_shift).

- parseDevinfoBlock(): after the 9-byte deviceInfo, parse the v3 extension at
  its new offsets (length/address_shift/*_start). Drop the old assumption that
  firmware_start sits in the 2 bytes right after deviceInfo.
- firmwareChunkAddress(): for v3, firmware_start is already a SET_ADDRESS value,
  so step by (offset >> address_shift); pre-v3 byte-offset path unchanged.
- read the full 27-byte block (was 20) for the magic devinfo read (CLI + GUI).
- GUI verify-read uses the shared firmwareChunkAddress; fix the flash-addr log.

Tested end-to-end against an ARK G491 (128k, address_shift=2): firmware_start
0x1000 -> app flashed at 0x08004000, FLASH SUCCESS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
tridge and others added 4 commits May 27, 2026 13:58
makeFourWayReadCommand() encodes a 256-byte read length as 0 (the 4-way
single-byte length field's standard sentinel). The shared response
parser was reading that byte at face value, so a 256-byte read silently
produced an empty payload. The current callers happen to use lengths
< 256 (27, 80, 128, 5), so this is a latent bug — fix it before someone
adds a 256-byte read.

Reported by codex in PR review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The v3 devinfo block exposes tune_start as a CMD_SET_ADDRESS value, but
getMusic()/writeMusic() were still computing the tune address as
"eeprom_address + 48". On 128k STM32 parts (address_shift == 2) that
arithmetic adds 48 in *wire-address* space, which the bootloader decodes
to physical eeprom + 192 — so reading or writing the tune region landed
in the wrong flash bytes.

Add FourWayIF::tuneAddress() which returns devinfo_v3.tune_start when
v3 is enabled, falling back to the old eeprom_address + 48 for pre-v3
bootloaders (where the absent address_shift made that arithmetic
correct). Use it in all four GUI music callsites.

Reported by codex in PR review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
connectMotor() only issued the ADDRESS_MAGIC_DEVINFO (0x23) magic read
in its 4-way passthrough branch. In direct (no Betaflight FC) mode it
parsed only the legacy 9-byte deviceInfo, so devinfo_v3.enabled stayed
false and firmwareChunkAddress() fell back to the flashcode-derived
firmware_start. For a v3 CAN bootloader (e.g. G431 CAN with firmware
base 0x4000) that left chunks pointing below APPLICATION_ADDRESS,
which the bootloader rejects.

Issue setAddress(ADDRESS_MAGIC_DEVINFO) + readFlash(27) right after
the BootInit handshake and feed the response through parseDevinfoBlock.
Some serial adapters echo the command back as a 4-byte prefix; strip
it BEFORE checking CRC (same heuristic as the existing direct EEPROM
read further down), otherwise the CRC validation always fails on those
adapters and devinfo_v3 silently stays disabled. Older bootloaders
reject the magic read; we leave devinfo_v3 disabled in that case so
the legacy fallback still works.

Reported by codex in PR review (initial fix landed without
echo-prefix handling; codex's follow-up flagged the CRC ordering).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When the firmware image size isn't a multiple of the chunk size, the
last QByteArray we send is shorter than chunk_size (e.g. 56245 % 256 =
181 bytes). On STM32G431 (and any part whose flash programs in 64-bit
doublewords) save_flash_nolib() in Mcu/g431/Src/eeprom.c rejects writes
whose length isn't a multiple of 8 with ACK_D_GENERAL_ERROR, so flashing
fails on the very last chunk for many real image sizes.

Pad the tail with 0xFF (the erased-flash value) until size is a
multiple of 8. The padding bytes match the erased state, so the verify
pass against the source binary's logical size is unaffected.

This matches the same fix already in the CLI testbed and the web
configurator (am32-configurator).

Reported by codex in PR review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant