Feat: Adding sdr-companion for decoding LoRa using an SDR

This commit is contained in:
Halcy0nic
2024-02-22 13:48:30 -07:00
parent 1ec72b0328
commit 0c80743dd8
8 changed files with 4830 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

34
sdr-companion/Dockerfile Normal file
View File

@@ -0,0 +1,34 @@
from archlinux:latest
workdir /lib
# Update to latest arch
run pacman -Syu --noconfirm
# Install required dependencies
run pacman -S git python2-scipy swig cppunit fftw boost boost-libs gnuradio gnuradio-osmosdr libvolk log4cpp base-devel cmake wxgtk-common wxgtk2 wxgtk3 wxpython libuhd-firmware gnuradio-companion python2-requests --noconfirm
workdir /liquid
# Manual liquid-dsp install
run git clone https://github.com/jgaeddert/liquid-dsp.git . && \
sh ./bootstrap.sh && \
sh ./configure --prefix=/usr && \
make && \
make install
# Install gr-lora
workdir /src
arg CACHEBUST
run git clone https://github.com/rpp0/gr-lora.git . && \
mkdir build && \
cd build && \
cmake ../ -DCMAKE_INSTALL_PREFIX=/usr && \
make && \
make install && \
ldconfig
workdir /src/apps
expose 40868

View File

@@ -0,0 +1,5 @@
#!/bin/sh
LATEST_VERSION=`git ls-remote https://github.com/rpp0/gr-lora.git | grep HEAD | cut -f 1`
docker build -t rpp0/gr-lora --build-arg CACHEBUST=$LATEST_VERSION .
#docker tag rpp0/gr-lora:latest rpp0/gr-lora:$LATEST_VERSION

View File

@@ -0,0 +1,6 @@
#!/bin/sh
DOCKER_XAUTH=/tmp/.docker.xauth
touch /tmp/.docker.xauth
xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $DOCKER_XAUTH nmerge -
docker run -i -t --rm --privileged -e DISPLAY=$DISPLAY -e XAUTHORITY=$DOCKER_XAUTH -v /tmp/.docker.xauth:/tmp/.docker.xauth:ro -v /tmp/.X11-unix:/tmp/.X11-unix:ro -v /dev/bus/usb:/dev/bus/usb --entrypoint /bin/bash rpp0/gr-lora:latest

View File

@@ -0,0 +1,91 @@
#
# /etc/pacman.conf
#
# See the pacman.conf(5) manpage for option and repository directives
#
# GENERAL OPTIONS
#
[options]
# The following paths are commented out with their default values listed.
# If you wish to use different paths, uncomment and update the paths.
#RootDir = /
#DBPath = /var/lib/pacman/
#CacheDir = /var/cache/pacman/pkg/
#LogFile = /var/log/pacman.log
#GPGDir = /etc/pacman.d/gnupg/
HoldPkg = pacman glibc
#XferCommand = /usr/bin/curl -C - -f %u > %o
#XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u
#CleanMethod = KeepInstalled
#UseDelta = 0.7
Architecture = auto
# Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup
#IgnorePkg =
#IgnoreGroup =
#NoUpgrade =
#NoExtract =
# Misc options
#UseSyslog
#Color
#TotalDownload
# We cannot check disk space from within a chroot environment
#CheckSpace
#VerbosePkgLists
# By default, pacman accepts packages signed by keys that its local keyring
# trusts (see pacman-key and its man page), as well as unsigned packages.
SigLevel = Required DatabaseOptional
LocalFileSigLevel = Optional
#RemoteFileSigLevel = Required
# NOTE: You must run `pacman-key --init` before first using pacman; the local
# keyring can then be populated with the keys of all official Arch Linux
# packagers with `pacman-key --populate archlinux`.
#
# REPOSITORIES
# - can be defined here or included from another file
# - pacman will search repositories in the order defined here
# - local/custom mirrors can be added here or in separate files
# - repositories listed first will take precedence when packages
# have identical names, regardless of version number
# - URLs will have $repo replaced by the name of the current repo
# - URLs will have $arch replaced by the name of the architecture
#
# Repository entries are of the format:
# [repo-name]
# Server = ServerName
# Include = IncludePath
#
# The header [repo-name] is crucial - it must be present and
# uncommented to enable the repo.
#
# The testing repositories are disabled by default. To enable, uncomment the
# repo name header and Include lines. You can add preferred servers immediately
# after the header, and they will be used before the default mirrors.
#[testing]
#Include = /etc/pacman.d/mirrorlist
[core]
Include = /etc/pacman.d/mirrorlist
[extra]
Include = /etc/pacman.d/mirrorlist
#[community-testing]
#Include = /etc/pacman.d/mirrorlist
[community]
Include = /etc/pacman.d/mirrorlist
# An example of a custom package repository. See the pacman manpage for
# tips on creating your own repositories.
#[custom]
#SigLevel = Optional TrustAll
#Server = file:///home/custompkgs

