Merge pull request #8247 from meshtastic/develop

Develop to master
This commit is contained in:
Ben Meadors
2025-10-07 06:26:28 -05:00
committed by GitHub
8 changed files with 276 additions and 186 deletions

View File

@@ -378,7 +378,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
case SHT31_4x_ADDR: // same as OPT3001_ADDR_ALT case SHT31_4x_ADDR: // same as OPT3001_ADDR_ALT
case SHT31_4x_ADDR_ALT: // same as OPT3001_ADDR case SHT31_4x_ADDR_ALT: // same as OPT3001_ADDR
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2); registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2);
if (registerValue == 0x11a2 || registerValue == 0x11da || registerValue == 0xe9c || registerValue == 0xc8d) { if (registerValue == 0x11a2 || registerValue == 0x11da || registerValue == 0x11f3 || registerValue == 0xe9c || registerValue == 0xc8d) {
type = SHT4X; type = SHT4X;
logFoundDevice("SHT4X", (uint8_t)addr.address); logFoundDevice("SHT4X", (uint8_t)addr.address);
} else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) { } else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) {

View File

@@ -506,10 +506,9 @@ bool GPS::setup()
delay(1000); delay(1000);
#endif #endif
if (probeTries < GPS_PROBETRIES) { if (probeTries < GPS_PROBETRIES) {
LOG_DEBUG("Probe for GPS at %d", serialSpeeds[speedSelect]);
gnssModel = probe(serialSpeeds[speedSelect]); gnssModel = probe(serialSpeeds[speedSelect]);
if (gnssModel == GNSS_MODEL_UNKNOWN) { if (gnssModel == GNSS_MODEL_UNKNOWN) {
if (++speedSelect == array_count(serialSpeeds)) { if (currentStep == 0 && ++speedSelect == array_count(serialSpeeds)) {
speedSelect = 0; speedSelect = 0;
++probeTries; ++probeTries;
} }
@@ -518,10 +517,9 @@ bool GPS::setup()
// Rare Serial Speeds // Rare Serial Speeds
#ifndef CONFIG_IDF_TARGET_ESP32C6 #ifndef CONFIG_IDF_TARGET_ESP32C6
if (probeTries == GPS_PROBETRIES) { if (probeTries == GPS_PROBETRIES) {
LOG_DEBUG("Probe for GPS at %d", rareSerialSpeeds[speedSelect]);
gnssModel = probe(rareSerialSpeeds[speedSelect]); gnssModel = probe(rareSerialSpeeds[speedSelect]);
if (gnssModel == GNSS_MODEL_UNKNOWN) { if (gnssModel == GNSS_MODEL_UNKNOWN) {
if (++speedSelect == array_count(rareSerialSpeeds)) { if (currentStep == 0 && ++speedSelect == array_count(rareSerialSpeeds)) {
LOG_WARN("Give up on GPS probe and set to %d", GPS_BAUDRATE); LOG_WARN("Give up on GPS probe and set to %d", GPS_BAUDRATE);
return true; return true;
} }
@@ -1033,7 +1031,7 @@ void GPS::down()
LOG_DEBUG("%us until next search", sleepTime / 1000); LOG_DEBUG("%us until next search", sleepTime / 1000);
// If update interval less than 10 seconds, no attempt to sleep // If update interval less than 10 seconds, no attempt to sleep
if (updateInterval <= 10 * 1000UL || sleepTime == 0) if (updateInterval <= GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS || sleepTime == 0)
setPowerState(GPS_IDLE); setPowerState(GPS_IDLE);
else { else {
@@ -1094,7 +1092,7 @@ int32_t GPS::runOnce()
return disable(); return disable();
} }
if (!setup()) if (!setup())
return 2000; // Setup failed, re-run in two seconds return currentDelay; // Setup failed, re-run in two seconds
// We have now loaded our saved preferences from flash // We have now loaded our saved preferences from flash
if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED) { if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
@@ -1104,6 +1102,29 @@ int32_t GPS::runOnce()
publishUpdate(); publishUpdate();
} }
// ======================== GPS_ACTIVE state ========================
// In GPS_ACTIVE state, GPS is powered on and we're receiving NMEA messages.
// We use the following logic to determine when to update the local position
// or time by running GPS::publishUpdate.
// Note: Local position update is asynchronous to position broadcast. We
// generally run this state every gps_update_interval seconds, and in most cases
// gps_update_interval is faster than the position broadcast interval so there's a
// fresh position ready when the device wants to broadcast one on the mesh.
//
// 1. Got a time for the first time --> set the time, don't publish.
// 2. Got a lock for the first time
// --> If gps_update_interval is <= 10s --> publishUpdate
// --> Otherwise, hold for MIN(gps_update_interval - GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS, 20s)
// 3. Got a lock after turning back on
// --> If gps_update_interval is <= 10s --> publishUpdate
// --> Otherwise, hold for MIN(gps_update_interval - GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS, 20s)
// 4. Hold has expired
// --> If we have a time and a location --> publishUpdate
// --> down()
// 5. Search time has expired
// --> If we have a time and a location --> publishUpdate
// --> If we had a location before but don't now --> publishUpdate
// --> down()
if (whileActive()) { if (whileActive()) {
// if we have received valid NMEA claim we are connected // if we have received valid NMEA claim we are connected
setConnected(); setConnected();
@@ -1113,55 +1134,81 @@ int32_t GPS::runOnce()
if (!config.position.fixed_position && powerState != GPS_ACTIVE && scheduling.isUpdateDue()) if (!config.position.fixed_position && powerState != GPS_ACTIVE && scheduling.isUpdateDue())
up(); up();
// If we've already set time from the GPS, no need to ask the GPS // quality of the previous fix. We set it to 0 when we go down, so it's a way
bool gotTime = (getRTCQuality() >= RTCQualityGPS); // to check if we're getting a lock after being GPS_OFF.
if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time
gotTime = true;
shouldPublish = true;
}
uint8_t prev_fixQual = fixQual; uint8_t prev_fixQual = fixQual;
bool gotLoc = lookForLocation();
if (gotLoc && !hasValidLocation) { // declare that we have location ASAP
LOG_DEBUG("hasValidLocation RISING EDGE");
hasValidLocation = true;
shouldPublish = true;
// Hold for 20secs after getting a lock to download ephemeris etc
fixHoldEnds = millis() + 20000;
}
if (gotLoc && prev_fixQual == 0) { // just got a lock after turning back on. if (powerState == GPS_ACTIVE) {
fixHoldEnds = millis() + 20000; // if gps_update_interval is <=10s, GPS never goes off, so we treat that differently
shouldPublish = true; // Publish immediately, since next publish is at end of hold uint32_t updateInterval = Default::getConfiguredOrDefaultMs(config.position.gps_update_interval);
}
bool tooLong = scheduling.searchedTooLong(); // 1. Got a time for the first time
if (tooLong) bool gotTime = (getRTCQuality() >= RTCQualityGPS);
LOG_WARN("Couldn't publish a valid location: didn't get a GPS lock in time"); if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time
gotTime = true;
}
// Once we get a location we no longer desperately want an update // 2. Got a lock for the first time, or 3. Got a lock after turning back on
if ((gotLoc && gotTime) || tooLong) { bool gotLoc = lookForLocation();
if (gotLoc) {
#ifdef GPS_DEBUG
if (!hasValidLocation) { // declare that we have location ASAP
LOG_DEBUG("hasValidLocation RISING EDGE");
}
#endif
if (updateInterval <= GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS) {
hasValidLocation = true;
shouldPublish = true;
} else if (!hasValidLocation || prev_fixQual == 0 || (fixHoldEnds + GPS_THREAD_INTERVAL) < millis()) {
hasValidLocation = true;
// Hold for up to 20secs after getting a lock to download ephemeris etc
uint32_t holdTime = updateInterval - GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS;
if (holdTime > GPS_FIX_HOLD_MAX_MS)
holdTime = GPS_FIX_HOLD_MAX_MS;
fixHoldEnds = millis() + holdTime;
#ifdef GPS_DEBUG
LOG_DEBUG("Holding for %ums after lock", holdTime);
#endif
}
}
bool tooLong = scheduling.searchedTooLong();
if (tooLong && !gotLoc) { if (tooLong && !gotLoc) {
LOG_WARN("Couldn't publish a valid location: didn't get a GPS lock in time");
// we didn't get a location during this ack window, therefore declare loss of lock // we didn't get a location during this ack window, therefore declare loss of lock
if (hasValidLocation) { if (hasValidLocation) {
LOG_DEBUG("hasValidLocation FALLING EDGE"); p = meshtastic_Position_init_default;
} hasValidLocation = false;
p = meshtastic_Position_init_default; shouldPublish = true;
hasValidLocation = false;
}
if (millis() > fixHoldEnds) {
shouldPublish = true; // publish our update at the end of the lock hold
publishUpdate();
down();
#ifdef GPS_DEBUG #ifdef GPS_DEBUG
} else { LOG_DEBUG("hasValidLocation FALLING EDGE");
#endif
}
}
// Hold has expired , Search time has expired, we got a time only, or we never needed to hold.
bool holdExpired = (fixHoldEnds != 0 && millis() > fixHoldEnds);
if (shouldPublish || tooLong || holdExpired) {
if (gotTime && hasValidLocation) {
shouldPublish = true;
}
if (shouldPublish) {
fixHoldEnds = 0;
publishUpdate();
}
// There's a chance we just got a time, so keep going to see if we can get a location too
if (tooLong || holdExpired) {
down();
}
#ifdef GPS_DEBUG
} else if (fixHoldEnds != 0) {
LOG_DEBUG("Holding for GPS data download: %d ms (numSats=%d)", fixHoldEnds - millis(), p.sats_in_view); LOG_DEBUG("Holding for GPS data download: %d ms (numSats=%d)", fixHoldEnds - millis(), p.sats_in_view);
#endif #endif
} }
} }
// ===================== end GPS_ACTIVE state ========================
// If state has changed do a publish
publishUpdate();
if (config.position.fixed_position == true && hasValidLocation) if (config.position.fixed_position == true && hasValidLocation)
return disable(); // This should trigger when we have a fixed position, and get that first position return disable(); // This should trigger when we have a fixed position, and get that first position
@@ -1218,163 +1265,197 @@ static const char *DETECTED_MESSAGE = "%s detected";
GnssModel_t GPS::probe(int serialSpeed) GnssModel_t GPS::probe(int serialSpeed)
{ {
uint8_t buffer[768] = {0};
switch (currentStep) {
case 0: {
#if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_STM32WL) #if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_STM32WL)
_serial_gps->end(); _serial_gps->end();
_serial_gps->begin(serialSpeed); _serial_gps->begin(serialSpeed);
#elif defined(ARCH_RP2040) #elif defined(ARCH_RP2040)
_serial_gps->end(); _serial_gps->end();
_serial_gps->setFIFOSize(256); _serial_gps->setFIFOSize(256);
_serial_gps->begin(serialSpeed); _serial_gps->begin(serialSpeed);
#else #else
if (_serial_gps->baudRate() != serialSpeed) { if (_serial_gps->baudRate() != serialSpeed) {
LOG_DEBUG("Set Baud to %i", serialSpeed); LOG_DEBUG("Set GPS Baud to %i", serialSpeed);
_serial_gps->updateBaudRate(serialSpeed); _serial_gps->updateBaudRate(serialSpeed);
} }
#endif #endif
memset(&ublox_info, 0, sizeof(ublox_info)); memset(&ublox_info, 0, sizeof(ublox_info));
uint8_t buffer[768] = {0}; delay(100);
delay(100);
// Close all NMEA sentences, valid for L76K, ATGM336H (and likely other AT6558 devices) // Close all NMEA sentences, valid for L76K, ATGM336H (and likely other AT6558 devices)
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n"); _serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
delay(20); delay(20);
// Close NMEA sequences on Ublox // Close NMEA sequences on Ublox
_serial_gps->write("$PUBX,40,GLL,0,0,0,0,0,0*5C\r\n"); _serial_gps->write("$PUBX,40,GLL,0,0,0,0,0,0*5C\r\n");
_serial_gps->write("$PUBX,40,GSV,0,0,0,0,0,0*59\r\n"); _serial_gps->write("$PUBX,40,GSV,0,0,0,0,0,0*59\r\n");
_serial_gps->write("$PUBX,40,VTG,0,0,0,0,0,0*5E\r\n"); _serial_gps->write("$PUBX,40,VTG,0,0,0,0,0,0*5E\r\n");
delay(20); delay(20);
// Close NMEA sequences on CM121 // Close NMEA sequences on CM121
_serial_gps->write("$CFGMSG,0,1,0,1*1B\r\n"); _serial_gps->write("$CFGMSG,0,1,0,1*1B\r\n");
_serial_gps->write("$CFGMSG,0,2,0,1*18\r\n"); _serial_gps->write("$CFGMSG,0,2,0,1*18\r\n");
_serial_gps->write("$CFGMSG,0,3,0,1*19\r\n"); _serial_gps->write("$CFGMSG,0,3,0,1*19\r\n");
delay(20); currentDelay = 20;
currentStep = 1;
// Unicore UFirebirdII Series: UC6580, UM620, UM621, UM670A, UM680A, or UM681A,or CM121
std::vector<ChipInfo> unicore = {
{"UC6580", "UC6580", GNSS_MODEL_UC6580}, {"UM600", "UM600", GNSS_MODEL_UC6580}, {"CM121", "CM121", GNSS_MODEL_CM121}};
PROBE_FAMILY("Unicore Family", "$PDTINFO", unicore, 500);
std::vector<ChipInfo> atgm = {
{"ATGM336H", "$GPTXT,01,01,02,HW=ATGM336H", GNSS_MODEL_ATGM336H},
/* ATGM332D series (-11(GPS), -21(BDS), -31(GPS+BDS), -51(GPS+GLONASS), -71-0(GPS+BDS+GLONASS)) based on AT6558 */
{"ATGM332D", "$GPTXT,01,01,02,HW=ATGM332D", GNSS_MODEL_ATGM336H}};
PROBE_FAMILY("ATGM33xx Family", "$PCAS06,1*1A", atgm, 500);
/* Airoha (Mediatek) AG3335A/M/S, A3352Q, Quectel L89 2.0, SimCom SIM65M */
_serial_gps->write("$PAIR062,2,0*3C\r\n"); // GSA OFF to reduce volume
_serial_gps->write("$PAIR062,3,0*3D\r\n"); // GSV OFF to reduce volume
_serial_gps->write("$PAIR513*3D\r\n"); // save configuration
std::vector<ChipInfo> airoha = {{"AG3335", "$PAIR021,AG3335", GNSS_MODEL_AG3335},
{"AG3352", "$PAIR021,AG3352", GNSS_MODEL_AG3352},
{"RYS3520", "$PAIR021,REYAX_RYS3520_V2", GNSS_MODEL_AG3352}};
PROBE_FAMILY("Airoha Family", "$PAIR021*39", airoha, 1000);
PROBE_SIMPLE("LC86", "$PQTMVERNO*58", "$PQTMVERNO,LC86", GNSS_MODEL_AG3352, 500);
PROBE_SIMPLE("L76K", "$PCAS06,0*1B", "$GPTXT,01,01,02,SW=", GNSS_MODEL_MTK, 500);
// Close all NMEA sentences, valid for MTK3333 and MTK3339 platforms
_serial_gps->write("$PMTK514,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*2E\r\n");
delay(20);
std::vector<ChipInfo> mtk = {{"L76B", "Quectel-L76B", GNSS_MODEL_MTK_L76B}, {"PA1010D", "1010D", GNSS_MODEL_MTK_PA1010D},
{"PA1616S", "1616S", GNSS_MODEL_MTK_PA1616S}, {"LS20031", "MC-1513", GNSS_MODEL_MTK_L76B},
{"L96", "Quectel-L96", GNSS_MODEL_MTK_L76B}, {"L80-R", "_3337_", GNSS_MODEL_MTK_L76B},
{"L80", "_3339_", GNSS_MODEL_MTK_L76B}};
PROBE_FAMILY("MTK Family", "$PMTK605*31", mtk, 500);
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00};
UBXChecksum(cfg_rate, sizeof(cfg_rate));
clearBuffer();
_serial_gps->write(cfg_rate, sizeof(cfg_rate));
// Check that the returned response class and message ID are correct
GPS_RESPONSE response = getACK(0x06, 0x08, 750);
if (response == GNSS_RESPONSE_NONE) {
LOG_WARN("No GNSS Module (baudrate %d)", serialSpeed);
return GNSS_MODEL_UNKNOWN; return GNSS_MODEL_UNKNOWN;
} else if (response == GNSS_RESPONSE_FRAME_ERRORS) {
LOG_INFO("UBlox Frame Errors (baudrate %d)", serialSpeed);
} }
case 1: {
memset(buffer, 0, sizeof(buffer)); // Unicore UFirebirdII Series: UC6580, UM620, UM621, UM670A, UM680A, or UM681A,or CM121
uint8_t _message_MONVER[8] = { std::vector<ChipInfo> unicore = {
0xB5, 0x62, // Sync message for UBX protocol {"UC6580", "UC6580", GNSS_MODEL_UC6580}, {"UM600", "UM600", GNSS_MODEL_UC6580}, {"CM121", "CM121", GNSS_MODEL_CM121}};
0x0A, 0x04, // Message class and ID (UBX-MON-VER) PROBE_FAMILY("Unicore Family", "$PDTINFO", unicore, 500);
0x00, 0x00, // Length of payload (we're asking for an answer, so no payload) currentDelay = 20;
0x00, 0x00 // Checksum currentStep = 2;
}; return GNSS_MODEL_UNKNOWN;
// Get Ublox gnss module hardware and software info }
UBXChecksum(_message_MONVER, sizeof(_message_MONVER)); case 2: {
clearBuffer(); std::vector<ChipInfo> atgm = {
_serial_gps->write(_message_MONVER, sizeof(_message_MONVER)); {"ATGM336H", "$GPTXT,01,01,02,HW=ATGM336H", GNSS_MODEL_ATGM336H},
/* ATGM332D series (-11(GPS), -21(BDS), -31(GPS+BDS), -51(GPS+GLONASS), -71-0(GPS+BDS+GLONASS)) based on AT6558 */
{"ATGM332D", "$GPTXT,01,01,02,HW=ATGM332D", GNSS_MODEL_ATGM336H}};
PROBE_FAMILY("ATGM33xx Family", "$PCAS06,1*1A", atgm, 500);
currentDelay = 20;
currentStep = 3;
return GNSS_MODEL_UNKNOWN;
}
case 3: {
/* Airoha (Mediatek) AG3335A/M/S, A3352Q, Quectel L89 2.0, SimCom SIM65M */
_serial_gps->write("$PAIR062,2,0*3C\r\n"); // GSA OFF to reduce volume
_serial_gps->write("$PAIR062,3,0*3D\r\n"); // GSV OFF to reduce volume
_serial_gps->write("$PAIR513*3D\r\n"); // save configuration
std::vector<ChipInfo> airoha = {{"AG3335", "$PAIR021,AG3335", GNSS_MODEL_AG3335},
{"AG3352", "$PAIR021,AG3352", GNSS_MODEL_AG3352},
{"RYS3520", "$PAIR021,REYAX_RYS3520_V2", GNSS_MODEL_AG3352}};
PROBE_FAMILY("Airoha Family", "$PAIR021*39", airoha, 1000);
currentDelay = 20;
currentStep = 4;
return GNSS_MODEL_UNKNOWN;
}
case 4: {
PROBE_SIMPLE("LC86", "$PQTMVERNO*58", "$PQTMVERNO,LC86", GNSS_MODEL_AG3352, 500);
PROBE_SIMPLE("L76K", "$PCAS06,0*1B", "$GPTXT,01,01,02,SW=", GNSS_MODEL_MTK, 500);
currentDelay = 20;
currentStep = 5;
return GNSS_MODEL_UNKNOWN;
}
case 5: {
uint16_t len = getACK(buffer, sizeof(buffer), 0x0A, 0x04, 1200); // Close all NMEA sentences, valid for MTK3333 and MTK3339 platforms
if (len) { _serial_gps->write("$PMTK514,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*2E\r\n");
uint16_t position = 0; delay(20);
for (int i = 0; i < 30; i++) { std::vector<ChipInfo> mtk = {{"L76B", "Quectel-L76B", GNSS_MODEL_MTK_L76B}, {"PA1010D", "1010D", GNSS_MODEL_MTK_PA1010D},
ublox_info.swVersion[i] = buffer[position]; {"PA1616S", "1616S", GNSS_MODEL_MTK_PA1616S}, {"LS20031", "MC-1513", GNSS_MODEL_MTK_L76B},
position++; {"L96", "Quectel-L96", GNSS_MODEL_MTK_L76B}, {"L80-R", "_3337_", GNSS_MODEL_MTK_L76B},
} {"L80", "_3339_", GNSS_MODEL_MTK_L76B}};
for (int i = 0; i < 10; i++) {
ublox_info.hwVersion[i] = buffer[position];
position++;
}
while (len >= position + 30) { PROBE_FAMILY("MTK Family", "$PMTK605*31", mtk, 500);
for (int i = 0; i < 30; i++) { currentDelay = 20;
ublox_info.extension[ublox_info.extensionNo][i] = buffer[position]; currentStep = 6;
position++; return GNSS_MODEL_UNKNOWN;
} }
ublox_info.extensionNo++; case 6: {
if (ublox_info.extensionNo > 9) uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00};
break; UBXChecksum(cfg_rate, sizeof(cfg_rate));
} clearBuffer();
_serial_gps->write(cfg_rate, sizeof(cfg_rate));
LOG_DEBUG("Module Info : "); // Check that the returned response class and message ID are correct
LOG_DEBUG("Soft version: %s", ublox_info.swVersion); GPS_RESPONSE response = getACK(0x06, 0x08, 750);
LOG_DEBUG("Hard version: %s", ublox_info.hwVersion); if (response == GNSS_RESPONSE_NONE) {
LOG_DEBUG("Extensions:%d", ublox_info.extensionNo); LOG_WARN("No GNSS Module (baudrate %d)", serialSpeed);
for (int i = 0; i < ublox_info.extensionNo; i++) { currentDelay = 2000;
LOG_DEBUG(" %s", ublox_info.extension[i]); currentStep = 0;
return GNSS_MODEL_UNKNOWN;
} else if (response == GNSS_RESPONSE_FRAME_ERRORS) {
LOG_INFO("UBlox Frame Errors (baudrate %d)", serialSpeed);
} }
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
uint8_t _message_MONVER[8] = {
0xB5, 0x62, // Sync message for UBX protocol
0x0A, 0x04, // Message class and ID (UBX-MON-VER)
0x00, 0x00, // Length of payload (we're asking for an answer, so no payload)
0x00, 0x00 // Checksum
};
// Get Ublox gnss module hardware and software info
UBXChecksum(_message_MONVER, sizeof(_message_MONVER));
clearBuffer();
_serial_gps->write(_message_MONVER, sizeof(_message_MONVER));
// tips: extensionNo field is 0 on some 6M GNSS modules uint16_t len = getACK(buffer, sizeof(buffer), 0x0A, 0x04, 1200);
for (int i = 0; i < ublox_info.extensionNo; ++i) { if (len) {
if (!strncmp(ublox_info.extension[i], "MOD=", 4)) { uint16_t position = 0;
strncpy((char *)buffer, &(ublox_info.extension[i][4]), sizeof(buffer)); for (int i = 0; i < 30; i++) {
} else if (!strncmp(ublox_info.extension[i], "PROTVER", 7)) { ublox_info.swVersion[i] = buffer[position];
char *ptr = nullptr; position++;
memset(buffer, 0, sizeof(buffer)); }
strncpy((char *)buffer, &(ublox_info.extension[i][8]), sizeof(buffer)); for (int i = 0; i < 10; i++) {
LOG_DEBUG("Protocol Version:%s", (char *)buffer); ublox_info.hwVersion[i] = buffer[position];
if (strlen((char *)buffer)) { position++;
ublox_info.protocol_version = strtoul((char *)buffer, &ptr, 10); }
LOG_DEBUG("ProtVer=%d", ublox_info.protocol_version);
} else { while (len >= position + 30) {
ublox_info.protocol_version = 0; for (int i = 0; i < 30; i++) {
ublox_info.extension[ublox_info.extensionNo][i] = buffer[position];
position++;
}
ublox_info.extensionNo++;
if (ublox_info.extensionNo > 9)
break;
}
LOG_DEBUG("Module Info : ");
LOG_DEBUG("Soft version: %s", ublox_info.swVersion);
LOG_DEBUG("Hard version: %s", ublox_info.hwVersion);
LOG_DEBUG("Extensions:%d", ublox_info.extensionNo);
for (int i = 0; i < ublox_info.extensionNo; i++) {
LOG_DEBUG(" %s", ublox_info.extension[i]);
}
memset(buffer, 0, sizeof(buffer));
// tips: extensionNo field is 0 on some 6M GNSS modules
for (int i = 0; i < ublox_info.extensionNo; ++i) {
if (!strncmp(ublox_info.extension[i], "MOD=", 4)) {
strncpy((char *)buffer, &(ublox_info.extension[i][4]), sizeof(buffer));
} else if (!strncmp(ublox_info.extension[i], "PROTVER", 7)) {
char *ptr = nullptr;
memset(buffer, 0, sizeof(buffer));
strncpy((char *)buffer, &(ublox_info.extension[i][8]), sizeof(buffer));
LOG_DEBUG("Protocol Version:%s", (char *)buffer);
if (strlen((char *)buffer)) {
ublox_info.protocol_version = strtoul((char *)buffer, &ptr, 10);
LOG_DEBUG("ProtVer=%d", ublox_info.protocol_version);
} else {
ublox_info.protocol_version = 0;
}
} }
} }
} if (strncmp(ublox_info.hwVersion, "00040007", 8) == 0) {
if (strncmp(ublox_info.hwVersion, "00040007", 8) == 0) { LOG_INFO(DETECTED_MESSAGE, "U-blox 6", "6");
LOG_INFO(DETECTED_MESSAGE, "U-blox 6", "6"); return GNSS_MODEL_UBLOX6;
return GNSS_MODEL_UBLOX6; } else if (strncmp(ublox_info.hwVersion, "00070000", 8) == 0) {
} else if (strncmp(ublox_info.hwVersion, "00070000", 8) == 0) { LOG_INFO(DETECTED_MESSAGE, "U-blox 7", "7");
LOG_INFO(DETECTED_MESSAGE, "U-blox 7", "7"); return GNSS_MODEL_UBLOX7;
return GNSS_MODEL_UBLOX7; } else if (strncmp(ublox_info.hwVersion, "00080000", 8) == 0) {
} else if (strncmp(ublox_info.hwVersion, "00080000", 8) == 0) { LOG_INFO(DETECTED_MESSAGE, "U-blox 8", "8");
LOG_INFO(DETECTED_MESSAGE, "U-blox 8", "8"); return GNSS_MODEL_UBLOX8;
return GNSS_MODEL_UBLOX8; } else if (strncmp(ublox_info.hwVersion, "00190000", 8) == 0) {
} else if (strncmp(ublox_info.hwVersion, "00190000", 8) == 0) { LOG_INFO(DETECTED_MESSAGE, "U-blox 9", "9");
LOG_INFO(DETECTED_MESSAGE, "U-blox 9", "9"); return GNSS_MODEL_UBLOX9;
return GNSS_MODEL_UBLOX9; } else if (strncmp(ublox_info.hwVersion, "000A0000", 8) == 0) {
} else if (strncmp(ublox_info.hwVersion, "000A0000", 8) == 0) { LOG_INFO(DETECTED_MESSAGE, "U-blox 10", "10");
LOG_INFO(DETECTED_MESSAGE, "U-blox 10", "10"); return GNSS_MODEL_UBLOX10;
return GNSS_MODEL_UBLOX10; }
} }
} }
}
LOG_WARN("No GNSS Module (baudrate %d)", serialSpeed); LOG_WARN("No GNSS Module (baudrate %d)", serialSpeed);
currentDelay = 2000;
currentStep = 0;
return GNSS_MODEL_UNKNOWN; return GNSS_MODEL_UNKNOWN;
} }

View File

@@ -16,6 +16,9 @@
#define GPS_EN_ACTIVE 1 #define GPS_EN_ACTIVE 1
#endif #endif
static constexpr uint32_t GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS = 10 * 1000UL;
static constexpr uint32_t GPS_FIX_HOLD_MAX_MS = 20000;
typedef enum { typedef enum {
GNSS_MODEL_ATGM336H, GNSS_MODEL_ATGM336H,
GNSS_MODEL_MTK, GNSS_MODEL_MTK,
@@ -151,6 +154,8 @@ class GPS : private concurrency::OSThread
TinyGPSPlus reader; TinyGPSPlus reader;
uint8_t fixQual = 0; // fix quality from GPGGA uint8_t fixQual = 0; // fix quality from GPGGA
uint32_t lastChecksumFailCount = 0; uint32_t lastChecksumFailCount = 0;
uint8_t currentStep = 0;
int32_t currentDelay = 2000;
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS #ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
// (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field // (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field
@@ -173,8 +178,6 @@ class GPS : private concurrency::OSThread
*/ */
bool hasValidLocation = false; // default to false, until we complete our first read bool hasValidLocation = false; // default to false, until we complete our first read
bool isInPowersave = false;
bool shouldPublish = false; // If we've changed GPS state, this will force a publish the next loop() bool shouldPublish = false; // If we've changed GPS state, this will force a publish the next loop()
bool hasGPS = false; // Do we have a GPS we are talking to bool hasGPS = false; // Do we have a GPS we are talking to

View File

@@ -67,7 +67,7 @@ SerialModuleRadio *serialModuleRadio;
defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE) defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE)
SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial") {} SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial") {}
static Print *serialPrint = &Serial; static Print *serialPrint = &Serial;
#elif defined(CONFIG_IDF_TARGET_ESP32C6) || defined(RAK3172) #elif defined(CONFIG_IDF_TARGET_ESP32C6) || defined(RAK3172) || defined(EBYTE_E77_MBL)
SerialModule::SerialModule() : StreamAPI(&Serial1), concurrency::OSThread("Serial") {} SerialModule::SerialModule() : StreamAPI(&Serial1), concurrency::OSThread("Serial") {}
static Print *serialPrint = &Serial1; static Print *serialPrint = &Serial1;
#else #else

View File

@@ -6,9 +6,12 @@ board_level = extra
build_flags = build_flags =
${stm32_base.build_flags} ${stm32_base.build_flags}
-Ivariants/stm32/CDEBYTE_E77-MBL -Ivariants/stm32/CDEBYTE_E77-MBL
-DSERIAL_UART_INSTANCE=1 -DSERIAL_UART_INSTANCE=2
-DPIN_SERIAL_RX=PA3 -DPIN_SERIAL_RX=PA3
-DPIN_SERIAL_TX=PA2 -DPIN_SERIAL_TX=PA2
-DENABLE_HWSERIAL1
-DPIN_SERIAL1_RX=PB7
-DPIN_SERIAL1_TX=PB6
-DMESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR=1 -DMESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR=1
-DMESHTASTIC_EXCLUDE_I2C=1 -DMESHTASTIC_EXCLUDE_I2C=1
-DMESHTASTIC_EXCLUDE_GPS=1 -DMESHTASTIC_EXCLUDE_GPS=1

View File

@@ -18,4 +18,6 @@ Do not expect a working Meshtastic device with this target.
#define LED_PIN PB4 // LED1 #define LED_PIN PB4 // LED1
// #define LED_PIN PB3 // LED2 // #define LED_PIN PB3 // LED2
#define LED_STATE_ON 1 #define LED_STATE_ON 1
#define EBYTE_E77_MBL
#endif #endif

View File

@@ -6,7 +6,6 @@ board_upload.maximum_size = 233472 ; reserve the last 28KB for filesystem
build_flags = build_flags =
${stm32_base.build_flags} ${stm32_base.build_flags}
-Ivariants/stm32/rak3172 -Ivariants/stm32/rak3172
-DRAK3172
-DENABLE_HWSERIAL1 -DENABLE_HWSERIAL1
-DPIN_SERIAL1_RX=PB7 -DPIN_SERIAL1_RX=PB7
-DPIN_SERIAL1_TX=PB6 -DPIN_SERIAL1_TX=PB6

View File

@@ -16,4 +16,6 @@ Do not expect a working Meshtastic device with this target.
#define LED_PIN PA0 // Green LED #define LED_PIN PA0 // Green LED
#define LED_STATE_ON 1 #define LED_STATE_ON 1
#define RAK3172
#endif #endif