[LoRaWAN] Improve channel masks for fixed bands

This commit is contained in:
StevenCellist 2024-01-22 11:40:57 +01:00
parent 598228fba0
commit 6979bff863

View file

@ -111,8 +111,12 @@ int16_t LoRaWANNode::restore() {
.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn,
.repeat = 0, .repeat = 0,
}; };
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), cmd.payload, cmd.len);
execMacCommand(&cmd, false); // only apply the single ADR command on dynamic bands; fixed bands is done through channel restore
if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) {
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), cmd.payload, cmd.len);
execMacCommand(&cmd, false);
}
cmd.cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE; cmd.cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE;
cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn;
@ -207,7 +211,7 @@ int16_t LoRaWANNode::restoreFcntUp() {
} }
int16_t LoRaWANNode::restoreChannels() { int16_t LoRaWANNode::restoreChannels() {
// first do the default channels // first do the default channels, in case these are not covered by restored channels
if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) {
this->setupChannelsDyn(false); this->setupChannelsDyn(false);
} else { // RADIOLIB_LORAWAN_BAND_FIXED } else { // RADIOLIB_LORAWAN_BAND_FIXED
@ -226,6 +230,7 @@ int16_t LoRaWANNode::restoreChannels() {
cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn;
memcpy(cmd.payload, &(bufferUp[i * cmd.len]), cmd.len); memcpy(cmd.payload, &(bufferUp[i * cmd.len]), cmd.len);
if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes
cmd.repeat = 1;
(void)execMacCommand(&cmd, false); (void)execMacCommand(&cmd, false);
} }
} }
@ -262,6 +267,7 @@ int16_t LoRaWANNode::restoreChannels() {
memcpy(cmd.payload, &buffer[i * cmd.len], cmd.len); memcpy(cmd.payload, &buffer[i * cmd.len], cmd.len);
// there COULD, according to spec, be an all zeroes ADR command - meh // there COULD, according to spec, be an all zeroes ADR command - meh
if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) {
cmd.repeat = (i+1);
execMacCommand(&cmd, false); execMacCommand(&cmd, false);
} }
} }
@ -1436,19 +1442,36 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event)
RADIOLIB_DEBUG_PRINTLN("fopts:"); RADIOLIB_DEBUG_PRINTLN("fopts:");
RADIOLIB_DEBUG_HEXDUMP(fopts, foptsLen); RADIOLIB_DEBUG_HEXDUMP(fopts, foptsLen);
bool hasADR = false;
uint8_t numADR = 0;
uint8_t lastCID = 0;
// process the MAC command(s) // process the MAC command(s)
int8_t remLen = foptsLen; int8_t remLen = foptsLen;
uint8_t* foptsPtr = fopts; uint8_t* foptsPtr = fopts;
while(remLen > 0) { while(remLen > 0) {
uint8_t cid = *foptsPtr; uint8_t cid = *foptsPtr;
uint8_t macLen = getMacPayloadLength(cid); uint8_t macLen = getMacPayloadLength(cid);
if(cid == RADIOLIB_LORAWAN_MAC_LINK_ADR) {
// if there was an earlier ADR command but it was not the last, ignore it
if(hasADR && lastCID != RADIOLIB_LORAWAN_MAC_LINK_ADR) {
RADIOLIB_DEBUG_PRINTLN("Encountered non-consecutive block of ADR commands - skipping");
remLen -= (macLen + 1);
foptsPtr += (macLen + 1);
lastCID = cid;
continue;
}
// otherwise, set ADR flag to true and increase counter
hasADR = true;
numADR++;
}
if(macLen + 1 > remLen) if(macLen + 1 > remLen)
break; break;
LoRaWANMacCommand_t cmd = { LoRaWANMacCommand_t cmd = {
.cid = cid, .cid = cid,
.payload = { 0 }, .payload = { 0 },
.len = macLen, .len = macLen,
.repeat = 0, .repeat = (cid == RADIOLIB_LORAWAN_MAC_LINK_ADR ? numADR : (uint8_t)0),
}; };
memcpy(cmd.payload, foptsPtr + 1, macLen); memcpy(cmd.payload, foptsPtr + 1, macLen);
RADIOLIB_DEBUG_PRINTLN("[%02X]: %02X %02X %02X %02X %02X (%d)", RADIOLIB_DEBUG_PRINTLN("[%02X]: %02X %02X %02X %02X %02X (%d)",
@ -1463,6 +1486,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event)
// processing succeeded, move in the buffer to the next command // processing succeeded, move in the buffer to the next command
remLen -= (macLen + 1); remLen -= (macLen + 1);
foptsPtr += (macLen + 1); foptsPtr += (macLen + 1);
lastCID = cid;
RADIOLIB_DEBUG_PRINTLN("Processed: %d, remaining: %d", (macLen + 1), remLen); RADIOLIB_DEBUG_PRINTLN("Processed: %d, remaining: %d", (macLen + 1), remLen);
} }
@ -1736,6 +1760,8 @@ int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) {
// chMask is set for 16 channels at once, so widen the Cntl value // chMask is set for 16 channels at once, so widen the Cntl value
uint8_t chMaskCntl = (subBand - 1) / 2; // compensate the 1 offset uint8_t chMaskCntl = (subBand - 1) / 2; // compensate the 1 offset
uint8_t numADR = 1;
LoRaWANMacCommand_t cmd = { LoRaWANMacCommand_t cmd = {
.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR,
.payload = { 0 }, .payload = { 0 },
@ -1752,6 +1778,7 @@ int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) {
cmd.payload[2] = 0; cmd.payload[2] = 0;
cmd.payload[3] = (7 << 4); // set the chMaskCntl value to all channels off cmd.payload[3] = (7 << 4); // set the chMaskCntl value to all channels off
cmd.payload[3] |= 0; // keep NbTrans the same cmd.payload[3] |= 0; // keep NbTrans the same
cmd.repeat = numADR++;
(void)execMacCommand(&cmd, false); (void)execMacCommand(&cmd, false);
} }
@ -1770,6 +1797,7 @@ int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) {
} }
cmd.payload[3] = (chMaskCntl << 4); // set the chMaskCntl value cmd.payload[3] = (chMaskCntl << 4); // set the chMaskCntl value
cmd.payload[3] |= 0; // keep NbTrans the same cmd.payload[3] |= 0; // keep NbTrans the same
cmd.repeat = numADR++;
(void)execMacCommand(&cmd, false); (void)execMacCommand(&cmd, false);
return(RADIOLIB_ERR_NONE); return(RADIOLIB_ERR_NONE);
@ -2204,7 +2232,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) {
} }
} }
bool isSuccessive = false;
uint8_t chMaskAck = 1; uint8_t chMaskAck = 1;
// only apply channel mask when the RFU bit is not set // only apply channel mask when the RFU bit is not set
// (which is set on the internal MAC command when creating new session) // (which is set on the internal MAC command when creating new session)
@ -2213,13 +2241,17 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) {
chMaskAck = (uint8_t)this->applyChannelMaskDyn(chMaskCntl, chMask); chMaskAck = (uint8_t)this->applyChannelMaskDyn(chMaskCntl, chMask);
} else { // RADIOLIB_LORAWAN_BAND_FIXED } else { // RADIOLIB_LORAWAN_BAND_FIXED
// if there was already an ADR response in the uplink MAC queue, bool clearChannels = false;
// this is a consecutive ADR command, so we delete the prior response if(cmd->repeat == 1) {
int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_ADR, &this->commandsUp); // if this is the first ADR command in the queue, clear all saved channels
if(state == RADIOLIB_ERR_NONE) { // so we can apply the new channel mask
isSuccessive = true; clearChannels = true;
} else {
// if this is not the first ADR command, clear the ADR response that was in the queue
(void)deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_ADR, &this->commandsUp);
} }
chMaskAck = (uint8_t)this->applyChannelMaskFix(chMaskCntl, chMask, !isSuccessive); RADIOLIB_DEBUG_PRINTLN("ADR mask: clearing channels");
chMaskAck = (uint8_t)this->applyChannelMaskFix(chMaskCntl, chMask, clearChannels);
} }
} }
@ -2242,32 +2274,28 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) {
// save to the single ADR MAC location // save to the single ADR MAC location
mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), &(cmd->payload[0]), payLen); mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), &(cmd->payload[0]), payLen);
} else { } else { // RADIOLIB_LORAWAN_BAND_FIXED
// read how many ADR masks are already stored RADIOLIB_DEBUG_PRINTLN("[1] Repeat: %d, RFU: %d, payload: %02X %02X %02X %02X",
uint8_t numMacADR = mod->hal->getPersistentParameter<uint8_t>(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID); cmd->repeat, (cmd->payload[3] >> 7),
RADIOLIB_DEBUG_PRINTLN("[1] Successive: %d, numMacADR: %d, RFU: %d, payload: %02X %02X %02X %02X",
isSuccessive, numMacADR, (cmd->payload[3] >> 7),
cmd->payload[0], cmd->payload[1], cmd->payload[2], cmd->payload[3]); cmd->payload[0], cmd->payload[1], cmd->payload[2], cmd->payload[3]);
// if RFU bit is set, this is just a change in Datarate or TxPower // if RFU bit is set, this is just a change in Datarate or TxPower
// so read bytes 1..3 from last stored ADR command into the current MAC payload and re-store it // so read bytes 1..3 from last stored ADR command into the current MAC payload and re-store it
if((cmd->payload[3] >> 7) == 1) { if((cmd->payload[3] >> 7) == 1) {
// read how many ADR masks are already stored
uint8_t numMacADR = mod->hal->getPersistentParameter<uint8_t>(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID);
if(numMacADR > 0) { if(numMacADR > 0) {
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + (numMacADR - 1) * payLen + 1, &(cmd->payload[1]), 3); mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + (numMacADR - 1) * payLen + 1, &(cmd->payload[1]), 3);
mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + (numMacADR - 1) * payLen, &(cmd->payload[0]), payLen); mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + (numMacADR - 1) * payLen, &(cmd->payload[0]), payLen);
} }
} else { } else {
// if no previous mask was processed, reset counter to 0 // save to the uplink channel location, to the cmd->repeat-th slot of 4 bytes
if(!isSuccessive) { mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + (cmd->repeat - 1) * payLen, &(cmd->payload[0]), payLen);
numMacADR = 0; // saved an ADR mask, so re-store counter
} mod->hal->setPersistentParameter<uint8_t>(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID, cmd->repeat);
// save to the uplink channel location, to the numMacADR-th slot of 4 bytes
mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + numMacADR * payLen, &(cmd->payload[0]), payLen);
// saved an ADR mask, so increase counter
mod->hal->setPersistentParameter<uint8_t>(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID, numMacADR + 1);
} }
RADIOLIB_DEBUG_PRINTLN("[2] Successive: %d, numMacADR: %d, RFU: %d, payload: %02X %02X %02X %02X", RADIOLIB_DEBUG_PRINTLN("[2] Repeat: %d, RFU: %d, payload: %02X %02X %02X %02X",
isSuccessive, numMacADR, (cmd->payload[3] >> 7), cmd->repeat, (cmd->payload[3] >> 7),
cmd->payload[0], cmd->payload[1], cmd->payload[2], cmd->payload[3]); cmd->payload[0], cmd->payload[1], cmd->payload[2], cmd->payload[3]);
} }
} }
@ -2276,6 +2304,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) {
// send the reply // send the reply
cmd->len = 1; cmd->len = 1;
cmd->payload[0] = (pwrAck << 2) | (drAck << 1) | (chMaskAck << 0); cmd->payload[0] = (pwrAck << 2) | (drAck << 1) | (chMaskAck << 0);
cmd->repeat = 0; // discard any repeat value that may have been set
RADIOLIB_DEBUG_PRINTLN("ADR ANS: status = 0x%02x", cmd->payload[0]); RADIOLIB_DEBUG_PRINTLN("ADR ANS: status = 0x%02x", cmd->payload[0]);
return(true); return(true);
} break; } break;