#include "BLE.h" #include #include #define BLE_DBG_EN 0 // 1=开启调试输出,0=关闭 #if (BLE_DBG_EN) #define DEBUG(format, ...) printf("[BLE] " format, ##__VA_ARGS__) #else #define DEBUG(format, ...) // 关闭时,宏替换为空,不产生任何代码 #endif char ble_rx_buffer[256]; BLE_STATE curr_state; static size_t current_cmd_index = 0; static uint32_t cmd_start_time; static uint8_t current_try_count = 0; static CmdExecutor_t init_executor; static CmdExecutor_t first_connect_executor; static CmdExecutor_t connect_executor; static CmdExecutor_t set_executor; const char* ble_state_names[] = { "BLE_INIT", "BLE_FIRST_CONECT", "BLE_CONNECTED", "BLE_READY", "BLE_ERROR", "BLE_SET", "BLE_WAITTING" }; const char* ble_sub_state_names[] = { "BLE_SUB_STATE_IDLE", "BLE_SUB_STATE_SEND_WAIT", "BLE_SUB_STATE_PROCESS_RESP" }; void BLE_Init(void) { curr_state = BLE_INIT; ble_cmd_rec_done = 0; } BLE_STATE BLE_GetState(void) { return curr_state; } void BLE_StateMachine_Handler(void) { switch(curr_state) { case BLE_INIT : { if(init_executor.sequence == NULL) { init_executor.sequence = ble_init_sequence; init_executor.cmd_index = 0; init_executor.retry_cnt = 0; init_executor.state = EXEC_STATE_IDLE; } ExecutorResult_t res = CmdExecutor_Process(&init_executor); if(res == EXECUTOR_DONE) { /* 尝试读取保存在本地的数据,如果没有则进入first connect 如果有则进入connected */ memset(&init_executor, 0, sizeof(init_executor)); } else if(res == EXECUTOR_ERROR) { g_ble_error.cmd_index = init_executor.cmd_index; g_ble_error.error_code =init_executor.error_code; g_ble_error.main_state = curr_state; g_ble_error.timestamp = HAL_GetTick(); g_ble_error.origin_state = BLE_INIT; curr_state = BLE_ERROR; memset(&init_executor, 0, sizeof(init_executor)); } } break; case BLE_FIRST_CONECT : { ExecutorResult_t res = CmdExecutor_Process(&first_connect_executor); if(res == EXECUTOR_DONE) { /* 保存参数到本地 */ curr_state = BLE_CONNECTED; } else if(res == EXECUTOR_ERROR) { g_ble_error.cmd_index = init_executor.cmd_index; g_ble_error.error_code =init_executor.error_code; g_ble_error.main_state = curr_state; g_ble_error.timestamp = HAL_GetTick(); g_ble_error.origin_state = BLE_FIRST_CONECT; curr_state = BLE_ERROR; memset(&init_executor, 0, sizeof(first_connect_executor)); } } break; case BLE_CONNECTED : { ExecutorResult_t res = CmdExecutor_Process(&connect_executor); if(res == EXECUTOR_DONE) { /* 保存参数到本地 */ curr_state = BLE_READY; } else if(res == EXECUTOR_ERROR) { g_ble_error.cmd_index = init_executor.cmd_index; g_ble_error.error_code =init_executor.error_code; g_ble_error.main_state = curr_state; g_ble_error.timestamp = HAL_GetTick(); g_ble_error.origin_state = BLE_CONNECTED; curr_state = BLE_ERROR; memset(&init_executor, 0, sizeof(connect_executor)); } } break; case BLE_READY : { /* 在已经开启透传的情况下周期性发送消息,一般情况不进行跳转其他状态 如果超时则返回连接状态,多次出问题则进error */ } break; case BLE_ERROR : { static uint8_t recovery_level = 0; const uint8_t MAX_RECOVERY_LEVEL = 3; switch(g_ble_error.type) { case ERR_TYPE_NONE: curr_state = g_ble_error.origin_state; break; case ERR_TYPE_PREPARE_FAILED: { g_ble_error.recovery_target = RECOVERY_TARGET_RECONFIG_UART; //curr_state = BLE_WAITTING; } break; case ERR_TYPE_TIMEOUT_EXCEEDED: { g_ble_error.recovery_target = RECOVERY_TARGET_RESTART_SEQ; //curr_state = BLE_SET; //重新配置串口信息 } break; case ERR_TYPE_PARSE_FAILED: { // DEBUG("error message ,main state:%s, sub state:%s, cmd_index:%d, timestamp:%d", // ble_state_names[g_ble_error.main_state], ble_sub_state_names[g_ble_error.sub_state], g_ble_error.cmd_index, g_ble_error.timestamp); g_ble_error.recovery_target = RECOVERY_TARGET_RESTART_SEQ; //重新配置串口信息 } break; case ERR_TYPE_MODULE_ERROR: { uint8_t table_size = sizeof(g_ble_error_table) / sizeof(g_ble_error_table[0]); uint8_t i; for(i = 0; i < table_size; i++) { if(g_ble_error.error_code == g_ble_error_table[i].code) { g_ble_error.recovery_target = g_ble_error_table[i].recovery_target; DEBUG("error message ,main state:%s, sub state:%s, cmd_index:%d, timestamp:%d", ble_state_names[g_ble_error.main_state], ble_sub_state_names[g_ble_error.sub_state], g_ble_error.cmd_index, g_ble_error.timestamp); //curr_state = BLE_SET; } if(i == table_size) { g_ble_error.recovery_target = RECOVERY_TARGET_RESTART_SEQ; } } } break; default: g_ble_error.recovery_target = RECOVERY_TARGET_PANIC; break; } if(g_ble_error.recovery_target >= RECOVERY_TARGET_SW_RESET_MODULE) { recovery_level++; if(recovery_level > MAX_RECOVERY_LEVEL) { // 超过最大恢复级别,无法恢复,进入等待 DEBUG("恢复级别 %d 超过阈值,进入等待", recovery_level); curr_state = BLE_WAITTING; break; // 跳出 BLE_ERROR } } // 3. 执行恢复动作 switch(g_ble_error.recovery_target) { case RECOVERY_TARGET_RESTART_SEQ: // 重启当前流程阶段:根据 origin_state 重置对应的执行器 switch(g_ble_error.origin_state) { case BLE_INIT: memset(&init_executor, 0, sizeof(init_executor)); break; case BLE_FIRST_CONECT: memset(&first_connect_executor, 0, sizeof(first_connect_executor)); break; case BLE_CONNECTED: memset(&connect_executor, 0, sizeof(connect_executor)); break; default: break; } // 返回原状态,重新开始执行序列 curr_state = g_ble_error.origin_state; break; case RECOVERY_TARGET_RECONFIG_UART: // 重新配置 MCU 串口(调用你的串口初始化函数) // 例如: MX_USART1_UART_Init(); // 然后重置对应执行器 switch(g_ble_error.origin_state) { case BLE_INIT: memset(&init_executor, 0, sizeof(init_executor)); break; case BLE_FIRST_CONECT: memset(&first_connect_executor, 0, sizeof(first_connect_executor)); break; case BLE_CONNECTED: memset(&connect_executor, 0, sizeof(connect_executor)); break; default: break; } curr_state = g_ble_error.origin_state; break; // case RECOVERY_TARGET_SW_RESET_MODULE: case RECOVERY_TARGET_FACTORY_RESET: // 需要通过 AT 命令执行,进入 BLE_SET 状态 // 注意:origin_state 保持不变,BLE_SET 执行完后会返回它 curr_state = BLE_SET; break; case RECOVERY_TARGET_HARD_RESET_MODULE: // 硬件复位模块:拉低复位引脚,延时,拉高 // 假设有 BLE_RST_PIN 控制 // HAL_GPIO_WritePin(BLE_RST_GPIO_Port, BLE_RST_Pin, GPIO_PIN_RESET); // HAL_Delay(100); // HAL_GPIO_WritePin(BLE_RST_GPIO_Port, BLE_RST_Pin, GPIO_PIN_SET); // 复位后重置对应执行器 switch(g_ble_error.origin_state) { case BLE_INIT: memset(&init_executor, 0, sizeof(init_executor)); break; case BLE_FIRST_CONECT: memset(&first_connect_executor, 0, sizeof(first_connect_executor)); break; case BLE_CONNECTED: memset(&connect_executor, 0, sizeof(connect_executor)); break; default: break; } curr_state = g_ble_error.origin_state; break; case RECOVERY_TARGET_SOFT_RESET_MCU: // 软件复位整个 MCU //NVIC_SystemReset(); break; case RECOVERY_TARGET_PANIC: default: // 无法恢复,进入等待状态 DEBUG("error message ,main state:%s, sub state:%s, cmd_index:%d, timestamp:%d", ble_state_names[g_ble_error.main_state], ble_sub_state_names[g_ble_error.sub_state], g_ble_error.cmd_index, g_ble_error.timestamp); curr_state = BLE_WAITTING; break; } } break; case BLE_SET : { const BleAtCmd_t* target_seq = NULL; switch(g_ble_error.recovery_target) { case RECOVERY_TARGET_SW_RESET_MODULE: { static const BleAtCmd_t sw_reset_sq[] = { {"AT+RESET\r\n", "OK", 100, 3, NULL, NULL}, {NULL, NULL, 0, 0, NULL, NULL} }; target_seq = sw_reset_sq; } break; case RECOVERY_TARGET_FACTORY_RESET: //回复出厂设置 { static const BleAtCmd_t factory_reset_seq[] = { {"AT+DEFAULT\r\n", "OK", 100, 3, NULL, NULL}, {NULL, NULL, 0, 0, NULL, NULL} }; target_seq = factory_reset_seq; } break; default: //没有匹配目标则返回原状态 curr_state = g_ble_error.origin_state; break; } if(target_seq != NULL) { // 如果 set_executor 尚未启动,则初始化 if(set_executor.sequence == NULL) { set_executor.sequence = target_seq; set_executor.cmd_index = 0; set_executor.retry_cnt = 0; set_executor.state = EXEC_STATE_IDLE; } ExecutorResult_t res = CmdExecutor_Process(&set_executor); if(res == EXECUTOR_DONE) { // 恢复命令执行成功,将恢复级别清零,返回原状态 // 注意:恢复级别 recovery_level 是在 BLE_ERROR 中定义的静态变量,这里无法直接访问。 // 解决方案:可以在 BLE_ERROR 中定义一个全局或外部变量,或者通过某种方式传递。 // 简单起见,我们可以在 BLE_ERROR 中重置 recovery_level,但这里无法做到。 // 一个常见的做法是在 BLE_ERROR 中判断恢复成功与否,但由于这里返回原状态,我们可以在返回前设置一个标志,让 BLE_ERROR 下次进入时重置级别。 // 但考虑到恢复级别只在 BLE_ERROR 中管理,我们可以这样处理:当 BLE_SET 成功返回原状态后,原状态会继续执行,如果再次出错会重新进入 BLE_ERROR,此时 recovery_level 仍然存在,但这是合理的(因为已经成功过,应该重置级别?) // 实际上,一次恢复成功意味着系统已经正常,应该重置级别。所以我们需要在 BLE_SET 成功时通知 BLE_ERROR 重置级别。 // 由于 recovery_level 是 BLE_ERROR 内部的静态变量,无法直接从外部修改。我们可以将 recovery_level 定义为全局变量,或者通过函数接口。 // 这里为了简单,我们假设 recovery_level 是全局变量(例如在文件顶部定义),并在 BLE_SET 成功时清零。 // 请根据实际情况调整。下面假设有一个全局变量 uint8_t g_recovery_level; 并在 BLE_ERROR 中改为使用它。 // 如果没有,你可以将 recovery_level 定义在文件作用域(static),然后在 BLE_SET 中包含一个 extern 声明。 // 这里我们暂时注释掉,你需要根据你的设计实现。 // g_recovery_level = 0; // 如果使用全局变量 memset(&set_executor, 0, sizeof(set_executor)); curr_state = g_ble_error.origin_state; } else if(res == EXECUTOR_ERROR) { // 恢复命令也失败,将 set_executor 中的错误信息复制到 g_ble_error(保留 origin_state) g_ble_error.type = set_executor.error_type; g_ble_error.error_code = set_executor.error_code; g_ble_error.cmd_index = set_executor.error_cmd_index; g_ble_error.timestamp = HAL_GetTick(); // 注意:不要覆盖 origin_state memset(&set_executor, 0, sizeof(set_executor)); // 再次进入 BLE_ERROR,恢复级别将在那里递增 curr_state = BLE_ERROR; } // 若返回 BUSY,则继续等待,不做状态切换 } } break; case BLE_WAITTING: { static uint32_t last_time = 0; uint32_t time = HAL_GetTick(); uint32_t rest = time - last_time; if(rest >= 500) { //输出警报 last_time = time; } } break; default: break; } } ExecutorResult_t CmdExecutor_Process(CmdExecutor_t* ex) { switch(ex->state) { case EXEC_STATE_IDLE: { ble_cmd_rec_done= 0; if(ex->sequence[ex->cmd_index].cmd == NULL) { DEBUG("init success"); return EXECUTOR_DONE; } const BleAtCmd_t *current_cmd = &ex->sequence[ex->cmd_index]; char final_cmd[64]; int prepare_ok = 0; // 标记准备是否成功 if(current_cmd->prepare_cmd != NULL) { int prepare_result = current_cmd->prepare_cmd(current_cmd->cmd, final_cmd, sizeof(final_cmd)); if(prepare_result != 0) { DEBUG("命令准备失败,错误码: %d,跳过此命令", prepare_result); ex->error_type = ERR_TYPE_PREPARE_FAILED; ex->error_code = prepare_result; ex->error_cmd_index = ex->cmd_index; ex->state = EXEC_STATE_ERROR; return EXECUTOR_ERROR; } else { prepare_ok = 1; } } else { strncpy(final_cmd, current_cmd->cmd, sizeof(final_cmd)); final_cmd[sizeof(final_cmd) - 1] = '\0'; prepare_ok = 1; } if(prepare_ok == 1) { //发送命令 待添加实际代码 ex->start_tick = HAL_GetTick(); ex->state = EXEC_STATE_SEND_WAIT; ble_cmd_rec_done = 0; return EXECUTOR_BUSY; } return EXECUTOR_BUSY; } break; case EXEC_STATE_SEND_WAIT: { const BleAtCmd_t *current_cmd = &ex->sequence[ex->cmd_index]; uint16_t out_time = current_cmd->timeout_ms; uint8_t try_max = current_cmd->retry_max; if(ble_cmd_rec_done == 1) { ex->retry_cnt = 0; ex->state = EXEC_STATE_PROCESS_RESP; return EXECUTOR_BUSY; } uint32_t time = HAL_GetTick(); if((time - ex->start_tick) > out_time) { ex->retry_cnt++; if(ex->retry_cnt <= try_max) { ex->state = EXEC_STATE_IDLE; ble_cmd_rec_done = 0; // 建议清零,避免旧数据影响下一次 return EXECUTOR_BUSY; } else { ex->error_type = ERR_TYPE_TIMEOUT_EXCEEDED; ex->error_code = 0; ex->error_cmd_index = ex->cmd_index; ex->state = EXEC_STATE_ERROR; return EXECUTOR_ERROR; } } return EXECUTOR_BUSY; } break; case EXEC_STATE_PROCESS_RESP: { //接受串口回传具体信息 //char process_data[] = 缓存区数据 const BleAtCmd_t *current_cmd = &ex->sequence[ex->cmd_index]; int result; if ((current_cmd->parse_resp) != NULL) { result = current_cmd->parse_resp(ble_rx_buffer); } else { result = parse_general_resp(ble_rx_buffer); } if(result == 0) //解析正确 { ex->cmd_index++; ex->retry_cnt = 0; ex->state = EXEC_STATE_IDLE; ble_cmd_rec_done = 0; return EXECUTOR_BUSY; } else if(result > 0) //模块返回错误码 { ex->retry_cnt++; if(ex->retry_cnt <= current_cmd->retry_max) { ex->state = EXEC_STATE_IDLE; ble_cmd_rec_done = 0; return EXECUTOR_BUSY; } else { ex->error_type = ERR_TYPE_MODULE_ERROR; ex->error_code = result; ex->error_cmd_index = ex->cmd_index; ex->state = EXEC_STATE_ERROR; return EXECUTOR_ERROR; } } else //result<0 { //解析失败的其他情况 ex->retry_cnt++; if(ex->retry_cnt <= current_cmd->retry_max) { ex->state = EXEC_STATE_IDLE; ble_cmd_rec_done = 0; return EXECUTOR_BUSY; } else { ex->error_type = ERR_TYPE_PARSE_FAILED; ex->error_code = result; ex->error_cmd_index = ex->cmd_index; ex->state = EXEC_STATE_ERROR; return EXECUTOR_ERROR; } } } break; default: break; } } uint8_t BLE_UART_RxCallback(void) { } int parse_general_resp(const char* resp) { if(resp == NULL) { return -1; } const char *ok_result = strstr(resp, "OK"); if(ok_result != NULL) { return 0; } int err_code = 0; int auth = sscanf(resp, "ERROR=<%d>", &err_code); if(auth == 1) { uint8_t table_size = sizeof(g_ble_error_table)/sizeof(g_ble_error_table[0]); for(uint8_t i = 0; i= buf_size) { return -2; } else { return -3; } } int parse_diradv_cmd(const char* cmd_template, char* cmd_buf, int buf_size) { }