Merge pull request #84 from BarryPSmith/receiveDutyCycle

Added sx126x receive duty cycle interface
pull/88/head
Jan Gromeš 2019-12-05 15:57:14 +01:00 zatwierdzone przez GitHub
commit 104c656860
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
4 zmienionych plików z 131 dodań i 7 usunięć

Wyświetl plik

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

Wyświetl plik

@ -524,6 +524,21 @@
*/
#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
/*!
\}
*/

Wyświetl plik

@ -18,6 +18,7 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, float
_ldro = 0x00;
_crcType = SX126X_LORA_CRC_ON;
_preambleLength = preambleLength;
_tcxoDelay = 0;
// set mode to 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 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
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) {
@ -457,12 +539,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);
}
@ -1072,6 +1148,8 @@ int16_t SX126x::setTCXO(float voltage, uint32_t delay) {
data[2] = (uint8_t)((delayValue >> 8) & 0xFF);
data[3] = (uint8_t)(delayValue & 0xFF);
_tcxoDelay = delay;
// enable TCXO control on DIO3
return(SPIwriteCommand(SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4));
}

Wyświetl plik

@ -499,6 +499,31 @@ 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.
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.
@ -747,7 +772,6 @@ class SX126x: public PhysicalLayer {
\returns Expected time-on-air in microseconds.
*/
uint32_t getTimeOnAir(size_t len);
#ifndef RADIOLIB_GODMODE
protected:
#endif
@ -777,6 +801,7 @@ class SX126x: public PhysicalLayer {
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 +828,8 @@ class SX126x: public PhysicalLayer {
float _dataRate;
uint32_t _tcxoDelay;
int16_t config(uint8_t modem);
// common low-level SPI interface