fix command code

This commit is contained in:
yelvlab 2025-08-13 00:39:30 +08:00
parent 05cebe979d
commit 5e6077884b
5 changed files with 274 additions and 111 deletions

View File

@ -11,6 +11,11 @@
// #define SOFTWARE_IIC // IIC Type : Software IIC
#undef SOFTWARE_IIC // IIC Type : Hardware IIC
/* >>>>>>>>>>>>>>>>>>>>[DEBUG ASSERTIONS DEFINE]<<<<<<<<<<<<<<<<<<<< */
// #define DEBUG_VERBOSE // Debug Assertions Status : Debug Verbose Information
#undef DEBUG_VERBOSE // Debug Assertions Status : No Debug Verbose Information
/******************************************************************************/
#define RCU_GPIO_I2C RCU_GPIOF

View File

@ -1,13 +1,101 @@
/**
* @file command.h
* @brief
* @details
* D5 03 LEN [cmd] CRC
*/
#ifndef COMMAND_H
#define COMMAND_H
#include <stdint.h>
#include <stdbool.h>
/**
* @defgroup Command
* @brief
* @{
*/
/**
* @section Command_Protocol
*
* @code
* [0] HEADER = 0xD5 // 包头标识
* [1] BOARD_TYPE = 0x03 // 板卡类型标识
* [2] LEN = // 有效载荷长度
* [3..(3+LEN-1)] // 命令数据
* [last] CRC // 校验码从索引1累加到len-2的低8位
* @endcode
*
*
* @code
* [0] HEADER = 0xB5 // 响应包头
* [1] TYPE // 响应类型0xF0=成功0xF1..=错误类型)
* [2] LEN // 响应数据长度
* [3..(3+LEN-1)] // 响应数据
* [last] CRC // 校验码
* @endcode
*
* @section Command_Usage 使
* 1)
* @code{.c}
* uart_ring_buffer_init();
* @endcode
*
* 2)
* @code{.c}
* while(1) {
* command_process(); // 处理接收到的命令
* // 其他业务逻辑
* }
* @endcode
*
* 3)
* @code{.c}
* if(get_sensor_report_enabled()) {
* // 执行传感器数据上报
* }
* @endcode
*/
/**
* @brief 使
* @return bool
* @retval true
* @retval false
* @ingroup Command
*/
bool get_sensor_report_enabled(void);
/**
* @brief 使
* @param enabled 使
* @arg true
* @arg false
* @note 便
* @ingroup Command
*/
void set_sensor_report_enabled(bool enabled);
/**
* @brief
* @details
*
* @note 使
* @warning
* @ingroup Command
*/
void command_process(void);
/**
* @brief
* @param cmd 0xD5
* @param len
* @note command_process() 使
* @ingroup Command
*/
void handle_command(const uint8_t *cmd, uint8_t len);
/** @} */ // end of Command group
#endif // COMMAND_H

View File

