和菜鳥一塊兒學android4.0.3源碼之硬件gps簡單移植【轉】

本文轉載自:http://blog.csdn.net/mwj19890829/article/details/18751447html

關於Android定位方式前端

android 定位通常有四種方法,這四種方式分別是GPS定位、WIFI定位、基站定位、AGPS定位。java

一、 Android GPSlinux

須要GPS硬件支持直接和衛星交互來獲取當前經緯度,這種方式須要手機支持GPS模塊如今大部分的智能機應該都有了。經過GPS方式準確度是最高的可是它的缺點也很是明顯。android

一、 比較耗電git

二、 絕大部分用戶默認不開啓GPS模塊web

三、 從GPS模塊啓動到獲取第一次定位數據可能須要比較長的時間算法

四、 室內幾乎沒法使用。後端

這其中缺點二、3都是比較致命的。須要指出的是GPS走的是衛星通訊的通道在沒有網絡鏈接的狀況下也能用。數組

 

二、 Android基站定位

Android基站定位只要明白了基站/WIFI定位的原理本身實現基站/WIFI定位其實不難。基站定位通常有幾種:第一種是利用手機附近的三個基站進行三角定位,因爲每一個基站的位置是固定的,利用電磁波在這三個基站間中轉所須要時間來算出手機所在的座標;第二種則是利用獲取最近的基站的信息,其中包括基站 id、location area code、mobile country code、mobile network code和信號強度將這些數據發送到google的定位web服務裏,就能拿到當前所在的位置信息,偏差通常在幾十米到幾百米以內。其中信號強度這個數據很重要。

 

三、 Android Wifi定位

根據一個固定的Wifi MAC地址經過收集到的該Wifi熱點的位置而後訪問網絡上的定位服務以得到經緯度座標。由於它和基站定位其實都須要使用網絡因此在Android也統稱爲Network方式。

 

四、 AGPS定位

AGPS(AssistedGPS)輔助全球衛星定位系統是結合GSM或GPRS與傳統衛星定位利用基地臺代送輔助衛星信息以縮減GPS芯片獲取衛星信號的延遲時間受遮蓋的室內也能借基地臺訊號彌補減輕GPS芯片對衛星的依賴度。和純GPS、基地臺三角定位比較,AGPS能提供範圍更廣、更省電、速度更快的定位服務。理想偏差範圍在10公尺之內,日本和美國都已經成熟運用AGPS於LBS服務(Location Based Service)基於位置的服務。AGPS技術是一種結合了網絡基站信息和GPS信息對移動臺進行定位的技術,能夠在GSM/GPRS、WCDMA和CDMA2000網絡中進行使用。該技術須要在手機內增長GPS接收機模塊並改造手機的天線,同時要在移動網絡上加建位置服務器、差分GPS基準站等設備。AGPS解決方案的優點主要體如今其定位精度上在室外等空曠地區其精度在正常的GPS工做環境下能夠達到10米左右,堪稱目前定位精度最高的一種定位技術。該技術的另外一優勢爲首次捕獲GPS信號的時間通常僅需幾秒,不像GPS的首次捕獲時間可能要2-3分鐘。

 

 

 

 

 

 

 

 

 

 

 

 

關於android上的gps定位

關於gps定位,從衛星信號到android終端地圖顯示的總體流程圖以下:

 

如下簡單介紹下GPS定位的相關知識

1、GPS簡介

GPS(Global Positioning System), 即全球定位系統,它是一個由覆蓋全球的24顆衛星組成的衛星系統。其目的是在全球範圍內對地面和空中目標進行準肯定位和監測。隨着全球性空間定位信息應用的日益普遍,GPS提供的全時域、全天候、高精度定位服務將給空間技術、地球物理、大地測繪、遙感技術、交通調度、軍事做戰以及人們的平常生活帶來巨大的變化和深遠的影響。

目前的民用GPS設備包括測量型和導航型。其中測量型產品的精度可達到米級甚至毫米級,但至少須要兩臺(套)才能達到設計精度要求,並且其內部結構複雜,單機成本通常在幾萬到幾十萬,適合專業高精度測量環境使用;導航型產品,因爲其使用者對精度要求不高,通常爲幾十米,所以機器內部硬件相對簡單,只須一臺就能夠完成導航工做,加之其價格相對較低,於是更有普及和推廣價值。

GPS系統通常由地面控制站、導航衛星和用戶接收機(GPS的移動用戶端)三大部分組成。導航衛星至少24顆,均勻分佈在6個極地軌道上,軌道的夾角爲60度,距地平均高度爲20200千米,每12恆星時繞地球一週。

 

 

 

2、GPS衛星信號結構

GPS衛星發射的信號包含有三種成分,即50Hz導航電文(D碼)僞隨機碼(C/A碼或P碼)載波(Ll,L2波段)。這3種信號份量都是在同一基準頻率F0=10.23MHZ的控制下產生的。

 

GPS衛星信號結構

 

 

 

 

GPS衛星所採用的兩種測距碼,即C/A碼和P碼(或Y碼),均屬於僞隨機碼。

 1)C/A碼:是由兩個10級反饋移位寄存器組合而產生。碼長Nu=1024-1=1023比特,碼元寬爲tu=1/f1=0.97752s,(f1爲基準頻率f0的10分之1,1.023 MHz),相應的距離爲293.1m。週期爲Tu= Nutu=1ms,數碼率爲1.023Mbit/s。

    C/A碼的碼長短,共1023個碼元,若以每秒50碼元的速度搜索,只需20.5s,易於捕獲,稱捕獲碼。

    碼元寬度大,假設兩序列的碼元對齊偏差爲爲碼元寬度的1/100,則相應的測距偏差爲2.9m。因爲精度低,又稱粗碼。

 2)P碼

    P碼產生的原理與C/A碼類似,但更復雜。發生電路採用的是兩組各由12級反饋移位寄存器構成。碼長Nu=2.35*10^14比特,碼元寬爲tu=1/f0=0.097752s,相應的距離爲29.3m。週期爲Tu= Nutu=267d,數碼率爲10.23Mbit/s。

     P碼的週期長,267天重複一次,實際應用時P碼的週期被分紅38部分,(每一部分爲7天,碼長約6.19 ,1012比特),其中1部分閒置,5部分給地面監控站使用,32部分分配給不一樣衛星,每顆衛星使用P碼的不一樣部分,都具備相同的碼長和週期,但結構不一樣。P碼的捕獲通常是先捕獲C/A碼,再根據導航電文信息,捕獲P碼。因爲P碼的碼元寬度爲C/A碼的1/10,若取碼元對齊精度仍爲碼元寬度的1/100,則相應的距離偏差爲0.29m,故P碼稱爲精碼。

 

導航電文是包含有關衛星的參考星曆、衛星工做狀態、時間改正參數、衛星鐘運行狀態、軌道攝動改正、大氣折射改正和由C/A碼捕獲P碼等導航信息的數據碼(或D碼)。

    導航電文也是二進制碼,依規定格式組成,按幀向外播送。每幀電文含有1500比特,播送速度50bit/s,每幀播送時間30s。

    每幀導航電文含5個子幀,每一個子幀分別含有10個字,每一個字30比特,故每一個子幀共300比特,播發時間6s。爲記載多達25顆衛星,子幀四、5各含有25頁。子幀一、二、3和子幀四、5的每一頁構成一個主幀。主幀中一、二、3的內容每小時更新一次,四、5的內容僅當給衛星注入新的導航電文後才得以更新。

       導航電文的格式

 

一幀導航電文的內容


 

