Tuesday, 19 May 2020

Selection between RTL-SDR device indexes (as a command-line parameter)

If you have multiple RTL-SDRs in attached to system for monitoring various services, you'll know that in most cases, you need to specify a device index to make sure you've got the correct device selected.

In my case, I'm watching POCSAG on 148 MHz, ADS-B on 1090 MHz and a weather station on 433 MHz.  Different frequencies need different antennas, so it's important I select the right one; I've found that the device index follows no pattern (it's been reported it's based on the order it's plugged in, but I've got devices that will take on index 0 even if another device already has it).


To achieve this, we need to be able to do three key things:
  • Uniquely identify each device in software
  • List all RTL-SDRs in a system by index and unique identifier
  • Retrieve the index that can be supplied in-line to existing tools

To uniquely identify the device, we can leverage the device serial number.  Fortunately, this turns out to be a user-editable value using the rtl_eeprom tool from the rtl-sdr library:

rtl_eeprom -d 0 -s 00000666

Just plug one device in at a time to ensure you've got the right one!  Everything going to plan, you'll see the message Configuration successfully written once the serial is updated.

Next, we need to enumerate all devices in the system - but we have to cheat a little bit here.  Like many of the tools in the rtl-sdr library, most will list all devices as part of their output.  We use the rtl_sdr tool for this, but the cheat is that we need to specify an invalid device index to get it to enumerate all devices in a way we can scrape the output:

pi@pitwo:~ $ rtl_sdr -d 9999
Found 3 device(s):
  0:  Realtek, RTL2838UHIDIR, SN: 00000001
  1:  Realtek, RTL2838UHIDIR, SN: 00000002
  2:  Realtek, RTL2838UHIDIR, SN: 00000666


No matching devices found.
rtl_sdr, an I/Q recorder for RTL2832 based DVB-T receivers

Usage:   -f frequency_to_tune_to [Hz]
        [-s samplerate (default: 2048000 Hz)]
        [-d device_index (default: 0)]
        [-g gain (default: 0 for auto)]
        [-p ppm_error (default: 0)]
        [-b output_block_size (default: 16 * 16384)]
        [-n number of samples to read (default: 0, infinite)]
        [-S force sync output (default: async)]
        filename (a '-' dumps samples to stdout)

Now all we need to do is grep the output for the serial number of the device we want, and return the corresponding device index:

rtl_sdr -d 9999 |& grep -P -o "\d(?=:\s*.+SN: 00000666)"

Which returns only the device index (2 in this instance).  If you're playing along at home, the above regex comprises the following:
  • \d: Any single digit
  • (? ): Lookahead query
  • .+ : Match any number of any characters
  • : and SN: 00000666: Strings to match

From here, you can slip it inline with an existing command using $():

$(rtl_sdr -d 9999 |& grep -P -o "\d(?=:\s*.+SN: 00000666)")

For example - here's rtl_fm (piping into multimon_ng for the sake of completeness):

rtl_fm -A lut -s 22050 -f 148.8788M -d $(rtl_sdr -d 9999 |& grep -P -o "\d(?=:\s*.+SN: 00000002)") -g 17.9 | multimon-ng -t raw -a POCSAG512 -a POCSAG1200 -a POCSAG2400 -f alpha /dev/stdin

It's worth noting that certain tools, such as dump1090, allow you to specify a serial number instead of device index - always use the device serial as the identifier wherever available!

No comments:

Post a comment