Email:[email protected]
Blog:http://blog.csdn.net/yinwei520
Author: Yww
Time:2011-8-22
一、首先建立這樣一個全局的觀念:
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文件,分析針對於其硬件工作原理的幾個函數。硬件初始化:
static int adxl345_init_client(struct i2c_client *client, int reset_cali)
{
struct adxl345_i2c_data *obj = i2c_get_clientdata(client);
int res = 0;
adxl345_gpio_config();//配置GPIO口,這裏由於不使用中斷,所以將中斷引腳配置成輸入輸出口。
res = ADXL345_CheckDeviceID(client); //檢測設備ID,通過讀ADXL345的DEVID寄存器
if(res != ADXL345_SUCCESS)
{
return res;
}
res = ADXL345_SetPowerMode(client, false);//設置電源模式,ADXL345有幾種電源模式,這裏設置false值指不讓芯片處於messure模式
if(res != ADXL345_SUCCESS)
{
return res;
}
res = ADXL345_SetBWRate(client, ADXL345_BW_100HZ);//設置帶寬,100Hz
if(res != ADXL345_SUCCESS ) //0x2C->BW=100Hz
{
return res;
}
//設置數據格式,具體見datasheet
res = ADXL345_SetDataFormat(client, ADXL345_FULL_RES|ADXL345_RANGE_2G);
if(res != ADXL345_SUCCESS) //0x2C->BW=100Hz
{
return res;
}
gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = obj->reso->sensitivity;
//設置中斷寄存器,關閉中斷
res = ADXL345_SetIntEnable(client, 0x00);//disable INT
if(res != ADXL345_SUCCESS)
{
return res;
}
if(0 != reset_cali)
{
/*reset calibration only in power on*/
res = ADXL345_ResetCalibration(client);
if(res != ADXL345_SUCCESS)
{
return res;
}
}
#ifdef CONFIG_ADXL345_LOWPASS
memset(&obj->fir, 0x00, sizeof(obj->fir));
#endif
return ADXL345_SUCCESS;
}
函數的分析都註釋在原理裏,紅色部分。具體寄存器的設置查看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接口