Added sx126x receive duty cycle interface

This commit is contained in:
BarryPSmith 2019-12-03 22:43:10 -08:00
parent f468608310
commit a20f62da2f
4 changed files with 136 additions and 10 deletions

View file

@ -115,6 +115,8 @@ setDio2AsRfSwitch KEYWORD2
getTimeOnAir KEYWORD2
setSyncBits KEYWORD2
setWhitening KEYWORD2
startReceiveDutyCycle KEYWORD2
startReceiveDutyCycleAuto KEYWORD2
# ESP8266
join KEYWORD2

View file

@ -305,6 +305,19 @@
*/
#define ERR_INVALID_ENCODING -23
/*!
\brief The supplied sleep period is invalid.
The specified sleep period is shorter than the time necessary to sleep and wake the hardware,
including TCXO delay
*/
#define ERR_INVALID_SLEEP_PERIOD -24
/*!
\brief A specified value would cause an integer overflow
*/
#define ERR_OVERFLOW -25
// RF69-specific status codes
/*!

View file

@ -443,7 +443,91 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
}
int16_t SX126x::startReceive(uint32_t timeout) {
// set DIO mapping
int16_t state = startReceiveCommon();
if(state != ERR_NONE) {
return(state);
}
// set mode to receive
state = setRx(timeout);
return(state);
}
int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod_us, uint32_t sleepPeriod_us)
{
// datasheet claims time to go to sleep is ~500us, same to wake up.
// compensate for that 1ms + tcxo delay:
uint32_t transitionTime = _tcxoDelay_us + 1000;
if (sleepPeriod_us < transitionTime + 16) {
return(ERR_INVALID_SLEEP_PERIOD);
}
sleepPeriod_us -= transitionTime;
// divide by 15.625
uint32_t rxPeriodRaw = (rxPeriod_us * 8) / 125;
uint32_t sleepPeriodRaw = (sleepPeriod_us * 8) / 125;
// 24 bit limit:
if ((rxPeriodRaw & 0xFF000000) || (sleepPeriodRaw & 0xFF000000)) {
return(ERR_OVERFLOW);
}
int16_t state = startReceiveCommon();
if (state != ERR_NONE) {
return(state);
}
byte data[6] = {
(rxPeriodRaw >> 16) & 0xFF, (rxPeriodRaw >> 8) & 0xFF, rxPeriodRaw & 0xFF,
(sleepPeriodRaw >> 16) & 0xFF, (sleepPeriodRaw >> 8) & 0xFF, sleepPeriodRaw & 0xFF
};
return(SPIwriteCommand(SX126X_CMD_SET_RX_DUTY_CYCLE, data, 6));
}
int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_t minSymbols)
{
if (senderPreambleLength == 0) {
senderPreambleLength = _preambleLength;
}
// worst case is that the sender starts transmiting when we're just less than minSymbols from going back to sleep.
// in this case, we don't catch minSymbols before going to sleep,
// so we must be awake for at least that long before the sender stops transmitting.
uint16_t sleepSymbols = senderPreambleLength - 2 * minSymbols;
// if we're not to sleep at all, just use the standard startReceive.
if (2 * minSymbols > senderPreambleLength) {
return(startReceive());
}
uint32_t symbolLength_us = ((uint32_t)(10 * 1000) << _sf) / (10 * _bwKhz);
uint32_t sleepPeriod_us = symbolLength_us * sleepSymbols;
RADIOLIB_DEBUG_PRINT(F("Auto sleep period: "));
RADIOLIB_DEBUG_PRINTLN(sleepPeriod_us);
// when the unit detects a preamble, it starts a timer that will timeout if it doesn't receive a header in time.
// the duration is sleepPeriod + 2 * wakePeriod.
// The sleepPeriod doesn't take into account shutdown and startup time for the unit (~1ms)
// We need to ensure that the timout is longer than senderPreambleLength.
// So we must satisfy: wakePeriod > (preamblePeriod - (sleepPeriod - 1000)) / 2. (A)
// we also need to ensure the unit is awake to see at least minSymbols. (B)
uint32_t wakePeriod_us = max(
(symbolLength_us * (senderPreambleLength + 1) - (sleepPeriod_us - 1000)) / 2, // (A)
symbolLength_us * (minSymbols + 1)); //(B)
RADIOLIB_DEBUG_PRINT(F("Auto wake period: "));
RADIOLIB_DEBUG_PRINTLN(wakePeriod_us);
//If our sleep period is shorter than our transition time, just use the standard startReceive
if (sleepPeriod_us < _tcxoDelay_us + 1016) {
return(startReceive());
}
return(startReceiveDutyCycle(wakePeriod_us, sleepPeriod_us));
}
int16_t SX126x::startReceiveCommon()
{
// set DIO mapping
int16_t state = setDioIrqParams(SX126X_IRQ_RX_DONE | SX126X_IRQ_TIMEOUT | SX126X_IRQ_CRC_ERR | SX126X_IRQ_HEADER_ERR, SX126X_IRQ_RX_DONE);
if(state != ERR_NONE) {
return(state);
@ -457,13 +541,6 @@ int16_t SX126x::startReceive(uint32_t timeout) {
// clear interrupt flags
state = clearIrqStatus();
if(state != ERR_NONE) {
return(state);
}
// set mode to receive
state = setRx(timeout);
return(state);
}
@ -1041,6 +1118,8 @@ int16_t SX126x::setTCXO(float voltage, uint32_t delay) {
data[2] = (uint8_t)((delayValue >> 8) & 0xFF);
data[3] = (uint8_t)(delayValue & 0xFF);
_tcxoDelay_us = delay;
// enable TCXO control on DIO3
return(SPIwriteCommand(SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4));
}

View file

@ -499,6 +499,36 @@ class SX126x: public PhysicalLayer {
*/
int16_t startReceive(uint32_t timeout = SX126X_RX_TIMEOUT_INF);
/*!
\brief Interrupt-driven receive method where the device mostly sleeps and periodically wakes to listen.
\param rxPeriod_us The duration the receiver will be in Rx mode, in microseconds.
\param sleepPeriod_us The duration the receiver will not be in Rx mode, in microseconds.
\returns \ref status_codes
Note that this function assumes the unit will take 500us to change state. See datasheet [SECTION].
*/
int16_t startReceiveDutyCycle(uint32_t rxPeriod_us, uint32_t sleepPeriod_us);
/*!
\brief Calls \ref startReceiveDutyCycle with rxPeriod and sleepPeriod set so the unit shouldn't miss any messages.
\param senderPreambleLength Expected preamble length of the messages to receive.
If zero, uses the currently configured preamble length. Default zero.
\param minSymbols Parameters will be chosen to ensure that the unit will catch at least this many symbols of any preamble of the specified length.
Default 3.
Note that Semtech in the CAD application note state that 2 symbols are fine for CAD,
but in the RX duty cycle note specify that sleep duration should be 8 symbols less than preamble length (corresponding to minSymbols = 4).
Testing suggests that a value of 3 for minSymbols works at high SNR.
\returns \ref status_codes
*/
int16_t startReceiveDutyCycleAuto(uint16_t senderPreambleLength = 0, uint16_t minSymbols = 3);
/*!
\brief Reads data received after calling startReceive method.
@ -747,7 +777,6 @@ class SX126x: public PhysicalLayer {
\returns Expected time-on-air in microseconds.
*/
uint32_t getTimeOnAir(size_t len);
#ifndef RADIOLIB_GODMODE
protected:
#endif
@ -776,7 +805,8 @@ class SX126x: public PhysicalLayer {
uint32_t getPacketStatus();
uint16_t getDeviceErrors();
int16_t clearDeviceErrors();
int16_t startReceiveCommon();
int16_t setFrequencyRaw(float freq);
int16_t setOptimalHiPowerPaConfig(int8_t* inOutPower);
int16_t setPacketMode(uint8_t mode, uint8_t len);
@ -803,6 +833,8 @@ class SX126x: public PhysicalLayer {
float _dataRate;
uint32_t _tcxoDelay_us = 0;
int16_t config(uint8_t modem);
// common low-level SPI interface