北斗gps Android hal层so库代码

来源:互联网 发布:淘宝开店取名 编辑:程序博客网 时间:2024/05/22 07:50

网上下载的代码,自己编辑修改,加入了北斗定位功能,主要是修改了GSV,GSA语句的解析,在A10平台上测试良好:

北斗双模下的LOG:

$GPGSV,3,3,10,31,46,012,,32,39,287,40*79$BDGSV,1,1,04,02,45,242,43,03,00,000,34,06,00,000,32,09,38,216,37*6C$GNRMC,040059.080,A,2230.8804,N,11354.9920,E,0.83,0.00,040613,,,A*7C$GNVTG,0.00,T,,M,0.83,N,1.54,K,A*28$GNZDA,040059.080,04,06,2013,00,00*4A$GNGGA,040100.000,2230.8897,N,11355.0128,E,1,06,28.3,79.2,M,0.0,M,,*71$GNGLL,2230.8897,N,11355.0128,E,040100.000,A,0*36$GPGSA,A,3,16,20,06,32,,,,,,,,,30.4,28.3,11.2*0C$BDGSA,A,3,02,09,,,,,,,,,,,30.4,28.3,11.2*14$GPGSV,3,1,10,03,06,197,,06,19,182,33,14,50,109,,16,48,230,46*75$GPGSV,3,2,10,20,16,305,41,22,15,171,,29,23,066,22,30,00,000,25*72$GPGSV,3,3,10,31,46,012,,32,39,287,40*79$BDGSV,1,1,04,02,45,242,43,03,00,000,34,06,00,000,32,09,38,216,37*6C$GNRMC,040100.000,A,2230.8897,N,11355.0128,E,0.64,0.00,040613,,,A*72$GNVTG,0.00,T,,M,0.64,N,1.19,K,A*28$GNZDA,040100.000,04,06,2013,00,00*4F


一些命令的解释:

$GNRMC,091356.000,V,2230.8777,N,11354.9659,E,7.88,270.95,040613,,,N*63
                                          |
                  这里V变成A时候表示定位成功
$GPGSV,3,1,11,01,46,169,,03,29,038,,06,13,045,,07,55,322,*74
$GPGSV,3,2,11,08,24,325,,11,72,159,,13,32,226,,16,17,081,*77
$GPGSV,3,3,11,19,49,022,,23,20,200,,28,07,296,*4D
$BDGSV,1,1,04,02,44,240,,07,64,173,,08,60,343,,10,77,244,*61
GPGSV表示GPS的GSV,BDGSV表示北斗的GSV
第一列3表示有3行GPGSV语句输出;紧接着第二列的1、2、3表示当前是第几行GSV;接着的11表示一共11颗星,接着的是4个数字为一组的信号值

$GPGSA,A,3,16,20,06,32,,,,,,,,,30.4,28.3,11.2*0C
$BDGSA,A,3,02,09,,,,,,,,,,,30.4,28.3,11.2*14

这里第3~14位,一共12位表示已经定位的卫星号,它们和GSV中可见卫星信息组中的卫星号一致,上层要判断这两个数值一致才表示可用卫星,可见

GSV中得到的是可见卫星数量,GSA中得到的是可用卫星数量,可见卫星数量>=可用卫星数量,他们就是GPS测试软件中的in view和in use数值

北斗的一些发送命令:
    
    char *str_B115200 = "$PCAS01,5*19\r\n";
    char *str_B9600  = "$PCAS01,1*1D\r\n";
    char *str_save = "$PCAS00*01\r\n";//将当前配置写入flash,否则断电后恢复为默认的
    char *str_beidou       = "$PCAS04,2*1B\r\n"; //北斗模式
    char *str_shuangmo = "$PCAS04,3*1A\r\n"; //北斗和GPS共存模式
这里的*后面的数字是异或校验,如$PCAS01,5*19这一行,'P' ^ 'C' ^ 'A' ^ 'S'^ '0' ^ '1' ^ ',' ^ '5' == 0x19;

详细的命令参考厂商的手册


下面是源代码:

Android.mk

LOCAL_PATH := $(call my-dir)#ifneq ($(TARGET_PRODUCT),sim)# HAL module implemenation, not prelinked and stored in# hw/<GPS_HARDWARE_MODULE_ID>.<ro.hardware>.soinclude $(CLEAR_VARS)LOCAL_PRELINK_MODULE := falseLOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hwLOCAL_CFLAGS += -DQEMU_HARDWARELOCAL_SHARED_LIBRARIES := liblog libcutils libhardwareLOCAL_SRC_FILES := gps.cLOCAL_MODULE := gps.defaultLOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY)#endif



gps.c:

