[Andorid] 通过JNI实现kernel与app进行spi通讯
CPU:RK3399
系统:Android 7.1
人脸识别的要求越来越高,因此主板增加了 SE 加密芯片,加密芯片通过 spi 接口与 CPU 通讯。
对于 kernel 层的代码,Linux 原始代码中有很经典的参考驱动,可以仿照写 spi 驱动。
如果没有过多要求,只需要修改设备号和节点名称,然后能和 dts 匹配成功就行,最后记得修改生成的节点权限
path:kernel/drivers/spi/spidev.c
diff --git a/device/rockchip/common/ueventd.rockchip.rc b/device/rockchip/common/ueventd.rockchip.rc
index 8d5d28d..4b6ac2a 100644
--- a/device/rockchip/common/ueventd.rockchip.rc
+++ b/device/rockchip/common/ueventd.rockchip.rc
@@ -65,6 +65,8 @@
/dev/ttyS2 0666 system system
/dev/ttyS3 0666 system system
+/dev/thm36 0666 system system
+
# for radio
/dev/ttyUSB0 0660 radio radio
/dev/ttyUSB1 0660 radio radio
JNI 的代码就需要自己完成(不需要 HAL 层),然后将 JNI 添加到 App 中编译。
下面代码只是实现简单的读写功能,完成 app 和 kernel 之间的通讯,复杂的地方就是数组之间的转化。
JNI 文件名:thm36_jni.c
#include <jni.h> #include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <assert.h> #include <termios.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include "android/log.h" static const char *TAG = "thm36_jni"; #define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args) #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) #define DEV_NAME "/dev/thm36" static jint fd; JNIEXPORT jint JNICALL Java_com_example_aaron_se_Thm36Native_thm36Open(JNIEnv *env, jclass clazz) { LOGD("JNI spi open ... ..."); fd = open(DEV_NAME, O_RDWR); if (fd < 0) { LOGD("open device fail!"); return -1; } return 0; } JNIEXPORT void JNICALL Java_com_example_aaron_se_Thm36Native_thm36Close(JNIEnv *env, jclass clazz) { LOGD("JNI spi close ... ..."); close(fd); } JNIEXPORT jint JNICALL Java_com_example_aaron_se_Thm36Native_thm36Read(JNIEnv *env, jclass clazz, jbyteArray jread_arr, jint len) { jbyte *array = NULL; jboolean *buf; int i = 0; LOGD("JNI spi read ... ..."); array = (*env)->GetByteArrayElements(env, jread_arr, NULL); if (array == NULL) { LOGD("JNI spi read: GetByteArrayElements faid!"); return -1; } buf = (jboolean *)calloc(sizeof(*array), sizeof(jboolean)); if (buf == NULL) { LOGD("JNI spi read: calloc fail!"); return -1; } read(fd, buf, len); for (i=0; i<len; i++) { LOGD("JNI spi read: buf: %#x", *(buf + i)); *(array + i) = (jchar)(*(buf + i)); } (*env)->ReleaseByteArrayElements(env, jread_arr, array, 0); free(buf); return 0; } JNIEXPORT jint JNICALL Java_com_example_aaron_se_Thm36Native_thm36Write(JNIEnv *env, jclass clazz, jbyteArray jwrite_arr, jint len) { jbyte *array = NULL; jboolean *buf; int i = 0; LOGD("JNI spi write ... ..."); array = (*env)->GetByteArrayElements(env, jwrite_arr, NULL); if (array == NULL) { LOGD("JNI spi write: GetByteArrayElements fail!"); return -1; } buf = (jboolean *)calloc(sizeof(*array), sizeof(jboolean)); if(buf == NULL) { LOGD("JNI spi write: calloc fail!"); return -1; } for(i = 0; i < len; i++) { *(buf + i) = (jboolean)(*(array + i)); LOGD("JNI spi write: data : %#x\n",*(buf + i)); } (*env)->ReleaseByteArrayElements(env, jwrite_arr, array, 0); write(fd, buf, len); free(buf); return 0; }
编译文件:Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
TARGET_PLATFORM := android-3
LOCAL_MODULE := thm36_jni
LOCAL_SRC_FILES := thm36_jni.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
App 的测试代码也很简单,一个是主活动,一个是与 JNI 链接
MainActivity.java
// JNI中的函数名前面部分要与此相同 package com.example.aaron.se; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ Thm36Native thm36 = new Thm36Native(); byte[] tx = {(byte)0xAA, 0x00, 0x06, 0x00, (byte)0xCA, 0x00, 0x00, 0x00, 0x00, (byte)0xCA}; byte[] rx = new byte[22]; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btn = (Button) findViewById(R.id.btn); btn.setOnClickListener(MainActivity.this); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.btn: thm36.thm36Open(); thm36.thm36Write(tx, tx.length); thm36.thm36Read(rx, rx.length); thm36.thm36Close(); break; default: break; } } }
Thm36Native.java
package com.example.aaron.se; import android.util.Log; public class Thm36Native { private final String TAG = "Thm36Native"; public native int thm36Open(); public native void thm36Close(); public native int thm36Read(byte[] buf, int len); public native int thm36Write(byte[] buf, int len); static { System.loadLibrary("thm36"); } }
参考:
https://blog.csdn.net/hanbo622/article/details/38944895