Skip to content

Commit 1a30fa5

Browse files
committed
wireless/lpwan: Add support for the RN903 and RN2483 family of LoRa
radio transceivers. This initial support includes transmit and receive functionality and configuration and reading of radio parameters like frequency and bandwidth. Signed-off-by: Matteo Golin <matteo.golin@gmail.com>
1 parent ff4d461 commit 1a30fa5

File tree

9 files changed

+2492
-2
lines changed

9 files changed

+2492
-2
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
================
22
Wireless Drivers
33
================
4+
5+
.. toctree::
6+
:glob:
7+
:maxdepth: 1
8+
:titlesonly:
9+
:caption: Contents
10+
11+
./wireless/*
Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
======
2+
RN2XX3
3+
======
4+
5+
This driver provides support for the RN2XX3 family of LoRa radio transceivers by
6+
Microchip. This includes both the RN2903 and RN2483 modules.
7+
8+
.. warning::
9+
This driver only contains preliminary support for a few 'radio set' commands
10+
and raw radio transmit/receive. There is no support for the LoRaWAN stack
11+
yet. IT IS EXPERIMENTAL.
12+
13+
Application Programming Interface
14+
=================================
15+
16+
To register the device for use, you will need to enable the standard upper half
17+
serial drivers (``CONFIG_STANDARD_SERIAL``), since the RN2XX3 driver requires
18+
the path to the UART interface the module is connected to.
19+
20+
You will also need to ensure that the baud rate of the UART interface is set to
21+
57600, which is the baud rate of the RN2XX3.
22+
23+
At registration time, the driver will automatically determine if the device is
24+
the RN2903 or RN2483.
25+
26+
.. code-block:: c
27+
28+
#include <nuttx/wireless/lpwan/rn2xx3.h>
29+
30+
#ifdef CONFIG_LPWAN_RN2XX3
31+
32+
/* Register the RN2XX3 device driver */
33+
34+
ret = rn2xx3_register("/dev/rn2903", "/dev/ttyS1");
35+
if (ret < 0) {
36+
syslog(LOG_ERR, "Failed to register RN2XX3 device driver: %d\n", ret);
37+
}
38+
#endif
39+
40+
This driver uses the standard POSIX character device interface, implementing
41+
``read()``, ``write()`` and ``ioctl()``.
42+
43+
To transmit, the ``write()`` function can be used. Bytes in the provided buffer
44+
will be transmitted as a packet. This has the following behaviour:
45+
46+
* If the radio is in FSK modulation mode, packets will only contain up to 64
47+
bytes. A buffer of more than 64 bytes will only have 64 bytes transmitted.
48+
* If the radio is in LoRa modulation mode, packets will only contain up to 255
49+
bytes.
50+
* If the buffer contains less than the current packet size limit (64 or 255
51+
bytes), its contents will be transmitted as a single packet.
52+
53+
.. code-block:: c
54+
55+
int radio = open("/dev/rn2903", O_RDWR);
56+
if (radio < 0)
57+
{
58+
fprintf(stderr, "Couldn't open radio: %d\n", errno);
59+
return -1;
60+
}
61+
62+
char message[] = "Hello, world!";
63+
ssize_t b_sent = write(radio, message, sizeof(message));
64+
if (b_sent < 0)
65+
{
66+
fprintf(stderr, "Couldn't transmit: %d\n", errno);
67+
return -1;
68+
}
69+
70+
To receive, the ``read()`` function can be used. As much of the received packet
71+
as possible will be stored in the user buffer. This has the following behaviour:
72+
73+
* If the buffer is too small to contain the full received packet, as much of the
74+
packet as possible will be stored in the buffer.
75+
* When the packet is fully read, ``read()`` will return ``0``.
76+
* If only part of the packet has been read and a call to ``write()`` or
77+
``ioctl()`` is made, the remainder of the packet is discarded.
78+
79+
.. code-block:: c
80+
81+
int radio = open("/dev/rn2903", O_RDWR);
82+
if (radio < 0)
83+
{
84+
fprintf(stderr, "Couldn't open radio: %d\n", errno);
85+
return -1;
86+
}
87+
88+
char buffer[16];
89+
ssize_t b_read;
90+
91+
do {
92+
b_read = read(radio, buffer, sizeof(buffer));
93+
if (b_read < 0)
94+
{
95+
fprintf(stderr, "Couldn't receive: %d\n", errno);
96+
return -1;
97+
}
98+
write(0, buffer, b_read); /* Print received bytes to stdout */
99+
} while (b_read != 0);
100+
101+
Finally, the ``ioctl()`` interface provides access to some underlying module
102+
commands.
103+
104+
``WLIOC_GETSNR``
105+
----------------
106+
107+
Gets the signal to noise ration of the last received packet. If no packets have
108+
been received, it will default to -128. Argument is a pointer to an ``int8_t``.
109+
110+
.. code-block:: c
111+
112+
int8_t snr;
113+
err = ioctl(radio, WLIOC_GETSNR, &snr);
114+
115+
``WLIOC_SETRADIOFREQ``
116+
----------------------
117+
118+
Sets the operating frequency of the radio module. The argument is the desired
119+
frequency in Hz (``uint32_t``).
120+
121+
.. code-block:: c
122+
123+
err = ioctl(radio, WLIOC_SETRADIOFREQ, 902400000);
124+
125+
``WLIOC_GETRADIOFREQ``
126+
----------------------
127+
128+
Gets the current operating frequency of the radio module in Hz. The argument is
129+
a pointer to a ``uint32_t``.
130+
131+
.. code-block:: c
132+
133+
uint32_t freq;
134+
err = ioctl(radio, WLIOC_GETRADIOFREQ, &freq);
135+
136+
``WLIOC_SETTXPOWERF``
137+
---------------------
138+
139+
Sets the transmission power of the radio. Argument is a pointer to a ``int32_t``
140+
containing the desired transmission power in 0.01 dBm. After setting the
141+
transmission power successfully, this pointer will contain the new transmission
142+
power. This value may be different from the desired value, but will be the
143+
closest available setting that is greater than or equal to the desired value.
144+
145+
.. code-block:: c
146+
147+
int32_t txpower = 1200;
148+
err = ioctl(radio, WLIOC_SETTXPOWERF, &txpower);
149+
printf("Actual TX power: %.2f dBm\n", txpower / 100.0f);
150+
151+
``WLIOC_GETTXPOWERF``
152+
---------------------
153+
154+
Gets the current transmission power level in 0.01 dBm. The argument is a pointer
155+
to a ``int32_t``.
156+
157+
.. code-block:: c
158+
159+
int32_t txpwr;
160+
err = ioctl(radio, WLIOC_GETTXPOWER, &txpwr);
161+
162+
``WLIOC_SETBANDWIDTH``
163+
----------------------
164+
165+
Sets the operating bandwidth of the radio module. The argument is the desired
166+
bandwidth in kHz (``uint32_t``). The radio only supports exact values of 125,
167+
250 and 500.
168+
169+
.. code-block:: c
170+
171+
err = ioctl(radio, WLIOC_SETBANDWIDTH, 250);
172+
173+
``WLIOC_GETBANDWIDTH``
174+
----------------------
175+
176+
Gets the current operating bandwidth of the radio module in kHz. The argument is
177+
a pointer to a ``uint32_t``.
178+
179+
.. code-block:: c
180+
181+
uint32_t bandwidth;
182+
err = ioctl(radio, WLIOC_GETBANDWIDTH, &bandwidth);
183+
184+
``WLIOC_SETSPREAD``
185+
----------------------
186+
187+
Sets the operating spread factor of the radio module. The argument is a
188+
``uint8_t`` containing the desired spread factor between 7 and 12 (inclusive).
189+
190+
.. code-block:: c
191+
192+
err = ioctl(radio, WLIOC_SETSPREAD, 8);
193+
194+
``WLIOC_GETSPREAD``
195+
----------------------
196+
197+
Gets the current operating spread factor of the radio module. The argument is a
198+
pointer to a ``uint8_t``.
199+
200+
.. code-block:: c
201+
202+
uint8_t spread;
203+
err = ioctl(radio, WLIOC_GETSPREAD, &spread);
204+
205+
``WLIOC_SETPRLEN``
206+
----------------------
207+
208+
Sets the operating preamble length of the radio module. The argument is a
209+
``uint16_t`` containing the desired preamble length.
210+
211+
.. code-block:: c
212+
213+
err = ioctl(radio, WLIOC_SETPRLEN, 8);
214+
215+
``WLIOC_GETPRLEN``
216+
----------------------
217+
218+
Gets the current operating preamble length of the radio module. The argument is
219+
a pointer to a ``uint16_t``.
220+
221+
.. code-block:: c
222+
223+
uint16_t prlen;
224+
err = ioctl(radio, WLIOC_GETPRLEN, &prlen);
225+
226+
``WLIOC_SETMOD``
227+
----------------------
228+
229+
Sets the operating modulation of the radio module. The argument is one of the
230+
values in ``enum rn2xx3_mod_e``.
231+
232+
.. code-block:: c
233+
234+
err = ioctl(radio, WLIOC_SETMOD, RN2XX3_MOD_FSK);
235+
236+
``WLIOC_GETMOD``
237+
----------------------
238+
239+
Gets the current operating modulation of the radio module. The argument is a
240+
pointer to an ``enum rn2xx3_mod_e``.
241+
242+
.. code-block:: c
243+
244+
enum rn2xx3_mod_e modulation;
245+
err = ioctl(radio, WLIOC_GETMOD, &modulation);
246+
if (modulation == RN2XX3_MOD_LORA)
247+
{
248+
printf("LoRa modulation!\n");
249+
}
250+
251+
``WLIOC_RESET``
252+
---------------
253+
254+
Resets the RN2xx3 radio module. This command takes no arguments.
255+
256+
.. code-block:: c
257+
258+
err = ioctl(radio, WLIOC_RESET, 0);
259+
260+
``WLIOC_SETSYNC``
261+
-----------------
262+
263+
Sets the sync word parameter of the RN2xx3 module. The argument is a pointer to
264+
a ``uint64_t``. Please note that when operating using FSK modulation, the sync
265+
word can be a full 8 bytes (64 bits), but LoRa modulation only accepts a single
266+
byte sync word.
267+
268+
.. code-block:: c
269+
270+
/* Radio in FSK mode prior to this call */
271+
272+
uint64_t syncword = 0xdeadbeefdeadbeef;
273+
err = ioctl(radio, WLIOC_SETSYNC, &syncword);
274+
275+
``WLIOC_GETSYNC``
276+
-----------------
277+
278+
Gets the sync word parameter of the RN2xx3 module. The argument is a pointer to
279+
a ``uint64_t``.
280+
281+
.. code-block:: c
282+
283+
uint64_t syncword;
284+
err = ioctl(radio, WLIOC_GETSYNC, &syncword);
285+
286+
``WLIOC_SETBITRATE``
287+
--------------------
288+
289+
Sets the bit rate of the RN2xx3 module. The argument is a ``uint32_t``. The
290+
bit rate only applies to the module when it is in FSK modulation mode, and it
291+
must be between 1 - 300000.
292+
293+
.. code-block:: c
294+
295+
/* Radio in FSK mode prior to this call */
296+
297+
err = ioctl(radio, WLIOC_SETBITRATE, 300000);
298+
299+
``WLIOC_GETBITRATE``
300+
--------------------
301+
302+
Gets the configured bit rate of the RN2xx3 module. The argument is a pointer to
303+
a ``uint32_t``.
304+
305+
.. code-block:: c
306+
307+
uint32_t bitrate;
308+
err = ioctl(radio, WLIOC_GETBITRATE, &bitrate);
309+
310+
``WLIOC_IQIEN``
311+
---------------
312+
313+
Enables the invert IQ functionality of the module. The argument is boolean of
314+
either true (non-zero) or false (zero).
315+
316+
.. code-block:: c
317+
318+
/* Enables IQI */
319+
320+
err = ioctl(radio, WLIOC_IQIEN, 1);
321+
322+
``WLIOC_CRCEN``
323+
---------------
324+
325+
Enables adding a CRC header to packets. The argument is a boolean of either true
326+
(non-zero) or false (zero).
327+
328+
.. code-block:: c
329+
330+
/* Enables CRC */
331+
332+
err = ioctl(radio, WLIOC_CRCEN, 1);
333+
334+
``WLIOC_SETCODERATE``
335+
---------------------
336+
337+
Sets the coding rate of the RN2xx3 module. The argument is one of the values in
338+
``enum rn2xx3_cr_e``.
339+
340+
.. code-block:: c
341+
342+
/* Sets 4/7 coding rate */
343+
344+
err = ioctl(radio, WLIOC_SETCODERATE, RN2XX3_CR_4_7);
345+
346+
``WLIOC_GETCODERATE``
347+
---------------------
348+
349+
Gets the currently configured coding rate of the RN2xx3 module. The argument is
350+
a pointer to an ``enum rn2xx3_cr_e``.
351+
352+
.. code-block:: c
353+
354+
enum rn2xx3_cr_e coderate;
355+
err = ioctl(radio, WLIOC_GETCODERATE, &coderate);

drivers/wireless/lpwan/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@
55

66
if DRIVERS_LPWAN
77

8+
config LPWAN_RN2XX3
9+
bool "Microchip RN2xx3 driver support"
10+
default n
11+
select UART # TODO what to select?
12+
---help---
13+
Enable driver support for the RN2xx3 LoRa radio transceiver.
14+
15+
if LPWAN_RN2XX3
16+
17+
endif # LPWAN_RN2XX3
18+
819
config LPWAN_SX127X
920
bool "SX127X Low Power Long Range transceiver support"
1021
default n

drivers/wireless/lpwan/Make.defs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,6 @@
2525
ifeq ($(CONFIG_DRIVERS_LPWAN),y)
2626

2727
include wireless/lpwan/sx127x/Make.defs
28+
include wireless/lpwan/rn2xx3/Make.defs
2829

2930
endif # CONFIG_DRIVERS_LPWAN

0 commit comments

Comments
 (0)