/* * 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 */#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> /*Unix ??????*/#include <sys/types.h> #include <sys/stat.h> #include <termios.h> /*PPSIX ??????*/#include <errno.h> /*?????*/#define  LOG_TAG  "gps_qemu"#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(...)   LOGE(__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  20typedef struct {    int     count;    Token   tokens[ MAX_NMEA_TOKENS ];} NmeaTokenizer;/*********************************************************************/GpsStatus g_status;    static intnmea_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] == '\n') {        end -= 1;        if (end > p && end[-1] == '\r')            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 Tokennmea_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 intstr2int( 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 doublestr2float( 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  83typedef 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 voidnmea_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 voidnmea_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 voidnmea_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 intnmea_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 intnmea_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 doubleconvert_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 intnmea_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 intnmea_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 intnmea_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 intnmea_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 voidnmea_reader_parse( NmeaReader*  r ){    /* we received a complete sentence, now parse it to generate     * a new GPS fix...     */    NmeaTokenizer  tzer[1];    Token          tok;    char *ptr;    D("Received: '%.*s'", r->pos, r->in);    /*********add by jhuang for call back NMEA***************/     /*     if(r->callback.nmea_cb)            {            r->callback.nmea_cb(r->fix.timestamp,r->in,r->pos);            }*/    /***************************************************/     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.    ptr = tok.p;    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 ?        int is_beidou = !memcmp(ptr, "BD", 2);#ifdef Ublox_6M           /* do something ? */          {              D("may%s,%d,%s,gsa\n",__FILE__,__LINE__,__FUNCTION__);              Token tok_fixStatus = nmea_tokenizer_get(tzer, 2);              int i;              if (tok_fixStatus.p[0] != '\0' && tok_fixStatus.p[0] != '1') {//等于'1'的话表示定位不可用模式                  Token tok_accuracy = nmea_tokenizer_get(tzer, 15);//position dilution of precision dop                   nmea_reader_update_accuracy(r, tok_accuracy);                  if(!is_beidou)//因为GPGSA在BDGSA前面,所以第一次进来为GPGSA,这时要清零                    r->sv_status.used_in_fix_mask = 0ul;                  D("\n");                  for (i = 3; i <= 14; ++i){                      Token tok_prn = nmea_tokenizer_get(tzer, i);                      int prn = str2int(tok_prn.p, tok_prn.end);                      D("gsa,prn=%d,",prn);                      if (prn > 0){                          r->sv_status.used_in_fix_mask |= (1ul << ( prn-1)); //这里有可能BD和GP的PRN号一样,就覆盖了,暂时不修改了,这里要prn-1,是因为                                                                            //prn最大值为32,所以要减1,否则左移会溢出啊, 要完善的支持BD和GP,还要在                                                                            //framework的GpsStatus.java-> setStatus方法中处理可用卫星的问题                          r->sv_status_changed = 1;                      }                  }D("\n");                  D("%s: fix mask is %x", __FUNCTION__, r->sv_status.used_in_fix_mask);                  //   D(" [log hit][%s:%d] fix.flags=0x%x ", __FUNCTION__, __LINE__, r->fix.flags);                }              D(" [log hit][%s:%d] fix.flags=0x%x ", __FUNCTION__, __LINE__, r->fix.flags);          }  #endif       } //////////////////////////////////////////////////////////////////////////////////////////////////#ifdef Ublox_6M       else if ( !memcmp(tok.p, "GSV", 3) ) {          int is_beidou = !memcmp(ptr, "BD", 2);        D("sclu is_Beidou = %d", is_beidou);        D("may%s,%d,%s,gsV\n",__FILE__,__LINE__,__FUNCTION__);          Token tok_noSatellites = nmea_tokenizer_get(tzer, 3);          int noSatellites = str2int(tok_noSatellites.p, tok_noSatellites.end);          D("%d,inview=%d,\n",__LINE__,noSatellites);            if (noSatellites > 0) {              Token tok_noSentences = nmea_tokenizer_get(tzer, 1); //             Token tok_sentence     = nmea_tokenizer_get(tzer, 2);              int sentence = str2int(tok_sentence.p, tok_sentence.end);//当前解析的是第几个GSV语句              int totalSentences = str2int(tok_noSentences.p, tok_noSentences.end);//一共有多少个GSV语句              D("%d,gsv_index=%d,gsv_total=%d\n",__LINE__,sentence,totalSentences);                int curr;              int i;              if ((sentence == 1) && !is_beidou) {                  D("msg_index=%d\n",sentence);                  //  r->sv_status_changed = 0;                   r->sv_status.num_svs = 0; //sv_list的下标,只有$GPGSV当前语句序号为1时候才会清零,$BDGSV时候不会,而是继续递增                 r->sv_status.ephemeris_mask=0ul;                  r->sv_status.almanac_mask=0ul;              }              curr = r->sv_status.num_svs;              i = 0;              if(is_beidou && (sentence == 1)){                noSatellites += r->sv_status.num_svs;                D("sclu add beidou total num");            }            while (i < 4 && r->sv_status.num_svs < noSatellites){                  Token    tok_prn = nmea_tokenizer_get(tzer, i * 4 + 4);                  Token    tok_elevation = nmea_tokenizer_get(tzer, i * 4 + 5);                  Token    tok_azimuth = nmea_tokenizer_get(tzer, i * 4 + 6);                  Token    tok_snr = nmea_tokenizer_get(tzer, i * 4 + 7);                  r->sv_status.sv_list[curr].prn = str2int(tok_prn.p, tok_prn.end);                  if(is_beidou){//北斗卫星编号加上偏移量,避免与GPS冲突                    D("sclu, number = %d", r->sv_status.sv_list[curr].prn);                    //r->sv_status.sv_list[curr].prn += 100;                }                r->sv_status.sv_list[curr].elevation = str2float(tok_elevation.p, tok_elevation.end);                  r->sv_status.sv_list[curr].azimuth = str2float(tok_azimuth.p, tok_azimuth.end);                  r->sv_status.sv_list[curr].snr = str2float(tok_snr.p, tok_snr.end);                  r->sv_status.ephemeris_mask|=(1ul << (r->sv_status.sv_list[curr].prn-1));                  r->sv_status.almanac_mask|=(1ul << (r->sv_status.sv_list[curr].prn-1));                           r->sv_status.num_svs += 1;                  D("**********curr=%d\n",curr);                  D("%d,prn=%d:snr=%f\n",__LINE__,r->sv_status.sv_list[curr].prn,r->sv_status.sv_list[curr].snr);                  curr += 1;                  i += 1;              }              if ((sentence == totalSentences) && is_beidou) { // $GPGSV和$BDGSV一起解析完了才可以上报                D("msg=%d,msgindex=%d, curr=%d",totalSentences,sentence, curr);  #ifdef Ublox_6M                   r->callback.sv_status_cb=_gps_state->callbacks.sv_status_cb;                  if (r->sv_status_changed !=0) {                      if (r->callback.sv_status_cb) {  #if GPS_DEBUG                           D("%d,SV_STATSU,change=%d\n",__LINE__,r->sv_status_changed);                          int nums=r->sv_status.num_svs;                          D("num_svs=%d,emask=%x,amask=%x,inusemask=%x\n",r->sv_status.num_svs,r->sv_status.ephemeris_mask,r->sv_status.almanac_mask,r->sv_status.used_in_fix_mask);                          D("************88\n");                                while(nums)                          {                              nums--;                              D("prn=%d:snr=%f\n",r->sv_status.sv_list[nums].prn,r->sv_status.sv_list[nums].snr);                          }D("************88\n");  #endif                           r->callback.sv_status_cb( &(r->sv_status) );                          r->sv_status_changed = 0;                      }else {                          D("no callback, keeping status data until needed !");                      }                  }  #endif               }              D("%s: GSV message with total satellites %d", __FUNCTION__, noSatellites);           }               }  #endif////////////////////////////////////////////////////////////////////////////////////////////    else if ( !memcmp(tok.p, "GLL", 3) ) {          Token tok_fixstaus = nmea_tokenizer_get(tzer,6);          if (tok_fixstaus.p[0] == 'A') {              Token tok_latitude = nmea_tokenizer_get(tzer,1);              Token tok_latitudeHemi = nmea_tokenizer_get(tzer,2);              Token tok_longitude = nmea_tokenizer_get(tzer,3);              Token tok_longitudeHemi = nmea_tokenizer_get(tzer,4);              Token tok_time = nmea_tokenizer_get(tzer,5);              nmea_reader_update_time(r, tok_time);              nmea_reader_update_latlong(r, tok_latitude, tok_latitudeHemi.p[0], tok_longitude, tok_longitudeHemi.p[0]);          }      }      /////////////////////////////////////////////////////////////////////////////////    else if ( !memcmp(tok.p, "RMC", 3) ) {        /* Token  tok_time          = nmea_tokenizer_get(tzer,1);           Token  tok_fixStatus     = nmea_tokenizer_get(tzer,2);           Token  tok_latitude      = nmea_tokenizer_get(tzer,3);           Token  tok_latitudeHemi  = nmea_tokenizer_get(tzer,4);           Token  tok_longitude     = nmea_tokenizer_get(tzer,5);           Token  tok_longitudeHemi = nmea_tokenizer_get(tzer,6);           Token  tok_speed         = nmea_tokenizer_get(tzer,7);           Token  tok_bearing       = nmea_tokenizer_get(tzer,8);           Token  tok_date          = nmea_tokenizer_get(tzer,9);           D("in RMC, fixStatus=%c", tok_fixStatus.p[0]);           if (tok_fixStatus.p[0] == 'A')           {           nmea_reader_update_date( r, tok_date, tok_time );           nmea_reader_update_latlong( r, tok_latitude,           tok_latitudeHemi.p[0],           tok_longitude,           tok_longitudeHemi.p[0] );           nmea_reader_update_bearing( r, tok_bearing );           nmea_reader_update_speed  ( r, tok_speed );           }*/        Token tok_time = nmea_tokenizer_get(tzer,1);          Token tok_fixStatus = nmea_tokenizer_get(tzer,2);          Token tok_latitude = nmea_tokenizer_get(tzer,3);          Token tok_latitudeHemi = nmea_tokenizer_get(tzer,4);          Token tok_longitude = nmea_tokenizer_get(tzer,5);          Token tok_longitudeHemi = nmea_tokenizer_get(tzer,6);          Token tok_speed = nmea_tokenizer_get(tzer,7);          Token tok_bearing = nmea_tokenizer_get(tzer,8);          Token tok_date = nmea_tokenizer_get(tzer,9);          D("in RMC, fixStatus=%c", tok_fixStatus.p[0]);          if (tok_fixStatus.p[0] == 'A')          {              nmea_reader_update_date( r, tok_date, tok_time );              nmea_reader_update_latlong( r, tok_latitude,                      tok_latitudeHemi.p[0],                      tok_longitude,                      tok_longitudeHemi.p[0] );              nmea_reader_update_bearing( r, tok_bearing );              nmea_reader_update_speed ( r, tok_speed );  #ifdef Ublox_6M               r->callback.location_cb=_gps_state->callbacks.location_cb;              r->callback.nmea_cb=_gps_state->callbacks.nmea_cb;              r->callback.status_cb=_gps_state->callbacks.status_cb;              if (r->callback.status_cb) {                  D("report,status,flags=%d\n",r->fix.flags);                  r->callback.status_cb( (struct GpsStatus *)&(r->fix.flags) );              }              if (r->callback.location_cb) {                  D("location_cb report:r->fix.flags=%d,r->latitude=%f,r->longitude=%f,r->altitude=%f,r->speed=%f,r->bearing=%f,r->accuracy=%f\n",r->fix.flags,r->fix.latitude,r->fix.longitude,r->fix.altitude,r->fix.speed,r->fix.bearing,r->fix.accuracy);                  r->callback.location_cb( &r->fix );                  r->fix.flags = 0;              }              if (r->callback.nmea_cb) {                  D("report,timestamp=%llx,%llu\n",r->fix.timestamp,r->fix.timestamp);                  r->callback.nmea_cb( r->fix.timestamp,r->in,r->pos );              }  #else               r->callback=_gps_state.callbacks->location_cb;              //r->callback.nmea_cb=_gps_state->callbacks.nmea_cb;               if (r->callback) {D("if2 (r->callback.location_cb)\n");                  r->callback( &r->fix );                  r->fix.flags = 0;              }  #endif           }      }      else     {        tok.p -= 2;        D("unknown sentence '%.*s", tok.end-tok.p, tok.p);    }    if (r->fix.flags != 0) {#if GPS_DEBUG        char   temp[256];        char*  p   = temp;        char*  end = p + sizeof(temp);        struct tm   utc;        p += snprintf( p, end-p, "sending fix" );        if (r->fix.flags & GPS_LOCATION_HAS_LAT_LONG) {            p += snprintf(p, end-p, " lat=%g lon=%g", r->fix.latitude, r->fix.longitude);        }        if (r->fix.flags & GPS_LOCATION_HAS_ALTITUDE) {            p += snprintf(p, end-p, " altitude=%g", r->fix.altitude);        }        if (r->fix.flags & GPS_LOCATION_HAS_SPEED) {            p += snprintf(p, end-p, " speed=%g", r->fix.speed);        }        if (r->fix.flags & GPS_LOCATION_HAS_BEARING) {            p += snprintf(p, end-p, " bearing=%g", r->fix.bearing);        }        if (r->fix.flags & GPS_LOCATION_HAS_ACCURACY) {            p += snprintf(p,end-p, " accuracy=%g", r->fix.accuracy);        }        gmtime_r( (time_t*) &r->fix.timestamp, &utc );        p += snprintf(p, end-p, " time=%s", asctime( &utc ) );        LOGD("%s",temp);#endif        /*    if (r->callback ) {              r->callback( &r->fix );              r->fix.flags = 0;              }*/        //else {        //  D("no callback, keeping data until needed !");        // }    }}    static voidnmea_reader_addc( NmeaReader*  r, int  c ){    if (r->overflow) {        r->overflow = (c != '\n');        return;    }    if (r->pos >= (int) sizeof(r->in)-1 ) {        r->overflow = 1;        r->pos      = 0;        return;    }    r->in[r->pos] = (char)c;    r->pos       += 1;    if (c == '\n') {        nmea_reader_parse( r );        r->pos = 0;    }}/*****************************************************************//*****************************************************************//*****                                                       *****//*****       C O N N E C T I O N   S T A T E                 *****//*****                                                       *****//*****************************************************************//*****************************************************************//* commands sent to the gps thread */enum {    CMD_QUIT  = 0,    CMD_START = 1,    CMD_STOP  = 2};    static voidgps_state_done( GpsState*  s ){    // tell the thread to quit, and wait for it    char   cmd = CMD_QUIT;    void*  dummy;    write( s->control[0], &cmd, 1 );    pthread_join(s->thread, &dummy);    // close the control socket pair    close( s->control[0] ); s->control[0] = -1;    close( s->control[1] ); s->control[1] = -1;    // close connection to the QEMU GPS daemon    close( s->fd ); s->fd = -1;    s->init = 0;}    static voidgps_state_start( GpsState*  s ){    char  cmd = CMD_START;    int   ret;    do { ret=write( s->control[0], &cmd, 1 ); }    while (ret < 0 && errno == EINTR);    if (ret != 1)        D("%s: could not send CMD_START command: ret=%d: %s",                __FUNCTION__, ret, strerror(errno));}    static voidgps_state_stop( GpsState*  s ){    char  cmd = CMD_STOP;    int   ret;    do { ret=write( s->control[0], &cmd, 1 ); }    while (ret < 0 && errno == EINTR);    if (ret != 1)        D("%s: could not send CMD_STOP command: ret=%d: %s",                __FUNCTION__, ret, strerror(errno));}    static intepoll_register( int  epoll_fd, int  fd ){    struct epoll_event  ev;    int                 ret, flags;    /* important: make the fd non-blocking */    flags = fcntl(fd, F_GETFL);    fcntl(fd, F_SETFL, flags | O_NONBLOCK);    ev.events  = EPOLLIN;    ev.data.fd = fd;    do {        ret = epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &ev );    } while (ret < 0 && errno == EINTR);    return ret;}    static intepoll_deregister( int  epoll_fd, int  fd ){    int  ret;    do {        ret = epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL );    } while (ret < 0 && errno == EINTR);    return ret;}/* this is the main thread, it waits for commands from gps_state_start/stop and, * when started, messages from the QEMU GPS daemon. these are simple NMEA sentences * that must be parsed to be converted into GPS fixes sent to the framework */    static voidgps_state_thread( void*  arg ){    GpsState*   state = (GpsState*) arg;    NmeaReader  reader[1];    int         epoll_fd   = epoll_create(2);    int         started    = 0;    int         gps_fd     = state->fd;    int         control_fd = state->control[1];    nmea_reader_init( reader );    // register control file descriptors for polling    epoll_register( epoll_fd, control_fd );    epoll_register( epoll_fd, gps_fd );    D("gps thread running");    // now loop    for (;;) {        struct epoll_event   events[2];        int                  ne, nevents;        nevents = epoll_wait( epoll_fd, events, 2, -1 );        if (nevents < 0) {            if (errno != EINTR)                LOGE("epoll_wait() unexpected error: %s", strerror(errno));            continue;        }        D("gps thread received %d events", nevents);        for (ne = 0; ne < nevents; ne++) {            if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) {                LOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?");                goto Exit;            }            if ((events[ne].events & EPOLLIN) != 0) {                int  fd = events[ne].data.fd;                if (fd == control_fd)                {                    char  cmd = 255;                    int   ret;                    D("gps control fd event");                    do {                        ret = read( fd, &cmd, 1 );                    } while (ret < 0 && errno == EINTR);                    if (cmd == CMD_QUIT) {                        D("gps thread quitting on demand");                        goto Exit;                    }                    else if (cmd == CMD_START) {                        if (!started) {                            D("gps thread starting  location_cb=%p", state->callbacks.location_cb);                            started = 1;                            //******************************************************************                            g_status.status=GPS_STATUS_SESSION_BEGIN;//??ʼ????                            state->callbacks.status_cb(&g_status);                             //******************************************************************                            nmea_reader_set_callback( reader, state->callbacks.location_cb );                            LOGE("%d",gps_fd);                        }                    }                    else if (cmd == CMD_STOP) {                        if (started) {                            D("gps thread stopping");                            started = 0;                            //********************************************************************                            g_status.status=GPS_STATUS_SESSION_END; //ֹͣ                            state->callbacks.status_cb(&g_status);                             //********************************************************************                            nmea_reader_set_callback( reader, NULL );                        }                    }                }                else if (fd == gps_fd)                {                    char  buff[32];                    D("gps fd event");                    for (;;) {                        int  nn, ret;                        ret = read( fd, buff, sizeof(buff) );                        if (ret < 0) {                            if (errno == EINTR)                                continue;                            if (errno != EWOULDBLOCK)                                LOGE("error while reading from gps daemon socket: %s:", strerror(errno));                            break;                        }                        D("received %d bytes: %.*s", ret, ret, buff);                        for (nn = 0; nn < ret; nn++)                            nmea_reader_addc( reader, buff[nn] );                    }                    D("gps fd event end");                }                else                {                    LOGE("epoll_wait() returned unkown fd %d ?", fd);                }            }        }    }Exit:    return ;}    static voidgps_state_init( GpsState*  state ){    state->init       = 1;    state->control[0] = -1;    state->control[1] = -1;    state->fd         = -1;    int ret = -1;    struct termios gps_termios;    //*****************************************************************************    state->fd= open("/dev/ttyS3",O_RDWR|O_NOCTTY|O_NDELAY);//?????õ???UART1    if( state->fd < 0){        LOGE("open port /dev/ttyS3 ERROR..state->fd=%s\n",strerror(state->fd));         exit(0);    }else        LOGE("open port:/dev/ttyS3 succceed..state->fd=%d\n",state->fd);    if(fcntl( state->fd,F_SETFL,0)<0)        LOGE("fcntl F_SETFL\n");    {        LOGI(">>>> Port setup..\n");        int err;        tcflush(state->fd, TCIOFLUSH);        if ((err = tcgetattr(state->fd,&gps_termios)) != 0)        {            LOGI("tcgetattr(%d) = %d,errno %d\r\n",state->fd,err,errno);            close(state->fd);        }        gps_termios.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);        gps_termios.c_oflag &= ~OPOST;        gps_termios.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);        gps_termios.c_cflag &= ~(CSIZE|PARENB);        gps_termios.c_cflag |= CS8;        gps_termios.c_cflag &= ~CRTSCTS;//no flow control        tcsetattr(state->fd, TCSANOW, &gps_termios);        tcflush(state->fd, TCIOFLUSH);        tcsetattr(state->fd, TCSANOW, &gps_termios);        tcflush(state->fd, TCIOFLUSH);        tcflush(state->fd, TCIOFLUSH);        if (cfsetispeed(&gps_termios,B115200))        {            LOGE("cfsetispeed.. errno..\r\n");            close(state->fd);            //return(-1);        }        // Set the output baud rates in the termios.        if (cfsetospeed(&gps_termios,B115200))        {            LOGE("cfsetispeed.. errno..\r\n");            close(state->fd);            //return(-1);        }        tcsetattr(state->fd,TCSANOW,&gps_termios);        LOGE("Port setup finished..\n");    }    if (state->fd < 0) {        LOGD("no gps emulation detected");        return;    }    //**********************************************************************    if ( socketpair( AF_LOCAL, SOCK_STREAM, 0, state->control ) < 0 ) {        LOGE("could not create thread control socket pair: %s", strerror(errno));        goto Fail;    }    /* if ( pthread_create( &state->thread, NULL, gps_state_thread, state ) != 0 ) {       LOGE("could not create gps thread: %s", strerror(errno));       goto Fail;       }*/    //***********************************************************************    LOGE("gps state initialized before");    state->thread=state->callbacks.create_thread_cb("gps_state_thread",gps_state_thread,state);    //**************************************************************************    //    D("gps state initialized");    LOGE("gps state initialized");    return;Fail:    gps_state_done( state );}/*****************************************************************//*****************************************************************//*****                                                       *****//*****       I N T E R F A C E                               *****//*****                                                       *****//*****************************************************************//*****************************************************************/    static intqemu_gps_init(GpsCallbacks* callbacks){    system("echo 1 > /sys/devices/platform/gps_power/bcm_gps_power_state");    GpsState*  s = _gps_state;    D("%s", __FUNCTION__);    /**************************************************/    s->callbacks = *callbacks; //ע???ص?????,JNI????\C0\B4?Ļص?????    g_status.status=GPS_STATUS_ENGINE_ON;//????״̬ ͨ?絫??û??ʼ????    s->callbacks.status_cb(&g_status);    /******************************************************/    if (!s->init)        gps_state_init(s);    if (s->fd < 0)        return -1;    // s->callbacks = *callbacks;    return 0;}    static voidqemu_gps_cleanup(void){    GpsState*  s = _gps_state;    D("%s", __FUNCTION__);    if (s->init)        gps_state_done(s);    system("echo 0 > /sys/devices/platform/gps_power/bcm_gps_power_state");}    static intqemu_gps_start(){    GpsState*  s = _gps_state;    D("%s", __FUNCTION__);    if (!s->init) {        D("%s: called with uninitialized state !!", __FUNCTION__);        return -1;    }    gps_state_start(s);    return 0;}    static intqemu_gps_stop(){    GpsState*  s = _gps_state;    D("%s", __FUNCTION__);    if (!s->init) {        D("%s: called with uninitialized state !!", __FUNCTION__);        return -1;    }    D("%s: called", __FUNCTION__);    gps_state_stop(s);    return 0;}    static intqemu_gps_inject_time(GpsUtcTime time, int64_t timeReference, int uncertainty){    return 0;}    static intqemu_gps_inject_location(double latitude, double longitude, float accuracy){    return 0;}    static voidqemu_gps_delete_aiding_data(GpsAidingData flags){}static int qemu_gps_set_position_mode(GpsPositionMode mode, GpsPositionRecurrence recurrence,uint32_t min_interval, uint32_t preferred_accuracy, uint32_t preferred_time)//(GpsPositionMode mode, int fix_frequency){    // FIXME - support fix_frequency    return 0;}    static const void*qemu_gps_get_extension(const char* name){    // no extensions supported    return NULL;}static const GpsInterface  qemuGpsInterface = {    sizeof(GpsInterface),    qemu_gps_init,    qemu_gps_start,    qemu_gps_stop,    qemu_gps_cleanup,    qemu_gps_inject_time,    qemu_gps_inject_location,    qemu_gps_delete_aiding_data,    qemu_gps_set_position_mode,    qemu_gps_get_extension,};const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev){    return &qemuGpsInterface;}static int open_gps(const struct hw_module_t* module, char const* name,        struct hw_device_t** device){    struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));    memset(dev, 0, sizeof(*dev));    dev->common.tag = HARDWARE_DEVICE_TAG;    dev->common.version = 0;    dev->common.module = (struct hw_module_t*)module;    //    dev->common.close = (int (*)(struct hw_device_t*))close_lights;    dev->get_gps_interface = gps__get_gps_interface;    *device = (struct hw_device_t*)dev;    return 0;}static struct hw_module_methods_t gps_module_methods = {    .open = open_gps};const struct hw_module_t HAL_MODULE_INFO_SYM = {    .tag = HARDWARE_MODULE_TAG,    .version_major = 1,    .version_minor = 0,    .id = GPS_HARDWARE_MODULE_ID,    .name = "Goldfish GPS Module",    .author = "The Android Open Source Project",    .methods = &gps_module_methods,};

