From 4f28911cecc5c4fb9c6038efb311447ecfbbd3c8 Mon Sep 17 00:00:00 2001 From: "Gary E. Miller" Date: Thu, 26 Jul 2018 14:18:10 -0700 Subject: cgps: Big clean up of code. More comments. Range checking of values. Tweaked formatting. More data in tall mode. Thanks to the support of Virgin Orbit for this patch. --- cgps.c | 484 +++++++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 292 insertions(+), 192 deletions(-) (limited to 'cgps.c') diff --git a/cgps.c b/cgps.c index d8338800..03aa1575 100644 --- a/cgps.c +++ b/cgps.c @@ -84,7 +84,7 @@ /* This is the maximum ysize we need for the 'satellites' window. */ #define MAX_SATWIN_SIZE (MAX_POSSIBLE_SATS + SATWIN_OVERHEAD) -/* Minimum xsize to display 3rd window with ECEF's, etc. */ +/* Minimum xsize to display 3rd window with DOPs, etc. */ #define MIN_ERRWIN_SIZE 100 #include @@ -122,11 +122,12 @@ static int debug; static WINDOW *datawin, *satellites, *messages; static bool raw_flag = false; -static bool ecef_flag = false; /* tall screen, show ECEF */ +static bool show_ecefs = false; /* taller screen, show ECEFs */ +static bool show_more_dops = false; /* tall screen, show more DOPs */ static bool silent_flag = false; static bool magnetic_flag = false; static int window_ysize = 0; -static int display_sats = 0; +static int display_sats = 0; /* number of rows of sats to display */ #ifdef TRUENORTH static bool compass_flag = false; #endif /* TRUENORTH */ @@ -137,6 +138,61 @@ static bool compass_flag = false; #define GPS_ERROR -2 /* low-level failure in GPS read */ #define GPS_TIMEOUT -3 /* low-level failure in GPS waiting */ +/* range test an int, return 5 chars + NUL */ +static const char *int_to_str(int val, int min, int max) +{ + static char buf[20]; + + if (val < min || val > max) { + return " n/a"; + } + (void)snprintf(buf, sizeof(buf), "%5d", val); + return buf; +} + +/* format a DOP into a 5 char string, handle NAN, INFINITE */ +static char *dop_to_str(double dop) +{ + static char buf[20]; + + if (isfinite(dop) == 0) { + return " n/a "; + } + (void)snprintf(buf, sizeof(buf), "%5.2f", dop); + return buf; +} + +/* format an EP into a string, handle NAN, INFINITE */ +static char *ep_to_str(double ep, double factor, char *units) +{ + static char buf[128]; + + if (isfinite(ep) == 0) { + return " n/a "; + } + (void)snprintf(buf, sizeof(buf), "+/-%4.1f %.10s", ep * factor, units); + return buf; +} + +/* format an ECEF p and v into a string, handle NAN, INFINITE */ +static char *ecef_to_str(double pos, double vel, double factor, char *units) +{ + static char buf[128]; + + if (isfinite(pos) == 0) { + if (isfinite(vel) == 0) { + return " n/a n/a "; + } else { + (void)snprintf(buf, sizeof(buf), " n/a %8.3f%.4s/s", + vel * factor, units); + } + } else { + (void)snprintf(buf, sizeof(buf), "% 14.3f%.4s %8.3f%.4s/s", + pos * factor, units, vel * factor, units); + } + return buf; +} + /* Function to call when we're all done. Does a bit of clean-up. */ static void die(int sig) { @@ -176,25 +232,6 @@ static void die(int sig) exit(EXIT_SUCCESS); } -/* format an ECEF p and v into a string, handle NAN, INFINITE */ -static char *ecef_to_str(double pos, double vel, double factor, char *units) -{ - static char buf[128]; - - if (isfinite(pos) == 0) { - if (isfinite(vel) == 0) { - return " n/a n/a "; - } else { - (void)snprintf(buf, sizeof(buf), " n/a %8.2f%.4s/s", - vel * factor, units); - } - } else { - (void)snprintf(buf, sizeof(buf), "% 14.4f%.4s %8.2f%.4s/s", - pos * factor, units, vel * factor, units); - } - return buf; -} - static enum deg_str_type deg_type = deg_dd; static void windowsetup(void) @@ -220,8 +257,8 @@ static void windowsetup(void) * satellites (MAXCHANNELS - 2) with space still left at the bottom, * add a window at the bottom in which to scroll raw gpsd data. * - * 4. If the screen is wide enough to display extra data, add a - * window on the right for PDOP, etc. + * 4. If the screen is tall enough to display extra data, expand + * data window down to show DOPs, ECEFs, etc. */ int xsize, ysize; @@ -249,25 +286,35 @@ static void windowsetup(void) } else #endif /* TRUENORTH */ { - if (ysize > MAX_GPS_DATAWIN_YSIZE + 7) { + if (ysize > MAX_GPS_DATAWIN_YSIZE + 10) { + raw_flag = true; + show_ecefs = true; + show_more_dops = true; + window_ysize = MAX_GPS_DATAWIN_YSIZE + 7; + } else if (ysize > MAX_GPS_DATAWIN_YSIZE + 6) { raw_flag = true; - ecef_flag = true; - window_ysize = MAX_GPS_DATAWIN_YSIZE + 3; + show_ecefs = false; + show_more_dops = true; + window_ysize = MAX_GPS_DATAWIN_YSIZE + 4; } else if (ysize > MAX_GPS_DATAWIN_YSIZE) { raw_flag = true; - ecef_flag = false; + show_ecefs = false; + show_more_dops = false; window_ysize = MAX_GPS_DATAWIN_YSIZE; } else if (ysize == MAX_GPS_DATAWIN_YSIZE) { raw_flag = false; - ecef_flag = false; + show_ecefs = false; + show_more_dops = false; window_ysize = MAX_GPS_DATAWIN_YSIZE; } else if (ysize > MIN_GPS_DATAWIN_YSIZE) { raw_flag = true; - ecef_flag = false; + show_ecefs = false; + show_more_dops = false; window_ysize = MIN_GPS_DATAWIN_YSIZE; } else if (ysize == MIN_GPS_DATAWIN_YSIZE) { raw_flag = false; - ecef_flag = false; + show_ecefs = false; + show_more_dops = false; window_ysize = MIN_GPS_DATAWIN_YSIZE; } else { (void)mvprintw(0, 0, @@ -284,6 +331,7 @@ static void windowsetup(void) /* Set up the screen for either a compass or a gps receiver. */ if (compass_flag) { /* We're a compass, set up accordingly. */ + int row = 1; datawin = newwin(window_ysize, DATAWIN_WIDTH, 0, 0); (void)nodelay(datawin, (bool) TRUE); @@ -297,18 +345,19 @@ static void windowsetup(void) (void)refresh(); /* Do the initial field label setup. */ - (void)mvwprintw(datawin, 1, DATAWIN_DESC_OFFSET, "Time:"); - (void)mvwprintw(datawin, 2, DATAWIN_DESC_OFFSET, "Heading:"); - (void)mvwprintw(datawin, 3, DATAWIN_DESC_OFFSET, "Pitch:"); - (void)mvwprintw(datawin, 4, DATAWIN_DESC_OFFSET, "Roll:"); - (void)mvwprintw(datawin, 5, DATAWIN_DESC_OFFSET, "Dip:"); - (void)mvwprintw(datawin, 6, DATAWIN_DESC_OFFSET, "Rcvr Type:"); + (void)mvwprintw(datawin, row++, DATAWIN_DESC_OFFSET, "Time:"); + (void)mvwprintw(datawin, row++, DATAWIN_DESC_OFFSET, "Heading:"); + (void)mvwprintw(datawin, row++, DATAWIN_DESC_OFFSET, "Pitch:"); + (void)mvwprintw(datawin, row++, DATAWIN_DESC_OFFSET, "Roll:"); + (void)mvwprintw(datawin, row++, DATAWIN_DESC_OFFSET, "Dip:"); + (void)mvwprintw(datawin, row++, DATAWIN_DESC_OFFSET, "Rcvr Type:"); (void)wborder(datawin, 0, 0, 0, 0, 0, 0, 0, 0); } else #endif /* TRUENORTH */ { /* We're a GPS, set up accordingly. */ + int row = 1; datawin = newwin(window_ysize, DATAWIN_WIDTH, 0, 0); satellites = @@ -325,14 +374,14 @@ static void windowsetup(void) (void)refresh(); /* Do the initial field label setup. */ - (void)mvwprintw(datawin, 1, DATAWIN_DESC_OFFSET, "Time:"); - (void)mvwprintw(datawin, 2, DATAWIN_DESC_OFFSET, "Latitude:"); - (void)mvwprintw(datawin, 3, DATAWIN_DESC_OFFSET, "Longitude:"); - (void)mvwprintw(datawin, 4, DATAWIN_DESC_OFFSET, "Altitude:"); - (void)mvwprintw(datawin, 5, DATAWIN_DESC_OFFSET, "Speed:"); - (void)mvwprintw(datawin, 6, DATAWIN_DESC_OFFSET, "Heading:"); - (void)mvwprintw(datawin, 7, DATAWIN_DESC_OFFSET, "Climb:"); - (void)mvwprintw(datawin, 8, DATAWIN_DESC_OFFSET, "Status:"); + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, "Time:"); + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, "Latitude:"); + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, "Longitude:"); + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, "Altitude:"); + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, "Speed:"); + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, "Heading:"); + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, "Climb:"); + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, "Status:"); /* Note that the following fields are exceptions to the * sizing rule. The minimum window size does not include these @@ -343,36 +392,58 @@ static void windowsetup(void) * sounded interesting. ;^) */ if (window_ysize >= MAX_GPS_DATAWIN_YSIZE) { - int row = 9; - - (void)mvwprintw(datawin, row++, DATAWIN_DESC_OFFSET, - "Longitude Err:"); - (void)mvwprintw(datawin, row++, DATAWIN_DESC_OFFSET, - "Latitude Err:"); - (void)mvwprintw(datawin, row++, DATAWIN_DESC_OFFSET, - "Altitude Err:"); + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, + "Long Err (XDOP, EPX):"); + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, + "Lat Err (YDOP, EPY):"); + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, + "Alt Err (VDOP, EPV):"); + + if (show_more_dops) { + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, + "2D Err (HDOP, CEP):"); + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, + "3D Err (PDOP, SEP):"); + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, + "Time Err (TDOP):"); + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, + "Geo Err (GDOP):"); + } - if (ecef_flag){ - (void)mvwprintw(datawin, row++, DATAWIN_DESC_OFFSET, + if (show_ecefs) { + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, "ECEF X, VX:"); - (void)mvwprintw(datawin, row++, DATAWIN_DESC_OFFSET, + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, "ECEF Y, VY:"); - (void)mvwprintw(datawin, row++, DATAWIN_DESC_OFFSET, + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, "ECEF Z, VZ:"); } - (void)mvwprintw(datawin, row++, DATAWIN_DESC_OFFSET, "Course Err:"); - (void)mvwprintw(datawin, row++, DATAWIN_DESC_OFFSET, "Speed Err:"); + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, + "Speed Err (EPS):"); + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, + "Head Err (EPD):"); /* it's actually esr that thought *these* were interesting */ - (void)mvwprintw(datawin, row++, DATAWIN_DESC_OFFSET, + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, "Time offset:"); - (void)mvwprintw(datawin, row++, DATAWIN_DESC_OFFSET, + (void)mvwaddstr(datawin, row++, DATAWIN_DESC_OFFSET, "Grid Square:"); } (void)wborder(datawin, 0, 0, 0, 0, 0, 0, 0, 0); - /* PRN is not unique, starting at 1, for GPS, GAILEO, etc. */ - (void)mvwprintw(satellites, 1, 1, " PRN Elev Azim SNR Used "); + /* PRN is not unique for all GNSS systems. + * Each GNSS (GPS, GALILEO, BeiDou, etc.) numbers their PRN from 1. + * What we really have here is USI, Universal Sat ID + * The USI for each GNSS satellite is unique, starting at 1. + * Not all GPS receivers compute the USI the same way. YMMV + * + * Javad (GREIS) GPS receivers compute USI this way: + * GPS is USI 1-37, GLONASS 38-70, GALILEO 71-119, SBAS 120-142, + * QZSS 193-197, BeiDou 211-247 + * + * Geostar GPS receivers compute USI this way: + * GPS is USI 1 to 32, SBAS is 33 to 64, GLONASS is 65 to 96 */ + (void)mvwaddstr(satellites, 1, 1, " PRN Elev Azim SNR Used "); (void)wborder(satellites, 0, 0, 0, 0, 0, 0, 0, 0); } } @@ -393,51 +464,50 @@ static void resize(int sig UNUSED) static void update_compass_panel(struct gps_data_t *gpsdata) { char scr[128]; + int row = 1; /* Print time/date. */ if (isfinite(gpsdata->fix.time) != 0) { (void)unix_to_iso8601(gpsdata->fix.time, scr, sizeof(scr)); } else - (void)snprintf(scr, sizeof(scr), " n/a"); - (void)mvwprintw(datawin, 1, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); + (void)snprintf(scr, sizeof(scr), "n/a"); + (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); /* Fill in the heading. */ if (isfinite(gpsdata->fix.track) != 0) { (void)snprintf(scr, sizeof(scr), "%.1f degrees", gpsdata->fix.track); } else - (void)snprintf(scr, sizeof(scr), " n/a"); - (void)mvwprintw(datawin, 2, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); + (void)snprintf(scr, sizeof(scr), "n/a"); + (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); /* Fill in the climb. */ if (isfinite(gpsdata->fix.climb) != 0) { (void)snprintf(scr, sizeof(scr), "%.2f", gpsdata->fix.climb); } else - (void)snprintf(scr, sizeof(scr), " n/a"); - (void)mvwprintw(datawin, 3, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); + (void)snprintf(scr, sizeof(scr), "n/a"); + (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); /* Fill in the speed. */ if (isfinite(gpsdata->fix.speed) != 0) (void)snprintf(scr, sizeof(scr), "%.2f", gpsdata->fix.speed); else - (void)snprintf(scr, sizeof(scr), " n/a"); - (void)mvwprintw(datawin, 4, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); + (void)snprintf(scr, sizeof(scr), "n/a"); + (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); /* Fill in the altitude. */ if (isfinite(gpsdata->fix.altitude) != 0) (void)snprintf(scr, sizeof(scr), "%.3f", gpsdata->fix.altitude); else - (void)snprintf(scr, sizeof(scr), " n/a"); - (void)mvwprintw(datawin, 5, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); + (void)snprintf(scr, sizeof(scr), "n/a"); + (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); /* When we need to fill in receiver type again, do it here. */ - (void)mvwprintw(datawin, 6, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); - - /* Be quiet if the user requests silence. */ - if (!silent_flag && raw_flag) { - (void)waddstr(messages, message); - } + (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); (void)wrefresh(datawin); - if (raw_flag) { + + if (raw_flag && !silent_flag) { + /* Be quiet if the user requests silence. */ + (void)waddstr(messages, message); (void)wrefresh(messages); } } @@ -457,11 +527,10 @@ static int sat_cmp(const void *p1, const void *p2) } -static void update_gps_panel(struct gps_data_t *gpsdata, char * message) +static void update_gps_panel(struct gps_data_t *gpsdata, char *message) /* This gets called once for each new GPS sentence. */ { int newstate; - int row = 9; char scr[128], *s; /* This is for the satellite status display. Originally lifted from @@ -472,65 +541,59 @@ static void update_gps_panel(struct gps_data_t *gpsdata, char * message) (void)mvwprintw(satellites, 1, 32, "%2d", gpsdata->satellites_used); if (gpsdata->satellites_visible != 0) { - int i; + int sat_no; + int loop_end = (display_sats < gpsdata->satellites_visible) ? \ + display_sats : gpsdata->satellites_visible; + qsort( gpsdata->skyview, gpsdata->satellites_visible, sizeof( struct satellite_t), sat_cmp); - if (display_sats >= MAX_POSSIBLE_SATS) { - for (i = 0; i < MAX_POSSIBLE_SATS; i++) { - if (i < gpsdata->satellites_visible) { - /* allow for 3 digit elevation, - * ublox uses -91 to signal something undocumented */ - (void)snprintf(scr, sizeof(scr), - " %3d %3d %3d %2d %c", - gpsdata->skyview[i].PRN, - gpsdata->skyview[i].elevation, - gpsdata->skyview[i].azimuth, - (int)gpsdata->skyview[i].ss, - gpsdata->skyview[i].used ? 'Y' : 'N'); - } else { - (void)strlcpy(scr, "", sizeof(scr)); - } - (void)mvwprintw(satellites, i + 2, 1, "%-*s", - SATELLITES_WIDTH - 3, scr); - } - } else { - int n = 0; - for (i = 0; i < MAX_POSSIBLE_SATS; i++) { - if (n < display_sats) { - if ((i < gpsdata->satellites_visible) - && (gpsdata->skyview[i].used - || (gpsdata->satellites_visible <= display_sats))) { - (void)snprintf(scr, sizeof(scr), - " %3d %2d %3d %2d %c", - gpsdata->skyview[i].PRN, - gpsdata->skyview[i].elevation, - gpsdata->skyview[i].azimuth, - (int)gpsdata->skyview[i].ss, - gpsdata->skyview[i].used ? 'Y' : 'N'); - (void)mvwprintw(satellites, n + 2, 1, "%-*s", - SATELLITES_WIDTH - 3, scr); - n++; - } - } - } + /* displayed all sats that fit, maybe all of them */ + for (sat_no = 0; sat_no < loop_end; sat_no++) { + int column = 1; /* column to write to */ + + /* no GPS uses PRN 0, some use 255 for 'unknown' + * u-blox uses PRN 1-255, NMEA 4.0 uses 1-437 */ + (void)mvwaddstr(satellites, sat_no + 2, column, + int_to_str(gpsdata->skyview[sat_no].PRN, + 1, 438)); + /* u-blox uses -91 to signal something undocumented */ + column += 6; + (void)mvwaddstr(satellites, sat_no + 2, column, + int_to_str(gpsdata->skyview[sat_no].elevation, + -90, 90)); + column += 7; + (void)mvwaddstr(satellites, sat_no + 2, column, + int_to_str(gpsdata->skyview[sat_no].azimuth, + 0, 359)); + column += 6; + (void)mvwaddstr(satellites, sat_no + 2, column, + int_to_str((int)round(gpsdata->skyview[sat_no].ss), + 0, 254)); + column += 6; + (void)mvwprintw(satellites, sat_no + 2, column, " %c", + gpsdata->skyview[sat_no].used ? 'Y' : 'N'); + } - if (n < display_sats) { - for (i = n; i <= display_sats; i++) { - (void)mvwprintw(satellites, i + 2, 1, "%-*s", - SATELLITES_WIDTH - 3, ""); - } + /* last line is either blank, or More... */ + if (sat_no < gpsdata->satellites_visible) { + /* Too many sats to show them all, tell the user. */ + (void)mvwprintw(satellites, sat_no + 2, 1, "%-*s", + SATELLITES_WIDTH - 3, "More..."); + } else { + /* Clear old data from the unused lines at bottom. */ + for ( ; sat_no <= display_sats; sat_no++) { + (void)mvwprintw(satellites, sat_no + 2, 1, "%-*s", + SATELLITES_WIDTH - 3, ""); } - } } - row = 1; /* Print time/date. */ if (isfinite(gpsdata->fix.time) != 0) { (void)unix_to_iso8601(gpsdata->fix.time, scr, sizeof(scr)); } else - (void)snprintf(scr, sizeof(scr), " n/a"); - (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); + (void)snprintf(scr, sizeof(scr), "n/a"); + (void)mvwprintw(datawin, 1, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); /* Fill in the latitude. */ @@ -539,8 +602,8 @@ static void update_gps_panel(struct gps_data_t *gpsdata, char * message) deg_to_str(deg_type, fabs(gpsdata->fix.latitude)), (gpsdata->fix.latitude < 0) ? 'S' : 'N'); } else - (void)snprintf(scr, sizeof(scr), " n/a"); - (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); + (void)snprintf(scr, sizeof(scr), "n/a"); + (void)mvwprintw(datawin, 2, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); /* Fill in the longitude. */ if (gpsdata->fix.mode >= MODE_2D && isfinite(gpsdata->fix.longitude) != 0) { @@ -548,24 +611,24 @@ static void update_gps_panel(struct gps_data_t *gpsdata, char * message) deg_to_str(deg_type, fabs(gpsdata->fix.longitude)), (gpsdata->fix.longitude < 0) ? 'W' : 'E'); } else - (void)snprintf(scr, sizeof(scr), " n/a"); - (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); + (void)snprintf(scr, sizeof(scr), "n/a"); + (void)mvwprintw(datawin, 3, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); /* Fill in the altitude. */ if (gpsdata->fix.mode >= MODE_3D && isfinite(gpsdata->fix.altitude) != 0) (void)snprintf(scr, sizeof(scr), "%9.3f %s", gpsdata->fix.altitude * altfactor, altunits); else - (void)snprintf(scr, sizeof(scr), " n/a"); - (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); + (void)snprintf(scr, sizeof(scr), "n/a"); + (void)mvwprintw(datawin, 4, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); /* Fill in the speed. */ if (gpsdata->fix.mode >= MODE_2D && isfinite(gpsdata->fix.track) != 0) (void)snprintf(scr, sizeof(scr), "%8.2f %s", gpsdata->fix.speed * speedfactor, speedunits); else - (void)snprintf(scr, sizeof(scr), " n/a"); - (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); + (void)snprintf(scr, sizeof(scr), "n/a"); + (void)mvwprintw(datawin, 5, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); /* Fill in the heading. */ if (gpsdata->fix.mode >= MODE_2D && isfinite(gpsdata->fix.track) != 0) { @@ -580,16 +643,16 @@ static void update_gps_panel(struct gps_data_t *gpsdata, char * message) magheading); } } else - (void)snprintf(scr, sizeof(scr), " n/a"); - (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET, " %-*s", 25, scr); + (void)snprintf(scr, sizeof(scr), "n/a"); + (void)mvwprintw(datawin, 6, DATAWIN_VALUE_OFFSET, " %-*s", 25, scr); /* Fill in the rate of climb. */ if (gpsdata->fix.mode >= MODE_3D && isfinite(gpsdata->fix.climb) != 0) (void)snprintf(scr, sizeof(scr), "%8.2f %s/min", gpsdata->fix.climb * altfactor * 60, altunits); else - (void)snprintf(scr, sizeof(scr), " n/a"); - (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); + (void)snprintf(scr, sizeof(scr), "n/a"); + (void)mvwprintw(datawin, 7, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr); /* Fill in the GPS status and the time since the last state * change. */ @@ -617,7 +680,7 @@ static void update_gps_panel(struct gps_data_t *gpsdata, char * message) break; } } - (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET + 1, "%-*s", 26, scr); + (void)mvwprintw(datawin, 8, DATAWIN_VALUE_OFFSET + 1, "%-*s", 26, scr); /* Note that the following fields are exceptions to the * sizing rule. The minimum window size does not include these @@ -628,36 +691,79 @@ static void update_gps_panel(struct gps_data_t *gpsdata, char * message) * sounded interesting. ;^) */ if (window_ysize >= (MIN_GPS_DATAWIN_YSIZE + 5)) { - /* Fill in the estimated horizontal position error. */ - if (isfinite(gpsdata->fix.epx) != 0) - (void)snprintf(scr, sizeof(scr), "+/- %d %s", - (int)(gpsdata->fix.epx * altfactor), altunits); - else - (void)snprintf(scr, sizeof(scr), " n/a"); - (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET + 5, "%-*s", 22, - scr); - - if (isfinite(gpsdata->fix.epy) != 0) - (void)snprintf(scr, sizeof(scr), "+/- %d %s", - (int)(gpsdata->fix.epy * altfactor), altunits); - else - (void)snprintf(scr, sizeof(scr), " n/a"); - (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET + 5, "%-*s", 22, - scr); + int row = 9; + char *ep_str = NULL; + char *dop_str = NULL; + + /* Fill in the estimated latitude position error, XDOP. */ + ep_str = ep_to_str(gpsdata->fix.epx, altfactor, altunits); + dop_str = dop_to_str(gpsdata->dop.xdop); + (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET + 8, "%s, %-*s", + dop_str, 11, ep_str); + + /* Fill in the estimated longitude position error, YDOP. */ + ep_str = ep_to_str(gpsdata->fix.epy, altfactor, altunits); + dop_str = dop_to_str(gpsdata->dop.ydop); + (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET + 8, "%s, %-*s", + dop_str, 11, ep_str); + + /* Fill in the estimated velocity error, VDOP. */ + ep_str = ep_to_str(gpsdata->fix.epv, altfactor, altunits); + dop_str = dop_to_str(gpsdata->dop.vdop); + (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET + 8, "%s, %-*s", + dop_str, 11, ep_str); + + /* extra tall screen, show more DOPs */ + if (show_more_dops) { + double cep = NAN; /* 2D EP */ + double sep = NAN; /* 3D EP */ + + /* Calculate estimated 2D circular position error, CEP */ + if (isfinite(gpsdata->fix.epy) != 0 + && isfinite(gpsdata->fix.epy) != 0) { + /* http://gauss.gge.unb.ca/papers.pdf/gpsworld.may99.pdf */ + /* CEP is just the hypotenuse of the triangle of epx and epy */ + cep = sqrt((gpsdata->fix.epx * gpsdata->fix.epx) + + (gpsdata->fix.epy * gpsdata->fix.epy)); + if (isfinite(gpsdata->fix.epv) != 0) { + /* SEP is the spherical (3D) error probability. + * The square root of the sum of the squares of epx, epy, + * and epv */ + sep = sqrt((gpsdata->fix.epx * gpsdata->fix.epx) + + (gpsdata->fix.epy * gpsdata->fix.epy) + + (gpsdata->fix.epv * gpsdata->fix.epv)); + } + } - /* Fill in the estimated vertical position error. */ - if (isfinite(gpsdata->fix.epv) != 0) - (void)snprintf(scr, sizeof(scr), "+/- %d %s", - (int)(gpsdata->fix.epv * altfactor), altunits); - else - (void)snprintf(scr, sizeof(scr), " n/a"); - (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET + 5, "%-*s", 22, - scr); + /* Fill in the estimated horizontal (2D) error, HDOP */ + ep_str = ep_to_str(cep, altfactor, altunits); + dop_str = dop_to_str(gpsdata->dop.hdop); + (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET + 8, + "%s, %-*s", dop_str, 11, ep_str); + + /* (spherical) position error, 3D error, PDOP */ + ep_str = ep_to_str(sep, altfactor, altunits); + dop_str = dop_to_str(gpsdata->dop.pdop); + (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET + 8, + "%s, %-*s", dop_str, 11, ep_str); + + /* time dilution of precision, TDOP */ + /* FIXME: time ep? */ + dop_str = dop_to_str(gpsdata->dop.tdop); + (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET + 8, "%-*s", + 18, dop_str); + + /* geometric dilution of precision, GDOP */ + /* FIXME: gdop ep? */ + dop_str = dop_to_str(gpsdata->dop.gdop); + (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET + 8, "%-*s", + 18, dop_str); + } - /* extra large screen, show more ECEF */ - if (ecef_flag) { - char *estr; + /* extra large screen, show ECEF */ + if (show_ecefs) { + char *estr; /* Fill in the ECEF's. */ estr = ecef_to_str(gpsdata->fix.ecef.x, gpsdata->fix.ecef.vx, @@ -674,32 +780,26 @@ static void update_gps_panel(struct gps_data_t *gpsdata, char * message) 1, " m"); (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET - 3, "%-*s", 27, estr); - } + } - /* Fill in the estimated track error. */ - if (isfinite(gpsdata->fix.epd) != 0) - (void)snprintf(scr, sizeof(scr), "+/- %d deg", - (int)(gpsdata->fix.epd)); - else - (void)snprintf(scr, sizeof(scr), " n/a"); - (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET + 5, "%-*s", 22, - scr); - /* Fill in the estimated speed error. */ - if (isfinite(gpsdata->fix.eps) != 0) - (void)snprintf(scr, sizeof(scr), "+/- %d %s", - (int)(gpsdata->fix.eps * speedfactor), speedunits); - else - (void)snprintf(scr, sizeof(scr), " n/a"); - (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET + 5, "%-*s", 22, - scr); + /* Fill in the estimated speed error, EPS. */ + ep_str = ep_to_str(gpsdata->fix.eps, speedfactor, speedunits); + (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET + 8, + " %-*s", 11, + ep_str); + + /* Fill in the estimated track error, EPD. */ + ep_str = ep_to_str(gpsdata->fix.epd, speedfactor, "deg"); + (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET + 8, "%-*s", 18, + ep_str); - /* Fill in the time offset, milli seconds. */ + /* Fill in the time offset, milliseconds. */ if (isfinite(gpsdata->fix.time) != 0) (void)snprintf(scr, sizeof(scr), "%6.3f sec", (double)(timestamp()-gpsdata->fix.time)); else - (void)snprintf(scr, sizeof(scr), " n/a"); + (void)snprintf(scr, sizeof(scr), " n/a"); (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET + 8, "%-*s", 18, scr); /* Fill in the grid square (esr thought *this* one was interesting). */ @@ -707,7 +807,7 @@ static void update_gps_panel(struct gps_data_t *gpsdata, char * message) isfinite(gpsdata->fix.latitude) != 0)) s = maidenhead(gpsdata->fix.latitude,gpsdata->fix.longitude); else - s = " n/a"; + s = "n/a"; (void)mvwprintw(datawin, row++, DATAWIN_VALUE_OFFSET + 9, "%-*s", 18, s); @@ -890,14 +990,14 @@ int main(int argc, char *argv[]) /* wait 1/2 second for gpsd */ if (!gps_waiting(&gpsdata, 500000)) { - /* 240 tries at .5 Sec a try is a 2 minute timeout */ + /* 240 tries at 0.5 seconds a try is a 2 minute timeout */ if ( 240 < wait_clicks++ ) die(GPS_TIMEOUT); } else { wait_clicks = 0; errno = 0; *message = '\0'; - if (gps_read(&gpsdata, message, sizeof(message)) == -1) { + if (gps_read(&gpsdata, message, sizeof(message)) == -1) { (void)fprintf(stderr, "cgps: socket error 4\n"); die(errno == 0 ? GPS_GONE : GPS_ERROR); } else { -- cgit v1.2.1