cgps.c

来自「gpsd, a popular GPS daemon.」· C语言 代码 · 共 843 行 · 第 1/2 页

C
843
字号
/* $Id: cgps.c 4547 2007-12-13 01:38:22Z esr $ *//* * Copyright (c) 2005 Jeff Francis <jeff@gritch.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *//*  Jeff Francis  jeff@gritch.org  Kind of a curses version of xgps for use with gpsd.*//* ==================================================================   These #defines should be modified if changing the number of fields   to be displayed.   ================================================================== *//* This defines how much overhead is contained in the 'datawin' window   (eg, box around the window takes two lines). */#define DATAWIN_OVERHEAD 2/* This defines how much overhead is contained in the 'satellites'   window (eg, box around the window takes two lines, plus the column   headers take another line). */#define SATWIN_OVERHEAD 3/* This is how many display fields are output in the 'datawin' window   when in GPS mode.  Change this value if you add or remove fields   from the 'datawin' window for the GPS mode. */#define DATAWIN_GPS_FIELDS 9/* This is how many display fields are output in the 'datawin' window   when in COMPASS mode.  Change this value if you add or remove fields   from the 'datawin' window for the COMPASS mode. */#define DATAWIN_COMPASS_FIELDS 6/* This is how far over in the 'datawin' window to indent the field   descriptions. */#define DATAWIN_DESC_OFFSET 5/* This is how far over in the 'datawin' window to indent the field   values. */#define DATAWIN_VALUE_OFFSET 17/* This is the width of the 'datawin' window.  It's recommended to   keep DATAWIN_WIDTH + SATELLITES_WIDTH <= 80 so it'll fit on a   "standard" 80x24 screen. */#define DATAWIN_WIDTH 45/* This is the width of the 'satellites' window.  It's recommended to   keep DATAWIN_WIDTH + SATELLITES_WIDTH <= 80 so it'll fit on a   "standard" 80x24 screen. */#define SATELLITES_WIDTH 35/* ================================================================   You shouldn't have to modify any #define values below this line.   ================================================================ *//* This is the minimum size we'll accept for the 'datawin' window in   GPS mode. */#define MIN_GPS_DATAWIN_SIZE (DATAWIN_GPS_FIELDS + DATAWIN_OVERHEAD)/* This is the minimum size we'll accept for the 'datawin' window in   COMPASS mode. */#define MIN_COMPASS_DATAWIN_SIZE (DATAWIN_COMPASS_FIELDS + DATAWIN_OVERHEAD)/* This is the maximum number of satellites gpsd can track. */#define MAX_POSSIBLE_SATS (MAXCHANNELS - 2)/* This is the maximum size we need for the 'satellites' window. */#define MAX_SATWIN_SIZE (MAX_POSSIBLE_SATS + SATWIN_OVERHEAD)#include <sys/types.h>#include <sys/select.h>#include <sys/socket.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <unistd.h>#include <math.h>#include <errno.h>#include <assert.h>#include <signal.h>#include "gpsd_config.h"#ifdef HAVE_NCURSES_H#include <ncurses.h>#else#include <curses.h>#endif /* HAVE_NCURSES_H */#include "gps.h"static struct gps_data_t *gpsdata;static time_t status_timer;    /* Time of last state change. */static time_t misc_timer;    /* Misc use timer. */static int state = 0;   /* or MODE_NO_FIX=1, MODE_2D=2, MODE_3D=3 */static float altfactor = METERS_TO_FEET;static float speedfactor = MPS_TO_MPH;static char *altunits = "ft";static char *speedunits = "mph";static WINDOW *datawin, *satellites, *messages;static int raw_flag=0;static int silent_flag=0;static int fixclear_flag=0;static int compass_flag=0;static int got_gps_type=0;static char gps_type[26];static int window_length;static int display_sats;/* Function to call when we're all done.  Does a bit of clean-up. */static void die(int sig UNUSED){  /* Ignore signals. */  (void)signal(SIGINT,SIG_IGN);  (void)signal(SIGHUP,SIG_IGN);  /* Move the cursor to the bottom left corner. */  (void)mvcur(0,COLS-1,LINES-1,0);  /* Put input attributes back the way they were. */  (void)echo();  /* Done with curses. */  (void)endwin();  /* We're done talking to gpsd. */  (void)gps_close(gpsdata);  /* Bye! */  exit(0);}static enum deg_str_type deg_type = deg_dd;/* This gets called once for each new sentence until we figure out   what's going on and switch to either update_gps_panel() or   update_compass_panel(). */static void update_probe(struct gps_data_t *gpsdata,		       char *message,		       size_t len UNUSED ,		       int level UNUSED){  /* Send an 'i' once per second until we figure out what the GPS     device is. */  if(time(NULL)-misc_timer > 2) {    (void)gps_query(gpsdata, "i\n");    (void)fprintf(stderr,"Probing...\n");    misc_timer=time(NULL);  }  assert(message != NULL);  if(strncmp(message,"GPSD,I=",6)==0) {    message+=7;    (void)strlcpy(gps_type, message, sizeof(gps_type));    got_gps_type=1;    /* If we're hooked to a compass, we display an entirely different       screen and label the data much differently. */    if(strstr(message,"True North")) {      compass_flag=1;    }  }}/*@ -globstate @*/static void windowsetup(void){  /* Set the window sizes per the following criteria:     1.  Set the window size to display the maximum number of     satellites possible, but not more than the size required to     display the maximum number of satellites gpsd is capable of     tracking (MAXCHANNELS - 2).     2.  If the screen size will not allow for the full complement of     satellites to be displayed, set the windows sizes smaller, but     not smaller than the number of lines necessary to display all of     the fields in the 'datawin'.  The list of displayed satellites     will be truncated to fit the available window size.  (TODO: If     the satellite list is truncated, omit the satellites not used to     obtain the current fix.)     3.  If the screen is large enough to display all possible     satellites (MAXCHANNELS - 2) with space still left at the bottom,     add a window at the bottom in which to scroll raw gpsd data.  */  int xsize, ysize;  getmaxyx(stdscr,ysize,xsize);  if(compass_flag==1) {    if(ysize == MIN_COMPASS_DATAWIN_SIZE) {      raw_flag = 0;      window_length = MIN_COMPASS_DATAWIN_SIZE;    } else if(ysize > MIN_COMPASS_DATAWIN_SIZE) {      raw_flag = 1;      window_length = MIN_COMPASS_DATAWIN_SIZE;    } else {      (void)mvprintw(0, 0, "Your screen must be at least 80x%d to run cgps.",MIN_COMPASS_DATAWIN_SIZE);      /*@ -nullpass @*/      (void)refresh();      /*@ +nullpass @*/      (void)sleep(5);      die(0);    }  } else {    if(ysize == MAX_SATWIN_SIZE) {      raw_flag = 0;      window_length = MAX_SATWIN_SIZE;      display_sats = MAX_POSSIBLE_SATS;    } else if(ysize == MAX_SATWIN_SIZE + 1) {      raw_flag = 1;      window_length = MAX_SATWIN_SIZE;      display_sats = MAX_POSSIBLE_SATS;    } else if(ysize > MAX_SATWIN_SIZE + 2) {      raw_flag = 1;      window_length = MAX_SATWIN_SIZE;      display_sats = MAX_POSSIBLE_SATS;    } else if(ysize > MIN_GPS_DATAWIN_SIZE) {      raw_flag = 0;      window_length = ysize - raw_flag;      display_sats = window_length - SATWIN_OVERHEAD - raw_flag;    } else if(ysize == MIN_GPS_DATAWIN_SIZE) {      raw_flag = 0;      window_length = MIN_GPS_DATAWIN_SIZE;      display_sats = window_length - SATWIN_OVERHEAD - 1;    } else {      (void)mvprintw(0, 0, "Your screen must be at least 80x%d to run cgps.",MIN_GPS_DATAWIN_SIZE);      /*@ -nullpass @*/      (void)refresh();      /*@ +nullpass @*/      (void)sleep(5);      die(0);    }  }  /* Set up the screen for either a compass or a gps receiver. */  if(compass_flag==1) {    /* We're a compass, set up accordingly. */    /*@ -onlytrans @*/    datawin    = newwin(window_length, DATAWIN_WIDTH, 0, 0);    (void)nodelay(datawin,(bool)TRUE);    if(raw_flag==1) {      messages   = newwin(0, 0, window_length, 0);      /*@ +onlytrans @*/      (void)scrollok(messages, true);      (void)wsetscrreg(messages, 0, ysize - (window_length));    }    /*@ -nullpass @*/    (void)refresh();    /*@ +nullpass @*/    /* 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)wborder(datawin, 0, 0, 0, 0, 0, 0, 0, 0);  } else {    /* We're a GPS, set up accordingly. */    /*@ -onlytrans @*/    datawin    = newwin(window_length, DATAWIN_WIDTH, 0, 0);    satellites = newwin(window_length, SATELLITES_WIDTH, 0, DATAWIN_WIDTH);    (void)nodelay(datawin,(bool)TRUE);    if(raw_flag==1) {      messages   = newwin(ysize - (window_length), xsize, window_length, 0);      /*@ +onlytrans @*/      (void)scrollok(messages, true);      (void)wsetscrreg(messages, 0, ysize - (window_length));    }    /*@ -nullpass @*/    (void)refresh();    /*@ +nullpass @*/    /* 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)mvwprintw(datawin, 9, DATAWIN_DESC_OFFSET, "GPS Type:");    /* Note that the following four fields are exceptions to the       sizing rule.  The minimum window size does not include these       fields, if the window is too small, they get excluded.  This       may or may not change if/when the output for these fields is       fixed and/or people request their permanance.  They're only       there in the first place because I arbitrarily thought they       sounded interesting. ;^) */    if(window_length >= (MIN_GPS_DATAWIN_SIZE + 4)) {      (void)mvwprintw(datawin, 10, DATAWIN_DESC_OFFSET, "Horizontal Err:");      (void)mvwprintw(datawin, 11, DATAWIN_DESC_OFFSET, "Vertical Err:");      (void)mvwprintw(datawin, 12, DATAWIN_DESC_OFFSET, "Course Err:");      (void)mvwprintw(datawin, 13, DATAWIN_DESC_OFFSET, "Speed Err:");    }    (void)wborder(datawin, 0, 0, 0, 0, 0, 0, 0, 0);    (void)mvwprintw(satellites, 1,1, "PRN:   Elev:  Azim:  SNR:  Used:");    (void)wborder(satellites, 0, 0, 0, 0, 0, 0, 0, 0);  }}/*@ +globstate @*//* This gets called once for each new compass sentence. */static void update_compass_panel(struct gps_data_t *gpsdata,			char *message,			size_t len UNUSED ,			int level UNUSED){  char scr[128];  /* Print time/date. */  if (isnan(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);  /* Fill in the heading. */  if (isnan(gpsdata->fix.track)==0) {    (void)snprintf(scr, sizeof(scr), "%.1f", gpsdata->fix.track);  } else    (void)snprintf(scr, sizeof(scr), "n/a");  (void)mvwprintw(datawin, 2, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr);  /* Fill in the pitch. */  if (isnan(gpsdata->fix.climb)==0) {    (void)snprintf(scr, sizeof(scr), "%.1f", gpsdata->fix.climb);  } else    (void)snprintf(scr, sizeof(scr), "n/a");  (void)mvwprintw(datawin, 3, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr);  /* Fill in the roll. */  if (isnan(gpsdata->fix.speed)==0)    (void)snprintf(scr, sizeof(scr), "%.1f",gpsdata->fix.speed);  else    (void)snprintf(scr, sizeof(scr), "n/a");  (void)mvwprintw(datawin, 4, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr);  /* Fill in the speed. */  if (isnan(gpsdata->fix.altitude)==0)    (void)snprintf(scr, sizeof(scr), "%.1f", gpsdata->fix.altitude);  else    (void)snprintf(scr, sizeof(scr), "n/a");  (void)mvwprintw(datawin, 5, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr);  /* Fill in receiver type. */  if(got_gps_type==1)    (void)snprintf(scr, sizeof(scr), "%s",gps_type);  else    (void)snprintf(scr, sizeof(scr), "unknown");  (void)mvwprintw(datawin, 6, DATAWIN_VALUE_OFFSET, "%-*s", 27, scr);  /* Be quiet if the user requests silence. */  if(silent_flag==0 && raw_flag==1) {    (void)wprintw(messages, "%s\n", message);  }  (void)wrefresh(datawin);  if(raw_flag==1) {    (void)wrefresh(messages);  }}/* This gets called once for each new GPS sentence. */static void update_gps_panel(struct gps_data_t *gpsdata,			char *message,			size_t len UNUSED ,			int level UNUSED){  int i,n;  int newstate;  char scr[128];  /* This is for the satellite status display.  Originally lifted from     xgps.c.  Note that the satellite list may be truncated based on     available screen size, or may only show satellites used for the     fix.  */  if (gpsdata->satellites!=0) {    if (display_sats >= MAX_POSSIBLE_SATS) {      for (i = 0; i < MAX_POSSIBLE_SATS; i++) {	if (i < gpsdata->satellites) {	    (void)snprintf(scr, sizeof(scr), 			 " %3d    %02d    %03d    %02d      %c",			gpsdata->PRN[i],			gpsdata->elevation[i], gpsdata->azimuth[i],			gpsdata->ss[i], gpsdata->used[i] ? 'Y' : 'N');	} else {          (void)strlcpy(scr, "", sizeof(scr));	}	(void)mvwprintw(satellites, i+2, 1, "%-*s", SATELLITES_WIDTH - 3, scr);      }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?