下面简单分析GPS源代码的上报过程,流程图如下所示:


应用:

    lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);    lm.addGpsStatusListener(statuslistener);private GpsStatus.Listener statuslistener = new GpsStatus.Listener(){    //实现public interface Listener 接口    public void onGpsStatusChanged(int event){    }};


调用LocationManager.java:
    1331             GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);    1332             result = mService.addGpsStatusListener(transport);    1333             if (result) {    1334                 mGpsStatusListeners.put(listener, transport);    1335             }


1331行:
    1228         GpsStatusListenerTransport(GpsStatus.Listener listener) {                                                     1229             mListener = listener;    1230             mNmeaListener = null;    1231         }


GpsStatusListenerTransport类提供了几个方法如onGpsStarted,onGpsStopped,onFirstFix,onSvStatusChanged,onNmeaReceived等,而在这些方法中,会调用
mGpsHandler.sendMessage(msg),将消息发送给mListener,这样前面应用中实现的接口onGpsStatusChanged就会接收到消息了;
现在回到谁会调用这些方法来发送消息的问题上?当然是LocationManagerService.java,所以要将GpsStatusListenerTransport注册到服务中,这是在1332行中实现的,所以看
LocationManagerService.java的addGpsStatusListener方法:
    1303         try {    1304             mGpsStatusProvider.addGpsStatusListener(listener);    1305         } catch (RemoteException e) {    1306             Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);    1307             return false;    1308         }


