Skip to content

Serial Command Reference

hardcoreerik edited this page Sep 4, 2026 · 1 revision

OrcSDR serial command reference

Transport: native ESP32-P4 USB Serial/JTAG (COM17 on the reference bench; the COM number is not a device identity), 8N1, line-terminated (\n). Examples use 115200 for compatibility; see the native-USB note below. Firmware: current main at 427c8c6; the authoritative parsers are main.cpp, rf_lab.cpp, and rf_visualizer.cpp.

This is the human/AI-facing control surface for the Tab5 radio — everything needed to tune, scan, monitor telemetry, and pull files off the device without touching the touchscreen. It's the same protocol the physical UI itself drives internally (touch handlers call the same underlying functions these commands do), so anything scriptable here is exactly what the device is already doing live.

Send one command per line. Most commands reply with one or more lines prefixed by the command's own name (e.g. RTL_TUNE ... replies RTL_TUNE_OK ... or RTL_TUNE_INVALID ...). A command that doesn't match anything produces no reply at all — there is no error line for "unknown command," so typos fail silently. RTL_HELP prints the short on-device list; this page also includes implemented specialist, transfer, test, and companion commands that do not fit in that short help response.

Every operator-facing control must expose a matching serial command or record why it cannot. RTL_SCREEN_STATUS is the read-only render-ownership diagnostic: it reports the active screen, Settings return target, transitions, rejected inactive draws, and visible update count.

Quick start

# One-shot: send a command, print whatever comes back for 2 seconds.
$port = New-Object System.IO.Ports.SerialPort COM17,115200,None,8,One
$port.ReadTimeout = 2000
$port.NewLine = "`n"
$port.Open()
$port.WriteLine("RTL_HELP")
Start-Sleep -Milliseconds 500
while ($true) { try { $port.ReadLine() } catch { break } }
$port.Close()

Any serial library in any language works the same way — this is a plain line protocol, nothing OrcSDR-specific about the transport itself.

USB Serial/JTAG: baud, identity, and large transfers

The Tab5's PC-facing port is the ESP32-P4's native USB Serial/JTAG interface, not an external USB-to-UART bridge. On the accepted bench unit Windows reports USB\VID_303A&PID_1001&MI_00. Confirm the current COM assignment instead of assuming COM17:

Get-PnpDevice -Class Ports |
    Format-Table Status, FriendlyName, InstanceId -AutoSize

Get-CimInstance Win32_SerialPort |
    Select-Object DeviceID, Name, Description, PNPDeviceID

For this native USB connection, the 115200 or 921600 value passed to SerialPort is configuration metadata, not a physical UART bit clock. A host connection at 921600 was hardware-verified while firmware still used Serial.begin(115200); it did not provide an 8x transfer-speed increase. Keep the existing scripts at 115200 unless the hardware path changes to a real UART bridge. With a real UART bridge, both ends must use the same baud.

Large captures use binary chunks, not ASCII samples or hex text. The current protocol uses 16 KiB host-to-device chunks and 2 KiB device-to-host chunks, then verifies the complete file with SHA-256. Use the repository clients:

# PC -> Tab5
.\tools\copy_to_tab5_sd.ps1 '.\capture.s16' `
    '/orcsdr/rds_debug/capture.s16' -Port COM17

# Tab5 -> PC
.\tools\copy_from_tab5_sd.ps1 '/orcsdr/rds_debug/capture.s16' `
    -Destination '.\capture.s16' -Port COM17

Transfer rules and failure meanings:

  • Only one process may own the COM port. Close serial monitors before running a transfer or upload. PermissionError(13) / Access is denied usually means a monitor or an orphaned PlatformIO/esptool process still holds it; identify the exact holder and stop only that process.
  • Do not run an automatic logger beside a binary transfer. Firmware now blocks radio auto-start while SD_GET/SD_PUT is active so radio logs cannot be inserted into file bytes.
  • Do not accept byte count alone. Completion requires the device and host SHA-256 values to match. The RDS investigation verified two 3,840,000-byte downloads this way.

Classification: native-USB baud behavior is expected device operation (a how-to), port contention is a host-side troubleshooting condition, and the former radio-log interleaving was a firmware bug fixed by the transfer guard.

Do not leave this cable connected for radio or Android TV use. The PC USB Serial/JTAG link supplies VBUS and keeps the JTAG device enumerated; under Wi-Fi + RTL-SDR load that path has produced ESP_RST_BROWNOUT on a unit that is stable with the same firmware when the flash cable is unplugged. Current firmware turns the P4 brownout reset off (CONFIG_ESP_BROWNOUT_DET=n) so the sag no longer reboots the chip; glitches are still possible. Flash, close the COM port, unplug the cable, then use the LAN console.

Auth model

