Android Studio JNI开发(三)——实现通过IIC协议控制硬件设备

Android Studio JNI开发(三)——实现通过IIC协议控制硬件设备,第1张

Android Studio JNI开发(三)——实现通过IIC协议控制硬件设备 Android Studio JNI开发(三)——实现通过IIC协议控制硬件设备
  1. 新建Java JNI 类 MyJni.java,并编写JNI native方法。
public class MyJNI {

    static {
        System.loadLibrary("jni_native");
    }

    public static native String getStringFromNative();

    public static native int OpenDeviceNode();

    public static native int CloseDeviceNode();

    public static native int IICWriteRead(byte[] wBuf, int wLen, byte[] rBuf, int rLen);
    
}
  1. 生成头文件,cmd进入到工程路径 NdkDemoappsrcmainjava,执行命令生成.h头文件。
javah -classpath . -jni com.csu.jni.MyJNI

在MyJNI.java文件的同级目录(mainjavacom.csu.jni)生成一个.h的头文件com_csu_jni_MyJNI.h。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 


#ifndef _Included_com_csu_jni_MyJNI
#define _Included_com_csu_jni_MyJNI
#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT jstring JNICALL Java_com_csu_jni_MyJNI_getStringFromNative
  (JNIEnv *, jclass);


JNIEXPORT jint JNICALL Java_com_csu_jni_MyJNI_OpenDeviceNode
  (JNIEnv *, jclass);


JNIEXPORT jint JNICALL Java_com_csu_jni_MyJNI_CloseDeviceNode
  (JNIEnv *, jclass);


JNIEXPORT jint JNICALL Java_com_csu_jni_MyJNI_IICWriteRead
  (JNIEnv *, jclass, jbyteArray, jint, jbyteArray, jint);

#ifdef __cplusplus
}
#endif
#endif

  1. main下java同级目录新建jni目录,将step6生成的.h文件拷贝到jni目录,然后新建com_csu_jni_MyJNI.c文件,实现.h文件中的方法。
//
// Created by Admin on 2021/11/17.
//
#include "com_csu_jni_MyJNI.h"

#define LOG_TAG "MyJNI"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)


#define DEVICE_NAME    "/dev/myjni"


static int fd = -1;

int file_read(jbyte *rbuf, jint rlen) {
    int ret;
    if (fd < 0) {
        LOGE("file_read(), JNI IS NOT OPENEDn");
    }
    LOGI("JNI file_read(), rlen=%d, rbuf=%dn", rlen, rbuf[0]);

    ret = read(fd, rbuf, rlen);
    if (ret < 0) {
        LOGE("JNI read failed, ret=%dn", ret);
    }
    LOGI("JNI read success, ret=%dn", ret);

    return ret;
}

int file_write(jbyte *wbuf, jint wlen) {
    int ret;
    if (fd < 0) {
        LOGE("file_write(), JNI IS NOT OPENEDn");
    }
    LOGI("JNI file_write(), wlen=%d, wbuf=%dn", wlen, wbuf[0]);

    ret = write(fd, wbuf, wlen);
    if (ret < 0) {
        LOGE("JNI write failed, ret=%dn", ret);
    }
    LOGI("JNI write success, ret=%dn", ret);

    return ret;
}


JNIEXPORT jstring JNICALL Java_com_csu_jni_MyJNI_getStringFromNative(JNIEnv *env, jclass clazz) {
    return (*env)->NewStringUTF(env, "My JNI string");
}


JNIEXPORT jint JNICALL Java_com_csu_jni_MyJNI_OpenDeviceNode(JNIEnv *env, jclass clazz) {

    fd = open(DEVICE_NAME, O_RDWR|O_NONBLOCK);
    if (fd < 0) {
        LOGE("MyJNI open device failed, fd =%dn", fd);
    }
    LOGI("MyJNI open device Success, fd =%dn", fd);

    return fd;
}


JNIEXPORT jint JNICALL Java_com_csu_jni_MyJNI_CloseDeviceNode(JNIEnv *env, jclass clazz) {
    close(fd);
    return 0;
}


