Stub entry

A running RadioFoundry loads the host's flash-access RAM monitor (the "stub") into free RAM and jumps to it, so a radio is updated with no key held at power-on. The web flasher, stub/stubtool.py (--rfoundry-enter) and tools/rfoundry use it. Because every update after the first one depends on it, the stub entry is its own small feature, apart from the debug link: a build without the debug link still offers it.

Part Where
Switch CONFIG_STUB_ENTRY: on wherever CONFIG_HOSTLINK is (every radio), needs only HOSTLINK
The STUB state machine (portable, host tested) core/stubentry/stub_load.c
Firmware glue: the RAM span, the transmit checks, the banner, the jump core/stubentry/stub_entry.c
Own listener for a build without the debug link (portable, host tested) core/stubentry/stub_link.c
Framing shared with the debug link core/debuglink/dl_frame.{h,c} (no RTOS, no board)
Platform: span and quiesce-and-jump hal_system_t.stub_region / enter_stub / stub_run_addr / stub_image_ok: the HR_C7000 platform code (platform/hrc7000), stub-stm32f4.md (STM32F4)
Tests tests/host/stubEntryTest.c (state machine), tests/host/stubLinkTest.c (wire bytes, both listeners)

1. Wire format

The stub entry speaks the debug link's framing (debuglink.md 2) and its command 0x1A STUB with the operations INFO, BEGIN, DATA and ENTER (debuglink.md 3.18). The request and reply bytes are the same whichever listener answers, and stubLinkTest replays recorded request frames and checks the replies byte for byte through both listeners. A host can't tell the listeners apart by the STUB command; VERSION says which one answered (section 2).

2. Listeners

The host link has one side protocol slot (hostlink_side_t, first byte 0xA5). Who takes it depends on the build:

Build Listener Commands answered
DEBUGLINK=y, STUB_ENTRY=y (the default) the debug link. Its dispatcher hands 0x1A to stub_entry_request and calls stub_entry_service after every frame every debug link command
DEBUGLINK=n, STUB_ENTRY=y the stub entry's own (stub_entry_start, stub_link.c), on the same framing PING (echo), VERSION (short), STUB; anything else DL_ST_UNKNOWN_CMD
STUB_ENTRY=n the debug link, or none STUB answers DL_ST_UNAVAILABLE

So with the debug link on, nothing changes on the wire and no code is duplicated: the debug link's parser is the listener. With it off, the stub entry brings the parser (dl_frame.c, about 0.4 KB) and an 89-byte reply buffer.

The own listener's VERSION carries the keys the flashing tools read, then stub=1:

proto=1
git=5277f73a
board=XR-100UV
codec=xr100uv-2501
stub=1

stubtool.py and f4stub.py take board= from it to pick the stub's profile, rfoundry and the web flasher's probe take board=, git= and codec=. Their INFO_CHIP request gets DL_ST_UNKNOWN_CMD, which every tool already treats as "older firmware" and goes on without the chip UID.

3. Coexistence on the host port

The listener sits where the debug link does (debuglink.md 1, hostlink.h): a frame is recognized only at a request boundary (idle; in a CPS session after the 3 ms gap; in hotspot mode between MMDVM frames), so the CPS, hotspot, TNC and PPP personalities work as with the debug link. In the USB network personality the host link feeds UDP serial bytes through the same dispatch, so the STUB frames arrive there too. The STM32 entry then tells the stub that the port is not a serial device (handoff_flags), and the stub enumerates again as one.

The stub entry reads no pins and does not touch PTT. On the HR_C7000 radios whose PTT shares the cable's serial line, the input task's shared-PTT filter (drivers/input/sharedptt) works from the UART's receive time, whoever parses the bytes, so a stub upload can't key the radio.

4. Safety

Check Where
The magic 'C7SB' on BEGIN and ENTER, the exact length and the CRC-32 of the whole image before the jump stub_load.c
ENTER while the radio core is transmitting, or the hotspot is sending, answers busy before the image is looked at stub_entry_request
The platform's image check (the STM32 IWDG: the stub must say it feeds it) hal_system_t.stub_image_ok, stub-stm32f4.md 3.1
100 ms after the ENTER reply, the jump is dropped if the radio is transmitting; otherwise tx_off, the banner, the jump stub_entry_service

The transmit check reads only the radio core's state (radio_get_state), not the whole view, so the check fits the host link task's stack in a build without the debug link.

5. Cost

Default builds (debug link on), against a build without the stub entry:

Board family Flash RAM
STM32 with an HR_C6000 +52 B 0
STM32 with an HR_C5000 +232 B (LTO inlining moves) 0
HR_C7000 +12 to +16 B 0

The stub entry without the debug link (an STM32 board with an HR_C5000, CONFIG_DEBUGLINK=n with and without CONFIG_STUB_ENTRY): 2,356 B of flash and 8,456 B of RAM, of which 8 KB is the STM32 staging buffer. The HR_C7000 boards load the image into the codec window and add no staging buffer.

View the source of this page