Skip to content

Changes to the GPS logic for newer GPS. #374

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/OpenBikeSensorFirmware.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,6 @@ void setup() {
gps.handle();

setupBluetooth(cfg, trackUniqueIdentifier);

obsDisplay->showTextOnGrid(2, obsDisplay->newLine(), "Wait for GPS");
obsDisplay->newLine();
gps.handle();
Expand Down
15 changes: 15 additions & 0 deletions src/configServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,9 @@ static const char* const development =
static const char* const rebootIndex =
"<h3>Device reboots now.</h3>";

static const char* const gpsColdIndex =
"<h3>GPS cold start</h3>";

// #########################################
// Wifi
// #########################################
Expand Down Expand Up @@ -456,6 +459,7 @@ static void handleNotFound(HTTPRequest * req, HTTPResponse * res);
static void handleIndex(HTTPRequest * req, HTTPResponse * res);
static void handleAbout(HTTPRequest * req, HTTPResponse * res);
static void handleReboot(HTTPRequest * req, HTTPResponse * res);
static void handleColdStartGPS(HTTPRequest * req, HTTPResponse * res);
static void handleBackup(HTTPRequest * req, HTTPResponse * res);
static void handleBackupDownload(HTTPRequest * req, HTTPResponse * res);
static void handleBackupRestore(HTTPRequest * req, HTTPResponse * res);
Expand Down Expand Up @@ -546,6 +550,7 @@ void registerPages(HTTPServer * httpServer) {
httpServer->registerNode(new ResourceNode("/", HTTP_GET, handleIndex));
httpServer->registerNode(new ResourceNode("/about", HTTP_GET, handleAbout));
httpServer->registerNode(new ResourceNode("/reboot", HTTP_GET, handleReboot));
httpServer->registerNode(new ResourceNode("/cold", HTTP_GET, handleColdStartGPS));
httpServer->registerNode(new ResourceNode("/settings/backup", HTTP_GET, handleBackup));
httpServer->registerNode(new ResourceNode("/settings/backup.json", HTTP_GET, handleBackupDownload));
httpServer->registerNode(new ResourceNode("/settings/restore", HTTP_POST, handleBackupRestore));
Expand Down Expand Up @@ -1065,6 +1070,8 @@ static void handleAbout(HTTPRequest *req, HTTPResponse * res) {
page += keyValue("GPS satellites", gps.getValidSatellites());
page += keyValue("GPS uptime", gps.getUptime(), "ms");
page += keyValue("GPS noise level", gps.getLastNoiseLevel());
page += keyValue("GPS Antenna Gain", gps.getLastAntennaGain());
page += keyValue("GPS Jamming Level", gps.getLastJamInd());
page += keyValue("GPS baud rate", gps.getBaudRate());
page += keyValue("GPS ALP bytes", gps.getNumberOfAlpBytesSent());
page += keyValue("GPS messages", gps.getMessagesHtml());
Expand Down Expand Up @@ -1123,6 +1130,14 @@ static void handleReboot(HTTPRequest *, HTTPResponse * res) {
ESP.restart();
}

static void handleColdStartGPS(HTTPRequest *, HTTPResponse * res) {
String html = createPage(gpsColdIndex);
html = replaceDefault(html, "Navigation");
sendHtml(res, html);
gps.coldStartGps();
res->finalize();
}


static void handleBackup(HTTPRequest *, HTTPResponse * res) {
String html = createPage(backupIndex, xhrUpload);
Expand Down
155 changes: 133 additions & 22 deletions src/gps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,63 @@ const String Gps::INF_SEVERITY_STRING[] = {
String("TST"), String("DBG")
};

bool Gps::is_neo6() const {
if (String(hwString).substring(0,4) == String("00040007").substring(0,4)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also have a module that returns '00040005'. Might be we should use only the 4 leading digits or use assume it is neo6 if none of the other patterns matches. Did you find references for the meaning of this number?

-> Which is what you do but (I just realize ;) ) this is rather confusing. If we do not know better, what about just comparing hwString[3] == '4'?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this to only look at the first 4 bytes and be more obvious about it - logic says that neo16m will have "0010" there, so just another 8 years or so.

return true;
}
return false;
}

bool Gps::is_neo8() const {
if (String(hwString).substring(0,4) == String("00080000").substring(0,4)) {
return true;
}
return false;
}

bool Gps::is_neo10() const {
if (String(hwString).substring(0,4) == String("000A0000").substring(0,4)) {
return true;
}
return false;
}

String Gps::hw() const {
if (is_neo6()){
return "Neo6";
}
if (is_neo8()){
return "Neo8";
}
if (is_neo10()) {
return "NeoA";
}
return "Neo" + String(hwString).substring(3,4);
}

void Gps::begin() {
setBaud();
softResetGps();
if (mGpsNeedsConfigUpdate) {
configureGpsModule();
}
enableAlpIfDataIsAvailable();
pollStatistics();
if((!is_neo6()) || (!SD.exists(AID_INI_DATA_FILE_NAME))) {
// we're on a non-6 neo and avoid AID_INI because is deprecated
// or we're on a neo6 but last boot we didn't get far enough to receive fresh
// ALP_INI data after initializing
// so restart GPS for good measure.
if (is_neo6()) log_i("We found no AID_INI on with neo6 on boot - coldstart gps in case its in a state where it doesn't get fixes");
if (!is_neo6()) log_i("Coldstart because we found that newer neos profit from that.");

coldStartGps();
}
pollStatistics();

if (is_neo6()) {
enableAlpIfDataIsAvailable();
}

if (mLastTimeTimeSet == 0) {
#ifdef UBX_M10
setMessageInterval(UBX_CFG_KEY_ID::CFG_MSGOUT_UBX_NAV_TIMEGPS_UART1, 1);
Expand Down Expand Up @@ -249,6 +298,14 @@ void Gps::configureGpsModule() {
} else {
addStatisticsMessage("No ack for setting timepulse in either new or old format");
}
const uint8_t UBX_CFG_RATE[] = {0xE8, 0x03, 0x01, 0x00, 0x00, 0x00};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks wrong - below 'UBX_CFG_RATE' is not sent but TP5. A comment would help to understand what this should do

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder where that came from - so I removed it.

if (!sendAndWaitForAck(UBX_MSG::CFG_TP5, UBX_CFG_TP5, sizeof(UBX_CFG_RATE))) {
addStatisticsMessage("Successfully set rate");
obsDisplay->showTextOnGrid(0, 5, "rate set");
} else{
obsDisplay->showTextOnGrid(0, 5, "rate not set");
}

}
#endif

Expand Down Expand Up @@ -293,7 +350,7 @@ void Gps::softResetGps() {
log_i("Soft-RESET GPS!");
handle();
const uint8_t UBX_CFG_RST[] = {0x00, 0x00, 0x02, 0x00}; // WARM START
// const uint8_t UBX_CFG_RST[] = {0xFF, 0xFF, 0x02, 0x00}; // Cold START
//const uint8_t UBX_CFG_RST[] = {0xFF, 0x81, 0x04, 0x00}; // Cold START '0xFF, 0x81, 0x04, 0x00'
// we had the case where the reset took several seconds
// see https://github.com/openbikesensor/OpenBikeSensorFirmware/issues/309
// Newer firmware (like M10 and likely also M8) will not ack this
Expand All @@ -304,6 +361,26 @@ void Gps::softResetGps() {
log_i("Soft-RESET GPS! Done");
}

void Gps::coldStartGps() {
log_i("Cold-Start GPS!");
handle();
//const uint8_t UBX_CFG_RST[] = {0x00, 0x00, 0x02, 0x00}; // WARM START
const uint8_t UBX_CFG_RST[] = {0xFF, 0x81, 0x04, 0x00}; // Cold START '0xFF, 0x81, 0x04, 0x00'
// https://content.u-blox.com/sites/default/files/products/documents/u-blox8-M8_ReceiverDescrProtSpec_UBX-13003221.pdf?utm_content=UBX-13003221
// eph=1, alm=1, health=1, klob=1, pos=1, clkd=1, osc=1, utc=1, rtc=1, aop=1, resetMode=4, reserved0=0
// can be generated via pyubx2 UBXMessage reset = pyubx2.UBXMessage(...)
// output via ", ".join([f"0x{b:02X}" for b in reset.payload])

// we had the case where the reset took several seconds
// see https://github.com/openbikesensor/OpenBikeSensorFirmware/issues/309
// Newer firmware (like M10 and likely also M8) will not ack this
// message so we do not wait for the ACK
sendUbx(UBX_MSG::CFG_RST, UBX_CFG_RST, 4);
waitForData(1000);
handle();
log_i("Cold Start GPS! Done");
}

/* There had been changes for the satellites used for SBAS
* in europe since the firmware of our GPS module was built
* we configure the module to use the 2 satellites that are
Expand Down Expand Up @@ -344,11 +421,15 @@ void Gps::enableAlpIfDataIsAvailable() {
/* Poll or refresh one time statistics, also spends some time
* to collect the results.
*/

void Gps::pollStatistics() {
handle();
sendUbx(UBX_MSG::AID_ALP);
handle();
sendUbx(UBX_MSG::MON_VER);
handle(20);
if (is_neo6()){
// AID_ALP is a neo6-only thing
sendUbx(UBX_MSG::AID_ALP);
}
handle();
sendUbx(UBX_MSG::MON_HW);
handle();
Expand Down Expand Up @@ -777,22 +858,32 @@ int32_t Gps::getMessagesWithFailedCrcCount() const {
}

void Gps::showWaitStatus(DisplayDevice const * display) const {
String satellitesString[2];
static bool clear = false;
if (!is_neo6() && !clear) {
obsDisplay->clear();
clear = true;
}
String satellitesString[3];
if (mValidMessagesReceived == 0) { // could not get any valid char from GPS module
satellitesString[0] = "OFF?";
} else if (mLastTimeTimeSet == 0) {
satellitesString[0] = String(mCurrentGpsRecord.mSatellitesUsed) + "sats SN:" + String(mLastNoiseLevel);
satellitesString[0] = "aGain:" + String(mLastGain);
satellitesString[1] = String(mCurrentGpsRecord.mSatellitesUsed) + "sats SN:" + String(mLastNoiseLevel);
} else {
satellitesString[0] = "GPS " + TimeUtils::timeToString();
satellitesString[0] = String(hw()).substring(1) + TimeUtils::timeToString();
satellitesString[1] = String(mCurrentGpsRecord.mSatellitesUsed) + "sats SN:" + String(mLastNoiseLevel);
}
satellitesString[2] = String(mCurrentGpsRecord.mFixStatus) + "<fx m>" + String(mValidMessagesReceived);

if (satellitesString[1].isEmpty()) {
obsDisplay->showTextOnGrid(2, display->currentLine(), satellitesString[0]);
} else {
obsDisplay->showTextOnGrid(2, display->currentLine() - 1, satellitesString[0]);
obsDisplay->showTextOnGrid(2, display->currentLine(), satellitesString[1]);
}
if (!is_neo6()){
obsDisplay->showTextOnGrid(0, 1, String(hw())+" Detail");
obsDisplay->showTextOnGrid(0, 2, "Gain:" + String(mLastGain) + " Jam:" + String(mLastJamInd));
obsDisplay->showTextOnGrid(0, 3, satellitesString[2]);
obsDisplay->showTextOnGrid(0, 4, String(mCurrentGpsRecord.mLatitude));
obsDisplay->showTextOnGrid(0, 5, String(mCurrentGpsRecord.mLongitude));
}
}

bool Gps::moduleIsAlive() const {
Expand Down Expand Up @@ -1098,12 +1189,25 @@ void Gps::parseUbxMessage() {
String(mGpsBuffer.monVer.swVersion).c_str(),
String(mGpsBuffer.monVer.hwVersion).c_str(),
mGpsBuffer.ubxHeader.length);
for (int i = 0; i < sizeof(hwString) && i < sizeof(mGpsBuffer.monVer.hwVersion) ; i++) {
hwString[i]=mGpsBuffer.monVer.hwVersion[i];
}
}
break;
case (uint16_t) UBX_MSG::MON_HW: {
log_v("MON-HW Antenna Status %d, noise level %d", mGpsBuffer.monHw.aStatus,
mGpsBuffer.monHw.noisePerMs);
const char* aStatus;
switch (mGpsBuffer.monHw.aStatus) {
case mGpsBuffer.monHw.INIT: aStatus = "init"; break;
case mGpsBuffer.monHw.DONTKNOW: aStatus = "?"; break;
case mGpsBuffer.monHw.OK: aStatus = "ok"; break;
case mGpsBuffer.monHw.SHORT: aStatus = "short"; break;
case mGpsBuffer.monHw.OPEN: aStatus = "open"; break;
default: aStatus = "invalid";
}
log_d("MON-HW Antenna Status %d %s, Antenna Power %d, Gain (0-8191) %d, noise level %d", mGpsBuffer.monHw.aStatus, aStatus, mGpsBuffer.monHw.aPower, mGpsBuffer.monHw.agcCnt, mGpsBuffer.monHw.noisePerMs);
mLastNoiseLevel = mGpsBuffer.monHw.noisePerMs;
mLastGain = mGpsBuffer.monHw.agcCnt;
mLastJamInd = mGpsBuffer.monHw.jamInd;
}
break;
case (uint16_t) UBX_MSG::NAV_STATUS: {
Expand All @@ -1113,7 +1217,7 @@ void Gps::parseUbxMessage() {
mGpsUptime = mGpsBuffer.navStatus.msss;
if (mGpsBuffer.navStatus.ttff != 0) {
addStatisticsMessage("TimeToFix: " + String(mGpsBuffer.navStatus.ttff) + "ms");
} else if (!mAidIniSent) {
} else if (!mAidIniSent and is_neo6()) {
mAidIniSent = true;
aidIni();
}
Expand All @@ -1130,7 +1234,7 @@ void Gps::parseUbxMessage() {
}
break;
case (uint16_t) UBX_MSG::NAV_SOL: {
log_v("SOL: iTOW: %u, gpsFix: %d, flags: %02x, numSV: %d, pDop: %04d.",
log_d("SOL: iTOW: %u, gpsFix: %d, flags: %02x, numSV: %d, pDop: %04d.",
mGpsBuffer.navSol.iTow, mGpsBuffer.navSol.gpsFix, mGpsBuffer.navSol.flags,
mGpsBuffer.navSol.numSv, mGpsBuffer.navSol.pDop);
if (mGpsBuffer.navSol.flags & 4) { // WKNSET
Expand All @@ -1148,15 +1252,15 @@ void Gps::parseUbxMessage() {
}
break;
case (uint16_t) UBX_MSG::NAV_PVT: {
log_v("PVT: iTOW: %u, fixType: %d, flags: %02x, numSV: %d, pDop: %04d.",
log_d("PVT: iTOW: %u, fixType: %d, flags: %02x, numSV: %d, pDop: %04d.",
mGpsBuffer.navPvt.iTow, mGpsBuffer.navPvt.fixType, mGpsBuffer.navPvt.flags,
mGpsBuffer.navPvt.numSV, mGpsBuffer.navPvt.pDOP);
prepareGpsData(mGpsBuffer.navPvt.iTow, mMessageStarted);
mIncomingGpsRecord.setInfo(mGpsBuffer.navPvt.numSV, mGpsBuffer.navPvt.fixType, mGpsBuffer.navPvt.flags);
}
break;
case (uint16_t) UBX_MSG::NAV_VELNED: {
log_v("VELNED: iTOW: %u, speed: %d cm/s, gSpeed: %d cm/s, heading: %d,"
log_d("VELNED: iTOW: %u, speed: %d cm/s, gSpeed: %d cm/s, heading: %d,"
" speedAcc: %d, cAcc: %d",
mGpsBuffer.navVelned.iTow, mGpsBuffer.navVelned.speed, mGpsBuffer.navVelned.gSpeed,
mGpsBuffer.navVelned.heading, mGpsBuffer.navVelned.sAcc, mGpsBuffer.navVelned.cAcc);
Expand Down Expand Up @@ -1289,7 +1393,7 @@ void Gps::parseUbxMessage() {
log_d("CFG_GNSS");
break;
default:
log_e("Got UBX_MESSAGE! Id: 0x%04x Len %d iTOW %d", mGpsBuffer.ubxHeader.ubxMsgId,
log_e("Got unparsed UBX_MESSAGE! Id: 0x%04x Len %d iTOW %d", mGpsBuffer.ubxHeader.ubxMsgId,
mGpsBuffer.ubxHeader.length, mGpsBuffer.navStatus.iTow);
}
}
Expand All @@ -1314,10 +1418,9 @@ void Gps::handleUbxNavTimeGps(const GpsBuffer::UbxNavTimeGps &message, const uin
mIncomingGpsRecord.setWeek(mLastGpsWeek);
}
if ((message.valid & 0x03) == 0x03 // WEEK && TOW
&& delayMs < 250
&& message.tAcc < (20 * 1000 * 1000 /* 20ms */)
&& (mLastTimeTimeSet == 0
|| (mLastTimeTimeSet + (2 * 60 * 1000 /* 2 minutes */)) < receivedMs)) {
&& ((mLastTimeTimeSet == 0)
|| ((mLastTimeTimeSet + (2 * 60 * 1000 /* 2 minutes */)) < receivedMs))) {
String oldTime = TimeUtils::dateTimeToString();
TimeUtils::setClockByGps(message.iTow, message.fTow, message.week);
String newTime = TimeUtils::dateTimeToString();
Expand All @@ -1331,7 +1434,7 @@ void Gps::handleUbxNavTimeGps(const GpsBuffer::UbxNavTimeGps &message, const uin
mLastTimeTimeSet = receivedMs;
// This triggers another NAV-TIMEGPS message!
#ifdef UBX_M6
setMessageInterval(UBX_MSG::NAV_TIMEGPS, 240, false); // every 4 minutes
setMessageInterval(UBX_MSG::NAV_TIMEGPS, (delayMs>200) ? 5 : 240, false); // every 4 minutes
#endif
#ifdef UBX_M10
setMessageInterval(UBX_CFG_KEY_ID::CFG_MSGOUT_UBX_NAV_TIMEGPS_UART1, 240, false); // every 4 minutes
Expand Down Expand Up @@ -1411,6 +1514,14 @@ uint16_t Gps::getLastNoiseLevel() const {
return mLastNoiseLevel;
}

uint16_t Gps::getLastAntennaGain() const {
return mLastGain;
}

uint8_t Gps::getLastJamInd() const {
return mLastJamInd;
}

uint32_t Gps::getBaudRate() {
return mSerial.baudRate();
}
Expand Down
Loading