zodiac.c

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

C
457
字号
/* $Id: zodiac.c 4661 2008-01-19 22:54:23Z garyemiller $ *//* * Handle the Rockwell binary packet format supported by the old Zodiac chipset */#include <sys/types.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <math.h>#include "gpsd_config.h"#include "gpsd.h"#define LITTLE_ENDIAN_PROTOCOL#include "bits.h"#ifdef ZODIAC_ENABLEstruct header {    unsigned short sync;    unsigned short id;    unsigned short ndata;    unsigned short flags;    unsigned short csum;};static unsigned short zodiac_checksum(unsigned short *w, int n){    unsigned short csum = 0;    while (n-- > 0)	csum += *(w++);    return -csum;}/* zodiac_spew - Takes a message type, an array of data words, and a length   for the array, and prepends a 5 word header (including checksum).   The data words are expected to be checksummed */#if defined (WORDS_BIGENDIAN)/* data is assumed to contain len/2 unsigned short words * we change the endianness to little, when needed. */static int end_write(int fd, void *d, int len){    char buf[BUFSIZ];    char *p = buf;    char *data = (char *)d;    size_t n = (size_t)len;    while (n>0) {	*p++ = *(data+1); *p++ = *data;	data += 2; n -= 2;    }    return write(fd, buf, len);}#else#define end_write write#endifstatic void zodiac_spew(struct gps_device_t *session, int type, unsigned short *dat, int dlen){    struct header h;    int i;    char buf[BUFSIZ];    h.sync = 0x81ff;    h.id = (unsigned short)type;    h.ndata = (unsigned short)(dlen - 1);    h.flags = 0;    h.csum = zodiac_checksum((unsigned short *) &h, 4);    if (session->gpsdata.gps_fd != -1) {#ifdef ALLOW_RECONFIGURE	(void)end_write(session->gpsdata.gps_fd, &h, sizeof(h));	(void)end_write(session->gpsdata.gps_fd, dat, sizeof(unsigned short) * dlen);#endif /* ALLOW_RECONFIGURE */    }    (void)snprintf(buf, sizeof(buf),		   "%04x %04x %04x %04x %04x",		   h.sync,h.id,h.ndata,h.flags,h.csum);    for (i = 0; i < dlen; i++)	(void)snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf),		       " %04x", dat[i]);    gpsd_report(LOG_RAW, "Sent Zodiac packet: %s\n",buf);}static bool zodiac_speed_switch(struct gps_device_t *session, speed_t speed){    unsigned short data[15];    if (session->driver.zodiac.sn++ > 32767)	session->driver.zodiac.sn = 0;          memset(data, 0, sizeof(data));    /* data is the part of the message starting at word 6 */    data[0] = session->driver.zodiac.sn;	/* sequence number */    data[1] = 1;			/* port 1 data valid */    data[2] = 1;			/* port 1 character width (8 bits) */    data[3] = 0;			/* port 1 stop bits (1 stopbit) */    data[4] = 0;			/* port 1 parity (none) */    data[5] = (unsigned short)(round(log((double)speed/300)/M_LN2)+1); /* port 1 speed */    data[14] = zodiac_checksum(data, 14);    zodiac_spew(session, 1330, data, 15);#ifdef ALLOW_RECONFIGURE    return true; /* it would be nice to error-check this */#else    return false;#endif /* ALLOW_RECONFIGURE */}static void send_rtcm(struct gps_device_t *session, 		      char *rtcmbuf, size_t rtcmbytes){    unsigned short data[34];    int n = 1 + (int)(rtcmbytes/2 + rtcmbytes%2);    if (session->driver.zodiac.sn++ > 32767)	session->driver.zodiac.sn = 0;    memset(data, 0, sizeof(data));    data[0] = session->driver.zodiac.sn;		/* sequence number */    memcpy(&data[1], rtcmbuf, rtcmbytes);    data[n] = zodiac_checksum(data, n);    zodiac_spew(session, 1351, data, n+1);}static ssize_t zodiac_send_rtcm(struct gps_device_t *session,			char *rtcmbuf, size_t rtcmbytes){    size_t len;    while (rtcmbytes > 0) {	len = (size_t)(rtcmbytes>64?64:rtcmbytes);	send_rtcm(session, rtcmbuf, len);	rtcmbytes -= len;	rtcmbuf += len;    }    return 1;}static gps_mask_t handle1000(struct gps_device_t *session){    double subseconds;    struct tm unpacked_date;    /* ticks                      = getlong(6); */    /* sequence                   = getword(8); */    /* measurement_sequence       = getword(9); */    /*@ -boolops -predboolothers @*/    session->gpsdata.status       = (getword(10) & 0x1c) ? 0 : 1;    if (session->gpsdata.status != 0)	session->gpsdata.fix.mode = (getword(10) & 1) ? MODE_2D : MODE_3D;    else	session->gpsdata.fix.mode = MODE_NO_FIX;    /*@ +boolops -predboolothers @*/    /* solution_type                 = getword(11); */    session->gpsdata.satellites_used = (int)getword(12);    /* polar_navigation              = getword(13); */    /* gps_week                      = getword(14); */    /* gps_seconds                   = getlong(15); */    /* gps_nanoseconds               = getlong(17); */    unpacked_date.tm_mday = (int)getword(19);    unpacked_date.tm_mon = (int)getword(20) - 1;    unpacked_date.tm_year = (int)getword(21) - 1900;    unpacked_date.tm_hour = (int)getword(22);    unpacked_date.tm_min = (int)getword(23);    unpacked_date.tm_sec = (int)getword(24);    subseconds = (int)getlong(25) / 1e9;    /*@ -compdef */    session->gpsdata.fix.time = session->gpsdata.sentence_time =	(double)mkgmtime(&unpacked_date) + subseconds;    /*@ +compdef */#ifdef NTPSHM_ENABLE    /* Removing/changing the magic number below is likely to disturb     * the handling of the 1pps signal from the gps device. The regression     * tests and simple gps applications do not detect this. A live test     * with the 1pps signal active is required. */    if (session->context->enable_ntpshm && session->gpsdata.fix.mode > MODE_NO_FIX)	(void)ntpshm_put(session, session->gpsdata.fix.time + 1.1);#endif    /*@ -type @*/    session->gpsdata.fix.latitude  = ((long)getlong(27)) * RAD_2_DEG * 1e-8;    session->gpsdata.fix.longitude = ((long)getlong(29)) * RAD_2_DEG * 1e-8;    /*     * The Rockwell Jupiter TU30-D140 reports altitude as uncorrected height     * above WGS84 geoid.  The Zodiac binary protocol manual does not      * specify whether word 31 is geodetic or WGS 84.      */    session->gpsdata.fix.altitude  = ((long)getlong(31)) * 1e-2;    /*@ +type @*/    session->gpsdata.separation    = ((short)getword(33)) * 1e-2;    session->gpsdata.fix.altitude -= session->gpsdata.separation;    session->gpsdata.fix.speed     = (int)getlong(34) * 1e-2;    session->gpsdata.fix.track     = (int)getword(36) * RAD_2_DEG * 1e-3;    session->mag_var               = ((short)getword(37)) * RAD_2_DEG * 1e-4;    session->gpsdata.fix.climb     = ((short)getword(38)) * 1e-2;    /* map_datum                   = getword(39); */    /* manual says these are 1-sigma */    session->gpsdata.fix.eph       = (int)getlong(40) * 1e-2 * GPSD_CONFIDENCE;    session->gpsdata.fix.epv       = (int)getlong(42) * 1e-2 * GPSD_CONFIDENCE;    session->gpsdata.fix.ept       = (int)getlong(44) * 1e-2 * GPSD_CONFIDENCE;    session->gpsdata.fix.eps       = (int)getword(46) * 1e-2 * GPSD_CONFIDENCE;    /* clock_bias                  = (int)getlong(47) * 1e-2; */    /* clock_bias_sd               = (int)getlong(49) * 1e-2; */    /* clock_drift                 = (int)getlong(51) * 1e-2; */    /* clock_drift_sd              = (int)getlong(53) * 1e-2; */#if 0    gpsd_report(LOG_INF, "date: %lf\n", session->gpsdata.fix.time);    gpsd_report(LOG_INF, "  solution invalid:\n");    gpsd_report(LOG_INF, "    altitude: %d\n", (getword(10) & 1) ? 1 : 0);    gpsd_report(LOG_INF, "    no diff gps: %d\n", (getword(10) & 2) ? 1 : 0);    gpsd_report(LOG_INF, "    not enough satellites: %d\n", (getword(10) & 4) ? 1 : 0);    gpsd_report(LOG_INF, "    exceed max EHPE: %d\n", (getword(10) & 8) ? 1 : 0);    gpsd_report(LOG_INF, "    exceed max EVPE: %d\n", (getword(10) & 16) ? 1 : 0);    gpsd_report(LOG_INF, "  solution type:\n");    gpsd_report(LOG_INF, "    propagated: %d\n", (getword(11) & 1) ? 1 : 0);    gpsd_report(LOG_INF, "    altitude: %d\n", (getword(11) & 2) ? 1 : 0);    gpsd_report(LOG_INF, "    differential: %d\n", (getword(11) & 4) ? 1 : 0);    gpsd_report(LOG_INF, "Number of measurements in solution: %d\n", getword(12));    gpsd_report(LOG_INF, "Lat: %f\n", getlong(27) * RAD_2_DEG * 1e-8);    gpsd_report(LOG_INF, "Lon: %f\n", getlong(29) * RAD_2_DEG * 1e-8);    gpsd_report(LOG_INF, "Alt: %f\n", (double) getlong(31) * 1e-2);    gpsd_report(LOG_INF, "Speed: %f\n", (double) getlong(34) * 1e-2 * MPS_TO_KNOTS);    gpsd_report(LOG_INF, "Map datum: %d\n", getword(39));

⌨️ 快捷键说明

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