[PHY] Staged modes (#1414)

* [PHY] Add PHY support for staged modes

* [SX126x] Add support for staged Rx/Tx

* [PHY] Add missing virtual specifiers

* [SX126x] Add missing overrides

* [LoRaWAN] Use new stageMode and launchMode, reduce scanGuard

* [LoRaWAN] A-synchronize transmissions (#1410)

* [PHY] Pass mode config by reference

* [PHY] Add default implementation of start transmit/receive

* [SX126x] Implement staged modes

* [SX128x] Implement staged modes

* [SX127x] Implement staged modes

* [LR11x0] Implement staged modes

* [SX127x] Remove unused method from header

* [SX126x] Make array const

* Add new methods to keywords

---------

Co-authored-by: StevenCellist <steven@boonstoppel.nu>
This commit is contained in:
Jan Gromeš 2025-02-05 20:41:43 +01:00 committed by GitHub
parent 9e832526a5
commit 2550fae4cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 771 additions and 600 deletions

View file

@ -343,6 +343,8 @@ setDataRate KEYWORD2
checkDataRate KEYWORD2
setModem KEYWORD2
getModem KEYWORD2
stageMode KEYWORD2
launchMode KEYWORD2
# LoRaWAN
getBufferNonces KEYWORD2

View file

@ -414,73 +414,6 @@ void LR11x0::clearPacketSentAction() {
this->clearIrqAction();
}
int16_t LR11x0::startTransmit(const uint8_t* data, size_t len, uint8_t addr) {
// suppress unused variable warning
(void)addr;
// check packet length
if(len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH) {
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
// maximum packet length is decreased by 1 when address filtering is active
if((this->addrComp != RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED) && (len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH - 1)) {
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
// set packet Length
int16_t state = RADIOLIB_ERR_NONE;
uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
state = getPacketType(&modem);
RADIOLIB_ASSERT(state);
if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, len, this->crcTypeLoRa, this->invertIQEnabled);
} else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, len, this->crcTypeGFSK, this->whitening);
} else if(modem != RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
return(RADIOLIB_ERR_UNKNOWN);
}
RADIOLIB_ASSERT(state);
// set DIO mapping
state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_TX_DONE | RADIOLIB_LR11X0_IRQ_TIMEOUT);
RADIOLIB_ASSERT(state);
if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
// in LR-FHSS mode, the packet is built by the device
// TODO add configurable device offset
state = lrFhssBuildFrame(this->lrFhssHdrCount, this->lrFhssCr, this->lrFhssGrid, true, this->lrFhssBw, this->lrFhssHopSeq, 0, const_cast<uint8_t*>(data), len);
RADIOLIB_ASSERT(state);
} else {
// write packet to buffer
state = writeBuffer8(const_cast<uint8_t*>(data), len);
RADIOLIB_ASSERT(state);
}
// clear interrupt flags
state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
RADIOLIB_ASSERT(state);
// set RF switch (if present)
this->mod->setRfSwitchState(Module::MODE_TX);
// start transmission
state = setTx(RADIOLIB_LR11X0_TX_TIMEOUT_NONE);
RADIOLIB_ASSERT(state);
// wait for BUSY to go low (= PA ramp up done)
while(this->mod->hal->digitalRead(this->mod->getGpio())) {
this->mod->hal->yield();
}
return(state);
}
int16_t LR11x0::finishTransmit() {
// clear interrupt flags
clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
@ -493,46 +426,6 @@ int16_t LR11x0::startReceive() {
return(this->startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
}
int16_t LR11x0::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) {
(void)len;
// check active modem
int16_t state = RADIOLIB_ERR_NONE;
uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
state = getPacketType(&modem);
RADIOLIB_ASSERT(state);
if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) &&
(modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
// set DIO mapping
uint32_t irq = irqMask;
if(timeout != RADIOLIB_LR11X0_RX_TIMEOUT_INF) {
irq |= (1UL << RADIOLIB_IRQ_TIMEOUT);
}
state = setDioIrqParams(getIrqMapped(irqFlags & irq));
RADIOLIB_ASSERT(state);
// clear interrupt flags
state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
RADIOLIB_ASSERT(state);
// set implicit mode and expected len if applicable
if((this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) && (modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA)) {
state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, this->invertIQEnabled);
RADIOLIB_ASSERT(state);
}
// set RF switch (if present)
this->mod->setRfSwitchState(Module::MODE_RX);
// set mode to receive
state = setRx(timeout);
return(state);
}
uint32_t LR11x0::getIrqStatus() {
// there is no dedicated "get IRQ" command, the IRQ bits are sent after the status bytes
uint8_t buff[6] = { 0 };
@ -2052,6 +1945,124 @@ int16_t LR11x0::getModem(ModemType_t* modem) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
int16_t LR11x0::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
int16_t state;
switch(mode) {
case(RADIOLIB_RADIO_MODE_RX): {
// check active modem
uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
state = getPacketType(&modem);
RADIOLIB_ASSERT(state);
if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) &&
(modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
// set DIO mapping
if(cfg->receive.timeout != RADIOLIB_LR11X0_RX_TIMEOUT_INF) {
cfg->receive.irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT);
}
state = setDioIrqParams(getIrqMapped(cfg->receive.irqFlags & cfg->receive.irqMask));
RADIOLIB_ASSERT(state);
// clear interrupt flags
state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
RADIOLIB_ASSERT(state);
// set implicit mode and expected len if applicable
if((this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) && (modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA)) {
state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, this->invertIQEnabled);
RADIOLIB_ASSERT(state);
}
this->rxTimeout = cfg->receive.timeout;
} break;
case(RADIOLIB_RADIO_MODE_TX): {
// check packet length
if(cfg->transmit.len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH) {
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
// maximum packet length is decreased by 1 when address filtering is active
if((this->addrComp != RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED) && (cfg->transmit.len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH - 1)) {
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
// set packet Length
state = RADIOLIB_ERR_NONE;
uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
state = getPacketType(&modem);
RADIOLIB_ASSERT(state);
if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcTypeLoRa, this->invertIQEnabled);
} else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening);
} else if(modem != RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
return(RADIOLIB_ERR_UNKNOWN);
}
RADIOLIB_ASSERT(state);
// set DIO mapping
state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_TX_DONE | RADIOLIB_LR11X0_IRQ_TIMEOUT);
RADIOLIB_ASSERT(state);
if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
// in LR-FHSS mode, the packet is built by the device
// TODO add configurable device offset
state = lrFhssBuildFrame(this->lrFhssHdrCount, this->lrFhssCr, this->lrFhssGrid, true, this->lrFhssBw, this->lrFhssHopSeq, 0, cfg->transmit.data, cfg->transmit.len);
RADIOLIB_ASSERT(state);
} else {
// write packet to buffer
state = writeBuffer8(cfg->transmit.data, cfg->transmit.len);
RADIOLIB_ASSERT(state);
}
// clear interrupt flags
state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
RADIOLIB_ASSERT(state);
} break;
default:
return(RADIOLIB_ERR_UNSUPPORTED);
}
this->stagedMode = mode;
return(state);
}
int16_t LR11x0::launchMode() {
int16_t state;
switch(this->stagedMode) {
case(RADIOLIB_RADIO_MODE_RX): {
this->mod->setRfSwitchState(Module::MODE_RX);
state = setRx(this->rxTimeout);
} break;
case(RADIOLIB_RADIO_MODE_TX): {
this->mod->setRfSwitchState(Module::MODE_TX);
state = setTx(RADIOLIB_LR11X0_TX_TIMEOUT_NONE);
RADIOLIB_ASSERT(state);
// wait for BUSY to go low (= PA ramp up done)
while(this->mod->hal->digitalRead(this->mod->getGpio())) {
this->mod->hal->yield();
}
} break;
default:
return(RADIOLIB_ERR_UNSUPPORTED);
}
this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
return(state);
}
int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) {
this->mod->init();
this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
@ -2334,12 +2345,12 @@ int16_t LR11x0::readRegMem32(uint32_t addr, uint32_t* data, size_t len) {
return(state);
}
int16_t LR11x0::writeBuffer8(uint8_t* data, size_t len) {
int16_t LR11x0::writeBuffer8(const uint8_t* data, size_t len) {
// check maximum size
if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) {
return(RADIOLIB_ERR_SPI_CMD_INVALID);
}
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_BUFFER, true, data, len));
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_BUFFER, true, const_cast<uint8_t*>(data), len));
}
int16_t LR11x0::readBuffer8(uint8_t* data, size_t len, size_t offset) {

View file

@ -877,6 +877,7 @@ class LR11x0: public PhysicalLayer {
using PhysicalLayer::transmit;
using PhysicalLayer::receive;
using PhysicalLayer::startTransmit;
using PhysicalLayer::startReceive;
using PhysicalLayer::readData;
/*!
@ -1073,16 +1074,6 @@ class LR11x0: public PhysicalLayer {
*/
void clearPacketSentAction() override;
/*!
\brief Interrupt-driven binary transmit method.
Overloads for string-based transmissions are implemented in PhysicalLayer.
\param data Binary data to be sent.
\param len Number of bytes to send.
\param addr Address to send the data to. Will only be added if address filtering was enabled.
\returns \ref status_codes
*/
int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override;
/*!
\brief Clean up after transmission is done.
\returns \ref status_codes
@ -1097,20 +1088,6 @@ class LR11x0: public PhysicalLayer {
*/
int16_t startReceive() override;
/*!
\brief Interrupt-driven receive method. IRQ1 will be activated when full packet is received.
\param timeout Raw timeout value, expressed as multiples of 1/32.768 kHz (approximately 30.52 us).
Defaults to RADIOLIB_LR11X0_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode),
set to RADIOLIB_LR11X0_RX_TIMEOUT_NONE for no timeout (Rx single mode).
If timeout other than infinite is set, signal will be generated on IRQ1.
\param irqFlags Sets the IRQ flags that will trigger IRQ1, defaults to RADIOLIB_LR11X0_IRQ_RX_DONE.
\param irqMask Only for PhysicalLayer compatibility, not used.
\param len Only for PhysicalLayer compatibility, not used.
\returns \ref status_codes
*/
int16_t startReceive(uint32_t timeout, uint32_t irqFlags = RADIOLIB_LR11X0_IRQ_RX_DONE, uint32_t irqMask = 0, size_t len = 0);
/*!
\brief Reads the current IRQ status.
\returns IRQ status bits
@ -1622,6 +1599,12 @@ class LR11x0: public PhysicalLayer {
*/
int16_t calibrateImageRejection(float freqMin, float freqMax);
/*! \copydoc PhysicalLayer::stageMode */
int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) override;
/*! \copydoc PhysicalLayer::launchMode */
int16_t launchMode() override;
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
#endif
@ -1630,7 +1613,7 @@ class LR11x0: public PhysicalLayer {
// LR11x0 SPI command implementations
int16_t writeRegMem32(uint32_t addr, const uint32_t* data, size_t len);
int16_t readRegMem32(uint32_t addr, uint32_t* data, size_t len);
int16_t writeBuffer8(uint8_t* data, size_t len);
int16_t writeBuffer8(const uint8_t* data, size_t len);
int16_t readBuffer8(uint8_t* data, size_t len, size_t offset);
int16_t clearRxBuffer(void);
int16_t writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data);
@ -1829,6 +1812,7 @@ class LR11x0: public PhysicalLayer {
uint8_t wifiScanMode = 0;
bool gnss = false;
uint32_t rxTimeout = 0;
int16_t modSetup(float tcxoVoltage, uint8_t modem);
static int16_t SPIparseStatus(uint8_t in);

View file

@ -518,115 +518,6 @@ void SX126x::clearChannelScanAction() {
this->clearDio1Action();
}
int16_t SX126x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) {
(void)addr;
// check packet length
if(len > RADIOLIB_SX126X_MAX_PACKET_LENGTH) {
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
// maximum packet length is decreased by 1 when address filtering is active
if((RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF != RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF) && (len > RADIOLIB_SX126X_MAX_PACKET_LENGTH - 1)) {
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
// set packet Length
int16_t state = RADIOLIB_ERR_NONE;
uint8_t modem = getPacketType();
if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, this->headerType, this->invertIQEnabled);
} else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType, len);
} else if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
return(RADIOLIB_ERR_UNKNOWN);
}
RADIOLIB_ASSERT(state);
// set DIO mapping
if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT, RADIOLIB_SX126X_IRQ_TX_DONE);
} else {
state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_LR_FHSS_HOP, RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_LR_FHSS_HOP);
}
RADIOLIB_ASSERT(state);
// set buffer pointers
state = setBufferBaseAddress();
RADIOLIB_ASSERT(state);
// write packet to buffer
if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
state = writeBuffer(const_cast<uint8_t*>(data), len);
} else {
// first, reset the LR-FHSS state machine
state = resetLRFHSS();
RADIOLIB_ASSERT(state);
// skip hopping for the first 4 - lrFhssHdrCount blocks
for(int i = 0; i < 4 - this->lrFhssHdrCount; ++i ) {
stepLRFHSS();
}
// in LR-FHSS mode, we need to build the entire packet manually
uint8_t frame[RADIOLIB_SX126X_MAX_PACKET_LENGTH] = { 0 };
size_t frameLen = 0;
this->lrFhssFrameBitsRem = 0;
this->lrFhssFrameHopsRem = 0;
this->lrFhssHopNum = 0;
state = buildLRFHSSPacket(const_cast<uint8_t*>(data), len, frame, &frameLen, &this->lrFhssFrameBitsRem, &this->lrFhssFrameHopsRem);
RADIOLIB_ASSERT(state);
// FIXME check max len for FHSS
state = writeBuffer(frame, frameLen);
RADIOLIB_ASSERT(state);
// activate hopping
uint8_t hopCfg[] = { RADIOLIB_SX126X_HOPPING_ENABLED, (uint8_t)frameLen, (uint8_t)this->lrFhssFrameHopsRem };
state = writeRegister(RADIOLIB_SX126X_REG_HOPPING_ENABLE, hopCfg, 3);
RADIOLIB_ASSERT(state);
// write the initial hopping table
uint8_t initHops = this->lrFhssFrameHopsRem;
if(initHops > 16) {
initHops = 16;
};
for(size_t i = 0; i < initHops; i++) {
// set the hop frequency and symbols
state = this->setLRFHSSHop(i);
RADIOLIB_ASSERT(state);
}
}
RADIOLIB_ASSERT(state);
// clear interrupt flags
state = clearIrqStatus();
RADIOLIB_ASSERT(state);
// fix sensitivity
state = fixSensitivity();
RADIOLIB_ASSERT(state);
// set RF switch (if present)
this->mod->setRfSwitchState(this->txMode);
// start transmission
state = setTx(RADIOLIB_SX126X_TX_TIMEOUT_NONE);
RADIOLIB_ASSERT(state);
// wait for BUSY to go low (= PA ramp up done)
while(this->mod->hal->digitalRead(this->mod->getGpio())) {
this->mod->hal->yield();
}
return(state);
}
int16_t SX126x::finishTransmit() {
// clear interrupt flags
int16_t state = clearIrqStatus();
@ -640,25 +531,6 @@ int16_t SX126x::startReceive() {
return(this->startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
}
int16_t SX126x::startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) {
// in implicit header mode, use the provided length if it is nonzero
// otherwise we trust the user has previously set the payload length manually
if((this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (len != 0)) {
this->implicitLen = len;
}
int16_t state = startReceiveCommon(timeout, irqFlags, irqMask);
RADIOLIB_ASSERT(state);
// set RF switch (if present)
this->mod->setRfSwitchState(Module::MODE_RX);
// set mode to receive
state = setRx(timeout);
return(state);
}
int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask) {
// datasheet claims time to go to sleep is ~500us, same to wake up, compensate for that with 1 ms + TCXO delay
uint32_t transitionTime = this->tcxoDelay + 1000;
@ -1666,6 +1538,152 @@ int16_t SX126x::getModem(ModemType_t* modem) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
int16_t SX126x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
int16_t state;
switch(mode) {
case(RADIOLIB_RADIO_MODE_RX): {
// in implicit header mode, use the provided length if it is nonzero
// otherwise we trust the user has previously set the payload length manually
if((this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (cfg->receive.len != 0)) {
this->implicitLen = cfg->receive.len;
}
state = startReceiveCommon(cfg->receive.timeout, cfg->receive.irqFlags, cfg->receive.irqMask);
RADIOLIB_ASSERT(state);
this->rxTimeout = cfg->receive.timeout;
} break;
case(RADIOLIB_RADIO_MODE_TX): {
// check packet length
if(cfg->transmit.len > RADIOLIB_SX126X_MAX_PACKET_LENGTH) {
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
// maximum packet length is decreased by 1 when address filtering is active
if((RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF != RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF) &&
(cfg->transmit.len > RADIOLIB_SX126X_MAX_PACKET_LENGTH - 1)) {
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
// set packet Length
state = RADIOLIB_ERR_NONE;
uint8_t modem = getPacketType();
if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, cfg->transmit.len, this->headerType, this->invertIQEnabled);
} else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType, cfg->transmit.len);
} else if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
return(RADIOLIB_ERR_UNKNOWN);
}
RADIOLIB_ASSERT(state);
// set DIO mapping
if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT, RADIOLIB_SX126X_IRQ_TX_DONE);
} else {
state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_LR_FHSS_HOP, RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_LR_FHSS_HOP);
}
RADIOLIB_ASSERT(state);
// set buffer pointers
state = setBufferBaseAddress();
RADIOLIB_ASSERT(state);
// write packet to buffer
if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
state = writeBuffer(cfg->transmit.data, cfg->transmit.len);
} else {
// first, reset the LR-FHSS state machine
state = resetLRFHSS();
RADIOLIB_ASSERT(state);
// skip hopping for the first 4 - lrFhssHdrCount blocks
for(int i = 0; i < 4 - this->lrFhssHdrCount; ++i ) {
stepLRFHSS();
}
// in LR-FHSS mode, we need to build the entire packet manually
uint8_t frame[RADIOLIB_SX126X_MAX_PACKET_LENGTH] = { 0 };
size_t frameLen = 0;
this->lrFhssFrameBitsRem = 0;
this->lrFhssFrameHopsRem = 0;
this->lrFhssHopNum = 0;
state = buildLRFHSSPacket(cfg->transmit.data, cfg->transmit.len, frame, &frameLen, &this->lrFhssFrameBitsRem, &this->lrFhssFrameHopsRem);
RADIOLIB_ASSERT(state);
// FIXME check max len for FHSS
state = writeBuffer(frame, frameLen);
RADIOLIB_ASSERT(state);
// activate hopping
const uint8_t hopCfg[] = { RADIOLIB_SX126X_HOPPING_ENABLED, (uint8_t)frameLen, (uint8_t)this->lrFhssFrameHopsRem };
state = writeRegister(RADIOLIB_SX126X_REG_HOPPING_ENABLE, hopCfg, 3);
RADIOLIB_ASSERT(state);
// write the initial hopping table
uint8_t initHops = this->lrFhssFrameHopsRem;
if(initHops > 16) {
initHops = 16;
};
for(size_t i = 0; i < initHops; i++) {
// set the hop frequency and symbols
state = this->setLRFHSSHop(i);
RADIOLIB_ASSERT(state);
}
}
RADIOLIB_ASSERT(state);
// clear interrupt flags
state = clearIrqStatus();
RADIOLIB_ASSERT(state);
// fix sensitivity
state = fixSensitivity();
RADIOLIB_ASSERT(state);
} break;
default:
return(RADIOLIB_ERR_UNSUPPORTED);
}
this->stagedMode = mode;
return(state);
}
int16_t SX126x::launchMode() {
int16_t state;
switch(this->stagedMode) {
case(RADIOLIB_RADIO_MODE_RX): {
this->mod->setRfSwitchState(Module::MODE_RX);
state = setRx(this->rxTimeout);
} break;
case(RADIOLIB_RADIO_MODE_TX): {
this->mod->setRfSwitchState(this->txMode);
state = setTx(RADIOLIB_SX126X_TX_TIMEOUT_NONE);
RADIOLIB_ASSERT(state);
// wait for BUSY to go low (= PA ramp up done)
while(this->mod->hal->digitalRead(this->mod->getGpio())) {
this->mod->hal->yield();
}
} break;
default:
return(RADIOLIB_ERR_UNSUPPORTED);
}
this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
return(state);
}
#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
void SX126x::setDirectAction(void (*func)(void)) {
setDio1Action(func);

View file

@ -478,6 +478,7 @@ class SX126x: public PhysicalLayer {
using PhysicalLayer::transmit;
using PhysicalLayer::receive;
using PhysicalLayer::startTransmit;
using PhysicalLayer::startReceive;
using PhysicalLayer::readData;
/*!
@ -681,16 +682,6 @@ class SX126x: public PhysicalLayer {
*/
void clearChannelScanAction() override;
/*!
\brief Interrupt-driven binary transmit method.
Overloads for string-based transmissions are implemented in PhysicalLayer.
\param data Binary data to be sent.
\param len Number of bytes to send.
\param addr Address to send the data to. Will only be added if address filtering was enabled.
\returns \ref status_codes
*/
int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override;
/*!
\brief Clean up after transmission is done.
\returns \ref status_codes
@ -705,23 +696,6 @@ class SX126x: public PhysicalLayer {
*/
int16_t startReceive() override;
/*!
\brief Interrupt-driven receive method. DIO1 will be activated when full packet is received.
\param timeout Receive mode type and/or raw timeout value, expressed as multiples of 15.625 us.
When set to RADIOLIB_SX126X_RX_TIMEOUT_INF, the timeout will be infinite and the device will remain
in Rx mode until explicitly commanded to stop (Rx continuous mode).
When set to RADIOLIB_SX126X_RX_TIMEOUT_NONE, there will be no timeout and the device will return
to standby when a packet is received (Rx single mode).
For any other value, timeout will be applied and signal will be generated on DIO1 for conditions
defined by irqFlags and irqMask.
\param irqFlags Sets the IRQ flags, defaults to RX done, RX timeout, CRC error and header error.
\param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RX done.
\param len Only for PhysicalLayer compatibility, not used.
\returns \ref status_codes
*/
int16_t startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK, size_t len = 0);
/*!
\brief Interrupt-driven receive method where the device mostly sleeps and periodically wakes to listen.
Note that this function assumes the unit will take 500us + TCXO_delay to change state.
@ -1145,6 +1119,12 @@ class SX126x: public PhysicalLayer {
\returns \ref status_codes
*/
int16_t getModem(ModemType_t* modem) override;
/*! \copydoc PhysicalLayer::stageMode */
int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) override;
/*! \copydoc PhysicalLayer::launchMode */
int16_t launchMode() override;
#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
/*!
@ -1304,6 +1284,7 @@ class SX126x: public PhysicalLayer {
size_t implicitLen = 0;
uint8_t invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD;
uint32_t rxTimeout = 0;
// LR-FHSS stuff - there's a lot of it because all the encoding happens in software
uint8_t lrFhssCr = RADIOLIB_SX126X_LR_FHSS_CR_2_3;

View file

@ -389,67 +389,6 @@ int16_t SX127x::startReceive() {
return(this->startReceive(0, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
}
int16_t SX127x::startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) {
uint8_t mode = RADIOLIB_SX127X_RXCONTINUOUS;
// set mode to standby
int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
RADIOLIB_ASSERT(state);
// set DIO pin mapping
state = this->setIrqFlags(getIrqMapped(irqFlags & irqMask));
RADIOLIB_ASSERT(state);
int16_t modem = getActiveModem();
if(modem == RADIOLIB_SX127X_LORA) {
if(timeout != 0) {
// for non-zero timeout value, change mode to Rx single and set the timeout
mode = RADIOLIB_SX127X_RXSINGLE;
uint8_t msb_sym = (timeout > 0x3FF) ? 0x3 : (uint8_t)(timeout >> 8);
uint8_t lsb_sym = (timeout > 0x3FF) ? 0xFF : (uint8_t)(timeout & 0xFF);
state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, msb_sym, 1, 0);
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB, lsb_sym);
RADIOLIB_ASSERT(state);
}
// in FHSS mode, enable channel change interrupt
if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) {
state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 5, 4);
}
// in implicit header mode, use the provided length if it is nonzero
// otherwise we trust the user has previously set the payload length manually
if((this->implicitHdr) && (len != 0)) {
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len);
this->packetLength = len;
}
// apply fixes to errata
RADIOLIB_ERRATA_SX127X(true);
// clear interrupt flags
clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
// set FIFO pointers
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX);
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX);
RADIOLIB_ASSERT(state);
} else if(modem == RADIOLIB_SX127X_FSK_OOK) {
// clear interrupt flags
clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
// FSK modem does not distinguish between Rx single and continuous
mode = RADIOLIB_SX127X_RX;
}
// set RF switch (if present)
this->mod->setRfSwitchState(Module::MODE_RX);
// set mode to receive
return(setMode(mode));
}
void SX127x::setDio0Action(void (*func)(void), uint32_t dir) {
this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, dir);
}
@ -568,80 +507,6 @@ bool SX127x::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen)
return(false);
}
int16_t SX127x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) {
// set mode to standby
int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
int16_t modem = getActiveModem();
if(modem == RADIOLIB_SX127X_LORA) {
// check packet length
if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH) {
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
// set DIO mapping
if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) {
this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4);
} else {
this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE, 7, 6);
}
// apply fixes to errata
RADIOLIB_ERRATA_SX127X(false);
// clear interrupt flags
clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
// set packet length
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len);
// set FIFO pointers
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX);
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX);
} else if(modem == RADIOLIB_SX127X_FSK_OOK) {
// clear interrupt flags
clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
// set DIO mapping
if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) {
this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY, 5, 4);
} else {
this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6);
}
// set packet length - increased by 1 when address filter is enabled
uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1);
if(this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) {
if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) {
this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, len + 1);
this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, addr);
} else {
this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, len);
}
}
}
// write packet to FIFO
size_t packetLen = len;
if((modem == RADIOLIB_SX127X_FSK_OOK) && (len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK)) {
packetLen = RADIOLIB_SX127X_FIFO_THRESH - 1;
this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7);
}
this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, const_cast<uint8_t*>(data), packetLen);
// set RF switch (if present)
this->mod->setRfSwitchState(Module::MODE_TX);
// start transmission
state |= setMode(RADIOLIB_SX127X_TX);
RADIOLIB_ASSERT(state);
return(RADIOLIB_ERR_NONE);
}
int16_t SX127x::finishTransmit() {
// wait for at least 1 bit at the lowest possible bit rate before clearing IRQ flags
// not doing this and clearing RADIOLIB_SX127X_FLAG_FIFO_OVERRUN will dump the FIFO,
@ -1776,6 +1641,161 @@ int16_t SX127x::getModem(ModemType_t* modem) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
int16_t SX127x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
int16_t state;
switch(mode) {
case(RADIOLIB_RADIO_MODE_RX): {
this->rxMode = RADIOLIB_SX127X_RXCONTINUOUS;
// set mode to standby
state = setMode(RADIOLIB_SX127X_STANDBY);
RADIOLIB_ASSERT(state);
// set DIO pin mapping
state = this->setIrqFlags(getIrqMapped(cfg->receive.irqFlags & cfg->receive.irqMask));
RADIOLIB_ASSERT(state);
int16_t modem = getActiveModem();
if(modem == RADIOLIB_SX127X_LORA) {
if(cfg->receive.timeout != 0) {
// for non-zero timeout value, change mode to Rx single and set the timeout
this->rxMode = RADIOLIB_SX127X_RXSINGLE;
uint8_t msb_sym = (cfg->receive.timeout > 0x3FF) ? 0x3 : (uint8_t)(cfg->receive.timeout >> 8);
uint8_t lsb_sym = (cfg->receive.timeout > 0x3FF) ? 0xFF : (uint8_t)(cfg->receive.timeout & 0xFF);
state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, msb_sym, 1, 0);
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB, lsb_sym);
RADIOLIB_ASSERT(state);
}
// in FHSS mode, enable channel change interrupt
if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) {
state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 5, 4);
}
// in implicit header mode, use the provided length if it is nonzero
// otherwise we trust the user has previously set the payload length manually
if((this->implicitHdr) && (cfg->receive.len != 0)) {
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, cfg->receive.len);
this->packetLength = cfg->receive.len;
}
// apply fixes to errata
RADIOLIB_ERRATA_SX127X(true);
// clear interrupt flags
clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
// set FIFO pointers
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX);
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX);
RADIOLIB_ASSERT(state);
} else if(modem == RADIOLIB_SX127X_FSK_OOK) {
// clear interrupt flags
clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
// FSK modem does not distinguish between Rx single and continuous
this->rxMode = RADIOLIB_SX127X_RX;
}
} break;
case(RADIOLIB_RADIO_MODE_TX): {
// set mode to standby
state = setMode(RADIOLIB_SX127X_STANDBY);
int16_t modem = getActiveModem();
if(modem == RADIOLIB_SX127X_LORA) {
// check packet length
if(cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH) {
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
// set DIO mapping
if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) {
this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4);
} else {
this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE, 7, 6);
}
// apply fixes to errata
RADIOLIB_ERRATA_SX127X(false);
// clear interrupt flags
clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
// set packet length
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, cfg->transmit.len);
// set FIFO pointers
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX);
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX);
} else if(modem == RADIOLIB_SX127X_FSK_OOK) {
// clear interrupt flags
clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
// set DIO mapping
if(cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) {
this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY, 5, 4);
} else {
this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6);
}
// set packet length - increased by 1 when address filter is enabled
uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1);
if(this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) {
if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) {
this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.len + 1);
this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.addr);
} else {
this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.len);
}
}
}
// write packet to FIFO
size_t packetLen = cfg->transmit.len;
if((modem == RADIOLIB_SX127X_FSK_OOK) && (cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK)) {
packetLen = RADIOLIB_SX127X_FIFO_THRESH - 1;
this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7);
}
this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.data, packetLen);
} break;
default:
return(RADIOLIB_ERR_UNSUPPORTED);
}
this->stagedMode = mode;
return(state);
}
int16_t SX127x::launchMode() {
int16_t state;
switch(this->stagedMode) {
case(RADIOLIB_RADIO_MODE_RX): {
this->mod->setRfSwitchState(Module::MODE_RX);
state = setMode(this->rxMode);
RADIOLIB_ASSERT(state);
} break;
case(RADIOLIB_RADIO_MODE_TX): {
this->mod->setRfSwitchState(Module::MODE_TX);
state = setMode(RADIOLIB_SX127X_TX);
RADIOLIB_ASSERT(state);
} break;
default:
return(RADIOLIB_ERR_UNSUPPORTED);
}
this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
return(state);
}
#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
void SX127x::setDirectAction(void (*func)(void)) {
setDio1Action(func, this->mod->hal->GpioInterruptRising);

View file

@ -586,6 +586,7 @@ class SX127x: public PhysicalLayer {
using PhysicalLayer::transmit;
using PhysicalLayer::receive;
using PhysicalLayer::startTransmit;
using PhysicalLayer::startReceive;
using PhysicalLayer::readData;
// constructor
@ -798,15 +799,6 @@ class SX127x: public PhysicalLayer {
*/
bool fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen);
/*!
\brief Interrupt-driven binary transmit method. Will start transmitting arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem.
\param data Binary data that will be transmitted.
\param len Length of binary data to transmit (in bytes).
\param addr Node address to transmit the packet to. Only used in FSK mode.
\returns \ref status_codes
*/
int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override;
/*!
\brief Clean up after transmission is done.
\returns \ref status_codes
@ -820,19 +812,6 @@ class SX127x: public PhysicalLayer {
*/
int16_t startReceive() override;
/*!
\brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer.
\param timeout Receive mode type and/or raw timeout value in symbols.
When set to 0, the timeout will be infinite and the device will remain
in Rx mode until explicitly commanded to stop (Rx continuous mode).
When non-zero (maximum 1023), the device will be set to Rx single mode and timeout will be set.
\param irqFlags Sets the IRQ flags, defaults to RX done, RX timeout, CRC error and header error.
\param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RX done.
\param len Expected length of packet to be received. Required for LoRa spreading factor 6.
\returns \ref status_codes
*/
int16_t startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK, size_t len = 0) override;
/*!
\brief Reads data that was received after calling startReceive method. When the packet length is not known in advance,
getPacketLength method must be called BEFORE calling readData!
@ -1163,6 +1142,12 @@ class SX127x: public PhysicalLayer {
\returns \ref status_codes
*/
int16_t getModem(ModemType_t* modem) override;
/*! \copydoc PhysicalLayer::stageMode */
int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) override;
/*! \copydoc PhysicalLayer::launchMode */
int16_t launchMode() override;
#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
/*!
@ -1268,6 +1253,7 @@ class SX127x: public PhysicalLayer {
float dataRate = 0;
bool packetLengthQueried = false; // FSK packet length is the first byte in FIFO, length can only be queried once
uint8_t packetLengthConfig = RADIOLIB_SX127X_PACKET_VARIABLE;
uint8_t rxMode = RADIOLIB_SX127X_RXCONTINUOUS;
int16_t config();
int16_t directMode();

View file

@ -513,70 +513,6 @@ void SX128x::clearPacketSentAction() {
this->clearDio1Action();
}
int16_t SX128x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) {
// suppress unused variable warning
(void)addr;
// check packet length
if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) {
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
// set packet Length
int16_t state = RADIOLIB_ERR_NONE;
uint8_t modem = getPacketType();
if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, len, this->crcLoRa, this->invertIQEnabled);
} else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) {
state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, len);
} else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) {
state = setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening);
} else {
return(RADIOLIB_ERR_WRONG_MODEM);
}
RADIOLIB_ASSERT(state);
// update output power
state = setTxParams(this->power);
RADIOLIB_ASSERT(state);
// set buffer pointers
state = setBufferBaseAddress();
RADIOLIB_ASSERT(state);
// write packet to buffer
if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) {
// first 2 bytes of BLE payload are PDU header
state = writeBuffer(const_cast<uint8_t*>(data), len, 2);
RADIOLIB_ASSERT(state);
} else {
state = writeBuffer(const_cast<uint8_t*>(data), len);
RADIOLIB_ASSERT(state);
}
// set DIO mapping
state = setDioIrqParams(RADIOLIB_SX128X_IRQ_TX_DONE | RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT, RADIOLIB_SX128X_IRQ_TX_DONE);
RADIOLIB_ASSERT(state);
// clear interrupt flags
state = clearIrqStatus();
RADIOLIB_ASSERT(state);
// set RF switch (if present)
this->mod->setRfSwitchState(Module::MODE_TX);
// start transmission
state = setTx(RADIOLIB_SX128X_TX_TIMEOUT_NONE);
RADIOLIB_ASSERT(state);
// wait for BUSY to go low (= PA ramp up done)
while(this->mod->hal->digitalRead(this->mod->getGpio())) {
this->mod->hal->yield();
}
return(state);
}
int16_t SX128x::finishTransmit() {
// clear interrupt flags
clearIrqStatus();
@ -589,49 +525,6 @@ int16_t SX128x::startReceive() {
return(this->startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
}
int16_t SX128x::startReceive(uint16_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) {
// in implicit header mode, use the provided length if it is nonzero
// otherwise we trust the user has previously set the payload length manually
if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (len != 0)) {
this->payloadLen = len;
}
// check active modem
if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
// set DIO mapping
if(timeout != RADIOLIB_SX128X_RX_TIMEOUT_INF) {
irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT);
}
int16_t state = setDioIrqParams(getIrqMapped(irqFlags), getIrqMapped(irqMask));
RADIOLIB_ASSERT(state);
// set buffer pointers
state = setBufferBaseAddress();
RADIOLIB_ASSERT(state);
// clear interrupt flags
state = clearIrqStatus();
RADIOLIB_ASSERT(state);
// set implicit mode and expected len if applicable
if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA)) {
state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled);
RADIOLIB_ASSERT(state);
}
// set RF switch (if present)
this->mod->setRfSwitchState(Module::MODE_RX);
// set mode to receive
state = setRx(timeout);
return(state);
}
int16_t SX128x::readData(uint8_t* data, size_t len) {
// check active modem
if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
@ -1493,6 +1386,128 @@ int16_t SX128x::invertIQ(bool enable) {
return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled));
}
int16_t SX128x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
int16_t state;
switch(mode) {
case(RADIOLIB_RADIO_MODE_RX): {
// in implicit header mode, use the provided length if it is nonzero
// otherwise we trust the user has previously set the payload length manually
if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (cfg->receive.len != 0)) {
this->payloadLen = cfg->receive.len;
}
// check active modem
if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
// set DIO mapping
if(cfg->receive.timeout != RADIOLIB_SX128X_RX_TIMEOUT_INF) {
cfg->receive.irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT);
}
state = setDioIrqParams(getIrqMapped(cfg->receive.irqFlags), getIrqMapped(cfg->receive.irqMask));
RADIOLIB_ASSERT(state);
// set buffer pointers
state = setBufferBaseAddress();
RADIOLIB_ASSERT(state);
// clear interrupt flags
state = clearIrqStatus();
RADIOLIB_ASSERT(state);
// set implicit mode and expected len if applicable
if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA)) {
state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled);
RADIOLIB_ASSERT(state);
}
this->rxTimeout = cfg->receive.timeout;
} break;
case(RADIOLIB_RADIO_MODE_TX): {
// check packet length
if(cfg->transmit.len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) {
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
// set packet Length
uint8_t modem = getPacketType();
if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcLoRa, this->invertIQEnabled);
} else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) {
state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, cfg->transmit.len);
} else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) {
state = setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening);
} else {
return(RADIOLIB_ERR_WRONG_MODEM);
}
RADIOLIB_ASSERT(state);
// update output power
state = setTxParams(this->power);
RADIOLIB_ASSERT(state);
// set buffer pointers
state = setBufferBaseAddress();
RADIOLIB_ASSERT(state);
// write packet to buffer
if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) {
// first 2 bytes of BLE payload are PDU header
state = writeBuffer(cfg->transmit.data, cfg->transmit.len, 2);
RADIOLIB_ASSERT(state);
} else {
state = writeBuffer(cfg->transmit.data, cfg->transmit.len);
RADIOLIB_ASSERT(state);
}
// set DIO mapping
state = setDioIrqParams(RADIOLIB_SX128X_IRQ_TX_DONE | RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT, RADIOLIB_SX128X_IRQ_TX_DONE);
RADIOLIB_ASSERT(state);
// clear interrupt flags
state = clearIrqStatus();
RADIOLIB_ASSERT(state);
} break;
default:
return(RADIOLIB_ERR_UNSUPPORTED);
}
this->stagedMode = mode;
return(state);
}
int16_t SX128x::launchMode() {
int16_t state;
switch(this->stagedMode) {
case(RADIOLIB_RADIO_MODE_RX): {
this->mod->setRfSwitchState(Module::MODE_RX);
state = setRx(this->rxTimeout);
RADIOLIB_ASSERT(state);
} break;
case(RADIOLIB_RADIO_MODE_TX): {
this->mod->setRfSwitchState(Module::MODE_TX);
state = setTx(RADIOLIB_SX128X_TX_TIMEOUT_NONE);
RADIOLIB_ASSERT(state);
// wait for BUSY to go low (= PA ramp up done)
while(this->mod->hal->digitalRead(this->mod->getGpio())) {
this->mod->hal->yield();
}
} break;
default:
return(RADIOLIB_ERR_UNSUPPORTED);
}
this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
return(state);
}
#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
void SX128x::setDirectAction(void (*func)(void)) {
// SX128x is unable to perform direct mode reception

View file

@ -354,6 +354,7 @@ class SX128x: public PhysicalLayer {
using PhysicalLayer::transmit;
using PhysicalLayer::receive;
using PhysicalLayer::startTransmit;
using PhysicalLayer::startReceive;
using PhysicalLayer::readData;
/*!
@ -530,16 +531,6 @@ class SX128x: public PhysicalLayer {
*/
void clearPacketSentAction() override;
/*!
\brief Interrupt-driven binary transmit method.
Overloads for string-based transmissions are implemented in PhysicalLayer.
\param data Binary data to be sent.
\param len Number of bytes to send.
\param addr Address to send the data to. Unsupported, compatibility only.
\returns \ref status_codes
*/
int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override;
/*!
\brief Clean up after transmission is done.
\returns \ref status_codes
@ -554,20 +545,6 @@ class SX128x: public PhysicalLayer {
*/
int16_t startReceive() override;
/*!
\brief Interrupt-driven receive method. DIO1 will be activated when full packet is received.
\param timeout Raw timeout value, expressed as multiples of 15.625 us. Defaults to
RADIOLIB_SX128X_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode),
set to RADIOLIB_SX128X_RX_TIMEOUT_NONE for no timeout (Rx single mode).
If timeout other than infinite is set, signal will be generated on DIO1.
\param irqFlags Sets the IRQ flags, defaults to RX done, RX timeout, CRC error and header error.
\param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RX done.
\param len Only for PhysicalLayer compatibility, not used.
\returns \ref status_codes
*/
int16_t startReceive(uint16_t timeout, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK, size_t len = 0);
/*!
\brief Reads the current IRQ status.
\returns IRQ status bits
@ -863,6 +840,12 @@ class SX128x: public PhysicalLayer {
\returns \ref status_codes
*/
int16_t invertIQ(bool enable) override;
/*! \copydoc PhysicalLayer::stageMode */
int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) override;
/*! \copydoc PhysicalLayer::launchMode */
int16_t launchMode() override;
#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
/*!
@ -920,6 +903,7 @@ class SX128x: public PhysicalLayer {
// common parameters
uint8_t power = 0;
uint32_t rxTimeout = 0;
// cached LoRa parameters
uint8_t invertIQEnabled = RADIOLIB_SX128X_LORA_IQ_STANDARD;

View file

@ -906,14 +906,22 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent)
RADIOLIB_ASSERT(state);
// calculate JoinRequest time-on-air in milliseconds
RadioLibTime_t toa = this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_JOIN_REQUEST_LEN) / 1000;
if(this->dwellTimeUp) {
RadioLibTime_t toa = this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_JOIN_REQUEST_LEN) / 1000;
if(toa > this->dwellTimeUp) {
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Dwell time exceeded: ToA = %lu, max = %d", (unsigned long)toa, this->dwellTimeUp);
return(RADIOLIB_ERR_DWELL_TIME_EXCEEDED);
}
}
RadioModeConfig_t modeCfg;
modeCfg.transmit.data = joinRequestMsg;
modeCfg.transmit.len = RADIOLIB_LORAWAN_JOIN_REQUEST_LEN;
modeCfg.transmit.addr = 0;
state = this->phyLayer->stageMode(RADIOLIB_RADIO_MODE_TX, &modeCfg);
RADIOLIB_ASSERT(state);
// if requested, delay until transmitting JoinRequest
RadioLibTime_t tNow = mod->hal->millis();
if(this->tUplink > tNow) {
@ -923,8 +931,26 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent)
}
}
// send it
state = this->phyLayer->transmit(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN);
// start transmission
state = this->phyLayer->launchMode();
RADIOLIB_ASSERT(state);
// sleep for the duration of the transmission
mod->hal->delay(toa);
RadioLibTime_t txEnd = mod->hal->millis();
// wait for an additional transmission duration as Tx timeout period
while(!mod->hal->digitalRead(mod->getIrq())) {
// yield for multi-threaded platforms
mod->hal->yield();
if(mod->hal->millis() > txEnd + toa) {
return(RADIOLIB_ERR_TX_TIMEOUT);
}
}
state = this->phyLayer->finishTransmit();
// set the timestamp so that we can measure when to start receiving
this->rxDelayStart = mod->hal->millis();
RADIOLIB_ASSERT(state);
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinRequest sent (DevNonce = %d) <-- Rx Delay start", this->devNonce);
@ -935,7 +961,7 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent)
LoRaWANNode::hton<uint16_t>(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE], this->devNonce);
// set the Time on Air of the JoinRequest
this->lastToA = this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_JOIN_REQUEST_LEN) / 1000;
this->lastToA = toa;
// configure Rx1 and Rx2 delay for JoinAccept message - these are re-configured once a valid JoinAccept is received
this->rxDelays[1] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS;
@ -1270,7 +1296,6 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u
Module* mod = this->phyLayer->getMod();
// check if the Rx windows were closed after sending the previous uplink
// this FORCES a user to call downlink() after an uplink()
if(this->rxDelayEnd < this->rxDelayStart) {
// not enough time elapsed since the last uplink, we may still be in an Rx window
return(RADIOLIB_ERR_UPLINK_UNAVAILABLE);
@ -1295,6 +1320,22 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u
RADIOLIB_LORAWAN_UPLINK,
this->txPowerMax - 2*this->txPowerSteps);
RADIOLIB_ASSERT(state);
// check whether dwell time limitation is exceeded
RadioLibTime_t toa = this->phyLayer->getTimeOnAir(len) / 1000;
if(this->dwellTimeUp) {
if(toa > this->dwellTimeUp) {
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Dwell time exceeded: ToA = %lu, max = %d", (unsigned long)toa, this->dwellTimeUp);
return(RADIOLIB_ERR_DWELL_TIME_EXCEEDED);
}
}
RadioModeConfig_t modeCfg;
modeCfg.transmit.data = in;
modeCfg.transmit.len = len;
modeCfg.transmit.addr = 0;
state = this->phyLayer->stageMode(RADIOLIB_RADIO_MODE_TX, &modeCfg);
RADIOLIB_ASSERT(state);
// if requested, wait until transmitting uplink
tNow = mod->hal->millis();
@ -1305,14 +1346,31 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u
}
}
state = this->phyLayer->transmit(in, len);
// start transmission
state = this->phyLayer->launchMode();
RADIOLIB_ASSERT(state);
// sleep for the duration of the transmission
mod->hal->delay(toa);
RadioLibTime_t txEnd = mod->hal->millis();
// wait for an additional transmission duration as Tx timeout period
while(!mod->hal->digitalRead(mod->getIrq())) {
// yield for multi-threaded platforms
mod->hal->yield();
if(mod->hal->millis() > txEnd + toa) {
return(RADIOLIB_ERR_TX_TIMEOUT);
}
}
state = this->phyLayer->finishTransmit();
// set the timestamp so that we can measure when to start receiving
this->rxDelayStart = mod->hal->millis();
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink sent <-- Rx Delay start");
// increase Time on Air of the uplink sequence
this->lastToA += this->phyLayer->getTimeOnAir(len) / 1000;
this->lastToA += toa;
return(state);
}
@ -1364,8 +1422,17 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne
RADIOLIB_ASSERT(state);
// calculate the Rx timeout
RadioLibTime_t timeoutHost = this->phyLayer->getTimeOnAir(0) + 2*this->scanGuard*1000;
RadioLibTime_t timeoutHost = this->phyLayer->getTimeOnAir(0) + this->scanGuard*1000;
RadioLibTime_t timeoutMod = this->phyLayer->calculateRxTimeout(timeoutHost);
// TODO remove default arguments
RadioModeConfig_t modeCfg;
modeCfg.receive.timeout = timeoutMod;
modeCfg.receive.irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS;
modeCfg.receive.irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK;
modeCfg.receive.len = 0;
state = this->phyLayer->stageMode(RADIOLIB_RADIO_MODE_RX, &modeCfg);
RADIOLIB_ASSERT(state);
// wait for the start of the Rx window
RadioLibTime_t waitLen = tReference + dlDelays[window] - mod->hal->millis();
@ -1380,14 +1447,13 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne
mod->hal->delay(waitLen);
// open Rx window by starting receive with specified timeout
// TODO remove default arguments
state = this->phyLayer->startReceive(timeoutMod, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0);
state = this->phyLayer->launchMode();
tOpen = mod->hal->millis();
RADIOLIB_ASSERT(state);
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opening Rx%d window (%d ms timeout)... <-- Rx Delay end ", window, (int)(timeoutHost / 1000 + scanGuard / 2));
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opening Rx%d window (%d ms timeout)... <-- Rx Delay end ", window, (int)(timeoutHost / 1000 + 2));
// wait for the timeout to complete (and a small additional delay)
mod->hal->delay(timeoutHost / 1000 + this->scanGuard / 2);
mod->hal->delay(timeoutHost / 1000 + 2);
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", window);
// if the IRQ bit for Rx Timeout is not set, something is received, so stop the windows

View file

@ -850,7 +850,7 @@ class LoRaWANNode {
500 is the **maximum** value, but it is not a good idea to go anywhere near that.
If you have to go above 50 you probably have a bug somewhere. Check your device timing.
*/
RadioLibTime_t scanGuard = 10;
RadioLibTime_t scanGuard = 5;
#if !RADIOLIB_GODMODE
protected:

