anrdoid iic

2023-10-06 20:02
文章标签 iic anrdoid

本文主要是介绍anrdoid iic,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

摘自:http://blog.csdn.net/rickbeyond/article/details/7839245

 

Android平台读写i2c设备开发笔记一
分类: android开发 2012-08-07 14:56 297人阅读 评论(0) 收藏 举报

在android开发和移植过程中,有时需要对某设备进行读写,但系统可能并未提供相应的服务。我们就需要自己开发硬件访问服务来控制设备。下面的例子是读写最简单的i2c设备eeprom的流程, i2c的驱动编写有两种方式,一种是利用系统提供的i2c-dev.c来实现一个i2c适配器的设备文件,然后通过在应用层操作I2C适配器来控制I2C设备;另一种是为I2C从设备独立编写一个设备驱动,不需要i2c-dev.c文件。由于前者比较简单通用性强,我们采用前者来展开。

根据android层次划分,我们照例对开发分为如下几步:

1. 添加HAL层接口模块访问设备

2. 使用JNI在应用程序框架层添加服务访问接口

3. 使用服务接口api开发应用程序


一. 添加HAL层接口模块访问设备

首先确认物理设备正常。根据开发板说明书获知设备挂载在/dev/i2c-1上,检测到该设备的存在,则通用设备驱动正常。

eeprom设备为at24c**系列,根据说明书获知设备从地址为0x50,准备工作完毕。

1. 编写hal层接口模块头文件iic.h

进入源码根目录下hardware/libhardware/include/hardware目录新建iic.h,代码如下:


[cpp] view plaincopyprint?
#ifndef ANDROID_IIC_INTERFACE_H
#define ANDROID_IIC_INTERFACE_H
#include <hardware/hardware.h>
__BEGIN_DECLS
/*定义模块ID*/
#define IIC_HARDWARE_MODULE_ID "iic"
/*硬件模块结构体*/
struct iic_module_t {
struct hw_module_t common;
};
/*硬件接口结构体*/
struct iic_device_t {
struct hw_device_t common;
int fd;
int (*iic_write)(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, unsigned short subAddr, int len);
int (*iic_read)(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, int len);
};
__END_DECLS
#endif

#ifndef ANDROID_IIC_INTERFACE_H  #define ANDROID_IIC_INTERFACE_H  #include <hardware/hardware.h>  __BEGIN_DECLS  /*定义模块ID*/  #define IIC_HARDWARE_MODULE_ID "iic"  /*硬件模块结构体*/  struct iic_module_t {  struct hw_module_t common;  };  /*硬件接口结构体*/  struct iic_device_t {  struct hw_device_t common;  int fd;  int (*iic_write)(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, unsigned short subAddr, int len);  int (*iic_read)(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, int len);  };  __END_DECLS  #endif


 

这里定义了iic_write和iic_read两个接口,头文件按照hal规范编写。

2. 编写hal层接口模块文件

进入源码根目录下hardware/libhardware/modules目录新建iic目录,并在iic目录中添加iic.c,代码如下:


[cpp] view plaincopyprint?
#include <hardware/hardware.h>
#include <hardware/iic.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <stdio.h>
#include<linux/i2c.h>
#include<linux/i2c-dev.h>
#include <stdlib.h>
#include <linux/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <string.h>

#include <hardware/hardware.h>  
#include <hardware/iic.h>  
#include <fcntl.h>  
#include <errno.h>  
#include <cutils/log.h>  
#include <cutils/atomic.h> 
#include <stdio.h>
#include<linux/i2c.h>
#include<linux/i2c-dev.h>
#include <stdlib.h>
#include <linux/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <string.h>


