2014-02-07

Linux SDR API committed to media treee!

Yaw, a big day for me. After the two years of work, it is finally there! Mauro just committed basic SDR API stuff to Media tree for kernel 3.15.

So when you next time see new /dev/swradio0 device node appearing to file system, you know where it is coming from :)

[media] devices.txt: add video4linux device for Software Defined Radio

Add Antti at the V4L2 revision list sdr


I have almost 100 SDR patches waiting on my queue, adding new features and hardware support, including kernel SDR drivers for Mirics MSi3101 and Realtek RTL2832U based devices.

Check out my kernel SDR tree


Related tools etc.

Big thanks to VideoForLinux API rockstar Hans Verkuil for tons of comments and reviews.

9 comments:

  1. Great! Thanks so much for all the work!

    ReplyDelete
  2. Does it mean we will be able to use the sticks for watching DVB-T and using it as a SDR without rmmod/insmod the drivers?

    Also will it work with gnuradio?

    ReplyDelete
    Replies
    1. If you mean RTL2832U, the answer is yes. However, you cannot use DVB-T and SDR at same time as device hardware resources are shared. Kernel creates different device nodes for DVB (/dev/dvb/adapter0/frontend0) and SDR (/dev/swradio0).
      I implemented GNU Radio and SDRSharp plugins during development as I needed some apps to test things. At some point I upgraded to Fedora 20 and due to that got GNU Radio 3.7. Unfortunately I had some problems to upgrade plugin from 3.6 to 3.7 format and GNU Radio plugin is now a much out of date...
      The plan is to keep that SDR stuff inside kernel staging for a while (staging is place where is things that are not ready and even small API changes are possible). Currently there is 2 kernel SDR drivers, Realtek RTL2832 and Mirics MSi3101. My current criteria to move that stuff out from staging is 2 more SDR drivers and/or 2-3 kernel releases. The reason for staging is that it gives me flexibility to make minor API fixes if ever needed - as kernel API is something it cannot be changed after it is 'frozen'.

      Delete
    2. But as I said, I really need more different kind of SDR hardware in order to finalize API. One which does real sampling (both RTL2832 and MSi3101 uses complex sampling) for example as I need add some thing to API to separate complex and real sampling. Maybe there is some more issues that should be taken into account...

      Delete
  3. How about the tools and applications which are using direct/raw USB interface to the SDR device? Example, gqrx, rtl-sdr tools, dump1090, dsd, ....

    Any changs need to be done to the app's code?

    What are the benefits using the SDR's kernel interface compared to the direct USB implementation?

    Thank you.

    ReplyDelete
    Replies
    1. Idea of operating system API is to offer standard way to communicate with certain hardware without even knowing what kind of hardware there is. Lets take a little bit too generic example, but every single application which needs keyboard do not need to have own driver for every supported keyboard as there is one common driver.

      So you write a application that uses Linux SDR API, then someone makes a device driver that translates commands between API and device.

      Writing SDR driver is somehow trivial task at least if you compare to digital television driver. Those two driver types are rather nice example to compare because of lot of similarities. For DTV there is 3 blocks: USB-bridge, demodulator and RF tuner. For SDR there is 3 blocks: USB-bridge, ADC and RF tuner. USB-bridge and RF tuner are just similar between those devices and code could be shared. On Linux kernel there is own driver for each chip, so you could share USB-bridge and RF tuner drivers. After that there is DTV/SDR specific drivers left: demodulator and ADC. Implementing ADC driver is very simple, whilst demodulator driver needs 2-3 times more work.

      Device drivers belongs to OS kernel traditionally. Kernel driver has also some performance advantages, which are still not very significant as it is signal processing required to demodulation which eats a lot of CPU and driver CPU usage is quite small when compared.

      So all-in-all, benefits I can quickly remember:
      * API is traditionally correct way to implement device access
      * it offers *standard manner* to communicate with hardware
      * offers multiple streaming I/O methods (read, mmap, user pointer) app can select (mmap and user pointer are zero-copy)
      * reuse existing kernel chipset drivers (between SDR, DTV, ATV and radio)
      * small performance benefit
      * app does not need root privileges (app needs root power in order to get direct hardware access)

      Delete
    2. Thank you for the explanations. Yes I agreed with you about the standardization of accessing to the device. This may make programming easier, without 're-inventing the wheel' of the methods of accessing the devices.

      Thank you.

      Good luck and hope we getting better GNU/Linux environments and perfomances.

      Delete
  4. Here is small show case using v4l2-ctl application. You will need to update recent v4l2-ctl from linuxtv.org in order to perform all those SDR specific commands. It tunes rtl2832 + e4000 device to FM radio 103.1 MHz and reads few samples (dumped through hexdump app to console at the end of log).

    $ ll /dev/swradio0
    crw-rw----+ 1 root video 81, 0 9.4. 16:41 /dev/swradio0
    $ ./v4l2-ctl -d /dev/swradio0 --info
    Driver Info (not using libv4l2):
    Driver name : rtl2832_sdr
    Card type : Realtek RTL2832 SDR
    Bus info : usb-0000:00:13.2-2
    Driver version: 3.14.0
    Capabilities : 0x85110000
    SDR Capture
    Tuner
    Read/Write
    Streaming
    Device Capabilities
    Device Caps : 0x05110000
    SDR Capture
    Tuner
    Read/Write
    Streaming
    $ # ADC is tuner index 0
    $ # RF tuner is tuner index 1
    $ # check supported sampling rates
    $ ./v4l2-ctl -d /dev/swradio0 --list-freq-bands --tuner=0
    ioctl: VIDIOC_ENUM_FREQ_BANDS
    Index : 0
    Modulation : Unknown
    Capability : 1 Hz freq-bands
    Frequency Range: 0.300000 MHz - 0.300000 MHz

    Index : 1
    Modulation : Unknown
    Capability : 1 Hz freq-bands
    Frequency Range: 0.900001 MHz - 2.800000 MHz

    Index : 2
    Modulation : Unknown
    Capability : 1 Hz freq-bands
    Frequency Range: 3.200000 MHz - 3.200000 MHz
    $ # set ADC sampling rate (2.048Msps) and RF tuner frequency (103.1MHz)
    $ ./v4l2-ctl -d /dev/swradio0 --tuner=0 --get-freq
    Frequency for tuner 0: 300000 (0.300000 MHz)
    $ ./v4l2-ctl -d /dev/swradio0 --tuner=1 --get-freq
    Frequency for tuner 1: 50000000 (50.000000 MHz)
    $ ./v4l2-ctl -d /dev/swradio0 --tuner=0 --set-freq=2.048
    Frequency for tuner 0 set to 2048000 (2.048000 MHz)
    $ ./v4l2-ctl -d /dev/swradio0 --tuner=1 --set-freq=103.1
    Frequency for tuner 1 set to 103100000 (103.100000 MHz)
    $ # enumerate and select desired stream format
    $ # ideally there is as many formats as hardware offers
    $ ./v4l2-ctl -d /dev/swradio0 --list-formats-sdr
    ioctl: VIDIOC_ENUM_FMT
    Index : 0
    Type : SDR Capture
    Pixel Format: 'CU08'
    Name : IQ U8

    Index : 1
    Type : SDR Capture
    Pixel Format: 'CU16'
    Name : IQ U16LE (emulated)

    $ # CU08 is native rtl2832 format, 8bit unsigned IQ pairs
    $ # CU16 is similar but driver converts samples to 16bit
    $ ./v4l2-ctl -d /dev/swradio0 --set-fmt-sdr=0
    $ ./v4l2-ctl -d /dev/swradio0 --get-fmt-sdr
    Format SDR Capture:
    Sample Format : CU08
    $ # control interface. there is only some RF tuner controls currently
    $ ./v4l2-ctl -d /dev/swradio0 --list-ctrls

    RF Tuner Controls

    bandwidth_auto (bool) : default=1 value=1 flags=update
    bandwidth (int) : min=4300000 max=11000000 step=100000 default=4300000 value=4300000 flags=inactive, slider
    lna_gain_auto (bool) : default=1 value=1 flags=update
    lna_gain (int) : min=0 max=15 step=1 default=10 value=10 flags=inactive, slider
    mixer_gain_auto (bool) : default=1 value=1 flags=update
    mixer_gain (int) : min=0 max=1 step=1 default=1 value=1 flags=inactive, slider
    if_gain_auto (bool) : default=1 value=1 flags=update
    if_gain (int) : min=0 max=54 step=1 default=0 value=0 flags=inactive, slider
    pll_lock (bool) : default=0 value=0 flags=volatile
    $ ./v4l2-ctl -d /dev/swradio0 --get-ctrl=bandwidth
    bandwidth: 4300000
    $ ./v4l2-ctl -d /dev/swradio0 --set-ctrl=bandwidth=5300000
    $ ./v4l2-ctl -d /dev/swradio0 --get-ctrl=bandwidth
    bandwidth: 5300000
    $ # lets capture some data, sample rate 2.048Msps, RF 103.1MHz
    $ # we use read method here as it is simple file op, but API supports also mmap and user pointer for zero-copy streaming
    $ dd bs=16 count=1 if=/dev/swradio0 | hexdump -C
    00000000 80 80 7f 7f 80 7f 7f 7f 7f 7e 80 7e 80 7f 80 7f |.........~.~....|
    1+0 records in
    1+0 records out
    00000010
    16 bytes (16 B) copied, 0,28942 s, 0,1 kB/s

    ReplyDelete