Repository: openbikesensor/OpenBikeSensorFirmware
Pull request #374: Changes to the GPS logic for newer GPS.
Author: login: gluap
Created: 2025-02-25T20:01:01Z | Merged: 2025-03-03T21:36:47Z

This adds a few changes to the GPS logic
- on non-neo6m we coldstart on bootup
- there is an extra http endpoint to trigger a coldstart (by @Jens-Kassel)
- we only do aid_ini and aid_alp on neo6m
- we interpret MON_HW in the way it is sent on neo8m (which only differs in bytes that we weren't using on neo6m)  (by @Jens-Kassel)
- We store gain and jamming indicator for display and logging (by @Jens-Kassel)
- We display more information from MON-HW 
- we give more debug data on-screen for non-neo6m
- Instead of ignoring datetimes below a minimum precision we keep asking for the datetime messge in short intervals until we receive one with a high precision (based on @Jens-Kassel s findings from last november).

@amandel what do you think?


Diff:
diff --git a/src/OpenBikeSensorFirmware.cpp b/src/OpenBikeSensorFirmware.cpp
index 39b26cd..bc32a01 100644
--- a/src/OpenBikeSensorFirmware.cpp
+++ b/src/OpenBikeSensorFirmware.cpp
@@ -399,9 +399,10 @@ void setup() {
       esp_bt_mem_release(ESP_BT_MODE_BTDM)); // no bluetooth at all here.
 
     delay(200);
-    startServer(&cfg);
+    obsDisplay->showTextOnGrid(2, obsDisplay->newLine(), "Start GPS...");
     gps.begin();
     gps.setStatisticsIntervalInSeconds(2); // ??
+    startServer(&cfg);
     while (true) {
       yield();
       serverLoop();
@@ -446,7 +447,6 @@ void setup() {
   gps.handle();
 
   setupBluetooth(cfg, trackUniqueIdentifier);
-
   obsDisplay->showTextOnGrid(2, obsDisplay->newLine(), "Wait for GPS");
   obsDisplay->newLine();
   gps.handle();
diff --git a/src/configServer.cpp b/src/configServer.cpp
index 272fac2..7b1b4fb 100644
--- a/src/configServer.cpp
+++ b/src/configServer.cpp
@@ -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
 // #########################################
@@ -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);
@@ -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));
@@ -724,7 +729,8 @@ static void wifiConnectedActions() {
   if (WiFiClass::status() == WL_CONNECTED) {
     TimeUtils::setClockByNtpAndWait(WiFi.gatewayIP().toString().c_str());
   }
-  if (SD.begin() && WiFiClass::status() == WL_CONNECTED) {
+  if (SD.begin() && WiFiClass::status() == WL_CONNECTED 
+       && (!gps.moduleIsAlive() || gps.is_neo6())) {
     AlpData::update(obsDisplay);
   }
 
@@ -1065,6 +1071,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());
@@ -1123,6 +1131,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);
diff --git a/src/gps.cpp b/src/gps.cpp
index b1f4db7..a364059 100644
--- a/src/gps.cpp
+++ b/src/gps.cpp
@@ -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("0004")) {
+    return true;
+  }
+  return false;
+}
+
+bool Gps::is_neo8() const {
+  if (String(hwString).substring(0,4) == String("0008")) {
+    return true;
+  }
+  return false;
+}
+
+bool Gps::is_neo10() const {
+  if (String(hwString).substring(0,4) == String("000A")) {
+    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);
@@ -293,7 +342,6 @@ 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
   // 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
@@ -304,6 +352,20 @@ void Gps::softResetGps() {
   log_i("Soft-RESET GPS! Done");
 }
 
+void Gps::coldStartGps() {
+  log_i("Cold-Start GPS!");
+  handle();
+  const uint8_t UBX_CFG_RST[] = {0xFF, 0xFF, 0x00, 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
+  // message so we do not wait for the ACK
+  sendUbx(UBX_MSG::CFG_RST, UBX_CFG_RST, 4);
+  waitForData(3000);
+  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
@@ -344,11 +406,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();
@@ -777,21 +843,35 @@ int32_t Gps::getMessagesWithFailedCrcCount() const {
 }
 
 void Gps::showWaitStatus(DisplayDevice const * display) const {
+  static bool clear = false;
+  if (!is_neo6() && !clear) {
+     obsDisplay->clear();
+     clear = true;
+  }
   String satellitesString[2];
   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);
   }
+  obsDisplay->showTextOnGrid(2, display->currentLine() - 1, satellitesString[0]);
+  obsDisplay->showTextOnGrid(2, display->currentLine(), satellitesString[1]);
+  if (!is_neo6()){
+    obsDisplay->showTextOnGrid(0, 1, String(hw())+" GPS");
+    obsDisplay->showTextOnGrid(2, 1, "HDOP: " + getHdopAsString() + "D");
 
-  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]);
+    obsDisplay->showTextOnGrid(0, 2, "Jam: " + String(mLastJamInd));
+    obsDisplay->showTextOnGrid(2, 2, "Msgs: " + String(mValidMessagesReceived));
+    obsDisplay->showTextOnGrid(2, 3, "Fix: " + String(mCurrentGpsRecord.mFixStatus) + "D");
+    obsDisplay->showTextOnGrid(0, 3, "lat,lon:");
+
+
+    obsDisplay->showTextOnGrid(0, 4, String(mCurrentGpsRecord.mLatitude));
+    obsDisplay->showTextOnGrid(0, 5, String(mCurrentGpsRecord.mLongitude));
   }
 }
 
@@ -1098,12 +1178,40 @@ 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);
-      mLastNoiseLevel = mGpsBuffer.monHw.noisePerMs;
+      const char* aStatus;
+      if (is_neo6()) {
+        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;
+      } else {
+        switch (mGpsBuffer.monHwNew.aStatus) {
+          case mGpsBuffer.monHwNew.INIT: aStatus = "init"; break;
+          case mGpsBuffer.monHwNew.DONTKNOW: aStatus = "?"; break;
+          case mGpsBuffer.monHwNew.OK: aStatus = "ok"; break;
+          case mGpsBuffer.monHwNew.SHORT: aStatus = "short"; break;
+          case mGpsBuffer.monHwNew.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.monHwNew.aStatus, aStatus, mGpsBuffer.monHwNew.aPower, mGpsBuffer.monHwNew.agcCnt, mGpsBuffer.monHwNew.noisePerMs);
+        mLastNoiseLevel = mGpsBuffer.monHwNew.noisePerMs;
+        mLastGain = mGpsBuffer.monHwNew.agcCnt;
+        mLastJamInd = mGpsBuffer.monHwNew.jamInd;
+      }
     }
       break;
     case (uint16_t) UBX_MSG::NAV_STATUS: {
@@ -1113,7 +1221,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();
       }
