RadioHead
RH_LoRaFileOps.h
1// RH_LoRaFileOps.h
2//
3// Definitions for RadioHead driver on RPi+Linux
4// and using LoRa-file-ops Linux driver ioctls to
5// transmit and receive RadioHead compatible messages via SX1276/77/78/79
6// and compatible radios.
7// Requires a modified version of LoRa-file-ops driver to be installed,
8// and a compatible radio to be connected
9// appropriately
10// https://github.com/starnight/LoRa/tree/file-ops
11//
12// Tested with:
13// RPi 2 + Debian 2021-03-04 (kernel 5.10.17-v7+ #1403)
14// Dragino LoRa/GPS HAT, https://wiki.dragino.com/index.php?title=Lora/GPS_HAT
15// modified so RFM95 pin 5 NSS was no longer connected to RPi
16// pin P1-22 (GPIO6), but is instead connected to RPi Pin P1-24 (CE0) which
17// is the one used by /dev/loraSPI0.0
18//
19// Author: Mike McCauley (mikem@airspayce.com)
20// Copyright (C) 2021 Mike McCauley
21//
22
23#ifndef RH_LORAFILEOPS_h
24#define RH_LORAFILEOPS_h
25
26#include <RHGenericDriver.h>
27#warning RH_LoRaFileOps unfinished
28
29// This can only build on Linux and compatible systems
30// Caution also requires Lora-file-ops driver to be installed
31// See https://github.com/starnight/LoRa/tree/file-ops
32#if (RH_PLATFORM == RH_PLATFORM_UNIX) || defined(DOXYGEN)
33
34// Driver constant definitions
35// These are copied from LoRa file-ops branch pull request #16
36// See the instructions in the RH_LoRaFileOps documentation for getting that version from github
37// which is absolutely necessary if you want to support RadioHead messages with CRC enabled,
38// which we strongly recommend.
39// since they are not necessarily available in the compile host file
40// system.
41// CAUTION: these must be kept in sync with LoRa-file-ops if it changes
42/* I/O control by each command. */
43#include <sys/ioctl.h>
44#define LORA_IOC_MAGIC '\x74'
45
46#define LORA_SET_STATE (_IOW(LORA_IOC_MAGIC, 0, int))
47#define LORA_GET_STATE (_IOR(LORA_IOC_MAGIC, 1, int))
48#define LORA_SET_FREQUENCY (_IOW(LORA_IOC_MAGIC, 2, int))
49#define LORA_GET_FREQUENCY (_IOR(LORA_IOC_MAGIC, 3, int))
50#define LORA_SET_POWER (_IOW(LORA_IOC_MAGIC, 4, int))
51#define LORA_GET_POWER (_IOR(LORA_IOC_MAGIC, 5, int))
52#define LORA_SET_LNA (_IOW(LORA_IOC_MAGIC, 6, int))
53#define LORA_GET_LNA (_IOR(LORA_IOC_MAGIC, 7, int))
54#define LORA_SET_LNAAGC (_IOR(LORA_IOC_MAGIC, 8, int))
55#define LORA_SET_SPRFACTOR (_IOW(LORA_IOC_MAGIC, 9, int))
56#define LORA_GET_SPRFACTOR (_IOR(LORA_IOC_MAGIC, 10, int))
57#define LORA_SET_BANDWIDTH (_IOW(LORA_IOC_MAGIC, 11, int))
58#define LORA_GET_BANDWIDTH (_IOR(LORA_IOC_MAGIC, 12, int))
59#define LORA_GET_RSSI (_IOR(LORA_IOC_MAGIC, 13, int))
60#define LORA_GET_SNR (_IOR(LORA_IOC_MAGIC, 14, int))
61/* Mikem added 2021-04-19 fro pull request 16: */
62#define LORA_SET_CRC (_IOW(LORA_IOC_MAGIC, 15, int))
63#define LORA_SET_CODINGRATE (_IOW(LORA_IOC_MAGIC, 16, int))
64#define LORA_GET_CODINGRATE (_IOR(LORA_IOC_MAGIC, 17, int))
65#define LORA_SET_IMPLICIT (_IOW(LORA_IOC_MAGIC, 18, int))
66#define LORA_SET_LDRO (_IOW(LORA_IOC_MAGIC, 19, int))
67#define LORA_SET_PREAMBLE (_IOW(LORA_IOC_MAGIC, 20, int))
68#define LORA_GET_PREAMBLE (_IOR(LORA_IOC_MAGIC, 21, int))
69#define LORA_SET_PARAMP (_IOW(LORA_IOC_MAGIC, 22, int))
70#define LORA_GET_PARAMP (_IOR(LORA_IOC_MAGIC, 23, int))
71#define LORA_SET_OCPIMAX (_IOW(LORA_IOC_MAGIC, 24, int))
72#define LORA_GET_OCPIMAX (_IOR(LORA_IOC_MAGIC, 25, int))
73#define LORA_SET_LNABOOSTHF (_IOW(LORA_IOC_MAGIC, 26, int))
74#define LORA_SET_PMAX20DBM (_IOW(LORA_IOC_MAGIC, 27, int))
75
76
77/* List the state of the LoRa device. */
78#define LORA_STATE_SLEEP 0
79#define LORA_STATE_STANDBY 1
80#define LORA_STATE_TX 2
81#define LORA_STATE_RX 3
82#define LORA_STATE_CAD 4
83
84// Max number of octets the SX1278 LORA Rx/Tx FIFO can hold
85#define RH_LORAFILEOPS_FIFO_SIZE 255
86
87// This is the maximum number of bytes that can be carried by the LORA.
88// We use some for headers, keeping fewer for RadioHead messages
89#define RH_LORAFILEOPS_MAX_PAYLOAD_LEN RH_LORAFILEOPS_FIFO_SIZE
90
91// The length of the headers we add.
92// The headers are inside the LORA's payload
93#define RH_LORAFILEOPS_HEADER_LEN 4
94
95// This is the maximum message length that can be supported by this driver.
96// Can be pre-defined to a smaller size (to save SRAM) prior to including this header
97// Here we allow for 1 byte message length, 4 bytes headers, user data and 2 bytes of FCS
98#ifndef RH_LORAFILEOPS_MAX_MESSAGE_LEN
99#define RH_LORAFILEOPS_MAX_MESSAGE_LEN (RH_LORAFILEOPS_MAX_PAYLOAD_LEN - RH_LORAFILEOPS_HEADER_LEN)
100#endif
101
102/////////////////////////////////////////////////////////////////////
103/// \class RH_LoRaFileOps RH_LoRaFileOps.h <RH_LoRaFileOps.h>
104/// \brief Driver to send and receive unaddressed, unreliable datagrams via a LoRa
105/// capable radio transceiver on a Linux platform (possibly Raspberry Pi), using the
106/// lora-file-ops driver by Jian-Hong Pan (starnight):
107/// https://github.com/starnight/LoRa/tree/file-ops
108///
109/// This RadioHead driver is only available to Commercial licensees. Apply to info@airspayce.com.
110///
111/// For an excellent discussion of LoRa range and modulations, see
112/// https://medium.com/home-wireless/testing-lora-radios-with-the-limesdr-mini-part-2-37fa481217ff
113/// Works with Dragino LoRa/GPS HAT, https://wiki.dragino.com/index.php?title=Lora/GPS_HAT
114/// modified so RFM95 pin 5 NSS was no longer connected to RPi
115/// pin P1-22 (GPIO6), but is instead connected to RPi Pin P1-24 (CE0) which
116/// is the one used by /dev/loraSPI0.0. Interoperates with RH_RF95
117/// with modem config RH_RF95::Bw125Cr45Sf2048
118///
119/// \par Overview
120///
121/// This class provides basic functions for sending and receiving unaddressed,
122/// unreliable datagrams of arbitrary length up to 251 octets per packet.
123///
124/// Manager classes may use this class to implement reliable, addressed datagrams and streams,
125/// mesh routers, repeaters, translators etc.
126///
127/// Naturally, for any 2 radios to communicate that must be configured to use the same frequency and
128/// modulation scheme.
129///
130/// This RadioHead Driver provides an object-oriented interface for sending and receiving
131/// data messages with Semtech SX1276/77/78/79
132/// and compatible radio modules in LoRa mode, using the lora-file-ops Linux driver. It only runs on Linux
133/// such as Raspberry Pi Debian etc.is a low-cost ISM transceiver
134/// chip. It supports FSK, GFSK, OOK over a wide range of frequencies and
135/// programmable data rates, and it also supports the proprietary LoRA (Long Range) mode, which
136/// is the only mode supported in this RadioHead driver (because that is the only mode supported by the
137/// underlying lora-file-ops Linux driver.
138///
139/// This Driver provides functions for sending and receiving messages of up
140/// to 251 octets on any frequency supported by the radio, in a range of
141/// predefined Bandwidths, Spreading Factors and Coding Rates. Frequency can be set with
142/// 61Hz precision to any frequency from 240.0MHz to 960.0MHz. Caution: most modules only support a more limited
143/// range of frequencies due to antenna tuning.
144///
145/// Up to 2 modules are supported by lora-file-ops
146/// permitting the construction of translators and frequency changers, etc.
147///
148/// Support for other features such as transmitter power control etc is
149/// also provided.
150///
151/// Tested with:
152/// RPi 2 + Debian 2021-03-04 (kernel 5.10.17-v7+ #1403)
153/// Dragino LoRa/GPS HAT, https://wiki.dragino.com/index.php?title=Lora/GPS_HAT
154/// modified so RFM95 pin 5 NSS was no longer connected to RPi
155/// pin P1-22 (GPIO6), but is instead connected to RPi Pin P1-24 (CE0) which
156/// is the one used by /dev/loraSPI0.0
157/// \par Packet Format
158///
159/// All messages sent and received by this RH_RF95 Driver conform to this packet format:
160///
161/// - LoRa mode:
162/// - 8 symbol PREAMBLE
163/// - Explicit header with header CRC (default CCITT, handled internally by the radio)
164/// - 4 octets HEADER: (TO, FROM, ID, FLAGS)
165/// - 0 to 251 octets DATA
166/// - CRC (default CCITT, handled internally by the radio)
167///
168/// This format is compatible with the one used by RH_RF95 by default.
169///
170/// \par Modulation
171///
172/// The default modulation scheme implemented by this driver is:
173/// 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on
174/// which is compatible withthe RH_RF95 modem config RH_RF95::Bw125Cr45Sf2048 and so this RadioHead driver will
175/// interoperate with RH_RF95.
176///
177/// \par Installing lora-file-ops
178/// For this driver to work on a Linux platform such as Raspberry Pi, it is absolutely necessary to install the
179/// LoRa-file-ops Linux driver written by starnight, and which is available from github.
180/// The version currently available (2021-04-19) does not support enabling CRCs in the radio, which is
181/// strongly recommended, and necessary to work with any other RadioHead lora driver/
182/// At this date, code to add CRC suport to the driver is avalable as a pull request on github
183/// as a Git pull request #16 from flyskywhy. We strongly recommend using it as described below.
184///
185/// To get LoRa-file-ops from starnight, plus the necessary patches and fixes from pull request #16 from flyskywhy
186/// and to build it and install it and load it into the kernel for testing:
187/// \code
188/// # ON a recent Debian kernel:
189/// sudo apt-get install linux-headers-rpi raspberrypi-kernel-headers
190/// # Enable the SPI interface in the kernel
191/// sudo raspi-config:
192/// -> 3 Interface Options
193/// -> P4 SPI
194/// -> Would you like the SPI interface to be enabled? select Yes, press Return, Return, Select Finish
195/// # in a working directory, not as root:
196/// git clone https://github.com/starnight/LoRa.git
197/// cd LoRa/
198/// git checkout file-ops
199/// git fetch origin pull/16/head:file-ops-patched # only until pull #16 is not merged into master
200/// git checkout file-ops-patched # only until pull #16 is not merged into master
201/// cd LoRa/
202/// make
203/// make install
204/// cd ../dts-overlay
205/// make
206/// cd ../
207/// # and after every reboot:
208/// sudo dtoverlay rpi-lora-spi
209/// sudo modprobe sx1278
210/// \endcode
211///
212/// If you want to permanently add the LoRa-file-ops Linux driver so it loads automatically
213/// on every boot, add this to /boot/config.txt
214/// \code
215/// dtparam=rpi-lora-spi=on
216/// \endcode
217///
218/// Note: it may be the case in the future that pull request 16 is merged into the master of LoRa-File-Ops
219/// in which case 2 steps are not needed above
221{
222public:
223 /// Constructor. You can have multiple instances each connected to a different LoRa port
224 /// \param[in] port Name of the lora-file-ops port, typically something like /dev/loraSPI0.0
225 RH_LoRaFileOps(const char* port);
226
227 /// Initialise the Driver transport hardware and software.
228 /// Opens the LorFileOps driver port and initalises the radio to default settings
229 /// Leaves the radio in receive mode,
230 /// with default configuration of: 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 2048chips/symbol, CRC on
231 /// which is compatible with RH_RF95::Bw125Cr45Sf2048
232 /// \return true if initialisation succeeded.
233 virtual bool init();
234
235 /// Tests whether a new message is available from the lora-file-ops Linux driver.
236 /// This can be called multiple times in a timeout loop
237 /// \return true if a new, complete, error-free uncollected message is available to be retreived by recv()
238 virtual bool available();
239
240 // Sigh, its not possible to implement waitAvailable and waitAvailableTimout in terms
241 // of select(), since the LoRa-file-ops driver does not detect any interrupts, and
242 // therefore select will not return when a packet is received by the radio.
243 // So we have to live with the RHGenericDriver implementations that call available() to poll the port.
244 // waitAvailableTimeout() supports an optional delay between each poll
245 // of available() so that on Linux at least another process can get the CPU.
246
247 /// If there is a valid message available and it is for this node, copy it to buf and return true
248 /// else return false.
249 /// If a message is copied, *len is set to the length (Caution, 0 length messages are permitted).
250 /// You should be sure to call this function frequently enough to not miss any messages
251 /// or call it aafter available(), waitAvailable() or waitAvailableTimeout()
252 /// indicate that a message is avalable
253 /// It is recommended that you call it in your main loop.
254 /// \param[in] buf Location to copy the received message
255 /// \param[in,out] len Pointer to available space in buf. Set to the actual number of octets copied.
256 /// \return true if a valid message addressed to this node was copied to buf
257 virtual bool recv(uint8_t* buf, uint8_t* len);
258
259 /// Loads a message into the transmitter and starts the transmitter. Note that a message length
260 /// of 0 is permitted. CAD is not supported yet.
261 /// The lora-file-ops driver waits for the entire message to be transmitted before resuming operations.
262 /// \param[in] data Array of data to be sent
263 /// \param[in] len Number of bytes of data to send
264 /// \return true if the message length was valid and it was correctly transmitted.
265 virtual bool send(const uint8_t* data, uint8_t len);
266
267 /// Returns the maximum message length
268 /// available in this Driver.
269 /// \return The maximum legal message length
270 virtual uint8_t maxMessageLength();
271
272 /// Sets the transmitter and receiver
273 /// centre (carrier) frequency.
274 /// \param[in] centre Frequency in Hz. 137000000 to 1020000000. Caution: SX1276/77/78/79 comes in several
275 /// different frequency ranges, and setting a frequency outside that range of your radio will probably not work
276 /// correctly becasue the antenna coupling or antenna wont work outside their designed frequency range
277 /// \return true if the selected frequency centre is within range
278 bool setFrequency(uint32_t centre);
279
280 /// Returns the current transmitter and receiver
281 /// centre frequency.
282 /// \return Centre frequency in Hz.
283 uint32_t getFrequency();
284
285 /// Returns the Signal-to-noise ratio (SNR) of the last received message, as measured
286 /// by the receiver.
287 /// \return SNR of the last received message in dB
288 int lastSNR();
289
290 /// Sets the transmitter power output level
291 /// Be a good neighbour and set the lowest power level you need.
292 /// Caution: legal power limits may apply in certain countries.
293 /// After init(), the power will be set to 13dBm
294 /// \param[in] power Transmitter power level in dBm. Max 20dBm.
295 void setTxPower(int32_t power);
296
297 /// Gets the currently set transmitter power output level
298 /// \return Current poer level in dbM
299 int32_t getTxPower();
300
301 /// Set the LoRa Spreading Factor
302 /// \param[in] sf The spreading factor. Valid values are 64, 128, 256, 512, 1024, 2048, 4096.
303 void setSpreadingFactor(int32_t sf);
304
305 /// Get the LoRa Spreading Factor
306 /// \return The current Spreading Factor
308
309 /// Gets the RSSI of the last received packet
310 /// \return RSSI of the last received packet
311 int32_t getRSSI();
312
313 /// Gets the Signal To Noise (SNR) of the last received packet
314 /// \return SNR of the last received packet
315 int32_t getSNR();
316
317 /// Set the receiver Low Noise Amplifier (LNA) gain
318 /// \param[in] lna LNA gain in dBm
319 void setLNA(int32_t lna);
320
321 /// Get the current LNA gain
322 /// \return The current LNA gain in dBm
323 int32_t getLNA();
324
325 /// Set the LNA Automatic Gain Control (AGC) enabled
326 /// \param[in] lnaagc 1 to enable LNA AGC, 0 to disable it
327 void setLNAAGC(int32_t lnaagc);
328
329 /// Set the transmitter and receiver modulation bandwidth
330 /// \param[in] bw Modulation bandwidth in Hz. Valid values are 7800, 10400, 15600, 20800,
331 /// 312500, 41700, 62500, 125000, 250000, 500000.
332 void setBW(int32_t bw);
333
334 /// Get the transmitter and receiver modulation bandwidth
335 /// \return Modulation bandwidth in Hz
336 int32_t getBW();
337
338 /// Enable Cyclic Redundancy Check (CRC) in the transmitter and receiver. If enabled,
339 /// the transmitter will always appenda CRC to every packet, and the receiver will
340 /// always check the CRC on received packets, ignoring packets with incorrect CRC
341 /// \param[in] crc 1 to enable CRC generation and detection, 0 to disable it
342 void setCRC(uint32_t crc);
343
344
345protected:
346 /// Set the current radio state, one of LORA_STATE_*
347 void setState(uint32_t state);
348
349 /// Get the current radio state
350 uint32_t getState();
351
352private:
353 // The name of the Unix filesystm port for the Lora SX1278 compatible radio
354 // typically /dev/loraSPI0.0 or similar
355 const char* _port;
356
357 /// Unix file system device number of the LoRa device port. -1 if not open
358 int _fd;
359
360 /// Last measured SNR, dB
361 int8_t _lastSNR;
362};
363
364/// @example lorafileops_client.cpp
365/// @example lorafileops_server.cpp
366
367#endif
368#endif
Abstract base class for a RadioHead driver.
Definition: RHGenericDriver.h:42
Driver to send and receive unaddressed, unreliable datagrams via a LoRa capable radio transceiver on ...
Definition: RH_LoRaFileOps.h:221
virtual bool init()
int32_t getTxPower()
uint32_t getFrequency()
RH_LoRaFileOps(const char *port)
void setBW(int32_t bw)
bool setFrequency(uint32_t centre)
int32_t getBW()
int32_t getLNA()
void setTxPower(int32_t power)
virtual uint8_t maxMessageLength()
void setLNAAGC(int32_t lnaagc)
virtual bool send(const uint8_t *data, uint8_t len)
void setState(uint32_t state)
Set the current radio state, one of LORA_STATE_*.
int32_t getRSSI()
int32_t getSpreadingFactor()
int32_t getSNR()
uint32_t getState()
Get the current radio state.
void setSpreadingFactor(int32_t sf)
virtual bool available()
void setCRC(uint32_t crc)
virtual bool recv(uint8_t *buf, uint8_t *len)
void setLNA(int32_t lna)