| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868 |
- /*
- * Copyright (c) 2019 Clementine Computing LLC.
- *
- * This file is part of PopuFare.
- *
- * PopuFare is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * PopuFare is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with PopuFare. If not, see <https://www.gnu.org/licenses/>.
- *
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <errno.h>
- #include <string.h>
- #include <time.h>
- #include <stdarg.h>
- #include "../common/common_defs.h"
- #include "commhub.h"
- #include "client_utils.h"
- gps_status gps_stat = {0};
- stop_status stop_stat = {0};
- driver_status driver_stat = {0};
- pass_status pass_stat = {0};
- bill_status bill_stat = {0};
- state_info_t state_info = {0};
- //-----------------------------------------------------------------
- float effective_lat() {
- if (gps_stat.gps_good) {
- return (float)gps_stat.lat;
- }
- else {
- return (float)stop_stat.lat;
- }
- }
- float effective_lon() {
- if (gps_stat.gps_good) {
- return (float)gps_stat.lon;
- }
- else {
- return (float)stop_stat.lon;
- }
- }
- //-----------------------------------------------------------------
- typedef struct message_callback_struct {
- char mailbox[MAILBOX_NAME_MAX + 1];
- int ident;
- message_notify_func callback;
- void *param;
- struct message_callback_struct *next;
- } message_callback;
- static message_callback *dispatch_list_head = NULL;
- //This function registers a callback to happen when a certain message is received.
- //It takes four parameters:
- // mailbox = string containing name of mailbox to trigger this callback
- // ident = a numeric identifier specifying both a unique identifier for this callback, and processing order
- // func = a message handling callback function
- // param = an untyped pointer used to pass any outside contect to the callback
- //
- int register_dispatch_callback(char *mailbox, int ident, message_notify_func func, void *param) {
- message_callback *p, *q, *n;
- if (!func || !mailbox) {
- return -1;
- }
- q = NULL;
- p = dispatch_list_head;
- // Scan our existing list
- //
- while (p) {
- // stop when we find a node with an identifier greater than ident or run off the end
- //
- if (p->ident > ident) {
- break;
- }
- q = p;
- p = p->next;
- }
- n = (message_callback *)malloc(sizeof(message_callback));
- if (n == NULL) {
- return -1;
- }
- // clear our new node
- //
- memset(n, 0, sizeof(message_callback));
- // copy our match string
- //
- strncpy(n->mailbox, mailbox, MAILBOX_NAME_MAX);
- // null terminate
- //
- n->mailbox[MAILBOX_NAME_MAX] = '\0';
- // record our identifier
- //
- n->ident = ident;
- // callback
- //
- n->callback = func;
- // and parameter
- //
- n->param = param;
- // register our next pointer as per above scan's determined insert point
- //
- n->next = p;
- // If we're inserting at the head of the lsit
- //
- if (q == NULL) {
- // set the list head to n
- //
- dispatch_list_head = n;
- }
- else {
- // tweak the next pointer of the previous node to perform the insertion
- //
- q->next = n;
- }
- return 0;
- }
- // This function unregisters a message callback function by its mailbox name and identifier
- // this allows for easy selective removal of a specific callback while still keeping the rest of the chain intact
- //
- int unregister_dispatch_callback(char *mailbox, int ident) {
- message_callback *p, *q;
- // if we have a bogus mailbox, give up
- //
- if (!mailbox) {
- return -1;
- }
- q = NULL;
- p = dispatch_list_head;
- // Scan our callback list looking for the identifier in question
- //
- while (p) {
- // if we find a mailbox with both a matching identifier and mailbox name, that's the one...
- //
- if ( (p->ident == ident) && !strncmp(mailbox, p->mailbox, MAILBOX_NAME_MAX) ) {
- break;
- }
- q = p;
- p = p->next;
- }
- // if we didn't find it, that is reported by the < 0 return value
- //
- if (p == NULL) {
- return -1;
- }
- // If we are removing at the head...
- //
- if (q == NULL) {
- // advance the head pointer down the list
- //
- dispatch_list_head = p->next;
- }
- else {
- // snip the node in question out mid-list
- //
- q->next = p->next;
- }
- // free the node in question
- //
- free(p);
- return 0;
- }
- // This function unregisters ALL callbacks in preparation for a clean exit
- //
- int unregister_all_callbacks() {
- message_callback *p, *q;
- q = NULL;
- p = dispatch_list_head;
- // traverse the list freeing all nodes
- //
- while (p) {
- q = p;
- p = p->next;
- free(q);
- }
- // reset our list pointers to empty state
- //
- dispatch_list_head = NULL;
- return 0;
- }
- // This function is used to translate any special "Command" messages (things addressed
- // by module or PID rather than mailbox, where the payload is a mailbox name for special
- // notifications (primarily MAILBOX_PING and MAILBOX_EXIT).
- //
- static int process_addressed_message(struct message_record *msg) {
- struct message_record translated_msg;
- // If this message is special...
- //
- if ( (!strncmp((char *)msg->payload, MAILBOX_PING, MAILBOX_NAME_MAX)) ||
- (!strncmp((char *)msg->payload, MAILBOX_HUP, MAILBOX_NAME_MAX)) ||
- (!strncmp((char *)msg->payload, MAILBOX_EXIT, MAILBOX_NAME_MAX)) ) {
- // Copy the message as a whole
- //
- memcpy(&translated_msg, msg, sizeof(translated_msg));
- // Then change its mailbox name to the special mailbox specified in the payload
- //
- strncpy(translated_msg.header.mailbox_name, (char *)msg->payload, MAILBOX_NAME_MAX);
- translated_msg.header.mailbox_name[MAILBOX_NAME_MAX] = '\0'; //this is not a bug, since mailbox_name is defined as MAILBOX_NAME_MAX + 1 bytes long
- // Go and feed this through the callback chain as if it originally came on on the actual mailbox...
- //
- process_message(&translated_msg);
- return 0;
- }
- return 0;
- }
- //---
- // Update _state_info with _gps_stat
- //
- int update_state_info_with_gps(state_info_t *_state_info, gps_status *_gps_stat) {
- _state_info->lat = _gps_stat->lat;
- _state_info->lon = _gps_stat->lon;
- _state_info->heading = _gps_stat->heading;
- _state_info->velocity = _gps_stat->velocity;
- _state_info->num_sats = _gps_stat->num_sats;
- _state_info->gps_good = _gps_stat->gps_good;
- _state_info->stamp = _gps_stat->stamp;
- _state_info->gpstime = _gps_stat->gpstime;
- return 0;
- }
- // Update _state_info with _stop_stat
- //
- int update_state_info_with_stop(state_info_t *_state_info, stop_status *_stop_stat) {
- _state_info->paddle = _stop_stat->paddle;
- _state_info->route = _stop_stat->route;
- _state_info->trip = _stop_stat->trip;
- _state_info->stop = _stop_stat->stop;
- _state_info->stop_lat = _stop_stat->lat;
- _state_info->stop_lon = _stop_stat->lon;
- memcpy(_state_info->stopname, _stop_stat->stopname, ( STATE_INFO_FIELD_SIZE < STOP_NAME_LEN ) ? STATE_INFO_FIELD_SIZE : STOP_NAME_LEN );
- _state_info->stopname[STATE_INFO_FIELD_SIZE-1] = '\0';
- return 0;
- }
- // Update _state_info with _driver_stat
- //
- int update_state_info_with_driver(state_info_t *_state_info, driver_status *_driver_stat) {
- _state_info->logged_in_driver = _driver_stat->logged_in_driver;
- memcpy(_state_info->driver_name, _driver_stat->driver_name, ( STATE_INFO_FIELD_SIZE < DRIVER_NAME_LEN) ? STATE_INFO_FIELD_SIZE : DRIVER_NAME_LEN );
- _state_info->driver_name[STATE_INFO_FIELD_SIZE-1] = '\0';
- _state_info->equip_num = _driver_stat->equip_num;
- return 0;
- }
- // Load global variable, state_info, with stat information,
- // stored in local file.
- // Other global variables might need to be initalized based
- // on the state_info so this function was created to help
- // facilitate that in the future, if needed.
- //
- int init_state_info(void) {
- get_state_info(&state_info);
- return 0;
- }
- //---
- // This function actually processes a message through the dispatch list
- // using the return values of the callbacks to determine whether to stop or continue
- // the return value is the return value of the last handler to have read the message.
- // a return value of MESSAGE_UNHANDLED means that no handler successfully handled the message.
- message_callback_return process_message(struct message_record *msg) {
- message_callback *p = dispatch_list_head;
- message_callback_return ret = MESSAGE_UNHANDLED;
- // if there is no message
- //
- if (msg == NULL) {
- // we can't handle it
- //
- return ret;
- }
- // Walk through this list of handlers (which is maintained sorted by ident)
- //
- while (p) {
- // if the message's mailbox matches the callback's mailbox
- //
- if (!strncmp(msg->header.mailbox_name, p->mailbox, MAILBOX_NAME_MAX)) {
- // go and run the callback
- //
- ret = p->callback(msg, p->param);
- // if this callback requested a STOP, do so
- //
- if (ret == MESSAGE_HANDLED_STOP) {
- break;
- }
- }
- // otherwise, keep going...
- //
- p = p->next;
- }
- // If nobody has said STOP yet, see if this is an individually addressed message
- //
- if ( (msg->header.mailbox_name[0] == ':') || (msg->header.mailbox_name[0] == '>') ) {
- process_addressed_message(msg);
- }
- return ret;
- }
- //------------------------------------ SOME USEFUL DEFAULT CALLBACKS -------------------------------------------
- message_callback_return ignore_message(struct message_record *msg, void *param) {
- return MESSAGE_HANDLED_STOP;
- }
- //------------------------------------ SYSTEM CALLBACKS -------------------------------------------------------
- static message_callback_return update_gps_status(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
- return MESSAGE_HANDLED_CONT;
- }
- static message_callback_return update_stop_status(struct message_record *msg, void *param) {
- // guard against version mismatch
- //
- if (msg->header.payload_length != sizeof(stop_status)) {
- return MESSAGE_HANDLED_STOP;
- }
- // otherwise, update our structure
- //
- memcpy(&stop_stat, msg->payload, sizeof(stop_status));
- return MESSAGE_HANDLED_CONT;
- }
- static message_callback_return update_driver_status(struct message_record *msg, void *param) {
- // guard against version mismatch
- //
- if (msg->header.payload_length != sizeof(driver_status)) {
- return MESSAGE_HANDLED_STOP;
- }
- // otherwise, update our structure
- //
- memcpy(&driver_stat, msg->payload, sizeof(driver_stat));
- return MESSAGE_HANDLED_CONT;
- }
- static message_callback_return update_bill_status(struct message_record *msg, void *param) {
- // guard against version mismatch
- //
- if (msg->header.payload_length != sizeof(bill_status)) {
- return MESSAGE_HANDLED_STOP;
- }
- // otherwise, update our structure
- //
- memcpy(&bill_stat, msg->payload, sizeof(bill_stat));
- return MESSAGE_HANDLED_CONT;
- }
- static message_callback_return update_pass_status(struct message_record *msg, void *param) {
- // guard against version mismatch
- //
- if (msg->header.payload_length != sizeof(pass_status)) {
- return MESSAGE_HANDLED_STOP;
- }
- memcpy(&pass_stat, msg->payload, sizeof(pass_stat)); //otherwise, update our structure
- return MESSAGE_HANDLED_CONT;
- }
- static message_callback_return polite_exit_request_message(struct message_record *msg, void *param) {
- request_polite_exit(EXIT_REQUEST_POLITE, "%s", (char *)msg->payload);
- return MESSAGE_HANDLED_CONT;
- }
- static message_callback_return hup_request_message(struct message_record *msg, void *param) {
- request_hup("HUP(%s)", (char *)msg->payload);
- return MESSAGE_HANDLED_CONT;
- }
- static message_callback_return ping_request_message(struct message_record *msg, void *param) {
- struct message_record outgoing;
- prepare_message(&outgoing, MAILBOX_PONG, msg->payload, msg->header.payload_length);
- send_message(msg->header.from_fd, &outgoing);
- return MESSAGE_HANDLED_CONT;
- }
- // This function unregisters the default system status callbacks
- //
- int unregister_system_status_callbacks() {
- unregister_dispatch_callback(MAILBOX_GPS_STATUS, CALLBACK_SYSTEM);
- unregister_dispatch_callback(MAILBOX_STOP_STATUS, CALLBACK_SYSTEM);
- unregister_dispatch_callback(MAILBOX_DRIVER_STATUS, CALLBACK_SYSTEM);
- unregister_dispatch_callback(MAILBOX_PASS_STATUS, CALLBACK_SYSTEM);
- unregister_dispatch_callback(MAILBOX_BILL_STATUS, CALLBACK_SYSTEM);
- unregister_dispatch_callback(MAILBOX_EXIT, CALLBACK_SYSTEM);
- unregister_dispatch_callback(MAILBOX_HUP, CALLBACK_SYSTEM);
- unregister_dispatch_callback(MAILBOX_PING, CALLBACK_SYSTEM);
- return 0;
- }
- // This function registers the default system status callbacks
- int register_system_status_callbacks() {
- unregister_system_status_callbacks();
- register_dispatch_callback(MAILBOX_GPS_STATUS, CALLBACK_SYSTEM, update_gps_status, NULL);
- register_dispatch_callback(MAILBOX_STOP_STATUS, CALLBACK_SYSTEM, update_stop_status, NULL);
- register_dispatch_callback(MAILBOX_DRIVER_STATUS, CALLBACK_SYSTEM, update_driver_status, NULL);
- register_dispatch_callback(MAILBOX_PASS_STATUS, CALLBACK_SYSTEM, update_pass_status, NULL);
- register_dispatch_callback(MAILBOX_BILL_STATUS, CALLBACK_SYSTEM, update_bill_status, NULL);
- register_dispatch_callback(MAILBOX_EXIT, CALLBACK_SYSTEM, polite_exit_request_message, NULL);
- register_dispatch_callback(MAILBOX_HUP, CALLBACK_SYSTEM, hup_request_message, NULL);
- register_dispatch_callback(MAILBOX_PING, CALLBACK_SYSTEM, ping_request_message, NULL);
- return 0;
- }
- // This function subscribes to a handful of essential messages
- //
- int subscribe_to_default_messages(int fd) {
- struct message_record outgoing_msg;
- if (fd < 0) {
- return -1;
- }
- //------------- things that keep us informed about the other modules
- prepare_message(&outgoing_msg, MAILBOX_SUBSCRIBE, MAILBOX_GPS_STATUS, strlen(MAILBOX_GPS_STATUS));
- send_message(fd, &outgoing_msg);
- prepare_message(&outgoing_msg, MAILBOX_SUBSCRIBE, MAILBOX_STOP_STATUS, strlen(MAILBOX_STOP_STATUS));
- send_message(fd, &outgoing_msg);
- prepare_message(&outgoing_msg, MAILBOX_SUBSCRIBE, MAILBOX_DRIVER_STATUS, strlen(MAILBOX_DRIVER_STATUS));
- send_message(fd, &outgoing_msg);
- prepare_message(&outgoing_msg, MAILBOX_SUBSCRIBE, MAILBOX_PASS_STATUS, strlen(MAILBOX_PASS_STATUS));
- send_message(fd, &outgoing_msg);
- prepare_message(&outgoing_msg, MAILBOX_SUBSCRIBE, MAILBOX_BILL_STATUS, strlen(MAILBOX_BILL_STATUS));
- send_message(fd, &outgoing_msg);
- //------------- things that every process should have a crack at
- prepare_message(&outgoing_msg, MAILBOX_SUBSCRIBE, MAILBOX_STATUS_REQUEST, strlen(MAILBOX_STATUS_REQUEST));
- send_message(fd, &outgoing_msg);
- prepare_message(&outgoing_msg, MAILBOX_SUBSCRIBE, MAILBOX_EXIT, strlen(MAILBOX_EXIT));
- send_message(fd, &outgoing_msg);
- prepare_message(&outgoing_msg, MAILBOX_SUBSCRIBE, MAILBOX_HUP, strlen(MAILBOX_HUP));
- send_message(fd, &outgoing_msg);
- prepare_message(&outgoing_msg, MAILBOX_SUBSCRIBE, MAILBOX_PING, strlen(MAILBOX_PING));
- send_message(fd, &outgoing_msg);
- return 0;
- }
- //--------------------------------------------------------------------------------------------------------------
- int compress_tabs_to_spaces(char *dest, char *src, int n) {
- int i;
- for (i=0; i < n; i++) {
- switch (src[i]) {
- case '\t':
- case '\r':
- case '\n':
- dest[i] = ' ';
- break;
- default:
- dest[i] = src[i];
- break;
- }
- if (src[i] == '\0') {
- break;
- }
- }
- return 0;
- }
- // This function is a printf-line interface to format user display messages:
- //
- // target = blank IPC message to fill with this log entry
- // line = which line of the display to draw on (0 or 1)
- // priority = what message priority?
- // duration = how many seconds to display this (0 makes it the default message)
- // fmt = printf format
- // ... = printf args
- //
- int format_piu_message(struct message_record *target, int line, int priority, int duration, const char *fmt, ...) {
- piu_message pmsg = {0};
- va_list ap;
- pmsg.line = line;
- pmsg.priority = priority;
- pmsg.seconds = duration;
- va_start(ap, fmt);
- vsnprintf(pmsg.message, PIU_MESSAGE_LEN, fmt, ap);
- va_end(ap);
- return prepare_message(target, MAILBOX_PIU_MESSAGE, &pmsg, sizeof(pmsg));
- }
- // This function takes a buffer and a buffer size and puts a
- // log prefix in that contains the equipment number and the local time
- //
- int make_log_prefix(char *prefix, int max) {
- int eqnum;
- time_t foo;
- struct tm t;
- foo = time(NULL);
- localtime_r(&foo, &t);
- // If the driver interface module has a current EQ num
- //
- if (driver_stat.equip_num > 0) {
- // use it so as not to thrash the file system
- //
- eqnum = driver_stat.equip_num;
- }
- else {
- // otherwise, get it off disk
- //
- eqnum = get_equip_num();
- }
- return snprintf(prefix, max, "EQ# %d %04d-%02d-%02d %02d:%02d:%02d ", eqnum, t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
- }
- // This function is a printf-line interface to format log messages for the server:
- //
- // target = blank IPC message to fill with this log entry
- // loglevel = one of the following: LOGLEVEL_DEBUG, LOGLEVEL_WARN, LOGLEVEL_ERROR
- // fmt = printf format
- // ... = printf args
- //
- // NOTE: DO NOT UNDER ANY CIRCUMSTANCES TERMINATE A LOG MESSAGE WITH A '\n' CHARACTER!
- //
- int format_log_message(struct message_record *target, char loglevel, const char *fmt, ...) {
- int len = 0;
- char payload[MAX_PAYLOAD_LENGTH] = {0};
- va_list ap;
- if (!target || !fmt) {
- return -1;
- }
- switch (loglevel) {
- case LOGLEVEL_DEBUG:
- case LOGLEVEL_WARN:
- case LOGLEVEL_ERROR:
- payload[0] = loglevel;
- len += 1;
- break;
- default:
- payload[0] = LOGLEVEL_ERROR;
- len += 1;
- break;
- }
- len += make_log_prefix(payload + len, MAX_PAYLOAD_LENGTH - len);
- va_start(ap, fmt);
- len += vsnprintf(payload + len, MAX_PAYLOAD_LENGTH - len, fmt, ap);
- va_end(ap);
- return prepare_message(target, MAILBOX_BILLING_LOG, payload, len);
- }
- // This function printf-line interface to format messages for debug and trace purposes
- //
- int format_trace_message(struct message_record *target, const char *fmt, ...) {
- int len = 0;
- char payload[MAX_PAYLOAD_LENGTH] = {0};
- va_list ap;
- if (!target || !fmt) {
- return -1;
- }
- va_start(ap, fmt);
- len += vsnprintf(payload + len, MAX_PAYLOAD_LENGTH - len, fmt, ap);
- va_end(ap);
- return prepare_message(target, "DEBUG_TRACE", payload, len);
- }
- // This function is a printf-line interface to format messages for the driver:
- //
- // target = blank IPC message to fill with this log entry
- // loglevel = one of the following: LOGLEVEL_DEBUG, LOGLEVEL_WARN, LOGLEVEL_ERROR
- // fmt = printf format
- // ... = printf args
- //
- // NOTE: DO NOT UNDER ANY CIRCUMSTANCES TERMINATE A LOG MESSAGE WITH A '\n' CHARACTER!
- //
- int format_driver_message(struct message_record *target, char loglevel, const char *fmt, ...) {
- int len = 0;
- char payload[MAX_PAYLOAD_LENGTH] = {0};
- va_list ap;
- if (!target || !fmt) {
- return -1;
- }
- switch(loglevel) {
- case LOGLEVEL_DEBUG:
- case LOGLEVEL_WARN:
- case LOGLEVEL_ERROR:
- case LOGLEVEL_ACCEPT:
- case LOGLEVEL_REJECT:
- case LOGLEVEL_EVENT:
- payload[0] = loglevel;
- len += 1;
- break;
- default:
- payload[0] = LOGLEVEL_ERROR;
- len += 1;
- break;
- }
- va_start(ap, fmt);
- len += vsnprintf(payload + len, MAX_PAYLOAD_LENGTH - len, fmt, ap);
- va_end(ap);
- return prepare_message(target, MAILBOX_DRIVER_NOTIFY, payload, len);
- }
- // This function formats a billing log entry into a form ready to pass off to the billdb process:
- //
- // target = blank IPC message to fill with this log entry
- // action = string specifying billing action (ACCEPT, REJECT, PASSBACK, etc...)
- // rule = string specifying which rule (if any) generated this billing entry
- // ruleparam = string specifying the parameter passed to the above rule
- // reason = human readable reason for the reject or accept of this rider
- // credential = string containing the magnetic or RFID credential used to identify the rider
- // logical_card_id = rider ID from pass table
- // cash_value = number of cents paid for this fare if it is a cash fare
- //
- // All other required values are supplied by the system status structures maintained by the default status callbacks:
- //
- // equipment number, GPS locaction, driver, paddle, route, trip, stop, and stop name
- //
- int format_billing_message(struct message_record *target, char *action, char *rule, char *ruleparam, char *reason, char *credential, unsigned long long logical_card_id, int cash_value) {
- int len = 0;
- char foo[MAX_PAYLOAD_LENGTH];
- char payload[MAX_PAYLOAD_LENGTH] = {0};
- if (!target)
- return -1;
- if (!action) action = "";
- if (!rule) rule = "";
- if (!ruleparam) ruleparam = "";
- if (!reason) reason = "";
- if (!credential) credential = "";
- // equipment number (which bus)
- //
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%d\t", driver_stat.equip_num);
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%d\t", driver_stat.logged_in_driver);
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%d\t", stop_stat.paddle);
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%d\t", stop_stat.route);
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%d\t", stop_stat.trip);
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%d\t", stop_stat.stop);
- // the UTC timestamp of now...
- //
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%d\t", (int)time(NULL));
- // if we have a valid GPS fix, put that into the structure
- //
- if (gps_stat.gps_good) {
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%f\t", gps_stat.lat);
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%f\t", gps_stat.lon);
- }
- // otherwise, use the location recorded in the paddle
- //
- else {
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%f\t", stop_stat.lat);
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%f\t", stop_stat.lon);
- }
- // billing action code
- //
- compress_tabs_to_spaces(foo, action, BILLING_ACTION_LEN);
- foo[BILLING_ACTION_LEN] = '\0';
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%s\t", foo);
- // billing rule code
- //
- compress_tabs_to_spaces(foo, rule, BILLING_RULE_LEN);
- foo[BILLING_RULE_LEN] = '\0';
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%s\t", foo);
- // billing rule parameter
- //
- compress_tabs_to_spaces(foo, ruleparam, BILLING_RULEPARAM_LEN);
- foo[BILLING_RULEPARAM_LEN] = '\0';
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%s\t", foo);
- // billing reason code
- //
- compress_tabs_to_spaces(foo, reason, BILLING_REASON_LEN);
- foo[BILLING_REASON_LEN] = '\0';
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%s\t", foo);
- // billing credential code
- //
- compress_tabs_to_spaces(foo, credential, BILLING_CREDENTIAL_LEN);
- foo[BILLING_CREDENTIAL_LEN] = '\0';
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%s\t", foo);
- // rider ID from pass table
- //
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%lld\t", logical_card_id);
- // cash fare in pennies
- //
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%d\t", cash_value);
- // billing stop name
- //
- compress_tabs_to_spaces(foo, stop_stat.stopname, STOP_NAME_LEN);
- foo[STOP_NAME_LEN] = '\0';
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%s\t", foo);
- // This field is not used by the database, but distinguishes multiple identical cash fares per second
- //
- // NOTE: This field ends without a newline OR tab, the newline is added by the billdb module before being sent
- //
- len += snprintf(payload + len, MAX_PAYLOAD_LENGTH - len, "%llu", get_usec_time());
- return prepare_message(target, MAILBOX_BILLING_LOG, payload, len);
- }
- /*
- int main(int argc, char **argv)
- {
- struct message_record msg;
- stop_stat.lat = 9999.99999f;
- stop_stat.lon = 9999.99999f;
- stop_stat.route = 99999;
- stop_stat.paddle = 99999;
- stop_stat.trip = 99;
- stop_stat.stop = 99;
- strcpy(stop_stat.stopname, "ABCDEFGIJKABCDEFGIJKABCDEFGIJKABCDEFGIJKABCDEFGIJKABCDEFGIJK123");
- driver_stat.logged_in_driver = 12345;
- driver_stat.equip_num = 12345;
- format_billing_message(&msg, "ACCEPT1ACCEPT2_", "RULE0123456789012345678", "PARA0123456789012345678", "R012345678900123456789001234567890", "C012345678900123456789001234567890", 9999);
- printf("%s", msg.payload);
- return 0;
- }
- */
|