#include <string.h>
#include <ctype.h>
#include <time.h>
#define GPS_STATE_1PPS 0x01
#define GPS_STATE_RX 0x02
#define GPS_STATE_TX_DONE 0x04
#define GPS_STATE_SAW_NMEA 0x08
typedef struct sAppGPSState {
unsigned int flags;
uint8_t keep_fix;
uint8_t last_fix;
unsigned int last_week_be;
unsigned int dropped_fix;
unsigned int app_lost_pkts;
unsigned int driver_lost_pkts;
unsigned int lost_octets;
const uint8_t * msg;
unsigned int msg_len;
unsigned long rx_utt;
unsigned long pps_tt;
int tx_rc;
} sAppGPSState;
static volatile sAppGPSState gps_state_;
static int
gps_serial_cb (const uint8_t * msg,
size_t len,
unsigned long rx_utt)
{
int rc;
unsigned int flags = GPS_STATE_RX;
if (NULL == msg) {
++gps_state_.driver_lost_pkts;
gps_state_.lost_octets += len;
} else if (NULL == gps_state_.msg) {
flags = GPS_STATE_SAW_NMEA;
break;
flags = 0;
rc = 0;
gps_state_.dropped_fix += 1;
break;
}
goto accept;
rc = 0;
flags = 0;
break;
}
default:
accept:
gps_state_.msg = msg;
gps_state_.msg_len = len;
gps_state_.rx_utt = rx_utt;
break;
}
} else {
++gps_state_.app_lost_pkts;
gps_state_.lost_octets += len;
}
if ((NULL != msg) && (gps_state_.msg != msg)) {
}
gps_state_.flags |= flags;
return rc;
}
static int
gps_pps_cb (unsigned long pps_tck)
{
gps_state_.flags |= GPS_STATE_1PPS;
gps_state_.pps_tt = pps_tck;
return 0;
}
static int
gps_tx_complete (const uint8_t * msg,
int rc)
{
gps_state_.flags |= GPS_STATE_TX_DONE;
gps_state_.tx_rc = rc;
}
void main ()
{
int rc;
size_t tx_length;
const uint8_t * msg_to_release;
unsigned int num_sync = 0;
time_t sync_utc = 0;
unsigned long sync_utt = 0;
unsigned long min_lag = 0;
unsigned long max_lag = 0;
unsigned long utt_per_sec;
cprintf(
"\n\nrtc " __DATE__
" " __TIME__
"\n");
cprintf(
"Uptime clock uses %lu Hz\n", utt_per_sec);
{
int rv;
memset(&config, 0, sizeof(config));
config.
pps_port = APP_PPS_PORT_PERIPH_HANDLE;
cprintf(
"Connect NMEA serial data at %lu baud to %s at:\n\t%s\n",
cprintf(
"Connect 1PPS to %s.%u on %s.%u\n",
}
{
memset(mp, 0, sizeof(*mp));
tx_length = sizeof(*mp);
cprintf(
"Queued SW version query\n");
}
memset((void*)&gps_state_, 0, sizeof(gps_state_));
gps_state_.keep_fix = 2;
gps_state_.last_fix = -1;
sync_utc = 0;
msg_to_release = NULL;
while (1) {
sAppGPSState state;
unsigned long now_utt;
do {
if (NULL != msg_to_release) {
msg_to_release = NULL;
}
if (0 < tx_length) {
if (0 == rc) {
tx_length = 0;
}
}
state = gps_state_;
gps_state_.flags = 0;
gps_state_.msg = NULL;
} while (0);
cprintf(
"%s: Wokeup with %x, lost %u octets in %u/d %u/a\n",
state.flags, state.lost_octets, state.driver_lost_pkts, state.app_lost_pkts);
if (NULL != state.msg) {
cprintf(
"\t%s [%u]: %s\n", timestamp, state.msg_len, state.msg);
break;
break;
cprintf(
"\t%s: SW version kernel %08lx odm %08lx rev %08lx\n",
timestamp,
break;
struct tm when_tm;
char cbuf[26];
uint16_t msec = (gps_csow % 100) * 10;
uint32_t gps_sow = gps_csow / 100;
time_t when_utc;
gmtime_r(&when_utc, &when_tm);
cprintf(
"\tfix %u GPS week %d sec %lu: %lu.%03u: %s",
np->
fix_mode, gps_week, gps_sow, when_utc, msec, ctime_r(&when_utc, cbuf));
sync_utc = 0;
}
if (state.flags & GPS_STATE_1PPS) {
unsigned long lag = state.rx_utt - state.pps_tt;
int show_lag = (0 == when_tm.tm_sec);
if ((0 == min_lag) || (lag < min_lag)) {
min_lag = lag;
show_lag = 1;
}
if (lag > max_lag) {
max_lag = lag;
show_lag = 1;
}
if (show_lag) {
}
if (((50 <= msec) && (msec <= 950))
cprintf(
"\tExcessive timestamp offset detected: %u ms\n", msec);
memset(mp, 0, sizeof(*mp));
mp->
mon = when_tm.tm_mon - 1;
mp->
mday = when_tm.tm_mday;
mp->
hour = when_tm.tm_hour;
mp->
min = when_tm.tm_min;
mp->
sec = when_tm.tm_sec;
tx_length = sizeof(*mp);
cprintf(
"** Queued restart command\n");
}
} else if (0 == sync_utc) {
++num_sync;
sync_utc = when_utc;
sync_utt = state.pps_tt;
cprintf(
"** First sync: %lu POSIX == %lu uptime\n", sync_utc, sync_utt);
} else {
unsigned int sync_duration_s = (when_utc - sync_utc);
unsigned long sync_duration_utt = sync_duration_s * utt_per_sec;
unsigned long expected_utt = sync_utt + sync_duration_utt;
long drift_utt = (long)state.pps_tt - (long)expected_utt;
cprintf(
"\tUTT-to-UTC offset %ld after %u s; UTT ", drift_utt, sync_duration_s);
if (0 > drift_utt) {
drift_utt = -drift_utt;
} else {
}
if ((1 == num_sync) && (90 == sync_duration_s)) {
++num_sync;
sync_utc = when_utc;
sync_utt = state.pps_tt;
}
}
}
break;
}
default:
break;
}
msg_to_release = state.msg;
}
if (state.flags & GPS_STATE_1PPS) {
#if 0
cprintf(
"\t1PPS at %lu\n", state.pps_tt);
#endif
}
if (state.flags & GPS_STATE_TX_DONE) {
cprintf(
"\tTX completed %d\n", state.tx_rc);
}
if ((state.flags & GPS_STATE_SAW_NMEA) && (0 == tx_message.
generic.
mid)) {
memset(mp, 0, sizeof(*mp));
tx_length = sizeof(*mp);
cprintf(
"Queued format=binary command\n");
}
}
}