| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607 |
- /**
- * @file at_cmd.c
- * @brief AT命令驱动核心 - 重构版(安全架构)
- * @note 采用查询模式而非回调,彻底避免函数指针导致的IBUSERR
- * 简化状态机,增加边界检查,提高可靠性
- */
- #define DBG_TAG "at.cmd"
- #define DBG_LVL DBG_LOG
- #include <rtdbg.h>
- #include "at_cmd.h"
- #include <string.h>
- #include <stdio.h>
- #include <rtdevice.h>
- /* ==================== 配置 ==================== */
- #ifndef AT_RECV_BUFFER_SIZE
- #define AT_RECV_BUFFER_SIZE 1024
- #endif
- #ifndef AT_CMD_TIMEOUT_MS
- #define AT_CMD_TIMEOUT_MS 5000
- #endif
- /* ==================== 内部状态 ==================== */
- typedef struct {
- /* 串口 */
- rt_device_t uart;
- /* 状态机 */
- volatile at_state_t state;
- at_result_t result;
- /* 当前命令 */
- const at_cmd_item_t *current_cmd;
- uint8_t retry_count;
- rt_tick_t start_tick;
- /* 接收缓冲 */
- char rx_buf[AT_RECV_BUFFER_SIZE];
- uint16_t rx_len;
- uint8_t rx_overflow; /* 溢出标志 */
- /* 错误信息 */
- char error_info[64];
- /* URC表 */
- struct {
- char prefix[AT_URC_MAX_LEN];
- at_urc_cb_t callback;
- uint8_t valid;
- } urc_table[AT_URC_MAX_NUM];
- /* 调试 */
- uint8_t debug_enable;
- /* 同步信号量(用于可选的同步API) */
- rt_sem_t cmd_sem;
- /* 初始化标志 */
- uint8_t initialized;
- } at_context_t;
- static at_context_t g_at = {0};
- /* ==================== 工具函数 ==================== */
- /**
- * @brief 安全字符串拷贝
- */
- static void safe_strcpy(char *dst, size_t dst_size, const char *src)
- {
- if (!dst || !src || dst_size == 0) return;
- size_t src_len = strlen(src);
- size_t copy_len = (src_len < dst_size - 1) ? src_len : dst_size - 1;
- memcpy(dst, src, copy_len);
- dst[copy_len] = '\0';
- }
- /**
- * @brief 清空接收缓冲区
- */
- static void rx_buf_clear(void)
- {
- g_at.rx_len = 0;
- g_at.rx_buf[0] = '\0';
- g_at.rx_overflow = 0;
- }
- /**
- * @brief 追加数据到接收缓冲区(带边界检查)
- */
- static void rx_buf_append(const char *data, uint16_t len)
- {
- if (!data || len == 0) return;
- /* 检查溢出 */
- if (g_at.rx_len + len >= AT_RECV_BUFFER_SIZE - 1) {
- /* 缓冲区满,丢弃旧数据(保留一半) */
- uint16_t keep_len = AT_RECV_BUFFER_SIZE / 2;
- memmove(g_at.rx_buf, g_at.rx_buf + g_at.rx_len - keep_len, keep_len);
- g_at.rx_len = keep_len;
- g_at.rx_overflow = 1;
- LOG_W("RX buffer overflow, discarding old data");
- }
- /* 追加数据 */
- uint16_t copy_len = len;
- if (g_at.rx_len + copy_len > AT_RECV_BUFFER_SIZE - 1) {
- copy_len = AT_RECV_BUFFER_SIZE - 1 - g_at.rx_len;
- }
- memcpy(g_at.rx_buf + g_at.rx_len, data, copy_len);
- g_at.rx_len += copy_len;
- g_at.rx_buf[g_at.rx_len] = '\0';
- }
- /**
- * @brief 从缓冲区移除已处理的数据
- */
- static void rx_buf_consume(uint16_t len)
- {
- if (len >= g_at.rx_len) {
- rx_buf_clear();
- } else {
- memmove(g_at.rx_buf, g_at.rx_buf + len, g_at.rx_len - len);
- g_at.rx_len -= len;
- g_at.rx_buf[g_at.rx_len] = '\0';
- }
- }
- /**
- * @brief 查找字符串,返回位置(类似strstr但限制长度)
- */
- static char* strnstr(const char *haystack, const char *needle, uint16_t haystack_len)
- {
- if (!haystack || !needle) return NULL;
- uint16_t needle_len = strlen(needle);
- if (needle_len == 0) return (char*)haystack;
- if (haystack_len < needle_len) return NULL;
- for (uint16_t i = 0; i <= haystack_len - needle_len; i++) {
- if (memcmp(haystack + i, needle, needle_len) == 0) {
- return (char*)(haystack + i);
- }
- }
- return NULL;
- }
- /**
- * @brief 检查是否包含完整响应行(以\n结尾)
- */
- static int has_complete_line(const char *buf, uint16_t len)
- {
- if (!buf || len == 0) return 0;
- for (uint16_t i = 0; i < len; i++) {
- if (buf[i] == '\n') return 1;
- }
- return 0;
- }
- /**
- * @brief 提取一行响应
- */
- static uint16_t extract_line(char *dst, uint16_t dst_size, const char *src, uint16_t src_len)
- {
- if (!dst || !src || dst_size == 0) return 0;
- for (uint16_t i = 0; i < src_len && i < dst_size - 1; i++) {
- if (src[i] == '\r' || src[i] == '\n') {
- dst[i] = '\0';
- /* 跳过\r\n */
- uint16_t skip = i;
- if (src[i] == '\r' && i + 1 < src_len && src[i+1] == '\n') {
- skip = i + 2;
- } else {
- skip = i + 1;
- }
- return skip;
- }
- dst[i] = src[i];
- }
- dst[0] = '\0';
- return 0;
- }
- /* ==================== URC处理 ==================== */
- /**
- * @brief 检查并处理URC
- * @return 1表示处理了URC,0表示无URC
- */
- static int process_urc(void)
- {
- if (g_at.rx_len == 0) return 0;
- /* 提取一行检查 */
- char line[128];
- uint16_t line_len = 0;
- for (uint16_t i = 0; i < g_at.rx_len && i < sizeof(line) - 1; i++) {
- if (g_at.rx_buf[i] == '\r' || g_at.rx_buf[i] == '\n') {
- line_len = i;
- break;
- }
- line[i] = g_at.rx_buf[i];
- }
- if (line_len == 0) return 0;
- line[line_len] = '\0';
- /* 匹配URC前缀 */
- for (int i = 0; i < AT_URC_MAX_NUM; i++) {
- if (!g_at.urc_table[i].valid) continue;
- const char *prefix = g_at.urc_table[i].prefix;
- if (strncmp(line, prefix, strlen(prefix)) == 0) {
- /* 匹配成功,调用回调 */
- if (g_at.urc_table[i].callback) {
- g_at.urc_table[i].callback(line, line_len);
- }
- /* 消费这行数据 */
- uint16_t consume = line_len;
- while (consume < g_at.rx_len &&
- (g_at.rx_buf[consume] == '\r' || g_at.rx_buf[consume] == '\n')) {
- consume++;
- }
- rx_buf_consume(consume);
- return 1;
- }
- }
- return 0;
- }
- /* ==================== 响应处理 ==================== */
- /**
- * @brief 检查响应是否完成
- * @return 1表示完成,0表示未完成
- */
- static int check_response_complete(void)
- {
- if (!g_at.current_cmd) return 1;
- const char *rsp = g_at.rx_buf;
- uint16_t rsp_len = g_at.rx_len;
- const at_cmd_item_t *cmd = g_at.current_cmd;
- /* 检查错误响应 */
- if (strnstr(rsp, "ERROR", rsp_len)) {
- g_at.result = AT_RESULT_ERROR;
- return 1;
- }
- /* 检查CME错误 */
- char *cme = strnstr(rsp, "+CME ERROR:", rsp_len);
- if (cme) {
- g_at.result = AT_RESULT_CME_ERROR;
- /* 提取错误信息 */
- safe_strcpy(g_at.error_info, sizeof(g_at.error_info), cme);
- return 1;
- }
- /* 检查CMS错误 */
- char *cms = strnstr(rsp, "+CMS ERROR:", rsp_len);
- if (cms) {
- g_at.result = AT_RESULT_CMS_ERROR;
- safe_strcpy(g_at.error_info, sizeof(g_at.error_info), cms);
- return 1;
- }
- /* 检查期望的成功响应 */
- if (cmd->expect_ok) {
- if (strnstr(rsp, cmd->expect_ok, rsp_len)) {
- /* 还需要OK确认(如果有) */
- if (strnstr(rsp, "OK", rsp_len)) {
- g_at.result = AT_RESULT_OK;
- return 1;
- }
- }
- } else {
- /* 没有指定期望响应,只要收到OK就算成功 */
- if (strnstr(rsp, "OK", rsp_len)) {
- g_at.result = AT_RESULT_OK;
- return 1;
- }
- }
- return 0;
- }
- /* ==================== 串口回调 ==================== */
- static rt_err_t uart_rx_ind(rt_device_t dev, rt_size_t size)
- {
- (void)dev;
- if (size == 0 || !g_at.uart) return RT_EOK;
- /* 读取数据 */
- char buf[128];
- rt_size_t read_len = rt_device_read(g_at.uart, 0, buf, sizeof(buf));
- if (read_len > 0) {
- /* 追加到缓冲区 */
- rx_buf_append(buf, read_len);
- /* 调试输出 */
- if (g_at.debug_enable) {
- rt_kprintf("<<< ");
- for (rt_size_t i = 0; i < read_len; i++) {
- rt_kprintf("%c", buf[i]);
- }
- }
- }
- return RT_EOK;
- }
- /* ==================== API实现 ==================== */
- int at_init(const char *uart_name)
- {
- if (g_at.initialized) {
- LOG_W("AT already initialized");
- return 0;
- }
- /* 清零上下文 */
- memset(&g_at, 0, sizeof(g_at));
- /* 打开串口 */
- g_at.uart = rt_device_find(uart_name);
- if (!g_at.uart) {
- LOG_E("UART %s not found", uart_name);
- return -1;
- }
- /* 配置串口 */
- struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
- config.baud_rate = BAUD_RATE_115200;
- config.data_bits = DATA_BITS_8;
- config.stop_bits = STOP_BITS_1;
- config.parity = PARITY_NONE;
- rt_device_control(g_at.uart, RT_DEVICE_CTRL_CONFIG, &config);
- rt_device_set_rx_indicate(g_at.uart, uart_rx_ind);
- rt_device_open(g_at.uart, RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX);
- /* 创建信号量 */
- g_at.cmd_sem = rt_sem_create("at_sem", 0, RT_IPC_FLAG_FIFO);
- g_at.initialized = 1;
- g_at.state = AT_STATE_IDLE;
- LOG_I("AT initialized on %s", uart_name);
- return 0;
- }
- void at_deinit(void)
- {
- if (!g_at.initialized) return;
- if (g_at.uart) {
- rt_device_close(g_at.uart);
- g_at.uart = NULL;
- }
- if (g_at.cmd_sem) {
- rt_sem_delete(g_at.cmd_sem);
- g_at.cmd_sem = NULL;
- }
- g_at.initialized = 0;
- LOG_I("AT deinitialized");
- }
- int at_exec_cmd(const at_cmd_item_t *cmd)
- {
- /* 安全检查 */
- if (!g_at.initialized) {
- LOG_E("AT not initialized");
- return -1;
- }
- if (!cmd) {
- LOG_E("cmd is NULL");
- return -1;
- }
- if (!cmd->cmd) {
- LOG_E("cmd->cmd is NULL");
- return -1;
- }
- /* 检查状态 */
- if (g_at.state != AT_STATE_IDLE) {
- LOG_W("AT busy, state=%d", g_at.state);
- return -1;
- }
- /* 设置当前命令 */
- g_at.current_cmd = cmd;
- g_at.retry_count = 0;
- g_at.result = AT_RESULT_IDLE;
- g_at.error_info[0] = '\0';
- /* 清空接收缓冲区 */
- rx_buf_clear();
- /* 发送命令 */
- rt_size_t cmd_len = strlen(cmd->cmd);
- rt_device_write(g_at.uart, 0, cmd->cmd, cmd_len);
- if (g_at.debug_enable) {
- rt_kprintf(">>> %s", cmd->cmd);
- }
- /* 转换状态 */
- g_at.state = AT_STATE_SENDING;
- g_at.start_tick = rt_tick_get();
- LOG_D("CMD started: %s", cmd->cmd);
- return 0;
- }
- int at_send_raw(const uint8_t *data, uint16_t len)
- {
- if (!g_at.initialized || !g_at.uart || !data || len == 0) {
- return 0;
- }
- return rt_device_write(g_at.uart, 0, data, len);
- }
- void at_process(void)
- {
- if (!g_at.initialized) return;
- /* 处理URC(高优先级) */
- while (process_urc()) {
- /* 持续处理所有URC */
- }
- /* 状态机 */
- switch (g_at.state) {
- case AT_STATE_IDLE:
- /* 空闲状态,检查是否有URC需要处理 */
- break;
- case AT_STATE_SENDING:
- /* 发送完成,进入等待 */
- g_at.state = AT_STATE_WAITING;
- g_at.start_tick = rt_tick_get();
- break;
- case AT_STATE_WAITING: {
- /* 检查是否收到完整响应 */
- if (check_response_complete()) {
- g_at.state = AT_STATE_DONE;
- if (g_at.cmd_sem) {
- rt_sem_release(g_at.cmd_sem);
- }
- break;
- }
- /* 检查超时 */
- uint32_t timeout = g_at.current_cmd ? g_at.current_cmd->timeout_ms : AT_CMD_TIMEOUT_MS;
- if (rt_tick_get() - g_at.start_tick > RT_TICK_PER_SECOND * timeout / 1000) {
- LOG_W("CMD timeout after %d ms", timeout);
- /* 检查重试 */
- if (g_at.current_cmd && g_at.retry_count < g_at.current_cmd->retries) {
- g_at.retry_count++;
- LOG_I("Retry %d/%d", g_at.retry_count, g_at.current_cmd->retries);
- /* 重新发送 */
- rx_buf_clear();
- rt_device_write(g_at.uart, 0, g_at.current_cmd->cmd,
- strlen(g_at.current_cmd->cmd));
- g_at.start_tick = rt_tick_get();
- } else {
- g_at.result = AT_RESULT_TIMEOUT;
- g_at.state = AT_STATE_DONE;
- if (g_at.cmd_sem) {
- rt_sem_release(g_at.cmd_sem);
- }
- }
- }
- break;
- }
- case AT_STATE_DONE:
- /* 完成状态,等待获取结果后自动回到IDLE */
- break;
- default:
- g_at.state = AT_STATE_IDLE;
- break;
- }
- }
- at_result_t at_get_result(void)
- {
- if (!g_at.initialized) return AT_RESULT_ERROR;
- /* 如果状态是DONE,获取结果后自动重置 */
- if (g_at.state == AT_STATE_DONE) {
- at_result_t result = g_at.result;
- g_at.state = AT_STATE_IDLE;
- g_at.current_cmd = NULL;
- return result;
- }
- return AT_RESULT_IDLE;
- }
- const char* at_get_response(void)
- {
- if (!g_at.initialized) return "";
- return g_at.rx_buf;
- }
- at_state_t at_get_state(void)
- {
- return g_at.state;
- }
- void at_abort_cmd(void)
- {
- if (!g_at.initialized) return;
- g_at.result = AT_RESULT_ABORT;
- g_at.state = AT_STATE_DONE;
- g_at.current_cmd = NULL;
- if (g_at.cmd_sem) {
- rt_sem_release(g_at.cmd_sem);
- }
- LOG_W("CMD aborted");
- }
- int at_register_urc(const char *prefix, at_urc_cb_t callback)
- {
- if (!prefix || !callback) return -1;
- /* 检查是否已注册 */
- for (int i = 0; i < AT_URC_MAX_NUM; i++) {
- if (g_at.urc_table[i].valid &&
- strcmp(g_at.urc_table[i].prefix, prefix) == 0) {
- /* 更新回调 */
- g_at.urc_table[i].callback = callback;
- return 0;
- }
- }
- /* 查找空槽 */
- for (int i = 0; i < AT_URC_MAX_NUM; i++) {
- if (!g_at.urc_table[i].valid) {
- safe_strcpy(g_at.urc_table[i].prefix, AT_URC_MAX_LEN, prefix);
- g_at.urc_table[i].callback = callback;
- g_at.urc_table[i].valid = 1;
- LOG_D("URC registered: %s", prefix);
- return 0;
- }
- }
- LOG_E("URC table full");
- return -1;
- }
- void at_unregister_urc(const char *prefix)
- {
- if (!prefix) return;
- for (int i = 0; i < AT_URC_MAX_NUM; i++) {
- if (g_at.urc_table[i].valid &&
- strcmp(g_at.urc_table[i].prefix, prefix) == 0) {
- g_at.urc_table[i].valid = 0;
- LOG_D("URC unregistered: %s", prefix);
- return;
- }
- }
- }
- void at_clear_response(void)
- {
- rx_buf_clear();
- }
- void at_set_debug(uint8_t enable)
- {
- g_at.debug_enable = enable;
- }
- const char* at_get_error_info(void)
- {
- return g_at.error_info[0] ? g_at.error_info : "Unknown error";
- }
|