140 lines
7.7 KiB
Markdown
140 lines
7.7 KiB
Markdown
|
|
|
||
|
|
# LoRa Modulation Jam
|
||
|
|
|
||
|
|
This is a project to measure packet delivery rates across different permutations of LoRa modulation settings. Two or more nodes operate as test stations are set up to send and receive packets at the same LoRa settings. Another node operates as the control station and sends commands to initiate the tests.
|
||
|
|
|
||
|
|
This test framework uses MeshCore since it creates realistic packet sizes, has a useful python interface, and does not require restarting the node to change radio settings.
|
||
|
|
|
||
|
|
|
||
|
|
## Test Stations
|
||
|
|
|
||
|
|
Python service running on a Raspberry Pi and interfacing with a MeshCore node using the `meshcore` python library over USB Serial.
|
||
|
|
|
||
|
|
The service runs on Pi boot and connects to the USB-attached node. It reads the config from `~/modjam-config.json` that looks something like this:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"this_station_name": "A",
|
||
|
|
"channel_name": "modjam",
|
||
|
|
"channel_psk": "1234abcdefg==",
|
||
|
|
"idle_heartbeat_min": 15,
|
||
|
|
"control_radio": {
|
||
|
|
"frequency_mhz": 915.125,
|
||
|
|
"bandwidth_khz": 500,
|
||
|
|
"spread_factor": 12,
|
||
|
|
"coding_rate": 8,
|
||
|
|
"tx_power_dbm": 22,
|
||
|
|
},
|
||
|
|
"data_radio": {
|
||
|
|
"frequency_mhz": 915.125,
|
||
|
|
"bandwidth_khz": 500,
|
||
|
|
"spread_factor": 7,
|
||
|
|
"coding_rate": 5,
|
||
|
|
"tx_power_dbm": 1,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Commands
|
||
|
|
|
||
|
|
The Test Stations listen for commands from the Control Station that come on the configured channel (channel_name, channel_psk, control_radio).
|
||
|
|
|
||
|
|
Commands follow this format: `<cmd>[:<station>]|<attr1:val1,val2,…>|<attr2:val1,val2,…>…`. They may be unicast addressed to a specific station or multicast to all stations. The commands take named arguments that are pipe-separated. Each consists of a name followed by a colon followed by a comma-separated list of values (there may be no comma if there is only one value). The arguments are not ordered.
|
||
|
|
|
||
|
|
#### `START`
|
||
|
|
|
||
|
|
The `START` command is not directed at a specific Test Station, it is multicast to all stations. It provides a test name, set of frequencies, set of bandwidths, set of spread factors, set of coding rates, and set of transmit powers that together provide all the permutations to be tested. The named test will run for all combinations of these radio parameters. The command also lists all the stations that should participate in that test.
|
||
|
|
|
||
|
|
`START|name:<testname>|f:<freq1>,<freq2>,…|bw:<62.5|125|250|500>,…|sf:<6,7,8,9,10,11,12>,…|cr:<4,5,6,7,8>,…|pow:<pow1>,<pow2>|stations:<a>,<b>,…|duration:<s>|padding:<s>|spacing:<s>|size:<bytes1>,<bytes2>,…|at:<n>`
|
||
|
|
|
||
|
|
- name (required): the string name of the test run, used to name the test file and reference the results later
|
||
|
|
- f: the float frequencies to test in MHz (default: 916.1)
|
||
|
|
- bw: a choice of bandwidths to test from the possible options 62.5, 125, 250, 500 (default: all of these)
|
||
|
|
- sf: a choice of spread factors to test from the options 7,8,9,10,11,12 (default: all of these)
|
||
|
|
- cr: a choice of coding rates to test from the options of 5,6,7,8 (default: all of these)
|
||
|
|
- pow: the int tx powers to test (default: 22,)
|
||
|
|
- stations: the string names of stations to participate (default: 'A','B')
|
||
|
|
- duration: the int seconds of each test case (default: 300)
|
||
|
|
- padding: the int seconds between each test case (default: 60)
|
||
|
|
- spacing: the int seconds between each test transmission (default: 2)
|
||
|
|
- size: the list of int payload sizes to test in bytes (default: 40,)
|
||
|
|
- at: the int %nth minute of the hour to begin the test (default: 5)
|
||
|
|
|
||
|
|
These arguments have defaults so not all need to be specified for the `START` command to be valid. Only the `name` is required.
|
||
|
|
|
||
|
|
A complete example command:
|
||
|
|
`START|name:ab123|f:915.1|bw:62.5,125,250,500|sf:6,7,8,9,10,11,12|cr:4,5,6,7,8|pow:10,22|stations:A,B,C|padding:60|duration:600|spacing:2|at:5|size:40`
|
||
|
|
|
||
|
|
#### `STOP`
|
||
|
|
|
||
|
|
The `STOP` command is a multicast command to all Test Stations. When they receive this, if they are `RUNNING`, they switch to an `IDLE` state and stop their test protocol wherever they were in it.
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
### States
|
||
|
|
|
||
|
|
The Test Station has two states: `IDLE`, `RUNNING`:
|
||
|
|
|
||
|
|
#### IDLE
|
||
|
|
|
||
|
|
After reading the config, the process configures the attached node with a channel named the `encryption_name` and using the `encryption_psk` (if such a channel is not already configured), and sets the radio to the `control_radio` settings, then enters the `IDLE` state.
|
||
|
|
|
||
|
|
While in the `IDLE` state the node sends heartbeat messages every `idle_heartbeat_min` on the configured channel: `<now>|<this_station_name>|<state>|<noise_floor>` where `now` is the unix timestamp, `this_station_name` is from the config file, `state` is the current process state, and `noise_floor` is the noise floor as measured by the attached node.
|
||
|
|
|
||
|
|
An example heartbeat message: `1778184205|B|IDLE|-102`.
|
||
|
|
|
||
|
|
The service stays in this `IDLE` state, sending regular heartbeats, until it receives a `START` command.
|
||
|
|
|
||
|
|
#### RUNNING
|
||
|
|
|
||
|
|
The control node sends a `START` command on the `control_radio` settings. This is received by all Test Stations in `IDLE` state. They build a cuesheet based on the specified test parameters. Then they enter a `RUNNING` state, wait until the time specified by the `START` command, then proceed to iterate through the cuesheet-defined permutations and taking turns transmitting or listening.
|
||
|
|
|
||
|
|
While `RUNNING`, the process iterates through the cuesheet based on the defined timing. If the specified `sender` matches its own station name, it executes transmissions. Otherwise, it waits. Every packet it sends or receives gets logged to a tab-separated `<testname>.tsv` file.
|
||
|
|
|
||
|
|
In between each test case, during the `padding` interval specified by the start command, the node switches back to the `control_radio` setting so it can emit status information and listen for other commands. `10` seconds _before_ the start time of the test case it sends a "next" message: `<now_ts>|<this_station_name>|next:<f>/<bw>/<sf>/<cr>/<pow>/<size>`. `10` seconds _after_ the end of the test case it sends a "done" message: `<now_ts>|<this_station_name>|done:<f>/<bw>/<sf>/<cr>/<pow>/<size> <n_sent>/<n_rcvd>`.
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
## Example
|
||
|
|
|
||
|
|
Two Test Stations start up, with nearly identical configurations but one is named `'A'` and one is named `'B'`. They tune to the `control_radio` settings and enter `IDLE` state.
|
||
|
|
|
||
|
|
The Control Station sends a `START|test1|f:910.2|bw:62.5,500|sf:8,9,10|cr:5` command at clock time 10:07:23. Test Stations A and B hear this enter `RUNNING` states. At time 10:10:10, stations A and B send "next" messages:
|
||
|
|
|
||
|
|
- `1778148610|A|next:910.2/62.5/8/5/22/40`
|
||
|
|
- `1778148610|B|next:910.2/62.5/8/5/22/40`
|
||
|
|
|
||
|
|
At 10:10:20 stations A and B set their radios to frequency 910.2 MHz, bandwidth 62.5 kHz, spread factor 8, coding rate 5, tx power 22.
|
||
|
|
|
||
|
|
At 10:10:30 station A begins a series of transmissions spaced 2 seconds apart:
|
||
|
|
|
||
|
|
- 1778148610.2168489,30.12679696083069,1|551097625881289327832
|
||
|
|
- 1778148612.738883,32.648837089538574,2|738453771722320023996
|
||
|
|
- 1778148615.468757,35.378714084625244,3|7910624607885536300710
|
||
|
|
- …
|
||
|
|
|
||
|
|
Station A logs every message it queues for the radio and every message the radio reports it transmitted. Station B logs every message received.
|
||
|
|
|
||
|
|
At 10:14:30 station A stops its test transmissions.
|
||
|
|
|
||
|
|
At 10:15:30 station B starts a similar series of transmissions. It logs every message it queues and transmits. Station A logs every message it receives.
|
||
|
|
|
||
|
|
At 10:19:30 station B stops its test transmissions.
|
||
|
|
|
||
|
|
At 10:19:40 stations A and B tune to the control_radio settings
|
||
|
|
|
||
|
|
At 10:19:50 stations A and B send "done" messages:
|
||
|
|
|
||
|
|
- 1778149190|A|done:910.2/62.5/8/5/22/40 120/110
|
||
|
|
- 1778149190|B|done:910.2/62.5/8/5/22/40 120/114
|
||
|
|
|
||
|
|
At 10:20:10 stations A and B send "next" messages, at 10:20:20 tune to the next test radio settings (910.2 MHz, 62.5 BW, 9 SF, 5 CR, 22 power), and repeat the process of sending and listening.
|
||
|
|
|
||
|
|
They continue doing this until they have performed tests in each direction for all permutations, at 11:10:00, retune to the control radio settings and enter IDLE state.
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|