export class RtlSdrDriver { private device: USBDevice | null = null; /** * Requests access to an RTL-SDR USB device from the user. * Must be called as a result of a user gesture (e.g., button click). */ async requestDevice(): Promise { if (!('usb' in navigator)) { throw new Error('WebUSB is not supported in this browser.'); } // Standard Vendor IDs for RTL2832U based dongles this.device = await navigator.usb.requestDevice({ filters: [ { vendorId: 0x0bda, productId: 0x2838 }, // RTL2838 DVB-T { vendorId: 0x0bda, productId: 0x2832 } // RTL2832U ] }); return this.device; } /** * Opens the USB device and claims the necessary interfaces. */ async open(): Promise { if (!this.device) throw new Error('No device selected. Call requestDevice() first.'); await this.device.open(); if (this.device.configuration === null) { await this.device.selectConfiguration(1); } await this.device.claimInterface(0); // Send a basic reset command via control transfer await this.device.controlTransferOut({ requestType: 'vendor', recipient: 'device', request: 0x01, // Example reset/init command value: 0, index: 0 }); } /** * Sets the center frequency of the SDR. * @param hz Frequency in Hertz */ async setFrequency(hz: number): Promise { if (!this.device) throw new Error('Device not connected'); console.log(`[RTL-SDR] Setting PLL frequency to ${hz} Hz`); // In a full implementation, this involves calculating PLL multipliers // and sending multiple controlTransferOut commands to the tuner IC (e.g., R820T2). } /** * Sets the sample rate. * @param rate Sample rate in Hz (e.g., 2048000 for 2.048 MSPS) */ async setSampleRate(rate: number): Promise { if (!this.device) throw new Error('Device not connected'); console.log(`[RTL-SDR] Setting sample rate to ${rate} Hz`); } /** * Sets the tuner gain. * @param gain Gain in tenths of a dB */ async setGain(gain: number): Promise { if (!this.device) throw new Error('Device not connected'); console.log(`[RTL-SDR] Setting gain to ${gain} dB`); } /** * Reads raw I/Q data from the bulk transfer endpoint. * @param length Number of bytes to read */ async readIQ(length: number = 16384): Promise { if (!this.device) throw new Error('Device not connected'); // Endpoint 1 is typically the bulk IN endpoint for RTL-SDR const result = await this.device.transferIn(1, length); return new Uint8Array(result.data?.buffer || new ArrayBuffer(0)); } /** * Closes the connection and releases the interface. */ async close(): Promise { if (this.device) { try { await this.device.releaseInterface(0); await this.device.close(); } catch (e) { console.error('Error closing RTL-SDR device:', e); } finally { this.device = null; } } } }