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