mGpsStatusProvider是什么?
    mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
gpsProvider又是什么?
    GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
看来要进入GpsLocationProvider类了,这个类是和GPS的JNI层打交道的地方,看他的getGpsStatusProvider方法:
     343     public IGpsStatusProvider getGpsStatusProvider() {     344         return mGpsStatusProvider;                                                                                      345     }


mGpsStatusProvider是:
     296     private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {     297         public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {     298             if (listener == null) {     299                 throw new NullPointerException("listener is null in addGpsStatusListener");     300             }     301      302             synchronized(mListeners) {     303                 IBinder binder = listener.asBinder();     304                 int size = mListeners.size();     305                 for (int i = 0; i < size; i++) {     306                     Listener test = mListeners.get(i);     307                     if (binder.equals(test.mListener.asBinder())) {     308                         // listener already added     309                         return;     310                     }     311                 }     312      313                 Listener l = new Listener(listener);     314                 binder.linkToDeath(l, 0);     315                 mListeners.add(l);     316             }     317         }


看来是实现了IGpsStatusProvider接口的一个服务类啊,所以1304行就是调用这里297行的addGpsStatusListener方法把客户端LocationManager中的listener添加到这里来啊。
307行先判断listener是否已经添加,接着313行,new Listener,315行的mListeners是ArrayList类型,就是把313创建的Listener加到动态数组中。
想想看,在GpsStatusProvider类中肯顶在某个地方会遍历mListeners中的成员,以便回调里面的方法,将数据发送出去;也就是说存在某个机制,已经运行起来了?这是什么机制?
其实没有什么机制,只不过GpsStatusProvider类实现了reportStatus和reportSvStatus方法,这些方法会提供给JNI层,也就是JNI主动调用java层的方法?那什么时候调用呢,进入
JNI层看看就知道了:
    method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");//看名字就知道是对应java的reportSvStatus方法了

     90 static void sv_status_callback(GpsSvStatus* sv_status)     91 {     92     JNIEnv* env = AndroidRuntime::getJNIEnv();     93     memcpy(&sGpsSvStatus, sv_status, sizeof(sGpsSvStatus));     94     env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);//这里CallVoidMethod就是调用method_reportSvStatus方法,即java层的reportSvStatus     95     checkAndClearExceptionFromCallback(env, __FUNCTION__);     96 }


sv_status_callback则在函数指针数组中被赋值:
    139 GpsCallbacks sGpsCallbacks = {    140     sizeof(GpsCallbacks),    141     location_callback,    142     status_callback,    143     sv_status_callback,                                                                                                144     nmea_callback,    145     set_capabilities_callback,    146     acquire_wakelock_callback,    147     release_wakelock_callback,    148     create_thread_callback,    149     request_utc_time_callback,    150 };


GpsCallbacks类在libhardware/include/hardware/gps.h定义:
    368 typedef struct {    369     /** set to sizeof(GpsCallbacks) */                                                                                          370     size_t      size;    371     gps_location_callback location_cb;    372     gps_status_callback status_cb;    373     gps_sv_status_callback sv_status_cb;    374     gps_nmea_callback nmea_cb;    375     gps_set_capabilities set_capabilities_cb;    376     gps_acquire_wakelock acquire_wakelock_cb;    377     gps_release_wakelock release_wakelock_cb;    378     gps_create_thread create_thread_cb;    379     gps_request_utc_time request_utc_time_cb;    380 } GpsCallbacks;


这里是HAL层主动调用JNI层的方法,看看是怎么回事,在JNI的android_location_GpsLocationProvider_is_supported中:
    if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)  
就是这一句,把sGpsCallbacks的地址传递了给HAL层,这里的sGpsInterface当然是在经过
    hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
    module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
    sGpsInterface = gps_device->get_gps_interface(gps_device);
之后得到的。
所以进入HAL层看看吧:
    1300 static const GpsInterface  qemuGpsInterface = {    1301     sizeof(GpsInterface),    1302     qemu_gps_init,    1303     qemu_gps_start,    1304     qemu_gps_stop,    1305     qemu_gps_cleanup,    1306     qemu_gps_inject_time,    1307     qemu_gps_inject_location,    1308     qemu_gps_delete_aiding_data,    1309     qemu_gps_set_position_mode,    1310     qemu_gps_get_extension,    1311 };    1312     1313 const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)    1314 {    1315     return &qemuGpsInterface;//返回给JNI层的地址    1316 }


GpsInterface类的定义:
    384 typedef struct {    386     size_t          size;    391     int   (*init)( GpsCallbacks* callbacks );    394     int   (*start)( void );    397     int   (*stop)( void );    400     void  (*cleanup)( void );    403     int   (*inject_time)(GpsUtcTime time, int64_t timeReference,    404                          int uncertainty);    411     int  (*inject_location)(double latitude, double longitude, float accuracy);    418     void  (*delete_aiding_data)(GpsAidingData flags);    425     int   (*set_position_mode)(GpsPositionMode mode, GpsPositionRecurrence recurrence,    426             uint32_t min_interval, uint32_t preferred_accuracy, uint32_t preferred_time);    429     const void* (*get_extension)(const char* name);    430 } GpsInterface;


看到了没,看来不用多说,JNI调用了qemu_gps_init方法:
    1198 qemu_gps_init(GpsCallbacks* callbacks)                                                                                       1199 {    1201     GpsState*  s = _gps_state;    1206     s->callbacks = *callbacks;    1208     g_status.status=GPS_STATUS_ENGINE_ON;    1210     s->callbacks.status_cb(&g_status);    1214     if (!s->init)    1215         gps_state_init(s);    1217     if (s->fd < 0)    1218         return -1;    1222     return 0;    1223 }


这样1206行就得到了JNI层的sv_status_callback结构体地址,然后就可以调用它了,什么时候调用啊?在线程中检测到串口有GPS数据上报了就会调用,在线程中解析GPS的GSV数据
后会调用r->callback.sv_status_cb( &(r->sv_status) ):
     90 static void sv_status_callback(GpsSvStatus* sv_status)     91 {     92     JNIEnv* env = AndroidRuntime::getJNIEnv();     93     memcpy(&sGpsSvStatus, sv_status, sizeof(sGpsSvStatus));                                                                                   94     env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);     95     checkAndClearExceptionFromCallback(env, __FUNCTION__);     96 }


93行把数据保存到JNI层,94行调用JAVA层的reportSvStatus方法:
    1209     private void reportSvStatus() {    1210     1211         int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks);    1212     1213         synchronized(mListeners) {    1214             int size = mListeners.size();    1215             for (int i = 0; i < size; i++) {    1216                 Listener listener = mListeners.get(i);    1217                 try {    1218                     listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs,    1219                             mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK],                              1220                             mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]);    1221                 } catch (RemoteException e) {    1222                     Log.w(TAG, "RemoteException in reportSvInfo");    1223                     mListeners.remove(listener);    1224                     // adjust for size of list changing    1225                     size--;    1226                 }    1227             }    1228         }


1211行它又调用JNI的native_read_sv_status,它不做别的事情,就是读取前面保存在HAL层的数据,因为前面HAL层只是把数据拷贝到JNI层的变量中:
    346 static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj,    347         jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray,    348         jintArray maskArray)    349 {    350     // this should only be called from within a call to reportSvStatus    351     352     jint* prns = env->GetIntArrayElements(prnArray, 0);    353     jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);    354     jfloat* elev = env->GetFloatArrayElements(elevArray, 0);    355     jfloat* azim = env->GetFloatArrayElements(azumArray, 0);    356     jint* mask = env->GetIntArrayElements(maskArray, 0);    357     358     int num_svs = sGpsSvStatus.num_svs;    359     for (int i = 0; i < num_svs; i++) {    360         prns[i] = sGpsSvStatus.sv_list[i].prn;    361         snrs[i] = sGpsSvStatus.sv_list[i].snr;    362         elev[i] = sGpsSvStatus.sv_list[i].elevation;    363         azim[i] = sGpsSvStatus.sv_list[i].azimuth;    364     }    365     mask[0] = sGpsSvStatus.ephemeris_mask;    366     mask[1] = sGpsSvStatus.almanac_mask;    367     mask[2] = sGpsSvStatus.used_in_fix_mask;                                                                              368     369     env->ReleaseIntArrayElements(prnArray, prns, 0);    370     env->ReleaseFloatArrayElements(snrArray, snrs, 0);    371     env->ReleaseFloatArrayElements(elevArray, elev, 0);    372     env->ReleaseFloatArrayElements(azumArray, azim, 0);    373     env->ReleaseIntArrayElements(maskArray, mask, 0);    374     return num_svs;    375 }


最终我们的应用也就在onGpsStatusChanged方法中得到了要处理的数据啦



2013.08.22续:

由于要做一个测试软件来测试GPS性能,但是多加了一个北斗的数据,android标准只支持1~32号星,大于32将无法校验该卫星是否用来定位。所以只能增加一个int型来保存北斗的校验值,具体修改的地方如下:

1. hardware/libhardware中:

diff --git a/include/hardware/gps.h b/include/hardware/gps.hindex 69bfd50..895ee4f 100755--- a/include/hardware/gps.h+++ b/include/hardware/gps.h@@ -298,6 +298,11 @@ typedef struct {      * were used for computing the most recent position fix.      */     uint32_t    used_in_fix_mask;++    /*+       add for beidou gps+    */+    uint32_t    bd_used_in_fix_mask; } GpsSvStatus;

2.beidou_gps.c中:

diff --git a/hardware/libhardware/gps/beidou_gps.c b/hardware/libhardware/gps/beidou_gps.cindex 131a16e..d6001f9 100644--- a/hardware/libhardware/gps/beidou_gps.c+++ b/hardware/libhardware/gps/beidou_gps.c-                if(!is_beidou)+                if(!is_beidou){                     r->sv_status.used_in_fix_mask = 0ul;  +                    r->sv_status.bd_used_in_fix_mask = 0ul;  +                }                 D("\n");                   for (i = 3; i <= 14; ++i){   @@ -571,9 +573,13 @@ nmea_reader_parse( NmeaReader*  r )                     int prn = str2int(tok_prn.p, tok_prn.end);                       D("gsa,prn=%d,",prn);                       if (prn > 0){  -                        r->sv_status.used_in_fix_mask |= (1ul << ( prn-1));  -                        r->sv_status_changed = 1;  +                        if(is_beidou){+                            D("sclu %d, prn=%d", __LINE__, prn);+                            r->sv_status.bd_used_in_fix_mask |= (1ul << ( prn-1));  +                        }else+                            r->sv_status.used_in_fix_mask |= (1ul << ( prn-1));   +                        r->sv_status_changed = 1;                       }  

3.frameworks/base中:

diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.javaindex 4af55a6..73e3bcc 100644--- a/location/java/android/location/GpsStatus.java+++ b/location/java/android/location/GpsStatus.java@@ -18,6 +18,7 @@ package android.location;  import java.util.Iterator; import java.util.NoSuchElementException;+import android.util.Log;   /**@@ -140,26 +141,35 @@ public final class GpsStatus {      */     synchronized void setStatus(int svCount, int[] prns, float[] snrs,             float[] elevations, float[] azimuths, int ephemerisMask,-            int almanacMask, int usedInFixMask) {+            int almanacMask, int usedInFixMask, int bdusedInFixMask) {         int i;          for (i = 0; i < mSatellites.length; i++) {             mSatellites[i].mValid = false;         }-        +       Log.e("sclu", "ephemeris = " + Integer.toBinaryString(ephemerisMask) + ", almanac = " + Integer.toBinaryString(almanacMask) + ", usedinfix = " + Intege         for (i = 0; i < svCount; i++) {+                 int prn = prns[i] - 1;-            int prnShift = (1 << prn);+            int prnShift;+            if(prns[i] <= 32)+                prnShift = (1 << (prn));+            else+                prnShift = (1 << (prn - 100));             if (prn >= 0 && prn < mSatellites.length) {                 GpsSatellite satellite = mSatellites[prn];-    +                Log.e("sclu", "prns[" + i + "] = " + prns[i]);                  satellite.mValid = true;                 satellite.mSnr = snrs[i];                 satellite.mElevation = elevations[i];                 satellite.mAzimuth = azimuths[i];                 satellite.mHasEphemeris = ((ephemerisMask & prnShift) != 0);                 satellite.mHasAlmanac = ((almanacMask & prnShift) != 0);-                satellite.mUsedInFix = ((usedInFixMask & prnShift) != 0);+                if(prns[i] <= 32){+                    satellite.mUsedInFix = ((usedInFixMask & prnShift) != 0);+                }else{+                    satellite.mUsedInFix = ((bdusedInFixMask & prnShift) != 0);+                }             }         }     }diff --git a/location/java/android/location/IGpsStatusListener.aidl b/location/java/android/location/IGpsStatusListener.aidlindex 62b1c6b..6a6bac9 100644--- a/location/java/android/location/IGpsStatusListener.aidl+++ b/location/java/android/location/IGpsStatusListener.aidl@@ -28,6 +28,6 @@ oneway interface IGpsStatusListener     void onFirstFix(int ttff);     void onSvStatusChanged(int svCount, in int[] prns, in float[] snrs,              in float[] elevations, in float[] azimuths, -            int ephemerisMask, int almanacMask, int usedInFixMask);+            int ephemerisMask, int almanacMask, int usedInFixMask, int bdusedInFixMask);     void onNmeaReceived(long timestamp, String nmea); }diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.javaindex 91d8bc1..5c1cfa9 100644--- a/location/java/android/location/LocationManager.java+++ b/location/java/android/location/LocationManager.java@@ -1263,10 +1263,10 @@ public class LocationManager {          public void onSvStatusChanged(int svCount, int[] prns, float[] snrs,                 float[] elevations, float[] azimuths, int ephemerisMask,-                int almanacMask, int usedInFixMask) {+                int almanacMask, int usedInFixMask, int bdusedInFixMask) {             if (mListener != null) {                 mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths,-                        ephemerisMask, almanacMask, usedInFixMask);+                        ephemerisMask, almanacMask, usedInFixMask, bdusedInFixMask);                  Message msg = Message.obtain();                 msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.javaindex bad57d5..82159a1 100755--- a/services/java/com/android/server/location/GpsLocationProvider.java+++ b/services/java/com/android/server/location/GpsLocationProvider.java@@ -1217,7 +1217,7 @@ public class GpsLocationProvider implements LocationProviderInterface {                 try {                     listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs,                              mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK], -                            mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]); +                            mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK], mSvMasks[BD_USED_FOR_FIX_MASK]);                  } catch (RemoteException e) {                     Log.w(TAG, "RemoteException in reportSvInfo");                     mListeners.remove(listener);@@ -1649,13 +1649,15 @@ public class GpsLocationProvider implements LocationProviderInterface {     private static final int EPHEMERIS_MASK = 0;     private static final int ALMANAC_MASK = 1;     private static final int USED_FOR_FIX_MASK = 2;+    //add for beidou gps+    private static final int BD_USED_FOR_FIX_MASK = 3;      // preallocated arrays, to avoid memory allocation in reportStatus()     private int mSvs[] = new int[MAX_SVS];     private float mSnrs[] = new float[MAX_SVS];     private float mSvElevations[] = new float[MAX_SVS];     private float mSvAzimuths[] = new float[MAX_SVS];-    private int mSvMasks[] = new int[3];+    private int mSvMasks[] = new int[4];     private int mSvCount;     // preallocated to avoid memory allocation in reportNmea()     private byte[] mNmeaBuffer = new byte[120];diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cppindex c823da5..88abf23 100755--- a/services/jni/com_android_server_location_GpsLocationProvider.cpp+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp@@ -361,6 +361,7 @@ static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, job     mask[0] = sGpsSvStatus.ephemeris_mask;     mask[1] = sGpsSvStatus.almanac_mask;     mask[2] = sGpsSvStatus.used_in_fix_mask;+    mask[3] = sGpsSvStatus.bd_used_in_fix_mask;      env->ReleaseIntArrayElements(prnArray, prns, 0);     env->ReleaseFloatArrayElements(snrArray, snrs, 0);