瀏覽代碼

"state.info" updates

* local file "state.info" holds state information (driver login, gps info, etc.)
* if a process exits prematurly or needs restarting it can read the "state.info"
  file to try to restore state
* added some README files to busuint processe
* small fixes to tinyscheme to get rid of warnings on 64 bit systems
* paddle, trip and route are not restored as this is more complicated. If needed,
  this can be done in the future
* added 'DEBUG_PRINT' for heartbeat messages for each process. By default,
  #define is set in common_config.h, so it's turned on
Abram Connelly 4 年之前
父節點
當前提交
dd35d13e49

+ 136 - 121
busunit/DIUv2/diu_main.c

@@ -54,7 +54,7 @@
 
 #define _SLEN LINE_BUFFER_SIZE
 
-#define DIU_MINDER_VERSION "2.1.12"
+#define DIU_MINDER_VERSION "2.1.13"
 
 static const char *s_http_port = "60535";
 static struct mg_serve_http_opts s_http_server_opts;
@@ -71,8 +71,8 @@ gps_status my_gps_stat={0};
 
 time_t mkgmtime(struct tm *tm);
 
-int   token_diag_serial = 0;
-char   token_diag_string[LINE_BUFFER_SIZE] = {0};
+int  token_diag_serial = 0;
+char token_diag_string[LINE_BUFFER_SIZE] = {0};
 
 
 // return total bytes in dst
@@ -100,6 +100,8 @@ set_paddle_req paddle_req = {0};
 driver_status my_driver_status={0};
 int update_driver_status = 0;
 
