zoukankan      html  css  js  c++  java
  • JNA操作sdk的指导手册

    JNI与JNA对比

    JNI介绍

    最开始,java与sdk相互调用,使用的是JNI技术,操作步骤如图


    步骤如下:

    (A) 用c/c++将已有的sdk进行重新编写(用sun规定的数据结构替代c/c++中的数据结构)
    (B) Java中引入第1步中新编写的sdk
    (C) 编写java native函数作为链接函数中的代理
    (D) 用java调用代理函数

    优点:JNI针对sdk是双向调用。sdk可以调用java的API,java可以调用sdk的API

    缺点:流程繁琐复杂,需要根据sun公司定义的通用数据结构将源sdk重写一遍(用c/c++),实在头疼

    JNA介绍

    正是由于JNI操作sdk太复杂,所以sun公司主导开发了JNA框架,其目的就是为了简化:java调用sdk的步骤

    步骤如下:

    (A) 编写java native函数作为链接函数中的代理
    (B) Java调用代理API

    优点:简单,省去了根据sun规定的通用数据结构重写sdk的步骤

    缺点:单向调用,只有java调用sdk的API,没有sdk调用java的API

    JNA运用

    加载

    windows平台sdk(xxx.dll)加载方法:

    public interface MyLibrary extends Library {
       // 不要写扩展名 MylLibrary INSTANCE
    = Native.load("xxx", MyLibrary.class); }

    linux平台sdk(xxx.so)加载方法:

    public interface MyLibrary extends Library {
       // 要写扩展名 MylLibrary INSTANCE
    = Native.load("xxx.so", MyLibrary.class); }

    类型对应

    回调函数

    sdk代码

    void CALLBACK PDCSSTATUS(
              int DCSID,
              int DeviceStatus,
              int DeviceFault, 
              int *pAmpStatus, 
              int ContactInputOpenFault,
              int ContactInputShortFault
    );

    注意:这里关注【int *pAmpStatus】,这是一个【int指针】,java中用【IntByReference】来做对应。(c/c++中的所有指针类型,JNA中都有对应的xxxByReference与之对应

    java映射代码

    public interface MyLibrary extends Library {
    
        MylLibrary INSTANCE = Native.load("xxx.so", MyLibrary.class);
    
       // 与SDK中的方法对应
    interface PDCSSTATUS extends Callback { void callback(int dcsID, int deviceStatus, int deviceFault, IntByReference pAmpStatus, int contactInputOpenFault, int contactInputShortFault); } }

    java调用

    public class MyTest {
    
        // dcs设备信息回调方法
         static MyLibrary.PDCSSTATUS pdcsstatus = (dcsID, deviceStatus, deviceFault, pAmpStatus, contactInputOpenFault, contactInputShortFault) -> {
           log.info("============================================");
           log.info("callback-dcsId:" + dcsID);
           log.info("callback-deviceStatus:" + deviceStatus);
           log.info("callback-deviceFault:" + Integer.toBinaryString(deviceFault));
    
           // 解析设备状态码
             log.error("callback-pAmpStatus:");
           int[] intArray = pAmpStatus.getPointer().getIntArray(0, 8);
           for (int i = 0; i < intArray.length; i++) {
               log.info("通道" + i + ":" + Integer.toBinaryString(intArray[i]));
           }
        };
    }

    返回类型为指针,指向数组

    sdk代码(其实与上文是同一个函数)

    void CALLBACK PDCSSTATUS(
              int DCSID,
              int DeviceStatus,
              int DeviceFault, 
              int *pAmpStatus, 
              int ContactInputOpenFault,
              int ContactInputShortFault
    );
    
    参数说明:
    pAmpStatus:
        这是一个整数数组,长度为8,对应于8个功放通道的状态和故障。
        每个数组元素的8bits描叙一个功放通道的状态和故障。
    
        Bit0: 功放通状态(0:未启用,1:正常运行, 2:未正常运行).
        Bit1: 回路故障 (1: 故障, 0: 正常);
        Bit2: 功放是否禁用 (1: 禁用, 0: 未禁用);
        Bit3: 保留
        Bit4: 电源或保护故障(1: 故障, 0: 正常);
        Bit5~Bit7: 保留.

    注意:

    1. 【int *pAmpStatus】,这是一个【int指针】,java中用【IntByReference】来做对应

    2. pAmpStatus参数指向的是一个int[]

    java映射代码

    public interface MyLibrary extends Library {
    
        MylLibrary INSTANCE = Native.load("xxx.so", MyLibrary.class);
    
       // 与SDK中的方法对应
         interface PDCSSTATUS extends Callback {
            void callback(int dcsID, int deviceStatus, int deviceFault,
                          IntByReference pAmpStatus, int contactInputOpenFault,
                          int contactInputShortFault);
        }
    }

    java调用

    public class MyTest {
    
        // dcs设备信息回调方法
        static MyLibrary.PDCSSTATUS pdcsstatus = (dcsID, deviceStatus, deviceFault, pAmpStatus, contactInputOpenFault, contactInputShortFault) -> {// 解析设备状态码
             log.error("callback-pAmpStatus:");
           int[] intArray = pAmpStatus.getPointer().getIntArray(0, 8);
           for (int i = 0; i < intArray.length; i++) {
               log.error("通道" + i + ":" + Integer.toBinaryString(intArray[i]));
           }
        };
    }

    处理指针步骤:

    1. 得到指针:getPointer()

    2. 根据sdk文档,指针指向的是一个int[8],所以getIntArray(0,8)得到对应的数据

    3. 核心代码:int[] intArray = pAmpStatus.getPointer().getIntArray(0, 8);

    结构体

    本次的sdk中无结构体代码,故没有应用,也就没有研究

    问题汇总

    sdk无法加载

    1. sdk根据不同平台,加载方法不同。上文已经给出了windows平台、linux平台的加载方法

    2. sdk版本与系统版本不一致。例如:sdk是32位,而系统是64位

    3. sdk依赖库的缺失

      linux可以用:ldd,命令查看

      

       如图:=>右侧没有出现 not found,表示依赖满足

      windows可以用:【dumpbin】进行查看,这里没有做对应的演示

    回调函数不执行

    java代码定义回调函数时,将其设置为静态变量,防止jvm对其进行回收

    结束语:感谢各位的耐心阅读。

    参考与代码下载

    入门

    jna项目(主要关注www文件夹下的案例代码)

    示例代码下载

  • 相关阅读:
    《2019年软件工程助教培训计划》
    地铁线路项目-结对编程
    预培训-个人项目(地铁线路规划)
    粗读《构建之法》后的问题
    netapp 修改IP地址
    jump server 2.6.1 安装与配置
    CCNA-实验1-Manage_IOS
    系统结构综合实践期末大作业 第22组
    2017级系统综合实践第7次实践作业 01组
    2017级系统综合实践第6次实践作业 01组
  • 原文地址:https://www.cnblogs.com/color-wolf/p/14291476.html
Copyright © 2011-2022 走看看