Android板级支持与硬件相关子系统
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

6.3 传感器BSP的结构

Android传感器系统自传感器硬件抽象层接口以下的部分是非标准的,因此传感器系统移植包括传感器的驱动程序和硬件抽象层。

Android中Sensor的驱动程序是非标准的,只是为了满足硬件抽象层的需要。

↘6.3.1 驱动程序

从Linux操作系统中驱动程序的角度,Sensor的驱动程序没有标准架构。因此在Android中构建的Sensor驱动程序也是通过非标准的Linux驱动程序实现的。

Sensor驱动程序的主要的职责是从硬件中获得传感器信息,通过在用户空间调用接口将数据传送给上层。

Sensor驱动程序可以基于如下的接口来实现。

·Event设备

·Misc杂项字符设备

·直接实现一个字符设备的主设备

·使用sys文件系统

传感器需要实现与硬件相关的机制包括读取信息、阻塞、控制。这三者对应的经典接口分别是read、poll和ioctl,事实上只有读取功能是必须实现的。

由于传感器本身是一种获取信息的工具,因此将其实现为用于输入的Event设备是很自然的方式。Event设备可以实现用于阻塞的poll调用,在中断到来时将poll解除阻塞,然后实现read调用,将数据传递给用户空间。如果使用Event设备,显然可以使用Input驱动框架中定义的数据类型。

如果使用Misc杂项字符设备或者字符设备的主设备实现传感器的驱动程序,实际上和Event实现的驱动程序是很类似的。也可以直接实现file_operations中的read、poll和ioctl接口来实现对应的功能。当然,read读取信息的功能和poll实现阻塞的功能也可以通过ioctl来实现。

提示:如果使用ioctl实现功能,为了保证用户空间调用的灵活性,阻塞和读取信息最好不要在一个命令中实现。

使用sys文件系统可以实现基本的读、写功能,对应驱动中的show和store接口实现。显然,sys文件系统也可以实现阻塞,只是通常不这样做。

↘6.3.2 硬件抽象层的内容

1.Sensor硬件抽象层的接口

sensors.h是Android传感器系统硬件层的接口,这是一个标准的Android硬件模块之一。头文件中的各个SENSOR_TYPE_*常量表示各种传感器的类型。

Sensor模块sensors_module_t的定义如下所示:

    struct sensors_module_t {
        struct hw_module_t common;
        int (*get_sensors_list)(struct sensors_module_t* module, struct sensor_t const** list);
    };

在标准的硬件模块(hw_module_t)的基础上增加了get_sensors_list()函数,用于获得传感器列表。

sensor_t结构用于描述传感器,如下所示:

    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];
    }

sensor_t表示单一传感器的信息,与Android Java层的传感器类对应。

sensors_vec_t结构表示的是一个传感器数据向量的结构体,内容如下所示:

    typedef struct {
        union {
            float v[3];                                             // 使用3个浮点数据表示
            struct {  float x; float y; float z;   };               // 使用轴坐标表示
            struct {  float azimuth; float pitch; float roll; };  // 使用极坐标表示
        };
        int8_t status;               // 状态信息
        uint8_t reserved[3];
    } sensors_vec_t;

按照如上的定义,sensors_vec_t数据结构的大小为16字节,其中第1个成员是一个共用体,可以表示为3个单精度浮点数,或者轴坐标和极坐标的单精度浮点数的格式。最后的3个字节补足了这个结构体为16字节。

sensors_event_t数据结构表示传感器事件的数据,如下所示:

    typedef struct {
        int  sensor;                            // sensor标识符
        int32_t type;                           // 类型
        int32_t reserved0;                      // 保留
        int64_t timestamp;                      // 时间戳(单位:nanosecond)
        union {
            sensors_vec_t   vector;             // x,y,z矢量
            sensors_vec_t   orientation;        // 方向(单位:度)
            sensors_vec_t   acceleration;       // 加速度(单位:m/s2)
            sensors_vec_t   magnetic;           // 磁矢量(单位:uT)
            float          temperature;         // 温度(单位:摄氏度)
            float          distance;            // 距离(单位:米)
            float          light;               // 光度(单位:SI luminous flux)
            float          pressure;            // 压力(单位:hPa)
        };
        uint32_t       reservedl[4];            // 保留
    } sensors_event_t;

在sensors_event_t中,使用一个共用体表示不同的传感器各自的数据类型,Sensor则是具体传感器的标识。

sensors_poll_device_t表示传感器的设备,其定义如下所示:

    struct sensors_poll_device_t {
        struct hw_device_t common;
        int (*activate)(struct sensors_poll_device_t *dev,      // 激活
                int handle, int enabled);
        int (*setDelay)(struct sensors_poll_device_t *dev,      // 设置延迟
                int handle, int64_t ns);
        int (*poll)(struct sensors_poll_device_t *dev,          // 获取数据
                sensors_event_t* data, int count);
    };

activate、set_delay属于辅助功能,poll则提供了获取数据的功能,此调用将阻塞,直到有数据返回。

2.实现和调试Sensor硬件抽象层

Sensor硬件抽象层主要是sensors_poll_device_t中的几个函数指针。

poll函数指针是传感器的核心功能,其名称就是“poll”的原本含义,调用时被阻塞,直到传感器获得数据时返回。poll调用的实现在经典的状态中是“阻塞+读取”这两个环节,都可以通过调用驱动程序的相关接口(可能是非标准的ioctl)来完成。由于传感器设备通常耗费系统资源不会很多,因此阻塞可能不需要一定实现,取而代之的是使用固定的延迟。

activate函数指针用于激活—无效;setDelay函数指针用于设置延时,也就是设置了传感器的精度。

在Android系统中,支持多种类型的传感器,同一种类型的传感器也可以支持多个,因此在硬件抽象层中也需要处理这个内容。首先需要构建一个sensor_t类型的数组表示各个传感器,在阻塞方面,如果驱动程序中实现了标准的poll接口,在用户空间的调用中可以通过调用select实现多路选择的功能。各个传感器的驱动可能没有标准的实现,甚至可能接口都是不一致的,这时就需要使用轮循的方式来处理了,必要时可以使用多线程。

nusensors是用于传感器的测试工程,代码路径为:hardware/libhardware/tests/nusensors/。由C++的代码组成,其中的内容将生成test-nusensors可执行程序。这部分程序直接打开硬件抽象层的模块进行调用,其代码与传感器JNI部分类似。但是可以在命令行直接运行,不需要其他命令行参数,它将直接调用sensors_open打开几个传感器并使能,然后调用poll从传感器中取出数据,从命令行打印出结果。