Android 下通过jni读取i2c数据

来源:互联网 发布:circrna数据库 编辑:程序博客网 时间:2024/04/30 14:04

Android 下通过jni读取i2c数据

Linux 平台:ubuntu 10.04(x86)

Android平台:AML18726-M3(Android4.0,  linux kernel2.6.34)

JNI: Java Native Interface

原理:JNI允许在Java虚拟机上运行的Java代码操作其他语言编写的应用程序和本地库方法,从而能够直与接特定的操作系统和硬件平台进行交互。

方法:(这里是在linux下编译so库的方式)

一. Linuxjni编译环境搭建

1. 安装ndk.

a. 将c文件编译成so库的时候需要用到ndk-build命令,必须安装ndk

下载android-ndk-r6-linux-x86.tar,拷贝到ubuntu下,解压到/home/tony/sda6/m3tools目录

b. 添加ndk环境变量

export PATH="$PATH:/home/tony/sda6/m3tools/android-ndk-r6"

添加完成后可以用ndk-build –v查看是否成功

二. Linux kernel 内核添加i2c设备

1. 根据原理图,i2cmcui2c B, mcu芯片地址为0xa0

2. 在kernel中将设备注册到i2c B总线上,这样才能通过i2c访问到mcu上的数据。

修改kernel/inch/arch/arm/mach-meson3/board-m3-reff17.c,i2c_board_info __initdata aml_i2c_bus_info_1[]结构体中注册设备(若是i2c A,则在i2c_bus_info_0[]中注册)

[java] view plaincopy
  1. static struct i2c_board_info __initdata aml_i2c_bus_info_1[] = {  
  2. //elevator  
  3.     {  
  4.         I2C_BOARD_INFO("elevator "0xa0),  
  5.     },    
  6. };  


 

3. 重新编译内核。

make uImage 并更新uImage.

三. Jni程序编写

1. 以电梯应用程序amlogicAD为例,在amlogicAD目录下新建jni目录

2. 编写Android.mk

[plain] view plaincopy
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4. LOCAL_MODULE := i2c_elevator    //name of so  
  5. LOCAL_SRC_FILES := i2c_elevator.c   //c file  
  6. LOCAL_LDLIBS := -llog  
  7. LOCAL_C_INCLUDES := $(MY_ANDROID_SOURCE)/frameworks/base/core/jni/android/graphics \  
  8.    $(MY_ANDROID_SOURCE)/external/skia/include/core \  
  9.    $(MY_ANDROID_SOURCE)/external/skia/include/images \  
  10.    $(MY_ANDROID_SOURCE)/frameworks/base/include \  
  11.    $(MY_ANDROID_SOURCE)/system/core/include  
  12. include $(BUILD_SHARED_LIBRARY)  


 

3. 利用javah生成jni头文件

a.javah命令自动生成头文件需要在java代码中先声明该函数。(示例程序中 需要在SerialThread.java中调用jni来操作i2c,先用public native来声明open,  read, write, colse函数,这里的open, read, write, close分别与i2c_elevator.c的函 数对应)

[java] view plaincopy
  1. public static class I2c {  
  2.         /** 
  3.          * @param nodeName 
  4.          *            node path name 
  5.          * @return return file hander else return <0 on fail 
  6.          */  
  7.         public native int open(String nodeName);  
  8.        
  9.         /** 
  10.          * @param fileHander 
  11.          * @param i2c_adr 
  12.          *            slave addr 
  13.          * @param buf 
  14.          * @param Lenth 
  15.          *            of buf 
  16.          * @return read length 
  17.          */  
  18.         public native int read(int fileHander, int i2c_adr, byte buf[], int Length);  
  19.        
  20.         /** 
  21.          * @param fileHander 
  22.          * @param i2c_adr 
  23.          *            slave addr 
  24.          * @param sub_adr 
  25.          *            sub addr 
  26.          * @param buf 
  27.          * @param Lenth 
  28.          *            of buf 
  29.          * @return write length 
  30.          */  
  31.         public native int write(int fileHander, int i2c_adr, int sub_adr, int buf[],            int Length);  
  32.        
  33.         public native void close(int fileHander);  
  34. }  


 