@@ -1130,7 +1238,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
@@ -1148,7 +1256,7 @@ 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);
@@ -1156,7 +1264,7 @@ void Gps::parseUbxMessage() {
     }
       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);
@@ -1289,7 +1397,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);
   }
 }
@@ -1314,10 +1422,10 @@ void Gps::handleUbxNavTimeGps(const GpsBuffer::UbxNavTimeGps &message, const uin
     mIncomingGpsRecord.setWeek(mLastGpsWeek);
   }
   if ((message.valid & 0x03) == 0x03  // WEEK && TOW
-      && delayMs < 250
+      && delayMs < 1000
       && 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();
@@ -1328,10 +1436,12 @@ void Gps::handleUbxNavTimeGps(const GpsBuffer::UbxNavTimeGps &message, const uin
                            + "ms. tAcc:" + String(message.tAcc) + "ns");
     }
     if (mLastTimeTimeSet == 0) {
-      mLastTimeTimeSet = receivedMs;
-      // This triggers another NAV-TIMEGPS message!
+      if (delayMs < 100) { // keep mLastTimeTimeSet at 0 unless reasonable delayMs
+        mLastTimeTimeSet = receivedMs;
+      }
+      // This triggers another NAV-TIMEGPS message! more often until good time is received
 #ifdef UBX_M6
-      setMessageInterval(UBX_MSG::NAV_TIMEGPS, 240, false); // every 4 minutes
+      setMessageInterval(UBX_MSG::NAV_TIMEGPS, (delayMs>100) ? 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
@@ -1411,6 +1521,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();
 }
diff --git a/src/gps.h b/src/gps.h
index e5fccab..a5cd341 100644
--- a/src/gps.h
+++ b/src/gps.h
@@ -70,6 +70,10 @@ class Gps {
 
     uint16_t getLastNoiseLevel() const;
 
+    uint16_t getLastAntennaGain() const;
+
+    uint8_t getLastJamInd() const;
+
     /* Collected informational messages as String. */
     String getMessages() const;
 
@@ -107,6 +111,12 @@ class Gps {
     uint32_t getNumberOfAlpBytesSent() const;
     uint32_t getUnexpectedCharReceivedCount() const;
 
+    void coldStartGps();
+
+    bool is_neo6() const;
+    bool is_neo8() const;
+    bool is_neo10() const;
+
   private:
     /* ALP msgs up to 0x16A seen might be more? */
     static const int MAX_MESSAGE_LENGTH = 128 * 3;
@@ -288,6 +298,37 @@ class Gps {
         uint32_t pinDir;
         uint32_t pinVal;
         uint16_t noisePerMs;
+        uint16_t agcCnt; // AGC (Automatic Gain Control) Monitor, as percentage of maximum gain,range 0 to 8191 (100%)
+        enum ANT_STATUS : uint8_t {
+          INIT = 0,
+          DONTKNOW = 1,
+          OK = 2,
+          SHORT = 3,
+          OPEN = 4,
+        } aStatus;
+        enum ANT_POWER : uint8_t {
+          OFF = 0,
+          ON = 1,
+          POWER_DONTKNOW = 2,
+        } aPower;
+        uint8_t flags;
+        uint8_t reserved1;
+        uint32_t usedMask;
+        uint8_t vp[17]; //M6 25bytes, M8 only 17bytes?
+        uint8_t jamInd; //cwSuppression / CW interference suppression level, scaled (0 = no CW jamming, 255 = strong CW jamming)
+        uint16_t reserved3;
+        uint32_t pinIrq;
+        uint32_t pullH;
+        uint32_t pullL;
+      } monHwNew;
+      struct __attribute__((__packed__)) {
+        UBX_HEADER ubxHeader;
+        uint32_t pinSel;
+        uint32_t pinBank;
+        uint32_t pinDir;
+        uint32_t pinVal;
+        uint16_t noisePerMs;
+        uint16_t agcCnt; // AGC (Automatic Gain Control) Monitor, as percentage of maximum gain,range 0 to 8191 (100%)
         enum ANT_STATUS : uint8_t {
           INIT = 0,
           DONTKNOW = 1,
@@ -550,6 +591,8 @@ class Gps {
     uint32_t mUnexpectedCharReceivedCount = 0;
     uint8_t mNmeaChk;
     uint16_t mLastNoiseLevel;
+    uint16_t mLastGain;
+    uint8_t mLastJamInd;
     AlpData mAlpData;
     bool mAidIniSent = false;
     /* record that was last received */
@@ -567,12 +610,16 @@ class Gps {
     bool mGpsNeedsConfigUpdate = false;
     static const String INF_SEVERITY_STRING[];
 
+    char hwString[10];
+
     void configureGpsModule();
 
     bool encode(uint8_t data);
 
     bool setBaud();
 
+    String hw() const;
+
     bool checkCommunication();
 
     void addStatisticsMessage(String message);
diff --git a/src/gpsrecord.h b/src/gpsrecord.h
index 9a89af3..60c6dc8 100644
--- a/src/gpsrecord.h
+++ b/src/gpsrecord.h
@@ -102,7 +102,6 @@ class GpsRecord {
     uint32_t mCreatedAtMillisTicks;
     static const int32_t pow10[10];
     static String toScaledString(int32_t value, uint16_t scale);
-
 };
 
 
diff --git a/src/utils/alpdata.cpp b/src/utils/alpdata.cpp
index baff084..fe9b549 100644
--- a/src/utils/alpdata.cpp
+++ b/src/utils/alpdata.cpp
@@ -172,6 +172,7 @@ size_t AlpData::loadMessage(uint8_t *data, size_t size) {
     result = f.read(data, size);
     f.close();
     log_d("Read %d bytes", result);
+    SD.remove(AID_INI_DATA_FILE_NAME);
   }
   return result;
 }


Reviews:
user: login: amandel
body: Thanks for adding this and thanks for the lot of experiments with the GPS modules. 

Long term we should also get rid of the ifdefs form UBX_M10 vs UBX_M6, but one thing after the other ;) Might be we should also not use the ALP data if a M8 or newer is detected. These modules can (if I remember correctly) collect the data over the time from the satellites and we could then persist it (AssistNow Autonomous).
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-28T12:32:13Z
user: login: Jens-Kassel
state: COMMENTED
author_association: NONE
submitted_at: 2025-02-28T14:20:52Z
user: login: Jens-Kassel
state: COMMENTED
author_association: NONE
submitted_at: 2025-02-28T14:29:53Z
user: login: amandel
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-28T14:51:32Z
user: login: gluap
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-28T19:09:41Z
user: login: gluap
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-28T19:41:21Z
user: login: gluap
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-28T19:41:35Z
user: login: gluap
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-28T19:43:05Z
user: login: gluap
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-28T20:03:04Z
user: login: gluap
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-28T20:06:37Z
user: login: gluap
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-28T20:11:19Z
user: login: amandel
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-28T20:15:49Z
user: login: amandel
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-28T20:16:45Z
user: login: gluap
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-28T20:16:54Z
user: login: gluap
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-28T20:17:37Z
user: login: amandel
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-28T20:31:18Z
user: login: amandel
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-28T20:35:15Z
user: login: gluap
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-01T09:49:32Z
user: login: gluap
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-01T10:04:16Z
user: login: amandel
body: <details>
    <summary>This PR introduces a GPS cold start feature and adds GPS module details to the about page.  However, it has several potential issues:

* **CI:** Removing `set -eux` from the CI reduces error visibility.  Provide justification.  Removing the AI code review workflow removes a quality check.  Is there a replacement?
* **GPS Cold Start:** Lacks error handling and user feedback.  `gpsColdIndex`'s purpose is unclear and needs documentation. The `handleColdStart` function declaration exists, but the implementation is missing.
* **`Gps.cpp`:** Redundant `is_neoX()` functions. SD card dependency for initialization should be explained or removed.  Inconsistent `waitForData` durations. Unclear and incomplete `showWaitStatus` logic. Potential `satellitesString` array out-of-bounds access. Unnecessary cold start for non-NEO-6 modules. Unclear `AID_INI` check.  Potential redundant `handle()` calls. Magic numbers for reset types.
* **`Gps.cpp` (Display Logic):** Magic numbers for grid indices. Unclear `hw()` function. Potential `hwString` buffer overflow. Missing `is_neo6()` definition. Inefficient string concatenation. Inconsistent logging levels. Inefficient `aStatus` string conversion. Duplicate logging code. Unclear `mAidIniSent` and `is_neo6()` logic. Missing error handling.
* **`Gps.cpp` (Data Handling):** Changing `vp` size to 17 bytes assumes only M8 modules are used. This should be configurable or dynamically determined.
* **`alpdata.cpp`:** Deleting `AID_INI_DATA_FILE_NAME` after reading might be problematic and needs justification.



**Suggested Code Changes:**

* **`web_server.cpp`:**  Add error handling and user feedback to `handleColdStartGPS()`.  Clarify `gpsColdIndex`'s purpose. Implement the `handleColdStart` function.
* **`Gps.cpp`:** Replace `is_neoX()` functions with direct string comparisons.  Explain or remove the SD card dependency in `begin()`. Use consistent `waitForData` durations.  Clarify and complete the `showWaitStatus` logic. Fix potential `satellitesString` out-of-bounds access.  Guard cold start logic with `is_neo6()`.  Clarify the `AID_INI` check.  Review and remove redundant `handle()` calls. Use named constants for reset types. Use named constants for grid indices. Clarify the `hw()` function and ensure `hwString` handling is safe.  Improve string concatenation efficiency.  Use consistent logging levels.  Improve `aStatus` string conversion efficiency. Refactor duplicate logging code.  Clarify `mAidIniSent` logic.  Add error handling. Make `vp` size configurable or dynamically determined. Initialize member variables in the constructor.
* **`alpdata.cpp`:** Make deletion of `AID_INI_DATA_FILE_NAME` optional or rename the file to indicate its temporary nature.


**General Recommendations:**

* Add unit tests for new functionality and error handling.
* Document all new functions and parameters, especially `coldStartGps()`.
* Justify the CI changes.


Addressing these issues will improve the code's robustness, readability, maintainability, and security.
</summary>
    ## Review Summary

This PR removes the AI code review workflow, removes a `set -eux` from the CI, and removes/adds some seemingly minor lines in the C++ code. While the changes themselves are small, the removal of the AI code review workflow and the `set -eux` raise concerns and warrant further explanation. The changes in the C++ code appear to be stylistic and functional improvements, but need further context to assess fully.  A new GPS Cold Start endpoint has been added; its purpose, usage, and potential side effects should be documented.

## File Comments

**`.github/workflows/ai-code-review.yml`**:

* **Major Issue:** Deleting the AI code review workflow removes an automated quality check.  While AI code review isn't perfect, it can catch potential issues.  *Justification for removal is required.* Is there a replacement process? If so, this should be part of the PR and clearly explained.  If not, reconsider removing this workflow.  Are there performance or cost issues driving this removal?

**`.github/workflows/ci.yml`**:

* **Minor Issue:** Removing `set -eux` within the SonarQube dependency installation step disables helpful shell debugging features (exit on error, print executed commands, expand variables).  While this *might* be intentional, it reduces the CI's ability to pinpoint errors during the installation process. *Justification for removal is needed.*  Is there a specific reason why these options are being removed? It's usually beneficial to keep them unless there's a compelling reason not to.

**`src/OpenBikeSensorFirmware.cpp`**:

* **Minor Issue:** Removing the blank line after `setupBluetooth(cfg, trackUniqueIdentifier);` is purely stylistic.  While consistent coding style is good, this change is so minor it doesn't warrant much discussion. Just be sure the overall project style guide is being followed.

**`src/configServer.cpp`**:

* **Minor Issue:** Adding `static const char* const gpsColdIndex = "<h3>GPS cold start</h3>";` suggests a new feature related to GPS cold starting.  *This requires documentation.*  What does a "GPS cold start" entail in this context?  How is this feature accessed/used? Are there any potential side effects? This should also be reflected in testing and potentially example usage.
* **Major Issue:** The function `handleColdStart` is declared, but its definition is missing. This will lead to a linker error. The implementation needs to be added in this PR.
* **Minor Issue:** The removal of blank lines within `configServer.cpp` is a style preference. Ensure consistency across the codebase.


**General Recommendation:**

* **Testing:** Any new features or changes to existing functionality should be accompanied by appropriate tests. If tests already exist, ensure they still pass after these changes.  If not, add new tests to cover the modified code.
* **Documentation:** Update any relevant documentation (e.g., README, user manual, code comments) to reflect the changes introduced by this PR, particularly concerning the GPS cold start functionality.


This review focuses on potential issues and areas for improvement.  Providing more context regarding the purpose and intended effects of these changes will help in conducting a more thorough and helpful review.

**Review Summary:**

This PR introduces a new feature to trigger a GPS cold start and adds information about the GPS module to the about page.  While the functionality seems reasonable, there are some potential issues related to error handling, code clarity, and potential misuse of the SD card.

**File: src/web_server.cpp**

* **Issue:** The new `/cold` endpoint triggers `gps.coldStartGps()` but doesn't handle potential errors or provide feedback to the user.  What happens if the cold start fails?
* **Suggestion:** Add error handling to `handleColdStartGPS()`. If `gps.coldStartGps()` fails, return an appropriate error code and message to the user. Also consider providing some visual feedback on the page to indicate that the cold start has been initiated.
* **Example:**

```cpp
static void handleColdStartGPS(HTTPRequest *, HTTPResponse * res) {
  String html = createPage(gpsColdIndex);
  html = replaceDefault(html, "Navigation");
  sendHtml(res, html);

  if (gps.coldStartGps()) {
      res->sendString("Cold start initiated."); // Provide user feedback
  } else {
      res->setStatusCode(500); // Internal Server Error
      res->sendString("Error initiating cold start.");
  }

  res->finalize();
}

```

* **Issue:** Unclear purpose and usage of `gpsColdIndex`. Is it a dedicated HTML page? What content does it display?
* **Suggestion:** Clarify the purpose of `gpsColdIndex` in a comment. Consider renaming it to something more descriptive.


**File: src/gps.cpp**

* **Issue:** The `is_neoX()` functions are redundant and potentially inefficient.  The `hwString` appears to already contain the hardware version information. Directly comparing substrings of `hwString` is simpler.
* **Suggestion:**  Remove the `is_neoX()` functions and use direct comparisons in the `hw()` function.
* **Example:**

```cpp
String Gps::hw() const {
  if (String(hwString).substring(0,4) == "0004") {
    return "Neo6";
  } else if (String(hwString).substring(0,4) == "0008") {
    return "Neo8";
  } else if (String(hwString).substring(0,4) == "000A") {
    return "NeoA";
  } else {
    return "Neo" + String(hwString).substring(3,4); // Is this correct logic for other versions?
  }
}

```

* **Issue:** In `begin()`, the conditional `if((!is_neo6()) || (!SD.exists(AID_INI_DATA_FILE_NAME)))` checks for the existence of a file on the SD card.  This introduces a dependency on the SD card and might cause issues if the SD card is not available or fails. It also seems incomplete. The code block ends abruptly.
* **Suggestion:**  Explain the purpose of this check. Why is it necessary to bypass certain initialization steps for non-Neo6 modules or when the  `AID_INI_DATA_FILE_NAME` file doesn't exist? Consider alternatives that don't depend on the SD card if possible. Complete the code block and handle the case where the file exists on Neo6. What should happen then?  Explain the rationale in a comment.


**General Suggestions:**

* **Consistent Naming:** Use a consistent naming convention for variables and functions (e.g., `coldStartGPS` or `cold_start_gps`).
* **Comments:** Add comments to explain the logic behind the changes, particularly the new features and conditional checks.
* **Testing:**  Add unit tests to verify the new functionality, especially error handling.




By addressing these issues, the code will be more robust, maintainable, and easier to understand.

File: Gps.cpp

**Review Summary:**

The changes aim to improve GPS initialization, especially for NEO-6 modules, and add some diagnostic information. While the intent is good, there are potential issues with the implementation and some areas could be improved.

**Issues and Suggestions:**

1. **Unnecessary Cold Start for Non-NEO-6 Modules:** (Gps.cpp lines 312-315)

   ```cpp
   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();
   ```

   A cold start is performed even for non-NEO-6 modules.  The log message suggests this is intended to benefit "newer neos," but the code executes unconditionally. This should be guarded by `is_neo6()`.

   Suggested change:

   ```cpp
   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");
       coldStartGps();
   } else if(/* Condition for other modules needing cold start */) {
       log_i("Coldstart for other reason.");
       coldStartGps();
   }
   ```

2. **Clarity on `AID_INI` Check:** (Gps.cpp lines 307-315)

   The code implies that the absence of `AID_INI` triggers a cold start, specifically for NEO-6 modules. However, it's unclear how the absence of `AID_INI` is determined.  There's no code snippet showing this check.  Add a comment or variable to make this explicit.

   Suggested change:  Add code or comment showing how the absence of `AID_INI` is determined.

3. **Potential Redundant `handle()` Calls:** (Gps.cpp lines 305, 355, 362) Multiple calls to `handle()` close together might be redundant. Consider consolidating them if they are intended to serve the same purpose.  Explain in a comment why each `handle()` is necessary or remove redundancies.

4. **Magic Numbers for Reset Types:** (Gps.cpp lines 291, 357)  Using named constants instead of magic numbers for reset types (e.g., `0x00, 0x00, 0x02, 0x00` and `0xFF, 0xFF, 0x00, 0x00`) would improve readability and maintainability.

   ```cpp
   const uint8_t WARM_START[] = {0x00, 0x00, 0x02, 0x00};
   const uint8_t COLD_START[] = {0xFF, 0xFF, 0x00, 0x00};
   ```

5. **Inconsistent `waitForData` duration:** In `softResetGps()`, `waitForData` is called with 1000ms, while in `coldStartGps()`, it's also 1000ms.  If there's a reason for the different durations, document it. Otherwise, use a consistent value or a named constant.

6. **Unclear Display Logic:** (Gps.cpp lines 843-861) The display logic in `showWaitStatus` is fragmented and difficult to understand. The purpose of `clear` and the conditions for displaying different messages aren't immediately obvious. Simplify and document this section.  Explain what `obsDisplay` is.  The code is also incomplete, ending with a comment.

7. **Potential Bug - String Index Out of Bounds:** (Gps.cpp 857-861) `satellitesString` is an array of size 3, but the code seems to try and access `satellitesString[2]` if `mLastTimeTimeSet != 0`. If there are conditions where both `satellitesString[1]` and `satellitesString[2]` would be set, then it would try to access `satellitesString[3]` which is out of bounds.


By addressing these issues, the code will be more robust, readable, and maintainable.  Provide the complete code for `showWaitStatus` so I can help you debug the display logic. Also, please explain what `obsDisplay` represents.

**File:** (It seems you haven't provided the filename, please provide it in future diffs) - Assuming `Gps.cpp` based on content.

**Review Summary:**

This change introduces additional debugging information and seemingly attempts to differentiate behavior between NEO-6 and other GPS modules. While the added information can be useful, the implementation has several issues related to code clarity, potential bugs, and memory management.

**Issues and Suggestions:**

1. **Magic Numbers:**  `0`, `1`, `2`, `3`, `4`, `5` are used as grid indices for displaying information.  Replace these with named constants for better readability and maintainability.  For example:

   ```cpp
   #define ROW_GPS_DETAIL 0
   #define ROW_GAIN_JAM 1
   #define ROW_SATELLITES 2
   // ... etc.
   obsDisplay->showTextOnGrid(0, ROW_GPS_DETAIL, String(hw())+" Detail");
   ```

2. **Unclear `hw()` function:**  The `hw()` function is used without context.  What does it return?  A string representation of the hardware version? This needs clarification and potentially a more descriptive name.  Also, directly converting its return value to a String might be inefficient.  Consider pre-formatting the string.

3. **Potential Buffer Overflow (hwString):**  The code copies `mGpsBuffer.monVer.hwVersion` into `hwString` without checking the size of `hwString`.  This can lead to a buffer overflow if `mGpsBuffer.monVer.hwVersion` is larger than `hwString`. Use `strncpy` or another safe string copy method:

   ```c++
   strncpy(hwString, mGpsBuffer.monVer.hwVersion, sizeof(hwString) - 1); // Leave space for null terminator
   hwString[sizeof(hwString) - 1] = '\0'; // Ensure null termination
   ```

4. **`is_neo6()` function missing:** The `is_neo6()` function is used but not defined in the provided code snippet.  Include its definition in the diff or explain its purpose.  Consider making the hardware detection more robust and less reliant on hardcoded checks. Perhaps store a hardware type enum during initialization.

5. **String concatenation inefficiency:** Repeatedly concatenating strings using `+` can be inefficient, especially within a loop. Consider using `sprintf` or a `stringstream` for better performance when building complex strings.

6. **Inconsistent Logging Levels:**  The code mixes `log_v` (verbose) and `log_d` (debug).  Choose a consistent logging level or use different levels appropriately based on the importance of the message.

7. **`aStatus` String Conversion:** The switch case for `aStatus` within the `UBX_MSG::MON_HW` handling creates temporary strings. Consider using a lookup table or an array of strings for better efficiency.

8. **Duplicate Code for Logging:** The logging statements for `NAV_SOL` and `NAV_PVT` are very similar. Consider refactoring them into a helper function to reduce code duplication.

9. **`mAidIniSent` and `is_neo6()` Logic:** The conditional `if (!mAidIniSent and is_neo6())` suggests that `aidIni()` should only be sent for NEO-6 modules.  Is this the intended behavior?  Document this logic clearly.

10. **Missing Error Handling:** The code doesn't appear to handle potential errors during GPS communication or parsing. Add checks for invalid data and appropriate error handling.


**Example incorporating some suggestions (for hwString and aStatus):**

```c++
// ... other code ...
    case (uint16_t) UBX_MSG::MON_VER: {
        // ... other code
        strncpy(hwString, mGpsBuffer.monVer.hwVersion, sizeof(hwString) - 1);
        hwString[sizeof(hwString) - 1] = '\0';
        // ... other code
    }
    break;
    case (uint16_t) UBX_MSG::MON_HW: {
        const char* aStatusStrings[] = {"init", "?", "ok", "short", "open", "invalid"};
        int aStatusIndex = mGpsBuffer.monHw.aStatus;
        if (aStatusIndex < 0 || aStatusIndex >= sizeof(aStatusStrings) / sizeof(aStatusStrings[0])) {
            aStatusIndex = sizeof(aStatusStrings) / sizeof(aStatusStrings[0]) - 1; // Default to "invalid"
        }
        const char* aStatus = aStatusStrings[aStatusIndex];
        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);
        // ... other code
    }
    break;
// ... other code ...
```



By addressing these issues, the code will be more robust, readable, and maintainable.  Please provide the complete file name in future diffs and the definition of `is_neo6()` and `hw()` for a more thorough review.

## Review Summary:

This PR introduces several changes related to GPS data handling, logging, and time synchronization. While most changes seem reasonable, there are some potential issues and areas for improvement regarding logging levels, time synchronization logic, and potential security implications of jamming information.

## File Comments:

**src/gps.cpp:**

* **Logging Level Change (Line 1277):** Changing `log_v` to `log_d` for `VELNED` messages increases the logging level from verbose to debug.  This might be excessive for regular operation and could lead to performance issues or log flooding.  Consider reverting to `log_v` or adding a configuration option to control the verbosity of these messages.  Provide a justification for the increased logging level.
    * *Suggestion:*  Keep `log_v` for regular operation and introduce a debug flag to enable `log_d` for troubleshooting purposes.

* **Time Synchronization Tolerance (Line 1403):** Increasing the delay tolerance from 250ms to 1000ms might negatively impact time accuracy. While it might improve robustness in some scenarios, it could also lead to accepting less accurate time updates. Carefully evaluate the trade-off between accuracy and robustness and provide a rationale for this change.  Consider making this configurable.
    * *Suggestion:* Add a configuration parameter for the maximum acceptable delay. Default it to a lower value (e.g., 250ms or 500ms) and document the implications of increasing it.

* **Repeated Time Sync Requests (Line 1419 and 1423):** The logic for requesting `NAV_TIMEGPS` messages seems potentially problematic. Continuously requesting time updates until a "good" time is received, especially when `delayMs > 100`, could create excessive traffic on the GPS interface. The condition `delayMs > 100` seems arbitrary and should be explained.
    * *Suggestion:* Limit the number of retry attempts for time synchronization and/or implement a backoff strategy to avoid flooding the GPS module with requests.  Clarify the reasoning behind `delayMs > 100`.

* **Jamming Indicator Exposure (Lines 1506, 1508, and corresponding changes in gps.h):** Exposing the jamming indicator (`mLastJamInd`) could have security implications. An attacker could potentially use this information to understand the effectiveness of their jamming attempts. Consider the security implications of exposing this data.
    * *Suggestion:* Carefully evaluate the need to expose this information. If it's crucial, consider adding access control mechanisms or obfuscating the data before exposing it.


**src/gps.h:**

* **New Methods for Specific GPS Modules (Lines 113-115):** Adding methods like `is_neo6()`, `is_neo8()`, and `is_neo10()` creates a tight coupling to specific GPS module models.  This could limit portability and make it harder to support different modules in the future.
    * *Suggestion:* Consider a more generic approach, such as querying the module's capabilities or using a configuration file to specify the module type.  This will make the code more flexible and maintainable.

* **Cold Start (Line 111):**  The addition of the `coldStartGps()` method should be documented clearly, explaining its purpose, behavior, and potential side effects.


## General Recommendations:

* **Error Handling:**  The code seems to lack robust error handling for cases where the GPS module doesn't respond or sends invalid data.  Consider adding checks for timeouts, invalid data lengths, and checksum errors.
* **Unit Tests:**  Add unit tests to verify the correctness of the implemented logic, especially for the time synchronization and message parsing functionalities.
* **Documentation:**  Improve the documentation for the new methods and configuration parameters, explaining their purpose, usage, and potential side effects.



By addressing these concerns, the code can be improved in terms of robustness, maintainability, and security.

File src/gps.cpp

* **Potential Issue (src/gps.cpp):**  Changing the size of `vp` from 25 to 17 bytes based on the assumption that M8 only uses 17 bytes needs careful consideration.  Is it confirmed that *only* the M8 will be used? If other modules (like the M6) might be used, this change will lead to data corruption or truncation. Consider making the size of `vp` configurable or dynamically determined based on the detected GPS module.
* **Suggestion (src/gps.cpp):** Add a check for the GPS module type (M6, M8, etc.) and adjust the size of `vp` accordingly.  This will prevent issues if different modules are used.  This might involve sending a command to the GPS module to query its identity.
* **Minor Issue (src/gps.cpp):** The comment "//M6 25bytes, M8 only 17bytes?" should be more definitive.  Replace with something like "// M8 uses 17 bytes.  M6 uses 25 bytes.  Adjusting to 17 based on assumed M8 usage."  This makes the reason for the change clearer and highlights the assumption.
* **Minor Issue (src/gps.cpp):**  For new member variables like `mLastGain`, `mLastJamInd`, and `hwString`, consider initializing them in the constructor to prevent uninitialized values.
* **Suggestion (src/gps.cpp):**  The `hw()` function should be `const` as indicated by the change. This is good practice. However, `hwString` must also be mutable if you intend to modify it within the `hw()` function. If it's only being assigned once, consider making it `const char* hwString` and initializing it directly.


File src/gpsrecord.h

* **Minor Issue (src/gpsrecord.h):** Removing blank lines generally doesn't improve readability or functionality. Unless it's part of a larger code cleanup effort to enforce consistent style, it's a trivial change.

File src/utils/alpdata.cpp

* **Potential Issue (src/utils/alpdata.cpp):** Deleting `AID_INI_DATA_FILE_NAME` immediately after reading it in `loadMessage()` might be problematic.  Why is the file being deleted?  Is this file only needed once? This could cause issues if the data is needed again. If it’s intended to be a temporary file, document this behavior clearly.
* **Suggestion (src/utils/alpdata.cpp):** If the intent is to only use the file once,  rename the file to clearly indicate its temporary nature (e.g., `temp_aid_ini_data.dat`). Or provide an option (a boolean parameter to `loadMessage`) to control whether or not the file is deleted.  This provides flexibility.


**Review Summary:**

The changes introduce potential issues related to the `vp` array size and the deletion of `AID_INI_DATA_FILE_NAME`.  The `vp` array size change should handle different GPS module types. The deletion of `AID_INI_DATA_FILE_NAME` should be carefully reviewed and justified or made optional. The other comments are minor style or good practice suggestions.  Addressing these issues will significantly improve the robustness and maintainability of the code.

    </details>
    
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-01T10:05:53Z
user: login: gluap
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-01T10:45:30Z

Review comments:
diff_hunk: @@ -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)) {
path: src/gps.cpp
user: login: amandel
body: 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'`?
created_at: 2025-02-28T11:31:34Z
author_association: MEMBER
diff_hunk: @@ -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};
path: src/gps.cpp
user: login: amandel
body: This looks wrong - below 'UBX_CFG_RATE' is not sent but TP5. A comment would help to understand what this should do
created_at: 2025-02-28T11:46:49Z
author_association: MEMBER
diff_hunk: @@ -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'
path: src/gps.cpp
user: login: amandel
body: Is this off by one... '0xFFFF Cold start'  -> 0xFF, 0xFF, 0x00, 0x00
I've see hints in the spec: 

Notes:
• If Galileo is enabled, UBX-CFG-RST Controlled GNSS start must be followed by
UBX-CFG-CFG to save current configuration to BBR and then by UBX-CFG-RST
with resetMode set to Hardware reset.
• If Galileo is enabled, use resetMode Hardware reset instead of Controlled
software reset or Controlled software reset (GNSS only).

created_at: 2025-02-28T11:52:34Z
author_association: MEMBER
diff_hunk: @@ -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) {
path: src/gps.cpp
user: login: amandel
body: Usually it is printed as next line in the obs init log - you can see other (not GPS related) init messages before the GPS status. 

I'm also fine if we use the whole display for GPS status - once everything before went fine. I would suggest to use the same code and display for both modules.
created_at: 2025-02-28T12:03:58Z
author_association: MEMBER
diff_hunk: @@ -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++) {
path: src/gps.cpp
user: login: amandel
body: Above I set `mGpsBuffer.monVer.hwVersion[sizeof(mGpsBuffer.monVer.hwVersion) - 1] = 0;` which might change your expected result. Since you do not need a trailing 0 I suggest to move this code at the beginning of this case.
created_at: 2025-02-28T12:09:16Z
author_association: MEMBER
diff_hunk: @@ -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
path: src/gps.cpp
user: login: amandel
body: I'm not sure here. Especially at the beginning there might be high delay because of other things outside GPS going on too. While this might be corrected later some tools rely on the 1st time stamp given and do not follow later adjustments. With the 1st time we also rename the csv file and other things. 

Might be we find out why the delay is so long? We also need to see that increased logging increases the delay too.
created_at: 2025-02-28T12:14:54Z
author_association: MEMBER
diff_hunk: @@ -288,6 +295,7 @@ class Gps {
         uint32_t pinDir;
         uint32_t pinVal;
         uint16_t noisePerMs;
+        uint16_t agcCnt; // AGC (Automatic Gain Control) Monitor, as percentage of maximum gain,range 0 to 8191 (100%)
path: src/gps.h
user: login: amandel
body: This was a bug before - U-BLOX6 also has this field 
created_at: 2025-02-28T12:18:04Z
author_association: MEMBER
diff_hunk: @@ -303,8 +311,8 @@ class Gps {
         uint8_t flags;
         uint8_t reserved1;
         uint32_t usedMask;
-        uint8_t vp[25];
-        uint8_t jamInd;
+        uint8_t vp[17]; //M6 25bytes, M8 only 17bytes?
path: src/gps.h
user: login: amandel
body: This is strange 1st time I see such a breaking change in the protocol, but I can confirm it with the PDFs I've at hand. 

Message has 68 bytes for M6 and 60 Bytes for M8. We should take care for this. 
created_at: 2025-02-28T12:22:43Z
author_association: MEMBER
diff_hunk: @@ -303,8 +311,8 @@ class Gps {
         uint8_t flags;
         uint8_t reserved1;
         uint32_t usedMask;
-        uint8_t vp[25];
-        uint8_t jamInd;
+        uint8_t vp[17]; //M6 25bytes, M8 only 17bytes?
path: src/gps.h
user: login: Jens-Kassel
body: Yes I read this also in the PDF, but had no M6N at hand to validate it.

We could define the Message twice and decide by msg-length which one to use for parsing.
created_at: 2025-02-28T14:20:51Z
author_association: NONE
diff_hunk: @@ -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
path: src/gps.cpp
user: login: Jens-Kassel
body: Should we make this configurable?

In most use cases even full seconds doesn't matter. (Probably you want to know if it was rush hour or not, but don't need the exact time.)
Synchronization with video or whatever where we want to have sub-second precision is used by few users, I guess.

But have an GPS fix at all is crucial.

In future I could imagine to attach a logic-analyser and figure out the timing of the messages.
The Evaluation board don't use the timing pin, the OBS-pro could use it.
created_at: 2025-02-28T14:29:52Z
author_association: NONE
diff_hunk: @@ -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
path: src/gps.cpp
user: login: amandel
body: I don't like the idea that users of the obs have to deal with this setting. We need to find a good value. If we are stable with the rest it might be a good idea to put the delay into a logfile (might be already part of the CSV debug info messages as part of `TIMEGPS set`). Might be the delay is because of a faulty message or wait before, we will see. 

If we do have a fix, we could also set the time on other messages (eg. 1st message with a new iTOW value) 
created_at: 2025-02-28T14:51:32Z
author_association: MEMBER
diff_hunk: @@ -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) {
path: src/gps.cpp
user: login: gluap
body: Neo6m doesn't give us some of the values that we're displaying, as that's a thing starting from 7m or 8m. So either we have users questioning why they see a constant zero (or even noise...?) for @Jens-Kassel's new values gain and jamming we will still need separat codepaths for 8m and 6m. Also I didn't want to pollute the screen for the normally well-working neo6m.
created_at: 2025-02-28T19:09:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -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};
path: src/gps.cpp
user: login: gluap
body: I wonder where that came from - so I removed it.
created_at: 2025-02-28T19:41:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -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'
path: src/gps.cpp
user: login: gluap
body: I believe we are implementing the notes (thanks for mentioning them, I didn't remember what the 0x04 was for)
- "reset mode hardware reset" -> we need ``0x04`` in the third byte. 
- As far as I can tell we never do controlled gnss start or stop so the UBX-CFG-CFG note doesn't apply
- We could do ``0xff 0xff 0x04 0x00`` here, but I believe all the other bits in the bitfield are irrelevant (14,10,9 are empty, ``SFDR`` ``VMON`` ``TCT`` are not available on our gps, leaving bit 15 ``aop`` and 8 ``rtc`` to be set -> ``0x81`` for the second byte.
created_at: 2025-02-28T19:41:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -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++) {
path: src/gps.cpp
user: login: gluap
body: We're still using the trailing zero for the log output to the web interface - at least I inferred that you added the trailing zero for the string gymnastics for the webinterface. therefore I didn't want to discard the trailing zero.

We only compare the first 4 bytes of hwVersion (which is 8 bytes long) so we don't really suffer from the last byte.
created_at: 2025-02-28T19:43:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -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
path: src/gps.cpp
user: login: gluap
body: my thinking was indeed: ``delay_ms`` doesn't really make a difference for the filename (it will be on the order of seconds, not minutes) and we will receive the next message with a valid time pretty soon (that's was the aim of decreasing the message interval below in case ``delay_ms`` is large).

To satisfy both needs I suggest the following:
- we always use the first valid time, no matter ``delayMs``
- but as long as ``delayMs`` is higher than say 100ms we remember that the time is still not perfect by not setting ``mLastTimeTimeSet``
- as soon as we get a ``delayMs`` below 100ms we flag the time as fine by setting ``mLastTimeTimeSet`` and increase to 240 s interval

This will still have the drawback that "tools that rely on the first timestamp" may be off by a few hundred miliseconds (we could limit it to 1000 or so by increasing from 250). But virtually all tools used on OpenBikeSensor `csv` are likely to be operated or written by very technical people that will be able to spot this with ease. Also it will be irrelevant for people driving out of one of their privacy zones with enabled privacy (unless they have the record in privacy zone feature on).

created_at: 2025-02-28T20:03:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -303,8 +311,8 @@ class Gps {
         uint8_t flags;
         uint8_t reserved1;
         uint32_t usedMask;
-        uint8_t vp[25];
-        uint8_t jamInd;
+        uint8_t vp[17]; //M6 25bytes, M8 only 17bytes?
path: src/gps.h
user: login: gluap
body: I believe this will work as long as we don't need anything beyond ``vp`` (on neo6) or beyond ``jamInd`` (on neo8). MAX_MESSAGE_LENGTH ensures that we don't overflow stuff that we shouldn't
created_at: 2025-02-28T20:06:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -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)) {
path: src/gps.cpp
user: login: gluap
body: 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.
created_at: 2025-02-28T20:11:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -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'
path: src/gps.cpp
user: login: amandel
body: I still think 0xFF, 0xFF, 0x00, 0x00 is correct:

> navBrkMask: 0xFFFF Cold start (see graphic below)

> resetMode
> 0x00 = Hardware reset (watchdog) immediately
> 0x01 = Controlled software reset
> 0x02 = Controlled software reset (GNSS only)
> 0x04 = Hardware reset (watchdog) after shutdown
> 0x08 = Controlled GNSS stop
> 0x09 = Controlled GNSS start


created_at: 2025-02-28T20:15:49Z
author_association: MEMBER
diff_hunk: @@ -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) {
path: src/gps.cpp
user: login: amandel
body: Okay ;)

created_at: 2025-02-28T20:16:45Z
author_association: MEMBER
diff_hunk: @@ -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("0004")) {
+    return true;
+  }
+  return false;
+}
+
+bool Gps::is_neo8() const {
+  if (String(hwString).substring(0,4) == String("0008")) {
+    return true;
+  }
+  return false;
+}
+
+bool Gps::is_neo10() const {
+  if (String(hwString).substring(0,4) == String("000A")) {
+    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();
path: src/gps.cpp
user: login: gluap
body: @amandel this is where we only do ALP for neo6.
created_at: 2025-02-28T20:16:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -344,11 +413,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);
+  }
path: src/gps.cpp
user: login: gluap
body: @amandel for good measure we also restrict AID_ALP to neo6 
created_at: 2025-02-28T20:17:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -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("0004")) {
+    return true;
+  }
+  return false;
+}
+
+bool Gps::is_neo8() const {
+  if (String(hwString).substring(0,4) == String("0008")) {
+    return true;
+  }
+  return false;
+}
+
+bool Gps::is_neo10() const {
+  if (String(hwString).substring(0,4) == String("000A")) {
+    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();
path: src/gps.cpp
user: login: amandel
body: We still download ALP data in server mode. We should know which version of GPS module we have at that point in time and so can skip the alp download altogether.
created_at: 2025-02-28T20:31:18Z
author_association: MEMBER
diff_hunk: @@ -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
path: src/gps.cpp
user: login: amandel
body: We might ignore this for now and add a issue for this. Might be we should add a log + status message entry for now, if we do not set the clock because a too long delay? I can eventually check for a implementation that uses and (1st) iTOW value to set the time.
created_at: 2025-02-28T20:35:14Z
author_association: MEMBER
diff_hunk: @@ -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'
path: src/gps.cpp
user: login: gluap
body: @amandel I see now - you're right about ``0x00`` instead of ``0x04`` in the third byte. I think fixing it with 0x04 worked equivalently in my tests on accident because it still causes the hardware reset - I believe at the next boot the "reset after shutdown" takes place, causing the OBS to wake up to a freshly reset GPS automagically. I must have locked in on the "Hardware reset" for 0x04 overlooking that there was a second hardware reset for 0x00.

As for ``0xFF 0x81`` in the first two bytes these are functionally equivalent (see below with all the bits for functionallity unavailable on our neos xed out) so as said earlier ``0xFF,0xFF" is OK as well.
![image](https://github.com/user-attachments/assets/aad5404d-c3b1-4750-8499-18644078be46)

We need to test with these new bytes though - I had played around with all kinds of things to make it work, and successfully tested this specifically.
created_at: 2025-03-01T09:49:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -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("0004")) {
+    return true;
+  }
+  return false;
+}
+
+bool Gps::is_neo8() const {
+  if (String(hwString).substring(0,4) == String("0008")) {
+    return true;
+  }
+  return false;
+}
+
+bool Gps::is_neo10() const {
+  if (String(hwString).substring(0,4) == String("000A")) {
+    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();
path: src/gps.cpp
user: login: gluap
body: I made ALP download conditional below with the latest commit.
created_at: 2025-03-01T10:04:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -303,8 +311,8 @@ class Gps {
         uint8_t flags;
         uint8_t reserved1;
         uint32_t usedMask;
-        uint8_t vp[25];
-        uint8_t jamInd;
+        uint8_t vp[17]; //M6 25bytes, M8 only 17bytes?
path: src/gps.h
user: login: gluap
body: I also re-added the old definition and conditionally use the new message when not ``is_neo6()``
created_at: 2025-03-01T10:45:30Z
author_association: CONTRIBUTOR

PR comments:
user: login: Jens-Kassel
created_at: 2025-02-28T14:35:44Z
body: > Long term we should also get rid of the ifdefs form UBX_M10 vs UBX_M6, but one thing after the other ;) Might be we should also not use the ALP data if a M8 or newer is detected. These modules can (if I remember correctly) collect the data over the time from the satellites and we could then persist it (AssistNow Autonomous).

I thought about storing the hardware-variant in the config. Then we can start fastly with an assumption. When we detect something else we can correct it an reboot. (This is very unlikely and acceptable for the first boot or changed hardware)


author_association: NONE
user: login: amandel
created_at: 2025-02-28T14:55:59Z
body: > I thought about storing the hardware-variant in the config.

On the other hand if the communication with the GPS module is up this info is just one message away. Would it be notable at all?
author_association: MEMBER
user: login: gluap
created_at: 2025-02-28T20:22:15Z
body: > Thanks for adding this and thanks for the lot of experiments with the GPS modules.
> 
> Long term we should also get rid of the ifdefs form UBX_M10 vs UBX_M6, but one thing after the other ;) Might be we should also not use the ALP data if a M8 or newer is detected. These modules can (if I remember correctly) collect the data over the time from the satellites and we could then persist it (AssistNow Autonomous).

@amandel I dropped some notes in the review where aid and alp are disabled unless neo6m is detected.

I agree that we should aim to check for the GPS version at runtime.

From my perspective I've addressed with the comments. Gemini is doing weird things. Earlier it was finished, showed red and left miles along, unrendered markdown comment, now it seems to have decided to re-run on its own.

I'm unsure if its bad practice if I resolve therefore I left them unresolved.
author_association: CONTRIBUTOR
user: login: amandel
created_at: 2025-02-28T20:27:17Z
body: > Gemini is doing weird things. Earlier it was finished, showed red and left miles along, unrendered markdown comment, now it seems to have decided to re-run on its own.

I've triggered gemini  :) - I see it just as bonus no blocker if it is red.
author_association: MEMBER
user: login: gluap
created_at: 2025-03-01T10:54:40Z
body: @amandel the AI is now posting in your name - I'd suggest to add a prefix the lines of "The following is the automatically-generated result of looking at the PR with gemini AI - sometimes these suggestions can be helpful, but don't be overly confused or put too much work in where the AI missed the point. We're currently testing how helpful it can be.". 

The AI suggestions are sometimes helpful, sometimes confusing, so I think we really want people to know when they get suggestions by an AI and when they are talking to real people.

**Also in the open source space usage of AI for code can be seen as controversial given that a lot of AI manufacturers and deter some contributors.**
author_association: CONTRIBUTOR
user: login: gluap
created_at: 2025-03-01T10:54:59Z
body: I think I went through all improvement suggestions now.

A quick smoke test still gets a fix with reasonable speed.
[firmware.zip](https://github.com/user-attachments/files/19038575/firmware.zip)


author_association: CONTRIBUTOR
user: login: amandel
created_at: 2025-03-02T09:49:38Z
body: Cool! I'm not at home and can not do a qick test with the NEO6 module, @gluap I assume you did only test with the NEO8 module?
author_association: MEMBER
user: login: amandel
created_at: 2025-03-02T10:12:55Z
body: > @amandel the AI is now posting in your name - I'd suggest to add a prefix the lines of "The following is the automatically-generated result of looking at the PR with gemini AI - sometimes these suggestions can be helpful, but don't be overly confused or put too much work in where the AI missed the point. We're currently testing how helpful it can be.".

Actually intention was just to test this and not to create posts in my name 🙈. While the created content was mostly valid, I'll switch it off for now.

> **Also in the open source space usage of AI for code can be seen as controversial given that a lot of AI manufacturers and deter some contributors.**

If you think we should give us some rules here we might need to discuss it in a Monday meeting? 
author_association: MEMBER
user: login: gluap
created_at: 2025-03-02T10:29:27Z
body: I tested on neo7 and neo8.

Things to test on neo6:

- does alp download still happen? (if there are messages about alp while starting server mode it does, the whole method is skipped on other neos)

One todo left i noticed yesterday is to clean up the gps info on the screen.
![IMG_20250302_113007~2.jpg](https://github.com/user-attachments/assets/00ad84a3-3986-49c8-a1ae-ca95a03e2912)


author_association: CONTRIBUTOR
user: login: gluap
created_at: 2025-03-02T10:34:55Z
body: I tested on neo6, neo7 and neo8.

- [x] does alp download still happen on neo6? (yes)
- [x] is ALP download skipped on neo8?(yes) 
- [x] clean up the gps info on the screen.
author_association: CONTRIBUTOR