127
sdr-companion/mkimage-arch.sh Executable file
View File

@@ -0,0 +1,127 @@
#!/usr/bin/env bash
# Generate a minimal filesystem for archlinux and load it into the local
# docker as "archlinux"
# requires root
set -e
hash pacstrap &>/dev/null || {
echo "Could not find pacstrap. Run pacman -S arch-install-scripts"
exit 1
}
hash expect &>/dev/null || {
echo "Could not find expect. Run pacman -S expect"
exit 1
}
export LANG="C.UTF-8"
ROOTFS=$(mktemp -d ${TMPDIR:-/var/tmp}/rootfs-archlinux-XXXXXXXXXX)
chmod 755 $ROOTFS
# packages to ignore for space savings
PKGIGNORE=(
cryptsetup
device-mapper
dhcpcd
iproute2
jfsutils
linux
lvm2
man-db
man-pages
mdadm
nano
netctl
openresolv
pciutils
pcmciautils
reiserfsprogs
s-nail
systemd-sysvcompat
usbutils
vi
xfsprogs
)
IFS=','
PKGIGNORE="${PKGIGNORE[*]}"
unset IFS
arch="$(uname -m)"
# Set to arch="armv7hf" in order to cross-compile
case "$arch" in
armv*)
if pacman -Q archlinuxarm-keyring >/dev/null 2>&1; then
pacman-key --init
pacman-key --populate archlinuxarm
else
echo "Could not find archlinuxarm-keyring. Please, install it and run pacman-key --populate archlinuxarm"
exit 1
fi
PACMAN_CONF=$(mktemp ${TMPDIR:-/var/tmp}/pacman-conf-archlinux-XXXXXXXXX)
version="$(echo $arch | cut -c 5)"
sed "s/Architecture = armv/Architecture = armv${version}h/g" './mkimage-archarm-pacman.conf' > "${PACMAN_CONF}"
PACMAN_MIRRORLIST='Server = http://mirror.archlinuxarm.org/$arch/$repo'
PACMAN_EXTRA_PKGS='archlinuxarm-keyring'
EXPECT_TIMEOUT=1800 # Most armv* based devices can be very slow (e.g. RPiv1)
ARCH_KEYRING=archlinuxarm
DOCKER_IMAGE_NAME="armv${version}h/archlinux"
;;
*)
PACMAN_CONF='./mkimage-arch-pacman.conf'
PACMAN_MIRRORLIST='Server = https://mirrors.kernel.org/archlinux/$repo/os/$arch'
PACMAN_EXTRA_PKGS=''
EXPECT_TIMEOUT=60
ARCH_KEYRING=archlinux
DOCKER_IMAGE_NAME=archlinux
;;
esac
export PACMAN_MIRRORLIST
expect <<EOF
set send_slow {1 .1}
proc send {ignore arg} {
sleep .1
exp_send -s -- \$arg
}
set timeout $EXPECT_TIMEOUT
spawn pacstrap -C $PACMAN_CONF -c -d -G -i $ROOTFS base haveged $PACMAN_EXTRA_PKGS --ignore $PKGIGNORE
expect {
-exact "anyway? \[Y/n\] " { send -- "n\r"; exp_continue }
-exact "(default=all): " { send -- "\r"; exp_continue }
-exact "installation? \[Y/n\]" { send -- "y\r"; exp_continue }
-exact "delete it? \[Y/n\]" { send -- "y\r"; exp_continue }
}
EOF
arch-chroot $ROOTFS /bin/sh -c 'rm -r /usr/share/man/*'
arch-chroot $ROOTFS /bin/sh -c "haveged -w 1024; pacman-key --init; pkill haveged; pacman -Rs --noconfirm haveged; pacman-key --populate $ARCH_KEYRING; pkill gpg-agent"
arch-chroot $ROOTFS /bin/sh -c "ln -s /usr/share/zoneinfo/UTC /etc/localtime"
echo 'en_US.UTF-8 UTF-8' > $ROOTFS/etc/locale.gen
arch-chroot $ROOTFS locale-gen
arch-chroot $ROOTFS /bin/sh -c 'echo $PACMAN_MIRRORLIST > /etc/pacman.d/mirrorlist'
# udev doesn't work in containers, rebuild /dev
DEV=$ROOTFS/dev
rm -rf $DEV
mkdir -p $DEV
mknod -m 666 $DEV/null c 1 3
mknod -m 666 $DEV/zero c 1 5
mknod -m 666 $DEV/random c 1 8
mknod -m 666 $DEV/urandom c 1 9
mkdir -m 755 $DEV/pts
mkdir -m 1777 $DEV/shm
mknod -m 666 $DEV/tty c 5 0
mknod -m 600 $DEV/console c 5 1
mknod -m 666 $DEV/tty0 c 4 0
mknod -m 666 $DEV/full c 1 7
mknod -m 600 $DEV/initctl p
mknod -m 666 $DEV/ptmx c 5 2
ln -sf /proc/self/fd $DEV/fd
tar --numeric-owner --xattrs --acls -C $ROOTFS -c . | docker import - $DOCKER_IMAGE_NAME
docker run --rm -t $DOCKER_IMAGE_NAME echo Success.
rm -rf $ROOTFS

