基於Android2.3的車載導航---andorid GPS HAL的移植與分析(by liukun321咕唧咕唧)
主控: Samsung ARM Cortex-A8(s5pv210)
Gps:Ublox-6M
系統:android 2.3.1
核心: Linux2.6.35
開發板: Tiny210V1 SDK2(512M DDR2RAM SLC NANDFLASH 256M)
複試結束,該忙的事忙完就到四月底了,這才有時間坐下來學點東西。這應該是本階段做的最後一個小玩意了。前戲縮短,廢話少說,進正題。
由於友善只提供了GPS驅動模組,並無原始碼,而且經測試友善的驅動並未完整解析GPS的幾大關鍵資料,因此上層應用只能獲得經緯度,精度,UTC時間。這樣就只能在google地圖,百度地圖類似於這樣應用提供定位。由於HAL無法返回衛星狀態資料(可見衛星數,可用衛星數,衛星訊號強度等),導致無法使用專業的GPS導航軟體。下面提供的原始碼是根據gps_qemu.c修改而來的,實現GPS關鍵資料解析,支援凱立德,道道通等導航軟體。下面會從GPS NMEA-0183協議開始到Android GPS HAL移植及模組的編譯載入簡要介紹Android車載導航儀是如何“煉成”的。下面附原始碼(理論上支援所有輸出NMEA-0183格式資料的串列埠及USB GPS)。
我在X寶上100塊買的GPS模組屬於硬GPS,也就是串列埠上直接輸出NMEA資料的。所以首先要做的是瞭解NMEA的資料結構。
NMEA-0183標準資料分析例項(四中常用資料)
$資訊型別,xxx,xxx,xxx,xxx,xxx,xxx,xxx,
每行開頭的字元都是$,接著是資訊型別,後面是資料,用逗號隔開
資訊型別為:
GPGSV:可見衛星資訊
GPGLL:地理定位資訊
GPRMC:推薦最小定位資訊
GPVTG:地面速度資訊
GPGGA:GPS定位資訊
GPGSA:當前衛星資訊
$GPGGA,012440.00,3202.1798,N,11849.0763,E,1,05,2.7,40.2,M,0.5,M,,*6F..
1 時間: 01+8=9點24分40.00秒
2 緯度: 北緯32度02.1798分
3 經度: 東經118度49.0763分
4 定位: 1=(定位sps模式) 0=(未定位)
5 應用衛星數: 05個
6 HDOP: 2.7米
7 海拔: 40.2
8 海拔單位: M=(米)
9 WGS84水準面劃分: 0.5
10 WGS84水準面劃分單位 M(米)
11
12 校驗位: 6F
$GPRMC,013946.00,A,3202.1855,N,11849.0769,E,0.05,218.30,111105,4.5,W,A*20..
01 時間01時39分46.00秒
02 定位狀態 A=可用 V=警告(不可用)
03 緯度: 北緯(N) 32度02.1855分
04 經度: 東經(E) 118度49.0769分
05 相對位移速度: 0.05 knots
06 相對位移方向: 218.30度
07 日期: 11日11月05年(日日月月年年)
08
09
10 檢查位
$GPGSA,A,3,01,03,14,20,,,,,,,,,2.6,2.5,1.0*35..
01 模式2: A=自動 M=手動
02 模式1: 1=未定位 2=二維定位 3=三維定位
03 衛星編號: 01到32
04 PDOP-位置精度稀釋:(2.6) 0.5--99.9
05 HDOP-水平經度稀釋:(2.6) 0.5--99.9
06 VDOP-垂直經度稀釋:(1.0) 0.5--99.9 07 檢驗位 35
$GPGSV,2,1,08,01,62,160,42,03,23,189,42,06,23,049,32,14,24,150,35*78..
01 天空中收到訊號的衛星總數
02 定位的衛星總數
03 天空中衛星總數
04 (01,62,160,42)分別是衛星編號01-32,衛星仰角00-90度,衛星方位角000-359度,訊號噪聲比00-99dB 以下類似(03,23,189,42) (06,23,049,32) (14,24,150,35)
05 Checksum檢查位*78
大體瞭解NMEA資料以後需要我們做的就是移植GPS HAL了。在Android平臺下,我們需要移植的GPS內容是位於JNI層下面的,也就是剛才提到的HAL硬體抽象層。對於GPS硬體抽象層來說不算複雜,裡面包括對對串列埠(或USB 轉串列埠)裝置的初始化,GPS執行緒建立及NMEA資料讀取、解析、資訊回撥等等工作。這在Android原始碼中給出了少量的參考資訊,也就是 Android-2.3.1/sdk/emulator/gps/這個目錄下的gps_qemu.c檔案。它要為我們所用,還需要做大量的修改和升級。對於GPS HAL的設計我們首現要了解Android原始碼中的幾個結構(結構內容就不貼出來了,大家可以參考原始碼),分別是:
GpsLocation; GpsStatus; GpsInterface;GpsCallbacks;GpsState; NmeaReader;
還有下面對GPS狀態的幾個重要的定義:
#define GPS_STATUS_NONE 0//未知狀態
#define GPS_STATUS_SESSION_BEGIN 1 //已經開始導航
#define GPS_STATUS_SESSION_END 2//停止導航
#define GPS_STATUS_ENGINE_ON 3//已經通電但沒有導航
#define GPS_STATUS_ENGINE_OFF 4//沒有通電狀態
gps是如何被開啟和初始化的:
見框圖:
對於gps_qemu.c 的修改就不一行行的貼原始碼了(內容太多)。這裡只簡述下需要修改的函式的函式名及其作用,修改細節大家可以參考上面連結提供的原始碼。
1.修改static int nmea_tokenizer_init( NmeaTokenizer* t, const char* p, const char* end )函式
if (q > p) { --------》》》if (q > =p) { //解決無法讀取空白NEMA資料的bug
if (count < MAX_NMEA_TOKENS) {
t->tokens[count].p = p;
t->tokens[count].end = q;
count += 1;
}
}
2.依次修改下面函式,細節參照原始碼
static void nmea_reader_init( NmeaReader* r )
static void nmea_reader_set_callback( NmeaReader* r, gps_location_callback cb )
static void nmea_reader_parse( NmeaReader* r )//關鍵 資訊回撥
static void* gps_state_thread( void* arg )
static void gps_state_init( GpsState* state )//關鍵 完成對串列埠的初始化
3.修改結構NmeaReader的定義,新增新成員。
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;
3.新增新函式static int nmea_reader_update_accuracy(NmeaReader * r, Token accuracy)
用於解析GPS定位精度資訊。
4.新增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_qemu.c
LOCAL_MODULE := gps.default
LOCAL_MODULE_TAGS := eng
include $(BUILD_SHARED_LIBRARY)
#endif
5.將gps_qemu.c Android.mk cp到gps目錄下(可新建任意名稱目錄),cp gps目錄到已經編譯過的Android原始碼下。
6.編譯,由於我的目標板是tiny210,在Android原始碼目錄下依次執行下面命令:
$ source 原始碼目錄/build/envsetup.sh
$ export TARGET_PRODUCT=full_mini210 //將目標生成的位置修改自己開發板的目錄
$mmm ./gps
編譯完成後會在out/target/product/smdkv210/system/lib/hw/目錄下生成gps.default.so庫,cp gps.default.so到檔案系統的system/lib/hw/目錄下,生成.img映象燒入開發板。
7.安裝凱立德到開發板,並安裝地圖包。
8.開機測試
分別使用GPS_Test_Plus_1.2.1和凱立德測試GPS。
附圖:
1.GPS_Test_Plus_1.2.1測試,衛星資訊概覽
2.可視衛星,可用衛星分佈測試
3.基本定位資訊
4.GPS衛星授時測試
5.海拔及速度測試
6.凱立德導航測試
7.GPS基本資訊測試
8.定位位置測試
9.Ublox-6M模組
10.