b.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中的函数名

[cpp] view plaincopy
  1. #include <jni.h>  
  2. #include <stdio.h>  
  3. #include <unistd.h>  
  4. #include <string.h>  
  5. #include <android/log.h>  
  6. #include <linux/i2c.h>  
  7. #include <linux/delay.h>  
  8. #include <linux/time.h>  
  9. #include <sys/types.h>  
  10. #include <sys/stat.h>  
  11. #include <sys/ioctl.h>  
  12. #include <fcntl.h>  
  13. #include <errno.h>  
  14. #include <assert.h>  
  15. #include <string.h>  
  16.   
  17. #define CHIP_ADDR  0xa0   //mcu i2c addr  
  18. #define I2C_DEV   "/dev/i2c-1"  // register i2c B bus  
  19.   
  20. #define LOG_TAG "i2c"       //android logcat  
  21. #define LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)  
  22. #define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)  
  23.   
  24. static int read_eeprom(int fd, char buff[], int addr, int count)  
  25. {  
  26.             int res;  
  27.             int i;  
  28.               
  29.             for(i=0; i<PAGE_SIZE; i++)  
  30.         {  
  31.            buff[i]=0;  
  32.             }  
  33.               
  34.   
  35.             if(write(fd, &addr, 1) != 1)  
  36.                 return -1;  
  37.             usleep(10000);  
  38.             res=read(fd, buff, count);  
  39.             LOGI("read %d byte at 0x%.2x\n", res, addr);  
  40.             for(i=0; i<PAGE_SIZE; i++)  
  41.             {  
  42.                 LOGI("0x%.2x, ", buff[i]);  
  43.             }  
  44.               
  45.             return res;  
  46. }  
  47.   
  48. static int write_eeprom(int fd, char  buff[], int addr, int count)  
  49. {  
  50.             int res;  
  51.             int i;  
  52.             char sendbuffer[PAGE_SIZE+1];  
  53.               
  54.             memcpy(sendbuffer+1, buff, count);  
  55.             sendbuffer[0]=addr;  
  56.               
  57.             res= write(fd, sendbuffer, count+1);  
  58.                 LOGI("write %d byte at 0x%.2x\n", res ,addr);  
  59.             usleep(10000);  
  60.                   
  61.             for(i=0; i<PAGE_SIZE; i++)  
  62.             {  
  63.                 LOGI("0x%.2x, ", buff[i]);  
  64.             }  
  65. }  
  66.   
  67.   
  68. JNIEXPORT jint JNICALL Java_peter_amlogic_serial_SerialThread_00024I2c_open(JNIEnv *env, jobject obj, jstring file)  
  69. {  
  70.       char fileName[64];  
  71.       const jbyte *str;  
  72.          
  73.       str = (*env)->GetStringUTFChars(env, file, NULL);  
  74.       if (str == NULL) {  
  75.           LOGI("Can't get file name!");  
  76.           return -1;  
  77.       }  
  78.       sprintf(fileName, "%s", str);  
  79.           LOGI("will open i2c device node %s", fileName);  
  80.       (*env)->ReleaseStringUTFChars(env, file, str);  
  81.       return open(fileName, O_RDWR);  
  82. }  
  83.      
  84. JNIEXPORT jint JNICALL Java_peter_amlogic_serial_SerialThread_00024I2c_read(JNIEnv * env, jobject obj, jint fileHander, jint slaveAddr, jintArray bufArr, jint len)  
  85. {  
  86.       jint *bufInt;  
  87.       char *bufByte;  
  88.       int res = 0, i = 0, j = 0;  
  89.          
  90.       if (len <= 0) {  
  91.           LOGE("I2C: buf len <=0");  
  92.           goto err0;  
  93.       }  
  94.          
  95.       bufInt = (jint *) malloc(len * sizeof(int));  
  96.       if (bufInt == 0) {  
  97.           LOGE("I2C: nomem");  
  98.           goto err0;  
  99.       }  
  100.       bufByte = (char*) malloc(len);  
  101.       if (bufByte == 0) {  
  102.           LOGE("I2C: nomem");  
  103.           goto err1;  
  104.       }  
  105.          
  106.       (*env)->GetIntArrayRegion(env, bufArr, 0, len, bufInt);  
  107.          
  108.       memset(bufByte, '\0', len);  
  109.       if ((j = read(fileHander, bufByte, len)) != len) {  
  110.         LOGE("read fail in i2c read jni i = %d buf 4", i);  
  111.         goto err2;          
  112.     } else   
  113.       
  114.     {  
  115.         for (i = 0; i < j ; i++)  
  116.             bufInt[i] = bufByte[i];  
  117.         LOGI("return %d %d %d %d in i2c read jni", bufByte[0], bufByte[1], bufByte[2], bufByte[3]);  
  118.         (*env)->SetIntArrayRegion(env, bufArr, 0, len, bufInt);  
  119.     }  
  120.        
  121.     free(bufByte);  
  122.     free(bufInt);  
  123.        
  124.     return j;  
  125.    
  126. err2:  
  127.     free(bufByte);  
  128. err1:  
  129.     free(bufInt);  
  130. err0:  
  131.     return -1;                                            
  132. }  
  133.      
  134. JNIEXPORT jint JNICALL Java_peter_amlogic_serial_SerialThread_00024I2c_write(JNIEnv *env, jobject obj, jint fileHander, jint slaveAddr, jint mode, jintArray bufArr, jint len)  
  135. {  
  136. #if 0  
  137.       jint *bufInt;  
  138.       char *bufByte;  
  139.       int res = 0, i = 0, j = 0;  
  140.          
  141.       if (len <= 0) {  
  142.           LOGE("I2C: buf len <=0");  
  143.           goto err0;  
  144.       }  
  145.          
  146.       bufInt = (jint *) malloc(len * sizeof(int));  
  147.       if (bufInt == 0) {  
  148.           LOGE("I2C: nomem");  
  149.           goto err0;  
  150.       }  
  151.       bufByte = (char*) malloc(len + 1);  
  152.       if (bufByte == 0) {  
  153.           LOGE("I2C: nomem");  
  154.           goto err1;  
  155.       }  
  156.          
  157.       (*env)->GetIntArrayRegion(env, bufArr, 0, len, bufInt);  
  158.       bufByte[0] = mode;  
  159.       for (i = 0; i < len; i++)  
  160.           bufByte[i + 1] = bufInt[i];        
  161.                 
  162.       if ((j = write(fileHander, bufByte, len + 1)) != len + 1) {  
  163.         LOGE("write fail in i2c");  
  164.         goto err2;          
  165.     }  
  166.        
  167.     LOGI("I2C: write %d byte", j);  
  168.     free(bufByte);  
  169.     free(bufInt);  
  170.        
  171.     return j - 1;  
  172.    
  173. err2:  
  174.     free(bufByte);  
  175. err1:  
  176.     free(bufInt);  
  177. err0:  
  178.     return -1;    
  179.       
  180. #endif     
  181. }  
  182.      
  183. JNIEXPORT void JNICALL Java_peter_amlogic_serial_SerialThread_00024I2c_close(JNIEnv *env, jobject obj, jint fileHander)  
  184. {  
  185.       close(fileHander);  
  186. }  


 

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函数参数较多,fileHanderopen device之后返回的描述符;

i2c_addri2c芯片上要去读取的地址,本项目中可以从0地址去读;

buf[ ] 中存放的是读取的数据。类型为byte,因此在jni中也应该定义为byte

GetByteArrayRegion:获得Javabyte[]类型参数,将Java传来的字节数组buf,复制len长度的数据到bufInt中。 

SetByteArrayRegion:正好相反,将bufInt中的值复制len长度到Java中的bufArr字节数组。

3.  close函数

open函数对应。