we are not valid until 60 PPS cycles after we have a valid gps

This commit is contained in:
Chris Liebman 2017-11-13 14:06:28 -08:00
parent adc4412326
commit aa265b1280
2 changed files with 152 additions and 105 deletions

View File

@ -27,16 +27,20 @@
#include "Logger.h" #include "Logger.h"
Ticker validityTimer; Ticker validityTimer;
uint32_t valid_count;
bool valid; bool valid;
bool gps_valid;
uint32_t pps_valid_count;
volatile uint32_t valid_count; // how many times we have gone from invalid to valid
bool sentence_unknown; bool sentence_unknown;
uint32_t bad_checksum_count;
uint32_t req_count;
uint32_t rsp_count;
int8_t precision; int8_t precision;
volatile uint32_t dispersion; volatile uint32_t dispersion;
volatile time_t seconds; volatile time_t seconds;
volatile uint32_t last_micros; volatile uint32_t last_micros;
volatile uint32_t micros_wraps;
volatile uint32_t min_micros; volatile uint32_t min_micros;
volatile uint32_t max_micros; volatile uint32_t max_micros;
@ -56,9 +60,7 @@ SoftwareSerial gps(GPS_RX_PIN, GPS_TX_PIN, false, SERIAL_BUFFER_SIZE);
char nmeaBuffer[NMEA_BUFFER_SIZE]; char nmeaBuffer[NMEA_BUFFER_SIZE];
MicroNMEA nmea(nmeaBuffer, NMEA_BUFFER_SIZE); MicroNMEA nmea(nmeaBuffer, NMEA_BUFFER_SIZE);
#if defined(USE_OLED_DISPLAY)
SSD1306Wire display(0x3c, SDA, SCL); SSD1306Wire display(0x3c, SDA, SCL);
#endif
#ifdef NTP_PACKET_DEBUG #ifdef NTP_PACKET_DEBUG
void dumpNTPPacket(NTPPacket* ntp) void dumpNTPPacket(NTPPacket* ntp)
@ -83,19 +85,45 @@ void dumpNTPPacket(NTPPacket* ntp)
#define dumpNTPPacket(x) #define dumpNTPPacket(x)
#endif #endif
void validityCheck() void invalidate()
{ {
valid = false; valid = false;
gps_valid = false;
last_micros = 0;
} }
void oneSecondInterrupt() void oneSecondInterrupt()
{ {
uint32_t cur_micros = micros(); uint32_t cur_micros = micros();
//
// don't trust PPS if GPS is not valid.
//
if (!gps_valid)
{
return;
}
//
// if we are still counting down then keep waiting
//
if (pps_valid_count)
{
--pps_valid_count;
if (pps_valid_count == 0)
{
// clear stats and mark us valid
min_micros = 0;
max_micros = 0;
valid = true;
++valid_count;
}
}
// //
// restart the validity timer, if it runs out we invalidate our data. // restart the validity timer, if it runs out we invalidate our data.
// //
validityTimer.attach_ms(VALIDITY_CHECK_MS, &validityCheck); validityTimer.attach_ms(VALIDITY_CHECK_MS, &invalidate);
// //
// increment seconds // increment seconds
@ -111,11 +139,6 @@ void oneSecondInterrupt()
return; return;
} }
if (cur_micros < last_micros)
{
++micros_wraps;
}
uint32_t micros_count = cur_micros - last_micros; uint32_t micros_count = cur_micros - last_micros;
last_micros = cur_micros; last_micros = cur_micros;
@ -163,7 +186,6 @@ void getNTPTime(NTPTime *time)
} }
double percent = us2s(micros_delta); double percent = us2s(micros_delta);
//dbprintf("micros_delta: %lu percent: %lf\n", micros_delta, percent);
time->fraction = (uint32_t)(percent * (double)4294967296L); time->fraction = (uint32_t)(percent * (double)4294967296L);
} }
@ -189,7 +211,8 @@ void recievePacket(AsyncUDPPacket aup)
void recievePacket() void recievePacket()
#endif #endif
{ {
static NTPPacket ntp; ++req_count;
NTPPacket ntp;
NTPTime recv_time; NTPTime recv_time;
getNTPTime(&recv_time); getNTPTime(&recv_time);
#if defined(USE_ASYNC_UDP) #if defined(USE_ASYNC_UDP)
@ -257,6 +280,7 @@ void recievePacket()
ntp.xmit_time.fraction = htonl(ntp.xmit_time.fraction); ntp.xmit_time.fraction = htonl(ntp.xmit_time.fraction);
#if defined(USE_ASYNC_UDP) #if defined(USE_ASYNC_UDP)
aup.write((uint8_t*)&ntp, sizeof(ntp)); aup.write((uint8_t*)&ntp, sizeof(ntp));
++rsp_count;
#else #else
IPAddress address = udp.remoteIP(); IPAddress address = udp.remoteIP();
uint16_t port = udp.remotePort(); uint16_t port = udp.remotePort();
@ -269,21 +293,21 @@ void recievePacket()
void badChecksum(MicroNMEA& mn) void badChecksum(MicroNMEA& mn)
{ {
const char* s = mn.getSentence(); ++bad_checksum_count;
dbprintf("badChecksum: (length:%d 1stbyte:%02x) '%s'\n", strlen(s), s[0], s); dbprintf("badChecksum: '%s'\n", mn.getSentence());
} }
void unknownSentence(MicroNMEA& mn) void unknownSentence(MicroNMEA& mn)
{ {
const char* sentence = mn.getSentence(); const char* sentence = mn.getSentence();
dbprintf("unknownSentence: %s\n", sentence);
if (!strncmp("$PMTK", sentence, 5)) if (!strncmp("$PMTK", sentence, 5))
{ {
dbprintf("unknownSentence: %s\n", sentence);
return; return;
} }
sentence_unknown = true; sentence_unknown = true;
dbprintf("unknownSentence: %s\n", sentence);
} }
void resetGPS() void resetGPS()
@ -291,12 +315,15 @@ void resetGPS()
dbprintln("resetGPS: starting!"); dbprintln("resetGPS: starting!");
// Empty input buffer // Empty input buffer
while (gps.available()) while (gps.available())
{
gps.read(); gps.read();
}
digitalWrite(GPS_EN_PIN, LOW); digitalWrite(GPS_EN_PIN, LOW);
delay(100); delay(100);
digitalWrite(GPS_EN_PIN, HIGH); digitalWrite(GPS_EN_PIN, HIGH);
#if 0
dbprintln("resetGPS: waiting on first sentence"); dbprintln("resetGPS: waiting on first sentence");
dbflush(); dbflush();
@ -316,22 +343,37 @@ void resetGPS()
} }
} }
} }
#endif
} }
void processGPS() void processGPS()
{ {
static boolean last_valid; static boolean last_valid = false;
if (last_valid && !valid) static boolean last_gps_valid = false;
//
// Print valid or invalid if stats has changed.
//
if ((last_valid && !valid) || (last_gps_valid && !gps_valid))
{ {
dbprintln("INVALID!"); dbprintln("INVALID!");
} }
else if (!last_valid && valid)
{
dbprintln("VALID!");
}
last_valid = valid; last_valid = valid;
last_gps_valid = gps_valid;
while (gps.available() > 0) while (gps.available() > 0)
{ {
if (nmea.process(gps.read())) if (nmea.process(gps.read()))
{ {
if (nmea.isValid() && nmea.getYear() > 2000) //
// if it was a GGA and its valid then check and maybe update the time
//
const char * id = nmea.getMessageID();
if (nmea.isValid() && nmea.getYear() > 2000 && strcmp("GGA", id) == 0)
{ {
static struct tm tm; static struct tm tm;
tm.tm_year = nmea.getYear() - 1900; tm.tm_year = nmea.getYear() - 1900;
@ -346,21 +388,17 @@ void processGPS()
if (old_seconds != new_seconds) if (old_seconds != new_seconds)
{ {
seconds = new_seconds; seconds = new_seconds;
dbprintf("adjusting seconds from %lu to %lu\n", old_seconds, new_seconds); dbprintf("%010lu: %s adjusting seconds from %lu to %lu\n", millis(), nmea.getMessageID(), old_seconds, new_seconds);
} }
// //
// if we were not valid, we are now // if gps was not valid, it is now
// //
if (!valid) if (!gps_valid)
{ {
// clear stats and mark us valid gps_valid = true;
last_micros = 0; pps_valid_count = PPS_VALID_COUNT;
min_micros = 0; dbprintln("gps valid!");
max_micros = 0;
valid = true;
++valid_count;
dbprintln("VALID!");
} }
} }
} }
@ -379,6 +417,7 @@ void sendSentence(const char* sentence)
void setup() void setup()
{ {
delay(5000); // delay for IDE to re-open serial
dbbegin(115200); dbbegin(115200);
dbprintln("\n\nStartup!"); dbprintln("\n\nStartup!");
@ -400,19 +439,17 @@ void setup()
#if !defined(USE_NO_WIFI) #if !defined(USE_NO_WIFI)
WiFiManager wifi; WiFiManager wifi;
//wifi.setDebugOutput(false); wifi.setDebugOutput(false);
String ssid = "SynchroClock" + String(ESP.getChipId()); String ssid = "SynchroClock" + String(ESP.getChipId());
wifi.autoConnect(ssid.c_str(), NULL); wifi.autoConnect(ssid.c_str(), NULL);
#endif #endif
#if defined(USE_OLED_DISPLAY)
if (!display.init()) if (!display.init())
{ {
dbprintln("display.init() failed!"); dbprintln("display.init() failed!");
} }
display.flipScreenVertically(); display.flipScreenVertically();
display.setFont(ArialMT_Plain_10); display.setFont(ArialMT_Plain_10);
#endif
gps.begin(9600); gps.begin(9600);
nmea.setBadChecksumHandler(&badChecksum); nmea.setBadChecksumHandler(&badChecksum);
@ -425,9 +462,11 @@ void setup()
// initialize UDP handler // initialize UDP handler
// //
#if defined(USE_ASYNC_UDP) #if defined(USE_ASYNC_UDP)
while(!udp.listen(NTP_PORT)) { while (!udp.listen(NTP_PORT))
{
#else #else
while(!udp.begin(NTP_PORT)) { while(!udp.begin(NTP_PORT))
{
#endif #endif
dbprintf("setup: failed to listen on port %d! Will retry in a bit...\n", NTP_PORT); dbprintf("setup: failed to listen on port %d! Will retry in a bit...\n", NTP_PORT);
delay(1000); delay(1000);
@ -459,7 +498,9 @@ void loop()
} }
static time_t last_seconds; static time_t last_seconds;
if (seconds != last_seconds && (seconds % 60) == 0) if (seconds != last_seconds)
{
if (seconds != last_seconds && ((seconds % 60) == 0 || pps_valid_count))
{ {
#if defined(MICROS_HISTORY_SIZE) #if defined(MICROS_HISTORY_SIZE)
@ -480,11 +521,15 @@ void loop()
#endif #endif
double disp = us2s(MAX(abs(MICROS_PER_SEC-max_micros), abs(MICROS_PER_SEC-min_micros))); double disp = us2s(MAX(abs(MICROS_PER_SEC-max_micros), abs(MICROS_PER_SEC-min_micros)));
dispersion = (uint32_t)(disp * 65536.0); dispersion = (uint32_t)(disp * 65536.0);
dbprintf("min:%lu max:%lu jitter:%lu valid_count:%lu valid:%s heap:%ld\n", dbprintf("min:%lu max:%lu jitter:%lu valid_count:%lu valid:%s numsat:%d heap:%ld pps_valid_count:%d badcs: %lu\n", min_micros, max_micros,
min_micros, max_micros, max_micros-min_micros, max_micros - min_micros, valid_count, valid ? "true" : "false", nmea.getNumSatellites(), ESP.getFreeHeap(), pps_valid_count,
valid_count, valid?"true":"false", ESP.getFreeHeap()); bad_checksum_count);
}
if (seconds < last_seconds)
{
dbprintf("OOPS: time went backwards: last:%lu now:%lu\n", last_seconds, seconds);
} }
last_seconds = seconds;
// //
// Update the display // Update the display
@ -492,12 +537,16 @@ void loop()
display.clear(); display.clear();
display.setTextAlignment(TEXT_ALIGN_LEFT); display.setTextAlignment(TEXT_ALIGN_LEFT);
display.setFont(ArialMT_Plain_10); display.setFont(ArialMT_Plain_10);
const char* s = ctime(&last_seconds); const char* current_time = ctime(&last_seconds);
display.drawString(0, 0, WiFi.localIP().toString()); display.drawString(0, 0, current_time);
display.drawString(0, 10, s); display.drawString(0, 10, "Address: "+WiFi.localIP().toString());
display.drawString(0, 20, "Heap Free:"+String(ESP.getFreeHeap())); display.drawString(0, 20, "Sat Count: " + String(nmea.getNumSatellites()));
display.drawString(0, 30, "Requests: " + String(req_count));
display.drawString(0, 40, "Responses: " + String(rsp_count));
// write the buffer to the display // write the buffer to the display
display.display(); display.display();
}
last_seconds = seconds;
delay(1); delay(1);
} }

View File

@ -21,7 +21,6 @@
*/ */
#define USE_ASYNC_UDP #define USE_ASYNC_UDP
#define USE_OLED_DISPLAY
//#define USE_NO_WIFI //#define USE_NO_WIFI
#ifndef _ESPNTPServer_H_ #ifndef _ESPNTPServer_H_
@ -35,9 +34,7 @@
#include "MicroNMEA.h" #include "MicroNMEA.h"
#include <time.h> #include <time.h>
#if defined(USE_OLED_DISPLAY)
#include "SSD1306Wire.h" #include "SSD1306Wire.h"
#endif
#if defined(USE_ASYNC_UDP) #if defined(USE_ASYNC_UDP)
#include "ESPAsyncUDP.h" #include "ESPAsyncUDP.h"
@ -63,6 +60,7 @@
#define SERIAL_BUFFER_SIZE 128 #define SERIAL_BUFFER_SIZE 128
#define NMEA_BUFFER_SIZE 128 #define NMEA_BUFFER_SIZE 128
#define VALIDITY_CHECK_MS 1100 #define VALIDITY_CHECK_MS 1100
#define PPS_VALID_COUNT 60 // must have at least this many "good" PPS interrupts to be valid
//#define MICROS_HISTORY_SIZE 1000 //#define MICROS_HISTORY_SIZE 1000
#define us2s(x) (((double)x)/(double)MICROS_PER_SEC) // microseconds to seconds #define us2s(x) (((double)x)/(double)MICROS_PER_SEC) // microseconds to seconds