[cpp] view plaincopyprint?
<SPAN style="FONT-SIZE: 14px">#define DEVICE_NAME "/dev/i2c-1"
#define MODULE_NAME "iic"
#define MODULE_AUTHOR "mfayz@sohu.com"
#define I2C_RETRIES 0x0701/* number of times a device address should be polled when not acknowledging */
#define I2C_TIMEOUT 0x0702/* set timeout in units of 10 ms */
#define I2C_RDWR 0x0707
/*********定义struct i2c_rdwr_ioctl_data和struct i2c_msg,要和内核一致*******/
struct i2c_msg
{
unsigned short addr;
unsigned short flags;
#define I2C_M_TEN 0x0010
#define I2C_M_RD 0x0001
unsigned short len;
unsigned char *buf;
};
struct i2c_rdwr_ioctl_data {
struct i2c_msg *msgs;/* pointers to i2c_msgs */
int nmsgs; /* number of i2c_msgs */
};
/*设备打开和关闭接口*/
static int iic_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);
static int iic_device_close(struct hw_device_t* device);
/*设备访问接口*/
static int iic_write(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, unsigned short subAddr, int len);
static int iic_read(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, int len);
/*模块方法表*/
static struct hw_module_methods_t iic_module_methods = {
open: iic_device_open
};
struct i2c_rdwr_ioctl_data iic_data;
int ret;
/*模块实例变量*/
struct iic_module_t HAL_MODULE_INFO_SYM = {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: IIC_HARDWARE_MODULE_ID,
name: MODULE_NAME,
author: MODULE_AUTHOR,
methods: &iic_module_methods, //实现了一个open的方法供jni层调用,从而实例化eeprom_device_t
}
};
static int iic_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device){
struct iic_device_t* dev;
dev = (struct iic_device_t*)malloc(sizeof(struct iic_device_t));
if(!dev) {
LOGE("iic Stub: failed to alloc space");
return -EFAULT;
}else{
LOGE("hal: alloc space succ!");
}
memset(dev, 0, sizeof(struct iic_device_t));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (hw_module_t*)module;
dev->common.close = iic_device_close;
dev->iic_write = iic_write;
dev->iic_read = iic_read;
*device = &dev->common; //将实例化后的iic_device_t地址返回给jni层,这样jni层就可以直接调用方法了。
if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {
LOGE("iic Stub hal: failed to open /dev/i2c-1 -- %s.", strerror(errno));
free(dev);
return -EFAULT;
}else{
LOGI("iic Stub hal: open /dev/i2c-1 successfully.");
iic_data.nmsgs=2;
iic_data.msgs=(struct i2c_msg*)malloc(iic_data.nmsgs*sizeof(struct i2c_msg));
if(!iic_data.msgs){
LOGE("malloc error");
close(dev->fd);
exit(1);
}
ioctl(dev->fd, I2C_TIMEOUT, 2);//设置超时时间
ioctl(dev->fd, I2C_RETRIES, 1);//设置重发次数
}
return 0;
}
static int iic_device_close(struct hw_device_t* device) {
struct iic_device_t* iic_device = (struct iic_device_t*)device;
if(iic_device) {
close(iic_device->fd);
free(iic_device);
}
return 0;
}
static int iic_write(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, unsigned short subAddr, int len) {
int count = 0;
unsigned char data[2];
unsigned char bytes;
LOGI("iic Stub hal: set value %s to device.", dataBuf);
iic_data.nmsgs=1;
(iic_data.msgs[0]).len=2; //写入地址位和数据长度
(iic_data.msgs[0]).addr=slaveAddr;// 设备地址0x50
(iic_data.msgs[0]).flags=0; //write
(iic_data.msgs[0]).buf=(unsigned char*)malloc(2);
while(count<len){
bytes = 0;
data[bytes++] = subAddr;//先写子地址
data[bytes] = dataBuf[count];//再写value
LOGI("IIC write HAL: %x,%x", data[0],data[1]);
(iic_data.msgs[0]).buf=data;//the data to write
ret=ioctl(dev->fd,I2C_RDWR,(unsigned long)&iic_data);
if(ret<0){
LOGI("IIC HAL ioctl error");
}
count++;
subAddr++;
usleep(3000);//延迟3毫秒
}
LOGI("you have write %s into iic at %x address len: %d",dataBuf, subAddr, len);
return 0;
}
static int iic_read(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, int len){
int count = 0;
iic_data.nmsgs=1;
(iic_data.msgs[0]).len=1;
(iic_data.msgs[0]).addr=slaveAddr; // 设备地址
(iic_data.msgs[0]).flags=I2C_M_RD;//read
(iic_data.msgs[0]).buf=(unsigned char*)malloc(1);
while(count<len){
(iic_data.msgs[0]).buf= dataBuf++;
if(ioctl(dev->fd,I2C_RDWR,(unsigned long)&iic_data)<0){
LOGE("ioctl read error");
}
LOGI("IIC read HAL: %x", dataBuf[count]);
count++;
}
return 0;
}</SPAN>

