
以AT指令操作WIFI模块和NB-IoT或者4G模块为例。使用一个串口发送AT指令号到外部模块同时接收模块返回数据进行联网、TCP连接、发送数据、接收数据以上就是对这些物联网模块的使用方法。但是当本次使用WIFI模块而下次使用4G模块的时候我们会遇到一个AT指令不兼容的问题也就是WIFI的AT指令无法使用在4G模块上即使同样使用WIFI模块不同厂家的AT指令同样不能兼容。但是无论是什么样的模块操作方法和步骤都是一样的大概就是分为以下几种操作读取SIM状态WIFI不需要、读取信号强度、联网、连接服务器、透传模式、收发数据。将上述的操作定义为应用层那么发送AT指令则被下放到驱动层。从NBIOT模块切换到4G模块应用层基本不需要做任何改变也正常因此我们需要使用适配器模式对驱动层进行转接而应用层不需要任何改变。而在工程开发中尤其是在项目开发前期不稳定的时候常常面临更换物联网模块的需求针对不同的物联网模块开发一套程序效率比较低。对于任何项目中面临更换硬件的风险都可以采用适配器模式编程来解决这个问题。以下使用两个4G模块进行程序上的介绍简单说明适配器模式是什么样的使用方法。简单的对程序的框架进行分层如下图所示适配器编程是针对第三层也就是AT设备层进行的。程序设计时应采用自顶向下设计顶层的应用层程序类似于这些简单明了功能明确无多余的内容。app_get_csq(); app_tcp_send(This is a test);进入网络管理层之后程序将会复杂的多首先要明确网络管理层的目的是为了对网络进行监控和管理使用的这一部分功能是非常重要的因为它是对网络的直接描述和管理一旦网络断开、设备故障都需要这部分程序作出反应和处理。因此需要设计一个简易的网络管理结构体static struct{ at_device_t *current_dev; //当前的网络AT设备 rt_bool_t network_connect; //网络连接状态 rt_bool_t data_active; //数据传输激活 ip_info_t ip_info; //IP地址信息 }g_managers;从本管理层中需要明确指向下一层(AT设备层的具体设备。而AT设备层也就是我们适配器编程中的核心。针对AT设备层的结构体描述如下typedef struct at_device{ at_vendor_t vendor; //模块厂商 at_model_t model; //模块型号 hdinface hardinterface; //硬件接口 const char *name; //模块名称 rt_bool_t initialized; //初始化标志 rt_bool_t powered_on; //上电标志 rt_bool_t sim_ready; //SIM卡状态 rt_bool_t network_registered; //网络注册标志 uint32_t baud_rate; //波特率 uint32_t timeout; //超时期限 uint8_t retry_count; //重试次数 at_resp_status_t status; //响应状态 char *rx_buffer; //接收数据缓存指针 uint32_t rx_buffer_size; //接收缓冲区数据长度 uint16_t rx_data_len; //接收数据长度 uint32_t error_count; //错误计数 uint32_t tx_count; //发送次数 at_urc_handler_t urc_handler; //URC处理程序 void* urc_user_data; //URC用户数据 rt_mutex_t lock; //互斥锁 rt_sem_t rx_sem; //信号量 void* paiv_data; //私有数据 at_device_ops_t *ops; //操作指针 }at_device_t; struct at_device_ops_t{ rt_err_t (*init)(at_device_t *dev); //模块初始化程序 rt_err_t (*deinit)(at_device_t *dev); //模块去初始化程序 rt_err_t (*power_on)(at_device_t *dev); //模块上电程序 rt_err_t (*power_off)(at_device_t *dev); //模块掉电程序 rt_err_t (*reset)(at_device_t *dev); //模块复位程序 rt_err_t (*get_model)(at_device_t *dev,char* buffer, uint16_t size); //获取模块型号 rt_err_t (*get_version)(at_device_t* dev,char *buffer, uint16_t size); //获取模块版本号 rt_err_t (*get_imei)(at_device_t *dev,char* buffer); //获取模块IMEI号 rt_err_t (*get_iccid)(at_device_t *dev,char* buffer, uint16_t size); //获取卡 ICCID号 rt_err_t (*check_sim)(at_device_t* dev,rt_bool_t *sim_ready); //检查SIM卡状态 rt_err_t (*check_network)(at_device_t *dev, network_info_t *info); //检查联网状态 rt_err_t (*get_signal)(at_device_t *dev, signal_strength_t *signal); //获取信号强度 rt_err_t (*get_operator)(at_device_t* dev,char *name,rt_size_t size); rt_err_t (*open_socket)(at_device_t *dev, int *socket_id, const char *type, const char *host, int port); //开启SOCKET rt_err_t (*close_socket)(at_device_t *dev, int socket_id); //关闭SOCKET rt_err_t (*send_data)(at_device_t *dev, int socket_id, const void *data, rt_size_t size); //发送数据 rt_err_t (*receive_data)(at_device_t *dev, int socket_id, void *buffer, rt_size_t size, rt_size_t *received); //接收数据 rt_err_t (*vendor_specific)(at_device_t *dev, int cmd, void *arg); };接下来所有的程序就要围绕上述的两个结构体展开。针对一个具体的4G模块进行程序开发--EC200U为例#include at_device_manager.h #include at_common.h #include board.h #include com_config.h typedef struct{ at_vendor_t vendor; at_model_t model; const char *name; }EC200AdapterData; static EC200AdapterData ec200data; static at_device_t ec200dev; static void ec200u_urc_handler() { } static rt_err_t ec200_poweron(at_device_t *dev) { HAL_GPIO_WritePin(dev-hardinterface.power_port, dev-hardinterface.power_pin, GPIO_PIN_SET); return RT_EOK; } static rt_err_t ec200_poweroff(at_device_t *dev) { HAL_GPIO_WritePin(dev-hardinterface.power_port, dev-hardinterface.power_pin, GPIO_PIN_RESET); return RT_EOK; } static rt_err_t ec200_reset(at_device_t *dev) { HAL_GPIO_WritePin(dev-hardinterface.reset_port, dev-hardinterface.reset_pin, GPIO_PIN_SET); rt_thread_mdelay(100); HAL_GPIO_WritePin(dev-hardinterface.reset_port, dev-hardinterface.reset_pin, GPIO_PIN_RESET); rt_thread_mdelay(100); return RT_EOK; } static rt_err_t ec200_get_model(at_device_t *dev,char* buffer, uint16_t size) { return RT_EOK; } static rt_err_t ec200_get_imei(at_device_t *dev,char* buffer) { rt_err_t result RT_ERROR; at_response_t resp {0}; result at_cmd_send_common(dev,CMD_AT_CIMI,resp); if(result RT_EOK) { } return result; } static rt_err_t ec200_get_iccid(at_device_t *dev,char* buffer, uint16_t size) { rt_err_t result RT_ERROR; at_response_t resp {0}; result at_cmd_send_common(dev,CMD_AT_CCID,resp); if(result RT_EOK) { } return result; } static rt_err_t ec200_check_sim(at_device_t *dev) { rt_err_t result RT_ERROR; at_response_t resp {0}; result at_cmd_send_common(dev,CMD_AT_CPIN,resp); if(result RT_EOK) { } return result; } static rt_err_t ec200_check_network(at_device_t *dev,char* buffer, uint16_t size) { rt_err_t result RT_ERROR; at_response_t resp {0}; result at_cmd_send_common(dev,CMD_AT_CCID,resp); if(result RT_EOK) { } return result; } static rt_err_t ec200_get_signal(at_device_t *dev,signal_strength_t *signal) { rt_err_t result RT_ERROR; at_response_t resp {0}; int csq,ber; //csq : 信号强度 ber:误码率 result at_cmd_send_common(dev,CMD_AT_CSQ,resp); if(result RT_EOK) { if(sscanf(resp.raw_response,CSQ: %d,%d,csq,ber)) { if(csq 0) { signal-rssi -115; }else if(csq 1) { signal-rssi -111; }else if(csq2 csq 30) { signal-rssi -110 (csq-2) * 2; }else if(csq 31) { signal-rssi -51; }else { signal-rssi -113; } signal-ber ber; } } return result; } static rt_err_t ec200_at_test(at_device_t *dev) { rt_err_t result RT_ERROR; at_response_t resp {0}; result at_cmd_send_common(dev,CMD_AT,resp); if(result RT_EOK resp.status AT_RESP_OK) { return RT_EOK; } dev-status resp.status; return RT_ERROR; } static rt_err_t ec200_init(at_device_t *dev) { rt_err_t result ; ec200_poweron(dev); ec200_reset(dev); result ec200_at_test(dev); if(result ! RT_EOK) { //加入log分析 return RT_ERROR; } result ec200_check_sim(dev); } static at_device_ops_t ec200_ops { .init ec200_init, .power_on ec200_poweron, .power_off ec200_poweroff, //其余省略 }; static at_device_register_t reg { .vendor VENDOR_QUECTEL, .model MODEL_EC200U, .dev ec200dev, .name MODEL_NAME, .ops ec200_ops, .priv_data_size 0 }; static struct rt_semaphore semaphore ; static struct rt_mutex mutex; int at_adapter_quectel_ec200u_register(UART_HandleTypeDef* huart) { rt_sem_init(semaphore, ec200, 0, RT_IPC_FLAG_PRIO); rt_mutex_init(mutex, ec200, RT_IPC_FLAG_PRIO); ec200dev.hardinterface.power_pin POWERPIN; //电源管脚 ec200dev.hardinterface.power_port POWERPORT; ec200dev.hardinterface.reset_pin RESETPIN; //复位管脚 ec200dev.hardinterface.reset_port RESETPORT; ec200dev.hardinterface.uart_dev huart; //串口号 ec200dev.initialized 0; ec200dev.name reg.name; ec200dev.network_registered 0; ec200dev.urc_handler ec200u_urc_handler; ec200dev.paiv_data RT_NULL; ec200dev.vendor reg.vendor; ec200dev.model reg.model; ec200dev.powered_on 0; ec200dev.rx_sem semaphore; ec200dev.lock mutex; ec200dev.paiv_data ec200data; return at_device_register(reg); }如果是另一个4G模块程序写法完全一致#include at_device_manager.h #include at_common.h #include board.h #include com_config.h typedef struct{ at_vendor_t vendor; at_model_t model; const char* name; }ME909SAdapterData; static ME909SAdapterData me909sdata; static at_device_t me909sdev; static void me909su_urc_handler() { } static rt_err_t me909s_poweron(at_device_t *dev) { return RT_EOK; } static rt_err_t me909s_poweroff(at_device_t *dev) { HAL_GPIO_WritePin(dev-hardinterface.power_port, dev-hardinterface.power_pin, GPIO_PIN_RESET); return RT_EOK; } static rt_err_t me909s_reset(at_device_t *dev) { HAL_GPIO_WritePin(dev-hardinterface.reset_port, dev-hardinterface.reset_pin, GPIO_PIN_SET); rt_thread_mdelay(100); HAL_GPIO_WritePin(dev-hardinterface.reset_port, dev-hardinterface.reset_pin, GPIO_PIN_RESET); rt_thread_mdelay(100); return RT_EOK; } static rt_err_t me909s_get_model(at_device_t *dev,char* buffer, uint16_t size) { return RT_EOK; } static rt_err_t me909s_get_imei(at_device_t *dev,char* buffer) { rt_err_t result RT_ERROR; at_response_t resp {0}; result at_cmd_send_common(dev,CMD_AT_CIMI,resp); if(result RT_EOK) { } return result; } static rt_err_t me909s_get_iccid(at_device_t *dev,char* buffer, uint16_t size) { rt_err_t result RT_ERROR; at_response_t resp {0}; result at_cmd_send_common(dev,CMD_AT_CCID,resp); if(result RT_EOK) { } return result; } static rt_err_t me909s_check_sim(at_device_t *dev) { rt_err_t result RT_ERROR; at_response_t resp {0}; result at_cmd_send_common(dev,CMD_AT_CPIN,resp); if(result RT_EOK) { } return result; } static rt_err_t me909s_check_network(at_device_t *dev,char* buffer, uint16_t size) { rt_err_t result RT_ERROR; at_response_t resp {0}; result at_cmd_send_common(dev,CMD_AT_CCID,resp); if(result RT_EOK) { } return result; } static rt_err_t me909s_get_signal(at_device_t *dev,signal_strength_t *signal) { rt_err_t result RT_ERROR; at_response_t resp {0}; int csq,ber; //csq : 信号强度 ber:误码率 result at_cmd_send_common(dev,CMD_AT_CSQ,resp); if(result RT_EOK) { if(sscanf(resp.raw_response,CSQ: %d,%d,csq,ber)) { if(csq 0) { signal-rssi -115; }else if(csq 1) { signal-rssi -111; }else if(csq2 csq 30) { signal-rssi -110 (csq-2) * 2; }else if(csq 31) { signal-rssi -51; }else { signal-rssi -113; } signal-ber ber; } } return result; } static rt_err_t me909s_at_test(at_device_t *dev) { rt_err_t result RT_ERROR; at_response_t resp {0}; result at_cmd_send_common(dev,CMD_AT,resp); if(result RT_EOK resp.status AT_RESP_OK) { return RT_EOK; } dev-status resp.status; return RT_ERROR; } static rt_err_t me909s_init(at_device_t *dev) { rt_err_t result ; me909s_poweron(dev); me909s_reset(dev); result me909s_at_test(dev); if(result ! RT_EOK) { //加入log分析 return RT_ERROR; } result me909s_check_sim(dev); } static at_device_ops_t me909s_ops { .init me909s_init, .power_on me909s_poweron, .power_off me909s_poweroff, //其余省略 }; static at_device_register_t reg { .vendor VENDOR_HUAWEI, .model MODEL_ME909S, .dev me909sdev, .name MODEL_NAME, .ops me909s_ops, .priv_data_size 0 }; static struct rt_semaphore semaphore ; static struct rt_mutex mutex; int at_adapter_quectel_me909su_register(UART_HandleTypeDef* huart) { rt_sem_init(semaphore, me909s, 0, RT_IPC_FLAG_PRIO); rt_mutex_init(mutex, me909s, RT_IPC_FLAG_PRIO); me909sdev.hardinterface.power_pin POWERPIN; //电源管脚 me909sdev.hardinterface.power_port POWERPORT; me909sdev.hardinterface.reset_pin RESETPIN; //复位管脚 me909sdev.hardinterface.reset_port RESETPORT; me909sdev.hardinterface.uart_dev huart; //串口号 me909sdev.initialized 0; me909sdev.name reg.name; me909sdev.network_registered 0; me909sdev.urc_handler me909su_urc_handler; me909sdev.paiv_data RT_NULL; me909sdev.vendor reg.vendor; me909sdev.model reg.model; me909sdev.powered_on 0; me909sdev.rx_sem semaphore; me909sdev.lock mutex; me909sdev.paiv_data me909sdata; return at_device_register(reg); }每增加一个模块就需要单独增加一个模块按照上述程序的写法重点在于at_adapter_quectel_xxx_register函数的补充以及at_device_ops_t的补充。这两个结构体的是以具体的通信模组操作来实现的。为了将上述AT_device和顶层g_managers结合在一起再次引入一个新的注册结构体typedef struct{ at_vendor_t vendor; at_model_t model; const char *name; at_device_t *dev; at_device_ops_t *ops; rt_size_t priv_data_size; }at_device_register_t;通过以下的函数at_device_register将AT_device设备注册到manager里面去rt_err_t at_device_register(const at_device_register_t *reg) { g_managers.current_dev reg-dev; g_managers.current_dev-ops reg-ops; return RT_EOK; }至此上三层已经打通。在程序读取ICCID号的时候两个模块读取的方法是使用了同一个函数也就是 at_cmd_send_common(dev,CMD_AT_CCID,resp);此函数中并没有具体使用AT指令这是因为对AT指令需要做一个映射来实现具体指向这种方法可以在统一函数名称的同时实现解耦。typedef enum{ CMD_AT, // AT测试 CMD_AT_NOECO, // 关闭回显 CMD_ATI, // 查询厂商信息 CMD_AT_MM, // 模块型号 CMD_AT_SN, // 产品序列号 CMD_AT_CSQ, // 信号质量 CMD_AT_CREG, // 网络注册状态 CMD_AT_CGREG, // GPRS注册状态 CMD_AT_CEREG, // EPS注册状态 CMD_AT_COPS, // 运营商选择 CMD_AT_CIMI, // IMSI查询 CMD_AT_CCID, // ICCID查询 CMD_AT_GSN, // IMEI查询 CMD_AT_CPIN, // SIM卡状态 CMD_AT_CMGF, // 短信格式 CMD_AT_CMGS, // 发送短信 CMD_AT_CMGR, // 读取短信 CMD_AT_CMGD, // 删除短信 CMD_AT_CGDCONT, // 定义PDP上下文 CMD_AT_CGACT, // 激活PDP上下文 CMD_AT_CGPADDR, // 获取IP地址 CMD_AT_CIPSTART, // 建立TCP/UDP连接 CMD_AT_CIPSEND, // 发送数据 CMD_AT_CIPCLOSE, // 关闭连接 CMD_AT_CIPSHUT, // 关闭所有连接 CMD_AT_HTTPINIT, // HTTP初始化 CMD_AT_HTTPPARA, // HTTP参数设置 CMD_AT_HTTPACTION, // HTTP执行动作 CMD_AT_HTTPREAD, // 读取HTTP响应 CMD_AT_HTTPTERM, // HTTP终止 CMD_AT_CGNSINF, // GPS信息查询 CMD_AT_CGNSPWR, // GPS电源控制 CMD_AT_PSMS, // 省电模式 CMD_MAX } at_cmd_common_t; //命令集 typedef struct{ at_cmd_common_t command_cmd; //命令集 at_vendor_t vendor; //厂家 const char *cmd_string; //AT指令 const char *resp_pattern; //AT指令正常回复 rt_uint32_t default_timeout; //默认超时时间 rt_uint32_t default_retries; //默认恢复时间 }at_cmd_mapping_t; //命令映射结构体核心的结构体在于at_cmd_mapping_t ,数据存储方式和核心操作函数如下static const at_cmd_mapping_t g_cmd_mappings[] { // 基础命令 #if ( VENDOR_QUECTEL_ENABLE ) {CMD_AT, VENDOR_QUECTEL, AT\r\n, OK, 1000, 6}, {CMD_AT_NOECO, VENDOR_QUECTEL, ATE0\r\n, OK, 1000, 3}, {CMD_AT_MM, VENDOR_QUECTEL, ATCGMM\r\n, OK, 1000, 3}, {CMD_AT_SN, VENDOR_QUECTEL, ATCGSN\r\n, OK, 1000, 3}, {CMD_ATI, VENDOR_QUECTEL, ATI\r\n, Quectel, 1000, 1}, {CMD_AT_CSQ, VENDOR_QUECTEL, ATCSQ\r\n, CSQ:, 2000, 2}, //信号强度 {CMD_AT_CREG, VENDOR_QUECTEL, ATCREG?\r\n, CREG:, 2000, 2}, //网络注册状态 {CMD_AT_CIMI, VENDOR_QUECTEL, ATCIMI?\r\n, OK, 2000, 2}, //读取IMSI {CMD_AT_CPIN, VENDOR_QUECTEL, ATCPIN?\r\n, CPIN:, 2000, 2}, {CMD_AT_GSN, VENDOR_QUECTEL, ATCGSN\r\n, CGSN:, 2000, 1}, //IMEI号 {CMD_AT_GSN, VENDOR_QUECTEL, ATQCCID\r\n, OK:, 2000, 1}, //ICCID号 {CMD_AT_CMGF, VENDOR_QUECTEL, ATCMGF1\r\n, OK, 2000, 2}, {CMD_AT_CMGS, VENDOR_QUECTEL, ATCMGS\%s\, , 10000, 2}, {CMD_AT_CGDCONT, VENDOR_QUECTEL, ATCGDCONT1,\IP\,\%s\, OK, 3000, 2}, {CMD_AT_CIPSTART, VENDOR_QUECTEL, ATQIOPEN1,0,\TCP\,\%s\,%d,0,1, QIOPEN:, 30000, 2}, #endif #if ( VENDOR_HUAWEI_ENABLE ) {CMD_AT, VENDOR_HUAWEI, AT, OK, 1000, 3}, {CMD_AT_NOECO, VENDOR_HUAWEI, ATE0, OK, 1000, 3}, {CMD_AT_MM, VENDOR_HUAWEI, ATE0, OK, 1000, 3}, {CMD_AT_MM, VENDOR_HUAWEI, ATE0, OK, 1000, 3}, {CMD_ATI, VENDOR_HUAWEI, ATI, Huawei, 1000, 1}, {CMD_AT_CSQ, VENDOR_HUAWEI, ATCSQ, CSQ:, 2000, 2}, {CMD_AT_CREG, VENDOR_HUAWEI, ATCREG?, CREG:, 2000, 2}, {CMD_AT_CPIN, VENDOR_HUAWEI, ATCPIN?, CPIN:, 2000, 2}, {CMD_AT_GSN, VENDOR_HUAWEI, ATCGSN, CGSN:, 2000, 1}, {CMD_AT_CMGF, VENDOR_HUAWEI, ATCMGF1, OK, 2000, 2}, {CMD_AT_CMGS, VENDOR_HUAWEI, ATCMGS\%s\, , 10000, 2}, {CMD_AT_CGDCONT, VENDOR_HUAWEI, ATCGDCONT1,\IP\,\%s\, OK, 3000, 2}, {CMD_AT_CIPSTART, VENDOR_HUAWEI, AT^SISS1,\srvType\,\Socket\\r\nAT^SISS1,\conId\,\1\\r\nAT^SISS1,\address\,\socktcp://%s:%d\, OK, 30000, 2}, {CMD_AT_CIPSTART, VENDOR_ZTE, ATZIPCALL1,\TCP\,\%s\,%d, ZIPCALL:, 30000, 2}, #endif #if (VENDOR_ZTE_ENABLE ) {CMD_AT, VENDOR_ZTE, AT, OK, 1000, 3}, {CMD_AT_NOECO, VENDOR_ZTE, ATE0, OK, 1000, 3}, {CMD_AT_MM, VENDOR_ZTE, ATE0, OK, 1000, 3}, {CMD_AT_MM, VENDOR_ZTE, ATE0, OK, 1000, 3}, {CMD_ATI, VENDOR_ZTE, ATCGMM, ZTE, 1000, 1}, {CMD_AT_CSQ, VENDOR_ZTE, ATCSQ, CSQ:, 2000, 2}, {CMD_AT_CREG, VENDOR_ZTE, ATCREG?, CREG:, 2000, 2}, {CMD_AT_CPIN, VENDOR_ZTE, ATCPIN?, CPIN:, 2000, 2}, {CMD_AT_GSN, VENDOR_ZTE, ATCGSN, CGSN:, 2000, 1}, {CMD_AT_CMGF, VENDOR_ZTE, ATCMGF1, OK, 2000, 2}, {CMD_AT_CMGS, VENDOR_ZTE, ATCMGS\%s\, , 10000, 2}, {CMD_AT_CGDCONT, VENDOR_ZTE, ATCGDCONT1,\IP\,\%s\, OK, 3000, 2}, #endif }; #define CMD_MAPPING_COUNT (sizeof(g_cmd_mappings) / sizeof(at_cmd_mapping_t)) const char *at_cmd_map(at_vendor_t vendor, at_cmd_common_t common_cmd) { for (int i 0; i CMD_MAPPING_COUNT ;i) { if(g_cmd_mappings[i].command_cmd common_cmd g_cmd_mappings[i].vendor vendor) { return g_cmd_mappings[i].cmd_string; } } switch(common_cmd) { case CMD_AT: return AT; break; case CMD_ATI: return ATI; break; case CMD_AT_CSQ: return ATCSQ; break; default: return ; } } const at_cmd_mapping_t* at_cmd_get_mapping(at_vendor_t vendor, at_cmd_common_t common_cmd) { for (int i 0;i CMD_MAPPING_COUNT ;i) { if( g_cmd_mappings[i].command_cmd common_cmd g_cmd_mappings[i].vendor vendor) { return g_cmd_mappings[i]; } } return RT_NULL; } rt_err_t at_cmd_send_common(at_device_t *dev, at_cmd_common_t cmd, at_response_t *resp, ...) { if (dev RT_NULL) { return -RT_EINVAL; } const at_cmd_mapping_t *mapping at_cmd_get_mapping(dev-vendor, cmd); if (mapping RT_NULL) { return -RT_ERROR; } // 格式化命令如果有参数 char formatted_cmd[256]; va_list args; va_start(args, resp); if (strchr(mapping-cmd_string, %) ! RT_NULL) { rt_vsnprintf(formatted_cmd, sizeof(formatted_cmd), mapping-cmd_string, args); } else { strncpy(formatted_cmd, mapping-cmd_string, sizeof(formatted_cmd)); } va_end(args); // 构建命令配置 at_cmd_config_t config { .cmd formatted_cmd, .time_out mapping-default_timeout, .retry_count mapping-default_retries, .expected_resp mapping-resp_pattern, .is_urc RT_FALSE, .wait_for_resp RT_TRUE }; // 发送命令 return at_device_send_cmd_ex(dev, config, resp); }最后则是调用串口发送函数发送AT指令并处理接收数据rt_err_t at_device_send_cmd_ex(at_device_t *dev, const at_cmd_config_t *config, at_response_t *resp) { rt_err_t result RT_ERROR; rt_tick_t start_tick; if(dev RT_NULL || config-cmd RT_NULL) { return -RT_EINVAL; } rt_mutex_take(dev-lock, RT_WAITING_FOREVER); do{ dev-rx_data_len 0; HAL_UART_Transmit(dev-hardinterface.uart_dev, config-cmd, strlen(config-cmd), 0xff); dev-tx_count ; resp-status AT_RESP_NO_ANSWER; if(resp ! RT_NULL) { start_tick rt_tick_get(); while(rt_tick_get() - start_tick rt_tick_from_millisecond(config-time_out)) { if(RT_EOK rt_sem_take(dev-rx_sem, 50)) { if(dev-rx_data_len 0) { dev-rx_buffer[dev-rx_data_len] \0; break; } } } if(strstr(dev-rx_buffer,resp-raw_response) ! RT_NULL) { resp-status AT_RESP_OK; result RT_EOK; } else if(strstr(dev-rx_buffer,ERROR)) { resp-status AT_RESP_ERROR; }else if(strstr(dev-rx_buffer,NO CARRIER)) { resp-status AT_RESP_NOCARRIER; }else if(strstr(dev-rx_buffer,busy)) { resp-status AT_RESP_BUSY; } }else { break; } HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); }while((resp-status ! AT_RESP_OK) (dev-tx_count config-retry_count)); if(resp ! RT_NULL resp-status AT_RESP_OK) { resp-raw_response dev-rx_buffer; resp-response_len dev-rx_data_len; resp-timestamp rt_tick_get(); } rt_mutex_release(dev-lock); return result; }