JNIEXPORT jint JNICALL Java_com_csu_jni_MyJNI_IICWriteRead(JNIEnv *env, jclass clazz, jbyteArray wBuf, jint wLen, jbyteArray rBuf, jint rLen) {
    int ret = 0;

    // 将Java层的数据拷到缓冲区
    jbyte* bufw = (*env)->GetByteArrayElements(env, wBuf, NULL);
    //jbyte* bufr = (*env)->GetByteArrayElements(env, rBuf, NULL);
    //jint wlen = (*env)->GetArrayLength(env, wBuf);
    jint len = (*env)->GetArrayLength(env, rBuf);

    // 驱动会把要读取数据的寄存器放在首位返回,所以从驱动获取的数据buf长度要+1
    len = len + 1;

    // 新建一个数组,用于将驱动数据拷贝到缓冲区
    jbyteArray jarr = (*env)->NewByteArray(env, len);
    jbyte* jbuf = (*env)->GetByteArrayElements(env, jarr, NULL);

    LOGI("JNI IICWriteRead(), wlen=%d, rlen=%dn", wLen, rLen);

    if (wLen > 1) {
        ret = file_write(bufw, wLen);
        LOGI("JNI IICWriteRead(), wlen=%d, ret=%dn", wLen, ret);
    }

    // get register addr
    jbuf[0] = bufw[0];

    if (rLen > 0) {
        ret = file_read(jbuf, rLen);
        LOGI("JNI IICWriteRead(), rlen=%d, ret=%d, rbuf=%d.%d.%d.%dn", rLen, ret, jbuf[1], jbuf[2], jbuf[3], jbuf[4]);

        // 驱动返回缓存区的数据,首位为寄存器地址,真正获取的数据从下标1开始
        memcpy(jbuf, jbuf + 1, len - 1);

        // 将缓冲区的数据返回给Java形参
        (*env)->SetByteArrayRegion(env, rBuf, 0, rLen, jbuf);

    }

    // 释放资源,避免内存泄漏
    (*env)->ReleaseByteArrayElements(env, rBuf, jbuf, 0);
    (*env)->DeleteLocalRef(env, jarr);

    LOGI("JNI IICWriteRead(), ret=%dn", ret);

    return ret;
}
  1. jni目录下新建Android.mk文件。
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := jni_native
LOCAL_SRC_FILES := com_csu_jni_MyJNI.c

LOCAL_LDLIBS :=-llog

APP_ABI := all

include $(BUILD_SHARED_LIBRARY)
  1. cmd进入到工程路径 NdkDemoappsrcmainjava,执行命令编译生成.so文件。
ndk-build

在jni同级目录下会生成两个文件夹libs和obj。

  1. 将libs文件夹下的内容拷贝到module项目名下的libs目录。

  2. module的build.gradle 文件的android{}节点中添加对libs的引用:

sourceSets {
    main {
        jniLibs.srcDirs = ['libs']
    }
}
  1. Activity中调用JNI方法
    MainActivity.java
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "lxy";

    private TextView tvInfo;

    private int id = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        String str = MyJNI.getStringFromNative();
        Log.i(TAG, "onCreate: rs = " + str);


        Button btnOpen = findViewById(R.id.btn_open);
        Button btnClose = findViewById(R.id.btn_close);
        Button btnFwVersion = findViewById(R.id.btn_read_fw_version);
        Button btnWrite = findViewById(R.id.btn_write);
        Button btnRead = findViewById(R.id.btn_read);
        tvInfo = findViewById(R.id.tv_info);

        btnOpen.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (id > 0) {
                    Log.i(TAG, "onClick: device is opened!!!");
                    updateTextInfo("device is opened!!!");
                } else {
                    id = MyJNI.OpenDeviceNode();
                    updateTextInfo("device open, id = " + id);
                    Log.i(TAG, "onClick: device open id = " + id);
                }
            }
        });

        btnClose.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (id > 0) {
                    int rs = MyJNI.CloseDeviceNode();
                    Log.i(TAG, "onClick: close device rs = " + rs);
                    updateTextInfo("close device, rs = " + rs);
                    id = 0;
                } else {
                    Log.i(TAG, "onClick: device is not open");
                    updateTextInfo("device is not open");
                }
            }
        });

        btnFwVersion.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (id > 0) {

                    byte[] wBuf = {0x10};
                    byte[] rBuf = new byte[256];
                    int rs = MyJNI.IICWriteRead(wBuf, 1, rBuf, 4);
                    Log.i(TAG, "onClick: ret = " + rs + ",rBuf= "
                            + rBuf[0] + "." + rBuf[1] + "." + rBuf[2] + "." + rBuf[3]);
                    updateTextInfo("ret = " + rs + ",rBuf= "
                            + rBuf[0] + "." + rBuf[1] + "." + rBuf[2] + "." + rBuf[3]);
                }
            }
        });

        btnWrite.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (id > 0) {
                    write();
                }
            }
        });

        btnRead.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (id > 0) {
                    read();
                }
            }
        });

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        int rs = MyJNI.CloseDeviceNode();
        Log.i(TAG, "onClick: close device rs = " + rs);
    }

    private void write() {

        byte[] wbuf = {0x00, 0x00, 0x01, 0x02, 0x03};
        byte[] rbuf = new byte[10];
        int rs = MyJNI.IICWriteRead(wbuf, 5, rbuf, 0);
        Log.i(TAG, "write(): ret=" + rs);
        updateTextInfo("write to fw : " + Arrays.toString(wbuf));
    }

    private void read() {

        byte[] wbuf = {0x00};
        byte[] rbuf = new byte[256];
        int rs = MyJNI.IICWriteRead(wbuf, 1, rbuf, 6);
        Log.i(TAG, "read(): ret=" + rs + ", rbuf = " + Arrays.toString(rbuf));
        updateTextInfo("read from fw : " + Arrays.toString(Arrays.copyOf(rbuf, 6)));
    }

    private void updateTextInfo(final String s) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                tvInfo.setText(s);
            }
        });
    }

}

布局xml文件:




    

    

    


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5696934.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存