Android源码分析:传感器系统

Sensors in Android

   

总述

   

如下图,应用程序开发者使用几个sensor的几个API类进行应用程序的开发。Java的部分的API使用C/C++来实现,也就是调用到JNI层。左侧运行于应用程序的进程空间,右侧运行于system server进程空间。双方通过ISensorEventConnection/SensorChannel进行通讯。SensorService负责与Sensors的硬件适配层HAL进行通讯,后者与驱动和硬件进行交互。

   

Java API

   

Java层的API类有SensorManager,利用它才可以使用系统的各种感应器(sensor)。sensor的采样值、精确度、时间戳以及信息是自哪个感应器等信息封装在Java类SensorEvent中。Java类Sensor代表一个感应器,包含感应器的各种信息,它的成员数据与本地Sensor类以及HAL层的sensor_t对应(见后述章节)。作为父类的SensorEventListener是一个监听器接口,应用开发者编写它的一个子类可以实现对SensorEvent的监听并做出相应反应。

   

在获取sensor service创建SensorManager时,会创建一个线程去轮询(poll,调用sensors_data_poll)去取sensor的数据,然后以发送消息的形式将SensorEvent发送给ListenerDelegate中的Handler,由handler在新一轮的线程循环中调用对应的sensorListener进行处理。

   

 

   

JNI与native层

   

JNI层位于frameworks/base/core/jni/下面,主要就是一个文件android_hardware_SensorManager.cpp。它使用的类如Sensor、SensorChannel、SensorEventQueue、、ISensorEventConnection和ISensorServer则放在libgui.so中,见目录frameworks/base/libs/gui。

   

 

   

Java层在轮询之前,必须调用sensors_create_queue创建(见SensorThreadRunnable的open函数)一个本地的SensorEventQueue队列,这个C++对象的指针被转换为int型后保存为SensorManager的静态成员变量sQueue。当轮询时,将该队列传递给JNI层的sensors_data_poll,用于从该队列中读取Event数据(具体数据类型是ASensorEvent)。

   

本地SensorEventQueue类主要借助于两个类进行工作。一是封装了管道的SensorChannel类,event的读取和写入都是针对封装的管道进行的;二是libutils库中的Looper类,Looper类实现了在调用者线程中对文件描述符的轮询(内部使用的epoll),甚至可以注册回调函数,当有文件描述符对应的文件有数据到达时使用回调函数进行处理。这样,队列类SensorEventQueue使用Looper监听着管道对应的描述符,当有数据达到时,就可以读取,没有使用回调机制。整个过程是:在Java层的SensorManager的线程中不断调用sensors_data_poll查询数据,这导致其JNI层的native实现在队列上等待event事件(见队列的成员函数waitForEvent,它使用poll进行轮询),也就是说,直到有管道中有数据可用才返回。当没有发生错误返回时,表示有数据可读,然后对数据进行读取。一次读取单位为一个event。

   

下面是JNI层中的sensors_data_poll代码片段:

   

res = queue->read(&event, 1);

if (res == -EAGAIN) {

res = queue->waitForEvent();//等待有数据可读取

if (res != NO_ERROR)//检查是否发生错误

return -1;

res = queue->read(&event, 1);//没错误,进行数据读取

}

   

封装管道的SensorChannel类的对象由ISensorEventConnection接口获取。另外,对sensor的激活/去激活也是通过ISensorEventConnection调用到server侧的SensorService完成的。

   

C++类Sensor代表了一个sensor,它是HAL层sensor_t的封装,同时又为Java层的Sensor类中的数据成员变量提供数据"源",也就是说,Java中的Sensor的成员变量信息是由该C++中的Sensor类设置,后者又是根据sensor_t而获取对应的sensor信息。Java中的Sensor是应用开发的API类。在C++中的Sensor类中定义了sensor的枚举类型:

   

enum {

TYPE_ACCELEROMETER = ASENSOR_TYPE_ACCELEROMETER, //加速度

TYPE_MAGNETIC_FIELD = ASENSOR_TYPE_MAGNETIC_FIELD, //磁场

TYPE_GYROSCOPE = ASENSOR_TYPE_GYROSCOPE, //陀螺仪

TYPE_LIGHT = ASENSOR_TYPE_LIGHT, //光传感器

TYPE_PROXIMITY = ASENSOR_TYPE_PROXIMITY //距离传感器

};

   

 

   

SensorService

   

