[LoRaWAN] Added event struct to pass extra info (#821)
This commit is contained in:
parent
cb9ba88d03
commit
75a9420552
5 changed files with 133 additions and 51 deletions
|
@ -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!
|
||||
|
|
|
@ -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!"));
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ ExternalRadio KEYWORD1
|
|||
BellClient KEYWORD1
|
||||
LoRaWANNode KEYWORD1
|
||||
LoRaWANBand_t KEYWORD1
|
||||
LoRaWANEvent_t KEYWORD1
|
||||
|
||||
# SSTV modes
|
||||
Scottie1 KEYWORD1
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Add table
Reference in a new issue