前提:GPS驱动已通,android4.0
其实不加这个也能定位,因为定位信息是模块结合gps和北斗的定位算好一起发上来的,加这个只是能让app能看到北斗的卫星信息(例如gps测试仪)
修改的部分为GSA 和 GSV
GSV -> 可见卫星
GSA -> 已连接卫星
方法是自己拍脑袋想的,测试好用,其他不保证
GSV存下GPGSV和BDGSV的信息后一起上传
else if ( !memcmp(tok.p, "GSV", 3) ) {
Token tok_noSatellites = nmea_tokenizer_get(tzer, 3);
int noSatellites = str2int(tok_noSatellites.p, tok_noSatellites.end);
//D("noSatellites=%d\n",noSatellites);
// if (noSatellites > 0) {
if( !memcmp(gp, "GP", 2) ) {
// D("GPGSV record");
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);
int totalSentences = str2int(tok_noSentences.p, tok_noSentences.end);
int curr;
int i;
//D("sentence=%d,totalSentences=%d\n",sentence,totalSentences);
if (sentence == 1) {
r->sv_status_changed = 0;
save_gps_num_svs = 0;
r->sv_status.num_svs = 0;
}
curr = save_gps_num_svs;
i = 0;
while (i < 4 && save_gps_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);
save_gps_sv[curr].prn = str2int(tok_prn.p, tok_prn.end);
save_gps_sv[curr].elevation = str2float(tok_elevation.p, tok_elevation.end);
save_gps_sv[curr].azimuth = str2float(tok_azimuth.p, tok_azimuth.end);
save_gps_sv[curr].snr = str2float(tok_snr.p, tok_snr.end);
//D("GPS: num=%d,prn=%d:snr=%f ",r->sv_status.num_svs,\
save_gps_sv[curr].prn,save_gps_sv[curr].snr);
save_gps_num_svs += 1;
r->sv_status.num_svs += 1;
curr += 1;
i += 1;
}
}
} else {
// D("BDGSV record");
// 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);
int totalSentences = str2int(tok_noSentences.p, tok_noSentences.end);
int curr;
int i;
//D("sentence=%d,totalSentences=%d\n",sentence,totalSentences);
if (sentence == 1) {
r->sv_status_changed = 0;
save_bd_num_svs = 0;
}
curr = save_bd_num_svs;
i = 0;
while (i < 4 && save_bd_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);
save_bd_sv[curr].prn = str2int(tok_prn.p, tok_prn.end);
save_bd_sv[curr].elevation = str2float(tok_elevation.p, tok_elevation.end);
save_bd_sv[curr].azimuth = str2float(tok_azimuth.p, tok_azimuth.end);
save_bd_sv[curr].snr = str2float(tok_snr.p, tok_snr.end);
D("BD: num=%d,prn=%d:snr=%f ",r->sv_status.num_svs,\
save_bd_sv[curr].prn,save_bd_sv[curr].snr);
//D("%d, %f, %f, %f curr = %d, %d",save_bd_sv[curr].prn,\
save_bd_sv[curr].elevation,\
save_bd_sv[curr].azimuth,\
save_bd_sv[curr].snr,\
curr,\
save_bd_num_svs);
save_bd_num_svs += 1;
r->sv_status.num_svs +=1;
curr += 1;
i += 1;
}
if (sentence == totalSentences) {
int nn=0;
int temp_prn;
for(i = 0; i < r->sv_status.num_svs ; i++){
if(i < save_gps_num_svs){
r->sv_status.sv_list[i].prn = save_gps_sv[i].prn;
r->sv_status.sv_list[i].elevation = save_gps_sv[i].elevation;
r->sv_status.sv_list[i].azimuth = save_gps_sv[i].azimuth;
r->sv_status.sv_list[i].snr = save_gps_sv[i].snr;
// D("%d, %f, %f, %f ",save_gps_sv[i].prn,\
save_gps_sv[i].elevation,\
save_gps_sv[i].azimuth,\
save_gps_sv[i].snr);
} else {
nn = i - save_gps_num_svs;
r->sv_status.sv_list[i].prn = save_bd_sv[nn].prn + 200;
r->sv_status.sv_list[i].elevation = save_bd_sv[nn].elevation;
r->sv_status.sv_list[i].azimuth = save_bd_sv[nn].azimuth;
r->sv_status.sv_list[i].snr = save_bd_sv[nn].snr;
// D("%d, %f, %f, %f %d",save_bd_sv[nn].prn,\
save_bd_sv[nn].elevation,\
save_bd_sv[nn].azimuth,\
save_bd_sv[nn].snr,\
(i-save_gps_num_svs));
}
}
r->sv_status_changed = 1;
}
// }
}
GSA取什么传什么
}else if ( !memcmp(tok.p, "GSA", 3) ) {
// do something ?
//D(">>>>>>>> GSA string");
Token tok_fixStatus = nmea_tokenizer_get(tzer, 2);
int i;
if( !memcmp(gp, "GP", 2) ) {
r->sv_status.used_in_fix_mask = 0ul;
if (tok_fixStatus.p[0] != '\0' && tok_fixStatus.p[0] != '1') {
Token tok_accuracy = nmea_tokenizer_get(tzer, 15);
nmea_reader_update_accuracy(r, tok_accuracy);
for (i = 3; i <= 14; ++i){
Token tok_prn = nmea_tokenizer_get(tzer, i);
r->sv_status.used_in_fix_mask |= (1ul << (str2int(tok_prn.p, tok_prn.end)-1));
}
r->sv_status_changed = 1;
}
}
else {
r->sv_status.used_in_fix_bd = 0ul;
if (tok_fixStatus.p[0] != '\0' && tok_fixStatus.p[0] != '1') {
Token tok_accuracy = nmea_tokenizer_get(tzer, 15);
nmea_reader_update_accuracy(r, tok_accuracy);
for (i = 3; i <= 14; ++i){
Token tok_prn = nmea_tokenizer_get(tzer, i);
r->sv_status.used_in_fix_bd |= (1ul <<(str2int(tok_prn.p, tok_prn.end)-1));
}
r->sv_status_changed = 1;
}
LOGD("used_in_fix_mask : %x",r->sv_status.used_in_fix_mask);
LOGD("used_in_fix_mask : %x",r->sv_status.used_in_fix_bd);
}
}
GSV传的时候没什么问题,为了和GPS卫星区分,prn卫星编号加上200的偏移就可以了
但是GSA中已连接卫星是用used_in_fix_mask表示的,它的定义在hardware/libhardware/include/hardware/gps.h中
typedef struct {
/** set to sizeof(GpsSvStatus) */
size_t size;
/** Number of SVs currently visible. */
int num_svs;
/** Contains an array of SV information. */
GpsSvInfo sv_list[GPS_MAX_SVS];
/** Represents a bit mask indicating which SVs
* have ephemeris data.
*/
uint32_t ephemeris_mask;
/** Represents a bit mask indicating which SVs
* have almanac data.
*/
uint32_t almanac_mask;
/**
* Represents a bit mask indicating which SVs
* were used for computing the most recent position fix.
*/
uint32_t used_in_fix_mask;
uint32_t used_in_fix_bd; // for gps+bd
} GpsSvStatus;
32位对应32颗卫星,每一位变成1即表示该卫星已连接
如果想要北斗,需要为北斗加一个 uint32_t used_in_fix_bd;
下一步修改jni frameworks/base/services/jni/com_android_server_location_GpsLocationProvider.cpp
找到used_in_fix_mask并加一行
mask[0] = sGpsSvStatus.ephemeris_mask;
mask[1] = sGpsSvStatus.almanac_mask;
mask[2] = sGpsSvStatus.used_in_fix_mask;
mask[3] = sGpsSvStatus.used_in_fix_bd;
这个android_location_GpsLocationProvider_read_sv_status 在java中由 native_read_sv_status 调用
调用native_read_sv_status在 frameworks/base/services/java/com/android/server/location/GpsLocationProvider.java 的reportSvStatus()中
int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks);
当然上边加了mask[3],mSvMasks的定义也得加
private int mSvMasks[] = new int[4];
reportSvStatus() 还有两个地方需要修改
1. onSvStatusChanged的参数需要加上北斗的mSvMasks[USED_FOR_FIX_BD]
try {
listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs,
mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK],
mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK], mSvMasks[USED_FOR_FIX_BD]);
} catch (RemoteException e) {
Log.w(TAG, "RemoteException in reportSvInfo");
mListeners.remove(listener);
// adjust for size of list changing
size--;
}
// return number of sets used in fix instead of total
updateStatus(mStatus, Integer.bitCount(mSvMasks[USED_FOR_FIX_MASK]) + Integer.bitCount(mSvMasks[USED_FOR_FIX_BD]));
onSvStatusChanged加了参数,需要修改定义
定义在frameworks/base/location/java/android/location/LocationManager.java
public void onSvStatusChanged(int svCount, int[] prns, float[] snrs,
float[] elevations, float[] azimuths, int ephemerisMask,
int almanacMask, int usedInFixMask, int usedInFixBd) {
if (mListener != null) {
mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths,
ephemerisMask, almanacMask, usedInFixMask, usedInFixBd);
Message msg = Message.obtain();
msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
// remove any SV status messages already in the queue
mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
mGpsHandler.sendMessage(msg);
}
}
加上 int usedInFixBd,继续修改setStatus定义
frameworks/base/location/java/android/location/GpsStatus.java
加上针对北斗的判断
synchronized void setStatus(int svCount, int[] prns, float[] snrs,
float[] elevations, float[] azimuths, int ephemerisMask,
int almanacMask, int usedInFixMask, int usedInFixBd) {
int i;
for (i = 0; i < mSatellites.length; i++) {
mSatellites[i].mValid = false;
}
for (i = 0; i < svCount; i++) {
int prn = prns[i] - 1;
int prnShift = (prn >= 200 ? 1 << (prn - 200) : (1 << prn));
if (prn >= 0 && prn < mSatellites.length) {
GpsSatellite satellite = mSatellites[prn];
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);
if(prn >= 200){
satellite.mUsedInFix = ((usedInFixBd & prnShift) != 0);
}else{
satellite.mUsedInFix = ((usedInFixMask & prnShift) != 0);
}
}
}
}
这时编译会提示错误,还需要修改aidl,frameworks/base/location/java/android/location/IGpsStatusListener.aidl
oneway interface IGpsStatusListener
{
void onGpsStarted();
void onGpsStopped();
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 usedInFixBd);
void onNmeaReceived(long timestamp, String nmea);
}
-------------android 5.1 ------------------------------------------------------------------------------------------
frameworks/base/services/core/java/com/android/server/location/GpsStatusListenerHelper.java 下修改
public void onSvStatusChanged(
final int svCount,
final int[] prns,
final float[] snrs,
final float[] elevations,
final float[] azimuths,
final int ephemerisMask,
final int almanacMask,
final int usedInFixMask,
final int usedInFixBd
) {
Operation operation = new Operation() {
@Override
public void execute(IGpsStatusListener listener) throws RemoteException {
listener.onSvStatusChanged(
svCount,
prns,
snrs,
elevations,
azimuths,
ephemerisMask,
almanacMask,
usedInFixMask,
usedInFixBd);
}
};