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进入到工程路径 NdkDemo\app\src\main\java,执行命令生成.h头文件。
javah -classpath . -jni com.csu.jni.MyJNI

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

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <errno.h>
#include <fcntl.h>
#include <malloc.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <jni.h>
#include <android/log.h>
/* Header for class com_csu_jni_MyJNI */

#ifndef _Included_com_csu_jni_MyJNI
#define _Included_com_csu_jni_MyJNI
#ifdef __cplusplus
extern "C" {
    
    
#endif
/*
 * Class:     com_csu_jni_MyJNI
 * Method:    getStringFromNative
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_csu_jni_MyJNI_getStringFromNative
  (JNIEnv *, jclass);

/*
 * Class:     com_csu_jni_MyJNI
 * Method:    OpenDeviceNode
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_csu_jni_MyJNI_OpenDeviceNode
  (JNIEnv *, jclass);

/*
 * Class:     com_csu_jni_MyJNI
 * Method:    CloseDeviceNode
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_csu_jni_MyJNI_CloseDeviceNode
  (JNIEnv *, jclass);

/*
 * Class:     com_csu_jni_MyJNI
 * Method:    IICWriteRead
 * Signature: ([BI[BI)I
 */
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__)

/**
 * My device name
 */
#define DEVICE_NAME    "/dev/myjni"

/**
 * File descriptor
 */
static int fd = -1;

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

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

    return ret;
}

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

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

    return ret;
}

/*
 * Class:     com_csu_jni_MyJNI
 * Method:    getStringFromNative
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_csu_jni_MyJNI_getStringFromNative(JNIEnv *env, jclass clazz) {
    
    
    return (*env)->NewStringUTF(env, "My JNI string");
}

/*
 * Class:     com_csu_jni_MyJNI
 * Method:    OpenDeviceNode
 * Signature: ()I
 */
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 =%d\n", fd);
    }
    LOGI("MyJNI open device Success, fd =%d\n", fd);

    return fd;
}

/*
 * Class:     com_csu_jni_MyJNI
 * Method:    CloseDeviceNode
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_csu_jni_MyJNI_CloseDeviceNode(JNIEnv *env, jclass clazz) {
    
    
    close(fd);
    return 0;
}

/*
 * Class:     com_csu_jni_MyJNI
 * Method:    IICWriteRead
 * Signature: ([BI[BI)I
 */
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=%d\n", wLen, rLen);

    if (wLen > 1) {
    
    
        ret = file_write(bufw, wLen);
        LOGI("JNI IICWriteRead(), wlen=%d, ret=%d\n", 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.%d\n", 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=%d\n", 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进入到工程路径 NdkDemo\app\src\main\java,执行命令编译生成.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文件:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="My IIC JNI Test"
        android:textSize="24sp"
        android:textColor="#353535"
        android:layout_marginTop="20dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>

    <Button
        android:id="@+id/btn_open"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="open"
        android:layout_marginTop="80dp"
        android:layout_marginStart="60dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"/>

    <Button
        android:id="@+id/btn_close"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="close"
        android:layout_marginStart="20dp"
        app:layout_constraintTop_toTopOf="@id/btn_open"
        app:layout_constraintStart_toEndOf="@id/btn_open"/>

    <Button
        android:id="@+id/btn_read_fw_version"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="fw_ver"
        android:layout_marginStart="20dp"
        app:layout_constraintTop_toTopOf="@id/btn_open"
        app:layout_constraintStart_toEndOf="@id/btn_close"/>

    <Button
        android:id="@+id/btn_write"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="w"
        app:layout_constraintTop_toBottomOf="@id/btn_open"
        app:layout_constraintStart_toStartOf="@id/btn_open"/>

    <Button
        android:id="@+id/btn_read"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="r"
        android:layout_marginStart="20dp"
        app:layout_constraintTop_toTopOf="@id/btn_write"
        app:layout_constraintStart_toEndOf="@id/btn_write"/>

    <TextView
        android:id="@+id/tv_info"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="40dp"
        app:layout_constraintTop_toBottomOf="@id/btn_write"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>


</androidx.constraintlayout.widget.ConstraintLayout>

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/tracydragonlxy/article/details/122303447