分类: 嵌入式
2012-04-13 10:12:17
一、首先建立这样一个全局的观念:
Android中sensor在Android系统架构中的位置及其工作。方框图如下:
从以上方框图中,可以看出Android中sensor在系统分为四层:驱动层(Sensor Driver)、硬件抽象层(Native)、中间层(Framework)、应用层(Java)。硬件抽象层与中间层可以合并一起作为Framework层。
针对我们xx这里一个具体的Gsensor,下面将以具体的源码形式来讲解以上的这个系统框图。
二、驱动层(Sensor Driver Layer)
芯片ADXL345为GSensor,至于硬件的具体工作原理,须分析ADXL345的DataSheet。驱动源码位于:xx\custom\common\kernel\accelerometer\adxl345目录。
由于ADXL345是以I2C形式接口挂接到Linux系统,因此同时需要分析Linux的I2C子系统架构(略)。其源码位于:
1、 xx\platform\xx\kernel\drivers\i2c
2、 kernel\drivers\i2c
查看ADXL345.c文件,分析针对于其硬件工作原理的几个函数。硬件初始化:
函数的分析都注释在原理里,红色部分。具体寄存器的设置查看ADXL345的datasheet,具体I2C的通信查看I2C.c文件(i2c控制器的驱动)。
关键问题:这里有个问题,没有弄懂,就是从ADXL345数据寄存器里读取原始数据之后,这个数据并不是我们应用程序所要用的,它需要转化,经过查看代码,可以发现这样一段注释:
/*
* @sign, map: only used in accelerometer/magnetic field
* sometimes, the sensor output need to be remapped before reporting to framework.
* the 'sign' is only -1 or +1 to align the sign for framework's coordinate system
* the 'map' align the value for framework's coordinate system. Take accelerometer
* as an exmaple:
* assume HAL receives original acceleration: acc[] = {100, 0, 100}
* sign[] = {1, -1, 1, 0};
* map[] = {HWM_CODE_ACC_Y, HWM_CODE_ACC_X, HWM_CODE_ACC_Z, 0};
* according to the above 'sign' & 'map', the sensor output need to remap as {y, -x, z}:
* float resolution = unit_numerator*GRAVITY_EARTH/unit_denominator;
* acc_x = sign[0]*acc[map[0]]*resolution;
* acc_y = sign[1]*acc[map[1]]*resolution;
* acc_z = sign[2]*acc[map[2]]*resolution;
*/
struct hwmsen_convert {
s8 sign[C_MAX_HWMSEN_EVENT_NUM];
u8 map[C_MAX_HWMSEN_EVENT_NUM];
};
这样一个转换算法的物理意义是怎样的?????
三、硬件抽象层(Native)
硬件抽象层主要是提供硬件层实现的接口,其代码路径如下:
hardware\libhardware\include\hardware\ sensors.h
其中:
struct sensors_module_t为sensor模块的定义。
struct sensors_module_t {
struct hw_module_t common;
int (*get_sensors_list)(struct sensors_module_t* module,
struct sensor_t const** list);
};
Struct sensor_t为某一个sensor的描述性定义。
struct sensor_t {
const char* name; /* 传感器的名称 */
const char* vendor; /* 传感器的vendor */
int version; /* 传感器的版本 */
int handle; /* 传感器的句柄 */
int type; /* 传感器的类型 */
float maxRange; /* 传感器的最大范围 */
float resolution; /* 传感器的辨析率 */
float power; /* 传感器的耗能(估计值,mA单位)*/
void* reserved[9];
}
struct sensors_event_t表示传感器的数据
/**
* Union of the various types of sensor data
* that can be returned.
*/
typedef struct sensors_event_t {
int32_t version; /* must be sizeof(struct sensors_event_t) */
int32_t sensor; /* sensor identifier */
int32_t type; /* sensor type */
int32_t reserved0; /* reserved */
int64_t timestamp; /* time is in nanosecond */
union {
float data[16];
/* acceleration values are in meter per second per second (m/s^2) */
sensors_vec_t acceleration;
/* magnetic vector values are in micro-Tesla (uT) */
sensors_vec_t magnetic;
sensors_vec_t orientation; /* orientation values are in degrees */
sensors_vec_t gyro; /* gyroscope values are in rad/s */
float temperature; /* temperature is in degrees centigrade (Celsius) */
float distance; /* distance in centimeters */
float light; /* light in SI lux units */
float pressure; /* pressure in hectopascal (hPa) */
};
uint32_t reserved1[4];
} sensors_event_t;
显然,在看完这些数据结构之后,我们都会有这样一个疑问:
这里只是申明了一些结构体,而这些结构体在使用时需要定义,而且结构体中还有一些函数指针,这些函数指针所对应的函数实现又在哪里呢??显然,那必定还要有一个.c源文件来实现这样的一些函数。经过搜索,其文件名为:sensors_hwmsen.c,路径为:
\xxk\source\hardware\sensor\hwmsen。在这里,你会看到get_sensors_list等函数的实现。
四、中间层(Framework)
这里,我也把它叫做JNI层,这里实现了JNI接口。其源码目录如下:
frameworks\base\core\jni\ android_hardware_SensorManager.cpp
在源码里,我们可以看到JNI接口的函数列表:
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 },
};
这些JNI接口所对应的实现,请看源码。
当然了,你可能又有疑问了,上层Java又是怎样来调用这些本地接口的呢??在android_hardware_SensorManager.cpp源码下面有这样一个函数:
int register_android_hardware_SensorManager(JNIEnv *env)
{
return jniRegisterNativeMethods(env, "android/hardware/SensorManager",
gMethods, NELEM(gMethods));
}
这个函数就将以上的JNI接口(gMethods数组)注册进系统。看上去很简单,其实过程是很复杂的。整个 native方法初始化过程如下:start(AndroidRuntime.cpp,938 行)->startReg(AndroidRuntime.cpp,1360 行)-> register_jni_procs(AndroidRuntime.cpp,1213行)。这样JAVA上层就能够调用这些JNI接口来操纵底层硬件 了。
五、应用层(Java)
传感器系统的JAVA部分包含了以下几个文件:
u SensorManager.java
实现传感器系统核心的管理类SensorManager
u Sensor.java
单一传感器的描述性文件Sensor
u SensorEvent.java
表示传感器系统的事件类SensorEvent
u SensorEventListener.java
传感器事件的监听者SensorEventListener接口
u SensorListener.java
传感器的监听者SensorListener接口