一、 遙測字(TLM-Telemetry WORD)

    位於每一個子幀的開頭,做爲捕獲導航電文的前導。

二、轉換碼(交接字)(HOW-Hand Over Word)    

緊接各子幀的遙測字,主要向用戶提供用於捕獲P碼的Z記數。所謂Z記數是從每一個星期六/星期日子夜零時起算的時間記數(1.5s),代表下一子幀開始瞬間的GPS時。

三、數據塊1:含有衛星鐘改正參數及數據齡期、星期的週數編號、電離層改正參數、和衛星工做狀態等信息。 衛星鐘改正參數a0、a一、a2分別表示該衛星的鐘差、鐘速和鐘速變化率。任意時刻t的鐘改正數爲: 

t=a0+a1(t-t0c)+a2(t-t0c)^2。

參考曆元t0e爲數據塊1的基準時間,從GPS時星期六/星期日子夜零時起算,變化於0-604800s之間。

數據齡期AODC表示衛星鐘改正參數的參考時刻t0c與最近一次更新鍾改正參數的時間TL之差,主要用於評價鍾改正數的可信程度。

現時星期編號WN:表示從1980年1月6日協調時零點起算的GPS時星期數。

四、數據塊2:包含在二、3兩個子幀裏,主要向用戶提供有關計算該衛星運行位置的信息。該數據通常稱爲衛星星曆,每30s重複1次,每小時更新一次。

五、數據塊3:包含在四、5兩個子幀中,主要向用戶提供其餘GPS衛星的概略星曆及其工做狀態信息,稱爲衛星的歷書。第3數據塊的內容每12.5分鐘重複一次,天天更新一次。

 

 

 

3、GPS接收機

 

 

天線單元

GPS信號接收機的天線單元爲接收設備的前置部分。天線單元包含接收天線和前置放大器兩部分。

其中天線部分多是全向振子天線或小型螺旋天線或微帶天線,但從發展趨勢來看,以微帶天線用的最廣、最有前途。

爲了提升信號強度,通常在天線後端設置前置放大器,前置放大器的做用是將由極微弱的GPS信號的電磁波能量轉換成爲弱電流放大。前置放大器分外差式和高放式兩種。因爲外差式前置放大器不只具備放大功能,還具備變頻功能,即將高頻的GPS信號變換成中頻信號,這有利於得到穩定的定位精度,因此絕大多數GPS接收機採用外差式天線單元。

 

信號通道

信號通道是一種軟件和硬件相結合的複雜電子裝置,是GPS接收機中的核心部分。其主要功能是捕獲、跟蹤、處理和量測衛星信號,以得到導航定位所須要的數據和信息。通道數目有1到24個不等,由接收機的類型而定。總的來說,信號通道目前有相關型、平方型和相位型等三種。新一代GPS信號接收機普遍採用相關型通道,主要由信號捕獲電路、僞噪聲跟蹤環路和載波跟蹤環路組成。

 

存儲器

這是GPS信號中接收機將定位現場採集的僞距、載波相位測量、人工量測的數據及解譯的衛星星曆儲存起來的一種裝置,以供差分導航和做相對定位的測後數據。

 

微處理機

接收機的計算部分由微處理機和機內軟件組成。機內軟件是由接收機生產廠家提供的,是實現數據採集、通道自校自動化的重要組成部分,主要用於信號捕獲、跟蹤和定位計算。微處理機結合機內軟件做下列計算和處理:

 (1)開機後指令各通道自檢,並測定、校訂和存儲各通道的時延值;

 (2)解譯衛星星曆,計算測站的三維座標;

 (3)由測站定位座標和衛星星曆計算全部衛星的升降時間、方位和高度角,提供可視衛星數據及衛星的工做情況,以便得到最佳定位星位,提升定位精度。

 

定位

靜態定位時,GPS接收機在捕獲和跟蹤GPS衛星的過程當中固定不變,接收機經過高精度測量GPS信號的傳播時間,並利用GPS衛星在軌的已知位置解算出接收機天線所在位置的三維座標。而動態定位則是用GPS接收機測定一個運動物體的運行軌跡。GPS信號接收機所在的運動物體叫作載體(如航行中的船艦,空中的飛機,行走的車輛等)。因爲載體上的GPS接收機天線在跟蹤GPS衛星的過程當中將相對地球而運動,這樣,接收機用GPS信號就可實時地測量運動載體的狀態參數(瞬間三維位置和三維速度)。

GPS定位還受GPS網的限制,應用GPS衛星定位技術創建的控制網叫GPS網。概括起來大體可分爲兩大類:一類是全球或全國性的高精度GPS網,這類GPS網中相鄰點的距離在數千千米至上萬千米, 其主要任務是做爲全球高精度座標框架或全國高精度座標框架,覺得全球性地球動力學和空間科學方面的科學研究工做服務。另外一類是區域性的 GPS網,包括城市或礦區GPS網,GPS工程網等,這類網中的相鄰點間的距離爲幾千米至幾十千米,其主要任務是直接爲國民經濟建設服務。

 

二維位置的肯定

 

 

由衛星產生的測距信號肯定三維位置

 

 

GPS接收機常識:

1. 座標 (coordinate)

  有2維、3維兩種座標表示,當GPS可以收到4顆及以上衛星的信號時,它能計算出本地的3維座標:經度、緯度、高度,若只能收到3顆衛星的信號,它只能計算出2維座標:經度和緯度,這時它可能還會顯示高度數據,但這數據是無效的。大部分GPS不只能以經/緯度(Lat/Long) 的方式,顯示座標,並且還能夠用 UTM(Universal TransverseMercator) 等座標系統顯示座標但咱們通常仍是使用 LAT/LONG 系統,這主要是由你所使用的地圖的座標系統決定的。

2. 航點 (Landmark or Waypoint)

  GPS內存中保存的一個點的座標值。在有GPS信號時,你能夠存儲成一個易認的名字,還能夠給它選定一個圖標。航點是GPS數據核心,它是構成「航線」的基礎。標記航點是GPS主要功能之一,可是你也能夠從地圖上讀出一個地點的座標,手工或經過計算機接口輸入GPS,成爲一個航點。一個航點能夠未來用於GOTO功能的目標,也能夠選進一條航線 Route,做爲一個支點。通常 GPS 能記錄500個或以上的航點。

      3. 航線 (ROUTE)

  航線是GPS內存中存儲的一組數據,包括一個起點和一個終點的座標,還能夠包括若干中間點的座標,每兩個座標點之間的線段叫一條"腿"(leg) 。常見 GPS 能存儲20條線路,每條線路30條"腿"。各座標點能夠從現有航點中選擇,或是手工/計算機輸入數值,輸入的路點同時作爲一個航點 (Waypoint/Landmark) 保存。

4. 前進方向 (Heading)

  GPS沒有指北針的功能,靜止不動時它是不知道方向的。可是一旦動了起來,它就能知道本身的運動方向。GPS每隔一秒更新一次當前地點信息,每一點的座標和上一點的座標一比較,就能夠知道前進的方向 。

      5. 導向 (Bearing)

  導向功能在如下條件下起做用:

  1.) 以設定"走向"(GOTO) 目標。"走向"目標的設定能夠按"GOTO"鍵,而後從列表中選擇一個航點。之後"導向"功能將導向此航點

   2.) 目前有活躍航線 (Activity route)。活躍航線通常在設置 -> 航線菜單下設定。若是目前有活動航線,那麼"導向"的點是航線中第一個路點,每到達一個路點後,自動指到下一個路點。

