diff --git a/hc_clock.c b/hc_clock.c index 583fe24..d66631f 100644 --- a/hc_clock.c +++ b/hc_clock.c @@ -63,6 +63,7 @@ static int clockShowDrift = 0; static int clockSynchronized = 0; +static hc_clock_status *hc_clock_status_db = 0; static int *hc_clock_drift_db = 0; const char *hc_clock_help (int level) { @@ -98,6 +99,17 @@ void hc_clock_initialize (int argc, const char **argv) { } hc_clock_drift_db = (int *) hc_db_get (HC_CLOCK_DRIFT); for (i = 0; i < 120; ++i) hc_clock_drift_db[i] = 0; + + i = hc_db_new (HC_CLOCK_STATUS, sizeof(hc_clock_status), 1); + if (i != 0) { + fprintf (stderr, + "cannot create %s: %s\n", HC_CLOCK_STATUS, strerror(i)); + exit (1); + } + hc_clock_status_db = (hc_clock_status *)hc_db_get (HC_CLOCK_STATUS); + hc_clock_status_db->synchronized = 0; + hc_clock_status_db->precision = clockPrecision; + hc_clock_status_db->drift = 0; } void hc_clock_synchronize(const struct timeval *gps, @@ -109,6 +121,10 @@ void hc_clock_synchronize(const struct timeval *gps, time_t absdrift = (drift < 0)? (0 - drift) : drift; if (hc_clock_drift_db) hc_clock_drift_db[local->tv_sec%120] = (int)drift; + if (hc_clock_status_db) { + hc_clock_status_db->drift = (int)drift; + hc_clock_status_db->timestamp = *local; + } if (clockShowDrift || hc_test_mode()) { printf ("[%d]=%8.3f\n", local->tv_sec%120, drift/1000.0); @@ -117,6 +133,7 @@ void hc_clock_synchronize(const struct timeval *gps, if (absdrift < clockPrecision) { clockSynchronized = 1; + if (hc_clock_status_db) hc_clock_status_db->synchronized = 1; return; } diff --git a/hc_clock.h b/hc_clock.h index d98b20c..3eac174 100644 --- a/hc_clock.h +++ b/hc_clock.h @@ -31,3 +31,12 @@ int hc_clock_synchronized (void); */ #define HC_CLOCK_DRIFT "ClockDrift" +#define HC_CLOCK_STATUS "ClockStatus" + +typedef struct { + int synchronized; + int precision; + int drift; + struct timeval timestamp; +} hc_clock_status; + diff --git a/hc_http.c b/hc_http.c index 8039cfc..bfcfe7a 100644 --- a/hc_http.c +++ b/hc_http.c @@ -46,27 +46,28 @@ static pid_t parent; +static char JsonBuffer[8192]; + static void hc_background (int fd, int mode) { if (kill (parent, 0) < 0) exit(0); } +static void *hc_http_attach (const char *name) { + void *p = hc_db_get (name); + if (p == 0) echttp_error (503, "Service Temporarily Unavailable"); + return p; +} + static const char *hc_http_status (const char *method, const char *uri, const char *data, int length) { - static char buffer[8192]; - static char *driftbuffer; - static int driftbuffersize; - static hc_nmea_status *status_db = 0; - static int *drift_db = 0; - static int drift_count; + static hc_nmea_status *nmea_db = 0; + static hc_clock_status *clock_db = 0; char latitude[20]; char longitude[20]; - if (status_db == 0) { - status_db = (hc_nmea_status *) hc_db_get (HC_NMEA_STATUS); - if (status_db == 0) { - echttp_error (503, "Service Temporarily Unavailable"); - return ""; - } + if (nmea_db == 0) { + nmea_db = (hc_nmea_status *) hc_http_attach (HC_NMEA_STATUS); + if (nmea_db == 0) return ""; if (hc_db_get_count (HC_NMEA_STATUS) != 1 || hc_db_get_size (HC_NMEA_STATUS) != sizeof(hc_nmea_status)) { fprintf (stderr, "wrong data structure for table %s\n", @@ -75,58 +76,78 @@ static const char *hc_http_status (const char *method, const char *uri, } } - if (drift_db == 0) { - drift_db = (int *) hc_db_get (HC_CLOCK_DRIFT); - if (drift_db == 0) { - echttp_error (503, "Service Temporarily Unavailable"); - return ""; - } - drift_count = hc_db_get_count (HC_CLOCK_DRIFT); - if (hc_db_get_size (HC_CLOCK_DRIFT) != sizeof(int)) { + if (clock_db == 0) { + clock_db = (hc_clock_status *) hc_http_attach (HC_CLOCK_STATUS); + if (clock_db == 0) return ""; + if (hc_db_get_count (HC_CLOCK_STATUS) != 1 + || hc_db_get_size (HC_CLOCK_STATUS) != sizeof(hc_clock_status)) { fprintf (stderr, "wrong data structure for table %s\n", - HC_CLOCK_DRIFT); + HC_CLOCK_STATUS); exit (1); } - driftbuffersize = drift_count * 12; - driftbuffer = malloc(driftbuffersize); - } - - snprintf (driftbuffer, driftbuffersize, "%d", drift_db[0]); - int room = driftbuffersize - strlen(driftbuffer); - char *p = driftbuffer + (driftbuffersize-room); - int i; - for (i = 1; i < drift_count; ++i) { - snprintf (p, room, ",%d", drift_db[i]); - room -= strlen(p); - p = driftbuffer + (driftbuffersize-room); } // This conversion is not made when decoding the NMEA stream to avoid // consuming CPU in the high-priority time synchronization process. // hc_nmea_convert (latitude, sizeof(latitude), - status_db->latitude, status_db->hemisphere[0]); + nmea_db->latitude, nmea_db->hemisphere[0]); hc_nmea_convert (longitude, sizeof(longitude), - status_db->longitude, status_db->hemisphere[1]); + nmea_db->longitude, nmea_db->hemisphere[1]); - snprintf (buffer, sizeof(buffer), + snprintf (JsonBuffer, sizeof(JsonBuffer), "{\"gps\":{\"fix\":%s" ",\"time\":[%c%c,%c%c,%c%c],\"date\":[%d,%c%c,%c%c]" - ",\"latitude\":%s,\"longitude\":%s,\"timestamp\":%zd.%03d}" - ",\"clock\":{\"drift\":[%s]}}", - status_db->fix?"true":"false", - status_db->time[0], status_db->time[1], - status_db->time[2], status_db->time[3], - status_db->time[4], status_db->time[5], - 2000 + (status_db->date[4]-'0')*10 + (status_db->date[5]-'0'), - status_db->date[2], status_db->date[3], - status_db->date[0], status_db->date[1], + ",\"latitude\":%s,\"longitude\":%s}" + ",\"clock\":{\"synchronized\":%s" + ",\"precision\":%d,\"drift\":%d,\"timestamp\":%zd.%03d}}", + nmea_db->fix?"true":"false", + nmea_db->time[0], nmea_db->time[1], + nmea_db->time[2], nmea_db->time[3], + nmea_db->time[4], nmea_db->time[5], + 2000 + (nmea_db->date[4]-'0')*10 + (nmea_db->date[5]-'0'), + nmea_db->date[2], nmea_db->date[3], + nmea_db->date[0], nmea_db->date[1], latitude, longitude, - (size_t) (status_db->timestamp.tv_sec), - status_db->timestamp.tv_usec/1000, - driftbuffer); + clock_db->synchronized?"true":"false", + clock_db->precision, + clock_db->drift, + (size_t) (clock_db->timestamp.tv_sec), + clock_db->timestamp.tv_usec/1000); + echttp_content_type_json(); + return JsonBuffer; +} + +static const char *hc_http_clockdrift (const char *method, const char *uri, + const char *data, int length) { + static int *drift_db = 0; + static int drift_count; + + if (drift_db == 0) { + drift_db = (int *) hc_http_attach (HC_CLOCK_DRIFT); + if (drift_db == 0) return ""; + drift_count = hc_db_get_count (HC_CLOCK_DRIFT); + if (hc_db_get_size (HC_CLOCK_DRIFT) != sizeof(int)) { + fprintf (stderr, "wrong data structure for table %s\n", + HC_CLOCK_DRIFT); + exit (1); + } + } + + snprintf (JsonBuffer, sizeof(JsonBuffer), + "{\"clock\":{\"drift\":[%d", drift_db[0]); + + int room = sizeof(JsonBuffer) - strlen(JsonBuffer); + char *p = JsonBuffer + (sizeof(JsonBuffer)-room); + int i; + for (i = 1; i < drift_count; ++i) { + snprintf (p, room, ",%d", drift_db[i]); + room -= strlen(p); + p = JsonBuffer + (sizeof(JsonBuffer)-room); + } + snprintf (p, room, "%s", "]}}"); echttp_content_type_json(); - return buffer; + return JsonBuffer; } void hc_http (int argc, const char **argv) { @@ -134,6 +155,7 @@ void hc_http (int argc, const char **argv) { if (echttp_open (argc, argv) <= 0) exit(1); echttp_route_uri ("/status", hc_http_status); + echttp_route_uri ("/clock/drift", hc_http_clockdrift); echttp_static_route ("/ui", "/usr/local/lib/houseclock/public"); echttp_background (&hc_background); echttp_loop();