#define DEVICE_NAME "/dev/i2c-1"  
#define MODULE_NAME "iic"  
#define MODULE_AUTHOR "mfayz@sohu.com"  #define I2C_RETRIES 0x0701/* number of times a device address should be polled when not acknowledging */
#define I2C_TIMEOUT 0x0702/* set timeout in units of 10 ms */
#define I2C_RDWR         0x0707/*********定义struct i2c_rdwr_ioctl_data和struct i2c_msg,要和内核一致*******/
struct i2c_msg{unsigned short addr;unsigned short flags;#define I2C_M_TEN 0x0010#define I2C_M_RD 0x0001unsigned short len;unsigned char *buf;};struct i2c_rdwr_ioctl_data {
struct i2c_msg *msgs;/* pointers to i2c_msgs */
int nmsgs; /* number of i2c_msgs */
}; /*设备打开和关闭接口*/  
static int iic_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);  
static int iic_device_close(struct hw_device_t* device);  /*设备访问接口*/  
static int iic_write(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, unsigned short subAddr, int len);  
static int iic_read(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, int len); /*模块方法表*/  
static struct hw_module_methods_t iic_module_methods = {  open: iic_device_open  
};  struct i2c_rdwr_ioctl_data iic_data;
int ret;/*模块实例变量*/  
struct iic_module_t HAL_MODULE_INFO_SYM = {  common: {  tag: HARDWARE_MODULE_TAG,  version_major: 1,  version_minor: 0,  id: IIC_HARDWARE_MODULE_ID,  name: MODULE_NAME,  author: MODULE_AUTHOR,  methods: &iic_module_methods, //实现了一个open的方法供jni层调用,从而实例化eeprom_device_t }  
};  static int iic_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device){  struct iic_device_t* dev;dev = (struct iic_device_t*)malloc(sizeof(struct iic_device_t));  if(!dev) {  LOGE("iic Stub: failed to alloc space");  return -EFAULT;  }else{
LOGE("hal: alloc space succ!");}  memset(dev, 0, sizeof(struct iic_device_t));  dev->common.tag = HARDWARE_DEVICE_TAG;  dev->common.version = 0;  dev->common.module = (hw_module_t*)module;  dev->common.close = iic_device_close;  dev->iic_write = iic_write;dev->iic_read = iic_read;*device = &dev->common;     //将实例化后的iic_device_t地址返回给jni层,这样jni层就可以直接调用方法了。if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {  LOGE("iic Stub hal: failed to open /dev/i2c-1 -- %s.", strerror(errno));
free(dev);  return -EFAULT;  }else{    LOGI("iic Stub hal: open /dev/i2c-1 successfully."); 
iic_data.nmsgs=2; 
iic_data.msgs=(struct i2c_msg*)malloc(iic_data.nmsgs*sizeof(struct i2c_msg)); if(!iic_data.msgs){LOGE("malloc error");
close(dev->fd);exit(1);}
ioctl(dev->fd, I2C_TIMEOUT, 2);//设置超时时间ioctl(dev->fd, I2C_RETRIES, 1);//设置重发次数}return 0;  
} static int iic_device_close(struct hw_device_t* device) {  struct iic_device_t* iic_device = (struct iic_device_t*)device;  if(iic_device) {  close(iic_device->fd);  free(iic_device);  }  return 0;  
}  static int iic_write(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, unsigned short subAddr, int len) {
int count = 0;
unsigned char data[2];
unsigned char bytes;LOGI("iic Stub hal: set value %s to device.", dataBuf); 
iic_data.nmsgs=1; (iic_data.msgs[0]).len=2; //写入地址位和数据长度(iic_data.msgs[0]).addr=slaveAddr;// 设备地址0x50(iic_data.msgs[0]).flags=0; //write(iic_data.msgs[0]).buf=(unsigned char*)malloc(2);
while(count<len){bytes = 0;data[bytes++] =  subAddr;//先写子地址 data[bytes]   = dataBuf[count];//再写valueLOGI("IIC write HAL: %x,%x", data[0],data[1]);(iic_data.msgs[0]).buf=data;//the data to write ret=ioctl(dev->fd,I2C_RDWR,(unsigned long)&iic_data);if(ret<0){LOGI("IIC HAL ioctl error");}count++;subAddr++;usleep(3000);//延迟3毫秒} LOGI("you have write %s into iic at %x address len: %d",dataBuf, subAddr, len);return 0;  
}  static int iic_read(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, int len){  int count = 0;iic_data.nmsgs=1;(iic_data.msgs[0]).len=1; (iic_data.msgs[0]).addr=slaveAddr; //  设备地址(iic_data.msgs[0]).flags=I2C_M_RD;//read(iic_data.msgs[0]).buf=(unsigned char*)malloc(1);while(count<len){(iic_data.msgs[0]).buf= dataBuf++;
if(ioctl(dev->fd,I2C_RDWR,(unsigned long)&iic_data)<0){LOGE("ioctl read error");}
LOGI("IIC read HAL: %x", dataBuf[count]);
count++;} return 0; 
}


 

