android系统之sensor学习

来源:互联网 发布:自动化控制软件图片 编辑:程序博客网 时间:2024/05/16 05:51

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的数据发生变化时,就会传过来。