Skip to content

Commit 8321f48

Browse files
authored
Feature upgrades for ABP, add errorReadout, poll after Retry Class A and more (#277)
* Add TheThingsMessage default timeout value TTN_DEFAULT_TOUT * Fix TheThingsMessage return Unsuccessful receive with no cnf response * Add TheThingsMessage getters for BW,CR,SF,Frequency,WDT,Power,RSSI,SNR * Add TheThingsMessage setter for LoRaWan power-index * poll: add check for receive length, return unsuccessful receive if 0 * setSF add default in case of Fre qPlan * sendBytes: fix return unsuccessful receive if send confirmed and no RX * add getLastError to poll last occurred error from modem buffer * add constructor init value for ADR * init value callback * add setChannel/Rx2Channel/Status to enable chn 4-8 config in ABP * poll add modem-only opt for ClassA for RX after failed confirmed attempt * add pgmstrcmp errorcheck length string 0 * Init debugstream to NULL * Update getSNR and getRSSI to return -128 and -255 respectively negative values are allowed in both, RSSI can reach -142dBm on some chips * add getStatus readout and mask, incl enum * add mac_err to error codes * add no response from modem to error text strings * fix error setRX2channel constant * changed getSF to the more useful getDR * getPower return value to default to -128 (0 is valid) * replace string with flash constant no response * moved setADR from reset to separate method * add get/set FCU and FCD * add/fix setChannel DR range configuration * add LinkCheck* methods strtol pointer validity check * add getter to read powerIndex * add declaration setDR * add getChannelStatus to read if enabled * add function parseBytes to unify parse modem response on RX send/Poll fixed typo UNSUCCESSFUL_RECEIVE * add 3 parameter variant for sendChSet * add setChannelDCycle to change configured duty cycle in percent * add 3 parameter variant sendMacSet * Add setRX1Delay function (RX2 is hardcoded +1s) * update TheThingsNetwork to use long variants for sendChSet/sendMacSet * Refactoring * fix poll typo, missing semicolon * add setChannel feature to set only frequency * Update docs with new methods; updated descriptions * Update docs with new methods; updated descriptions * TTN EU868 fixed duty cycle inits according to ETSI standard G1/G2 bands Adjusted to sum 1% for both bands, G1 and G2, with sum total of 1% https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/ * TTN Refactoring ttn_response_code_t ttn_modem_status_t CMP_* * TTN Documentation update, get status + enum getLastError * TTN replace ADR&channel status commands with private calls to save bytes (94 total) fix typos enum
1 parent ea60c59 commit 8321f48

File tree

3 files changed

+790
-139
lines changed

3 files changed

+790
-139
lines changed

docs/TheThingsNetwork.md

Lines changed: 256 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ The `TheThingsNetwork` class enables Arduino devices with supported LoRaWAN modu
44

55
## Class: `TheThingsNetwork`
66

7-
Include and instantiate the TheThingsNetwork class. The constructor initialize the library with the Streams it should communicate with. It also sets the value of the spreading factor, the frequency plan and the frequency sub-band.
7+
Include and instantiate the TheThingsNetwork class. The constructor initializes the library with the Streams it should communicate with. It also sets the value of the spreading factor, the frequency plan, and the frequency sub-band.
88

99
```c
1010
#include <TheThingsNetwork.h>
@@ -30,7 +30,7 @@ void reset(bool adr);
3030

3131
## Method: `hardReset`
3232

33-
Performs a hardware reset of the RN module. Input parameter is the pin which the reset pin from the module is connected to. This does clear saved state, e.g. provisioned keys.
33+
Performs a hardware reset of the RN module. Input parameter is the pin to which the reset pin from the module is connected. This does clear saved state, e.g., provisioned keys.
3434

3535
```c
3636
void hardReset(uint8_t resetPin);
@@ -78,7 +78,7 @@ See the [DeviceInfo](https://github.com/TheThingsNetwork/arduino-device-lib/blob
7878

7979
## Method: `onMessage`
8080

81-
Sets a function which will be called to process incoming messages. You'll want to do this in your `setup()` function and then define a `void (*cb)(const byte* payload, size_t length, port_t port)` function somewhere else in your sketch.
81+
Sets a function that will be called to process incoming messages. You'll want to do this in your `setup()` function and then define a `void (*cb)(const byte* payload, size_t length, port_t port)` function somewhere else in your sketch.
8282

8383
```c
8484
void onMessage(void (*cb)(const byte* payload, size_t length, port_t port));
@@ -101,7 +101,7 @@ bool join(int8_t retries = -1, uint32_t retryDelay = 10000);
101101

102102
- `const char *appEui`: Application EUI the device is registered to.
103103
- `const char *appKey`: Application Key assigned to the device.
104-
- `int8_t retries = -1`: Number of times to retry after failed or unconfirmed join. Defaults to `-1` which means infinite.
104+
- `int8_t retries = -1`: Number of times to retry after failed or unconfirmed join. Defaults to `-1`, which means infinite.
105105
- `uint32_t retryDelay = 10000`: Delay in ms between attempts. Defaults to 10 seconds.
106106
- `lorawan_class = CLASS_A`: The LoRaWAN class to use for downlink message reception.
107107

@@ -130,7 +130,7 @@ See the [SendABP](https://github.com/TheThingsNetwork/arduino-device-lib/blob/ma
130130
131131
## Method: `setClass`
132132
133-
Change the downlink receive LoRaWAN Class. Class C is only supported in firmware version 1.0.5 and up. For other firmware versions this method will have no effect.
133+
Change the downlink receive LoRaWAN Class. Class C is only supported in firmware version 1.0.5 and up. For other firmware versions, this method will have no effect.
134134
135135
```c
136136
bool setClass(lorawan_class p_lw_class);
@@ -155,14 +155,15 @@ ttn_response_t sendBytes(const byte* payload, size_t length, port_t port = 1, bo
155155
- `const byte* payload `: Bytes to send.
156156
- `size_t length`: The number of bytes. Use `sizeof(payload)` to get it.
157157
- `port_t port = 1`: The port to address. Defaults to `1`.
158-
- `bool confirm = false`: Whether to ask for confirmation. Defaults to `false`. If confirmation fails, the method will return error code `TTN_ERROR_UNEXPECTED_RESPONSE`.
158+
- `bool confirm = false`: Whether to ask for confirmation—defaults to `false`. If confirmation fails, the method will return the error code `TTN_ERROR_UNEXPECTED_RESPONSE`.
159159
- `uint8_t sf = 0`: Override the spreading factor (SF). If the default value `0` is passed, the SF is not changed from the constructor or previous value.
160160
161161
Returns a success or error code and logs the related error message:
162162
163163
* `TTN_ERROR_SEND_COMMAND_FAILED`: Send command failed.
164164
* `TTN_SUCCESSFUL_TRANSMISSION`: Successful transmission.
165165
* `TTN_SUCCESSFUL_RECEIVE`: Successful transmission. Received \<N> bytes
166+
* `TTN_UNSUCCESSFUL_RECEIVE`: if we sent a confirmed message but did not get an acknowledgment
166167
* `TTN_ERROR_UNEXPECTED_RESPONSE`: Unexpected response: \<Response>
167168
168169
See the [SendOTAA](https://github.com/TheThingsNetwork/arduino-device-lib/blob/master/examples/SendOTAA/SendOTAA.ino) example.
@@ -177,8 +178,12 @@ int8_t poll(port_t port = 1, bool confirm = false);
177178

178179
- `port_t port = 1`: The port to address. Defaults to `1`.
179180
- `bool confirm = false`: Whether to ask for confirmation.
181+
- `bool modem_only = false`: (only class A) Whether to avoid sending an empty frame and only listen to the modem's incoming message.
180182

181-
Returns the result of `sendBytes()`.
183+
Returns the result of `sendBytes()`, with one difference:
184+
* `TTN_UNSUCCESSFUL_RECEIVE`: In class C or class A `modem_only` poll, we only listened, and there was no incoming message.
185+
186+
The `modem_only` option for poll may be useful if the sending procedure did not terminate yet, e.g., we sent a confirmed message and did not get a response. In such a case, the modem will independently retry. With `modem_only` we thus just listen to the modem output to verify the status of the further attempts.
182187

183188
See the [Receive](https://github.com/TheThingsNetwork/arduino-device-lib/blob/master/examples/Receive/Receive.ino) example.
184189

@@ -213,7 +218,7 @@ void wake();
213218

214219
## Method: `linkCheck`
215220

216-
Sets the time interval for the link check process to be triggered. When the interval expires, the next uplink will include a Link Check Request MAC command. When using this method, it should be called after joining has completed.
221+
Sets the time interval for the link check process to be triggered. The next uplink will include a Link Check Request MAC command when the interval expires. This method should be called after joining has been completed.
217222

218223
```c
219224
void linkCheck(uint16_t seconds);
@@ -237,10 +242,252 @@ Gets the demodulation margin as received in the last Link Check Answer frame.
237242
uint8_t getLinkCheckMargin();
238243
```
239244

245+
# Additional for operation
246+
240247
## Method: `getVDD`
241248

242-
Returns the voltage in millivolt (mV) measured by the RN2xxx LoRa module. It's for information only since we don't know how it's measured but looks like accurate.
249+
Returns the voltage in millivolt (mV) measured by the RN2xxx LoRa module. It's for information only since we don't know how it's calculated but looks accurate.
243250

244251
```c
245252
uint16_t getVDD();
246253
```
254+
255+
## Method: `getStatus`
256+
257+
Returns the status of the RN2xxx modem's state machine in one of the nine possible states of `ttn_modem_status_t`. Unfortunately, due to a firmware bug, this does not work for RN2493 modems with firmware < 1.05. If unsuccessful, the method returns `TTN_MODEM_READ_ERROR`.
258+
259+
```c
260+
enum ttn_modem_status_t getStatus()
261+
```
262+
263+
Possible return codes are:
264+
265+
- `TTN_MODEM_READ_ERR` could not read out the status
266+
- `TTN_MODEM_IDLE` modem idle, ready for next tx
267+
- `TTN_MODEM_TX` modem transmitting
268+
- `TTN_MODEM_BEFORE_RX` waiting time between tx and rx1 windows
269+
- `TTN_MODEM_RX1` RX1 window open
270+
- `TTN_MODEM_BEFORE_RX2` waiting time between the two rx windows
271+
- `TTN_MODEM_RETRY_DELAY` waiting before retry again
272+
- `TTN_MODEM_APB_DELAY` APB join delay
273+
- `TTN_MODEM_C_RX1` RX1 window open in class C
274+
- `TTN_MODEM_C_RX2` RX2 window open in class C
275+
276+
277+
## Method: `getLastError`
278+
279+
Returns the last error code encountered by the RN2xxx modem. The error code may be one of the twelve possible errors of `ttn_response_code_t`. Call this method after an unsuccessful execution.
280+
281+
```c
282+
ttn_response_code_t getLastError();
283+
```
284+
285+
For example, suppose you perform a send via `sendbytes` and get a `TTN_ERROR_SEND_COMMAND_FAILED`. In that case, you can call this method and get a `TTN_ERR_BUSY`, which means the modem already has a message to send in the buffer.
286+
287+
Possible error codes are:
288+
289+
- `TTN_OK` nothing actually went wrong.
290+
- `TTN_ERROR_BUSY` busy sending a message
291+
- `TTN_ERROR_FRAME_COUNTER_ERROR` if the frame counter rolled over
292+
- `TTN_ERROR_INVALID_CLASS` selected LoRaWan class is invalid
293+
- `TTN_ERROR_INVALID_LENGTH` data length is not available for the current configuration
294+
- `TTN_ERROR_INVALID_PARAMETER` invalid parameter specified
295+
- `TTN_ERROR_NO_KEY_INTITIALIZED` network keys not initialized
296+
- `TTN_ERROR_MAC_PAUSE` mac level has been paused
297+
- `TTN_ERROR_NO_KEY_MULTICAST` multicast keys not set
298+
- `TTN_ERROR_NO_FREE_CHANNEL` all channels exhausted their duty cycle, so we can not send
299+
- `TTN_ERROR_NOT_JOINED` modem did not join a network
300+
- `TTN_ERROR_SILENT` if the module is in a Silent Immediately state
301+
- `TTN_ERROR_ERR` other unspecified error
302+
303+
## Method: `getFCU`
304+
305+
Returns the next used uplink frame counter. In LoRaWan, this counter must match on both sides, server, and end-node, for a transmission to be successful. Please note that although the counter is 32bit, the frame itself contains only the lowest 16bits of the message. Nonetheless, the message is encrypted using all 32bits of the FCU in the key. Therefore, it _must_ be up to date and in sync. If the readout is unsuccessful, the method returns 0. However, the first frame after a reset is also set to 0.
306+
307+
```c
308+
uint32_t getFCU();
309+
```
310+
311+
## Method: `setFCU`
312+
313+
Sets the FCU as of above. The method returns true if successful.
314+
315+
```c
316+
bool setFCU(uint32_t fcu);
317+
```
318+
319+
## Method: `getFCD`
320+
321+
Returns the next expected downlink frame counter. In LoRaWan, this counter must match on both sides, server, and end-node, for a transmission to be successful. Please note that although the counter is 32bit, the frame itself contains only the lowest 16bits of the message. Nonetheless, the message is encrypted using all 32bits of the FCD in the key. Therefore, it _must_ be up to date and in sync. If the readout is unsuccessful, the method returns 0. However, the first frame after a reset is also sent with frame number 0.
322+
323+
```c
324+
uint32_t getFCD();
325+
```
326+
327+
## Method: `setFCD`
328+
329+
Sets the FCD as of above. The method returns true if successful.
330+
331+
```c
332+
bool setFCD(uint32_t fcd);
333+
```
334+
335+
## Method: `getDR`
336+
337+
Returns the data rate that the modem will use for the next uplink frame. If the readout is unsuccessful, the method returns -1.
338+
339+
```c
340+
int8_t getDR();
341+
```
342+
343+
## Method: `setDR`
344+
345+
Sets the data rate to use for the next uplink frame; see `getDR`. This is mainly useful for operating with adaptive data rate (ADR) in `off`; see `setADR`. If ADR is on, it will set the DR for the next uplink, but the value for the successive transmissions may change according to the ADR protocol. The range of valid DR values depends on the frequency plan. The method returns true if successful.
346+
347+
```c
348+
bool setDR(uint8_t dr);
349+
```
350+
351+
## Method: `getPowerIndex`
352+
353+
Returns the power index that the LoRa modem will use for the next uplink frame. If the readout is unsuccessful, the method returns -1.
354+
355+
```c
356+
int8_t getPowerIndex();
357+
```
358+
359+
## Method: `setPowerIndex`
360+
361+
Sets the power index to use for the next uplink frame; see `getPowerIndex`. This is mainly useful for operating with adaptive data rate (ADR) in `off`; see `setADR`. If ADR is on, it will set the power index for the next uplink. Still, the value for the following transmissions may change according to the ADR protocol. The range of valid values depends on modem hardware and the frequency plan. The method returns true if successful.
362+
363+
```c
364+
bool setPowerIndex(uint8_t index);
365+
```
366+
367+
## Method: `setChannel`
368+
369+
The TTN module can store multiple channel configurations. With this method, you can configure a logical channel of the modem by defining frequency in `Hz`, minimum and maximum usable data rates for the channel. Data rates depend on the used frequency plan and must be between 0 and 15. The method returns true if a configuration is successful.
370+
371+
```c
372+
bool setChannel(uint8_t channel, uint32_t frequency = 0l, uint8_t dr_min = 255, uint8_t dr_max = 255);
373+
```
374+
375+
Alternatively, you can only re-set the data rates for the channel by leaving (omitting) frequency to 0.
376+
377+
```c
378+
setChannel(2, dr_min = 0, dr_max = 4);
379+
```
380+
381+
Or, you can only re-set the frequency for the channel by leaving (omitting) dr_* to 255.
382+
383+
```c
384+
setChannel(2, 863500000);
385+
```
386+
387+
However, the whole configuration must have been set at least once to be successful in both cases.
388+
389+
## Method: `setRX2Channel`
390+
391+
In some plans, the TTN module stores a common RX2 downlink channel, which is used for RX2 window communication. With this method, you can configure this channel by defining frequency in `Hz` and its data rates. The valid data rates depend on the used frequency plan. The method returns true if a configuration is successful.
392+
393+
```c
394+
bool setRx2Channel(uint32_t frequency, uint8_t dr);
395+
```
396+
397+
## Method: `getChannelStatus`
398+
399+
The TTN module can store multiple channel configurations. This method returns true if the channel is enabled for transmission and/or receiving.
400+
401+
```c
402+
bool getChannelStatus (uint8_t channel);
403+
```
404+
405+
## Method: `setChannelStatus`
406+
407+
Sets the channel status of the selected channel number; see `getChannelStatus`. If set to true and the channel is configured, the modem may use the channel for transmission. The method returns true if successful.
408+
409+
```c
410+
bool setChannelStatus (uint8_t channel, bool status);
411+
```
412+
413+
## Method: `setChannelDCycle`
414+
415+
Sets the channel maximum allowed duty cycle of a selected channel number in `%`. Depending on regional regulations, the duty cycle may limit the maximum frequency use to a percentage in time. With this method, we set the ratio of transmission time for the selected channel, e.g., `1%` with 1 second transmission time means the radio has to pause for 99 seconds on this channel before retransmitting. The method returns true if successful.
416+
417+
```c
418+
bool setChannelDCycle (uint8_t channel, float duty_cycle);
419+
```
420+
421+
## Method: `setADR`
422+
423+
We can manually disable or enable the adaptive data rate (ADR) algorithm on the device with this method. It independently adapts the transmission data rate (and power) in runtime if active. If disabled, we must select power index and data rate manually, see `setDR` and `setPowerIndex`. The method returns true if successful.
424+
425+
```c
426+
bool setADR(bool adr);
427+
```
428+
429+
## Method: `setRX1Delay`
430+
431+
When transmitting in LoRaWan, we usually operate on a TX window and two RX windows. This setting defines how long the modem has to wait before opening the channel for listening for RX window 1. RX window two is hardcoded to be one second after RX1. This parameter is configurable between 1 and 15 seconds in `ms`. By default, we have a delay of 1000 ms, and you should not change this if you do not change the network server accordingly. Longer window delays may be helpful with slow, unresponsive Internet connectivity. The method returns true if successful.
432+
433+
```c
434+
bool setRX1Delay(uint16_t delay);
435+
```
436+
437+
# Additional for statistics
438+
439+
## Method: `getRSSI`
440+
441+
Returns the relative signal strength of the last received frame in `dBm`. Typical values are between -70dBm (very strong) and -136dBm (weak/sensitivity threshold). If the readout is unsuccessful, the method returns -255.
442+
443+
```c
444+
int16_t getRSSI();
445+
```
446+
447+
## Method: `getSNR`
448+
449+
Returns the signal to noise ratio of the last received frame in `dB`. Note that LoRa also allows negative values for SNR. Typical values are between +20dB (very clear) and -20dB (weak/sensitivity threshold). If the readout is unsuccessful, the method returns -128.
450+
451+
```c
452+
int8_t getSNR();
453+
```
454+
455+
## Method: `getFrequency`
456+
457+
Returns the channel frequency of the last received frame in `Hz`. If the readout is unsuccessful, the method returns 0.
458+
459+
```c
460+
uint32_t getFrequency();
461+
```
462+
463+
## Method: `getWatchDogTimer`
464+
465+
Returns the LoRa modem's internal watch-dog timer in `ms`. If this time is exceeded, the modem resets. If instead, the readout is unsuccessful, the method returns 0.
466+
467+
```c
468+
uint32_t getWatchDogTimer();
469+
```
470+
471+
## Method: `getBW`
472+
473+
Returns the used channel bandwidth of the last received frame in `kHz`. If the readout is unsuccessful, the method returns 0.
474+
475+
```c
476+
uint8_t getBW();
477+
```
478+
479+
## Method: `getCR`
480+
481+
Returns the used code rate of the last received frame in `4/x`. If the readout is unsuccessful, the method returns 0.
482+
483+
```c
484+
uint8_t getCR();
485+
```
486+
487+
## Method: `getPower`
488+
489+
Returns the power of the last incoming transmission in `dBm`. If the readout is unsuccessful, the method returns -128.
490+
491+
```c
492+
int8_t getPower();
493+
```

0 commit comments

Comments
 (0)