注意:需打开设备/dev/i2c-1权限,否则会碰到Pemission Denied错误。从源码根目录下进入system/core/rootdir目录,打开ueventd.rc 添加一行:/dev/i2c-1 0666 root root (这里设备各开发板可能不同)

3. 在iic目录下编写android.mk进行编译


[cpp] view plaincopyprint?
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SRC_FILES := iic.c
LOCAL_MODULE := iic.default
include $(BUILD_SHARED_LIBRARY)

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE_TAGS := optionalLOCAL_PRELINK_MODULE := falseLOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hwLOCAL_SRC_FILES := iic.cLOCAL_MODULE := iic.defaultinclude $(BUILD_SHARED_LIBRARY)


 

编译命令:mmm -B hardware/libhardware/module/iic 编译成功会得到iic.default.so,打包进img默认会被加载。


(待续)

Android平台读写i2c设备开发笔记二
分类: android开发 2012-08-07 16:43 758人阅读 评论(0) 收藏 举报

二、 使用JNI在应用程序框架层添加服务访问接口

APP应用不能直接访问HAL层,需要JNI层访问HAL模块并向上提供API接口。可以直接提供接口,但建议最好使用服务的方式提供访问。

我们先看JNI如何访问刚才的HAL模块。

进入源码根目录下的frameworks/base/service/jni目录,新建com_android_server_IICService.cpp,代码如下:


[cpp] view plaincopyprint?
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include <utils/misc.h>
#include <cutils/log.h>
#include <hardware/hardware.h>
#include <hardware/iic.h>
#include <stdio.h>
namespace android
{
/*在硬件抽象层中定义的硬件访问结构体,参考<hardware/iic.h>*/
struct iic_device_t* iic_device = NULL;
/*通过硬件抽象层定义的硬件访问接口设置硬件寄存器val的值*/
static void iic_setVal(JNIEnv* env, jobject clazz, jstring val, jint slaveAddr, jint subAddr, jint len) {
const char *str = env->GetStringUTFChars(val, NULL);
LOGI("iic JNI: set value %s to device.", str);
if(!iic_device) {
LOGI("iic JNI: device is not open.");
return;
}
iic_device->iic_write(iic_device, (unsigned char*)str, slaveAddr, subAddr, len);
env->ReleaseStringUTFChars(val, str); //注意释放资源
}
/*通过硬件抽象层定义的硬件访问接口读取硬件寄存器val的值*/
static jstring iic_getVal(JNIEnv* env, jobject clazz, jint slaveAddr, jint len) {
unsigned char* data = (unsigned char*)malloc(len);
iic_device->iic_read(iic_device, data, slaveAddr, len);
if(!iic_device) {
LOGI("iic JNI: device is not open.");
}
int i = 0;
for(;i<strlen((const char*)data);i++){
LOGI("data: %c ", data[i]);
}
//LOGI("iic JNI: get value %s from device @ %x address!", data, subAddr);
jstring tmp = env->NewStringUTF((const char*)data);
free(data);
data = NULL;
return tmp;
}
/*通过硬件抽象层定义的硬件模块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);
}
/*通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件*/
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;
}
/*JNI方法表*/
static const JNINativeMethod method_table[] = {
{"init_native", "()Z", (void*)iic_init},
{"setVal_native", "(Ljava/lang/String;III)V", (void*)iic_setVal},
{"getVal_native", "(III)Ljava/lang/String;", (void*)iic_getVal},
};
/*注册JNI方法*/
int register_android_server_IICService(JNIEnv *env) {
return jniRegisterNativeMethods(env, "com/android/server/IICService", method_table, NELEM(method_table));
}
};

