施月玲,宣 凱,張海平,孫志海
(1.杭州電子科技大學計算機學院,浙江 杭州310018;2.杭州電子科技大學信息工程學院,浙江 杭州310018)
現代公安應急通信系統具有通話頻次高、位置相對固定、多方同時接聽等特點,對講機很好地適應了這些特點,并占了絕對地位[1]。但公安集群網絡主要覆蓋中心城市,覆蓋不到偏遠地區,出現很多盲區,不能完全滿足工作需要。本文利用移動通信公網覆蓋范圍廣的特點,實現對講機與Android系統融合,利用后臺調度系統,將集群網絡的盲區用3G 網絡來彌補,當終端處于無集群網絡信號時,仍然能接收集群網絡的對講語音信息。
終端設備安裝Android 主板,采用TI的A8 芯片,軟件平臺為Android 2.3.4系統,此外加裝了公安部專用集群對講板,支持MPT1327 信令,具有集群對講功能和常規對講功能兩種;對講板與Android 主板之間通過20Pin的軟排線相連作為實時通信接口。
終端以集群對講功能為主(常規與3G 對講功能為輔),由于集群網絡范圍有限,當終端脫離集群網絡時將自動(或手動)切換到3G 對講模式,通過后臺系統實現終端在3G 下與集群網絡語音的轉發,用戶體驗如同一直在集群網絡狀態,當終端檢測到集群網絡范圍時,將自動(或手動)切換回集群(常規)APP。在特殊場合還能啟用對講機的常規對講功能,實現同頻對講。
終端融合軟件層次結構如圖1所示,主要包括Linux層應用、SERVICE 程序、集群(常規)APP 三個部分。功能主要為:1)Linux層應用。與對講板硬件直接交互,通過SERVICE控制集群(常規)APP與3G 對講APP 進行切換;通過與集群(常規)APP的交互,實現集群撥號,守候組切換等各種控制;當上層APP 崩潰后自啟動時,切換相關音頻線路與按鍵控制權,確保產品能作為普通對講機使用。2)SERVICE程序。負責與Linux層應用、集群(常規)APP以及3G 對講APP 交互,實現自動或者手動模式切換;當集群(常規)APP 或者3G 對講APP 崩潰后再次啟動APP。3)集群(常規)APP。與Linux層應用交互、顯示對講機狀態、設置各種參數以及提供撥號界面并將撥號信息傳給Linux層應用操作對講板撥號。4)3G 對講APP。當集群網絡信號不好,避免丟失語音信息時,替代對講功能(需要后臺系統的支持)。
Android系統在內存資源不足情況下,會結束部分APP以釋放內存。然而作為一個定位在公安通信系統領域的產品,其功能絕對不能完全依托于APP(Android 應用程序),所以在設計時采用分層設計,讓APP 不直接參與硬件控制,即使在使用中發生上層APP 被關閉,對講功能仍能正常使用,使用者仍能像操作普通對講機一樣實現正常通信。
APP 整體框架如圖2所示,其中基于Linux層的*.so 庫文件使用JNI技術進行串口開發,實現上層APP與底層對講板進行交互,交互方式通過AT 指令集來完成。

圖1 融合通信終端架構圖

圖2 JNI 開發架構圖
JNI是Java 本地的調用,可以使Java 同其他編程語言進行交互[1]。Android 編程使用JNI 調用C/C++語言編寫的代碼,實現同用戶專門定制的硬件進行交互,或是執行一些更為復雜、耗時的操作,從而提高程序的執行效率。編程時在程序中加載對應的鏈接庫,然后使用鏈接庫中定義的方法。
本地方法是以庫的形式存放(Windows系統中為*.dll 文件的形式,在Unix 機器上是*.so 文件的形式)。調用本地的庫文件包含的方法,讓Java可以實現與本地機器的緊密聯系,從而調用系統級接口方法。
利用Java 同本地已編譯的代碼進行交互,會影響平臺可移植性,但有些情況下必須要這么做。比如,使用一些舊版本的庫、同硬件或底層操作系統進行交互,或為了提高程序自身的性能。JNI 能確保本地代碼在Java 虛擬機中正常工作。
1)Java層功能。在Java 程序中,首先在類中導入程序執行所需要的鏈接庫,聲明所調用的庫名稱,再對要調用到的方法進行本地聲明,關鍵字為native,只需要進行聲明,不需要其具體的實現,然后編譯Java 程序,生成class 文件,再使用javah 命令,JNI 就會生成對應的C/C++的頭文件。
2)C/C++層功能。對已生成的頭文件,C/C++需要把頭文件中定義的方法進行具體的實現,然后編譯鏈接成庫文件,再把庫文件復制到Java 程序的文件目錄下面,用Java 調用C/C++所實現的方法。在具體實現的時候,主要有以下兩種方法原型:

