加入RUN!PC粉絲團
最近新增的精選文章
 
最多人點閱的精選文章
 
 
精選文章 - 開發技術
分享到Plurk
分享到FaceBook
 
Android車載系統(1)
Android車載裝置驅動程式開發
文/圖 張哲瑜.責任編輯/洪羿漣

車載系統運作的主要核心,是架構於車載硬體之上的車載作業系統。因為有了作業系統,程式開發人員才能夠在車輛上開發各式各樣的服務。本篇文章所要介紹的便是基於Android車載作業系統的OBD裝置程式設計。

近年來Telematics產業蓬勃發展,使得各產業大國紛紛投入車載資通訊之研究與開發,車載資通訊是一種結合資訊、通訊,及汽車電子技術的整合性應用服務,可滿足行車駕駛人對環境的各項需求。

其應用服務如:行車導航服務、地區性服務導引(Location-Based Service)、行車記錄服務、車隊管理系統等。而這些服務可衍生的效益,使得原本汽車產業轉型為以服務為主的移動式服務平台。

以技術而言,車載資通訊包含了硬體與軟體領域。硬體方面如車用運算處理器、車輛控制網路、車輛感知元件、實體通訊網路建置等;軟體方面如車載作業系統建置、車載裝置驅動程式設計、應用服務程式設計等。

總體而言,車載資通訊其實就是一個透過車輛硬體與系統軟體,實現各種車輛創新服務類型的車載系統。

車載系統運作的主要核心,是架構於車載硬體之上的車載作業系統。因為有了作業系統,程式開發人員才能夠在車輛上開發各式各樣的服務。本篇文章所要介紹的便是基於Android車載作業系統的OBD裝置程式設計。


Android解決Linux版本問題
Android為Google所開發的一套基於Linux核心之作業系統,目前廣泛使用於手持平台,如手機、PND等。如今德國一線汽車電子零組件供應商Continental,發表了一款專為汽車設計的AutoLinQ網際網路平台,就是採用Android作業系統。

Android不但承襲Linux的open source理念,並且有效收斂了Linux的程式開發,以前若是要撰寫Linux的系統程式,就需要去煩惱Linux的版本問題,在網路上發布了許多網友自行製作的patch檔,究竟要如何去使用?與自有環境是否有衝突?這些都是讓人頭痛的問題。

如今Google自行維護了一個Linux核心版本,並且在其核心上建置了一套Android Framework,工程師只需要使用Google所提供的SDK,便可很容易的進行程式開發。如此Linux的版本相容問題就交給Google,工程師只需要專心開發程式就好了。


Android On-Board Diagnostic
那什麼又是OBD呢?OBD全名為On-Board Diagnostic,主要是作為行車狀態診斷,現階段的車廠以及修車廠,已使用此技術作為車輛維修的主要依據。

就技術方面,OBD提供了使用者與車輛控制網路的溝通介面,在車輛控制網路裡建置了許多電子控制元件(Electronic Control Unit, ECU)負責偵測各車輛裝置如引擎、水箱、電瓶、車門…等的使用情形,當車輛裝置發生異常時,使用者便能透過OBD介面,檢查各個ECU是否發出錯誤訊息。

要設計Android OBD程式,基本上可以分為2種模式,一種是使用Android的HAL架構撰寫OBD的驅動程式;第二種是直接使用Google所提供的Android NDK撰寫OBD程式,接下來本文章將會針對HAL與NDK程式撰寫做概括性的介紹。


Android OBD程式設計:HAL
HAL全名為Hardware Abstraction Layer也就是硬體抽象層,是Google在Android作業系統新提出的一個操作層,如圖1所示。

圖1:HAL架構圖。(圖片出處:2008 Google I/O Session Videos and Slides)


HAL所在的位置是介於Android Libraries和Linux kernel之間,主要目的就是要將Android的framework與Linux kernel適當的區隔,當Android framework需要任何必須接觸到硬體的功能時,皆透過HAL向底層呼叫,如此一來Android framework便可以在完全不考慮驅動程式的情況下發展。

瞭解了HAL架構後,接下來介紹使用HAL設計OBD驅動程式的流程,如圖2所示。

圖2:HAL動作流程。


在Android裡有關硬體的程式設計是使用Service來實現,Service在Android架構中,是負責聯繫上層的應用程式,以及使用HAL裝置函式庫來存取底層的硬體,因此我們所需要做的,便是實作可以讓Service使用的HAL裝置函式庫,在此我們以Android已經實現的HAL架構的SensorService作進一步講解。


SensorService與HAL模組

由於Google已經釋放Android的原始碼,所以我們可以很容易的從網路上下載原始碼。SensorService模組程式碼是位於:
/frameworks/base/services/java/com/android/server/SensorService.java

以及:
/frameworks/base/service/jni/com_android_server_SensorService.cpp

而HAL模組的程式碼是位於:
/hardware/libhardware/hardware.c
/hardware/libhardware/include/hardware.h

SensorService是由C與JAVA語言所組成的,SensorService.java負責與上層應用程式聯繫,及呼叫com_android_server_SensorService.cpp的輸出函式(Export function),com_android_server_SensorService.cpp負責呼叫HAL模組,而HAL模組則負責呼叫Sensor HAL裝置函式庫。接下來我們用top-down的角度來講解程式重點,首先在SensorService.java的部分程式碼,如下所示:



