.\" Automatically generated by Pandoc 2.2.1 .\" .TH "LORAPIPE" "1" "October 2019" "John Goerzen" "lorapipe Manual" .hy .SH NAME .PP lorapipe \- Transfer data and run a network over LoRa long\-range radios .SH SYNOPSIS .PP \f[B]lorapipe\f[] [ \f[I]OPTIONS\f[] ] \f[B]PORT\f[] \f[B]COMMAND\f[] [ \f[I]command_options\f[] ] .SH OVERVIEW .PP \f[B]lorapipe\f[] is designed to integrate LoRa long\-range radios into a Unix/Linux system. In particular, lorapipe can: .IP \[bu] 2 Bidirectionally pipe data across a LoRa radio system .IP \[bu] 2 Do an RF ping and report signal strength at each end .IP \[bu] 2 Operate an AX.25 network using LoRa, and atop it, TCP/IP .SH HARDWARE REQUIREMENTS .PP \f[B]lorapipe\f[] is designed to run with a Microchip RN2903/RN2483 as implemented by LoStik. .PP Drivers for other hardware may be added in the future. .PP The Microchip firmware must be upgraded to 1.0.5 before running with \f[B]lorapipe\f[]. Previous versions lacked the \f[C]radio\ rxstop\f[] command, which is a severe limitation when receiving multiple packets rapidly. .PP See the documents tab for the RN2093 (https://www.microchip.com/wwwproducts/en/RN2903) and the firmware upgrade guide (https://www.pocketmagic.net/rn2483-rn2903-firmware-upgrade-guide/) \- note that the upgrade part is really finicky and you need the \[lq]offset\[rq] file. .SH PROTOCOL .PP The \f[B]lorapipe pipe\f[] command is the primary one of interest here. It will receive data on stdin, break it up into LoRa\-sized packets (see \f[B]\[en]maxpacketsize\f[]), and transmit it across the radio. It also will receive data from the radio channel and send it to stdout. No attempt at encryption or authentication is made; all packets successfully decoded will be sent to stdout. Authentication and filtering is left to other layers of the stack atop \f[B]lorapipe\f[]. .PP A thin layer atop \f[B]lorapipe pipe\f[] is \f[B]lorapipe kiss\f[], which implements the AX.25 KISS protocol. It transmits each KISS frame it receives as a LoRa frame, and vice\-versa. It performs rudimentary checking to ensure it is receiving valid KISS data, and will not pass anything else to stdout. This support can be used to build a TCP/IP network atop LoRa as will be shown below. Encryption and authentication could be added atop this by using tools such as OpenVPN or SSH. .PP \f[B]lorapipe\f[] provides only the guarantees that LoRa itself does: that raw LoRa frames which are decoded are intact, but not all frames will be received. It is somewhat akin to UDP in this sense. Protocols such as UUCP, ZModem, or TCP can be layered atop \f[B]lorapipe\f[] to transform this into a \[lq]reliable\[rq] connection. .SS Broadcast Use and Separate Frequencies .PP It is quite possible to use \f[B]lorapipe\f[] to broadcast data to multiple listeners; an unlimited number of systems can run \f[B]lorapipe pipe\f[] to receive data, and as long as there is nothing on stdin, they will happily decode data received over the air without transmitting anything. .PP Separate communication channels may be easily achieved by selecting separate radio frequencies. .SS Collision Mitigation .PP \f[B]lorapipe\f[] cannot provide collision detection or avoidance, though it does impliement a collision mitigation strategy as described below. .PP As LoRa radios are half\-duplex (they cannot receive while transmitting), this poses challenges for quite a few applications that expect full\-duplex communication or something like it. In testing, a particular problem was observed with protocols that use transmission windows and send data in packets. These protocols send ACKs after a successful packet transmission, which frequently collided with the next packet transmitted from the other radio. This caused serious performance degredations, and for some protocols, complete failure. .PP There is no carrier detect signal from the LoRa radio. Therefore, a turn\-based mechanism is implemented; with each frame transmitted, a byte is prepended indicating whether the sender has more data in queue to transmit or not. The sender will continue transmitting until its transmit buffer is empty. When that condition is reached, the other end will begin transmitting whatever is in its queue. This enables protocols such as UUCP \[lq]g\[rq] and UUCP \[lq]i\[rq] to work quite well. .PP A potential complication could arise if the \[lq]last\[rq] packet from the transmitter never arrives at the receiver; the receiver might therefore never take a turn to transmit. To guard against this possibility, there is a timer, and after receiving no packets for a certain amount of time, the receiver will assume it is acceptable to transmit. This timeout is set by the \f[B]\[en]eotwait\f[] option and defaults to 1000ms (1 second). .PP The signal about whether or not data remains in the queue takes the form of a single byte prepended to every frame. It is 0x00 if no data will follow immediately, and 0x01 if data exists in the transmitters queue which will be sent immediately. The receiving side processes this byte and strips it off before handing the data to the application. This byte is, however, visible under \f[B]\[en]debug\f[] mode, so you can observe the protocol at this low level. .SH RADIO PARAMETERS AND INITIALIZATION .PP The Microchip command reference, available at , describes the parameters available for the radio. A LoRa data rate calculator is available at to give you a rough sense of the speed of different parameters. In general, by sacrificing speed, you can increase range and robustness of the signal. The default initialization uses fairly slow and high\-range settings: .IP .nf \f[C] sys\ get\ ver mac\ reset mac\ pause radio\ get\ mod radio\ get\ freq radio\ get\ pwr radio\ get\ sf radio\ get\ bw radio\ get\ cr radio\ get\ wdt radio\ set\ pwr\ 20 radio\ set\ sf\ sf12 radio\ set\ bw\ 125 radio\ set\ cr\ 4/5 radio\ set\ wdt\ 60000 \f[] .fi .PP The \f[C]get\f[] commands will cause the pre\-initialization settings to be output to stderr if \f[C]\-\-debug\f[] is used. A maximum speed init would look like this: .IP .nf \f[C] sys\ get\ ver mac\ reset mac\ pause radio\ get\ mod radio\ get\ freq radio\ get\ pwr radio\ get\ sf radio\ get\ bw radio\ get\ cr radio\ get\ wdt radio\ set\ pwr\ 20 radio\ set\ sf\ sf7 radio\ set\ bw\ 500 radio\ set\ cr\ 4/5 radio\ set\ wdt\ 60000 \f[] .fi .PP You can craft your own parameters and pass them in with \f[C]\-\-initfile\f[] to customize the performance of your RF link. .PP A particular hint: if \f[C]\-\-debug\f[] shows \f[C]radio_err\f[] after a \f[C]radio\ rx\ 0\f[] command, the radio is seeing carrier but is getting CRC errors decoding packets. Increasing the code rate with \f[C]radio\ set\ cr\f[] to a higher value such as \f[C]4/6\f[] or even \f[C]4/8\f[] will increase the FEC redundancy and enable it to decode some of those packets. Increasing code rate will not help if there is complete silence from the radio during a transmission; for those situations, try decreasing bandwidth or increasing the spreading factor. Note that coderate \f[C]4/5\f[] to the radio is the same as \f[C]1\f[] to the calculator, while \f[C]4/8\f[] is the same as \f[C]4\f[]. .SH PROTOCOL HINTS .PP Although \f[B]lorapipe pipe\f[] doesn't guarantee it preserves application framing, in many cases it does. For applications that have their own framing, it is highly desirable to set their frame size to be less than the \f[B]lorapipe \&... pipe \[en]maxpacketsize\f[] setting. This will reduce the amount of data that would have to be retransmitted due to lost frames. .PP As speed decreases, packet size should as well. .SH APPLICATION HINTS .SS SOCAT .PP The \f[B]socat\f[](1) program can be particularly helpful; it can gateway TCP ports and various other sorts of things into \f[B]lorapipe\f[]. This is helpful if the \f[B]lorapipe\f[] system is across a network from the system you wish to run an application on. \f[B]ssh\f[](1) can also be useful for this purpose. .PP A basic command might be like this: .IP .nf \f[C] socat\ TCP\-LISTEN:12345\ EXEC:\[aq]lorapipe\ /dev/ttyUSB0\ pipe\[aq] \f[] .fi .PP Some systems might require disabling buffering in some situations, or using a pty. In those instances, something like this may be in order: .IP .nf \f[C] socat\ TCP\-LISTEN:10104\ EXEC:\[aq]stdbuf\ \-i0\ \-o0\ \-e0\ lorapipe\ /dev/ttyUSB4\ pipe,pty,rawer\[aq] \f[] .fi .SS UUCP .PP For UUCP, I recommend protocol \f[C]i\f[] with the default window\-size setting. Use as large of a packet size as you can; for slow links, perhaps 32, up to around 100 for fast, high\-quality links. (LoRa seems to not do well with packets above 100 bytes). .PP Protocol \f[C]g\f[] (or \f[C]G\f[] with a smaller packet size) can also work, but won't work as well. .PP Make sure to specify \f[C]half\-duplex\ true\f[] in \f[C]/etc/uucp/port\f[]. .PP Here is an example of settings in \f[C]sys\f[]: .IP .nf \f[C] protocol\ i protocol\-parameter\ i\ packet\-size\ 90 protocol\-parameter\ i\ timeout\ 30 chat\-timeout\ 60 \f[] .fi .PP Note that UUCP protocol i adds 10 bytes of overhead per packet, so this is designed to work with the default recommended packet size of 100. .PP Then in \f[C]/etc/uucp/port\f[]: .IP .nf \f[C] half\-duplex\ true reliable\ false \f[] .fi .SS YMODEM (and generic example of bidirectional pipe) .PP ZModem makes a poor fit for LoRa because its smallest block size is 1K. YModem, however, uses a 128\-byte block size. Here's an example of how to make it work. Let's say we want to transmit /bin/true over the radio. We could run this: .IP .nf \f[C] socat\ EXEC:\[aq]sz\ \-\-ymodem\ /bin/true\[aq]\ EXEC:\[aq]lorapipe\ /dev/ttyUSB0\ pipe\[aq] \f[] .fi .PP And on the receiving end: .IP .nf \f[C] socat\ EXEC:\[aq]rz\ \-\-ymodem\[aq]\ EXEC:\[aq]lorapipe\ /dev/ttyUSB0\ pipe\[aq] \f[] .fi .PP This approach can also be used with many other programs. For instance, \f[C]uucico\ \-l\f[] for UUCP logins. .SS KERMIT .PP Using the C\-kermit distribution (\f[B]apt\-get install ckermit\f[]), you can configure for \f[B]lorapipe\f[] like this: .IP .nf \f[C] set\ receive\ packet\-length\ 90 set\ send\ packet\-length\ 90 set\ duplex\ half set\ window\ 2 set\ receive\ timeout\ 10 set\ send\ timeout\ 10 \f[] .fi .PP Then, on one side, run: .IP .nf \f[C] pipe\ lorapipe\ /dev/ttyUSB0\ pipe Ctrl\-\\\ c server \f[] .fi .PP And on the other: .IP .nf \f[C] pipe\ lorapipe\ /dev/ttyUSB0\ pipe Ctrl\-\\\ c \f[] .fi .PP Now you can do things like \f[C]rdir\f[] (to see ls from the remote), \f[C]get\f[], \f[C]put\f[], etc. .SS DEBUGGING WITH CU .PP To interact directly with the modem, something like this will work: .IP .nf \f[C] cu\ \-h\ \-\-line\ /dev/ttyUSB0\ \-s\ 57600\ \-e\ \-o\ \-f\ \-\-nostop \f[] .fi .SH INSTALLATION .PP \f[B]lorapipe\f[] is a Rust program and can be built by running \f[B]\f[BC]cargo\ build\ \-\-release\f[B]\f[]. The executable will then be placed in \f[B]target/release/lorapipe\f[]. Rust can be easily installed from . .SH INVOCATION .PP Every invocation of \f[B]lorapipe\f[] requires at least the name of a serial port (for instance, \f[B]/dev/ttyUSB0\f[]) and a subcommand to run. .SH GLOBAL OPTIONS .PP These options may be specified for any command, and must be given before the port and command on the command line. .TP .B \f[B]\-d\f[], \f[B]\[en]debug\f[] Activate debug mode. Details of program operation will be sent to stderr. .RS .RE .TP .B \f[B]\-h\f[], \f[B]\[en]help\f[] Display brief help on program operation. .RS .RE .TP .B \f[B]\[en]readqual\f[] Attempt to read and log information about the RF quality of incoming packets after each successful packet received. There are some corner cases where this is not possible. The details will be logged with \f[B]lorapipe\f[]'s logging facility, and are therefore only visible if \f[B]\[en]debug\f[] is also used. .RS .RE .TP .B \f[B]\-V\f[], \f[B]\[en]version\f[] Display the version number of \f[B]lorapipe\f[]. .RS .RE .TP .B \f[B]\[en]eotwait\f[] \f[I]TIME\f[] The amount of time in milliseconds to wait after receiving a packet that indicates more are coming before giving up on receiving an additional packet and proceeding to transmit. Ideally this would be at least the amount of time it takes to transmit 2 packets. Default: 1000. .RS .RE .TP .B \f[B]\[en]initfile\f[] \f[I]FILE\f[] A file listing commands to send to the radio to initialize it. If not given, a default set will be used. .RS .RE .TP .B \f[B]\[en]txwait\f[] \f[I]TIME\f[] Amount of time in milliseconds to pause before transmitting each packet. Due to processing delays on the receiving end, packets cannot be transmitted immediately back to back. Increase this if you are seeing frequent receive errors for back\-to\-back packets, which may be indicative of a late listen. Experimentation has shown that a value of 120 is needed for very large packets, and is the default. You may be able to use 50ms or less if you are sending small packets. In my testing, with 100\-byte packets, a txwait of 50 was generally sufficient. .RS .RE .TP .B \f[I]PORT\f[] The name of the serial port to which the radio is attached. .RS .RE .TP .B \f[I]COMMAND\f[] The subcommand which will be executed. .RS .RE .SH SUBCOMMANDS .SS lorapipe \&... pipe .PP The \f[B]pipe\f[] subcommand is the main workhorse of the application and is described extensively above. It has one optional parameter: .TP .B \f[B]\[en]maxpacketsize\f[] \f[I]BYTES\f[] The maximum frame size, in the range of 10 \- 250. The actual frame transmitted over the air will be one byte larger due to \f[B]lorapipe\f[] collision mitigation as described above. Experimentation myself, and reports from others, suggests that LoRa works best when this is 100 or less. .RS .RE .SS lorapipe \&... ping .PP The \f[B]ping\f[] subcommand will transmit a simple line of text every 10 seconds including an increasing counter. It can be displayed at the other end with \f[B]lorapipe \&... pipe\f[] or reflected with \f[B]lorapipe \&... pong\f[]. .SS lorapipe \&... pong .PP The \f[B]pong\f[] subcommand receives packets and crafts a reply. It is intended to be used with \f[B]lorapipe \&... ping\f[]. Its replies include the signal quality SNR and RSSI if available. .SH AUTHOR .PP John Goerzen .SH COPYRIGHT AND LICENSE .PP Copyright (C) 2019 John Goerzen . .SH AUTHORS John Goerzen.