在frameworks/base/services/sensorservice/下面给出sensorService的相关实现代码,它们最终生成libsensorservice.so库文件,作为service被注册到system server后,最终运行于system_server后台进程空间。

   

Sensor service模块的核心部分是SensorService类。另外还定义了几个逻辑上的虚拟sensor:GravitySensor、LinearAccelerationSensor和RotationVectorSensor,它们的接口由抽象类SensorInterface定义,物理意义上实际传感器HardwareSensor也同样遵循该接口规范。

   

SensorInterface与四个子类继承关系图如下:

   

SensorInterface是个抽象类,定义了五个接口:

   

virtual bool process(sensors_event_t* outEvent,const sensors_event_t& event) = 0; //处理原始数据,换成上层应用希望得到的数据

   

virtual status_t activate(void* ident, bool enabled) = 0; //激活与去激活

   

virtual sttus_t setDelay(void* ident, int handle, int64_t ns) = 0;//设置报告处理频率

   

virtual Sensor getSensor() const = 0;//获取对应的sensor

   

virtual bool isVirtual() const = 0;//是否为虚拟的,即是否为逻辑(虚拟)传感器

   

GravitySensor和LinearAccelerationSensor,它们不是物理意义上的传感器,只是逻辑意义上的传感器,可称之为虚拟(virtual)传感器。它们实际上是将加速器(即gsensor)的值经过处理过滤后再上报。

   

RotationVectorSensor方向向量传感器,实际上它由加速器和磁场传感器(compass)组成,根据它们上报的值来判断是否旋转屏幕。

   

引入虚拟传感器的目的是方便上层程序的处理。在上层看来,它不需要关注设备上的传感器的某些原始数据,只需要经过加工处理后的数据,如是否旋转屏幕,它是依据虚拟的"传感器"sensorRotationVectorSensor得来的经过加工后的数据。这些虚拟传感器包含了处理原始数据的算法。算法包含在重载的process函数中。

   

HardwareSensor代表了真正的传感器,它继承自SensorInterface,实现了各个抽象接口,但其实现是借助于与位于下层的HAL层的sensor硬件模块打交道的类SensorDevice来完成的。

   

SensorDevice与HAL中的libsensors.so打交道,如获取对应的硬件module,打开sensor设备,参见其构造函数:

   

SensorDevice::SensorDevice()

: mSensorDevice(0),

mSensorModule(0)

{

status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,

(hw_module_t const**)&mSensorModule);//打开sensor硬件模块

   

LOGE_IF(err, "couldn't load %s module (%s)",

SENSORS_HARDWARE_MODULE_ID, strerror(-err));

   

if (mSensorModule) {

err = sensors_open(&mSensorModule->common, &mSensorDevice);//打开HAL层的poll设备

LOGE_IF(err, "couldn't open device for module %s (%s)",

SENSORS_HARDWARE_MODULE_ID, strerror(-err));

if (mSensorDevice) {

sensor_t const* list;

ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);//获取sensor_t列表

mActivationCount.setCapacity(count);

Info model;

for (size_t i=0 ; i<size_t(count) ; i++) {

mActivationCount.add(list[i].handle, model);

mSensorDevice->activate(mSensorDevice, list[i].handle, 0);

}

}

}

}

   

其结构图如下:

   

作为核心代码的SensorService类有三个父类:

   

BinderService<SensorService>:继承该父类使其成为一个标准的本地(native) service,将自己添加到系统的system server中去,其它感兴趣者可以使用该service。

   

BnSensorServer:意味着作为子类,SensorService是抽象类ISensorServer中定义的两个接口(getSensorList和createSensorEventConnection)的server侧的真正实现者。一个接口是用来获取系统的sensor列表,另一个则是创建一个事件连接(EventConnection),用于基于管道加上轮询方式的event传输。

   

 

   

 

   

 

   

Thread:意味着它也是一个线程类,在SensorService创建后,有个单独的线程去执行重载的threadLoop。

   

这个threadLoop可以说是整个sensor的调度处理中心,让sensor相关的模块都动起来。作为一个后台线程,它是个无限循环,不断去处理

   

bool SensorService::threadLoop()

