Android 串口通信開發(fā)筆記3:CMake 方式實(shí)現(xiàn)和 多對(duì)多的實(shí)現(xiàn)邏輯

上一篇:Android 串口通信筆記2 調(diào)試工具分析 工具類實(shí)現(xiàn)分析、項(xiàng)目實(shí)現(xiàn)
Android串口開發(fā) 延伸和擴(kuò)展,
1.使用JNI Cmake 自己編譯串口通信 的so庫(kù):Android Studio 3.0 實(shí)現(xiàn)方式。
2.CRC校驗(yàn) 以及擴(kuò)展設(shè)計(jì):

a.一(串口)對(duì)多(硬件通信);
b.多(串口)對(duì)多(硬件)的實(shí)現(xiàn)。

1.以串口調(diào)試工具為例,使用其原本的源代碼使用JNI Cmake Android Studio 3.0 實(shí)現(xiàn)方式。

creat project

勾選 include C++ support 沒有下載ndk 的要下載。

①.延續(xù)使用jni 的方式


image.png

把相關(guān)的 been 和實(shí)現(xiàn)方法 都復(fù)制過(guò)來(lái)如圖。

創(chuàng)建.h 文件 注:一定要現(xiàn)進(jìn)入到app/main/java/ 目錄下

然后 javah -classpath -jni +完整路徑到類名

image.png

在main目錄下創(chuàng)建jni 文件夾,把生成的.h 文件復(fù)制進(jìn)去 ,新建同名的.c文件,把實(shí)現(xiàn)代碼拷進(jìn)去--注意需要修改 open 和close方法的名字 和.h 文件里改為一致。

.c.png

這是.h 文件的

image.png

修改 cmakelist.txt 中 add_library 的so文件名 和路徑

add_library( # Sets the name of the library.
  # 設(shè)置so文件名稱.
   serial_port

   # Sets the library as a shared library.
   SHARED
   # 設(shè)置這個(gè)so文件為共享.

   # Provides a relative path to your source file(s).
   # 設(shè)置這個(gè)so文件為共享.
   src/main/jni/com_silencefun_comtest_serialport_SerialPort.c)
// .......省略注釋部分
  target_link_libraries( # Specifies the target library.
        # 制定目標(biāo)庫(kù).
        serial_port

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib} )

注: “serial_port” 這個(gè) so庫(kù)名稱要和你要加載的要保持一致
在SerialPortJava類中,

image.png

在app的build.gradle中 defaultConfig中配置生成平臺(tái)so包

  defaultConfig {
    applicationId "com.silencefun.comtest"
    minSdkVersion 19
    targetSdkVersion 26
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    externalNativeBuild {
        cmake {
            cppFlags ""
            //生成多個(gè)版本的so文件
            abiFilters 'arm64-v8a','armeabi-v7a','x86','x86_64'
        }
    }
}

然后 同步,build-make project 執(zhí)行完畢之后切換視圖

如圖已經(jīng)生成了so:

image.png

②直接使用cmake方式 不得不說(shuō)新支持方式的簡(jiǎn)單了好多。

創(chuàng)建完支持C的項(xiàng)目后,

在需要調(diào)用java 的Native 類中聲明方法,其實(shí)還是直接復(fù)制SerialPort把加載的so 文件名字改一下:


image.png

直接在自動(dòng)生成的Native-lib.c中完善實(shí)現(xiàn) (其他都不用改,方便快捷)

把 原來(lái).c文件中的實(shí)現(xiàn)方法 直接拷過(guò)去然后修改方法名:
注意 要對(duì)應(yīng)好路徑


image.png
出現(xiàn)問(wèn)題反思:采

用jni方式在Android 5.1的板子沒有問(wèn)題 換到4.4結(jié)果就不行 總是 LOGE("tcgetattr() failed");

后來(lái) 更新ndk 、cmake、 LLDB到最新,完全解決問(wèn)題。

github 地址歡迎 star?

https://github.com/silencefun/ComTest/tree/master/AndroidStuido_3.0_COMTEST

2.擴(kuò)展設(shè)計(jì):一(串口)對(duì)多(硬件通信)、多(串口)對(duì)多(硬件)的實(shí)現(xiàn)。

