网上下载的代码,自己编辑修改,加入了北斗定位功能,主要是修改了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/..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
#include
#include
#include
#include
#include
#include /*????????*/
#include /*???????*/
#include /*Unix ??????*/
#include
#include
#include /*PPSIX ??????*/
#include /*?????*/
#define LOG_TAG "gps_qemu"
#include
#include
#include
#include
#include
/* 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,
};
应用:
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
lm.addGpsStatusListener(statuslistener);
private GpsStatus.Listener statuslistener = new GpsStatus.Listener(){
//实现public interface Listener 接口
public void onGpsStatusChanged(int event){
}
};
1331 GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
1332 result = mService.addGpsStatusListener(transport);
1333 if (result) {
1334 mGpsStatusListeners.put(listener, transport);
1335 }
1228 GpsStatusListenerTransport(GpsStatus.Listener listener) {
1229 mListener = listener;
1230 mNmeaListener = null;
1231 }
1303 try {
1304 mGpsStatusProvider.addGpsStatusListener(listener);
1305 } catch (RemoteException e) {
1306 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
1307 return false;
1308 }
343 public IGpsStatusProvider getGpsStatusProvider() {
344 return mGpsStatusProvider;
345 }
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 }
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 }
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 };
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;
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 }
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;
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 }
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 }
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 }
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;
}
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);