1. 程式人生 > >基於Android2.3的車載導航---andorid GPS HAL的移植與分析(by liukun321咕唧咕唧)

基於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標準資料分析例項(四中常用資料)

$資訊型別,xxxxxxxxxxxxxxxxxxxxx

每行開頭的字元都是$,接著是資訊型別,後面是資料,用逗號隔開

資訊型別為:

GPGSV:可見衛星資訊

GPGLL:地理定位資訊

GPRMC:推薦最小定位資訊

GPVTG:地面速度資訊

GPGGAGPS定位資訊

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.