+state_info_t my_state_info = {0};
+
 int md5_of_file(char *filename, void *result) {
   FILE *f = NULL;
   char chunk[LINE_BUFFER_SIZE]={0};
@@ -110,20 +112,20 @@ int md5_of_file(char *filename, void *result) {
 
   if (!filename) { return -1; }
 
-  if(!MD5_Init(&ctx)) {
+  if (!MD5_Init(&ctx)) {
     return -1;
   }
 
   f = fopen(filename, "rb");
 
-  if(!f) {
+  if (!f) {
     return -1;
   }
 
   while(1) {
     retval = fread(chunk, 1, LINE_BUFFER_SIZE, f);
 
-    if(retval <= 0) {
+    if (retval <= 0) {
       break;
     }
 
@@ -237,7 +239,7 @@ int handle_gps_time(float gtime, int date) {
 
   // If we scanned at all required fields
   //
-  if(n >= 6) {
+  if (n >= 6) {
     struct tm gpstm = {0};
 
     // GPS date only uses two digits for year, so we must assume the century
@@ -270,7 +272,7 @@ int handle_gps_time(float gtime, int date) {
 
     // if we have more than MAX_GPS_CLOCK_DRIFT seconds of clock drift
     //
-    if(abs(utc - now) > MAX_GPS_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.
@@ -284,7 +286,7 @@ int handle_gps_time(float gtime, int date) {
 
       // If we have a valid connection to the IPC hub
       //
-      if( hub_fd >= 0) {
+      if ( hub_fd >= 0) {
 
         // Stick a message into the diagnostic log to record the fact that we've set the system clock from GPS
         //
@@ -333,10 +335,10 @@ static int handle_stale_gps_condition() {
 
   // If we have entered this function with the impression that we have a valid GPS fix...
   //
-  if(previous_good_flag > 0) {
+  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 ) {
+    if ( stale_time >= GPS_STALE_THRESHOLD ) {
       clear_stale_gps_data();
       my_gps_stat.gps_good = 0;
       return_code |= 1;
@@ -348,7 +350,7 @@ static int handle_stale_gps_condition() {
   // 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) ) {
+  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);
@@ -375,7 +377,7 @@ int update_gps(char *in) {
   int return_code = 0;
 
 
-  if(!strncmp(in,"$GPRMC",6)) {
+  if (!strncmp(in,"$GPRMC",6)) {
     float f1=0;
     char f2=0;
     float f3=0;
@@ -392,12 +394,12 @@ int update_gps(char *in) {
 
     // If we have a full GPRMC sentence we can consider setting the time
     //
-    if(num == 11) {
+    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) {
+      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).
@@ -405,7 +407,7 @@ int update_gps(char *in) {
       }
     }
 
-    if(num > 0) {
+    if (num > 0) {
 
       // update snapshot with latitude
       //
@@ -431,7 +433,7 @@ int update_gps(char *in) {
     }
   }
 
-  else if(!strncmp(in,"$GPGGA",6)) {
+  else if (!strncmp(in,"$GPGGA",6)) {
     int f1=0;
     float f2=0;
     char f3=0;
@@ -447,7 +449,7 @@ int update_gps(char *in) {
 
     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) {
+    if (num == 12) {
 
       // require 3 satellites minimum
       //
@@ -479,7 +481,7 @@ int update_gps(char *in) {
   //     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) ) {
+  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);
@@ -494,11 +496,11 @@ void maintain_ipc_hub_connect(char *progname) {
 
   // if we have no connection to the IPC hub
   //
-  if(hub_fd < 0) {
+  if (hub_fd < 0) {
 
     // if we haven't tried the hub in a few seconds
     //
-    if( (time(NULL) - last_hub_try) > HUB_RETRY_TIME ) {
+    if ( (time(NULL) - last_hub_try) > HUB_RETRY_TIME ) {
 
       // retry it
       //
@@ -508,7 +510,7 @@ void maintain_ipc_hub_connect(char *progname) {
       //
       hub_fd = connect_to_message_server(progname);
 
-      if(hub_fd >= 0) {
+      if (hub_fd >= 0) {
         // Subscribe to the default status messages
         //
         subscribe_to_default_messages(hub_fd);
@@ -545,7 +547,7 @@ void maintain_ipc_hub_connect(char *progname) {
 message_callback_return handle_status_request(struct message_record *msg, void *param) {
   struct message_record outgoing_msg;
 
-  if(hub_fd >= 0) {
+  if (hub_fd >= 0) {
     prepare_message(&outgoing_msg, MAILBOX_DRIVER_STATUS, &my_driver_status, sizeof(my_driver_status));
     send_message(hub_fd, &outgoing_msg);
     prepare_message(&outgoing_msg, MAILBOX_GPS_STATUS, &my_gps_stat, sizeof(my_gps_stat));
@@ -556,7 +558,7 @@ message_callback_return handle_status_request(struct message_record *msg, void *
 }
 
 message_callback_return handle_vault_drop(struct message_record *msg, void *param) {
-  if(diu_fd >= 0) {
+  if (diu_fd >= 0) {
     write(diu_fd, "/V:\r", 4);
   }
   return MESSAGE_HANDLED_CONT;
@@ -573,7 +575,7 @@ message_callback_return handle_driver_notify(struct message_record *msg, void *p
   long long dup_usec_delta = 0;
 
 
-  if(strncmp((const char *)(msg->payload), dup_notify_str, MAX_PAYLOAD_LENGTH)) {
+  if (strncmp((const char *)(msg->payload), dup_notify_str, MAX_PAYLOAD_LENGTH)) {
     dup_notify_count = 1;
     strncpy(dup_notify_str, (const char *)(msg->payload), MAX_PAYLOAD_LENGTH - 1);
     dup_notify_str[MAX_PAYLOAD_LENGTH - 1] = '\0';
@@ -589,25 +591,25 @@ message_callback_return handle_driver_notify(struct message_record *msg, void *p
 
   switch(msg->payload[0]) {
     case LOGLEVEL_EVENT:
-      if(!is_dup || (dup_usec_delta >= DUP_USEC_BEEP_THRESHOLD)) {
+      if (!is_dup || (dup_usec_delta >= DUP_USEC_BEEP_THRESHOLD)) {
         DIU_ACK_BEEP(diu_fd);
       }
       break;
 
       case LOGLEVEL_REJECT:
-        if(!is_dup || (dup_usec_delta >= DUP_USEC_BEEP_THRESHOLD)) {
+        if (!is_dup || (dup_usec_delta >= DUP_USEC_BEEP_THRESHOLD)) {
           DIU_ERROR_BEEP(diu_fd);
         }
         break;
 
       case LOGLEVEL_ACCEPT:
-        if(!is_dup || (dup_usec_delta >= DUP_USEC_BEEP_THRESHOLD)) {
+        if (!is_dup || (dup_usec_delta >= DUP_USEC_BEEP_THRESHOLD)) {
           DIU_ACK_BEEP(diu_fd);
         }
         break;
 
       case LOGLEVEL_ERROR:
-        if(!is_dup || (dup_usec_delta >= DUP_USEC_BEEP_THRESHOLD)) {
+        if (!is_dup || (dup_usec_delta >= DUP_USEC_BEEP_THRESHOLD)) {
           DIU_CRITICAL_BEEP(diu_fd);
         }
         break;
@@ -615,7 +617,7 @@ message_callback_return handle_driver_notify(struct message_record *msg, void *p
       default: break;
   }
 
-  if(is_dup) {
+  if (is_dup) {
     snprintf(_text, MAX_PAYLOAD_LENGTH, "driver_notify replace %s %s %d x %s", "white", "black", dup_notify_count, &msg->payload[1]);
     ws_send(&g_mgr, _text);
   }
@@ -649,7 +651,7 @@ static inline int can_report_diu_error() {
 
   // If our last potential burst lockout has expired...
   //
-  if( (now - diu_error_burst) >= DIU_ERROR_RATE_LIMIT) {
+  if ( (now - diu_error_burst) >= DIU_ERROR_RATE_LIMIT) {
 
     // reset our burst counter
     //
@@ -662,7 +664,7 @@ static inline int can_report_diu_error() {
 
   // if we haven't hit our burst limit...
   //
-  if(diu_error_counter < DIU_ERROR_BURST_LIMIT) {
+  if (diu_error_counter < DIU_ERROR_BURST_LIMIT) {
 
     // count this message against our burst limit
     //
@@ -725,11 +727,11 @@ static void process_ws_message(struct websocket_message *ws_msg) {
 //
 static void ui_handle_status_input(struct mg_connection *nc, struct http_message *hm) {
   int i, npkgs, npkgnet=0, ncfgline=0;
-  char buf[4*_SLEN],
-       pkgnetline[_SLEN],
-       cfgline[_SLEN],
-       _str[_SLEN];
-  char date_str[32];
+  char buf[4*_SLEN] = {0},
+       pkgnetline[_SLEN] = {0},
+       cfgline[_SLEN] = {0},
+       _str[_SLEN] = {0};
+  char date_str[32] = {0};
   time_t t;
   struct tm tm, pkgtime;
   FILE *fp;
@@ -754,7 +756,7 @@ static void ui_handle_status_input(struct mg_connection *nc, struct http_message
                           pkgtime.tm_mon + 1, pkgtime.tm_mday, pkgtime.tm_year + 1900,
                           pkgtime.tm_hour, pkgtime.tm_min, pkgtime.tm_sec);
 
-		_strnncat(pkgnetline, "|", _SLEN);
+    _strnncat(pkgnetline, "|", _SLEN);
     _strnncat(pkgnetline, _str, _SLEN);
     npkgnet++;
   }
@@ -840,6 +842,8 @@ static void ui_handle_logout_input(struct mg_connection *nc, struct http_message
     "ok .",
   };
 
+  driver_logout();
+
   mg_printf(nc, "HTTP/1.1 200 OK\r\nContent-Length: %lu\r\n\r\n%s",
       (unsigned long)strlen(msg[1]), msg[1]);
 
@@ -1392,21 +1396,6 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
 }
 
 
-//DEBUG
-//
-void _test_ws(struct mg_mgr *mgr) {
-  struct mg_connection *conn;
-  char buf[_SLEN];
-
-  snprintf(buf, _SLEN, "test message");
-
-  for (conn = mg_next(mgr, NULL); conn; conn = mg_next(mgr, conn)) {
-    if (!is_websocket(conn)) { continue; }
-    mg_send_websocket_frame(conn, WEBSOCKET_OP_TEXT, buf, strlen(buf));
-  }
-
-}
-
 //-------- web server functions ----
 
 
@@ -1438,18 +1427,30 @@ int main(int argc, char **argv) {
 
   struct mg_connection *nc;
 
+#ifdef DEBUG_PRINT
   long long int _usec_now, _usec_prv, _usec_del;
+  _usec_now = get_usec_time();
+  _usec_prv = _usec_now;
+  _usec_del = 60000000;
+#endif
+
 
   if ( (argc>1) && (
         (strncmp(argv[1], "-h", 3)==0) ||
-        (strncmp(argv[1], "-v", 3)==0) ) ) { 
+        (strncmp(argv[1], "-v", 3)==0) ) ) {
     printf("diu_minder version: %s\n", DIU_MINDER_VERSION);
     exit(0);
   }
 
-  _usec_now = get_usec_time();
-  _usec_prv = _usec_now;
-  _usec_del = 60000000;
+  // get current state in case the diu_minder crashed
+  // and forgot it (diu_minder broadcasts initial
+  // state on startup, which defaults to zero)
+  //
+  get_state_info(&my_state_info);
+  my_driver_status.logged_in_driver = my_state_info.logged_in_driver;
+  memcpy(my_driver_status.driver_name, my_state_info.driver_name, DRIVER_NAME_LEN);
+  my_driver_status.driver_name[DRIVER_NAME_LEN-1] = '\0';
+  my_driver_status.equip_num = my_state_info.equip_num;
 
   // setup mongoose web server
   //
@@ -1503,36 +1504,40 @@ int main(int argc, char **argv) {
   //
   while( exit_request_status == EXIT_REQUEST_NONE ) {
 
+#ifdef DEBUG_PRINT
     _usec_now = get_usec_time();
     if ((_usec_now - _usec_prv) > _usec_del) {
-      //DEBUG
       printf("[%lli] diu_minder: heartbeat\n", get_usec_time());
-      //DEBUG
-
       _usec_prv = _usec_now;
     }
+#endif
 
     RESET_WATCHDOG();
 
     maintain_ipc_hub_connect(argv[0]);
 
-    if(diu_fd < 0) {
+    if (diu_fd < 0) {
 
       diu_fd = open_rs232_device(DRIVER_UI_PORT, USE_DEFAULT_BAUD, RS232_LINE);
 
-      if(diu_fd < 0) {
+      if (diu_fd < 0) {
         //fprintf(stderr, "Cannot open serial port %s for DIU!\n", DRIVER_UI_PORT);
       }
+
       else {
-        write(diu_fd, "/Q:aK\r", 6);  //Turn on all messages except ACKs for sent commands
+
+        // Turn on all messages except ACKs for sent commands
+        //
+        write(diu_fd, "/Q:aK\r", 6);
       }
+
     }
 
     now = time(NULL);
 
     //Every second, we want to update the DIU clock (even though it only shows minutes, this covers power events...)
     //
-    if((now - last_diu_clock) > 0) {
+    if ((now - last_diu_clock) > 0) {
 
       if (diu_fd>=0) {
         set_diu_clock(diu_fd, now);
@@ -1543,28 +1548,33 @@ int main(int argc, char **argv) {
 
     //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 ((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 ( 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
+        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) {
+    if (hup_request_status) {
 
       hup_request_status = 0;
 
@@ -1574,7 +1584,7 @@ int main(int argc, char **argv) {
 
     //If it is time to send out a driver status update
     //
-    if(update_driver_status && (hub_fd >= 0)) {
+    if (update_driver_status && (hub_fd >= 0)) {
 
       //do so...
       //
@@ -1586,9 +1596,9 @@ int main(int argc, char **argv) {
     check_paddle_request();
 
     //If we have to redraw the UI
-    //if(redraw_flag && !calibration)
+    //if (redraw_flag && !calibration)
     //
-    if(!calibration) {
+    if (!calibration) {
 
       //Redraw the menu reflecting any changes from the last touchscreen input
       //or other stimulus
@@ -1609,14 +1619,14 @@ int main(int argc, char **argv) {
 
     nfd = 0;
 
-    if(hub_fd >= 0) {
+    if (hub_fd >= 0) {
       fds[nfd].fd = hub_fd;
       fds[nfd].events = POLLIN;
       fds[nfd].revents = 0;
       nfd++;
     }
 
-    if(diu_fd >= 0) {
+    if (diu_fd >= 0) {
       fds[nfd].fd = diu_fd;
       fds[nfd].events = POLLIN;
       fds[nfd].revents = 0;
@@ -1640,7 +1650,7 @@ int main(int argc, char **argv) {
 
     //if we have any file descriptors, poll them
     //
-    if(nfd > 0) {
+    if (nfd > 0) {
       poll_return = poll(fds, nfd, POLL_TIMEOUT);
     }
 
@@ -1658,22 +1668,25 @@ int main(int argc, char **argv) {
 
     //if poll didn't net us any work to do,
     //
-    if(poll_return < 1) {
+    if (poll_return < 1) {
+
       //lets try again
       //
       continue;
+
     }
 
-    for(i = 0; i < nfd; i++)  //Loop through all polled file descriptors
-    {
+    // Loop through all polled file descriptors
+    //
+    for (i = 0; i < nfd; i++)  {
 
       //If we're looking at the DIU...
       //
-      if( fds[i].fd == diu_fd ) {
+      if ( fds[i].fd == diu_fd ) {
 
         //if poll says our serial port has become bogus...
         //
-        if(fds[i].revents & (POLLHUP | POLLERR | POLLNVAL)) {
+        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);
 
           if (diu_fd >= 0) {
@@ -1683,53 +1696,54 @@ int main(int argc, char **argv) {
           break;
         }
 
-        if(fds[i].revents & POLLIN) {
+        if (fds[i].revents & POLLIN) {
           read_return = read(fds[i].fd, line, sizeof(line));
 
-          if(read_return > 0) {
+          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++; }
+            // advance until EOL or we hit our start sentinel
+            //
+            while (*trav && (*trav != '/') ) { trav++; }
 
-            //Check to see that our address header is intact...
+            // Check to see that our address header is intact...
             //
-            if( (trav[0] == '/') && (trav[2] == ':') ) {
+            if ( (trav[0] == '/') && (trav[2] == ':') ) {
 
-              switch(trav[1]) {
+              switch (trav[1]) {
 
                 //-----------------------------------"/T:" means it's a touchscreen event
                 //
                 case 'T':
 
-                  //advance past the header
+                  // advance past the header
                   //
                   trav += 3;
 
                   retval = sscanf(trav, "%x,%x,%x", &tz, &tx, &ty);
 
-                  if(retval == 3) {
-                    if(tz) {
+                  if (retval == 3) {
+                    if (tz) {
 
-                      if(down_time == 0) {
+                      if (down_time == 0) {
                         down_time = time(NULL);
                       }
                       else {
-                        if( (time(NULL) - down_time) > TS_CALIB_HOLD_TIME) {
+                        if ( (time(NULL) - down_time) > TS_CALIB_HOLD_TIME) {
                           begin_touchscreen_calibration();
                           calibration = 1;
                         }
                       }
 
 
-                      if(!calibration) {
+                      if (!calibration) {
                         // calibration from here turned off...
                       }
                       else {
-                        if(advance_touchscreen_calibration(tx, ty, tz)) {
+                        if (advance_touchscreen_calibration(tx, ty, tz)) {
                           calibration = 0;
                         }
                         else {
@@ -1737,12 +1751,11 @@ int main(int argc, char **argv) {
                         }
                       }
                     }
-                    else
-                    {
+                    else {
                       down_time = 0;
-                      if(!calibration) { }
+                      if (!calibration) { }
                       else {
-                        if(advance_touchscreen_calibration(tx, ty, tz)) {
+                        if (advance_touchscreen_calibration(tx, ty, tz)) {
                           calibration = 0;
                           //redraw_flag = 1;
                         }
@@ -1759,51 +1772,53 @@ int main(int argc, char **argv) {
                 //
                 case 'G':
 
-                  //advance past the header
+                  // advance past the header
                   //
                   trav += 3;
 
-                  //If this GPS update constitutes a meaningful piece of data
+                  // If this GPS update constitutes a meaningful piece of data
                   //
-                  if(update_gps(trav) > 0)  {
+                  if (update_gps(trav) > 0)  {
 
-                    //and we have a connection to the IPC hub
+                    // and we have a connection to the IPC hub
                     //
-                    if(hub_fd >= 0) {
+                    if (hub_fd >= 0) {
 
-                      //Go and toss the data to any other modules who happen to care about GPS
+                      // 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);
                     }
 
-                    last_stale_gps_check = now;  //Remember that we did a stale GPS check as part of our update.
+                    // Remember that we did a stale GPS check as part of our update.
+                    //
+                    last_stale_gps_check = now;
                   }
                   break;
 
-                //handle warnings
+                // handle warnings
                 //
                 case '*':
 
-                //debugs
+                // debugs
                 //
                 case '#':
 
-                //and errors
+                // and errors
                 //
                 case '!':
 
-                  //If this DIU error/debug message has not run afoul of the rate limiting policy...
+                  // If this DIU error/debug message has not run afoul of the rate limiting policy...
                   //
-                  if( can_report_diu_error() ) {
+                  if ( can_report_diu_error() ) {
 
-                    //send them all to the log server
+                    // send them all to the log server
                     //
                     format_log_message(&outgoing_msg, trav[1], "DIU Reports: %s", trav + 3);
                     send_message(hub_fd, &outgoing_msg);
 
                     //but in the case of errors, send them to the driver too
-                    if(trav[1] == '!') {
+                    if (trav[1] == '!') {
                       format_driver_message(&outgoing_msg, trav[1], "DIU Reports: %s", trav + 3);
                       send_message(hub_fd, &outgoing_msg);
                     }
@@ -1832,13 +1847,13 @@ int main(int argc, char **argv) {
 
       }
 
-      //If we're looking at the IPC hub...
+      // If we're looking at the IPC hub...
       //
-      else if( fds[i].fd == hub_fd ) {
+      else if ( fds[i].fd == hub_fd ) {
 
-        //if poll says our connection to the IPC hub has died...
+        // if poll says our connection to the IPC hub has died...
         //
-        if(fds[i].revents & (POLLHUP | POLLERR | POLLNVAL)) {
+        if (fds[i].revents & (POLLHUP | POLLERR | POLLNVAL)) {
           fprintf(stderr, "The connection to the IPC hub has gone away...\n");
 
           close(hub_fd);
@@ -1846,12 +1861,12 @@ int main(int argc, char **argv) {
           break;
         }
 
-        //if we have mail in any of our mailboxes...
+        // if we have mail in any of our mailboxes...
         //
-        if(fds[i].revents & POLLIN) {
+        if (fds[i].revents & POLLIN) {
           read_return = get_message(hub_fd, &incoming_msg);
 
-          if(read_return < 0) {
+          if (read_return < 0) {
             fprintf(stderr, "The connection to the IPC hub has gone away...\n");
 
             close(hub_fd);
@@ -1879,11 +1894,11 @@ int main(int argc, char **argv) {
     }
   }
 
-  if(hub_fd >= 0) {
+  if (hub_fd >= 0) {
     close(hub_fd);
   }
 
-  if(diu_fd >= 0) {
+  if (diu_fd >= 0) {
     write(diu_fd, "/C:----\r",8);
     close(diu_fd);
   }

+ 101 - 82
busunit/DIUv2/driver.c

@@ -23,93 +23,112 @@
 // This function searches the driver file and checks a driver, pin pair returning 0 on success
 // or -1 on failure.
 //
-int driver_login(int drivernum, char *pinnum)
-{
-    FILE *f;
-    char name[DRIVER_NAME_LEN]={0};
-    char pin[64];
-    char line[LINE_BUFFER_SIZE]={0};
-    char *inc_line;
-    struct message_record outgoing_msg;
+int driver_login(int drivernum, char *pinnum) {
+  FILE *f;
+  char name[DRIVER_NAME_LEN]={0};
+  char pin[64];
+  char line[LINE_BUFFER_SIZE]={0};
+  char *inc_line;
+  struct message_record outgoing_msg;
 
 
-    int drv;
-    int retval;
+  int drv;
+  int retval;
 
-    if(!drivernum || !pinnum) { return -1; }
+  if (!drivernum || !pinnum) { return -1; }
 
-    f=fopen(DRIVERS_FILE,"rb");       //open the driver file
+  // open the driver file
+  //
+  f=fopen(DRIVERS_FILE,"rb");
 
-    if(!f)
-    {
-        format_log_message(&outgoing_msg, LOGLEVEL_ERROR, "Cannot open %s\n", DRIVERS_FILE);
-        send_message(hub_fd,&outgoing_msg);
-        return -1;            //fail if we can't read it
+  if (!f) {
+    format_log_message(&outgoing_msg, LOGLEVEL_ERROR, "Cannot open %s\n", DRIVERS_FILE);
+    send_message(hub_fd,&outgoing_msg);
+
+    // fail if we can't read it
+    //
+    return -1;
+  }
+
+  // while we haven't hit EOF
+  //
+  while (!feof(f)) {
+
+    // read it line by line
+    //
+    if (!fgets(line,sizeof(line)-1,f)) {
+      break;
+    }
+
+    // terminating each line safely
+    //
+    line[sizeof(line)-1] = '\0';
+
+    inc_line = line;
+
+    // and ignoring any leading whitespace
+    //
+    while (1) {
+      char c = *inc_line;
+
+      if ( (c == ' ') ||(c == '\t') ||(c == '\r') ||(c == '\n') ) {
+        inc_line++;
+        continue;
+      }
+
+      break;
     }
 
-    while(!feof(f))         //while we haven't hit EOF
-    {
-        if(!fgets(line,sizeof(line)-1,f))   //read it line by line
-            break;
-
-        line[sizeof(line)-1] = '\0';          //terminating each line safely
-
-        inc_line = line;
-
-        while(1)        //and ignoring any leading whitespace
-        {
-            char c = *inc_line;
-
-            if( (c == ' ') ||(c == '\t') ||(c == '\r') ||(c == '\n') )
-            {
-                inc_line++;
-                continue;
-            }
-
-            break;
-        }
-
-        if( (inc_line[0] == '#') || (inc_line[0] == '\0'))                      //and ignoring blank/comment lines
-            continue;
-
-        name[0]='\0';
-        pin[0]='\0';
-
-        retval=sscanf(inc_line,"%d %63[0123456789] %63[^\r\n]",&drv,pin,name);  //parse the line format (drivernum pin_num drivername)
-
-        if(retval >= 2)           //if we get at least a driver number and pin number
-        {
-            if(drv != drivernum)          //check to see if we've found a match
-                continue;
-
-            if(!strcmp(pinnum, pin))    //if the PIN matches
-            {
-                my_driver_status.logged_in_driver = drivernum;
-                strncpy(my_driver_status.driver_name, name, DRIVER_NAME_LEN);
-                my_driver_status.driver_name[DRIVER_NAME_LEN - 1] = '\0';
-                my_driver_status.equip_num = get_equip_num();
-
-                format_log_message(&outgoing_msg, LOGLEVEL_DEBUG, "Successful login for driver %d\n", drivernum);
-                send_message(hub_fd,&outgoing_msg);
-
-                update_driver_status |= 1;
-                fclose(f);
-                return 0;
-            }
-            else
-            {
-                format_log_message(&outgoing_msg, LOGLEVEL_DEBUG, "Failed login for driver %d\n", drivernum);
-                send_message(hub_fd,&outgoing_msg);
-                fclose(f);
-                return -1;
-            }
-        }
+    // and ignoring blank/comment lines
+    //
+    if ( (inc_line[0] == '#') || (inc_line[0] == '\0')) {
+      continue;
     }
 
-    format_log_message(&outgoing_msg, LOGLEVEL_DEBUG, "Failed login for unknown driver %d\n", drivernum);
-    send_message(hub_fd,&outgoing_msg);
-    fclose(f);
-    return -1;
+    name[0]='\0';
+    pin[0]='\0';
+
+    // parse the line format (drivernum pin_num drivername)
+    //
+    retval=sscanf(inc_line,"%d %63[0123456789] %63[^\r\n]",&drv,pin,name);
+
+    // if we get at least a driver number and pin number
+    //
+    if (retval >= 2) {
+      // check to see if we've found a match
+      //
+      if (drv != drivernum) {
+        continue;
+      }
+
+      // if the PIN matches
+      //
+      if (!strcmp(pinnum, pin)) {
+        my_driver_status.logged_in_driver = drivernum;
+        strncpy(my_driver_status.driver_name, name, DRIVER_NAME_LEN);
+        my_driver_status.driver_name[DRIVER_NAME_LEN - 1] = '\0';
+        my_driver_status.equip_num = get_equip_num();
+
+        format_log_message(&outgoing_msg, LOGLEVEL_DEBUG, "Successful login for driver %d\n", drivernum);
+        send_message(hub_fd,&outgoing_msg);
+
+        update_driver_status |= 1;
+        fclose(f);
+        return 0;
+      }
+      else {
+        format_log_message(&outgoing_msg, LOGLEVEL_DEBUG, "Failed login for driver %d\n", drivernum);
+        send_message(hub_fd,&outgoing_msg);
+        fclose(f);
+        return -1;
+      }
+    }
+  }
+
+  format_log_message(&outgoing_msg, LOGLEVEL_DEBUG, "Failed login for unknown driver %d\n", drivernum);
+  send_message(hub_fd,&outgoing_msg);
+  fclose(f);
+  return -1;
 }
 
 // Log a driver out and cancel any pending set paddle request
@@ -117,7 +136,7 @@ int driver_login(int drivernum, char *pinnum)
 int driver_logout() {
   struct message_record outgoing_msg;
 
-  if(my_driver_status.logged_in_driver) {
+  if (my_driver_status.logged_in_driver) {
     format_log_message(&outgoing_msg, LOGLEVEL_DEBUG, "Driver logout for driver %d\n", my_driver_status.logged_in_driver);
     send_message(hub_fd,&outgoing_msg);
   }
@@ -146,9 +165,9 @@ int check_paddle_request() {
   char buf[LINE_BUFFER_SIZE];
   struct message_record outgoing_msg;
 
-  if(paddle_req_timeout != 0) {
+  if (paddle_req_timeout != 0) {
 
-    if(paddle_req.request == paddle_req.result) {
+    if (paddle_req.request == paddle_req.result) {
       format_log_message(&outgoing_msg, LOGLEVEL_DEBUG, "Set Paddle %d\n", paddle_req.request);
       send_message(hub_fd, &outgoing_msg);
       paddle_req_timeout = 0;
@@ -158,7 +177,7 @@ int check_paddle_request() {
 
       return 1;
     }
-    else if( (paddle_req.result < 0) || (paddle_req_timeout < time(NULL)) ) {
+    else if ( (paddle_req.result < 0) || (paddle_req_timeout < time(NULL)) ) {
       format_log_message(&outgoing_msg, LOGLEVEL_DEBUG, "Failed to set Paddle %d\n", paddle_req.request);
       send_message(hub_fd, &outgoing_msg);
       paddle_req.result = 0;

+ 1 - 0
busunit/DIUv2/driver.h

@@ -52,6 +52,7 @@ int check_paddle_request();
 int make_paddle_request(int);
 
 int driver_login(int, char*);
+int driver_logout(void);
 
 void action_nextstop(void);
 void action_prevstop(void);

+ 4 - 2
busunit/PIU/piu_main.c

@@ -312,10 +312,12 @@ int main(int argc, char **argv) {
 
   int i, j;
 
+#ifdef DEBUG_PRINT
   long long int _usec_now, _usec_prv, _usec_del;
   _usec_now = get_usec_time();
   _usec_prv = _usec_now;
   _usec_del = 60000000;
+#endif
 
   long long int _usec_ratelimit_now, _usec_ratelimit_prv, _usec_ratelimit_del;
   _usec_ratelimit_now = get_usec_time();
@@ -354,13 +356,13 @@ int main(int argc, char **argv) {
 
     RESET_WATCHDOG();
 
-    //DEBUG
+#ifdef DEBUG_PRINT
     _usec_now = get_usec_time();
     if ((_usec_now - _usec_prv) > _usec_del) {
       printf("[%lli] piu_minder: heartbeat\n", get_usec_time());
       _usec_prv = _usec_now;
     }
-    //DEBUG
+#endif
 
 
     maintain_ipc_hub_connect(argv[0]);

+ 26 - 26
busunit/avls/avls_communication.c

@@ -37,6 +37,8 @@
 #include "../commhub/commhub.h"
 #include "../commhub/client_utils.h"
 
+#define AVLS_COMMUNICATION_VERSION "2.1.1"
+
 //----------GLOBAL STATE VARIABLES
 
 time_t   last_sync_attempt = 0;  //Time of the last normal chirp in seconds since epoch
@@ -69,10 +71,6 @@ int load_avls_config()
                 avls_motion_interval = motion;
                 avls_still_interval = still;
 
-                //DEBUG
-                fprintf(stderr, "#avls (motion %i, still %i) interval\n", avls_motion_interval, avls_still_interval);
-                //DEBUG
-
                 fclose(f);
                 return 0;
             }
@@ -183,8 +181,6 @@ void maintain_ipc_hub_connect(char *progname)
     {
         commhub_fd = connect_to_message_server(progname);  //try and get one
 
-//        printf("commhub_fd = %d\n", commhub_fd);
-
         if(commhub_fd >= 0)  //if it worked
         {
             //Subscribe to the relevant status management mailboxes
@@ -208,15 +204,36 @@ int main(int argc, char **argv)
 
     struct message_record incoming_msg;
 
+#ifdef DEBUG_PRINT
     long long int _usec_now, _usec_prv, _usec_del;
     _usec_del = 60000000;
     _usec_now = get_usec_time();
     _usec_prv = _usec_now;
+#endif
+
+		if ( (argc>1) && (
+					(strncmp(argv[1], "-h", 3)==0) ||
+					(strncmp(argv[1], "-v", 3)==0) ) ) {
+			printf("avls_communication version: %s\n", AVLS_COMMUNICATION_VERSION);
+			exit(0);
+		}
+
 
     //------------------
 
     load_avls_config();
 
+    // load current AVLS position from global state
+    // (state.info file).
+    //
+    init_state_info();
+    gps_stat.lat = state_info.lat;
+    gps_stat.lon = state_info.lon;
+    gps_stat.heading = state_info.heading;
+    gps_stat.velocity = state_info.velocity;
+
+    //------------------
+
     configure_signal_handlers(argv[0]);
 
     maintain_ipc_hub_connect(argv[0]);
@@ -231,13 +248,13 @@ int main(int argc, char **argv)
 
         RESET_WATCHDOG();
 
-        //DEBUG
+#ifdef DEBUG_PRINT
         _usec_now = get_usec_time();
         if ((_usec_now - _usec_prv) > _usec_del) {
           printf("[%lli] avls: heartbeat\n", get_usec_time());
           _usec_prv = _usec_now;
         }
-        //DEBUG
+#endif
 
         if(hup_request_status)
         {
@@ -255,8 +272,6 @@ int main(int argc, char **argv)
                 {
                      server_fd = connect_to_avls_server();    //if so, try again...
 
-//                     printf("server_fd = %d\n", server_fd);
-
                      if(server_fd >= 0)  //if it worked
                      {
                          last_sync_attempt = 0;
@@ -329,12 +344,6 @@ int main(int argc, char **argv)
             poll_return = 0;
         }
 
-//        printf("Poll returns %d (of %d)\n", poll_return, nfds);
-//        for(i=0; i < nfds; i++)
-//        {
-//            printf("\t%d: fd=%d ev=%d rev=%d\n", i, fds[i].fd, fds[i].events, fds[i].revents);
-//        }
-
         if(poll_return <= 0)
         {
             continue;
@@ -342,7 +351,7 @@ int main(int argc, char **argv)
 
         for(i=0; i < nfds; i++)
         {
-//            printf("Processing Poll Result %d\n",i);
+
             if( fds[i].fd == server_fd )
             {
                 //If we've lost connection, break this loop and poll all over again
@@ -356,8 +365,6 @@ int main(int argc, char **argv)
                 if(fds[i].revents & POLLOUT)
                 {
                     //sent a query here...
-
-//                    printf("Trying to write to server...\n");
                     read_return = send_avls_chirp(server_fd);
 
                     //and then update our last sync attempt time
@@ -385,7 +392,6 @@ int main(int argc, char **argv)
 
                 if(fds[i].revents & POLLIN)
                 {
-//                    printf("Trying to read from hub...\n");
                     read_return = get_message(commhub_fd, &incoming_msg);
 
                     if( read_return < 0 )
@@ -403,12 +409,6 @@ int main(int argc, char **argv)
         }
     }
 
-
-
     return 0;
 }
 
-
-
-
-

+ 19 - 0
busunit/billdb/README.md

@@ -0,0 +1,19 @@
+`billdb`
+===
+
+`billdb` is responsible for accepted fares and passing them back to the
+central server for storage into a remote database.
+
+The main responsibilities include:
+
+* Sending billing entries to the central server
+* Queuing up entries locally if the connection is lost
+* Sending queued entries to the central server when connection has been re-established
+
+The standard use case will be for a system wide tunnel to be established
+to a central server and for this program to connect "locally" through
+a special port to communicate.
+The address and port are currently set to `127.0.0.1` and `2455` respectively
+but see `busunit/common/common_config.h` for [details](/busunit/common/common_config.h).
+
+

+ 4 - 4
busunit/billdb/bill_communication.c

@@ -269,8 +269,6 @@ void maintain_ipc_hub_connect(char *progname)
     {
         commhub_fd = connect_to_message_server(progname);  //try and get one
 
-//        printf("commhub_fd = %d\n", commhub_fd);
-
         if(commhub_fd >= 0)  //if it worked
         {
             //Subscribe to the basics
@@ -449,10 +447,12 @@ int main(int argc, char **argv)
     int input_idx = 0;
     int checked_idx = 0;
 
+#ifdef DEBUG_PRINT
     long long int _usec_now, _usec_prv, _usec_del;
     _usec_del = 60000000;
     _usec_now = get_usec_time();
     _usec_prv = _usec_now;
+#endif
 
     billdb_context ctx = {0};
 
@@ -498,13 +498,13 @@ int main(int argc, char **argv)
 
         RESET_WATCHDOG();
 
-        //DEBUG
+#ifdef DEBUG_PRINT
         _usec_now = get_usec_time();
         if ((_usec_now - _usec_prv) > _usec_del) {
           printf("[%lli] billdb: heartbeat\n", get_usec_time());
           _usec_prv = _usec_now;
         }
-        //DEBUG
+#endif
 
         maintain_ipc_hub_connect(argv[0]);
 

+ 90 - 9
busunit/client_supervisor/client_supervisor.c

@@ -39,6 +39,8 @@
 #include "../commhub/commhub.h"
 #include "../commhub/client_utils.h"
 
+#define CLIENT_SUPERVISOR_VERSION "2.1.1"
+
 // Number of modules we are actively tracking
 //
 int NUM_MODULES = 0;
@@ -779,7 +781,7 @@ message_callback_return handle_pong_message(struct message_record *msg, void *pa
     if ( module_status[i].active && (msg->header.sender == module_status[i].pid) ) {
       module_status[i].last_pong = get_usec_time();
       module_status[i].ping_lag = (module_status[i].last_pong - module_status[i].last_ping);
-//      printf("PING->PONG latency %lld microseconds.\n", module_status[i].ping_lag);
+      // printf("PING->PONG latency %lld microseconds.\n", module_status[i].ping_lag);
     }
 
   }
@@ -787,6 +789,67 @@ message_callback_return handle_pong_message(struct message_record *msg, void *pa
   return MESSAGE_HANDLED_CONT;
 }
 
+//----
+
+// Client_supervisor is now in charge of managing the state_info file,
+// so we need to have gps, stop and driver messages handled explicitely
+// to be able to write to the state_info file.
+// `client_supervisor` should be the sole process writing to the state_info
+// file while any other client should be able to read.
+//
+
+message_callback_return handle_gps_message(struct message_record *msg, void *param) {
+
+  // guard against version mismatch
+  //
+  if (msg->header.payload_length != sizeof(gps_status))  {
+    return MESSAGE_HANDLED_STOP;
+  }
+
+  memcpy(&gps_stat, msg->payload, sizeof(gps_status));    //otherwise, update our structure
+  update_state_info_with_gps(&state_info, &gps_stat);
+  memcpy(state_info.comment, "client_supervisor gps", strlen("client_supervisor gps")+1);
+  set_state_info(&state_info);
+
+  return MESSAGE_HANDLED_CONT;
+}
+
+static message_callback_return handle_stop_message(struct message_record *msg, void *param) {
+
+  // guard against version mismatch
+  //
+  if (msg->header.payload_length != sizeof(stop_status))  {
+    return MESSAGE_HANDLED_STOP;
+  }
+
+  memcpy(&stop_stat, msg->payload, sizeof(stop_status));
+  update_state_info_with_stop(&state_info, &stop_stat);
+  memcpy(state_info.comment, "client_supervisor stop", strlen("client_supervisor stop")+1);
+  set_state_info(&state_info);
+
+  return MESSAGE_HANDLED_CONT;
+}
+
+static message_callback_return handle_driver_message(struct message_record *msg, void *param) {
+
+  // guard against version mismatch
+  //
+  if (msg->header.payload_length != sizeof(driver_status))  {
+    return MESSAGE_HANDLED_STOP;
+  }
+
+  memcpy(&driver_stat, msg->payload, sizeof(driver_stat));
+  update_state_info_with_driver(&state_info, &driver_stat);
+  memcpy(state_info.comment, "client_supervisor driver", strlen("client_supervisor driver")+1);
+  set_state_info(&state_info);
+
+  return MESSAGE_HANDLED_CONT;
+}
+
+
+
+//----
+
 void clear_ping_attempt() {
   int i;
 
@@ -969,12 +1032,16 @@ void maintain_ipc_hub_connect(char *progname) {
   }
 }
 
-void usage(char *progname) {
-  fprintf(stderr,"%s:  %d modules given to be supervised, minimum = 1, maximum = %d\n", progname, NUM_MODULES, SUPERVISOR_MAX_MODULES - 1);
-  fprintf(stderr,"%s:  Usage: %s [module ...] [--[no-]ping] [module ...]\n", progname, progname);
-  fprintf(stderr,"%s:  By default modules will be subjet to PING monitoring through\n", progname);
-  fprintf(stderr,"%s:  the IPC hub, --no-ping will effect all modules following it until a --ping\n", progname);
-  fprintf(stderr,"\n");
+void print_version(FILE *fp) {
+  fprintf(fp, "version %s\n", CLIENT_SUPERVISOR_VERSION);
+}
+
+void usage(FILE *fp, char *progname) {
+  fprintf(fp,"%s:  %d modules given to be supervised, minimum = 1, maximum = %d\n", progname, NUM_MODULES, SUPERVISOR_MAX_MODULES - 1);
+  fprintf(fp,"%s:  Usage: %s [module ...] [--[no-]ping] [module ...]\n", progname, progname);
+  fprintf(fp,"%s:  By default modules will be subjet to PING monitoring through\n", progname);
+  fprintf(fp,"%s:  the IPC hub, --no-ping will effect all modules following it until a --ping\n", progname);
+  fprintf(fp,"\n");
   exit(EX_USAGE);
 }
 
@@ -993,6 +1060,14 @@ void handle_command_line(int argc, char **argv) {
     else if ( !strcmp(argv[i], "--ping") ) {
       needs_ping = 1;
     }
+    else if ( !strcmp(argv[i], "-v") ) {
+      print_version(stdout);
+      exit(0);
+    }
+    else if ( !strcmp(argv[i], "-h") ) {
+      usage(stdout, argv[0]);
+      exit(EX_USAGE);
+    }
     else {
 
       // Here we look for the last / in the module name
@@ -1026,12 +1101,12 @@ void handle_command_line(int argc, char **argv) {
     }
 
     if (NUM_MODULES >= SUPERVISOR_MAX_MODULES) {
-      usage(argv[0]);
+      usage(stderr, argv[0]);
     }
   }
 
   if (NUM_MODULES == 0) {
-    usage(argv[0]);
+    usage(stderr, argv[0]);
   }
 }
 
@@ -1049,6 +1124,8 @@ int main(int argc, char **argv) {
   struct pollfd fds[1 + (2 * SUPERVISOR_MAX_MODULES)] = {{0}};
   int poll_to_module[1 + (2 * SUPERVISOR_MAX_MODULES)] = {0};
 
+  init_state_info();
+
   // Parse our command line to figure out what modules we need to supervise
   //
   handle_command_line(argc, argv);
@@ -1079,6 +1156,10 @@ int main(int argc, char **argv) {
   //
   register_dispatch_callback(MAILBOX_PONG, CALLBACK_USER(1), handle_pong_message, NULL);
 
+  register_dispatch_callback(MAILBOX_GPS_STATUS, CALLBACK_USER(1), handle_gps_message, NULL);
+  register_dispatch_callback(MAILBOX_STOP_STATUS, CALLBACK_USER(1), handle_stop_message, NULL);
+  register_dispatch_callback(MAILBOX_DRIVER_STATUS, CALLBACK_USER(1), handle_driver_message, NULL);
+
   //  This is the main processing loop which monitors system status and pumps I/O from
   // all of the client modules (debug and error messages) and from the IPC hub when it is up
   // as indicated by poll().

File diff suppressed because it is too large
+ 701 - 560
busunit/commhub/client_utils.c


+ 5 - 0
busunit/commhub/client_utils.h

@@ -27,6 +27,7 @@ extern stop_status	stop_stat;
 extern driver_status	driver_stat;
 extern pass_status	pass_stat;
 extern bill_status	bill_stat;
+extern state_info_t state_info;
 
 //---------------------------------------------------
 
@@ -190,5 +191,9 @@ int format_trace_message(struct message_record *target, const char *fmt, ...);
 //
 int format_billing_message(struct message_record *target, char *action, char *rule, char *ruleparam, char *reason, char *credential, unsigned long long rider_id, int cash_value);
 
+int update_state_info_with_gps(state_info_t *, gps_status *);
+int update_state_info_with_stop(state_info_t *, stop_status *);
+int update_state_info_with_driver(state_info_t *, driver_status *);
+int init_state_info(void);
 
 #endif

+ 466 - 228
busunit/commhub/commhub.c

@@ -2,17 +2,17 @@
  * 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/>.
  *
@@ -32,257 +32,495 @@
 #include "../common/common_defs.h"
 #include "commhub.h"
 
-//This function gets the number of microseconds since epoch for storing in message headers and
-//comparison to determine how timely a message is.
-long long int get_usec_time()
-{
-    struct timeval tv;
-    
-    //Get the number of seconds (and remainder microseconds) since epoch.
-    gettimeofday(&tv,NULL);
-    
-    //Return those in a single sane 64 bit integer containing the total number 
-    //of microseconds since epoch by multiplying tv_sec by a million and summing 
-    //the two values
-    return (long long int)tv.tv_usec + (1000000 * (long long int)tv.tv_sec);
+// This function gets the number of microseconds since epoch for storing in message headers and
+// comparison to determine how timely a message is.
+//
+long long int get_usec_time() {
+  struct timeval tv;
+
+  // Get the number of seconds (and remainder microseconds) since epoch.
+  //
+  gettimeofday(&tv,NULL);
+
+  // Return those in a single sane 64 bit integer containing the total number
+  // of microseconds since epoch by multiplying tv_sec by a million and summing
+  // the two values
+  //
+  return (long long int)tv.tv_usec + (1000000 * (long long int)tv.tv_sec);
 }
 
-//This function does a non-blocking poll to determine if the message passing socket is
-//ready for input or output (depending on 
-//since it is much more efficient to block on the entire list of your I/O file descriptors
-//and service any that cause you to unblock.
+// This function does a non-blocking poll to determine if the message passing socket is
+// ready for input or output (depending on
+// since it is much more efficient to block on the entire list of your I/O file descriptors
+// and service any that cause you to unblock.
 //
-//	Returns:  MSG_NO_ACTION = no message 
-//		  MSG_ERROR 	= fatal error (passed fd is no good) 
+//  Returns:  MSG_NO_ACTION = no message
+//      MSG_ERROR   = fatal error (passed fd is no good)
 //
-//		  If the socket is ready, the return value will be
-//		  whatever combination of events specified in mask (MSG_SEND, MSG_RECV)
-//		  that is actually ready.
+//      If the socket is ready, the return value will be
+//      whatever combination of events specified in mask (MSG_SEND, MSG_RECV)
+//      that is actually ready.
 //
-int message_socket_status(int message_socket_fd, int mask)
-{
-    struct pollfd fds[1];
-    int retval;
-    
-    fds[0].fd = message_socket_fd;
-    
-    do
-    {
-        fds[0].events = mask;
-        retval = poll(fds,1,0);		//poll the 1 file descriptor, returning immediately.            
-      
-        if(retval < 0)
-        {
-            //if we were interrupted by a signal, try again...
-            if(errno == EINTR)
-              continue;
-        
-            //otherwise poll() has failed, which is BAD news.
-            return MSG_ERROR;
+int message_socket_status(int message_socket_fd, int mask) {
+  struct pollfd fds[1];
+  int retval;
+
+  fds[0].fd = message_socket_fd;
+
+  do {
+    fds[0].events = mask;
+    retval = poll(fds,1,0);    //poll the 1 file descriptor, returning immediately.
+
+    if (retval < 0) {
+
+      // if we were interrupted by a signal, try again...
+      //
+      if(errno == EINTR) {
+        continue;
+      }
+
+      // otherwise poll() has failed, which is BAD news.
+      //
+      return MSG_ERROR;
+    }
+
+    if (retval == 0) {
+      return MSG_NO_ACTION;
+    }
+
+    // If poll tells us that the fd is invalid or has encountered a serious error, return -1.
+    //
+    if(fds[0].revents & (POLLERR | POLLNVAL)) {
+      return MSG_ERROR;
+    }
+
+    // If any of the events supplied in mask have occurred, report them.
+    //
+    if(fds[0].revents & mask) {
+      return fds[0].revents & mask;
+    }
+
+    // if there are no more message to drain (see above) and a hangup has occurred,
+    // let the user know the socket is done for.
+    if (fds[0].revents & POLLHUP) {
+      return MSG_ERROR;
+    }
+
+    // Otherwise, by process of elimination we have no message and no error condition to report
+    return MSG_NO_ACTION;
+
+  } while(1);
+}
+
+// this function will pack a mailbox address and a payload into the supplied message structure and
+// set the correct timestamp.
+//
+int prepare_message(struct message_record *target, char *mailbox, void *payload, unsigned int payload_len) {
+  if (target == NULL) {
+    return -1;
+  }
+
+  if (mailbox == NULL) {
+    return -1;
+  }
+
+  if (payload == NULL) {
+    return -1;
+  }
+
+  if (payload_len > MAX_PAYLOAD_LENGTH) {
+    return -1;
+  }
+
+  memset(target, 0, sizeof(struct message_record));
+
+  strncpy(target->header.mailbox_name, mailbox, MAILBOX_NAME_MAX);
+  target->header.mailbox_name[MAILBOX_NAME_MAX] = '\0';
+  target->header.usec_time = get_usec_time();
+  target->header.payload_length = payload_len;
+  target->header.sender = getpid();
+  target->header.from_fd = 0;
+
+  memmove(target->payload, payload, payload_len);
+
+  return 0;
+}
+
+// the send_message function will transmit a message and its header (trimmed to the specified payload length).
+// zero will be returned on success, -1 on failure.
+//
+int send_message(int message_socket_fd, struct message_record *message) {
+  int txlen;
+  int retval;
+
+  if (message == NULL) {
+    return -1;
+  }
+
+  // If we are trying to send a message that is longer than allowed, throw an error!
+  //
+  if (message->header.payload_length > MAX_PAYLOAD_LENGTH) {
+    return -1;
+  }
+
+  // Calculate the total message length (header + payload) so that we don't send
+  // any extra padding that we don't need.
+  txlen = sizeof(struct message_header_record) + message->header.payload_length;
+
+  do {
+    retval = send(message_socket_fd, message, txlen, MSG_EOR);
+
+    // if we were interrupted by a signal, try again.
+    //
+    if ( (retval == -1) && (errno == EINTR) ) {
+      continue;
+    }
+
+    // if we tried to send a message and it got truncated, return failure.
+    //
+    if (retval != txlen) {
+      return -1;
+    }
+
+    return 0;
+
+  } while(1);
+}
+
+// the get_message function will receive a message from the opposite end of the socket and place it in the
+// supplied message structure incliding its header.  -1 is returned on failure, 0 on success.
+//
+int get_message(int message_socket_fd, struct message_record *message) {
+  int retval;
+
+  if (message == NULL) {
+    return -1;
+  }
+
+  // clear our buffer of any garbage before using it to read in the message
+  //
+  memset(message, 0, sizeof(struct message_record));
+
+  do {
+    // try and receive our message
+    //
+    retval = recv(message_socket_fd, message, sizeof(struct message_record), 0);
+
+    // if we were interrupted by a signal, try again.
+    //
+    if ( (retval == -1) && (errno == EINTR) ) {
+      continue;
+    }
+
+    // zero is a special case for recv which indicates that the other side has shut down the connection.
+    if (retval == 0) {
+      return -1;
+    }
+
+    // if the received message size does not add up (between header and payload)
+    //
+    if (retval != (sizeof(struct message_header_record) + message->header.payload_length)) {
+
+      // throw an error!
+      //
+      return -1;
+    }
+
+    // Record which IPC socket we got this from (for things like PING replies)
+    message->header.from_fd = message_socket_fd;
+
+    // otherwise, return success
+    //
+    return 0;
+
+  } while(1);
+}
+
+// This function connects to the communication hub and returns the file descriptor of the connection.
+// If the connection failed, -1 is returned.  The progname parameter (if not NULL) will be used to
+// register a module name (snagged from argv[0]) with the server for ease of debugging.
+//
+int connect_to_message_server(char *progname) {
+  int fd;
+  int retval;
+  int len;
+  char *message_text;
+  struct sockaddr_un addr;
+
+  struct message_record msg;
+
+  fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+
+  if (fd < 0) {
+    return -1;
+  }
+
+  // construct our address structure (pointing to the agreed upon server address)
+  // to pass to connect.
+  addr.sun_family = AF_UNIX;
+  strncpy(addr.sun_path, COMMHUB_ADDRESS, sizeof(addr.sun_path) - 1);
+  addr.sun_path[sizeof(addr.sun_path) - 1]='\0';
+  len=strlen(COMMHUB_ADDRESS) + sizeof(addr.sun_family);
+
+  // attempt to connect to said server
+  //
+  retval = connect(fd,(struct sockaddr *)&addr,len);
+
+  if (retval) {
+    fprintf(stderr, "Cannot connect to IPC hub at %s\n", COMMHUB_ADDRESS);
+    close(fd);
+    return -1;
+  }
+
+  // if we have been passed a module name to register as, use that, otherwise default to "ANONYMOUS"
+  //
+  if (progname) {
+    message_text = progname;
+  }
+
+  else {
+    message_text = "ANONYMOUS";
+  }
+
+  len = strlen(message_text);
+
+  // if for some inconceivable reason our module name is longer than the server allows, truncate it.
+  //
+  if (len > MAX_MODULE_NAME_LENGTH) {
+    len = MAX_MODULE_NAME_LENGTH;
+  }
+
+  // prepare and send our registation message
+  //
+  prepare_message(&msg, MAILBOX_HELLO, message_text, len);
+  send_message(fd, &msg);
+
+  return fd;
+}
+
+//---------------------------------------------------------------------
+
+
+// Read the `state_info_t` from the on disk text file.
+// Format is field (in caps) followed by the field value
+// separated by a single space.
+//
+// return:
+// 0 on success
+// non-zero on error
+//
+int get_state_info(state_info_t *_state) {
+  FILE *fp;
+  int ch = 1,
+      input_idx=0,
+      n=0,
+      field_len=0;
+  char buffer[LINE_BUFFER_SIZE],
+       *chp;
+
+  if (access(STATE_INFO_FILE, R_OK)!=0) {
+    return -1;
+  }
+
+  memset(buffer, 0, sizeof(char)*LINE_BUFFER_SIZE);
+
+  if ((fp = fopen(STATE_INFO_FILE, "r")) == NULL) {
+    return -1;
+  }
+
+  while (!feof(fp)) {
+    ch = fgetc(fp);
+    if ((ch == '\n') || (ch == EOF)) {
+
+      // ignore blank lines and comment lines
+      // (begining with '#')
+      //
+      if (input_idx == 0) { continue; }
+      if (buffer[0] == '#') {
+        buffer[0] = '\0';
+        input_idx = 0;
+        continue;
+      }
+
+      chp = strchr(buffer, ' ');
+      if (chp != NULL) {
+        chp++;
+
+        n = chp - buffer;
+
+        if (strncmp(buffer, "LAT ", n)==0) {
+          _state->lat = atof(chp);
         }
-      
-        if(retval == 0)
-        {
-            return MSG_NO_ACTION;  
+
+        else if (strncmp(buffer, "LON ", n)==0) {
+          _state->lon = atof(chp);
         }
-      
-        //If poll tells us that the fd is invalid or has encountered a serious error, return -1.
-        if(fds[0].revents & (POLLERR | POLLNVAL))
-        {
-            return MSG_ERROR;
+
+        else if (strncmp(buffer, "HEADING ", n)==0) {
+          _state->heading = atof(chp);
         }
-      
-        //If any of the events supplied in mask have occurred, report them.
-        if(fds[0].revents & mask)
-        {
-            return fds[0].revents & mask;
+
+        else if (strncmp(buffer, "VELOCITY ", n)==0) {
+          _state->velocity = atof(chp);
         }
-      
-        //if there are no more message to drain (see above) and a hangup has occurred, 
-        //let the user know the socket is done for.
-        if(fds[0].revents & POLLHUP)
-        {
-            return MSG_ERROR;
+
+        else if (strncmp(buffer, "NUM_SATS ", n)==0) {
+          _state->num_sats = atoi(chp);
         }
-      
-        //Otherwise, by process of elimination we have no message and no error condition to report
-        return MSG_NO_ACTION;
-      
-    } while(1);
-}
 
-//this function will pack a mailbox address and a payload into the supplied message structure and
-//set the correct timestamp.
-int prepare_message(struct message_record *target, char *mailbox, void *payload, unsigned int payload_len)
-{
-    if(target == NULL)
-        return -1;
-        
-    if(mailbox == NULL)
-        return -1;
-        
-    if(payload == NULL)
-        return -1;
-
-    if(payload_len > MAX_PAYLOAD_LENGTH)
-        return -1;
-
-    memset(target, 0, sizeof(struct message_record));
-            
-    strncpy(target->header.mailbox_name, mailbox, MAILBOX_NAME_MAX);
-    target->header.mailbox_name[MAILBOX_NAME_MAX] = '\0';
-    target->header.usec_time = get_usec_time();
-    target->header.payload_length = payload_len;
-    target->header.sender = getpid();
-    target->header.from_fd = 0;
-    
-    memmove(target->payload, payload, payload_len);
+        else if (strncmp(buffer, "GPS_GOOD ", n)==0) {
+          _state->gps_good = atoi(chp);
+        }
 
-    return 0;
-}
+        else if (strncmp(buffer, "STAMP ", n)==0) {
+          _state->stamp = (time_t)atoi(chp);
+        }
 
-//the send_message function will transmit a message and its header (trimmed to the specified payload length).
-//zero will be returned on success, -1 on failure.
-int send_message(int message_socket_fd, struct message_record *message)
-{
-    int txlen;
-    int retval;
-    
-    if(message == NULL)
-        return -1;
-
-    //If we are trying to send a message that is longer than allowed, throw an error!    
-    if(message->header.payload_length > MAX_PAYLOAD_LENGTH)
-        return -1;
-    
-    //Calculate the total message length (header + payload) so that we don't send
-    //any extra padding that we don't need.
-    txlen = sizeof(struct message_header_record) + message->header.payload_length;
-    
-    do
-    {
-        retval = send(message_socket_fd, message, txlen, MSG_EOR);
-    
-        //if we were interrupted by a signal, try again.
-        if( (retval == -1) && (errno == EINTR) )
-        {
-            continue;
+        else if (strncmp(buffer, "GPSTAMP ", n)==0) {
+          _state->gpstime = (time_t)atoi(chp);
         }
-    
-        //if we tried to send a message and it got truncated, return failure.
-        if(retval != txlen)
-        {
-            return -1;
+
+        else if (strncmp(buffer, "PADDLE ", n)==0) {
+          _state->paddle = atoi(chp);
         }
-    
-        return 0;
-        
-    } while(1);
-}
 
-//the get_message function will receive a message from the opposite end of the socket and place it in the
-//supplied message structure incliding its header.  -1 is returned on failure, 0 on success.
-int get_message(int message_socket_fd, struct message_record *message)
-{
-    int retval;
-   
-    if(message == NULL)
-        return -1; 
-
-    //clear our buffer of any garbage before using it to read in the message
-    memset(message, 0, sizeof(struct message_record));
-    
-    do
-    {
-        //try and receive our message
-        retval = recv(message_socket_fd, message, sizeof(struct message_record), 0);
-    
-        //if we were interrupted by a signal, try again.
-        if( (retval == -1) && (errno == EINTR) )
-        {
-            continue;
+        else if (strncmp(buffer, "ROUTE ", n)==0) {
+          _state->route = atoi(chp);
         }
-    
-        //zero is a special case for recv which indicates that the other side has shut down the connection.
-        if(retval == 0)
-        {
-            return -1;
+
+        else if (strncmp(buffer, "TRIP ", n)==0) {
+          _state->trip = atoi(chp);
         }
-    
-        //if the received message size does not add up (between header and payload) 
-        if(retval != (sizeof(struct message_header_record) + message->header.payload_length))
-        {
-            return -1;	//throw an error!
+
+        else if (strncmp(buffer, "STOP ", n)==0) {
+          _state->stop = atoi(chp);
         }
- 
-        //Record which IPC socket we got this from (for things like PING replies)
-        message->header.from_fd = message_socket_fd;
-    
-        return 0;	//otherwise, return success
-          
-    } while(1);
-}
 
-//This function connects to the communication hub and returns the file descriptor of the connection.
-//If the connection failed, -1 is returned.  The progname parameter (if not NULL) will be used to 
-//register a module name (snagged from argv[0]) with the server for ease of debugging.
-int connect_to_message_server(char *progname)
-{
-    int fd;
-    int retval;
-    int len;
-    char *message_text;
-    struct sockaddr_un addr;
-    
-    struct message_record msg;
-
-    fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
-
-    if(fd < 0)
-        return -1;
-
-    //construct our address structure (pointing to the agreed upon server address)
-    //to pass to connect.
-    addr.sun_family = AF_UNIX;
-    strncpy(addr.sun_path, COMMHUB_ADDRESS, sizeof(addr.sun_path) - 1);
-    addr.sun_path[sizeof(addr.sun_path) - 1]='\0';
-    len=strlen(COMMHUB_ADDRESS) + sizeof(addr.sun_family);
-
-    //attempt to connect to said server
-    retval = connect(fd,(struct sockaddr *)&addr,len);
-
-    if(retval)
-    {
-        fprintf(stderr, "Cannot connect to IPC hub at %s\n", COMMHUB_ADDRESS);
-        close(fd);
-        return -1;
-    }
+        else if (strncmp(buffer, "STOPNAME ", n)==0) {
+          field_len = input_idx - n;
+          if (field_len >= STATE_INFO_FIELD_SIZE) {
+            field_len = STATE_INFO_FIELD_SIZE-1;
+          }
+          memcpy(_state->stopname, chp, field_len);
+          _state->stopname[field_len] = '\0';
+        }
 
-    //if we have been passed a module name to register as, use that, otherwise default to "ANONYMOUS"
-    if(progname)
-    {
-        message_text = progname;
-    }
-    else
-    {
-        message_text = "ANONYMOUS";
+        else if (strncmp(buffer, "LOGGED_IN_DRIVER ", n)==0) {
+          _state->logged_in_driver = atoi(chp);
+        }
+
+        else if (strncmp(buffer, "DRIVER_NAME ", n)==0) {
+          field_len = input_idx - n;
+          if (field_len >= STATE_INFO_FIELD_SIZE) {
+            field_len = STATE_INFO_FIELD_SIZE-1;
+          }
+          memcpy(_state->driver_name, chp, input_idx - n + 1);
+          _state->driver_name[field_len] = '\0';
+        }
+
+        else if (strncmp(buffer, "EQUIP_NUM ", n)==0) {
+          _state->equip_num = atoi(chp);
+        }
+
+      }
+
+      buffer[0] = '\0';
+      input_idx = 0;
+      continue;
     }
-    
-    len = strlen(message_text);
-    
-    //if for some inconceivable reason our module name is longer than the server allows, truncate it.
-    if(len > MAX_MODULE_NAME_LENGTH)
-    {
-        len = MAX_MODULE_NAME_LENGTH;
+
+    buffer[input_idx] = ch;
+    input_idx++;
+    if (input_idx >= LINE_BUFFER_SIZE) {
+      input_idx = LINE_BUFFER_SIZE-1;
     }
+    buffer[input_idx] = '\0';
 
-    //prepare and send our registation message
-    prepare_message(&msg, MAILBOX_HELLO, message_text, len);
-    send_message(fd, &msg);
+  }
 
-    return fd;
+  fclose(fp);
+
+  return 0;
 }
 
-//---------------------------------------------------------------------
+// Save `state_info_t` on disk.
+// Format it field name (in caps) separated by
+// a single space followed by the field value.
+//
+// Constructs the text state file as a temporary file
+// (specified by STATE_INFO_TEMPFILE) then moves it
+// after it's finished.
+//
+// return:
+// 0 on success
+// non-zero on error
+//
+int set_state_info(state_info_t *_state) {
+  FILE *fp;
+
+  if ((fp = fopen(STATE_INFO_TEMPFILE, "w")) == NULL) {
+    return -1;
+  }
+
+  fprintf(fp, "# updated %lli\n", get_usec_time());
+  fprintf(fp, "# %s\n", _state->comment);
+
+  fprintf(fp, "LAT %f\n", _state->lat);
+  fprintf(fp, "LON %f\n", _state->lon);
+
+  fprintf(fp, "HEADING %f\n", _state->heading);
+  fprintf(fp, "VELOCITY %f\n", _state->velocity);
+
+  fprintf(fp, "NUM_SATS %i\n", _state->num_sats);
+  fprintf(fp, "GPS_GOOD %i\n", _state->gps_good);
+
+  fprintf(fp, "STAMP %i\n", (int)(_state->stamp));
+  fprintf(fp, "GPSTAMP %i\n", (int)(_state->gpstime));
+
+  fprintf(fp, "PADDLE %i\n", _state->paddle);
+  fprintf(fp, "ROUTE %i\n", _state->route);
+  fprintf(fp, "TRIP %i\n", _state->trip);
+  fprintf(fp, "STOP %i\n", _state->stop);
+
+  fprintf(fp, "STOPNAME %s\n", _state->stopname);
+
+  fprintf(fp, "LOGGED_IN_DRIVER %i\n", _state->logged_in_driver);
+  fprintf(fp, "DRIVER_NAME %s\n", _state->driver_name);
+  fprintf(fp, "EQUIP_NUM %i\n", _state->equip_num);
+
+  fclose(fp);
+
+  return rename(STATE_INFO_TEMPFILE, STATE_INFO_FILE);
+}
+
+// print out the state information
+int print_state_info(state_info_t *_state) {
+  FILE *fp = stdout;
+
+  fprintf(fp, "LAT %f\n", _state->lat);
+  fprintf(fp, "LON %f\n", _state->lon);
+
+  fprintf(fp, "HEADING %f\n", _state->heading);
+  fprintf(fp, "VELOCITY %f\n", _state->velocity);
+
+  fprintf(fp, "NUM_SATS %i\n", _state->num_sats);
+  fprintf(fp, "GPS_GOOD %i\n", _state->gps_good);
+
+  fprintf(fp, "STAMP %i\n", (int)(_state->stamp));
+  fprintf(fp, "GPSTAMP %i\n", (int)(_state->gpstime));
+
+  fprintf(fp, "PADDLE %i\n", _state->paddle);
+  fprintf(fp, "ROUTE %i\n", _state->route);
+  fprintf(fp, "TRIP %i\n", _state->trip);
+  fprintf(fp, "STOP %i\n", _state->stop);
+
+  fprintf(fp, "STOPNAME %s\n", _state->stopname);
+
+  fprintf(fp, "LOGGED_IN_DRIVER %i\n", _state->logged_in_driver);
+  fprintf(fp, "DRIVER_NAME %s\n", _state->driver_name);
+  fprintf(fp, "EQUIP_NUM %i\n", _state->equip_num);
+
+  return 0;
+}
 
 

+ 26 - 0
busunit/commhub/commhub.h

@@ -307,6 +307,32 @@ typedef struct driver_rulecall_struct
 
 } driver_rulecall;
 
+#define STATE_INFO_FIELD_SIZE (64)
+
+typedef struct state_info_struct {
+  double lat, lon, heading, velocity;
+  int num_sats;
+  int gps_good;
+
+  time_t stamp;
+  time_t gpstime;
+
+  int paddle;
+  int route, trip, stop;
+  double stop_lat, stop_lon;
+  char stopname[STATE_INFO_FIELD_SIZE];
+
+  int logged_in_driver;
+  char driver_name[STATE_INFO_FIELD_SIZE];
+  int equip_num;
+
+  char comment[STATE_INFO_FIELD_SIZE];
+} state_info_t;
+
+
+int get_state_info(state_info_t *);
+int set_state_info(state_info_t *);
+int print_state_info(state_info_t *);
 
 #endif	//#ifdef _TRANSIT_COMMHUB_API
 

File diff suppressed because it is too large
+ 1376 - 808
busunit/commhub/commserver.c


+ 3 - 0
busunit/common/common_config.h

@@ -333,6 +333,9 @@
 #define TOUCHSCREEN_CALIB_FILE  (CONFIG_FILE_PATH "touchscreen_calib.txt")
 #define AVLS_CONFIG_FILE  (CONFIG_FILE_PATH "avls_freq.txt")
 
+#define STATE_INFO_FILE (CONFIG_FILE_PATH "state.info")
+#define STATE_INFO_TEMPFILE (CONFIG_FILE_PATH "state.tmp")
+
 #define SERVER_LIST_FILE    (CONFIG_FILE_PATH "server/server_list")
 #define SERVER_DESC_FILE    (CONFIG_FILE_PATH "server/server_desc")
 

File diff suppressed because it is too large
+ 1206 - 656
busunit/common/common_defs.c


+ 83 - 55
busunit/common/common_defs.h

@@ -2,17 +2,17 @@
  * 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/>.
  *
@@ -25,6 +25,8 @@
 
 //#define COMMON_PRINT_WARNING
 
+#define DEBUG_PRINT
+
 //------------------------------- PASSDB_SLIM ----------------------------------
 
 #define CHECK_ALLOC_FAIL( x ) if (!(x)) { fprintf(stderr, "CHECK_ALLOC_FAIL: %s, line %i: (%s is null)\n", __FILE__, __LINE__, #x ); return FAIL_MEM; }
@@ -64,42 +66,42 @@
 //------------------------------- PROCESS DEATH MANAGEMENT ----------------------
 
 #ifdef USE_WATCHDOG_ALARM
-  
+
 //    #define WATCHDOG_DEBUG
 
     #ifdef WATCHDOG_DEBUG
-        #define WD_DEBUG_MSG(cmd, x)		printf("WD %s (%d seconds left)\n", (cmd), (x))
+        #define WD_DEBUG_MSG(cmd, x)    printf("WD %s (%d seconds left)\n", (cmd), (x))
     #else
-        #define WD_DEBUG_MSG(cmd, x)		(x)
+        #define WD_DEBUG_MSG(cmd, x)    (x)
     #endif
-  
+
 #endif
 
 //------------------- Watchdog Timer Related
 #ifdef USE_WATCHDOG_ALARM
-  #define RESET_WATCHDOG()		{WD_DEBUG_MSG("reset", alarm(MODULE_WATCHDOG_VALUE));}
+  #define RESET_WATCHDOG()    {WD_DEBUG_MSG("reset", alarm(MODULE_WATCHDOG_VALUE));}
 #else
-  #define RESET_WATCHDOG()		{/*nop*/}
+  #define RESET_WATCHDOG()    {/*nop*/}
 #endif
 //-------------------
 #ifdef USE_WATCHDOG_ALARM
-  #define RESET_WATCHDOG_LONG(x)		{WD_DEBUG_MSG("long_reset", alarm(MODULE_WATCHDOG_VALUE * (x)));}
+  #define RESET_WATCHDOG_LONG(x)    {WD_DEBUG_MSG("long_reset", alarm(MODULE_WATCHDOG_VALUE * (x)));}
 #else
-  #define RESET_WATCHDOG_LONG(x)		{/*nop*/}
+  #define RESET_WATCHDOG_LONG(x)    {/*nop*/}
 #endif
 //---------
 #ifdef USE_WATCHDOG_ALARM
-  #define STOP_WATCHDOG()		{WD_DEBUG_MSG("stopped",alarm(0));}
+  #define STOP_WATCHDOG()    {WD_DEBUG_MSG("stopped",alarm(0));}
 #else
-  #define STOP_WATCHDOG()		{/*nop*/}
+  #define STOP_WATCHDOG()    {/*nop*/}
 #endif
 //----------
 
 
-#define EXIT_REQUEST_NONE		(0)	//no exit is requested
-#define EXIT_REQUEST_POLITE		(1)	//we have an IPC message asking us to wind down
-#define EXIT_REQUEST_INT_TERM		(2)	//we caught a SIGINT or SIGTERM
-#define EXIT_REQUEST_CRASH		(4)	//the watchdog timer has overflowed, or a SEGV has occurred
+#define EXIT_REQUEST_NONE    (0)  //no exit is requested
+#define EXIT_REQUEST_POLITE    (1)  //we have an IPC message asking us to wind down
+#define EXIT_REQUEST_INT_TERM    (2)  //we caught a SIGINT or SIGTERM
+#define EXIT_REQUEST_CRASH    (4)  //the watchdog timer has overflowed, or a SEGV has occurred
 
 //This variable is populated by the signal handlers, and should be checked in main while loops.
 extern volatile int exit_request_status;
@@ -127,26 +129,26 @@ void request_polite_exit(int reason, char *fmt, ...);
 void configure_signal_handlers(char *procname);
 
 //------------------- database operation returns
-#define OKAY_MIN		(0)
+#define OKAY_MIN    (0)
 
-#define	FAIL_PARAM		(-1)
-#define	FAIL_DATABASE		(-2)
-#define	FAIL_DUPKEY		(-3)
-#define	FAIL_FULL		(-4)
-#define FAIL_MEM		(-5)
+#define  FAIL_PARAM    (-1)
+#define  FAIL_DATABASE    (-2)
+#define  FAIL_DUPKEY    (-3)
+#define  FAIL_FULL    (-4)
+#define FAIL_MEM    (-5)
 
-#define FAIL_MAX		(-1)
-#define FAIL_MIN		(-99)
+#define FAIL_MAX    (-1)
+#define FAIL_MIN    (-99)
 
-#define WARN_NOTFOUND		(-100)
-#define WARN_NOCHANGE		(-101)
+#define WARN_NOTFOUND    (-100)
+#define WARN_NOCHANGE    (-101)
 
-#define WARN_MAX		(-100)
-#define WARN_MIN		(-199)
+#define WARN_MAX    (-100)
+#define WARN_MIN    (-199)
 
-#define DB_OKAY(x)		( (x) >= 0 )
-#define DB_FAIL(x)		( ((x) <= FAIL_MAX) && ((x) > FAIL_MIN) )
-#define DB_WARN(x)		( ((x) <= WARN_MAX) && ((x) > WARN_MIN) )
+#define DB_OKAY(x)    ( (x) >= 0 )
+#define DB_FAIL(x)    ( ((x) <= FAIL_MAX) && ((x) > FAIL_MIN) )
+#define DB_WARN(x)    ( ((x) <= WARN_MAX) && ((x) > WARN_MIN) )
 
 //----------------- common utility functions
 
@@ -170,50 +172,50 @@ int strip_crlf(char *buffer);
 //
 //    When linemode = 1 read() will return a whole line at a time, and
 //  poll() and select() will not unblock on input from this device until
-//  either A) a whole line is available, or B) it's been ACCUM_SECONDS 
+//  either A) a whole line is available, or B) it's been ACCUM_SECONDS
 //  seconds since the last character has been received.
 //
 int open_rs232_device(char *devname, int custom_baud, int linemode);
 
 //Defines for the above
 
-#define USE_DEFAULT_BAUD	(0)
+#define USE_DEFAULT_BAUD  (0)
 //#define GPS_DEFAULT_BAUD (9600)
 #define GPS_DEFAULT_BAUD (115200)
 
-#define RS232_RAW		(0)
-#define RS232_LINE		(1)
+#define RS232_RAW    (0)
+#define RS232_LINE    (1)
 
 
 typedef struct device_test_vector_struct
 {
-    char 	*dev_id;		//Expected Device ID returned in the "/?: ?=device_id" message from device
-    char 	*init_string;		//Initialization String to send to device (Example "/0:Foo Bar\n/m:09 00 03 42 5A 44 56\r")
-    int 	n_reply_lines;		//Number of expected lines coming back from device...
-    char 	**reply_strings;	//An optional list of n_reply_lines where NULLs mean "don't care" and non-null 
-                                        //means reply line N much match supplied string (sans pre '/' garbage and 
+    char   *dev_id;    //Expected Device ID returned in the "/?: ?=device_id" message from device
+    char   *init_string;    //Initialization String to send to device (Example "/0:Foo Bar\n/m:09 00 03 42 5A 44 56\r")
+    int   n_reply_lines;    //Number of expected lines coming back from device...
+    char   **reply_strings;  //An optional list of n_reply_lines where NULLs mean "don't care" and non-null
+                                        //means reply line N much match supplied string (sans pre '/' garbage and
                                         //trailing '\r' and '\n' characters. Example:
                                         // {NULL, "/OK:m:09 00 03 42 5A 44 56", "/M:^"} means line 0 == Don't care, lines 1 and 2 must match their spec
-                                        
-    int 	init_tries;		//Number of times to try getting device ID		(0 == use default)
-    int		init_timeout;		//Number of milliseconds to wait for device ID reply.	(0 == use default)
+
+    int   init_tries;    //Number of times to try getting device ID    (0 == use default)
+    int    init_timeout;    //Number of milliseconds to wait for device ID reply.  (0 == use default)
 
 } device_test_vector;
 
 
 /*
-device_test_vector sample_dev_test_vector = 
+device_test_vector sample_dev_test_vector =
 {
-    .dev_id 		= "rider_ui",
-    .init_string	= "/0:\r/1:\r/m:09 00 03 42 5A 44 56\r",
-    .n_reply_lines	= 4, 
-    .reply_strings	= (char *[]){NULL, NULL, "/OK:m:09 00 03 42 5A 44 56", "/M:^"},
+    .dev_id     = "rider_ui",
+    .init_string  = "/0:\r/1:\r/m:09 00 03 42 5A 44 56\r",
+    .n_reply_lines  = 4,
+    .reply_strings  = (char *[]){NULL, NULL, "/OK:m:09 00 03 42 5A 44 56", "/M:^"},
 };
 
 */
 
-#define DEV_INIT_BUFFER_SIZE	(256)
-#define DIAG_BUFFER_SIZE	(DEV_INIT_BUFFER_SIZE * 4)
+#define DEV_INIT_BUFFER_SIZE  (256)
+#define DIAG_BUFFER_SIZE  (DEV_INIT_BUFFER_SIZE * 4)
 
 //This function takes a file descriptor, a pointer to a test vector structure,
 //and an optional diagnostic output string (this string must be at least DIAG_BUFFER_SIZE
@@ -233,7 +235,7 @@ int test_and_init_device(int fd, device_test_vector *vec, char *diag);
 
 
 #define PKG_STRING_SIZE (64)
-#define PKG_STRING_FORMAT "%63s"	//for use in sscanf format string.  Eeew...
+#define PKG_STRING_FORMAT "%63s"  //for use in sscanf format string.  Eeew...
 
 typedef struct package_signature_struct
 {
@@ -243,7 +245,7 @@ typedef struct package_signature_struct
     time_t installed;
 
 } package_signature;
-                
+
 
 //    This function fills up to n package_signature structures with the name, version, md5 checksum, and install time of
 //installed packages as gleaned from the package management dropfiles in the configuration directory.  This is useful for
@@ -264,11 +266,37 @@ int get_equip_num();
 int set_equip_num(int num);
 
 
-#define SERVER_DESC_LEN	(64)
-#define MAX_SERVER_LIST	(16)
+#define SERVER_DESC_LEN  (64)
+#define MAX_SERVER_LIST  (16)
 
 //This ges the current server description into the supplied buffer up to N characters
 int get_server_desc(char *desc, int len);
 
+/*
+#define STATE_INFO_FIELD_SIZE (64)
+
+typedef struct state_info_struct {
+  double lat, lon, heading, velocity;
+  int num_sats;
+  int gps_good;
+
+  time_t stamp;
+  time_t gpstime;
+
+  int paddle;
+  int route, trip, stop;
+  double stop_lat, stop_lon;
+  char stopname[STATE_INFO_FIELD_SIZE];
+
+  int logged_in_driver;
+  char driver_name[STATE_INFO_FIELD_SIZE];
+  int equip_num;
+} state_info_t;
+
+int get_state_info(state_info_t *);
+int set_state_info(state_info_t *);
+int print_state_info(state_info_t *);
+*/
+
 #endif
 

+ 1 - 1
busunit/gps/README.md

@@ -1,7 +1,7 @@
 `gps_minder`
 ===
 
-This file listens on the GPS `tty` interface (`/dev/ttyGPS`) for GPS
+This program listens on the GPS `tty` interface (`/dev/ttyGPS`) for GPS
 messages and sends messages to the Inter Process Communications (IPC) hub
 with GPS updates.
 

+ 28 - 3
busunit/gps/gps_main.c

@@ -35,13 +35,16 @@
 #include "../commhub/commhub.h"
 #include "../commhub/client_utils.h"
 
+#define GPS_MINDER_VERSION "2.1.1"
+
 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};
+gps_status my_gps_stat = {0};
+state_info_t my_state_info = {0};
 
 time_t mkgmtime(struct tm *tm);
 
@@ -526,16 +529,38 @@ int main(int argc, char **argv) {
   time_t now;
   time_t last_stale_gps_check = 0;
 
+#ifdef DEBUG_PRINT
   long long int _usec_now, _usec_prv, _usec_del;
   _usec_now = get_usec_time();
   _usec_prv = _usec_now;
   _usec_del = 60000000;
+#endif
 
   long long int _usec_ratelimit_now, _usec_ratelimit_prv, _usec_ratelimit_del;
   _usec_ratelimit_now = get_usec_time();
   _usec_ratelimit_del = 1000000;
   _usec_ratelimit_prv = _usec_ratelimit_now - _usec_ratelimit_del;
 
+  if ( (argc>1) && (
+        (strncmp(argv[1], "-h", 3)==0) ||
+        (strncmp(argv[1], "-v", 3)==0) ) ) {
+    printf("gps_minder version: %s\n", GPS_MINDER_VERSION);
+    exit(0);
+  }
+
+  // Restore GPS state in case `gps_minder` has been restarted
+  //
+  get_state_info(&my_state_info);
+  my_gps_stat.lat = my_state_info.lat;
+  my_gps_stat.lon = my_state_info.lon;
+  my_gps_stat.heading = my_state_info.heading;
+  my_gps_stat.velocity = my_state_info.velocity;
+  my_gps_stat.num_sats = my_state_info.num_sats;
+  my_gps_stat.gps_good = my_state_info.gps_good;
+  my_gps_stat.stamp = my_state_info.stamp;
+  my_gps_stat.gpstime = my_state_info.gpstime;
+
+
   // Configure our signal handlers to deal with SIGINT, SIGTERM, etc... 
   // and make graceful exits while logging
   //
@@ -556,13 +581,13 @@ int main(int argc, char **argv) {
 
     RESET_WATCHDOG();
 
-    //DEBUG
+#ifdef DEBUG_PRINT
     _usec_now = get_usec_time();
     if ((_usec_now - _usec_prv) > _usec_del) {
       printf("[%lli] gps_minder: heartbeat\n", get_usec_time());
       _usec_prv = _usec_now;
     }
-    //DEBUG
+#endif
 
     maintain_ipc_hub_connect(argv[0]);
 

+ 4 - 2
busunit/paddlemgr/paddlemgr.c

@@ -431,10 +431,12 @@ int main(int argc, char **argv) {
 
   struct message_record incoming_msg;
 
+#ifdef DEBUG_PRINT
   long long int _usec_now, _usec_prv, _usec_del;
   _usec_now = get_usec_time();
   _usec_prv = _usec_now;
   _usec_del = 60000000;
+#endif
 
   configure_signal_handlers(argv[0]);
   maintain_ipc_hub_connect(argv[0]);
@@ -455,14 +457,14 @@ int main(int argc, char **argv) {
 
     RESET_WATCHDOG();
 
-    //DEBUG
+#ifdef DEBUG_PRINT
     _usec_now = get_usec_time();
     if ((_usec_now - _usec_prv) > _usec_del) {
       printf("[%lli] paddlemgr: heartbeat\n", get_usec_time());
       fflush(stdout);
       _usec_prv = _usec_now;
     }
-    //DEBUG
+#endif
 
     maintain_ipc_hub_connect(argv[0]);
 

+ 4 - 2
busunit/passdb/pass_communication.c

@@ -1041,10 +1041,12 @@ int main(int argc, char **argv)
     int input_idx = 0;
     int checked_idx = 0;
 
+#ifdef DEBUG_PRINT
 		long long int _usec_now, _usec_prv, _usec_del;
 		_usec_now = get_usec_time();
 		_usec_prv = _usec_now;
 		_usec_del = 60000000;
+#endif
 
     passdb_context ctx = {0};
 
@@ -1105,13 +1107,13 @@ int main(int argc, char **argv)
 
         RESET_WATCHDOG();
 
-        //DEBUG
+#ifdef DEBUG_PRINT
         _usec_now = get_usec_time();
         if ((_usec_now - _usec_prv) > _usec_del) {
           printf("[%lli] passdb: heartbeat\n", get_usec_time());
           _usec_prv = _usec_now;
         }
-        //DEBUG
+#endif
 
 
         maintain_ipc_hub_connect(argv[0]);

+ 187 - 187
busunit/passdb/tinyscheme1.39/scheme-private.h

@@ -1,187 +1,187 @@
-/* scheme-private.h */
-
-#ifndef _SCHEME_PRIVATE_H
-#define _SCHEME_PRIVATE_H
-
-#include "scheme.h"
-/*------------------ Ugly internals -----------------------------------*/
-/*------------------ Of interest only to FFI users --------------------*/
-
-
-enum scheme_port_kind { 
-  port_free=0, 
-  port_file=1, 
-  port_string=2, 
-  port_input=16, 
-  port_output=32 
-};
-
-typedef struct port {
-  unsigned char kind;
-  union {
-    struct {
-      FILE *file;
-      int closeit;
-    } stdio;
-    struct {
-      char *start;
-      char *past_the_end;
-      char *curr;
-    } string;
-  } rep;
-} port;
-
-/* cell structure */
-struct cell {
-  unsigned int _flag;
-  union {
-    struct {
-      char   *_svalue;
-      int   _length;
-    } _string;
-    num _number;
-    port *_port;
-    foreign_func _ff;
-    struct {
-      struct cell *_car;
-      struct cell *_cdr;
-    } _cons;
-  } _object;
-};
-
-struct scheme {
-/* arrays for segments */
-func_alloc malloc;
-func_dealloc free;
-
-/* return code */
-int retcode;
-int tracing;
-
-#define CELL_SEGSIZE    5000  /* # of cells in one segment */
-#define CELL_NSEGMENT   10    /* # of segments for cells */
-char *alloc_seg[CELL_NSEGMENT];
-pointer cell_seg[CELL_NSEGMENT];
-int     last_cell_seg;
-
-/* We use 4 registers. */
-pointer args;            /* register for arguments of function */
-pointer envir;           /* stack register for current environment */
-pointer code;            /* register for current code */
-pointer dump;            /* stack register for next evaluation */
-
-int interactive_repl;    /* are we in an interactive REPL? */
-
-struct cell _sink;
-pointer sink;            /* when mem. alloc. fails */
-struct cell _NIL;
-pointer NIL;             /* special cell representing empty cell */
-struct cell _HASHT;
-pointer T;               /* special cell representing #t */
-struct cell _HASHF;
-pointer F;               /* special cell representing #f */
-struct cell _EOF_OBJ;
-pointer EOF_OBJ;         /* special cell representing end-of-file object */
-pointer oblist;          /* pointer to symbol table */
-pointer global_env;      /* pointer to global environment */
-
-/* global pointers to special symbols */
-pointer LAMBDA;               /* pointer to syntax lambda */
-pointer QUOTE;           /* pointer to syntax quote */
-
-pointer QQUOTE;               /* pointer to symbol quasiquote */
-pointer UNQUOTE;         /* pointer to symbol unquote */
-pointer UNQUOTESP;       /* pointer to symbol unquote-splicing */
-pointer FEED_TO;         /* => */
-pointer COLON_HOOK;      /* *colon-hook* */
-pointer ERROR_HOOK;      /* *error-hook* */
-pointer SHARP_HOOK;  /* *sharp-hook* */
-
-pointer free_cell;       /* pointer to top of free cells */
-long    fcells;          /* # of free cells */
-
-pointer inport;
-pointer outport;
-pointer save_inport;
-pointer loadport;
-
-#define MAXFIL 64
-port load_stack[MAXFIL];     /* Stack of open files for port -1 (LOADing) */
-int nesting_stack[MAXFIL];
-int file_i;
-int nesting;
-
-char    gc_verbose;      /* if gc_verbose is not zero, print gc status */
-char    no_memory;       /* Whether mem. alloc. has failed */
-
-#define LINESIZE 1024
-char    linebuff[LINESIZE];
-char    strbuff[256];
-
-FILE *tmpfp;
-int tok;
-int print_flag;
-pointer value;
-int op;
-
-void *ext_data;     /* For the benefit of foreign functions */
-long gensym_cnt;
-
-struct scheme_interface *vptr;
-void *dump_base;	 /* pointer to base of allocated dump stack */
-int dump_size;		 /* number of frames allocated for dump stack */
-};
-
-/* operator code */
-enum scheme_opcodes { 
-#define _OP_DEF(A,B,C,D,E,OP) OP, 
-#include "opdefines.h" 
-  OP_MAXDEFINED 
-}; 
-
-
-#define cons(sc,a,b) _cons(sc,a,b,0)
-#define immutable_cons(sc,a,b) _cons(sc,a,b,1)
-
-int is_string(pointer p);
-char *string_value(pointer p);
-int is_number(pointer p);
-num nvalue(pointer p);
-long ivalue(pointer p);
-double rvalue(pointer p);
-int is_integer(pointer p);
-int is_real(pointer p);
-int is_character(pointer p);
-long charvalue(pointer p);
-int is_vector(pointer p);
-
-int is_port(pointer p);
-
-int is_pair(pointer p);
-pointer pair_car(pointer p);
-pointer pair_cdr(pointer p);
-pointer set_car(pointer p, pointer q);
-pointer set_cdr(pointer p, pointer q);
-
-int is_symbol(pointer p);
-char *symname(pointer p);
-int hasprop(pointer p);
-
-int is_syntax(pointer p);
-int is_proc(pointer p);
-int is_foreign(pointer p);
-char *syntaxname(pointer p);
-int is_closure(pointer p);
-#ifdef USE_MACRO
-int is_macro(pointer p);
-#endif
-pointer closure_code(pointer p);
-pointer closure_env(pointer p);
-
-int is_continuation(pointer p);
-int is_promise(pointer p);
-int is_environment(pointer p);
-int is_immutable(pointer p);
-void setimmutable(pointer p);
-
-#endif
+/* scheme-private.h */
+
+#ifndef _SCHEME_PRIVATE_H
+#define _SCHEME_PRIVATE_H
+
+#include "scheme.h"
+/*------------------ Ugly internals -----------------------------------*/
+/*------------------ Of interest only to FFI users --------------------*/
+
+
+enum scheme_port_kind {
+  port_free=0,
+  port_file=1,
+  port_string=2,
+  port_input=16,
+  port_output=32
+};
+
+typedef struct port {
+  unsigned char kind;
+  union {
+    struct {
+      FILE *file;
+      int closeit;
+    } stdio;
+    struct {
+      char *start;
+      char *past_the_end;
+      char *curr;
+    } string;
+  } rep;
+} port;
+
+/* cell structure */
+struct cell {
+  unsigned int _flag;
+  union {
+    struct {
+      char   *_svalue;
+      int   _length;
+    } _string;
+    num _number;
+    port *_port;
+    foreign_func _ff;
+    struct {
+      struct cell *_car;
+      struct cell *_cdr;
+    } _cons;
+  } _object;
+};
+
+struct scheme {
+/* arrays for segments */
+func_alloc malloc;
+func_dealloc free;
+
+/* return code */
+int retcode;
+int tracing;
+
+#define CELL_SEGSIZE    5000  /* # of cells in one segment */
+#define CELL_NSEGMENT   10    /* # of segments for cells */
+char *alloc_seg[CELL_NSEGMENT];
+pointer cell_seg[CELL_NSEGMENT];
+int     last_cell_seg;
+
+/* We use 4 registers. */
+pointer args;            /* register for arguments of function */
+pointer envir;           /* stack register for current environment */
+pointer code;            /* register for current code */
+pointer dump;            /* stack register for next evaluation */
+
+int interactive_repl;    /* are we in an interactive REPL? */
+
+struct cell _sink;
+pointer sink;            /* when mem. alloc. fails */
+struct cell _NIL;
+pointer NIL;             /* special cell representing empty cell */
+struct cell _HASHT;
+pointer T;               /* special cell representing #t */
+struct cell _HASHF;
+pointer F;               /* special cell representing #f */
+struct cell _EOF_OBJ;
+pointer EOF_OBJ;         /* special cell representing end-of-file object */
+pointer oblist;          /* pointer to symbol table */
+pointer global_env;      /* pointer to global environment */
+
+/* global pointers to special symbols */
+pointer LAMBDA;               /* pointer to syntax lambda */
+pointer QUOTE;           /* pointer to syntax quote */
+
+pointer QQUOTE;               /* pointer to symbol quasiquote */
+pointer UNQUOTE;         /* pointer to symbol unquote */
+pointer UNQUOTESP;       /* pointer to symbol unquote-splicing */
+pointer FEED_TO;         /* => */
+pointer COLON_HOOK;      /* *colon-hook* */
+pointer ERROR_HOOK;      /* *error-hook* */
+pointer SHARP_HOOK;  /* *sharp-hook* */
+
+pointer free_cell;       /* pointer to top of free cells */
+long    fcells;          /* # of free cells */
+
+pointer inport;
+pointer outport;
+pointer save_inport;
+pointer loadport;
+
+#define MAXFIL 64
+port load_stack[MAXFIL];     /* Stack of open files for port -1 (LOADing) */
+int nesting_stack[MAXFIL];
+int file_i;
+int nesting;
+
+char    gc_verbose;      /* if gc_verbose is not zero, print gc status */
+char    no_memory;       /* Whether mem. alloc. has failed */
+
+#define LINESIZE 1024
+char    linebuff[LINESIZE];
+char    strbuff[256];
+
+FILE *tmpfp;
+int tok;
+int print_flag;
+pointer value;
+int op;
+
+void *ext_data;     /* For the benefit of foreign functions */
+long gensym_cnt;
+
+struct scheme_interface *vptr;
+void *dump_base;   /* pointer to base of allocated dump stack */
+int dump_size;     /* number of frames allocated for dump stack */
+};
+
+/* operator code */
+enum scheme_opcodes {
+#define _OP_DEF(A,B,C,D,E,OP) OP,
+#include "opdefines.h"
+  OP_MAXDEFINED
+};
+
+
+#define cons(sc,a,b) _cons(sc,a,b,0)
+#define immutable_cons(sc,a,b) _cons(sc,a,b,1)
+
+int is_string(pointer p);
+char *string_value(pointer p);
+int is_number(pointer p);
+num nvalue(pointer p);
+long ivalue(pointer p);
+double rvalue(pointer p);
+int is_integer(pointer p);
+int is_real(pointer p);
+int is_character(pointer p);
+long charvalue(pointer p);
+int is_vector(pointer p);
+
+int is_port(pointer p);
+
+int is_pair(pointer p);
+pointer pair_car(pointer p);
+pointer pair_cdr(pointer p);
+pointer set_car(pointer p, pointer q);
+pointer set_cdr(pointer p, pointer q);
+
+int is_symbol(pointer p);
+char *symname(pointer p);
+int hasprop(pointer p);
+
+int is_syntax(pointer p);
+int is_proc(pointer p);
+int is_foreign(pointer p);
+char *syntaxname(pointer p);
+int is_closure(pointer p);
+#ifdef USE_MACRO
+int is_macro(pointer p);
+#endif
+pointer closure_code(pointer p);
+pointer closure_env(pointer p);
+
+int is_continuation(pointer p);
+int is_promise(pointer p);
+int is_environment(pointer p);
+int is_immutable(pointer p);
+void setimmutable(pointer p);
+
+#endif

File diff suppressed because it is too large
+ 774 - 774
busunit/passdb/tinyscheme1.39/scheme.c