This directory provides a driver library to program LoRa devices using a Raspberry Pi 3B+ and the Dragino HAT v1.4.
Initially forked from MMw-Unibo/CLUES.
Install Rust with a suitable linker (e.g. gcc). Install Docker and run cargo install cross --git https://github.com/cross-rs/cross to enable cross compilation. You can skip the Docker and cross setup steps if you are installing Rust on a Raspberry Pi for direct compilation.
You need a Raspberry Pi 3B and a Dragino LoRa GPS HAT v1.4 module. Install Raspberry Pi OS 64bits (tested on this version) and make sure the SPI interface is enabled with sudo raspi-config.
You can either clone this repo and install rust on the Raspberry Pis (as above, minus the installation of Docker and cross) to automatically build & run for their architecture, or you can cross compile the binaries with
cross build --target aarch64-unknown-linux-gnu --releaseand transfer them over via ssh with scp or using an USB drive. When cross-compiling, the output binaries can be found under target/aarch64-unknown-linux-gnu/release/. As an example, we provide a lora_phy binary to periodically send LoRa transmissions with various options. Transfer the binary on the first Raspberry Pi and run it with ./lora_phy. Check available options with ./lora_phy --help.
The example src/main.rs driver implements the following features:
- Blocking transmission (
transmit_blocking): waits for the TxDone signal on DIO0 before returning control, ensuring that a packet is fully transmitted before sending the next one - Packet identification: each payload contains a structured header
[MAGIC 0xCAFE][DEV_ID][PKT_COUNT], allowing packets to be filtered on the gateway side --devidoption: unique device identifier (0–65535) embedded in each payload- Jammer mode (
--jammer): continuous transmission without inter-packet delay to simulate a radio jammer - CSV logging (
--log): detailed logging of each transmission with timestamp, TX duration, status, and payload in hex format - Public sync word (
0x34): packets are visible to standard LoRaWAN gateways
code/
|-- lora/ # Rust library — SX1276 driver
| |-- src/lib.rs # init(), transmit_blocking()
| ...
|-- src/ # LoRa PHY TX application (no LoRaWAN join)
| |-- main.rs # sending loop with CAFE header
Each transmitted packet contains an 8-byte header followed by random data:
Offset: 0 1 2 3 4 5 6 7 8 ...
[CA] [FE] [00] [01] [00] [00] [00] [2A] [random...]
--MAGIC-- --DEV_ID- -PKT_COUNT--padding------------
| Field | Size | Description |
|---|---|---|
| MAGIC | 2 bytes | Fixed signature 0xCAFE |
| DEV_ID | 2 bytes | Device identifier (big-endian) |
| PKT_COUNT | 4 bytes | Packet counter (big-endian) |
| Padding | variable | Random bytes up to --payload |
| Option | Description | Default |
|---|---|---|
--sf <7-12> |
Spreading Factor | 7 |
--freq <Hz> |
Frequency in Hz | 868100000 |
--power <2-17> |
TX power in dBm | 14 |
--payload <1-255> |
Payload size in bytes | 12 |
--wait <ms> |
Delay between packets (ms) | 41000 |
--nbpkt <n> |
Number of packets to send | 1000 |
--devid <0-65535> |
Device identifier | 1 |
--log <file> |
Enable CSV logging | disabled |
--jammer |
Jammer mode (wait=0, infinite loop) | disabled |
--down |
Downchirp generation/reception | disabled |
--rx |
Continuous reception mode | disabled |
# Standard transmission: 100 packets, SF7, 868.1 MHz
./lora_phy --nbpkt 100
# Test with CSV logging and custom device ID
./lora_phy --sf 9 --nbpkt 500 --devid 2 --log test_sf9.csv
# Jammer mode
./lora_phy --jammer --sf 7 --power 17
Alessandro Aimi alessandro.aimi@unibo.it, Olivier Maire olivier.maire2.auditeur@lecnam.net
CNAM 2026