开了一个交流群,欢迎爱好者和开发者一起交流,转载请注明出处。
QQ群:519230208,为避免广告骚扰,申请时请注明 “开发者” 字样
========================================================
参考资料:
GPS数据包分析:http://www.cnblogs.com/csMapx/archive/2011/11/02/2232663.html 手机定位原理,关于GPS&GLONASS&北斗:http://www.cnblogs.com/radiolover/p/4307453.html
GSP 数据解析(搜索 NMEA parser)
C Project : http://nmea.sourceforge.net/#downloads
C++ Project : http://www.visualgps.net/WhitePapers/NMEAParser/NMEAParser.htm
单片机(郭天详):http://download.csdn.net/detail/suzhouzhouchunhua/2370503
Makefile中添加以下内容:
CC=arm-poky-linux-gnueabi-gcc --sysroot=/home/summer/test-yocto/qemuarm LD=arm-poky-linux-gnueabi-ld --sysroot=/home/summer/test-yocto/qemuarm CFLAGS=-O2 -pipe -g -feliminate-unused-debug-types CXXFLAGS=-O2 -pipe -g -feliminate-unused-debug-types
ERROR记录与解决方法
error: lib/libnmea.a(generate.o):在函数‘nmea_gsv_npack’中: generate.c:(.text+0x7f0):对‘ceil’未定义的引用 collect2: error: ld returned 1 exit status make: *** [samples_generate] 错误 1 rm samples/generate/main.o Makefile中添加红色,ubuntu编译器不能识别加在前边。。。晕,macos完全不用修改 samples_%: samples/%/main.o $(CC) $< $(LIBS) -o build/$@ -lm
Error case :
129, Lat: -nan, Lon: nan, Sig: 1, Fix: 3 $GPRMC,213922.000,A,4221.1129,N,07102.9146,W,0.00,,010207,,,A*6F Trace: $GPGGA,213923.000,4221.1129,N,07102.9146,W,1,04,3.9,129.7,M,-33.7,M,,0000*6F Trace: 130, Lat: -nan, Lon: nan, Sig: 1, Fix: 3 $GPGSA,A,3,26,07,06,21,,,,,,,,,4.1,3.9,1.0*3A Trace: 131, Lat: -nan, Lon: nan, Sig: 1, Fix: 3 $GPRMC,213923.000,A,4221.1129,N,07102.9146,W,0.00,,010207,,,A*6E Trace: $GPGGA,213924.000,4221.1129,N,07102.9146,W,1,04,3.9,129.7,M,-33.7,M,,0000*68 Trace: 132, Lat: -nan, Lon: nan, Sig: 1, Fix: 3 $GPGSA,A,3,26,07,06,21,,,,,,,,,4.0,3.9,1.0*3B Trace: 133, Lat: -nan, Lon: nan, Sig: 1, Fix: 3 $GPRMC,213924.000,A,4221.1129,N,07102.9146,W,0.00,,010207,,,A*69 Trace: $GPGGA,213925.000,4221.1129,N,07102.9146,W,1,04,3.9,129.7,M,-33.7,M,,0000*69 Trace: 134, Lat: -nan, Lon: nan, Sig: 1, Fix: 3 $GPGSA,A,3,26,07,06,21,,,,,,,,,4.0,3.9,1.0*3B Trace: $GPRMC,213925.000,A,4221.1129,N,07102.9146,W,0.00,,010207,,,A*68 Trace: 135, Lat: -nan, Lon: nan, Sig: 1, Fix: 3 $GPGGA,213926.000,4221.1112,N,07102.9177,W,1,04,3.9,136.5,M,-33.7,M,,0000*6C Trace: 136, Lat: -nan, Lon: nan, Sig: 1, Fix: 3 ---------------------------------------------------------------------------------
--------------------------------------------------------------------------------- Right case:
$GPGSV,3,2,11,24,83,061,,29,64,170,,10,45,056,,02,23,121,*7F Trace: $GPGSV,3,3,11,08,17,067,28,27,10,041,,18,05,257,*41 Trace: 127, Lat: 0.739180, Lon: -1.240032, Sig: 1, Fix: 3 $GPRMC,213921.000,A,4221.1129,N,07102.9146,W,0.00,,010207,,,A*6C Trace: 128, Lat: 0.739180, Lon: -1.240032, Sig: 1, Fix: 3 $GPGGA,213922.000,4221.1129,N,07102.9146,W,1,04,3.9,129.7,M,-33.7,M,,0000*6E Trace: $GPGSA,A,3,26,07,06,21,,,,,,,,,4.1,3.9,1.0*3A Trace: 129, Lat: 0.739180, Lon: -1.240032, Sig: 1, Fix: 3 $GPRMC,213922.000,A,4221.1129,N,07102.9146,W,0.00,,010207,,,A*6F Trace: $GPGGA,213923.000,4221.1129,N,07102.9146,W,1,04,3.9,129.7,M,-33.7,M,,0000*6F Trace: 130, Lat: 0.739180, Lon: -1.240032, Sig: 1, Fix: 3 $GPGSA,A,3,26,07,06,21,,,,,,,,,4.1,3.9,1.0*3A Trace: 131, Lat: 0.739180, Lon: -1.240032, Sig: 1, Fix: 3 $GPRMC,213923.000,A,4221.1129,N,07102.9146,W,0.00,,010207,,,A*6E Trace: $GPGGA,213924.000,4221.1129,N,07102.9146,W,1,04,3.9,129.7,M,-33.7,M,,0000*68 Trace: 132, Lat: 0.739180, Lon: -1.240032, Sig: 1, Fix: 3 $GPGSA,A,3,26,07,06,21,,,,,,,,,4.0,3.9,1.0*3B Trace: 133, Lat: 0.739180, Lon: -1.240032, Sig: 1, Fix: 3 $GPRMC,213924.000,A,4221.1129,N,07102.9146,W,0.00,,010207,,,A*69
/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* this implements a GPS hardware library for the Android emulator. * the following code should be built as a shared library that will be * placed into /system/lib/hw/gps.goldfish.so * * it will be loaded by the code in hardware/libhardware/hardware.c * which is itself called from android_location_GpsLocationProvider.cpp ****************************************************************************** ****************************************************************************** * * Modified by liukun321 GJGJ * http://blog.csdn.net/liukun321 * ****************************************************************************** ******************************************************************************/ #include <errno.h> #include <pthread.h> #include <fcntl.h> #include <sys/epoll.h> #include <math.h> #include <time.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <termios.h> #include <errno.h> #define LOG_TAG "gps_Ublox6M" #include <cutils/log.h> #include <cutils/sockets.h> #include <hardware/gps.h> #include <hardware/qemud.h> #include <hardware/hardware.h> /* the name of the qemud-controlled socket */ #define QEMU_CHANNEL_NAME "gps" #define GPS_DEBUG 0 #define Ublox_6M 1 #if GPS_DEBUG # define D(...) LOGD(__VA_ARGS__) #else # define D(...) ((void)0) #endif /*****************************************************************/ /*****************************************************************/ /***** *****/ /***** N M E A T O K E N I Z E R *****/ /***** *****/ /*****************************************************************/ /*****************************************************************/ typedef struct { const char* p; const char* end; } Token; #define MAX_NMEA_TOKENS 16 typedef struct { int count; Token tokens[ MAX_NMEA_TOKENS ]; } NmeaTokenizer; /*********************************************************************/ GpsStatus g_status; static int nmea_tokenizer_init( NmeaTokenizer* t, const char* p, const char* end ) { int count = 0; char* q; // the initial '$' is optional if (p < end && p[0] == '$') p += 1; // remove trailing newline if (end > p && end[-1] == ' ') { end -= 1; if (end > p && end[-1] == ' ') end -= 1; } // get rid of checksum at the end of the sentecne if (end >= p+3 && end[-3] == '*') { end -= 3; } while (p < end) { const char* q = p; q = memchr(p, ',', end-p); if (q == NULL) q = end; if (q >= p) {////////////////////////////////////////////////////////////////////////////// if (count < MAX_NMEA_TOKENS) { t->tokens[count].p = p; t->tokens[count].end = q; count += 1; } } if (q < end) q += 1; p = q; } t->count = count; return count; } static Token nmea_tokenizer_get( NmeaTokenizer* t, int index ) { Token tok; static const char* dummy = ""; if (index < 0 || index >= t->count) { tok.p = tok.end = dummy; } else tok = t->tokens[index]; return tok; } static int str2int( const char* p, const char* end ) { int result = 0; int len = end - p; for ( ; len > 0; len--, p++ ) { int c; if (p >= end) goto Fail; c = *p - '0'; if ((unsigned)c >= 10) goto Fail; result = result*10 + c; } return result; Fail: return -1; } static double str2float( const char* p, const char* end ) { int result = 0; int len = end - p; char temp[16]; if (len >= (int)sizeof(temp)) return 0.; memcpy( temp, p, len ); temp[len] = 0; return strtod( temp, NULL ); } /*****************************************************************/ /*****************************************************************/ /***** *****/ /***** N M E A P A R S E R *****/ /***** *****/ /*****************************************************************/ /*****************************************************************/ #define NMEA_MAX_SIZE 83 typedef struct { int pos; int overflow; int utc_year; int utc_mon; int utc_day; int utc_diff; GpsLocation fix; //******************************** GpsSvStatus sv_status; int sv_status_changed; #ifdef Ublox_6M GpsCallbacks callback; #else //********************************* gps_location_callback callback; #endif char in[ NMEA_MAX_SIZE+1 ]; } NmeaReader; static void nmea_reader_update_utc_diff( NmeaReader* r ) { time_t now = time(NULL); struct tm tm_local; struct tm tm_utc; long time_local, time_utc; gmtime_r( &now, &tm_utc ); localtime_r( &now, &tm_local ); time_local = tm_local.tm_sec + 60*(tm_local.tm_min + 60*(tm_local.tm_hour + 24*(tm_local.tm_yday + 365*tm_local.tm_year))); time_utc = tm_utc.tm_sec + 60*(tm_utc.tm_min + 60*(tm_utc.tm_hour + 24*(tm_utc.tm_yday + 365*tm_utc.tm_year))); r->utc_diff = time_local - time_utc; } static void nmea_reader_init( NmeaReader* r ) { memset( r, 0, sizeof(*r) ); r->pos = 0; r->overflow = 0; r->utc_year = -1; r->utc_mon = -1; r->utc_day = -1; #ifdef Ublox_6M r->callback.sv_status_cb = NULL;////////////////////////////////////////// r->callback.nmea_cb = NULL; r->callback.location_cb = NULL; r->callback.status_cb = NULL; #else r->callback = NULL; #endif r->fix.size = sizeof(r->fix); nmea_reader_update_utc_diff( r ); } static void nmea_reader_set_callback( NmeaReader* r, gps_location_callback cb ) { #ifdef Ublox_6M r->callback.location_cb = cb;////////////////////////////////////////////////// #else r->callback = cb; #endif if (cb != NULL && r->fix.flags != 0) { D("%s: sending latest fix to new callback", __FUNCTION__); #ifdef Ublox_6M r->callback.location_cb( &r->fix );///////////////////////////////////////////// #else r->fix.flags = 0; #endif } } static int nmea_reader_update_time( NmeaReader* r, Token tok ) { int hour, minute; double seconds; struct tm tm; time_t fix_time; if (tok.p + 6 > tok.end) return -1; if (r->utc_year < 0) { // no date yet, get current one time_t now = time(NULL); gmtime_r( &now, &tm ); r->utc_year = tm.tm_year + 1900; r->utc_mon = tm.tm_mon + 1; r->utc_day = tm.tm_mday; } hour = str2int(tok.p, tok.p+2); minute = str2int(tok.p+2, tok.p+4); seconds = str2float(tok.p+4, tok.end); tm.tm_hour = hour; tm.tm_min = minute; tm.tm_sec = (int) seconds; tm.tm_year = r->utc_year - 1900; tm.tm_mon = r->utc_mon - 1; tm.tm_mday = r->utc_day; tm.tm_isdst = -1; fix_time = mktime( &tm ) + r->utc_diff; r->fix.timestamp = (long long)fix_time * 1000; return 0; } static int nmea_reader_update_date( NmeaReader* r, Token date, Token time ) { Token tok = date; int day, mon, year; if (tok.p + 6 != tok.end) { D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p); return -1; } day = str2int(tok.p, tok.p+2); mon = str2int(tok.p+2, tok.p+4); year = str2int(tok.p+4, tok.p+6) + 2000; if ((day|mon|year) < 0) { D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p); return -1; } r->utc_year = year; r->utc_mon = mon; r->utc_day = day; return nmea_reader_update_time( r, time ); } static double convert_from_hhmm( Token tok ) { double val = str2float(tok.p, tok.end); int degrees = (int)(floor(val) / 100); double minutes = val - degrees*100.; double dcoord = degrees + minutes / 60.0; return dcoord; } static int nmea_reader_update_latlong( NmeaReader* r, Token latitude, char latitudeHemi, Token longitude, char longitudeHemi ) { double lat, lon; Token tok; tok = latitude; if (tok.p + 6 > tok.end) { D("latitude is too short: '%.*s'", tok.end-tok.p, tok.p); return -1; } lat = convert_from_hhmm(tok); if (latitudeHemi == 'S') lat = -lat; tok = longitude; if (tok.p + 6 > tok.end) { D("longitude is too short: '%.*s'", tok.end-tok.p, tok.p); return -1; } lon = convert_from_hhmm(tok); if (longitudeHemi == 'W') lon = -lon; r->fix.flags |= GPS_LOCATION_HAS_LAT_LONG; r->fix.latitude = lat; r->fix.longitude = lon; return 0; } static int nmea_reader_update_altitude( NmeaReader* r, Token altitude, Token units ) { double alt; Token tok = altitude; if (tok.p >= tok.end) return -1; r->fix.flags |= GPS_LOCATION_HAS_ALTITUDE; r->fix.altitude = str2float(tok.p, tok.end); return 0; } static int nmea_reader_update_bearing( NmeaReader* r, Token bearing ) { double alt; Token tok = bearing; if (tok.p >= tok.end) return -1; r->fix.flags |= GPS_LOCATION_HAS_BEARING; r->fix.bearing = str2float(tok.p, tok.end); return 0; } static int nmea_reader_update_speed( NmeaReader* r, Token speed ) { double alt; Token tok = speed; if (tok.p >= tok.end) return -1; r->fix.flags |= GPS_LOCATION_HAS_SPEED; r->fix.speed = str2float(tok.p, tok.end); return 0; } static int nmea_reader_update_accuracy(NmeaReader * r, Token accuracy) { double acc; Token tok = accuracy; if(tok.p >= tok.end) return -1; r->fix.accuracy = str2float(tok.p, tok.end); if(r->fix.accuracy == 99.99){ return 0; } r->fix.flags |= GPS_LOCATION_HAS_ACCURACY; return 0; } /* this is the state of our connection to the qemu_gpsd daemon */ typedef struct { int init; int fd; GpsCallbacks callbacks; pthread_t thread; int control[2]; } GpsState; static GpsState _gps_state[1]; static void nmea_reader_parse( NmeaReader* r ) { /* we received a complete sentence, now parse it to generate * a new GPS fix... */ NmeaTokenizer tzer[1]; Token tok; D("Received: '%.*s'", r->pos, r->in); if (r->pos < 9) { D("Too short. discarded."); return; } nmea_tokenizer_init(tzer, r->in, r->in + r->pos); #if GPS_DEBUG { int n; D("Found %d tokens", tzer->count); for (n = 0; n < tzer->count; n++) { Token tok = nmea_tokenizer_get(tzer,n); D("%2d: '%.*s'", n, tok.end-tok.p, tok.p); } } #endif tok = nmea_tokenizer_get(tzer, 0); if (tok.p + 5 > tok.end) { D("sentence id '%.*s' too short, ignored.", tok.end-tok.p, tok.p); return; } // ignore first two characters. tok.p += 2; if ( !memcmp(tok.p, "GGA", 3) ) { // GPS fix Token tok_time = nmea_tokenizer_get(tzer,1); Token tok_latitude = nmea_tokenizer_get(tzer,2); Token tok_latitudeHemi = nmea_tokenizer_get(tzer,3); Token tok_longitude = nmea_tokenizer_get(tzer,4); Token tok_longitudeHemi = nmea_tokenizer_get(tzer,5); Token tok_altitude = nmea_tokenizer_get(tzer,9); Token tok_altitudeUnits = nmea_tokenizer_get(tzer,10); nmea_reader_update_time(r, tok_time); nmea_reader_update_latlong(r, tok_latitude, tok_latitudeHemi.p[0], tok_longitude, tok_longitudeHemi.p[0]); nmea_reader_update_altitude(r, tok_altitude, tok_altitudeUnits); } else if ( !memcmp(tok.p, "GSA", 3) ) { // do something ? #ifdef Ublox_6M { D("may%s,%d,%s,gsa ",__FILE__,__LINE__,__FUNCTION__); Token tok_fixStatus = nmea_tokenizer_get(tzer, 2); int i; if (tok_fixStatus.p[0] != '