6. 日出日落時間 (Sun set/raise time)

  大多數GPS可以顯示當地的日出、日落時間,這在計劃出發 / 宿營時間時是有用的。這個時間是 GPS 根據當地經度和日期計算獲得的,是指平原地區的日出、日落時間,在山區由於有山脊遮擋,日照時間根據狀況要遲早各少半個小時以上。GPS的時間是從衛星信號獲得的格林尼制時間,在設置 (setup) 菜單裏能夠設置本地的時間偏移,對中國來講,應設+8小時,此值只與時間的顯示有關。

7. 航跡 (Plot trail)

  GPS每秒更新一次座標信息,因此能夠記載本身的運動軌跡。通常GPS能記錄1024個以上足跡點,在一個專用頁面上,以可調比例尺顯示移動軌跡。足跡點的採樣有自動和定時兩種方式自動採樣由 GPS 自動決定足跡點的採樣方式,通常是隻記錄方向轉折點,長距離直線行走時不記點;定時採樣能夠規定採樣時間間隔,好比30秒、一分鐘、 5 分鐘或其餘時間,每隔這麼長時間記一個足跡點。

 

 

 

4、主流GPS方案供應商

一臺GPS設備關鍵的元件有天線、低噪音放大器(LNA)、射頻接收轉換(RF Section)、數字部分(也稱數字基帶,Digital Baseband)、微處理器(Microprocessor)、微處理器周邊外設(Processor Peripherals)、輸入輸出和驅動(I/OandDriver)等幾個部分。芯片提供商也強手如雲,包括 SiRF、u-blox、Ti、Analog Devices、NXP、高通、英飛凌、索尼、意法半導體、Trimble(天寶)、Atmel、SiGe、u-Nav 等等。

一、SiRF公司

SiRF是GPS芯片的龍頭供應商,產品線完整,可以提供完整的解決方案。

表明產品:基於SiRFstarIII 架構的芯片GSC3e/LP與GSC3f/LP、GSC3LT與 GSC3LTf、GSC3LTi and GSC3Ltif,基於 SiRF Instant 架構的 GSCi-5000。現最新的模塊爲Fastrax iT430,它是基於SiRFstar IV芯片和SiRFaware軟件技術的GPS模塊。

 

尺寸:9.6 x 9.6 x 1.85 mm

二、Nemerix 

NemeriX 提供的產品包括模擬射頻接收器和數字基帶處理器。

Nemerix NB1042GPS 接收器模塊,世界上功耗最低的GPS芯片組。

 

三、TI

TI的輔助GPS (A-GPS)解決方案在異步和同步蜂窩式網絡內提供快速而精確的定位服務。這些解決方案在優化以後,適用於全部當前和發展中的無線標準(如 GSM、GPRS、EDGE、CDMA、UMTS 和 WCDMA)。 TI 在 2005 年推出的 90nm 工藝技術的單芯片 A-GPS 解決方案,GPS5300NaviLink 4.0單芯片採用 TI DRP技術,可實現離散的GPS解決方案。

四、Atmel

Atmel 的低功耗 GPS 模塊芯片組高度集成並能極大節省製版空間。

Atmel與Magellan推出新的GPS芯片組ATR0663,包括一個先進的 GPS 基帶和一個具有集成 2D 圖形加速器的 LCD 控制器(以實現 2048 x 2048像素的虛擬屏幕支持)、一個 AC97 音頻控制器,以及一個圖像傳感器接口。多種輸入/輸出 (I/O) 選項,包括以太網 (Ethernet)、USB 2.0 Full Speed Hostand Device、SD/MMC、TWI 和 USART,爲PND應用提供了一個高針對性的片上系統 (SoC) 解決方案。

五、意法半導體

ST 也可以提供面向 GPS 應用的全系列解決方案,適用於車載與便攜式導航系統。最新一代的 ST 導航/信息娛樂平臺名爲 NaviFlex,其集成度更高:融合 GPS 接收器和 Nomadik 應用處理器,保證了汽車多媒體應用無與倫比的音頻、視頻和成像質量。

六、Maxim

       Maxim 公司可以提供低噪聲、低功耗的GPS前端接收器和獨特的GPS方案。

七、NXP

恩智浦半導體 (NXP Semiconductors,原飛利浦半導體),恩智浦的解決方案成功地將高質量導航功能與豐富的多媒體處理結合在一塊兒,包括 MP3 播放、標準的以及高清晰的視頻播放及錄製、調頻收音機、圖像存儲和遊戲等。

八、英飛凌 

Infineon和Global Locate合做推出的Hammerhead是全球首款單芯片CMOS GPS 接收器。該芯片支持移動站輔助式(MS-A)、移動站基於式(MS-B)、自主式和加強式跟蹤模式。一流的室內信號跟蹤效果,徹底支持輔助式和自主式跟蹤模式,即便在最微弱的信號環境中也能夠進行高度精確的導航。Hammerhead 芯片的基於主機的軟件架構,不只將器件尺寸和成本減至最小,還容許將協議消息直接嵌入到 GPS 導航軟件中。

九、U-Blox

來自瑞士的GPS技術公司u-blox AG公司以往主要提供命名爲 TIM的GPS 模塊,其中採用的SiRF公司GPS芯片。如今u-blox 也開始注重核心芯片的開發。新推出的 u-blox 5 系列全球定位系統以及隨時可用的伽利略系統單芯片和芯片組擁有不到一秒的接收性能。這種新的芯片還擁有 SuperSense-160 dBm 探測和跟蹤靈敏度、小於 50mW 的功率需求以及一個小於 100 平方毫米的覆蓋區,適用於掌上電腦(PDA)、我的導航設備、照相機、手機、媒體播放器和其它電池操做便攜式設備。

十、高通

目前,全球已有總計超過兩億部手機裝備了高通公司的gpsOne輔助型GPS 技術。gpsOne 技術支持一系列極具吸引力的位置服務,其中包括各類各樣針對消費者、商務和我的安全的應用。

 

 

 

5、GPS標準格式數據

 

 

模塊輸出信息主要包括4個部分:

一、GPS定位信息GPGGA(Global Positioning SystemFix Data)

 

[html]  view plain copy
 
 
  1. $GPGGA,063740.998,2234.2551,N,11408.0339,E,1,08,00.9,00053.A,M,-2.1,M,,*7B  
  2. $GPGGA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,M,<10>,M,<11>,<12>*hh<CR><LF>  
  3. <1> UTC時間,hhmmss(時分秒)格式  
  4. <2> 緯度ddmm.mmmm(度分)格式(前面的0也將被傳輸)  
  5. <3> 緯度半球N(北半球)或S(南半球)  
  6. <4> 經度dddmm.mmmm(度分)格式(前面的0也將被傳輸)  
  7. <5> 經度半球E(東經)或W(西經)  
  8. <6> GPS狀態:0=未定位,1=非差分定位,2=差分定位,6=正在估算  
  9. <7> 正在使用解算位置的衛星數量(00~12)(前面的0也將被傳輸)  
  10. <8> HDOP水平精度因子(0.5~99.9)  
  11. <9> 海拔高度(-9999.9~99999.9)  
  12. <10> 地球橢球面相對大地水準面的高度  
  13. <11> 差分時間(從最近一次接收到差分信號開始的秒數,若是不是差分定位將爲空)  
  14. <12> 差分站ID號0000~1023(前面的0也將被傳輸,若是不是差分定位將爲空)  

 

 

 

二、當前衛星信息GPGSA(GPS DOP and ActiveSatellites)

   

