Merge pull request #84 from BarryPSmith/receiveDutyCycle

Added sx126x receive duty cycle interface
This commit is contained in:
Jan Gromeš 2019-12-05 15:57:14 +01:00 committed by GitHub
commit 104c656860
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 131 additions and 7 deletions

View file

@ -115,6 +115,8 @@ setDio2AsRfSwitch KEYWORD2
getTimeOnAir KEYWORD2 getTimeOnAir KEYWORD2
setSyncBits KEYWORD2 setSyncBits KEYWORD2
setWhitening KEYWORD2 setWhitening KEYWORD2
startReceiveDutyCycle KEYWORD2
startReceiveDutyCycleAuto KEYWORD2
# ESP8266 # ESP8266
join KEYWORD2 join KEYWORD2
@ -246,3 +248,5 @@ ERR_INVALID_MODULATION_PARAMETERS LITERAL1
ERR_SPI_CMD_TIMEOUT LITERAL1 ERR_SPI_CMD_TIMEOUT LITERAL1
ERR_SPI_CMD_INVALID LITERAL1 ERR_SPI_CMD_INVALID LITERAL1
ERR_SPI_CMD_FAILED LITERAL1 ERR_SPI_CMD_FAILED LITERAL1
ERR_INVALID_SLEEP_PERIOD LITERAL1
ERR_INVALID_RX_PERIOD LITERAL1

View file

@ -524,6 +524,21 @@
*/ */
#define ERR_SPI_CMD_FAILED -707 #define ERR_SPI_CMD_FAILED -707
/*!
\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, or longer than the maximum possible
*/
#define ERR_INVALID_SLEEP_PERIOD -708
/*!
\brief The supplied Rx period is invalid.
The specified Rx period is shorter or longer than the hardware can handle.
*/
#define ERR_INVALID_RX_PERIOD -709
/*! /*!
\} \}
*/ */

View file

@ -18,6 +18,7 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, float
_ldro = 0x00; _ldro = 0x00;
_crcType = SX126X_LORA_CRC_ON; _crcType = SX126X_LORA_CRC_ON;
_preambleLength = preambleLength; _preambleLength = preambleLength;
_tcxoDelay = 0;
// set mode to standby // set mode to standby
int16_t state = standby(); int16_t state = standby();
@ -443,6 +444,87 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
} }
int16_t SX126x::startReceive(uint32_t timeout) { int16_t SX126x::startReceive(uint32_t timeout) {
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, uint32_t sleepPeriod) {
// datasheet claims time to go to sleep is ~500us, same to wake up, compensate for that with 1 ms + TCXO delay
uint32_t transitionTime = _tcxoDelay + 1000;
sleepPeriod -= transitionTime;
// divide by 15.625
uint32_t rxPeriodRaw = (rxPeriod * 8) / 125;
uint32_t sleepPeriodRaw = (sleepPeriod * 8) / 125;
// check 24 bit limit and zero value (likely not intended)
if((rxPeriodRaw & 0xFF000000) || (rxPeriodRaw == 0)) {
return(ERR_INVALID_RX_PERIOD);
}
// this check of the high byte also catches underflow when we subtracted transitionTime
if((sleepPeriodRaw & 0xFF000000) || (sleepPeriodRaw == 0)) {
return(ERR_INVALID_SLEEP_PERIOD);
}
int16_t state = startReceiveCommon();
if(state != ERR_NONE) {
return(state);
}
uint8_t 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 = ((uint32_t)(10 * 1000) << _sf) / (10 * _bwKhz);
uint32_t sleepPeriod = symbolLength * sleepSymbols;
RADIOLIB_DEBUG_PRINT(F("Auto sleep period: "));
RADIOLIB_DEBUG_PRINTLN(sleepPeriod);
// 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 = max(
(symbolLength * (senderPreambleLength + 1) - (sleepPeriod - 1000)) / 2, // (A)
symbolLength * (minSymbols + 1)); //(B)
RADIOLIB_DEBUG_PRINT(F("Auto wake period: "));
RADIOLIB_DEBUG_PRINTLN(wakePeriod);
//If our sleep period is shorter than our transition time, just use the standard startReceive
if(sleepPeriod < _tcxoDelay + 1016) {
return(startReceive());
}
return(startReceiveDutyCycle(wakePeriod, sleepPeriod));
}
int16_t SX126x::startReceiveCommon() {
// set DIO mapping // 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); 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) { if(state != ERR_NONE) {
@ -457,12 +539,6 @@ int16_t SX126x::startReceive(uint32_t timeout) {
// clear interrupt flags // clear interrupt flags
state = clearIrqStatus(); state = clearIrqStatus();
if(state != ERR_NONE) {
return(state);
}
// set mode to receive
state = setRx(timeout);
return(state); return(state);
} }
@ -1072,6 +1148,8 @@ int16_t SX126x::setTCXO(float voltage, uint32_t delay) {
data[2] = (uint8_t)((delayValue >> 8) & 0xFF); data[2] = (uint8_t)((delayValue >> 8) & 0xFF);
data[3] = (uint8_t)(delayValue & 0xFF); data[3] = (uint8_t)(delayValue & 0xFF);
_tcxoDelay = delay;
// enable TCXO control on DIO3 // enable TCXO control on DIO3
return(SPIwriteCommand(SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4)); return(SPIwriteCommand(SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4));
} }

