Add `calculateTimeOnAir()` method to relevant modules

pull/1596/head
GUVWAF 2025-09-13 14:22:21 +02:00
rodzic 690b63abe0
commit b6b3eafa18
12 zmienionych plików z 441 dodań i 55 usunięć

Wyświetl plik

@ -1203,7 +1203,124 @@ size_t LR11x0::getPacketLength(bool update, uint8_t* offset) {
return((size_t)len);
}
RadioLibTime_t LR11x0::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) {
// check active modem
if (modem == ModemType_t::RADIOLIB_MODEM_LORA) {
uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << dr.lora.spreadingFactor) / (dr.lora.bandwidth * 10) ;
uint8_t sfCoeff1_x4 = 17; // (4.25 * 4)
uint8_t sfCoeff2 = 8;
if(dr.lora.spreadingFactor == 5 || dr.lora.spreadingFactor == 6) {
sfCoeff1_x4 = 25; // 6.25 * 4
sfCoeff2 = 0;
}
uint8_t sfDivisor = 4*dr.lora.spreadingFactor;
if(pc.lora.ldrOptimize) {
sfDivisor = 4*(dr.lora.spreadingFactor - 2);
}
const int8_t bitsPerCrc = 16;
const int8_t N_symbol_header = pc.lora.implicitHeader ? 0 : 20;
// numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8)
int16_t bitCount = (int16_t) 8 * len + pc.lora.crcEnabled * bitsPerCrc - 4 * dr.lora.spreadingFactor + sfCoeff2 + N_symbol_header;
if(bitCount < 0) {
bitCount = 0;
}
// add (sfDivisor) - 1 to the numerator to give integer CEIL(...)
uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor);
// preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit
uint32_t nSymbol_x4 = (pc.lora.preambleLength + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * dr.lora.codingRate * 4;
// get time-on-air in us
return((symbolLength_us * nSymbol_x4) / 4);
} else if(modem == ModemType_t::RADIOLIB_MODEM_FSK) {
return((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (uint32_t)len * 8) / (dr.fsk.bitRate / 1000.0f)));
} else if(modem == ModemType_t::RADIOLIB_MODEM_LRFHSS) {
// calculate the number of bits based on coding rate
uint16_t N_bits;
switch(dr.lrFhss.cr) {
case RADIOLIB_LR11X0_LR_FHSS_CR_5_6:
N_bits = ((len * 6) + 4) / 5; // this is from the official LR11xx driver, but why the extra +4?
break;
case RADIOLIB_LR11X0_LR_FHSS_CR_2_3:
N_bits = (len * 3) / 2;
break;
case RADIOLIB_LR11X0_LR_FHSS_CR_1_2:
N_bits = len * 2;
break;
case RADIOLIB_LR11X0_LR_FHSS_CR_1_3:
N_bits = len * 3;
break;
default:
return(RADIOLIB_ERR_INVALID_CODING_RATE);
}
// calculate number of bits when accounting for unaligned last block
uint16_t N_payBits = (N_bits / RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS) * RADIOLIB_LR11X0_LR_FHSS_BLOCK_BITS;
uint16_t N_lastBlockBits = N_bits % RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS;
if(N_lastBlockBits) {
N_payBits += N_lastBlockBits + 2;
}
// add header bits
uint16_t N_totalBits = (RADIOLIB_LR11X0_LR_FHSS_HEADER_BITS * pc.lrFhss.hdrCount) + N_payBits;
return(((uint32_t)N_totalBits * 8 * 1000000UL) / RADIOLIB_LR11X0_LR_FHSS_BIT_RATE);
} else {
return(RADIOLIB_ERR_WRONG_MODEM);
}
return(0);
}
RadioLibTime_t LR11x0::getTimeOnAir(size_t len) {
ModemType_t modem;
int32_t state = this->getModem(&modem);
RADIOLIB_ASSERT(state);
DataRate_t dr = {};
PacketConfig_t pc = {};
switch(modem) {
case ModemType_t::RADIOLIB_MODEM_LORA: {
uint8_t cr = this->codingRate;
// We assume same calculation for short and long interleaving, so map CR values 0-4 and 5-7 to the same values
if (cr < 5) {
cr = cr + 4;
} else if (cr == 7) {
cr = cr + 1;
}
dr = {.lora = { .spreadingFactor = this->spreadingFactor, .bandwidth = this->bandwidthKhz, .codingRate = cr } };
pc = {.lora = { .preambleLength = this->preambleLengthLoRa, .implicitHeader = (this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) ? true : false, \
.crcEnabled = (this->crcTypeLoRa == RADIOLIB_LR11X0_LORA_CRC_ENABLED) ? true : false, \
.ldrOptimize = (bool)this->ldrOptimize } };
break;
}
case ModemType_t::RADIOLIB_MODEM_FSK: {
dr = {.fsk = { .bitRate = (float)this->bitRate / 1000.0f, .freqDev = (float)this->frequencyDev } };
uint8_t crcLen = 0;
if(this->crcTypeGFSK == RADIOLIB_LR11X0_GFSK_CRC_1_BYTE || this->crcTypeGFSK == RADIOLIB_LR11X0_GFSK_CRC_1_BYTE_INV) {
crcLen = 1;
} else if(this->crcTypeGFSK == RADIOLIB_LR11X0_GFSK_CRC_2_BYTE || this->crcTypeGFSK == RADIOLIB_LR11X0_GFSK_CRC_2_BYTE_INV) {
crcLen = 2;
}
pc = {.fsk = { .preambleLength = this->preambleLengthGFSK, .syncWordLength = this->syncWordLength, .crcLength = crcLen } };
break;
}
case ModemType_t::RADIOLIB_MODEM_LRFHSS: {
dr = {.lrFhss = { .bw = this->lrFhssBw, .cr = this->lrFhssCr, .narrowGrid = (this->lrFhssGrid == RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_NON_FCC) ? true : false } };
pc = {.lrFhss = { .hdrCount = this->lrFhssHdrCount } };
break;
}
default:
return(RADIOLIB_ERR_WRONG_MODEM);
}
return(this->calculateTimeOnAir(modem, dr, pc, len));
}
RadioLibTime_t LR11x0::getTimeOnAir_old(size_t len) {
// check active modem
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
(void)getPacketType(&type);

Wyświetl plik

@ -1372,6 +1372,16 @@ class LR11x0: public PhysicalLayer {
*/
int16_t getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC);
/*!
\brief Calculate the expected time-on-air for a given modem, data rate, packet configuration and payload size.
\param modem Modem type.
\param dr Data rate.
\param pc Packet config.
\param len Payload length in bytes.
\returns Expected time-on-air in microseconds.
*/
RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len);
/*!
\brief Get expected time-on-air for a given size of payload
\param len Payload length in bytes.
@ -1379,6 +1389,8 @@ class LR11x0: public PhysicalLayer {
*/
RadioLibTime_t getTimeOnAir(size_t len) override;
RadioLibTime_t getTimeOnAir_old(size_t len);
/*!
\brief Calculate the timeout value for this specific module / series (in number of symbols or units of time)
\param timeoutUs Timeout in microseconds to listen for
@ -1688,7 +1700,7 @@ class LR11x0: public PhysicalLayer {
int16_t resetStats(void);
int16_t getStats(uint16_t* nbPktReceived, uint16_t* nbPktCrcError, uint16_t* data1, uint16_t* data2);
int16_t getPacketType(uint8_t* type);
virtual int16_t getPacketType(uint8_t* type);
int16_t getRxBufferStatus(uint8_t* len, uint8_t* startOffset);
int16_t getPacketStatusLoRa(float* rssiPkt, float* snrPkt, float* signalRssiPkt);
int16_t getPacketStatusGFSK(float* rssiSync, float* rssiAvg, uint8_t* rxLen, uint8_t* stat);

Wyświetl plik

@ -1348,7 +1348,7 @@ int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) {
return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, maxLen));
}
RadioLibTime_t SX126x::getTimeOnAir(size_t len) {
RadioLibTime_t SX126x::getTimeOnAir_old(size_t len) {
// everything is in microseconds to allow integer arithmetic
// some constants have .25, these are multiplied by 4, and have _x4 postfix to indicate that fact
uint8_t modem = getPacketType();
@ -1419,6 +1419,110 @@ RadioLibTime_t SX126x::getTimeOnAir(size_t len) {
return(RADIOLIB_ERR_UNKNOWN);
}
RadioLibTime_t SX126x::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) {
// everything is in microseconds to allow integer arithmetic
// some constants have .25, these are multiplied by 4, and have _x4 postfix to indicate that fact
switch (modem) {
case RADIOLIB_MODEM_LORA: {
uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << dr.lora.spreadingFactor) / (dr.lora.bandwidth * 10) ;
uint8_t sfCoeff1_x4 = 17; // (4.25 * 4)
uint8_t sfCoeff2 = 8;
if(dr.lora.spreadingFactor == 5 || dr.lora.spreadingFactor == 6) {
sfCoeff1_x4 = 25; // 6.25 * 4
sfCoeff2 = 0;
}
uint8_t sfDivisor = 4*dr.lora.spreadingFactor;
if(pc.lora.ldrOptimize) {
sfDivisor = 4*(dr.lora.spreadingFactor - 2);
}
const int8_t bitsPerCrc = 16;
const int8_t N_symbol_header = pc.lora.implicitHeader ? 0 : 20;
// numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8)
int16_t bitCount = (int16_t) 8 * len + pc.lora.crcEnabled * bitsPerCrc - 4 * dr.lora.spreadingFactor + sfCoeff2 + N_symbol_header;
if(bitCount < 0) {
bitCount = 0;
}
// add (sfDivisor) - 1 to the numerator to give integer CEIL(...)
uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor);
// preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit
uint32_t nSymbol_x4 = (pc.lora.preambleLength + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * dr.lora.codingRate * 4;
return((symbolLength_us * nSymbol_x4) / 4);
}
case RADIOLIB_MODEM_FSK: {
return((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (uint32_t)len * 8) / (dr.fsk.bitRate / 1000.0f)));
}
case RADIOLIB_MODEM_LRFHSS: {
// calculate the number of bits based on coding rate
uint16_t N_bits;
switch(dr.lrFhss.cr) {
case RADIOLIB_SX126X_LR_FHSS_CR_5_6:
N_bits = ((len * 6) + 4) / 5; // this is from the official LR11xx driver, but why the extra +4?
break;
case RADIOLIB_SX126X_LR_FHSS_CR_2_3:
N_bits = (len * 3) / 2;
break;
case RADIOLIB_SX126X_LR_FHSS_CR_1_2:
N_bits = len * 2;
break;
case RADIOLIB_SX126X_LR_FHSS_CR_1_3:
N_bits = len * 3;
break;
default:
return(RADIOLIB_ERR_INVALID_CODING_RATE);
}
// calculate number of bits when accounting for unaligned last block
uint16_t N_payBits = (N_bits / RADIOLIB_SX126X_LR_FHSS_FRAG_BITS) * RADIOLIB_SX126X_LR_FHSS_BLOCK_BITS;
uint16_t N_lastBlockBits = N_bits % RADIOLIB_SX126X_LR_FHSS_FRAG_BITS;
if(N_lastBlockBits) {
N_payBits += N_lastBlockBits + 2;
}
// add header bits
uint16_t N_totalBits = (RADIOLIB_SX126X_LR_FHSS_HEADER_BITS * pc.lrFhss.hdrCount) + N_payBits;
return(((uint32_t)N_totalBits * 8 * 1000000UL) / 488.28215f);
}
default:
return(RADIOLIB_ERR_WRONG_MODEM);
}
return(RADIOLIB_ERR_UNKNOWN);
}
RadioLibTime_t SX126x::getTimeOnAir(size_t len) {
uint8_t type = getPacketType();
ModemType_t modem = RADIOLIB_MODEM_LORA;
DataRate_t dataRate = {};
PacketConfig_t packetConfig = {};
if(type == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
dataRate = {.lora = {.spreadingFactor = this->spreadingFactor, .bandwidth = this->bandwidthKhz, .codingRate = (uint8_t)(this->codingRate + 4) } };
packetConfig = {.lora = {.preambleLength = this->preambleLengthLoRa, .implicitHeader = this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, .crcEnabled = (bool)this->crcTypeLoRa, .ldrOptimize = (bool)this->ldrOptimize}};
} else if(type == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
modem = RADIOLIB_MODEM_FSK;
float bitRate = RADIOLIB_SX126X_CRYSTAL_FREQ * 32.0f * 1000.0f / (float)this->bitRate;
dataRate = {.fsk = {.bitRate = bitRate, .freqDev = (float)this->frequencyDev }};
uint8_t crcLen = 0;
if(this->crcTypeFSK == RADIOLIB_SX126X_GFSK_CRC_1_BYTE || this->crcTypeFSK == RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV) {
crcLen = 1;
} else if(this->crcTypeFSK == RADIOLIB_SX126X_GFSK_CRC_2_BYTE || this->crcTypeFSK == RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV) {
crcLen = 2;
}
packetConfig = {.fsk = {.preambleLength = this->preambleLengthFSK, .syncWordLength = this->syncWordLength, .crcLength = crcLen}};
} else if(type == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
modem = RADIOLIB_MODEM_LRFHSS;
dataRate = {.lrFhss = {.bw = this->lrFhssBw, .cr = this->lrFhssCr, .narrowGrid = this->lrFhssGridNonFcc }};
packetConfig = {.lrFhss = {.hdrCount = this->lrFhssHdrCount}};
} else {
return(RADIOLIB_ERR_WRONG_MODEM);
}
return(calculateTimeOnAir(modem, dataRate, packetConfig, len));
}
RadioLibTime_t SX126x::calculateRxTimeout(RadioLibTime_t timeoutUs) {
// the timeout value is given in units of 15.625 microseconds
// the calling function should provide some extra width, as this number of units is truncated to integer

Wyświetl plik

@ -1008,6 +1008,16 @@ class SX126x: public PhysicalLayer {
*/
int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX126X_MAX_PACKET_LENGTH);
/*!
\brief Calculate the expected time-on-air for a given modem, data rate, packet configuration and payload size.
\param modem Modem type.
\param dr Data rate.
\param pc Packet config.
\param len Payload length in bytes.
\returns Expected time-on-air in microseconds.
*/
RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len);
/*!
\brief Get expected time-on-air for a given size of payload
\param len Payload length in bytes.
@ -1015,6 +1025,8 @@ class SX126x: public PhysicalLayer {
*/
RadioLibTime_t getTimeOnAir(size_t len) override;
RadioLibTime_t getTimeOnAir_old(size_t len);
/*!
\brief Calculate the timeout value for this specific module / series (in number of symbols or units of time)
\param timeoutUs Timeout in microseconds to listen for
@ -1231,7 +1243,7 @@ class SX126x: public PhysicalLayer {
virtual int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX126X_IRQ_ALL);
int16_t setRfFrequency(uint32_t frf);
int16_t calibrateImage(const uint8_t* data);
uint8_t getPacketType();
virtual uint8_t getPacketType();
int16_t setTxParams(uint8_t power, uint8_t rampTime);
int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro);
int16_t setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev);

Wyświetl plik

@ -122,8 +122,10 @@ int16_t SX1272::setBandwidth(float bw) {
float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth;
Module* mod = this->getMod();
if(symbolLength >= 16.0f) {
this->ldroEnabled = true;
state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0);
} else {
this->ldroEnabled = false;
state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0);
}
}
@ -483,6 +485,7 @@ int16_t SX1272::forceLDRO(bool enable) {
}
this->ldroAuto = false;
this->ldroEnabled = enable;
Module* mod = this->getMod();
if(enable) {
return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0));

Wyświetl plik

@ -324,12 +324,6 @@ class SX1272: public SX127x {
int16_t configFSK() override;
void errataFix(bool rx) override;
#if !RADIOLIB_GODMODE
private:
#endif
bool ldroAuto = true;
bool ldroEnabled = false;
};
#endif

Wyświetl plik

@ -136,8 +136,10 @@ int16_t SX1278::setBandwidth(float bw) {
float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth;
Module* mod = this->getMod();
if(symbolLength >= 16.0f) {
this->ldroEnabled = true;
state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3);
} else {
this->ldroEnabled = false;
state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3);
}
}
@ -522,6 +524,7 @@ int16_t SX1278::forceLDRO(bool enable) {
Module* mod = this->getMod();
this->ldroAuto = false;
this->ldroEnabled = enable;
if(enable) {
return(mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3));
} else {

Wyświetl plik

@ -336,12 +336,6 @@ class SX1278: public SX127x {
int16_t configFSK() override;
void errataFix(bool rx) override;
#if !RADIOLIB_GODMODE
private:
#endif
bool ldroAuto = true;
bool ldroEnabled = false;
};
/*!

Wyświetl plik

@ -833,6 +833,8 @@ int16_t SX127x::setFrequencyDeviation(float freqDev) {
return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
}
this->frequencyDev = newFreqDev;
// set mode to STANDBY
int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
RADIOLIB_ASSERT(state);
@ -1127,52 +1129,73 @@ int16_t SX127x::variablePacketLengthMode(uint8_t maxLen) {
return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_VARIABLE, maxLen));
}
float SX127x::getNumSymbols(size_t len) {
// get symbol length in us
float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
float SX127x::getNumSymbols(size_t len, DataRate_t dr, PacketConfig_t pc) {
// get Low Data Rate optimization flag
float de = 0;
if (symbolLength >= 16.0f) {
de = 1;
}
float de = pc.lora.ldrOptimize ? 1.0f : 0.0f;
// get explicit/implicit header enabled flag
float ih = (float) this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, 0, 0);
float ih = (float) pc.lora.implicitHeader;
// get CRC enabled flag
float crc = (float) (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2);
float crc = (float) pc.lora.crcEnabled;
// get number of preamble symbols
float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB));
float n_pre = (float) pc.lora.preambleLength;
// get number of payload symbols
float n_pay = 8.0f + RADIOLIB_MAX(ceilf((8.0f * (float) len - 4.0f * (float) this->spreadingFactor + 28.0f + 16.0f * crc - 20.0f * ih) / (4.0f * (float) this->spreadingFactor - 8.0f * de)) * (float) this->codingRate, 0.0f);
float n_pay = 8.0f + RADIOLIB_MAX(ceilf((8.0f * (float) len - 4.0f * (float) dr.lora.spreadingFactor + 28.0f + 16.0f * crc - 20.0f * ih) / (4.0f * (float) dr.lora.spreadingFactor - 8.0f * de)) * (float) dr.lora.codingRate, 0.0f);
// add 4.25 symbols for the sync
return(n_pre + n_pay + 4.25f);
}
RadioLibTime_t SX127x::getTimeOnAir(size_t len) {
// check active modem
uint8_t modem = getActiveModem();
if (modem == RADIOLIB_SX127X_LORA) {
RadioLibTime_t SX127x::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) {
if (modem == RADIOLIB_MODEM_LORA) {
// get symbol length in us
float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
float symbolLength = (float) (uint32_t(1) << dr.lora.spreadingFactor) / (float) dr.lora.bandwidth;
// get number of symbols
float n_sym = getNumSymbols(len);
float n_sym = getNumSymbols(len, dr, pc);
// get time-on-air in us
return ceil((double)symbolLength * (double)n_sym) * 1000;
} else if(modem == RADIOLIB_SX127X_FSK_OOK) {
} else if(modem == RADIOLIB_MODEM_FSK) {
// calculate time-on-air in us {[(length in bytes) * (8 bits / 1 byte)] / [(Bit Rate in kbps) * (1000 bps / 1 kbps)]} * (1000000 us in 1 sec)
return((uint32_t) ((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (float) (len * 8)) / (dr.fsk.bitRate * 1000.0f)) * 1000000.0f));
} else {
return(RADIOLIB_ERR_WRONG_MODEM);
}
return(RADIOLIB_ERR_UNKNOWN);
}
RadioLibTime_t SX127x::getTimeOnAir(size_t len) {
uint8_t modem = getActiveModem();
DataRate_t dataRate = {};
PacketConfig_t packetConfig = {};
switch (modem) {
case(RADIOLIB_SX127X_LORA): {
// Get number of preamble symbols
uint16_t n_pre = ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB));
dataRate = { .lora = { .spreadingFactor = this->spreadingFactor, .bandwidth = this->bandwidth, .codingRate = this->codingRate } };
packetConfig = { .lora = { .preambleLength = n_pre, .implicitHeader = this->implicitHdr, .crcEnabled = this->crcEnabled, .ldrOptimize = this->ldroEnabled } };
return(calculateTimeOnAir((ModemType_t)RADIOLIB_MODEM_LORA, dataRate, packetConfig, len));
}
case(RADIOLIB_SX127X_FSK_OOK): {
dataRate = { .fsk = { .bitRate = this->bitRate, .freqDev = this->frequencyDev } };
// get number of bits preamble
float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8;
uint16_t n_pre = (uint16_t) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8;
// get the number of bits of the sync word
float n_syncWord = (float) (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1) * 8;
// get CRC bits
float crc = (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) == RADIOLIB_SX127X_CRC_ON) * 16;
uint8_t n_syncWord = (uint8_t) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1) * 8);
// get CRC enabled status
bool crcEnabled = (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) == RADIOLIB_SX127X_CRC_ON);
if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_FIXED) {
// if packet size fixed -> len = fixed packet length
@ -1182,11 +1205,13 @@ RadioLibTime_t SX127x::getTimeOnAir(size_t len) {
len += 1;
}
// calculate time-on-air in us {[(length in bytes) * (8 bits / 1 byte)] / [(Bit Rate in kbps) * (1000 bps / 1 kbps)]} * (1000000 us in 1 sec)
return((uint32_t) (((crc + n_syncWord + n_pre + (float) (len * 8)) / (this->bitRate * 1000.0f)) * 1000000.0f));
}
packetConfig = { .fsk = { .preambleLength = n_pre, .syncWordLength = n_syncWord, .crcLength = (uint8_t)(crcEnabled * 2) } };
return(RADIOLIB_ERR_UNKNOWN);
return(calculateTimeOnAir((ModemType_t)RADIOLIB_MODEM_FSK, dataRate, packetConfig, len));
}
default:
return(RADIOLIB_ERR_WRONG_MODEM);
}
}
RadioLibTime_t SX127x::calculateRxTimeout(RadioLibTime_t timeoutUs) {

Wyświetl plik

@ -1040,9 +1040,11 @@ class SX127x: public PhysicalLayer {
/*!
\brief Convert from bytes to LoRa symbols.
\param len Payload length in bytes.
\param dr Data rate.
\param pc Packet configuration.
\returns The total number of LoRa symbols, including preamble, sync and possible header.
*/
float getNumSymbols(size_t len);
float getNumSymbols(size_t len, DataRate_t dr, PacketConfig_t pc);
/*!
\brief Get expected time-on-air for a given size of payload.
@ -1051,6 +1053,16 @@ class SX127x: public PhysicalLayer {
*/
RadioLibTime_t getTimeOnAir(size_t len) override;
/*!
\brief Calculate the expected time-on-air for a given modem, data rate, packet configuration and payload size.
\param modem Modem type.
\param dr Data rate.
\param pc Packet config.
\param len Payload length in bytes.
\returns Expected time-on-air in microseconds.
*/
RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len);
/*!
\brief Calculate the timeout value for this specific module / series (in number of symbols or units of time)
\param timeoutUs Timeout in microseconds to listen for
@ -1251,6 +1263,8 @@ class SX127x: public PhysicalLayer {
bool crcEnabled = false;
bool ookEnabled = false;
bool implicitHdr = false;
bool ldroAuto = false;
bool ldroEnabled = false;
virtual int16_t configFSK();
int16_t getActiveModem();
@ -1264,7 +1278,7 @@ class SX127x: public PhysicalLayer {
#endif
Module* mod;
float bitRate = 0;
float bitRate = 0, frequencyDev = 0;
bool crcOn = true; // default value used in FSK mode
float dataRate = 0;
bool packetLengthQueried = false; // FSK packet length is the first byte in FIFO, length can only be queried once

Wyświetl plik

@ -969,6 +969,7 @@ int16_t SX128x::setFrequencyDeviation(float freqDev) {
}
// update modulation parameters
this->frequencyDev = newFreqDev;
this->modIndex = modInd;
return(setModulationParams(this->bitRate, this->modIndex, this->shaping));
}
@ -1334,7 +1335,102 @@ int16_t SX128x::variablePacketLengthMode(uint8_t maxLen) {
return(setPacketMode(RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE, maxLen));
}
RadioLibTime_t SX128x::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) {
switch(modem) {
case (ModemType_t::RADIOLIB_MODEM_LORA): {
// calculate number of symbols
float N_symbol = 0;
uint8_t sf = dr.lora.spreadingFactor;
float cr = (float)dr.lora.codingRate;
// get SF coefficients
float coeff1 = 0;
int16_t coeff2 = 0;
int16_t coeff3 = 0;
if(sf < 7) {
// SF5, SF6
coeff1 = 6.25;
coeff2 = 4*sf;
coeff3 = 4*sf;
} else if(sf < 11) {
// SF7. SF8, SF9, SF10
coeff1 = 4.25;
coeff2 = 4*sf + 8;
coeff3 = 4*sf;
} else {
// SF11, SF12
coeff1 = 4.25;
coeff2 = 4*sf + 8;
coeff3 = 4*(sf - 2);
}
// get CRC length
int16_t N_bitCRC = 16;
if(!pc.lora.crcEnabled) {
N_bitCRC = 0;
}
// get header length
int16_t N_symbolHeader = 20;
if(pc.lora.implicitHeader) {
N_symbolHeader = 0;
}
// calculate number of LoRa preamble symbols
uint32_t N_symbolPreamble = pc.lora.preambleLength;
// calculate the number of symbols
N_symbol = (float)N_symbolPreamble + coeff1 + 8.0f + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * cr;
// get time-on-air in us
return(((uint32_t(1) << sf) / dr.lora.bandwidth) * N_symbol * 1000.0f);
}
case (ModemType_t::RADIOLIB_MODEM_FSK):
return((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (uint32_t)len * 8) / (dr.fsk.bitRate / 1000.0f)));
default:
return(RADIOLIB_ERR_WRONG_MODEM);
}
}
RadioLibTime_t SX128x::getTimeOnAir(size_t len) {
// check active modem
uint8_t modem = getPacketType();
DataRate_t dr;
PacketConfig_t pc;
if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
uint8_t sf = this->spreadingFactor >> 4;
uint8_t cr = this->codingRateLoRa;
// We assume same calculation for short and long interleaving, so map CR values 0-4 and 5-7 to the same values
if (cr < 5) {
cr = cr + 4;
} else if (cr == 7) {
cr = cr + 1;
}
dr = {.lora = {.spreadingFactor = sf, .bandwidth = this->bandwidthKhz, .codingRate = cr}};
uint16_t preambleLength = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4));
pc = {.lora = { .preambleLength = preambleLength, .implicitHeader = this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT, .crcEnabled = this->crcLoRa == RADIOLIB_SX128X_LORA_CRC_ON, .ldrOptimize = false }};
return(calculateTimeOnAir(ModemType_t::RADIOLIB_MODEM_LORA, dr, pc, len));
} else if (modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) {
dr = {.fsk = {.bitRate = (float)this->bitRateKbps, .freqDev = this->frequencyDev}};
uint8_t crcLength = this->crcGFSK >> 4;
uint16_t preambleLength = (this->preambleLengthGFSK >> 2) + 4;
uint8_t syncWordLen = ((this->syncWordLen >> 1) + 1) * 8;
pc = {.fsk = {.preambleLength = preambleLength, .syncWordLength = syncWordLen, .crcLength = crcLength}};
return(calculateTimeOnAir(ModemType_t::RADIOLIB_MODEM_FSK, dr, pc, len));
} else {
return(RADIOLIB_ERR_WRONG_MODEM);
}
}
RadioLibTime_t SX128x::getTimeOnAir_old(size_t len) {
// check active modem
uint8_t modem = getPacketType();
if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {

Wyświetl plik

@ -828,6 +828,16 @@ class SX128x: public PhysicalLayer {
*/
int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX128X_MAX_PACKET_LENGTH);
/*!
\brief Calculate the expected time-on-air for a given modem, data rate, packet configuration and payload size.
\param modem Modem type.
\param dr Data rate.
\param pc Packet config.
\param len Payload length in bytes.
\returns Expected time-on-air in microseconds.
*/
RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len);
/*!
\brief Get expected time-on-air for a given size of payload.
\param len Payload length in bytes.
@ -835,6 +845,8 @@ class SX128x: public PhysicalLayer {
*/
RadioLibTime_t getTimeOnAir(size_t len) override;
RadioLibTime_t getTimeOnAir_old(size_t len);
/*!
\brief Set implicit header mode for future reception/transmission.
\returns \ref status_codes
@ -913,7 +925,7 @@ class SX128x: public PhysicalLayer {
int16_t setTx(uint16_t periodBaseCount = RADIOLIB_SX128X_TX_TIMEOUT_NONE, uint8_t periodBase = RADIOLIB_SX128X_PERIOD_BASE_15_625_US);
int16_t setRx(uint16_t periodBaseCount, uint8_t periodBase = RADIOLIB_SX128X_PERIOD_BASE_15_625_US);
int16_t setCad(uint8_t symbolNum);
uint8_t getPacketType();
virtual uint8_t getPacketType();
int16_t setRfFrequency(uint32_t frf);
int16_t setTxParams(uint8_t pwr, uint8_t rampTime = RADIOLIB_SX128X_PA_RAMP_10_US);
int16_t setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00);
@ -942,7 +954,7 @@ class SX128x: public PhysicalLayer {
uint8_t invertIQEnabled = RADIOLIB_SX128X_LORA_IQ_STANDARD;
// cached GFSK parameters
float modIndexReal = 0;
float modIndexReal = 0, frequencyDev = 0;
uint16_t bitRateKbps = 0;
uint8_t bitRate = 0, modIndex = 0, shaping = 0;
uint8_t preambleLengthGFSK = 0, syncWordLen = 0, syncWordMatch = 0, crcGFSK = 0, whitening = 0;