[html]  view plain copy
 
 
  1. $GPGSA,A,3,06,16,14,22,25,01,30,20,,,,,01.6,00.9,01.3*0D  
  2. $GPGSA,<1>,<2>,<3>,<3>,,,,,<3>,<3>,<3>,<4>,<5>,<6>,<7><CR><LF>  
  3. <1>模式 :M = 手動, A = 自動。  
  4. <2>定位型式 1 = 未定位, 2 = 二維定位, 3 = 三維定位。  
  5. <3>PRN 數字:01 至 32 表天空使用中的衛星編號,最多可接收12顆衛星信息。  
  6. <4> PDOP位置精度因子(0.5~99.9)  
  7. <5> HDOP水平精度因子(0.5~99.9)  
  8. <6> VDOP垂直精度因子(0.5~99.9)  
  9. <7> Checksum.(檢查位).  

 

 

 

三、可見衛星信息GPGSV(GPS Satellites in View)     

 

[html]  view plain copy
 
 
  1. $GPGSV,2,1,08,06,26,075,44,16,50,227,47,14,57,097,44,22,17,169,41*70  
  2. $GPGSV,2,2,08,25,49,352,45,01,64,006,45,30,13,039,39,20,15,312,34*7A  
  3. $GPGSV,<1>,<2>,<3>,<4>,<5>,<6>,<7>,?<4>,<5>,<6>,<7>,<8><CR><LF>  
  4. <1> GSV語句的總數  
  5. <2> 本句GSV的編號  
  6. <3> 可見衛星的總數,00 至 12。  
  7. <4> 衛星編號, 01 至 32。  
  8. <5>衛星仰角, 00 至 90 度。  
  9. <6>衛星方位角, 000 至 359 度。實際值。  
  10. <7>訊號噪聲比(C/No), 00 至 99 dB;無表未接收到訊號。  
  11. <8>Checksum.(檢查位).  
  12. <4>,<5>,<6>,<7>項個別衛星會重複出現,每行最多有四顆衛星。其他衛星信息會於次一行出現,若未使用,這些字段會空白。  

 

 

 

四、推薦最小定位信息GPRMC(Recommended MinimumSpecific GPS/TRANSIT Data)

 

[html]  view plain copy
 
 
  1. $GPRMC,012724.000,A,2234.3157,N,11408.0921,E,0.00,,290108,,,A*71  
  2. $GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh<CR><LF>  
  3. <1> UTC時間,hhmmss(時分秒)格式  
  4. <2> 定位狀態,A=有效定位,V=無效定位  
  5. <3> 緯度ddmm.mmmm(度分)格式(前面的0也將被傳輸)  
  6. <4> 緯度半球N(北半球)或S(南半球)  
  7. <5> 經度dddmm.mmmm(度分)格式(前面的0也將被傳輸)  
  8. <6> 經度半球E(東經)或W(西經)  
  9. <7> 地面速率(000.0~999.9節,前面的0也將被傳輸)  
  10. <8> 地面航向(000.0~359.9度,以真北爲參考基準,前面的0也將被傳輸)  
  11. <9> UTC日期,ddmmyy(日月年)格式  
  12. <10> 磁偏角(000.0~180.0度,前面的0也將被傳輸)  
  13. <11> 磁偏角方向,E(東)或W(西)  
  14. <12> 模式指示(僅NMEA0183 3.00版本輸出,A=自主定位,D=差分,E=估算,N=數據無效)  
  15. 咱們所關心的是GPRMC這條信息,由於其中包括當前格林威治時間、經度、緯度、日期等。  

6、Linux driver層

       UART接口,與gps模塊通訊,即讀取gps的信息。

 

7、android GPS hal層

       由於linux底層驅動只須要有uart接口就能夠接收到gps數據了,而android的hal層會調用linux內核層的uart驅動,因此,這裏uart驅動就再也不分析了,只要hal層打開串口,而後read就能夠了,這裏我參考的是模擬器的gps。

本身新建的文件夾,用來適配gps:

hardware/libhardware_legacy/gps

gps頭文件:

hardware/libhardware_legacy/include/hardware_legacy/gps.h

首先看一下GpsLocation這個結構體。

 

[html]  view plain copy
 
 
  1. /** Represents a location. */  
  2. typedef struct {  
  3.     /**set to sizeof(GpsLocation) */  
  4.    size_t          size;  
  5.     /**Contains GpsLocationFlags bits. */  
  6.    uint16_t        flags;  
  7.     /**Represents latitude in degrees. */  
  8.    double          latitude;  
  9.     /**Represents longitude in degrees. */  
  10.    double          longitude;  
  11.     /**Represents altitude in meters above the WGS 84 reference  
  12.      *ellipsoid. */  
  13.    double          altitude;  
  14.     /**Represents speed in meters per second. */  
  15.    float           speed;  
  16.     /**Represents heading in degrees. */  
  17.    float           bearing;  
  18.     /**Represents expected accuracy in meters. */  
  19.    float           accuracy;  
  20.     /**Timestamp for the location fix. */  
  21.    GpsUtcTime      timestamp;  
  22. } GpsLocation;  

 

 

全部咱們要知道的數據都在這裏了:經度、緯度、海拔、速度、精確度、世界標準時間等。而上層也只是須要這個數據結構,因此只要把這個數據結構給android上層,那麼就OK了。

下面仍是主要分析下android模擬器是如何實現的。先看下簡單的流程圖:

 

首先看下hw主要結構體,gps是註冊爲hw模塊的。編譯後是生成gps.*.so的,而他的方法是調用gps_module_methods。

 

[html]  view plain copy
 
 
  1. const struct hw_module_t HAL_MODULE_INFO_SYM = {  
  2.     .tag =HARDWARE_MODULE_TAG,  
  3.    .version_major = 1,  
  4.    .version_minor = 0,  
  5.     .id =GPS_HARDWARE_MODULE_ID,  
  6.     .name ="Goldfish GPS Module",  
  7.     .author ="The Android Open Source Project",  
  8.     .methods =&gps_module_methods,  
  9. };  
  10. 而gps_module_methods又調用了open_gps  
  11. static struct hw_module_methods_t gps_module_methods ={  
  12.     .open = open_gps  
  13. };  

 

 

再看看open_gps作了什麼,初始化了不少函數指針,具體含義能夠看

 

[html]  view plain copy
 
 
  1. static constGpsInterface  qemuGpsInterface = {  
  2.     sizeof(GpsInterface),  
  3.     qemu_gps_init,   //打開接口,提供callback函數  
  4.     qemu_gps_start,  //開始導航  
  5.     qemu_gps_stop,   //中止導航  
  6.     qemu_gps_cleanup, //關閉接口  
  7.     qemu_gps_inject_time,//注入當前時間  
  8.     qemu_gps_inject_location, //注入從其餘定位方式得的當前位置。  
  9.     qemu_gps_delete_aiding_data, //  
  10.     qemu_gps_set_position_mode, //設置座標模式  
  11.     qemu_gps_get_extension, //擴展信息  
  12. };  

 

 

而後再看看各個函數,這些函數是jni層會調用到的,這裏簡單介紹初始化、數據上報等操做。

首先是初始化函數qemu_gps_init,這裏調用了gps_state_init函數,而後在這裏打開咱們要的串口驅動設備,開啓讀取gps數據的線程。

 

