[LoRaWAN] Verification cleanup

This commit is contained in:
StevenCellist 2024-09-16 00:39:12 +02:00
parent d371b50c5a
commit 740ee7e235
2 changed files with 74 additions and 40 deletions

View file

@ -1009,6 +1009,9 @@ void LoRaWANNode::processCFList(uint8_t* cfList) {
num++; num++;
} }
cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL;
(void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK);
uint8_t freqZero[3] = { 0 }; uint8_t freqZero[3] = { 0 };
// datarate range for all new channels is equal to the default channels // datarate range for all new channels is equal to the default channels
@ -1018,8 +1021,6 @@ void LoRaWANNode::processCFList(uint8_t* cfList) {
if(memcmp(&cfList[i*3], freqZero, 3) == 0) { if(memcmp(&cfList[i*3], freqZero, 3) == 0) {
break; break;
} }
cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL;
(void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK);
cOcts[0] = num; cOcts[0] = num;
memcpy(&cOcts[1], &cfList[i*3], 3); memcpy(&cOcts[1], &cfList[i*3], 3);
(void)execMacCommand(cid, cOcts, cLen); (void)execMacCommand(cid, cOcts, cLen);
@ -1099,22 +1100,20 @@ void LoRaWANNode::adrBackoff() {
// check if we need to do ADR stuff // check if we need to do ADR stuff
uint32_t adrLimit = 0x01 << this->adrLimitExp; uint32_t adrLimit = 0x01 << this->adrLimitExp;
uint32_t adrDelay = 0x01 << this->adrDelayExp; uint32_t adrDelay = 0x01 << this->adrDelayExp;
if((this->fCntUp - this->adrFCnt) >= adrLimit) {
this->adrAckReq = true; // don't need to do any backoff for first Limit+Delay uplinks
} else { if((this->fCntUp - this->adrFCnt) < (adrLimit + adrDelay)) {
this->adrAckReq = false; return;
} }
if ((this->fCntUp - this->adrFCnt) < (adrLimit + adrDelay)) { // only perform backoff every Delay uplinks
if((this->fCntUp - this->adrFCnt - adrLimit) % adrDelay != 0) {
return; return;
} }
// if we hit the Limit + Delay, try one of three, in order: // if we hit the Limit + Delay, try one of three, in order:
// set TxPower to max, set DR to min, enable all default channels // set TxPower to max, set DR to min, enable all default channels
// as we try to do something to improve the range, increase the ADR frame counter by 'ADR delay'
this->adrFCnt += adrDelay;
// if the TxPower field has some offset, remove it and switch to maximum power // if the TxPower field has some offset, remove it and switch to maximum power
if(this->txPowerSteps > 0) { if(this->txPowerSteps > 0) {
// set the maximum power supported by both the module and the band // set the maximum power supported by both the module and the band
@ -1136,7 +1135,11 @@ void LoRaWANNode::adrBackoff() {
this->selectChannelPlanFix(); // go back to default selected subband this->selectChannelPlanFix(); // go back to default selected subband
} }
this->nbTrans = 1; this->nbTrans = 1;
return; // nothing else to do
// as there is nothing more to do, set ADR counter to maximum value to indicate that we've tried everything
this->adrFCnt = RADIOLIB_LORAWAN_FCNT_NONE;
return;
} }
void LoRaWANNode::composeUplink(uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_t fPort, bool isConfirmed) { void LoRaWANNode::composeUplink(uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_t fPort, bool isConfirmed) {
@ -1153,7 +1156,11 @@ void LoRaWANNode::composeUplink(uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_
out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] = 0x00; out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] = 0x00;
if(this->adrEnabled) { if(this->adrEnabled) {
out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ENABLED; out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ENABLED;
if(adrAckReq) {
// AdrAckReq is set if no downlink has been received for >=Limit uplinks
// but it is unset once backoff has been completed (which is internally denoted by adrFCnt == FCNT_NONE)
uint32_t adrLimit = 0x01 << this->adrLimitExp;
if(this->adrFCnt != RADIOLIB_LORAWAN_FCNT_NONE && (this->fCntUp - this->adrFCnt) >= adrLimit) {
out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ; out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ;
} }
} }
@ -1378,7 +1385,7 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne
if(this->TS011) { if(this->TS011) {
maxPayLen = RADIOLIB_MIN(maxPayLen, 230); // payload length is limited to 230 if under repeater maxPayLen = RADIOLIB_MIN(maxPayLen, 230); // payload length is limited to 230 if under repeater
} }
RadioLibTime_t tMax = this->phyLayer->getTimeOnAir(maxPayLen); RadioLibTime_t tMax = this->phyLayer->getTimeOnAir(maxPayLen + 13); // mandatory FHDR is 12/13 bytes
bool downlinkComplete = true; bool downlinkComplete = true;
// wait for the DIO to fire indicating a downlink is received // wait for the DIO to fire indicating a downlink is received
@ -1401,11 +1408,11 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne
this->phyLayer->clearPacketReceivedAction(); this->phyLayer->clearPacketReceivedAction();
this->phyLayer->standby(); this->phyLayer->standby();
// if all windows passed without receiving anything, return 0 // if all windows passed without receiving anything, set return value to 0
if(!downlinkComplete) { if(!downlinkComplete) {
state = 0; state = 0;
// if we received something during a window, return the window number // if we received something during a window, set return value to the window number
} else { } else {
state = window; state = window;
} }
@ -1413,7 +1420,7 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne
// Any frame received by an end-device containing a MACPayload greater than // Any frame received by an end-device containing a MACPayload greater than
// the specified maximum length M over the data rate used to receive the frame // the specified maximum length M over the data rate used to receive the frame
// SHALL be silently discarded. // SHALL be silently discarded.
if(this->phyLayer->getPacketLength() > maxPayLen) { if(this->phyLayer->getPacketLength() > maxPayLen + 13) { // mandatory FHDR is 12/13 bytes
return(0); // act as if no downlink was received return(0); // act as if no downlink was received
} }
@ -1530,6 +1537,15 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e
} }
// MAC commands SHALL NOT be present in the payload field and the frame options field simultaneously.
// Should this occur, the end-device SHALL silently discard the frame.
if(fOptsPbLen > 0 && payLen > 0 && fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) {
#if !RADIOLIB_STATIC_ONLY
delete[] downlinkMsg;
#endif
return(RADIOLIB_ERR_INVALID_PORT);
}
// get the frame counter // get the frame counter
uint16_t fCnt16 = LoRaWANNode::ntoh<uint16_t>(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); uint16_t fCnt16 = LoRaWANNode::ntoh<uint16_t>(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]);
@ -1917,9 +1933,19 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin
this->txPowerSteps = macTxSteps; this->txPowerSteps = macTxSteps;
if(lenIn > 1) { if(lenIn > 1) {
uint8_t macNbTrans = optIn[13] & 0x0F; uint8_t macNbTrans = optIn[13] & 0x0F;
if(macNbTrans) { // if there is a value for NbTrans, set this value
// if there is a value for NbTrans > 0, apply it
if(macNbTrans) {
this->nbTrans = macNbTrans; this->nbTrans = macNbTrans;
} else {
// for LoRaWAN v1.0.4, if NbTrans == 0, the end-device SHALL use the default value (being 1)
if(this->rev == 0) {
this->nbTrans = 1;
} }
// for LoRaWAN v1.1, if NbTrans == 0, the end-device SHALL keep the current NbTrans value unchanged
// so, don't do anything
}
} }
// restore original active channels // restore original active channels
@ -2022,14 +2048,22 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin
uint8_t macDrMax = (optIn[4] & 0xF0) >> 4; uint8_t macDrMax = (optIn[4] & 0xF0) >> 4;
uint8_t macDrMin = optIn[4] & 0x0F; uint8_t macDrMin = optIn[4] & 0x0F;
uint8_t newChAck = 0; uint8_t drAck = 0;
uint8_t freqAck = 0; uint8_t freqAck = 0;
// on LoRaWAN v1.1, the default channels may be modified - not on v1.0.x. // the default channels shall not be modified, so check if this is a default channel
// in that case, only allow non-default channels to be modified // if the channel index is set, this channel is defined, so return a NACK
// there are at most three default channels, so either check for >2 or else if index is used if(macChIndex < 3 && this->band->txFreqs[macChIndex].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) {
if(this->rev == 1 || macChIndex > 2 || this->band->txFreqs[macChIndex].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { optOut[0] = 0;
newChAck = 1; return(true);
}
// check if the outermost datarates are defined and if the device supports them
DataRate_t dr;
if(this->band->dataRates[macDrMin] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED && this->findDataRate(macDrMin, &dr) == RADIOLIB_ERR_NONE) {
if(this->band->dataRates[macDrMax] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED && this->findDataRate(macDrMax, &dr) == RADIOLIB_ERR_NONE) {
drAck = 1;
}
} }
// check if the frequency is allowed and possible // check if the frequency is allowed and possible
@ -2043,7 +2077,7 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin
} }
// set ACK bits // set ACK bits
optOut[0] = (newChAck << 1) | (freqAck << 0); optOut[0] = (drAck << 1) | (freqAck << 0);
// if not fully acknowledged, return now without applying the requested configuration // if not fully acknowledged, return now without applying the requested configuration
if(optOut[0] != 0x03) { if(optOut[0] != 0x03) {
@ -3169,36 +3203,37 @@ uint8_t LoRaWANNode::getMaxPayloadLen() {
RADIOLIB_LORAWAN_UPLINK, RADIOLIB_LORAWAN_UPLINK,
this->txPowerMax - 2*this->txPowerSteps); this->txPowerMax - 2*this->txPowerSteps);
uint8_t minPayLen = 0; // mandatory FHDR is 12/13, so add & subtract 13 from calculations where necessary
uint8_t maxPayLen = this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr]; uint8_t minLen = 0;
uint8_t maxLen = this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr] + 13;
if(this->TS011) { if(this->TS011) {
maxPayLen = RADIOLIB_MIN(maxPayLen, 230); // payload length is limited to 230 if under repeater maxLen = RADIOLIB_MIN(maxLen, 230 + 13); // payload length is limited to 230 if under repeater
} }
// if not limited by dwell-time, just return maximum // if not limited by dwell-time, just return maximum
if(!this->dwellTimeEnabledUp) { if(!this->dwellTimeEnabledUp) {
// subtract FHDR (13 bytes) as well as any FOpts // subtract FHDR (13 bytes) as well as any FOpts
return(maxPayLen - 13 - this->fOptsUpLen); return(maxLen - 13 - this->fOptsUpLen);
} }
// fast exit in case upper limit is already good // fast exit in case upper limit is already good
if(this->phyLayer->getTimeOnAir(maxPayLen) / 1000 <= this->dwellTimeUp) { if(this->phyLayer->getTimeOnAir(maxLen) / 1000 <= this->dwellTimeUp) {
// subtract FHDR (13 bytes) as well as any FOpts // subtract FHDR (13 bytes) as well as any FOpts
return(maxPayLen - 13 - this->fOptsUpLen); return(maxLen - 13 - this->fOptsUpLen);
} }
// do some binary search to find maximum allowed payload length // do some binary search to find maximum allowed length
uint8_t payLen = (minPayLen + maxPayLen) / 2; uint8_t curLen = (minLen + maxLen) / 2;
while(payLen != minPayLen && payLen != maxPayLen) { while(curLen != minLen && curLen != maxLen) {
if(this->phyLayer->getTimeOnAir(payLen) / 1000 > this->dwellTimeUp) { if(this->phyLayer->getTimeOnAir(curLen) / 1000 > this->dwellTimeUp) {
maxPayLen = payLen; maxLen = curLen;
} else { } else {
minPayLen = payLen; minLen = curLen;
} }
payLen = (minPayLen + maxPayLen) / 2; curLen = (minLen + maxLen) / 2;
} }
// subtract FHDR (13 bytes) as well as any FOpts // subtract FHDR (13 bytes) as well as any FOpts
return(payLen - 13 - this->fOptsUpLen); return(curLen - 13 - this->fOptsUpLen);
} }
int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) {
@ -3234,7 +3269,7 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) {
break; break;
case(RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS): case(RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS):
// not yet supported by DataRate_t // not yet supported by DataRate_t
break; return(RADIOLIB_ERR_UNSUPPORTED);
default: default:
return(RADIOLIB_ERR_UNSUPPORTED); return(RADIOLIB_ERR_UNSUPPORTED);
} }

View file

@ -918,7 +918,6 @@ class LoRaWANNode {
// ADR is enabled by default // ADR is enabled by default
bool adrEnabled = true; bool adrEnabled = true;
bool adrAckReq = false;
// duty cycle is set upon initialization and activated in regions that impose this // duty cycle is set upon initialization and activated in regions that impose this
bool dutyCycleEnabled = false; bool dutyCycleEnabled = false;