[LoRaWAN] Added event struct to pass extra info (#821)

This commit is contained in:
jgromes 2023-11-12 17:53:05 +01:00
parent cb9ba88d03
commit 75a9420552
5 changed files with 133 additions and 51 deletions

View file

@ -1,5 +1,5 @@
/*
RadioLib LoRaWAN End Device Example
RadioLib LoRaWAN End Device Persistent Example
This example assumes you have tried one of the OTAA or ABP
examples and are familiar with the required keys and procedures.
@ -7,7 +7,7 @@
deepsleep or survive power cycles. Before you start, you will
have to register your device at https://www.thethingsnetwork.org/
and join the network using either OTAA or ABP.
Please refer to one of the other examples for more
Please refer to one of the other LoRaWAN examples for more
information regarding joining a network.
NOTE: LoRaWAN requires storing some parameters persistently!

View file

@ -1,5 +1,5 @@
/*
RadioLib LoRaWAN End Device Example
RadioLib LoRaWAN End Device Reference Example
This example joins a LoRaWAN network and will send
uplink packets. Before you start, you will have to
@ -131,13 +131,13 @@ void setup() {
// this tries to minimize packet loss by searching for a free channel
// before actually sending an uplink
node.setCSMA(6, 2, true);
}
void loop() {
int state = RADIOLIB_ERR_NONE;
// set battery fill level,
// set battery fill level - the LoRaWAN network server
// may periodically request this information
// 0 = external power source
// 1 = lowest (empty battery)
// 254 = highest (full battery)
@ -170,7 +170,12 @@ void loop() {
// after uplink to receive the downlink!
Serial.print(F("[LoRaWAN] Waiting for downlink ... "));
String strDown;
state = node.downlink(strDown);
// you can also retrieve additional information about
// uplink or downlink by passing a reference to
// LoRaWANEvent_t structure
LoRaWANEvent_t event;
state = node.downlink(strDown, &event);
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
@ -197,6 +202,31 @@ void loop() {
Serial.print(radio.getFrequencyError());
Serial.println(F(" Hz"));
// print extra information about the event
Serial.println(F("[LoRaWAN] Event information:"));
Serial.print(F("[LoRaWAN] Direction:\t"));
if(event.dir == RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK) {
Serial.println(F("uplink"));
} else {
Serial.println(F("downlink"));
}
Serial.print(F("[LoRaWAN] Confirmed:\t"));
Serial.println(event.confirmed);
Serial.print(F("[LoRaWAN] Confirming:\t"));
Serial.println(event.confirming);
Serial.print(F("[LoRaWAN] Frequency:\t"));
Serial.print(event.freq, 3);
Serial.println(F(" MHz"));
Serial.print(F("[LoRaWAN] Output power:\t"));
Serial.print(event.power);
Serial.println(F(" dBm"));
Serial.print(F("[LoRaWAN] Frame count:\t"));
Serial.println(event.fcnt);
Serial.print(F("[LoRaWAN] Port:\t\t"));
Serial.println(event.port);
Serial.print(radio.getFrequencyError());
} else if(state == RADIOLIB_ERR_RX_TIMEOUT) {
Serial.println(F("timeout!"));

View file

@ -58,6 +58,7 @@ ExternalRadio KEYWORD1
BellClient KEYWORD1
LoRaWANNode KEYWORD1
LoRaWANBand_t KEYWORD1
LoRaWANEvent_t KEYWORD1
# SSTV modes
Scottie1 KEYWORD1

View file

@ -657,16 +657,16 @@ int16_t LoRaWANNode::saveChannels() {
#if defined(RADIOLIB_BUILD_ARDUINO)
int16_t LoRaWANNode::uplink(String& str, uint8_t port, bool isConfirmed) {
return(this->uplink(str.c_str(), port, isConfirmed));
int16_t LoRaWANNode::uplink(String& str, uint8_t port, bool isConfirmed, LoRaWANEvent_t* event) {
return(this->uplink(str.c_str(), port, isConfirmed, event));
}
#endif
int16_t LoRaWANNode::uplink(const char* str, uint8_t port, bool isConfirmed) {
return(this->uplink((uint8_t*)str, strlen(str), port, isConfirmed));
int16_t LoRaWANNode::uplink(const char* str, uint8_t port, bool isConfirmed, LoRaWANEvent_t* event) {
return(this->uplink((uint8_t*)str, strlen(str), port, isConfirmed, event));
}
int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed) {
int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed, LoRaWANEvent_t* event) {
Module* mod = this->phyLayer->getMod();
// check if the Rx windows were closed after sending the previous uplink
@ -783,12 +783,11 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf
}
// if the saved confirm-fcnt is set, set the ACK bit
bool isConfirmingDown;
bool isConfirmingDown = false;
if(this->confFcntDown != RADIOLIB_LORAWAN_FCNT_NONE) {
isConfirmingDown = true;
uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ACK;
}
(void)isConfirmingDown;
LoRaWANNode::hton<uint16_t>(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS], (uint16_t)this->fcntUp);
@ -895,13 +894,16 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf
// the downlink confirmation was acknowledged, so clear the counter value
this->confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE;
// LoRaWANEvent:
// dir = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK
// confirmed = isConfirmed
// confirming = isConfirmingDown
// power = this->txPwrCur
// fcnt = this->fcntUp
// port = port
// pass the extra info if requested
if(event) {
event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK;
event->confirmed = isConfirmed;
event->confirming = isConfirmingDown;
event->freq = currentChannels[event->dir].freq;
event->power = this->txPwrCur;
event->fcnt = this->fcntUp;
event->port = port;
}
return(RADIOLIB_ERR_NONE);
}
@ -1012,7 +1014,7 @@ int16_t LoRaWANNode::downlinkCommon() {
}
#if defined(RADIOLIB_BUILD_ARDUINO)
int16_t LoRaWANNode::downlink(String& str) {
int16_t LoRaWANNode::downlink(String& str, LoRaWANEvent_t* event) {
int16_t state = RADIOLIB_ERR_NONE;
// build a temporary buffer
@ -1021,7 +1023,7 @@ int16_t LoRaWANNode::downlink(String& str) {
uint8_t data[251];
// wait for downlink
state = this->downlink(data, &length);
state = this->downlink(data, &length, event);
if(state == RADIOLIB_ERR_NONE) {
// add null terminator
data[length] = '\0';
@ -1034,8 +1036,7 @@ int16_t LoRaWANNode::downlink(String& str) {
}
#endif
int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) {
// handle Rx1 and Rx2 windows - returns RADIOLIB_ERR_NONE if a downlink is received
int16_t state = downlinkCommon();
RADIOLIB_ASSERT(state);
@ -1086,13 +1087,11 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
LoRaWANNode::hton<uint16_t>(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt16);
// if this downlink is confirming an uplink, its MIC was generated with the least-significant 16 bits of that fcntUp
// TODO get this to the user somehow
bool isConfirmingUp = false;
if((downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FCTRL_ACK) && (this->rev == 1)) {
isConfirmingUp = true;
LoRaWANNode::hton<uint16_t>(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFcntUp);
}
(void)isConfirmingUp;
RADIOLIB_DEBUG_PRINTLN("downlinkMsg:");
RADIOLIB_DEBUG_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen);
@ -1157,7 +1156,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
this->confFcntDown = this->aFcntDown;
isConfirmedDown = true;
}
(void)isConfirmedDown;
// check the address
uint32_t addr = LoRaWANNode::ntoh<uint32_t>(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS]);
@ -1242,13 +1240,16 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
// a downlink was received, so reset the ADR counter to this uplink's fcnt
this->adrFcnt = this->fcntUp;
// LoRaWANEvent:
// dir = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK
// confirmed = isConfirmedDown
// confirming = isConfirmingUp
// power = this->txPwrCur
// fcnt = isAppDownlink ? this->aFcntDown : this->nFcntDown
// port = ...
// pass the extra info if requested
if(event) {
event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK;
event->confirmed = isConfirmedDown;
event->confirming = isConfirmingUp;
event->freq = currentChannels[event->dir].freq;
event->power = this->txPwrCur;
event->fcnt = isAppDownlink ? this->aFcntDown : this->nFcntDown;
event->port = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)];
}
// process payload (if there is any)
if(payLen <= 0) {
@ -1276,34 +1277,34 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
}
#if defined(RADIOLIB_BUILD_ARDUINO)
int16_t LoRaWANNode::sendReceive(String& strUp, uint8_t port, String& strDown, bool isConfirmed) {
int16_t LoRaWANNode::sendReceive(String& strUp, uint8_t port, String& strDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) {
// send the uplink
int16_t state = this->uplink(strUp, port, isConfirmed);
int16_t state = this->uplink(strUp, port, isConfirmed, eventUp);
RADIOLIB_ASSERT(state);
// wait for the downlink
state = this->downlink(strDown);
state = this->downlink(strDown, eventDown);
return(state);
}
#endif
int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed) {
int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) {
// send the uplink
int16_t state = this->uplink(strUp, port, isConfirmed);
int16_t state = this->uplink(strUp, port, isConfirmed, eventUp);
RADIOLIB_ASSERT(state);
// wait for the downlink
state = this->downlink(dataDown, lenDown);
state = this->downlink(dataDown, lenDown, eventDown);
return(state);
}
int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed) {
int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) {
// send the uplink
int16_t state = this->uplink(dataUp, lenUp, port, isConfirmed);
int16_t state = this->uplink(dataUp, lenUp, port, isConfirmed, eventUp);
RADIOLIB_ASSERT(state);
// wait for the downlink
state = this->downlink(dataDown, lenDown);
state = this->downlink(dataDown, lenDown, eventDown);
return(state);
}

View file

@ -311,6 +311,34 @@ struct LoRaWANMacCommandQueue_t {
LoRaWANMacCommand_t commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE];
};
/*!
\struct LoRaWANEvent_t
\brief Structure to save extra information about uplink/downlink event.
*/
struct LoRaWANEvent_t {
/*! \brief Event direction, one of RADIOLIB_LORAWAN_CHANNEL_DIR_* */
uint8_t dir;
/*! \brief Whether the event is confirmed or not (e.g., confirmed uplink sent by user application) */
bool confirmed;
/*! \brief Whether the event is confirming a previous request
(e.g., server downlink reply to confirmed uplink sent by user application)*/
bool confirming;
/*! \brief Frequency in MHz */
float freq;
/*! \brief Transmit power in dBm for uplink, or RSSI for downlink */
int16_t power;
/*! \brief The appropriate frame counter - for different events, different frame counters will be reported! */
uint32_t fcnt;
/*! \brief Port number */
uint8_t port;
};
/*!
\class LoRaWANNode
\brief LoRaWAN-compatible node (class A device).
@ -388,9 +416,11 @@ class LoRaWANNode {
\param str Address of Arduino String that will be transmitted.
\param port Port number to send the message to.
\param isConfirmed Whether to send a confirmed uplink or not.
\param event Pointer to a structure to store extra information about the event
(port, frame counter, etc.). If set to NULL, no extra information will be passed to the user.
\returns \ref status_codes
*/
int16_t uplink(String& str, uint8_t port, bool isConfirmed = false);
int16_t uplink(String& str, uint8_t port, bool isConfirmed = false, LoRaWANEvent_t* event = NULL);
#endif
/*!
@ -398,9 +428,11 @@ class LoRaWANNode {
\param str C-string that will be transmitted.
\param port Port number to send the message to.
\param isConfirmed Whether to send a confirmed uplink or not.
\param event Pointer to a structure to store extra information about the event
(port, frame counter, etc.). If set to NULL, no extra information will be passed to the user.
\returns \ref status_codes
*/
int16_t uplink(const char* str, uint8_t port, bool isConfirmed = false);
int16_t uplink(const char* str, uint8_t port, bool isConfirmed = false, LoRaWANEvent_t* event = NULL);
/*!
\brief Send a message to the server.
@ -408,26 +440,32 @@ class LoRaWANNode {
\param len Length of the data.
\param port Port number to send the message to.
\param isConfirmed Whether to send a confirmed uplink or not.
\param event Pointer to a structure to store extra information about the event
(port, frame counter, etc.). If set to NULL, no extra information will be passed to the user.
\returns \ref status_codes
*/
int16_t uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed = false);
int16_t uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed = false, LoRaWANEvent_t* event = NULL);
#if defined(RADIOLIB_BUILD_ARDUINO)
/*!
\brief Wait for downlink from the server in either RX1 or RX2 window.
\param str Address of Arduino String to save the received data.
\param event Pointer to a structure to store extra information about the event
(port, frame counter, etc.). If set to NULL, no extra information will be passed to the user.
\returns \ref status_codes
*/
int16_t downlink(String& str);
int16_t downlink(String& str, LoRaWANEvent_t* event = NULL);
#endif
/*!
\brief Wait for downlink from the server in either RX1 or RX2 window.
\param data Buffer to save received data into.
\param len Pointer to variable that will be used to save the number of received bytes.
\param event Pointer to a structure to store extra information about the event
(port, frame counter, etc.). If set to NULL, no extra information will be passed to the user.
\returns \ref status_codes
*/
int16_t downlink(uint8_t* data, size_t* len);
int16_t downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event = NULL);
#if defined(RADIOLIB_BUILD_ARDUINO)
/*!
@ -436,9 +474,13 @@ class LoRaWANNode {
\param port Port number to send the message to.
\param strDown Address of Arduino String to save the received data.
\param isConfirmed Whether to send a confirmed uplink or not.
\param eventUp Pointer to a structure to store extra information about the uplink event
(port, frame counter, etc.). If set to NULL, no extra information will be passed to the user.
\param eventDown Pointer to a structure to store extra information about the downlink event
(port, frame counter, etc.). If set to NULL, no extra information will be passed to the user.
\returns \ref status_codes
*/
int16_t sendReceive(String& strUp, uint8_t port, String& strDown, bool isConfirmed = false);
int16_t sendReceive(String& strUp, uint8_t port, String& strDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL);
#endif
/*!
@ -448,9 +490,13 @@ class LoRaWANNode {
\param dataDown Buffer to save received data into.
\param lenDown Pointer to variable that will be used to save the number of received bytes.
\param isConfirmed Whether to send a confirmed uplink or not.
\param eventUp Pointer to a structure to store extra information about the uplink event
(port, frame counter, etc.). If set to NULL, no extra information will be passed to the user.
\param eventDown Pointer to a structure to store extra information about the downlink event
(port, frame counter, etc.). If set to NULL, no extra information will be passed to the user.
\returns \ref status_codes
*/
int16_t sendReceive(const char* strUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false);
int16_t sendReceive(const char* strUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL);
/*!
\brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window.
@ -460,9 +506,13 @@ class LoRaWANNode {
\param dataDown Buffer to save received data into.
\param lenDown Pointer to variable that will be used to save the number of received bytes.
\param isConfirmed Whether to send a confirmed uplink or not.
\param eventUp Pointer to a structure to store extra information about the uplink event
(port, frame counter, etc.). If set to NULL, no extra information will be passed to the user.
\param eventDown Pointer to a structure to store extra information about the downlink event
(port, frame counter, etc.). If set to NULL, no extra information will be passed to the user.
\returns \ref status_codes
*/
int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false);
int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL);
/*!
\brief Set device status.