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 =
"
Device reboots now.
";
+static const char* const gpsColdIndex =
+ "GPS cold start
";
+
// #########################################
// 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;
}