Android系统下JNI的第二种编写方法
来源:互联网 发布:java调用微信接口开发 编辑:程序博客网 时间:2024/05/22 00:46
#include <hardware/hardware.h>
#include <hardware/iic.h>
所以实现起来依赖关系很严重,而上层app的开发需要有自己生成的jni的.h方法,导致上下不通,具体体现在:
例如 open方法:
/*通过硬件抽象层定义的硬件模块open接口打开硬件设备*/
static inline int iic_device_open(const hw_module_t* module, struct iic_device_t** device) {
return module->methods->open(module, IIC_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
}
static jboolean iic_init(JNIEnv* env, jclass clazz) {
iic_module_t* module;
LOGI("iic JNI: initializing......");
if(hw_get_module(IIC_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {
LOGI("iic JNI: iic Stub found.");
if(iic_device_open(&(module->common), &iic_device) == 0) {
LOGI("eeprom JNI: iic device is opening...");
return 0;
}
LOGE("eeprom JNI: failed to open iic device.");
return -1;
}
LOGE("eeprom JNI: failed to get iic stub module.");
return -1;
}
open方法里包含了HAL层的定义结构体,而APP实现起来这些头文件根本不能包含的,所以JNI的通用方法是用的基本的系统调用形式:
JNIEXPORT jint JNICALL Java_peter_amlogic_serial_SerialThread_00024I2c_open(JNIEnv *env, jobject obj, jstring file)
{
char fileName[64];
const jbyte *str;
str = (*env)->GetStringUTFChars(env, file, NULL);
if (str == NULL) {
LOGI("Can't get file name!");
return -1;
}
sprintf(fileName, "%s", str);
LOGI("will open i2c device node %s", fileName);
(*env)->ReleaseStringUTFChars(env, file, str);
return open(fileName, O_RDWR);
}
具体实现:
1、利用javah生成jni头文件
用javah命令自动生成头文件需要在java代码中先声明该函数。
(示例程序中 需要在SerialThread.java中调用jni来操作i2c,先用public native来声明open, read, write, colse函数,这里的open, read, write, close分别与i2c_elevator.c的
函 数对应)
- public static class I2c {
- /**
- * @param nodeName
- * node path name
- * @return return file hander else return <0 on fail
- */
- public native int open(String nodeName);
- /**
- * @param fileHander
- * @param i2c_adr
- * slave addr
- * @param buf
- * @param Lenth
- * of buf
- * @return read length
- */
- public native int read(int fileHander, int i2c_adr, byte buf[], int Length);
- /**
- * @param fileHander
- * @param i2c_adr
- * slave addr
- * @param sub_adr
- * sub addr
- * @param buf
- * @param Lenth
- * of buf
- * @return write length
- */
- public native int write(int fileHander, int i2c_adr, int sub_adr, int buf[], int Length);
- public native void close(int fileHander);
- }
从linux下终端进入到项目目录
找到SerialThread.java对应的class文件
用javah命令自动生成头文件
javah -classpath bin/classes -d jni peter.amlogic.serial.SerialThread
其中:classpath 指定classes的目录,
-d :指定jni目录
运行此命令后,会在jni目录下生成符合jni规范的头文件
c.打开peter_amlogic_serial_SerialThread_I2c.h,里面有和前面在SerialThread.java中函数对应的函数名
在i2c_elevator.c中,函数名应该和peter_amlogic_serial_SerialThread_I2c.h一致,才能被识别
4. 在jni目录新建i2c_elevator.c 此c文件为jni核心,java层主要通过该文件中的函数来实现i2c的读写等操作。注意函数名字要用peter_amlogic_serial_SerialThread_I2c.h中的函数名
- #include <jni.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <string.h>
- #include <android/log.h>
- #include <linux/i2c.h>
- #include <linux/delay.h>
- #include <linux/time.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/ioctl.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <assert.h>
- #include <string.h>
- #define CHIP_ADDR 0xa0 //mcu i2c addr
- #define I2C_DEV "/dev/i2c-1" // register i2c B bus
- #define LOG_TAG "i2c" //android logcat
- #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
- #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
- static int read_eeprom(int fd, char buff[], int addr, int count)
- {
- int res;
- int i;
- for(i=0; i<PAGE_SIZE; i++)
- {
- buff[i]=0;
- }
- if(write(fd, &addr, 1) != 1)
- return -1;
- usleep(10000);
- res=read(fd, buff, count);
- LOGI("read %d byte at 0x%.2x\n", res, addr);
- for(i=0; i<PAGE_SIZE; i++)
- {
- LOGI("0x%.2x, ", buff[i]);
- }
- return res;
- }
- static int write_eeprom(int fd, char buff[], int addr, int count)
- {
- int res;
- int i;
- char sendbuffer[PAGE_SIZE+1];
- memcpy(sendbuffer+1, buff, count);
- sendbuffer[0]=addr;
- res= write(fd, sendbuffer, count+1);
- LOGI("write %d byte at 0x%.2x\n", res ,addr);
- usleep(10000);
- for(i=0; i<PAGE_SIZE; i++)
- {
- LOGI("0x%.2x, ", buff[i]);
- }
- }
- JNIEXPORT jint JNICALL Java_peter_amlogic_serial_SerialThread_00024I2c_open(JNIEnv *env, jobject obj, jstring file)
- {
- char fileName[64];
- const jbyte *str;
- str = (*env)->GetStringUTFChars(env, file, NULL);
- if (str == NULL) {
- LOGI("Can't get file name!");
- return -1;
- }
- sprintf(fileName, "%s", str);
- LOGI("will open i2c device node %s", fileName);
- (*env)->ReleaseStringUTFChars(env, file, str);
- return open(fileName, O_RDWR);
- }
- JNIEXPORT jint JNICALL Java_peter_amlogic_serial_SerialThread_00024I2c_read(JNIEnv * env, jobject obj, jint fileHander, jint slaveAddr, jintArray bufArr, jint len)
- {
- jint *bufInt;
- char *bufByte;
- int res = 0, i = 0, j = 0;
- if (len <= 0) {
- LOGE("I2C: buf len <=0");
- goto err0;
- }
- bufInt = (jint *) malloc(len * sizeof(int));
- if (bufInt == 0) {
- LOGE("I2C: nomem");
- goto err0;
- }
- bufByte = (char*) malloc(len);
- if (bufByte == 0) {
- LOGE("I2C: nomem");
- goto err1;
- }
- (*env)->GetIntArrayRegion(env, bufArr, 0, len, bufInt);
- memset(bufByte, '\0', len);
- if ((j = read(fileHander, bufByte, len)) != len) {
- LOGE("read fail in i2c read jni i = %d buf 4", i);
- goto err2;
- } else
- {
- for (i = 0; i < j ; i++)
- bufInt[i] = bufByte[i];
- LOGI("return %d %d %d %d in i2c read jni", bufByte[0], bufByte[1], bufByte[2], bufByte[3]);
- (*env)->SetIntArrayRegion(env, bufArr, 0, len, bufInt);
- }
- free(bufByte);
- free(bufInt);
- return j;
- err2:
- free(bufByte);
- err1:
- free(bufInt);
- err0:
- return -1;
- }
- JNIEXPORT jint JNICALL Java_peter_amlogic_serial_SerialThread_00024I2c_write(JNIEnv *env, jobject obj, jint fileHander, jint slaveAddr, jint mode, jintArray bufArr, jint len)
- {
- #if 0
- jint *bufInt;
- char *bufByte;
- int res = 0, i = 0, j = 0;
- if (len <= 0) {
- LOGE("I2C: buf len <=0");
- goto err0;
- }
- bufInt = (jint *) malloc(len * sizeof(int));
- if (bufInt == 0) {
- LOGE("I2C: nomem");
- goto err0;
- }
- bufByte = (char*) malloc(len + 1);
- if (bufByte == 0) {
- LOGE("I2C: nomem");
- goto err1;
- }
- (*env)->GetIntArrayRegion(env, bufArr, 0, len, bufInt);
- bufByte[0] = mode;
- for (i = 0; i < len; i++)
- bufByte[i + 1] = bufInt[i];
- if ((j = write(fileHander, bufByte, len + 1)) != len + 1) {
- LOGE("write fail in i2c");
- goto err2;
- }
- LOGI("I2C: write %d byte", j);
- free(bufByte);
- free(bufInt);
- return j - 1;
- err2:
- free(bufByte);
- err1:
- free(bufInt);
- err0:
- return -1;
- #endif
- }
- JNIEXPORT void JNICALL Java_peter_amlogic_serial_SerialThread_00024I2c_close(JNIEnv *env, jobject obj, jint fileHander)
- {
- close(fileHander);
- }
5. 编译i2c_elevator.c
在amlogicAD_iic目录下运行ndk-build, 成功之后在libs/armeabi目录下生成libi2c_elevator.so
四.如何在java中调用so库
1. SerialThread.java中添加libi2c_elevator.so . 添加的时候,名称只取i2c_elevator
{
System.loadLibrary("i2c_elevator");//
}
2. 此时在java中可以调用open, read, close了
五.权限权限chmod 777 /dev/i2c-1
操作设备之前要修改设备的权限,才能完成读写等操作。
修改权限可以修改device/amlogic/f17ref/init.rc脚本,加入chmod 0777 /dev/i2c-1命令(具体在文件什么位置没有限定,此处放在了on boot后)
注意:修改完成之后要make clean,然后重新编译
六.关于java调用jni时的参数传递
1. open函数参数为注册的i2c设备名,类型为String, 在jni中打开成功后返回一个文件描述符。
JAVA:
JNI:
2. read函数
read函数参数较多,fileHander为open device之后返回的描述符;
i2c_addr为i2c芯片上要去读取的地址,本项目中可以从0地址去读;
buf[ ] 中存放的是读取的数据。类型为byte,因此在jni中也应该定义为byte
GetByteArrayRegion:获得Java的byte[]类型参数,将Java传来的字节数组buf,复制len长度的数据到bufInt中。
SetByteArrayRegion:正好相反,将bufInt中的值复制len长度到Java中的bufArr字节数组。
3. close函数
与open函数对应。
参考:点击打开链接
- Android系统下JNI的第二种编写方法
- android编写JNI方法
- android平台中编写jni模块的方法(1)
- 编写android程序调用jni本地方法的实现
- Android开发-jni的编写
- Android下的JNI创建多线程的方法
- Android下的JNI创建多线程的方法
- 编写JNI的两种应用层与JNI层方法映射方式
- Ubuntu下编译Android JNI最靠谱的方法...
- Ubuntu下编译Android JNI最靠谱的方法..
- android jni 的编写一(JNI的静态注册)
- 如何编写jni方法
- 如何编写jni方法
- 如何编写jni方法
- android jni的编写, 控制led灯
- android JNI的编写最全过程
- 编写自己的android jni程序
- Android中JNI程序的编写
- 类成员函数的指针
- 从未停止进化的MaxCompute
- 关于ACTIVEX控件应用于对话框程序与单文档程序的区别
- 验证码输入框
- 软件测试之易用性测试
- Android系统下JNI的第二种编写方法
- libpng error
- Three.js创建一个场景(Creating a scene)
- ssd-300 代码分析
- Java多态性详细举例说明(很经典例子)
- mvc实现
- linux服务器部署记录
- 各种符号的日语读音
- 2016山东教师教育网- 一师一优课