#include "jni.h"  
#include "JNIHelp.h"  
#include "android_runtime/AndroidRuntime.h"  
#include <utils/misc.h>  
#include <cutils/log.h>  
#include <hardware/hardware.h>  
#include <hardware/iic.h>  
#include <stdio.h>namespace android  
{  /*在硬件抽象层中定义的硬件访问结构体,参考<hardware/iic.h>*/  struct iic_device_t* iic_device = NULL;  /*通过硬件抽象层定义的硬件访问接口设置硬件寄存器val的值*/  static void iic_setVal(JNIEnv* env, jobject clazz, jstring val, jint slaveAddr, jint subAddr, jint len) {  const char *str = env->GetStringUTFChars(val, NULL);  LOGI("iic JNI: set value %s to device.", str);  if(!iic_device) {  LOGI("iic JNI: device is not open.");  return;  }  iic_device->iic_write(iic_device, (unsigned char*)str, slaveAddr, subAddr, len);  env->ReleaseStringUTFChars(val, str);  //注意释放资源}  /*通过硬件抽象层定义的硬件访问接口读取硬件寄存器val的值*/  static jstring iic_getVal(JNIEnv* env, jobject clazz, jint slaveAddr, jint len) {unsigned char* data = (unsigned char*)malloc(len);iic_device->iic_read(iic_device, data, slaveAddr, len);if(!iic_device) {  LOGI("iic JNI: device is not open.");  }int i = 0;for(;i<strlen((const char*)data);i++){LOGI("data: %c ", data[i]);}  //LOGI("iic JNI: get value %s from device @ %x address!", data, subAddr);jstring tmp = env->NewStringUTF((const char*)data);free(data);data = NULL;return tmp;   } /*通过硬件抽象层定义的硬件模块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);  }  /*通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件*/  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;        }  /*JNI方法表*/  static const JNINativeMethod method_table[] = {  {"init_native", "()Z", (void*)iic_init},  {"setVal_native", "(Ljava/lang/String;III)V", (void*)iic_setVal},  {"getVal_native", "(III)Ljava/lang/String;", (void*)iic_getVal},  };  /*注册JNI方法*/  int register_android_server_IICService(JNIEnv *env) {  return jniRegisterNativeMethods(env, "com/android/server/IICService", method_table, NELEM(method_table));  }  
};

然后需要让android启动时加载此jni模块

在同目录下修改onload.cpp:

在namespace android中添加一行 int register_android_server_IICService(JNIEnv *env);

在JNI_onLoad方法中添加一行 register_android_server_IICService(env);

在同目录下修改Android.mk:

LOCAL_SRC_FILES增加一行 com_android_server_IICService \

编译命令:mmm frameworks/base/services/jni

注意:

1. HAL是根据iic_init中的IIC_HARDWARE_MODULE_ID加载相应模块。

2. 根据jni规则我们知道这里存在一个调用jni的java服务类:com.android.server.IICService 位置为:frameworks/base/services/java/com/android/server 代码如下:


[java] view plaincopyprint?
package com.android.server;
import android.content.Context;
import android.os.IIICService;
import android.util.Slog;
public class IICService extends IIICService.Stub {
private static final String TAG = "IICService";
IICService() {
init_native();
}
public void setVal(String val,int slaveAddr, int regAddr, int len) {
setVal_native(val, slaveAddr, regAddr, len);
}
public String getVal(int slaveAddr,int len) {
return getVal_native( slaveAddr, len);
}
//本地方法
private static native boolean init_native();
private static native void setVal_native(String val, int slaveAddr, int regAddr, int len);
private static native String getVal_native(int slaveAddr, int len);
};

package com.android.server;  
import android.content.Context;  
import android.os.IIICService;  
import android.util.Slog;  
public class IICService extends IIICService.Stub {  private static final String TAG = "IICService";  IICService() {  init_native();  }  public void setVal(String val,int slaveAddr, int regAddr, int len) {  setVal_native(val, slaveAddr, regAddr, len);  }     public String getVal(int slaveAddr,int len) {  return getVal_native( slaveAddr, len);  }  //本地方法 private static native boolean init_native();  private static native void setVal_native(String val, int slaveAddr, int regAddr, int len);  private static native String getVal_native(int slaveAddr, int len);  
}; 

从代码中我们可以看到它继承了IIICService.Stub,因为硬件访问一般需要放在一个独立的线程中,这里使用了代理的方法来处理app与硬件服务的通信。
我们需要在frameworks/base/core/java/android/os中新建IIICService.aidl(注意是III)

package android.os;
interface IIICService {
void setVal(String val, int slaveAddr, int regAddr, int len);
String getVal(int slaveAddr, int len);
}
它定义了服务的接口,接口在IICService中实现并关联到jni方法中。

同时我们需要修改frameworkd/base下的Android.mk编译文件,在LOCAL_SRC_FILES中增加 core/java/android/os/IIICService.aidl

编译命令: mmm frameworks/base

最后需要把新增的IICService服务加入到ServiceManager中,这样就可以通过ServiceManager进行调用。

修改frameworks/base/services/java/com/android/server下的SystemServer.java 在run()方法中添加

try{

Slog.i(TAG, "IIC SERVICE");

ServiceManager.addService("iic", new IICService());

}catch(Throwable e){

Slog.e(TAG, "Failure starting IIC Service", e);

}
编译命令:mmm frameworks/base/services/java

注意:有可能会编译不通过,因为这里修改了android的官方api, 需要运行make update-api更新frameworks/base/api/current.xml

打包后,app就可以使用IICService接口来访问硬件了。
下一节发上app相关代码

(待续)

Android平台读写i2c设备开发笔记三
分类: android开发 2012-08-07 17:06 677人阅读 评论(0) 收藏 举报

三、app调用服务接口访问硬件

上主要代码EEPROMActivity.java


[java] view plaincopyprint?
package com.zkgd.eeprom;
import android.app.Activity;
import android.os.Bundle;
import android.os.ServiceManager;
import android.os.IIICService;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class EEPROMActivity extends Activity implements OnClickListener{
private final static String LOG_TAG = "com.zkgd.eeprom";
private IIICService iicService = null;
private EditText valueText = null;
private Button readButton = null;
private Button writeButton = null;
private Button clearButton = null;
int len = 1;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
iicService = IIICService.Stub.asInterface(
ServiceManager.getService("iic"));
valueText = (EditText)findViewById(R.id.edit_value);
readButton = (Button)findViewById(R.id.button_read);
writeButton = (Button)findViewById(R.id.button_write);
clearButton = (Button)findViewById(R.id.button_clear);
readButton.setOnClickListener(this);
writeButton.setOnClickListener(this);
clearButton.setOnClickListener(this);
Log.i(LOG_TAG, "Activity Created");
}
public void onClick(View v) {
if(v.equals(readButton)) {
try {
len = 1;
//在从设备中读取数据
String val = iicService.getVal(0x50,len);
valueText.setText(val);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Remote Exception while reading value from device.");
}
}
else if(v.equals(writeButton)) {
try {
String val = valueText.getText().toString();
len = val.length();
//在从设备的子地址处开始写入数据
iicService.setVal(val,0x50,0x10,len);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Remote Exception while writing value to device.");
}
}
else if(v.equals(clearButton)) {
String text = "";
valueText.setText(text);
}
}
}

