转自:http://blog.csdn.net/yunjinwang/article/details/8461711
Sensor作为Android系统的一个输入设备,对Android设备来说是必不可少的。Sensor主要包括G-Sensor、LightsSensor、ProximitySensor、TemperatureSensor等。这里主要对G-Sensor模块进行解析。
我的平台是AML8276,android系统是4.0.4,kernel是3.0,所用的gsensor是kionix_accel;
整个sensor的工作包括driver, HAL, framework(c/c++, java)和application层;
首先我们从驱动driver开始,然后一层层向上看;
一, 驱动层
在驱动层,内核需要增加和修改的部分包括:
1,相应硬件模块驱动代码,包括两个文件,这里是
kionix_accel.h,
kionix_accel.c,分别将kionix_accel.h放到kernel/common/customer/include/linux/中,将kionix_accel.c放到kernel/customer/drivers/misc/中;
2,编译目录(
kernel/customer/drivers/misc/
)下的Makefie 和KConfig,在KConfig中增加:
config SENSORS_KXTJ2
tristate "KXTJ2 accelerometer sensor driver"
depends on I2C
help
Say yes here to support Kionix's KXTJ2 accelerometer sensor
在MakeFile 下增加:obj-$(CONFIG_SENSORS_KXTJ2) += kionix_accel.o
3, 在平台编译配置文件中(也就是make menuconfig生成的),增加:CONFIG_SENSORS_KXTJ2=y------->指定编译到内核中,如果是m则编译成ko;
4,在平台模块代码文件中(kernel/customer/
boards/board-m6g17-t069.c
),在相应的i2c配置中,增加此模块:
static struct i2c_board_info __initdata aml_i2c_bus_info_b[] = {
........
#ifdef CONFIG_SENSORS_KXTJ2
{
I2C_BOARD_INFO("kionix_accel", KIONIX_ACCEL_I2C_ADDR),
//.irq = INT_GPIO_1,
.platform_data = (void *) &kionix_accel_pdata,
},
#endif
}
经过以上几步操作以后,就可以将此模块驱动编译到内核中。
G-sensor driver工作的大致流程:系统开机后,内核会先加载i2c总线驱动,然后再加载设备驱动,在设备驱动中的init函数中通过调用i2c_add_driver(&kionix_accel_driver)注册i2c_driver;此函数将driver注册到i2c_bus_type的总线上,此总线的匹配规则是利用i2c_client的名称和i2c_driver中id_table中的名称作匹配。其中i2c_client是系统自动创建的,
board-m6g17-t069.c文件中的结构变量
static struct i2c_board_info __initdata aml_i2c_bus_info_b中需要添加G-sensor的设备信息。
当匹配成功时,i2c_driver中的probe()函数开始执行。
module_init(kionix_accel_init)---->i2c_add_driver(&kionix_accel_driver)----->
static struct i2c_driver kionix_accel_driver = {
.driver = {
.name = KIONIX_ACCEL_NAME,
.owner = THIS_MODULE,
},
.probe = kionix_accel_probe,
.remove = __devexit_p(kionix_accel_remove),
.id_table = kionix_accel_id,
};
Probe()函数
kionix_accel_probe()主要完成以下功能:
1.从i2c_client结构中得到初始化信息
2.创建G-sensor的工作队列
2.注册input_device设备
3.读取Chip ID
4.设置寄存器,使能G-sensor
5.设置并启动中断
当G-sensor上报数据的时候会触发中断,然后在中断处理函数中提交一个报值的任务到队列中并禁止中断。
在工作队列中读数G-sensor的数据并上报到input子系统中,最后使能中断。
系统启动后,驱动会在/sys/class/input/inputX下生成相应的设备文件,里面name节点包含有相应的模块名;
shell@
capabilities
device
event4
id
modalias
name
phys
power
properties
subsystem
uevent
uniq
同时会在/dev/input/里面也会生成inputX的节点,它是用来实际读取数据的。
驱动在工作的时候,主要分两部分:数据的采集及上报、设备的控制;
1,数据的采集主要是指通过I2C从硬件设备读取相关的数据并把数据上报,读取数据有两种方式,一种是通过中断,当有数据时,设备会发出中断信号给驱动,驱动去采集,另一种就是采用定时器不断的去定时采集数据;由于sensor也属于输入设备(
还有TouchScreen,Keyboard,Mouse,Sensor等),所以上报的时候,也要报到linux kernel的输入子系统里面,上层通过相应的子系统设备节点读取数据。
上报数据的过程:static void report_abs(void)
{
short x,y,z,tilt;
if(read_data(&x,&y,&z,&tilt) != 0) {
/* report the absulate sensor data to input device */
input_report_abs(idev, ABS_X, y);
input_report_abs(idev, ABS_Y, x);
input_report_abs(idev, ABS_Z, z);
input_sync(idev);
}
2,设备的控制包括打开、关闭、设置参数和使能等,一般上层会通过ioctl方式来交互
二, HAL层
android的HAL层,相当于它的应用层中的驱动,HAL与内核硬件驱动密切相关,由于硬件模块的差别性,HAL代码的编写也各有差别,特别是关于sensor的HAL代码基本上都要自己去实现,但基本架构是一样的。
sensor的HAL结构基本分两部分,一部分是控制操作,一部分是数据操作;
1,首先在android\hardware\libhardware\include\hardware目录下,有sensors.h文件,定义了struct sensors_module_t(sensor模块对象结构,如get_list), struct sensor_t(具体sensor设备对象结构,如名字,类型), struct sensors_poll_device_t(每个设备操作数据结构,如激活、设置参数、poll等), typedef struct sensors_event_t(sensor的事件结构,如类型、数据), 同时也定义了所有传感器的类型:
/**
* Sensor types
*/
#define SENSOR_TYPE_ACCELEROMETER 1
#define SENSOR_TYPE_MAGNETIC_FIELD 2
#define SENSOR_TYPE_ORIENTATION 3
#define SENSOR_TYPE_GYROSCOPE 4
#define SENSOR_TYPE_LIGHT 5
#define SENSOR_TYPE_PRESSURE 6
#define SENSOR_TYPE_TEMPERATURE 7 // deprecated
#define SENSOR_TYPE_PROXIMITY 8
#define SENSOR_TYPE_GRAVITY 9
#define SENSOR_TYPE_LINEAR_ACCELERATION 10
#define SENSOR_TYPE_ROTATION_VECTOR 11
#define SENSOR_TYPE_RELATIVE_HUMIDITY 12
#define SENSOR_TYPE_AMBIENT_TEMPERATURE 13
在android/hardware/amlogic/sendsors/aml_gsensor目录是特定平台实际HAL的代码存放的位置,当然也有的平台只会给一个so的文件,不给源码。
在sensor_aml.cpp中,首先要定义HAL_MODULE_INFO_SYM,这个是每个HAL模块必须的,
struct sensors_module_t HAL_MODULE_INFO_SYM = {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: SENSORS_HARDWARE_MODULE_ID,
name: "Sensors module",
author: "Amlogic",
methods: &sensors_module_methods,
},
get_sensors_list: sensors__get_sensors_list,
};
static int sensors__get_sensors_list(struct sensors_module_t* module,
struct sensor_t const** list)
{
*list = sSensorList;
return ARRAY_SIZE(sSensorList);
}
/* The SENSORS Module */
static const struct sensor_t sSensorList[] = {
{ "BMA250 3-axis Accelerometer",
"Bosch",
1, SENSORS_ACCELERATION_HANDLE,
SENSOR_TYPE_ACCELEROMETER,
4.0f*9.81f,
(4.0f*9.81f)/1024.0f,
0.2f,
0,
{ }
},
#ifdef ENABLE_LIGHT_SENSOR
{ "Light sensor",
"(none)",
1, SENSORS_LIGHT_HANDLE,
SENSOR_TYPE_LIGHT, 5000.0f, 1.0f, 1.0f, 20000,{ } },
#endif
};
可以看出在事先定义当前支持的sensor模块,android通过module->get_sensors_list获取。
获取module后,利用open_sensors();得到hw_device_t ==sensors_poll_device_t==sensors_poll_context_t->device mSensor结构对象,这个结构对象在初始化时会创建相应的sensor对象,且它们都是以SensorBase为基础类,
sensors_poll_context_t::sensors_poll_context_t()
{
mSensors[aml_accel] = new GSensor();
mPollFds[aml_accel].fd = mSensors[aml_accel]->getFd();
mPollFds[aml_accel].events = POLLIN;
mPollFds[aml_accel].revents = 0;
#ifdef ENABLE_LIGHT_SENSOR
mSensors[aml_light] = new LightSensor();
mPollFds[aml_light].fd = mSensors[aml_light]->getFd();
mPollFds[aml_light].events = POLLIN;
mPollFds[aml_light].revents = 0;
#endif
}
通过
mSensor
对象就可以调用 activate、setDelay、poll进行激活读取数据处理了。
mSensors[aml_accel] = new GSensor();
在创建GSensor对象时会对/sys/class/input/inputX目录下的name读取,通过对比名称判断当前sensor到底是在哪个目录并记录下path,在后面对设备进行设置,也就是控制部分会用到这个目录下的结点;
同时由于
GSensor 是继承sensorBase的,所以在构造sendsorBase的时候会找到相应的/dev下的inputX设备open得到设备fd,用于后面读取数据,也就是数据部分。
HAL层准备好后,最后会编译成一个库,这里为sensor.amlogic.so
三, Framework层
对于每一个模块,framework层是最复杂的,它涉及到java部分和C++部分,且根据功能,又可分为service部分和manager部分,它们之间是通过binder进行通信的。
frameworks/base/libs/gui/ISensorServer.cpp
class ISensorServer : public IInterface
{
public:
DECLARE_META_INTERFACE(SensorServer);
virtual Vector<Sensor> getSensorList() = 0;
virtual sp<ISensorEventConnection> createSensorEventConnection() = 0;
};
在Android中,和Sensor相关的几个类是:
SensorManager : 通过它实现系统对Sensor的相关调用。
SensorEvent :对各个Sensor数据的封装,具体可以参考Android的开发文档。
SensorEventListener :对Sensor数据的监视,一旦有数据,就会调相应的函数。
Sensor : 对Sensor的封装。
对于service部分: 它是负责与HAL层建立联系并处理实际数据的服务。
frameworks/base/services/sensorservice/sensorService.cpp , 它继承了public BnSensorServer
系统启动时会执行systemProcess,同时会加载sensorService.java进程,在sensorService.java的构造函数中调用JNI方法_sensor_control_init()。
sensorService.cpp中SensorService::onFirstRef()会被执行,会创建SensorDevice& dev(SensorDevice::getInstance())对象,通过SensorService::threadLoop()里就对各个sensor进行poll并将数据发送到对应的申请connection中connection->sendEvents(buffer, count, scratch);
SensorDevice是一个单一对象类,故SensorDevice::getInstance()会在同一进程中只保留一个对象,SensorDevice::SensorDevice()通过hardware.c中读取HAL层生成的sensor.amlogic.so库。
对于manager部分:它是负责给应用程序提供接口的,与sensorserivce通过binder进行交互数据与控制。
frameworks/base/core/java/android/hardware/SensorManager.java
frameworks/base/core/jni/android_hardware_SensorManager.cpp
frameworks/base/libs/gui/sensorManager.cpp
android_hardware_SensorManager.cpp:
static JNINativeMethod gMethods[] = {
{"nativeClassInit", "()V", (void*)nativeClassInit },
{"sensors_module_init","()I", (void*)sensors_module_init },
{"sensors_module_get_next_sensor","(Landroid/hardware/Sensor;I)I", (void*)sensors_module_get_next_sensor },
{"sensors_create_queue", "()I", (void*)sensors_create_queue },
{"sensors_destroy_queue", "(I)V", (void*)sensors_destroy_queue },
{"sensors_enable_sensor", "(ILjava/lang/String;II)Z", (void*)sensors_enable_sensor },
{"sensors_data_poll", "(I[F[I[J)I", (void*)sensors_data_poll },
};
sensors_module_init()---->SensorManager::getInstance();由于SensorManager也是单一对象类,这里生成实体对象;
sensors_create_queue()----->SensorManager& mgr.createEventQueue():
sp<SensorEventQueue> SensorManager::createEventQueue()
{
sp<SensorEventQueue> queue;
Mutex::Autolock _l(mLock);
while (assertStateLocked() == NO_ERROR) {
sp<ISensorEventConnection> connection =
mSensorServer->createSensorEventConnection();
if (connection == NULL) {
// SensorService just died.
LOGE("createEventQueue: connection is NULL. SensorService died.");
continue;
}
queue = new SensorEventQueue(connection);
break;
}
return queue;
}
通过创建一个connection来建立queuece,其实就是利用connection中与sensorService建立的channel:
mSensorChannel = mSensorEventConnection->getSensorChannel();
通过循环获取sensor list中的各个对象的属性:
sensors_module_get_next_sensor()------>sensorManager::getSensorList()----->SensorManager::assertStateLocked()---->mSensorServer->getSensorList()通过binder从sensorService获取sensorlist;
使能某一sensor对象:
sensors_enable_sensor()---->queue->enableSensor(sensor, delay)---->mSensorEventConnection->setEventRate(handle, us2ns(us))----->
通过ISensorEventConnection对象与sensorService:SensorEventConnection进行交互-------->
SensorService::SensorEventConnection::enableDisable(int handle, bool enabled)---> SensorService::enable()---->mActiveConnections.add(connection)只是将connection加入到激活数组中,而并非直接使能或关闭硬件;
循环监听事件:
sensorChannel用一对pipe来sensorService到sensorEventQueue的事件信息。
sensors_data_poll()------->queue->read(&event, 1)---->mSensorChannel->read()-
---->通过pipe<------ SensorChannel::write()<---------mChannel->write() <----------SensorService::SensorEventConnection::sendEvents() <-------activeConnections[i]->sendEvents(buffer, count, scratch)<---------SensorService::threadLoop()
四, 应用层
一个应用要实现Sensor的事件监听,要做到如下几步:
1、定义要监控的Sensor。
Sensor lightSensor = null;
SensorManager sensormanager=null;
sensormanager = (SensorManager)getSystemService(SENSOR_SERVICE);
lightSensor = sensormanager.getDefaultSensor(Sensor.TYPE_LIGHT);
2、实现SensorEvenetListener。
private SensorEventListener mListener = new SensorEventListener() {
public void onSensorChanged(SensorEvent event) {
... ...
if (event.sensor==lightSensor)
{
Log.i("", "Found light sensor");
}
... ...
}
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
};
3、向系统注册SensorEventListener。一般在resume中进行注册。
sensormanager= (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = (sensormanager.getSensorList(sensor)).get(0);
sensormanager.registerListener(mListener, mSensor,SensorManager.SENSOR_DELAY_NORMAL);
用完之后,记得注销,一般在onStop的时候注销。
sensormanager.unregisterListener(mListener);
这样就可以用Sensor了,当sensor的数据发生变化时,就会传过来。