@ -1,56 +1,92 @@
/**
* @file command.c
* @brief
* @details D5 03 LEN [cmd] CRC
*
* @author Hulk
* @date 2025-08-13
* @version 1.0.0
* @ingroup Command
*/
#include "command.h"
#include "uart_ring_buffer.h"
#include "led.h"
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "board_config.h"
/*
Host -> Device
[0] HEADER = 0xD5
[1] BOARD_TYPE = 0x03
[2] LEN =
[3..(3+LEN-1)]
[last] CRC = 1 (last-1) 8
/* ============================================================================
*
* ============================================================================ */
6
"M1" / "M2" / "M3"
Device -> Host 0xB5
[0] 0xB5, [1] TYPE( 0xF0=OK, 0xF1..=), [2] LEN, [3..] payload, [last] CRC
/**
* @name
* @{
* @details
* Host -> Device
* [0] HEADER = 0xD5 // 包头标识
* [1] BOARD_TYPE = 0x03 // 板卡类型标识
* [2] LEN = // 有效载荷长度
* [3..(3+LEN-1)] // 命令数据,如 "M1", "M2S123"
* [last] CRC = // 从索引1到(last-1)的累加和低8位
*
* 6
* "M1" / "M2" / "M3"
*
* Device -> Host
* [0] 0xB5 // 响应包头
* [1] TYPE // 响应类型0xF0=成功0xF1..=错误类型)
* [2] LEN // 响应数据长度
* [3..(3+LEN-1)] // 响应数据,如 "ok", "err"
* [last] CRC // 校验码(同命令帧规则)
* @}
*/
// 旧工程中的外部状态与复位函数(本工程暂不直接使用,按要求保留为注释):
// void fwdgt_reset_mcu(void); // 看门狗复位
/* ============================================================================
*
* ============================================================================ */
#define PROTOCOL_PACKAGE_HEADER 0xD5
#define PROTOCOL_BOARD_TYPE 0x03
#define PROTOCOL_PACKAGE_LENGTH 0x02
/** @name 协议帧标识符
* @{ */
#define PROTOCOL_PACKAGE_HEADER 0xD5 /**< 命令帧包头标识 */
#define PROTOCOL_BOARD_TYPE 0x03 /**< 板卡类型标识 */
/** @} */
#define COMMAND_MIN_LEN 2 // 最小命令长度如M1 M2命令
// 最小/最大整帧长度header(1)+type(1)+len(1)+payload(len>=2)+crc(1) = 3 + LEN + 1
#define PROTOCOL_MIN_FRAME_LEN (3 + COMMAND_MIN_LEN + 1)
#define PROTOCOL_MAX_FRAME_LEN 32
/* 可选的应答类型定义(与示例保持一致,可按需扩展) */
#define RESP_HEADER 0xB5
#define RESP_TYPE_OK 0xF0
#define RESP_TYPE_CRC_ERR 0xF1
#define RESP_TYPE_HEADER_ERR 0xF2
#define RESP_TYPE_TYPE_ERR 0xF3
#define RESP_TYPE_LEN_ERR 0xF4
/** @name 命令长度限制
* @{ */
#define COMMAND_MIN_LEN 2 /**< 最小命令长度,如"M1" */
#define PROTOCOL_MIN_FRAME_LEN (3 + COMMAND_MIN_LEN + 1) /**< 最小完整帧长度header+type+len+payload+crc = 6 */
#define PROTOCOL_MAX_FRAME_LEN 16 /**< 最大完整帧长度 */
/** @} */
/** @name 响应帧标识符
* @{ */
#define RESP_HEADER 0xB5 /**< 响应帧包头标识 */
#define RESP_TYPE_OK 0xF0 /**< 成功响应类型 */
#define RESP_TYPE_CRC_ERR 0xF1 /**< CRC校验错误 */
#define RESP_TYPE_HEADER_ERR 0xF2 /**< 包头错误 */
#define RESP_TYPE_TYPE_ERR 0xF3 /**< 类型错误 */
#define RESP_TYPE_LEN_ERR 0xF4 /**< 长度错误 */
/** @} */
/* ============================================================================
*
* ============================================================================ */
/** @brief 传感器周期上报使能标志 */
static volatile bool s_sensor_report_enabled = false;
static volatile uint32_t s_cmd_param = 0; // 保存形如 M123S<param> 的附加参数(十进制),完整保留为 uint32_t
// 统一的应答负载常量
static const uint8_t s_report_status_ok[] = { 'o', 'k' };
static const uint8_t s_report_status_err[] = { 'e','r','r' };
/** @name 预设响应数据
* @{ */
static const uint8_t s_report_status_ok[] = { 'o', 'k' }; /**< 成功响应数据 */
static const uint8_t s_report_status_err[] = { 'e','r','r' }; /**< 错误响应数据 */
/** @} */
/* ============================================================================
*
* ============================================================================ */
/**
* @brief
@ -99,7 +135,17 @@ static uint8_t command_sum_crc_calc(const uint8_t *data, uint8_t len)
return (uint8_t)(crc & 0xFF);
}
/* 发送应答header(0xB5), type, len, payload[len], crc */
/**
* @brief
* @details B5 TYPE LEN [payload] CRC
* CRC校验值并通过串口输出
* @param type RESP_TYPE_OK, RESP_TYPE_CRC_ERR
* @param payload NULL
* @param len payload为NULL时填充0
* @note 使
* @warning printf
* @ingroup Command
*/
static void send_response(uint8_t type, const uint8_t *payload, uint8_t len)
{
uint8_t buf_len = (uint8_t)(3 + len + 1);
@ -115,26 +161,33 @@ static void send_response(uint8_t type, const uint8_t *payload, uint8_t len)
for (uint8_t i = 0; i < buf_len; i++) {
printf("%c", buf[i]);
}
// 刷新缓冲区
fflush(stdout);
}
/* 简单数字工具 */
/**
* @brief
* @param c ASCII 0..255
* @return true c '0'..'9' false
* @param c ASCII码值
* @return bool
* @retval true '0' '9'
* @retval false
* @ingroup Command
*/
static inline bool is_dec_digit(uint8_t c) { return (c >= '0' && c <= '9'); }
/**
* @brief
* @details s[0] '0'..'9' 32
* n n
* @param s '\0'
* @param n s[0]
* @param out NULL 0 out
* @return uint8_t 0
* @note uint32_t
* @brief
* @details 32
*
* @param s
* @param n
* @param out NULL
* @return uint8_t
* @retval 0
* @retval >0
* @note
* @warning uint32_t范围时按无符号算术溢出处理
* @ingroup Command
*/
static uint8_t parse_uint_dec(const uint8_t *s, uint8_t n, uint32_t *out)
@ -151,15 +204,25 @@ static uint8_t parse_uint_dec(const uint8_t *s, uint8_t n, uint32_t *out)
return i;
}
/* ============================================================================
*
* ============================================================================ */
/**
* @brief
* @details D5 03 LEN [cmd] CRCLEN [cmd] 'M'
* - M<base> M1M10M201M100
* - M<base>S<param>param uint32_t M1S123M22S456
* 3+LEN+1==len [cmd]
* led_on/off send_response
* @param frame HEADER=0xD5
* @param len
* @brief
* @details
* - M<> M1M2M10M201
* - M<>S<> M100S123
*
*
* - M1: LED
* - M2: LED
* - M100S<value>: PWM值
*
* @param frame 0xD5
* @param len
* @note
* @warning CRC等
* @ingroup Command
*/
void handle_command(const uint8_t *frame, uint8_t len) {
@ -198,12 +261,16 @@ void handle_command(const uint8_t *frame, uint8_t len) {
set_sensor_report_enabled(true);
led_on();
send_response(RESP_TYPE_OK, s_report_status_ok, sizeof(s_report_status_ok));
uint8_t test_response1[] = { 0xAA, 0xBB, 0xCC, 0xDD };
send_response(RESP_TYPE_OK, test_response1, sizeof(test_response1));
return;
case 2u: // M2命令
led_off();
set_sensor_report_enabled(false);
led_off();
send_response(RESP_TYPE_OK, s_report_status_ok, sizeof(s_report_status_ok));
uint8_t test_response2[] = { 0xDD, 0xCC, 0xBB, 0xAA };
send_response(RESP_TYPE_OK, test_response2, sizeof(test_response2));
return;
// 示例M3、M10、M201、M100 等(按需添加)
@ -253,10 +320,34 @@ void handle_command(const uint8_t *frame, uint8_t len) {
}
}
/**
* @brief
* @details D5 03 LEN [cmd] CRC
* - 1 PROTOCOL_PACKAGE_HEADER (0xD5)
* - 2 PROTOCOL_BOARD_TYPE (0x03)
* - 3
* - 4
* - 5CRC
*
*
*
*
* @note 使使
* PROTOCOL_MAX_FRAME_LEN
*
* @warning uart_ring_buffer_available() uart_ring_buffer_get()
*
*
* @see handle_command()
* @see command_sum_crc_calc() CRC
* @see send_response()
*
* @ingroup Command
*/
void command_process(void) {
static uint8_t cmd_buf[PROTOCOL_MAX_FRAME_LEN];
static uint8_t cmd_len = 0;
static uint8_t expected_total = 0; // 0 表示尚未确定总长度
static uint8_t expected_cmd_len = 0; // 0 表示尚未确定总长度
while (uart_ring_buffer_available() > 0) {
int byte = uart_ring_buffer_get();
@ -265,81 +356,65 @@ void command_process(void) {
if (cmd_len == 0) {
if ((uint8_t)byte == PROTOCOL_PACKAGE_HEADER) {
cmd_buf[cmd_len++] = (uint8_t)byte;
expected_total = 0; // 等待进一步字段以确定长度
expected_cmd_len = 0; // 等待进一步字段以确定长度
} else {
// 丢弃非起始字节
}
continue;
}
// 累积后续字节
if (cmd_len >= PROTOCOL_MAX_FRAME_LEN) {
// 防御:缓冲溢出,复位状态机
cmd_len = 0;
expected_cmd_len = 0;
}
// 缓存后续字节
cmd_buf[cmd_len++] = (uint8_t)byte;
// 当到达长度字段(索引 2确定总长度3 + LEN + 1
if (cmd_len == 3) {
uint8_t payload_len = cmd_buf[2];
expected_total = (uint8_t)(3 + payload_len + 1);
if (expected_total > PROTOCOL_MAX_FRAME_LEN) {
expected_cmd_len = (uint8_t)(3 + payload_len + 1);
if (expected_cmd_len > PROTOCOL_MAX_FRAME_LEN) {
// 异常:长度超界,复位状态机
cmd_len = 0;
expected_total = 0;
expected_cmd_len = 0;
}
continue;
}
if (expected_total > 0 && cmd_len == expected_total) {
if (expected_cmd_len > 0 && cmd_len == expected_cmd_len) {
// 到帧尾,进行各项校验
bool ok = true;
bool verification_status = true;
#ifdef DEBUG_VERBOSE
if (cmd_buf[0] != PROTOCOL_PACKAGE_HEADER) {
send_response(RESP_TYPE_HEADER_ERR, s_report_status_err, sizeof(s_report_status_err));
ok = false;
verification_status = false;
}
if (ok && cmd_buf[1] != PROTOCOL_BOARD_TYPE) {
#endif
if (verification_status && cmd_buf[1] != PROTOCOL_BOARD_TYPE) {
send_response(RESP_TYPE_TYPE_ERR, s_report_status_err, sizeof(s_report_status_err));
ok = false;
verification_status = false;
}
if (ok) {
uint8_t crc_calc = command_sum_crc_calc(cmd_buf, expected_total);
uint8_t crc_recv = cmd_buf[expected_total - 1];
if (verification_status) {
uint8_t crc_calc = command_sum_crc_calc(cmd_buf, expected_cmd_len);
uint8_t crc_recv = cmd_buf[expected_cmd_len - 1];
if (crc_calc != crc_recv) {
send_response(RESP_TYPE_CRC_ERR, s_report_status_err, sizeof(s_report_status_err));
ok = false;
verification_status = false;
}
}
if (ok) {
handle_command(cmd_buf, expected_total);
if (verification_status) {
handle_command(cmd_buf, expected_cmd_len);
}
// 复位,等待下一帧
cmd_len = 0;
expected_total = 0;
}
if (cmd_len >= PROTOCOL_MAX_FRAME_LEN) {
// 防御:缓冲溢出,复位状态机
cmd_len = 0;
expected_total = 0;
expected_cmd_len = 0;
}
}
}
// -----------------------------------------------------------------------------
// 下列为与传感器相关的报告函数占位,按要求“保留但注释掉”。
// 原工程中依赖 ldc1612/tmp112a 读数并通过 0xB5 帧打印上报。
// 若后续集成这些传感器驱动,可解注释并补齐实现。
//
// static uint8_t package_header[3] = {0xB5, 0xF0, 0x04};
// static uint8_t package_data[4] = {0};
//
// void eddy_current_value_report(void) {
// uint32_t eddy_current_value_uint32 = ldc1612_get_raw_channel_result(CHANNEL_0);
// (void)eddy_current_value_uint32;
// // 按原协议组帧并 printf 发送B5 F0 04 [data3..data0] CRC
// }
//
// void tempture_value_report(void) {
// uint32_t temperature_uint32 = tmp112a_get_raw_channel_result();
// (void)temperature_uint32;
// // 按原协议组帧并 printf 发送B5 F0 04 [data3..data0] CRC
// }

View File

@ -4,7 +4,7 @@ void led_init(void) {
rcu_periph_clock_enable(LED_RCU);
gpio_mode_set(LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_PIN);
gpio_output_options_set(LED_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LED_PIN);
gpio_bit_reset(LED_PORT, LED_PIN);
gpio_bit_set(LED_PORT, LED_PIN);
}
void led_on(void) {

View File

@ -59,11 +59,6 @@ int main(void)
printf("Hello USART0!");
led_off();
while(1){
// led_toggle();
// 发送数据到 USART0
// usart_data_transmit(RS485_PHY, (uint8_t)'H');
// printf("Hello USART0!");
delay_ms(100);
command_process();
}