[LR11x0] GNSS support (#1275)
* [LR11x0] Added WIP GNSS control * [LR11x0] Added almanac update * [LR11x0] Added almanac update example * [LR11x0] Add missing memory deallocation * [LR11x0] Fix underflow in delay until subframe * [LR11x0] Remove pin mapping from example * [LR11x0] Finish rework of the GNSS API * [LR11x0] Added position and satellite examples * [LR11x0] Fix result member in example * Added LR11x0 GNSS keywords * [LR11x0] Fix typo in macro name * [LR11x0] Print scan failed in example * [LR11x0] Added GNSS abort
This commit is contained in:
parent
710a1540b5
commit
00699ce225
8 changed files with 925 additions and 16 deletions
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
RadioLib LR11x0 GNSS Almanac Update Example
|
||||
|
||||
This example updates the LR11x0 GNSS almanac.
|
||||
Almanac is a database of orbital predictions of
|
||||
GNSS satellites, which allows the module to predict
|
||||
when different satellites will appear in the sky,
|
||||
and frequency of their signal.
|
||||
|
||||
Up-to-date almanac is necessary for operation!
|
||||
After an update, data will remain valid for 30 days.
|
||||
All GNSS examples require at least limited
|
||||
visibility of the sky!
|
||||
|
||||
NOTE: This example will only work for LR11x0 devices
|
||||
with sufficiently recent firmware!
|
||||
LR1110: 4.1
|
||||
LR1120: 2.1
|
||||
If your device firmware reports older firmware,
|
||||
update it using the LR11x0_Firmware_Update example.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// LR1110 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// NRST pin: 3
|
||||
// BUSY pin: 9
|
||||
LR1110 radio = new Module(10, 2, 3, 9);
|
||||
|
||||
// structure to save information about the GNSS almanac
|
||||
LR11x0GnssAlmanacStatus_t almStatus;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
// initialize LR1110 with default settings
|
||||
Serial.print(F("[LR1110] Initializing ... "));
|
||||
int state = radio.beginGNSS(RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS);
|
||||
if (state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while (true) { delay(10); }
|
||||
}
|
||||
|
||||
// check the firmware version
|
||||
Serial.print(F("[LR1110] Checking firmware version ... "));
|
||||
state = radio.isGnssScanCapable();
|
||||
if (state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("check passed!"));
|
||||
} else {
|
||||
Serial.println(F("check failed, firmware update needed."));
|
||||
while (true) { delay(10); }
|
||||
}
|
||||
|
||||
// run GNSS scans until we get at least the time
|
||||
// NOTE: Depending on visibility of satellites,
|
||||
// this may take multiple attempts!
|
||||
while(true) {
|
||||
// run GNSS scan
|
||||
Serial.print(F("[LR1110] Running GNSS scan ... "));
|
||||
state = radio.gnssScan(NULL);
|
||||
if (state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while (true) { delay(10); }
|
||||
}
|
||||
|
||||
// check almanac status
|
||||
Serial.print(F("[LR1110] Checking GNSS almanac ... "));
|
||||
state = radio.getGnssAlmanacStatus(&almStatus);
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while (true) { delay(10); }
|
||||
}
|
||||
|
||||
// we have the status, check if we have demodulated time
|
||||
if(almStatus.gps.status < RADIOLIB_LR11X0_GNSS_ALMANAC_STATUS_UP_TO_DATE) {
|
||||
Serial.println(F("time unknown, another scan needed."));
|
||||
|
||||
} else if(almStatus.gps.numUpdateNeeded > 0) {
|
||||
Serial.print(almStatus.gps.numUpdateNeeded);
|
||||
Serial.println(F(" satellites out-of-date."));
|
||||
break;
|
||||
|
||||
} else {
|
||||
Serial.println(F("no update needed!"));
|
||||
while (true) { delay(10); }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// wait until almanac data is available in the signal
|
||||
// multiple attempts are needed for this
|
||||
Serial.print(F("[LR1110] Waiting for subframe ... "));
|
||||
int state = radio.gnssDelayUntilSubframe(&almStatus, RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS);
|
||||
if(state == RADIOLIB_ERR_GNSS_SUBFRAME_NOT_AVAILABLE) {
|
||||
Serial.println(F("not enough time left."));
|
||||
|
||||
// wait until the next update window
|
||||
delay(2000);
|
||||
|
||||
} else {
|
||||
Serial.println(F("done!"));
|
||||
|
||||
// we have enough time to start the update
|
||||
Serial.print(F("[LR1110] Starting update ... "));
|
||||
state = radio.updateGnssAlmanac(RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS);
|
||||
if(state != RADIOLIB_ERR_NONE) {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
} else {
|
||||
Serial.println(F("done!"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// check whether another update is needed
|
||||
Serial.print(F("[LR1110] Checking GNSS almanac ... "));
|
||||
state = radio.getGnssAlmanacStatus(&almStatus);
|
||||
if(state != RADIOLIB_ERR_NONE) {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while (true) { delay(10); }
|
||||
}
|
||||
|
||||
// check if we have completed the update
|
||||
if(almStatus.gps.numUpdateNeeded == 0) {
|
||||
Serial.println(F("all satellites up-to-date!"));
|
||||
while (true) { delay(10); }
|
||||
} else {
|
||||
Serial.print(almStatus.gps.numUpdateNeeded);
|
||||
Serial.println(F(" satellites out-of-date."));
|
||||
}
|
||||
|
||||
// wait a bit before the next update attempt
|
||||
delay(1000);
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
RadioLib LR11x0 GNSS Autonomous Position Example
|
||||
|
||||
This example performs GNSS scans and calculates
|
||||
position of the device using autonomous mode.
|
||||
In this mode, scan data does not need to be uploaded
|
||||
to LoRaCloud, however, it requires up-to-date almanac
|
||||
data. Run the LR11x0_Almanac_Update example to update
|
||||
the device almanac.
|
||||
|
||||
NOTE: This example will only work for LR11x0 devices
|
||||
with sufficiently recent firmware!
|
||||
LR1110: 4.1
|
||||
LR1120: 2.1
|
||||
If your device firmware reports older firmware,
|
||||
update it using the LR11x0_Firmware_Update example.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// LR1110 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// NRST pin: 3
|
||||
// BUSY pin: 9
|
||||
LR1110 radio = new Module(10, 2, 3, 9);
|
||||
|
||||
// structure to save information about the GNSS scan result
|
||||
LR11x0GnssResult_t gnssResult;
|
||||
|
||||
// structure to save information about the calculated GNSS position
|
||||
LR11x0GnssPosition_t gnssPosition;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
// initialize LR1110 with default settings
|
||||
Serial.print(F("[LR1110] Initializing ... "));
|
||||
int state = radio.beginGNSS(RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS);
|
||||
if (state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while (true) { delay(10); }
|
||||
}
|
||||
|
||||
// check the firmware version
|
||||
Serial.print(F("[LR1110] Checking firmware version ... "));
|
||||
state = radio.isGnssScanCapable();
|
||||
if (state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("check passed!"));
|
||||
} else {
|
||||
Serial.println(F("check failed, firmware update needed."));
|
||||
while (true) { delay(10); }
|
||||
}
|
||||
|
||||
Serial.println(F("Scan result\t| Latitude\t| Longitude\t| Accuracy\t| Number of satellites"));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// run GNSS scan
|
||||
int state = radio.gnssScan(&gnssResult);
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
// success!
|
||||
Serial.print(gnssResult.demodStat); Serial.print("\t\t| ");
|
||||
|
||||
// get the actual data
|
||||
state = radio.getGnssPosition(&gnssPosition);
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
// print the position
|
||||
Serial.print(gnssPosition.latitude, 6);
|
||||
Serial.print("\t| ");
|
||||
Serial.print(gnssPosition.longitude, 6);
|
||||
Serial.print("\t| ");
|
||||
Serial.print(gnssPosition.accuracy);
|
||||
Serial.print("\t\t| ");
|
||||
Serial.println(gnssPosition.numSatsUsed);
|
||||
|
||||
} else {
|
||||
Serial.print(F("Failed to read result, code "));
|
||||
Serial.print(state);
|
||||
Serial.print(F(" (solver error "));
|
||||
Serial.print(RADIOLIB_GET_GNSS_SOLVER_ERROR(state));
|
||||
Serial.println(F(")"));
|
||||
}
|
||||
|
||||
} else {
|
||||
Serial.print(F("Scan failed, code "));
|
||||
Serial.print(state);
|
||||
Serial.print(F(" (demodulator error "));
|
||||
Serial.print(RADIOLIB_GET_GNSS_DEMOD_ERROR(state));
|
||||
Serial.println(F(")"));
|
||||
|
||||
}
|
||||
|
||||
// wait a bit before the next scan
|
||||
delay(1000);
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
RadioLib LR11x0 GNSS Satellites Example
|
||||
|
||||
This example performs GNSS scans and shows the satellites
|
||||
currently in view. It is mostly useful to verify
|
||||
visibility and antenna setup.
|
||||
|
||||
NOTE: This example will only work for LR11x0 devices
|
||||
with sufficiently recent firmware!
|
||||
LR1110: 4.1
|
||||
LR1120: 2.1
|
||||
If your device firmware reports older firmware,
|
||||
update it using the LR11x0_Firmware_Update example.
|
||||
|
||||
For default module settings, see the wiki page
|
||||
https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---wifi-scan
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// LR1110 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// NRST pin: 3
|
||||
// BUSY pin: 9
|
||||
LR1110 radio = new Module(10, 2, 3, 9);
|
||||
|
||||
// structure to save information about the GNSS scan result
|
||||
LR11x0GnssResult_t gnssResult;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
// initialize LR1110 with default settings
|
||||
Serial.print(F("[LR1110] Initializing ... "));
|
||||
int state = radio.beginGNSS(RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS);
|
||||
if (state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while (true) { delay(10); }
|
||||
}
|
||||
|
||||
// check the firmware version
|
||||
Serial.print(F("[LR1110] Checking firmware version ... "));
|
||||
state = radio.isGnssScanCapable();
|
||||
if (state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("check passed!"));
|
||||
} else {
|
||||
Serial.println(F("check failed, firmware update needed."));
|
||||
while (true) { delay(10); }
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Serial.print(F("[LR1110] Running GNSS scan ... "));
|
||||
int state = radio.gnssScan(&gnssResult);
|
||||
if(state != RADIOLIB_ERR_NONE) {
|
||||
// some error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.print(state);
|
||||
Serial.print(F(" (demodulator error "));
|
||||
Serial.print(RADIOLIB_GET_GNSS_DEMOD_ERROR(state));
|
||||
Serial.println(F(")"));
|
||||
|
||||
} else {
|
||||
Serial.println(F("success!"));
|
||||
|
||||
// print the table header
|
||||
Serial.print(F("[LR1110] Detected "));
|
||||
Serial.print(gnssResult.numSatsDet);
|
||||
Serial.println(F(" satellite(s):"));
|
||||
Serial.println(F(" # | ID | C/N0 [dB]\t| Doppler [Hz]"));
|
||||
|
||||
// read all results at once
|
||||
LR11x0GnssSatellite_t satellites[32];
|
||||
state = radio.getGnssSatellites(satellites, gnssResult.numSatsDet);
|
||||
if(state != RADIOLIB_ERR_NONE) {
|
||||
Serial.print(F("Failed to read results, code "));
|
||||
Serial.println(state);
|
||||
} else {
|
||||
// print all the results
|
||||
for(int i = 0; i < gnssResult.numSatsDet; i++) {
|
||||
if(i < 10) { Serial.print(" "); } Serial.print(i); Serial.print(" | ");
|
||||
Serial.print(satellites[i].svId); Serial.print(" | ");
|
||||
Serial.print(satellites[i].c_n0); Serial.print("\t\t| ");
|
||||
Serial.println(satellites[i].doppler);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// wait for a second before scanning again
|
||||
delay(1000);
|
||||
}
|
19
keywords.txt
19
keywords.txt
|
@ -100,6 +100,11 @@ LR11x0WifiResult_t KEYWORD1
|
|||
LR11x0WifiResultFull_t KEYWORD1
|
||||
LR11x0WifiResultExtended_t KEYWORD1
|
||||
LR11x0VersionInfo_t KEYWORD1
|
||||
LR11x0GnssResult_t KEYWORD1
|
||||
LR11x0GnssPosition_t KEYWORD1
|
||||
LR11x0GnssSatellite_t KEYWORD1
|
||||
LR11x0GnssAlmanacStatusPart_t KEYWORD1
|
||||
LR11x0GnssAlmanacStatus_t KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
|
@ -261,6 +266,14 @@ setWiFiScanAction KEYWORD2
|
|||
clearWiFiScanAction KEYWORD2
|
||||
getVersionInfo KEYWORD2
|
||||
updateFirmware KEYWORD2
|
||||
beginGNSS KEYWORD2
|
||||
isGnssScanCapable KEYWORD2
|
||||
gnssScan KEYWORD2
|
||||
getGnssAlmanacStatus KEYWORD2
|
||||
gnssDelayUntilSubframe KEYWORD2
|
||||
updateGnssAlmanac KEYWORD2
|
||||
getGnssPosition KEYWORD2
|
||||
getGnssSatellites KEYWORD2
|
||||
|
||||
# RTTY
|
||||
idle KEYWORD2
|
||||
|
@ -473,6 +486,12 @@ RADIOLIB_ERR_SESSION_DISCARDED LITERAL1
|
|||
RADIOLIB_ERR_INVALID_MODE LITERAL1
|
||||
|
||||
RADIOLIB_ERR_INVALID_WIFI_TYPE LITERAL1
|
||||
RADIOLIB_ERR_GNSS_SUBFRAME_NOT_AVAILABLE LITERAL1
|
||||
RADIOLIB_GET_GNSS_DEMOD_ERROR LITERAL1
|
||||
RADIOLIB_GET_GNSS_SOLVER_ERROR LITERAL1
|
||||
RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS LITERAL1
|
||||
RADIOLIB_LR11X0_GNSS_CONSTELLATION_BEIDOU LITERAL1
|
||||
RADIOLIB_LR11X0_GNSS_ALMANAC_STATUS_UP_TO_DATE LITERAL1
|
||||
|
||||
RADIOLIB_LR1110_FIRMWARE_IN_RAM LITERAL1
|
||||
RADIOLIB_LR11X0_FIRMWARE_IMAGE_SIZE LITERAL1
|
||||
|
|
|
@ -339,18 +339,20 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write
|
|||
}
|
||||
|
||||
// ensure GPIO is low
|
||||
if(this->gpioPin == RADIOLIB_NC) {
|
||||
this->hal->delay(50);
|
||||
} else {
|
||||
RadioLibTime_t start = this->hal->millis();
|
||||
while(this->hal->digitalRead(this->gpioPin)) {
|
||||
this->hal->yield();
|
||||
if(this->hal->millis() - start >= this->spiConfig.timeout) {
|
||||
RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO pre-transfer timeout, is it connected?");
|
||||
#if !RADIOLIB_STATIC_ONLY
|
||||
delete[] buffOut;
|
||||
#endif
|
||||
return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
|
||||
if(waitForGpio) {
|
||||
if(this->gpioPin == RADIOLIB_NC) {
|
||||
this->hal->delay(50);
|
||||
} else {
|
||||
RadioLibTime_t start = this->hal->millis();
|
||||
while(this->hal->digitalRead(this->gpioPin)) {
|
||||
this->hal->yield();
|
||||
if(this->hal->millis() - start >= this->spiConfig.timeout) {
|
||||
RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO pre-transfer timeout, is it connected?");
|
||||
#if !RADIOLIB_STATIC_ONLY
|
||||
delete[] buffOut;
|
||||
#endif
|
||||
return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -605,6 +605,27 @@
|
|||
*/
|
||||
#define RADIOLIB_ERR_INVALID_WIFI_TYPE (-1200)
|
||||
|
||||
/*!
|
||||
\brief GNSS subframe not available in the next 2.3 seconds.
|
||||
*/
|
||||
#define RADIOLIB_ERR_GNSS_SUBFRAME_NOT_AVAILABLE (-1201)
|
||||
|
||||
/*!
|
||||
\brief Offset of GNSS demodulator errors.
|
||||
See LR11x0 datasheet for details on the actual demodulator error
|
||||
*/
|
||||
#define RADIOLIB_ERR_GNSS_DEMOD_OFFSET (-1210)
|
||||
#define RADIOLIB_ERR_GNSS_DEMOD(X) (RADIOLIB_ERR_GNSS_DEMOD_OFFSET + (X))
|
||||
#define RADIOLIB_GET_GNSS_DEMOD_ERROR(X) ((X) - RADIOLIB_ERR_GNSS_DEMOD_OFFSET)
|
||||
|
||||
/*!
|
||||
\brief GNSS solver errors.
|
||||
See LR11x0 datasheet for details on the actual solver error
|
||||
*/
|
||||
#define RADIOLIB_ERR_GNSS_SOLVER_OFFSET (-1230)
|
||||
#define RADIOLIB_ERR_GNSS_SOLVER(X) (RADIOLIB_ERR_GNSS_SOLVER_OFFSET - (X))
|
||||
#define RADIOLIB_GET_GNSS_SOLVER_ERROR(X) (-((X) - RADIOLIB_ERR_GNSS_SOLVER_OFFSET))
|
||||
|
||||
/*!
|
||||
\}
|
||||
*/
|
||||
|
|
|
@ -120,6 +120,34 @@ int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid, float tcxoV
|
|||
return(setModulationParamsLrFhss(RADIOLIB_LR11X0_LR_FHSS_BIT_RATE_RAW, RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0));
|
||||
}
|
||||
|
||||
int16_t LR11x0::beginGNSS(uint8_t constellations, float tcxoVoltage) {
|
||||
// set module properties and perform initial setup - packet type does not matter
|
||||
int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_LORA);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = this->clearErrors();
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = this->configLfClock(RADIOLIB_LR11X0_LF_BUSY_RELEASE_DISABLED | RADIOLIB_LR11X0_LF_CLK_XOSC);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
uint16_t errs = 0;
|
||||
state = this->getErrors(&errs);
|
||||
RADIOLIB_ASSERT(state);
|
||||
if(errs & 0x40) {
|
||||
RADIOLIB_DEBUG_BASIC_PRINTLN("LF_XOSC_START_ERR");
|
||||
return(RADIOLIB_ERR_SPI_CMD_FAILED);
|
||||
}
|
||||
|
||||
state = this->gnssSetConstellationToUse(constellations);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setRegulatorLDO();
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
return(RADIOLIB_ERR_NONE);
|
||||
}
|
||||
|
||||
int16_t LR11x0::reset() {
|
||||
// run the reset sequence
|
||||
this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput);
|
||||
|
@ -1723,6 +1751,260 @@ 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;
|
||||
state = RADIOLIB_ERR_UNSUPPORTED;
|
||||
if((version.device == RADIOLIB_LR11X0_DEVICE_LR1110) && (versionFull >= 0x0401)) {
|
||||
state = RADIOLIB_ERR_NONE;
|
||||
} else if((version.device == RADIOLIB_LR11X0_DEVICE_LR1120) && (versionFull >= 0x0201)) {
|
||||
state = RADIOLIB_ERR_NONE;
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// in debug mode, dump the almanac
|
||||
#if RADIOLIB_DEBUG_PROTOCOL
|
||||
uint32_t addr = 0;
|
||||
uint16_t sz = 0;
|
||||
state = this->gnssAlmanacReadAddrSize(&addr, &sz);
|
||||
RADIOLIB_ASSERT(state);
|
||||
RADIOLIB_DEBUG_BASIC_PRINTLN("Almanac@%08x, %d bytes", addr, sz);
|
||||
uint32_t buff[32] = { 0 };
|
||||
while(sz > 0) {
|
||||
size_t len = sz > 32 ? 32 : sz/sizeof(uint32_t);
|
||||
state = this->readRegMem32(addr, buff, len);
|
||||
RADIOLIB_ASSERT(state);
|
||||
Module::hexdump(NULL, (uint8_t*)buff, len*sizeof(uint32_t), addr);
|
||||
addr += len*sizeof(uint32_t);
|
||||
sz -= len*sizeof(uint32_t);
|
||||
}
|
||||
|
||||
uint8_t almanac[22] = { 0 };
|
||||
for(uint8_t i = 0; i < 128; i++) {
|
||||
RADIOLIB_DEBUG_BASIC_PRINTLN("Almanac[%d]:", i);
|
||||
state = this->gnssAlmanacReadSV(i, almanac);
|
||||
RADIOLIB_ASSERT(state);
|
||||
Module::hexdump(NULL, almanac, 22);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t LR11x0::gnssScan(LR11x0GnssResult_t* res) {
|
||||
if(!res) {
|
||||
return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED);
|
||||
}
|
||||
|
||||
// go to standby
|
||||
int16_t state = standby();
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set DIO mapping
|
||||
state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_GNSS_DONE | RADIOLIB_LR11X0_IRQ_GNSS_ABORT);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set scan mode (single vs multiple)
|
||||
state = this->gnssSetMode(0x03);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set RF switch
|
||||
this->mod->setRfSwitchState(LR11x0::MODE_GNSS);
|
||||
|
||||
// start scan with high effort
|
||||
RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan start");
|
||||
state = this->gnssPerformScan(RADIOLIB_LR11X0_GNSS_EFFORT_MID, 0x3C, 16);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// wait for scan finished or timeout
|
||||
// this can take very long if both GPS and BeiDou are enabled
|
||||
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) {
|
||||
this->gnssAbort();
|
||||
RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for IRQ");
|
||||
}
|
||||
}
|
||||
|
||||
// restore the switch
|
||||
this->mod->setRfSwitchState(Module::MODE_IDLE);
|
||||
RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start));
|
||||
|
||||
// distinguish between GNSS-done and GNSS-abort outcomes and clear the flags
|
||||
uint32_t irq = this->getIrqStatus();
|
||||
this->clearIrq(RADIOLIB_LR11X0_IRQ_ALL);
|
||||
if(irq & RADIOLIB_LR11X0_IRQ_GNSS_ABORT) {
|
||||
return(RADIOLIB_ERR_RX_TIMEOUT);
|
||||
}
|
||||
|
||||
// retrieve the demodulator status
|
||||
uint8_t info = 0;
|
||||
state = this->gnssReadDemodStatus(&res->demodStat, &info);
|
||||
RADIOLIB_ASSERT(state);
|
||||
RADIOLIB_DEBUG_BASIC_PRINTLN("Demod status %d, info %02x", (int)res->demodStat, (unsigned int)info);
|
||||
|
||||
// retrieve the number of detected satellites
|
||||
state = this->gnssGetNbSvDetected(&res->numSatsDet);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// retrieve the result size
|
||||
state = this->gnssGetResultSize(&res->resSize);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// check and return demodulator status
|
||||
if(res->demodStat < RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_FOUND) {
|
||||
return(RADIOLIB_ERR_GNSS_DEMOD(res->demodStat));
|
||||
}
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t LR11x0::getGnssAlmanacStatus(LR11x0GnssAlmanacStatus_t *stat) {
|
||||
if(!stat) {
|
||||
return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED);
|
||||
}
|
||||
|
||||
// save the time the time until subframe is relative to
|
||||
stat->start = this->mod->hal->millis();
|
||||
|
||||
// get the raw data
|
||||
uint8_t raw[53] = { 0 };
|
||||
int16_t state = this->gnssReadAlmanacStatus(raw);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// parse the reply
|
||||
stat->gps.status = (int8_t)raw[0];
|
||||
stat->gps.timeUntilSubframe = ((uint32_t)(raw[1]) << 24) | ((uint32_t)(raw[2]) << 16) | ((uint32_t)(raw[3]) << 8) | (uint32_t)raw[4];
|
||||
stat->gps.numSubframes = raw[5];
|
||||
stat->gps.nextSubframe4SvId = raw[6];
|
||||
stat->gps.nextSubframe5SvId = raw[7];
|
||||
stat->gps.nextSubframeStart = raw[8];
|
||||
stat->gps.numUpdateNeeded = raw[9];
|
||||
stat->gps.flagsUpdateNeeded[0] = ((uint32_t)(raw[10]) << 24) | ((uint32_t)(raw[11]) << 16) | ((uint32_t)(raw[12]) << 8) | (uint32_t)raw[13];
|
||||
stat->gps.flagsActive[0] = ((uint32_t)(raw[14]) << 24) | ((uint32_t)(raw[15]) << 16) | ((uint32_t)(raw[16]) << 8) | (uint32_t)raw[17];
|
||||
stat->beidou.status = (int8_t)raw[18];
|
||||
stat->beidou.timeUntilSubframe = ((uint32_t)(raw[19]) << 24) | ((uint32_t)(raw[20]) << 16) | ((uint32_t)(raw[21]) << 8) | (uint32_t)raw[22];
|
||||
stat->beidou.numSubframes = raw[23];
|
||||
stat->beidou.nextSubframe4SvId = raw[24];
|
||||
stat->beidou.nextSubframe5SvId = raw[25];
|
||||
stat->beidou.nextSubframeStart = raw[26];
|
||||
stat->beidou.numUpdateNeeded = raw[27];
|
||||
stat->beidou.flagsUpdateNeeded[0] = ((uint32_t)(raw[28]) << 24) | ((uint32_t)(raw[29]) << 16) | ((uint32_t)(raw[30]) << 8) | (uint32_t)raw[31];
|
||||
stat->beidou.flagsUpdateNeeded[1] = ((uint32_t)(raw[32]) << 24) | ((uint32_t)(raw[33]) << 16) | ((uint32_t)(raw[34]) << 8) | (uint32_t)raw[35];
|
||||
stat->beidou.flagsActive[0] = ((uint32_t)(raw[36]) << 24) | ((uint32_t)(raw[37]) << 16) | ((uint32_t)(raw[38]) << 8) | (uint32_t)raw[39];
|
||||
stat->beidou.flagsActive[1] = ((uint32_t)(raw[40]) << 24) | ((uint32_t)(raw[41]) << 16) | ((uint32_t)(raw[42]) << 8) | (uint32_t)raw[43];
|
||||
stat->beidouSvNoAlmanacFlags[0] = ((uint32_t)(raw[44]) << 24) | ((uint32_t)(raw[45]) << 16) | ((uint32_t)(raw[46]) << 8) | (uint32_t)raw[47];
|
||||
stat->beidouSvNoAlmanacFlags[1] = ((uint32_t)(raw[18]) << 24) | ((uint32_t)(raw[49]) << 16) | ((uint32_t)(raw[50]) << 8) | (uint32_t)raw[51];
|
||||
stat->nextAlmanacId = raw[52];
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t LR11x0::gnssDelayUntilSubframe(LR11x0GnssAlmanacStatus_t *stat, uint8_t constellation) {
|
||||
if(!stat) {
|
||||
return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED);
|
||||
}
|
||||
|
||||
// almanac update has to be called at least 1.3 seconds before the subframe
|
||||
// we use 2.3 seconds to be on the safe side
|
||||
|
||||
// calculate absolute times
|
||||
RadioLibTime_t window = stat->start + stat->gps.timeUntilSubframe - 2300;
|
||||
if(constellation == RADIOLIB_LR11X0_GNSS_CONSTELLATION_BEIDOU) {
|
||||
window = stat->start + stat->beidou.timeUntilSubframe - 2300;
|
||||
}
|
||||
RadioLibTime_t now = this->mod->hal->millis();
|
||||
if(now > window) {
|
||||
// we missed the window
|
||||
return(RADIOLIB_ERR_GNSS_SUBFRAME_NOT_AVAILABLE);
|
||||
}
|
||||
|
||||
RadioLibTime_t delay = window - now;
|
||||
RADIOLIB_DEBUG_BASIC_PRINTLN("Time until subframe %lu ms", delay);
|
||||
this->mod->hal->delay(delay);
|
||||
return(RADIOLIB_ERR_NONE);
|
||||
}
|
||||
|
||||
// TODO fix last satellite always out of date
|
||||
int16_t LR11x0::updateGnssAlmanac(uint8_t constellation) {
|
||||
int16_t state = this->setDioIrqParams(RADIOLIB_LR11X0_IRQ_GNSS_DONE | RADIOLIB_LR11X0_IRQ_GNSS_ABORT);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = this->gnssAlmanacUpdateFromSat(RADIOLIB_LR11X0_GNSS_EFFORT_MID, constellation);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// wait for scan finished or timeout, assumes 2 subframes and up to 2.3s pre-roll
|
||||
uint32_t softTimeout = 16UL * 1000UL;
|
||||
uint32_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) {
|
||||
this->gnssAbort();
|
||||
RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for almanac update");
|
||||
}
|
||||
}
|
||||
|
||||
RADIOLIB_DEBUG_BASIC_PRINTLN("GPS almanac update done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start));
|
||||
|
||||
// distinguish between GNSS-done and GNSS-abort outcomes and clear the flags
|
||||
uint32_t irq = this->getIrqStatus();
|
||||
this->clearIrq(RADIOLIB_LR11X0_IRQ_ALL);
|
||||
if(irq & RADIOLIB_LR11X0_IRQ_GNSS_ABORT) {
|
||||
state = RADIOLIB_ERR_RX_TIMEOUT;
|
||||
}
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t LR11x0::getGnssPosition(LR11x0GnssPosition_t* pos, bool filtered) {
|
||||
if(!pos) {
|
||||
return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED);
|
||||
}
|
||||
|
||||
uint8_t error = 0;
|
||||
int16_t state;
|
||||
if(filtered) {
|
||||
state = this->gnssReadDopplerSolverRes(&error, &pos->numSatsUsed, NULL, NULL, NULL, NULL, &pos->latitude, &pos->longitude, &pos->accuracy, NULL);
|
||||
} else {
|
||||
state = this->gnssReadDopplerSolverRes(&error, &pos->numSatsUsed, &pos->latitude, &pos->longitude, &pos->accuracy, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// check the solver error
|
||||
if(error != 0) {
|
||||
return(RADIOLIB_ERR_GNSS_SOLVER(error));
|
||||
}
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t LR11x0::getGnssSatellites(LR11x0GnssSatellite_t* sats, uint8_t numSats) {
|
||||
if((!sats) || (numSats >= 32)) {
|
||||
return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED);
|
||||
}
|
||||
|
||||
uint8_t svId[32] = { 0 };
|
||||
uint8_t snr[32] = { 0 };
|
||||
int16_t doppler[32] = { 0 };
|
||||
int16_t state = this->gnssGetSvDetected(svId, snr, doppler, numSats);
|
||||
RADIOLIB_ASSERT(state);
|
||||
for(size_t i = 0; i < numSats; i++) {
|
||||
sats[i].svId = svId[i];
|
||||
sats[i].c_n0 = snr[i] + 31;
|
||||
sats[i].doppler = doppler[i];
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -1816,7 +2098,9 @@ bool LR11x0::findChip(uint8_t ver) {
|
|||
// read the version
|
||||
LR11x0VersionInfo_t info;
|
||||
int16_t state = getVersionInfo(&info);
|
||||
if((state == RADIOLIB_ERR_NONE) && (info.device == ver)) {
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
if(info.device == ver) {
|
||||
RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR11x0: RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", info.device);
|
||||
RADIOLIB_DEBUG_BASIC_PRINTLN("Base FW version: %d.%d", (int)info.fwMajor, (int)info.fwMinor);
|
||||
if(this->chipType != RADIOLIB_LR11X0_DEVICE_LR1121) {
|
||||
|
@ -2122,7 +2406,7 @@ int16_t LR11x0::setDioIrqParams(uint32_t irq1, uint32_t irq2) {
|
|||
}
|
||||
|
||||
int16_t LR11x0::setDioIrqParams(uint32_t irq) {
|
||||
return(setDioIrqParams(irq, irq));
|
||||
return(setDioIrqParams(irq, 0));
|
||||
}
|
||||
|
||||
int16_t LR11x0::clearIrq(uint32_t irq) {
|
||||
|
@ -3314,6 +3598,16 @@ int16_t LR11x0::gnssWriteBitMaskSatActivated(uint8_t bitMask, uint32_t* bitMaskA
|
|||
return(state);
|
||||
}
|
||||
|
||||
void LR11x0::gnssAbort() {
|
||||
// send the abort signal (single NOP)
|
||||
this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
|
||||
this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_NOP, NULL, 0, false, false);
|
||||
this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16;
|
||||
|
||||
// wait for at least 2.9 seconds as specified by the user manual
|
||||
this->mod->hal->delay(3000);
|
||||
}
|
||||
|
||||
int16_t LR11x0::cryptoSetKey(uint8_t keyId, uint8_t* key) {
|
||||
if(!key) {
|
||||
return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED);
|
||||
|
@ -3374,11 +3668,17 @@ int16_t LR11x0::cryptoProcessJoinAccept(uint8_t decKeyId, uint8_t verKeyId, uint
|
|||
// check the crypto engine state
|
||||
if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) {
|
||||
RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]);
|
||||
#if !RADIOLIB_STATIC_ONLY
|
||||
delete[] rplBuff;
|
||||
#endif
|
||||
return(RADIOLIB_ERR_SPI_CMD_FAILED);
|
||||
}
|
||||
|
||||
// pass the data
|
||||
memcpy(dataOut, &rplBuff[1], len);
|
||||
#if !RADIOLIB_STATIC_ONLY
|
||||
delete[] rplBuff;
|
||||
#endif
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
@ -3609,6 +3909,9 @@ int16_t LR11x0::cryptoCommon(uint16_t cmd, uint8_t keyId, uint8_t* dataIn, size_
|
|||
|
||||
// pass the data
|
||||
memcpy(dataOut, &rplBuff[1], len);
|
||||
#if !RADIOLIB_STATIC_ONLY
|
||||
delete[] rplBuff;
|
||||
#endif
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
|
|
@ -274,7 +274,8 @@
|
|||
#define RADIOLIB_LR11X0_IRQ_FSK_LEN_ERROR (0x01UL << 24) // 31 0 FSK packet received with length error
|
||||
#define RADIOLIB_LR11X0_IRQ_FSK_ADDR_ERROR (0x01UL << 25) // 31 0 FSK packet received with address error
|
||||
#define RADIOLIB_LR11X0_IRQ_LORA_RX_TIMESTAMP (0x01UL << 27) // 31 0 last LoRa symbol was received (timestamp source)
|
||||
#define RADIOLIB_LR11X0_IRQ_ALL (0x0BF80FFCUL) // 31 0 all interrupts
|
||||
#define RADIOLIB_LR11X0_IRQ_GNSS_ABORT (0x01UL << 28) // 31 0 GNSS scan aborted
|
||||
#define RADIOLIB_LR11X0_IRQ_ALL (0x1BF80FFCUL) // 31 0 all interrupts
|
||||
#define RADIOLIB_LR11X0_IRQ_NONE (0x00UL << 0) // 31 0 no interrupts
|
||||
|
||||
// RADIOLIB_LR11X0_CMD_CONFIG_LF_LOCK
|
||||
|
@ -552,7 +553,7 @@
|
|||
#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_FLASH (0x03UL << 0) // 7 4 flash integrity error
|
||||
#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_ALMANAC_UPD (0x04UL << 0) // 7 4 almanac update not allowed
|
||||
#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_250_HZ (0x00UL << 0) // 8 7 frequency search space: 250 Hz
|
||||
#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_500_HZ (0x01UL << 0) // 8 7 500 H
|
||||
#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_500_HZ (0x01UL << 0) // 8 7 500 Hz
|
||||
#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_1000_HZ (0x02UL << 0) // 8 7 1000 Hz
|
||||
#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_2000_HZ (0x03UL << 0) // 8 7 2000 Hz
|
||||
|
||||
|
@ -564,6 +565,65 @@
|
|||
#define RADIOLIB_LR11X0_GNSS_ALMANAC_HEADER_ID (0x80UL << 0) // 7 0 starting byte of GNSS almanac header
|
||||
#define RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE (20)
|
||||
|
||||
// RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME
|
||||
#define RADIOLIB_LR11X0_GNSS_EFFORT_LOW (0x00UL << 0) // 7 0 GNSS effort mode: low sensitivity
|
||||
#define RADIOLIB_LR11X0_GNSS_EFFORT_MID (0x01UL << 0) // 7 0 medium sensitivity
|
||||
#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW (0x00UL << 0) // 7 0 time fetch options: ToW only, requires WN to demodulated beforehand
|
||||
#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW_WN (0x01UL << 0) // 7 0 ToW and WN
|
||||
#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW_WN_ROLL (0x02UL << 0) // 7 0 ToW, WN and rollover
|
||||
|
||||
// RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NOT_POSSIBLE (-21) // 7 0 GNSS demodulation status: not possible to demodulate
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SAT_LOST (-20) // 7 0 satellite lost
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_ALMANAC_DEMOD_ERROR (-19) // 7 0 almanac demodulation error
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOO_LATE (-18) // 7 0 woke up after preamble (demodulation started too late)
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_20_MS_FAIL (-17) // 7 0 20ms real-time clock failed
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WAKE_UP_FAIL (-16) // 7 0 wake up sync failed
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WN_INVALID (-15) // 7 0 week number not validated
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_ACTIVE_SAT (-14) // 7 0 no active satellite selected in satellite list
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SLEEP_TOO_LONG (-13) // 7 0 sleep time too long
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_INVALID (-12) // 7 0 wrong time-of-week demodulated
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PREAMBLE_INVALID (-11) // 7 0 preamble not validated
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_DISABLED (-10) // 7 0 demodulator disabled
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_EXTR_FAILED (-9) // 7 0 demodulator extraction failed
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_BIT_CHANGE (-8) // 7 0 no bit change found during demodulation start
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_BIT_CHANGE_ADV (-7) // 7 0 no bit change found during advanced scan
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_SAT_FOUND (-6) // 7 0 no satellites found
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SYNC_LOST (-5) // 7 0 word sync lost
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PARITY_NOT_ENOUGH (-3) // 7 0 parity check fail (not enough)
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PARITY_TOO_MANY (-2) // 7 0 parity check fail (too many)
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_PARITY (-1) // 7 0 parity check fail (no parity found)
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_NONE (0) // 7 0 word sync search not started
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_POT (1) // 7 0 potential word sync found
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_OK (2) // 7 0 word sync found
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_FOUND (3) // 7 0 time-of-week found
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WN_FOUND (4) // 7 0 week number and time-of-week found
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_ALM_FOUND_UNSAVED (5) // 7 0 almanac found but not saved
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_HALF_ALM_SAVED (6) // 7 0 half of almanac found and saved
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_FULL_ALM_SAVED (7) // 7 0 full almanac found and saved
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WORD_SYNC_FOUND (0x01UL << 0) // 7 0 GNSS demodulation info: word synchronization found
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_TOW_FOUND (0x01UL << 1) // 7 0 time-of-week found
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WN_DEMODED (0x01UL << 2) // 7 0 week number demodulated
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WN_FOUND (0x01UL << 3) // 7 0 week number found
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_1_FOUND (0x01UL << 4) // 7 0 subframe 1 found
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_4_FOUND (0x01UL << 5) // 7 0 subframe 4 found
|
||||
#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_5_FOUND (0x01UL << 6) // 7 0 subframe 5 found
|
||||
|
||||
// RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS
|
||||
#define RADIOLIB_LR11X0_GNSS_ALMANAC_STATUS_UP_TO_DATE (0) // 7 0 GPS/BeiDou almanac status: all satellites up-to-date
|
||||
#define RADIOLIB_LR11X0_GNSS_ALMANAC_STATUS_OUTDATED (1) // 7 0 at least one satellite needs update
|
||||
|
||||
// RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES
|
||||
#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NONE (0) // 7 0 internal 2D solver error: no error
|
||||
#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_RES_HIGH (1) // 7 0 residue too high
|
||||
#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NOT_CONVERGED (2) // 7 0 not converged on solution
|
||||
#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NOT_ENOUGH_SV (3) // 7 0 not enough satellites
|
||||
#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ILL_MATRIX (4) // 7 0 matrix error (?)
|
||||
#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_TIME (5) // 7 0 time error
|
||||
#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ALM_PART_OLD (6) // 7 0 part of almanac too old or not available
|
||||
#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_INCONSISTENT (7) // 7 0 not consistent with history (?)
|
||||
#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ALM_OLD (8) // 7 0 all of almanac too old
|
||||
|
||||
// RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY
|
||||
#define RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS (0x00UL << 0) // 7 0 crypto engine status: success
|
||||
#define RADIOLIB_LR11X0_CRYPTO_STATUS_FAIL_CMAC (0x01UL << 0) // 7 0 MIC check failed
|
||||
|
@ -717,8 +777,90 @@ struct LR11x0VersionInfo_t {
|
|||
uint8_t almanacGNSS;
|
||||
};
|
||||
|
||||
/*!
|
||||
\struct LR11x0GnssResult_t
|
||||
\brief Structure to report information results of a GNSS scan.
|
||||
*/
|
||||
struct LR11x0GnssResult_t {
|
||||
/*! \brief Demodulator status. One of RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_* */
|
||||
int8_t demodStat;
|
||||
|
||||
/*! \brief Number of satellites detected during the scan. */
|
||||
uint8_t numSatsDet;
|
||||
|
||||
/*! \brief Result size, used when passing data to LoRa cloud. */
|
||||
uint16_t resSize;
|
||||
};
|
||||
|
||||
/*!
|
||||
\struct LR11x0GnssPosition_t
|
||||
\brief Structure to report position from LR11x0 internal solver.
|
||||
*/
|
||||
struct LR11x0GnssPosition_t {
|
||||
/*! \brief Latitude in degrees. */
|
||||
float latitude;
|
||||
|
||||
/*! \brief Longitude in degrees. */
|
||||
float longitude;
|
||||
|
||||
/*! \brief Accuracy of this result. */
|
||||
uint16_t accuracy;
|
||||
|
||||
/*! \brief Number of satellites used to solve this position. */
|
||||
uint8_t numSatsUsed;
|
||||
};
|
||||
|
||||
/*!
|
||||
\struct LR11x0GnssSatellite_t
|
||||
\brief Structure to save information about a satellite found during GNSS scan.
|
||||
*/
|
||||
struct LR11x0GnssSatellite_t {
|
||||
/*! \brief Satellite vehicle (SV) identifier. */
|
||||
uint8_t svId;
|
||||
|
||||
/*! \brief C/N0 in dB. */
|
||||
uint8_t c_n0;
|
||||
|
||||
/*! \brief Doppler shift of the signal in Hz. */
|
||||
int16_t doppler;
|
||||
};
|
||||
|
||||
/*!
|
||||
\struct LR11x0GnssAlmanacStatusPart_t
|
||||
\brief Structure to save information about one constellation of the GNSS almanac.
|
||||
*/
|
||||
struct LR11x0GnssAlmanacStatusPart_t {
|
||||
int8_t status;
|
||||
uint32_t timeUntilSubframe;
|
||||
uint8_t numSubframes;
|
||||
uint8_t nextSubframe4SvId;
|
||||
uint8_t nextSubframe5SvId;
|
||||
uint8_t nextSubframeStart;
|
||||
uint8_t numUpdateNeeded;
|
||||
uint32_t flagsUpdateNeeded[2];
|
||||
uint32_t flagsActive[2];
|
||||
};
|
||||
|
||||
/*!
|
||||
\struct LR11x0GnssAlmanacStatus_t
|
||||
\brief Structure to save information about the GNSS almanac.
|
||||
This is not the actual almanac, just some context information about it.
|
||||
*/
|
||||
struct LR11x0GnssAlmanacStatus_t {
|
||||
/*! \brief GPS part of the almanac */
|
||||
LR11x0GnssAlmanacStatusPart_t gps;
|
||||
|
||||
/*! \brief BeiDou part of the almanac */
|
||||
LR11x0GnssAlmanacStatusPart_t beidou;
|
||||
|
||||
/*! \brief Extra flags present for BeiDou only */
|
||||
uint32_t beidouSvNoAlmanacFlags[2];
|
||||
|
||||
/*! \brief Next almanac ID */
|
||||
uint8_t nextAlmanacId;
|
||||
|
||||
/*! \brief Timestamp of when almanac status was retrieved - timeUntilSubframe is relative to this value. */
|
||||
RadioLibTime_t start;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -802,6 +944,14 @@ class LR11x0: public PhysicalLayer {
|
|||
*/
|
||||
int16_t beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid, float tcxoVoltage);
|
||||
|
||||
/*!
|
||||
\brief Initialization method for GNSS scanning.
|
||||
\param constellations GNSS constellations to use (GPS, BeiDou or both). Defaults to both.
|
||||
\param tcxoVoltage TCXO reference voltage to be set.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t beginGNSS(uint8_t constellations = RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS | RADIOLIB_LR11X0_GNSS_CONSTELLATION_BEIDOU, float tcxoVoltage = 1.6);
|
||||
|
||||
/*!
|
||||
\brief Reset method. Will reset the chip to the default state using RST pin.
|
||||
\returns \ref status_codes
|
||||
|
@ -1396,6 +1546,63 @@ class LR11x0: public PhysicalLayer {
|
|||
*/
|
||||
int16_t updateFirmware(const uint32_t* image, size_t size, bool nonvolatile = true);
|
||||
|
||||
/*!
|
||||
\brief Method to check whether the device is capable of performing a GNSS scan.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t isGnssScanCapable();
|
||||
|
||||
/*!
|
||||
\brief Performs GNSS scan.
|
||||
\param res Pointer to LR11x0GnssPosition_t structure to populate.
|
||||
Will not be saved if set to NULL, defaults to NULL.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t gnssScan(LR11x0GnssResult_t* res = NULL);
|
||||
|
||||
/*!
|
||||
\brief Read information about the almanac.
|
||||
\param stat Pointer to structure to save the almanac status into.
|
||||
This is not the actual almanac, just a structure providing information about it.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t getGnssAlmanacStatus(LR11x0GnssAlmanacStatus_t *stat);
|
||||
|
||||
/*!
|
||||
\brief Blocking wait until the next subframe with almanac data is available.
|
||||
Used to control timing during almanac update from satellite.
|
||||
\param stat Pointer to structure containing the almanac status read by getGnssAlmanacStatus.
|
||||
This is not the actual almanac, just a structure providing information about it.
|
||||
\param constellation Constellation to wait for, one of RADIOLIB_LR11X0_GNSS_CONSTELLATION_*.
|
||||
Constellations cannot be updated at the same time, but rather must be updated sequentially!
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t gnssDelayUntilSubframe(LR11x0GnssAlmanacStatus_t *stat, uint8_t constellation);
|
||||
|
||||
/*!
|
||||
\brief Perform almanac update. Must be called immediately after gnssDelayUntilSubframe.
|
||||
\param constellation Constellation to update, one of RADIOLIB_LR11X0_GNSS_CONSTELLATION_*.
|
||||
Constellations cannot be updated at the same time, but rather must be updated sequentially!
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t updateGnssAlmanac(uint8_t constellation);
|
||||
|
||||
/*!
|
||||
\brief Get GNSS position. Called after gnssScan to retrieve the position calculated by the internal solver.
|
||||
\param pos Pointer to LR11x0GnssPosition_t structure to populate.
|
||||
\param filtered Whether to save the filtered, or unfiltered values. Defaults to true (filtered).
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t getGnssPosition(LR11x0GnssPosition_t* pos, bool filtered = true);
|
||||
|
||||
/*!
|
||||
\brief Get GNSS satellites found during the last scan.
|
||||
\param sats Pointer to array of LR11x0GnssSatellite_t structures to populate.
|
||||
\param numSats Number of satellites to read. Can be retrieved from LR11x0GnssResult_t passed to gnssScan.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t getGnssSatellites(LR11x0GnssSatellite_t* sats, uint8_t numSats);
|
||||
|
||||
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
|
||||
protected:
|
||||
#endif
|
||||
|
@ -1546,6 +1753,7 @@ class LR11x0: public PhysicalLayer {
|
|||
int16_t gnssReadWarmStartStatus(uint8_t bitMask, uint8_t* nbVisSat, uint32_t* timeElapsed);
|
||||
int16_t gnssGetSvSync(uint8_t mask, uint8_t nbSv, uint8_t* syncList);
|
||||
int16_t gnssWriteBitMaskSatActivated(uint8_t bitMask, uint32_t* bitMaskActivated0, uint32_t* bitMaskActivated1);
|
||||
void gnssAbort();
|
||||
|
||||
int16_t cryptoSetKey(uint8_t keyId, uint8_t* key);
|
||||
int16_t cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, uint8_t* key);
|
||||
|
|
Loading…
Add table
Reference in a new issue