其中JNIEXPORT和JNICALL 都是JNI的關鍵字,即該函數將被JNI 調用。jint以JNI為中介,讓Java中的int數據類型與本地的int數據類型進行映射,函數的名稱則是“Java”加上java 程序的包名路徑再加上函數名稱組成。
Android NDK的全名是Android Native Development Kit,是Android SDK的補充與完善。Android NDK 用來編譯Android 程序的JNI 代碼部分,生成Android 程序需要的鏈接庫文件。NDK 提供了很多能幫助開發人員快速開發動態庫的工具,能自動將*.so 庫文件和Java 代碼一起打包成APK 文件。
因為Android是基于Linux的操作系統,要對串口進行控制,就需先開發出一個可以在用戶空間執行的程序,使其在Linux系統的文件層對串口設備進行相關的讀寫、控制等操作。
JNI 程序遵循C/C++的語法,但此程序要作為Android 程序的庫文件被Android 應用所調用,所以它的格式需要做一些改變[2]。
2.1.1 打開串口
首先進行波特率通信格式轉換,然后打開設備,獲取串口句柄,保存全局串口描述符,清除輸入輸出緩沖區,接著配置設備,把終端屬性設置成原始屬性,設置輸入輸出波特率和串行通信格式,創建一個文件描述符供上層使用[3-4],流程如圖3所示。

圖3 打開串口流程圖
2.1.2 關閉串口
首先將輸入輸出緩沖區清零,然后釋放文件描述符,其流程如圖4所示。
2.1.3 設置串口數據位,停止位和校驗位
數據位為7 或者8,停止位為1 或者2,校驗位取值為N/E/O/S。
2.1.4 直接往串口發送數據
首先將數據轉為C 字節,然后開辟內存空間,拷貝數據,寫入串口,釋放數據,其流程如圖5所示。

圖4 關閉串口流程圖

圖5 串口發送數據流程圖
2.2.1 創建含有本地方法的類
此類中聲明了需要調用的本地方法,其中的方法有打開串口、關閉串口、寫數據、打開或者關閉對講板等功能[5]。格式如下:

2.2.2 生成JNI 頭文件
使用Java的Javah 命令生成一個*.so 頭文件,這個頭文件中給出了以上本地方法在C 語言中的聲明,代碼如下所示:

2.2.3 實現C 程序文件
使用C/C++語言來依次實現以上聲明的方法,實現串口設備的打開、初始化、讀、寫、關閉等操作。
SerialPort.c 中包含了如下內容:
1)波特率通信格式轉換的本地函數getBaudrate(jint baudrate);
2)打開串口的函數SerialPort _open (JNIEnv * env,jobject thiz,jstring path,jint baudrate);
3)關閉串口的函數SerialPort_close (JNIEnv * env,jobject thiz);
4)設置串口數據位、停止位和校驗位的set_Parity(int fd,int databits,int stopbits,int parity);
5)用于控制底層I/O的Serial Port _GPIO (JNIEnv * env,jobject thiz,jint led_nu,jint on);
6)直接往串口發送數據的SerialPort_write (JNIEnv * env,jobject thiz,jstring at);
7)底層設備控制的SerialPort_writeint (JNIEnv * env,jobject thiz,jint onoff)。
本文開發的樣機于2014年8月10日在某市公安局交警大隊進行試用,經過2個月的測試運行,用戶反映本產品軟件界面簡潔、使用方便、功能完善,樣機方便攜帶,運行效果良好,解決了多網通信調度障礙問題。
本文結合對講機與Android系統,利用Android的APP 來控制對講機,交互界面友好。對講功能由APP控制,同時與3G 對講APP 一起實現了多網融合調度,經用戶試用反饋良好,具有較強的工程應用價值。
[1]王林林.基于Android平臺的集群通信系統終端軟件的設計與實現[D].成都:西南交通大學,2012∶6-8.
[2]高海彬.JNI 在Android系統下串口控制的應用[J].信息技術,2013,37(10):173-176.
[3]張譯恬,王純.基于安卓系統JNI 機制的SO 庫加固方案設計[J].電信技術,2014,(10):90-93.
[4]唐建東,盧貴主.嵌入式操作系統Linux中的串口應用編程[J].單片機與嵌入式系統應用,2002,(8):82-84.
[5]龔建偉,熊光明.Visual C++/Turbo C 串口通信編程實踐[M].北京:電子工業出版社,2004:10-63.