MCU 通用AT指令处理框架_at指令框架
文章目录
-
- 设计原理与架构图
-
- 类图表示
- 序列图: AT命令发送流程
- 序列图: URC处理流程
- 头文件: `at_client.h`
- 源文件: `at_client.c`
- 使用示例
本文描述了一个基于RTOS的通用AT指令处理框架设计,适用于各类嵌入式MCU系统。该框架提供了完整的AT指令通信能力,包括命令发送、响应处理、URC事件处理和数据透传模式。
设计原理与架构图
类图表示
#mermaid-svg-LjoflxrR1UnHVOJh {font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-LjoflxrR1UnHVOJh .error-icon{fill:#552222;}#mermaid-svg-LjoflxrR1UnHVOJh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LjoflxrR1UnHVOJh .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-LjoflxrR1UnHVOJh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LjoflxrR1UnHVOJh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LjoflxrR1UnHVOJh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LjoflxrR1UnHVOJh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LjoflxrR1UnHVOJh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LjoflxrR1UnHVOJh .marker.cross{stroke:#333333;}#mermaid-svg-LjoflxrR1UnHVOJh svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LjoflxrR1UnHVOJh g.classGroup text{fill:#9370DB;fill:#131300;stroke:none;font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-LjoflxrR1UnHVOJh g.classGroup text .title{font-weight:bolder;}#mermaid-svg-LjoflxrR1UnHVOJh .nodeLabel,#mermaid-svg-LjoflxrR1UnHVOJh .edgeLabel{color:#131300;}#mermaid-svg-LjoflxrR1UnHVOJh .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-LjoflxrR1UnHVOJh .label text{fill:#131300;}#mermaid-svg-LjoflxrR1UnHVOJh .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-LjoflxrR1UnHVOJh .classTitle{font-weight:bolder;}#mermaid-svg-LjoflxrR1UnHVOJh .node rect,#mermaid-svg-LjoflxrR1UnHVOJh .node circle,#mermaid-svg-LjoflxrR1UnHVOJh .node ellipse,#mermaid-svg-LjoflxrR1UnHVOJh .node polygon,#mermaid-svg-LjoflxrR1UnHVOJh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-LjoflxrR1UnHVOJh .divider{stroke:#9370DB;stroke:1;}#mermaid-svg-LjoflxrR1UnHVOJh g.clickable{cursor:pointer;}#mermaid-svg-LjoflxrR1UnHVOJh g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-LjoflxrR1UnHVOJh g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-LjoflxrR1UnHVOJh .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-LjoflxrR1UnHVOJh .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-LjoflxrR1UnHVOJh .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-LjoflxrR1UnHVOJh .dashed-line{stroke-dasharray:3;}#mermaid-svg-LjoflxrR1UnHVOJh #compositionStart,#mermaid-svg-LjoflxrR1UnHVOJh .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-LjoflxrR1UnHVOJh #compositionEnd,#mermaid-svg-LjoflxrR1UnHVOJh .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-LjoflxrR1UnHVOJh #dependencyStart,#mermaid-svg-LjoflxrR1UnHVOJh .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-LjoflxrR1UnHVOJh #dependencyStart,#mermaid-svg-LjoflxrR1UnHVOJh .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-LjoflxrR1UnHVOJh #extensionStart,#mermaid-svg-LjoflxrR1UnHVOJh .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-LjoflxrR1UnHVOJh #extensionEnd,#mermaid-svg-LjoflxrR1UnHVOJh .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-LjoflxrR1UnHVOJh #aggregationStart,#mermaid-svg-LjoflxrR1UnHVOJh .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-LjoflxrR1UnHVOJh #aggregationEnd,#mermaid-svg-LjoflxrR1UnHVOJh .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-LjoflxrR1UnHVOJh .edgeTerminals{font-size:11px;}#mermaid-svg-LjoflxrR1UnHVOJh :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;} URC注册表 1 * 命令状态 1 1 at_client_t - int uart_port - uint32_t baudrate - uint32_t default_timeout - at_cmd_state_t cmd_state - bool in_data_mode - bool cmd_in_progress - data_receive_cb_t data_cb - void* data_context - urc_entry_t* urc_table - size_t urc_table_size - size_t urc_count - SemaphoreHandle_t mutex - SemaphoreHandle_t resp_sem - TaskHandle_t task_handle +at_status_t(*send_command) +void(*register_urc) +void(*enter_data_mode) +void(*exit_data_mode) +size_t(*send_data) urc_entry_t - const char* prefix - urc_handler_t handler - void* context at_cmd_state_t - const char* expect - uint32_t timeout - char* resp_buf - size_t buf_size - size_t resp_len
序列图: AT命令发送流程
#mermaid-svg-L96KwIfKlqnOKqlK {font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-L96KwIfKlqnOKqlK .error-icon{fill:#552222;}#mermaid-svg-L96KwIfKlqnOKqlK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-L96KwIfKlqnOKqlK .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-L96KwIfKlqnOKqlK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-L96KwIfKlqnOKqlK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-L96KwIfKlqnOKqlK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-L96KwIfKlqnOKqlK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-L96KwIfKlqnOKqlK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-L96KwIfKlqnOKqlK .marker.cross{stroke:#333333;}#mermaid-svg-L96KwIfKlqnOKqlK svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-L96KwIfKlqnOKqlK .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-L96KwIfKlqnOKqlK text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-L96KwIfKlqnOKqlK .actor-line{stroke:grey;}#mermaid-svg-L96KwIfKlqnOKqlK .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-L96KwIfKlqnOKqlK .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-L96KwIfKlqnOKqlK #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-L96KwIfKlqnOKqlK .sequenceNumber{fill:white;}#mermaid-svg-L96KwIfKlqnOKqlK #sequencenumber{fill:#333;}#mermaid-svg-L96KwIfKlqnOKqlK #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-L96KwIfKlqnOKqlK .messageText{fill:#333;stroke:#333;}#mermaid-svg-L96KwIfKlqnOKqlK .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-L96KwIfKlqnOKqlK .labelText,#mermaid-svg-L96KwIfKlqnOKqlK .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-L96KwIfKlqnOKqlK .loopText,#mermaid-svg-L96KwIfKlqnOKqlK .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-L96KwIfKlqnOKqlK .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-L96KwIfKlqnOKqlK .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-L96KwIfKlqnOKqlK .noteText,#mermaid-svg-L96KwIfKlqnOKqlK .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-L96KwIfKlqnOKqlK .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-L96KwIfKlqnOKqlK .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-L96KwIfKlqnOKqlK .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-L96KwIfKlqnOKqlK .actorPopupMenu{position:absolute;}#mermaid-svg-L96KwIfKlqnOKqlK .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-L96KwIfKlqnOKqlK .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-L96KwIfKlqnOKqlK .actor-man circle,#mermaid-svg-L96KwIfKlqnOKqlK line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-L96KwIfKlqnOKqlK :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;} 应用程序 AT客户端 UART驱动 RTOS内核 send_command(\"AT+CSQ\", \"+CSQ:\", 2000, buffer, 128) 获取互斥锁 锁成功 发送\"AT+CSQ\\r\\n\" 等待响应信号量(2000ms) 超时 释放互斥锁 AT_TIMEOUT 接收到\"+CSQ:24,99\" 匹配到期望响应 发送响应信号量 信号量到达 释放互斥锁 AT_OK alt [超时] [收到响应] 应用程序 AT客户端 UART驱动 RTOS内核
序列图: URC处理流程
#mermaid-svg-6nI6d29XlRGpvxag {font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-6nI6d29XlRGpvxag .error-icon{fill:#552222;}#mermaid-svg-6nI6d29XlRGpvxag .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6nI6d29XlRGpvxag .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-6nI6d29XlRGpvxag .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6nI6d29XlRGpvxag .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6nI6d29XlRGpvxag .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6nI6d29XlRGpvxag .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6nI6d29XlRGpvxag .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6nI6d29XlRGpvxag .marker.cross{stroke:#333333;}#mermaid-svg-6nI6d29XlRGpvxag svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6nI6d29XlRGpvxag .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-6nI6d29XlRGpvxag text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-6nI6d29XlRGpvxag .actor-line{stroke:grey;}#mermaid-svg-6nI6d29XlRGpvxag .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-6nI6d29XlRGpvxag .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-6nI6d29XlRGpvxag #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-6nI6d29XlRGpvxag .sequenceNumber{fill:white;}#mermaid-svg-6nI6d29XlRGpvxag #sequencenumber{fill:#333;}#mermaid-svg-6nI6d29XlRGpvxag #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-6nI6d29XlRGpvxag .messageText{fill:#333;stroke:#333;}#mermaid-svg-6nI6d29XlRGpvxag .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-6nI6d29XlRGpvxag .labelText,#mermaid-svg-6nI6d29XlRGpvxag .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-6nI6d29XlRGpvxag .loopText,#mermaid-svg-6nI6d29XlRGpvxag .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-6nI6d29XlRGpvxag .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-6nI6d29XlRGpvxag .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-6nI6d29XlRGpvxag .noteText,#mermaid-svg-6nI6d29XlRGpvxag .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-6nI6d29XlRGpvxag .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-6nI6d29XlRGpvxag .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-6nI6d29XlRGpvxag .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-6nI6d29XlRGpvxag .actorPopupMenu{position:absolute;}#mermaid-svg-6nI6d29XlRGpvxag .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-6nI6d29XlRGpvxag .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-6nI6d29XlRGpvxag .actor-man circle,#mermaid-svg-6nI6d29XlRGpvxag line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-6nI6d29XlRGpvxag :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;} UART驱动 AT客户端 应用程序 接收到\"+CMT: +8613800138000,Hello\" 检查URC表 调用注册的URC处理函数 处理短信通知v UART驱动 AT客户端 应用程序
头文件: at_client.h
#ifndef AT_CLIENT_H#define AT_CLIENT_H#include #include #include // RTOS头文件 (根据实际RTOS选择)#ifdef USE_FREERTOS#include \"FreeRTOS.h\"#include \"semphr.h\"#else// 其他RTOS适配#endif// AT指令执行状态typedef enum { AT_OK = 0, // 执行成功 AT_ERROR, // 执行失败 AT_TIMEOUT, // 超时 AT_BUSY, // 模块忙 AT_MEM_ERR, // 内存错误 AT_PARAM_ERR // 参数错误} at_status_t;// URC处理函数类型typedef void (*urc_handler_t)(void* context, const char* urc);// 数据接收回调类型typedef void (*data_receive_cb_t)(void* context, uint8_t* data, size_t len);// URC注册项typedef struct { const char* prefix; // URC前缀 urc_handler_t handler; // 处理函数 void* context; // 上下文指针} urc_entry_t;// AT命令状态typedef struct { const char* expect; // 期望响应 uint32_t timeout; // 超时时间 (RTOS ticks) char* resp_buf; // 响应缓冲区 size_t buf_size; // 缓冲区大小 size_t resp_len; // 已接收长度} at_cmd_state_t;// AT客户端对象typedef struct at_client { // 配置参数 int uart_port; // UART端口号 uint32_t baudrate; // 波特率 uint32_t default_timeout; // 默认超时(ms) // 内部状态 at_cmd_state_t cmd_state; // 命令状态 bool in_data_mode; // 数据模式标志 bool cmd_in_progress; // 命令执行中标志 // 回调函数 data_receive_cb_t data_cb; // 数据接收回调 void* data_context; // 数据回调上下文 // URC处理 urc_entry_t* urc_table; // URC注册表 size_t urc_table_size; // URC表大小 size_t urc_count; // 已注册URC数量 // RTOS资源 #ifdef USE_FREERTOS SemaphoreHandle_t mutex; // 互斥锁 SemaphoreHandle_t resp_sem; // 响应信号量 TaskHandle_t task_handle; // 任务句柄 #endif // 方法指针 at_status_t (*send_command)(struct at_client* self, const char* cmd, const char* expect, uint32_t timeout, char* resp_buf, size_t buf_size); void (*register_urc)(struct at_client* self, const char* prefix, urc_handler_t handler, void* context); void (*enter_data_mode)(struct at_client* self, data_receive_cb_t cb, void* context); void (*exit_data_mode)(struct at_client* self); size_t (*send_data)(struct at_client* self, const uint8_t* data, size_t len);} at_client_t;// 创建AT客户端实例at_client_t* at_client_create(int uart_port, uint32_t baudrate, uint32_t default_timeout);// 销毁AT客户端实例void at_client_destroy(at_client_t* client);// 启动AT服务任务bool at_client_start(at_client_t* client);// 停止AT服务任务void at_client_stop(at_client_t* client);#endif // AT_CLIENT_H
源文件: at_client.c
#include \"at_client.h\"#include #include // 模拟UART驱动接口void uart_write(int port, const uint8_t* data, size_t len);size_t uart_read(int port, uint8_t* data, size_t len, uint32_t timeout);// 内部函数声明static void at_service_task(void* arg);static void at_process_line(at_client_t* client, const char* line);static at_status_t at_cmd_send_impl(at_client_t* self, const char* cmd, const char* expect, uint32_t timeout, char* resp_buf, size_t buf_size); static void register_urc_impl(at_client_t* self, const char* prefix, urc_handler_t handler, void* context); static void enter_data_mode_impl(at_client_t* self, data_receive_cb_t cb, void* context); static void exit_data_mode_impl(at_client_t* self); static size_t send_data_impl(at_client_t* self, const uint8_t* data, size_t len);// 创建AT客户端实例at_client_t* at_client_create(int uart_port, uint32_t baudrate, uint32_t default_timeout) { at_client_t* client = malloc(sizeof(at_client_t)); if (!client) return NULL; memset(client, 0, sizeof(at_client_t)); // 初始化配置 client->uart_port = uart_port; client->baudrate = baudrate; client->default_timeout = default_timeout; // 初始化状态 client->cmd_in_progress = false; client->in_data_mode = false; // 初始化方法指针 client->send_command = at_cmd_send_impl; client->register_urc = register_urc_impl; client->enter_data_mode = enter_data_mode_impl; client->exit_data_mode = exit_data_mode_impl; client->send_data = send_data_impl; // 创建URC表 (固定大小) client->urc_table_size = 10; client->urc_table = malloc(client->urc_table_size * sizeof(urc_entry_t)); if (!client->urc_table) { free(client); return NULL; } memset(client->urc_table, 0, client->urc_table_size * sizeof(urc_entry_t)); client->urc_count = 0; // 创建RTOS资源 #ifdef USE_FREERTOS client->mutex = xSemaphoreCreateMutex(); client->resp_sem = xSemaphoreCreateBinary(); if (!client->mutex || !client->resp_sem) { free(client->urc_table); free(client); return NULL; } #endif return client;}// 销毁AT客户端实例void at_client_destroy(at_client_t* client) { if (!client) return; // 停止服务任务 at_client_stop(client); // 释放RTOS资源 #ifdef USE_FREERTOS if (client->mutex) vSemaphoreDelete(client->mutex); if (client->resp_sem) vSemaphoreDelete(client->resp_sem); #endif // 释放URC表 if (client->urc_table) free(client->urc_table); // 释放命令状态缓冲区 if (client->cmd_state.resp_buf) free(client->cmd_state.resp_buf); free(client);}// 启动AT服务任务bool at_client_start(at_client_t* client) { #ifdef USE_FREERTOS // 创建服务任务 BaseType_t result = xTaskCreate( at_service_task, // 任务函数 \"AT_Service\", // 任务名 configMINIMAL_STACK_SIZE * 4, // 堆栈大小 client, // 参数 tskIDLE_PRIORITY + 2, // 优先级 &client->task_handle // 任务句柄 ); return (result == pdPASS); #else // 其他RTOS实现 return true; #endif}// 停止AT服务任务void at_client_stop(at_client_t* client) { #ifdef USE_FREERTOS if (client->task_handle) { vTaskDelete(client->task_handle); client->task_handle = NULL; } #endif}// AT服务任务实现static void at_service_task(void* arg) { at_client_t* client = (at_client_t*)arg; uint8_t rx_buf[256]; size_t rx_index = 0; while (1) { uint8_t c; // 从串口读取一个字节 if (uart_read(client->uart_port, &c, 1, 10) != 1) { #ifdef USE_FREERTOS vTaskDelay(1); // 短暂延时避免忙等 #endif continue; } // 处理回车符(忽略) if (c == \'\\r\') { continue; } // 处理换行符(行结束) if (c == \'\\n\') { if (rx_index > 0) { rx_buf[rx_index] = \'\\0\'; // 确保字符串终止 if (client->in_data_mode) { // 数据模式处理 if (client->data_cb) { client->data_cb(client->data_context, rx_buf, rx_index); } } else { // 命令模式处理 at_process_line(client, (const char*)rx_buf); } rx_index = 0; } continue; } // 处理普通字符 if (rx_index < sizeof(rx_buf) - 1) { rx_buf[rx_index++] = c; } else { // 缓冲区溢出处理 rx_index = 0; // 重置缓冲区 } }}// 处理接收行static void at_process_line(at_client_t* client, const char* line) { // 1. 检查URC for (size_t i = 0; i < client->urc_count; i++) { urc_entry_t* entry = &client->urc_table[i]; if (strstr(line, entry->prefix) == line) { entry->handler(entry->context, line); return; } } // 2. 检查命令响应 if (client->cmd_in_progress) { // 检查期望响应 if (strstr(line, client->cmd_state.expect) != NULL) { // 成功响应 #ifdef USE_FREERTOS xSemaphoreGive(client->resp_sem); #endif } // 检查错误响应 else if (strstr(line, \"ERROR\") != NULL) { // 错误响应 #ifdef USE_FREERTOS xSemaphoreGive(client->resp_sem); #endif } // 保存响应数据 if (client->cmd_state.resp_buf && client->cmd_state.resp_len < client->cmd_state.buf_size) { int len = snprintf( client->cmd_state.resp_buf + client->cmd_state.resp_len, client->cmd_state.buf_size - client->cmd_state.resp_len, \"%s\\n\", line ); if (len > 0) { client->cmd_state.resp_len += len; } } }}// AT命令发送实现static at_status_t at_cmd_send_impl(at_client_t* self, const char* cmd, const char* expect, uint32_t timeout, char* resp_buf, size_t buf_size) { #ifdef USE_FREERTOS // 获取互斥锁 if (xSemaphoreTake(self->mutex, pdMS_TO_TICKS(100)) != pdTRUE) { return AT_BUSY; } #endif // 检查是否已有命令在执行 if (self->cmd_in_progress) { #ifdef USE_FREERTOS xSemaphoreGive(self->mutex); #endif return AT_BUSY; } // 设置命令状态 self->cmd_in_progress = true; self->cmd_state.expect = expect ? expect : \"OK\"; self->cmd_state.timeout = timeout ? timeout : self->default_timeout; self->cmd_state.resp_buf = resp_buf; self->cmd_state.buf_size = buf_size; self->cmd_state.resp_len = 0; // 发送命令 uart_write(self->uart_port, (const uint8_t*)cmd, strlen(cmd)); uart_write(self->uart_port, (const uint8_t*)\"\\r\\n\", 2); // 等待响应 at_status_t status = AT_TIMEOUT; #ifdef USE_FREERTOS if (xSemaphoreTake(self->resp_sem, pdMS_TO_TICKS(self->cmd_state.timeout)) == pdTRUE) { status = AT_OK; } #endif // 清理命令状态 self->cmd_in_progress = false; #ifdef USE_FREERTOS xSemaphoreGive(self->mutex); #endif return status;}// 注册URC实现static void register_urc_impl(at_client_t* self, const char* prefix, urc_handler_t handler, void* context) { if (!prefix || !handler) return; #ifdef USE_FREERTOS xSemaphoreTake(self->mutex, portMAX_DELAY); #endif // 检查是否已存在 for (size_t i = 0; i < self->urc_count; i++) { if (strcmp(self->urc_table[i].prefix, prefix) == 0) { // 更新现有条目 self->urc_table[i].handler = handler; self->urc_table[i].context = context; #ifdef USE_FREERTOS xSemaphoreGive(self->mutex); #endif return; } } // 添加新条目 if (self->urc_count < self->urc_table_size) { urc_entry_t* entry = &self->urc_table[self->urc_count++]; entry->prefix = prefix; entry->handler = handler; entry->context = context; } #ifdef USE_FREERTOS xSemaphoreGive(self->mutex); #endif}// 进入数据模式实现static void enter_data_mode_impl(at_client_t* self, data_receive_cb_t cb, void* context) { #ifdef USE_FREERTOS xSemaphoreTake(self->mutex, portMAX_DELAY); #endif self->in_data_mode = true; self->data_cb = cb; self->data_context = context; #ifdef USE_FREERTOS xSemaphoreGive(self->mutex); #endif}// 退出数据模式实现static void exit_data_mode_impl(at_client_t* self) { #ifdef USE_FREERTOS xSemaphoreTake(self->mutex, portMAX_DELAY); #endif self->in_data_mode = false; self->data_cb = NULL; self->data_context = NULL; #ifdef USE_FREERTOS xSemaphoreGive(self->mutex); #endif}// 发送数据实现static size_t send_data_impl(at_client_t* self, const uint8_t* data, size_t len) { #ifdef USE_FREERTOS xSemaphoreTake(self->mutex, portMAX_DELAY); #endif size_t sent = 0; if (self->in_data_mode) { sent = uart_write(self->uart_port, data, len); } #ifdef USE_FREERTOS xSemaphoreGive(self->mutex); #endif return sent;}
使用示例
#include \"at_client.h\"// URC处理函数void sms_urc_handler(void* context, const char* urc) { printf(\"Received SMS: %s\\n\", urc); // 实际项目中解析短信内容}// 数据接收回调void data_receive_callback(void* context, uint8_t* data, size_t len) { printf(\"Received %zu bytes: %.*s\\n\", len, (int)len, data);}int main() { // 创建AT客户端 at_client_t* at_client = at_client_create(1, 115200, 2000); if (!at_client) { printf(\"Failed to create AT client\\n\"); return -1; } // 注册URC at_client->register_urc(at_client, \"+CMT:\", sms_urc_handler, NULL); // 启动服务任务 if (!at_client_start(at_client)) { printf(\"Failed to start AT service\\n\"); at_client_destroy(at_client); return -1; } // 发送AT命令 char resp_buffer[128]; at_status_t status = at_client->send_command(at_client, \"AT+CSQ\", \"+CSQ:\", 2000, resp_buffer, sizeof(resp_buffer)); if (status == AT_OK) { printf(\"Signal quality: %s\\n\", resp_buffer); } else { printf(\"Command failed: %d\\n\", status); } // 进入数据模式 at_client->enter_data_mode(at_client, data_receive_callback, NULL); // 发送数据 const char* data = \"Hello, module!\"; at_client->send_data(at_client, (uint8_t*)data, strlen(data)); // 保持运行... while(1) { // 主循环 } // 清理资源 at_client_stop(at_client); at_client_destroy(at_client); return 0;