前面的博文中,我们已经接触并分析了Sensors HAL Library,sensor1 remoting layer(libsensor1)以及SensorDaemon的相关流程,这里先串一下各个部分的主要功能。
Sensor HAL Library: android的通用HAL接口,高通实现了自己的部分,相关文件为sensors_hal.cpp
sensor1 remoting layer(libsensor1): 这是一个通信库,通过该库函数提供的API可以允许客户端向SensorDaemon服务端请求消息或者接收来自服务端的消息。
SensorDaemon:用户空间的一个后台守护进程,用于监听sensor客户端的请求以及通过共享内存与DSPS通信。
这三部分的代码结构如下:
那么DSPS是什么呢? 今天我们主要了解下DSPS架构和重要组成部分,有些知识点会涉及QMI的相关技术QCCI以及QCSI,之前的博客我们也讲解了相关的接口定义,请点击复习:
Qualcomm messaging Interface(QMI)消息定义概述
Dedicated Sensors Processor Subsystem(DSPS)
如标题所述,DSPS即Dedicated Sensors Processor Subsystem,专用传感器处理器子系统。
下面这张图完整的展示了整个Sensor模块DSPS相关的架构图,包括我们的DSPS部分。
我们重点从图中标注的6部分来看,各个部分主要功能是什么。
Device Driver Framework(DDF)
首先第一部分即Device Driver Framework板块。
这部分即高通的设备驱动框架,而sensor相关的代码则在adsp_proc/Sensors/ddf/下,而驱动代码则在dd路径下,DDF的主要功能如下:
1 完成所有的环境配置
2 支持一个驱动控制多个设备
3 支持同一设备或类似设备的同一驱动程序的多个实例
4同步异步数据检索
5 支持NV参数设定
6 驱动属性的运行时配置,如分辨率,范围及功率状态
7 访问系统时间以便对于延时代码的执行
8 抽象的通信接口以便于扩展
9 memhandler,内存管理对象,用于分配释放内存
在DDF中有一个非常重要的接口我们已经在之前的相关文章中见过,即sns_ddf_driver_if_s:
typedef struct
{
/**
* 初始化驱动并且开启sensor设备
* 主要工作: 1. 分配一个驱动实例句柄 2. 打开相关设备的通信端口
* 3. 配置驱动和设备,将设备设到默认的电源状态
*/
sns_ddf_status_e (*init)(
sns_ddf_handle_t* dd_handle_ptr,
sns_ddf_handle_t smgr_handle,
sns_ddf_nv_params_s* nv_params,
sns_ddf_device_access_s device_info[],
uint32_t num_devices,
sns_ddf_memhandler_s* memhandler,
sns_ddf_sensor_e** sensors,
uint32_t* num_sensors);
/**
* 向每一个特定的sensor请求单个数据样本
* 数据有如下两种方式返回:
* (1) 当读到数据的序号相匹配后立即返回
* (2) 在sensor需要读取几个步骤的情形下,
* 以SNS_DDF_PENDING状态通过sns_ddf_smgr_data_notify携带数据异步返回
*/
sns_ddf_status_e (*get_data)(
sns_ddf_handle_t dd_handle,
sns_ddf_sensor_e sensors[],
uint32_t num_sensors,
sns_ddf_memhandler_s* memhandler,
sns_ddf_sensor_data_s** data);
/**
* 设置sensor指定的属性值
*/
sns_ddf_status_e (*set_attrib)(
sns_ddf_handle_t dd_handle,
sns_ddf_sensor_e sensor,
sns_ddf_attribute_e attrib,
void* value);
/**
* 获取sensor指定的属性值
*/
sns_ddf_status_e (*get_attrib)(
sns_ddf_handle_t dd_handle,
sns_ddf_sensor_e sensor,
sns_ddf_attribute_e attrib,
sns_ddf_memhandler_s* memhandler,
void** value,
uint32_t* num_elems);
/**
* timer回调,初始化timer时要指定回调方法
*/
void (*handle_timer)(sns_ddf_handle_t dd_handle, void* arg);
/**
* 处理驱动中断
*/
void (*handle_irq)(
sns_ddf_handle_t dd_handle,
uint32_t gpio_num,
sns_ddf_time_t timestamp);
/**
* 重置驱动及设备回到init状态
*/
sns_ddf_status_e (*reset)(sns_ddf_handle_t dd_handle);
/**
* 运行一个指定的工厂测试,流式数据不能调用该方法
*/
sns_ddf_status_e (*run_test)(
sns_ddf_handle_t dd_handle,
sns_ddf_sensor_e sensor,
sns_ddf_test_e test,
uint32_t* err);
/**
* 启动设备调度采样,通过DRI使能通知功能
* 数据就绪后,handle_irq被调用
*/
sns_ddf_status_e (*enable_sched_data)(
sns_ddf_handle_t handle,
sns_ddf_sensor_e sensor,
bool enable);
/**
* 根据给定的配置探测设备
*/
sns_ddf_status_e(*probe)(
sns_ddf_device_access_s* device_info,
sns_ddf_memhandler_s* memhandler,
uint32_t* num_sensors,
sns_ddf_sensor_e** sensors );
/**
* 从指定的sensor中检索一组传感器数据,异步API
* 使用sns_ddf_data_notify_data上报数据
*/
sns_ddf_status_e (*trigger_fifo_data)(
sns_ddf_handle_t dd_handle,
sns_ddf_sensor_e sensor,
uint16_t num_samples,
bool trigger_now);
/**
* 发送一个DAF消息到驱动,异步/同步API
*/
sns_ddf_status_e (*process_daf_req)(
sns_ddf_handle_t dd_handle,
uint32_t req_id,
const void* req_msg,
uint32_t req_size,
sns_ddf_memhandler_s* memhandler,
void** resp_msg,
uint32_t* resp_size,
const uint8_t* trans_id_ptr,
void* conn_handle);
/**
* 为提供的connect handle取消所有驱动当前的DAF异步事务
*/
void (*cancel_daf_trans)(
sns_ddf_handle_t dd_handle,
void* conn_handle);
} sns_ddf_driver_if_s;
所有的传感器驱动程序都要实现上面的接口,并将其对应的结构体在sns_dd.h中进行声明,如:
extern sns_ddf_driver_if_s sns_dd_mpu6515_if;
extern sns_ddf_driver_if_s sns_accel_driver_fn_list;
extern sns_ddf_driver_if_s sns_accel_adxl350_driver_fn_list;
extern sns_ddf_driver_if_s sns_gyro_driver_fn_list;
extern sns_ddf_driver_if_s sns_mag_driver_fn_list;
………………
举例mpu6515陀螺仪传感器的驱动实现:
// Function driver API
sns_ddf_driver_if_s sns_dd_mpu6515_if =
{
.init = &mpu6515_init,
.get_data = &mpu6515_get_data,
.set_attrib = &mpu6515_set_attr,
.get_attrib = &mpu6515_get_attr,
.handle_timer = &mpu6515_handle_timer,
.handle_irq = &mpu6515_handle_irq,
.reset = &mpu6515_reset,
.run_test = &mpu6515_run_test,
.enable_sched_data = &mpu6515_enable_sched_data,
.probe = &mpu6515_probe,
.trigger_fifo_data = &mpu6515_trigger_fifo_data
};
Sensor Manager(SMGR)
第二部分则是Sensor的管理器服务SMGR,其主要功能如下:
1 首先它在自己的DSPS线程中运行
2 可移植到其他目标并可扩展到其他传感器类型
3 传感器原始值使用SI单位,二进制缩放Q16,(例外:磁感应器MAG使用高斯(不是SI单位))
4 跟踪多个自主客户端请求的所有传感器需求
5 维护所有传感器设备驱动程序
- 列出所有可用的传感器
- 列出每个传感器的属性
6 支持客户端自定义的report可操作选择
- 每个客户端可以指定不同的报告速率(在传感器支持的最小值和最大值以内)。
- 每个报告可以组合任何可用传感器的组合。
- 利用硬件滤波实现报告率和数据处理
Sensors Algorithm Manager (SAM)
第三部分则是sensor algorithm manager,sensor算法管理器,其主要功能如下:
1 提供客户端和算法之间的抽象
- 只要算法符合简单的SAM接口集,就提供可移植性和重用性
- 被许可者可以通过做极小的修改将自己的算法插入-使用到SAM架构中
2 是一个控制模块,管理由算法提供的服务
- 管理算法和提供算法服务的外部客户端之间的所有交互
3 管理所有算法间的交互,例如算法X请求算法Y的数据
4 可以服务运行在不同的处理器上的客户机
- AP
- DSPS
- CP(modem)
5 管理算法实例的实例化和销毁
通过下列方式进行最小内存分配:
- 允许多个客户端共享相同的算法实例
- 允许多个算法实例共享相同的传感器数据批处理
Sensor Message Router(SMR)
第四部分则是Sensor Message Router,光从名字就能知道他是负责消息传递用的。事实上也是这样的,SMR是一个集中在应用程序处理器(ap)、调制解调器处理器(cp/modem)上的消息传递实用程序,其主要的功能如下:
1 支持一个互操作协议,通过该协议将编码的QMI消息打包并发送到接收处理器上的对等实体。
2 支持处理器内部的软件协议,其中处理器内部的软件模块在没有QMI编码的情况下进行通信。
3 在处理器和模块分区中提供模块位置透明性
- 模块可以在与其他模块透明的处理器之间迁移,例如保持相同的接口
4 通过部署两个优先级级别来支持消息优先级排序(现在禁用,但是当需要消息优先级时可以启用)
5 提供流量控制——SMR保证将消息传递到目的队列,或通知源模块失败。
Qualcomm Messaging Interface(QMI)
第五部分就是我们已经提到的QMI了。之所以选择QMI作为AP与BP侧的通信协议,高通给出的理由如下:
1 QMI提供了标准的消息编解码机制
2 QMI提供的版本支持机制,sensor框架层可以更新消息,添加新的服务且提供向后兼容
3 QMI不会编码参数块中无用的可选部分,节约IPC通信共享内存
4 同一个处理器间的通信不需要进行QMI编解码
5 Sensors的接口消息都定义在IDL,这遵循命名和转换规则,并将其转换成C类型数据
Client Manager(CM)
客户端管理器主要用于向客户端提供请求接口,其内部有一个Receive thread,当有消息从SMR发过来,receive thread查找回调函数,并将该消息通过对应的cb分发至对应的客户端。其架构图如下:
特性如下:
1 API设计是模块化的,引入新特性时不需要做太多修改;
2 API依赖于高层操作系统;
3 允许内部及外部客户端;
4 支持模块化框架设计,用以实现路由消息到当地服务以及DSPS中的服务器;
5 提供灵活的线程模型;
6 为客户端提供不同优先级服务;
在上面的DSPS架构图中,我们还看到一个模块,叫Sensor Calibration Manager,这个模块主要用于sensor数据校验等,比如出厂设置时的校验等,后面分析数据校验的时候再重点关注这部分。
好了,介绍完DSPS的架构及相关的重要模块,后续的文章我们将重点分析SensoDaemon是怎样通过QCCI, QCSI通信API与DSPS端通信的,欢迎关注。