View file

@ -132,11 +132,18 @@ int16_t PhysicalLayer::startReceive() {
}
int16_t PhysicalLayer::startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) {
(void)timeout;
(void)irqFlags;
(void)irqMask;
(void)len;
return(RADIOLIB_ERR_UNSUPPORTED);
RadioModeConfig_t cfg = {
.receive = {
.timeout = timeout,
.irqFlags = irqFlags,
.irqMask = irqMask,
.len = len,
}
};
int16_t state = this->stageMode(RADIOLIB_RADIO_MODE_RX, &cfg);
RADIOLIB_ASSERT(state);
return(this->launchMode());
}
#if defined(RADIOLIB_BUILD_ARDUINO)
@ -150,10 +157,17 @@ int16_t PhysicalLayer::startTransmit(const char* str, uint8_t addr) {
}
int16_t PhysicalLayer::startTransmit(const uint8_t* data, size_t len, uint8_t addr) {
(void)data;
(void)len;
(void)addr;
return(RADIOLIB_ERR_UNSUPPORTED);
RadioModeConfig_t cfg = {
.transmit = {
.data = data,
.len = len,
.addr = addr,
}
};
int16_t state = this->stageMode(RADIOLIB_RADIO_MODE_TX, &cfg);
RADIOLIB_ASSERT(state);
return(this->launchMode());
}
int16_t PhysicalLayer::finishTransmit() {
@ -537,6 +551,16 @@ int16_t PhysicalLayer::getModem(ModemType_t* modem) {
return(RADIOLIB_ERR_UNSUPPORTED);
}
int16_t PhysicalLayer::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
(void)mode;
(void)cfg;
return(RADIOLIB_ERR_UNSUPPORTED);
}
int16_t PhysicalLayer::launchMode() {
return(RADIOLIB_ERR_UNSUPPORTED);
}
#if RADIOLIB_INTERRUPT_TIMING
void PhysicalLayer::setInterruptSetup(void (*func)(uint32_t)) {
Module* mod = getMod();

View file

@ -130,6 +130,58 @@ union ChannelScanConfig_t {
RSSIScanConfig_t rssi;
};
struct StandbyConfig_t {
/*! \brief Module-specific standby mode configuration. */
uint8_t mode;
};
struct ReceiveConfig_t {
/*! \brief Raw timeout value. Some modules use this argument to specify operation mode (single vs. continuous receive). */
uint32_t timeout;
/*! \brief Sets the IRQ flags. */
RadioLibIrqFlags_t irqFlags;
/*! \brief Sets the mask of IRQ flags that will trigger the radio interrupt pin. */
RadioLibIrqFlags_t irqMask;
/*! \brief Packet length, needed for some modules under special circumstances (e.g. LoRa implicit header mode). */
size_t len;
};
struct TransmitConfig_t {
/*! \brief Binary data that will be transmitted. */
const uint8_t* data;
/*! \brief Length of binary data to transmit (in bytes). */
size_t len;
/*! \brief Node address to transmit the packet to. Only used in FSK mode. */
uint8_t addr;
};
struct SleepConfig_t {
/*! \brief Module-specific sleep mode configuration. */
uint8_t mode;
};
union RadioModeConfig_t {
/*! \brief Interpretation for standby mode */
StandbyConfig_t standby;
/*! \brief Interpretation for Rx mode */
ReceiveConfig_t receive;
/*! \brief Interpretation for Tx mode */
TransmitConfig_t transmit;
/*! \brief Interpretation for scanning */
ChannelScanConfig_t scan;
/*! \brief Interpretation for sleep mode */
SleepConfig_t sleep;
};
/*!
\enum ModemType_t
\brief Type of modem, used by setModem.
@ -140,6 +192,19 @@ enum ModemType_t {
RADIOLIB_MODEM_LRFHSS,
};
/*!
\enum RadioModeType_t
\brief Basic radio operating modes, used by stageMode.
*/
enum RadioModeType_t {
RADIOLIB_RADIO_MODE_NONE = 0,
RADIOLIB_RADIO_MODE_STANDBY,
RADIOLIB_RADIO_MODE_RX,
RADIOLIB_RADIO_MODE_TX,
RADIOLIB_RADIO_MODE_SCAN,
RADIOLIB_RADIO_MODE_SLEEP,
};
/*!
\class PhysicalLayer
@ -241,7 +306,7 @@ class PhysicalLayer {
\param len Packet length, needed for some modules under special circumstances (e.g. LoRa implicit header mode).
\returns \ref status_codes
*/
virtual int16_t startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len);
virtual int16_t startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK, size_t len = 0);
/*!
\brief Binary receive method. Must be implemented in module class.
@ -669,6 +734,20 @@ class PhysicalLayer {
*/
virtual int16_t getModem(ModemType_t* modem);
/*!
\brief Stage mode of the radio to be launched later using launchMode.
\param mode Radio mode to prepare.
\param cfg Configuration of this mode (mode-dependent).
\returns \ref status_codes
*/
virtual int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg);
/*!
\brief Launch previously staged mode.
\returns \ref status_codes
*/
virtual int16_t launchMode();
#if RADIOLIB_INTERRUPT_TIMING
/*!
@ -690,6 +769,7 @@ class PhysicalLayer {
protected:
#endif
uint32_t irqMap[10] = { 0 };
RadioModeType_t stagedMode = RADIOLIB_RADIO_MODE_NONE;
#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
void updateDirectBuffer(uint8_t bit);