1. 程式人生 > >谷歌Android開源串列埠通訊使用

谷歌Android開源串列埠通訊使用

Demo下載地址:
谷歌官方串列埠庫使用

引言:

現在的串列埠通訊多用於嵌入裝置中,Android主機板與各種板卡之間的通訊。因此串列埠通訊在未來智慧裝置中應用會很廣泛。

現在市面上幾乎所有的Android串列埠通訊庫都是用的Google開源的https://github.com/cepr/android-serialport-api封裝而成。
但是很多第三方庫質量參差不齊,出了問題也不知道是什麼原因。因此自己基於官方公佈.so來封裝串列埠庫就顯得猶為重要。

  • 下載Goolgle官方串列埠庫工程

前往https://github.com/cepr/android-serialport-api

下載示例工程,並解壓。會看到有兩個資料夾,一個為android-sercd,一個為android-serialport-api。
這裡寫圖片描述
這裡寫圖片描述

  • 新建自己的串列埠庫使用工程

新建自己的工程,如GoogleSerialDemo,將上圖android-serialport-api->project->libs資料夾下的三個.so資料夾拷到自己工程的libs目錄下。
這裡寫圖片描述

拷貝後:
這裡寫圖片描述

  • 配置自己的工程

雙擊android-serialport-api資料夾,進入project->src,這時你會發現又有一個android-serialport-api資料夾。
這裡寫圖片描述

讓我們來看看這個資料夾下的內容是什麼?
這裡寫圖片描述

該資料夾包含了寫好的SerialPort.java類及SerialPortFinder.java類,這兩個類的作用是提供應用呼叫底層串列埠C++程式碼的介面,而且完全是官方程式碼,因此不用擔心被坑。
sample資料夾則是串列埠示例程式碼。
將這個android-serialport-api資料夾整個拷到自己工程下的src->main->java目錄下。這時可能你有疑問了,我們需要的是SerialPort.java和SerialPortFinder.java這兩個類,為什麼要將整個資料夾一起拷過來?
這也是很多部落格沒有提及的。


原因其實也很簡單,熟悉jni的都知道,jni呼叫是需要嚴格對應應用的包名的。而我們需要呼叫的是Google寫好的C++程式碼,這些程式碼已經封裝在.so庫中,其包名已經確定了的。我們需要使用就必須知道其包名,其包名就是android_serialport_api。因此使用到jni的SerialPort.java和SerialPortFinder.java類必須要在android_serialport_api目錄下。
這裡寫圖片描述

拷貝過來後我們可以把目錄下的sample刪除掉以減少記憶體佔用。然後開啟工程我們就多了一個android_serialport_api的目錄。
這裡寫圖片描述

要使用串列埠還需要一步,還記得之前拷的那些.so的資料夾嗎?這一步就需要在build.gradle的defaultConfig下面加入以下程式碼,注意是跟defaultConfig同級的,不是在defaultConfig聲明裡面。

sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

這裡寫圖片描述

  • 使用串列埠庫

到了這一步就可以愉快地使用串列埠庫了,再也不用擔心第三方串列埠庫封裝出現的bug了。這裡提供一個封裝的基類供參考。

package com.mhwang.goolgleserialdemo;

import android.util.Log;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;

import android_serialport_api.SerialPort;

/**
 * Description : 串列埠通訊基類,定義串列埠通訊的常量及操作方法
 * Author :mhwang
 * Date : 2018/6/14
 * Version : V1.0
 */

abstract class BaseSerialPort {

    InputStream mInputStream = null;
    OutputStream mOutputStream = null;
    SerialPort mSerialPort = null;
    Map<String,String> mSerialMap;

    abstract public boolean write(String data);
    abstract public boolean write(byte[] data);
    abstract public String receive();
    abstract public byte[] receiveBytes();
    abstract public boolean open();
    abstract public boolean close();

    /** 讀取資料
     * @param inputStream 串列埠物件
     * @return byte[]陣列,若沒有,返回null
     */
    byte[] readData(InputStream inputStream){
//        // 暫停200毫秒以等待資料返回       有些串列埠延遲會出現粘包,比如門卡板,因此根據實際情況新增
//        SystemClock.sleep(200);
        int size;
        try {
            if (inputStream == null) {
                showLog("inputStream is null");
                return null;
            }
            byte[] buffer = new byte[256];
            size = inputStream.read(buffer);
            byte[] data = new byte[size];
            System.arraycopy(buffer,0,data,0,size);
            if (size > 0) {
                return data;
            }else{
                showLog("receive no data");
            }
        }catch (Exception e){
            showLog(e.toString());
        }
        return null;
    }

    /** 開啟串列埠
     * @param device 要開啟的串列埠檔案
     * @param baudrate 波特率
     * @param flag 標誌
     * @return true,開啟成功,false,開啟失敗
     */
    boolean openSerialPort(File device, int baudrate, int flag){
        try {
            mSerialPort = new SerialPort(device, baudrate, flag);
            mInputStream = mSerialPort.getInputStream();
            mOutputStream = mSerialPort.getOutputStream();
        } catch (IOException e) {
            mInputStream = null;
            mOutputStream = null;
            e.printStackTrace();
            return false;
        }

        if (mInputStream == null || mOutputStream == null) return false;

        return true;
    }

    boolean closeSerialPort(){      // 這裡不做事情是因為有時應用頻繁開啟關閉會使得再次開啟串列埠收不到訊息
//        try {
//            if (mInputStream != null){
//                mInputStream.close();
//                mInputStream = null;
//            }
//            if (mOutputStream != null){
//                mOutputStream.close();
//                mOutputStream = null;
//            }
//            if (mSerialPort != null){
//                mSerialPort.close();
//                mSerialPort = null;
//            }
//        }catch (Exception e){
//            FileUtil.writeNote("BaseSerialPort-->"+ AppError.SERIAL_CLOSE_FAIL+e.toString());
//            return false;
//        }

        return true;
    }

    private void showLog(String s) {
        Log.d("BaseSerialPort-->",s);
    }
}