Wednesday, January 24, 2018

Long Range Radios Linux/macOS Part 2 - Adafruit Feather m0 RFM96 Lora Radio

After previously playing around with the e32-ttl-100 modules, this time the focus is on microcontroller boards that include a lora transceiver. These devices are very small, the library for radio access seems to be quite stable and it already has support for packet transmission! So not only is SLIP encoding obsolete here but the maximum packet size is also significantly larger at over 250 bytes! The downside? You have to write your code in C/C++ for a microcontroller! This is something completely different than developing for Linux systems such as a Raspberry Pi or even an OpenWRT-based router!


Adafruit Feather m0 lora with ghetto-style wire antenna

The solution? Use the integrated serial port on the microcontroller to simulate a modem. Therefore, only the low level stuff has to be developed for the microcontroller and higher level communication stuff can be handled on other devices! In my case, I prototyped all this on an Adafruit Feather m0 lora module as shown in the picture above.

The rf95modem firmware is available open source and can be easily build using PlatformIO. Currently, only some of the RFM95 parameters can be manipulated through the serial interface and one can only send and receive data frames via the serial port. The "modem" is controlled through AT commands similar to classic dial-up modems.

Here is a list of currently implemented commands:

AT+HELP Print this usage information. AT+TX=<hexdata> Send binary data. AT+RX=<0|1> Turn receiving on (1) or off (2). AT+INFO Output status information. AT+MODE=<NUM> Set modem config: 0 - medium range (default) Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. 1 - fast+short range Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. 2 - slow+long range Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. 3 - slow+long range Bw = 125 kHz, Cr = 4/8, Sf = 4096chips/symbol, CRC on.

This makes sending raw data really easy:
AT+TX=414141
Beware, overlong packets might be a problem since the radio drivers might not always give correct numbers for maximum message length!

Receiving this data on another module is just as easy. First, the receive listener must be activated:
AT+RX=1
And the for each incoming transmission a line similar to the following is printed to the serial line:
+RX 3,414141,-15,8
This means that 3 bytes, encoded as a HEX string, were received. RSSI for this packet was -15 and SNR was 8.

Furthermore, one can display various status information about the current configuration using the AT+INFO command:
status info: firmware: 0.1 modem config: medium range max pkt size: 251 frequency: 433.00 rx listener: 1 rx bad: 0 rx good: 0 tx good: 3

This makes it really easy to tap into machine-to-machine networks using rf95-family based lora chips from any mac or linux computer. Due to the fact that I only have simple wire antennas attached, I have not made any real range tests yet. Once my uFL connectors and antennas from aliexpress  get here, I will  do some more serious experiments.

Long Range Radios Linux/macOS Part 1 - E32-TTL-100

One of the cheapest ways to get long range communication on any computer is equipping it with a E32-TTL-100 (or E45-TTL-100) lora module. These modules transparently provide a communication channel via a serial interface. The specs can be found all over the internet such as here and here. Unfortunately, there is no application for linux or macOS to set the module parameters such as frequency and air speed.



These modules can be directly hooked up to any serial connector for sending and receiving text messages. Problematic is just switching between the configuration mode and sending mode, therefore the m0 and m1 pins have to be both LOW or both HIGH requiring some extra wiring, jumpers or extra GPIO pins. For ease of use, there are special adapters available like the e15-usb-t2. Another solution that I prefer is hooking the m0 and m1 pins to some raspberry pi GPIO pins. I connected them to pins GPIO17 and GPIO27. This has the benefit that switching between config and transmission mode can be done in software without the use of jumpers!

Configuration