一開始上層應用程式呼叫SensorService時,便會產生一個SensorService類別的物件,並且執行「native function “_sensors_control_init()”」。此函數實作於com_android_server_SensorService.cpp檔案中,程式碼如下所示:



SensorService在此會呼叫由HAL模組提供的hw_get_module函式,來取得HAL裝置函式庫的操作結構,之後對硬體的所有操作行為,皆會透過此結構所回傳的函式指標來執行。

附帶一提,經由程式碼我們可以發現,Android的native function使用的並非原本JAVA的JNI模式,而是利用一個function mapping table,讓作業系統知道應該呼叫哪一個native function。以本程式為例,當SensorService.java呼叫了_sensors_control_init,系統自然知道必須呼叫android_init這個函式。

至此我們已經大概掌握了SensorService的主要行為,接下來繼續了解當SensorService執行hw_get_module函式時的行為模式。hw_get_module 函式實作於hardware.c,其部分程式碼如下所示:



由此段程式碼可以發現,hw_get_module其實就是做了函式庫(*.so)讀取的動作。依據hw_get_module所輸入的模組名稱,讀取對應的函式庫,並且從函式庫讀取操作結構,將結構指標回傳。

截至目前我們了解了SensorService以及讀取HAL裝置函式庫的動作流程,如果要將之實現到OBD硬體擷取程式,也是同一套概念,接下來就剩下實作HAL裝置函式庫了。


實作HAL裝置

在Android的原始碼已經實作了模擬器的Sensor HAL裝置函式庫,程式碼位於[/development/emulator/sensors/sensors_qemu.c]、[/hardware/libhardware/include/sensors.h],部分程式碼如下:



在上述程式碼中宣告了一個sensors_module_t結構實體,並且命名為HAL_MODULE_INFO_SYM,而需注意的是,此名稱是HAL操作結構的固定名稱,當Service層讀取HAL操作結構時,會讀取此名稱之結構。

而此結構中又包含了一個擁有操作函數「open」的操作結構hw_module_methods_t,如前面所述,此結構就是操作HAL的主要結構,而「open」函數會回傳一個操作結構hw_device_t給Service層,此結構便是提供所有硬體操作函數的結構,所以如果我們要撰寫OBD裝置的擷取程式,便需要去實現一個hw_device_t結構。

如此我們已經將Android的HAL概念介紹完畢,並且也呈現了使用HAL的車載程式之主要架構。接下來我們將介紹另一種較為廣泛使用的設計模式,也就是使用Android NDK來設計車載程式。


Android OBD程式設計:NDK
使用Android NDK來開發車載程式是非常方便的,NDK的主要作法其實跟JAVA的JNI技術相差無幾,只是Android在此技術上增加了自己的編譯機制。在此筆者將講解如何使用Android NDK,做出一個簡單的OBD裝置擷取的概念程式。

首先從Andorid官網下載Android NDK套件並且安裝,安裝的步驟可以參照附件的README.TXT。若順利安裝完成,接著在Android NDK資料夾裡的apps資料夾中,建置一個Android應用程式專案,筆者所使用的建置方式,是使用eclipse的Android元件。但專案建立的方式有很多種,筆者不在此贅述,詳細方法可以參考Android官網的建置方式。

建置完成後,接著在建置的專案資料夾內建立名為jni的資料夾,若是使用eclipse工具,則建置後的畫面如圖3所示。在此畫面裡我們建置了一個OBD專案,並且宣告了讀取OBD資訊的native function,以及讀取OBDopts library,所以當程式執行函數resultFromOBD,便能從車輛讀取OBD資訊。接下來便是要實作OBDopts library的內容。

圖3:OBD專案。


用Android NDK實作library,必須先在專案資料夾下建立application.mk,並撰寫以下內容:



依序所代表的是專案的所在位置,以及所要編譯的模組名稱。編寫完之後,接著要在jni資料夾內,撰寫OBDopts library的程式碼,部分內容如下:



上述程式是jni格式的函式呼叫介面,因此介面的函式名稱必須遵循「Package_class_function()」的規則。撰寫完後接著在jni資料夾內,建立Android.mk,並撰寫以下內容:



依序所代表的是原始碼的所在位置、清除變數值、產生的模組名稱、編譯的檔案名稱、產生的檔案類型,若讀者還需要其他Android的編譯屬性設定,可以參考NDK資料夾的ANDROID-MK.TXT,裡頭有更完整的解說。

一切就緒後,接著開啟Command Line視窗,跳到Android NDK的資料夾底下,輸入「make APP=OBD(OBD為專案名稱)」便可以開始編譯原始碼。若沒有任何錯誤,則在專案的資料夾底下會出現lib資料夾,裡面存放著libOBDopts.so,接著回到eclipse工具下執行Android的應用程式編譯工具,便可順利的產生「*.apk」檔,將之放到模擬器上執行可以得到如圖4的結果。

圖4:OBD專案執行結果。



總結
不久的將來,網路將會是所有人資訊傳遞的主要媒介,而車載資通訊,必定會成為車輛的必備技術。經過以上敘述,我們已經知道了如何使用Android開發車載資通訊程式,使用Android作為車載資通訊的系統平台,不但有眾多的技術資源,更可利用Google所提供各式各樣的服務,達到多樣化的行車生活。





【原文刊載於RUN!PC雜誌:2010年2月號】