xbnet/doc/lorapipe.1

467 lines
15 KiB
Groff

.\" 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
<http://ww1.microchip.com/downloads/en/DeviceDoc/40001811A.pdf>,
describes the parameters available for the radio.
A LoRa data rate calculator is available at
<https://www.rfwireless-world.com/calculators/LoRa-Data-Rate-Calculator.html>
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 <https://www.rust-lang.org/>.
.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 <jgoerzen@complete.org>
.SH COPYRIGHT AND LICENSE
.PP
Copyright (C) 2019 John Goerzen <jgoerzen\@complete.org
.PP
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
.PP
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
.PP
You should have received a copy of the GNU General Public License along
with this program.
If not, see <http://www.gnu.org/licenses/>.
.SH AUTHORS
John Goerzen.