[LoRaWAN] Improve band & ADR logic, allow setting ADR, DR, subband, update examples
This commit is contained in:
parent
6c093b2491
commit
4138dacb19
11 changed files with 410 additions and 181 deletions
|
@ -87,17 +87,28 @@ void setup() {
|
||||||
// and can be set to NULL
|
// and can be set to NULL
|
||||||
|
|
||||||
// some frequency bands only use a subset of the available channels
|
// some frequency bands only use a subset of the available channels
|
||||||
// you can set the starting channel and their number
|
// you can select the specific band or set the first channel and last channel
|
||||||
// for example, the following corresponds to US915 FSB2 in TTN
|
// for example, either of the following corresponds to US915 FSB2 in TTN
|
||||||
/*
|
/*
|
||||||
node.startChannel = 8;
|
node.selectSubband(2);
|
||||||
node.numChannels = 8;
|
node.selectSubband(8, 16);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// now we can start the activation
|
// now we can start the activation
|
||||||
// this can take up to 20 seconds, and requires a LoRaWAN gateway in range
|
// this can take up to 20 seconds, and requires a LoRaWAN gateway in range
|
||||||
|
// a specific starting-datarate can be selected in dynamic bands (e.g. EU868):
|
||||||
|
/*
|
||||||
|
uint8_t joinDr = 8;
|
||||||
|
state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, joinDr);
|
||||||
|
*/
|
||||||
|
// a specific band can be selected for joining in fixed bands (e.g. US915):
|
||||||
|
/*
|
||||||
|
uint8_t subband = 2;
|
||||||
|
state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, subband);
|
||||||
|
*/
|
||||||
Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... "));
|
Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... "));
|
||||||
state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey);
|
state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey);
|
||||||
|
|
||||||
if(state == RADIOLIB_ERR_NONE) {
|
if(state == RADIOLIB_ERR_NONE) {
|
||||||
Serial.println(F("success!"));
|
Serial.println(F("success!"));
|
||||||
} else {
|
} else {
|
||||||
|
@ -107,11 +118,11 @@ void setup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// after the device has been activated,
|
// after the device has been activated,
|
||||||
// network can be rejoined after device power cycle
|
// the session can be restored without rejoining after device power cycle
|
||||||
// by calling "begin"
|
// on EEPROM-enabled boards by calling "restore"
|
||||||
/*
|
/*
|
||||||
Serial.print(F("[LoRaWAN] Resuming previous session ... "));
|
Serial.print(F("[LoRaWAN] Resuming previous session ... "));
|
||||||
state = node.begin();
|
state = node.restore();
|
||||||
if(state == RADIOLIB_ERR_NONE) {
|
if(state == RADIOLIB_ERR_NONE) {
|
||||||
Serial.println(F("success!"));
|
Serial.println(F("success!"));
|
||||||
} else {
|
} else {
|
||||||
|
@ -178,6 +189,12 @@ void loop() {
|
||||||
Serial.println(state);
|
Serial.println(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// on EEPROM enabled boards, you can save the current session
|
||||||
|
// by calling "saveSession" which allows retrieving the session after reboot or deepsleep
|
||||||
|
/*
|
||||||
|
node.saveSession();
|
||||||
|
*/
|
||||||
|
|
||||||
// wait before sending another packet
|
// wait before sending another packet
|
||||||
delay(10000);
|
delay(30000);
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,16 +83,27 @@ void setup() {
|
||||||
// and can be set to NULL
|
// and can be set to NULL
|
||||||
|
|
||||||
// some frequency bands only use a subset of the available channels
|
// some frequency bands only use a subset of the available channels
|
||||||
// you can set the starting channel and their number
|
// you can select the specific band or set the first channel and last channel
|
||||||
// for example, the following corresponds to US915 FSB2 in TTN
|
// for example, either of the following corresponds to US915 FSB2 in TTN
|
||||||
/*
|
/*
|
||||||
node.startChannel = 8;
|
node.selectSubband(2);
|
||||||
node.numChannels = 8;
|
node.selectSubband(8, 16);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// if using EU868 on ABP in TTN, you need to set the SF for RX2 window manually
|
||||||
|
/*
|
||||||
|
node.rx2.drMax = 3;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// to start a LoRaWAN v1.1 session, the user should also provide
|
||||||
|
// fNwkSIntKey and sNwkSIntKey similar to nwkSKey and appSKey
|
||||||
|
/*
|
||||||
|
state = node.beginABP(devAddr, nwkSKey, appSKey, fNwkSIntKey, sNwkSIntKey);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// start the device by directly providing the encryption keys and device address
|
// start the device by directly providing the encryption keys and device address
|
||||||
Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... "));
|
Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... "));
|
||||||
state = node.beginAPB(devAddr, (uint8_t*)nwkSKey, (uint8_t*)appSKey);
|
state = node.beginABP(devAddr, nwkSKey, appSKey);
|
||||||
if(state == RADIOLIB_ERR_NONE) {
|
if(state == RADIOLIB_ERR_NONE) {
|
||||||
Serial.println(F("success!"));
|
Serial.println(F("success!"));
|
||||||
} else {
|
} else {
|
||||||
|
@ -102,11 +113,11 @@ void setup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// after the device has been activated,
|
// after the device has been activated,
|
||||||
// network can be rejoined after device power cycle
|
// the session can be restored without rejoining after device power cycle
|
||||||
// by calling "begin"
|
// on EEPROM-enabled boards by calling "restore"
|
||||||
/*
|
/*
|
||||||
Serial.print(F("[LoRaWAN] Resuming previous session ... "));
|
Serial.print(F("[LoRaWAN] Resuming previous session ... "));
|
||||||
state = node.begin();
|
state = node.restore();
|
||||||
if(state == RADIOLIB_ERR_NONE) {
|
if(state == RADIOLIB_ERR_NONE) {
|
||||||
Serial.println(F("success!"));
|
Serial.println(F("success!"));
|
||||||
} else {
|
} else {
|
||||||
|
@ -173,6 +184,12 @@ void loop() {
|
||||||
Serial.println(state);
|
Serial.println(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// on EEPROM enabled boards, you can save the current session
|
||||||
|
// by calling "saveSession" which allows retrieving the session after reboot or deepsleep
|
||||||
|
/*
|
||||||
|
node.saveSession();
|
||||||
|
*/
|
||||||
|
|
||||||
// wait before sending another packet
|
// wait before sending another packet
|
||||||
delay(10000);
|
delay(10000);
|
||||||
}
|
}
|
||||||
|
|
|
@ -553,6 +553,11 @@
|
||||||
*/
|
*/
|
||||||
#define RADIOLIB_ERR_A_FCNT_DOWN_INVALID (-1114)
|
#define RADIOLIB_ERR_A_FCNT_DOWN_INVALID (-1114)
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Datarate requested by user is invalid.
|
||||||
|
*/
|
||||||
|
#define RADIOLIB_ERR_DATA_RATE_INVALID (-1115)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\}
|
\}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1443,13 +1443,17 @@ uint32_t SX126x::calculateRxTimeout(uint8_t numSymbols, uint32_t timeoutUs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t SX126x::irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) {
|
int16_t SX126x::irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) {
|
||||||
irqFlags = 0b0000000000000010; // RxDone
|
irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT; // flags that can appear in the IRQ register
|
||||||
irqMask = 0b0000000000000010;
|
irqMask = RADIOLIB_SX126X_IRQ_RX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT; // flags that will trigger DIO0
|
||||||
irqFlags |= 0b0000001000000000; // RxTimeout
|
|
||||||
irqMask |= 0b0000001000000000;
|
|
||||||
return(RADIOLIB_ERR_NONE);
|
return(RADIOLIB_ERR_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SX126x::isRxTimeout() {
|
||||||
|
uint16_t irq = getIrqStatus();
|
||||||
|
bool rxTimedOut = irq & RADIOLIB_SX126X_IRQ_TIMEOUT;
|
||||||
|
return(rxTimedOut);
|
||||||
|
}
|
||||||
|
|
||||||
int16_t SX126x::implicitHeader(size_t len) {
|
int16_t SX126x::implicitHeader(size_t len) {
|
||||||
return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, len));
|
return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, len));
|
||||||
}
|
}
|
||||||
|
|
|
@ -965,6 +965,12 @@ class SX126x: public PhysicalLayer {
|
||||||
*/
|
*/
|
||||||
int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask);
|
int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Check whether the IRQ bit for RxTimeout is set
|
||||||
|
\returns \ref RxTimeout IRQ is set
|
||||||
|
*/
|
||||||
|
bool isRxTimeout();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Set implicit header mode for future reception/transmission.
|
\brief Set implicit header mode for future reception/transmission.
|
||||||
\param len Payload length in bytes.
|
\param len Payload length in bytes.
|
||||||
|
|
|
@ -1245,10 +1245,8 @@ uint32_t SX127x::getTimeOnAir(size_t len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t SX127x::calculateRxTimeout(uint8_t numSymbols, uint32_t timeoutUs) {
|
uint32_t SX127x::calculateRxTimeout(uint8_t numSymbols, uint32_t timeoutUs) {
|
||||||
(void)numSymbols; // not used for these modules
|
(void)timeoutUs;
|
||||||
// numSymbols += (109 / 4) + 1;
|
numSymbols = 20;
|
||||||
float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
|
|
||||||
numSymbols = timeoutUs / symbolLength + 1;
|
|
||||||
return(numSymbols);
|
return(numSymbols);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -174,7 +174,7 @@ int16_t LoRaWANNode::restoreChannels() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force) {
|
int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, uint8_t drJoinSubband, bool force) {
|
||||||
// check if we actually need to send the join request
|
// check if we actually need to send the join request
|
||||||
Module* mod = this->phyLayer->getMod();
|
Module* mod = this->phyLayer->getMod();
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
|
||||||
RADIOLIB_ASSERT(state);
|
RADIOLIB_ASSERT(state);
|
||||||
|
|
||||||
// setup uplink/downlink frequencies and datarates
|
// setup uplink/downlink frequencies and datarates
|
||||||
state = this->selectChannelsJR(this->devNonce);
|
state = this->selectChannelsJR(this->devNonce, drJoinSubband);
|
||||||
RADIOLIB_ASSERT(state);
|
RADIOLIB_ASSERT(state);
|
||||||
|
|
||||||
// configure for uplink with default configuration
|
// configure for uplink with default configuration
|
||||||
|
@ -617,16 +617,16 @@ int16_t LoRaWANNode::saveChannels() {
|
||||||
|
|
||||||
|
|
||||||
#if defined(RADIOLIB_BUILD_ARDUINO)
|
#if defined(RADIOLIB_BUILD_ARDUINO)
|
||||||
int16_t LoRaWANNode::uplink(String& str, uint8_t port, bool isConfirmed, bool adrEnabled) {
|
int16_t LoRaWANNode::uplink(String& str, uint8_t port, bool isConfirmed) {
|
||||||
return(this->uplink(str.c_str(), port, isConfirmed, adrEnabled));
|
return(this->uplink(str.c_str(), port, isConfirmed));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int16_t LoRaWANNode::uplink(const char* str, uint8_t port, bool isConfirmed, bool adrEnabled) {
|
int16_t LoRaWANNode::uplink(const char* str, uint8_t port, bool isConfirmed) {
|
||||||
return(this->uplink((uint8_t*)str, strlen(str), port, isConfirmed, adrEnabled));
|
return(this->uplink((uint8_t*)str, strlen(str), port, isConfirmed));
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed, bool adrEnabled) {
|
int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed) {
|
||||||
Module* mod = this->phyLayer->getMod();
|
Module* mod = this->phyLayer->getMod();
|
||||||
|
|
||||||
// check if sufficient time has elapsed since the last uplink
|
// check if sufficient time has elapsed since the last uplink
|
||||||
|
@ -734,7 +734,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf
|
||||||
|
|
||||||
// length of fopts will be added later
|
// length of fopts will be added later
|
||||||
uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] = 0x00;
|
uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] = 0x00;
|
||||||
if(adrEnabled) {
|
if(this->adrEnabled) {
|
||||||
uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ENABLED;
|
uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ENABLED;
|
||||||
if(adrAckReq) {
|
if(adrAckReq) {
|
||||||
uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ;
|
uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ;
|
||||||
|
@ -1284,22 +1284,20 @@ int16_t LoRaWANNode::setPhyProperties() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t LoRaWANNode::setupChannels(uint8_t* cfList) {
|
int16_t LoRaWANNode::setupChannels(uint8_t* cfList) {
|
||||||
uint8_t num = 0;
|
size_t num = 0;
|
||||||
LoRaWANChannel_t chnl;
|
|
||||||
|
|
||||||
// in case of frequency list-type band, copy the default TX channels into the available channels, with RX1 = TX
|
// in case of frequency list-type band, copy the default TX channels into the available channels, with RX1 = TX
|
||||||
if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES) {
|
if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) {
|
||||||
for(uint8_t i = 0; i < 3; i++) {
|
// copy the default defined channels into the first slots
|
||||||
chnl = this->band->txFreqs[i];
|
for(; num < 3 && this->band->txFreqs[num].enabled; num++) {
|
||||||
if(chnl.enabled) {
|
availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num];
|
||||||
availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = chnl;
|
availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num];
|
||||||
availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = chnl;
|
RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].idx, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq);
|
||||||
RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", num, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq);
|
|
||||||
num++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// if there is a cflist present, parse its frequencies into the next five slots, with datarate range copied from default channel 0
|
||||||
if(cfList != nullptr) {
|
if(cfList != nullptr) {
|
||||||
for(uint8_t i = 0; i < 5; i++) {
|
for(uint8_t i = 0; i < 5; i++, num++) {
|
||||||
|
LoRaWANChannel_t chnl;
|
||||||
chnl.enabled = true;
|
chnl.enabled = true;
|
||||||
chnl.idx = num;
|
chnl.idx = num;
|
||||||
uint32_t freq = LoRaWANNode::ntoh<uint32_t>(&cfList[3*i], 3);
|
uint32_t freq = LoRaWANNode::ntoh<uint32_t>(&cfList[3*i], 3);
|
||||||
|
@ -1308,97 +1306,175 @@ int16_t LoRaWANNode::setupChannels(uint8_t* cfList) {
|
||||||
chnl.drMax = this->band->txFreqs[0].drMax; // drMax is equal for all channels
|
chnl.drMax = this->band->txFreqs[0].drMax; // drMax is equal for all channels
|
||||||
availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = chnl;
|
availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = chnl;
|
||||||
availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = chnl;
|
availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = chnl;
|
||||||
RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", num, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq);
|
RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", chnl.idx, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq);
|
||||||
num++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // RADIOLIB_LORAWAN_CFLIST_TYPE_MASK
|
|
||||||
uint8_t chSpan = 0;
|
|
||||||
uint8_t chNum = 0;
|
|
||||||
// in case of mask-type bands, copy those frequencies that are masked true into the available TX channels
|
|
||||||
for(uint8_t i = 0; i < 5; i++) {
|
|
||||||
uint16_t mask = LoRaWANNode::ntoh<uint16_t>(&cfList[2*i]);
|
|
||||||
RADIOLIB_DEBUG_PRINTLN("mask[%d] = 0x%04x", i, mask);
|
|
||||||
for(uint8_t j = 0; j < 16; j++) {
|
|
||||||
// if we must roll over to next span, reset chNum and move to next channel span
|
|
||||||
if(chNum >= this->band->txSpans[chSpan].numChannels) {
|
|
||||||
chNum = 0;
|
|
||||||
chSpan++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mask & (1UL << j)) {
|
} else { // RADIOLIB_LORAWAN_BAND_FIXED
|
||||||
if(chSpan >= this->band->numTxSpans || chNum >= this->band->txSpans[chSpan].numChannels) {
|
if(cfList != nullptr) {
|
||||||
RADIOLIB_DEBUG_PRINTLN("channel bitmask overrun!");
|
uint8_t chSpan = 0;
|
||||||
return(RADIOLIB_ERR_UNKNOWN);
|
uint8_t chNum = 0;
|
||||||
|
// in case of mask-type bands, copy those frequencies that are masked true into the available TX channels
|
||||||
|
for(size_t chMaskCntl = 0; chMaskCntl < 5; chMaskCntl++) {
|
||||||
|
uint16_t mask = LoRaWANNode::ntoh<uint16_t>(&cfList[2*chMaskCntl]);
|
||||||
|
RADIOLIB_DEBUG_PRINTLN("mask[%d] = 0x%04x", chMaskCntl, mask);
|
||||||
|
for(size_t i = 0; i < 16; i++) {
|
||||||
|
// if we must roll over to next span, reset chNum and move to next channel span
|
||||||
|
if(chNum >= this->band->txSpans[chSpan].numChannels) {
|
||||||
|
chNum = 0;
|
||||||
|
chSpan++;
|
||||||
}
|
}
|
||||||
chnl.enabled = true;
|
|
||||||
chnl.idx = i*16 + j;
|
if(mask & (1UL << i)) {
|
||||||
chnl.freq = this->band->txSpans[chSpan].freqStart + chNum*this->band->txSpans[chSpan].freqStep;
|
if(chSpan >= this->band->numTxSpans) {
|
||||||
chnl.drMin = this->band->txSpans[chSpan].drMin;
|
RADIOLIB_DEBUG_PRINTLN("channel bitmask overrun!");
|
||||||
chnl.drMax = this->band->txSpans[chSpan].drMax;
|
return(RADIOLIB_ERR_UNKNOWN);
|
||||||
availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = chnl;
|
}
|
||||||
RADIOLIB_DEBUG_PRINTLN("Channel UL %d frequency = %f MHz", num, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq);
|
LoRaWANChannel_t chnl;
|
||||||
num++;
|
chnl.enabled = true;
|
||||||
|
chnl.idx = chMaskCntl*16 + i;
|
||||||
|
chnl.freq = this->band->txSpans[chSpan].freqStart + chNum*this->band->txSpans[chSpan].freqStep;
|
||||||
|
chnl.drMin = this->band->txSpans[chSpan].drMin;
|
||||||
|
chnl.drMax = this->band->txSpans[chSpan].drMax;
|
||||||
|
availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = chnl;
|
||||||
|
// downlink channels are dynamically calculated on each uplink in selectChannels()
|
||||||
|
RADIOLIB_DEBUG_PRINTLN("Channel UL %d frequency = %f MHz", num, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq);
|
||||||
|
num++;
|
||||||
|
}
|
||||||
|
chNum++;
|
||||||
}
|
}
|
||||||
chNum++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(RADIOLIB_ERR_NONE);
|
return(RADIOLIB_ERR_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t LoRaWANNode::selectChannelsJR(uint16_t devNonce) {
|
int16_t LoRaWANNode::selectSubband(uint8_t idx) {
|
||||||
LoRaWANChannel_t channelUp;
|
int16_t state = this->selectSubband((idx - 1) * 8, idx * 8);
|
||||||
LoRaWANChannel_t channelDn;
|
return(state);
|
||||||
if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES) {
|
}
|
||||||
// count the number of available channels for a join-request
|
|
||||||
uint8_t numJRChannels = 0;
|
|
||||||
for(uint8_t i = 0; i < 3; i++) {
|
|
||||||
if(this->band->txFreqs[i].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) {
|
|
||||||
numJRChannels++;
|
|
||||||
}
|
|
||||||
if(this->band->txJoinReq[i].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) {
|
|
||||||
numJRChannels++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint8_t channelId = devNonce % numJRChannels; // cycle through channels (seed with devNonce)
|
|
||||||
if(channelId < 3) {
|
|
||||||
channelUp = this->band->txFreqs[channelId];
|
|
||||||
} else {
|
|
||||||
channelUp = this->band->txJoinReq[channelId - 3];
|
|
||||||
}
|
|
||||||
channelDn = channelUp; // RX1 is equal to TX
|
|
||||||
|
|
||||||
// configure data rates for TX and RX1: for TX the (floored) average of min and max; for RX1 identical with base offset
|
int16_t LoRaWANNode::selectSubband(uint8_t startChannel, uint8_t endChannel) {
|
||||||
this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = int((channelUp.drMax + channelUp.drMin) / 2);
|
if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) {
|
||||||
this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = getDownlinkDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK],
|
RADIOLIB_DEBUG_PRINTLN("This is a dynamic band plan which does not support subbands");
|
||||||
this->rx1DrOffset, this->band->rx1DataRateBase, channelDn.drMin, channelDn.drMax);
|
return(RADIOLIB_ERR_INVALID_CHANNEL);
|
||||||
} else { // RADIOLIB_LORAWAN_CFLIST_TYPE_MASK
|
}
|
||||||
|
|
||||||
|
uint8_t numChannels = endChannel - startChannel;
|
||||||
|
if(startChannel > this->band->txSpans[0].numChannels) {
|
||||||
|
RADIOLIB_DEBUG_PRINTLN("There are only %d channels available in this band", this->band->txSpans[0].numChannels);
|
||||||
|
return(RADIOLIB_ERR_INVALID_CHANNEL);
|
||||||
|
}
|
||||||
|
if(startChannel + numChannels > this->band->txSpans[0].numChannels) {
|
||||||
|
numChannels = this->band->txSpans[0].numChannels - startChannel;
|
||||||
|
RADIOLIB_DEBUG_PRINTLN("Could only select %d channels due to end of band", numChannels);
|
||||||
|
}
|
||||||
|
if(numChannels > RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS) {
|
||||||
|
numChannels = RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS;
|
||||||
|
RADIOLIB_DEBUG_PRINTLN("Could only select %d channels due to specified limit", numChannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoRaWANChannel_t chnl;
|
||||||
|
for(size_t chNum = 0; chNum < numChannels; chNum++) {
|
||||||
|
chnl.enabled = true;
|
||||||
|
chnl.idx = startChannel + chNum;
|
||||||
|
chnl.freq = this->band->txSpans[0].freqStart + chnl.idx*this->band->txSpans[0].freqStep;
|
||||||
|
chnl.drMin = this->band->txSpans[0].drMin;
|
||||||
|
chnl.drMax = this->band->txSpans[0].drMax;
|
||||||
|
availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chNum] = chnl;
|
||||||
|
// downlink channel is dynamically calculated on each uplink in selectChannels()
|
||||||
|
RADIOLIB_DEBUG_PRINTLN("Channel UL %d frequency = %f MHz", chNum, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chNum].freq);
|
||||||
|
}
|
||||||
|
return(RADIOLIB_ERR_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t LoRaWANNode::selectChannelsJR(uint16_t devNonce, uint8_t drJoinSubband) {
|
||||||
|
LoRaWANChannel_t channelUp;
|
||||||
|
LoRaWANChannel_t channelDown;
|
||||||
|
uint8_t drUp;
|
||||||
|
uint8_t drDown;
|
||||||
|
if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) {
|
||||||
|
// count the number of available channels for a join-request (default channels + join-request channels)
|
||||||
|
uint8_t numJRChannels = 0;
|
||||||
|
for(size_t i = 0; i < 3; i++) {
|
||||||
|
if(this->band->txFreqs[i].enabled) {
|
||||||
|
numJRChannels++;
|
||||||
|
}
|
||||||
|
if(this->band->txJoinReq[i].enabled) {
|
||||||
|
numJRChannels++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cycle through the available channels (seed with devNonce)
|
||||||
|
uint8_t channelId = devNonce % numJRChannels;
|
||||||
|
|
||||||
|
// find the channel whose index is selected
|
||||||
|
for(size_t i = 0; i < 3; i++) {
|
||||||
|
if(this->band->txFreqs[i].idx == channelId) {
|
||||||
|
channelUp = this->band->txFreqs[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(this->band->txJoinReq[i].idx == channelId) {
|
||||||
|
channelUp = this->band->txJoinReq[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if join datarate is user-specified and valid, select that value; otherwise use
|
||||||
|
if(drJoinSubband != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) {
|
||||||
|
if(drJoinSubband >= channelUp.drMin && drJoinSubband <= channelUp.drMax) {
|
||||||
|
drUp = drJoinSubband;
|
||||||
|
} else {
|
||||||
|
RADIOLIB_DEBUG_PRINTLN("Datarate %d is not valid (min: %d, max %d) - using default", drJoinSubband, channelUp.drMin, channelUp.drMax);
|
||||||
|
drJoinSubband = RADIOLIB_LORAWAN_DATA_RATE_UNUSED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(drJoinSubband == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) {
|
||||||
|
drUp = int((channelUp.drMax + channelUp.drMin) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// derive the downlink channel and datarate from the uplink channel and datarate
|
||||||
|
channelDown = channelUp;
|
||||||
|
drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase, channelDown.drMin, channelDown.drMax);
|
||||||
|
|
||||||
|
} else { // RADIOLIB_LORAWAN_BAND_FIXED
|
||||||
channelUp.enabled = true;
|
channelUp.enabled = true;
|
||||||
uint8_t numBlocks = this->band->txSpans[0].numChannels / 8; // calculate number of 8-channel blocks
|
uint8_t numBlocks = this->band->txSpans[0].numChannels / 8; // calculate number of 8-channel blocks
|
||||||
uint8_t numBlockChannels = 8 + this->band->txSpans[1].numChannels > 0 ? 1 : 0; // add a 9th channel if there's a second span
|
uint8_t numBlockChannels = 8 + (this->band->numTxSpans == 2 ? 1 : 0); // add a 9th channel if there's a second span
|
||||||
uint8_t blockID = devNonce % numBlocks; // currently selected block (seed with devNonce)
|
uint8_t blockID = devNonce % numBlocks; // currently selected block (seed with devNonce)
|
||||||
|
// if the user defined a specific subband, use that
|
||||||
|
if(drJoinSubband == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) {
|
||||||
|
blockID = (drJoinSubband - 1);
|
||||||
|
}
|
||||||
uint8_t channelID = this->phyLayer->random(numBlockChannels); // select randomly from these 8 or 9 channels
|
uint8_t channelID = this->phyLayer->random(numBlockChannels); // select randomly from these 8 or 9 channels
|
||||||
|
RADIOLIB_DEBUG_PRINTLN("blocks: %d, channels/block: %d, blockID: %d, channelID: %d", numBlocks, numBlockChannels, blockID, channelID);
|
||||||
|
|
||||||
|
// if channel 0-7 is selected, retrieve this channel from span 0; otherwise span 1
|
||||||
uint8_t spanID;
|
uint8_t spanID;
|
||||||
if(channelID < 8) {
|
if(channelID < 8) {
|
||||||
spanID = 0;
|
spanID = 0;
|
||||||
channelUp.idx = blockID * numBlockChannels + channelID;
|
channelUp.idx = blockID * 8 + channelID;
|
||||||
} else {
|
} else {
|
||||||
spanID = 1;
|
spanID = 1;
|
||||||
channelUp.idx = blockID;
|
channelUp.idx = blockID;
|
||||||
}
|
}
|
||||||
channelUp.freq = this->band->txSpans[spanID].freqStart + channelUp.idx*this->band->txSpans[spanID].freqStep;
|
channelUp.freq = this->band->txSpans[spanID].freqStart + channelUp.idx*this->band->txSpans[spanID].freqStep;
|
||||||
|
|
||||||
channelDn.idx = blockID % this->band->rx1Span.numChannels;
|
// for fixed channel plans, the user-specified datarate is ignored and span-specific value must be used
|
||||||
channelDn.freq = this->band->rx1Span.freqStart + channelDn.idx*this->band->rx1Span.freqStep;
|
drUp = this->band->txSpans[spanID].joinRequestDataRate;
|
||||||
|
|
||||||
|
// derive the downlink channel and datarate from the uplink channel and datarate
|
||||||
|
channelDown.enabled = true;
|
||||||
|
channelDown.idx = channelID % this->band->rx1Span.numChannels;
|
||||||
|
channelDown.freq = this->band->rx1Span.freqStart + channelDown.idx*this->band->rx1Span.freqStep;
|
||||||
|
channelDown.drMin = this->band->rx1Span.drMin;
|
||||||
|
channelDown.drMax = this->band->rx1Span.drMax;
|
||||||
|
drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase, channelDown.drMin, channelDown.drMax);
|
||||||
|
|
||||||
// configure data rates for TX and RX1: for TX the specified value for this band; for RX1 identical with base offset
|
|
||||||
this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = this->band->txSpans[spanID].joinRequestDataRate;
|
|
||||||
this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = getDownlinkDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK],
|
|
||||||
this->rx1DrOffset, this->band->rx1DataRateBase, channelDn.drMin, channelDn.drMax);
|
|
||||||
}
|
}
|
||||||
this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = channelUp;
|
this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = channelUp;
|
||||||
this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = channelDn;
|
this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = channelDown;
|
||||||
|
this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = drUp;
|
||||||
|
this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown;
|
||||||
|
|
||||||
return(RADIOLIB_ERR_NONE);
|
return(RADIOLIB_ERR_NONE);
|
||||||
}
|
}
|
||||||
|
@ -1418,14 +1494,20 @@ int16_t LoRaWANNode::selectChannels() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(numChannels == 0) {
|
||||||
|
RADIOLIB_DEBUG_PRINTLN("There are no channels defined - are you in ABP mode with no defined subband?");
|
||||||
|
return(RADIOLIB_ERR_INVALID_CHANNEL);
|
||||||
|
}
|
||||||
// select a random ID & channel from the list of enabled and possible channels
|
// select a random ID & channel from the list of enabled and possible channels
|
||||||
uint8_t channelID = channelsEnabled[this->phyLayer->random(numChannels)];
|
uint8_t channelID = channelsEnabled[this->phyLayer->random(numChannels)];
|
||||||
this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][channelID];
|
this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][channelID];
|
||||||
|
|
||||||
// in case of frequency list-type band, downlink is equal to uplink, otherwise retrieve `modulo` numChannels
|
if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) {
|
||||||
if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES) {
|
// for dynamic bands, the downlink channel is the one matched to the uplink channel
|
||||||
this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][channelID];
|
this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][channelID];
|
||||||
} else { // RADIOLIB_LORAWAN_CFLIST_TYPE_MASK
|
|
||||||
|
} else { // RADIOLIB_LORAWAN_BAND_FIXED
|
||||||
|
// for fixed bands, the downlink channel is the uplink channel ID `modulo` number of downlink channels
|
||||||
LoRaWANChannel_t channelDn;
|
LoRaWANChannel_t channelDn;
|
||||||
channelDn.enabled = true;
|
channelDn.enabled = true;
|
||||||
channelDn.idx = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx % this->band->rx1Span.numChannels;
|
channelDn.idx = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx % this->band->rx1Span.numChannels;
|
||||||
|
@ -1433,10 +1515,34 @@ int16_t LoRaWANNode::selectChannels() {
|
||||||
channelDn.drMin = this->band->rx1Span.drMin;
|
channelDn.drMin = this->band->rx1Span.drMin;
|
||||||
channelDn.drMax = this->band->rx1Span.drMax;
|
channelDn.drMax = this->band->rx1Span.drMax;
|
||||||
this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = channelDn;
|
this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = channelDn;
|
||||||
|
uint8_t drDown = getDownlinkDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], this->rx1DrOffset,
|
||||||
|
this->band->rx1DataRateBase, channelDn.drMin, channelDn.drMax);
|
||||||
|
this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown;
|
||||||
|
|
||||||
}
|
}
|
||||||
return(RADIOLIB_ERR_NONE);
|
return(RADIOLIB_ERR_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int16_t LoRaWANNode::setDatarate(uint8_t drUp) {
|
||||||
|
if(drUp < this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].drMin) {
|
||||||
|
return(RADIOLIB_ERR_DATA_RATE_INVALID);
|
||||||
|
}
|
||||||
|
if(drUp > this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].drMax) {
|
||||||
|
return(RADIOLIB_ERR_DATA_RATE_INVALID);
|
||||||
|
}
|
||||||
|
uint8_t drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase,
|
||||||
|
this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin, this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMax);
|
||||||
|
|
||||||
|
this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = drUp;
|
||||||
|
this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown;
|
||||||
|
|
||||||
|
return(RADIOLIB_ERR_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoRaWANNode::setADR(bool enable) {
|
||||||
|
this->adrEnabled = enable;
|
||||||
|
}
|
||||||
|
|
||||||
int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) {
|
int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) {
|
||||||
uint8_t dataRateBand = this->band->dataRates[dr];
|
uint8_t dataRateBand = this->band->dataRates[dr];
|
||||||
|
|
||||||
|
@ -1550,27 +1656,23 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) {
|
||||||
|
|
||||||
case(RADIOLIB_LORAWAN_MAC_CMD_LINK_ADR): {
|
case(RADIOLIB_LORAWAN_MAC_CMD_LINK_ADR): {
|
||||||
// get the ADR configuration
|
// get the ADR configuration
|
||||||
// TODO all these configuration should only be set if all ACKs are set, otherwise retain previous state
|
// TODO all these configuration should only be set if all ACKs are set, otherwise retain previous state (per spec)
|
||||||
uint8_t dr = (cmd->payload[0] & 0xF0) >> 4;
|
uint8_t drUp = (cmd->payload[0] & 0xF0) >> 4;
|
||||||
uint8_t txPower = cmd->payload[0] & 0x0F;
|
uint8_t txPower = cmd->payload[0] & 0x0F;
|
||||||
uint16_t chMask = LoRaWANNode::ntoh<uint16_t>(&cmd->payload[1]);
|
uint16_t chMask = LoRaWANNode::ntoh<uint16_t>(&cmd->payload[1]);
|
||||||
uint8_t chMaskCntl = (cmd->payload[3] & 0x70) >> 4;
|
uint8_t chMaskCntl = (cmd->payload[3] & 0x70) >> 4;
|
||||||
uint8_t nbTrans = cmd->payload[3] & 0x0F;
|
uint8_t nbTrans = cmd->payload[3] & 0x0F;
|
||||||
RADIOLIB_DEBUG_PRINTLN("ADR REQ: dataRate = %d, txPower = %d, chMask = 0x%02x, chMaskCntl = %02x, nbTrans = %d", dr, txPower, chMask, chMaskCntl, nbTrans);
|
RADIOLIB_DEBUG_PRINTLN("ADR REQ: dataRate = %d, txPower = %d, chMask = 0x%02x, chMaskCntl = %02x, nbTrans = %d", drUp, txPower, chMask, chMaskCntl, nbTrans);
|
||||||
|
|
||||||
// apply the configuration
|
// apply the configuration
|
||||||
uint8_t drAck = 0;
|
uint8_t drAck = 0;
|
||||||
if(dr == 0x0F) {
|
if(drUp == 0x0F) {
|
||||||
drAck = 1;
|
drAck = 1;
|
||||||
} else if (this->band->dataRates[dr] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) {
|
} else if (this->band->dataRates[drUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) {
|
||||||
this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = dr;
|
uint8_t drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase,
|
||||||
this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = dr + this->band->rx1DataRateBase - this->rx1DrOffset;
|
this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin, this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMax);
|
||||||
if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] < this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin) {
|
this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = drUp;
|
||||||
this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin;
|
this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown;
|
||||||
} else if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] > this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMax) {
|
|
||||||
this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
drAck = 1;
|
drAck = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1587,28 +1689,66 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) {
|
||||||
this->txPwrCur = pwr;
|
this->txPwrCur = pwr;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->nbTrans = nbTrans;
|
|
||||||
// TODO implement channel mask
|
|
||||||
uint8_t chMaskAck = 1;
|
uint8_t chMaskAck = 1;
|
||||||
(void)chMaskCntl;
|
if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) {
|
||||||
if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES) {
|
for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) {
|
||||||
for(uint8_t i = 0; i < 16; i++) {
|
if(chMaskCntl == 0) {
|
||||||
// check if this channel ID should be enabled
|
// if chMaskCntl == 0, apply the mask by looking at each channel bit
|
||||||
RADIOLIB_DEBUG_PRINTLN("ADR channel %d: %d --> %d", i, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, (chMask >> i) & 0x01);
|
RADIOLIB_DEBUG_PRINTLN("ADR channel %d: %d --> %d", i, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, (chMask >> i) & 0x01);
|
||||||
if(chMask & (1UL << i)) {
|
if(chMask & (1UL << i)) {
|
||||||
// if it should be enabled but is not currently defined, stop immediately
|
// if it should be enabled but is not currently defined, stop immediately
|
||||||
if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled == false) {
|
if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) {
|
||||||
chMaskAck = 0;
|
chMaskAck = 0;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true;
|
||||||
|
} else {
|
||||||
|
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = false;
|
||||||
}
|
}
|
||||||
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true;
|
|
||||||
} else {
|
|
||||||
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
|
} else if(chMaskCntl == 6) {
|
||||||
|
// if chMaskCntl == 6, enable all defined channels
|
||||||
|
if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) {
|
||||||
|
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else { // RADIOLIB_LORAWAN_BAND_FIXED
|
||||||
|
// delete any prior ADR responses from the uplink queue, but do not care about if none is present yet
|
||||||
|
(void)deleteMacCommand(RADIOLIB_LORAWAN_MAC_CMD_LINK_ADR, &this->commandsUp);
|
||||||
|
RADIOLIB_DEBUG_PRINTLN("mask[%d] = 0x%04x", chMaskCntl, chMask);
|
||||||
|
uint8_t chNum = chMaskCntl*16;
|
||||||
|
uint8_t chSpan = 0;
|
||||||
|
for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) {
|
||||||
|
// if we must roll over to next span, reset chNum and move to next channel span
|
||||||
|
if(chNum >= this->band->txSpans[chSpan].numChannels) {
|
||||||
|
chNum = 0;
|
||||||
|
chSpan++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(chMask & (1UL << i)) {
|
||||||
|
if(chSpan >= this->band->numTxSpans) {
|
||||||
|
RADIOLIB_DEBUG_PRINTLN("channel bitmask overrun!");
|
||||||
|
return(RADIOLIB_ERR_UNKNOWN);
|
||||||
|
}
|
||||||
|
LoRaWANChannel_t chnl;
|
||||||
|
chnl.enabled = true;
|
||||||
|
chnl.idx = chMaskCntl*16 + i;
|
||||||
|
chnl.freq = this->band->txSpans[chSpan].freqStart + chNum*this->band->txSpans[chSpan].freqStep;
|
||||||
|
chnl.drMin = this->band->txSpans[chSpan].drMin;
|
||||||
|
chnl.drMax = this->band->txSpans[chSpan].drMax;
|
||||||
|
availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = chnl;
|
||||||
|
// downlink channels are dynamically calculated on each uplink in selectChannels()
|
||||||
|
RADIOLIB_DEBUG_PRINTLN("Channel UL %d frequency = %f MHz", i, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq);
|
||||||
|
}
|
||||||
|
chNum++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// TODO should we actually save the channels because the masks may have changed stuff?
|
||||||
|
// this may wear the storage quickly on more mobile devices / changing RF environment
|
||||||
|
|
||||||
|
this->nbTrans = nbTrans;
|
||||||
|
|
||||||
// send the reply
|
// send the reply
|
||||||
cmd->len = 1;
|
cmd->len = 1;
|
||||||
|
@ -1679,8 +1819,8 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) {
|
||||||
// find first empty channel and configure this as the new channel
|
// find first empty channel and configure this as the new channel
|
||||||
if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx == 0) {
|
if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx == 0) {
|
||||||
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true;
|
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true;
|
||||||
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx = chIndex;
|
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx = chIndex;
|
||||||
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq = freq;
|
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq = freq;
|
||||||
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin = minDr;
|
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin = minDr;
|
||||||
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax = maxDr;
|
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax = maxDr;
|
||||||
|
|
||||||
|
|
|
@ -69,8 +69,8 @@
|
||||||
#define RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK (0x01 << 0)
|
#define RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK (0x01 << 0)
|
||||||
#define RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH (0x02 << 0)
|
#define RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH (0x02 << 0)
|
||||||
#define RADIOLIB_LORAWAN_CHANNEL_DIR_NONE (0x03 << 0)
|
#define RADIOLIB_LORAWAN_CHANNEL_DIR_NONE (0x03 << 0)
|
||||||
#define RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES (0)
|
#define RADIOLIB_LORAWAN_BAND_DYNAMIC (0)
|
||||||
#define RADIOLIB_LORAWAN_CFLIST_TYPE_MASK (1)
|
#define RADIOLIB_LORAWAN_BAND_FIXED (1)
|
||||||
#define RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES (15)
|
#define RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES (15)
|
||||||
#define RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE (0xFF < 0)
|
#define RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE (0xFF < 0)
|
||||||
|
|
||||||
|
@ -239,6 +239,9 @@ struct LoRaWANChannelSpan_t {
|
||||||
\brief Structure to save information about LoRaWAN band
|
\brief Structure to save information about LoRaWAN band
|
||||||
*/
|
*/
|
||||||
struct LoRaWANBand_t {
|
struct LoRaWANBand_t {
|
||||||
|
/*! \brief Whether the channels are fixed per specification, or dynamically allocated through the network (plus defaults) */
|
||||||
|
uint8_t bandType;
|
||||||
|
|
||||||
/*! \brief Array of allowed maximum payload lengths for each data rate */
|
/*! \brief Array of allowed maximum payload lengths for each data rate */
|
||||||
uint8_t payloadLenMax[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES];
|
uint8_t payloadLenMax[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES];
|
||||||
|
|
||||||
|
@ -248,9 +251,6 @@ struct LoRaWANBand_t {
|
||||||
/*! \brief Number of power steps in this band */
|
/*! \brief Number of power steps in this band */
|
||||||
int8_t powerNumSteps;
|
int8_t powerNumSteps;
|
||||||
|
|
||||||
/*! \brief Whether the optional channels are defined as list of frequencies or bit mask */
|
|
||||||
uint8_t cfListType;
|
|
||||||
|
|
||||||
/*! \brief A set of default uplink (TX) channels for frequency-type bands */
|
/*! \brief A set of default uplink (TX) channels for frequency-type bands */
|
||||||
LoRaWANChannel_t txFreqs[3];
|
LoRaWANChannel_t txFreqs[3];
|
||||||
|
|
||||||
|
@ -357,13 +357,6 @@ class LoRaWANNode {
|
||||||
\returns \ref status_codes
|
\returns \ref status_codes
|
||||||
*/
|
*/
|
||||||
int16_t restore();
|
int16_t restore();
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Restore frame counter for uplinks from persistent storage.
|
|
||||||
Note that the usable frame counter width is 'only' 30 bits for highly efficient wear-levelling.
|
|
||||||
\returns \ref status_codes
|
|
||||||
*/
|
|
||||||
int16_t restoreFcntUp();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -373,10 +366,12 @@ class LoRaWANNode {
|
||||||
\param devEUI 8-byte device identifier.
|
\param devEUI 8-byte device identifier.
|
||||||
\param nwkKey Pointer to the network AES-128 key.
|
\param nwkKey Pointer to the network AES-128 key.
|
||||||
\param appKey Pointer to the application AES-128 key.
|
\param appKey Pointer to the application AES-128 key.
|
||||||
|
\param drJoinSubband (OTAA:) The datarate at which to send the join-request; (ABP:) the subband at which to send the join-request
|
||||||
\param force Set to true to force joining even if previously joined.
|
\param force Set to true to force joining even if previously joined.
|
||||||
|
|
||||||
\returns \ref status_codes
|
\returns \ref status_codes
|
||||||
*/
|
*/
|
||||||
int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force = false);
|
int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, uint8_t joinDrSubband = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, bool force = false);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Join network by performing activation by personalization.
|
\brief Join network by performing activation by personalization.
|
||||||
|
@ -398,23 +393,15 @@ class LoRaWANNode {
|
||||||
*/
|
*/
|
||||||
int16_t saveSession();
|
int16_t saveSession();
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Save the current uplink frame counter.
|
|
||||||
Note that the usable frame counter width is 'only' 30 bits for highly efficient wear-levelling.
|
|
||||||
\returns \ref status_codes
|
|
||||||
*/
|
|
||||||
int16_t saveFcntUp();
|
|
||||||
|
|
||||||
#if defined(RADIOLIB_BUILD_ARDUINO)
|
#if defined(RADIOLIB_BUILD_ARDUINO)
|
||||||
/*!
|
/*!
|
||||||
\brief Send a message to the server.
|
\brief Send a message to the server.
|
||||||
\param str Address of Arduino String that will be transmitted.
|
\param str Address of Arduino String that will be transmitted.
|
||||||
\param port Port number to send the message to.
|
\param port Port number to send the message to.
|
||||||
\param isConfirmed Whether to send a confirmed uplink or not.
|
\param isConfirmed Whether to send a confirmed uplink or not.
|
||||||
\param adrEnabled Whether ADR is enabled or not.
|
|
||||||
\returns \ref status_codes
|
\returns \ref status_codes
|
||||||
*/
|
*/
|
||||||
int16_t uplink(String& str, uint8_t port, bool isConfirmed = false, bool adrEnabled = true);
|
int16_t uplink(String& str, uint8_t port, bool isConfirmed = false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -422,10 +409,9 @@ class LoRaWANNode {
|
||||||
\param str C-string that will be transmitted.
|
\param str C-string that will be transmitted.
|
||||||
\param port Port number to send the message to.
|
\param port Port number to send the message to.
|
||||||
\param isConfirmed Whether to send a confirmed uplink or not.
|
\param isConfirmed Whether to send a confirmed uplink or not.
|
||||||
\param adrEnabled Whether ADR is enabled or not.
|
|
||||||
\returns \ref status_codes
|
\returns \ref status_codes
|
||||||
*/
|
*/
|
||||||
int16_t uplink(const char* str, uint8_t port, bool isConfirmed = false, bool adrEnabled = true);
|
int16_t uplink(const char* str, uint8_t port, bool isConfirmed = false);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Send a message to the server.
|
\brief Send a message to the server.
|
||||||
|
@ -433,10 +419,9 @@ class LoRaWANNode {
|
||||||
\param len Length of the data.
|
\param len Length of the data.
|
||||||
\param port Port number to send the message to.
|
\param port Port number to send the message to.
|
||||||
\param isConfirmed Whether to send a confirmed uplink or not.
|
\param isConfirmed Whether to send a confirmed uplink or not.
|
||||||
\param adrEnabled Whether ADR is enabled or not.
|
|
||||||
\returns \ref status_codes
|
\returns \ref status_codes
|
||||||
*/
|
*/
|
||||||
int16_t uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed = false, bool adrEnabled = true);
|
int16_t uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed = false);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Wait for, open and listen during Rx1 and Rx2 windows; only performs listening
|
\brief Wait for, open and listen during Rx1 and Rx2 windows; only performs listening
|
||||||
|
@ -468,6 +453,34 @@ class LoRaWANNode {
|
||||||
*/
|
*/
|
||||||
void setDeviceStatus(uint8_t battLevel);
|
void setDeviceStatus(uint8_t battLevel);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set uplink datarate. This should _not_ be used when ADR is enabled.
|
||||||
|
\param dr Datarate to use for uplinks
|
||||||
|
\returns \ref status_codes
|
||||||
|
*/
|
||||||
|
int16_t setDatarate(uint8_t drUp);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Toggle ADR to on or off
|
||||||
|
\param enable Whether to disable ADR or not
|
||||||
|
*/
|
||||||
|
void setADR(bool enable = true);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Select a single subband (8 channels) for fixed bands such as US915
|
||||||
|
\param idx The subband to be used (starting from 1!)
|
||||||
|
\returns \ref status_codes
|
||||||
|
*/
|
||||||
|
int16_t selectSubband(uint8_t idx);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Select a set of channels for fixed bands such as US915
|
||||||
|
\param startChannel The first channel of the band to be used (inclusive)
|
||||||
|
\param endChannel The last channel of the band to be used (exclusive)
|
||||||
|
\returns \ref status_codes
|
||||||
|
*/
|
||||||
|
int16_t selectSubband(uint8_t startChannel, uint8_t endChannel);
|
||||||
|
|
||||||
#if !defined(RADIOLIB_GODMODE)
|
#if !defined(RADIOLIB_GODMODE)
|
||||||
private:
|
private:
|
||||||
#endif
|
#endif
|
||||||
|
@ -511,6 +524,9 @@ class LoRaWANNode {
|
||||||
uint32_t confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE;
|
uint32_t confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE;
|
||||||
uint32_t adrFcnt = 0;
|
uint32_t adrFcnt = 0;
|
||||||
|
|
||||||
|
// ADR is enabled by default
|
||||||
|
bool adrEnabled = true;
|
||||||
|
|
||||||
// available channel frequencies from list passed during OTA activation
|
// available channel frequencies from list passed during OTA activation
|
||||||
LoRaWANChannel_t availableChannels[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS] = { { 0 }, { 0 } };
|
LoRaWANChannel_t availableChannels[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS] = { { 0 }, { 0 } };
|
||||||
|
|
||||||
|
@ -535,6 +551,22 @@ class LoRaWANNode {
|
||||||
// indicates whether an uplink has MAC commands as payload
|
// indicates whether an uplink has MAC commands as payload
|
||||||
bool isMACPayload = false;
|
bool isMACPayload = false;
|
||||||
|
|
||||||
|
#if !defined(RADIOLIB_EEPROM_UNSUPPORTED)
|
||||||
|
/*!
|
||||||
|
\brief Save the current uplink frame counter.
|
||||||
|
Note that the usable frame counter width is 'only' 30 bits for highly efficient wear-levelling.
|
||||||
|
\returns \ref status_codes
|
||||||
|
*/
|
||||||
|
int16_t saveFcntUp();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Restore frame counter for uplinks from persistent storage.
|
||||||
|
Note that the usable frame counter width is 'only' 30 bits for highly efficient wear-levelling.
|
||||||
|
\returns \ref status_codes
|
||||||
|
*/
|
||||||
|
int16_t restoreFcntUp();
|
||||||
|
#endif
|
||||||
|
|
||||||
// method to generate message integrity code
|
// method to generate message integrity code
|
||||||
uint32_t generateMIC(uint8_t* msg, size_t len, uint8_t* key);
|
uint32_t generateMIC(uint8_t* msg, size_t len, uint8_t* key);
|
||||||
|
|
||||||
|
@ -551,7 +583,7 @@ class LoRaWANNode {
|
||||||
int16_t setupChannels(uint8_t* cfList);
|
int16_t setupChannels(uint8_t* cfList);
|
||||||
|
|
||||||
// select a set of semi-random TX/RX channels for the join-request and -accept message
|
// select a set of semi-random TX/RX channels for the join-request and -accept message
|
||||||
int16_t selectChannelsJR(uint16_t devNonce);
|
int16_t selectChannelsJR(uint16_t devNonce, uint8_t drJoinSubband);
|
||||||
|
|
||||||
// select a set of random TX/RX channels for up- and downlink
|
// select a set of random TX/RX channels for up- and downlink
|
||||||
int16_t selectChannels();
|
int16_t selectChannels();
|
||||||
|
|
|
@ -13,10 +13,10 @@ uint8_t getDownlinkDataRate(uint8_t uplink, uint8_t offset, uint8_t base, uint8_
|
||||||
}
|
}
|
||||||
|
|
||||||
const LoRaWANBand_t EU868 = {
|
const LoRaWANBand_t EU868 = {
|
||||||
|
.bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC,
|
||||||
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 },
|
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
.powerMax = 16,
|
.powerMax = 16,
|
||||||
.powerNumSteps = 7,
|
.powerNumSteps = 7,
|
||||||
.cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES,
|
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
{ .enabled = true, .idx = 0, .freq = 868.100, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 0, .freq = 868.100, .drMin = 0, .drMax = 5},
|
||||||
{ .enabled = true, .idx = 1, .freq = 868.300, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 1, .freq = 868.300, .drMin = 0, .drMax = 5},
|
||||||
|
@ -55,10 +55,10 @@ const LoRaWANBand_t EU868 = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const LoRaWANBand_t US915 = {
|
const LoRaWANBand_t US915 = {
|
||||||
|
.bandType = RADIOLIB_LORAWAN_BAND_FIXED,
|
||||||
.payloadLenMax = { 19, 61, 133, 250, 250, 0, 0, 0, 41, 117, 230, 230, 230, 230, 0 },
|
.payloadLenMax = { 19, 61, 133, 250, 250, 0, 0, 0, 41, 117, 230, 230, 230, 230, 0 },
|
||||||
.powerMax = 30,
|
.powerMax = 30,
|
||||||
.powerNumSteps = 10,
|
.powerNumSteps = 10,
|
||||||
.cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_MASK,
|
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
||||||
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
||||||
|
@ -118,10 +118,10 @@ const LoRaWANBand_t US915 = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const LoRaWANBand_t CN780 = {
|
const LoRaWANBand_t CN780 = {
|
||||||
|
.bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC,
|
||||||
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 250, 230, 0, 0, 0, 0, 0, 0, 0 },
|
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 250, 230, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
.powerMax = 12,
|
.powerMax = 12,
|
||||||
.powerNumSteps = 5,
|
.powerNumSteps = 5,
|
||||||
.cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES,
|
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
{ .enabled = true, .idx = 0, .freq = 779.500, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 0, .freq = 779.500, .drMin = 0, .drMax = 5},
|
||||||
{ .enabled = true, .idx = 1, .freq = 779.700, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 1, .freq = 779.700, .drMin = 0, .drMax = 5},
|
||||||
|
@ -160,10 +160,10 @@ const LoRaWANBand_t CN780 = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const LoRaWANBand_t EU433 = {
|
const LoRaWANBand_t EU433 = {
|
||||||
|
.bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC,
|
||||||
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 },
|
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
.powerMax = 12,
|
.powerMax = 12,
|
||||||
.powerNumSteps = 5,
|
.powerNumSteps = 5,
|
||||||
.cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES,
|
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
{ .enabled = true, .idx = 0, .freq = 433.175, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 0, .freq = 433.175, .drMin = 0, .drMax = 5},
|
||||||
{ .enabled = true, .idx = 1, .freq = 433.375, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 1, .freq = 433.375, .drMin = 0, .drMax = 5},
|
||||||
|
@ -202,10 +202,10 @@ const LoRaWANBand_t EU433 = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const LoRaWANBand_t AU915 = {
|
const LoRaWANBand_t AU915 = {
|
||||||
|
.bandType = RADIOLIB_LORAWAN_BAND_FIXED,
|
||||||
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 0, 41, 117, 230, 230, 230, 230, 0 },
|
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 0, 41, 117, 230, 230, 230, 230, 0 },
|
||||||
.powerMax = 30,
|
.powerMax = 30,
|
||||||
.powerNumSteps = 10,
|
.powerNumSteps = 10,
|
||||||
.cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_MASK,
|
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
||||||
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
||||||
|
@ -265,10 +265,10 @@ const LoRaWANBand_t AU915 = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const LoRaWANBand_t CN500 = {
|
const LoRaWANBand_t CN500 = {
|
||||||
|
.bandType = RADIOLIB_LORAWAN_BAND_FIXED,
|
||||||
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
.powerMax = 19,
|
.powerMax = 19,
|
||||||
.powerNumSteps = 7,
|
.powerNumSteps = 7,
|
||||||
.cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_MASK,
|
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
||||||
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
||||||
|
@ -321,10 +321,10 @@ const LoRaWANBand_t CN500 = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const LoRaWANBand_t AS923 = {
|
const LoRaWANBand_t AS923 = {
|
||||||
|
.bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC,
|
||||||
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 },
|
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
.powerMax = 16,
|
.powerMax = 16,
|
||||||
.powerNumSteps = 7,
|
.powerNumSteps = 7,
|
||||||
.cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES,
|
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
{ .enabled = true, .idx = 0, .freq = 923.200, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 0, .freq = 923.200, .drMin = 0, .drMax = 5},
|
||||||
{ .enabled = true, .idx = 1, .freq = 923.400, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 1, .freq = 923.400, .drMin = 0, .drMax = 5},
|
||||||
|
@ -363,10 +363,10 @@ const LoRaWANBand_t AS923 = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const LoRaWANBand_t KR920 = {
|
const LoRaWANBand_t KR920 = {
|
||||||
|
.bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC,
|
||||||
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
.powerMax = 14,
|
.powerMax = 14,
|
||||||
.powerNumSteps = 7,
|
.powerNumSteps = 7,
|
||||||
.cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES,
|
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
{ .enabled = true, .idx = 0, .freq = 922.100, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 0, .freq = 922.100, .drMin = 0, .drMax = 5},
|
||||||
{ .enabled = true, .idx = 1, .freq = 922.300, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 1, .freq = 922.300, .drMin = 0, .drMax = 5},
|
||||||
|
@ -405,10 +405,10 @@ const LoRaWANBand_t KR920 = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const LoRaWANBand_t IN865 = {
|
const LoRaWANBand_t IN865 = {
|
||||||
|
.bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC,
|
||||||
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 },
|
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
.powerMax = 30,
|
.powerMax = 30,
|
||||||
.powerNumSteps = 10,
|
.powerNumSteps = 10,
|
||||||
.cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES,
|
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
{ .enabled = true, .idx = 0, .freq = 865.0625, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 0, .freq = 865.0625, .drMin = 0, .drMax = 5},
|
||||||
{ .enabled = true, .idx = 1, .freq = 865.4025, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 1, .freq = 865.4025, .drMin = 0, .drMax = 5},
|
||||||
|
|
|
@ -306,6 +306,10 @@ int16_t PhysicalLayer::irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask)
|
||||||
return(RADIOLIB_ERR_UNSUPPORTED);
|
return(RADIOLIB_ERR_UNSUPPORTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PhysicalLayer::isRxTimeout() {
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
int16_t PhysicalLayer::startChannelScan() {
|
int16_t PhysicalLayer::startChannelScan() {
|
||||||
return(RADIOLIB_ERR_UNSUPPORTED);
|
return(RADIOLIB_ERR_UNSUPPORTED);
|
||||||
}
|
}
|
||||||
|
|
|
@ -326,6 +326,12 @@ class PhysicalLayer {
|
||||||
*/
|
*/
|
||||||
virtual int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask);
|
virtual int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Check whether the IRQ bit for RxTimeout is set
|
||||||
|
\returns \ref RxTimeout IRQ is set
|
||||||
|
*/
|
||||||
|
virtual bool isRxTimeout();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Interrupt-driven channel activity detection method. interrupt will be activated
|
\brief Interrupt-driven channel activity detection method. interrupt will be activated
|
||||||
when packet is detected. Must be implemented in module class.
|
when packet is detected. Must be implemented in module class.
|
||||||
|
|
Loading…
Add table
Reference in a new issue