LakeShark · Volume 9
LakeShark Volume 9 — Flashing, Building & the C6 Dance
Web installer, two-slot OTA, the ESP-IDF source build, and the one-time C6 UART reflash
9.1 About this Volume
This is the operations volume: how to get LakeShark onto hardware, keep it updated, build it from source, and recover the one component that cannot be flashed over USB. Three audiences are served in order of effort: someone who wants a running board in five minutes (the web installer, §2), someone who wants to track the near-daily releases (OTA, §4), and someone who wants to build and modify the firmware themselves (ESP-IDF, §8).
One section — the C6 co-processor reflash (§7) — is genuinely fiddly and deserves its reputation. It is the only step that needs an external USB-UART adapter, a button dance, and correct knowledge of two different sets of flash offsets. It is also a one-time operation for most owners, after which the wireless half of the board simply works. The volume treats it in full because getting it wrong leaves Wi-Fi/BT (and therefore OTA, LINK, and DETECTOR’s beacon listening) dead.
All offsets, commands and version numbers here are drawn from the repo’s
docs/TDP4_FIRST_FLASH.md and docs/HACKRF_BRINGUP.md at the
v2.15.0 (2026-10-15) state. Version churn is real — see Vol 10 — so every
claim is dated and the repo is the tiebreaker over anything in this volume. Vol 2
carries the canonical “where this firmware runs” supported-hardware table; the
four build targets in §8 are the authoritative “what can I flash this on” list in
terms of the firmware’s own build profiles.
Warning. Two power pitfalls (§6) can disrupt a flashing session or reboot- loop the board. Read §6 before connecting anything. The short version: flash only over the right-hand USB-C, and never back-feed 5 V from the MIX-RF add-on.
9.2 The easy path: the terminalbay.com web installer
For almost everyone, flashing LakeShark is a browser operation. The author hosts a WebSerial installer that writes (and later updates) the board over USB with no toolchain installed.
Web installer
URL: terminalbay.com/?m=lakeshark&board=tdp4
Browser: Chrome or Edge (WebSerial required; Firefox/Safari will not work)
Port: the RIGHT-hand USB-C, labelled "P4U" (CH343 USB-UART)
The flow:
- Open the URL in Chrome or Edge.
- Connect the board by its right-hand USB-C port (“P4U”) — this is the P4’s flash/serial path through the CH343 bridge. The left-hand USB-C is charge- only and will not flash (§6).
- Let the WebSerial installer enumerate the port and write the images. It can also update an already-flashed board over USB, which is the fallback when OTA (§4) is not an option.
That is the whole happy path for the display. It does not flash the C6 co-processor — the C6 is on no USB port and needs the separate procedure in §7 — but a factory board already has some C6 firmware; the C6 reflash is only needed to put the ESP-Hosted build LakeShark requires in place of incompatible factory firmware.
First boot, in brief. After a successful flash the board comes up at the
launcher (ls-home.png’s layout). The two things worth doing immediately are
connecting Wi-Fi in LINK (which both proves the C6 link is up and enables OTA,
§4) and inserting a formatted microSD card (the bulk store, §5). If LINK reports
no wireless at all, the C6 is on incompatible firmware and the §7 reflash is the
fix — this is the single most common “it flashed but half of it does not work”
outcome, and it is expected on a fresh factory board.
Tip. WebSerial is a Chromium feature. If the installer never sees a port, the browser is the first suspect (use Chrome/Edge), the cable is the second (a charge-only cable presents no data lines), and the port is the third (must be the right-hand P4U, not the left charge port).
A quick triage table for the web-installer step, since three of the four common failures are not the firmware’s fault:
Table 1 — failures are not the firmware's fault
| Symptom | Most likely cause | Fix |
|---|---|---|
| No serial port offered | Non-Chromium browser | Use Chrome or Edge |
| Port offered, no device | Charge-only cable | Use a data cable |
| Enumerates then drops | Wrong USB-C port | Use the right-hand P4U port |
| Flashes, then no wireless | C6 on factory firmware | Do the C6 reflash (§7) |
The web installer is also the designated recovery tool: a board that will not boot after a bad from-source flash, or one that needs to migrate from a pre-v2.9.0 layout, is recovered by a full USB install through the same page. There is no separate “unbrick” procedure for the P4 — the P4 is always reachable over P4U, so a full reinstall is the recovery. (The C6 is the one part that can need the UART-adapter recovery of §7; the P4 never does.)
9.3 Flash offsets and what lives where
A full install from source (or a manual recovery) writes four images to the P4’s internal flash at fixed offsets. These are the P4 offsets; the C6 uses a different set (§7), and confusing the two is the classic reflash mistake.
Table 2 — 3. Flash offsets and what lives where
| Image | Offset | Role |
|---|---|---|
bootloader/bootloader.bin | 0x2000 | Second-stage bootloader |
partition_table/partition-table.bin | 0x8000 | Partition map |
lakeshark.bin | 0x10000 | The application |
storage.bin | 0x910000 | On-board storage (settings, saved Wi-Fi) |
From an ESP-IDF build tree, the full install is driven by the build’s own flasher args rather than by typing offsets by hand:
# Full install from a source build (writes all images + OTA data init)
idf.py -B build_tdp4 -D SDKCONFIG=build_tdp4/sdkconfig -p YOUR_PORT flash
# build_tdp4/flasher_args.json carries the offsets above + OTA-data init
Warning. A full install rewrites internal storage. Back up SD-card data and note your saved Wi-Fi before a full reinstall. A two-slot OTA update (§4) preserves settings and saved Wi-Fi; a from-scratch flash does not necessarily, and the storage partition at
0x910000is the thing being overwritten.
Note the P4 bootloader lives at 0x2000 — remember this number, because the C6
bootloader is at 0x0, and §7 depends on keeping the two straight.
9.4 Two-slot signed OTA
LakeShark releases are near-daily, so updating matters, and since v2.9.0 the firmware updates itself over Wi-Fi with a fail-safe two-slot (A/B) scheme.
How it works:
- The app partition is split into two slots. A new build is written to the inactive slot, verified, then booted. The old slot is retained.
- Updates are signed. If a new build fails to boot, the board automatically reverts to the previous slot — a bad update cannot brick the device.
- Because the running app can be in either slot, there is no fixed app offset
for an update (unlike the one-shot install in §3). This is why OTA tooling must
not assume
0x10000.
The operator flow:
LINK → connect Wi-Fi (needs the C6 running ESP-Hosted, §7)
HOME > SYSTEM > UPDATE → pull and apply the new build to the spare slot
SET > DEVICE > Check for updates → Daily | Off
The two-slot design is worth appreciating as a reliability feature on a
near-daily-release project. On a single-slot device, a bad update that fails to
boot bricks the unit until it is re-flashed over USB; on LakeShark, the old slot
is retained untouched and the signed new build is only committed once it boots, so
a failed update is a silent no-op rather than a brick. That is precisely the
safety margin a user needs to be comfortable running the Daily update cadence —
the cost of staying current is near zero because the downside is bounded by the
revert. It also means the “which slot is running” question has no fixed answer,
which is why OTA tooling must never assume the app is at 0x10000 (that is the
initial install offset only, §3).
The one prerequisite is the boundary condition worth flagging: boards on v2.8 or earlier do not have the two-slot layout, so they need one full USB or web install to lay down the new partition scheme before OTA is available. That first install rewrites internal storage but keeps settings and saved Wi-Fi. After it, every subsequent update can be OTA.
Table 3 — 4. Two-slot signed OTA
| Mechanism | When to use |
|---|---|
| Web installer (§2) | First flash; recovery; pre-v2.9.0 → v2.9.0+ migration |
| Two-slot OTA | Every routine update on v2.9.0+ |
From-source idf.py flash (§8) | Developers / custom builds |
The update cadence is set from the SET > DEVICE > Check for updates control,
which offers Daily or Off. Given the near-daily release pace (Vol 10 §8),
Daily is the way to stay current without manual checking; Off is the way to pin a
known-good build and update deliberately. Either way the two-slot revert is the
safety net — an update that does not boot falls back to the slot that did.
Note. OTA depends on Wi-Fi, Wi-Fi depends on the C6, and the C6 depends on the correct ESP-Hosted firmware (§7). A board whose C6 is on factory firmware cannot OTA — which is exactly the chicken-and-egg the C6 reflash resolves.
9.5 The SD card and its roles
A microSD card is LakeShark’s bulk store. The repo does not publish a size or format specification, but it names the roles the card plays, and they add up to “everything the internal flash is too small for”:
Table 4 — "everything the internal flash is too small for"
| SD role | Content |
|---|---|
| Call / recording archive | P25 call archive, voice recordings |
| Music | MUSIC app media |
| Sub-GHz library | .sub captures (Vol 8 §3) |
| Notes | NOTES app Markdown files |
| C6 firmware images | For SD-based C6 updates after the first UART flash (§7) |
| DETECTOR rules | User rules file (Vol 8 §7) |
| Map tiles | Offline PMTiles (Vol 6) |
The C6-images role is the one that saves future pain: once the C6 has been flashed over UART the first time (§7), later C6 updates can be applied from the SD card without the adapter and the button dance. So the SD card is not just a data store — it is the C6’s maintenance path after the initial bring-up.
The division of labour between internal flash and SD is the usual MCU pattern:
the 16 MB internal flash holds the bootloader, two app slots and a small settings
partition (§3), while everything large and user-generated — call archives,
recordings, music, .sub captures, notes, map tiles — lives on SD. That means a
full P4 reinstall (§3) loses settings/storage but leaves the SD-card content
alone, and conversely reformatting the SD card loses captures and maps but not the
firmware or its settings. Backing up the SD card before a from-scratch session is
cheap insurance precisely because the two stores fail independently.
Note. Because no explicit format spec is published, a standard FAT/exFAT card of ordinary capacity is the safe assumption. Keep a backup of anything on the card before a full P4 reinstall (§3), since a from-scratch session is exactly when a card is most likely to be reformatted by mistake.
9.6 Power pitfalls — the part that bricks a session
Two power rules are documented as hardware hazards, not preferences. Both are easy to violate because the board has three USB connectors and an add-on with its own power output.
1. Flash only over the right-hand USB-C (P4U). The board has two USB-C ports. The right-hand one (“P4U”, CH343 bridge) carries flash and serial. The left-hand one is charge-only and presents no data path. A flashing session that will not enumerate is very often a cable plugged into the charge port.
2. Never back-feed 5 V from the MIX-RF add-on into the P4. The MIX-RF keyboard (Vol 8 §5) has a 5 V USB output. Routing it back into the P4 caused repeated power cycling (reboot loops) in testing. Power the P4 only from its own USB-C; let the add-on draw from the board, not push into it.
T-Display P4 USB map
┌───────────────┐
│ [L] USB-C │ charge only — will NOT flash
│ [R] USB-C P4U│ flash + serial (CH343) ← use this
│ USB-A host │ RTL-SDR dongle in here
└───────────────┘
MIX-RF 5V out ──╳──► NEVER into the P4 (reboot loop)
C6 UART header ──────► external 3.3V USB-UART only (§7)
Warning. A related item is still in development: a shared battery pack for the P4 and the RTL-SDR is not finished. Powering a thirsty RTL-SDR and the P4 off one ill-designed supply invites brownouts; until the shared pack ships, power them cleanly and expect the RTL-SDR to be a real current draw.
The RTL-SDR’s draw is worth taking seriously for battery planning: an RTL2832U+R820T2 dongle pulls a few hundred milliamps continuously while streaming, on top of the P4, AMOLED and C6. That is why the shared-pack work exists and why, until it lands, a generous battery and a clean supply matter more than they would on a receive-only ESP32 toy. The BQ27220 fuel gauge (Vol 2) at least gives an honest state-of-charge readout while the power story is being sorted.
9.7 The C6 co-processor reflash — the fiddly bit
LakeShark’s wireless features — Wi-Fi, Bluetooth, OTA, LINK, DETECTOR’s beacon
listening — all run on the onboard ESP32-C6, not on the P4 (the P4 has no
radio of its own, Vol 2). The C6 must run a specific build: ESP-Hosted 2.12.9,
the network_adapter firmware shipped in the repo’s c6_firmware/. Factory ESP-AT
firmware and other ESP-Hosted versions do not work — a board on the wrong C6
firmware logs a transport timeout and has no wireless.
The complication: the C6 is on no USB port. It can only be flashed through its UART header with an external 3.3 V USB-to-UART adapter. This is the “C6 dance.”
Step 1 — prepare the P4. Flash LilyGO’s coprocessor_download_mode image over
P4U (the right USB-C) and wait for the serial line:
"Coprocessor preparation completed."
This temporarily overwrites LakeShark on the P4 (step 4 restores it) and puts the P4 into a mode that bridges to the C6 for flashing.
Step 2 — wire the adapter, RX and TX crossed. A 3.3 V USB-UART adapter on the C6 UART header:
C6 RX ←── adapter TX (crossed)
C6 TX ──→ adapter RX (crossed)
C6 GND ←─→ adapter GND
C6 3.3V NOT connected — the board powers the C6 itself
Warning. Do not connect the adapter’s 3.3 V to the C6. The board powers the C6; feeding a second 3.3 V source in is the C6-side equivalent of the MIX-RF 5 V back-feed in §6.
Step 3 — enter download mode and flash. Hold the C6 BOOT button, press and
release RESET, then release BOOT. Flash the four C6 images with esptool.py —
and note these are C6 offsets, different from the P4 offsets in §3 (C6
bootloader at 0x0, not 0x2000):
esptool.py -c esp32c6 -p YOUR_ADAPTER_PORT -b 460800 write_flash \
0x0 c6_firmware/bootloader.bin \
0x8000 c6_firmware/partition-table.bin \
0xd000 c6_firmware/ota_data_initial.bin \
0x10000 c6_firmware/network_adapter.bin
Note the -b 460800 baud and the explicit -c esp32c6 — the adapter talks to the
C6 directly here, not through the P4, so the port in the command is the adapter’s
serial port, not P4U. This is the one place in the whole flashing story where the
port is not P4U, and getting that wrong is a common early stumble.
Step 4 — restore LakeShark on the P4. Flash the P4 again over P4U (web
installer or idf.py flash), then power-cycle. Confirm the link came up in the
serial log:
I (....) headless: ESP-Hosted co-processor link: up (0)
Table 5 — 7. The C6 co-processor reflash — the fiddly bit
| Offset | P4 (§3) | C6 (this section) |
|---|---|---|
| bootloader | 0x2000 | 0x0 |
| partition table | 0x8000 | 0x8000 |
| ota_data | (in flasher args) | 0xd000 |
| app | 0x10000 (lakeshark.bin) | 0x10000 (network_adapter.bin) |
A triage table for when step 3 or 4 does not go cleanly:
Table 6 — A triage table for when step 3 or 4 does not go cleanly
| Symptom | Likely cause | Fix |
|---|---|---|
| esptool cannot connect to C6 | Not in download mode | Re-do BOOT-hold / tap RESET / release BOOT |
| esptool connects, wrong chip | -c esp32c6 omitted / wrong port | Set the chip and the adapter port |
| Flashes, but no wireless after | Wrong offsets (used P4’s) | C6 bootloader is 0x0, not 0x2000 |
| No “link: up (0)” after restore | C6 image mismatch | Confirm ESP-Hosted 2.12.9 images |
| Intermittent / brownout | 3.3V back-fed from adapter | Leave adapter 3.3V disconnected |
Note. This is a one-time operation. Once the C6 runs ESP-Hosted 2.12.9, later C6 updates can be pushed from the SD card (§5) without the adapter or the button dance. The UART path is still the recovery route if an SD update ever fails. See
c6_firmware/README.md.
Tip. The single most common C6-reflash mistake is reusing the P4 offsets. They are not the same map: the C6 bootloader is at
0x0, the P4 bootloader is at0x2000. Keep the twowrite_flashcommand lines in separate files so they never get crossed.
9.8 Building from source: ESP-IDF 5.5.4 and the per-board profiles
For developers, LakeShark builds against Espressif’s ESP-IDF 5.5.4, with six
patches applied via bench/patch-idf.ps1 (documented in bench/IDF554.md). Both
LoRa variants (SX1262 and LR2021) build from the same image — the firmware
auto-detects the radio at boot (Vol 7 §2), so there is no separate build per
radio.
There are four build targets, one per supported board/display:
Table 7 — There are four build targets, one per supported board/display
| Target | Board / display | Build dir | Extra defaults |
|---|---|---|---|
| TDP4 AMOLED | T-Display P4, RM69A10 568×1232 | build_tdp4 | boards/t_display_p4.defaults |
| TDP4 TFT | T-Display P4, HI8561 540×1168 | build_tdp4_tft | … + boards/t_display_p4_tft.defaults |
| Waveshare P4 headless | Waveshare ESP32-P4-NANO / WIFI6, no display | build_nano | boards/nano_headless_ble.defaults |
| Waveshare LCD-4.3 | Waveshare P4 with 4.3” LCD | (per-board profile) | (per-board defaults) |
Each target differs in exactly two dimensions — display and whether there is one at all — which is why one codebase covers all four. The AMOLED and TFT builds are the same T-Display P4 hardware with different display controllers (RM69A10 vs HI8561) and resolutions; the two Waveshare targets drop the display entirely (headless) or carry a 4.3” LCD. The radio variant (SX1262 vs LR2021) is not a build dimension — both ship in the same image and are auto-detected at boot, so there is no “SX1262 build” to pick wrong.
The AMOLED build, as the canonical example:
# Build (AMOLED T-Display P4)
idf.py -B build_tdp4 \
-D SDKCONFIG=build_tdp4/sdkconfig \
-D SDKCONFIG_DEFAULTS="sdkconfig.defaults;boards/t_display_p4.defaults" \
build
# TFT variant: build dir build_tdp4_tft, and append boards/t_display_p4_tft.defaults
The four C6 images flashed in §7 correspond one-to-one to the ESP-Hosted layout:
bootloader.bin (the C6’s second-stage boot), partition-table.bin (its map),
ota_data_initial.bin (initial OTA-slot selector), and network_adapter.bin (the
ESP-Hosted application itself — the part that makes the C6 behave as the P4’s
radio). Mismatching any of them to a different ESP-Hosted version is the quiet way
to end up with a C6 that enumerates but never brings the link up.
Building on Linux. The bench tooling (patch-idf.ps1, the wrap/build
helpers) is PowerShell and Windows-first, which is a friction point on a Linux
workstation. The patches those scripts apply are mandatory, but the underlying
operations are ordinary IDF ones; the portable route is to install ESP-IDF 5.5.4,
apply the equivalent patches described in bench/IDF554.md by hand (or run the
.ps1 under PowerShell Core, which exists on Linux), and then drive the per-board
idf.py invocations above directly. There is nothing Windows-specific in the
firmware — only in the convenience wrappers.
Two practical flags for anyone cloning the repo:
- The build tooling is PowerShell-oriented. The patch script (
patch-idf.ps1) and bench tooling are.ps1— Windows-first. On Linux/macOS the equivalentidf.pyinvocations above still work; the.ps1wrappers are convenience, not a hard dependency, but the patches they apply are required. - There is a stale SDK in the tree. The repo carries a leftover
sdk/esp-idf-5.4.3alongside the required 5.5.4.Build against 5.5.4; the 5.4.3 directory appears to be a vestige and should not be used.
Tip. The per-board
SDKCONFIG_DEFAULTSchain is the mechanism that keeps one codebase building four different physical products. The basesdkconfig.defaultssets the common config; each board’s.defaultslayered after it overrides display, radio and feature settings. Do not edit a generatedsdkconfigby hand — change the.defaultsso the difference is tracked.
Why the IDF patches exist. LakeShark applies six patches to a stock ESP-IDF
5.5.4 via bench/patch-idf.ps1 (described in bench/IDF554.md). The reason is the
same one that dominates the whole project: the P4’s USB-host stack and the
real-time demands of streaming an RTL-SDR at 2 MSPS push on parts of IDF that a
typical application never touches. The HackRF bring-up notes (see the HackRF
discussion in Vol 3 and §3 here) record one concrete example of the class of
problem being worked around — USB interface claims failing with ESP_ERR_NO_MEM
because 512-byte-aligned DMA descriptors could not be allocated from PSRAM, fixed
by reserving internal 512-byte slots managed by an atomic bitmap while keeping the
IQ ring in PSRAM. Patches of that flavour are why a stock IDF checkout is not
enough; apply the bench patches or the USB-host path will not behave.
A rough map of the internal flash a build lays down (the storage partition at
0x910000 is the one a full reinstall overwrites, §3):
P4 internal flash (16 MB)
0x002000 bootloader
0x008000 partition table
0x00d000 (ota data)
0x010000 app slot A (lakeshark.bin) ─┐ two-slot OTA
0x… app slot B ─┘ (running app in either)
0x910000 storage (settings, saved Wi-Fi)
The DIAG app is the on-device counterpart to all of this: it reports radio presence, the C6 link state, sensor health and USB enumeration, and is the first place to look when a feature is silently absent. A dead wireless stack shows up in DIAG (and the serial log) as the missing “co-processor link: up (0)” line from §7; a missing RTL-SDR shows up as no USB radio enumerated. Reach for DIAG before assuming a flash failed.
9.9 Headless and Flipper-control-head modes
LakeShark does not require its display. Two “no-screen” modes exist, and they turn the firmware into something closer to a receiver module driven by another device.
Headless mode runs on the Waveshare ESP32-P4-NANO and ESP32-P4-WIFI6
boards — same receivers, no display — built with the build_nano target and
boards/nano_headless_ble.defaults (§8). Control is through the serial console
or over Bluetooth from a Flipper Zero. This is the right form for a fixed install
(a monitoring node in a known location) or for anyone who wants the decode engine
without paying for the AMOLED. Because the receiver stack is identical to the
T-Display P4 build, a headless node loses nothing but the screen — it decodes the
same P25/FM/ADS-B/POCSAG and hosts the same RTL-SDR; it simply presents the result
over serial (or to a Flipper) instead of on glass.
Flipper control-head mode turns a Flipper Zero into LakeShark’s display and
keypad. The companion LakeShark-Flipper app connects over Bluetooth (on the
T-Display P4) or GPIO, and the radio advertises its connection and pairs
automatically with no pairing code. The Flipper then shows LakeShark’s
screens — the launcher, the offline aircraft map, ADS-B traffic, and the P25 radio
view are the ones demonstrated.
Control topologies
┌─ T-Display P4 ─┐ its own AMOLED/TFT + touch (default)
┌─ Waveshare P4 ─┐ headless: serial console OR BT → Flipper
┌─ any P4 board ─┐ LakeShark-Flipper app: Flipper = screen+keys (BT/GPIO)

