Bläddra i källkod

adding DIU debugging tools, removing cruft

* passdb_inspect to look at the passdb.mem file (only dumps
  entries and does simple load timing)
* billdb_inspect to look at the billdb.mem file (only dumps
  entries)
* remove commented code cruft from common_defs.[ch]
* renamed `set_state_info` to `save_state_info` to indicate
  the file is saved to system rather than some internal update
abetusk 4 år sedan
förälder
incheckning
d4bf25d8e1

+ 2 - 0
.gitignore

@@ -60,3 +60,5 @@ server/diu_packager/package/*
 
 # exclude binaries
 busunit/helper/gpsdist
+busunit/debug/passdb_inspect
+busunit/debug/billdb_inspect

+ 4 - 4
busunit/client_supervisor/client_supervisor.c

@@ -39,7 +39,7 @@
 #include "../commhub/commhub.h"
 #include "../commhub/client_utils.h"
 
-#define CLIENT_SUPERVISOR_VERSION "2.1.1"
+#define CLIENT_SUPERVISOR_VERSION "2.1.2"
 
 // Number of modules we are actively tracking
 //
@@ -809,7 +809,7 @@ message_callback_return handle_gps_message(struct message_record *msg, void *par
   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);
+  save_state_info(&state_info);
 
   return MESSAGE_HANDLED_CONT;
 }
@@ -825,7 +825,7 @@ static message_callback_return handle_stop_message(struct message_record *msg, v
   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);
+  save_state_info(&state_info);
 
   return MESSAGE_HANDLED_CONT;
 }
@@ -841,7 +841,7 @@ static message_callback_return handle_driver_message(struct message_record *msg,
   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);
+  save_state_info(&state_info);
 
   return MESSAGE_HANDLED_CONT;
 }

+ 1 - 1
busunit/commhub/commhub.c

@@ -455,7 +455,7 @@ int get_state_info(state_info_t *_state) {
 // 0 on success
 // non-zero on error
 //
-int set_state_info(state_info_t *_state) {
+int save_state_info(state_info_t *_state) {
   FILE *fp;
 
   if ((fp = fopen(STATE_INFO_TEMPFILE, "w")) == NULL) {

+ 1 - 1
busunit/commhub/commhub.h

@@ -331,7 +331,7 @@ typedef struct state_info_struct {
 
 
 int get_state_info(state_info_t *);
-int set_state_info(state_info_t *);
+int save_state_info(state_info_t *);
 int print_state_info(state_info_t *);
 
 #endif	//#ifdef _TRANSIT_COMMHUB_API

+ 0 - 457
busunit/common/common_defs.c

@@ -248,463 +248,6 @@ int set_equip_num(int num) {
 
 //
 
-/*
-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] == '#') { continue; }
-
-      chp = strchr(buffer, ' ');
-      if (chp != NULL) {
-        chp++;
-
-        n = chp - buffer;
-
-        if (strncmp(buffer, "LAT ", n)==0) {
-          _state->lat = atof(chp+1);
-        }
-
-        else if (strncmp(buffer, "LON ", n)==0) {
-          _state->lon = atof(chp+1);
-        }
-
-        else if (strncmp(buffer, "HEADING ", n)==0) {
-          _state->heading = atof(chp+1);
-        }
-
-        else if (strncmp(buffer, "VELOCITY ", n)==0) {
-          _state->velocity = atof(chp+1);
-        }
-
-        else if (strncmp(buffer, "NUM_SATS ", n)==0) {
-          _state->num_sats = atoi(chp+1);
-        }
-
-        else if (strncmp(buffer, "GPS_GOOD ", n)==0) {
-          _state->gps_good = atoi(chp+1);
-        }
-
-        else if (strncmp(buffer, "STAMP ", n)==0) {
-          _state->stamp = (time_t)atoi(chp+1);
-        }
-
-        else if (strncmp(buffer, "GPSTAMP ", n)==0) {
-          _state->gpstime = (time_t)atoi(chp+1);
-        }
-
-        else if (strncmp(buffer, "PADDLE ", n)==0) {
-          _state->paddle = atoi(chp+1);
-        }
-
-        else if (strncmp(buffer, "ROUTE ", n)==0) {
-          _state->route = atoi(chp+1);
-        }
-
-        else if (strncmp(buffer, "TRIP ", n)==0) {
-          _state->trip = atoi(chp+1);
-        }
-
-        else if (strncmp(buffer, "STOP ", n)==0) {
-          _state->stop = atoi(chp+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';
-        }
-
-        else if (strncpy(buffer, "LOGGED_IN_DRIVER ", n)==0) {
-          _state->logged_in_driver = atoi(chp+1);
-        }
-
-        else if (strncpy(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+1, input_idx - n + 1);
-          _state->driver_name[field_len] = '\0';
-        }
-
-        else if (strncmp(buffer, "EQUIP_NUM ", n)==0) {
-          _state->equip_num = atoi(chp+1);
-        }
-
-      }
-
-      buffer[0] = '\0';
-      input_idx = 0;
-      continue;
-    }
-
-    buffer[input_idx] = ch;
-    input_idx++;
-    if (input_idx >= LINE_BUFFER_SIZE) {
-      input_idx = LINE_BUFFER_SIZE-1;
-    }
-    buffer[input_idx] = '\0';
-
-  }
-
-  fclose(fp);
-
-  return 0;
-}
-
-// save on disk state
-//
-int set_state_info(state_info_t *_state) {
-  FILE *fp;
-
-  if ((fp = fopen(STATE_INFO_TEMPFILE, "w")) == NULL) {
-    return -1;
-  }
-
-  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);
-}
-
-// save on disk state
-//
-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;
-}
-*/
-
-/*
-int get_driver_state(driver_status *_driver_stat) {
-  FILE *fp;
-  int input_idx=0,
-      n=0,
-      ch;
-  char buffer[LINE_BUFFER_SIZE];
-
-  // 0 - logged_in_driver
-  // 1 - driver_name
-  // 2 - equip_num
-  //
-  int _read_state = 0;
-
-  if (access(DRIVER_STATE_FILE, R_OK)!=0) {
-    return -1;
-  }
-
-  memset(buffer, 0, sizeof(char)*LINE_BUFFER_SIZE);
-
-  n = DRIVER_NAME_LEN;
-  if (LINE_BUFFER_SIZE < n) {
-    n = LINE_BUFFER_SIZE;
-  }
-
-  fp = fopen(DRIVER_STATE_FILE, "r");
-  while ( (ch = fgetc(fp)) != EOF ) {
-
-    if ((ch == '\n') || (ch == EOF)) {
-
-      if (_read_state == 0) {
-        _driver_stat->logged_in_driver = atoi(buffer);
-        _read_state++;
-      }
-      else if (_read_state == 1) {
-
-        n = input_idx+1;
-        if (n > DRIVER_NAME_LEN) {
-          n = DRIVER_NAME_LEN;
-        }
-        buffer[n-1] = '\0';
-
-        memcpy(_driver_stat->driver_name, buffer, n);
-        _read_state++;
-      }
-      else if (_read_state == 2) {
-        _driver_stat->equip_num = atoi(buffer);
-        _read_state++;
-      }
-
-      memset(buffer, 0, sizeof(char)*LINE_BUFFER_SIZE);
-      input_idx=0;
-      continue;
-    }
-
-    buffer[input_idx] = ch;
-    input_idx++;
-    if (input_idx >= LINE_BUFFER_SIZE) {
-      input_idx = LINE_BUFFER_SIZE-1;
-      buffer[LINE_BUFFER_SIZE-1] = 0;
-    }
-  }
-  fclose(fp);
-
-  if (_read_state < 3) {
-    return -2;
-  }
-
-  return 0;
-}
-
-
-int get_stop_state(stop_status *_stop_stat) {
-  FILE *fp;
-  int input_idx=0,
-      n=0,
-      ch;
-  char buffer[LINE_BUFFER_SIZE];
-
-  // 0 - paddle
-  // 1 - route
-  // 2 - trip
-  // 3 - stop
-  // 4 - lat
-  // 5 - lon
-  // 6 - stopname
-  //
-  int _read_state = 0;
-
-  if (access(STOP_STATE_FILE, R_OK)!=0) {
-    return -1;
-  }
-
-  memset(buffer, 0, sizeof(char)*LINE_BUFFER_SIZE);
-
-  fp = fopen(DRIVER_STATE_FILE, "r");
-  while ( (ch = fgetc(fp)) != EOF ) {
-
-    if ((ch == '\n') || (ch == EOF)) {
-
-      if (_read_state == 0) {
-        _stop_stat->paddle= atoi(buffer);
-        _read_state++;
-      }
-      else if (_read_state == 1) {
-        _stop_stat->route = atoi(buffer);
-        _read_state++;
-      }
-
-      else if (_read_state == 2) {
-        _stop_stat->trip = atoi(buffer);
-        _read_state++;
-      }
-
-      else if (_read_state == 3) {
-        _stop_stat->stop= atoi(buffer);
-        _read_state++;
-      }
-
-      else if (_read_state == 4) {
-        _stop_stat->lat = atof(buffer);
-        _read_state++;
-      }
-
-      else if (_read_state == 5) {
-        _stop_stat->lon = atof(buffer);
-        _read_state++;
-      }
-
-      else if (_read_state == 6) {
-
-        n = input_idx+1;
-        if (n > STOP_NAME_LEN) {
-          n = DRIVER_NAME_LEN;
-        }
-        buffer[n-1] = '\0';
-
-        memcpy(_stop_stat->stopname, buffer, n);
-        _read_state++;
-      }
-
-      memset(buffer, 0, sizeof(char)*LINE_BUFFER_SIZE);
-      input_idx=0;
-      continue;
-    }
-
-    buffer[input_idx] = ch;
-    input_idx++;
-    if (input_idx >= LINE_BUFFER_SIZE) {
-      input_idx = LINE_BUFFER_SIZE-1;
-      buffer[LINE_BUFFER_SIZE-1] = 0;
-    }
-  }
-  fclose(fp);
-
-  if (_read_state < 6) {
-    return -2;
-  }
-
-  return 0;
-
-
-}
-
-
-int get_gps_state(gps_status *_gps_stat) {
-  FILE *fp;
-  int input_idx=0,
-      ch;
-  char buffer[LINE_BUFFER_SIZE];
-
-  // 0 - lat
-  // 1 - lon
-  // 2 - heading
-  // 3 - velocity
-  // 4 - num_sats
-  // 5 - gps_good
-  // 6 - stamp
-  // 7 - gpstime
-  //
-  int _read_state = 0;
-
-  if (access(GPS_STATE_FILE, R_OK)!=0) {
-    return -1;
-  }
-
-  memset(buffer, 0, sizeof(char)*LINE_BUFFER_SIZE);
-
-  fp = fopen(DRIVER_STATE_FILE, "r");
-  while ( (ch = fgetc(fp)) != EOF ) {
-
-    if ((ch == '\n') || (ch == EOF)) {
-
-      if (_read_state == 0) {
-        _gps_stat->lat = atof(buffer);
-        _read_state++;
-      }
-
-      else if (_read_state == 1) {
-        _gps_stat->lon = atof(buffer);
-        _read_state++;
-      }
-
-      else if (_read_state == 2) {
-        _gps_stat->heading = atof(buffer);
-        _read_state++;
-      }
-
-      else if (_read_state == 3) {
-        _gps_stat->velocity = atof(buffer);
-        _read_state++;
-      }
-
-      else if (_read_state == 4) {
-        _gps_stat->num_sats = atoi(buffer);
-        _read_state++;
-      }
-
-      else if (_read_state == 5) {
-        _gps_stat->gps_good = atoi(buffer);
-        _read_state++;
-      }
-
-      else if (_read_state == 6) {
-        _gps_stat->stamp = (time_t)atoi(buffer);
-        _read_state++;
-      }
-
-      else if (_read_state == 7) {
-        _gps_stat->gpstime = (time_t)atoi(buffer);
-        _read_state++;
-      }
-
-      memset(buffer, 0, sizeof(char)*LINE_BUFFER_SIZE);
-      input_idx=0;
-      continue;
-    }
-
-    buffer[input_idx] = ch;
-    input_idx++;
-    if (input_idx >= LINE_BUFFER_SIZE) {
-      input_idx = LINE_BUFFER_SIZE-1;
-      buffer[LINE_BUFFER_SIZE-1] = 0;
-    }
-  }
-  fclose(fp);
-
-  if (_read_state < 7) {
-    return -2;
-  }
-
-  return 0;
-}
-*/
-
-
-
 int get_server_desc(char *desc, int len) {
   char svrname[LINE_BUFFER_SIZE];
   FILE *f;

+ 0 - 26
busunit/common/common_defs.h

@@ -272,31 +272,5 @@ int set_equip_num(int num);
 //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
 

+ 158 - 0
busunit/debug/billdb_inspect.c

@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2021 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 <stdio.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <unistd.h>
+
+#include <string.h>
+#include <ctype.h>
+
+#include <getopt.h>
+#include <errno.h>
+
+#include "../common/common_config.h"
+#include "../billdb/billdb.h"
+
+#define VERSION "0.1.0"
+
+void _version(FILE *fp) {
+  fprintf(fp, "version: %s\n", VERSION);
+}
+
+void _usage(FILE *fp) {
+  _version(fp);
+  fprintf(fp, "usage:\n\n");
+  fprintf(fp, "    billdb_inspect [-h] [-v] [billdb]\n\n");
+  fprintf(fp, "  [billdb]       billdbd file (defualt '%s')\n", BILLING_FILE);
+  fprintf(fp, "  [-h]           help (this screen)\n");
+  fprintf(fp, "  [-v]           show version\n");
+  fprintf(fp, "\n");
+}
+
+struct option g_long_option[] = {
+  {"version", no_argument, 0, 'v'},
+  {"help", no_argument, 0, 'h'},
+  {0,0,0,0}
+};
+
+char *g_bill_file = NULL;
+
+int main(int argc, char **argv) {
+  int i, j, k;
+
+  extern char *optarg;
+  extern int optind;
+  int option_index;
+
+  int ch;
+  int retcode = 0;
+  int fd;
+
+  ssize_t del_s=0;
+  size_t offset=0, bill_size=0;
+
+  billing_record *billmem = NULL;
+
+  while ((ch = getopt_long(argc, argv, "hv", g_long_option, &option_index)) > 0) switch(ch) {
+    case 'h':
+      _usage(stdout);
+      exit(0);
+      break;
+    case 'v':
+      _version(stdout);
+      exit(0);
+      break;
+    case 0:
+    default:
+      fprintf(stderr, "bad option (%i, %i)\n", option_index, (int)ch);
+      _usage(stderr);
+      exit(-2);
+      break;
+  }
+
+  if (optind < argc) {
+    g_bill_file = strdup(argv[optind]);
+  } else {
+    g_bill_file = strdup(BILLING_FILE);
+  }
+
+  //---
+
+  bill_size = sizeof(billing_record)*NUM_BILLING_ENTRIES;
+  billmem = (billing_record *)malloc(bill_size);
+  fd = open(g_bill_file, O_RDONLY);
+  if (fd<0) {
+    perror(g_bill_file);
+    retcode = -1;
+    goto free_and_exit;
+  }
+
+  while (offset < bill_size) {
+    del_s = read(fd, ((void *)billmem) + offset, bill_size - offset);
+    if (del_s<0) {
+      perror(g_bill_file);
+      goto free_and_exit;
+    }
+
+    offset += del_s;
+  }
+  close(fd);
+
+  //---
+
+  for (i=0; i<NUM_BILLING_ENTRIES; i++) {
+    printf("[%4i] ", i);
+    for (j=0; j<BILLING_LINE_SIZE; j++) {
+      if (isalpha(billmem[i].data[j])) {
+        printf("%c", billmem[i].data[j]);
+      }
+      else {
+        printf(".");
+      }
+    }
+
+    printf(" (");
+    for (j=0; j<BILLING_CHECKSUM_SIZE; j++) {
+      printf("%02x", billmem[i].checksum[j]);
+    }
+
+    printf(")\n");
+  }
+
+
+  //---
+
+free_and_exit:
+  if (g_bill_file) {
+    free(g_bill_file);
+  }
+
+  if (billmem) {
+    free(billmem);
+  }
+
+  exit(retcode);
+}

+ 24 - 0
busunit/debug/buildit.sh

@@ -0,0 +1,24 @@
+#!/bin/bash
+#
+# 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/>.
+#
+
+
+
+gcc -D TARGET_DEVEL_DESKTOP -I ../common/ -I ../commhub/ -I ../billdb billdb_inspect.c -o billdb_inspect
+gcc -D TARGET_DEVEL_DESKTOP -I ../common/ -I ../commhub/ -I ../passdb passdb_inspect.c -o passdb_inspect

+ 211 - 0
busunit/debug/passdb_inspect.c

@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2021 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 <stdio.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <sys/time.h>
+
+#include <unistd.h>
+
+#include <string.h>
+#include <ctype.h>
+
+#include <getopt.h>
+#include <errno.h>
+
+#include "../common/common_config.h"
+#include "../passdb/passdb.h"
+
+#define VERSION "0.1.0"
+
+void _version(FILE *fp) {
+  fprintf(fp, "version: %s\n", VERSION);
+}
+
+void _usage(FILE *fp) {
+  _version(fp);
+  fprintf(fp, "usage:\n\n");
+  fprintf(fp, "    passdb_inspect [-h] [-v] [passdb]\n\n");
+  fprintf(fp, "  [passdb]       passdb file (defualt '%s')\n", PASSES_FILE);
+  fprintf(fp, "  [-h]           help (this screen)\n");
+  fprintf(fp, "  [-v]           show version\n");
+  fprintf(fp, "\n");
+}
+
+struct option g_long_option[] = {
+  {"version", no_argument, 0, 'v'},
+  {"help", no_argument, 0, 'h'},
+  {0,0,0,0}
+};
+
+char *g_pass_file = NULL;
+
+double del_tv( struct timeval *tv_e, struct timeval *tv_s) {
+  double d=0.0;
+
+  d += (double)(tv_e->tv_sec - tv_s->tv_sec) * (1000000.0);
+  d += (double)(tv_e->tv_usec - tv_s->tv_usec);
+
+  return d;
+}
+
+int main(int argc, char **argv) {
+  int i, j, k;
+
+  extern char *optarg;
+  extern int optind;
+  int option_index;
+
+  int ch;
+  int retcode = 0;
+  int fd;
+
+  ssize_t del_s=0;
+  size_t offset=0, pass_size=0;
+
+  rider_record *passmem = NULL;
+
+  struct timeval tv_s, tv_e;
+
+  while ((ch = getopt_long(argc, argv, "hv", g_long_option, &option_index)) > 0) switch(ch) {
+    case 'h':
+      _usage(stdout);
+      exit(0);
+      break;
+    case 'v':
+      _version(stdout);
+      exit(0);
+      break;
+    case 0:
+    default:
+      fprintf(stderr, "bad option (%i, %i)\n", option_index, (int)ch);
+      _usage(stderr);
+      exit(-2);
+      break;
+  }
+
+  if (optind < argc) {
+    g_pass_file = strdup(argv[optind]);
+  } else {
+    g_pass_file = strdup(PASSES_FILE);
+  }
+
+  //---
+
+  gettimeofday(&tv_s, NULL);
+
+  pass_size = sizeof(rider_record)*NUM_STORED_PASSES;
+  passmem = (rider_record *)malloc(pass_size);
+  fd = open(g_pass_file, O_RDONLY);
+  if (fd<0) {
+    perror(g_pass_file);
+    retcode = -1;
+    goto free_and_exit;
+  }
+
+  while (offset < pass_size) {
+    del_s = read(fd, ((void *)passmem) + offset, pass_size - offset);
+    if (del_s<0) {
+      perror(g_pass_file);
+      goto free_and_exit;
+    }
+
+    offset += del_s;
+  }
+  close(fd);
+
+  gettimeofday(&tv_e, NULL);
+
+  printf("## loaded in %f\n", del_tv(&tv_e, &tv_s));
+
+  //---
+
+  for (i=0; i<NUM_STORED_PASSES; i++) {
+
+    if (passmem[i].seq == 0) { continue; }
+
+    printf("[%4i] ", i);
+    printf(" %8lli %8lli ", passmem[i].seq, passmem[i].id);
+
+    for (j=0; j<CREDENTIAL_LEN; j++) {
+
+      //printf("%2x", passmem[i].magstripe_value[j]);
+      //continue;
+
+      if (isprint(passmem[i].magstripe_value[j])) {
+        printf("%c", passmem[i].magstripe_value[j]);
+      }
+      else {
+        printf(".");
+      }
+    }
+
+    printf(" ");
+    for (j=0; j<CREDENTIAL_LEN; j++) {
+      if (isprint(passmem[i].rfid_value[j])) {
+        printf("%c", passmem[i].rfid_value[j]);
+      }
+      else {
+        printf(".");
+      }
+    }
+
+    printf(" ");
+    for (j=0; j<RULENAME_LEN; j++) {
+      if (isprint(passmem[i].rule_name[j])) {
+        printf("%c", passmem[i].rule_name[j]);
+      }
+      else {
+        printf(".");
+      }
+    }
+
+    printf(" ");
+    for (j=0; j<PARAM_LEN; j++) {
+      if (isprint(passmem[i].rule_param[j])) {
+        printf("%c", passmem[i].rule_param[j]);
+      }
+      else {
+        printf(".");
+      }
+    }
+    printf("\n");
+
+  }
+
+
+  //---
+
+free_and_exit:
+  if (g_pass_file) {
+    free(g_pass_file);
+  }
+
+  if (passmem) {
+    free(passmem);
+  }
+
+  exit(retcode);
+}

+ 140 - 0
busunit/passdb/README.md

@@ -0,0 +1,140 @@
+`passdb`
+===
+
+`passdb` is responsible for checking fares against the rule set, updating the local
+pass database and communicating formatted billing entries to the inter-process communication
+(IPC) hub.
+
+The main fare media are RFID and mag stripe cards.
+There are also "manual" fares that can be issued by the driver,
+in most/all cases from the DIU process, for things like cash fares
+or other non media fare acceptances.
+
+`passdb` connects to a central server for updates to card and pass information.
+The card and pass updates are updated in the local database.
+The local database is used to ensure that if there is a loss of connectivity,
+the most recent card and pass information will be used.
+
+By default, `passdb` connects to the central server through a system wide tunnel
+through the localhost, `127.0.0.1`, on port `7277`.
+
+Database Structure
+---
+
+`passdb` uses a local database of cards and passes.
+The database is, by default, located in `/home/bus/database/passes.mem`.
+See `busunit/common/common_config.h` for details.
+
+The pass database is a fixed record flat file.
+Each record mirrors the in memory struct and is as follows:
+
+```
+| seq_num | logical_card_id | magstripe_value | rfid_value | rule_name | rule_param |
+```
+
+| Field Name | Type | Byte Length | Description |
+|---|---|---|
+| `seq` | `unsigned long long`  | `8` | Sequence number of entry |
+| `logical_card_id` | `unsigned long long` | `8` | Logical ID of card |
+| `magstripe_value` | `charCREDENTIAL_LEN]` | `32` | ASCII string of magstripe token |
+| `rfid_value` | `char[CREDENTIAL_LEN]` | `32` | ASCII string of RFID token |
+| `rule_name` | `char[RULENAME_LEN]` | `24` | ASCII string of rule name |
+| `rule_param` | `char[PARAM_LEN]` | `24` | ASCII string of rule parameter |
+
+The structure is created to be an exact power of two (`8+8+32+32+24+24=128`).
+Currently, the number of entries is `1048576` (`2^20` or just over 1M).
+
+When messages are received for local fare updates, the database is updated appropriately
+and pass updates are sent via billing messages that are handled by the appropriate processes.
+
+Server updates to cards and passes override entries in the local database.
+This serves to allow for "quick" fare updates, for example, many NRIDE passes being used locally
+and not allowing more than the appropriate number of rides, while allowing for "slower"
+updates from the server to propagate back and update cards and passes to reach eventual
+consistency.
+
+The pass database is memory mapped if possible to keep on-disk consistent with the in memory
+representation.
+
+`passdb` stores the latest sequence number (`seq` above) to know what its latest entry is
+and to send back to the central server for incremental updates relative to the most current
+sequenc number.
+
+In Memory State
+---
+
+`passdb` creates three hashes to facilitate quick lookup, an ID hash, a magstripe hash and an RF hash.
+
+Each hash list uses the appropriate hash of its field (`logical_car_id`, `magstripe_value`, `rfid_value`)
+to put it in a "bucket", which then resolves to a linear linked list to traverse.
+
+Additions and deletions update the appropriate in memory hash list.
+
+Each hash entry stores the index into the flat file pass database.
+
+Rules
+---
+
+`passdb` loads a the scheme file `rules.scm` (located by default in `/home/bus/config/rules.scm`) to
+process complex rule logic.
+By pushing the rules into a scheme file, complex rules for fare acceptance can be created and customized
+depending on need.
+
+`passdb` exposes a few functions to the underlying `rules.scm` file:
+
+| Funciton | Description |
+|---|---|
+| `debug_print_nonl` | Debug print |
+| `debug_print` | Debug print |
+| `tell_rider` | Send a PIU message |
+| `accept_fare_no_passback` | Accept a fare without updating the passback state |
+| `drop_vault` | Drop vault cash vault on bus (deprecated) |
+| `accept_fare` | Accept fare updating the passback state |
+| `reject_fare` | Reject fare |
+| `handle_rule_error` | Handle rule error (display message to driver, etc.) |
+| `get_stopnum` | Get the stop number |
+| `get_routenum` | Get the route number (the floor route number divided by 100) |
+| `get_longroutenum` | Get the complete route number |
+| `get_tripnum` | Get the trip number |
+| `get_time` | Get the time in `HH:MM` format |
+| `get_date` | Get the date in `YYYY-mm-dd` format |
+| `get_day_of_week` | Get the day of week |
+| `get_gps` | Get the GPS position (latitude and longitude) |
+| `get_rulename` | Get the current rule name (e.g. for billing log purposes) |
+| `get_ruleparam` | Get the rule parameter (e.g. for NRide or NDay processing) |
+| `scheme_set_lookaside` | |
+| `scheme_get_lookaside` | |
+| `get_lookaside_param` | |
+| `scheme_strtok` | |
+| `gps_distance` | Return GPS distance of two GPS positions as returned by `get_gps` |
+
+
+The `rules.scm` file is processed using `tinyscheme`.
+Rules can be re-loaded on a HUP signal to the `passdb` process.
+
+`init.scm` holds common functions that can be used in the `rules.scm` file.
+`init.scm` is loaded before the `rules.scm` file is loaded and will be reloaded on a HUP signal.
+
+Additional Information
+---
+
+The `passdb` listens to the following messages:
+
+| Message Type | Action |
+|---|---|
+| `MAILBOX_UPDATE_PASSES` | A pass update from the central server indicating an entry in the local pass database should be updated |
+| `MAILBOX_FLUSH_PASSES` | A message to recreate the pass database by asking for all current passes |
+| `MAILBOX_STATUS_REQUEST` | Status request |
+| `MAILBOX_TOKEN_RFID` | Handle an RFID fare media presenteation |
+| `MAILBOX_TOKEN_MAG` | Handle a magstripe fare media presentation |
+| `MAILBOX_RULE_CALL` | Handle a generic rule call |
+| `MAILBOX_GPS_STATUS` | Update "anti-passback" logic to allow for NDay rules to be allowed |
+| `MAILBOX_STOP_STATUS` | Update "anti-passback" logic to allow for NDay rules to be allowed |
+
+---
+
+Though `billdb` is the process that communicates billing messages back to the central server, `passdb` is the process
+that originally formats the message through a call to `format_billing_message`.
+
+Additional log messages (through calls to `format_log_message`) are also contructed here and find their way to the `diagnostic_log` table
+in the central server.