SENSOR数据对接¶
SENSOR 数据对接是连接传感器硬件、算法处理与 UI 应用的核心环节,整体流程分为传感器算法适配与应用数据获取两大模块。前者负责传感器原始数据的采集与算法加工,后者实现处理后数据的分发、存储、通知及 UI 刷新,最终支撑应用层的功能展示。
1. 传感器算法和数据¶
传感器原始数据需经算法处理(如运动状态识别、生理参数计算等)后,才能转换为应用可直接使用的标准化数据。具体适配流程、算法集成方法及数据格式定义,可参考传感器与算法适配
2. 应用数据获取¶
算法处理后的传感器数据通过固定链路分发至应用层,涵盖数据分发、线程处理、存储获取、UI 通知四大关键环节,核心实现集中在sensor_service.c与sensor_service_ui.c文件中。
2.1 数据分发¶
算法输出的数据首先传输至 HCPU,由sensor_service.c中的sensors_msg_process_in_hcpu_cb函数根据数据类型,分发至不同线程处理。
void sensors_msg_process_in_hcpu_cb(uint16_t msg_id, void *data, uint16_t data_len)
{
if (SENSOR_APP_EVENT_ID_BEGIN < msg_id && msg_id < SENSOR_APP_EVENT_ID_END || SENSOR_APP_TEST_RANDOM_IND == msg_id)
{
//提醒类事件,唤醒YI
send_msg_to_gui_thread(data, data_len, sensors_wakeup_msg_process_in_gui_thread_cb, msg_id, NEED_WAKEUP_UI);
}
else if (SENSOR_APP_HISTORY_ID_BEGIN < msg_id && msg_id < SENSOR_APP_HISTORY_ID_END)
{
send_msg_to_bg_thread(data, data_len, sensors_msg_process_in_bg_thread_cb, msg_id, 0); //历史数据类,在bg线程存储
}
else
{
sensors_data_splitting_process_cb(msg_id, data, data_len); //数据拆分为基本单位,使sensor数据结构和UI无关
#if defined(BSP_BLE_SIBLES) && defined(PKG_USING_NANOPB)
sensors_msg_process_in_ble_to_app(msg_id, data, data_len); //发送数据到手机
#endif
//发送数据到UI线程,进行实时数据存储和通知
send_msg_to_gui_thread(data, data_len, sensors_no_wakeup_msg_process_in_gui_thread_cb, msg_id, DONT_NEED_WAKEUP_UI);
}
}
2.2 分发数据处理¶
HCPU会分发sensor的实时数据和提醒消息到UI线程,历史数据到bg线程,处理都在sensor_service_ui.c中实现。
实时数据¶
回调函数:sensors_no_wakeup_msg_process_in_gui_thread_cb(comm_msg_t *msg)
核心功能:
调用存储接口将实时数据写入内存数据库;
触发lv_obj_datasubs_notify接口,通知 UI 控件刷新显示;
不唤醒休眠的 UI 线程,降低系统功耗。
提醒消息¶
回调函数:sensors_wakeup_msg_process_in_gui_thread_cb(comm_msg_t *msg)
核心功能:
唤醒休眠的 UI 线程;
解析消息类型(如心率过高、久坐提醒),生成对应弹窗;
确保紧急通知及时触达用户。
历史数据¶
调函数:sensors_msg_process_in_bg_thread_cb(comm_msg_t *msg)
核心功能:
将历史数据(如小时级 / 日级运动数据)写入 Flash 存储;
避免 UI 线程被大数据量存储操作阻塞,保证交互流畅性。
2.3 数据存储和获取¶
Solution提供整体数据存储与拆分数据存储两种模式,分别适配不同的解耦需求与使用场景。
整体数据存储和获取¶
直接按传感器数据结构体进行存储与读取,适用于数据结构稳定、UI 与传感器耦合度较低的场景。
存储接口
//id 类型,见rt_info_type_t,
//rt 数据地址
//length 数据长度
void app_rt_info_update(rt_info_type_t id, void *rt, uint16_t length);
获取接口
//id 类型,见rt_info_type_t,
//return 根据类型转换为结构体指针,结构体类型见rt_info_t rt_info_db[MAX_RT_TYPE]表
void *app_rt_info_get(rt_info_type_t id);
示例
// 1. 定义步数数据结构体并赋值
step_info_t step_data = {
.step = 1500, // 步数
.distance = 1200, // 距离(米)
.calories = 80 // 卡路里(千卡)
};
// 2. 存储整体数据
app_rt_info_update(RT_STEP, (void *)&step_data, sizeof(step_info_t));
// 3. 获取整体数据并解析
step_info_t *p_step = (step_info_t *)app_rt_info_get(RT_STEP);
if (p_step != NULL) {
rt_kprintf("当前步数:%d,消耗:%d千卡\n", p_step->step, p_step->calories);
}
拆分数据存储和获取¶
将传感器数据结构体的每个成员单独拆分存储,实现 UI 与传感器数据结构的解耦(UI 仅需关注所需字段,无需感知完整结构体)。
存储接口
//id 类型,见rt_data_info_type_t,
//data 基本数据地址
//length 数据长度,不超过4,对于double类型需要转换为float后再进行存储
void app_rt_data_info_update(rt_data_info_type_t id, void *data, uint16_t length);
获取接口
//id 类型,见rt_data_info_type_t,
//return 转换为存储类型后进行
void *app_rt_data_info_get(rt_data_info_type_t id);
示例
step_info_t *step = (step_info_t *)data;
app_rt_data_info_update(APP_STEP_STEP, &step->step, sizeof(step->step));
app_rt_data_info_update(APP_STEP_DISTANCE, &step->distance, sizeof(step->distance));
app_rt_data_info_update(APP_STEP_CALORIE, &step->calories, sizeof(step->calories));
app_rt_data_info_update(APP_STEP_TYPE, &step->active_type, sizeof(step->active_type));
app_rt_data_info_update(APP_STEP_FREQUENCY, &step->step_frequency, sizeof(step->step_frequency));
app_rt_data_info_update(APP_STEP_LENGTH, &step->step_length, sizeof(step->step_length));
app_rt_data_info_update(APP_STEP_PACE, &step->pace, sizeof(step->pace));
uint32_t step = *(uint32_t *)app_rt_data_info_get(APP_STEP_STEP);
uint32_t distance = *(uint32_t *)app_rt_data_info_get(APP_STEP_DISTANCE);
uint32_t calorie = *(uint32_t *)app_rt_data_info_get(APP_STEP_CALORIE);
uint8_t type = *(uint8_t *)app_rt_data_info_get(APP_STEP_TYPE);
float sp = *(float *)app_rt_data_info_get(APP_STEP_FREQUENCY);
float sl = *(float *)app_rt_data_info_get(APP_STEP_LENGTH);
float pace = *(float *)app_rt_data_info_get(APP_STEP_PACE);
//do someting
2.4 数据通知¶
数据存储后,通过lv_obj_datasubs_notify接口通知 UI 控件更新,实现 “数据变更→UI 自动刷新” 的被动响应。通知方式随存储模式不同而存在差异,详细用法参数据被动更新
整体数据通知时type是唯一的,id不用填
v_obj_datasubs_notify(NULL, SENSOR_APP_RT_HR_INFO_IND, msg->data, msg->data_len, NULL);
拆分数据通知时type不是唯一的,需要用id来确保唯一
lv_obj_datasubs_notify("rt_step", LV_EVENT_REFRESH, &step->step, sizeof(step_db->step), NULL);
2.5 UI数据刷新¶
UI 应用获取传感器数据并刷新显示,支持被动订阅与主动更新两种模式,具体实现可参考:页面数据更新