/* GPS speedometer as a wrapper around an Athena widget Tachometer
* - Derrick J Brashear <shadow@dementia.org>
*/
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <math.h>
#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Paned.h>
#include <Xm/Xm.h>
#include <Xm/XmStrDefs.h>
#include <Tachometer.h>
#include "config.h"
#include "gps.h"
#include "xgpsspeed.icon"
/*@ -nullassign @*/
static XrmOptionDescRec options[] = {
{"-rv", "*reverseVideo", XrmoptionNoArg, "TRUE"},
{"-nc", "*needleColor", XrmoptionSepArg, NULL},
{"-needlecolor","*needleColor", XrmoptionSepArg, NULL},
{"-speedunits", "*speedunits", XrmoptionSepArg, NULL},
};
String fallback_resources[] = {NULL};
/*@ +nullassign @*/
static struct gps_data_t *gpsdata;
static Widget tacho;
static double speedfactor;
static Widget toplevel;
static void update_display(struct gps_data_t *gpsdata,
char *buf UNUSED, size_t len UNUSED, int level UNUSED)
{
int temp_int = (int)rint(gpsdata->fix.speed * speedfactor);
if (temp_int < 0) temp_int = 0;
else if (temp_int > 100) temp_int = 100;
(void)TachometerSetValue(tacho, temp_int);
}
static void handle_input(XtPointer client_data UNUSED,
int *source UNUSED, XtInputId * id UNUSED)
{
if (gps_poll(gpsdata) < 0) {
(void)fprintf(stderr, "Read error on server socket.");
exit(1);
}
}
static char *get_resource(Widget w, char *name, char *default_value)
{
XtResource xtr;
char *value = NULL;
/*@ -observertrans -statictrans -immediatetrans -compdestroy -nullpass @*/
xtr.resource_name = name;
xtr.resource_class = "AnyClass";
xtr.resource_type = XmRString;
xtr.resource_size = (Cardinal)sizeof(String);
xtr.resource_offset = 0;
xtr.default_type = XmRImmediate;
xtr.default_addr = default_value;
XtGetApplicationResources(w, &value, &xtr, 1, NULL, 0);
if (value) return value;
/*@ +observertrans +statictrans +immediatetrans +compdestroy +nullpass @*/
/*@i@*/return default_value;
}
/*@ -mustfreefresh @*/
int main(int argc, char **argv)
{
Arg args[10];
XtAppContext app;
int option;
char *arg = NULL, *colon1, *colon2, *device = NULL, *server = NULL, *port = DEFAULT_GPSD_PORT;
char *speedunits;
Widget base;
/*@ -compdef -nullpass -onlytrans @*/
toplevel = XtVaAppInitialize(&app, "xgpsspeed",
options, XtNumber(options),
&argc, argv, fallback_resources, NULL);
/*@ +compdef +nullpass +onlytrans @*/
speedfactor = MPS_TO_MPH; /* Software maintained in US */
speedunits = get_resource(toplevel, "speedunits", "mph");
if (strcmp(speedunits, "kph")==0)
speedfactor = MPS_TO_KPH;
else if (strcmp(speedunits, "knots")==0)
speedfactor = MPS_TO_KNOTS;
while ((option = getopt(argc, argv, "hV")) != -1) {
switch (option) {
case 'V':
(void)printf("xgpsspeed %s\n", VERSION);
exit(0);
case 'h': default:
(void)fputs("usage: gps [-h] [-V] [-rv] [-nc] [-needlecolor] [-speedunits {mph,kph,knots}] [server[:port]]\n", stderr);
exit(1);
}
}
/*@ -branchstate -nullpass @*/
if (optind < argc) {
arg = strdup(argv[optind]);
colon1 = strchr(arg, ':');
server = arg;
if (colon1 != NULL) {
if (colon1 == arg)
server = NULL;
else
*colon1 = '\0';
port = colon1 + 1;
colon2 = strchr(port, ':');
if (colon2 != NULL) {
if (colon2 == port)
port = NULL;
else
*colon2 = '\0';
device = colon2 + 1;
}
}
colon1 = colon2 = NULL;
}
/*@ +branchstate @*/
/*@ -immediatetrans -usedef -observertrans -statictrans @*/
/**** Shell Widget ****/
(void)XtSetArg(args[0], XtNiconPixmap,
XCreateBitmapFromData(XtDisplay(toplevel),
XtScreen(toplevel)->root, (char*)xgps_bits,
xgps_width, xgps_height));
(void)XtSetValues(toplevel, args, 1);
/**** Form widget ****/
base = XtCreateManagedWidget("pane", panedWidgetClass, toplevel, NULL, 0);
/**** Label widget (Title) ****/
(void)XtSetArg(args[0], XtNlabel, "GPS Speedometer");
(void)XtCreateManagedWidget("title", labelWidgetClass, base, args, 1);
/**** Label widget ****/
if (speedfactor == MPS_TO_MPH)
(void)XtSetArg(args[0], XtNlabel, "Miles per Hour");
else if (speedfactor == MPS_TO_KPH)
(void)XtSetArg(args[0], XtNlabel, "Km per Hour");
else
(void)XtSetArg(args[0], XtNlabel, "Knots");
/*@ +immediatetrans +usedef +observertrans +statictrans @*/
(void)XtCreateManagedWidget("name", labelWidgetClass, base, args, 1);
/**** Tachometer widget ****/
/*@ -onlytrans -mustfreeonly @*/
tacho = XtCreateManagedWidget("meter", tachometerWidgetClass,base,NULL,0);
(void)XtRealizeWidget(toplevel);
if (!(gpsdata = gps_open(server, DEFAULT_GPSD_PORT))) {
(void)fputs("xgpsspeed: no gpsd running or network error\n", stderr);
exit(2);
}
/*@ +onlytrans +mustfreeonly @*/
/*@ -usedef @*/
(void)XtAppAddInput(app, gpsdata->gps_fd, (XtPointer) XtInputReadMask,
handle_input, NULL);
/*@ +nullpass +usedef @*/
gps_set_raw_hook(gpsdata, update_display);
if (device) {
char *channelcmd = (char *)malloc(strlen(device)+3);
if (channelcmd) {
/*@i1@*/(void)strcpy(channelcmd, "F=");
(void)strcpy(channelcmd+2, device);
(void)gps_query(gpsdata, channelcmd);
(void)free(channelcmd);
}
}
(void)gps_query(gpsdata, "w+x\n");
(void)XtAppMainLoop(app);
(void)gps_close(gpsdata);
if (arg != NULL)
(void)free(arg);
return 0;
}
/*@ +mustfreefresh @*/
syntax highlighted by Code2HTML, v. 0.9.1