-
Notifications
You must be signed in to change notification settings - Fork 68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Port from librtlsdr to SoapySDR API (rtl_fm, rtl_sdr, and rtl_power) #1
Conversation
Current status: able to list devices, open, set some settings, but cannot yet receive samples. librtlsdr has an rtlsdr_read_async API with a callback, data as pairs of unsigned 8-bit values, SoapySDR has streams, and can read in a variety of formats (SOAPY_SDR_U8 for compatibility), not yet working, some impedance mismatches, but not by much. Crashes in buffer handling:
|
…nd Q) invalid format 'U8' -- Only CS8, CS16 and CF32 are supported by SoapyRTLSDR module
Some progress, there is now stream output, but when played through When piped through to sox to convert to wav: ./rtl_fm -M wbfm -f 107.1M | sox -r 32k -t raw -e s -b 16 -c 1 -V1 - -t wav /tmp/a.wav it is a solid buzzing sound: https://soundcloud.com/user-223812058/rtl-fm-fail-1 Audacity plot spectrum shows: |
Slight problem: SoapyRTLSDR reports native format as SOAPY_SDR_CS8 (complex signed 8-bit pairs), but is actually CU8 (unsigned), the driver actually subtracts 127 https://github.com/pothosware/SoapyRTLSDR/blob/a44abc3f1ac2c62d707902551f1c2c1e70551c84/Streaming.cpp#L372-L391 - although the direct stream access API uses CU8, see pothosware/SoapyRTLSDR#15. But even then, something seems wrong with the samples:
actually not necessarily, rtlsdr_callback first thing does:
unnecessary conversions (-127 in SoapyRTLSDR, +127 in rtl_fm dongle_thread_fn, then -127 in rtl_fm rtlsdr_callback!) but now fixing the buffer types, get choppy static |
It may be more straightforward to port rtl_sdr first, since it outputs raw I/Q samples, without the complexity of FM demodulation to debug. Pushed what I have so far, but quite broken, curiously readStream returns 8192 bytes but all bytes are 00 or 01(?), not sure what is happening here. |
Turning up the gain (-g 40 with rtl_sdr) gives more interesting results:
at a lower gain, 00 and 01 similar to 7f and 80 (signed/unsigned offset) with librtlsdr rtl_sdr. However, with no gain specified, librtlsdr rtl_sdr works as expected, but this branch rtl_sdr only shows 00/01's. Auto-gain is not set, in src/convenience/convenience.c verbose_auto_gain (and verbose_gain_set), couldn't find an equivalent for rtlsdr_set_tuner_gain_mode(dev, 0); (= set auto gain) and rtlsdr_set_tuner_gain_mode(dev, 1); (= set manual gain). Not called in SoapyRTLSDR: https://github.com/pothosware/SoapyRTLSDR/search?utf8=✓&q=rtlsdr_set_tuner_gain_mode - so for now, will need to set gain explicitly (or hardcode a reasonable default?). update: filed pothosware/SoapyRTLSDR#21 Automatic gain mode setting, rtlsdr_set_tuner_gain_mode(dev, 0) equivalent |
With gain, something can now be heard, just barely:
but it is still choppy (the rtl_fm stream starts and stops). Recording to a .wav file on disk with sox (therefore removing the gaps): https://soundcloud.com/user-223812058/rtl-fm-progress-1 it sounds noisy but also as if it was sped up. Halving the sample rate ( Another potential problem: setting the bandwidth? "Bandwidth set to automatic resulted in 0 Hz." vs expected "Bandwidth set to automatic resulted in 350000 Hz.". verbose_set_bandwidth uses rtlsdr_set_and_get_tuner_bandwidth, to both set and get the bandwidth. 0 indicates "automatic", meaning equal to the sampling rate ( Setting bandwidth is relatively "new", rtlsdr_set_tuner_bandwidth was added in librtlsdr/librtlsdr@92df068 Mar 17, 2015 see http://lists.osmocom.org/pipermail/osmocom-sdr/2015-June/000077.html. Other projects have ran into problems relying on this function - jpoirier/gortlsdr#14 - since it "is not present in Linux distro releases of rtl-sdr package" (Feb 28). There was a post to osmocom-sdr requesting a new official librtlsdr release: http://lists.osmocom.org/pipermail/osmocom-sdr/2016-February/001373.html but meanwhile "A project I've been using this package in simply requires users to build rtlsdr from source" hmm.. may be premature to update SoapyRTLSDR setBandwidth to call rtlsdr_set_tuner_bandwidth(). Either way, not likely the problem here. update: filed pothosware/SoapyRTLSDR#20 setBandwidth/getBandwidth no-ops, should call rtlsdr_set_and_get_tuner_bandwidth? Possibly has to do with rtlsdr_read_async: - rtl_sdr has a sync mode, but rtl_fm is only async, calls the callback, when porting I replaced with SoapySDRDevice_readStream, sync. There is significant logic in librtlsdr to buffer async, and then call the callback when appropriate: https://github.com/librtlsdr/librtlsdr/blob/development/src/librtlsdr.c#L1840 - although SoapyRTLSDR https://github.com/pothosware/SoapyRTLSDR/blob/master/Streaming.cpp does call rtlsdr_read_async under the hood. What parameters are there to adjust how fast I can read from the SDR, via SoapySDR? ... There is a "buflen" kwarg argument for setupStream in SoapyRTLSDR, but it defaults to 16384, same as DEFAULT_BUF_LENGTH in rtl_fm (but rtl_sdr has 16 * 16384), changing no effect, still reads 8192. The original rtl_fm's rtlsdr_callback gets called consistently with len=262144 (= 16384 * 16). |
Turned out to be a simple problem, readStream returns the number of elements read, aka the number of samples, which consist of both I and Q values, each 8-bit, forming a complex number. |
Instead of having rtl_fm and rtl_sdr convert CS8 to CU8, add the read_samples_cu8() convenience function. This reads from SoapySDR using CS8 format, and adds 127 to convert to CU8, the actual native format - a redundant but necessary conversion, could be improved after pothosware/SoapyRTLSDR#15 if SoapyRTLSDR adds native CU8 support (remove the loop in read_samples_cu8()).
rtl_fm and rtl_sdr basically work now (rtl_power potentially as well but needs more longer-term testing), with an RTL-SDR. Not compatible with a bladeRF yet due to higher bit-rate #8. With a HackRF, rtl_sdr emits output, but only silence (0x7f - 0x83), need to adjust the multiple gains? SoapyHackRF::setGain https://github.com/pothosware/SoapyHackRF/blob/master/HackRF_Settings.cpp#L358 has some.. interesting logic, to set a AMP, VGA, and LNA (comments mine): if ( gain <= 0 )
{
_rx_stream->lna_gain = 0;
_rx_stream->vga_gain = 0;
_current_amp = 0;
}else if ( gain <= /*51*/ (HACKRF_RX_LNA_MAX_DB / 2) + (HACKRF_RX_VGA_MAX_DB / 2) )
{
_rx_stream->vga_gain = (gain / 3) & ~0x1;
_rx_stream->lna_gain = gain - _rx_stream->vga_gain;
_current_amp = 0;
}else if ( gain <= /*65*/ ( (HACKRF_RX_LNA_MAX_DB / 2) + (HACKRF_RX_VGA_MAX_DB / 2) + HACKRF_AMP_MAX_DB) )
{
_current_amp = HACKRF_AMP_MAX_DB;
_rx_stream->vga_gain = ( (gain - _current_amp) / 3) & ~0x1;
_rx_stream->lna_gain = gain -_current_amp - _rx_stream->vga_gain;
}else if ( gain <= /*116*/ HACKRF_RX_LNA_MAX_DB + HACKRF_RX_VGA_MAX_DB + HACKRF_AMP_MAX_DB )
{
_current_amp = HACKRF_AMP_MAX_DB;
_rx_stream->vga_gain = (gain - _current_amp) * double(HACKRF_RX_LNA_MAX_DB) / double(HACKRF_RX_VGA_MAX_DB);
_rx_stream->lna_gain = gain - _current_amp - _rx_stream->vga_gain;
}
_rx_stream->amp_gain=_current_amp;
ret = hackrf_set_lna_gain( _dev, _rx_stream->lna_gain );
ret |= hackrf_set_vga_gain( _dev, _rx_stream->vga_gain );
ret |= hackrf_set_amp_enable( _dev, (_current_amp > 0) ? 1 : 0 ); and in the headers: #define HACKRF_RX_VGA_MAX_DB 62
#define HACKRF_TX_VGA_MAX_DB 47
#define HACKRF_RX_LNA_MAX_DB 40
#define HACKRF_AMP_MAX_DB 14 setGain(40) results in LNA=28, VGA=12, AMP=0 (from adding logging to SoapyHackRF), which I can copy in CubicSDR. Seeing strange return values from readStream with the HackRF:
then it stops. Why the error? -1 is SOAPY_SDR_TIMEOUT, fixed by increasing timeout, but only hear static with the HackRF. readStream ret=131072 (=16384 * 8) Setting bandwidth and sampling rate 20e6, no difference. SoapySDRUtil --probe shows:
with -g 116, I can sometimes sort of hear something above the static with the HackRF, even though it logs invalid parameter: HackRF device setting gains: LNA=36, VGA=63, AMP=14 |
Merged what I have so far since it works well with rtlsdr driver, new issue for HackRF: #9 |
Port to use the vendor-neutral SoapySDR library instead, see https://github.com/pothosware/SoapySDR/wiki
References: