libgpsd_core.c

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

C
864
字号
	    tm.tm_mday,	    tm.tm_mon,	    tm.tm_year);    /*@ +usedef @*/    nmea_add_checksum(bufp);}static void gpsd_binary_fix_dump(struct gps_device_t *session,				 char bufp[], size_t len){    gpsd_position_fix_dump(session, bufp, len);    gpsd_transit_fix_dump(session, bufp + strlen(bufp), len - strlen(bufp));}static void gpsd_binary_satellite_dump(struct gps_device_t *session, 				char bufp[], size_t len){    int i;    char *bufp2 = bufp;    bufp[0] = '\0';    for( i = 0 ; i < session->gpsdata.satellites; i++ ) {	if (i % 4 == 0) {	    bufp += strlen(bufp);            bufp2 = bufp;	    len -= snprintf(bufp, len,		    "$GPGSV,%d,%d,%02d", 		    ((session->gpsdata.satellites-1) / 4) + 1, 		    (i / 4) + 1,		    session->gpsdata.satellites);	}	bufp += strlen(bufp);	if (i < session->gpsdata.satellites)	    len -= snprintf(bufp, len, 		    ",%02d,%02d,%03d,%02d", 		    session->gpsdata.PRN[i],		    session->gpsdata.elevation[i], 		    session->gpsdata.azimuth[i], 		    session->gpsdata.ss[i]);	if (i % 4 == 3 || i == session->gpsdata.satellites-1) {	    nmea_add_checksum(bufp2);	    len -= 5;	}    }#ifdef ZODIAC_ENABLE    if (session->packet.type == ZODIAC_PACKET && session->driver.zodiac.Zs[0] != 0) {	bufp += strlen(bufp);	bufp2 = bufp;	(void)strlcpy(bufp, "$PRWIZCH", len);	for (i = 0; i < ZODIAC_CHANNELS; i++) {	    len -= snprintf(bufp+strlen(bufp), len,			  ",%02u,%X", 			    session->driver.zodiac.Zs[i], 			    session->driver.zodiac.Zv[i] & 0x0f);	}	nmea_add_checksum(bufp2);    }#endif /* ZODIAC_ENABLE */}static void gpsd_binary_quality_dump(struct gps_device_t *session, 			      char bufp[], size_t len){    int	i, j;    char *bufp2 = bufp;    (void)snprintf(bufp, len-strlen(bufp),		   "$GPGSA,%c,%d,", 'A', session->gpsdata.fix.mode);    j = 0;    for (i = 0; i < session->device_type->channels; i++) {	if (session->gpsdata.used[i]) {	    bufp += strlen(bufp);	    (void)snprintf(bufp, len-strlen(bufp),			   "%02d,", session->gpsdata.used[i]);	    j++;	}    }    for (i = j; i < session->device_type->channels; i++) {	bufp += strlen(bufp);	(void)strlcpy(bufp, ",", len);    }    bufp += strlen(bufp);#define ZEROIZE(x)	(isnan(x)!=0 ? 0.0 : x)      if (session->gpsdata.fix.mode == MODE_NO_FIX)	(void)strlcat(bufp, ",,,", len);    else	(void)snprintf(bufp, len-strlen(bufp),		       "%.1f,%.1f,%.1f*", 		       ZEROIZE(session->gpsdata.pdop), 		       ZEROIZE(session->gpsdata.hdop),		       ZEROIZE(session->gpsdata.vdop));    nmea_add_checksum(bufp2);    bufp += strlen(bufp);    if (finite(session->gpsdata.fix.eph)	|| finite(session->gpsdata.fix.epv)	|| finite(session->gpsdata.epe)) {        /*	 * Output PGRME only if realistic.  Note: we're converting back to	 * our guess about Garmin's confidence units here, make sure this	 * stays consistent with the in-conversion in nmea_parse.c!	 */        (void)snprintf(bufp, len-strlen(bufp),	    "$PGRME,%.2f,M,%.2f,M,%.2f,M",	    ZEROIZE(session->gpsdata.fix.eph * (CEP50_SIGMA/GPSD_CONFIDENCE)), 	    ZEROIZE(session->gpsdata.fix.epv * (CEP50_SIGMA/GPSD_CONFIDENCE)), 	    ZEROIZE(session->gpsdata.epe * (CEP50_SIGMA/GPSD_CONFIDENCE)));        nmea_add_checksum(bufp);     }#undef ZEROIZE}static void gpsd_binary_dump(struct gps_device_t *session, 			      char bufp[], size_t len){    if ((session->gpsdata.set & LATLON_SET) != 0)	gpsd_binary_fix_dump(session, bufp+strlen(bufp), len-strlen(bufp));    if ((session->gpsdata.set & (DOP_SET | ERR_SET)) != 0)	gpsd_binary_quality_dump(session, bufp+strlen(bufp), len-strlen(bufp));    if ((session->gpsdata.set & SATELLITE_SET) != 0)	gpsd_binary_satellite_dump(session,bufp+strlen(bufp),len-strlen(bufp));}#endif /* BINARY_ENABLE */void gpsd_error_model(struct gps_device_t *session, 		      struct gps_fix_t *fix, struct gps_fix_t *oldfix)/* compute errors and derived quantities */{    /*     * Now we compute derived quantities.  This is where the tricky error-     * modeling stuff goes. Presently we don't know how to derive      * time error.     *     * Some drivers set the position-error fields.  Only the Zodiacs      * report speed error.  Nobody reports track error or climb error.     */#define UERE_NO_DGPS	8.0	/* meters, 95% confidence */#define UERE_WITH_DGPS	2.0	/* meters, 95% confidence */    double uere;    if (NULL == session)	return;    uere = (session->gpsdata.status == STATUS_DGPS_FIX ? UERE_WITH_DGPS : UERE_NO_DGPS);    /*     * Field reports match the theoretical prediction that     * expected time error should be half the resolution of     * the GPS clock, so we put the bound of the error     * in as a constant pending getting it from each driver.     */    if (isnan(fix->ept)!=0)	fix->ept = 0.005;    /* Other error computations depend on having a valid fix */    if (fix->mode >= MODE_2D) {	if (isnan(fix->eph)!=0 && finite(session->gpsdata.hdop)!=0)		fix->eph = session->gpsdata.hdop * uere;	if ((fix->mode >= MODE_3D)		&& isnan(fix->epv)!=0 && finite(session->gpsdata.vdop)!=0)	    fix->epv = session->gpsdata.vdop * uere;	if (isnan(session->gpsdata.epe)!=0 && finite(session->gpsdata.pdop)!=0)	    session->gpsdata.epe = session->gpsdata.pdop * uere;	else	    session->gpsdata.epe = NAN;	/*	 * If we have a current fix and an old fix, and the packet handler 	 * didn't set the speed error and climb error members itself, 	 * try to compute them now.	 */	if (isnan(fix->eps)!=0)	{	    if (oldfix->mode > MODE_NO_FIX && fix->mode > MODE_NO_FIX			&& isnan(oldfix->eph)==0 && isnan(oldfix->eph)==0 			&& isnan(oldfix->time)==0 && isnan(oldfix->time)==0 			&& fix->time > oldfix->time) {		double t = fix->time-oldfix->time;		double e = oldfix->eph + fix->eph;		fix->eps = e/t;	    } else		fix->eps = NAN;	}	if ((fix->mode >= MODE_3D) 	    	&& isnan(fix->epc)!=0 && fix->time > oldfix->time) {	    if (oldfix->mode > MODE_3D && fix->mode > MODE_3D) {		double t = fix->time-oldfix->time;		double e = oldfix->epv + fix->epv;		/* if vertical uncertainties are zero this will be too */		fix->epc = e/t;	    }	    /*	     * We compute a track error estimate solely from the	     * position of this fix and the last one.  The maximum	     * track error, as seen from the position of last fix, is	     * the angle subtended by the two most extreme possible	     * error positions of the current fix; the expected track	     * error is half that.  Let the position of the old fix be	     * A and of the new fix B.  We model the view from A as	     * two right triangles ABC and ABD with BC and BD both	     * having the length of the new fix's estimated error.	     * adj = len(AB), opp = len(BC) = len(BD), hyp = len(AC) =	     * len(AD). This leads to spurious uncertainties	     * near 180 when we're moving slowly; to avoid reporting	     * garbage, throw back NaN if the distance from the previous	     * fix is less than the error estimate.	     */	    fix->epd = NAN;	    if (oldfix->mode >= MODE_2D) {		double adj = earth_distance(		    oldfix->latitude, oldfix->longitude, 		    fix->latitude, fix->longitude);		if (isnan(adj)==0 && adj > fix->eph) {		    double opp = fix->eph;		    double hyp = sqrt(adj*adj + opp*opp);		    fix->epd = RAD_2_DEG * 2 * asin(opp / hyp);		}	    }	}    }    /* save old fix for later error computations */    /*@ -mayaliasunique @*/    if (fix->mode >= MODE_2D)	(void)memcpy(oldfix, fix, sizeof(struct gps_fix_t));    /*@ +mayaliasunique @*/}gps_mask_t gpsd_poll(struct gps_device_t *session)/* update the stuff in the scoreboard structure */{    ssize_t newlen;    gps_clear_fix(&session->gpsdata.fix);    if (session->packet.inbuflen==0)	session->gpsdata.d_xmit_time = timestamp();    /* can we get a full packet from the device? */    if (session->device_type) {	newlen = session->device_type->get_packet(session);	session->gpsdata.d_xmit_time = timestamp();	if (session->packet.outbuflen>0 && session->device_type->probe_subtype!=NULL)	    session->device_type->probe_subtype(session, ++session->packet.counter);    } else {	newlen = generic_get(session);	session->gpsdata.d_xmit_time = timestamp();	gpsd_report(LOG_RAW, 		    "packet sniff finds type %d\n", 		    session->packet.type);	if (session->packet.type != BAD_PACKET) {	    switch (session->packet.type) {	    case COMMENT_PACKET:		break;#ifdef SIRF_ENABLE	    case SIRF_PACKET:		(void)gpsd_switch_driver(session, "SiRF binary");		break;#endif /* SIRF_ENABLE */#ifdef TSIP_ENABLE	    case TSIP_PACKET:		(void)gpsd_switch_driver(session, "Trimble TSIP");		break;#endif /* TSIP_ENABLE */#ifdef GARMIN_ENABLE	    case GARMIN_PACKET:		(void)gpsd_switch_driver(session, "Garmin Serial binary");		break;#endif /* GARMIN_ENABLE */#ifdef NMEA_ENABLE	    case NMEA_PACKET:		(void)gpsd_switch_driver(session, "Generic NMEA");		break;#endif /* NMEA_ENABLE */#ifdef ZODIAC_ENABLE	    case ZODIAC_PACKET:		(void)gpsd_switch_driver(session, "Zodiac binary");		break;#endif /* ZODIAC_ENABLE */#ifdef UBX_ENABLE	    case UBX_PACKET:		(void)gpsd_switch_driver(session, "uBlox UBX");		break;#endif /* UBX_ENABLE */#ifdef NAVCOM_ENABLE 	    case NAVCOM_PACKET:         	(void)gpsd_switch_driver(session, "Navcom binary");         	break;#endif /* NAVCOM_ENABLE */#ifdef EVERMORE_ENABLE	    case EVERMORE_PACKET:		(void)gpsd_switch_driver(session, "EverMore binary");		break;#endif /* EVERMORE_ENABLE */#ifdef ITRAX_ENABLE	    case ITALK_PACKET:		(void)gpsd_switch_driver(session, "iTalk binary");		break;#endif /* ITRAX_ENABLE */#ifdef RTCM104_ENABLE	    case RTCM_PACKET:		(void)gpsd_switch_driver(session, "RTCM104");		break;#endif /* RTCM104_ENABLE */	    }	} else if (!gpsd_next_hunt_setting(session))	    return ERROR_SET;    }    /* update the scoreboard structure from the GPS */    gpsd_report(LOG_RAW+2, "GPS sent %d new characters\n", newlen);    if (newlen == -1)	{		/* read error */	session->gpsdata.online = 0;	return 0;    } else if (newlen == 0) {		/* no new data */	if (session->device_type != NULL && timestamp()>session->gpsdata.online+session->device_type->cycle+1){		gpsd_report(LOG_PROG, "GPS is offline (%lf sec since data)\n", 			timestamp() - session->gpsdata.online);	    session->gpsdata.online = 0;	    return 0;	} else	    return ONLINE_SET;    } else if (session->packet.outbuflen == 0) {   /* got new data, but no packet */	    gpsd_report(LOG_RAW+3, "New data, not yet a packet\n");	    return ONLINE_SET;    } else {	gps_mask_t received, dopmask = 0;	session->gpsdata.online = timestamp();	/*@ -nullstate @*/	if (session->gpsdata.raw_hook)	    session->gpsdata.raw_hook(&session->gpsdata, 				      (char *)session->packet.outbuffer,				      (size_t)session->packet.outbuflen, 2);	/*@ -nullstate @*/	session->gpsdata.sentence_length = session->packet.outbuflen;	session->gpsdata.d_recv_time = timestamp();	/* Get data from current packet into the fix structure */	received = 0;	if (session->packet.type != COMMENT_PACKET)	    if (session->device_type != NULL && session->device_type->parse_packet!=NULL)		received = session->device_type->parse_packet(session);	/*	 * Compute fix-quality data from the satellite positions.	 * These will not overwrite DOPs reported from the packet we just got.	 */	if (session->gpsdata.fix.mode > MODE_NO_FIX 		    && (session->gpsdata.set & SATELLITE_SET) != 0		    && session->gpsdata.satellites > 0) {	    dopmask = dop(&session->gpsdata);	    session->gpsdata.epe = NAN;	}	session->gpsdata.set = ONLINE_SET | dopmask | received;	/*	 * Count good fixes. We used to check 	 *	session->gpsdata.status > STATUS_NO_FIX	 * here, but that wasn't quite right.  That tells us whether	 * we think we have a valid fix for the current cycle, but remains	 * true while following non-fix packets are received.  What we	 * really want to know is whether the last packet received was a	 * fix package AND held a valid fix. We must ignore non-fix packages	 * AND packages which have fix data but are flagged as invalid. Some	 * devices output fix packets on a regular basis, even when unable	 * to derive a good fix. Such packets should set STATUS_NO_FIX.	 */	if ((session->gpsdata.set & LATLON_SET )!=0 && session->gpsdata.status > STATUS_NO_FIX)	    session->context->fixcnt++;	session->gpsdata.d_decode_time = timestamp();	/* also copy the sentence up to clients in raw mode */	if (session->packet.type == NMEA_PACKET) {	    if (session->gpsdata.raw_hook)		session->gpsdata.raw_hook(&session->gpsdata,					  (char *)session->packet.outbuffer,					  strlen((char *)session->packet.outbuffer),					  1);	} else {	    char buf2[MAX_PACKET_LENGTH*3+2];	    buf2[0] = '\0';#ifdef RTCM104_ENABLE	    if ((session->gpsdata.set & RTCM_SET) != 0)		rtcm_dump(&session->gpsdata.rtcm, 			  buf2+strlen(buf2), 			  (sizeof(buf2)-strlen(buf2)));	    else {#endif /* RTCM104_ENABLE */#ifdef BINARY_ENABLE		gpsd_binary_dump(session, buf2, sizeof(buf2));#endif /* BINARY_ENABLE */#ifdef RTCM104_ENABLE	    }#endif /* RTCM104_ENABLE */	    if (buf2[0] != '\0') {		gpsd_report(LOG_IO, "<= GPS: %s", buf2);		if (session->gpsdata.raw_hook)		    session->gpsdata.raw_hook(&session->gpsdata, 					      buf2, strlen(buf2), 1);	    }	}	if (session->gpsdata.fix.mode == MODE_3D)	    dgnss_report(session);	return session->gpsdata.set;    }}void gpsd_wrap(struct gps_device_t *session)/* end-of-session wrapup */{    if (session->gpsdata.gps_fd != -1)	gpsd_deactivate(session);}void gpsd_zero_satellites(/*@out@*/struct gps_data_t *out){    (void)memset(out->PRN,       0, sizeof(out->PRN));    (void)memset(out->elevation, 0, sizeof(out->elevation));    (void)memset(out->azimuth,   0, sizeof(out->azimuth));    (void)memset(out->ss,        0, sizeof(out->ss));    out->satellites = 0;}

⌨️ 快捷键说明

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