kopia lustrzana https://github.com/jgromes/RadioLib
Add `calculateTimeOnAir()` method to relevant modules
rodzic
690b63abe0
commit
b6b3eafa18
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
/*!
|
||||
|
|
|
@ -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,68 +1129,91 @@ 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) {
|
||||
// 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;
|
||||
// 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;
|
||||
|
||||
if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_FIXED) {
|
||||
// if packet size fixed -> len = fixed packet length
|
||||
len = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK);
|
||||
} else {
|
||||
// if packet variable -> Add 1 extra byte for payload length
|
||||
len += 1;
|
||||
}
|
||||
|
||||
} 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) (((crc + n_syncWord + n_pre + (float) (len * 8)) / (this->bitRate * 1000.0f)) * 1000000.0f));
|
||||
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
|
||||
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
|
||||
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
|
||||
len = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK);
|
||||
} else {
|
||||
// if packet variable -> Add 1 extra byte for payload length
|
||||
len += 1;
|
||||
}
|
||||
|
||||
packetConfig = { .fsk = { .preambleLength = n_pre, .syncWordLength = n_syncWord, .crcLength = (uint8_t)(crcEnabled * 2) } };
|
||||
|
||||
return(calculateTimeOnAir((ModemType_t)RADIOLIB_MODEM_FSK, dataRate, packetConfig, len));
|
||||
}
|
||||
default:
|
||||
return(RADIOLIB_ERR_WRONG_MODEM);
|
||||
}
|
||||
}
|
||||
|
||||
RadioLibTime_t SX127x::calculateRxTimeout(RadioLibTime_t timeoutUs) {
|
||||
RadioLibTime_t timeout = 0;
|
||||
if(getActiveModem() == RADIOLIB_SX127X_LORA) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
Ładowanie…
Reference in New Issue