除了显示驱动,其余全部测试通过

This commit is contained in:
guo
2026-08-30 14:13:24 +08:00
commit c0ace98dff
146 changed files with 9476 additions and 0 deletions
+726
View File
@@ -0,0 +1,726 @@
#include "system/includes.h"
#include "system/timer.h"
#include "app_log.h"
#include "r60abd1.h"
#include "radar_uart.h"
#include <string.h>
/*
* R60ABD1协议格式:
*
* [0] 0x53
* [1] 0x59
* [2] CTRL
* [3] CMD
* [4] DATA_LEN_H
* [5] DATA_LEN_L
* [6..] DATA
* [-3] CHECKSUM
* [-2] 0x54
* [-1] 0x43
*
* full_len = 9 + data_len
*/
#define R60_FRAME_HEADER1 0x53
#define R60_FRAME_HEADER2 0x59
#define R60_FRAME_TAIL1 0x54
#define R60_FRAME_TAIL2 0x43
#define R60_CTRL_PRESENCE 0x80
#define R60_CTRL_BREATH 0x81
#define R60_CTRL_SLEEP 0x84
#define R60_CTRL_HEART 0x85
#define R60_PARSE_BUF_SIZE 128
#ifndef R60ABD1_DEBUG_LOG
#define R60ABD1_DEBUG_LOG 1
#endif
#if R60ABD1_DEBUG_LOG
#define R60_LOG(...) APP_LOG(__VA_ARGS__)
#else
#define R60_LOG(...)
#endif
static u8 r60_parse_buf[R60_PARSE_BUF_SIZE];
static u16 r60_parse_len;
static u32 r60_rx_bytes;
static u32 r60_valid_frame_count;
static u32 r60_data_update_count;
static u32 r60_checksum_error_count;
static struct radar_r60abd1_data radar_data;
static OS_MUTEX radar_data_mutex;
static u8 radar_data_mutex_ready;
/*
* R60坐标格式:
*
* bit15 = 符号位
* bit14..0 = 数值绝对值
*/
static s16 r60_parse_signed_coordinate(u16 raw_value)
{
s16 value = (s16)(raw_value & 0x7fff);
if (raw_value & 0x8000) {
value = -value;
}
return value;
}
/*
* 协议层初始化。
*
* 必须在:
* radar_r60abd1_input_bytes()
* radar_r60abd1_get_data()
*
* 之前调用。
*/
int radar_r60abd1_init(void)
{
memset(r60_parse_buf, 0, sizeof(r60_parse_buf));
memset(&radar_data, 0, sizeof(radar_data));
r60_parse_len = 0;
r60_rx_bytes = 0;
r60_valid_frame_count = 0;
r60_data_update_count = 0;
r60_checksum_error_count = 0;
if (!radar_data_mutex_ready) {
os_mutex_create(&radar_data_mutex);
radar_data_mutex_ready = 1;
}
R60_LOG("[R60] init success\n");
return 0;
}
/*
* 完整帧合法性校验。
*/
static int r60_validate_frame(const u8 *frame, u16 frame_len)
{
u8 checksum = 0;
u16 data_len;
u16 i;
if (!frame || frame_len < 9) {
return -1;
}
if (frame[0] != R60_FRAME_HEADER1 ||
frame[1] != R60_FRAME_HEADER2) {
return -2;
}
data_len =
((u16)frame[4] << 8) |
frame[5];
if ((u16)(9 + data_len) != frame_len) {
return -3;
}
if (frame[frame_len - 2] != R60_FRAME_TAIL1 ||
frame[frame_len - 1] != R60_FRAME_TAIL2) {
return -4;
}
/*
* checksum:
*
* frame[0] 到 DATA最后一个字节之和。
* 不包含checksum本身和帧尾。
*/
for (i = 0; i < frame_len - 3; i++) {
checksum += frame[i];
}
if (checksum != frame[frame_len - 3]) {
if (radar_data_mutex_ready) {
os_mutex_pend(&radar_data_mutex, 0);
r60_checksum_error_count++;
radar_data.checksum_errors =
r60_checksum_error_count;
os_mutex_post(&radar_data_mutex);
} else {
r60_checksum_error_count++;
}
R60_LOG("[R60] checksum error: calc=%02X recv=%02X\n",
checksum,
frame[frame_len - 3]);
return -5;
}
return 0;
}
/*
* 业务解析。
*
* 只负责:
* 1. CTRL/CMD解释
* 2. 更新RAM中的最新状态
*
* 不做:
* Flash
* 网络上传
*/
static int r60_parse_frame(const u8 *frame, u16 frame_len)
{
u8 ctrl;
u8 cmd;
u16 data_len;
int updated = 0;
if (!frame || frame_len < 9) {
return 0;
}
if (!radar_data_mutex_ready) {
return 0;
}
ctrl = frame[2];
cmd = frame[3];
data_len =
((u16)frame[4] << 8) |
frame[5];
os_mutex_pend(&radar_data_mutex, 0);
switch (ctrl) {
/*
* 人体存在 / 运动 / 距离 / 坐标
*/
case R60_CTRL_PRESENCE:
switch (cmd) {
case 0x01:
case 0x81:
if (data_len >= 1) {
radar_data.presence = frame[6];
updated = 1;
R60_LOG("[R60][PARSE] presence=%u\n",
radar_data.presence);
}
break;
case 0x02:
if (data_len >= 1) {
radar_data.motion = frame[6];
updated = 1;
R60_LOG("[R60][PARSE] motion=%u\n",
radar_data.motion);
}
break;
case 0x03:
if (data_len >= 1) {
radar_data.body_movement = frame[6];
updated = 1;
R60_LOG("[R60][PARSE] body_movement=%u\n",
radar_data.body_movement);
}
break;
case 0x04:
if (data_len >= 2) {
radar_data.distance_cm =
((u16)frame[6] << 8) |
frame[7];
updated = 1;
R60_LOG("[R60][PARSE] distance=%u cm\n",
radar_data.distance_cm);
}
break;
case 0x05:
if (data_len >= 6) {
radar_data.pos_x_mm =
r60_parse_signed_coordinate(
((u16)frame[6] << 8) |
frame[7]);
radar_data.pos_y_mm =
r60_parse_signed_coordinate(
((u16)frame[8] << 8) |
frame[9]);
radar_data.pos_z_mm =
r60_parse_signed_coordinate(
((u16)frame[10] << 8) |
frame[11]);
updated = 1;
R60_LOG("[R60][PARSE] pos=(%d,%d,%d) mm\n",
radar_data.pos_x_mm,
radar_data.pos_y_mm,
radar_data.pos_z_mm);
}
break;
default:
break;
}
break;
/*
* 呼吸
*/
case R60_CTRL_BREATH:
switch (cmd) {
case 0x02:
case 0x82:
if (data_len >= 1) {
radar_data.breath_rate_x10 =
(u16)frame[6] * 10;
updated = 1;
R60_LOG("[R60][PARSE] breath=%u /min\n",
radar_data.breath_rate_x10 / 10);
}
break;
case 0x05:
if (data_len >= 1) {
radar_data.breath_waveform = frame[6];
updated = 1;
}
break;
default:
break;
}
break;
/*
* 心率
*/
case R60_CTRL_HEART:
switch (cmd) {
case 0x02:
case 0x82:
if (data_len >= 1) {
radar_data.heart_rate_x10 =
(u16)frame[6] * 10;
updated = 1;
R60_LOG("[R60][PARSE] heart=%u bpm\n",
radar_data.heart_rate_x10 / 10);
}
break;
case 0x05:
if (data_len >= 1) {
radar_data.heart_waveform = frame[6];
updated = 1;
}
break;
default:
break;
}
break;
/*
* 睡眠
*/
case R60_CTRL_SLEEP:
switch (cmd) {
case 0x0c:
case 0x8d:
if (data_len >= 2) {
radar_data.presence = frame[6];
radar_data.sleep_state = frame[7];
updated = 1;
R60_LOG("[R60][PARSE] sleep presence=%u state=%u\n",
radar_data.presence,
radar_data.sleep_state);
}
break;
default:
break;
}
break;
/*
* 手册已确认、但当前公共状态结构尚未承载的合法帧,例如:
*
* ctrl=07 cmd=07
* ctrl=81 cmd=01
*
* 本阶段暂不映射,避免顺带扩展业务字段。
*/
default:
break;
}
/*
* 通信统计和业务新鲜度严格分开:
*
* frame_count:
* 所有checksum正确的合法帧都会增加。
*
* data_update_count / update_ms:
* 只有当前parser真正识别并更新业务字段时才推进。
*
* 因此07/07、01/01等未知合法帧不会把旧数据“续鲜”。
*/
radar_data.rx_bytes = r60_rx_bytes;
radar_data.frame_count = r60_valid_frame_count;
radar_data.checksum_errors =
r60_checksum_error_count;
if (updated) {
r60_data_update_count++;
radar_data.data_update_count =
r60_data_update_count;
radar_data.update_ms = timer_get_ms();
} else {
R60_LOG(
"[R60] ignored business frame ctrl=%02X cmd=%02X "
"frame=%u data=%u\n",
ctrl,
cmd,
r60_valid_frame_count,
r60_data_update_count
);
}
os_mutex_post(&radar_data_mutex);
return updated;
}
/*
* 收到一帧完整数据。
*/
static void r60_frame_received(const u8 *frame, u16 frame_len)
{
int ret;
u32 frame_count;
ret = r60_validate_frame(frame, frame_len);
if (ret != 0) {
R60_LOG("[R60] invalid frame, ret=%d\n",
ret);
return;
}
if (!radar_data_mutex_ready) {
return;
}
os_mutex_pend(&radar_data_mutex, 0);
r60_valid_frame_count++;
radar_data.frame_count =
r60_valid_frame_count;
frame_count =
r60_valid_frame_count;
os_mutex_post(&radar_data_mutex);
R60_LOG("[R60] valid frame=%u len=%u ctrl=%02X cmd=%02X\n",
frame_count,
frame_len,
frame[2],
frame[3]);
r60_parse_frame(frame, frame_len);
}
/*
* 逐字节组帧。
*/
static void r60_feed_byte(u8 byte)
{
u16 data_len;
u16 full_len;
/*
* 找0x53。
*/
if (r60_parse_len == 0) {
if (byte != R60_FRAME_HEADER1) {
return;
}
r60_parse_buf[0] = byte;
r60_parse_len = 1;
return;
}
/*
* 已收到0x53,找0x59。
*/
if (r60_parse_len == 1) {
if (byte == R60_FRAME_HEADER2) {
r60_parse_buf[1] = byte;
r60_parse_len = 2;
return;
}
/*
* 53 53
* 后一个53仍可能是新帧头。
*/
if (byte == R60_FRAME_HEADER1) {
return;
}
r60_parse_len = 0;
return;
}
/*
* parser buffer保护。
*/
if (r60_parse_len >= sizeof(r60_parse_buf)) {
R60_LOG("[R60] frame buffer overflow\n");
r60_parse_len = 0;
return;
}
r60_parse_buf[r60_parse_len++] = byte;
/*
* 前6字节收齐后才能读取DATA_LEN。
*/
if (r60_parse_len < 6) {
return;
}
data_len =
((u16)r60_parse_buf[4] << 8) |
r60_parse_buf[5];
full_len =
(u16)(9 + data_len);
if (full_len > sizeof(r60_parse_buf)) {
R60_LOG("[R60] invalid frame length: data=%u full=%u\n",
data_len,
full_len);
r60_parse_len = 0;
return;
}
if (r60_parse_len < full_len) {
return;
}
r60_frame_received(
r60_parse_buf,
full_len
);
r60_parse_len = 0;
}
/*
* UART层收到数据后调用。
*/
int radar_r60abd1_input_bytes(const u8 *data, u16 len)
{
u16 i;
if (!data || !len) {
return -1;
}
if (!radar_data_mutex_ready) {
return -2;
}
/*
* 统计UART输入字节数。
*/
os_mutex_pend(&radar_data_mutex, 0);
r60_rx_bytes += len;
radar_data.rx_bytes = r60_rx_bytes;
os_mutex_post(&radar_data_mutex);
/*
* 逐字节送入组帧器。
*/
for (i = 0; i < len; i++) {
r60_feed_byte(data[i]);
}
return 0;
}
/*
* 获取当前最新雷达状态快照。
*
* 可供其他任务调用。
*/
int radar_r60abd1_get_data(struct radar_r60abd1_data *out)
{
if (!out) {
return -1;
}
if (!radar_data_mutex_ready) {
return -2;
}
os_mutex_pend(&radar_data_mutex, 0);
memcpy(out,
&radar_data,
sizeof(*out));
os_mutex_post(&radar_data_mutex);
return 0;
}
/*
* 向R60ABD1发送原始协议命令。
*
* 协议层只负责把完整命令交给UART层发送。
*/
int radar_r60abd1_send_command(const u8 *cmd, u16 len)
{
if (!cmd || !len) {
return -1;
}
return radar_uart_write(
cmd,
len
);
}
+106
View File
@@ -0,0 +1,106 @@
#ifndef R60ABD1_H
#define R60ABD1_H
#include "typedef.h"
/*
* R60ABD1最新状态快照。
*
* 该结构只表示“当前最新值”,
* 不负责历史数据存储。
*/
struct radar_r60abd1_data {
/* 人体存在/运动 */
u8 presence;
u8 motion;
u8 body_movement;
/* 距离 */
u16 distance_cm;
/*
* 心率/呼吸率。
*
* x10保存:
* 例如 72.0 bpm -> 720
*/
u16 heart_rate_x10;
u16 breath_rate_x10;
/* 睡眠状态 */
u8 sleep_state;
/* XYZ坐标 */
s16 pos_x_mm;
s16 pos_y_mm;
s16 pos_z_mm;
/* 最新波形采样值 */
u8 heart_waveform;
u8 breath_waveform;
/*
* 最近一次“已识别业务数据更新”的系统时间。
*
* 未知但checksum正确的合法帧不会刷新该时间。
* 单位:ms。
*/
u32 update_ms;
/* 运行统计 */
u32 rx_bytes;
/*
* checksum正确的合法帧总数。
* 包含当前没有解析业务含义的帧。
*/
u32 frame_count;
/*
* 当前parser真正识别并更新业务字段的帧数。
*/
u32 data_update_count;
u32 checksum_errors;
};
/*
* 初始化R60ABD1协议层。
*
* 必须在input/get_data之前调用。
*/
int radar_r60abd1_init(void);
/*
* 输入UART收到的原始字节流。
*/
int radar_r60abd1_input_bytes(
const u8 *data,
u16 len
);
/*
* 获取当前最新状态快照。
*
* 内部使用mutex保护。
*/
int radar_r60abd1_get_data(
struct radar_r60abd1_data *out
);
/*
* 发送一条已经组好的R60ABD1协议命令。
*/
int radar_r60abd1_send_command(
const u8 *cmd,
u16 len
);
#endif
+449
View File
@@ -0,0 +1,449 @@
#include "system/includes.h"
#include "system/timer.h"
#include "app_log.h"
#include "radar_command_service.h"
#include "r60abd1.h"
#define RADAR_COMMAND_FRAME_LEN 10
#define RADAR_COMMAND_STARTUP_INTERVAL_MS 50
#define RADAR_COMMAND_PERIODIC_INTERVAL_MS 2000
#define RADAR_COMMAND_SKIP_INTERVAL_MS 100
#define RADAR_COMMAND_RETRY_INTERVAL_MS 100
#define RADAR_COMMAND_TASK_PRIO 20
#define RADAR_COMMAND_TASK_STACK 1024
enum radar_command_phase {
RADAR_COMMAND_PHASE_STARTUP = 0,
RADAR_COMMAND_PHASE_PERIODIC
};
/*
* ESP32参考工程启动阶段:
*
* 1. queryPresenceCmd原始10字节
* 2. 12条startupCommands
*
* 每条之间50ms。
*/
static const u8 radar_startup_commands[][RADAR_COMMAND_FRAME_LEN] = {
{0x53, 0x59, 0x80, 0x81, 0x00, 0x01, 0x00, 0xAE, 0x54, 0x43},
{0x53, 0x59, 0x80, 0x00, 0x00, 0x01, 0x01, 0x2E, 0x54, 0x43},
{0x53, 0x59, 0x81, 0x00, 0x00, 0x01, 0x01, 0x2F, 0x54, 0x43},
{0x53, 0x59, 0x85, 0x00, 0x00, 0x01, 0x01, 0x33, 0x54, 0x43},
{0x53, 0x59, 0x84, 0x00, 0x00, 0x01, 0x01, 0x32, 0x54, 0x43},
{0x53, 0x59, 0x81, 0x0C, 0x00, 0x01, 0x01, 0x3B, 0x54, 0x43},
{0x53, 0x59, 0x85, 0x0A, 0x00, 0x01, 0x01, 0x3D, 0x54, 0x43},
{0x53, 0x59, 0x84, 0x13, 0x00, 0x01, 0x01, 0x45, 0x54, 0x43},
{0x53, 0x59, 0x84, 0x14, 0x00, 0x01, 0x01, 0x46, 0x54, 0x43},
{0x53, 0x59, 0x80, 0x80, 0x00, 0x01, 0x0F, 0xBC, 0x54, 0x43},
{0x53, 0x59, 0x81, 0x80, 0x00, 0x01, 0x0F, 0xBD, 0x54, 0x43},
{0x53, 0x59, 0x85, 0x80, 0x00, 0x01, 0x0F, 0xC1, 0x54, 0x43},
{0x53, 0x59, 0x84, 0x80, 0x00, 0x01, 0x0F, 0xC0, 0x54, 0x43},
};
/*
* 周期查询命令:
*
* 84系列保持ESP32参考任务的查询顺序;
* 心率/呼吸数值查询按R60ABD1 V3.4手册使用85/82、81/82。
* 每条value固定为0x0F,正常每2秒发送一条。
*/
static const u8 radar_periodic_commands[][RADAR_COMMAND_FRAME_LEN] = {
{0x53, 0x59, 0x84, 0x81, 0x00, 0x01, 0x0F, 0xC1, 0x54, 0x43},
{0x53, 0x59, 0x84, 0x8D, 0x00, 0x01, 0x0F, 0xCD, 0x54, 0x43},
{0x53, 0x59, 0x84, 0x8F, 0x00, 0x01, 0x0F, 0xCF, 0x54, 0x43},
{0x53, 0x59, 0x84, 0x8E, 0x00, 0x01, 0x0F, 0xCE, 0x54, 0x43},
{0x53, 0x59, 0x84, 0x91, 0x00, 0x01, 0x0F, 0xD1, 0x54, 0x43},
{0x53, 0x59, 0x84, 0x92, 0x00, 0x01, 0x0F, 0xD2, 0x54, 0x43},
{0x53, 0x59, 0x84, 0x83, 0x00, 0x01, 0x0F, 0xC3, 0x54, 0x43},
{0x53, 0x59, 0x84, 0x84, 0x00, 0x01, 0x0F, 0xC4, 0x54, 0x43},
{0x53, 0x59, 0x84, 0x85, 0x00, 0x01, 0x0F, 0xC5, 0x54, 0x43},
{0x53, 0x59, 0x84, 0x86, 0x00, 0x01, 0x0F, 0xC6, 0x54, 0x43},
{0x53, 0x59, 0x84, 0x90, 0x00, 0x01, 0x0F, 0xD0, 0x54, 0x43},
{0x53, 0x59, 0x85, 0x82, 0x00, 0x01, 0x0F, 0xC3, 0x54, 0x43},
{0x53, 0x59, 0x81, 0x82, 0x00, 0x01, 0x0F, 0xBF, 0x54, 0x43},
};
static enum radar_command_phase radar_command_phase;
static u8 radar_command_sleep_query_enabled;
static u16 radar_command_startup_cmd_index;
static u16 radar_command_periodic_query_index;
static u32 radar_command_next_ms;
static int radar_command_task_pid;
/*
* ESP32中可关闭的睡眠查询:
* periodic_query_index 1 -> 84/8D
* periodic_query_index 10 -> 84/90
*/
static int radar_command_is_sleep_query(u16 query_index)
{
return (query_index == 1) ||
(query_index == 10);
}
static int radar_command_time_reached(
u32 now,
u32 deadline
)
{
/*
* 兼容u32毫秒计数回绕。
*/
return ((s32)(now - deadline) >= 0);
}
static int radar_command_send_frame(
const u8 *frame
)
{
int ret;
ret = radar_r60abd1_send_command(
frame,
RADAR_COMMAND_FRAME_LEN
);
if (ret < 0) {
return ret;
}
/*
* 当前UART写接口成功时应返回实际写入长度。
*/
if (ret != RADAR_COMMAND_FRAME_LEN) {
return -2;
}
return 0;
}
/*
* 单次非阻塞调度。
*
* 只由本模块内部任务调用。
*/
static int radar_command_process_once(void)
{
int ret;
u32 now;
const u8 *frame;
now = timer_get_ms();
if (!radar_command_time_reached(
now,
radar_command_next_ms
)) {
return 0;
}
/*
* 第一阶段:
* 13条启动命令,50ms间隔。
*/
if (radar_command_phase ==
RADAR_COMMAND_PHASE_STARTUP) {
frame =
radar_startup_commands[
radar_command_startup_cmd_index
];
ret = radar_command_send_frame(frame);
if (ret != 0) {
radar_command_next_ms =
now +
RADAR_COMMAND_RETRY_INTERVAL_MS;
APP_LOG(
"[RADAR_CMD] startup send failed "
"startup_cmd_index=%u ctrl=%02X cmd=%02X ret=%d\n",
radar_command_startup_cmd_index,
frame[2],
frame[3],
ret
);
return ret;
}
APP_LOG(
"[RADAR_CMD] startup sent "
"startup_cmd_index=%u ctrl=%02X cmd=%02X value=%02X\n",
radar_command_startup_cmd_index,
frame[2],
frame[3],
frame[6]
);
radar_command_startup_cmd_index++;
if (radar_command_startup_cmd_index >=
(sizeof(radar_startup_commands) /
sizeof(radar_startup_commands[0]))) {
radar_command_phase =
RADAR_COMMAND_PHASE_PERIODIC;
radar_command_periodic_query_index = 0;
radar_command_next_ms =
now +
RADAR_COMMAND_PERIODIC_INTERVAL_MS;
APP_LOG(
"[RADAR_CMD] startup complete\n"
);
} else {
radar_command_next_ms =
now +
RADAR_COMMAND_STARTUP_INTERVAL_MS;
}
return 1;
}
/*
* 第二阶段:
* 周期查询。
*/
if ((!radar_command_sleep_query_enabled) &&
radar_command_is_sleep_query(
radar_command_periodic_query_index
)) {
APP_LOG(
"[RADAR_CMD] periodic skip "
"periodic_query_index=%u ctrl=%02X cmd=%02X\n",
radar_command_periodic_query_index,
radar_periodic_commands[
radar_command_periodic_query_index
][2],
radar_periodic_commands[
radar_command_periodic_query_index
][3]
);
radar_command_periodic_query_index =
(u16)(
(radar_command_periodic_query_index + 1) %
(
sizeof(radar_periodic_commands) /
sizeof(radar_periodic_commands[0])
)
);
radar_command_next_ms =
now +
RADAR_COMMAND_SKIP_INTERVAL_MS;
return 0;
}
frame =
radar_periodic_commands[
radar_command_periodic_query_index
];
ret = radar_command_send_frame(frame);
if (ret != 0) {
radar_command_next_ms =
now +
RADAR_COMMAND_RETRY_INTERVAL_MS;
APP_LOG(
"[RADAR_CMD] periodic send failed "
"periodic_query_index=%u ctrl=%02X cmd=%02X ret=%d\n",
radar_command_periodic_query_index,
frame[2],
frame[3],
ret
);
return ret;
}
APP_LOG(
"[RADAR_CMD] periodic sent "
"periodic_query_index=%u ctrl=%02X cmd=%02X value=%02X\n",
radar_command_periodic_query_index,
frame[2],
frame[3],
frame[6]
);
radar_command_periodic_query_index =
(u16)(
(radar_command_periodic_query_index + 1) %
(
sizeof(radar_periodic_commands) /
sizeof(radar_periodic_commands[0])
)
);
radar_command_next_ms =
now +
RADAR_COMMAND_PERIODIC_INTERVAL_MS;
return 1;
}
static void radar_command_task(void *priv)
{
(void)priv;
while (1) {
/*
* process_once自身按timer_get_ms()判断是否到期。
* 这里仅短暂让出CPU,不依赖app_main的UART阻塞周期。
*/
radar_command_process_once();
os_time_dly(1);
}
}
int radar_command_service_init(void)
{
int ret;
if (radar_command_task_pid) {
return 0;
}
radar_command_phase =
RADAR_COMMAND_PHASE_STARTUP;
radar_command_sleep_query_enabled = 1;
radar_command_startup_cmd_index = 0;
radar_command_periodic_query_index = 0;
/*
* 任务启动后允许立即发送首条queryPresenceCmd。
*/
radar_command_next_ms =
timer_get_ms();
ret = thread_fork(
"radar_cmd",
RADAR_COMMAND_TASK_PRIO,
RADAR_COMMAND_TASK_STACK,
0,
&radar_command_task_pid,
radar_command_task,
NULL
);
if (ret != OS_NO_ERR) {
radar_command_task_pid = 0;
APP_LOG(
"[RADAR_CMD] task start failed ret=%d\n",
ret
);
return -1;
}
APP_LOG(
"[RADAR_CMD] init success "
"startup=%u periodic=%u\n",
(u32)(
sizeof(radar_startup_commands) /
sizeof(radar_startup_commands[0])
),
(u32)(
sizeof(radar_periodic_commands) /
sizeof(radar_periodic_commands[0])
)
);
return 0;
}
void radar_command_service_set_sleep_query_enabled(
u8 enabled
)
{
radar_command_sleep_query_enabled =
enabled ? 1 : 0;
APP_LOG(
"[RADAR_CMD] sleep query %s\n",
radar_command_sleep_query_enabled ?
"enabled" :
"disabled"
);
}
u8 radar_command_service_get_sleep_query_enabled(void)
{
return radar_command_sleep_query_enabled;
}
+55
View File
@@ -0,0 +1,55 @@
#ifndef RADAR_COMMAND_SERVICE_H
#define RADAR_COMMAND_SERVICE_H
#include "typedef.h"
/*
* radar_command_service
*
* 职责:
* - 按参考工程顺序发送R60ABD1启动命令
* - 启动完成后按周期轮询查询命令
* - 控制是否跳过睡眠相关查询
*
* 调度任务由本模块内部持有。
*
* 不负责:
* - UART硬件初始化
* - 雷达接收/协议解析
* - radar_manager状态
* - MQTT/WiFi
*/
/*
* 初始化并启动命令调度任务。
*
* 调用前要求:
* radar_uart_init() 已成功
* radar_r60abd1_init() 已成功
*
* 重复调用安全:已经启动时直接返回0。
*/
int radar_command_service_init(void);
/*
* 是否发送睡眠相关周期查询。
*
* 默认开启,与ESP32参考工程一致。
*
* enabled:
* 0 跳过84/8D和84/90
* 非0 正常发送
*/
void radar_command_service_set_sleep_query_enabled(u8 enabled);
/*
* 获取当前睡眠查询开关。
*/
u8 radar_command_service_get_sleep_query_enabled(void);
#endif
+159
View File
@@ -0,0 +1,159 @@
#include "system/includes.h"
#include "app_log.h"
#include "radar_data_service.h"
#include "r60abd1.h"
#include "radar_manager.h"
#include <string.h>
/*
* 已经成功同步到radar_manager的
* R60 data_update_count。
*
* 不使用frame_count
* 未知但checksum正确的合法帧只增加frame_count
* 不应该触发manager业务状态更新。
*/
static u32 radar_data_service_last_update_count;
/*
* 把R60协议层的公开快照
* 映射成manager通用输入结构。
*
* 这里不做:
* - 合法性判断
* - meaningful change判断
* - freshness判断
*
* 这些都属于radar_manager职责。
*/
static void radar_data_service_build_manager_input(
const struct radar_r60abd1_data *r60,
struct radar_manager_input *input
)
{
memset(input, 0, sizeof(*input));
input->presence =
r60->presence;
input->motion =
r60->motion;
input->body_movement =
r60->body_movement;
input->distance_cm =
r60->distance_cm;
input->heart_rate_x10 =
r60->heart_rate_x10;
input->breath_rate_x10 =
r60->breath_rate_x10;
input->sleep_state =
r60->sleep_state;
input->pos_x_mm =
r60->pos_x_mm;
input->pos_y_mm =
r60->pos_y_mm;
input->pos_z_mm =
r60->pos_z_mm;
/*
* 当前稳定R60接口没有abnormal_state来源。
* 不猜协议,保持0。
*/
input->abnormal_state = 0;
/*
* 使用协议层“真正业务数据更新”的时间。
*
* manager自身不依赖AC79 timer API。
*/
input->update_ms =
r60->update_ms;
}
int radar_data_service_init(void)
{
radar_data_service_last_update_count = 0;
APP_LOG("[RADAR_DATA] init success\n");
return 0;
}
int radar_data_service_process(void)
{
int ret;
struct radar_r60abd1_data r60;
struct radar_manager_input input;
ret = radar_r60abd1_get_data(&r60);
if (ret != 0) {
return ret;
}
/*
* 没有新的“已识别业务更新”:
* 不重复刷新manager。
*
* 这里直接比较计数即可。
* 即使u32未来发生回绕,也仍能识别下一次变化。
*/
if (r60.data_update_count ==
radar_data_service_last_update_count) {
return 0;
}
radar_data_service_build_manager_input(
&r60,
&input
);
ret = radar_manager_update(&input);
if (ret != 0) {
/*
* manager更新失败时不要推进last_update_count
* 下次process还能重试同一份最新数据。
*/
return ret;
}
/*
* 只有manager真正接收成功后,
* 才认为这次R60更新已被消费。
*/
radar_data_service_last_update_count =
r60.data_update_count;
return 1;
}
+49
View File
@@ -0,0 +1,49 @@
#ifndef RADAR_DATA_SERVICE_H
#define RADAR_DATA_SERVICE_H
/*
* radar_data_service 的职责:
*
* R60ABD1最新业务数据
* ↓
* radar_manager_input
* ↓
* radar_manager
*
* 它只负责协议层与业务状态层之间的数据适配。
*
* 它不知道:
* - UART硬件
* - R60 CTRL/CMD具体含义
* - MQTT
* - WiFi
* - Flash
* - 上报周期
*/
/*
* 初始化数据适配服务。
*
* 注意:
* radar_r60abd1_init() 和 radar_manager_init()
* 仍由更上层负责。
*/
int radar_data_service_init(void);
/*
* 尝试把R60ABD1最新业务数据同步到radar_manager。
*
* 返回:
* 1 本次发现新业务数据,并成功更新manager
* 0 本次没有新的业务数据
* <0 读取R60或更新manager失败
*
* 建议由单一任务/主循环调用。
*/
int radar_data_service_process(void);
#endif
+332
View File
@@ -0,0 +1,332 @@
#include "system/includes.h"
#include "radar_manager.h"
#include <string.h>
#include "app_log.h"
static struct radar_sensor_data current_data;
static struct radar_sensor_data consumed_data;
static OS_MUTEX radar_manager_mutex;
static u8 radar_manager_mutex_ready;
static u8 has_consumed_snapshot;
static u16 abs_diff_u16(u16 a, u16 b)
{
return (a >= b) ? (u16)(a - b) : (u16)(b - a);
}
static u8 abs_diff_u8(u8 a, u8 b)
{
return (a >= b) ? (u8)(a - b) : (u8)(b - a);
}
/*
* 保留 ESP32 当前最终业务判定:
* heart: > 0 && < 200 bpm
* breath: > 0 && <= 60 /min
*
* AC79 内部使用 x10 整数。
*/
static u8 heart_rate_valid(u16 value_x10)
{
return (value_x10 > 0 && value_x10 < 2000) ? 1 : 0;
}
static u8 breath_rate_valid(u16 value_x10)
{
return (value_x10 > 0 && value_x10 <= 600) ? 1 : 0;
}
/*
* 调用者必须持有 radar_manager_mutex。
*/
static void build_change_flags_locked(
struct radar_change_flags *flags
)
{
memset(flags, 0, sizeof(*flags));
if (!has_consumed_snapshot) {
if (current_data.last_update_ms != 0) {
flags->any_changed = 1;
}
return;
}
flags->presence_changed =
current_data.presence != consumed_data.presence;
flags->motion_changed =
current_data.motion != consumed_data.motion;
flags->sleep_state_changed =
current_data.sleep_state != consumed_data.sleep_state;
/*
* ESP32 当前 meaningful-change 阈值:
* body movement >= 5
* distance >= 10 cm
* heart >= 3 bpm
* breath >= 2 /min
*/
flags->body_movement_changed =
abs_diff_u8(
current_data.body_movement,
consumed_data.body_movement
) >= 5;
flags->distance_changed =
abs_diff_u16(
current_data.distance_cm,
consumed_data.distance_cm
) >= 10;
flags->heart_rate_changed =
abs_diff_u16(
current_data.heart_rate_x10,
consumed_data.heart_rate_x10
) >= 30;
flags->breath_rate_changed =
abs_diff_u16(
current_data.breath_rate_x10,
consumed_data.breath_rate_x10
) >= 20;
flags->abnormal_state_changed =
current_data.abnormal_state !=
consumed_data.abnormal_state;
flags->any_changed =
flags->presence_changed ||
flags->motion_changed ||
flags->sleep_state_changed ||
flags->body_movement_changed ||
flags->distance_changed ||
flags->heart_rate_changed ||
flags->breath_rate_changed ||
flags->abnormal_state_changed;
}
int radar_manager_init(void)
{
memset(&current_data, 0, sizeof(current_data));
memset(&consumed_data, 0, sizeof(consumed_data));
has_consumed_snapshot = 0;
if (!radar_manager_mutex_ready) {
os_mutex_create(&radar_manager_mutex);
radar_manager_mutex_ready = 1;
}
APP_LOG("[RADAR_MGR] init success\n");
return 0;
}
int radar_manager_update(
const struct radar_manager_input *input
)
{
if (!input) {
return -1;
}
if (!radar_manager_mutex_ready) {
return -2;
}
os_mutex_pend(&radar_manager_mutex, 0);
current_data.presence = input->presence;
current_data.motion = input->motion;
current_data.body_movement = input->body_movement;
current_data.distance_cm = input->distance_cm;
current_data.heart_rate_x10 = input->heart_rate_x10;
current_data.breath_rate_x10 = input->breath_rate_x10;
current_data.heart_valid =
heart_rate_valid(input->heart_rate_x10);
current_data.breath_valid =
breath_rate_valid(input->breath_rate_x10);
current_data.sleep_state = input->sleep_state;
current_data.pos_x_mm = input->pos_x_mm;
current_data.pos_y_mm = input->pos_y_mm;
current_data.pos_z_mm = input->pos_z_mm;
current_data.abnormal_state = input->abnormal_state;
current_data.last_update_ms = input->update_ms;
os_mutex_post(&radar_manager_mutex);
return 0;
}
int radar_manager_get_sensor_data(
struct radar_sensor_data *out
)
{
if (!out) {
return -1;
}
if (!radar_manager_mutex_ready) {
return -2;
}
os_mutex_pend(&radar_manager_mutex, 0);
memcpy(out, &current_data, sizeof(*out));
os_mutex_post(&radar_manager_mutex);
return 0;
}
int radar_manager_get_change_flags(
struct radar_change_flags *out
)
{
if (!out) {
return -1;
}
if (!radar_manager_mutex_ready) {
return -2;
}
os_mutex_pend(&radar_manager_mutex, 0);
build_change_flags_locked(out);
os_mutex_post(&radar_manager_mutex);
return 0;
}
int radar_manager_get_report_snapshot(
u32 now_ms,
u32 max_age_ms,
struct radar_report_snapshot *out
)
{
struct radar_change_flags flags;
u32 age;
if (!out) {
return -1;
}
if (!radar_manager_mutex_ready) {
return -2;
}
memset(out, 0, sizeof(*out));
os_mutex_pend(&radar_manager_mutex, 0);
memcpy(
&out->sensor,
&current_data,
sizeof(out->sensor)
);
build_change_flags_locked(&flags);
out->has_person =
current_data.presence != 0;
/*
* 先保持 ESP32 当前语义:
* presence != 0 或 sleep_state > 0
*/
out->bed_occupied =
(current_data.presence != 0) ||
(current_data.sleep_state > 0);
out->has_valid_vitals =
current_data.heart_valid ||
current_data.breath_valid;
out->has_meaningful_change =
flags.any_changed;
if (current_data.last_update_ms != 0) {
age =
(u32)(
now_ms -
current_data.last_update_ms
);
out->sample_age_ms = age;
if (age <= max_age_ms) {
out->has_fresh_sample = 1;
}
}
os_mutex_post(&radar_manager_mutex);
return 0;
}
int radar_manager_mark_snapshot_consumed(void)
{
if (!radar_manager_mutex_ready) {
return -1;
}
os_mutex_pend(&radar_manager_mutex, 0);
memcpy(
&consumed_data,
&current_data,
sizeof(consumed_data)
);
has_consumed_snapshot = 1;
os_mutex_post(&radar_manager_mutex);
return 0;
}
+115
View File
@@ -0,0 +1,115 @@
#ifndef RADAR_MANAGER_H
#define RADAR_MANAGER_H
#include "typedef.h"
/*
* radar_manager 的职责:
* 1. 保存“当前最新雷达状态”
* 2. 对上层提供一致快照
* 3. 判断 fresh / valid / meaningful change
*
* 它不知道:
* - UART
* - R60 CTRL/CMD
* - MQTT
* - WiFi
* - Flash
*/
struct radar_manager_input {
u8 presence;
u8 motion;
u8 body_movement;
u16 distance_cm;
u16 heart_rate_x10;
u16 breath_rate_x10;
u8 sleep_state;
s16 pos_x_mm;
s16 pos_y_mm;
s16 pos_z_mm;
u8 abnormal_state;
/*
* 由调用者传入本次数据真正更新的系统时间。
* manager 自己不依赖 AC79 timer API
* 保持模块纯净。
*/
u32 update_ms;
};
struct radar_sensor_data {
u8 presence;
u8 motion;
u8 body_movement;
u16 distance_cm;
u16 heart_rate_x10;
u16 breath_rate_x10;
u8 heart_valid;
u8 breath_valid;
u8 sleep_state;
s16 pos_x_mm;
s16 pos_y_mm;
s16 pos_z_mm;
u8 abnormal_state;
u32 last_update_ms;
};
struct radar_change_flags {
u8 presence_changed;
u8 motion_changed;
u8 sleep_state_changed;
u8 body_movement_changed;
u8 distance_changed;
u8 heart_rate_changed;
u8 breath_rate_changed;
u8 abnormal_state_changed;
u8 any_changed;
};
struct radar_report_snapshot {
struct radar_sensor_data sensor;
u8 has_person;
u8 bed_occupied;
u8 has_valid_vitals;
u8 has_fresh_sample;
u8 has_meaningful_change;
u32 sample_age_ms;
};
int radar_manager_init(void);
int radar_manager_update(
const struct radar_manager_input *input
);
int radar_manager_get_sensor_data(
struct radar_sensor_data *out
);
int radar_manager_get_change_flags(
struct radar_change_flags *out
);
int radar_manager_get_report_snapshot(
u32 now_ms,
u32 max_age_ms,
struct radar_report_snapshot *out
);
int radar_manager_mark_snapshot_consumed(void);
#endif
+307
View File
@@ -0,0 +1,307 @@
#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,
&current
);
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,
&current,
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,
&current
);
if (ret != 0) {
return ret;
}
if (radar_report_business_equal(
&pending_snapshot,
&current
)) {
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;
}
+94
View File
@@ -0,0 +1,94 @@
#ifndef RADAR_REPORT_SERVICE_H
#define RADAR_REPORT_SERVICE_H
#include "typedef.h"
#include "radar_manager.h"
/*
* radar_report_service 的职责:
*
* 1. 从 radar_manager 获取统一业务快照
* 2. 判断当前是否需要上报
* 3. 在真正上报成功后推进“已上报”状态
*
* 它不知道:
* - UART
* - R60 CTRL/CMD
* - WiFi
* - MQTT
* - JSON
* - Flash
*
* 本模块不创建任务。
* 由未来的上报/网络执行流主动调用。
*/
enum radar_report_reason {
RADAR_REPORT_REASON_NONE = 0,
RADAR_REPORT_REASON_INITIAL,
RADAR_REPORT_REASON_CHANGE,
RADAR_REPORT_REASON_PERIODIC,
};
struct radar_report_service_config {
/*
* manager 快照允许的最大数据年龄。
* 超过这个时间的数据不提交给上层上报。
*/
u32 max_age_ms;
/*
* 即使没有 meaningful change
* 也允许按周期强制产生一次快照。
*
* 设为 0 表示关闭周期强制上报。
*/
u32 periodic_interval_ms;
};
/*
* 初始化上报决策层。
*/
int radar_report_service_init(
const struct radar_report_service_config *config
);
/*
* 检查当前是否存在待上报快照。
*
* return:
* 1 有快照需要上报,out/reason 有效
* 0 当前不需要上报
* <0 错误
*
* 注意:
* 一旦产生 pending snapshot
* 在 radar_report_service_mark_reported() 成功调用前,
* 后续 check 会返回同一份 pending snapshot。
*
* 这样上层发送失败时可以重试,
* 不会因为 manager 又更新而偷偷替换发送内容。
*/
int radar_report_service_check(
u32 now_ms,
struct radar_report_snapshot *out,
u8 *reason
);
/*
* 只有“上层已经真正发送成功”后才调用。
*
* 该函数会:
* - 清除 pending snapshot
* - 记录成功上报时间
* - 在安全情况下推进 manager 的 consumed baseline
*
* 如果 pending 产生以后 manager 又发生了有意义字段变化,
* 本函数不会把那个新变化错误地消费掉;
* 下一次 check 仍会重新产生 CHANGE 上报。
*/
int radar_report_service_mark_reported(
u32 now_ms
);
#endif
+119
View File
@@ -0,0 +1,119 @@
#include "radar_uart.h"
static struct device *radar_uart_hdl = NULL;//串口操作句柄
static u8 radar_uart_rx_buf[RADAR_UART_RX_BUF_SIZE]//串口驱动环形缓冲区
__attribute__((aligned(32)));
/* UART1初始化 PC6 = TX PC7 = RX */
UART1_PLATFORM_DATA_BEGIN(radar_uart_data)
.baudrate = RADAR_UART_BAUDRATE,
.port = PORT_REMAP,
.tx_pin = IO_PORTC_06,
.rx_pin = IO_PORTC_07,
.output_channel = OUTPUT_CHANNEL3,
.input_channel = INPUT_CHANNEL3,
.max_continue_recv_cnt = RADAR_UART_RX_BUF_SIZE,
.idle_sys_clk_cnt = 500000,
.clk_src = PLL_48M,
UART1_PLATFORM_DATA_END();
/* 注册串口设备 */
REGISTER_DEVICES(radar_uart_devices) = {
{
RADAR_UART_NAME,
&uart_dev_ops,
(void *)&radar_uart_data
},
};
int radar_uart_init(void)
{
int ret;
if (radar_uart_hdl) {
return 0;
}
radar_uart_hdl = dev_open(RADAR_UART_NAME, NULL);
if (!radar_uart_hdl) {
return -1;
}//句柄写入失败跳出返回-1
ret = dev_ioctl(
radar_uart_hdl,
UART_SET_CIRCULAR_BUFF_ADDR,//配置驱动缓冲区地址
(u32)radar_uart_rx_buf
);
if (ret) {
goto error;
}
ret = dev_ioctl(
radar_uart_hdl,
UART_SET_CIRCULAR_BUFF_LENTH,//配置驱动缓冲区长度
sizeof(radar_uart_rx_buf)
);
if (ret) {
goto error;
}
ret = dev_ioctl(
radar_uart_hdl,
UART_SET_RECV_BLOCK,//配置为阻塞接收模式
1
);
if (ret) {
goto error;
}
ret = dev_ioctl(
radar_uart_hdl,
UART_SET_RECV_TIMEOUT,//配置接收超时时间
RADAR_UART_RX_TIMEOUT_MS
);
if (ret) {
goto error;
}
ret = dev_ioctl(
radar_uart_hdl,
UART_START,//启动串口
0
);
if (ret) {
goto error;
}
return 0;
//goto error时会跳转至此,释放资源返回ret
error:
dev_close(radar_uart_hdl);
radar_uart_hdl = NULL;
return ret;
}
int radar_uart_read(u8 *buf, u32 len)//从驱动缓冲区读取数据并存到buf中,len为读取的最大长度
{
if (!radar_uart_hdl || !buf || !len) {
return -1;
}
return dev_read(radar_uart_hdl, buf, len);
}
int radar_uart_write(const u8 *data, u32 len)//给雷达写命令,data为写入数据,len为实际写入长度
{
if (!radar_uart_hdl || !data || !len) {
return -1;
}
return dev_write(
radar_uart_hdl,
(void *)data,
len
);
}
+18
View File
@@ -0,0 +1,18 @@
#ifndef RADAR_UART_H
#define RADAR_UART_H
#include "device/uart.h" //串口驱动头文件
#include "asm/includes.h" //芯片引脚定义
#include "typedef.h"
#define RADAR_UART_NAME "uart1"
#define RADAR_UART_BAUDRATE 115200
#define RADAR_UART_RX_BUF_SIZE 1024
#define RADAR_UART_RX_TIMEOUT_MS 500
int radar_uart_init(void);
int radar_uart_read(u8 *buf, u32 len);
int radar_uart_write(const u8 *data, u32 len);
int radar_uart_flush(void);
#endif