Skip to content

Working with OOT Modules

Out-of-Tree (OOT) modules extend GNU Radio with specialized functionality like LoRa demodulation, ADS-B decoding, or hardware support. GR-MCP provides tools to discover, install, and combine OOT modules into Docker images.

Browse Available Modules

GR-MCP includes a curated catalog of 24 OOT modules accessible via MCP resources:

# List all modules
# Resource: oot://directory
# Get details for a specific module
# Resource: oot://directory/lora_sdr

12 Preinstalled

Available in the base gnuradio-runtime image: osmosdr, satellites, gsm, rds, fosphor, air_modes, etc.

12 Installable

Built on-demand: lora_sdr, ieee802_11, adsb, iridium, dab, nrsc5, etc.

Module Categories

CategoryModules
Hardwareosmosdr, funcube, hpsdr, limesdr
Satellitesatellites, satnogs, iridium, leo
Cellulargsm
Broadcastrds, dab, dl5eu, nrsc5
Aviationair_modes, adsb
IoTlora_sdr, ieee802_15_4
WiFiieee802_11
Analysisiqbal, radar, inspector
Visualizationfosphor
Utilityfoo

Install a Module

  1. Enable runtime mode (required for Docker operations)

    enable_runtime_mode()
  2. Install the module

    For catalog modules:

    install_oot_module(
    git_url="https://github.com/tapparelj/gr-lora_sdr",
    branch="master"
    )

    This:

    • Clones the repository
    • Compiles with cmake
    • Creates a Docker image: gnuradio-lora_sdr-runtime:latest
  3. Use the new image

    launch_flowgraph(
    flowgraph_path="lora_rx.py",
    image="gnuradio-lora_sdr-runtime:latest"
    )

With Build Dependencies

Some modules need extra packages for compilation:

install_oot_module(
git_url="https://github.com/hboeglen/gr-dab",
branch="maint-3.10",
build_deps=["autoconf", "automake", "libtool", "libfaad-dev"],
cmake_args=["-DENABLE_DOXYGEN=OFF"]
)

Detect Required Modules

GR-MCP can analyze flowgraphs to identify OOT dependencies:

detect_oot_modules(flowgraph_path="lora_rx.py")
# Returns OOTDetectionResult:
# detected_modules: ["lora_sdr"]
# unknown_blocks: []
# recommended_image: "gnuradio-lora_sdr-runtime:latest"

For .grc files, detection uses prefix matching against the catalog. For .py files, it parses Python imports for more accuracy.

Auto-Image Selection

The simplest approach: let GR-MCP handle everything:

launch_flowgraph(
flowgraph_path="lora_rx.py",
auto_image=True
)

This automatically:

  1. Detects required OOT modules
  2. Installs missing modules from the catalog
  3. Builds combo images if multiple modules are needed
  4. Launches with the appropriate image

Combine Multiple Modules

Some flowgraphs need multiple OOT modules. Create a combo image:

build_multi_oot_image(module_names=["lora_sdr", "adsb"])
# Returns ComboImageResult:
# success: True
# image: ComboImageInfo(
# combo_key: "combo:adsb+lora_sdr",
# image_tag: "gr-combo-adsb-lora_sdr:latest",
# modules: ["adsb", "lora_sdr"]
# )

Missing modules are auto-built from the catalog.

Launch with Combo Image

launch_flowgraph(
flowgraph_path="multi_protocol_rx.py",
image="gr-combo-adsb-lora_sdr:latest"
)

Or use auto-detection:

detect_oot_modules("multi_protocol_rx.py")
# detected_modules: ["lora_sdr", "adsb"]
# recommended_image: "gr-combo-adsb-lora_sdr:latest"

Manage Installed Images

# List installed OOT images
list_oot_images()
# Returns: [OOTImageInfo(module_name="lora_sdr", image_tag="..."), ...]
# List combo images
list_combo_images()
# Returns: [ComboImageInfo(combo_key="combo:adsb+lora_sdr", ...)]
# Remove a single-module image
remove_oot_image(module_name="lora_sdr")
# Remove a combo image
remove_combo_image(combo_key="combo:adsb+lora_sdr")

Load OOT Blocks at Design Time

For flowgraph design (without Docker), load OOT block definitions:

# Add a path containing .block.yml files
add_block_path("/usr/local/share/gnuradio/grc/blocks")
# Check current paths and block count
get_block_paths()
# Returns BlockPathsModel with paths and total_blocks
# Load multiple paths at once
load_oot_blocks(paths=[
"/usr/local/share/gnuradio/grc/blocks",
"/home/user/gr-modules/lib/grc"
])

Example: LoRa Receiver Setup

Complete workflow for receiving LoRa packets:

# 1. Enable runtime mode
enable_runtime_mode()
# 2. Check if lora_sdr is available
# Resource: oot://directory/lora_sdr
# -> preinstalled: False, installed: False
# 3. Install the module
install_oot_module(
git_url="https://github.com/tapparelj/gr-lora_sdr",
branch="master"
)
# -> image_tag: "gnuradio-lora_sdr-runtime:latest"
# 4. Load blocks for design
add_block_path("/usr/local/share/gnuradio/grc/blocks")
# 5. Build the flowgraph
make_block(block_type="lora_sdr_lora_sdr_lora_rx")
# ... configure and connect ...
# 6. Generate code
generate_code(output_dir="/tmp")
# 7. Launch with the new image
launch_flowgraph(
flowgraph_path="/tmp/lora_rx.py",
name="lora-receiver",
image="gnuradio-lora_sdr-runtime:latest",
device_paths=["/dev/bus/usb"]
)

Export Custom Blocks to OOT

GR-MCP can also create OOT modules from scratch using the block development tools:

  1. Enable block dev mode

    enable_block_dev_mode()
  2. Generate a block

    result = generate_sync_block(
    name="my_filter",
    description="Custom bandpass filter",
    input_signature=[{"dtype": "complex", "vlen": 1}],
    output_signature=[{"dtype": "complex", "vlen": 1}],
    )
  3. Generate GRC YAML (for GUI integration)

    yaml_result = generate_grc_yaml(
    source_code=result.source_code,
    block_name="my_filter",
    module_name="custom",
    category="Filters"
    )
  4. Export to OOT module

    export_block_to_oot(
    source_code=result.source_code,
    block_name="my_filter",
    module_name="custom",
    output_dir="/tmp/gr-custom"
    )
    # Creates: CMakeLists.txt, python/custom/my_filter.py, grc/custom_my_filter.block.yml
  5. Build as Docker image (for container deployment)

    enable_runtime_mode()
    install_oot_module(
    git_url="file:///tmp/gr-custom",
    branch="main"
    )

Next Steps