Android 串口通信开发笔记3:CMake 方式实现和 多对多的实现逻辑

上一篇:Android 串口通信笔记2 调试工具分析 工具类实现分析、项目实现
Android串口开发 延伸和扩展,
1.使用JNI Cmake 自己编译串口通信 的so库:Android Studio 3.0 实现方式。
2.CRC校验 以及扩展设计:

a.一(串口)对多(硬件通信);
b.多(串口)对多(硬件)的实现。

1.以串口调试工具为例,使用其原本的源代码使用JNI Cmake Android Studio 3.0 实现方式。

creat project

勾选 include C++ support 没有下载ndk 的要下载。

①.延续使用jni 的方式


image.png

把相关的 been 和实现方法 都复制过来如图。

创建.h 文件 注:一定要现进入到app/main/java/ 目录下

然后 javah -classpath -jni +完整路径到类名

image.png

在main目录下创建jni 文件夹,把生成的.h 文件复制进去 ,新建同名的.c文件,把实现代码拷进去--注意需要修改 open 和close方法的名字 和.h 文件里改为一致。

.c.png

这是.h 文件的

image.png

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

add_library( # Sets the name of the library.
  # 设置so文件名称.
   serial_port

   # Sets the library as a shared library.
   SHARED
   # 设置这个so文件为共享.

   # Provides a relative path to your source file(s).
   # 设置这个so文件为共享.
   src/main/jni/com_silencefun_comtest_serialport_SerialPort.c)
// .......省略注释部分
  target_link_libraries( # Specifies the target library.
        # 制定目标库.
        serial_port

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

注: “serial_port” 这个 so库名称要和你要加载的要保持一致
在SerialPortJava类中,

image.png

在app的build.gradle中 defaultConfig中配置生成平台so包

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

然后 同步,build-make project 执行完毕之后切换视图

如图已经生成了so:

image.png

②直接使用cmake方式 不得不说新支持方式的简单了好多。

创建完支持C的项目后,

在需要调用java 的Native 类中声明方法,其实还是直接复制SerialPort把加载的so 文件名字改一下:


image.png

直接在自动生成的Native-lib.c中完善实现 (其他都不用改,方便快捷)

把 原来.c文件中的实现方法 直接拷过去然后修改方法名:
注意 要对应好路径


image.png
出现问题反思:采

用jni方式在Android 5.1的板子没有问题 换到4.4结果就不行 总是 LOGE("tcgetattr() failed");

后来 更新ndk 、cmake、 LLDB到最新,完全解决问题。

github 地址欢迎 star❤

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

2.扩展设计:一(串口)对多(硬件通信)、多(串口)对多(硬件)的实现。

因为 有些智能终端硬件限制有些可能只开放一个通信口来接多个硬件模块数据,当然前提是 挂在这一个通信口上的 硬件模块 是在同一波特率,因为打开初始化的时候已经设定好了波特率(尝试动态更改,不太理解底层实现过程代码,屡败屡试,最终放弃)。

相似的某些硬件模块要采集的数据可能是多条数据(多个命令下返回多条数据 最后在封装)所以设定一个【命令组】的概念:把硬件模块对应的命令放进一个数组或者list中。

命令组,即 该硬件所需要的数据是需要连续发送一组 若干个命令,根据接收到的多条数据来解析--- 此处只是解析方式不同,可以根据每次传递标志位来区分,待所有所需所有数值都有,即执行一轮次之后 完全解析再更新数据。

同理多串口情况下就是多个通信串口,每一个口上边都挂了N(N>=1)个硬件模块(当然这么残暴的情形是有的:比如波特率不同必须多个串口)。

在之前一篇笔记中 Android 串口通信笔记2 的SerialHelper,即控制类---每个硬件串口对象的管理控制实例 中添加 相应的 成员变量 来区分 目前 具体是哪一个 硬件模块 的哪一个命令 响应的 值。

所以对应的 封装 读取到的 信息 也要添加上 当前 对应的 命令 和硬件 模块标志。

Combean 添加字段

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

对应的 硬件模块 数据结构大概可以:

MeterInfo 
private String name;//名称
private String modenname;//型号
private String modertype;//类型
private List<String>  cmdlist;//发送命令
private String cleandatacmd;//清除命令
private String decimal;//小数位置 (可能解析能用到)
private String portname;//port路径 类似 /dev/ttys1
private String sFlag;//flag 可取 模块name

SerialHelper 类要在原有基础之上 添加 部分字段

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

所以初始化串口控制类SerialHelper的实例时候,要先set List<MeterInfo> ,
 在send 命令线程中,两层循环:

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));
                        //设定两次的时间间隔
                   setTimespace(meterlist .get(i));
                    send(getbLoopData());//发送命令
                  try {
                    Thread.sleep(iDelay);
                   } catch (InterruptedException e) {
                     e.printStackTrace();
                   }
           }
  }

对应的在 发送线程发送后 发送线程sleep 的时候 ,读的线程一直在跑,读取到数据 封装Combean 对象:

int size = mInputStream.read(buffer);
       if (size > 0) {
         ComBean ComRecData = new ComBean(sPort, buffer, size);
         ComRecData.setScmd(scmd);
         ComRecData.setSflag(sflag);
         onDataReceived(ComRecData); //调用抽象方法传递
       }

这样在业务处理部分实现 onDataReceived 方法时候就能判断是哪个模块哪个命令对应的值。

关于CRC校验:

   /**
 * 获取 crc校验码
 *
 * @param hextext 16进制
 * @return 低位高位顺序
 */
public static String getCrc16(String hextext) {
    byte[] arr_buff = SerialFunc.HexToByteArr(hextext);

    int len = arr_buff.length;

    // 预置 1 个 16 位的寄存器为十六进制FFFF, 称此寄存器为 CRC寄存器。
    int crc = 0xFFFF;
    int i, j;
    for (i = 0; i < len; i++) {
        // 把第一个 8 位二进制数据 与 16 位的 CRC寄存器的低 8 位相异或, 把结果放于 CRC寄存器
        crc = ((crc & 0xFF00) | (crc & 0x00FF) ^ (arr_buff[i] & 0xFF));
        for (j = 0; j < 8; j++) {
            // 把 CRC 寄存器的内容右移一位( 朝低位)用 0 填补最高位, 并检查右移后的移出位
            if ((crc & 0x0001) > 0) {
                // 如果移出位为 1, CRC寄存器与多项式A001进行异或
                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 串口通信开发笔记01

Android 串口通信笔记2 调试工具分析 工具类实现分析、项目实现
Android 串口通信开发笔记3:CMake 方式实现和 多对多的实现逻辑
Android 串口开发 支持N-8-1(数据位停止位校验方式) 设定

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,398评论 25 707
  • 前言: 最近在总是看见有人在群里面问一些串口通信相关的问题,特别是对于我们这些做APP出生的程序员来说,初次接触串...
    Roy88阅读 37,443评论 30 37
  • 大学的时候,帮朋友写的操作系统调研的作业,最近整理过去的文档时候偶然发现,遂作为博客发出来。 从串口驱动到Linu...
    free_will阅读 7,361评论 7 59
  • 原创/氧气是个地铁(大梦) 需要吗?不需要吗? 需要,同时也不需要。这并不是两个对立的结论,而是一个过程的两种形式...
    氧气是个地铁阅读 1,463评论 0 0
  • 好想好想感謝司徒。那天和司徒聊完後,更體會到佛法的精妙,也愈發渴望親近佛法。自那天起,每天把大部分時間放在思維觀察...
    Tsangce阅读 184评论 0 0