Two tiers, and the split is not fully consistent across the codebase (some state-changing commands require auth, some don't — documented per-command below rather than papered over):

  • Unauthenticated — works immediately over the physical serial connection. Covers all status/query commands and several state-changing ones (RTL_REC_START, RTL_TOOL, RTL_RDS_STATUS, RTL_FREQ query).
  • authenticated — gates the rest (RTL_TUNE, RTL_VOLUME <n>, RTL_CAPTURE/RTL_LISTEN, RTL_STOP, RTL_PRESET_SCAN, RTL_PRESET_TUNE). Requires the PAIR/AUTH HMAC handshake below. This exists for a remote/untrusted-host scenario (e.g. Bluetooth); if you're driving the device over a physically-attached USB cable, that trust boundary is arguably already crossed, but the gate is enforced as written today. Pair once per session:
> PAIR <32-byte-hex-key>
< PAIR_OK                              (or PAIR_LOCKED if already paired to a different key)

> AUTH <16-byte-hex-nonce> <32-byte-hex-hmac-of("host"+nonce)>
< AUTH_OK <32-byte-hex-hmac-of("device"+nonce)>

The pairing key is stored in NVS after first pair and persists across reboots. There is currently no documented out-of-band way to generate a compliant nonce/proof pair from a plain script without replicating the HMAC-SHA256 handshake — treat the authenticated commands as requiring a proper pairing client, not something to hand-roll casually.

The repository clients already implement this handshake. Use tools/help_media.py or one of the PowerShell regression/copy tools instead of printing, copying, or embedding the pairing key in a command log.

General, health, and driver commands

Command Auth What it does / how to use it
RTL_HELP no Prints the concise built-in command list between RTL_HELP_BEGIN and RTL_HELP_END.
RTL_STATUS no Reports whether the RTL-SDR is enumerated plus VID, PID, USB speed, and serial number.
RTL_HEALTH no Reports uptime, current/minimum heap, DMA heap and largest block, task count, main-task stack high-water mark, and reset reason. Use it before and during soak tests.
RTL_RESET yes Prints RTL_RESETTING and performs a software restart.
RTL_SERIAL VERBOSITY no Reads the persistent serial logging level.
RTL_SERIAL VERBOSITY <QUIET|NORMAL|DEBUG|TRACE> yes Changes and persists logging. QUIET retains command replies and crash/reset evidence.
RTL_SCREEN_STATUS no Reports active/return screens, transitions, rejected inactive draws, visible updates, and the last transition time.
RTL_UI_REGRESSION CHECK no Runs passive UI geometry/ownership checks.
RTL_UI_REGRESSION RUN yes Exercises a bounded Home-to-dashboard-to-Home transition and reports whether state was restored.
RTL_DRIVER STATUS no Reports driver version/state/capabilities, gain/AGC/bias shadows, bytes, blocks, effective sample rate, overruns, and consumer drops.
RTL_DRIVER SELF_CHECK no Verifies the installed driver exposes the minimum capabilities required by OrcSDR.
RTL_DRIVER GAINMODE <AUTO|MANUAL> yes Selects tuner automatic or manual gain mode.
RTL_DRIVER GAIN <0..496> yes Sets tuner gain in tenths of a dB; 297 means 29.7 dB. The driver may reject a value unsupported by the tuner.
RTL_DRIVER RTLAGC <ON|OFF> yes Enables or disables RTL2832 digital AGC.
RTL_DRIVER BIAS <ON|OFF> yes Controls the RTL-SDR Blog V4 bias tee. Disconnect DC-short loads before enabling it.
RTL_CAPTURE_STATUS no Reports the state of a legacy one-shot/continuous capture and, when finished, byte statistics, SHA-256, and any error.

Tuning and band control

Command Auth Reply Notes
RTL_TUNE <BAND> <HZ> yes RTL_TUNE_OK band=... frequency_hz=... BAND = FM|AM|WX|CB|LORA|BROWSE|ADSB|P25. Full retune (stops/restarts the capture path as needed).
RTL_FREQ no RTL_FREQ_STATUS band=... frequency_hz=... mode=... Query only.
RTL_FREQ <HZ> yes RTL_FREQ_OK band=... frequency_hz=... Hot retune within the current band — cheaper than RTL_TUNE, use for stepping/scanning.
RTL_CAPTURE [KZEL|NOAA|AM|LORA] / RTL_LISTEN <KZEL|FM|NOAA|WX|AM|LORA> yes RTL_CAPTURE_QUEUED ... or RTL_CAPTURE_BUSY_OR_UNAVAILABLE Older, band-limited entry point. RTL_LISTEN is continuous; RTL_CAPTURE is one-shot. Prefer RTL_TUNE for new work.
RTL_STOP yes RTL_STOPPING Stops the active capture/stream.
RTL_TOOL no RTL_TOOL_STATUS tool=RADIO|SCOPE|CAPTURE Query the active tool tab.
RTL_TOOL <RADIO|SCOPE|CAPTURE> no (none) or RTL_TOOL_INVALID Switch tool tab. Case-insensitive value.
RTL_SOUND no RTL_SOUND_STATUS enabled=0|1 Reads the audio/demod pipeline state.
RTL_SOUND <ON|OFF> no RTL_SOUND_OK enabled=... Enables or disables audio and demodulation.
RTL_AUDIO_TEST STATUS no status line Reports the audio-test state.
RTL_AUDIO_TEST TONE no status/result line Starts the built-in speaker tone test.
RTL_AUDIO_TEST FM no status/result line Routes the FM audio test path.
RTL_AUDIO_TEST STOP no status/result line Stops the active audio test.

Band default frequencies (used when a command doesn't specify one, e.g. RTL_LISTEN WX): FM 96.113 MHz (last-tuned FM freq persists in NVS and overrides this), AM/WX/CB/LoRa each have their own fixed default — see rtl_band_default_frequency() in main.cpp for exact values, they're band-plan specific and not usually worth hardcoding in a client.

Volume

Command Auth Reply
RTL_VOLUME no RTL_VOLUME_STATUS volume=<0-32>
RTL_VOLUME <0-32> yes RTL_VOLUME_OK volume=... or RTL_VOLUME_INVALID

LAN web console

Off by default. Enable from Settings → Companion or the serial commands below. The page is read-only (GET / and GET /api/status); it does not tune, change volume, or return passwords or coordinates.

Command Auth Reply
RTL_WEB / RTL_WEB_STATUS no RTL_WEB_STATUS enabled=0|1 listening=0|1 url=http://…/|offline
RTL_WEB ON|OFF yes RTL_WEB_OK enabled=… listening=… url=…

Telemetry

Command Auth Reply
RTL_STATUS no RTL_SDR_STATUS connected=... vid=... pid=... speed=... serial="..." — is the RTL-SDR dongle itself present/enumerated.
RTL_SIGNAL no RTL_SIGNAL_STATUS band=... frequency_hz=... signal_dbfs_tenths=... stereo_locked=0|1 left_dbfs_tenths=... right_dbfs_tenths=... rds_carrier=0|1 rds_signal_tenths=... pilot_env_thou=... filter_hz=... lo_nudge=... — one-shot snapshot of the dashboard and DSP state. Divide *_tenths fields by 10 for dBFS.

signal_dbfs_tenths is the RF-level meter (matches the SIG bar). left_dbfs_tenths/ right_dbfs_tenths are FM stereo decoder outputs — meaningful only when stereo_locked=1; when unlocked they mirror mono and both read the same value. rds_carrier/rds_signal_tenths are RDS Stage 1 (carrier presence only, see below) — always present on FM band regardless of whether the station actually broadcasts RDS.

FM presets

Command Auth Reply Notes
RTL_PRESET_SCAN yes RTL_PRESET_SCAN_QUEUED or RTL_PRESET_SCAN_INVALID (not on FM) Sweeps 87.5–108 MHz, ~800 kHz steps, collects up to 10 stations by signal strength. Takes tens of seconds; poll RTL_PRESET_LIST afterward.
RTL_PRESET_LIST no RTL_PRESET_LIST_BEGIN count=N then N × RTL_PRESET <n> frequency_hz=... level=... then RTL_PRESET_LIST_END Persists across reboots (NVS).
RTL_PRESET_TUNE <n> yes RTL_PRESET_TUNE_OK index=... frequency_hz=... or RTL_PRESET_TUNE_INVALID 1-based index, matching the on-screen list numbering.

RDS (FM band only)

RDS decoding is staged — see phasing.md for the current status. Stage 1 (carrier detection) and Stage 2 (bit/block sync) are hardware-verified against live 96.1 KZEL and a captured MPX replay. Stage 3 parsing/display of PS, PTY, and RadioText remains open.

Command Auth Reply
RTL_RDS_STATUS no see below
RTL_RDS_CAPTURE_START no starts an 8-second, 240 kS/s MPX capture in PSRAM
RTL_RDS_CAPTURE_STOP / RTL_RDS_CAPTURE_SAVE no stops and exports .s16 plus .json metadata to SD
RTL_RDS_CAPTURE_STATUS no capture progress, frequency, SD state, and last path
RTL_RDS_REPLAY <path.s16> no resets and replays an MPX capture through the same RDS processor; live radio must be stopped
RDS_STATUS carrier=0|1 carrier_signal=<dB> block_locked=0|1 bler=<%>
           good=<n> total=<n> hyp0_streak=<n> hyp1_streak=<n>
           timing_chip_rate=<Hz> timing_correction_ppm=<ppm>
           nco_freq_off=<rad/sample> i_lpf=<n> q_lpf=<n> mu=<0..1>
           A=<hex16> B=<hex16> C=<hex16> D=<hex16>
           driver_overruns=<n> driver_drops=<n> effective_sps=<n>
           audio_chunks=<n> audio_drops=<n>
  • carrier — Stage 1, whether 57 kHz subcarrier energy is present.
  • block_locked / bler / good / total — Stage 2 block-sync status. bler=100% with total=0 means block sync has never been achieved since tuning to this frequency, not that the signal is bad.
  • hyp0_streak / hyp1_streak — best streak for each chip-pair polarity across four fractional timing phases. A streak of 4 correctly-spaced offset-word matches declares lock.
  • A/B/C/D — last decoded block content (hex). Not meaningful until block_locked=1 — treat as noise otherwise, per the current known-issue in phasing.md.

The legacy periodic diagnostic pair is compiled off by default. Use RTL_RDS_STATUS for on-demand diagnostics without a continuous serial load:

RDS_STAGE2 locked=... bler=... good=... total=... hyp0_locked=... hyp0_streak=...
           hyp1_locked=... hyp1_streak=... nco_freq_off=... i_lpf=... q_lpf=...
           bp_env=... A=... B=... C=... D=...
RDS_TIMING chip_rate=... mu=... symbols_sec=... correction_ppm=... freq_off=...

i_lpf/q_lpf are the complex 57 kHz baseband before carrier-independent differential pairing. timing_correction_ppm reports the measured RTL sample clock calibration (-10 on the accepted fixture); nco_freq_off is retained for protocol compatibility and currently reports zero. The driver/audio fields are explicit, on-demand stream-continuity counters. symbols_sec should read close to 2375 (the RDS biphase chip rate, not the final 1187.5 bit/s information rate).

MPX capture and replay

Capture stores signed 16-bit little-endian FM multiplex samples at 240 kS/s under /orcsdr/rds_debug/, with a sibling JSON file containing the sample rate, tuned frequency, sample count, radians-per-LSB scale, and start uptime. The raw .s16 file is directly consumable by Redsea:

RTL_RDS_CAPTURE_START
... wait up to 8 seconds ...
RTL_RDS_CAPTURE_STOP
RTL_RDS_CAPTURE_STATUS

After copying the reported .s16 file to a PC:

redsea --input mpx -r 240k < capture.s16

For deterministic on-device replay, stop the live radio first and use the SD path reported by RTL_RDS_CAPTURE_STOP:

RTL_RDS_REPLAY /orcsdr/rds_debug/001_96113000_mpx.s16
RTL_RDS_STATUS

ADS-B and P25

Command Auth What it does / how to use it
RTL_ADSB_START no Starts the 1090 MHz ADS-B receive path and opens its default frequency.
RTL_ADSB_STOP no Stops reception when ADS-B currently owns the radio. A call made in another band has no reply.
RTL_ADSB_LOCATION <latitude> <longitude> no Validates decimal coordinates, persists them, and refreshes range/bearing calculations. Latitude must be -90..90 and longitude -180..180.
RTL_P25_STATUS no Reports the active profile/site, control candidates and levels, frame/NID/TSBK health, identity, BER estimate, grant/follow state, voice counters, queue drops, stack margin, and worst processing times.
RTL_P25_SCAN yes Opens P25 if needed and starts its configured control-channel survey. Poll RTL_P25_STATUS for progress.
RTL_P25_CONFIG_RELOAD yes Reloads the SD-backed P25 configuration, cancels an active survey, and retunes/redraws the P25 screen when active.

Recording (post-demod WAV capture)

Command Auth Reply
RTL_REC_START no (switches to Capture tool, starts recording)
RTL_REC_STOP no (stops and exports WAV to SD)
RTL_REC_STATUS no multi-line status (buffered seconds, sample count, last file path — see audio_rec_status_print())
RTL_REC_SAVE no re-exports the currently-held PCM buffer, useful after inserting an SD card mid-session

Capped at kAudioRecMaxSeconds (12s) per recording, 48 kHz mono PCM, written under /orcsdr/rec_NNN_<BAND>_<HZ>.wav.

SD card file transfer

Chunked binary protocol (SD_LIST, SD_GET_BEGIN/_CHUNK/_ABORT, SD_PUT_BEGIN/_CHUNK/_ABORT, SD_REMOVE) with SHA-256 verification and staged-write rollback on failure. All paths must be under /orcsdr/.

Use copy_to_tab5_sd.ps1 and copy_from_tab5_sd.ps1 rather than re-implementing the binary framing by hand; they handle chunking and hashing:

.\tools\copy_to_tab5_sd.ps1 <local-file> /orcsdr/<name> -Port COM17
.\tools\copy_from_tab5_sd.ps1 /orcsdr/<name> -Destination <local-file> -Port COM17

SD_LIST alone (no chunking needed) returns one SD_LIST_ENTRY bytes=... modified=... pathhex=<hex> line per file, then SD_LIST_DONE count=N — safe to call directly for a quick directory dump.

Command What it does / how to use it
SD_LIST Lists files beneath /orcsdr/; returned paths are hex encoded.
SD_GET_BEGIN <path_hex> Opens an allowed file for download and reports chunk/total sizes.
SD_GET_CHUNK Emits an SD_GET_DATA bytes=N header followed by exactly N binary bytes. Repeat until SD_GET_DONE supplies total bytes and SHA-256.
SD_GET_ABORT Closes an active download, or acknowledges that none is active.
SD_PUT_BEGIN <bytes> <sha256_hex> <path_hex> Creates a staged .part upload and reports the allowed chunk size.
SD_PUT_CHUNK <bytes> Announces the size of the immediately following binary payload. Repeat until the staged upload reaches its declared size and verifies its hash.
SD_PUT_ABORT Aborts the upload and removes its temporary file.
SD_REMOVE <path_hex> Removes an allowed writable file beneath /orcsdr/.

All SD writes are refused with ..._ERROR radio_busy while a capture/ stream is active — stop the radio (RTL_STOP, needs auth) or wait for it to be idle first.

Data Catalog

These commands invoke the exact same manual Data & Maps actions as the touchscreen. They never run at boot and they do not create an alternate download path. Connect Wi-Fi first, then check the signed catalog before selecting a pack by its returned stable id.

Command Auth Reply / notes
RTL_CATALOG_STATUS / RTL_CATALOG_LIST no RTL_CATALOG_STATUS, then one RTL_CATALOG_PACK per pack. Safe state query.
RTL_CATALOG_CHECK / RTL_CATALOG_FETCH yes Downloads and verifies the signed release manifest. Requires mounted SD and connected Wi-Fi. The reply uses the selected CHECK or FETCH name.
RTL_CATALOG_INSTALL <id> yes Streams the selected published pack to SD, validates its hash/schema, then activates it atomically. Run a check first.
RTL_CATALOG_REMOVE <id> CONFIRM yes Removes only the selected installed pack. The literal CONFIRM is required.

The currently named pack IDs are faa_aircraft, faa_aviation, noaa_weather, fcc_broadcast, and lane_county_map. Treat RTL_CATALOG_STATUS as authoritative because a future signed catalog can change availability and versions.

Example:

RTL_CATALOG_CHECK
RTL_CATALOG_STATUS
RTL_CATALOG_INSTALL faa_aircraft

Dashboard control

RTL_UI gives a serial agent the same semantic action handlers used by the FM, P25, LoRa, and Settings touch views. It is authenticated because every action can change device state. Credentials continue to use signed SET_WIFI; ADS-B coordinates use RTL_ADSB_LOCATION.

RTL_UI STATUS
RTL_UI OPEN ADSB
RTL_UI ACTION SETTINGS RANGE 50
RTL_UI ACTION P25 SURVEY
RTL_UI ACTION LORA VIEW 3
RTL_UI ACTION FM TUNE 101900000

RTL_UI OPEN accepts HOME, FM, P25, ADSB, LORA, RF_LAB, WIFI_ANALYSIS, or SETTINGS. RTL_UI ACTION accepts a domain and one of its visible touch actions:

  • FM: TUNE, DOWN, UP, SEEK_DOWN, SEEK_UP, SAVE, STEP, FILTER_DOWN, FILTER_UP, SPAN_DOWN, SPAN_UP, SOUND, VOL_DOWN, VOL_UP, GRAPHICS, RECORD, SCAN, SETTINGS, HOME.
  • P25: TUNE, PREV, NEXT, SURVEY, HOLD, HOLD_TG <id>, SKIP, FOLLOW, ENCRYPT_SKIP, RELOAD, SPAN_DOWN, SPAN_UP, SOUND, VOL_DOWN, VOL_UP, SETTINGS, HOME.
  • LORA: VIEW <0-5>, NODE <index>, FAVORITE, FILTER, SCAN, IQ, LOG, CLEAR, EXPORT, FOLLOW, CHANNELS, SETTINGS, HOME.
  • SETTINGS: WIFI_POWER <0|1>, WIFI_BOOT <0|1>, ANTENNA <0|1>, C6_UPDATE_CONFIRM, SCAN, CONNECT_SAVED <index>, FORGET <index>, MOVE_UP <index>, MOVE_DOWN <index>, RANGE <nm>, BRIGHTNESS <0-255>, ROTATION <1|3>, TIMEOUT <seconds>, VOLUME <0-255>, SOUND <0|1>, AUTO_START <0|1>, GRAPHICS <0|1>, WEB <0|1>, CATALOG_CHECK, CATALOG_INSTALL <index>, CATALOG_REMOVE <index>, CLOSE.

Each succeeds with RTL_UI_ACTION_OK. Inputs are intentionally routed through the existing dashboard handlers rather than duplicating touch-only state.

RTL_RF24_PAGE <0-4> is an authenticated shortcut for selecting a page on the active 2.4 GHz analysis dashboard. It returns RTL_RF24_PAGE_OK, rejects values outside 0-4, and reports dashboard_inactive if that screen is not open.

RF Lab commands

These commands drive the same test bench described in RF Lab. Only STATUS, SELF_CHECK, GET, RECIPE LIST, and RECORDS LIST are available without authentication; every other RTL_LAB command requires it.

Command What it does / how to use it
RTL_LAB OPEN / RTL_LAB CLOSE Opens RF Lab or queues its close action.
RTL_LAB STATUS Reports active page, RF source, frequency, sample rate, PPM, gain mode/value, RTL AGC, bias tee, and keep-settings state.
RTL_LAB PAGE <LIVE|CONTROLS|MEASUREMENTS|RECORDS> Selects a lab page. Names are case-insensitive.
RTL_LAB SELF_CHECK Runs RF Lab's internal bounds, parser, layout, calibration, and analysis checks.
RTL_LAB GET <id> Reads one of frequency_hz, sample_rate_sps, ppm, gain_tenth_db, gain_mode, rtl_agc, or bias_tee.
RTL_LAB SET <id> <integer> Queues a supported receiver change. The same seven IDs are accepted. gain_mode, rtl_agc, and bias_tee use 0/1. Frequency, sample-rate, PPM, gain, and driver capabilities are validated.
RTL_LAB ACTION bias_ack Opens a 30-second safety window required before RTL_LAB SET bias_tee 1. Disconnect DC-short loads first.
RTL_LAB ACTION calibrate Calculates a reference-based dBm offset when the reference and source are stable.
RTL_LAB REFERENCE STATUS Reports the configured signal-generator reference and calibration state.
RTL_LAB REFERENCE SET <hz> <source_dbm> <path_loss_db> <tolerance_db> [note] Defines the external reference used for calibration. Notes reject CSV/JSON-unsafe punctuation.
RTL_LAB REFERENCE CLEAR Clears the reference and invalidates calibration.
RTL_LAB SNAPSHOT [note] Queues a point-in-time RF Lab evidence record on SD.
RTL_LAB RUN START [seconds] Starts a measurement run. Omit seconds for a manual run; timed runs are bounded by the in-memory reading capacity.
RTL_LAB RUN MARK [note] Adds a timestamped marker to an active run.
RTL_LAB RUN STOP Finishes and queues the current run for storage.
RTL_LAB RECIPE LIST Lists the current recipe IDs: identity, transport, rate_passport, gain_quick, gain_full, tuner_auto, rtl_agc, ppm, hf_path, source_reconnect, and bias_off_on_off.
RTL_LAB RECIPE START <id> Starts a recipe. Some recipes are guided/manual and intentionally return an inconclusive status until external measurements are supplied.
RTL_LAB RECIPE STATUS Reports the active recipe and status.
RTL_LAB RECIPE INPUT <volts> Supplies the requested voltage measurement during bias_off_on_off. Follow the reported state; values are accepted only at expected stages.
RTL_LAB RECIPE CONFIRM_BIAS_SAFE Confirms it is safe for the bias recipe to energize the bias tee after the initial off-voltage check.
RTL_LAB RECIPE CANCEL Cancels the recipe/run and forces the bias tee off when applicable.
RTL_LAB RECORDS LIST Reports the recent record count and newest result.
RTL_LAB RECORDS SHOW <record-id> Returns the selected recent record and SD path.

RF visualizer commands

The visualizer commands are what let a serial client open Phosphor Persistence directly, for example:

RTL_VIS OPEN phosphor
RTL_VIS STATUS

Only STATUS, SELF_CHECK, GET, and PRESET LIST work without authentication. Other visualizer commands change UI or persisted state and require an authenticated session.

Command What it does / how to use it
RTL_VIS OPEN [view] Opens the visualizer, optionally selecting a view. Valid slugs: spectrum, waterfall, phosphor, spectrum3d, constellation, iqscope, polar, occupancy, peakavg, doppler, channelizer, audiospec.
RTL_VIS CLOSE Queues the visualizer close action.
RTL_VIS STATUS Reports active view, source availability, freeze/HUD/drawer state, presentation and analysis FPS, dropped inputs, and effective quality.
RTL_VIS NEXT / RTL_VIS PREV Moves to the next or previous view.
RTL_VIS FREEZE <ON|OFF> Freezes or resumes history updates.
RTL_VIS GET <control-id> Reads a control's formatted value and whether it is currently enabled.
RTL_VIS SET <control-id> <number> Sets a numeric, toggle, or choice control. Toggles use 0/1; choices use their zero-based option index. Values are validated and clamped by the shared UI control.
RTL_VIS ACTION <control-id> Runs an action control such as persistence.clear.
RTL_VIS PRESET LIST Lists four preset slots for the current view.
RTL_VIS PRESET <SAVE|APPLY|RENAME|DELETE> <1-4> [name] Manages the current view's persisted presets. Names are limited to 20 characters.
RTL_VIS SELF_CHECK Runs visualizer control, layout, analysis, and buffer-invariant checks.
Visualizer control IDs
  • Common: rf.center_hz, rf.span_hz, rf.gain_mode, rf.gain_db, display.floor_dbfs, display.ceiling_dbfs, display.auto_levels, display.grid, display.palette, visual.freeze, visual.quality, visual.fps_overlay; action visual.reset.
  • Spectrum: fft.size, fft.window, fft.overlap, fft.detector, fft.average_mode, fft.average_time_ms, fft.peak_hold_mode, fft.peak_hold_s, fft.peak_decay_db_s, fft.marker_count, fft.marker_threshold_db, fft.trace_thickness, fft.center_cursor; action fft.clear_peak.
  • Waterfall: waterfall.palette, waterfall.direction, waterfall.speed, waterfall.history_s, waterfall.gamma, waterfall.level_mode, waterfall.floor_dbfs, waterfall.ceiling_dbfs, waterfall.bin_mapping, waterfall.time_grid_s, waterfall.frequency_labels; action waterfall.clear.
  • Phosphor: persistence.half_life_s, persistence.accumulation, persistence.exposure, persistence.decay_curve, persistence.point_size, persistence.blur_px, persistence.palette, persistence.rare_hold_s, persistence.background_reject_db; action persistence.clear.
  • 3D spectrum: spectrum3d.slices, spectrum3d.history_s, spectrum3d.elevation_deg, spectrum3d.azimuth_deg, spectrum3d.zoom, spectrum3d.depth_scale, spectrum3d.z_gain, spectrum3d.mesh_mode, spectrum3d.color_mode, spectrum3d.line_decimation, spectrum3d.auto_orbit; action spectrum3d.reset_camera.
  • Constellation: constellation.source, constellation.profile, constellation.channel_bw_hz, constellation.points, constellation.persistence_s, constellation.point_size, constellation.normalize, constellation.axis_scale, constellation.dc_remove, constellation.phase_deg, constellation.carrier_recovery, constellation.timing_recovery, constellation.symbol_rate, constellation.show_ideal; action constellation.clear.
  • IQ scope: iqscope.traces, iqscope.timebase, iqscope.vertical_scale, iqscope.vertical_position, iqscope.coupling, iqscope.trigger_mode, iqscope.trigger_source, iqscope.trigger_level, iqscope.trigger_slope, iqscope.pretrigger_pct, iqscope.decimation, iqscope.interpolation; action iqscope.arm_single.
  • Polar: polar.source, polar.mode, polar.phase_reference, polar.rotation_deg, polar.radial_scale, polar.normalize, polar.persistence_s, polar.magnitude_gate_db, polar.trail_width, polar.angle_labels, polar.show_histogram; action polar.clear.
  • Occupancy: occupancy.band_plan, occupancy.band_count, occupancy.threshold_mode, occupancy.threshold_offset_db, occupancy.absolute_dbfs, occupancy.minimum_dwell_ms, occupancy.integration, occupancy.time_bin_ms, occupancy.basis, occupancy.alert_enabled, occupancy.alert_pct, occupancy.sort_bars; actions occupancy.reset_session, occupancy.save_csv.
  • Peak/average: peakavg.show_live, peakavg.show_average, peakavg.show_max, peakavg.average_mode, peakavg.average_time_s, peakavg.live_smoothing, peakavg.max_mode, peakavg.hold_time_s, peakavg.decay_db_s, peakavg.marker_count, peakavg.shared_scale, peakavg.trace_width; actions peakavg.clear_hold, peakavg.clear_average.
  • Doppler: doppler.span_hz, doppler.fft_size, doppler.window, doppler.integration, doppler.history_s, doppler.tracking, doppler.track_window_hz, doppler.threshold_db, doppler.reference, doppler.fixed_reference_hz, doppler.detrend, doppler.units, doppler.show_fit; actions doppler.lock_track, doppler.clear, doppler.save_csv.
  • Channelizer: channelizer.count, channelizer.layout, channelizer.plan, channelizer.bandwidth, channelizer.demod, channelizer.squelch_dbfs, channelizer.selected_offset_hz, channelizer.guard_pct, channelizer.scale_mode, channelizer.metric, channelizer.threshold_mode, channelizer.threshold_db, channelizer.refresh_hz, channelizer.selected_action, channelizer.tile_labels, channelizer.solo, channelizer.mute; actions channelizer.edit_channel, channelizer.reset_plan.
  • Audio spectrogram: audiospec.source, audiospec.sample_rate, audiospec.fft_size, audiospec.window, audiospec.overlap, audiospec.max_frequency, audiospec.frequency_scale, audiospec.floor_dbfs, audiospec.ceiling_dbfs, audiospec.normalization, audiospec.palette, audiospec.time_span_s, audiospec.preemphasis, audiospec.filter_overlay, audiospec.cursor; action audiospec.clear.

Exact ranges and choice ordering are defined in rf_visualizer_controls.cpp.

Wi-Fi automation

Wi-Fi automation uses the same bounded scan snapshot and Settings handlers as the display. SSIDs are returned as hexadecimal bytes so arbitrary SSID text cannot forge serial records. Passwords are never returned.

Command Auth Reply / behavior
RTL_WIFI_STATUS no Station/Hosted state, scan/connect state, profile/AP counts, power, auto-connect, and antenna.
RTL_WIFI_SCAN no Queues one scan; wait for RTL_WIFI_SCAN_RESULTS count=N and RTL_WIFI_COEX event=scan_complete.
RTL_WIFI_RESULTS no Bounded RTL_WIFI_AP rows with ssid_hex, BSSID, RSSI, channel, and security flag.
RTL_WIFI_PROFILES no Priority-ordered SSID-only profile list; never returns passwords.
RTL_WIFI_CONNECT_SAVED no Compatibility shortcut for saved profile 0. Indexed connection uses RTL_UI ACTION SETTINGS CONNECT_SAVED <index>.
RTL_WIFI_CONNECT_SAVED PAUSE no Queues connection to profile 0 and explicitly pauses the SDR during association.
RTL_WIFI_DISCONNECT yes Disconnects Wi-Fi and restores the paused radio/audio path.
RTL_WIFI_C6_STATUS no Reports host and C6 firmware versions, transport readiness, embedded-update availability, update stage/percent, and version match.
RTL_WIFI_C6_UPDATE CONFIRM yes Starts the explicit embedded C6 firmware update when ready. This is disruptive; poll RTL_WIFI_C6_STATUS until terminal state.
RTL_WIFI_COEX_STATUS no Reports the Wi-Fi/SDR coexistence state and counters.
SET_WIFI <ssid_hex> <pass_hex> <hmac> yes + signed payload Provisions slot 0 and attempts connection without echoing credentials.

Location commands

Command Auth What it does / how to use it
RTL_LOCATION STATUS no Reports whether a location lookup is busy/ready, the candidate coordinates in E7 form, and status text.
RTL_LOCATION IP yes Queues an IP-based location estimate; Wi-Fi must be connected.
RTL_LOCATION LOOKUP <ZIP-or-address> yes Queues a text lookup. The query must be nonempty and shorter than 64 bytes.
RTL_LOCATION CONFIRM yes Saves the ready candidate location through the same Settings action used by touch.

Power, auto-connect, antenna selection, scan, indexed connection, forget, and priority moves use authenticated RTL_UI ACTION SETTINGS ... commands listed above. Invalid boolean values and profile indices return RTL_UI_ACTION_INVALID instead of a false success.

Run the complete non-destructive hardware surface with:

apps/orcsdr-tab5/tools/run-tab5-ui-regression.ps1 -WifiOnly -PairingKeyPath <key-file>

Add -RequireWifiConnection when a real saved profile must associate for the test to pass.

UI regression

The regression command checks the shared radio-control geometry and screen ownership self-checks without changing receiver state or NVS. RUN also exercises an actual screen handoff: Home to the current FM, P25, ADS-B, or LoRa dashboard and back to Home. It refuses to run over Settings, NAV, keypad, or documentation overlays.

Command Reply Notes
RTL_UI_REGRESSION CHECK RTL_UI_REGRESSION_RESULT ... pass=1 Passive checks only.
RTL_UI_REGRESSION RUN RTL_UI_REGRESSION_RESULT ... transitioned=1 restored=1 Exercises the bounded handoff and confirms the original UI snapshot returned.

Use the repeatable runner; it disables DTR/RTS before opening COM17 so it does not reset the Tab5:

.\tools\run-tab5-ui-regression.ps1 -Port COM17
.\tools\run-tab5-ui-regression.ps1 -Port COM17 -Run
.\tools\run-tab5-ui-regression.ps1 -Port COM17 -Soak -Cycles 10 -DwellSeconds 2
.\tools\run-tab5-ui-regression.ps1 -Port COM17 -Profile Smoke
.\tools\run-tab5-ui-regression.ps1 -Port COM17 -Profile Stress -Seed 12345
.\tools\run-tab5-ui-regression.ps1 -Port COM17 -Profile Stress -Cycles 1 -WifiEvery 1
.\tools\run-tab5-ui-regression.ps1 -Port COM17 -Profile Overnight -Cycles 500
.\tools\run-tab5-ui-regression.ps1 -Port COM17 -RadioScan -Cycles 10

-RadioScan repeatedly starts FM and P25 scans, transfers tuner ownership to another dashboard during each scan, rejects stale restoration, and records heap, DMA, stack, uptime, reset, watchdog, and panic evidence. The first cycle warms the dashboards before the memory baseline is recorded. The run fails if free heap falls by more than 4 KiB, DMA-capable heap falls by more than 2 KiB, or the largest DMA-capable block falls below 20 KiB.

-Soak authenticates with .orclink\ui-doc.key, then drives every radio dashboard through Home and Settings. Smoke, Stress, and Overnight provide 5, 50, and 500-cycle defaults. Stress and Overnight randomize the radio order from the recorded seed and cycle Wi-Fi every ten passes. All profiles exercise mute/unmute, query heap health, require advancing FM audio after every return, and save a timestamped log under artifacts\ui-soak. The runner fails on panic, watchdog, brownout, assertion, reboot, timeout, exclusive-screen violation, or lost audio; after failure it stays attached briefly to capture reset evidence. It restores the starting dashboard, tuning, sound, and verbosity when possible. Use -WifiEvery 1 for a focused Wi-Fi cycle on every pass.

Serial verbosity and crash evidence

Command Reply Notes
RTL_SERIAL VERBOSITY RTL_SERIAL_VERBOSITY mode=... Query without authentication.
RTL_SERIAL VERBOSITY QUIET|NORMAL|DEBUG|TRACE RTL_SERIAL_VERBOSITY_OK mode=... Authenticated, persistent setting. NORMAL is the default.
RTL_HEALTH RTL_HEALTH_STATUS ... Heap, internal DMA, task count, uptime, and boot reset reason.

QUIET retains errors, command replies, panic text, and reset evidence. NORMAL adds normal lifecycle information. DEBUG enables periodic receiver, RDS, power, and heartbeat diagnostics. TRACE additionally enables decoded ADS-B frames, LoRa energy triggers, spectrum timing, and scan samples.

The partition table reserves a 256 KiB flash core-dump partition. With the matching ELF from build-native-hosted3, inspect a retained panic using idf.py -B build-native-hosted3 -p COM17 coredump-info.

Run the host-side crash/audio parser check without a device:

.\tools\run-tab5-ui-regression.ps1 -SelfCheck

Documentation capture

The authenticated documentation commands stage stable views and save an exact 1280x720 BMP through M5GFX. Use tools/build-help-media.ps1 instead of driving the commands by hand; it verifies the firmware/catalog, retrieves each BMP through the hash-checked SD protocol, and always attempts state restoration.

Command Reply Notes
UI_DOC_LIST UI_DOC_LIST_BEGIN, one UI_DOC_SCREEN per view, UI_DOC_LIST_DONE Enumerates the firmware-owned screen catalog.
UI_DOC_SHOW <screen-id> <live|demo> UI_DOC_SHOW_DONE Enters documentation mode without persisting navigation or demo state. Demo views carry a visible DEMO badge.
UI_CAPTURE <slug> UI_CAPTURE_DONE ... bytes=... width=1280 height=720 firmware=... sha256=... Freezes the frame, stops reception if needed, and writes /orcsdr/screenshots/<slug>.bmp.
UI_DOC_EXIT UI_DOC_EXIT_DONE restored=true Restores the prior dashboard, view, sound, and reception state.

All four commands require the normal PAIR/AUTH session. Arbitrary editors cannot be selected; the only keyboard capture is a sanitized deterministic example, so saved credentials and private location fields are never exposed.

IQ / LoRa capture

These commands serve the LoRa energy-trigger and host-decode round trip. See the repository's LoRa developer guide for the binary framing and payload formats.

Command Auth What it does / how to use it
RTL_IQ_START no Starts a bounded raw-IQ capture into PSRAM.
RTL_IQ_STOP / RTL_IQ_SAVE no Stops capture and exports it to SD. The two names currently use the same implementation.
RTL_IQ_STATUS no Reports capture/ready state, bytes, frequency, LoRa SF/BW metadata, detector state/counters, thresholds, and last SD path.
RTL_IQ_RETRIEVE_BEGIN no Locks a completed PSRAM capture for host retrieval and reports its size and RF metadata.
RTL_IQ_GET_BEGIN no Starts the binary IQ read protocol after RTL_IQ_RETRIEVE_BEGIN.
RTL_IQ_GET_CHUNK no Requests the next binary IQ chunk. Use the repository client rather than a line-only terminal.
RTL_IQ_GET_ABORT no Aborts the active binary read while retaining the completed capture.
RTL_IQ_RETRIEVE_END no Releases the completed capture and resumes LoRa reception when it was paused for retrieval.
RTL_LORA_NATIVE_STATUS no Reports decoder readiness/busy state, authorized-key presence, CRC/encryption/failure counters, preamble/header/CRC diagnostics, and CFO.
RTL_LORA_AUTO <ON|OFF> no Enables or disables the energy-triggered LoRa detector.
RTL_LORA_TUNE <HZ> no Tunes or starts LoRa reception within the firmware's allowed LoRa range.
LORA_SD_LOG <ON|OFF> no Enables or disables SD event logging.
LORA_SD_LOG STATUS no Reports requested/ready/error state, queue depth, drops, and log path.
LORA_MESSAGE <fields> no Injects a validated host-decoded message into the LoRa UI. Intended for the repository decoder workflow.
LORA_PACKET <fields> no Injects a validated host-decoded packet/metadata record into the LoRa UI. Intended for the repository decoder workflow.
LORA_MESSAGE_CLEAR no Clears displayed packets and cached node positions.

Companion and maintenance protocol

These commands support a paired host, updater, or reliability test. They are implemented serial commands, but most users should call them through the repository tooling because several require signed fields and some intentionally have no reply.

Command Auth What it does / how to use it
PING yes Refreshes the authenticated-session timeout. It intentionally has no reply.
PREPARE_FLASH <sha256_hex> yes Records host approval for a firmware digest and returns FLASH_READY <digest>. It does not itself write or flash firmware.
SET_WIFI <ssid_hex> <password_hex> <hmac> yes + signed payload Validates the signature, stores profile 0, and begins connection. Never log the password or key.
INSTALL_STATUS <revision> <max_runs> <hmac> yes + signed payload Installs a newer bounded workflow configuration and resets its run counter. Stale revisions are rejected.
ROTATE_KEY <new_key_hex> <hmac> yes + signed payload Replaces the pairing key, ends authentication, and requires the host to reconnect with the new key.
TEST_PRESSURE yes Adds ten synthetic journal events and reports how many events were dropped. Used to test bounded-journal pressure behavior.
PRESSURE_ACK yes Clears the journal's dropped-event count.
ACK <sequence> yes Acknowledges journal events through the supplied sequence. It intentionally has no reply.

The device also emits unsolicited JSON hello, snapshot, telemetry, and journal records after authentication. Those records are outputs rather than commands.

Example workflows

Tune to a specific frequency and check signal:

> RTL_TUNE FM 101900000
< RTL_TUNE_OK band=FM frequency_hz=101900000
> RTL_SIGNAL
< RTL_SIGNAL_STATUS band=FM frequency_hz=101900000 signal_dbfs_tenths=-382 stereo_locked=1 ...

Scan and tune to the strongest preset:

> RTL_PRESET_SCAN
< RTL_PRESET_SCAN_QUEUED
  (wait ~30-60s, sweeping the whole FM band)
> RTL_PRESET_LIST
< RTL_PRESET_LIST_BEGIN count=6
< RTL_PRESET 1 frequency_hz=94500000 level=-45.0
< ...
< RTL_PRESET_LIST_END
> RTL_PRESET_TUNE 1
< RTL_PRESET_TUNE_OK index=1 frequency_hz=94500000

Poll RDS decode progress while developing the decoder:

> RTL_TUNE FM 96100000
> RTL_RDS_STATUS
< RDS_STATUS carrier=1 carrier_signal=-6.2 block_locked=0 bler=100.0% ...
  (poll RTL_RDS_STATUS; continuous stream diagnostics are disabled by default)

What's not here yet

  • No JSON output mode — everything is key=value space-separated text. Fine for line-oriented parsing, more work for a strict JSON client.
  • RTL_HELP's command list is maintained by hand alongside this doc — if you add a command, update both.

Clone this wiki locally