BorIP Server

From SpenchWiki
Jump to: navigation, search

Introduction

BorIP is a system that allows you to control a Software Defined Radio over a network, and stream the received baseband samples from your remote hardware back to a client application (e.g. HDSDR or GNU Radio). The following multi-platform BorIP servers therefore allow you to make your SDR hardware available on your LAN for remote control.

For a complete complete overview of what you can do with BorIP, you may watch this demonstration video. If you wish to see the demo on OS X, you can watch this one too.

To learn about the protocol (control channel and baseband format), please see the BorIP page.

Windows

The Windows server (available on the USRP Interfaces page) is a self-contained server with support for the same devices at the ExtIO plugin:

  • USRP accessible through the Legacy and UHD hosts
  • Realtek RTL2832U-based DVB-T dongles
  • the FUNcube Dongle

If you feel brave, you can compile GNU Radio for Windows using MinGW or Cygwin, and then run the Linux/Mac version (below) on Windows too!

Linux & Mac

This is available in the apps directory of gr-baz as a Python 2.x program:

./borip_server

NOTE: You must first check out the gr-baz code, compile and install it - this will make necessary dependencies available. There are more instructions regarding how to do this on the gr-baz page.

Currently, there is support for:

  • RTL2832U devices
  • USRPs accessible with the Legacy host interface (not UHD, as yet)

Please see below for more information on how device support is offerred, and how you can easily add your own without writing any code!

HDSDR under Wine

HDSDR works well under Wine on both Linux and Mac OS X.

Install it the same way (using Wine), along with the ExtIO plugin, by using the bundled installer from the USRP Interfaces page.

Then connect to a Remote device using the Device Control window, and set the address to localhost to connect to the BorIP server running on your own computer. It will then send baseband samples via the loopback interface!

For a demonstration on both platforms, please watch the videos referenced in the Introduction.

If you encounter any issues, please consult this thread on the ultra-cheap-sdr forum.

