at_cmd.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. /**
  2. * @file at_cmd.c
  3. * @brief AT命令驱动核心 - 重构版(安全架构)
  4. * @note 采用查询模式而非回调,彻底避免函数指针导致的IBUSERR
  5. * 简化状态机,增加边界检查,提高可靠性
  6. */
  7. #define DBG_TAG "at.cmd"
  8. #define DBG_LVL DBG_LOG
  9. #include <rtdbg.h>
  10. #include "at_cmd.h"
  11. #include <string.h>
  12. #include <stdio.h>
  13. #include <rtdevice.h>
  14. /* ==================== 配置 ==================== */
  15. #ifndef AT_RECV_BUFFER_SIZE
  16. #define AT_RECV_BUFFER_SIZE 1024
  17. #endif
  18. #ifndef AT_CMD_TIMEOUT_MS
  19. #define AT_CMD_TIMEOUT_MS 5000
  20. #endif
  21. /* ==================== 内部状态 ==================== */
  22. typedef struct {
  23. /* 串口 */
  24. rt_device_t uart;
  25. /* 状态机 */
  26. volatile at_state_t state;
  27. at_result_t result;
  28. /* 当前命令 */
  29. const at_cmd_item_t *current_cmd;
  30. uint8_t retry_count;
  31. rt_tick_t start_tick;
  32. /* 接收缓冲 */
  33. char rx_buf[AT_RECV_BUFFER_SIZE];
  34. uint16_t rx_len;
  35. uint8_t rx_overflow; /* 溢出标志 */
  36. /* 错误信息 */
  37. char error_info[64];
  38. /* URC表 */
  39. struct {
  40. char prefix[AT_URC_MAX_LEN];
  41. at_urc_cb_t callback;
  42. uint8_t valid;
  43. } urc_table[AT_URC_MAX_NUM];
  44. /* 调试 */
  45. uint8_t debug_enable;
  46. /* 同步信号量(用于可选的同步API) */
  47. rt_sem_t cmd_sem;
  48. /* 初始化标志 */
  49. uint8_t initialized;
  50. } at_context_t;
  51. static at_context_t g_at = {0};
  52. /* ==================== 工具函数 ==================== */
  53. /**
  54. * @brief 安全字符串拷贝
  55. */
  56. static void safe_strcpy(char *dst, size_t dst_size, const char *src)
  57. {
  58. if (!dst || !src || dst_size == 0) return;
  59. size_t src_len = strlen(src);
  60. size_t copy_len = (src_len < dst_size - 1) ? src_len : dst_size - 1;
  61. memcpy(dst, src, copy_len);
  62. dst[copy_len] = '\0';
  63. }
  64. /**
  65. * @brief 清空接收缓冲区
  66. */
  67. static void rx_buf_clear(void)
  68. {
  69. g_at.rx_len = 0;
  70. g_at.rx_buf[0] = '\0';
  71. g_at.rx_overflow = 0;
  72. }
  73. /**
  74. * @brief 追加数据到接收缓冲区(带边界检查)
  75. */
  76. static void rx_buf_append(const char *data, uint16_t len)
  77. {
  78. if (!data || len == 0) return;
  79. /* 检查溢出 */
  80. if (g_at.rx_len + len >= AT_RECV_BUFFER_SIZE - 1) {
  81. /* 缓冲区满,丢弃旧数据(保留一半) */
  82. uint16_t keep_len = AT_RECV_BUFFER_SIZE / 2;
  83. memmove(g_at.rx_buf, g_at.rx_buf + g_at.rx_len - keep_len, keep_len);
  84. g_at.rx_len = keep_len;
  85. g_at.rx_overflow = 1;
  86. LOG_W("RX buffer overflow, discarding old data");
  87. }
  88. /* 追加数据 */
  89. uint16_t copy_len = len;
  90. if (g_at.rx_len + copy_len > AT_RECV_BUFFER_SIZE - 1) {
  91. copy_len = AT_RECV_BUFFER_SIZE - 1 - g_at.rx_len;
  92. }
  93. memcpy(g_at.rx_buf + g_at.rx_len, data, copy_len);
  94. g_at.rx_len += copy_len;
  95. g_at.rx_buf[g_at.rx_len] = '\0';
  96. }
  97. /**
  98. * @brief 从缓冲区移除已处理的数据
  99. */
  100. static void rx_buf_consume(uint16_t len)
  101. {
  102. if (len >= g_at.rx_len) {
  103. rx_buf_clear();
  104. } else {
  105. memmove(g_at.rx_buf, g_at.rx_buf + len, g_at.rx_len - len);
  106. g_at.rx_len -= len;
  107. g_at.rx_buf[g_at.rx_len] = '\0';
  108. }
  109. }
  110. /**
  111. * @brief 查找字符串,返回位置(类似strstr但限制长度)
  112. */
  113. static char* strnstr(const char *haystack, const char *needle, uint16_t haystack_len)
  114. {
  115. if (!haystack || !needle) return NULL;
  116. uint16_t needle_len = strlen(needle);
  117. if (needle_len == 0) return (char*)haystack;
  118. if (haystack_len < needle_len) return NULL;
  119. for (uint16_t i = 0; i <= haystack_len - needle_len; i++) {
  120. if (memcmp(haystack + i, needle, needle_len) == 0) {
  121. return (char*)(haystack + i);
  122. }
  123. }
  124. return NULL;
  125. }
  126. /**
  127. * @brief 检查是否包含完整响应行(以\n结尾)
  128. */
  129. static int has_complete_line(const char *buf, uint16_t len)
  130. {
  131. if (!buf || len == 0) return 0;
  132. for (uint16_t i = 0; i < len; i++) {
  133. if (buf[i] == '\n') return 1;
  134. }
  135. return 0;
  136. }
  137. /**
  138. * @brief 提取一行响应
  139. */
  140. static uint16_t extract_line(char *dst, uint16_t dst_size, const char *src, uint16_t src_len)
  141. {
  142. if (!dst || !src || dst_size == 0) return 0;
  143. for (uint16_t i = 0; i < src_len && i < dst_size - 1; i++) {
  144. if (src[i] == '\r' || src[i] == '\n') {
  145. dst[i] = '\0';
  146. /* 跳过\r\n */
  147. uint16_t skip = i;
  148. if (src[i] == '\r' && i + 1 < src_len && src[i+1] == '\n') {
  149. skip = i + 2;
  150. } else {
  151. skip = i + 1;
  152. }
  153. return skip;
  154. }
  155. dst[i] = src[i];
  156. }
  157. dst[0] = '\0';
  158. return 0;
  159. }
  160. /* ==================== URC处理 ==================== */
  161. /**
  162. * @brief 检查并处理URC
  163. * @return 1表示处理了URC,0表示无URC
  164. */
  165. static int process_urc(void)
  166. {
  167. if (g_at.rx_len == 0) return 0;
  168. /* 提取一行检查 */
  169. char line[128];
  170. uint16_t line_len = 0;
  171. for (uint16_t i = 0; i < g_at.rx_len && i < sizeof(line) - 1; i++) {
  172. if (g_at.rx_buf[i] == '\r' || g_at.rx_buf[i] == '\n') {
  173. line_len = i;
  174. break;
  175. }
  176. line[i] = g_at.rx_buf[i];
  177. }
  178. if (line_len == 0) return 0;
  179. line[line_len] = '\0';
  180. /* 匹配URC前缀 */
  181. for (int i = 0; i < AT_URC_MAX_NUM; i++) {
  182. if (!g_at.urc_table[i].valid) continue;
  183. const char *prefix = g_at.urc_table[i].prefix;
  184. if (strncmp(line, prefix, strlen(prefix)) == 0) {
  185. /* 匹配成功,调用回调 */
  186. if (g_at.urc_table[i].callback) {
  187. g_at.urc_table[i].callback(line, line_len);
  188. }
  189. /* 消费这行数据 */
  190. uint16_t consume = line_len;
  191. while (consume < g_at.rx_len &&
  192. (g_at.rx_buf[consume] == '\r' || g_at.rx_buf[consume] == '\n')) {
  193. consume++;
  194. }
  195. rx_buf_consume(consume);
  196. return 1;
  197. }
  198. }
  199. return 0;
  200. }
  201. /* ==================== 响应处理 ==================== */
  202. /**
  203. * @brief 检查响应是否完成
  204. * @return 1表示完成,0表示未完成
  205. */
  206. static int check_response_complete(void)
  207. {
  208. if (!g_at.current_cmd) return 1;
  209. const char *rsp = g_at.rx_buf;
  210. uint16_t rsp_len = g_at.rx_len;
  211. const at_cmd_item_t *cmd = g_at.current_cmd;
  212. /* 检查错误响应 */
  213. if (strnstr(rsp, "ERROR", rsp_len)) {
  214. g_at.result = AT_RESULT_ERROR;
  215. return 1;
  216. }
  217. /* 检查CME错误 */
  218. char *cme = strnstr(rsp, "+CME ERROR:", rsp_len);
  219. if (cme) {
  220. g_at.result = AT_RESULT_CME_ERROR;
  221. /* 提取错误信息 */
  222. safe_strcpy(g_at.error_info, sizeof(g_at.error_info), cme);
  223. return 1;
  224. }
  225. /* 检查CMS错误 */
  226. char *cms = strnstr(rsp, "+CMS ERROR:", rsp_len);
  227. if (cms) {
  228. g_at.result = AT_RESULT_CMS_ERROR;
  229. safe_strcpy(g_at.error_info, sizeof(g_at.error_info), cms);
  230. return 1;
  231. }
  232. /* 检查期望的成功响应 */
  233. if (cmd->expect_ok) {
  234. if (strnstr(rsp, cmd->expect_ok, rsp_len)) {
  235. /* 还需要OK确认(如果有) */
  236. if (strnstr(rsp, "OK", rsp_len)) {
  237. g_at.result = AT_RESULT_OK;
  238. return 1;
  239. }
  240. }
  241. } else {
  242. /* 没有指定期望响应,只要收到OK就算成功 */
  243. if (strnstr(rsp, "OK", rsp_len)) {
  244. g_at.result = AT_RESULT_OK;
  245. return 1;
  246. }
  247. }
  248. return 0;
  249. }
  250. /* ==================== 串口回调 ==================== */
  251. static rt_err_t uart_rx_ind(rt_device_t dev, rt_size_t size)
  252. {
  253. (void)dev;
  254. if (size == 0 || !g_at.uart) return RT_EOK;
  255. /* 读取数据 */
  256. char buf[128];
  257. rt_size_t read_len = rt_device_read(g_at.uart, 0, buf, sizeof(buf));
  258. if (read_len > 0) {
  259. /* 追加到缓冲区 */
  260. rx_buf_append(buf, read_len);
  261. /* 调试输出 */
  262. if (g_at.debug_enable) {
  263. rt_kprintf("<<< ");
  264. for (rt_size_t i = 0; i < read_len; i++) {
  265. rt_kprintf("%c", buf[i]);
  266. }
  267. }
  268. }
  269. return RT_EOK;
  270. }
  271. /* ==================== API实现 ==================== */
  272. int at_init(const char *uart_name)
  273. {
  274. if (g_at.initialized) {
  275. LOG_W("AT already initialized");
  276. return 0;
  277. }
  278. /* 清零上下文 */
  279. memset(&g_at, 0, sizeof(g_at));
  280. /* 打开串口 */
  281. g_at.uart = rt_device_find(uart_name);
  282. if (!g_at.uart) {
  283. LOG_E("UART %s not found", uart_name);
  284. return -1;
  285. }
  286. /* 配置串口 */
  287. struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
  288. config.baud_rate = BAUD_RATE_115200;
  289. config.data_bits = DATA_BITS_8;
  290. config.stop_bits = STOP_BITS_1;
  291. config.parity = PARITY_NONE;
  292. rt_device_control(g_at.uart, RT_DEVICE_CTRL_CONFIG, &config);
  293. rt_device_set_rx_indicate(g_at.uart, uart_rx_ind);
  294. rt_device_open(g_at.uart, RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX);
  295. /* 创建信号量 */
  296. g_at.cmd_sem = rt_sem_create("at_sem", 0, RT_IPC_FLAG_FIFO);
  297. g_at.initialized = 1;
  298. g_at.state = AT_STATE_IDLE;
  299. LOG_I("AT initialized on %s", uart_name);
  300. return 0;
  301. }
  302. void at_deinit(void)
  303. {
  304. if (!g_at.initialized) return;
  305. if (g_at.uart) {
  306. rt_device_close(g_at.uart);
  307. g_at.uart = NULL;
  308. }
  309. if (g_at.cmd_sem) {
  310. rt_sem_delete(g_at.cmd_sem);
  311. g_at.cmd_sem = NULL;
  312. }
  313. g_at.initialized = 0;
  314. LOG_I("AT deinitialized");
  315. }
  316. int at_exec_cmd(const at_cmd_item_t *cmd)
  317. {
  318. /* 安全检查 */
  319. if (!g_at.initialized) {
  320. LOG_E("AT not initialized");
  321. return -1;
  322. }
  323. if (!cmd) {
  324. LOG_E("cmd is NULL");
  325. return -1;
  326. }
  327. if (!cmd->cmd) {
  328. LOG_E("cmd->cmd is NULL");
  329. return -1;
  330. }
  331. /* 检查状态 */
  332. if (g_at.state != AT_STATE_IDLE) {
  333. LOG_W("AT busy, state=%d", g_at.state);
  334. return -1;
  335. }
  336. /* 设置当前命令 */
  337. g_at.current_cmd = cmd;
  338. g_at.retry_count = 0;
  339. g_at.result = AT_RESULT_IDLE;
  340. g_at.error_info[0] = '\0';
  341. /* 清空接收缓冲区 */
  342. rx_buf_clear();
  343. /* 发送命令 */
  344. rt_size_t cmd_len = strlen(cmd->cmd);
  345. rt_device_write(g_at.uart, 0, cmd->cmd, cmd_len);
  346. if (g_at.debug_enable) {
  347. rt_kprintf(">>> %s", cmd->cmd);
  348. }
  349. /* 转换状态 */
  350. g_at.state = AT_STATE_SENDING;
  351. g_at.start_tick = rt_tick_get();
  352. LOG_D("CMD started: %s", cmd->cmd);
  353. return 0;
  354. }
  355. int at_send_raw(const uint8_t *data, uint16_t len)
  356. {
  357. if (!g_at.initialized || !g_at.uart || !data || len == 0) {
  358. return 0;
  359. }
  360. return rt_device_write(g_at.uart, 0, data, len);
  361. }
  362. void at_process(void)
  363. {
  364. if (!g_at.initialized) return;
  365. /* 处理URC(高优先级) */
  366. while (process_urc()) {
  367. /* 持续处理所有URC */
  368. }
  369. /* 状态机 */
  370. switch (g_at.state) {
  371. case AT_STATE_IDLE:
  372. /* 空闲状态,检查是否有URC需要处理 */
  373. break;
  374. case AT_STATE_SENDING:
  375. /* 发送完成,进入等待 */
  376. g_at.state = AT_STATE_WAITING;
  377. g_at.start_tick = rt_tick_get();
  378. break;
  379. case AT_STATE_WAITING: {
  380. /* 检查是否收到完整响应 */
  381. if (check_response_complete()) {
  382. g_at.state = AT_STATE_DONE;
  383. if (g_at.cmd_sem) {
  384. rt_sem_release(g_at.cmd_sem);
  385. }
  386. break;
  387. }
  388. /* 检查超时 */
  389. uint32_t timeout = g_at.current_cmd ? g_at.current_cmd->timeout_ms : AT_CMD_TIMEOUT_MS;
  390. if (rt_tick_get() - g_at.start_tick > RT_TICK_PER_SECOND * timeout / 1000) {
  391. LOG_W("CMD timeout after %d ms", timeout);
  392. /* 检查重试 */
  393. if (g_at.current_cmd && g_at.retry_count < g_at.current_cmd->retries) {
  394. g_at.retry_count++;
  395. LOG_I("Retry %d/%d", g_at.retry_count, g_at.current_cmd->retries);
  396. /* 重新发送 */
  397. rx_buf_clear();
  398. rt_device_write(g_at.uart, 0, g_at.current_cmd->cmd,
  399. strlen(g_at.current_cmd->cmd));
  400. g_at.start_tick = rt_tick_get();
  401. } else {
  402. g_at.result = AT_RESULT_TIMEOUT;
  403. g_at.state = AT_STATE_DONE;
  404. if (g_at.cmd_sem) {
  405. rt_sem_release(g_at.cmd_sem);
  406. }
  407. }
  408. }
  409. break;
  410. }
  411. case AT_STATE_DONE:
  412. /* 完成状态,等待获取结果后自动回到IDLE */
  413. break;
  414. default:
  415. g_at.state = AT_STATE_IDLE;
  416. break;
  417. }
  418. }
  419. at_result_t at_get_result(void)
  420. {
  421. if (!g_at.initialized) return AT_RESULT_ERROR;
  422. /* 如果状态是DONE,获取结果后自动重置 */
  423. if (g_at.state == AT_STATE_DONE) {
  424. at_result_t result = g_at.result;
  425. g_at.state = AT_STATE_IDLE;
  426. g_at.current_cmd = NULL;
  427. return result;
  428. }
  429. return AT_RESULT_IDLE;
  430. }
  431. const char* at_get_response(void)
  432. {
  433. if (!g_at.initialized) return "";
  434. return g_at.rx_buf;
  435. }
  436. at_state_t at_get_state(void)
  437. {
  438. return g_at.state;
  439. }
  440. void at_abort_cmd(void)
  441. {
  442. if (!g_at.initialized) return;
  443. g_at.result = AT_RESULT_ABORT;
  444. g_at.state = AT_STATE_DONE;
  445. g_at.current_cmd = NULL;
  446. if (g_at.cmd_sem) {
  447. rt_sem_release(g_at.cmd_sem);
  448. }
  449. LOG_W("CMD aborted");
  450. }
  451. int at_register_urc(const char *prefix, at_urc_cb_t callback)
  452. {
  453. if (!prefix || !callback) return -1;
  454. /* 检查是否已注册 */
  455. for (int i = 0; i < AT_URC_MAX_NUM; i++) {
  456. if (g_at.urc_table[i].valid &&
  457. strcmp(g_at.urc_table[i].prefix, prefix) == 0) {
  458. /* 更新回调 */
  459. g_at.urc_table[i].callback = callback;
  460. return 0;
  461. }
  462. }
  463. /* 查找空槽 */
  464. for (int i = 0; i < AT_URC_MAX_NUM; i++) {
  465. if (!g_at.urc_table[i].valid) {
  466. safe_strcpy(g_at.urc_table[i].prefix, AT_URC_MAX_LEN, prefix);
  467. g_at.urc_table[i].callback = callback;
  468. g_at.urc_table[i].valid = 1;
  469. LOG_D("URC registered: %s", prefix);
  470. return 0;
  471. }
  472. }
  473. LOG_E("URC table full");
  474. return -1;
  475. }
  476. void at_unregister_urc(const char *prefix)
  477. {
  478. if (!prefix) return;
  479. for (int i = 0; i < AT_URC_MAX_NUM; i++) {
  480. if (g_at.urc_table[i].valid &&
  481. strcmp(g_at.urc_table[i].prefix, prefix) == 0) {
  482. g_at.urc_table[i].valid = 0;
  483. LOG_D("URC unregistered: %s", prefix);
  484. return;
  485. }
  486. }
  487. }
  488. void at_clear_response(void)
  489. {
  490. rx_buf_clear();
  491. }
  492. void at_set_debug(uint8_t enable)
  493. {
  494. g_at.debug_enable = enable;
  495. }
  496. const char* at_get_error_info(void)
  497. {
  498. return g_at.error_info[0] ? g_at.error_info : "Unknown error";
  499. }