/** * STM32 firmware flash via STM32_Programmer_CLI (ST's CubeProgrammer CLI). * * Two methods, mirroring the invocations documented in the firmware repo's * CLAUDE.md: * - swd → ST-Link over SWD: -c port=SWD freq=4000 -w 0x08000000 -rst --start 0x08000000 * - dfu → USB DFU bootloader: -c port=USB1 -e [0 0] -w 0x08000800 * -w 0x08000000 -s 0x08000000 * (board must be in ST system bootloader — hold pad 1 at boot, or * trigger boot_request_dfu / the CDC STM_DFU verb). * * The DFU write order is deliberate: erase page 0 first, program the tail, * program page 0 last. The G0 ROM's empty check forces the system bootloader * on a POR when the first flash word is 0xFFFFFFFF, so a flash interrupted at * any point before the final 2 KB page leaves a board that re-enters DFU on a * simple replug — no ST-Link, no buttons. (A non-POR reset in that state * LOCKUPs at pc=0xFFFFFFFE instead — the empty check is only sampled on * POR/OBL resets — but with no battery a replug IS a POR.) The final * head-page write is the only unprotected window, ~tens of ms. * * The flasher binary is resolved from user config → $STM32_PROG → PATH; if none * resolves we fail early with actionable guidance rather than spawning garbage. */ import { OnLine } from "../utils/exec.js"; export interface StmFlashResult { success: boolean; method: "swd" | "dfu"; programmer: string; firmware_path: string; duration_seconds: number; output_tail: string[]; error?: string; } /** * Resolve the STM32_Programmer_CLI binary. Order: user config → * $STM32_PROG env → PATH lookup. Returns null when nothing usable is found. * @internal exported for testing */ export declare function resolveProgrammer(): string | null; /** First-page size of the G0 flash — the chunk written last over DFU. */ export declare const DFU_HEAD_SIZE = 2048; export interface DfuSplit { head: string; tail: string; } /** * Split the firmware into head (first flash page) and tail files next to the * bin so the DFU flash can program the tail first and the boot-critical page * last (see the header comment). Returns null for a bin that fits one page. * @internal exported for testing */ export declare function prepareDfuSplit(bin: string): DfuSplit | null; /** * Build the STM32_Programmer_CLI argv for a flash method. No shell — bin path * may be user-supplied, so it never touches a command line. * @internal exported for testing */ export declare function stmFlashArgv(method: "swd" | "dfu", bin: string, split?: DfuSplit | null): string[]; export declare function crosspadStmFlash(method: "swd" | "dfu", buildType: string | undefined, firmwarePath: string | undefined, onLine?: OnLine, signal?: AbortSignal): Promise;