MODULATION -> BURST keys the generator output on and off: ON TIME of every
PERIOD, continuously or COUNT bursts. In burst mode the FREQ / AM DEPTH /
FM DEVIATION buttons set PERIOD / ON TIME / COUNT, START SWEEP becomes
START BURST (fires COUNT bursts, restarts continuous bursts) and the CTCSS
button is blank. Console: "modulation burst|period|ontime|count|trigger".
The Si4468 stays in TX with its PLL untouched: it runs OOK in asynchronous
TX direct mode from GPIO1, driven by TIM8_CH3 PWM on PB9 (one pulse mode
with the repetition counter for COUNT bursts). GPIO1 is normally the CTS
line to PB9, so while burst is selected GPIO1 is an input and CTS is polled
over SPI (READ_CMD_BUFF, the reply is read in the same transaction). PB9
only drives while GPIO1 is an input and is released before every Si4468
reset. MODEM_FREQ_DEV is set to 0 in burst mode, OOK otherwise shifts the
carrier by the deviation of the RX configuration.
- Burst works where the Si4468 makes the output (up to 1.13 GHz and the
mixer path above it), not from the ADF directly ("MOD: BURST N/A").
- Period 2us..89s, resolution about period/65536, timing from the MCU
clock (about 1%).
- The new settings fill alignment holes of setting_t: its size and the
stored presets stay valid.
F072 builds are unchanged. Tested on HW V0.5.4 with a tinySA basic in zero
span: ON level and frequency equal to CW, about 48 dB on/off ratio, COUNT
bursts exact, pulses from about 2 us.
The copyright year is 2026. The thread table of the tinySA Ultra did not
line up: the font is proportional and a space is narrower than a digit or
letter, so padding with spaces moved the columns (e.g. "idle", priority 1).
The numbers are now zero padded, the name follows them and the state is
drawn at a fixed position.
Tested on a ZS407. tinySA Ultra +16 B, BASIC unchanged.
When test 3 found no signal the hint was drawn directly on the screen and
the next redraw of the test list overwrote it (only "Did Y" remained). The
waiting line of the test list now shows "Cable connected? Touch screen to
continue" instead of "Touch screen to continue", so it is redrawn with the
list. Test 3 itself already shows the signal level fail.
Tested: on a ZS407 test 3 forced to no signal through the debugger, the
hint stays visible; the tinySA BASIC self test passes all tests and ends
with "Touch screen to continue". BASIC net about -4 B flash, +4 B RAM.
BANDS->SD stored start, end and level only, so the band names were lost.
The name is now written as a quoted fourth field (older firmware ignores
it) and loaded when present (files of older firmware keep the current
names). A line needs start, end and level: the level was read from lines
with only two fields as well.
Tested on a ZS407: band named FMRADIO stored as
0, 900000000, 0.000000000, "FMRADIO"
renamed, loaded from SD: FMRADIO again. tinySA Ultra only.
Loading a preset from SD did not call update_rbw() as caldata_recall()
does, so the RBW menu showed the preset's RBW while the sweep kept using
the previous one.
Tested on a ZS407: preset stored with RBW 30 kHz, RBW set to 300 kHz,
preset loaded from SD: "rbw" and the status panel show 30 kHz.
tinySA Ultra only, +4 B.
"ext_gain" without an argument now prints the current external gain after
the usage line, as "attenuate" and "rbw" do.
Tested on a ZS407 and a tinySA BASIC: 0.0, 12.5 after "ext_gain 12.5". +16 B.
draw_cal_status() clears the whole left panel, the battery included. The
battery is redrawn when a sweep completes, which does not happen while
paused, so after the "pause" command (it draws the status panel directly)
the battery and voltage stayed blank. draw_cal_status() now also requests
the battery redraw (not in output mode, which shows no battery).
Tested on a ZS407 and a tinySA BASIC: battery and voltage shown after
"pause". +8 B.
All units reported the ChibiOS kernel version "400" as USB serial number,
so Windows could not tell two tinySAs apart: with two of them on the same
VID/PID only one enumerated, and a unit could get another unit's COM port.
The serial number is now 12 hex digits made from the MCU unique ID the way
the STM32F303 DFU bootloader makes its serial number (UID0 + UID2, then the
upper half of UID2): a tinySA Ultra has the same serial as COM port and in
DFU mode. It is filled at every USB reset, before the host asks for it.
Windows assigns every unit a new COM port once.
Tested: ZS407 enumerates as 1781:0A44\205D346A2039 (its DFU serial), the
tinySA BASIC as 0483:5740\2056325F2039, both work side by side.
BASIC about +80 B flash, +26 B RAM.
The tinySA ULTRA enumerates as VID 0x1781 PID 0x0A44 instead of the ST
virtual COM port pair 0x0483 0x5740; the tinySA keeps 0x0483 0x5740.
The IDs now follow the model (TINYSA4) instead of the USB descriptor
variant (__USE_USB_MSC__). bcdDevice is unchanged.
Tested on a ZS405 (HW V0.4.5.1) under Windows 11: the composite device,
the serial port and the mass storage interface bind to the inbox drivers
(usbccgp, usbser, USBSTOR) without an INF, the console works on the new
COM port and "reset dfu" enters the bootloader (0483:DF11) as before.
tinySA-App with both IDs accepted connects to either firmware.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Report: in output mode, with each command sent as soon as the prompt
arrives, a command right after "output" or "modulation" (e.g. "level -30"
after "output off", or "mode low input" after "output off" twice) got no
prompt and was dropped with "Command timeout" after 20 s; the next
command worked.
Cause: after a direct command the shell set operation_requested = true,
which is OP_LEVER. The sweep thread left sweep(), found no command yet,
and ui_process() handled that "lever event" and then set
operation_requested = OP_NONE. When the shell had parsed the next command
in between (shell_function set, OP_CONSOLE set), that clear wiped
OP_CONSOLE. A zero span output mode sweep only returns when
operation_requested is set, so the command never ran. Caught on hardware
with a breakpoint on the clear: operation_requested 0x05 with cmd_level /
cmd_mode waiting, every time.
- ui_process() clears only the bit it handled, locked, so OP_CONSOLE
survives lever and touch handling (a touch, e.g. a remote "touch" from
tinySA-App, hit the same clear).
- The sweep thread clears OP_CONSOLE together with taking shell_function,
which the shell sets together, so a request left by a direct or timed
out command does not keep aborting sweeps.
- A direct command asks for the sweep restart with OP_CONSOLE instead of
a fake lever event.
- SI4432_Listen() keeps OP_CONSOLE on entry, so a command ends listen
mode instead of being lost the same way.
Tested on a ZS405 (HW V0.4.5.1): both reported sequences 15 rounds each
without a hang (release firmware: 7 of 7 hung), every reply < 0.5 s.
In zero span output mode the sweep thread loop passes once per direct
command ("output off/on", "level") and not while idle. Remote touches
mixed with commands in output mode: 10 rounds without a hang. Input mode
touch menu and sweeping work. Listen mode and the jog lever not tested
on hardware. ULTRA +88 bytes, BASIC +84 bytes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Report: after PRESET > LOAD FROM SD and STORE > STORE 1 the name keypad
opened empty, and ENTER on an empty name kept the name stored inside the
.prs file (often the old name of the slot), so the user had to look up
and retype the name of the file they had just loaded.
The keypad now starts with the name of the active preset, the same way
STORE > SD already defaults to the file the preset was loaded from:
- loaded from SD: the file name without ".prs"
- otherwise: setting.preset_name, e.g. of a recalled slot
cut to PRESET_NAME_LENGTH - 1 characters so the keypad shows what the
slot stores. An unnamed preset still opens an empty keypad. A remote
"menu" invoke ignores the default as before (ui_process_keypad).
Tested on a ZS405 (HW V0.4.5.1): an unnamed preset opens empty, a
recalled slot "RESR1" offers RESR1, and with sd_preset_path set through
the ST-Link (this unit's SD card does not mount) "FMBAND.prs" offers
FMBAND and "AIRBAND_118.prs" offers AIRBAND_1; ENTER stores the slot
under the offered name. ULTRA +68 bytes, BASIC builds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Report: switching an Ultra (ZS405) on showed a momentary all white screen,
an Ultra+ (ZS406, ZS407) did not.
- The backlight came on before ili9341_init(), so the panel was lit in
reset and during its init; the ZS405 panel shows white then (the
ZS406/ZS407 panels, the ones with display inversion, stay black). It
now comes on at DEFAULT_BRIGHTNESS once the screen is cleared.
- That left a very brief flash: the backlight came on before the panel
had settled. The init now waits the 120 ms the controller needs after
SLEEP_OUT before DISPLAY_ON (LCD_WAKE_UP_MS). Only with
__LCD_BRIGHTNESS__: without backlight control a longer wait would
only show the uninitialised panel longer, so the BASIC is unchanged.
Tested on a ZS405 (HW V0.4.5.1) with the ST-Link: DAC2 at 0 darkens the
backlight, the backlight is dark with the CPU held in reset, the
backlight switched on 2 s after the init shows no flash, and with this
build power-ons show no flash. Start-up 120 ms longer; ULTRA +12 bytes,
BASIC binary unchanged in size.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Remote editing of a file name with tinySA-App became very slow after a
character or two, and the shell could end up not reading any input.
CMD_WAIT_MUTEX commands are run by the sweep thread, but while a keypad
is open that thread stays in ui_process_keypad() and never picks them
up, so the shell waited 4 x 5 s for each before "Command timeout". The
app polls vbat every 6 s outside live remote control, and every touch
queued behind those waits; local editing was not affected.
ui_process_keypad() now sets keypad_open while it waits for input, and
VNAShell_executeLine() answers a CMD_WAIT_MUTEX command with "keypad
active" instead of waiting, like "usb disk mode active". touch, release,
text, refresh, version and capture (CMD_RUN_IN_UI) run as before.
Tested on HW V0.4.5.1: with a keypad open vbat, pause and sweep answer
in 1 ms, capture rle and remote typing work, and after closing vbat and
sweep answer normally. tinySA-App clicking the screen without live
remote control (vbat polls every 6 s) typed all 8 characters, each poll
answered within 3 ms; before, the first poll stalled the rest.
Flash: ULTRA +44 bytes, BASIC +52.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
File, band and preset names could only be typed and erased at the end.
The text keypad now has a cursor where characters are inserted and
deleted.
- Touching the text line moves the cursor to the nearest character
boundary and it follows the finger while touched (remote touch too).
- Keys insert at the cursor (still at most TXTINPUT_LEN characters),
backspace deletes the character before it and does nothing at the
start; a long backspace still erases the whole name and backspace on
an empty name still cancels.
- The cursor is a blue 2 pixel bar in its own 3 pixel gap that sticks
out 4 pixels above and below the letters, so it is never read as an
I (the glyphs are only 1 pixel apart). The input line is now cleared
up to the screen edge, so a shorter name leaves nothing behind.
- The text keypad exists only with __USE_SD_CARD__: IS_TXT_KEYBOARD is
a constant false without it, which drops the text keypad code from
the tinySA (BASIC).
Tested on HW V0.4.6 with remote touch and screen captures: insert,
backspace, drag to the end, edits at the start, long press, cancel and
a full 27 character name edited in the middle; the edit logic also in a
host build with AddressSanitizer. Flash: ULTRA +376 bytes, BASIC -164.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
releaselog.txt (an old generated version line) is removed; changelog.txt
holds the release notes.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>