[html]  view plain copy
 
 
  1. state->fd = open(GPS_Serial_Name, O_RDONLY );  
  2. state->thread = callbacks->eate_thread_cb("gps_state_thread」,gps_state_thread,  tate);  

 

 

當線程啓動之後,那麼就會在這個線程中處理一些事情了,接着看下gps_state_thread函數。

這裏會把callback函數給設置好,用以傳數據給jni層。

 

[html]  view plain copy
 
 
  1. nmea_reader_set_callback( reader,state->callbacks.location_cb );  

 

串口讀取gps的數據ret = read( fd, buff, sizeof(buff) );

解析數據 nmea_reader_addc(reader, buff[nn] );

       而後他會調用nmea_reader_parse(r );函數

這個函數會根據不一樣的gps協議格式來分別處理。

if ( !memcmp(tok.p, "GGA", 3) )

這裏會根據GGA的格式來處理,好比:

更新時間nmea_reader_update_time(r, tok_time);

       更新經緯度nmea_reader_update_latlong

       更新海拔nmea_reader_update_altitude

 

[html]  view plain copy
 
 
  1. else if ( !memcmp(tok.p, "GLL", 3) )  
  2. else if ( !memcmp(tok.p, "GSA", 3) )  
  3. else if ( !memcmp(tok.p, "GSV", 3) )  

 

 

       其餘的依次都差很少。具體能夠看源碼。

最後處理完了之後,把便要把數據給jni層了。經過r->callback( &r->fix );這個callback函數,就是數據傳輸的主要函數了。

 

 

 

8、android GPS的JNI層

先仍是看下jni層的主要流程吧:分爲一、Java到jni到hal和二、hal到jni到java。

 

 

 

GPS的jni的代碼是在下面這個目錄下的:

 

[html]  view plain copy
 
 
  1. /framework/base/services/jni/com_android_server_location_GpsLocationProvider.cpp  

 

 

在com_android_server_location_GpsLocationProvider.cpp文件中,實現JNI方法。注意文件的命令方法,com_android_server_location前綴表示的是包名,表示硬件服務GpsLocationProvider是放在frameworks/base/services/java目錄的com/android/server/location目錄下的,即存在一個命令爲

com.android.server.location.GpsLocationProvider的類。

在同一個目錄下有一個onload.cpp,這個會註冊這個jni而且調用register_android_server_location_GpsLocationProvider來實現java層到hal層的接口的調用。

在android_location_GpsLocationProvider_init函數中,經過Android硬件抽象層提供的hw_get_module方法來加載模塊ID爲GPS_HARDWARE_MODULE_ID的硬件抽象層模塊,其中,GPS_HARDWARE_MODULE_ID是在<hardware/gps.h>中定義的。Android硬件抽象層會根據GPS_HARDWARE_MODULE_ID的值在Android系統的/system/lib/hw目錄中找到相應的模塊,而後加載起來,而且返回hw_module_t接口給調用者使用。在jniRegisterNativeMethods函數中,第二個參數的值必須對應GpsLocationProvider所在的包的路徑,即com/android/server/location/GpsLocationProvider。

       下面分步來看下,jni是如何工做的。

首先是onload.cpp這裏會調用到

com_android_server_location_GpsLocationProvider.cpp的註冊函數

register_android_server_location_GpsLocationProvider,而這個註冊函數就註冊了應用層的GpsLocationProvider的jni。他會調用下面這個註冊函數。具體各個參數含義,第一個是env,是jni技術的主要結構體JNIEnv,第二個參數就是所要註冊的java服務程序的包。最後一個是native方法的回調函數了。

 

[html]  view plain copy
 
 
  1. jniRegisterNativeMethods(env,"com/android/server/location/GpsLocationProvider", sMethods,NELEM(sMethods));  

 

 

下面的是native方法的一些函數。

 

[html]  view plain copy
 
 
  1. staticJNINativeMethod sMethods[] = {  
  2. {"class_init_native","()V", (void*)android_location_GpsLocationProvider_class_init_native},  
  3.     {"native_is_supported","()Z",(void*)android_location_GpsLocationProvider_is_supported},  
  4.     {"native_init", "()Z",(void*)android_location_GpsLocationProvider_init},  
  5.     {"native_cleanup","()V", (void*)android_location_GpsLocationProvider_cleanup},  
  6. {"native_set_position_mode","(IIIII)Z",(void*)android_location_GpsLocationProvider_set_position_mode},  
  7.     {"native_start", "()Z",(void*)android_location_GpsLocationProvider_start},  
  8.     {"native_stop", "()Z",(void*)android_location_GpsLocationProvider_stop},  
  9. …………………………  
  10. };  

 

 

對於這個method作一些簡單的解釋吧:。

第一個參數name是在java服務層定義的native函數。具體能夠看

frameworks/base/location/java/com/android/server/location/GpsLocationProvide.java下的代碼。

這個稍後分析。

第二個參數signature是java服務層調用jni層的參數,具體的能夠先看下面這個表:

 

[html]  view plain copy
 
 
  1. 字符   Java類型    C類型  
  2. V      void         void  
  3. Z       jboolean     boolean  
  4. I        jint         int  
  5. J       jlong        long  
  6. D      jdouble       double  
  7. F      jfloat         float  
  8. B      jbyte         byte  
  9. C      jchar         char  
  10. S      jshort         short  

 

 

 

數組則以"["開始,用兩個字符表示

 

[html]  view plain copy
 
 
  1.    
  2. [I       jintArray      int[]  
  3. [F     jfloatArray      float[]  
  4. [B     jbyteArray      byte[]  
  5. [C    jcharArray       char[]  
  6. [S    jshortArray       short[]  
  7. [D    jdoubleArray     double[]  
  8. [J     jlongArray       long[]  
  9. [Z    jbooleanArray     boolean[]  
  10.    

 

 

實際上這些字符是與函數的參數類型一一對應的。

"()"中的字符表示參數,後面的則表明返回值。例如"()V" 就表示void Func();

"(II)V"表示 void Func(int, int);

 

上面的都是基本類型。若是Java函數的參數是class,則以"L"開頭,以";"結尾中間是用"/" 隔開的包及類名。而其對應的C函數名的參數則爲jobject. 一個例外是String類,其對應的類爲jstring

 

[html]  view plain copy
 
 
  1. Ljava/lang/String;String jstring  
  2. Ljava/net/Socket;Socket jobject  

 

 

 

若是JAVA函數位於一個嵌入類,則用$做爲類名間的分隔符。

例如"(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"

由此,上面寫函數的參數也知道了。

 

第三個變量fnPtr是函數指針,指向C函數,也就是在jni的cpp代碼中的。

 

而jni和java代碼的交互能夠看下圖所示:

其實,java層和jni層都是能夠互相調用的,而具體的java層調用jni的方法就是native聲明的方法;jni調用java的話,要先獲取java層的方法id,而後經過CallVoidMethod()等回調函數實現。

 

有了以上的知識點做爲基礎的話,那麼如今來分析下GPS的jni代碼了。

一、首先是android_location_GpsLocationProvider_class_init_native這個函數了。

 

[html]  view plain copy
 
 
  1. method_reportLocation =env->GetMethodID(clazz, "reportLocation","(IDDDFFFJ)V");  
  2.     ……………………………………  
  3.    method_requestUtcTime = env->GetMethodID(clazz,"requestUtcTime","()V")  

 

 

他先是獲取全部的方法id。而後調用hw模塊,也就是上面hal層編譯的gps.*.so連接庫

 

[html]  view plain copy
 
 
  1. err =hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);  

 

 

而後調用了hal層的gps的open函數了。

 

[html]  view plain copy
 
 
  1. err =module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);  

 

 

獲取接口sGpsInterface =gps_device->get_gps_interface(gps_device);

由於是gps不是agps因此

[html]  view plain copy
 
 
  1. sGpsXtraInterface =  
  2.           (constGpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE);  

 

 

二、接着即是android_location_GpsLocationProvider_init這個初始化函數了。

       該函數主要是調用了

 

[html]  view plain copy
 
 
  1. if(sGpsXtraInterface &&sGpsXtraInterface->init(&sGpsXtraCallbacks) != 0)  
  2.         sGpsXtraInterface = NULL;  

 

 

這個函數的函數指針init就調用到hal層的init函數。也就是qemu_gps_init函數了。

這裏傳進來了callback函數了。

具體以下:

 

[html]  view plain copy
 
 
  1. GpsCallbackssGpsCallbacks = {  
  2.     sizeof(GpsCallbacks),  
  3.     location_callback,  //回調位置信息  
  4.     status_callback,    //回調狀態信息  
  5.     sv_status_callback,  //回調sv狀態信息  
  6.     nmea_callback,    //上報nema信息  
  7.     set_capabilities_callback, //回調告知框架層GPS的性能  
  8.     acquire_wakelock_callback, //獲取GPS鎖,不進行休眠  
  9.     release_wakelock_callback, //釋放GPS鎖  
  10.     create_thread_callback, //建立線程,能夠調用java framework的代碼  
  11.     request_utc_time_callback, //獲取utc時間  
  12. };  

 

 

具體函數能夠看下面:

 

[html]  view plain copy
 
 
  1. staticvoid location_callback(GpsLocation* location)  
  2. {  
  3.     JNIEnv* env = AndroidRuntime::getJNIEnv();  
  4.     env->CallVoidMethod(mCallbacksObj, method_reportLocation,location->flags,  
  5.             (jdouble)location->latitude,(jdouble)location->longitude,  
  6.             (jdouble)location->altitude,  
  7.             (jfloat)location->speed,(jfloat)location->bearing,  
  8.             (jfloat)location->accuracy,(jlong)location->timestamp);  
  9.     checkAndClearExceptionFromCallback(env,__FUNCTION__);  
  10. }  

 

 

這裏會調用method_reportLocation這個方法,這個方法是在java服務層調用的。這裏經過CallVoidMethod函數調用了Java framework的函數。

 

[html]  view plain copy
 
 
  1. staticvoid status_callback(GpsStatus* status)  
  2. {  
  3.     JNIEnv* env = AndroidRuntime::getJNIEnv();  
  4.    env->CallVoidMethod(mCallbacksObj, method_reportStatus,status->status);  
  5.     checkAndClearExceptionFromCallback(env,__FUNCTION__);  
  6. }  
  7.    
  8. staticvoid sv_status_callback(GpsSvStatus* sv_status)  
  9. {  
  10.     JNIEnv* env = AndroidRuntime::getJNIEnv();  
  11.     memcpy(&sGpsSvStatus, sv_status,sizeof(sGpsSvStatus));  
  12.     env->CallVoidMethod(mCallbacksObj,method_reportSvStatus);  
  13.     checkAndClearExceptionFromCallback(env,__FUNCTION__);  
  14. }  
  15.    
  16. staticvoid nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)  
  17. {  
  18.     JNIEnv* env = AndroidRuntime::getJNIEnv();  
  19.     // The Java code will call back to readthese values  
  20.     // We do this to avoid creating unnecessaryString objects  
  21.     sNmeaString = nmea;  
  22.     sNmeaStringLength = length;  
  23.     env->CallVoidMethod(mCallbacksObj,method_reportNmea, timestamp);  
  24.     checkAndClearExceptionFromCallback(env,__FUNCTION__);  
  25. }  
  26.    
  27. staticvoid set_capabilities_callback(uint32_t capabilities)  
  28. {  
  29.     LOGD("set_capabilities_callback:%ld\n", capabilities);  
  30.     JNIEnv* env = AndroidRuntime::getJNIEnv();  
  31.     env->CallVoidMethod(mCallbacksObj,method_setEngineCapabilities, capabilities);  
  32.     checkAndClearExceptionFromCallback(env,__FUNCTION__);  
  33. }  
  34.    
  35. staticvoid acquire_wakelock_callback()  
  36. {  
  37.     acquire_wake_lock(PARTIAL_WAKE_LOCK,WAKE_LOCK_NAME);  
  38. }  
  39. 獲取GPS的鎖  
  40. staticvoid release_wakelock_callback()  
  41. {  
  42.     release_wake_lock(WAKE_LOCK_NAME);  
  43. }  
  44. 釋放了GPS的鎖  
  45. staticvoid request_utc_time_callback()  
  46. {  
  47.     JNIEnv* env = AndroidRuntime::getJNIEnv();  
  48.     env->CallVoidMethod(mCallbacksObj,method_requestUtcTime);  
  49.     checkAndClearExceptionFromCallback(env,__FUNCTION__);  
  50. }  
  51. 更新時間  
  52. staticpthread_t create_thread_callback(const char* name, void (*start)(void *), void*arg)  
  53. {  
  54.     return(pthread_t)AndroidRuntime::createJavaThread(name, start, arg);  
  55. }  
  56. 建立線程。  

 

 

 

三、其餘函數,開啓導航,關閉導航等的就不一一介紹了,和上面的相似。能夠看源碼。

好了,jni層就大概分析好了,那麼接着就是framework層的代碼了。

 

 

 

9、android GPS的framework層

       首先仍是主要流程圖吧:

 

Framework層主要就是爲上層應用調用提供接口。而GPS的framework層,根據jni的代碼咱們也能夠知道就在下面這個目錄下了。

frameworks/base/services/java/com/android/server/location/GpsLocationProvide.java

那麼android framework是怎麼開始往下調用jni的呢?仍是看代碼吧。

首先是在frameworks/base/services/java/com/android/server/SystemServer.Java

對於這個系統服務,仍是要從android啓動流程講起,首先linux內核啓動完了以後,會調用android的init程序,而後掛載文件最小系統,解析init.rc和init.*.rc等腳本,接着zygote,啓動虛擬機,而後就是運行到了systemserver了,也就是上面那個SystemServer.Java函數,在這個函數中,先看下SystemServer 這個類,發現了有一個native的init1函數。

native public static void init1(String[]args);

這個函數是調用了jni層的函數的,能夠看

frameworks/base/services/jni/com_android_server_SystemServer.cpp

首先是進入其main函數,

 

[html]  view plain copy
 
 
  1. System.loadLibrary("android_servers");  
  2.       init1(args);  

 

 

加載庫,而後就是調用了jni層的init1函數。

 

[html]  view plain copy
 
 
  1. static voidandroid_server_SystemServer_init1(JNIEnv* env, jobject clazz)  
  2. {  
  3.    system_init();  
  4. }  

 

 

其調用了system_init();函數,而在system_init函數中

 

[html]  view plain copy
 
 
  1. jmethodID methodId =env->GetStaticMethodID(clazz, "init2", "()V");  
  2. env->CallStaticVoidMethod(clazz,methodId);  

 

 

他又回調了SystemServer.Java中的init2函數。

在init2函數中

 

[html]  view plain copy
 
 
  1. public static final void init2() {  
  2.        Slog.i(TAG, "Entered the Android system server!");  
  3.        Thread thr = new ServerThread();  
  4.        thr.setName("android.server.ServerThread");  
  5.        thr.start();  
  6.     }  

 

 

建立了一個線程,最後他會調用到ServerThread的run方法。

在其run()方法中會啓動不少服務,好比Account Manager、ContentManager、System Content Providers、Lights Service、BatteryService、Vibrator Service、Alarm Manager、InitWatchdog、Window Manager等等,咱們這裏最主要的就是關注LocationManagerService。

 

[html]  view plain copy
 
 
  1. try {  
  2.                 Slog.i(TAG, "LocationManager");  
  3.                 location = new LocationManagerService(context);  
  4.                ServiceManager.addService(Context.LOCATION_SERVICE, location);  
  5.             } catch (Throwable e) {  
  6.                 reportWtf("startingLocation Manager", e);  
  7.            }  

 

 

這裏new了一個LocationManagerService對象,而且添加了這個service。

而後finalLocationManagerService locationF = location;

 

[html]  view plain copy
 
 
  1. try {  
  2.                     if (locationF != null)locationF.systemReady();  
  3.                 } catch (Throwable e) {  
  4.                     reportWtf("makingLocation Service ready", e);  
  5.                 }  

 

 

當activity manager好了以後就調用了locationF.systemReady();函數了。

下面進LocationManagerService.java中的system函數。

 

[html]  view plain copy
 
 
  1. voidsystemReady() {  
  2.         // we defer starting up the service untilthe system is ready  
  3.         Thread thread = new Thread(null, this,"LocationManagerService");  
  4.         thread.start();  
  5.     }  

 

 

這裏建立了一個線程,而後線程啓動了,接着他會調用run方法。也就是

 

[html]  view plain copy
 
 
  1. publicvoid run()  
  2.     {  
  3.         Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
  4.         Looper.prepare();  
  5.         mLocationHandler = newLocationWorkerHandler();  
  6.         initialize();  
  7.         Looper.loop();  
  8.     }  

 

 

在run方法中,他會初始化一些東東,也就是initialize();函數了。

 

[html]  view plain copy
 
 
  1. privatevoid initialize() {  
  2.         // Create a wake lock, needs to be donebefore calling loadProviders() below  
  3.         PowerManager powerManager =(PowerManager)  
  4. mContext.getSystemService(Context.POWER_SERVICE);  
  5.         mWakeLock =  
  6. powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,WAKELOCK_KEY);  
  7.    
  8.         // Load providers  
  9.         loadProviders();  
  10. ………………  
  11. ………………  
  12. }  

 

 

這裏主要看loadProviders();函數。

 

[html]  view plain copy
 
 
  1. privatevoid loadProviders() {  
  2.         synchronized (mLock) {  
  3.             if (sProvidersLoaded) {  
  4.                 return;  
  5.             }  
  6.    
  7.             // Load providers  
  8.             loadProvidersLocked();  
  9.             sProvidersLoaded = true;  
  10.         }  
  11.     }  

 

 

這裏又會調用loadProvidersLocked(),而後是_loadProvidersLocked()函數。其中就會調用到咱們須要的gpsprovider了。

 

[html]  view plain copy
 
 
  1. if(GpsLocationProvider.isSupported()) {  
  2.             // Create a gps location provider  
  3.             GpsLocationProvider gpsProvider =new GpsLocationProvider(mContext, this);  
  4.             mGpsStatusProvider =gpsProvider.getGpsStatusProvider();  
  5.             mNetInitiatedListener =gpsProvider.getNetInitiatedListener();  
  6.             addProvider(gpsProvider);  
  7.             mGpsLocationProvider = gpsProvider;  
  8.         }  

 

 

在new一個GpsLocationProvider的時候會開一個GpsLocationProviderThread的線程

 

[html]  view plain copy
 
 
  1. mThread =new GpsLocationProviderThread();  
  2. mThread.start();  

 

 

而後啓動了線程,在這裏會初始化,而後主要仍是new了一個ProviderHandler的類。

         

[html]  view plain copy
 
 
  1. initialize();  
  2.          mHandler = new ProviderHandler();  

 

 

這個類中

 

[html]  view plain copy
 
 
  1. publicvoid handleMessage(Message msg) {  
  2.             int message = msg.what;  
  3.             switch (message) {  
  4.                 case ENABLE:  
  5.                     if (msg.arg1 == 1) {  
  6.                         handleEnable();  
  7.                     } else {  
  8.                         handleDisable();  
  9.                     }  
  10.                     break;  
  11.                 case ENABLE_TRACKING:  
  12.                    handleEnableLocationTracking(msg.arg1 == 1);  
  13.                     break;  
  14.                 case REQUEST_SINGLE_SHOT:  
  15.                     handleRequestSingleShot();  
  16.                     break;  
  17.                 case UPDATE_NETWORK_STATE:  
  18.                    handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj);  
  19.                     break;  
  20.                 case INJECT_NTP_TIME:  
  21.                     handleInjectNtpTime();  
  22.                     break;  
  23.                 case DOWNLOAD_XTRA_DATA:  
  24.                     if (mSupportsXtra) {  
  25.                         handleDownloadXtraData();  
  26.                     }  
  27.                     break;  
  28.                 case UPDATE_LOCATION:  
  29.                    handleUpdateLocation((Location)msg.obj);  
  30.                     break;  
  31.                 case ADD_LISTENER:  
  32.                     handleAddListener(msg.arg1);  
  33.                     break;  
  34.                 case REMOVE_LISTENER:  
  35.                    handleRemoveListener(msg.arg1);  
  36.                     break;  
  37.             }  

 

 

就會處理不少事情了。具體能夠看上面的代碼。

接着他調用了updateProvidersLocked();這個函數。

updateProviderListenersLocked(name,true);

而後就啓動了gps服務了

 

[html]  view plain copy
 
 
  1. if (enabled) {  
  2.             p.enable();  
  3.             if (listeners > 0) {  
  4.                p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource);  
  5.                 p.enableLocationTracking(true);  
  6.             }  
  7.         }  

 

 

接着咱們開始往GpsLocationProvide.java這裏看

 

[html]  view plain copy
 
 
  1. public void enable() {  
  2.         synchronized (mHandler) {  
  3.             sendMessage(ENABLE, 1, null);  
  4.         }  
  5.     }  

 

 

這裏發送了一個ENABLE消息,而後就會調用到上面ProviderHandler的函數,handleEnable();

 

[html]  view plain copy
 
 
  1. privatevoid handleEnable() {  
  2.        ……  
  3.         mEnabled = native_init();  
  4.    
  5.         if (mEnabled) {  
  6.             mSupportsXtra =native_supports_xtra();  
  7.        ……  
  8.     }  

 

 

這裏就會調用到了jni的native函數了。

而native的全部函數,在jni中咱們都已經分析過了。

接着即是

 

enable函數結束後,那即是

 

[html]  view plain copy
 
 
  1. publicvoid enableLocationTracking(boolean enable) {  
  2.         // FIXME - should set a flag here to avoidrace conditions with single shot request  
  3.         synchronized (mHandler) {  
  4.             sendMessage(ENABLE_TRACKING,(enable ? 1 : 0), null);  
  5.         }  
  6.     }  

 

 

一樣,他也發送了ENABLE_TRACKING的消息,接着調用

 

[html]  view plain copy
 
 
  1. handleEnableLocationTracking(msg.arg1== 1);  
  2. if (enable) {  
  3.             mTTFF = 0;  
  4.             mLastFixTime = 0;  
  5.             startNavigating(false);  
  6.         }  

 

 

接着調用了startNavigating函數,

 

[html]  view plain copy
 
 
  1. privatevoid startNavigating(boolean singleShot) {  
  2.        ……  
  3.  if (!native_set_position_mode(mPositionMode,GPS_POSITION_RECURRENCE_PERIODIC,  
  4.     interval, 0, 0)) {  
  5.                 mStarted = false;  
  6.                 Log.e(TAG,"set_position_mode failed in startNavigating()");  
  7.                 return;  
  8.    }  
  9.     if(!native_start()) {  
  10.          mStarted = false;  
  11.          Log.e(TAG, "native_start failedin startNavigating()");  
  12.         return;  
  13.     ……  
  14.    }  
  15. }  

 

 

這裏主要仍是設置position mode,而後啓動了。

接下來,咱們看看,jni調用的一些callback函數在這裏作了些什麼。

首先就是reportLocation函數了。

 

[html]  view plain copy
 
 
  1. privatevoid reportLocation(int flags, double latitude, double longitude, doublealtitude,  
  2.             float speed, float bearing, floataccuracy, long timestamp) {  
  3.         …………  
  4.         synchronized (mLocation) {  
  5.             mLocationFlags = flags;  
  6.             if ((flags &LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {  
  7.                mLocation.setLatitude(latitude);  
  8.                mLocation.setLongitude(longitude);  
  9.                 mLocation.setTime(timestamp);  
  10.             }  
  11.             if ((flags &LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {  
  12.                 mLocation.setAltitude(altitude);  
  13.             } else {  
  14.                 mLocation.removeAltitude();  
  15.             }  
  16.             if ((flags &LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {  
  17.                 mLocation.setSpeed(speed);  
  18.             } else {  
  19.                 mLocation.removeSpeed();  
  20.             }  
  21.             if ((flags &LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {  
  22.                 mLocation.setBearing(bearing);  
  23.             } else {  
  24.                 mLocation.removeBearing();  
  25.             }  
  26.             if ((flags & LOCATION_HAS_ACCURACY) ==LOCATION_HAS_ACCURACY) {  
  27.                mLocation.setAccuracy(accuracy);  
  28.             } else {  
  29.                 mLocation.removeAccuracy();  
  30.             }  
  31.    
  32.             try {  
  33.                 mLocationManager.reportLocation(mLocation,false);  
  34.             } catch (RemoteException e) {  
  35.                 Log.e(TAG,"RemoteException calling reportLocation");  
  36.             }  
  37.         }  
  38.    
  39.         mLastFixTime =System.currentTimeMillis();  
  40.         // report time to first fix  
  41.         if (mTTFF == 0 && (flags &LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {  
  42.             mTTFF = (int)(mLastFixTime -mFixRequestTime);  
  43.             if (DEBUG) Log.d(TAG, "TTFF:" + mTTFF);  
  44.    
  45.             // notify status listeners  
  46.             synchronized(mListeners) {  
  47.                 int size = mListeners.size();  
  48.                 for (int i = 0; i size;i++) {  
  49.                     Listener listener =mListeners.get(i);  
  50.                     try {  
  51.                        listener.mListener.onFirstFix(mTTFF);  
  52.                     } catch (RemoteException e){  
  53.                         Log.w(TAG,"RemoteException in stopNavigating");  
  54.                        mListeners.remove(listener);  
  55.                         // adjust for size oflist changing  
  56.                         size--;  
  57.                     }  
  58.                 }  
  59.             }  
  60.         }  
  61.    
  62.         if (mSingleShot) {  
  63.             stopNavigating();  
  64.         }  
  65.         if (mStarted && mStatus !=LocationProvider.AVAILABLE) {  
  66.             // we want to time out if we do notreceive a fix  
  67.             // within the time out and we arerequesting infrequent fixes  
  68.             if(!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval <NO_FIX_TIMEOUT) {  
  69.                mAlarmManager.cancel(mTimeoutIntent);  
  70.             }  
  71.    
  72.             // send an intent to notify that the GPSis receiving fixes.  
  73.             Intent intent = newIntent(LocationManager.GPS_FIX_CHANGE_ACTION);  
  74.            intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);  
  75.             mContext.sendBroadcast(intent);  
  76.            updateStatus(LocationProvider.AVAILABLE, mSvCount);  
  77.         }  
  78.    
  79.        if(!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&mFixInterval > 1000) {  
  80.             if (DEBUG) Log.d(TAG, "gotfix, hibernating");  
  81.             hibernate();  
  82.         }  
  83.    }  

 

 

這裏對於jni層獲取的數據,作了處理後,更新了location信息。

其中下面這些都是給應用層的接口。

 

[html]  view plain copy
 
 
  1.            mLocation.setLatitude(latitude);  
  2. Location.setLongitude(longitude);  
  3. mLocation.setTime(timestamp);  

 

 

Ok,那麼framwork層就介紹到這裏了。

 

 

 

10、android GPS的APP層

首先看流程:

 

接上面的framework層,這裏調用了mLocation是new了一個Location的類,這個類主要是給應用層接口的。

 

[html]  view plain copy
 
 
  1. if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {  
  2.                mLocation.setLatitude(latitude);  
  3.                mLocation.setLongitude(longitude);  
  4.                 mLocation.setTime(timestamp);  
  5.             }  

 

 

其代碼在frameworks/base/location/java/android/location/Location.java

取其中一部分的函數作下簡單的介紹。

 

[html]  view plain copy
 
 
  1. /**  
  2.  * Sets the UTC time of this fix, inmilliseconds since January 1,  
  3.  * 1970.  
  4.  */  
  5. public void setTime(long time) {  
  6.     mTime = time;  
  7. }  
  8.   
  9. /**  
  10.  * Returns the latitude of this fix.  
  11.  */  
  12. public double getLatitude(){  
  13.     return mLatitude;  
  14. }  
  15.   
  16. /**  
  17.  * Sets the latitude of this fix.  
  18.  */  
  19. public void setLatitude(double latitude) {  
  20.     mLatitude = latitude;  
  21. }  
  22.   
  23. /**  
  24.  * Returns the longitude of this fix.  
  25.  */  
  26. public double getLongitude() {  
  27.     return mLongitude;  
  28. }  
  29.   
  30. /**  
  31.  * Sets the longitude of this fix.  
  32.  */  
  33. public void setLongitude(double longitude){  
  34.     mLongitude = longitude;  
  35. }  

 

 

mLocation.setLatitude(latitude);函數就會把

mLatitude= latitude;

而後,應用層只要getLatitude()就知道了緯度了。

其餘的函數接口相似。

簡單看下下面的一段應用層的代碼

功能:展現GPS信息

 

 

[html]  view plain copy
 
 
  1. private void updateToNewLocation(Locationlocation)  
  2.    {       
  3.    
  4.      if (location != null)  
  5.      {           
  6.       bear = location.getBearing(); //偏離正北方的度數  
  7.       double latitude =location.getLatitude();      //維度  
  8.       double longitude=location.getLongitude();     //經度  
  9.       double GpsSpeed = location.getSpeed(); //速度  
  10.       long GpsTime = location.getTime(); //時間  
  11.       Date date = new Date(GpsTime);  
  12.       DateFormat df = newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
  13.        
  14.       float GpsAlt =(float)location.getAltitude();  //海拔  
  15.       latitudeview.setText("" +latitude);  
  16.       longitudeview.setText("" +longitude);  
  17.       speedview.setText(""+GpsSpeed);  
  18.      timeview.setText(""+df.format(date));  
  19.      altitudeview.setText(""+GpsAlt);  
  20.       bearingview.setText(""+bear);  
  21.       }  
  22.       else  
  23.       {     
  24.        Toast.makeText(this, "沒法獲取地理信息", Toast.LENGTH_SHORT).show();  
  25.       }  
  26.    
  27. }  

 

 

終於,從衛星信號到android APP層獲取到數據那個簡單的數據流程分析好了。要想更加細緻的瞭解其機制,仍是得須要花更多的時間繼續深刻下去的。其中還有不少的細節,不少概念都不是很明白。只知道個大概。不過經過此次分析,收穫很多。凡事都須要從總體到部分再到整理,從整理的GPS框架,到分紅不少塊理解,再把那些模塊整合在一塊兒,從而瞭解其整個機制。

相關文章
相關標籤/搜索