The Flipper-as-control-head idea is one of the firmware’s more distinctive
integration choices, and it ties LakeShark to the Flipper Zero deep dive elsewhere
in this hub — the same .sub interchange (Vol 8 §3) and now a shared display
role. For an owner who already carries a Flipper, a headless Waveshare P4 plus the
Flipper app is a cheaper, pocketable way into the decode engine than the full
AMOLED board.
A quick decision table for the three ways to drive the firmware:
Table 8 — A quick decision table for the three ways to drive the firmware
| Topology | Board | Display / control | Best for |
|---|---|---|---|
| Native | T-Display P4 | Onboard AMOLED/TFT + touch | The default, all-in-one handheld |
| Headless + serial | Waveshare P4-NANO/WIFI6 | Serial console | Fixed monitoring node, scripted |
| Headless + Flipper | Waveshare P4 (or TDP4 over BT) | Flipper Zero screen+keys | Carrying a Flipper already; pocketable |
The serial-console control of the headless build is also the plain-text way to
drive the device for logging or automation: the TERMINAL/console is where
commands like radios ble off (persisted in NVS) and the hackrf diagnostics
(Vol 3) live, and a headless node on a serial tether can be scripted the way any
console device can. That makes the Waveshare headless target the natural choice
for an always-on receiver feeding a larger system, with the AMOLED board reserved
for the walk-around use case.
Note. Automatic, codeless pairing is convenient but means the radio will accept a control-head connection without authentication. For a device that can key sub-GHz and LoRa transmitters (Vols 7–8), that is worth remembering in any threat model, even though in practice the BT range is short and the feature is aimed at the owner’s own Flipper.
The shape of the whole operations story, in one line each: the web installer is
the five-minute path for almost everyone; two-slot OTA keeps a fast-moving device
current without risk; the SD card holds everything large and fails independently
of the firmware; the ESP-IDF source build is there for developers, four targets
from one tree; and the C6 dance is the one genuinely fiddly step — a one-time
UART reflash, after which the wireless half simply works and future C6 updates
come from SD. Get the port and the bootloader offsets right (right-hand P4U;
0x2000 for the P4, 0x0 for the C6) and nothing here is difficult. Get them
wrong and the symptoms are exactly the ones the triage tables above name.
Vol 10 closes the dive: how LakeShark compares to a PC-plus-RTL-SDR, a HackRF/PortaPack and other ESP32 SDRs; the open-source credit map; the legal and RF-listening envelope; the version-churn caveat; and a laminate-ready quick- reference card.
Comments (0)