For example:

  • If the installer fails to install the VC2008 runtime, you can do this manually instead.
  • The first time you run HDSDR with the ExtIO plugin installed, the Device Control window may be created behind the main HDSDR window (you may think instead the ExtIO hasn't loaded) - make sure you look behind HDSDR.
  • The program may appear to freeze after clicking 'Create' in the Device Control window, or 'Start' in the HDSDR window. Simply move the mouse over either window and it will start working again.

Setting up OS X

Alain De Carolis says in this thread (edited after I have successfully replicated the following steps):

  1. Install Xcode with command line utilities
  2. Install MacPorts
  3. Install GNU Radio by issuing (will take a long time):
    sudo port install gnuradio
  4. Get gr-baz from SVN or git
  5. Change the 'bootstrap' script on line 28 from:
    'libtoolize --automake -c -f'
    to
    'glibtoolize --automake -c -f'
  6. Compile and install gr-baz
  7. Copy the files inside gr-baz/grc/ to ~/.grc_gnuradio/
  8. Run the following command:
export PYTHONPATH=$PYTHONPATH:/opt/local/lib/python2.6/site-packages:/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/:/usr/local/lib/python2.7/site-packages/

Remember the last step for all future Terminal sessions!

Arguments

Usage: borip_server.py: [options]

Options:
  -h, --help            show this help message and exit
  -l LISTEN, --listen=LISTEN
                        server listen port
  -p PORT, --port=PORT  default data port
  -v, --verbose         verbose output
  -g, --debug           debug output
  -c, --command         command output
  -r, --realtime        realtime scheduling
  -R, --no-reload       disable dynamic reload
  -d DEVICE, --device=DEVICE
                        immediately create device
  -L, --lock            lock device
  -D DEFAULT, --default=DEFAULT
                        device to create when default hint supplied

Notes on Included Device Flowgraphs

The following titles are the names of the GRC flowgraphs (not the generated Python file).

borip-USRP-Legacy

  • This uses my patched version of the Legacy USRP Source which outputs status messages (i.e. uO overruns, etc).
    If you wish to use this with the original (un-patched) version, load the GRC file, and turn the Accept status property Off in the UDP Sink. Otherwise you will get a complaint about setting up a message queue at device creation.
  • Make sure that the 'unit' Parameter is first in the __init__ constructor if you re-generate the file!

borip-RTL

  • This will generate a self-contained top block.
  • Only three supported arguments currently: tuner, readlen & buf.

borip_block-RTL

  • This will generate a Hierarchical block.
  • Only three supported arguments currently: tuner, readlen & buf.
  • Remember: the generated file will be placed in ~/.grc_gnuradio/.

Extensibility

Please note that the architecture of this version means the above main Python server program does not contain any native hardware interfaces (like the Windows version). It dynamically loads separate Python modules at runtime (e.g. GNU Radio flowgraphs) that provide access to hardware receivers, based on the Device Hint supplied at the client.

If you wish to add your own interfaces to access other hardware, you may:

  • Write your own, and implement the Device and NetworkTransport classes (see class interfaces in apps/borip_server.py
  • Create a GNU Radio flowgraph (e.g. in GR Companion), generate the Python code, and the server will automatically load it using a wrapper to make it look like the above classes. The name in the GRC Options block should be the same as the Device Hint you intend to use.

Note: the second method requires you have GNU Radio installed!

Dynamic Loading

Place Python files in locations where they will be picked up by Python (e.g. the apps directory). You can also add paths to the PYTHONPATH environement variable.

The server will load files in the following manner:

  • Call the 'device hint mapper' function with the Device Hint from the connected client, and see if it returns a name
  • If no name is returned, then use the first (non-whitespace) part of the Device Hint as the name

The server will then attempt to import the following Python module (file):

borip_<name>

Certain Device Hints (e.g. Legacy USRP device index, UHD Device Hint) are not suitable for direct use in a file name, which is where the 'device hint mapper' is used.

The default function is:

def _default_device_hint_mapper(hint):
    if hint is None or len(hint) == 0 or hint == "-":
        return "usrp_uhd"
    parts = hint.split(" ")
    try:
        idx = int(parts[0])
        return "usrp_legacy"
    except:
        pass
    try:
        kv = parts[0].index('=')    # key=value
        return "usrp_uhd"
    except:
        pass
    return parts[0].upper() # FCD, RTL

If you wish to create your own to support other devices, you can:

  • edit this code directly, or (preferably):
  • create another Python file called borip_server_devmap which will be imported on startup.

borip_server_devmap should contain a function called device_hint_mapper that should conform to the same interface as _default_device_hint_mapper above (take a string, and return one).

IMPORTANT: If you are creating Hierarchical Blocks, GRC will place the generated Python code in this directory:

~/.grc_gnuradio/

For the server to pick up files in this path, you could do something like:

export PYTHONPATH=~/.grc_gnuradio/

REMEMBER: You must set the name of the generated file in the Options block in GRC! Otherwise it will just end up 'top_block' and will not be picked-up by the server!

GNU Radio Flowgraph Wrapper

The wrapper will attempt to find 'helpers' in the flowgraph to fill in the information it needs. Helpers are Python attributes that are either normal (value) variables, or functions. You can create a 'function' variable easily in GRC by using the Variable block and entering a lambda function as the value.

The search order for helpers is:

  1. the local flowgraph object
  2. the local source (the GRC block, and therefore variable, should be called source)
  3. the local flowgraph's parent (when a Hierarchical Block is loaded by the ServerWrapper class)

Please see the GnuRadioDevice implementation of the Device class to see which helpers are sought after by which functions, and in what order.

The list so far is:

source_name, name (for 'name', try local source first)
serial, serial_number
gain_range
master_clock
samples_per_packet, recv_samples_per_packet
antennas
set_gain
gain
set_samp_rate, set_sample_rate
samp_rate, sample_rate
set_freq, set_frequency
freq, frequency
was_tune_successful, was_tuning_successful
tune_tolerance, tuning_tolerance
last_tune_result
set_antenna
antenna

GRC Parameter blocks introduce variables to the __init__ constructor of the flowgraph. These will be filled in by additional arguments on the Device Hint. However only those Parameters that exist will be accepted during instantiation of the generated Python class!

If you are creating a Hierarchical Block, and wish to output status messages from the source block, you can use the Message Callback in dummy mode (and the Variable value set to '0'). The Message Callback won't actually call a function - it is just there so the BorIP server can get a handle on the message queue that GRC generates for it.

Self-contained Server in BorIP Sink

This will start the server internally, but external devices will not be created. Any Device Hint from a client will be ignored.

To prevent the sample rate being changed (i.e. stop the client from changing the samp_rate variable), create two Variable blocks:

  • sample_rate
lambda: self.samp_rate
  • set_sample_rate
lambda f: self.samp_rate

To set the number of samples transmitted in each packet, create a samples_per_packet Variable and set its value (this will set the payload size of the internal BorIP-enhanced UDP Sink block).

IMPORTANT: Remember to set the value of the BorIP Sink's Contant Multiplier property to ensure a normalised floating-point sample stream ([-1, +1]) is expanded to the range of a 16-bit signed integer ([-32768, +32767]), otherwise you won't get anything useful at the client!