#include "system/includes.h" #include "system/timer.h" #include "app_log.h" #include "r60abd1.h" #include "radar_uart.h" #include /* * 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 ); }