{

LOGD("nuSensorService thread starting…");

   

const size_t numEventMax = 16 * (1 + mVirtualSensorList.size());

sensors_event_t buffer[numEventMax];

sensors_event_t scratch[numEventMax];

SensorDevice& device(SensorDevice::getInstance());

const size_t vcount = mVirtualSensorList.size();

   

ssize_t count;

do {

count = device.poll(buffer, numEventMax);//轮询event数据到缓冲区

if (count<0) {

LOGE("sensor poll failed (%s)", strerror(-count));

break;

}

   

recordLastValue(buffer, count);//记录每个sensor最新的值,记入到mLastEventSeen这个KeyedVector(从sensor标识符到sensors_event_t的映射)中。

   

// handle virtual sensors

if (count && vcount) {//下面是处理虚拟sensors数据

const DefaultKeyedVector<int, SensorInterface*> virtualSensors( getActiveVirtualSensors());

   

const size_t activeVirtualSensorCount = virtualSensors.size();

   

if (activeVirtualSensorCount) {

size_t k = 0;

for (size_t i=0 ; i<size_t(count) ; i++) {

sensors_event_t const * const event = buffer;

for (size_t j=0 ; j<activeVirtualSensorCount ; j++) {

sensors_event_t out;

if (virtualSensors.valueAt(j)->process(&out, event[i])) {//处理原始数据,经过处理转换后的数据信息保存在out这个event中

buffer[count + k] = out;//将它们添加到buffer中

k++;

}

}

}

   

if (k) {

// record the last synthesized values

recordLastValue(&buffer[count], k);//同样对虚拟的sensor的event最新值添加到mLastEventSeen中

count += k;

// sort the buffer by time-stamps

sortEventBuffer(buffer, count);//按时间戳排序

}

}

}

   

// send our events to clients…

const SortedVector< wp<SensorEventConnection> > activeConnections(

getActiveConnections());

size_t numConnections = activeConnections.size();

for (size_t i=0 ; i<numConnections ; i++) {

sp<SensorEventConnection> connection(

activeConnections[i].promote());

if (connection != 0) {

connection->sendEvents(buffer, count, scratch);//发送给client端,实际是写入管道

}

}

} while (count >= 0 || Thread::exitPending());

   

LOGW("Exiting SensorService::threadLoop!");

return false;

}

   

因此,可以看出,SensorService的工作线程不断去轮询设备中是否有数据可用。当有数据可用时,将它们写入管道。对方的应用程序中的线程也不断轮询管道,当有数据时,便调用对应的listener进行处理。它们工作在不断的线程中,或使用looper,或使用handler,在不同的线程循环中进行处理,多次的异步操作构成了sensor的处理过程。

   

 

   

HAL

   

在Android HAL中只对sensors的数据结构进行了定义(见头文件hardware/libhardware/include/hardware/sensors.h),其具体实现应由芯片厂家给出。

   

在使用sensors的HAL时,首先使用HAL提供的hw_get_module函数,根据其模块ID字符串(SENSORS_HARDWARE_MODULE_ID)获取硬件模块sensors_module_t,然后借助于sensors_module_t枚举中设备中所带的所有sensors(sensor由结构体sensor_t定义)列表。

   

数据结构sensors_module_t定义了sensors硬件模块,其中的get_sensors_list函数指针用于枚举设备上的各种类型的sensor,实现由平台厂商给出。

   

同样,可以接着使用API函数sensors_open打开HAL中定义的sensors_poll_device_t类型的设备,该结构体定义三个API,用于激活/去激活sensor(见成员activate函数指针)、设置数据报告频率(见setDelay函数指针)和轮训(见poll函数指针)。同样,这三个函数也由平台厂家实现。

   

这样,我们可以使用hw_get_module函数打开硬件模块,并得到sensors列表,同时,也可以使用sensors_open打开sensors_poll_device_t类型的设备,对sensor进行激活/去激活,轮询读数和设置数据报告频率等基本操作。

   

结构体sensor_t代表了一个sensor,定义了sensor的各种属性,如:名称、厂家、版本、句柄、类型、最大值范围、解析度、功耗、数据上报频率等。其定义具体如下:

   

