├── README.md ├── docs └── Tencent_AT_instruction_set_V3.1.3.pdf ├── include ├── at_client.h ├── at_log.h ├── at_sanity_check.h ├── at_utils.h ├── config.h ├── dev_config.h ├── hal_export.h ├── module_api_inf.h ├── qcloud_iot_api_export.h ├── qcloud_iot_export_data_template.h ├── qcloud_iot_export_error.h ├── qcloud_iot_export_method.h ├── qcloud_iot_export_mqtt.h └── ringbuff.h ├── port ├── hal_at.c └── hal_os.c ├── sample ├── light_data_template_sample.c └── mqtt_sample.c ├── src ├── data_template │ ├── data_template_aciton.c │ ├── data_template_client.c │ ├── data_template_client_common.c │ ├── data_template_client_json.c │ ├── data_template_client_manager.c │ └── data_template_event.c ├── include │ ├── data_template_action.h │ ├── data_template_client.h │ ├── data_template_client_common.h │ ├── data_template_client_json.h │ ├── data_template_event.h │ ├── json_parser.h │ ├── lite-list.h │ ├── lite-utils.h │ ├── utils_list.h │ └── utils_timer.h ├── module_at │ ├── at_client.c │ ├── at_log.c │ ├── at_timer.c │ ├── at_utils.c │ ├── iot_device.c │ ├── module_api_inf.c │ └── ringbuff.c ├── mqtt │ └── mqtt.c └── utils │ ├── json_parser.c │ ├── json_token.c │ ├── string_utils.c │ ├── utils_list.c │ └── utils_timer.c ├── tools ├── codegen.py └── example_config.json └── usr_logic ├── action_config.c ├── data_config.c ├── data_template_usr_logic.c └── events_config.c /README.md: -------------------------------------------------------------------------------- 1 | ## qcloud-iot-sdk-tecent-at-based 2 | 3 | ### 介绍 4 | 5 | qcloud-iot-sdk-tecent-at-based 面向使用支持腾讯MQTT AT指令的模组(2/3/4/5G、NB、WIFI等)接入腾讯物联网平台的终端设备开发者,典型应用场景为MCU+腾讯定制AT模组,MCU侧集成AT_SDK,AT_SDK完成实现了MCU和模组数据交互的AT框架,并基于AT框架配合腾讯AT指令,实现了MQTT、影子及数据模板的功能,同时提供了示例sample。开发者需要实现的HAL层适配接口见hal_export.h,需要实现串口的收发接口(中断接收),延时函数,模组上下电及os相关接口适配(互斥锁、动态内存申请释放、线程创建),适配层接口单独剥离在port目录。 6 | 7 | ### qcloud-iot-sdk-tecent-at-based 软件架构 8 | 9 | 10 | 11 | ### 目录结构 12 | 13 | | 名称 | 说明 | 14 | | ---- | ---- | 15 | | docs | 文档目录,包含腾讯AT指令集定义 | 16 | | port | HAL层移植目录,需要实现串口的收发接口(中断接收),延时函数,模组上下电及os相关接口| 17 | | sample | 应用示例,示例使用MQTT、影子、数据模板的使用方式| 18 | | src | AT框架及协议逻辑实现 | 19 | |   ├───── event | 事件功能协议封装 | 20 | |   ├───── module_at |at client抽象,实现RX解析,命令下行,urc匹配,resp异步匹配| 21 | |   ├───── data_template |基于AT框架的数据模板协议| 22 | |   ├───── mqtt |基于AT框架的mqtt协议实现| 23 | |   ├───── utils |json、timer、链表等应用| 24 | |   ├───── include |SDK对外头文件及设备信息配置头文件| 25 | | tools | 代码生成脚本 | 26 | | README.md | SDK使用说明 | 27 | 28 | ### 定制腾讯MQTT AT指令模组说明 29 | 腾讯定义的MQTT AT指令见文档目录,模组侧把MQTT协议封装在模组固件中,各家模组商遵循统一的MQTT通信的AT指令名称、参数及命令返回,并实现了通过设置的设备参数及鉴权方式实现和平台的鉴权。已经支持的[模组列表](https://github.com/tencentyun/qcloud-iot-explorer-sdk-embedded-c/blob/master/docs/MCU%2B%E8%85%BE%E8%AE%AF%E4%BA%91%E5%AE%9A%E5%88%B6AT%E6%A8%A1%E7%BB%84.md)。 30 | 31 | ##### 1.1 使用MQTT AT定制模组实现MQTT通信 32 | AT_SDK中module_api_inf.c把docs目录下的《腾讯云IoT AT指令集-V3.1.3.pdf》各AT指令独立实现为单独的函数,在mqtt_sample.c中示例了如何组合这些命令序列,包括初始化、模组上下电、联网/注册网络、设备信息写入、MQTT连接、主题订阅、消息发布、订阅消息回调处理。如果不源移植AT_SDK,可以基于如下AT指令交互流程使用MQTT功能: 33 | 34 | ![](https://main.qcloudimg.com/raw/81942fc551f6df8696490ffd5985cce9.jpg) 35 | 36 | ##### 1.2 数据模板功能 37 | 数据模板功能是基于MQTT的基础上,通过订阅特定的topic,payload部分基于为json格式实现数据协议交互,AT_SDK已是实现数据协议的封装和示例模板,可以参考示例data_template_sample.c及light_data_template_sample.c。 38 | 39 | [数据模板协议说明](https://cloud.tencent.com/document/product/1081/34916) 40 | 41 | ### 移植指导 42 | 根据所选的嵌入式平台,适配 hal_export.h 头文件对应的hal层API的移植实现。主要有串口收发(中断接收)、模组开关机、任务/线程创建、动态内存申请/释放、时延、打印等API。可参考基于STM32+FreeRTOS的AT-SDK[移植示例](https://github.com/tencentyun/tc-iot-at-sdk-stm32-freertos-based-example.git) 43 | 44 | ##### 2.1 **hal_export.h**: 45 | hal层对外的API接口及HAL层宏开关控制。 46 | 47 | | 序号 | 宏定义 | 说明 | 48 | | ----| ---------------------------- | -----------------------------------| 49 | | 1 | PARSE_THREAD_STACK_SIZE | 串口at解析线程栈大小 | 50 | | 2 | OS_USED | 是否使用OS,目前的AT-SDK是基于多线程框架的,所以OS是必须的 | 51 | | 3 | AUTH_MODE_KEY | 认证方式,证书认证还是秘钥认证 | 52 | | 4 | DEBUG_DEV_INFO_USED | 默认使能该宏,设备信息使用调试信息,正式量产关闭该宏,并实现设备信息存取接口 | 53 | 54 | ##### 2.2 **hal_os.c**: 55 | 该源文件主要实现打印、延时、时间戳、锁、线程创建、设备信息存取等。 56 | 57 | | 序号 | HAL_API | 说明 | 58 | | ---- | -----------------------------------| ---------------------------------- | 59 | | 1 | HAL_Printf | 打印函数,log输出需要,可选实现 | 60 | | 2 | HAL_Snprintf | 格式化打印,json数据处理需要,必须实现 | 61 | | 3 | HAL_Vsnprintf | 格式化输出, 可选实现 | 62 | | 4 | HAL_DelayMs | 毫秒延时,必选实现 | 63 | | 5 | HAL_DelayUs | 微妙延时,可选实现 | 64 | | 6 | HAL_GetTimeMs | 获取毫秒数,必选实现 | 65 | | 7 | HAL_GetTimeSeconds | 获取时间戳,必须实现,时戳不需绝对准确,但不可重复 | 66 | | 8 | hal_thread_create | 线程创建,必选实现 | 67 | | 9 | hal_thread_destroy | 线程销毁,必选实现 | 68 | | 10 | HAL_SleepMs | 放权延时,必选实现 | 69 | | 11 | HAL_MutexCreate | 互斥锁创建,必选实现 | 70 | | 12 | HAL_MutexDestroy | 互斥锁销毁,必选实现 | 71 | | 13 | HAL_MutexLock | 获取互斥锁,必选实现 | 72 | | 14 | HAL_MutexUnlock | 释放互斥锁,必选实现 | 73 | | 15 | HAL_Malloc | 动态内存申请,必选实现 | 74 | | 16 | HAL_Free | 动态内存释放,必选实现 | 75 | | 17 | HAL_GetDevInfo | 获取设备信息,必选实现 | 76 | | 18 | HAL_SetDevInfo | 设置设备信息,必须存放在非易失性存储介质,必选实现 | 77 | 78 | ##### 2.3 **hal_at.c**: 79 | 该源文件主要实现AT串口初始化、串口收发、模组开关机。 80 | 81 | | 序号 | HAL_API | 说明 | 82 | | ---- | -------------------------------| ---------------------------------- | 83 | | 1 | module_power_on | 模组开机,AT串口初始化,必选实现 | 84 | | 1 | module_power_off | 模组关机,低功耗需要,可选实现 | 85 | | 2 | AT_UART_IRQHandler | 串口接收中断ISR,将收取到的数据放入ringbuff中,AT解析线程会实时解析数据,必选实现| 86 | | 3 | at_send_data | AT串口发送接口 | 87 | 88 | ##### 2.4 **module_api_inf.c**: 89 | 配网/注网 API业务适配,该源文件基于腾讯定义的AT指令实现了MQTT的交互,但有一个关于联网/注网的API(module_register_network)需要根据模组适配。代码基于[ESP8266腾讯定制AT固件](https://main.qcloudimg.com/raw/6811fc7631dcf0ce5509ccbdba5c72b7.zip)示例了WIFI直连的方式连接网络,但更常用的场景是根据特定事件(譬如按键)触发配网(softAP/一键配网),这块的逻辑各具体业务逻辑自行实现。ESP8266有封装配网指令和示例APP。对于蜂窝模组,则是使用特定的网络注册指令。开发者参照module_handshake应用AT-SDK的AT框架添加和模组的AT指令交互。 90 | 91 | ``` 92 | //模组联网(NB/2/3/4G注册网络)、wifi配网(一键配网/softAP)暂时很难统一,需要用户根据具体模组适配。 93 | //开发者参照 module_handshake API使用AT框架的API和模组交互,实现适配。 94 | eAtResault module_register_network(eModuleType eType) 95 | { 96 | eAtResault result = AT_ERR_SUCCESS; 97 | 98 | #if (MODULE_TYPE == eMODULE_ESP8266) 99 | #define WIFI_SSID "youga_wifi" 100 | #define WIFI_PW "Iot@2018" 101 | 102 | 103 | /*此处示例传递热点名字直接联网,通常的做法是特定产品根据特定的事件(譬如按键)触发wifi配网(一键配网/softAP)*/ 104 | result = wifi_connect(WIFI_SSID, WIFI_PW); 105 | //result |= wifi_set_test_server_ip("111.230.126.244"); 106 | if(AT_ERR_SUCCESS != result) 107 | { 108 | Log_e("wifi connect fail,ret:%d", result); 109 | } 110 | 111 | #else 112 | /*模组网络注册、或者wifi配网需要用户根据所选模组实现*/ 113 | #endif 114 | 115 | return result; 116 | } 117 | ``` 118 | 119 | ##### 2.5 设备信息修改 120 | 调试时,在hal_export.h将设备信息调试宏定义打开。量产时需要关闭该宏定义,实现hal-os中序列17-26的设备信息存取API 121 | ``` 122 | #define DEBUG_DEV_INFO_USED 123 | ``` 124 | 修改下面宏定义的设备信息,则系统将会使用调试信息。 125 | ``` 126 | #ifdef DEBUG_DEV_INFO_USED 127 | 128 | static char sg_product_id[MAX_SIZE_OF_PRODUCT_ID + 1] = "PRODUCT_ID"; 129 | static char sg_device_name[MAX_SIZE_OF_DEVICE_NAME + 1] = "YOUR_DEVICE_NAME"; 130 | 131 | #ifdef AUTH_MODE_CERT 132 | static char sg_device_cert_file_name[MAX_SIZE_OF_DEVICE_CERT_FILE_NAME + 1] = "YOUR_DEVICE_NAME_cert.crt"; 133 | static char sg_device_privatekey_file_name[MAX_SIZE_OF_DEVICE_KEY_FILE_NAME + 1] = "YOUR_DEVICE_NAME_private.key"; 134 | #else 135 | char sg_device_secret[MAX_SIZE_OF_DEVICE_SERC + 1] = "YOUR_IOT_PSK"; 136 | #endif 137 | 138 | #endif 139 | ``` 140 | 141 | ##### 2.6业务逻辑开发 142 | 自动生成的代码data_template_usr_logic.c,已实现数据、事件收发及响应的通用处理逻辑。但是具体的数据处理的业务逻辑需要用户自己根据业务逻辑添加,上下行业务逻辑添加的入口函数分别为deal_up_stream_user_logic 、deal_down_stream_user_logic,可以参考基于场景的示例light_data_template_sample.c添加业务处理逻辑。 143 | 144 | **下行业务逻辑实现:** 145 | ``` 146 | /*用户需要实现的下行数据的业务逻辑,pData除字符串变量已实现用户定义的所有其他变量值解析赋值,待用户实现业务逻辑*/ 147 | static void deal_down_stream_user_logic(ProductDataDefine * pData) 148 | { 149 | Log_d("someting about your own product logic wait to be done"); 150 | } 151 | ``` 152 | 153 | **上行业务逻辑实现:** 154 | ``` 155 | /*用户需要实现的上行数据的业务逻辑,此处仅供示例*/ 156 | static int deal_up_stream_user_logic(DeviceProperty *pReportDataList[], int *pCount) 157 | { 158 | int i, j; 159 | 160 | for (i = 0, j = 0; i < TOTAL_PROPERTY_COUNT; i++) { 161 | if(eCHANGED == sg_DataTemplate[i].state) { 162 | pReportDataList[j++] = &(sg_DataTemplate[i].data_property); 163 | sg_DataTemplate[i].state = eNOCHANGE; 164 | } 165 | } 166 | *pCount = j; 167 | 168 | return (*pCount > 0)?AT_ERR_SUCCESS:AT_ERR_FAILURE; 169 | } 170 | ``` 171 | 172 | ##### 2.7 示例说明 173 | Smaple目录一共有3个示例,分别是mqtt_sample.c、data_template_sample.c、light_data_template_sample.c。 174 | 各示例说明如下: 175 | 176 | | 序号 | 示例名称 | 说明 | 177 | | ---- | -------------------------------| ---------------------------------- | 178 | | 1 | mqtt_sample.c | MQTT示例,该示例示例基于定制的AT指令如何便捷的接入腾讯物联网平台及收发数据| 179 | | 2 | data_template_sample.c | 通用数据模板及事件功能示例,示例如何基于腾讯物联网平台的数据模板功能快速开发产品| 180 | | 3 | light_data_template_sample.c | 基于智能灯的控制场景,示例具体的产品如何应用数据模板及事件功能 | 181 | 182 | ### SDK接口说明 183 | 关于 SDK 的更多使用方式及接口了解, 参见 qcloud_iot_api_export.h 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /docs/Tencent_AT_instruction_set_V3.1.3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/qcloud-iot-sdk-tencent-at-based/deef817aedb69f0465a57b16640e829e7f23057b/docs/Tencent_AT_instruction_set_V3.1.3.pdf -------------------------------------------------------------------------------- /include/at_client.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file : at_client.h 4 | * @brief : at client header file 5 | ****************************************************************************** 6 | * 7 | * Copyright (c) 2019 Tencent. 8 | * All rights reserved. 9 | ****************************************************************************** 10 | */ 11 | 12 | #ifndef __AT_CLIENT_H__ 13 | #define __AT_CLIENT_H__ 14 | 15 | #include "ringbuff.h" 16 | #include "module_api_inf.h" 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | #define AT_FRAME_VERSION "1.0.0" 23 | 24 | #define AT_CMD_NAME_LEN 16 25 | #define AT_END_MARK_LEN 4 26 | 27 | 28 | //#define CLINET_BUFF_LEN (4*RING_BUFF_LEN)MAX_TOPIC_PAYLOAD_LEN 29 | #define CLINET_BUFF_LEN (MAX_TOPIC_PAYLOAD_LEN) 30 | #define GET_CHAR_TIMEOUT_MS (5000) 31 | #define CMD_TIMEOUT_MS (10000) 32 | #define CMD_RESPONSE_INTERVAL_MS (100) 33 | 34 | 35 | typedef void (*ParserFunc)(void *userContex); 36 | 37 | typedef enum 38 | { 39 | AT_STATUS_UNINITIALIZED = 0, 40 | AT_STATUS_INITIALIZED, 41 | AT_STATUS_BUSY, 42 | }at_status; 43 | 44 | 45 | enum at_resp_status 46 | { 47 | AT_RESP_OK = 0, /* AT response end is OK */ 48 | AT_RESP_ERROR = -1, /* AT response end is ERROR */ 49 | AT_RESP_TIMEOUT = -2, /* AT response is timeout */ 50 | AT_RESP_BUFF_FULL= -3, /* AT response buffer is full */ 51 | }; 52 | typedef enum at_resp_status at_resp_status_t; 53 | 54 | typedef struct _at_response_ 55 | { 56 | /* response buffer */ 57 | char *buf; 58 | /* the maximum response buffer size */ 59 | int buf_size; 60 | /* the number of setting response lines 61 | * == 0: the response data will auto return when received 'OK' or 'ERROR' 62 | * != 0: the response data will return when received setting lines number data */ 63 | int line_num; 64 | /* the count of received response lines */ 65 | int line_counts; 66 | /* the maximum response time */ 67 | uint32_t timeout; 68 | }at_response; 69 | 70 | 71 | typedef at_response * at_response_t; 72 | 73 | /* URC(Unsolicited Result Code) object, such as: 'RING', 'READY' request by AT server */ 74 | typedef struct _at_urc_ 75 | { 76 | const char *cmd_prefix; 77 | const char *cmd_suffix; 78 | void (*func)(const char *data, uint32_t size); 79 | }at_urc; 80 | 81 | typedef at_urc *at_urc_t; 82 | 83 | typedef struct _at_client_ 84 | { 85 | at_status status; 86 | char end_sign; 87 | 88 | ring_buff_t pRingBuff; 89 | 90 | char *recv_buffer; 91 | uint32_t recv_bufsz; 92 | uint32_t cur_recv_len; 93 | void *lock; //pre cmd take the lock wait for resp , another cmd need wait for unlock 94 | 95 | at_response_t resp; 96 | at_resp_status_t resp_status; 97 | bool resp_notice; 98 | 99 | const at_urc *urc_table; 100 | uint16_t urc_table_size; 101 | 102 | ParserFunc parser; //RX parser 103 | }at_client; 104 | 105 | typedef at_client *at_client_t; 106 | 107 | 108 | /* AT client initialize and start*/ 109 | eAtResault at_client_init(at_client_t pClient); 110 | 111 | /* get AT client handle*/ 112 | at_client_t at_client_get(void); 113 | 114 | /*AT connect detect*/ 115 | eAtResault at_client_wait_connect(uint32_t timeout); 116 | 117 | /* ========================== multiple AT client function ============================ */ 118 | /* set AT client a line end sign */ 119 | void at_set_end_sign(char ch); 120 | 121 | /* Set URC(Unsolicited Result Code) table */ 122 | void at_set_urc_table(at_client_t client, const at_urc_t table, uint32_t size); 123 | 124 | /* AT client send commands to AT server and waiter response */ 125 | int at_client_send(at_client_t client, char *buf, int size); 126 | 127 | eAtResault at_obj_exec_cmd(at_response_t resp, const char *cmd_expr, ...); 128 | #define at_exec_cmd(resp, ...) at_obj_exec_cmd(resp, __VA_ARGS__) 129 | 130 | /* AT response object create and delete */ 131 | at_response_t at_create_resp(uint32_t buf_size, uint32_t line_num, uint32_t timeout); 132 | void at_delete_resp(at_response_t resp); 133 | 134 | 135 | /* AT response line buffer get and parse response buffer arguments */ 136 | const char *at_resp_get_line(at_response_t resp, uint32_t resp_line); 137 | const char *at_resp_get_line_by_kw(at_response_t resp, const char *keyword); 138 | int at_resp_parse_line_args(at_response_t resp, uint32_t resp_line, const char *resp_expr, ...); 139 | int at_resp_parse_line_args_by_kw(at_response_t resp, const char *keyword, const char *resp_expr, ...); 140 | 141 | /* ========================== single AT client function ============================ */ 142 | #ifdef __cplusplus 143 | } 144 | #endif 145 | 146 | #endif /* __AT_H__ */ 147 | 148 | -------------------------------------------------------------------------------- /include/at_log.h: -------------------------------------------------------------------------------- 1 | #ifndef _AT_LOG_H_ 2 | #define _AT_LOG_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | /** 15 | * 日志输出等级 16 | */ 17 | typedef enum { 18 | LOG_DEBUG, 19 | LOG_INFO, 20 | LOG_WARN, 21 | LOG_ERROR 22 | } LOG_LEVEL; 23 | 24 | /** 25 | * 全局日志级别输出标志, 只输出小于或等于该等级的日志信息 26 | */ 27 | extern LOG_LEVEL g_log_level; 28 | 29 | 30 | /** 31 | * @brief 32 | * 33 | * @param 34 | */ 35 | void At_Log_Set_Level(LOG_LEVEL level); 36 | 37 | /** 38 | * @brief 获取当前日志等级 39 | * 40 | * @return 41 | */ 42 | LOG_LEVEL At_Log_Get_Level(void); 43 | 44 | 45 | /** 46 | * @brief 日志打印函数,默认打印到标准输出 47 | * 48 | * @param file 源文件名 49 | * @param func 函数名 50 | * @param line 行号 51 | * @param level 日志等级 52 | */ 53 | void Log_writter(const char *file, const char *func, const int line, const int level, const char *fmt, ...); 54 | 55 | /** 56 | * @brief buff数据dump 57 | * 58 | * @param pData 待dump的buff指针 59 | * @param len 待dump的buff数据长度 60 | */ 61 | void HexDump(const uint8_t *pData, unsigned int len); 62 | 63 | #define Log_d(args...) Log_writter(__FILE__, __FUNCTION__, __LINE__, LOG_DEBUG, args) 64 | #define Log_i(args...) Log_writter(__FILE__, __FUNCTION__, __LINE__, LOG_INFO, args) 65 | #define Log_w(args...) Log_writter(__FILE__, __FUNCTION__, __LINE__, LOG_WARN, args) 66 | #define Log_e(args...) Log_writter(__FILE__, __FUNCTION__, __LINE__, LOG_ERROR, args) 67 | 68 | //#define DEBUG_EABLE 69 | #ifdef DEBUG_EABLE 70 | #define IOT_FUNC_ENTRY \ 71 | {\ 72 | printf("FUNC_ENTRY: %s L#%d \n", __FUNCTION__, __LINE__); \ 73 | } 74 | #define IOT_FUNC_EXIT \ 75 | {\ 76 | printf("FUNC_EXIT: %s L#%d \n", __FUNCTION__, __LINE__); \ 77 | return;\ 78 | } 79 | #define IOT_FUNC_EXIT_RC(x) \ 80 | {\ 81 | printf("FUNC_EXIT: %s L#%d Return Code : %ld \n", __FUNCTION__, __LINE__, (long)(x)); \ 82 | return x; \ 83 | } 84 | #else 85 | #define IOT_FUNC_ENTRY 86 | #define IOT_FUNC_EXIT \ 87 | {\ 88 | return;\ 89 | } 90 | #define IOT_FUNC_EXIT_RC(x) \ 91 | {\ 92 | return x; \ 93 | } 94 | #endif 95 | 96 | #ifdef __cplusplus 97 | } 98 | #endif 99 | 100 | #endif /* QCLOUD_IOT_EXPORT_LOG_H_ */ 101 | -------------------------------------------------------------------------------- /include/at_sanity_check.h: -------------------------------------------------------------------------------- 1 | #ifndef _AT_SANITY_CHECK_H_ 2 | #define _AT_SANITY_CHECK_H_ 3 | 4 | #if defined(__cplusplus) 5 | extern "C" { 6 | #endif 7 | 8 | #include "at_log.h" 9 | 10 | 11 | #define NUMBERIC_SANITY_CHECK(num, err) \ 12 | do { \ 13 | if (0 == (num)) { \ 14 | Log_e("Invalid argument, numeric 0"); \ 15 | return (err); \ 16 | } \ 17 | } while(0) 18 | 19 | #define NUMBERIC_SANITY_CHECK_RTN(num) \ 20 | do { \ 21 | if (0 == (num)) { \ 22 | Log_e("Invalid argument, numeric 0"); \ 23 | return; \ 24 | } \ 25 | } while(0) 26 | 27 | #define POINTER_SANITY_CHECK(ptr, err) \ 28 | do { \ 29 | if (NULL == (ptr)) { \ 30 | Log_e("Invalid argument, %s = %p", #ptr, ptr); \ 31 | return (err); \ 32 | } \ 33 | } while(0) 34 | 35 | #define POINTER_SANITY_CHECK_RTN(ptr) \ 36 | do { \ 37 | if (NULL == (ptr)) { \ 38 | Log_e("Invalid argument, %s = %p", #ptr, ptr); \ 39 | return; \ 40 | } \ 41 | } while(0) 42 | 43 | #define STRING_PTR_SANITY_CHECK(ptr, err) \ 44 | do { \ 45 | if (NULL == (ptr)) { \ 46 | Log_e("Invalid argument, %s = %p", #ptr, (ptr)); \ 47 | return (err); \ 48 | } \ 49 | if (0 == strlen((ptr))) { \ 50 | Log_e("Invalid argument, %s = '%s'", #ptr, (ptr)); \ 51 | return (err); \ 52 | } \ 53 | } while(0) 54 | 55 | #define STRING_PTR_SANITY_CHECK_RTN(ptr) \ 56 | do { \ 57 | if (NULL == (ptr)) { \ 58 | Log_e("Invalid argument, %s = %p", #ptr, (ptr)); \ 59 | return; \ 60 | } \ 61 | if (0 == strlen((ptr))) { \ 62 | Log_e("Invalid argument, %s = '%s'", #ptr, (ptr)); \ 63 | return; \ 64 | } \ 65 | } while(0) 66 | 67 | #if defined(__cplusplus) 68 | } 69 | #endif 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /include/at_utils.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file : at_utils.h 4 | * @brief : head file of api for at utils 5 | ****************************************************************************** 6 | * 7 | * History: