Prerequisites
Complete WIR-101 (Wireless Penetration Testing) and CSA-101 (Computer Systems Architecture) before enrolling. You need:
- Python 3.11+ with NumPy, SciPy, and Matplotlib
- GNU Radio 3.10+ (GR3) installed and functional from WIR-101
- Familiarity with reading and writing
.iq/.sigmfcapture files - Comfort with basic GNU Radio flowgraph construction (WIR-101 Week 9 baseline)
Hardware Kit
Per-Student (required)
| Item | Purpose | Approx. Cost |
|---|---|---|
| RTL-SDR Blog V4 dongle + dipole antenna | Passive receive; spectrum survey; sub-GHz labs | ~$40 |
| Alfa AWUS036ACM 802.11ac USB NIC | Monitor mode; 802.11 fuzzing labs | ~$35 |
Minimum per-student outlay (if WIR-101 kit owned): ~$0. Both items carry forward from WIR-101.
Program-Supplied (shared; one per lab cohort)
| Item | Purpose |
|---|---|
| ANTSDR E200 (AD9361 + Zynq-7020) | Academy canonical full-duplex SDR platform; IQ-sampling labs; LoRa demodulator; URH replay; capstone |
| LimeSDR Mini | Alternate TX/RX platform; alternate for LoRa/BLE labs |
| HackRF One | TX-capable replay; PT cross-cut module |
| nRF52840 USB dongle | Bluetooth Classic + BLE sniffer for Lab 4 |
| Faraday cage enclosure (50x30x30 cm) | Contain live transmissions for all TX labs |
Remote students use the virtual/recorded-capture path for all transmit-side work (see below).
Software Environment
Option A — Kali Linux 2025.x (recommended)
sudo apt update && sudo apt full-upgrade -y
sudo apt install -y \
gnuradio gnuradio-dev gr-osmosdr \
rtl-sdr librtlsdr-dev \
libiio-utils libiio-dev \
python3-iio \
urh \
inspectrum \
wireshark tshark \
libpcap-dev \
aircrack-ng \
scapy \
python3-numpy python3-scipy python3-matplotlib \
python3-pip \
bluez bluez-tools bluetooth \
nrf-sniffer-for-bluetooth-le 2>/dev/null || true
pip3 install sigmf pysdr pyserial
Option B — Ubuntu 24.04 LTS
Same apt commands. Install GNU Radio from PPA if apt version is older than 3.10:
sudo add-apt-repository ppa:gnuradio/gnuradio-releases
sudo apt update
sudo apt install gnuradio
Option C — Windows 11 + WSL2
WSL2 Ubuntu 24.04 works for Python DSP analysis. USB passthrough (usbipd-win) required for SDR hardware. ANTSDR E200 connects via Ethernet to the host at 192.168.1.10; accessible from WSL2 with network passthrough or via the libiio network context ip:192.168.1.10. GNU Radio under WSL2 requires an X server (VcXsrv or WSLg) for the GRC GUI.
ANTSDR E200 Setup
The ANTSDR E200 is the academy's canonical lab platform. It carries an AD9361 RF front-end (identical chip to ADALM-PLUTO / PlutoSDR) on a Xilinx Zynq-7020 FPGA-SoC. Two firmware options are supported; the course uses both at different points.
Connection
Connect the E200 via Ethernet to your lab machine. Default IP: 192.168.1.10. Set your host NIC to the same subnet (192.168.1.x/24).
Verify connectivity:
ping 192.168.1.10
Firmware Option 1: libiio (IIO driver) — Weeks 8-9 + Lab 11
libiio is the recommended firmware for GNU Radio work via gr-iio.
# Install libiio from source (if packaged version < 0.24)
sudo apt install -y libavahi-client-dev libxml2-dev
git clone https://github.com/analogdevicesinc/libiio
cd libiio && mkdir build && cd build
cmake .. -DINSTALL_UDEV_RULE=OFF
make && sudo make install && sudo ldconfig
# Verify: discover the E200 over network
iio_info -u "ip:192.168.1.10"
# Expect: iio:device0 = ad9361-phy; iio:device1 = cf-ad9361-lpc; etc.
Install gr-iio for GNU Radio integration:
sudo apt install gnuradio-dev cmake libboost-all-dev
git clone https://github.com/analogdevicesinc/gr-iio
cd gr-iio && mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr
make && sudo make install && sudo ldconfig
Verify in GNU Radio: search for "IIO" in the GRC block search bar. You should see PlutoSDR Source and PlutoSDR Sink blocks — these work with the ANTSDR E200 (same AD9361 chip, same libiio API).
Firmware Option 2: UHD driver — Lab 10 cross-cut
sudo apt install uhd-host libuhd-dev
uhd_find_devices
# Expect: ANTSDR E200 listed as UHD device at 192.168.1.10
ANTSDR E200 GNU Radio flowgraph (libiio path)
Minimum receive flowgraph:
| Block | Settings |
|---|---|
| PlutoSDR Source | URI: ip:192.168.1.10 / Frequency: 433.92e6 / Sample Rate: 2e6 / RF Bandwidth: 2e6 |
| Throttle | Sample Rate: 2e6 |
| QT GUI Frequency Sink | Center Freq: 433.92e6 / Bandwidth: 2e6 |
LimeSDR Mini Setup
sudo apt install limesuite gr-limesdr
LimeUtil --find
# Verify device detected
GNU Radio: use LimeSuite Source block.
RTL-SDR v4 Refresher
The RTL-SDR carries forward from WIR-101. Verify still working:
rtl_test -t
# Expect: Found 1 device(s), no errors
If errors appear, re-run the driver blacklist procedure from WIR-101 SETUP.md.
nRF52840 Dongle (Bluetooth sniffer)
sudo apt install nrfutil
# Flash Wireshark Bluetooth sniffer firmware onto nRF52840
# Nordic: https://www.nordicsemi.com/Products/Development-hardware/nRF52840-Dongle
# Firmware: nrf-sniffer-for-bluetooth-le (Nordic Infocenter download)
nrfutil pkg generate --hw-version 52 --sd-req 0x00 \
--application nrf_sniffer_for_bluetooth_le.hex --application-version 1 pkg.zip
nrfutil dfu usb-serial -pkg pkg.zip -p /dev/ttyACM0
Wireshark integration: Tools > Serial Capture > select the nRF52840 COM port. Real-time BT/BLE frames appear in the capture window.
GNU Radio Custom Blocks (Week 9 prerequisite)
RF-201 Week 9 requires writing custom GNU Radio blocks in Python. Prerequisites:
# Verify GR3 OOT module infrastructure
gnuradio-config-info --prefix
# Expect: /usr
# gr_modtool for OOT module scaffold
gr_modtool newmod myblock
cd gr-myblock
gr_modtool add myblock_ff --block-type sync
Review: GNU Radio wiki "OutOfTreeModules" tutorial before Week 9.
Virtual / Recorded-Capture Path
Remote and hardware-limited students complete physical-SDR labs through pre-captured IQ archives.
Supported IQ formats
import numpy as np
# GNU Radio / HackRF default (complex64 = interleaved float32 I,Q)
samples = np.fromfile("capture.iq", dtype=np.complex64)
# RTL-SDR raw uint8 (unsigned byte pairs: I0,Q0,I1,Q1,...)
raw = np.fromfile("rtlsdr.bin", dtype=np.uint8)
iq = ((raw.astype(np.float32) - 127.5) / 127.5)[0::2] + \
1j * ((raw.astype(np.float32) - 127.5) / 127.5)[1::2]
# SigMF (preferred; captures metadata alongside samples)
import sigmf
meta = sigmf.SigMFFile(metadata_file="capture.sigmf-meta",
data_file="capture.sigmf-data")
samples = meta.read_samples()
GNU Radio virtual path
For each physical-hardware lab, a virtual path exists:
- Replace the
PlutoSDR Source/osmocom Sourceblock with aFile Sourceblock - Set File Source type to
complex, file to the provided.iqarchive - Add a
Throttleblock after File Source (prevents CPU runaway in file-mode) - Set Throttle sample rate to match the capture metadata
Each lab section marked Virtual path gives the exact .iq filename and capture metadata.
Lab IQ archive index
| Lab | Archive file | Sample rate | Center freq | Duration |
|---|---|---|---|---|
| Lab 1 | lab1-modulation-zoo.iq |
2 MSPS | varies | 10 s per mod |
| Lab 2 | lab2-dsss-demo.iq |
4 MSPS | 915 MHz | 30 s |
| Lab 3 | lab3-80211-mgmt.pcapng |
n/a (PCAP) | 2.4 GHz | 5 min capture |
| Lab 4 | lab4-ble-pairing.pcapng |
n/a (BT PCAP) | 2.4 GHz | full pairing exchange |
| Lab 5 | lab5-lora-868.iq |
1 MSPS | 868.1 MHz | 60 s |
| Lab 6 | lab6-zigbee-mesh.pcapng |
n/a (802.15.4 PCAP) | 2.405 GHz | mesh traffic 5 min |
| Lab 7 | lab7-2msps.iq, lab7-8msps.iq, lab7-20msps.iq |
2/8/20 MSPS | 433.92 MHz | 15 s each |
| Lab 9 | lab9-unknown-protocol.iq |
250 kSPS | 433.92 MHz | 45 s |
| Lab 11 | N/A — ANTSDR E200 required for this lab | — | — | — |
Lab 11 (ANTSDR E200 advanced IQ) has no virtual path; it requires physical access to the ANTSDR E200. Remote students with cohort access to a lab-server-hosted E200 connect via the IIO network context ip:<server>. Check the course portal for lab-server scheduling.
First-Day Smoke Tests
# 1. ANTSDR E200 network reachable
ping -c 3 192.168.1.10
# 2. libiio discovers E200
iio_info -u "ip:192.168.1.10" | grep "ad9361"
# Expect: device name containing "ad9361"
# 3. GNU Radio with gr-iio installed
gnuradio-companion --version
python3 -c "import gnuradio; from gnuradio import iio; print('gr-iio OK')"
# 4. NumPy IQ pipeline
python3 -c "
import numpy as np
samples = np.zeros(1024, dtype=np.complex64)
print('IQ pipeline OK, dtype:', samples.dtype)
"
# 5. URH launches
urh --version
# 6. Inspectrum launches
inspectrum --version 2>/dev/null || inspectrum &
# Should open GUI without errors
# 7. scapy 802.11 layers
python3 -c "from scapy.layers.dot11 import Dot11; print('scapy 802.11 OK')"
Flag any failures to the instructor before Week 1.