[Andorid] 通过JNI实现kernel与app进行spi通讯

摘要:
CPU:RK3399系统:Android 7.1人脸识别要求越来越高,所以主板上增加了SE加密芯片,加密芯片通过spi接口与CPU通信。对于内核层的代码,Linux源代码中有非常经典的参考驱动程序,可以将其建模为spi驱动程序。如果没有太多的要求,只需要修改设备号和节点名,然后与dts成功匹配,最后,请记住修改生成的节点权限路径:kernel/drivers/spi/spi.cdiff--gita/device/rockchip/common/ueventd.rockchip.rcb/device/rockchip/common/ueventd.rockchip.rcindex8d5d28d..4b6ac2a100644--a/device/rrockchip/common/ueventd.crockchip.rc+++b/device/rockchip/common/uventd.rockcchip.rc@@-65,6+65,8@//dev/tyS20666systemsystem/dev/ttyS30666systemsystem+/dev/thm360666systemsystem+#forradio/dev/ttyUSB00660radio的代码需要自己完成,然后将JNI添加到App中进行编译。以下代码仅实现简单的读写功能,并完成应用程序和内核之间的通信。复杂的部分是数组之间的转换。

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
",*(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

免责声明:文章转载自《[Andorid] 通过JNI实现kernel与app进行spi通讯》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇SCSS提取和懒加载提高生产力:文件和IO操作(ApacheCommonsIO-汉化分享)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

ubuntu12.04 make xconfig出错解决

xconfig是linux下X Window环境中用于配制的一个工具,和menuconfig相似,但用法更友好方便,用如下命令可以进入配制界面: make xconfig 因为在ubuntu系统中,编译内核需要安装一些工具,如makemenuconfig或make xconfig,来配置内核参数,但弹出下面的错误信息: HOSTCC  scripts/b...

第4步:创建RAC共享磁盘组

第4步:创建RAC共享磁盘组 方法一:使用asmdevices(推荐使用,但不适用EMC Powerpath) (1)查看硬盘的SCSI号,两个机器认到的/dev/sda对应在实际的物理盘可能不是一块,但scsi号肯定是完全一致的。 代码1 [root@sgdb1 ~]# scsi_id -g -u -d /dev/sdc 36000c294cea6...

Android版本与Linux内核的关系及代码获取

一.Android版本与Linux内核的关系 英文名 中文名 Android版本 Linux内核版本 No 无 1.1 Cupcake 纸杯蛋糕 1.5 2.6.27 Donut 甜甜圈 1.6 2.6.29 Eclair 松饼 2.0 2.6.29 Eclair 松饼 2.1 2.6.29 Froyo 冻酸奶 2.2 2.6....

u-boot中分区和内核MTD分区关系【转】

转自:https://www.cnblogs.com/lidabo/p/4774327.html 一、u-boot中环境变量与uImage中MTD的分区关系 分区只是内核的概念,就是说A~B地址放内核,C~D地址放文件系统,(也就是规定哪个地址区间放内核或者文件系统)等等。 一般我们只需要分3-4个区,第一个为boot区,一个为boot参数区(传递给内核的...

下载android的linux内核的方法

1、安装git android的linux内核可以从http://android.git.kernel.org/下载,但下载需要使用git,windows版的git可以从http://code.google.com/p/msysgit/下载,有完全安装版和便携版(portable)两个版本可供选择,不常用git的话选portable版就可以了。 下载por...

Ubantu 16.04升级内核版本和还原到升级之前的内核版本的方法

一、查看系统信息 1、查看发布版本: 命令: lsb_release -a 运行结果: / 2、查看内核版本: 命令: uname -sr 运行结果: 二、升级内核的方法 1、内核下载地址:http://kernel.ubuntu.com/~kernel-ppa/mainline/ 。打开地址后,拖动鼠标到网页最底端,找到最新版本的内核v4.15...