struct sensor_t {

/* name of this sensors */

const char* name;//sensor的名称

   

/* vendor of the hardware part */

const char* vendor;//厂家

   

/* version of the hardware part + driver. The value of this field is

* left to the implementation and doesn't have to be monotonically

* increasing.

*/

int version;//版本

   

/* handle that identifies this sensors. This handle is used to activate

* and deactivate this sensor. The value of the handle must be 8 bits

* in this version of the API.

*/

int handle;//句柄,用于标识是激活/去激活哪个sensor,亦即sensors_event_t中的int32_t sensor;它实际是由四个字符的ascii码值来填充

   

/* this sensor's type. */

int type;//sensor类型,在sensor.h中定义了多达12种类型(有的为逻辑上的sensor),并以注释的方式对它们进行了详细解释

   

/* maximaum range of this sensor's value in SI units */

float maxRange;//最大取值范围

   

/* smallest difference between two values reported by this sensor */

float resolution;//解析度

   

/* rough estimate of this sensor's power consumption in mA */

float power;//估计的功耗,单位为mA

   

/* minimum delay allowed between events in microseconds. A value of zero means that this sensor doesn't report events at a constant rate, but rather only when a new data is available */

int32_t minDelay;//报告读数值的events时间间隔(单位:ms),若为0,意味着不按该频率报告,而是数据到来时才报告

   

/* reserved fields, must be zero */

void* reserved[8];//保留

};

   

sensor的采样值的上报可以按照某个固定的频率进行上报,也可以当有可用的数据时再上报(minDelay设为0)。上报数据以event的形式进行,见结构体sensors_event_t,它包含了sensor的标识符、类型、数据采样时间戳以及采样数据。因为各种sensor的采样值各式各样,它更多地是用联合体union来定义,根据不同的sensor来解释返回的值,比如,当是加速器sensor或磁场sensor时,就分别取联合体中的acceleration和magnetic两个字段,它们的类型是结构体sensors_vec_t,其中又包含有union联合体。这样,Android将各种sensor统一成一种接口,依据不同的sensor分别对其标识和类型对采样值进行解释。

转载于:https://www.cnblogs.com/postmaster/p/3660575.html

多功能健康传感器集成平台系统板概述: 健康传感器平台为集成传感器平台,帮助客户评估Maxim的综合、创新性医疗和高端健身方案。平台集成1个生物电势模拟前端方案(MAX30003)、1个脉冲血氧仪和心率传感器(MAX30101)、2个体温传感器(MAX30205)、1个3轴加速度计、1个3D加速度计和3D陀螺仪,和1个绝对大气压传感器。 该健康系统板内部框图: 多功能健康传感器集成平台开发板实物展示: 工作模式健康传感器平台可工作在以下三种模式之一: 系留模式:用户可使用USB-C电缆将健康传感器平台连接到基于PC的GUI。该模式支持电路板上安装的全部传感器,包括ECG、光学和温度传感器。GUI提供运行快速演示(使用默认寄存器设置)的选项,以及通过更改各个传感器或模拟前端的寄存器设置,详细评估各个传感器。 非系留模式(离线):健康传感器平台收集数据并将其保存到板载闪存,随后即可下载数据,进行后期处理。该模式要求像系留模式一样将健康传感器平台连接PC GUI,以配置传感器和向板载闪存写入任务;随后即可断开,离线执行。工作在该模式时,必须安装电池支架和纽扣电池(不含)。 非系留模式(实时):客户可实时将数据流化传输到Android (备有app可供下载)。我们提供了一些演示功能,介绍如何将平台连接到app。客户可利用提供的源代码开发自己的app,以满足具体需求。 app支持以下功能: 温度,使用温度传感器 大气压,使用压力传感器 HR,使用ECG模拟前端 电路板位置,使用加速度计 HSP板连接到app时,即支持前两项功能;对于后两项功能,客户需要在连接至app之前设置任务。请参考设置任务的说明。设计资源标签页中提供PC和Android应用程序,帮助用户快速入门和开展工作。PC应用程序提供图形用户界面(GUI),使用户能够通过USB连接配置以及与所有传感器进行交互。Android应用程序提供通过BLE监测传感器数据的能力。关于安装和运行应用程序的说明,请参见详细资料标签页。 支持ARM mbed开发环境,适用于希望自定义平台操作的开发者。与平台配套提供的MAXREFDES100HDK#编程适配器提供无需驱动的拖放式编程方法,可用于更新固件,另外也提供虚拟UART接口和CMSIS-DAP兼容调试器。关于固件开发的详细信息和源代码示例,请访问:MAX32620HSP platform page on the ARM mbed developer site。 附件内容包括:设计文件、固件及软件,供需要的人下载。 多功能健康传感器集成平台系统板PCB 截图: 更多详细介绍: https://www.maximintegrated.com/cn/design/referenc...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值