[LoRaWAN] Change Rx windows from CAD to RxSingle
This commit is contained in:
parent
dd79213461
commit
c8bc157090
5 changed files with 120 additions and 112 deletions
|
@ -1436,6 +1436,36 @@ uint32_t SX126x::getTimeOnAir(size_t len) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Table below defines the size of one symbol as
|
||||||
|
// symtime = 256us * 2^T(sf,bw)
|
||||||
|
// 256us is called one symunit.
|
||||||
|
// SF:
|
||||||
|
// BW: |__7___8___9__10__11__12
|
||||||
|
// 125kHz | 2 3 4 5 6 7
|
||||||
|
// 250kHz | 1 2 3 4 5 6
|
||||||
|
// 500kHz | 0 1 2 3 4 5
|
||||||
|
//
|
||||||
|
uint32_t SX126x::calculateRxTimeout(uint8_t numSymbols, DataRate_t *datarate, uint32_t offsetUs, uint32_t& timeoutUs) {
|
||||||
|
uint8_t exponent = 0;
|
||||||
|
exponent += datarate->lora.spreadingFactor - 7;
|
||||||
|
|
||||||
|
switch((int)datarate->lora.bandwidth) {
|
||||||
|
case 125:
|
||||||
|
exponent += 2;
|
||||||
|
break;
|
||||||
|
case 250:
|
||||||
|
exponent += 1;
|
||||||
|
break;
|
||||||
|
default: // includes 500 kHz
|
||||||
|
exponent += 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeoutUs = (uint32_t)numSymbols * 256 * (0x01 << exponent) + offsetUs;
|
||||||
|
uint32_t timeout = timeoutUs / 15.625;
|
||||||
|
return(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
#define RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS 0x8C
|
#define RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS 0x8C
|
||||||
#define RADIOLIB_SX126X_CMD_SET_CAD_PARAMS 0x88
|
#define RADIOLIB_SX126X_CMD_SET_CAD_PARAMS 0x88
|
||||||
#define RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F
|
#define RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F
|
||||||
#define RADIOLIB_SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT 0x0A
|
#define RADIOLIB_SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT 0xA0
|
||||||
|
|
||||||
// status commands
|
// status commands
|
||||||
#define RADIOLIB_SX126X_CMD_GET_STATUS 0xC0
|
#define RADIOLIB_SX126X_CMD_GET_STATUS 0xC0
|
||||||
|
@ -219,7 +219,7 @@
|
||||||
#define RADIOLIB_SX126X_IRQ_HEADER_ERR 0b0000000000100000 // 5 5 LoRa header CRC error
|
#define RADIOLIB_SX126X_IRQ_HEADER_ERR 0b0000000000100000 // 5 5 LoRa header CRC error
|
||||||
#define RADIOLIB_SX126X_IRQ_HEADER_VALID 0b0000000000010000 // 4 4 valid LoRa header received
|
#define RADIOLIB_SX126X_IRQ_HEADER_VALID 0b0000000000010000 // 4 4 valid LoRa header received
|
||||||
#define RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID 0b0000000000001000 // 3 3 valid sync word detected
|
#define RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID 0b0000000000001000 // 3 3 valid sync word detected
|
||||||
#define RADIOLIB_SX126X_IRQ_RADIOLIB_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected
|
#define RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected
|
||||||
#define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000000000010 // 1 1 packet received
|
#define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000000000010 // 1 1 packet received
|
||||||
#define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000000000001 // 0 0 packet transmission completed
|
#define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000000000001 // 0 0 packet transmission completed
|
||||||
#define RADIOLIB_SX126X_IRQ_RX_DEFAULT 0b0000001001100010 // 14 0 default for Rx (RX_DONE, TIMEOUT, CRC_ERR and HEADER_ERR)
|
#define RADIOLIB_SX126X_IRQ_RX_DEFAULT 0b0000001001100010 // 14 0 default for Rx (RX_DONE, TIMEOUT, CRC_ERR and HEADER_ERR)
|
||||||
|
@ -949,6 +949,16 @@ class SX126x: public PhysicalLayer {
|
||||||
*/
|
*/
|
||||||
uint32_t getTimeOnAir(size_t len) override;
|
uint32_t getTimeOnAir(size_t len) override;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Get the Rx timeout required to listen to a preamble of a certain number of symbols
|
||||||
|
\param numSymbols Number of symbols to listen for
|
||||||
|
\param datarate The datarate for which to calculate the timeout
|
||||||
|
\param offsetUs Additional offset in microseconds to allow increasing the timeout
|
||||||
|
\param timeoutUs Returns the timeout in microseconds for the host to sleep
|
||||||
|
\returns Timeout value in a unit that is specific for the used module
|
||||||
|
*/
|
||||||
|
uint32_t calculateRxTimeout(uint8_t numSymbols, DataRate_t *datarate, uint32_t offsetUs, uint32_t& timeoutUss);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\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.
|
||||||
|
|
|
@ -20,14 +20,14 @@ static void LoRaWANNodeOnDownlink(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// flag to indicate whether channel scan operation is complete
|
// flag to indicate whether channel scan operation is complete
|
||||||
static volatile bool scanFlag = false;
|
static volatile bool downlinkTimeout = false;
|
||||||
|
|
||||||
// interrupt service routine to handle downlinks automatically
|
// interrupt service routine to handle downlinks automatically
|
||||||
#if defined(ESP8266) || defined(ESP32)
|
#if defined(ESP8266) || defined(ESP32)
|
||||||
IRAM_ATTR
|
IRAM_ATTR
|
||||||
#endif
|
#endif
|
||||||
static void LoRaWANNodeOnChannelScan(void) {
|
static void LoRaWANNodeOnChannelScan(void) {
|
||||||
scanFlag = true;
|
downlinkTimeout = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) {
|
LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) {
|
||||||
|
@ -629,7 +629,7 @@ int16_t LoRaWANNode::downlink(String& str) {
|
||||||
int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
|
int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
|
||||||
// check if there are any upcoming Rx windows
|
// check if there are any upcoming Rx windows
|
||||||
Module* mod = this->phyLayer->getMod();
|
Module* mod = this->phyLayer->getMod();
|
||||||
const uint32_t scanGuard = 10;
|
const uint32_t scanGuard = 50;
|
||||||
if(mod->hal->millis() - this->rxDelayStart > (this->rxDelays[1] + scanGuard)) {
|
if(mod->hal->millis() - this->rxDelayStart > (this->rxDelays[1] + scanGuard)) {
|
||||||
// time since last Tx is greater than RX2 delay + some guard period
|
// time since last Tx is greater than RX2 delay + some guard period
|
||||||
// we have nothing to downlink
|
// we have nothing to downlink
|
||||||
|
@ -646,18 +646,22 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
|
||||||
RADIOLIB_ASSERT(state);
|
RADIOLIB_ASSERT(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate the channel scanning timeout
|
downlinkTimeout = false;
|
||||||
// according to the spec, this must be at least enough time to effectively detect a preamble
|
|
||||||
uint32_t scanTimeout = this->phyLayer->getTimeOnAir(0)/1000;
|
|
||||||
|
|
||||||
// set up everything for channel scan
|
|
||||||
downlinkReceived = false;
|
downlinkReceived = false;
|
||||||
scanFlag = false;
|
|
||||||
bool packetDetected = false;
|
|
||||||
this->phyLayer->setChannelScanAction(LoRaWANNodeOnChannelScan);
|
this->phyLayer->setChannelScanAction(LoRaWANNodeOnChannelScan);
|
||||||
|
|
||||||
|
// calculate the Rx timeout
|
||||||
|
// according to the spec, this must be at least enough time to effectively detect a preamble
|
||||||
|
// but pad it a bit on both sides (start and end) to make sure it is wide enough
|
||||||
|
DataRate_t dataRate;
|
||||||
|
findDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK], &dataRate);
|
||||||
|
uint32_t timeoutHost = 0;
|
||||||
|
uint32_t timeoutMod = this->phyLayer->calculateRxTimeout(8, &dataRate, 2*scanGuard*1000, timeoutHost);
|
||||||
|
RADIOLIB_DEBUG_PRINTLN("RxTimeout host: %d, module: %06x", timeoutHost, timeoutMod);
|
||||||
|
|
||||||
// perform listening in the two Rx windows
|
// perform listening in the two Rx windows
|
||||||
for(uint8_t i = 0; i < 2; i++) {
|
for(uint8_t i = 0; i < 2; i++) {
|
||||||
|
|
||||||
// wait for the start of the Rx window
|
// wait for the start of the Rx window
|
||||||
// the waiting duration is shortened a bit to cover any possible timing errors
|
// the waiting duration is shortened a bit to cover any possible timing errors
|
||||||
uint32_t waitLen = this->rxDelays[i] - (mod->hal->millis() - this->rxDelayStart);
|
uint32_t waitLen = this->rxDelays[i] - (mod->hal->millis() - this->rxDelayStart);
|
||||||
|
@ -668,49 +672,27 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
|
||||||
mod->hal->delay(waitLen);
|
mod->hal->delay(waitLen);
|
||||||
RADIOLIB_DEBUG_PRINTLN("Opening Rx%d window...", (i+1));
|
RADIOLIB_DEBUG_PRINTLN("Opening Rx%d window...", (i+1));
|
||||||
|
|
||||||
// wait until we get a preamble
|
// TODO somehow make this module-independent, currently configured for SX126x
|
||||||
uint32_t scanStart = mod->hal->millis();
|
uint16_t irqFlags = 0b0000000000000010; // RxDone
|
||||||
while((mod->hal->millis() - scanStart) < (scanTimeout + scanGuard)) {
|
uint16_t irqMask = 0b0000000000000010;
|
||||||
// check channel detection timeout
|
irqFlags |= 0b0000001000000000; // RxTimeout
|
||||||
state = this->phyLayer->startChannelScan();
|
irqMask |= 0b0000001000000000;
|
||||||
RADIOLIB_ASSERT(state);
|
|
||||||
|
|
||||||
// wait with some timeout, though it should not be hit
|
|
||||||
uint32_t cadStart = mod->hal->millis();
|
|
||||||
while(!scanFlag) {
|
|
||||||
mod->hal->yield();
|
|
||||||
if(mod->hal->millis() - cadStart >= 3000) {
|
|
||||||
// timed out, stop waiting
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the scan result
|
|
||||||
scanFlag = false;
|
|
||||||
state = this->phyLayer->getChannelScanResult();
|
|
||||||
if((state == RADIOLIB_PREAMBLE_DETECTED) || (state == RADIOLIB_LORA_DETECTED)) {
|
|
||||||
packetDetected = true;
|
|
||||||
|
|
||||||
// channel scan is finished, swap the actions
|
|
||||||
this->phyLayer->clearChannelScanAction();
|
|
||||||
this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlink);
|
|
||||||
|
|
||||||
// start receiving
|
|
||||||
state = this->phyLayer->startReceive(0x00, 0b0000001001100010, 0b0000000000000010, 0); // RxSingle
|
|
||||||
RADIOLIB_ASSERT(state);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
uint32_t rxStart = mod->hal->millis();
|
||||||
|
this->phyLayer->startReceive(timeoutMod, irqFlags, irqMask, 0);
|
||||||
|
RADIOLIB_DEBUG_PRINT("Opened Rx%d window (%d us timeout)... ", i+1, timeoutHost);
|
||||||
|
while(!downlinkTimeout && ((mod->hal->millis() - rxStart) < (timeoutHost / 1000))) {
|
||||||
|
mod->hal->yield();
|
||||||
}
|
}
|
||||||
|
RADIOLIB_DEBUG_PRINTLN("closing");
|
||||||
|
|
||||||
// check if we have a packet
|
// check if we detected something of a packet
|
||||||
if(packetDetected) {
|
if(!downlinkTimeout) {
|
||||||
RADIOLIB_DEBUG_PRINTLN("Detected a packet...");
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
} else if(i == 0) {
|
} else if(i == 0) {
|
||||||
// nothing in the first window, configure for the second
|
// nothing in the first window, configure for the second
|
||||||
|
this->phyLayer->standby();
|
||||||
state = this->phyLayer->setFrequency(this->rx2.freq);
|
state = this->phyLayer->setFrequency(this->rx2.freq);
|
||||||
RADIOLIB_ASSERT(state);
|
RADIOLIB_ASSERT(state);
|
||||||
|
|
||||||
|
@ -718,12 +700,15 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
|
||||||
findDataRate(this->rx2.drMax, &dataRate);
|
findDataRate(this->rx2.drMax, &dataRate);
|
||||||
state = this->phyLayer->setDataRate(dataRate);
|
state = this->phyLayer->setDataRate(dataRate);
|
||||||
RADIOLIB_ASSERT(state);
|
RADIOLIB_ASSERT(state);
|
||||||
|
timeoutMod = this->phyLayer->calculateRxTimeout(8, &dataRate, 2*scanGuard*1000, timeoutHost);
|
||||||
|
downlinkTimeout = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
this->phyLayer->clearChannelScanAction();
|
||||||
|
|
||||||
// check if we received a packet at all
|
// check if we received a packet at all
|
||||||
if(!packetDetected) {
|
if(downlinkTimeout) {
|
||||||
this->phyLayer->standby();
|
this->phyLayer->standby();
|
||||||
if(!this->FSK) {
|
if(!this->FSK) {
|
||||||
this->phyLayer->invertIQ(false);
|
this->phyLayer->invertIQ(false);
|
||||||
|
@ -731,27 +716,14 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
|
||||||
|
|
||||||
return(RADIOLIB_ERR_RX_TIMEOUT);
|
return(RADIOLIB_ERR_RX_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlink);
|
||||||
|
|
||||||
// wait for reception with some timeout
|
|
||||||
uint32_t rxStart = mod->hal->millis();
|
|
||||||
while(!downlinkReceived) {
|
while(!downlinkReceived) {
|
||||||
mod->hal->yield();
|
mod->hal->yield();
|
||||||
// 3 seconds is maximum airtime
|
|
||||||
if(mod->hal->millis() - rxStart >= 3000) {
|
|
||||||
// timed out
|
|
||||||
RADIOLIB_DEBUG_PRINTLN("Packet length: %d", this->phyLayer->getPacketLength());
|
|
||||||
this->phyLayer->standby();
|
|
||||||
if(!this->FSK) {
|
|
||||||
this->phyLayer->invertIQ(false);
|
|
||||||
}
|
|
||||||
// return(RADIOLIB_ERR_RX_TIMEOUT);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// we have a message, clear actions, go to standby and reset the IQ inversion
|
// we have a message, clear actions, go to standby and reset the IQ inversion
|
||||||
downlinkReceived = false;
|
this->phyLayer->standby(); // TODO check: this should be done automagically due to RxSingle?
|
||||||
this->phyLayer->standby();
|
|
||||||
this->phyLayer->clearPacketReceivedAction();
|
this->phyLayer->clearPacketReceivedAction();
|
||||||
if(!this->FSK) {
|
if(!this->FSK) {
|
||||||
state = this->phyLayer->invertIQ(false);
|
state = this->phyLayer->invertIQ(false);
|
||||||
|
@ -760,6 +732,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
|
||||||
|
|
||||||
// get the packet length
|
// get the packet length
|
||||||
size_t downlinkMsgLen = this->phyLayer->getPacketLength();
|
size_t downlinkMsgLen = this->phyLayer->getPacketLength();
|
||||||
|
RADIOLIB_DEBUG_PRINTLN("Downlink message length: %d", downlinkMsgLen);
|
||||||
|
|
||||||
// check the minimum required frame length
|
// check the minimum required frame length
|
||||||
// an extra byte is subtracted because downlink frames may not have a port
|
// an extra byte is subtracted because downlink frames may not have a port
|
||||||
|
@ -803,7 +776,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
|
||||||
// TODO cache the ADR bit?
|
// TODO cache the ADR bit?
|
||||||
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]);
|
||||||
LoRaWANNode::hton<uint16_t>(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt16);
|
LoRaWANNode::hton<uint16_t>(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt16);
|
||||||
uint32_t fcnt32 = fcnt16; // calculate possible rollover once decided if this is network downlink or application downlink
|
|
||||||
|
|
||||||
RADIOLIB_DEBUG_PRINTLN("downlinkMsg:");
|
RADIOLIB_DEBUG_PRINTLN("downlinkMsg:");
|
||||||
RADIOLIB_DEBUG_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen);
|
RADIOLIB_DEBUG_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen);
|
||||||
|
@ -825,9 +797,12 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
|
||||||
fcntDownPrev = mod->hal->getPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID);
|
fcntDownPrev = mod->hal->getPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RADIOLIB_DEBUG_PRINTLN("fcnt: %d, fcntPrev: %d, isAppDownlink: %d", fcnt16, fcntDownPrev, (int)isAppDownlink);
|
||||||
|
|
||||||
// if this is not the first downlink...
|
// if this is not the first downlink...
|
||||||
// assume a 16-bit to 32-bit rollover if difference between counters in LSB is smaller than MAX_FCNT_GAP
|
// assume a 16-bit to 32-bit rollover if difference between counters in LSB is smaller than MAX_FCNT_GAP
|
||||||
// if that isn't the case and the received fcnt is smaller or equal to the last heard fcnt, then error
|
// if that isn't the case and the received fcnt is smaller or equal to the last heard fcnt, then error
|
||||||
|
uint32_t fcnt32 = fcnt16;
|
||||||
if(fcntDownPrev > 0) {
|
if(fcntDownPrev > 0) {
|
||||||
if((fcnt16 <= fcntDownPrev) && ((0xFFFF - (uint16_t)fcntDownPrev + fcnt16) > RADIOLIB_LORAWAN_MAX_FCNT_GAP)) {
|
if((fcnt16 <= fcntDownPrev) && ((0xFFFF - (uint16_t)fcntDownPrev + fcnt16) > RADIOLIB_LORAWAN_MAX_FCNT_GAP)) {
|
||||||
#if !defined(RADIOLIB_STATIC_ONLY)
|
#if !defined(RADIOLIB_STATIC_ONLY)
|
||||||
|
@ -839,7 +814,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
|
||||||
return(RADIOLIB_ERR_N_FCNT_DOWN_INVALID);
|
return(RADIOLIB_ERR_N_FCNT_DOWN_INVALID);
|
||||||
}
|
}
|
||||||
} else if (fcnt16 <= fcntDownPrev) {
|
} else if (fcnt16 <= fcntDownPrev) {
|
||||||
uint16_t msb = (fcntDownPrev >> 16) + 1; // assume a rollover
|
uint16_t msb = (fcntDownPrev >> 16) + 1; // assume a rollover
|
||||||
fcnt32 |= (msb << 16); // add back the MSB part
|
fcnt32 |= (msb << 16); // add back the MSB part
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -923,7 +898,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
|
||||||
RADIOLIB_DEBUG_PRINTLN("Uplink MAC payload (%d commands):", foptsNum);
|
RADIOLIB_DEBUG_PRINTLN("Uplink MAC payload (%d commands):", foptsNum);
|
||||||
RADIOLIB_DEBUG_HEXDUMP(foptsBuff, foptsBufSize);
|
RADIOLIB_DEBUG_HEXDUMP(foptsBuff, foptsBufSize);
|
||||||
|
|
||||||
isMACPayload = true;
|
this->isMACPayload = true;
|
||||||
this->uplink(foptsBuff, foptsBufSize, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND);
|
this->uplink(foptsBuff, foptsBufSize, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -951,9 +926,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
|
||||||
// there is payload, and so there should be a port too
|
// there is payload, and so there should be a port too
|
||||||
// TODO pass the port?
|
// TODO pass the port?
|
||||||
*len = payLen - 1;
|
*len = payLen - 1;
|
||||||
|
|
||||||
// TODO it COULD be the case that the assumed rollover is incorrect, then figure out a way to catch this and retry with just fcnt16
|
// TODO it COULD be the case that the assumed rollover is incorrect, then figure out a way to catch this and retry with just fcnt16
|
||||||
// TODO does the erratum hold here as well?
|
processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(foptsLen)], payLen - 1, this->appSKey, data, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true);
|
||||||
processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], downlinkMsgLen, this->appSKey, data, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true);
|
|
||||||
|
|
||||||
#if !defined(RADIOLIB_STATIC_ONLY)
|
#if !defined(RADIOLIB_STATIC_ONLY)
|
||||||
delete[] downlinkMsg;
|
delete[] downlinkMsg;
|
||||||
|
@ -1061,20 +1036,20 @@ int16_t LoRaWANNode::setupChannels(uint8_t* cfList) {
|
||||||
num++;
|
num++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if(cfList != nullptr) {
|
if(cfList != nullptr) {
|
||||||
// for(uint8_t i = 0; i < 5; i++) {
|
for(uint8_t i = 0; i < 5; i++) {
|
||||||
// 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);
|
||||||
// chnl.freq = (float)freq/10000.0;
|
chnl.freq = (float)freq/10000.0;
|
||||||
// chnl.drMin = this->band->txFreqs[0].drMin; // drMin is equal for all channels
|
chnl.drMin = this->band->txFreqs[0].drMin; // drMin is equal for all channels
|
||||||
// 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", num, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq);
|
||||||
// num++;
|
num++;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
} else { // RADIOLIB_LORAWAN_CFLIST_TYPE_MASK
|
} else { // RADIOLIB_LORAWAN_CFLIST_TYPE_MASK
|
||||||
uint8_t chSpan = 0;
|
uint8_t chSpan = 0;
|
||||||
uint8_t chNum = 0;
|
uint8_t chNum = 0;
|
||||||
|
@ -1301,15 +1276,6 @@ int16_t LoRaWANNode::pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQ
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&queue->commands[queue->numCommands], cmd, sizeof(LoRaWANMacCommand_t));
|
memcpy(&queue->commands[queue->numCommands], cmd, sizeof(LoRaWANMacCommand_t));
|
||||||
/*RADIOLIB_DEBUG_PRINTLN("push MAC CID = %02x, len = %d, payload = %02x %02x %02x %02x %02x, repeat = %d ",
|
|
||||||
queue->commands[queue->numCommands - 1].cid,
|
|
||||||
queue->commands[queue->numCommands - 1].len,
|
|
||||||
queue->commands[queue->numCommands - 1].payload[0],
|
|
||||||
queue->commands[queue->numCommands - 1].payload[1],
|
|
||||||
queue->commands[queue->numCommands - 1].payload[2],
|
|
||||||
queue->commands[queue->numCommands - 1].payload[3],
|
|
||||||
queue->commands[queue->numCommands - 1].payload[4],
|
|
||||||
queue->commands[queue->numCommands - 1].repeat);*/
|
|
||||||
queue->numCommands++;
|
queue->numCommands++;
|
||||||
queue->len += 1 + cmd->len; // 1 byte for command ID, len bytes for payload
|
queue->len += 1 + cmd->len; // 1 byte for command ID, len bytes for payload
|
||||||
|
|
||||||
|
@ -1322,15 +1288,6 @@ int16_t LoRaWANNode::popMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQu
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cmd) {
|
if(cmd) {
|
||||||
// RADIOLIB_DEBUG_PRINTLN("pop MAC CID = %02x, len = %d, payload = %02x %02x %02x %02x %02x, repeat = %d ",
|
|
||||||
// queue->commands[index].cid,
|
|
||||||
// queue->commands[index].len,
|
|
||||||
// queue->commands[index].payload[0],
|
|
||||||
// queue->commands[index].payload[1],
|
|
||||||
// queue->commands[index].payload[2],
|
|
||||||
// queue->commands[index].payload[3],
|
|
||||||
// queue->commands[index].payload[4],
|
|
||||||
// queue->commands[index].repeat);
|
|
||||||
memcpy(cmd, &queue->commands[index], sizeof(LoRaWANMacCommand_t));
|
memcpy(cmd, &queue->commands[index], sizeof(LoRaWANMacCommand_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1350,15 +1307,6 @@ int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* que
|
||||||
|
|
||||||
for(size_t index = 0; index < queue->numCommands; index++) {
|
for(size_t index = 0; index < queue->numCommands; index++) {
|
||||||
if(queue->commands[index].cid == cid) {
|
if(queue->commands[index].cid == cid) {
|
||||||
// RADIOLIB_DEBUG_PRINTLN("delete MAC CID = %02x, len = %d, payload = %02x %02x %02x %02x %02x, repeat = %d ",
|
|
||||||
// queue->commands[index].cid,
|
|
||||||
// queue->commands[index].len,
|
|
||||||
// queue->commands[index].payload[0],
|
|
||||||
// queue->commands[index].payload[1],
|
|
||||||
// queue->commands[index].payload[2],
|
|
||||||
// queue->commands[index].payload[3],
|
|
||||||
// queue->commands[index].payload[4],
|
|
||||||
// queue->commands[index].repeat);
|
|
||||||
queue->len -= (1 + queue->commands[index].len); // 1 byte for command ID, len for payload
|
queue->len -= (1 + queue->commands[index].len); // 1 byte for command ID, len for payload
|
||||||
// move all subsequent commands one forward in the queue
|
// move all subsequent commands one forward in the queue
|
||||||
if(index < RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - 1) {
|
if(index < RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - 1) {
|
||||||
|
@ -1412,7 +1360,7 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) {
|
||||||
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%04x, 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", dr, txPower, chMask, chMaskCntl, nbTrans);
|
||||||
|
|
||||||
// apply the configuration
|
// apply the configuration
|
||||||
uint8_t drAck = 0;
|
uint8_t drAck = 0;
|
||||||
|
@ -1447,17 +1395,18 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) {
|
||||||
this->nbTrans = nbTrans;
|
this->nbTrans = nbTrans;
|
||||||
// TODO implement channel mask
|
// TODO implement channel mask
|
||||||
uint8_t chMaskAck = 1;
|
uint8_t chMaskAck = 1;
|
||||||
(void)chMask;
|
|
||||||
(void)chMaskCntl;
|
(void)chMaskCntl;
|
||||||
if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES) {
|
if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES) {
|
||||||
for(uint8_t i = 0; i < 16; i++) {
|
for(uint8_t i = 0; i < 16; i++) {
|
||||||
// check if this channel ID should be enabled
|
// check if this channel ID should be enabled
|
||||||
|
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].enabled == false) {
|
||||||
chMaskAck = 0;
|
chMaskAck = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true;
|
||||||
} else {
|
} else {
|
||||||
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = false;
|
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = false;
|
||||||
}
|
}
|
||||||
|
@ -1732,6 +1681,7 @@ void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out
|
||||||
// on downlink frames, this has a decryption effect because server actually "decrypts" the plaintext
|
// on downlink frames, this has a decryption effect because server actually "decrypts" the plaintext
|
||||||
size_t remLen = len;
|
size_t remLen = len;
|
||||||
for(size_t i = 0; i < numBlocks; i++) {
|
for(size_t i = 0; i < numBlocks; i++) {
|
||||||
|
|
||||||
if(counter) {
|
if(counter) {
|
||||||
encBlock[RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_POS] = i + 1;
|
encBlock[RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_POS] = i + 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -294,6 +294,14 @@ uint32_t PhysicalLayer::getTimeOnAir(size_t len) {
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t PhysicalLayer::calculateRxTimeout(uint8_t numSymbols, DataRate_t *datarate, uint32_t offsetUs, uint32_t& timeoutUs) {
|
||||||
|
(void)numSymbols;
|
||||||
|
(void)datarate;
|
||||||
|
(void)offsetUs;
|
||||||
|
(void)timeoutUs;
|
||||||
|
return(RADIOLIB_ERR_UNSUPPORTED);
|
||||||
|
}
|
||||||
|
|
||||||
int16_t PhysicalLayer::startChannelScan() {
|
int16_t PhysicalLayer::startChannelScan() {
|
||||||
return(RADIOLIB_ERR_UNSUPPORTED);
|
return(RADIOLIB_ERR_UNSUPPORTED);
|
||||||
}
|
}
|
||||||
|
|
|
@ -310,6 +310,16 @@ class PhysicalLayer {
|
||||||
*/
|
*/
|
||||||
virtual uint32_t getTimeOnAir(size_t len);
|
virtual uint32_t getTimeOnAir(size_t len);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Get the Rx timeout required to listen to a preamble of a certain number of symbols
|
||||||
|
\param numSymbols Number of symbols to listen for
|
||||||
|
\param datarate The datarate for which to calculate the timeout
|
||||||
|
\param offsetUs Additional offset in microseconds to allow increasing the timeout
|
||||||
|
\param timeoutUs Returns the timeout in microseconds for the host to sleep
|
||||||
|
\returns Timeout value in a unit that is specific for the used module
|
||||||
|
*/
|
||||||
|
virtual uint32_t calculateRxTimeout(uint8_t numSymbols, DataRate_t* datarate, uint32_t offsetUs, uint32_t& timeoutUs);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\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