View file

@ -499,6 +499,31 @@ class SX126x: public PhysicalLayer {
*/ */
int16_t startReceive(uint32_t timeout = SX126X_RX_TIMEOUT_INF); 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.
Note that this function assumes the unit will take 500us + TCXO_delay to change state. See datasheet section 13.1.7, version 1.2.
\param rxPeriod The duration the receiver will be in Rx mode, in microseconds.
\param sleepPeriod The duration the receiver will not be in Rx mode, in microseconds.
\returns \ref status_codes
*/
int16_t startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod);
/*!
\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 set to zero, the currently configured preamble length will be used. Defaults to 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. Defaults to 8.
According to Semtech, receiver requires 8 symbols to reliably latch a preamble. This makes this method redundant when transmitter preamble length is less than 17 (2*minSymbols + 1).
\returns \ref status_codes
*/
int16_t startReceiveDutyCycleAuto(uint16_t senderPreambleLength = 0, uint16_t minSymbols = 8);
/*! /*!
\brief Reads data received after calling startReceive method. \brief Reads data received after calling startReceive method.
@ -747,7 +772,6 @@ class SX126x: public PhysicalLayer {
\returns Expected time-on-air in microseconds. \returns Expected time-on-air in microseconds.
*/ */
uint32_t getTimeOnAir(size_t len); uint32_t getTimeOnAir(size_t len);
#ifndef RADIOLIB_GODMODE #ifndef RADIOLIB_GODMODE
protected: protected:
#endif #endif
@ -777,6 +801,7 @@ class SX126x: public PhysicalLayer {
uint16_t getDeviceErrors(); uint16_t getDeviceErrors();
int16_t clearDeviceErrors(); int16_t clearDeviceErrors();
int16_t startReceiveCommon();
int16_t setFrequencyRaw(float freq); int16_t setFrequencyRaw(float freq);
int16_t setOptimalHiPowerPaConfig(int8_t* inOutPower); int16_t setOptimalHiPowerPaConfig(int8_t* inOutPower);
int16_t setPacketMode(uint8_t mode, uint8_t len); int16_t setPacketMode(uint8_t mode, uint8_t len);
@ -803,6 +828,8 @@ class SX126x: public PhysicalLayer {
float _dataRate; float _dataRate;
uint32_t _tcxoDelay;
int16_t config(uint8_t modem); int16_t config(uint8_t modem);
// common low-level SPI interface // common low-level SPI interface