The next problem was that setting parameters requires setting individual bits in hex string encoded bytes. For windows an official software is available with an easy to use GUI - so far I have never used this piece of software :) We first used python to ease the process of generating a valid config a bit. The project is very incomplete and not that useful at the moment. A few months later, I found some time during the cold winter months to play some more with these modules. This time I wanted to produce something more stable and useful. This is where go-e32-lora comes in to play. It is a library as well as a set of command line tools written in golang and optimized for the e32 chips. First of all it provides e32config a simple tool to read-out a config, decode hex config strings, generate a new one, switch operating modes (if GPIOs connected) and apply configs. There is even a dialog-based wizard for config generation included:


After developing the textmode e32config I found a graphical e45config tool which could probably be easily tweaked to work with an e32 chip. The major difference being only the chosen radio frequency.

Applications

One of the biggest problems you will encounter when dealing with e32 chips is the maximum packet size of 58 bytes! Since the plan was to run something like serval-dna via these lora links this is unacceptable. The solution is fragmentation! But since the chip hides all packet information from us and instead transparently delivers raw character streams one does not know when a specific transmission is beginning, finished, interrupted or mixed with another transmission from another node! Therefore, the  go-e32-lora lib uses SLIP encoding together with a fragmentation mechanism to provide the required features. This works surprisingly well, even though lost fragments are not retransmitted at the moment. Since bandwidth is very precious and golang is so easy I also added an option to compress all the payload. Depending on what you send this can dramatically reduce the number of bytes or in some cases even increase them!
To specify where the e32 module is connected, the library checks for a LORAPORT environment variable. By default it tries to open /dev/ttyS0 but you can easily point it to /dev/ttyUSB0 or similar.

Commands

Several useful commands are provided by the go-e32-lora project:
- pktsend - a simple tool to send any provided string via lora-SLIP-frag packet. Due to the rx/tx buffer limit of 256 bytes on the E32 chips the total number of bytes should not exceed that limit.
- pktrecv - the counterpart to pktsend, receives lora-SLIP-frag packets and prints them to the console.
- pktdump - for debugging purposes just dumps anything received via lora interface has hex bytes.

Evaluation

For evaluation purposes I wanted to do some range checks. The bcaster command  periodically broadcasts the hostname, a sequence number and the current time via lora. On the other side there is monitor which just listens for any incoming transmissions and outputs them to the command line. In previous tests I ran around carrying a laptop in one hand, an antenna in the other and various pieces of electronics in between. This time I wanted something smaller and even more portable. I still had an 16x2 I2C lcd display from a raspberry pi jukebox project laying around. Together with an unused RPi PowerPack and a Pi Zero W this makes a super portable prototype device!

Pi Zero W, E32-TTL-100, 16x2 LCD, RPi PowerPack

After looking around in the house I even found a case for the device that was easy to customize and unlike a 3d printed one did not rely on fossil fuels or had me waiting for hours just to realize that it does not fit :) So this is how the Lora RangeFinder 2000 was born!

3d printed case? no thanks! 
I set up two main bcaster nodes, one at my office and the other one at home. Since the office building is built of thick concrete walls and my office window is facing away from the city, the main range test results come from my home node. The building is surrounded by several others in the middle of the city, in direction of my working place there is also a large forrest area in between. The next morning I placed the Lora RangeFinder 2000 on the passenger seat of my car while driving to work to record received beacons.

Display last received lora beacon.
So how far could I go? With 1K airspeed and forward-error-correction off the last packets I received were in a distance of 1.8 - 2 km from my home. With 25K airspeed and FEC on I still got some packets in a distance of 1.7 km but with much higher packet loss. But keep in mind that this was all logged in a vehicle constantly driving about 70 km/h! Considering that the transmitter was placed in the middle of a room, next to my computer, far away from any window and then several houses and parts of a forrest in between (no line of sight!) the results are still quite good!

After the initial success I started porting mesher to this lora lib. This was straight forward and easy but the code still needs some clean-up, especially, after I added some DTN-like features to it.

These developments have been delayed by the fact that I got my hands on a different lora module: RFM95. More specific the adafruit feather boards with lora chips (m0 and 32u4). These will be featured in part 2 of this series.