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"
Ticker validityTimer;
uint32_t valid_count;
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;
uint32_t bad_checksum_count;
uint32_t req_count;
uint32_t rsp_count;
int8_t precision;
volatile uint32_t dispersion;
volatile time_t seconds;
volatile uint32_t last_micros;
volatile uint32_t micros_wraps;
volatile uint32_t min_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];
MicroNMEA nmea(nmeaBuffer, NMEA_BUFFER_SIZE);
#if defined(USE_OLED_DISPLAY)
SSD1306Wire display(0x3c, SDA, SCL);
#endif
#ifdef NTP_PACKET_DEBUG
void dumpNTPPacket(NTPPacket* ntp)
@ -83,19 +85,45 @@ void dumpNTPPacket(NTPPacket* ntp)
#define dumpNTPPacket(x)
#endif
void validityCheck()
void invalidate()
{
valid = false;
gps_valid = false;
last_micros = 0;
}
void oneSecondInterrupt()
{
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.
//
validityTimer.attach_ms(VALIDITY_CHECK_MS, &validityCheck);
validityTimer.attach_ms(VALIDITY_CHECK_MS, &invalidate);
//
// increment seconds
@ -111,11 +139,6 @@ void oneSecondInterrupt()
return;
}
if (cur_micros < last_micros)
{
++micros_wraps;
}
uint32_t micros_count = cur_micros - last_micros;
last_micros = cur_micros;
@ -163,7 +186,6 @@ void getNTPTime(NTPTime *time)
}
double percent = us2s(micros_delta);
//dbprintf("micros_delta: %lu percent: %lf\n", micros_delta, percent);
time->fraction = (uint32_t)(percent * (double)4294967296L);
}
@ -189,7 +211,8 @@ void recievePacket(AsyncUDPPacket aup)
void recievePacket()
#endif
{
static NTPPacket ntp;
++req_count;
NTPPacket ntp;
NTPTime recv_time;
getNTPTime(&recv_time);
#if defined(USE_ASYNC_UDP)
@ -257,6 +280,7 @@ void recievePacket()
ntp.xmit_time.fraction = htonl(ntp.xmit_time.fraction);
#if defined(USE_ASYNC_UDP)
aup.write((uint8_t*)&ntp, sizeof(ntp));
++rsp_count;
#else
IPAddress address = udp.remoteIP();
uint16_t port = udp.remotePort();
@ -269,21 +293,21 @@ void recievePacket()
void badChecksum(MicroNMEA& mn)
{
const char* s = mn.getSentence();
dbprintf("badChecksum: (length:%d 1stbyte:%02x) '%s'\n", strlen(s), s[0], s);
++bad_checksum_count;
dbprintf("badChecksum: '%s'\n", mn.getSentence());
}
void unknownSentence(MicroNMEA& mn)
{
const char* sentence = mn.getSentence();
dbprintf("unknownSentence: %s\n", sentence);
if (!strncmp("$PMTK", sentence, 5))
{
dbprintf("unknownSentence: %s\n", sentence);
return;
}
sentence_unknown = true;
dbprintf("unknownSentence: %s\n", sentence);
}
void resetGPS()
@ -291,12 +315,15 @@ void resetGPS()
dbprintln("resetGPS: starting!");
// Empty input buffer
while (gps.available())
{
gps.read();
}
digitalWrite(GPS_EN_PIN, LOW);
delay(100);
digitalWrite(GPS_EN_PIN, HIGH);
#if 0
dbprintln("resetGPS: waiting on first sentence");
dbflush();
@ -316,22 +343,37 @@ void resetGPS()
}
}
}
#endif
}
void processGPS()
{
static boolean last_valid;
if (last_valid && !valid)
static boolean last_valid = false;
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!");
}
else if (!last_valid && valid)
{
dbprintln("VALID!");
}
last_valid = valid;
last_gps_valid = gps_valid;
while(gps.available() > 0)
while (gps.available() > 0)
{
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;
tm.tm_year = nmea.getYear() - 1900;
@ -346,21 +388,17 @@ void processGPS()
if (old_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
last_micros = 0;
min_micros = 0;
max_micros = 0;
valid = true;
++valid_count;
dbprintln("VALID!");
gps_valid = true;
pps_valid_count = PPS_VALID_COUNT;
dbprintln("gps valid!");
}
}
}
@ -379,6 +417,7 @@ void sendSentence(const char* sentence)
void setup()
{
delay(5000); // delay for IDE to re-open serial
dbbegin(115200);
dbprintln("\n\nStartup!");
@ -400,19 +439,17 @@ void setup()
#if !defined(USE_NO_WIFI)
WiFiManager wifi;
//wifi.setDebugOutput(false);
wifi.setDebugOutput(false);
String ssid = "SynchroClock" + String(ESP.getChipId());
wifi.autoConnect(ssid.c_str(), NULL);
#endif
#if defined(USE_OLED_DISPLAY)
if (!display.init())
{
dbprintln("display.init() failed!");
}
display.flipScreenVertically();
display.setFont(ArialMT_Plain_10);
#endif
gps.begin(9600);
nmea.setBadChecksumHandler(&badChecksum);
@ -425,9 +462,11 @@ void setup()
// initialize UDP handler
//
#if defined(USE_ASYNC_UDP)
while(!udp.listen(NTP_PORT)) {
while (!udp.listen(NTP_PORT))
{
#else
while(!udp.begin(NTP_PORT)) {
while(!udp.begin(NTP_PORT))
{
#endif
dbprintf("setup: failed to listen on port %d! Will retry in a bit...\n", NTP_PORT);
delay(1000);
@ -459,7 +498,9 @@ void loop()
}
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)
@ -480,11 +521,15 @@ void loop()
#endif
double disp = us2s(MAX(abs(MICROS_PER_SEC-max_micros), abs(MICROS_PER_SEC-min_micros)));
dispersion = (uint32_t)(disp * 65536.0);
dbprintf("min:%lu max:%lu jitter:%lu valid_count:%lu valid:%s heap:%ld\n",
min_micros, max_micros, max_micros-min_micros,
valid_count, valid?"true":"false", ESP.getFreeHeap());
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,
max_micros - min_micros, valid_count, valid ? "true" : "false", nmea.getNumSatellites(), ESP.getFreeHeap(), pps_valid_count,
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
@ -492,12 +537,16 @@ void loop()
display.clear();
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.setFont(ArialMT_Plain_10);
const char* s = ctime(&last_seconds);
display.drawString(0, 0, WiFi.localIP().toString());
display.drawString(0, 10, s);
display.drawString(0, 20, "Heap Free:"+String(ESP.getFreeHeap()));
const char* current_time = ctime(&last_seconds);
display.drawString(0, 0, current_time);
display.drawString(0, 10, "Address: "+WiFi.localIP().toString());
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
display.display();
}
last_seconds = seconds;
delay(1);
}

View File

@ -21,7 +21,6 @@
*/
#define USE_ASYNC_UDP
#define USE_OLED_DISPLAY
//#define USE_NO_WIFI
#ifndef _ESPNTPServer_H_
@ -35,9 +34,7 @@
#include "MicroNMEA.h"
#include <time.h>
#if defined(USE_OLED_DISPLAY)
#include "SSD1306Wire.h"
#endif
#if defined(USE_ASYNC_UDP)
#include "ESPAsyncUDP.h"
@ -63,6 +60,7 @@
#define SERIAL_BUFFER_SIZE 128
#define NMEA_BUFFER_SIZE 128
#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 us2s(x) (((double)x)/(double)MICROS_PER_SEC) // microseconds to seconds