北斗gps Android hal层so库代码

网上下载的代码,自己编辑修改,加入了北斗定位功能,主要是修改了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>.so
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_CFLAGS += -DQEMU_HARDWARE
LOCAL_SHARED_LIBRARIES := liblog libcutils libhardware
LOCAL_SRC_FILES := gps.c
LOCAL_MODULE := gps.default
LOCAL_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  20

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] == '\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 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;
    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 void
nmea_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 void
gps_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 void
gps_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 void
gps_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 int
epoll_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 int
epoll_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 void
gps_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 void
gps_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 int
qemu_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 void
qemu_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 int
qemu_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 int
qemu_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 int
qemu_gps_inject_time(GpsUtcTime time, int64_t timeReference, int uncertainty)
{
    return 0;
}

    static int
qemu_gps_inject_location(double latitude, double longitude, float accuracy)
{
    return 0;
}

    static void
qemu_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源代码的上报过程,流程图如下所示:

北斗gps Android hal层so库代码_第1张图片

应用:

    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.h
index 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.c
index 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.java
index 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.aidl
index 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.java
index 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.java
index 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.cpp
index 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);


















你可能感兴趣的:(北斗gps Android hal层so库代码)