This repository contains software to construct, transmit, and receive data packets with forward error correction (FEC) via packet injection and monitor mode using the AR9271 chip. We leverage packet injection and monitoring using the PCAP library to send and receive custom raw data frames over the air without the need for a traditional access point connection.
The transmit software is responsible for crafting custom packets in user space and attaching correct headers before handing them off to PCAP. In particular, each custom packet includes these three components:
- Radiotap header: the “de facto” standard for 802.11 frame injection and reception, these fields control transmission parameters like the data rate, and can alert the driver that we will not expect ACKs.
- IEEE80211 MAC Layer header: we are primarily concerned with the address section of this header, which we can stuff with a fake MAC address the receiver can listen for.
- Payload: The actual block of data to send.
When a packet is captured (based on the fake MAC address) and forwarded to PCAP, we receive a raw byte array in user space. After unpacking the payload, we have the original transmitted data.
As with any wireless communication link, the connection between OreSat and the ground will not be perfect. We anticipate two types of errors: bit errors, where bits in the received data are randomly flipped; and packet loss errors, in which entire packets of data are not received on the ground.
In most applications, these errors can be avoided by having the receiver detect lost packets or bit errors (e.g. with checksums) and request retransmission when necessary. However, since OreSat Live is a unidirectional link, there will be no way for the ground stations to request packet retransmission. We therefore implement forward error correction (FEC), in which OreSat sends packets encoded with redundant information in such a way that the receiver can reconstruct the original data even in the face of bit errors and packet loss.
We base our FEC implementation on the approach developed at the Universitat Politècnica de Catalunya. Two separate FEC encodings are concatenated to create a transmission that is robust to both kinds of errors. First, data is split into blocks and put through a low-density parity-check (LDPC) encoder built on OpenFEC, which is able to correct for packet loss errors. The encoded data is then pushed through a Reed-Solomon encoder built on rscode, which is designed to correct single bit errors. These doubly-encoded packets are then transmitted, received on the other end, and decoded to reconstruct the original data.
A diagram of the process is available here.
.
├── .github <-- GitHub workflow specification for automatic build / test
├── archive <-- Previous DxWiFi capstone work
├── config <-- Configuration files for rsyslog, Debian installer, etc.
├── dxwifi <-- Source code for DxWifi suite of programs
├── libdxwifi <-- Shared library code for the DxWiFi suite
├── openfec <-- OpenFEC library (http://openfec.org/)
├── patches <-- Firmware patches for the Atheros AR9271
├── platform <-- Cross compilation scripts
├── rscode <-- Reed-Solomon library (submodule)
├── test <-- System tests and test data
├── .gitignore
├── .gitmodules
├── CMakeLists.txt
├── LICENSE <-- GNU GPL v3
├── README.md <-- You are here
└── startmonitor.sh <-- Script to put a WiFi card in monitor mode
- 2 Linux devices (Raspberry Pi, BeagleBone Black, laptop, etc.)
- 2 WiFi adapters that support monitor mode (tested with Atheros AR9271)
- CMake
ip
iw
libgpiod-dev
libpcap-dev
pybind11-dev
- Python 3.6 or higher and
python3-dev
(for tests and bindings)
Note: if you're using VSCode, you should probably use the CMake Tools extension.
These programs use CMake to generate the correct build files. The following should get you going, but if you need to generate a build for a specific platform then you should probably check out the documentation.
First, make sure the rscode
submodule is up-to-date.
git submodule update --init --recursive
Then you can generate build scripts and make the executables.
mkdir build
cd build && cmake ..
make
Alternatively, to make multiple out-of-source builds you can do the following with any of the default configurations: Debug, Release, RelWithDebInfo, MinSizeRel, TestDebug, TestRel.
cmake -S . -B build/Debug -DCMAKE_BUILD_TYPE=Debug
cmake --build build/Debug
The executables are located in bin
and libraries in lib
. You can also build a
specific target as follows.
cmake --build --target dxwifi
Currently this only supports the armv7l
architecture. You'll first
need to setup your toolchain.
sudo apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf qemu-user-static debootstrap -y
sudo qemu-debootstrap --arch armhf buster /mnt/data/armhf http://deb.debian.org/debian/
sudo chroot /mnt/data/armhf
apt-get install libpcap-dev
This will install the armhf version of libpcap-dev
in mnt/data/armhf/lib/arm-linux-gnueabihf
. Then you can generate the
correct build scripts with:
cmake -S . -B build -DPLATFORM=armhf
With the project built and CMake files present in the build
directory you do the following:
make install
This will install the rx
, tx
, encode
, decode
and startmonitor
programs into /usr/bin
and define a daemon with oresat-dxwifi-txd.service
, which you can start with systemctl
.
To build debian packages to install you can run the following in the build
directory:
cpack # or `make package`
This will create two debian packages oresat-dxwifi-rx_<version>_<arch>.deb
and oresat-dxwifi-tx_<version>_<arch>.deb
. The former installs just the rx
program, and the latter installs installs tx
, startmonitor
and the oresat-dxwifi-txd.service
daemon.
Note: The oresat-dxwifi-txd.service
daemon is currently configured for OreSat0. As such, all it does is transmit a test sequence of bytes ad infinitum or until stopped.
On the receiver, run:
sudo ./startMonitor.sh mon0
sudo ./rx --dev mon0 copy.md
On the transmitter, run:
sudo ./startMonitor.sh mon0
sudo ./tx --dev mon0 README.md
Congratulations, you just copied this README to the receiving device!
(Be sure to change mon0
to the name of your network device.)
Both the receiver and transmitter support a variety of different options. You can get a full list of options and descriptions by running with --help
.
Here's an example where we set the receiver to output received files in the test
directory with format test_n.raw
, timing out after 10 seconds without receiving a packet, logging everything, strictly ordering the packets, filling in missing packets with noise, and only capturing packets addressed to 11:22:33:44:55:66
.
sudo ./rx --dev mon0 -v 6 --ordered --add-noise --timeout 10 --extension raw --prefix test --filter="wlan addr1 11:22:33:44:55:66" test/
For the transmitter, we set it to transmit everything in the dxwifi
directory matching the glob pattern *.md
, listening for new files, timing out after 20 seconds
without a new file, splitting each file into 512 byte blocks, sending 5 redundant control frames, and delaying 10ms between each tranmission block and 10ms between each file transmission.
sudo ./tx --dev mon0 --blocksize 512 --redundancy 5 --delay 10 --file-delay 10 --filter "*.md" --include-all --watch-timeout 20 dxwifi/
When doing multi-file transmission like in the example above, it's critical to set the --file-delay
and --redundancy
parameters
to something reasonable for your channel. If these parameters are not set then file boundaries will not be clearly delimited to the receiver.
To exercise the software's error-correcting capabilities, the tx
program can introduce artifical bit errors and packet losses. To control the rate of occurrence, use the --error-rate
and --packet-loss
(respectively) with values between 0 and 1.
These programs can also be run in "offline" mode for testing purposes. Use the --savefile
flag to save output to or read input from a file instead of transmitting over the air.
Note: As of Release 1.0, the tx
and rx
programs automatically perform forward error correction encoding internally with preset defaults. The below documentation is provided if manual encoding and decoding is still necessary.
To encode a file at a specific code rate:
./encode <input filename> -o <output filename> -c <code rate between 0.0 and 1.0>
The code rate is the rate at which repair symbols will be added to the source data. Note that this will spit out an error if the code rate is too low for the data being encoded. Also note that OpenFEC can only handle a maximum of 50,000 repair symbols before it will internally throw an error. If more than 50,000 repair symbols are needed, OF_LDPC_STAIRCASE_MAX_NB_ENCODING_SYMBOLS_DEFAULT
must be modified in openfec/src/lib_stable/ldpc_staircase/of_codec_profile.h
To decode an encoded file:
./decode <input filename> -o <output filename>
If input file was not correctly encoded (or is corrupted beyond recognition), this will throw an error.
Note: these test scripts require Python 3.6 or higher.
To run the system tests first you'll need to compile the project with DXWIFI_TESTS
defined.
The project Cmake file defines two build configurations with this macro enabled, TestDebug
and TestRel
.
Building with this macro defined will force tx
/rx
to run in offline mode causing them to write or read
packetized data from a savefile
. With the correct binaries built, simply run the following to execute the tests:
python -m unittest
There is also a script sweep.py
to automatically iterate through code rate, error rate, and packet loss rate parameters. To use (from the repository root):
python test/sweep.py --code-rate | -c [min] [max] [step]
--error-rate | -e [min] [max] [step]
--packet-loss | -p [min] [max] [step]
--source | -s [source file path]
--output | -o [output directory path]
This will perform all combinations of code rates, error rates, and packet loss rates (offline) and save the outputs in subdirectories in the specified output directory.