From e406c550b81567b63513d4ae88fe631c73ab7d08 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 21 Jun 2024 17:53:11 +0200 Subject: [PATCH] [LR11x0] Fix output power configuration at S-band (#1128) --- src/modules/LR11x0/LR1110.cpp | 59 +++++++++- src/modules/LR11x0/LR1110.h | 35 ++++++ src/modules/LR11x0/LR1120.cpp | 82 +++++++++++++- src/modules/LR11x0/LR1120.h | 46 ++++++++ src/modules/LR11x0/LR11x0.cpp | 195 +++++++++++++++++++++------------- src/modules/LR11x0/LR11x0.h | 58 +++------- 6 files changed, 354 insertions(+), 121 deletions(-) diff --git a/src/modules/LR11x0/LR1110.cpp b/src/modules/LR11x0/LR1110.cpp index 77e1a02f..62bf116f 100644 --- a/src/modules/LR11x0/LR1110.cpp +++ b/src/modules/LR11x0/LR1110.cpp @@ -7,31 +7,40 @@ LR1110::LR1110(Module* mod) : LR11x0(mod) { int16_t LR1110::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::begin(bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage); + int16_t state = LR11x0::begin(bw, sf, cr, syncWord, preambleLength, tcxoVoltage); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); return(state); } int16_t LR1110::beginGFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::beginGFSK(br, freqDev, rxBw, power, preambleLength, tcxoVoltage); + int16_t state = LR11x0::beginGFSK(br, freqDev, rxBw, preambleLength, tcxoVoltage); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); return(state); } int16_t LR1110::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, int8_t power, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::beginLRFHSS(bw, cr, power, tcxoVoltage); + int16_t state = LR11x0::beginLRFHSS(bw, cr, tcxoVoltage); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); return(state); } @@ -52,4 +61,48 @@ int16_t LR1110::setFrequency(float freq, bool calibrate, float band) { return(LR11x0::setRfFrequency((uint32_t)(freq*1000000.0f))); } +int16_t LR1110::setOutputPower(int8_t power) { + return(this->setOutputPower(power, false)); +} + +int16_t LR1110::setOutputPower(int8_t power, bool forceHighPower) { + // check if power value is configurable + int16_t state = this->checkOutputPower(power, NULL, forceHighPower); + RADIOLIB_ASSERT(state); + + // determine whether to use HP or LP PA and check range accordingly + bool useHp = forceHighPower || (power > 14); + + // TODO how and when to configure OCP? + + // update PA config - always use VBAT for high-power PA + state = setPaConfig((uint8_t)useHp, (uint8_t)useHp, 0x04, 0x07); + RADIOLIB_ASSERT(state); + + // set output power + state = setTxParams(power, RADIOLIB_LR11X0_PA_RAMP_48U); + return(state); +} + +int16_t LR1110::checkOutputPower(int8_t power, int8_t* clipped) { + return(checkOutputPower(power, clipped, false)); +} + +int16_t LR1110::checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower) { + if(forceHighPower || (power > 14)) { + if(clipped) { + *clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power)); + } + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + } else { + if(clipped) { + *clipped = RADIOLIB_MAX(-17, RADIOLIB_MIN(14, power)); + } + RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + } + return(RADIOLIB_ERR_NONE); +} + #endif \ No newline at end of file diff --git a/src/modules/LR11x0/LR1110.h b/src/modules/LR11x0/LR1110.h index 60040ed0..fcc65f2e 100644 --- a/src/modules/LR11x0/LR1110.h +++ b/src/modules/LR11x0/LR1110.h @@ -86,6 +86,41 @@ class LR1110: public LR11x0 { \returns \ref status_codes */ int16_t setFrequency(float freq, bool calibrate, float band = 4); + + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). + \param power Output power to be set in dBm, output PA is determined automatically preferring the low-power PA. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power) override; + + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). + \param power Output power to be set in dBm. + \param forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically + based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power, bool forceHighPower); + + /*! + \brief Check if output power is configurable. + This method is needed for compatibility with PhysicalLayer::checkOutputPower. + \param power Output power in dBm, PA will be determined automatically. + \param clipped Clipped output power value to what is possible within the module's range. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped) override; + + /*! + \brief Check if output power is configurable. + \param power Output power in dBm. + \param clipped Clipped output power value to what is possible within the module's range. + \param forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically + based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower); #if !RADIOLIB_GODMODE private: diff --git a/src/modules/LR11x0/LR1120.cpp b/src/modules/LR11x0/LR1120.cpp index a1107036..a69dc359 100644 --- a/src/modules/LR11x0/LR1120.cpp +++ b/src/modules/LR11x0/LR1120.cpp @@ -7,31 +7,40 @@ LR1120::LR1120(Module* mod) : LR11x0(mod) { int16_t LR1120::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::begin(bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage); + int16_t state = LR11x0::begin(bw, sf, cr, syncWord, preambleLength, tcxoVoltage); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); return(state); } int16_t LR1120::beginGFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::beginGFSK(br, freqDev, rxBw, power, preambleLength, tcxoVoltage); + int16_t state = LR11x0::beginGFSK(br, freqDev, rxBw, preambleLength, tcxoVoltage); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); return(state); } int16_t LR1120::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, int8_t power, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::beginLRFHSS(bw, cr, power, tcxoVoltage); + int16_t state = LR11x0::beginLRFHSS(bw, cr, tcxoVoltage); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); return(state); } @@ -47,13 +56,76 @@ int16_t LR1120::setFrequency(float freq, bool calibrate, float band) { } // calibrate image rejection + int16_t state; if(calibrate) { - int16_t state = LR11x0::calibImage(freq - band, freq + band); + state = LR11x0::calibImage(freq - band, freq + band); RADIOLIB_ASSERT(state); } // set frequency - return(LR11x0::setRfFrequency((uint32_t)(freq*1000000.0f))); + state = LR11x0::setRfFrequency((uint32_t)(freq*1000000.0f)); + RADIOLIB_ASSERT(state); + this->highFreq = (freq > 1000.0); + return(RADIOLIB_ERR_NONE); +} + +int16_t LR1120::setOutputPower(int8_t power) { + return(this->setOutputPower(power, false)); +} + +int16_t LR1120::setOutputPower(int8_t power, bool forceHighPower) { + // check if power value is configurable + int16_t state = this->checkOutputPower(power, NULL, forceHighPower); + RADIOLIB_ASSERT(state); + + // determine whether to use HP or LP PA and check range accordingly + uint8_t paSel = 0; + uint8_t paSupply = 0; + if(this->highFreq) { + paSel = 2; + } else if(forceHighPower || (power > 14)) { + paSel = 1; + paSupply = 1; + } + + // TODO how and when to configure OCP? + + // update PA config - always use VBAT for high-power PA + state = setPaConfig(paSel, paSupply, 0x04, 0x07); + RADIOLIB_ASSERT(state); + + // set output power + state = setTxParams(power, RADIOLIB_LR11X0_PA_RAMP_48U); + return(state); +} + +int16_t LR1120::checkOutputPower(int8_t power, int8_t* clipped) { + return(checkOutputPower(power, clipped, false)); +} + +int16_t LR1120::checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower) { + if(this->highFreq) { + if(clipped) { + *clipped = RADIOLIB_MAX(-18, RADIOLIB_MIN(13, power)); + } + RADIOLIB_CHECK_RANGE(power, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + return(RADIOLIB_ERR_NONE); + } + + if(forceHighPower || (power > 14)) { + if(clipped) { + *clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power)); + } + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + } else { + if(clipped) { + *clipped = RADIOLIB_MAX(-17, RADIOLIB_MIN(14, power)); + } + RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + } + return(RADIOLIB_ERR_NONE); } #endif \ No newline at end of file diff --git a/src/modules/LR11x0/LR1120.h b/src/modules/LR11x0/LR1120.h index 62045b02..c4fbbde5 100644 --- a/src/modules/LR11x0/LR1120.h +++ b/src/modules/LR11x0/LR1120.h @@ -71,6 +71,8 @@ class LR1120: public LR11x0 { /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz, 1900 - 2200 MHz and 2400 - 2500 MHz. Will also perform calibrations. + NOTE: When switching between sub-GHz and high-frequency bands, after changing the frequency, + setOutputPower() must be called in order to set the correct power amplifier! \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ @@ -79,6 +81,8 @@ class LR1120: public LR11x0 { /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz, 1900 - 2200 MHz and 2400 - 2500 MHz. Will also perform calibrations. + NOTE: When switching between sub-GHz and high-frequency bands, after changing the frequency, + setOutputPower() must be called in order to set the correct power amplifier! \param freq Carrier frequency to be set in MHz. \param calibrate Run image calibration. \param band Half bandwidth for image calibration. For example, @@ -88,9 +92,51 @@ class LR1120: public LR11x0 { */ int16_t setFrequency(float freq, bool calibrate, float band = 4); + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). + \param power Output power to be set in dBm, output PA is determined automatically preferring the low-power PA. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power) override; + + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA), -17 to 14 dBm (low-power PA) + or -18 to 13 dBm (high-frequency PA). + \param power Output power to be set in dBm. + \param forceHighPower Force using the high-power PA in sub-GHz bands, or high-frequency PA in 2.4 GHz band. + If set to false, PA will be determined automatically based on configured output power and frequency, + preferring the low-power PA but always using high-frequency PA in 2.4 GHz band. + Ignored when operating in 2.4 GHz band. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power, bool forceHighPower); + + /*! + \brief Check if output power is configurable. + This method is needed for compatibility with PhysicalLayer::checkOutputPower. + \param power Output power in dBm, PA will be determined automatically. + \param clipped Clipped output power value to what is possible within the module's range. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped) override; + + /*! + \brief Check if output power is configurable. + \param power Output power in dBm. + \param clipped Clipped output power value to what is possible within the module's range. + \param forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically + based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used. + Ignored when operating in 2.4 GHz band. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower); + #if !RADIOLIB_GODMODE private: #endif + // flag to determine whether we are in the sub-GHz or 2.4 GHz range + // this is needed to automatically detect which PA to use + bool highFreq = false; }; diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 71737176..701ca6d1 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -13,7 +13,7 @@ LR11x0::LR11x0(Module* mod) : PhysicalLayer(RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE, this->XTAL = false; } -int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { +int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage) { // set module properties and perform initial setup int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_LORA); RADIOLIB_ASSERT(state); @@ -30,9 +30,6 @@ int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t state = setSyncWord(syncWord); RADIOLIB_ASSERT(state); - - state = setOutputPower(power); - RADIOLIB_ASSERT(state); state = setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); @@ -50,7 +47,7 @@ int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t return(RADIOLIB_ERR_NONE); } -int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) { +int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage) { // set module properties and perform initial setup int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_GFSK); RADIOLIB_ASSERT(state); @@ -64,9 +61,6 @@ int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, int8_t power, uin state = setRxBandwidth(rxBw); RADIOLIB_ASSERT(state); - - state = setOutputPower(power); - RADIOLIB_ASSERT(state); state = setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); @@ -94,7 +88,7 @@ int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, int8_t power, uin return(RADIOLIB_ERR_NONE); } -int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, int8_t power, float tcxoVoltage) { +int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, float tcxoVoltage) { // set module properties and perform initial setup int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS); RADIOLIB_ASSERT(state); @@ -103,9 +97,6 @@ int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, int8_t power, float tcxoVolt state = setLrFhssConfig(bw, cr); RADIOLIB_ASSERT(state); - state = setOutputPower(power); - RADIOLIB_ASSERT(state); - state = setSyncWord(0x12AD101B); RADIOLIB_ASSERT(state); @@ -605,50 +596,6 @@ int16_t LR11x0::getChannelScanResult() { return(RADIOLIB_ERR_UNKNOWN); } -int16_t LR11x0::setOutputPower(int8_t power) { - return(this->setOutputPower(power, false)); -} - -int16_t LR11x0::setOutputPower(int8_t power, bool forceHighPower) { - // check if power value is configurable - int16_t state = checkOutputPower(power, NULL, forceHighPower); - RADIOLIB_ASSERT(state); - - // determine whether to use HP or LP PA and check range accordingly - bool useHp = forceHighPower || (power > 14); - - // TODO how and when to configure OCP? - - // update PA config - always use VBAT for high-power PA - state = setPaConfig((uint8_t)useHp, (uint8_t)useHp, 0x04, 0x07); - RADIOLIB_ASSERT(state); - - // set output power - state = setTxParams(power, RADIOLIB_LR11X0_PA_RAMP_48U); - return(state); -} - -int16_t LR11x0::checkOutputPower(int8_t power, int8_t* clipped) { - return(checkOutputPower(power, clipped, false)); -} - -int16_t LR11x0::checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower) { - if(forceHighPower || (power > 14)) { - if(clipped) { - *clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power)); - } - RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); - - } else { - if(clipped) { - *clipped = RADIOLIB_MAX(-17, RADIOLIB_MIN(14, power)); - } - RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); - - } - return(RADIOLIB_ERR_NONE); -} - int16_t LR11x0::setBandwidth(float bw) { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; @@ -1057,6 +1004,10 @@ int16_t LR11x0::setDataRate(DataRate_t dr) { // set the coding rate state = this->setCodingRate(dr.lora.codingRate); + + } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { + + } return(state); @@ -1701,6 +1652,112 @@ int16_t LR11x0::updateFirmware(const uint32_t* image, size_t size, bool nonvolat return(state); } +int16_t LR11x0::isGnssScanCapable() { + // get the version + LR11x0VersionInfo_t version; + int16_t state = this->getVersionInfo(&version); + RADIOLIB_ASSERT(state); + + // check the device firmware version is sufficient + uint16_t versionFull = ((uint16_t)version.fwMajor << 8) | (uint16_t)version.fwMinor; + if((version.device == RADIOLIB_LR11X0_DEVICE_LR1110) && (versionFull >= 0x0401)) { + return(RADIOLIB_ERR_NONE); + } else if((version.device == RADIOLIB_LR11X0_DEVICE_LR1120) && (versionFull >= 0x0201)) { + return(RADIOLIB_ERR_NONE); + } + + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t LR11x0::gnssScan(uint16_t* resSize) { + // go to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set DIO mapping + state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_GNSS_DONE, 0); + RADIOLIB_ASSERT(state); + + state = this->gnssSetConstellationToUse(0x03); + RADIOLIB_ASSERT(state); + + // set scan mode + state = this->gnssSetMode(0x03); + RADIOLIB_ASSERT(state); + + // start scan with high effort + RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan start"); + state = this->gnssPerformScan(0x01, 0x3C, 8); + RADIOLIB_ASSERT(state); + + // wait for scan finished or timeout + RadioLibTime_t softTimeout = 300UL * 1000UL; + RadioLibTime_t start = this->mod->hal->millis(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->millis() - start > softTimeout) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for IRQ"); + this->standby(); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + } + + RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start)); + + state = this->clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + RADIOLIB_ASSERT(state); + + int8_t status = 0; + uint8_t info = 0; + state = this->gnssReadDemodStatus(&status, &info); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("Demod status %d, info %02x", (int)status, (unsigned int)info); + + uint8_t fwVersion = 0; + uint32_t almanacCrc = 0; + uint8_t errCode = 0; + uint8_t almUpdMask = 0; + uint8_t freqSpace = 0; + state = this->gnssGetContextStatus(&fwVersion, &almanacCrc, &errCode, &almUpdMask, &freqSpace); + RADIOLIB_DEBUG_BASIC_PRINTLN("Context status fwVersion %d, almanacCrc %lx, errCode %d, almUpdMask %d, freqSpace %d", + (int)fwVersion, (unsigned long)almanacCrc, (int)errCode, (int)almUpdMask, (int)freqSpace); + RADIOLIB_ASSERT(state); + + uint8_t stat[53] = { 0 }; + state = this->gnssReadAlmanacStatus(stat); + RADIOLIB_ASSERT(state); + //Module::hexdump(NULL, stat, 53); + + return(this->gnssGetResultSize(resSize)); +} + +int16_t LR11x0::getGnssScanResult(uint16_t size) { + // read the result + uint8_t res[256] = { 0 }; + int16_t state = this->gnssReadResults(res, size); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("Result type: %02x", (int)res[0]); + //Module::hexdump(NULL, res, size); + + return(state); +} + +int16_t LR11x0::getGnssPosition(float* lat, float* lon, bool filtered) { + uint8_t error = 0; + uint8_t nbSvUsed = 0; + uint16_t accuracy = 0; + int16_t state; + if(filtered) { + state = this->gnssReadDopplerSolverRes(&error, &nbSvUsed, NULL, NULL, NULL, NULL, lat, lon, &accuracy, NULL); + } else { + state = this->gnssReadDopplerSolverRes(&error, &nbSvUsed, lat, lon, &accuracy, NULL, NULL, NULL, NULL, NULL); + } + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("Solver error %d, nbSvUsed %d, accuracy = %u", (int)error, (int)nbSvUsed, (unsigned int)accuracy); + + return(state); +} + int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) { this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); @@ -2885,21 +2942,17 @@ int16_t LR11x0::gnssPushDmMsg(uint8_t* payload, size_t len) { } int16_t LR11x0::gnssGetContextStatus(uint8_t* fwVersion, uint32_t* almanacCrc, uint8_t* errCode, uint8_t* almUpdMask, uint8_t* freqSpace) { - // send the command - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS, true, NULL, 0); - RADIOLIB_ASSERT(state); - - // read the result - this requires some magic bytes first, that's why LR11x0::SPIcommand cannot be used - uint8_t cmd_buff[3] = { 0x00, 0x02, 0x18 }; + // send the command - datasheet here shows extra bytes being sent in the request + // but doing that fails so treat it like any other read command uint8_t buff[9] = { 0 }; - state = this->mod->SPItransferStream(cmd_buff, sizeof(cmd_buff), false, NULL, buff, sizeof(buff), true); + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS, false, buff, sizeof(buff)); // pass the replies - if(fwVersion) { *fwVersion = buff[0]; } - if(almanacCrc) { *almanacCrc = ((uint32_t)(buff[1]) << 24) | ((uint32_t)(buff[2]) << 16) | ((uint32_t)(buff[3]) << 8) | (uint32_t)buff[4]; } - if(errCode) { *errCode = (buff[5] & 0xF0) >> 4; } - if(almUpdMask) { *almUpdMask = (buff[5] & 0x0E) >> 1; } - if(freqSpace) { *freqSpace = ((buff[5] & 0x01) << 1) | ((buff[6] & 0x80) >> 7); } + if(fwVersion) { *fwVersion = buff[2]; } + if(almanacCrc) { *almanacCrc = ((uint32_t)(buff[3]) << 24) | ((uint32_t)(buff[4]) << 16) | ((uint32_t)(buff[5]) << 8) | (uint32_t)buff[6]; } + if(errCode) { *errCode = (buff[7] & 0xF0) >> 4; } + if(almUpdMask) { *almUpdMask = (buff[7] & 0x0E) >> 1; } + if(freqSpace) { *freqSpace = ((buff[7] & 0x01) << 1) | ((buff[8] & 0x80) >> 7); } return(state); } @@ -3000,10 +3053,10 @@ int16_t LR11x0::gnssGetSvVisible(uint32_t time, float lat, float lon, uint8_t co return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE, false, nbSv, 1, reqBuff, sizeof(reqBuff))); } -// TODO check version > 02.01 -int16_t LR11x0::gnssScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax) { +int16_t LR11x0::gnssPerformScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax) { uint8_t buff[3] = { effort, resMask, nbSvMax }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SCAN, true, buff, sizeof(buff))); + // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts + return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_GNSS_SCAN, buff, sizeof(buff), false, false)); } int16_t LR11x0::gnssReadLastScanModeLaunched(uint8_t* lastScanMode) { diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 04d5d2f8..8aa16da0 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -700,6 +700,10 @@ struct LR11x0VersionInfo_t { uint8_t almanacGNSS; }; +struct LR11x0GnssResult_t { + +}; + /*! \class LR11x0 \brief Base class for %LR11x0 series. All derived classes for %LR11x0 (e.g. LR1110 or LR1120) inherit from this base class. @@ -753,34 +757,31 @@ class LR11x0: public PhysicalLayer { \param sf LoRa spreading factor. \param cr LoRa coding rate denominator. \param syncWord 1-byte LoRa sync word. - \param power Output power in dBm. \param preambleLength LoRa preamble length in symbols \param tcxoVoltage TCXO reference voltage to be set. \returns \ref status_codes */ - int16_t begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage); + int16_t begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage); /*! \brief Initialization method for FSK modem. \param br FSK bit rate in kbps. \param freqDev Frequency deviation from carrier frequency in kHz. \param rxBw Receiver bandwidth in kHz. - \param power Output power in dBm. \param preambleLength FSK preamble length in bits. \param tcxoVoltage TCXO reference voltage to be set. \returns \ref status_codes */ - int16_t beginGFSK(float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage); + int16_t beginGFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage); /*! \brief Initialization method for LR-FHSS modem. \param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. \param cr LR-FHSS coding rate, one of RADIOLIB_LR11X0_LR_FHSS_CR_* values. - \param power Output power in dBm. \param tcxoVoltage TCXO reference voltage to be set. \returns \ref status_codes */ - int16_t beginLRFHSS(uint8_t bw, uint8_t cr, int8_t power, float tcxoVoltage); + int16_t beginLRFHSS(uint8_t bw, uint8_t cr, float tcxoVoltage); /*! \brief Reset method. Will reset the chip to the default state using RST pin. @@ -980,41 +981,6 @@ class LR11x0: public PhysicalLayer { int16_t getChannelScanResult() override; // configuration methods - - /*! - \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). - \param power Output power to be set in dBm, output PA is determined automatically preferring the low-power PA. - \returns \ref status_codes - */ - int16_t setOutputPower(int8_t power) override; - - /*! - \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). - \param power Output power to be set in dBm. - \param forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically - based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used. - \returns \ref status_codes - */ - int16_t setOutputPower(int8_t power, bool forceHighPower); - - /*! - \brief Check if output power is configurable. - This method is needed for compatibility with PhysicalLayer::checkOutputPower. - \param power Output power in dBm, PA will be determined automatically. - \param clipped Clipped output power value to what is possible within the module's range. - \returns \ref status_codes - */ - int16_t checkOutputPower(int8_t power, int8_t* clipped) override; - - /*! - \brief Check if output power is configurable. - \param power Output power in dBm. - \param clipped Clipped output power value to what is possible within the module's range. - \param forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically - based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used. - \returns \ref status_codes - */ - int16_t checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower); /*! \brief Sets LoRa bandwidth. Allowed values are 62.5, 125.0, 250.0 and 500.0 kHz. @@ -1392,6 +1358,14 @@ class LR11x0: public PhysicalLayer { \returns \ref status_codes */ int16_t updateFirmware(const uint32_t* image, size_t size, bool nonvolatile = true); + + int16_t isGnssScanCapable(); + + int16_t gnssScan(uint16_t* resSize); + + int16_t getGnssScanResult(uint16_t size); + + int16_t getGnssPosition(float* lat, float* lon, bool filtered); #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: @@ -1514,7 +1488,7 @@ class LR11x0: public PhysicalLayer { int16_t gnssAlmanacFullUpdateHeader(uint16_t date, uint32_t globalCrc); int16_t gnssAlmanacFullUpdateSV(uint8_t svn, uint8_t* svnAlmanac); int16_t gnssGetSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv); - int16_t gnssScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax); + int16_t gnssPerformScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax); int16_t gnssReadLastScanModeLaunched(uint8_t* lastScanMode); int16_t gnssFetchTime(uint8_t effort, uint8_t opt); int16_t gnssReadTime(uint8_t* err, uint32_t* time, uint32_t* nbUs, uint32_t* timeAccuracy);