Self-contained ESP-IDF component (firmware/esp32p4-sensor-node/components/ rtlsdr_experimental/) exploring RTL2832U-over-USB-host on the ESP32-P4, ported from frontend/src/lib/sdr.ts's researched WebUSB protocol sequence (vendor commands, I2C-repeater tuner init) to the ESP-IDF USB Host Library. Implements: USB Host Library install/client lifecycle, RTL2832U/Terratec vendor-ID device matching, the demod+R820T init vendor-command sequence over control transfers, a pipelined bulk-IN read loop for raw IQ, and an inert-by-default upstream IQ-forwarding stub targeting a proposed separate binary endpoint (not the JSON telemetry shape — reasoning documented in the README) since no such backend endpoint exists yet. Off by default (RTLSDR_EXP_ENABLE Kconfig, default n). Unverified against real hardware and never compiled (no ESP-IDF toolchain in this environment) — marked as such in every source file and in a dedicated "Workstream J" section of firmware/esp32p4-sensor-node/README.md, which this commit also creates since Workstream I's core skeleton (owned by a separate, unmerged worktree) hadn't created one yet. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
152 lines
7.7 KiB
C
152 lines
7.7 KiB
C
/*
|
|
* rtlsdr_experimental.h — EXPERIMENTAL RTL2832U-over-USB-Host module for the
|
|
* ESP32-P4 sensor node (Workstream J, ESP32-P4 Sensor Node spec).
|
|
*
|
|
* ============================================================================
|
|
* HARDWARE PASS REQUIRED — UNVERIFIED AGAINST REAL HARDWARE
|
|
* ============================================================================
|
|
* This entire module (this header + rtlsdr_experimental.c) has been written
|
|
* from documented ESP-IDF USB Host Library API shape and the RTL2832U/R820T
|
|
* register sequence already researched for this project in
|
|
* frontend/src/lib/sdr.ts (a WebUSB driver, real and documented against
|
|
* librtlsdr's public register map). It has NOT been compiled against a real
|
|
* ESP-IDF toolchain (none is available in this environment) and has NOT run
|
|
* against real ESP32-P4 + RTL2832U dongle hardware. Treat every register
|
|
* value, timing constant, buffer size, and API call signature here as
|
|
* "structurally reasoned, not verified." See the "Workstream J" section of
|
|
* ../../README.md for the full honesty write-up, including exactly what a
|
|
* real hardware bring-up session needs to check before this is trusted.
|
|
*
|
|
* Scope reminder: this is a self-contained ESP-IDF *component*, deliberately
|
|
* kept out of `main/` so it can be dropped into Workstream I's firmware
|
|
* project skeleton (WiFi/HTTP/BME280/presence-sensor core) without touching
|
|
* any file that workstream owns. Integration is one line in the consuming
|
|
* project: add this directory to EXTRA_COMPONENT_DIRS (or copy it under that
|
|
* project's own components/) and call rtlsdr_exp_init()/rtlsdr_exp_start()
|
|
* from wherever app_main() sets up its other sensor drivers.
|
|
* ============================================================================
|
|
*/
|
|
#pragma once
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
|
|
#include "esp_err.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* USB identification — ported 1:1 from frontend/src/lib/sdr.ts
|
|
* (RTL2832U_VENDOR / RTL2832U_PRODUCTS / TERRATEC_VENDOR, lines ~30-34).
|
|
*
|
|
* sdr.ts deliberately filters WebUSB's device picker by *vendor* id only
|
|
* (see its requestDevice() comment: "many dongles report product ids
|
|
* outside the handful we know, so filtering by productId hides them from
|
|
* the picker"). We mirror that: RTLSDR_EXP_KNOWN_PRODUCT_IDS below is
|
|
* informational only (used for a startup log line), never a hard match
|
|
* filter. Any device presenting vendor id RTL2832U or TERRATEC is treated
|
|
* as a candidate and bring-up is attempted.
|
|
* ------------------------------------------------------------------------ */
|
|
#define RTLSDR_EXP_VENDOR_RTL2832U 0x0BDAu
|
|
#define RTLSDR_EXP_VENDOR_TERRATEC 0x0CCDu
|
|
|
|
/* Known RTL2832U product ids (informational/logging only — see above). */
|
|
extern const uint16_t RTLSDR_EXP_KNOWN_PRODUCT_IDS[4];
|
|
#define RTLSDR_EXP_NUM_KNOWN_PRODUCT_IDS 4
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* Configuration
|
|
* ------------------------------------------------------------------------ */
|
|
typedef struct {
|
|
/* Tuning defaults, applied once bring-up completes. Matches sdr.ts's
|
|
* open(sampleRateHz = 2_048_000) default and its FM-band test tune of
|
|
* 98 MHz — pick whatever the product actually wants to listen to. */
|
|
uint32_t center_freq_hz; /* e.g. 98_000_000 */
|
|
uint32_t sample_rate_hz; /* e.g. 2_048_000 */
|
|
|
|
/* Bulk-IN read tuning. bulk_read_chunk_bytes MUST be a multiple of 512
|
|
* (USB high-speed bulk max packet size) — this mirrors sdr.ts's own
|
|
* assumption ("Length must be multiple of 512" on readSamples()).
|
|
* UNVERIFIED: real chunk size vs. USB Host Library heap/DMA limits and
|
|
* actual achievable throughput needs a real device. See README. */
|
|
size_t bulk_read_chunk_bytes; /* default suggestion: 16384 */
|
|
size_t bulk_read_queue_depth; /* in-flight pipelined transfers, e.g. 4 */
|
|
|
|
/* Upstream IQ forwarding (see rtlsdr_exp_forward_iq_block() and the
|
|
* "IQ forwarding architecture" section of the README for the reasoning
|
|
* behind a *separate* raw-binary stream rather than reusing the JSON
|
|
* sensor telemetry endpoint). NOTE: the backend endpoint referenced
|
|
* here does not exist yet anywhere in this repo as of this workstream —
|
|
* this is a client-side stub against a *proposed* shape, not a wired
|
|
* integration. */
|
|
const char *iq_upload_url; /* e.g. "https://host/api/device/iq-stream" */
|
|
const char *device_bearer_token; /* same raw pairing token used for
|
|
* the regular telemetry POST loop */
|
|
} rtlsdr_exp_config_t;
|
|
|
|
/* Fills in documented, conservative defaults. Caller still MUST set
|
|
* iq_upload_url / device_bearer_token before starting. */
|
|
void rtlsdr_exp_config_default(rtlsdr_exp_config_t *config);
|
|
|
|
typedef struct rtlsdr_exp_handle_s *rtlsdr_exp_handle_t;
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* Lifecycle
|
|
* ------------------------------------------------------------------------ */
|
|
|
|
/* Allocates internal state. Does NOT touch USB hardware yet. */
|
|
esp_err_t rtlsdr_exp_init(const rtlsdr_exp_config_t *config, rtlsdr_exp_handle_t *out_handle);
|
|
esp_err_t rtlsdr_exp_deinit(rtlsdr_exp_handle_t handle);
|
|
|
|
/* Installs the USB Host Library, registers a client, and spawns the
|
|
* background tasks that watch for a matching RTL2832U device, run the
|
|
* init vendor-command sequence on attach, and (once bring-up succeeds)
|
|
* start the bulk-IN read/forward loop. Non-blocking — returns once the
|
|
* tasks are created, not once a device is found.
|
|
*
|
|
* UNVERIFIED beyond "this is the documented shape of the ESP-IDF USB Host
|
|
* Library API" — see README for exactly what needs a real board to check. */
|
|
esp_err_t rtlsdr_exp_start(rtlsdr_exp_handle_t handle);
|
|
|
|
/* Stops streaming, releases the USB interface/device if held, deregisters
|
|
* the USB Host client, and tears down the background tasks. Does NOT call
|
|
* usb_host_uninstall() if other USB Host clients might still be active in
|
|
* the wider firmware project (Workstream I owns whether anything else in
|
|
* the project also uses USB host) — see README integration notes. */
|
|
esp_err_t rtlsdr_exp_stop(rtlsdr_exp_handle_t handle);
|
|
|
|
/* Best-effort retune while streaming — same caveats as sdr.ts's
|
|
* setFrequency()/setSampleRate() (simplified PLL/resampler math, marked
|
|
* HARDWARE PASS REQUIRED there too). */
|
|
esp_err_t rtlsdr_exp_set_frequency(rtlsdr_exp_handle_t handle, uint32_t hz);
|
|
esp_err_t rtlsdr_exp_set_sample_rate(rtlsdr_exp_handle_t handle, uint32_t hz);
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* Observability — deliberately exposed so this experimental module can
|
|
* report its own health (e.g. folded into the regular sensor_type registry
|
|
* as a synthetic "sdr_status" reading) rather than fail silently.
|
|
* ------------------------------------------------------------------------ */
|
|
typedef struct {
|
|
bool device_present; /* a matching-vendor USB device is enumerated */
|
|
bool bring_up_ok; /* init vendor-command sequence completed without
|
|
* a control-transfer error (does NOT mean the
|
|
* tuner/demod are actually producing valid IQ —
|
|
* only real hardware + a spectrum check can
|
|
* confirm that) */
|
|
bool streaming;
|
|
uint32_t bulk_reads_ok;
|
|
uint32_t bulk_reads_failed;
|
|
uint32_t iq_blocks_dropped; /* forward queue was full — see README */
|
|
uint32_t bytes_forwarded_upstream;
|
|
uint32_t forward_failures;
|
|
} rtlsdr_exp_stats_t;
|
|
|
|
void rtlsdr_exp_get_stats(rtlsdr_exp_handle_t handle, rtlsdr_exp_stats_t *out_stats);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|