因?yàn)?有些智能終端硬件限制有些可能只開放一個(gè)通信口來(lái)接多個(gè)硬件模塊數(shù)據(jù),當(dāng)然前提是 掛在這一個(gè)通信口上的 硬件模塊 是在同一波特率,因?yàn)榇蜷_初始化的時(shí)候已經(jīng)設(shè)定好了波特率(嘗試動(dòng)態(tài)更改,不太理解底層實(shí)現(xiàn)過(guò)程代碼,屢敗屢試,最終放棄)。

相似的某些硬件模塊要采集的數(shù)據(jù)可能是多條數(shù)據(jù)(多個(gè)命令下返回多條數(shù)據(jù) 最后在封裝)所以設(shè)定一個(gè)【命令組】的概念:把硬件模塊對(duì)應(yīng)的命令放進(jìn)一個(gè)數(shù)組或者list中。

命令組,即 該硬件所需要的數(shù)據(jù)是需要連續(xù)發(fā)送一組 若干個(gè)命令,根據(jù)接收到的多條數(shù)據(jù)來(lái)解析--- 此處只是解析方式不同,可以根據(jù)每次傳遞標(biāo)志位來(lái)區(qū)分,待所有所需所有數(shù)值都有,即執(zhí)行一輪次之后 完全解析再更新數(shù)據(jù)。

同理多串口情況下就是多個(gè)通信串口,每一個(gè)口上邊都掛了N(N>=1)個(gè)硬件模塊(當(dāng)然這么殘暴的情形是有的:比如波特率不同必須多個(gè)串口)。

在之前一篇筆記中 Android 串口通信筆記2 的SerialHelper,即控制類---每個(gè)硬件串口對(duì)象的管理控制實(shí)例 中添加 相應(yīng)的 成員變量 來(lái)區(qū)分 目前 具體是哪一個(gè) 硬件模塊 的哪一個(gè)命令 響應(yīng)的 值。

所以對(duì)應(yīng)的 封裝 讀取到的 信息 也要添加上 當(dāng)前 對(duì)應(yīng)的 命令 和硬件 模塊標(biāo)志。

Combean 添加字段

private String scmd = "";
private String sflag = "";

對(duì)應(yīng)的 硬件模塊 數(shù)據(jù)結(jié)構(gòu)大概可以:

MeterInfo 
private String name;//名稱
private String modenname;//型號(hào)
private String modertype;//類型
private List<String>  cmdlist;//發(fā)送命令
private String cleandatacmd;//清除命令
private String decimal;//小數(shù)位置 (可能解析能用到)
private String portname;//port路徑 類似 /dev/ttys1
private String sFlag;//flag 可取 模塊name

SerialHelper 類要在原有基礎(chǔ)之上 添加 部分字段

....
private String scmd = "";
private String sflag = "";
private List<MeterInfo> meterlist = new ArrayList<>(); //一個(gè)串口肯能要和多個(gè) 硬件通信
.....

所以初始化串口控制類SerialHelper的實(shí)例時(shí)候,要先set List<MeterInfo> ,
 在send 命令線程中,兩層循環(huán):

for (int i = 0; i < meterlist .size(); i++) {
        List<String> cmdlist = meterlist .get(i).getGetdatacmdlist();

         for (int j = 0; j < cmdlist.size(); j++) {
                 setHexLoopData(cmdlist.get(j));
                  setSflag(meterlist .get(i).getsFlag());
                   setScmd(cmdlist.get(j));
                        //設(shè)定兩次的時(shí)間間隔
                   setTimespace(meterlist .get(i));
                    send(getbLoopData());//發(fā)送命令
                  try {
                    Thread.sleep(iDelay);
                   } catch (InterruptedException e) {
                     e.printStackTrace();
                   }
           }
  }

對(duì)應(yīng)的在 發(fā)送線程發(fā)送后 發(fā)送線程sleep 的時(shí)候 ,讀的線程一直在跑,讀取到數(shù)據(jù) 封裝Combean 對(duì)象:

int size = mInputStream.read(buffer);
       if (size > 0) {
         ComBean ComRecData = new ComBean(sPort, buffer, size);
         ComRecData.setScmd(scmd);
         ComRecData.setSflag(sflag);
         onDataReceived(ComRecData); //調(diào)用抽象方法傳遞
       }

這樣在業(yè)務(wù)處理部分實(shí)現(xiàn) onDataReceived 方法時(shí)候就能判斷是哪個(gè)模塊哪個(gè)命令對(duì)應(yīng)的值。

關(guān)于CRC校驗(yàn):

   /**
 * 獲取 crc校驗(yàn)碼
 *
 * @param hextext 16進(jìn)制
 * @return 低位高位順序
 */
public static String getCrc16(String hextext) {
    byte[] arr_buff = SerialFunc.HexToByteArr(hextext);

    int len = arr_buff.length;

    // 預(yù)置 1 個(gè) 16 位的寄存器為十六進(jìn)制FFFF, 稱此寄存器為 CRC寄存器。
    int crc = 0xFFFF;
    int i, j;
    for (i = 0; i < len; i++) {
        // 把第一個(gè) 8 位二進(jìn)制數(shù)據(jù) 與 16 位的 CRC寄存器的低 8 位相異或, 把結(jié)果放于 CRC寄存器
        crc = ((crc & 0xFF00) | (crc & 0x00FF) ^ (arr_buff[i] & 0xFF));
        for (j = 0; j < 8; j++) {
            // 把 CRC 寄存器的內(nèi)容右移一位( 朝低位)用 0 填補(bǔ)最高位, 并檢查右移后的移出位
            if ((crc & 0x0001) > 0) {
                // 如果移出位為 1, CRC寄存器與多項(xiàng)式A001進(jìn)行異或
                crc = crc >> 1;
                crc = crc ^ 0xA001;
            } else
                // 如果移出位為 0,再次右移一位
                crc = crc >> 1;
        }
    }
    String c = Integer.toHexString(crc);
    if (c.length() == 4) {
        c = c.substring(2, 4) + c.substring(0, 2);
    } else if (c.length() == 3) {
        c = "0" + c;
        c = c.substring(2, 4) + c.substring(0, 2);
    } else if (c.length() == 2) {
        c = "0" + c.substring(1, 2) + "0" + c.substring(0, 1);
    }
    return c.toUpperCase();
}

Android 串口通信開發(fā)筆記01

Android 串口通信筆記2 調(diào)試工具分析 工具類實(shí)現(xiàn)分析、項(xiàng)目實(shí)現(xiàn)
Android 串口通信開發(fā)筆記3:CMake 方式實(shí)現(xiàn)和 多對(duì)多的實(shí)現(xiàn)邏輯
Android 串口開發(fā) 支持N-8-1(數(shù)據(jù)位停止位校驗(yàn)方式) 設(shè)定

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,048評(píng)論 25 709
  • 前言: 最近在總是看見有人在群里面問(wèn)一些串口通信相關(guān)的問(wèn)題,特別是對(duì)于我們這些做APP出生的程序員來(lái)說(shuō),初次接觸串...
    Roy88閱讀 37,775評(píng)論 30 37
  • 大學(xué)的時(shí)候,幫朋友寫的操作系統(tǒng)調(diào)研的作業(yè),最近整理過(guò)去的文檔時(shí)候偶然發(fā)現(xiàn),遂作為博客發(fā)出來(lái)。 從串口驅(qū)動(dòng)到Linu...
    free_will閱讀 7,685評(píng)論 7 59
  • 原創(chuàng)/氧氣是個(gè)地鐵(大夢(mèng)) 需要嗎?不需要嗎? 需要,同時(shí)也不需要。這并不是兩個(gè)對(duì)立的結(jié)論,而是一個(gè)過(guò)程的兩種形式...
    氧氣是個(gè)地鐵閱讀 1,580評(píng)論 0 0
  • 好想好想感謝司徒。那天和司徒聊完後,更體會(huì)到佛法的精妙,也愈發(fā)渴望親近佛法。自那天起,每天把大部分時(shí)間放在思維觀察...
    Tsangce閱讀 348評(píng)論 0 0

友情鏈接更多精彩內(nèi)容