Przeglądaj źródła

gps minder

* defines for GPS
* cosmetic code changes
clementinecomputing 6 lat temu
rodzic
commit
2104f5c679

+ 0 - 12
busunit/DIUv2/diu_main.c

@@ -1057,17 +1057,8 @@ int main(int argc, char **argv) {
   // setup mongoose web server
   //
 
-  //struct mg_mgr mgr;
   struct mg_connection *nc;
 
-  /*
-  mg_mgr_init(&mgr, NULL);
-  nc = mg_bind(&mgr, s_http_port, ev_handler);
-  if (!nc) {
-    printf("failed to create listener\n");
-    return 1;
-  }
-  */
   mg_mgr_init(&g_mgr, NULL);
   nc = mg_bind(&g_mgr, s_http_port, ev_handler);
   if (!nc) {
@@ -1137,9 +1128,6 @@ int main(int argc, char **argv) {
 
     RESET_WATCHDOG();
 
-    // service our UI updates
-    //mg_mgr_poll(&mgr, POLL_TIMEOUT);
-
     maintain_ipc_hub_connect(argv[0]);
 
     if(diu_fd < 0) {

+ 27 - 26
busunit/common/common_config.h

@@ -340,29 +340,25 @@
 #define TUNNEL_DROPFILE    "/tmp/tunnel-is-up"
 #define GPRS_DROPFILE    "/tmp/network-is-up"
 
-//Serial port mapping
+// Serial port mapping
+//
 #ifdef TARGET_DEVEL_DESKTOP
-    //TARGET_DEVEL_DESKTOP is an x86 Linux box w/ a multiport serial board
-    //#define CONSOLE_PORT  "/dev/tty81a"
-    //#define DRIVER_UI_PORT  "/dev/tty81b"
-    //#define PASSENGER_UI_PORT  "/dev/tty81c"
-    //#define MODEM_PORT    "/dev/tty81d"
-
-    #define CONSOLE_PORT  "/dev/ttyCONSOLE"
-    //#define DRIVER_UI_PORT  "/dev/ttyDIU"
-    #define DRIVER_UI_PORT  "/tmp/ttyDIU"
-    #define PASSENGER_UI_PORT  "/dev/ttyPIU"
-    #define MODEM_PORT    "/dev/ttyGPRS"
-
+  #define CONSOLE_PORT  "/dev/ttyCONSOLE"
+  #define DRIVER_UI_PORT  "/tmp/ttyDIU"
+  #define PASSENGER_UI_PORT  "/dev/ttyPIU"
+  #define MODEM_PORT    "/dev/ttyGPRS"
+  #define GPS_PORT "/dev/ttyGPS"
 #else
-    //The real target is an ARM Linux box with real serial ports at the expected locations
-    #define CONSOLE_PORT  "/dev/ttyS0"
-    #define DRIVER_UI_PORT  "/dev/ttyS1"
-    #define PASSENGER_UI_PORT  "/dev/ttyS2"
-    #define MODEM_PORT    "/dev/ttyS3"
+  // Legacy
+  //
+  #define CONSOLE_PORT  "/dev/ttyS0"
+  #define DRIVER_UI_PORT  "/dev/ttyS1"
+  #define PASSENGER_UI_PORT  "/dev/ttyS2"
+  #define MODEM_PORT    "/dev/ttyS3"
 #endif
 
-//Network protocol ports
+// Network protocol ports
+//
 #define PASS_SERVER_IP    "127.0.0.1"
 #define PASS_SERVER_PORT  (7277)
 
@@ -375,7 +371,8 @@
 #define HELLO_SERVER_IP    "127.0.0.1"
 #define HELLO_SERVER_PORT  (3556)
 
-//Framebuffer location:
+// Framebuffer location: (legacy)
+//
 #define CONFIG_FRAMEBUFFER_PATH  "/dev/fb0"
 
 //----------------------------------------------------------------
@@ -383,19 +380,23 @@
 //----------------------------------------------------------------
 
 //  This is the size of the buffer used to read lines from sockets and serial ports.
-//reads longer than this will either be truncated, or trigger an exit-with-error
-//Any sadistic bastard who writes config file lines longer than 1KB (that would be 
-//half a screen-full to the character on a standard 80x25 text screen!) deserves some
-//rude truncation.
+// reads longer than this will either be truncated, or trigger an exit-with-error
+// Any sadistic bastard who writes config file lines longer than 1KB (that would be 
+// half a screen-full to the character on a standard 80x25 text screen!) deserves some
+// rude truncation.
+//
 #define LINE_BUFFER_SIZE  (1024)
 
-//This is the hardware page size for the mmap()'d data files:
+// This is the hardware page size for the mmap()'d data files:
+//
 #define  MEMORY_PAGE_SIZE  (4096)    
 
-//This is the maximum size of a command line that can be assembled by the driver UI menu system using the <shellcall/> action.
+// This is the maximum size of a command line that can be assembled by the driver UI menu system using the <shellcall/> action.
+//
 #define SHELLCALL_BUFFER_SIZE  (2048)
 
 //This defines the expected size of the pass database and its RAM based index tables:
+//
 
 #define NUM_STORED_PASSES  (131072)  //A nice round number that multiplies by sizeof(rider_record) to a page boundary
 #define STORED_PASS_HASH  (131101)  //A prime number larger than NUM_STORED_PASSES

+ 1 - 0
busunit/common/common_defs.h

@@ -178,6 +178,7 @@ int open_rs232_device(char *devname, int custom_baud, int linemode);
 //Defines for the above
 
 #define USE_DEFAULT_BAUD	(0)
+#define GPS_DEFAULT_BAUD (9600)
 
 #define RS232_RAW		(0)
 #define RS232_LINE		(1)

+ 9 - 0
busunit/gps/buildit.sh

@@ -0,0 +1,9 @@
+#!/bin/sh
+
+expat_dir="./expat-2.0.1/"
+
+common_stuff="../commhub/commhub.c ../commhub/client_utils.c ../common/common_defs.c"
+
+rm -f gps_minder
+$target_cc $target_ccopts -o gps_minder gps_main.c mkgmtime.c $common_stuff
+

+ 690 - 0
busunit/gps/gps_main.c

@@ -0,0 +1,690 @@
+/*
+ * Copyright (c) 2019 Clementine Computing LLC.
+ *
+ * This file is part of PopuFare.
+ *
+ * PopuFare is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * PopuFare is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with PopuFare.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <sys/time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <poll.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+
+#include <ctype.h>
+#include <string.h>
+
+#include "../common/common_defs.h"
+#include "../commhub/commhub.h"
+#include "../commhub/client_utils.h"
+
+int gps_fd = -1;
+int hub_fd = -1;
+
+time_t last_hub_try = 0;
+time_t last_diu_clock = 0;
+
+gps_status my_gps_stat={0};
+
+time_t mkgmtime(struct tm *tm);
+
+//    This function takes a GPS timestamp (in gross GPS float format + gross integer date) and
+// makes it into a sane UTC timestamp.  If we are more than MAX_GPS_CLOCK_DRIFT seconds off
+// from GPS time, it sets the system clock to GPS time.
+//
+int handle_gps_time(float gtime, int date) {   
+  int day,month,year;
+  int hour,min,sec,frac;
+  int n = 0;
+  time_t utc,now;
+
+  char buffer[32] = {0};
+
+  struct message_record outgoing_msg;
+
+  now = time(NULL);
+
+  day = month = year = 0; 
+  hour = min = sec = frac = 0;
+
+     
+  //  Just to be *ahem* clear, as per NMEA standard the date is encoded DDMMYY, and the time of day
+  // is encoded HHMMSS[.frac] where there is an optional fractional second field denoted by a decimal point.
+  // we must be able to decode the fractional seconds field but we discard the information since it is not
+  // reliable enough to be worth the bother.
+  //
+
+
+  // Start out with zero parsed fields
+  //
+  n = 0;
+     
+  //  Construct and then re-parse the time from its icky format to discrete values (this should result
+  // in at least three (possibly four) fields.
+  //
+  sprintf(buffer,"%010.3f", gtime);
+  n += sscanf(buffer,"%02d%02d%02d.%d", &hour, &min, &sec, &frac);
+
+  // Construct and then re-parse the date from its icky format to discrete values.  This should result in three fields.
+  //
+  sprintf(buffer,"%06d", date);
+  n += sscanf(buffer,"%02d%02d%02d", &day, &month, &year);
+
+  if(n >= 6)  //if we scanned at all required fields
+  {   
+    struct tm gpstm = {0};
+
+    // GPS date only uses two digits for year, so we must assume the century
+    //
+    year += GPS_DATE_CENTURY;
+
+    // tm.tm_year is based on the year 1900
+    //
+    gpstm.tm_year = year - 1900;
+
+    // January = month 0 in struct tm.tm_mon whereas January = month 1 in an NMEA GPS date.
+    //
+    gpstm.tm_mon = month - 1;
+    gpstm.tm_mday = day;
+    gpstm.tm_hour = hour;
+    gpstm.tm_min = min;
+    gpstm.tm_sec = sec;
+
+    // Go and turn the struct tm we've just populated into an utc time stamp (seconds since epoch)
+    //
+    utc = mkgmtime(&gpstm);
+
+    // Most importantly... Remember what the self-reported GPS time stamp is.
+    //
+    my_gps_stat.gpstime = utc;
+
+//    printf("%02d-%02d-%04d %02d:%02d:%02d\n",day,month,year,hour,min,sec);
+//    printf("CALCULATED: %d\nSYSTEM  : %d\n\n",(int)utc,(int)time(NULL));
+
+    // if we have more than MAX_GPS_CLOCK_DRIFT seconds of clock drift
+    //
+    if(abs(utc - now) > MAX_GPS_CLOCK_DRIFT) {   
+      struct timeval ts = {0};
+
+      // Set the timeval struct to the calculated utc timestamp from the GPS unit.
+      //
+      ts.tv_sec = utc;
+      ts.tv_usec = 0;
+
+      // Set the system clock from GPS time using said timeval struct.
+      //
+      settimeofday(&ts, NULL);
+
+      //system("/sbin/hwclock --systohc");  //Go and push the new system clock value into the hardware realtime clock chip.
+
+      // If we have a valid connection to the IPC hub
+      //
+      if( hub_fd >= 0) {   
+
+        // Stick a message into the diagnostic log to record the fact that we've set the system clock from GPS
+        //
+        format_log_message(&outgoing_msg, LOGLEVEL_DEBUG, "Set syatem clock from previous value (%d) to GPS time (%d).", (int)now, (int)utc );
+        send_message(hub_fd, &outgoing_msg);
+      }
+    }
+  }
+
+  return 0;
+}
+
+
+#ifdef CLEAR_GPS_ON_STALE
+static inline void clear_stale_gps_data() {   
+  my_gps_stat.lat = my_gps_stat.lon = my_gps_stat.heading = my_gps_stat.velocity = 0;
+  my_gps_stat.num_sats = 0;
+}
+#else
+static inline void clear_stale_gps_data() { }
+#endif
+
+static int handle_stale_gps_condition() {
+  //   This return code will be > 0 if this function generates a status change that
+  // will then need to be communicated to other modules in the system via a message to
+  // MAILBOX_GPS_STATUS.
+  //
+  int return_code = 0;
+     
+  //   This will hold the gps_good flag as it stood at the beginning of this subroutine
+  // previous to any adjustments we make.
+  //
+  int previous_good_flag = my_gps_stat.gps_good;
+
+  int stale_time = 0;
+
+  time_t now = time(NULL);
+
+  stale_time = (now - my_gps_stat.stamp);
+
+  // If we have entered this function with the impression that we have a valid GPS fix...
+  //
+  if(previous_good_flag > 0) {   
+
+    // If it has been at least GPS_STALE_THRESHOLD seconds since the last fix
+    //
+    if( stale_time >= GPS_STALE_THRESHOLD ) {   
+      clear_stale_gps_data();
+      my_gps_stat.gps_good = 0;
+      return_code |= 1;
+    }
+
+  }
+     
+  //   If we have determined that we need to declare the GPS data stale and invalid and
+  // we have a valid connection to the IPC hub we should use that IPC hub connection to
+  // add a note to the diagnostic log indicating that we've declared the GPS data stale.
+  //
+  if( return_code && (hub_fd >= 0) ) {   
+    struct message_record outgoing_msg;
+
+    format_log_message(&outgoing_msg, LOGLEVEL_DEBUG, "GPS fix has been stale for %d seconds, setting GPS = NO.", stale_time);
+    send_message(hub_fd, &outgoing_msg);
+  }
+
+  return return_code;
+}
+
+int update_gps(char *in) {
+  // This will hold the number of matched variables populated by sscanf().
+  //
+  int num = 0;
+
+  //   This will allow us to know if we have made a transition from an invalid
+  // GPS fix to a valid one so that we can log this information.
+  //
+  int previous_good_flag = my_gps_stat.gps_good;
+
+  //   This return code will be > 0 if this function generates a status change that
+  // will then need to be communicated to other modules in the system via a message to
+  // MAILBOX_GPS_STATUS.
+  //
+  int return_code = 0;
+
+
+  if(!strncmp(in,"$GPRMC",6)) {   
+    float f1=0;
+    char f2=0;
+    float f3=0;
+    char f4=0;
+    float f5=0;
+    char f6=0;
+    float f7=0;
+    float f8=0;
+    int f9=0; 
+    float f10=0;
+    char f11=0;
+
+    //DEBUG
+    printf(">> gprmc\n");
+
+    num = sscanf(in,"$GPRMC,%f,%c,%f,%c,%f,%c,%f,%f,%d,%f,%c",&f1,&f2,&f3,&f4,&f5,&f6,&f7,&f8,&f9,&f10,&f11);
+
+    // If we have a full GPRMC sentence we can consider setting the time
+    //
+    if(num == 11) {
+
+      //   Require at least MIN_SATS_FOR_TIME satellites to accept a new system clock value from the GPS unit.
+      // This is to keep a crummy GPS fix from generating a bogus or unstable system time.
+      //
+  
+      if(my_gps_stat.num_sats >= MIN_SATS_FOR_TIME) {
+
+        //   Pass the time field (f1) and the date field (f9) in to the routine that sets the system clock if needed.
+        // (this routine also stores the utc timestamp derived from the GPS date and time fields so it can be passed to
+        // other modules that may have a need for this information).
+        //
+        handle_gps_time(f1,f9);
+
+      }
+    }
+
+    if(num > 0) {
+      // update snapshot with latitude
+      //
+      my_gps_stat.lat = f3 * ((f4 == 'N')?(1):(-1));
+  
+      // longitude
+      //
+      my_gps_stat.lon = f5 * ((f6 == 'E')?(1):(-1));
+
+      // meters per second (converted from knots)
+      //
+      my_gps_stat.velocity = f7 / 1.94384449f;
+
+      // course
+      //
+      my_gps_stat.heading = f8;
+
+      // update snapshot's staledate
+      //
+      my_gps_stat.stamp = time(NULL);
+      
+      return_code |= 1;
+    }
+  }
+  else if(!strncmp(in,"$GPGGA",6)) {   
+    int f1=0;
+    float f2=0;
+    char f3=0;
+    float f4=0;
+    char f5=0;
+    int f6=0;
+    int f7=0;
+    float f8=0;
+    float f9=0;
+    char f10=0;
+    float f11=0;
+    char f12=0;
+
+    //DEBUG
+    printf(">> gpgga\n");
+
+
+
+    num=sscanf(in,"$GPGGA,%d,%f,%c,%f,%c,%d,%d,%f,%f,%c,%f,%c",&f1,&f2,&f3,&f4,&f5,&f6,&f7,&f8,&f9,&f10,&f11,&f12);
+
+    if(num == 12) {   
+
+      // require 3 satellites minimum
+      //
+      if ( f7 >= 3 ) {   
+
+        // store GPS valid flag in snapshot
+        //
+        my_gps_stat.gps_good = f6;
+
+        // store number of satellites in view in snapshot
+        //
+        my_gps_stat.num_sats = f7;
+
+
+           
+        //   Do NOT store the timestamp since we only want to remember timestamps of position
+        // fixes and the GPGGA message is all metadata (number of satellites, fix quality, etc...).
+        // It is worth noting that GPGGA does report altitude, but that is not a piece of information
+        // we track because the road is where the road is, and if a bus becomes airborn we have much
+        // bigger problems than figuring out how far off the ground it is...
+        //
+        return_code |= 1;
+      }
+    }
+
+  }
+
+  return_code |= handle_stale_gps_condition();
+
+  //   If we have a connection to the IPC hub and we had previously not had a valid
+  // GPS fix but we now do, make a note of it in the diagnostic log.
+  //
+  if( (previous_good_flag == 0) && (my_gps_stat.gps_good != 0) && (hub_fd >= 0) ) {   
+    struct message_record outgoing_msg;
+
+    format_log_message(&outgoing_msg, LOGLEVEL_DEBUG, "GPS fix is now valid with %d satellites. Setting GPS = YES.", my_gps_stat.num_sats);
+    send_message(hub_fd, &outgoing_msg);
+  }
+
+  return return_code;
+}
+
+
+
+void maintain_ipc_hub_connect(char *progname) {
+  struct message_record outgoing_msg;
+
+  // if we have no connection to the IPC hub
+  //
+  if(hub_fd < 0) {
+
+    // if we haven't tried the hub in a few seconds
+    //
+    if( (time(NULL) - last_hub_try) > HUB_RETRY_TIME ) {
+
+
+      // retry it
+      //
+      last_hub_try = time(NULL);
+
+      // try and get one
+      //
+      hub_fd = connect_to_message_server(progname);
+
+      if(hub_fd >= 0) {
+
+        //Subscribe to the default status messages
+        //
+        subscribe_to_default_messages(hub_fd);
+
+        // Ask for a status update
+        //
+        prepare_message(&outgoing_msg, MAILBOX_STATUS_REQUEST, "", 0);
+        send_message(hub_fd,&outgoing_msg);
+      }
+      else {
+        fprintf(stderr, "Cannot connect to IPC hub!\n");
+      }
+    }
+  }
+}
+
+
+
+//----------------------------------
+
+int main(int argc, char **argv) {
+  char line[LINE_BUFFER_SIZE] = {0};
+
+  struct message_record incoming_msg;
+  struct message_record outgoing_msg;
+
+  struct pollfd fds[2];
+  int nfd;
+
+  int poll_return;
+  int read_return;
+
+  int i;
+
+  time_t now;
+
+  //int retval = 0;
+
+  time_t last_stale_gps_check = 0;
+
+
+  // Configure our signal handlers to deal with SIGINT, SIGTERM, etc... 
+  // and make graceful exits while logging
+  //
+  configure_signal_handlers(argv[0]);
+
+  // Make an initial attempt to get in touch with the
+  // interprocess communication hub (it may not be up yet depending on the start order)
+  //
+  maintain_ipc_hub_connect(argv[0]);
+
+  // Register our defualt system message processing callbacks
+  //
+  register_system_status_callbacks();
+
+
+  // This is the main dispatch loop:
+  //
+  // * reset watchdog to make sure we haven't crashed/frozen
+  // * if need be, open a connection to the DIU microcontroller, quieting all messages except for acks
+  // * handle GPS message dispatch through IPC
+  // * if need be, handle reload of menu.xml
+  // * manage driver status message communication
+  // * handle paddle change
+  // * draw menu
+  // * listen on the mailboxes for messages and process. This includes
+  //   - touchscreen events
+  //   - gps updates
+  //   - warning/debug/error messages
+  //
+  while( exit_request_status == EXIT_REQUEST_NONE )  //loop until we get asked to exit...
+  {
+
+    //DEBUG
+    printf("[%lli] gps_minder: heartbeat\n", get_usec_time());
+    //DEBUG
+
+    RESET_WATCHDOG();
+
+    maintain_ipc_hub_connect(argv[0]);
+
+    if(gps_fd < 0) {
+      gps_fd = open_rs232_device(GPS_PORT, GPS_DEFAULT_BAUD, RS232_LINE);
+
+      if(gps_fd < 0) {
+        fprintf(stderr, "Cannot open serial port %s for GPS!\n", GPS_PORT);
+      }
+
+    }
+
+    //---
+
+    now = time(NULL);
+
+    // Every second we want to check to make sure that our GPS data have note gone stale...
+    //
+    if((now - last_stale_gps_check) > 0) {
+
+      //   If the stale check results in an update to my_gps_stat, we must update any other
+      // modules which may be tracking GPS status via the IPC hub.
+      //
+      if( handle_stale_gps_condition() > 0 ) {
+
+        // If we have a connection to the IPC hub
+        //
+        if(hub_fd >= 0) {
+
+          // Go and toss the data to any other modules who happen to care about GPS
+          //
+          prepare_message(&outgoing_msg, MAILBOX_GPS_STATUS, &my_gps_stat, sizeof(my_gps_stat));
+          send_message(hub_fd, &outgoing_msg);
+
+        }
+
+      }
+
+      // Either way, remember that we did this stale check.
+      //
+      last_stale_gps_check = now;
+    }
+
+    //---
+
+    if (hup_request_status) {
+      fprintf(stderr, "gps_minder: hup request\n");
+      hup_request_status = 0;
+    }
+
+    //---
+
+    nfd = 0;
+
+    if(hub_fd >= 0)
+    {
+      fds[nfd].fd = hub_fd;
+      fds[nfd].events = POLLIN;
+      fds[nfd].revents = 0;
+      nfd++;
+    }
+
+    if(gps_fd >= 0)
+    {
+      fds[nfd].fd = gps_fd;
+      fds[nfd].events = POLLIN;
+      fds[nfd].revents = 0;
+      nfd++;
+    }
+
+    // if we have any file descriptors, poll them
+    //
+    if(nfd > 0) {
+      poll_return = poll(fds, nfd, POLL_TIMEOUT);
+    }
+
+    // otherwise, whistle and look busy
+    //
+    else {
+      poll_return = 0;  //(this keeps us from buringing 100% cpu cycles if we don't have contact with either
+      sleep(1);    //the IPC hub or the DIU hardware).
+    }
+
+    //--------------------------------------------------------------------------------------------------
+
+    // if poll didn't net us any work to do,
+    //
+    if(poll_return < 1) {
+      // lets try again
+      //
+      continue;
+    }
+
+    // Loop through all polled file descriptors
+    //
+    for(i = 0; i < nfd; i++) {
+
+      // If we're looking at the DIU...
+      //
+      if( fds[i].fd == gps_fd ) {
+
+        // if poll says our serial port has become bogus...
+        //
+        if(fds[i].revents & (POLLHUP | POLLERR | POLLNVAL)) {
+          fprintf(stderr, "This is very odd... Poll returned flags %d on our serial port...\n", fds[i].revents);
+
+          // close it, flag as invalid, 
+          // and break out of the for loop to allow the while to cycle
+          //
+          close(gps_fd);
+          gps_fd = -1;
+          break;    
+        }
+
+        if(fds[i].revents & POLLIN) {
+          read_return = read(fds[i].fd, line, sizeof(line));
+
+          if(read_return > 0) {
+            char *trav = line;
+
+            line[read_return] = '\0';
+            strip_crlf(line);
+
+            // advance until EOL or we hit our start sentinel
+            //
+            while(*trav && (*trav != '$') ) {
+              trav++;
+            }
+
+            // Check to see that our address header is intact...
+            //
+            if (trav[0] == '$') {
+              switch(trav[1]) {
+
+                case 'G':  //-----------------------------------"/G:" means it is a new GPS input
+
+                  // If this GPS update constitutes a meaningful piece of data
+                  //
+                  if(update_gps(trav) > 0) {
+
+                    //and we have a connection to the IPC hub
+                    //
+                    if(hub_fd >= 0) {
+
+                      // Go and toss the data to any other modules who happen to care about GPS
+                      //
+                      prepare_message(&outgoing_msg, MAILBOX_GPS_STATUS, &my_gps_stat, sizeof(my_gps_stat));
+                      send_message(hub_fd, &outgoing_msg);
+
+                    }
+
+                    // Remember that we did a stale GPS check as part of our update.
+                    //
+                    last_stale_gps_check = now;
+                  }
+                  break;
+
+                // ignore any message addresses that we don't know what to do with
+                //
+                default:
+                  printf("Ignoring command \"%s\"\n", trav);
+                  break;
+              }
+            }
+            else { }
+          }
+          else {
+
+            fprintf(stderr, "Read from %s returned %d!\n", DRIVER_UI_PORT, read_return);
+
+            // close it, flag it invalid and break out of the
+            // for loop to allow for the while to cycle.
+            //
+            close(gps_fd);
+            gps_fd = -1;
+            break;
+
+          }
+        }
+
+      }
+
+      // If we're looking at the IPC hub...
+      //
+      else if( fds[i].fd == hub_fd ) {
+
+        // if poll says our connection to the IPC hub has died...
+        //
+        if(fds[i].revents & (POLLHUP | POLLERR | POLLNVAL)) {
+          fprintf(stderr, "The connection to the IPC hub has gone away...\n");  //complain
+
+          // close it, flag it invalid and break out of the
+          // for loop to allow for the while to cycle.
+          //
+          close(hub_fd);
+          hub_fd = -1;
+          break;
+        }
+
+        // if we have mail in any of our mailboxes...
+        //
+        if(fds[i].revents & POLLIN) {
+
+          read_return = get_message(hub_fd, &incoming_msg);
+
+          if(read_return < 0) {
+            fprintf(stderr, "The connection to the IPC hub has gone away...\n");  //complain
+
+            // close it, flag it invalid and break out of the
+            // for loop to allow for the while to cycle.
+            //
+            close(hub_fd);
+            hub_fd = -1;
+            break;
+          }
+          else {
+            message_callback_return msg_status;
+            msg_status = process_message(&incoming_msg);
+            if (msg_status) { }
+          }
+
+        }
+
+      }
+    }
+  }
+
+
+  if(hub_fd >= 0) {
+    close(hub_fd);
+  }
+
+  if(gps_fd >= 0) {
+    close(gps_fd);
+  }
+
+  return 0;
+}
+

+ 192 - 0
busunit/gps/mkgmtime.c

@@ -0,0 +1,192 @@
+/*this guts of this file come from the following source*/
+/*standing on the shoulders of giants and all*/
+/*I have stripped it down to minimize gross namespace collisions and*/
+/*reduce complexity as I only really need the mkgmtime function*/
+
+
+/* free mktime function
+   Copyright 1988, 1989 by David MacKenzie <djm@ai.mit.edu>
+   and Michael Haertel <mike@ai.mit.edu>
+   Unlimited distribution permitted provided this copyright notice is
+   retained and any functional modifications are prominently identified.  */
+
+/* Revised 1997 by Christian Spieler:
+   The code was changed to get more conformance with ANSI's (resp. modern
+   UNIX releases) definition for mktime():
+   - Added adjustment for out-of-range values in the fields of struct tm.
+   - Added iterations to get the correct UTC result for input values at
+     the gaps when daylight saving time is switched on or off.
+   - Allow forcing of DST "on" or DST "off" by setting `tm_isdst' field in
+     the tm struct to positive number resp. zero. The `tm_isdst' field must
+     be negative on entrance of mktime() to enable automatic determination
+     if DST is in effect for the requested local time.
+   - Added optional check for overflowing the time_t range.  */
+
+/* Note: This version of mktime is ignorant of the tzfile.
+   When the tm structure passed to mktime represents a local time that
+   is valid both as DST time and as standard time (= time value in the
+   gap when switching from DST back to standard time), the behaviour
+   for `tm_isdst < 0' depends on the current timezone: TZ east of GMT
+   assumes winter time, TZ west of GMT assumes summer time.
+   Although mktime() (resp. mkgmtime()) tries to adjust for invalid values
+   of struct tm members, this may fail for input values that are far away
+   from the valid ranges. The adjustment process does not check for overflows
+   or wrap arounds in the struct tm components.  */
+
+#include <time.h>
+#include <stdio.h>
+
+#ifndef NO_TIME_T_MAX
+   /* Provide default values for the upper limit of the time_t range.
+      These are the result of the decomposition into a `struct tm' for
+      the time value 0xFFFFFFFEL ( = (time_t)-2 ).
+      Note: `(time_t)-1' is reserved for "invalid time"!  */
+#  ifndef TM_YEAR_MAX
+#    define TM_YEAR_MAX         2106
+#  endif
+#  ifndef TM_MON_MAX
+#    define TM_MON_MAX          1       /* February */
+#  endif
+#  ifndef TM_MDAY_MAX
+#    define TM_MDAY_MAX         7
+#  endif
+#  ifndef TM_HOUR_MAX
+#    define TM_HOUR_MAX         6
+#  endif
+#  ifndef TM_MIN_MAX
+#    define TM_MIN_MAX          28
+#  endif
+#  ifndef TM_SEC_MAX
+#    define TM_SEC_MAX          14
+#  endif
+#endif /* NO_TIME_T_MAX */
+
+/* Adjusts out-of-range values for `tm' field `tm_member'. */
+#define ADJUST_TM(tm_member, tm_carry, modulus) \
+  if ((tm_member) < 0) { \
+    tm_carry -= (1 - ((tm_member)+1) / (modulus)); \
+    tm_member = (modulus-1) + (((tm_member)+1) % (modulus)); \
+  } else if ((tm_member) >= (modulus)) { \
+    tm_carry += (tm_member) / (modulus); \
+    tm_member = (tm_member) % (modulus); \
+  }
+
+/* Nonzero if `y' is a leap year, else zero. */
+#define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
+
+/* Number of leap years from 1970 to `y' (not including `y' itself). */
+#define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
+
+/* Additional leapday in February of leap years. */
+#define leapday(m, y) ((m) == 1 && leap (y))
+
+/* Length of month `m' (0 .. 11) */
+#define monthlen(m, y) (ydays[(m)+1] - ydays[m] + leapday (m, y))
+
+/* Accumulated number of days from 01-Jan up to start of current month. */
+static const short ydays[] =
+{
+  0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
+};
+
+/* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT
+   of the Greenwich Mean time and date in the exploded time structure `tm'.
+   This function does always put back normalized values into the `tm' struct,
+   parameter, including the calculated numbers for `tm->tm_yday',
+   `tm->tm_wday', and `tm->tm_isdst'.
+   Returns -1 if the time in the `tm' parameter cannot be represented
+   as valid `time_t' number. */
+
+time_t mkgmtime(struct tm *tm)
+{
+  int years, months, days, hours, minutes, seconds;
+
+  years = tm->tm_year + 1900;   /* year - 1900 -> year */
+  months = tm->tm_mon;          /* 0..11 */
+  days = tm->tm_mday - 1;       /* 1..31 -> 0..30 */
+  hours = tm->tm_hour;          /* 0..23 */
+  minutes = tm->tm_min;         /* 0..59 */
+  seconds = tm->tm_sec;         /* 0..61 in ANSI C. */
+
+  ADJUST_TM(seconds, minutes, 60)
+  ADJUST_TM(minutes, hours, 60)
+  ADJUST_TM(hours, days, 24)
+  ADJUST_TM(months, years, 12)
+  if (days < 0)
+    do {
+      if (--months < 0) {
+        --years;
+        months = 11;
+      }
+      days += monthlen(months, years);
+    } while (days < 0);
+  else
+    while (days >= monthlen(months, years)) {
+      days -= monthlen(months, years);
+      if (++months >= 12) {
+        ++years;
+        months = 0;
+      }
+    }
+
+  /* Restore adjusted values in tm structure */
+  tm->tm_year = years - 1900;
+  tm->tm_mon = months;
+  tm->tm_mday = days + 1;
+  tm->tm_hour = hours;
+  tm->tm_min = minutes;
+  tm->tm_sec = seconds;
+
+  /* Set `days' to the number of days into the year. */
+  days += ydays[months] + (months > 1 && leap (years));
+  tm->tm_yday = days;
+
+  /* Now calculate `days' to the number of days since Jan 1, 1970. */
+  days = (unsigned)days + 365 * (unsigned)(years - 1970) +
+         (unsigned)(nleap (years));
+  tm->tm_wday = ((unsigned)days + 4) % 7; /* Jan 1, 1970 was Thursday. */
+  tm->tm_isdst = 0;
+
+  if (years < 1970)
+    return (time_t)-1;
+
+#if (defined(TM_YEAR_MAX) && defined(TM_MON_MAX) && defined(TM_MDAY_MAX))
+#if (defined(TM_HOUR_MAX) && defined(TM_MIN_MAX) && defined(TM_SEC_MAX))
+  if (years > TM_YEAR_MAX ||
+      (years == TM_YEAR_MAX &&
+       (tm->tm_yday > ydays[TM_MON_MAX] + (TM_MDAY_MAX - 1) +
+                      (TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) ||
+        (tm->tm_yday == ydays[TM_MON_MAX] + (TM_MDAY_MAX - 1) +
+                        (TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) &&
+         (hours > TM_HOUR_MAX ||
+          (hours == TM_HOUR_MAX &&
+           (minutes > TM_MIN_MAX ||
+            (minutes == TM_MIN_MAX && seconds > TM_SEC_MAX) )))))))
+    return (time_t)-1;
+#endif
+#endif
+
+  return (time_t)(86400L * (unsigned long)(unsigned)days +
+                  3600L * (unsigned long)hours +
+                  (unsigned long)(60 * minutes + seconds));
+}
+
+/*
+int main()
+{
+  struct tm crud;
+  time_t now,then;
+  
+  
+  now=time(NULL);
+  
+  
+  gmtime_r(&now,&crud);
+  
+  then=mkgmtime(&crud);
+  
+  printf("%d %d",now,then);  
+  printf("Hello World!\n");
+}
+*/
+