308 lines
5.7 KiB
C
308 lines
5.7 KiB
C
#include "system/includes.h"
|
||
|
||
#include "app_log.h"
|
||
#include "radar_report_service.h"
|
||
|
||
#include <string.h>
|
||
|
||
|
||
static struct radar_report_service_config report_config;
|
||
|
||
static struct radar_report_snapshot pending_snapshot;
|
||
|
||
static u8 report_service_initialized;
|
||
static u8 report_pending;
|
||
static u8 pending_reason;
|
||
|
||
static u32 last_report_ms;
|
||
|
||
|
||
/*
|
||
* 判断两个快照在“manager meaningful-change 关注的字段”上
|
||
* 是否仍然一致。
|
||
*
|
||
* 不比较 position:
|
||
* 当前 manager 的 meaningful-change 本来就不以 XYZ 作为
|
||
* 上报变化条件,位置的持续抖动不应阻止 consumed baseline 推进。
|
||
*
|
||
* 不比较 last_update_ms/sample_age_ms:
|
||
* 它们是时间信息,不是业务状态本身。
|
||
*/
|
||
static u8 radar_report_business_equal(
|
||
const struct radar_report_snapshot *a,
|
||
const struct radar_report_snapshot *b
|
||
)
|
||
{
|
||
if (!a || !b) {
|
||
return 0;
|
||
}
|
||
|
||
if (a->sensor.presence != b->sensor.presence) {
|
||
return 0;
|
||
}
|
||
|
||
if (a->sensor.motion != b->sensor.motion) {
|
||
return 0;
|
||
}
|
||
|
||
if (a->sensor.sleep_state != b->sensor.sleep_state) {
|
||
return 0;
|
||
}
|
||
|
||
if (a->sensor.body_movement !=
|
||
b->sensor.body_movement) {
|
||
return 0;
|
||
}
|
||
|
||
if (a->sensor.distance_cm !=
|
||
b->sensor.distance_cm) {
|
||
return 0;
|
||
}
|
||
|
||
if (a->sensor.heart_rate_x10 !=
|
||
b->sensor.heart_rate_x10) {
|
||
return 0;
|
||
}
|
||
|
||
if (a->sensor.breath_rate_x10 !=
|
||
b->sensor.breath_rate_x10) {
|
||
return 0;
|
||
}
|
||
|
||
if (a->sensor.abnormal_state !=
|
||
b->sensor.abnormal_state) {
|
||
return 0;
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
|
||
int radar_report_service_init(
|
||
const struct radar_report_service_config *config
|
||
)
|
||
{
|
||
if (!config) {
|
||
return -1;
|
||
}
|
||
|
||
if (config->max_age_ms == 0) {
|
||
return -2;
|
||
}
|
||
|
||
memset(
|
||
&pending_snapshot,
|
||
0,
|
||
sizeof(pending_snapshot)
|
||
);
|
||
|
||
report_config = *config;
|
||
|
||
report_pending = 0;
|
||
pending_reason = RADAR_REPORT_REASON_NONE;
|
||
last_report_ms = 0;
|
||
|
||
report_service_initialized = 1;
|
||
|
||
APP_LOG(
|
||
"[RADAR_REPORT] init success max_age=%u periodic=%u\n",
|
||
report_config.max_age_ms,
|
||
report_config.periodic_interval_ms
|
||
);
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
int radar_report_service_check(
|
||
u32 now_ms,
|
||
struct radar_report_snapshot *out,
|
||
u8 *reason
|
||
)
|
||
{
|
||
int ret;
|
||
u8 due_reason;
|
||
struct radar_report_snapshot current;
|
||
|
||
if (!out || !reason) {
|
||
return -1;
|
||
}
|
||
|
||
if (!report_service_initialized) {
|
||
return -2;
|
||
}
|
||
|
||
|
||
/*
|
||
* 已经有一份等待真正发送成功的快照:
|
||
* 始终返回同一份,避免发送失败重试时内容漂移。
|
||
*/
|
||
if (report_pending) {
|
||
|
||
memcpy(
|
||
out,
|
||
&pending_snapshot,
|
||
sizeof(*out)
|
||
);
|
||
|
||
*reason = pending_reason;
|
||
|
||
return 1;
|
||
}
|
||
|
||
|
||
ret = radar_manager_get_report_snapshot(
|
||
now_ms,
|
||
report_config.max_age_ms,
|
||
¤t
|
||
);
|
||
|
||
if (ret != 0) {
|
||
return ret;
|
||
}
|
||
|
||
|
||
/*
|
||
* 没有真正业务样本,或者样本已经过期:
|
||
* 不把旧数据交给上层发送。
|
||
*/
|
||
if (current.sensor.last_update_ms == 0 ||
|
||
!current.has_fresh_sample) {
|
||
|
||
*reason = RADAR_REPORT_REASON_NONE;
|
||
return 0;
|
||
}
|
||
|
||
|
||
due_reason = RADAR_REPORT_REASON_NONE;
|
||
|
||
|
||
/*
|
||
* 第一次成功上报之前,
|
||
* 只要已经有 fresh sample 就先产生一份初始快照。
|
||
*/
|
||
if (last_report_ms == 0) {
|
||
|
||
due_reason =
|
||
RADAR_REPORT_REASON_INITIAL;
|
||
|
||
} else if (current.has_meaningful_change) {
|
||
|
||
due_reason =
|
||
RADAR_REPORT_REASON_CHANGE;
|
||
|
||
} else if (
|
||
report_config.periodic_interval_ms != 0 &&
|
||
(u32)(now_ms - last_report_ms) >=
|
||
report_config.periodic_interval_ms
|
||
) {
|
||
|
||
due_reason =
|
||
RADAR_REPORT_REASON_PERIODIC;
|
||
}
|
||
|
||
|
||
if (due_reason == RADAR_REPORT_REASON_NONE) {
|
||
|
||
*reason = RADAR_REPORT_REASON_NONE;
|
||
return 0;
|
||
}
|
||
|
||
|
||
memcpy(
|
||
&pending_snapshot,
|
||
¤t,
|
||
sizeof(pending_snapshot)
|
||
);
|
||
|
||
report_pending = 1;
|
||
pending_reason = due_reason;
|
||
|
||
|
||
memcpy(
|
||
out,
|
||
&pending_snapshot,
|
||
sizeof(*out)
|
||
);
|
||
|
||
*reason = pending_reason;
|
||
|
||
|
||
return 1;
|
||
}
|
||
|
||
|
||
int radar_report_service_mark_reported(
|
||
u32 now_ms
|
||
)
|
||
{
|
||
int ret;
|
||
struct radar_report_snapshot current;
|
||
|
||
if (!report_service_initialized) {
|
||
return -1;
|
||
}
|
||
|
||
if (!report_pending) {
|
||
return 0;
|
||
}
|
||
|
||
|
||
/*
|
||
* 发送成功后重新看一次 manager 当前状态。
|
||
*
|
||
* 如果从生成 pending 到发送成功之间,
|
||
* meaningful-change 相关业务字段没有变化,
|
||
* 才安全推进 manager consumed baseline。
|
||
*
|
||
* 如果已经变化,则不消费:
|
||
* 下一次 check 会继续看到 CHANGE,
|
||
* 防止“发送旧快照却把新状态标记为已消费”。
|
||
*/
|
||
ret = radar_manager_get_report_snapshot(
|
||
now_ms,
|
||
report_config.max_age_ms,
|
||
¤t
|
||
);
|
||
|
||
if (ret != 0) {
|
||
return ret;
|
||
}
|
||
|
||
|
||
if (radar_report_business_equal(
|
||
&pending_snapshot,
|
||
¤t
|
||
)) {
|
||
|
||
ret =
|
||
radar_manager_mark_snapshot_consumed();
|
||
|
||
if (ret != 0) {
|
||
return ret;
|
||
}
|
||
|
||
} else {
|
||
|
||
APP_LOG(
|
||
"[RADAR_REPORT] state changed while pending, "
|
||
"keep manager change for next report\n"
|
||
);
|
||
}
|
||
|
||
|
||
last_report_ms = now_ms;
|
||
|
||
report_pending = 0;
|
||
pending_reason = RADAR_REPORT_REASON_NONE;
|
||
|
||
memset(
|
||
&pending_snapshot,
|
||
0,
|
||
sizeof(pending_snapshot)
|
||
);
|
||
|
||
|
||
return 0;
|
||
}
|