import { ProbeBackend, CommandResult, GDBServerInfo } from "./backend"; import { ProcessManager } from "../utils/process-manager"; export interface JLinkConfig { installDir: string; device: string; interface: "SWD" | "JTAG"; speed: number; serialNumber?: string; gdbPort: number; rttTelnetPort: number; swoTelnetPort: number; } export declare class JLinkBackend extends ProbeBackend { readonly type: "jlink"; readonly displayName = "SEGGER J-Link"; private config; private processManager; private gdbOutputBuffer; constructor(config: Partial, processManager: ProcessManager); private get jlinkExe(); private get gdbServerExe(); /** * Raw JLinkExe execution. Does NOT include preflight/locking. * Use the public methods (which call withPreflight) instead. * * Notes on flags: * - `-ExitOnError 1` is intentionally NOT passed. J-Link Commander * treats the transient "Failed to initialize DAP" line emitted before * a successful `connect under reset` fallback as an error, causing * the interpreter to bail before running the user's script. That * breaks any target where the first attach attempt is unreliable * (e.g. STM32L0 at 4 MHz SWD, MCU running from MSI). We classify * real failures below by parsing stdout instead. */ private execRaw; /** * Deterministic recovery sequence: * 1. Stop GDB server if running * 2. Try connect under reset * 3. If that fails, reduce speed (4000 → 1000 → 400) and retry */ recover(): Promise; /** * Override preflight to use execRaw directly (avoids deadlock since * preflight is called inside acquireLock from withPreflight). */ preflight(): Promise; /** True when we should prefer the GDB bridge over spawning JLinkExe. */ private useGdb; /** * Translate a caller-supplied register name into what GDB accepts. * * The `read_register` tool documents J-Link-style names ('PC', 'SP', * 'R0'), but GDB's register names are lowercase and case-sensitive — * `info registers PC` fails with "Invalid register `PC'". Strip an * optional `$` sigil, lowercase, and map the J-Link-only spellings * that have a GDB equivalent. */ private static toGdbRegName; /** Wrap a GDB command result in the shared `CommandResult` shape. */ private runViaGdb; getDeviceInfo(): Promise; halt(): Promise; resume(): Promise; reset(halt?: boolean): Promise; step(): Promise; /** * Read `length` bytes at `address`. * * The byte count goes to J-Link Commander as bare hex digits. * * `mem` parses its length as hex, so a decimal count is silently misread: * `mem 0x0, 20` returns 0x20 = 32 bytes and `mem 0x0, 256` returns 0x256 = * 598. Both observed on hardware. Every caller passing a decimal length — * readFaultRegisters asking for 20, snapshot asking for 64 — was * over-reading, and any caller counting bytes back got the wrong answer. * * It must be bare hex, NOT 0x-prefixed: `mem 0xe000edf0, 0x4` is rejected * outright, which took out even the DHCSR preflight read and made every * memory tool report "Target may be unreachable". Address takes 0x, length * does not. */ readMemory(address: number, length: number): Promise; writeMemory(address: number, value: number): Promise; readAllRegisters(): Promise; /** * Read one named register. * * The JLinkExe path deliberately does NOT use `rreg`. J-Link Commander * rejects both the ARM mnemonics and the architectural names it prints as * valid — `rreg PC` and `rreg R15` both answer "Illegal register name." and * dump a 100-entry list — so the tool returned an error page instead of a * value. `regs` prints the whole set reliably, so read the set and pick the * register out of it with the parser that already understands both the * J-Link and GDB formats. * * This also makes the tool answer the question that was asked: previously a * successful call returned the entire register dump. */ readRegister(name: string): Promise; /** * Normalize a register name to the spelling `parseRegisters` produces. * Accepts the ARM mnemonics, the Rn forms, and a `$` sigil. */ private static toCanonicalRegName; /** * Read memory over the GDB session and normalize the output to the * J-Link Commander format (`ADDR = XX XX ... ASCII`) so downstream * consumers like `readFaultRegisters` / `parseMemoryDump` don't need to * care which channel served the read. */ private readMemoryViaGdb; flash(filePath: string, baseAddress?: number): Promise; erase(): Promise; /** * Breakpoints during a GDB session must go through GDB. * * The JLinkExe path is doubly wrong once a session is live. It evicts the * GDB server (one client per probe), and the breakpoint it sets dies with * the transient JLinkExe process anyway — so the caller loses their session * and does not even get a breakpoint for it. GDB's own breakpoints persist * for the life of the session and are what `resume`/`gdb_wait` will actually * stop on. */ setBreakpoint(address: number): Promise; clearBreakpoints(): Promise; executeRaw(commands: string[]): Promise; startGDBServer(): Promise<{ success: boolean; message: string; }>; stopGDBServer(): { success: boolean; message: string; }; isGDBServerRunning(): boolean; getGDBServerStatus(): GDBServerInfo; getGDBServerOutput(lines?: number): string[]; isDeviceConfigured(): boolean; getDeviceName(): string; setDevice(device: string): void; listDevices(): Promise; supportsRTT(): boolean; getRTTPort(): number; dispose(): void; } //# sourceMappingURL=jlink.d.ts.map