View File

@@ -0,0 +1,75 @@
# Introduction
In certain scenarios, traditional LoRa receivers, such as the Adafruit Feather LoRa or Lostik, may not adequately decode LoRa traffic. To address this, we introduce a Software Defined Radio (SDR) companion module designed to offer a more robust alternative for decoding when the conventional LoRa Scanner application falls short.
SDRs provide unparalleled flexibility compared to traditional hardware radios, which are often limited by their specific design and capabilities. With an SDR, you can decode a wide array of signals beyond LoRa, making it an invaluable tool for radio signal research and experimentation. The ability to tweak settings and experiment with different decoding algorithms allows for a deeper exploration into radio communications. This is especially beneficial in the evolving field of LoRa technology, where ongoing research and experimentation can yield significant insights. Projects like the HackRF demonstrate the power of a supportive community, offering extensive resources to enhance your SDR experience.
## gr-lora
The **gr-lora** project comprises GNU Radio blocks designed to decode LoRa-modulated radio messages using an SDR. LoRa (Long Range) is crucial for Internet of Things (IoT) applications due to its long-range, low-power, and low-bitrate communication capabilities.
While gr-lora supports the majority of LoRa's physical-layer modulation features, it does not facilitate CRC checks of payload and header or decode multiple channels simultaneously. Tested primarily with a USRP B201 and a Microchip RN2483 transmitter, it is also compatible with popular SDRs like the HackRF.
A standout feature of gr-lora is its clock recovery algorithm, introduced in version 0.6, enhancing the handling of long LoRa messages. Improvements in whitening, detection, and decoding further solidify its utility in IoT applications. This ongoing project exemplifies the collaborative spirit of the open-source community, continually evolving to meet users' needs.
## Running the sdr-companion
Ensure [Docker](https://www.docker.com/get-started/) is installed on your system to proceed with the sdr-companion setup.
1. **Download the Docker Image**: Begin by downloading the gr-lora image using the following command:
```bash
docker pull rpp0/gr-lora:latest
```
2. **Prepare Your SDR**: Connect your SDR (e.g., HackRF) to your machine. Ensure device permissions are correctly set to avoid detection issues.
3. **Run the Docker Container**: Execute the script to start the Docker container with gr-lora:
```bash
./docker_run_grlora.sh
```
Upon success, you'll enter the Docker container environment:
```bash
[root@9089ddfe32b5 apps]#
```
4. **Launch GNU Radio Companion**: Inside the container, open the lora_receive_realtime.grc flowgraph with GNU Radio Companion:
```bash
gnuradio-companion lora_receive_realtime.grc
```
5. **Configure and Execute**: Adjust the frequency, spreading factor, and other settings as needed at the gnuradio-companion interface. Start receiving and decoding by selecting *Run -> Execute*.
Decoded traffic will be displayed in hex format in the gnuradio-companion console.
## Prebuilt Flowgraphs
For convenience, prebuilt flowgraphs for specific frequencies are available:
- **915 MHz SF7 125k BW CR 4/5**: `915-sf7-125bw-cr4_5.grc`
- **868 MHz SF7 125k BW CR 4/5**: `868-sf7-125bw-cr4_5.grc`
To download these into the Docker container:
1. **Identify Host IP**: Use `ip addr` (or `ifconfig` if available) to find your host machine's IP address.
2. **Host Web Server**: On your host machine, in the directory with the flowgraphs, start a web server:
```bash
python3 -m http.server 80
```
3. **Download Flowgraphs**: Inside the container, use curl to download the desired flowgraph:
```bash
curl -O http://<your-host-ip>/915-sf7-125bw-cr4_5.grc
curl -O http://<your-host-ip>/868-sf7-125bw-cr4_5.grc
```
## Troubleshooting and Support
For troubleshooting common issues or seeking additional guidance, refer to the gr-lora project documentation and community forums. These resources can provide valuable support as you navigate installation and operation challenges.