package com.zkgd.eeprom;import android.app.Activity;
import android.os.Bundle;
import android.os.ServiceManager;
import android.os.IIICService;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;public class EEPROMActivity extends Activity  implements OnClickListener{
private final static String LOG_TAG = "com.zkgd.eeprom";  private IIICService iicService = null;  private EditText valueText = null;  private Button readButton = null;  private Button writeButton = null;  private Button clearButton = null;  int len = 1;/** Called when the activity is first created. */  @Override  public void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.main);  iicService = IIICService.Stub.asInterface(  ServiceManager.getService("iic"));  valueText = (EditText)findViewById(R.id.edit_value);  readButton = (Button)findViewById(R.id.button_read);  writeButton = (Button)findViewById(R.id.button_write);  clearButton = (Button)findViewById(R.id.button_clear);  readButton.setOnClickListener(this);  writeButton.setOnClickListener(this);  clearButton.setOnClickListener(this);  Log.i(LOG_TAG, "Activity Created");  }  public void onClick(View v) {  if(v.equals(readButton)) {  try {  len = 1;//在从设备中读取数据String val =  iicService.getVal(0x50,len);    valueText.setText(val);  } catch (RemoteException e) {  Log.e(LOG_TAG, "Remote Exception while reading value from device.");  }         }  else if(v.equals(writeButton)) {  try {  String val = valueText.getText().toString();  len = val.length(); //在从设备的子地址处开始写入数据iicService.setVal(val,0x50,0x10,len);  } catch (RemoteException e) {  Log.e(LOG_TAG, "Remote Exception while writing value to device.");  }  }  else if(v.equals(clearButton)) {  String text = "";  valueText.setText(text);  }  }  
}

工程eeprom放置在源码目录package/app/下

编译命令:mmm package/app/eeprom

打包,烧写固件至开发板,启动就可以看到该应用的图标了。


小结:

整个调用流程为:app--->framework层服务--->JNI本地接口--->HAL--->硬件

一个问题,这种方法改动了android原生api,移植通用性不好。如果想做通用app,可以考虑NDK源码开发,底层功能打包成库文件进行调用,又可分为eclipse开发和源码环境开发,推荐源码环境下开发,eclipse老是报缺这缺那的,在源码环境下只要把Android.mk文件写好,基本不会报找不到包找不到方法等错误。

另一个问题,硬件访问会遭遇到权限问题。如果做通用app,需要设备root了,然后在代码里添加权限修改操作,如:"chmod 777 "+getPackageCodePath(); "chmod 777 /dev/i2c-1";

这篇关于anrdoid iic的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/153903

相关文章

【STM32+HAL库】---- 硬件IIC驱动0.96OLED

硬件开发板:STM32G0B1RET6软件平台:cubemax+keil+VScode 内容原著声明 代码借鉴学习于以下文章: STM32 使用硬件IIC驱动0.96寸4针IOLED显示器(HAL库) 1 新建cubemax工程 1.1 配置系统时钟RCC 1.2 配置引脚 1.3 导出工程 略… 2 代码 2.1 OLED_IIC_Config.h /*** **

STM32 IIC

第一块:介绍协议规则,然后用软件模拟的形式来实现协议, 第二块:介绍STM32的IIC外设,然后用硬件来实现协议 因为IIC是同步时序的额,软件模拟协议也非常方便,像我们单片机一样,外挂芯片里的众多外设也是通过读写寄存器来控制运行的,寄存器本身也是存储器的一种,,这个芯片多有的寄存器也是都被分配到了一个线性的存储空间,如果我们想要读写寄存器来控制硬件电路,我们就至少需要定义两个字节数据,一个字节

Linux-IIC驱动(3)-IIC用户态驱动程序设计

之前已经说过,有2种i2c驱动程序的设计,比如说针对EEPROM的驱动程序。我们可以专门编写一个针对EEPROM的驱动程序。另一种方式就是通过i2c-dev,即通过i2c通用通用驱动,来编写一个应用程序,来完成对设备的控制。   我们现在就来实现i2c用户态驱动程序的设计。 通用设备驱动分析 首先需要分析i2c-dev,先打开i2c-dev.c这个文件,找到i2c_dev_init函

Linux-IIC驱动(2)-Linux下IIC子系统的介绍

IIC子系统架构   Linux下IIC的架构模型大概可以分为3层: 第一层是IIC的从设备驱动,他包含图中的device driver和i2c-dev。device driver需要用户编写,i2c-dev由内核实现,包含了IIC设备的通用方法,但是用户不能直接使用这个驱动,需要编写一个用户层驱动,它们2个合起来才可以实现一个驱动程序。   第二层总线驱动,他又叫做控制器驱动

Linux-IIC驱动(1)-IIC总线介绍

IIC我在很久之前就接触并使用过了,现在来回顾一下它的硬件结构和时序   硬件结构 I2C(Inter-Integrated Circuit)总线是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。硬件结构如下:   I2C总线只有两根双向信号线。 SDA: Serial Data Line-数据线 SCL :Serial Clock-时钟线   I2C总线

三、IIC总线协议——2、AT24C02

一、AT24C02介绍         EEPROM是一种掉电后数据不丢失的储存器,常用来存储一些配置信息,在系统重新上电时就可以加载。         AT24C02是一个2K bit的EEPROM存储器,使用IIC通信方式。         A0/1/2 : 设备地址决定引脚。、         WP : 写保护引脚。         SCL : 时钟线。         SDA

57.基于IIC协议的EEPROM驱动控制(4)

(1)顶层代码: module IIC_EEPROM(input wire clk ,input wire reset_n ,input wire key_r ,input wire key_w ,output

Xilinx FPGA Microblaze AXI_IIC使用方法及心得

Xilinx FPGA Microblaze AXI_IIC使用方法及心得 前言 本着好好学习,认真负责的态度,我计划在空闲时间把自己用到的一些模块的使用方法与心得总结下与大家分享下,技术交流的同时共同进步,如有问题,欢迎批评指正! 本次先着重讲下AXI_IIC核的使用,后续还会包括以下模块 UART_AXI核使用及AXI总线详解QSPI_AXI核的使用AXI_DMA与AXI_FIFO使用,

Linux驱动学习之IIC(驱动BH1750)

Linux内核IIC底层驱动,厂家已经写好了,我们需要做的是,修改设备树,调用他的驱动,添加我们设备的信息(在设备树中添加节点),对于初学者来讲,linux驱动学习最重要的不是学习linux内核,而是对设备树的学习(后面会出专题),可以说学会设备树规则,就已经成功了一办,剩下的就是了解API接口。 在设备树中添加设备节点 在根节点外修改I2C节点 (&+标签名==追加)原节点没有的会追

小实战项目-第二章2.3软件IIC 硬件IIC讲解 STM32 IIC通讯协议讲解

这篇章我们说明硬件IIC,软件IIC和相关基础知识在这文章里面 添加链接描述 https://blog.csdn.net/qq_46187594/article/details/141642801 2.3-硬件I2C 我们还使用第0章的工程 初始化硬件IIC 设置串口,方便输出调试 重映射 /*** @brief 重定向printf (重定向fputc),使用时候记得勾选