Quellcode durchsuchen

【修改】更新 V2.0.0 版本,添加 AT Socket 多客户端支持功能

Signed-off-by: chenyong <1521761801@qq.com>
chenyong vor 6 Jahren
Ursprung
Commit
84303edb8a

+ 115 - 31
README.md

@@ -2,19 +2,22 @@
 
 ## 1. 简介 ##
 
-AT device 软件包是由 RT-Thread AT 组件针对不同 AT 设备的移植文件和示例代码组成,目前支持的 AT 设备有:ESP8266、M26、MC20、EC20、RW007、SIM800C 以及 SIM76XX 系列设备等,目前上述设备都完成对 `AT socket` 功能的移植,及设备通过 AT 命令实现标准 socket 编程接口,完成 socket 通讯的功能,具体功能介绍可参考 [《RT-Thread 编程指南》](https://github.com/RT-Thread/rtthread-manual-doc)AT 命令章节 。 
+AT device 软件包是由 RT-Thread AT 组件针对不同 AT 设备的移植文件和示例代码组成,目前支持的 AT 设备有:ESP8266、M26、MC20、RW007、SIM800C 以及 SIM76XX 系列设备等,目前上述设备都完成对 `AT socket` 功能的移植,及设备通过 AT 命令实现标准 socket 编程接口,完成 socket 通讯的功能,具体功能介绍可参考 [《RT-Thread 编程指南》](https://github.com/RT-Thread/rtthread-manual-doc)AT 命令章节 。 
 
-### 1.1. 文件结构 ###
+### 1.1. 目录结构 ###
 
 | 名称 | 说明 |
 | ---- | ---- |
-| at_socket_esp8266.c  |  ESP8266 模块针对 AT 组件的移植文件,实现 AT socket |
-| at_socket_rw007.c  |  RW007 模块针对 AT 组件的移植文件,实现 AT socket |
-| at_socket_sim800c.c  |  SIM800C 模块针对 AT 组件的移植文件,实现 AT socket |
-| at_socket_sim76xx.c  |  SIM76XX 模块针对 AT 组件的移植文件,实现 AT socket |
-| at_socket_m26.c | M26/MC20 模块针对 AT 组件的移植文件,实现 AT socket |
-| at_socket_ec20.c | EC20 模块针对 AT 组件的移植文件,实现 AT socket |
-| at_client_sample.c | ESP8266 模块 AT Client 功能示例文件 |
+| src | AT device 实现源码目录 |
+| inc | AT device 头文件目录 |
+| sample | 不同设备示例文件目录 |
+| class | 不同设备针对 AT 组件的移植适配目录 |
+| class/esp8266 | ESP8266 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
+| class/rw007 | RW007 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
+| class/sim800c | SIM800C 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
+| class/sim76xx | SIM76XX 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
+| class/m26 | M26/MC20 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
+| class/ec20 | EC20 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
 
 ### 1.2 许可证 ###
 
@@ -29,42 +32,123 @@ at_device package 遵循 LGPLv2.1 许可,详见 `LICENSE` 文件。
 
 ## 2. 获取方式 ##
 
-AT device 软件包是对 AT 组件和 AT socket 功能的移植,需开启 AT 组件库和 AT socket 功能来获取 AT device 软件包。
+AT device 软件包是对 AT 组件和 AT socket 功能的移植,需开启 AT 组件库和 AT socket 功能来获取 AT device 软件包。
 
-先要开启 AT 组件库和 AT socket 功能, 具体路径如下所示:
+**版本号说明**
 
-    RT-Thread Components  --->
-        Network stack  --->
-             Socket abstraction layer  --->
-                protocol stack implement  --->
-                  [ ] Support lwIP stack
-                  [*] Support AT Commands stack
+AT device 软件包目前已经发布多个版本,各个版本之间选项配置方式和其对应的系统版本有所不同,下面主要列出当前可使用的软件包版本信息:
 
-开启 AT socket 功能之后,默认开启 AT device 软件包, 具体路径如下所示:
+- **V1.2.0**:RT-Thread 版本小于 V3.1.3,AT 组件版本等于 V1.0.0;
+- **V1.3.0**:RT-Thread 版本小于 V3.1.3,AT 组件版本等于 V1.1.0;
+- **V1.4.0**:RT-Thread 版本小于 V3.1.3或等于 V4.0.0, AT 组件版本等于 V1.2.0;
+- **V1.5.0**:  RT-Thread 版本小于 V3.1.3 或等于 V4.0.0, AT 组件版本等于 V1.2.0;
+- **V1.6.0**:  RT-Thread 版本等于 V3.1.3 或等于 V4.0.1, AT 组件版本等于 V1.2.0;
+- **laster**: RT-Thread 版本小于大于 V4.0.1 或者 大于 3.1.3, AT 组件版本大于 V1.2.0;
+
+>  上述 版本判断在 menuconfig 中自动完成,at_device 软件包选择版本时会根据当前系统环境给出最佳版本支持,这里版本介绍作为运行环境参考。
+
+针对不同的版本号,在 ENV 中的选项配置也有所不同,主要分为如下几部分:
+
+**V1.X.X 版本配置选项介绍**
+
+开启 AT device 软件包,该版本只支持**同时开启一种 AT 设备**, 配置选项具体如下所示:                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
 
     RT-Thread online packages  --->
          IoT - internet of things  --->
             -*- AT DEVICE: RT-Thread AT component porting or samples for different device  
             [ ]   Enable at device init by thread
                   AT socket device modules (Not selected, please select)  --->    
-                  Version (latest)  --->
-
-- `Enable at device init by thread`: 配置开启设备网络初始化是否通过创建线程完成;
-- `AT socket device modules`: AT 设备选择,目前支持 RW007、ESP8266、M26/MC20、EC20、SIM800C、SIM76XX  等设备;
-- `Version`: 下载软件包版本;
-  - **V1.2.0**:RT-Thread 版本小于 V3.1.3,AT 组件版本等于 V1.0.0;
-  - **V1.3.0**:RT-Thread 版本小于 V3.1.3,AT 组件版本等于 V1.1.0;
-  - **V1.4.0**:RT-Thread 版本小于 V3.1.3 或等于 V4.0.0, AT 组件版本等于 V1.2.0;
-  - **V1.5.0**:RT-Thread 版本小于 V3.1.3 或等于 V4.0.0, AT 组件版本等于 V1.2.0;
-  - **V1.6.0**:RT-Thread 版本等于 V3.1.3 或等于 V4.0.1, AT 组件版本等于 V1.2.0;
-  - **laster**:RT-Thread 版本小于大于 V4.0.1 或者 大于 3.1.3, AT 组件版本大于 V1.2.0;
-
->上述 版本判断在 menuconfig 中自动完成,at_device 软件包选择版本时会根据当前系统环境给出最佳版本支持,这里版本介绍作为运行环境参考。
+                  Version (V1.6.0)  --->
+
+- **Enable at device init by thread**: 配置开启设备网络初始化是否通过创建线程完成;
+- **AT socket device modules**: AT 设备选择,目前支持 RW007、ESP8266、M26/MC20、EC20、SIM800C、SIM76XX  等设备;
+- **Version**: 下载软件包版本;
+
+**V2.X.X (laster) 版本配置选项介绍**
+
+开启 AT device 软件包,该版本支持**同时开启多种 AT 设备**配置选项具体如下所示:
+
+```c
+RT-Thread online packages  --->
+     IoT - internet of things  --->
+        -*- AT DEVICE: RT-Thread AT component porting or samples for different device
+        [*]   Quectel M26/MC20  --->
+          [*]   Enable initialize by thread
+          [*]   Enable sample
+          (-1)    Power pin
+          (-1)    Power status pin
+          (uart3) AT client device name
+          (512)   The maximum length of receive line buffer
+        [ ]   Quectel EC20  --->
+        [*]   Espressif ESP8266  --->
+          [*]   Enable initialize by thread
+          [*]   Enable sample
+          (realthread) WIFI ssid
+          (12345678) WIFI password
+          (uart2) AT client device name
+          (512)   The maximum length of receive line buffer
+        [ ]   Realthread RW007  --->
+        [ ]   SIMCom SIM800C  --->
+        [ ]   SIMCom SIM76XX  --->
+        Version (latest)  --->
+```
+
+- **Quectel M26/MC20**:开启 M20/MC20(2G 模块)设备支持;
+  - **Enable initialize by thread**:开启使用线程进行设备初始化功能(非阻塞模式初始化);
+  - **Enable sample**:开启示例代码,该示例代码中有对示例设备的注册;
+  - **Power pin**:配置该示例设备上电引脚;
+  - **Power status pin**:配置该示例设备上电状态引脚;
+  - **AT client device name**:配置该示例设备使用的串口设备名称;
+  - **The maximum length of receive line buffer**:配置该示例设备最大一行接收的数据长度;
+- **Quectel EC20 **:开启 EC20(4G 模块)设备支持;
+- **Espressif ESP8266**:开启 ESP8266 (WIFI 模块)设备支持;
+  - **Enable initialize by thread**:开启使用线程进行设备初始化功能(非阻塞模式初始化);
+  - **Enable sample**:开启示例代码,该示例代码中有对示例设备的注册;
+  - **WIFI ssid**:配置该示例设备连接的 WIFI 用户名;
+  - **WIFI password**:配置该示例设备连接的 WIFI 密码;
+  - **AT client device name**:配置该示例设备使用的串口设备名称;
+  - **The maximum length of receive line buffer**:配置该示例设备最大一行接收的数据长度;
+- **Realthread RW007**:开启 RW007 (WIFI 模块)设备支持;
+- **SIMCom SIM800C**:开启 SIM800C (2G 模块)设备支持;
+- **SIMCom SIM76XX**:开启 SIM76XX (4G 模块)设备支持; 
+- **Version** 下载软件包版本;
+
+上面配置选项以 2G 模块和 WIFI 模块选项为例,介绍了`V2.X.X` 版本 AT device 软件包配置方式,如下几点值得注意:
+
+- `V2.X.X` 版本支持同时开启多个 AT 设备,可以在 FinSH 中通过 `ifocnfig` 命令查看开启的设备信息;
+- `V2.X.X` 版本设备需要注册之后才可使用,目前在 samples 目录文件中完成设备注册,用户也可以在应用层自定义设备注册。
+-  `Power pin` 和 `Power status pin` 等引脚选项根据具体设备硬件连接情况配置,如果不使用硬件上电功能,可以配置为 `-1`;
+- 一个 AT 设备对应一个串口名称,及每个设备配置的`AT client device name` 应该都不相同。
+
+**AT 组件相关配置选项介绍**
+
+选中 AT device 软件包并开启相关设备支持之后,会默认选中 AT 组件的客户端功能,下面是 AT 组件配置选项,
+
+```c
+RT-Thread Components  --->
+    Network  --->
+        AT commands  --->
+    [ ]   Enable debug log output
+    [ ]   Enable AT commands server 
+    -*-   Enable AT commands client
+    (1)     The maximum number of supported clients
+    -*-     Enable BSD Socket API support by AT commnads
+    [*]     Enable CLI(Command-Line Interface) for AT commands
+    [ ]     Enable print RAW format AT command communication data
+    (128)   The maximum lenght of AT Commonds buffe
+```
+
+其中和 AT device 软件包相关的配置选项:
+
+- **The maximum number of supported clients**:最大支持的同时开启的 AT 客户端数量(AT device 软件包中选中多个设备需要配置该选项为对应数值);
+- **Enable BSD Socket API support by AT commnads**:开启 AT Socket 功能支持,选中 AT device 软件包默认选中该选项;
+- **The maximum lenght of AT Commonds buffe**:最大支持的发送命令数据的长度。
 
 ## 3. 注意事项  ##
 
 - AT device 软件包适配的模块暂时不支持作为 TCP Server 完成服务器相关操作(如 accept 等);
 - AT device 软件包默认设备类型为未选择,使用时需要指定使用设备型号;
+- `laster` 版本支持多个选中多个 AT 设备接入实现 AT Socket 功能,`V1.X.X` 版本只支持单个 AT 设备接入。
 - AT device 软件包目前多个版本主要用于适配 AT 组件和系统的改动,推荐使用最新版本  RT-Thread 系统,并在 menuconfig 选项中选择 `latest` 版本;
 
 ## 5. 联系方式

+ 58 - 25
SConscript

@@ -1,30 +1,63 @@
 from building import *
 
 cwd = GetCurrentDir()
-
-src = []
-
-if GetDepend(['AT_DEVICE_M26']):
-    src = Glob('at_socket_m26.c')
-
-if GetDepend(['AT_DEVICE_EC20']):
-    src = Glob('at_socket_ec20.c')
-
-if GetDepend(['AT_DEVICE_ESP8266']):
-    src = Glob('at_socket_esp8266.c')
-
-if GetDepend(['AT_DEVICE_RW007']):
-    src = Glob('at_socket_rw007.c')
-
-if GetDepend(['AT_DEVICE_SIM800C']):
-    src += Glob('at_socket_sim800c.c')
-
-if GetDepend(['AT_DEVICE_SIM76XX']):
-    src += Glob('at_socket_sim76xx.c')
-
-if GetDepend(['AT_DEVICE_NOT_SELECTED']):
-   src = Glob('*.c')
-
-group = DefineGroup('at_device', src, depend = ['PKG_USING_AT_DEVICE','AT_USING_SOCKET'], CPPPATH = [cwd])
+path = [cwd + '/inc']
+src  = Glob('src/*.c')
+
+# M26/MC20
+if GetDepend(['AT_DEVICE_USING_M26']):
+    path += [cwd + '/class/m26']
+    src += Glob('class/m26/at_device_m26.c')
+    if GetDepend(['AT_USING_SOCKET']):
+        src += Glob('class/m26/at_socket_m26.c')
+    if GetDepend(['AT_DEVICE_M26_SAMPLE']):
+        src += Glob('samples/at_sample_m26.c')
+
+# EC20
+if GetDepend(['AT_DEVICE_USING_EC20']):
+    path += [cwd + '/class/ec20']
+    src += Glob('class/ec20/at_device_ec20.c')
+    if GetDepend(['AT_USING_SOCKET']):
+        src += Glob('class/ec20/at_socket_ec20.c')
+    if GetDepend(['AT_DEVICE_EC20_SAMPLE']):
+        src += Glob('samples/at_sample_ec20.c')
+
+# ESP8266
+if GetDepend(['AT_DEVICE_USING_ESP8266']):
+    path += [cwd + '/class/esp8266']
+    src += Glob('class/esp8266/at_device_esp8266.c')
+    if GetDepend(['AT_USING_SOCKET']):
+        src += Glob('class/esp8266/at_socket_esp8266.c')
+    if GetDepend(['AT_DEVICE_ESP8266_SAMPLE']):
+        src += Glob('samples/at_sample_esp8266.c')
+        
+# RW007
+if GetDepend(['AT_DEVICE_USING_RW007']):
+    path += [cwd + '/class/rw007']
+    src += Glob('class/rw007/at_device_rw007.c')
+    if GetDepend(['AT_USING_SOCKET']):
+        src += Glob('class/rw007/at_socket_rw007.c')
+    if GetDepend(['AT_DEVICE_RW007_SAMPLE']):
+        src += Glob('samples/at_sample_rw007.c')
+
+# SIM800C
+if GetDepend(['AT_DEVICE_USING_SIM800C']):
+    path += [cwd + '/class/sim800c']
+    src += Glob('class/sim800c/at_device_sim800c.c')
+    if GetDepend(['AT_USING_SOCKET']):
+        src += Glob('class/sim800c/at_socket_sim800c.c')
+    if GetDepend(['AT_DEVICE_SIM800C_SAMPLE']):
+        src += Glob('samples/at_sample_sim800c.c')
+
+# SIM76XX
+if GetDepend(['AT_DEVICE_USING_SIM76XX']):
+    path += [cwd + '/class/sim76xx']
+    src += Glob('class/sim76xx/at_device_sim76xx.c')
+    if GetDepend(['AT_USING_SOCKET']):
+        src += Glob('class/sim76xx/at_socket_sim76xx.c')
+    if GetDepend(['AT_DEVICE_SIM76XX_SAMPLE']):
+        src += Glob('samples/at_sample_sim76xx.c')
+
+group = DefineGroup('at_device', src, depend = ['PKG_USING_AT_DEVICE'], CPPPATH = path)
 
 Return('group')

+ 0 - 1715
at_socket_ec20.c

@@ -1,1715 +0,0 @@
-/*
- * File      : at_socket_ec20.c
- * This file is part of RT-Thread RTOS
- * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Change Logs:
- * Date           Author       Notes
- * 2018-06-12     chenyong     first version
- * 2018-08-12     Marcus       port to ec20
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include <rtthread.h>
-#include <sys/socket.h>
-
-#include <at.h>
-#include <at_socket.h>
-
-#if !defined(RT_USING_NETDEV)
-#error "This RT-Thread version is older, please check and updata laster RT-Thread!"
-#else
-#include <arpa/inet.h>
-#include <netdev.h>
-#endif /* RT_USING_NETDEV */
-
-#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10200
-#error "This AT Client version is older, please check and update latest AT Client!"
-#endif
-
-#define LOG_TAG              "at.ec20"
-#include <at_log.h>
-
-#ifdef AT_DEVICE_EC20
-
-#define EC20_NETDEV_NAME               "ec20"
-
-#define EC20_MODULE_SEND_MAX_SIZE       1460
-#define EC20_WAIT_CONNECT_TIME          5000
-#define EC20_THREAD_STACK_SIZE          1024
-#define EC20_THREAD_PRIORITY            (RT_THREAD_PRIORITY_MAX/2)
-
-/* set real event by current socket and current state */
-#define SET_EVENT(socket, event)       (((socket + 1) << 16) | (event))
-
-/* AT socket event type */
-#define EC20_EVENT_CONN_OK              (1L << 0)
-#define EC20_EVENT_SEND_OK              (1L << 1)
-#define EC20_EVENT_RECV_OK              (1L << 2)
-#define EC20_EVNET_CLOSE_OK             (1L << 3)
-#define EC20_EVENT_CONN_FAIL            (1L << 4)
-#define EC20_EVENT_SEND_FAIL            (1L << 5)
-#define EC20_EVENT_DOMAIN_OK            (1L << 6)
-
-/* AT+QICSGP command default*/
-char *QICSGP_CHINA_MOBILE = "AT+QICSGP=1,1,\"CMNET\",\"\",\"\",0";
-char *QICSGP_CHINA_UNICOM = "AT+QICSGP=1,1,\"UNINET\",\"\",\"\",0";
-char *QICSGP_CHINA_TELECOM = "AT+QICSGP=1,1,\"CTNET\",\"\",\"\",0";
-
-static int cur_socket;
-static char recv_ip[16] = { 0 };
-static rt_event_t at_socket_event;
-static rt_mutex_t at_event_lock;
-static at_evt_cb_t at_evt_cb_set[] = {
-        [AT_SOCKET_EVT_RECV] = NULL,
-        [AT_SOCKET_EVT_CLOSED] = NULL,
-};
-
-static void at_cme_errcode_parse(int result)
-{
-    switch(result)
-    {
-    case 0   : LOG_E("%d : Phone failure",                result); break;
-    case 1   : LOG_E("%d : No connection to phone",       result); break;
-    case 2   : LOG_E("%d : Phone-adaptor link reserved",  result); break;
-    case 3   : LOG_E("%d : Operation not allowed",        result); break;
-    case 4   : LOG_E("%d : Operation not supported",      result); break;
-    case 5   : LOG_E("%d : PH-SIM PIN required",          result); break;
-    case 6   : LOG_E("%d : PH-FSIM PIN required",         result); break;
-    case 7   : LOG_E("%d : PH-FSIM PUK required",         result); break;
-    case 10  : LOG_E("%d : SIM not inserted",             result); break;
-    case 11  : LOG_E("%d : SIM PIN required",             result); break;
-    case 12  : LOG_E("%d : SIM PUK required",             result); break;
-    case 13  : LOG_E("%d : SIM failure",                  result); break;
-    case 14  : LOG_E("%d : SIM busy",                     result); break;
-    case 15  : LOG_E("%d : SIM wrong",                    result); break;
-    case 16  : LOG_E("%d : Incorrect password",           result); break;
-    case 17  : LOG_E("%d : SIM PIN2 required",            result); break;
-    case 18  : LOG_E("%d : SIM PUK2 required",            result); break;
-    case 20  : LOG_E("%d : Memory full",                  result); break;
-    case 21  : LOG_E("%d : Invalid index",                result); break;
-    case 22  : LOG_E("%d : Not found",                    result); break;
-    case 23  : LOG_E("%d : Memory failure",               result); break;
-    case 24  : LOG_E("%d : Text string too long",         result); break;
-    case 25  : LOG_E("%d : Invalid characters in text string", result); break;
-    case 26  : LOG_E("%d : Dial string too long",         result); break;
-    case 27  : LOG_E("%d : Invalid characters in dial string", result); break;
-    case 30  : LOG_E("%d : No network service",           result); break;
-    case 31  : LOG_E("%d : Network timeout",              result); break;
-    case 32  : LOG_E("%d : Network not allowed - emergency calls only", result); break;
-    case 40  : LOG_E("%d : Network personalization PIN required", result); break;
-    case 41  : LOG_E("%d : Network personalization PUK required", result); break;
-    case 42  : LOG_E("%d : Network subset personalization PIN required", result); break;
-    case 43  : LOG_E("%d : Network subset personalization PUK required", result); break;
-    case 44  : LOG_E("%d : Service provider personalization PIN required", result); break;
-    case 45  : LOG_E("%d : Service provider personalization PUK required", result); break;
-    case 46  : LOG_E("%d : Corporate personalization PIN required", result); break;
-    case 47  : LOG_E("%d : Corporate personalization PUK required", result); break;
-    case 901 : LOG_E("%d : Audio unknown error",          result); break;
-    case 902 : LOG_E("%d : Audio invalid parameters",     result); break;
-    case 903 : LOG_E("%d : Audio operation not supported", result); break;
-    case 904 : LOG_E("%d : Audio device busy",            result); break;
-    default  : LOG_E("%d : Unknown err code",             result); break;
-    }
-}
-
-static void at_cms_errcode_parse(int result)
-{
-    switch(result)
-    {
-    case 300 : LOG_E("%d : ME failure",                   result); break;
-    case 301 : LOG_E("%d : SMS ME reserved",              result); break;
-    case 302 : LOG_E("%d : Operation not allowed",        result); break;
-    case 303 : LOG_E("%d : Operation not supported",      result); break;
-    case 304 : LOG_E("%d : Invalid PDU mode",             result); break;
-    case 305 : LOG_E("%d : Invalid text mode",            result); break;
-    case 310 : LOG_E("%d : SIM not inserted",             result); break;
-    case 311 : LOG_E("%d : SIM pin necessary",            result); break;
-    case 312 : LOG_E("%d : PH SIM pin necessary",         result); break;
-    case 313 : LOG_E("%d : SIM failure",                  result); break;
-    case 314 : LOG_E("%d : SIM busy",                     result); break;
-    case 315 : LOG_E("%d : SIM wrong",                    result); break;
-    case 316 : LOG_E("%d : SIM PUK required",             result); break;
-    case 317 : LOG_E("%d : SIM PIN2 required",            result); break;
-    case 318 : LOG_E("%d : SIM PUK2 required",            result); break;
-    case 320 : LOG_E("%d : Memory failure",               result); break;
-    case 321 : LOG_E("%d : Invalid memory index",         result); break;
-    case 322 : LOG_E("%d : Memory full",                  result); break;
-    case 330 : LOG_E("%d : SMSC address unknown",         result); break;
-    case 331 : LOG_E("%d : No network",                   result); break;
-    case 332 : LOG_E("%d : Network timeout",              result); break;
-    case 500 : LOG_E("%d : Unknown",                      result); break;
-    case 512 : LOG_E("%d : SIM not ready",                result); break;
-    case 513 : LOG_E("%d : Message length exceeds",       result); break;
-    case 514 : LOG_E("%d : Invalid request parameters",   result); break;
-    case 515 : LOG_E("%d : ME storage failure",           result); break;
-    case 517 : LOG_E("%d : Invalid service mode",         result); break;
-    case 528 : LOG_E("%d : More message to send state error", result); break;
-    case 529 : LOG_E("%d : MO SMS is not allow",          result); break;
-    case 530 : LOG_E("%d : GPRS is suspended",            result); break;
-    case 531 : LOG_E("%d : ME storage full",              result); break;
-    default  : LOG_E("%d : Unknown err code",             result); break;
-    }
-}
-
-static void at_mms_errcode_parse(int result)//MMS
-{
-    switch(result)
-    {
-    case 751 : LOG_E("%d : Unknown error",                result); break;
-    case 752 : LOG_E("%d : URL length error",             result); break;
-    case 753 : LOG_E("%d : URL error",                    result); break;
-    case 754 : LOG_E("%d : Invalid proxy type",           result); break;
-    case 755 : LOG_E("%d : Proxy address error",          result); break;
-    case 756 : LOG_E("%d : Invalid parameter",            result); break;
-    case 757 : LOG_E("%d : Recipient address full",       result); break;
-    case 758 : LOG_E("%d : CC recipient address full",    result); break;
-    case 759 : LOG_E("%d : BCC recipient address full",   result); break;
-    case 760 : LOG_E("%d : Attachments full",             result); break;
-    case 761 : LOG_E("%d : File error",                   result); break;
-    case 762 : LOG_E("%d : No recipient",                 result); break;
-    case 763 : LOG_E("%d : File not found",               result); break;
-    case 764 : LOG_E("%d : MMS busy",                     result); break;
-    case 765 : LOG_E("%d : Server response failed",       result); break;
-    case 766 : LOG_E("%d : Error response of HTTP(S) post", result); break;
-    case 767 : LOG_E("%d : Invalid report of HTTP(S) post", result); break;
-    case 768 : LOG_E("%d : PDP activation failed",        result); break;
-    case 769 : LOG_E("%d : PDP deactivated",              result); break;
-    case 770 : LOG_E("%d : Socket creation failed",       result); break;
-    case 771 : LOG_E("%d : Socket connection failed",     result); break;
-    case 772 : LOG_E("%d : Socket read failed",           result); break;
-    case 773 : LOG_E("%d : Socket write failed",          result); break;
-    case 774 : LOG_E("%d : Socket closed",                result); break;
-    case 775 : LOG_E("%d : Timeout",                      result); break;
-    case 776 : LOG_E("%d : Encode data error",            result); break;
-    case 777 : LOG_E("%d : HTTP(S) decode data error",    result); break;
-    default  : LOG_E("%d : Unknown err code",             result); break;
-    }
-}
-    
-static void at_tcp_ip_errcode_parse(int result)//TCP/IP_QIGETERROR
-{
-    switch(result)
-    {
-    case 0   : LOG_D("%d : Operation successful",         result); break;
-    case 550 : LOG_E("%d : Unknown error",                result); break;
-    case 551 : LOG_E("%d : Operation blocked",            result); break;
-    case 552 : LOG_E("%d : Invalid parameters",           result); break;
-    case 553 : LOG_E("%d : Memory not enough",            result); break;
-    case 554 : LOG_E("%d : Create socket failed",         result); break;
-    case 555 : LOG_E("%d : Operation not supported",      result); break;
-    case 556 : LOG_E("%d : Socket bind failed",           result); break;
-    case 557 : LOG_E("%d : Socket listen failed",         result); break;
-    case 558 : LOG_E("%d : Socket write failed",          result); break;
-    case 559 : LOG_E("%d : Socket read failed",           result); break;
-    case 560 : LOG_E("%d : Socket accept failed",         result); break;
-    case 561 : LOG_E("%d : Open PDP context failed",      result); break;
-    case 562 : LOG_E("%d : Close PDP context failed",     result); break;
-    case 563 : LOG_W("%d : Socket identity has been used", result); break;
-    case 564 : LOG_E("%d : DNS busy",                     result); break;
-    case 565 : LOG_E("%d : DNS parse failed",             result); break;
-    case 566 : LOG_E("%d : Socket connect failed",        result); break;
-    case 567 : LOG_W("%d : Socket has been closed",       result); break;
-    case 568 : LOG_E("%d : Operation busy",               result); break;
-    case 569 : LOG_E("%d : Operation timeout",            result); break;
-    case 570 : LOG_E("%d : PDP context broken down",      result); break;
-    case 571 : LOG_E("%d : Cancel send",                  result); break;
-    case 572 : LOG_E("%d : Operation not allowed",        result); break;
-    case 573 : LOG_E("%d : APN not configured",           result); break;
-    case 574 : LOG_E("%d : Port busy",                    result); break;
-    default  : LOG_E("%d : Unknown err code",             result); break;
-    }
-}
-
-static void at_http_errcode_parse(int result)//HTTP
-{
-    switch(result)
-    {
-    case 0   : LOG_D("%d : Operation successful",         result); break;
-    case 701 : LOG_E("%d : HTTP(S) unknown error",        result); break;
-    case 702 : LOG_E("%d : HTTP(S) timeout",              result); break;
-    case 703 : LOG_E("%d : HTTP(S) busy",                 result); break;
-    case 704 : LOG_E("%d : HTTP(S) UART busy",            result); break;
-    case 705 : LOG_E("%d : HTTP(S) no GET/POST requests", result); break;
-    case 706 : LOG_E("%d : HTTP(S) network busy",         result); break;
-    case 707 : LOG_E("%d : HTTP(S) network open failed",  result); break;
-    case 708 : LOG_E("%d : HTTP(S) network no configuration", result); break;
-    case 709 : LOG_E("%d : HTTP(S) network deactivated",  result); break;
-    case 710 : LOG_E("%d : HTTP(S) network error",        result); break;
-    case 711 : LOG_E("%d : HTTP(S) URL error",            result); break;
-    case 712 : LOG_E("%d : HTTP(S) empty URL",            result); break;
-    case 713 : LOG_E("%d : HTTP(S) IP address error",     result); break;
-    case 714 : LOG_E("%d : HTTP(S) DNS error",            result); break;
-    case 715 : LOG_E("%d : HTTP(S) socket create error",  result); break;
-    case 716 : LOG_E("%d : HTTP(S) socket connect error", result); break;
-    case 717 : LOG_E("%d : HTTP(S) socket read error",    result); break;
-    case 718 : LOG_E("%d : HTTP(S) socket write error",   result); break;
-    case 719 : LOG_E("%d : HTTP(S) socket closed",        result); break;
-    case 720 : LOG_E("%d : HTTP(S) data encode error",    result); break;
-    case 721 : LOG_E("%d : HTTP(S) data decode error",    result); break;
-    case 722 : LOG_E("%d : HTTP(S) read timeout",         result); break;
-    case 723 : LOG_E("%d : HTTP(S) response failed",      result); break;
-    case 724 : LOG_E("%d : Incoming call busy",           result); break;
-    case 725 : LOG_E("%d : Voice call busy",              result); break;
-    case 726 : LOG_E("%d : Input timeout",                result); break;
-    case 727 : LOG_E("%d : Wait data timeout",            result); break;
-    case 728 : LOG_E("%d : Wait HTTP(S) response timeout", result); break;
-    case 729 : LOG_E("%d : Memory allocation failed",     result); break;
-    case 730 : LOG_E("%d : Invalid parameter",            result); break;
-    default  : LOG_E("%d : Unknown err code",             result); break;
-    }
-}
-
-static void at_http_rsponsecode_parse(int result)//HTTP
-{
-    switch(result)
-    {
-    case 200 : LOG_D("%d : OK",                           result); break;
-    case 400 : LOG_E("%d : Bad request",                  result); break;
-    case 403 : LOG_E("%d : Forbidden",                    result); break;
-    case 404 : LOG_E("%d : Not found",                    result); break;
-    case 409 : LOG_E("%d : Conflict",                     result); break;
-    case 411 : LOG_E("%d : Length required",              result); break;
-    case 500 : LOG_E("%d : Internal server error",        result); break;
-    case 502 : LOG_E("%d : Bad gate way",                 result); break;
-    default  : LOG_E("%d : Unknown err code",             result); break;
-    }
-}
-
-static void at_ftp_errcode_parse(int result)//FTP
-{
-    switch(result)
-    {
-    case 0   : LOG_D("%d : Operation successful",         result); break;
-    case 601 : LOG_E("%d : Unknown error",                result); break;
-    case 602 : LOG_E("%d : FTP(S) server blocked",        result); break;
-    case 603 : LOG_E("%d : FTP(S) server busy",           result); break;
-    case 604 : LOG_E("%d : DNS parse failed",             result); break;
-    case 605 : LOG_E("%d : Network error",                result); break;
-    case 606 : LOG_E("%d : Control connection closed.",   result); break;
-    case 607 : LOG_E("%d : Data connection closed",       result); break;
-    case 608 : LOG_E("%d : Socket closed by peer",        result); break;
-    case 609 : LOG_E("%d : Timeout error",                result); break;
-    case 610 : LOG_E("%d : Invalid parameter",            result); break;
-    case 611 : LOG_E("%d : Failed to open file",          result); break;
-    case 612 : LOG_E("%d : File position invalid",        result); break;
-    case 613 : LOG_E("%d : File error",                   result); break;
-    case 614 : LOG_E("%d : Service not available, closing control connection", result); break;
-    case 615 : LOG_E("%d : Open data connection failed",  result); break;
-    case 616 : LOG_E("%d : Connection closed; transfer aborted", result); break;
-    case 617 : LOG_E("%d : Requested file action not taken", result); break;
-    case 618 : LOG_E("%d : Requested action aborted: local error in processing", result); break;
-    case 619 : LOG_E("%d : Requested action not taken: insufficient system storage", result); break;
-    case 620 : LOG_E("%d : Syntax error, command unrecognized", result); break;
-    case 621 : LOG_E("%d : Syntax error in parameters or arguments", result); break;
-    case 622 : LOG_E("%d : Command not implemented",      result); break;
-    case 623 : LOG_E("%d : Bad sequence of commands",     result); break;
-    case 624 : LOG_E("%d : Command parameter not implemented", result); break;
-    case 625 : LOG_E("%d : Not logged in",                result); break;
-    case 626 : LOG_E("%d : Need account for storing files", result); break;
-    case 627 : LOG_E("%d : Requested action not taken",   result); break;
-    case 628 : LOG_E("%d : Requested action aborted: page type unknown", result); break;
-    case 629 : LOG_E("%d : Requested file action aborted", result); break;
-    case 630 : LOG_E("%d : Requested file name invalid",  result); break;
-    case 631 : LOG_E("%d : SSL authentication failed",    result); break;
-    default  : LOG_E("%d : Unknown err code",             result); break;
-    }
-}
-
-static void at_ftp_protocol_errcode_parse(int result)//FTP_Protocol
-{
-    switch(result)
-    {
-    case 421 : LOG_E("%d : Service not available, closing control connection", result); break;
-    case 425 : LOG_E("%d : Open data connection failed",  result); break;
-    case 426 : LOG_E("%d : Connection closed; transfer aborted", result); break;
-    case 450 : LOG_E("%d : Requested file action not taken", result); break;
-    case 451 : LOG_E("%d : Requested action aborted: local error in processing", result); break;
-    case 452 : LOG_E("%d : Requested action not taken: insufficient system storage", result); break;
-    case 500 : LOG_E("%d : Syntax error, command unrecognized", result); break;
-    case 501 : LOG_E("%d : Syntax error in parameters or arguments", result); break;
-    case 502 : LOG_E("%d : Command not implemented",      result); break;
-    case 503 : LOG_E("%d : Bad sequence of commands",     result); break;
-    case 504 : LOG_E("%d : Command parameter not implemented", result); break;
-    case 530 : LOG_E("%d : Not logged in",                result); break;
-    case 532 : LOG_E("%d : Need account for storing files", result); break;
-    case 550 : LOG_E("%d : Requested action not taken: file unavailable", result); break;
-    case 551 : LOG_E("%d : Requested action aborted: page type unknown", result); break;
-    case 552 : LOG_E("%d : Requested file action aborted: exceeded storage allocation", result); break;
-    case 553 : LOG_E("%d : Requested action not taken: file name not allowed", result); break;
-    default  : LOG_E("%d : Unknown err code",             result); break;
-    }
-}
-
-static void at_smtp_errcode_parse(int result)//Email
-{
-    switch(result)
-    {
-    case 651 : LOG_E("%d : Unknown error",                result); break;
-    case 652 : LOG_E("%d : The SMTP server is busy, such as uploading the body or sending an email.", result); break;
-    case 653 : LOG_E("%d : Failed to get IP address according to the domain name.", result); break;
-    case 654 : LOG_E("%d : Network error, such as failed to activate GPRS/CSD context, failed to establish the TCP connection with the SMTP server or failed to send an email to the SMTP server, etc.", result); break;
-    case 655 : LOG_E("%d : Unsupported authentication type", result); break;
-    case 656 : LOG_E("%d : The connection for the SMTP server is closed by peer.", result); break;
-    case 657 : LOG_E("%d : GPRS/CSD context is deactivated.", result); break;
-    case 658 : LOG_E("%d : Timeout",                      result); break;
-    case 659 : LOG_E("%d : No recipient for the SMTP server", result); break;
-    case 660 : LOG_E("%d : Failed to send an email",      result); break;
-    case 661 : LOG_E("%d : Failed to open a file",        result); break;
-    case 662 : LOG_E("%d : No enough memory for the attachment", result); break;
-    case 663 : LOG_E("%d : Failed to save the attachment", result); break;
-    case 664 : LOG_E("%d : The input parameter is wrong", result); break;
-    case 665 : LOG_E("%d : SSL authentication failed",    result); break;
-    case 666 : LOG_E("%d : Service not available, closing transmission channel", result); break;
-    case 667 : LOG_E("%d : Requested mail action not taken: mailbox unavailable", result); break;
-    case 668 : LOG_E("%d : Requested action aborted: local error in processing", result); break;
-    case 669 : LOG_E("%d : Requested action not taken: insufficient system storage", result); break;
-    case 670 : LOG_E("%d : Syntax error, command unrecognized", result); break;
-    case 671 : LOG_E("%d : Syntax error in parameters or arguments", result); break;
-    case 672 : LOG_E("%d : Command not implemented",      result); break;
-    case 673 : LOG_E("%d : Bad sequence of commands",     result); break;
-    case 674 : LOG_E("%d : Command parameter not implemented", result); break;
-    case 675 : LOG_E("%d : <domain> does not accept mail (see RFC1846)", result); break;
-    case 676 : LOG_E("%d : Access denied",                result); break;
-    case 677 : LOG_E("%d : Authentication failed",        result); break;
-    case 678 : LOG_E("%d : Requested action not taken: mailbox unavailable", result); break;
-    case 679 : LOG_E("%d : User not local; please try <forward-path>", result); break;
-    case 680 : LOG_E("%d : Requested mail action aborted: exceeded storage allocation", result); break;
-    case 681 : LOG_E("%d : Requested action not taken: mailbox name not allowed", result); break;
-    case 682 : LOG_E("%d : Transaction failed",           result); break;
-    default  : LOG_E("%d : Unknown err code",             result); break;
-    }
-}
-
-static void at_smtp_protocol_errcode_parse(int result)//Email_Protocol
-{
-    switch(result)
-    {
-    case 421 : LOG_E("%d : Service not available, closing transmission channel", result); break;
-    case 450 : LOG_E("%d : Requested mail action not taken: mailbox unavailable", result); break;
-    case 451 : LOG_E("%d : Requested action aborted: local error in processing", result); break;
-    case 452 : LOG_E("%d : Requested action not taken: insufficient system storage", result); break;
-    case 500 : LOG_E("%d : Syntax error, command unrecognized", result); break;
-    case 501 : LOG_E("%d : Syntax error in parameters or arguments", result); break;
-    case 502 : LOG_E("%d : Command not implemented",      result); break;
-    case 503 : LOG_E("%d : Bad sequence of commands",     result); break;
-    case 504 : LOG_E("%d : Command parameter not implemented", result); break;
-    case 521 : LOG_E("%d : <domain> does not accept mail (see RFC1846)", result); break;
-    case 530 : LOG_E("%d : Access denied",                result); break;
-    case 535 : LOG_E("%d : Authentication failed",        result); break;
-    case 550 : LOG_E("%d : Requested action not taken: mailbox unavailable", result); break;
-    case 551 : LOG_E("%d : User not local; please try <forward-path>", result); break;
-    case 552 : LOG_E("%d : Requested mail action aborted: exceeded storage allocation", result); break;
-    case 553 : LOG_E("%d : Requested action not taken: mailbox name not allowed", result); break;
-    case 554 : LOG_E("%d : Transaction failed",           result); break;
-    default  : LOG_E("%d : Unknown err code",             result); break;
-    }
-}
-
-static int at_socket_event_send(uint32_t event)
-{
-    return (int) rt_event_send(at_socket_event, event);
-}
-
-static int at_socket_event_recv(uint32_t event, uint32_t timeout, rt_uint8_t option)
-{
-    int result = 0;
-    rt_uint32_t recved;
-
-    result = rt_event_recv(at_socket_event, event, option | RT_EVENT_FLAG_CLEAR, timeout, &recved);
-    if (result != RT_EOK)
-    {
-        return -RT_ETIMEOUT;
-    }
-
-    return recved;
-}
-
-/**
- * close socket by AT commands.
- *
- * @param current socket
- *
- * @return  0: close socket success
- *         -1: send AT commands error
- *         -2: wait socket event timeout
- *         -5: no memory
- */
-static int ec20_socket_close(int socket)
-{
-    int result = 0;
-    at_response_t resp = RT_NULL;
-
-    resp = at_create_resp(128, 0, RT_TICK_PER_SECOND);
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    /* default connection timeout is 10 seconds, but it set to 1 seconds is convenient to use.*/
-    result = at_exec_cmd(resp, "AT+QICLOSE=%d,1", socket);
-    if (result < 0)
-    {
-        return result;
-    }
-
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-/**
- * create TCP/UDP client or server connect by AT commands.
- *
- * @param socket current socket
- * @param ip server or client IP address
- * @param port server or client port
- * @param type connect socket type(tcp, udp)
- * @param is_client connection is client
- *
- * @return   0: connect success
- *          -1: connect failed, send commands error or type error
- *          -2: wait socket event timeout
- *          -5: no memory
- */
-static int ec20_socket_connect(int socket, char *ip, int32_t port, enum at_socket_type type, rt_bool_t is_client)
-{
-    int result = 0, event_result = 0;
-    rt_bool_t retryed = RT_FALSE;
-    at_response_t resp = RT_NULL;
-
-    RT_ASSERT(ip);
-    RT_ASSERT(port >= 0);
-
-    resp = at_create_resp(128, 0, 5 * RT_TICK_PER_SECOND);
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    /* lock AT socket connect */
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-__retry:
-    
-    /* Clear socket connect event */
-    at_socket_event_recv(SET_EVENT(socket, EC20_EVENT_CONN_OK | EC20_EVENT_CONN_FAIL), 0, RT_EVENT_FLAG_OR);
-
-    if (is_client)
-    {
-        switch (type)
-        {
-        case AT_SOCKET_TCP:
-            /* send AT commands(AT+QIOPEN=<contextID>,<socket>,"<TCP/UDP>","<IP_address>/<domain_name>",<remote_port>,<local_port>,<access_mode>) to connect TCP server */
-            /* contextID = 1 : use same contextID as AT+QICSGP & AT+QIACT */
-            /* local_port=0 : local port assigned automatically */
-            /* access_mode = 1 : Direct push mode */
-            if (at_exec_cmd(resp, "AT+QIOPEN=1,%d,\"TCP\",\"%s\",%d,0,1", socket, ip, port) < 0)
-            {
-                result = -RT_ERROR;
-                goto __exit;
-            }
-            break;
-
-        case AT_SOCKET_UDP:
-            if (at_exec_cmd(resp, "AT+QIOPEN=1,%d,\"UDP\",\"%s\",%d,0,1", socket, ip, port) < 0)
-            {
-                result = -RT_ERROR;
-                goto __exit;
-            }
-            break;
-
-        default:
-            LOG_E("Not supported connect type : %d.", type);
-            return -RT_ERROR;
-        }
-    }
-
-    /* waiting result event from AT URC, the device default connection timeout is 75 seconds, but it set to 10 seconds is convenient to use.*/
-    if (at_socket_event_recv(SET_EVENT(socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
-    {
-        LOG_E("socket (%d) connect failed, wait connect result timeout.", socket);
-        result = -RT_ETIMEOUT;
-        goto __exit;
-    }
-    /* waiting OK or failed result */
-    if ((event_result = at_socket_event_recv(EC20_EVENT_CONN_OK | EC20_EVENT_CONN_FAIL, 1 * RT_TICK_PER_SECOND,
-            RT_EVENT_FLAG_OR)) < 0)
-    {
-        LOG_E("socket (%d) connect failed, wait connect OK|FAIL timeout.", socket);
-        result = -RT_ETIMEOUT;
-        goto __exit;
-    }
-    /* check result */
-    if (event_result & EC20_EVENT_CONN_FAIL)
-    {
-        if (!retryed)
-        {
-            LOG_W("socket (%d) connect failed, maybe the socket was not be closed at the last time and now will retry.", socket);
-            /* default connection timeout is 10 seconds, but it set to 1 seconds is convenient to use.*/
-            if (ec20_socket_close < 0)
-            {
-                result = -RT_ERROR;
-                goto __exit;
-            }
-            retryed = RT_TRUE;
-            goto __retry;
-        }
-        LOG_E("socket (%d) connect failed, failed to establish a connection.", socket);
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-__exit:
-    /* unlock AT socket connect */
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-static int at_get_send_size(int socket, size_t *size, size_t *acked, size_t *nacked)
-{
-    at_response_t resp = at_create_resp(128, 0, 5 * RT_TICK_PER_SECOND);
-    int result = 0;
-
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-
-    if (at_exec_cmd(resp, "AT+QISEND=%d,0", socket) < 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    if (at_resp_parse_line_args_by_kw(resp, "+QISEND:", "+QISEND: %d,%d,%d", size, acked, nacked) <= 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-static int at_wait_send_finish(int socket, size_t settings_size)
-{
-    /* get the timeout by the input data size */
-    rt_tick_t timeout = rt_tick_from_millisecond(settings_size);
-    rt_tick_t last_time = rt_tick_get();
-    size_t size = 0, acked = 0, nacked = 0xFFFF;
-
-    while (rt_tick_get() - last_time <= timeout)
-    {
-        at_get_send_size(socket, &size, &acked, &nacked);
-        if (nacked == 0)
-        {
-            return RT_EOK;
-        }
-        rt_thread_mdelay(50);
-    }
-
-    return -RT_ETIMEOUT;
-}
-
-/**
- * send data to server or client by AT commands.
- *
- * @param socket current socket
- * @param buff send buffer
- * @param bfsz send buffer size
- * @param type connect socket type(tcp, udp)
- *
- * @return >=0: the size of send success
- *          -1: send AT commands error or send data error
- *          -2: waited socket event timeout
- *          -5: no memory
- */
-static int ec20_socket_send(int socket, const char *buff, size_t bfsz, enum at_socket_type type)
-{
-    int result = 0, event_result = 0;
-    at_response_t resp = RT_NULL;
-    size_t cur_pkt_size = 0, sent_size = 0;
-
-    RT_ASSERT(buff);
-
-    resp = at_create_resp(128, 2, 5 * RT_TICK_PER_SECOND);
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    /* Clear socket send event */
-    at_socket_event_recv(SET_EVENT(socket, EC20_EVENT_SEND_OK | EC20_EVENT_SEND_FAIL), 0, RT_EVENT_FLAG_OR);
-
-    /* set current socket for send URC event */
-    cur_socket = socket;
-    /* set AT client end sign to deal with '>' sign.*/
-    at_set_end_sign('>');
-
-    while (sent_size < bfsz)
-    {
-        if (bfsz - sent_size < EC20_MODULE_SEND_MAX_SIZE)
-        {
-            cur_pkt_size = bfsz - sent_size;
-        }
-        else
-        {
-            cur_pkt_size = EC20_MODULE_SEND_MAX_SIZE;
-        }
-
-        /* send the "AT+QISEND" commands to AT server than receive the '>' response on the first line. */
-        if (at_exec_cmd(resp, "AT+QISEND=%d,%d", socket, cur_pkt_size) < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* send the real data to server or client */
-        result = (int) at_client_send(buff + sent_size, cur_pkt_size);
-        if (result == 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* waiting result event from AT URC */
-        if (at_socket_event_recv(SET_EVENT(socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
-        {
-            result = -RT_ETIMEOUT;
-            goto __exit;
-        }
-        /* waiting OK or failed result */
-        if ((event_result = at_socket_event_recv(EC20_EVENT_SEND_OK | EC20_EVENT_SEND_FAIL, 1 * RT_TICK_PER_SECOND,
-                RT_EVENT_FLAG_OR)) < 0)
-        {
-            LOG_E("socket (%d) send failed, wait connect OK|FAIL timeout.", socket);
-            result = -RT_ETIMEOUT;
-            goto __exit;
-        }
-        /* check result */
-        if (event_result & EC20_EVENT_SEND_FAIL)
-        {
-            LOG_E("socket (%d) send failed, return failed.", socket);
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        if (type == AT_SOCKET_TCP)
-        {
-            at_wait_send_finish(socket, cur_pkt_size);
-        }
-
-        sent_size += cur_pkt_size;
-    }
-
-
-__exit:
-    /* reset the end sign for data conflict */
-    at_set_end_sign(0);
-
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-/**
- * domain resolve by AT commands.
- *
- * @param name domain name
- * @param ip parsed IP address, it's length must be 16
- *
- * @return  0: domain resolve success
- *         -1: send AT commands error or response error
- *         -2: wait socket event timeout
- *         -5: no memory
- */
-static int ec20_domain_resolve(const char *name, char ip[16])
-{
-#define RESOLVE_RETRY                  3
-
-    int i, result;
-//    char recv_ip[16] = { 0 };
-    at_response_t resp = RT_NULL;
-
-    RT_ASSERT(name);
-    RT_ASSERT(ip);
-
-    /* The maximum response time is 60 seconds, but it set to 10 seconds is convenient to use. */
-    resp = at_create_resp(128, 0, 10 * RT_TICK_PER_SECOND);
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-    
-    /* Clear EC20_EVENT_DOMAIN_OK */
-    at_socket_event_recv(EC20_EVENT_DOMAIN_OK, 0, RT_EVENT_FLAG_OR);
-
-    result = at_exec_cmd(resp, "AT+QIDNSGIP=1,\"%s\"", name);
-    if (result < 0)
-    {
-        goto __exit;
-    }
-    
-    if (result == RT_EOK)
-    {
-        for(i = 0; i < RESOLVE_RETRY; i++)
-        {
-            /* waiting result event from AT URC, the device default connection timeout is 60 seconds.*/
-            if (at_socket_event_recv(EC20_EVENT_DOMAIN_OK, 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
-            {
-                continue;
-            }
-            else
-            {
-                if (strlen(recv_ip) < 8)
-                {
-                    rt_thread_mdelay(100);
-                    /* resolve failed, maybe receive an URC CRLF */
-                    result = -RT_ERROR;
-                    continue;
-                }
-                else
-                {
-                    strncpy(ip, recv_ip, 15);
-                    ip[15] = '\0';
-                    result = RT_EOK;
-                    break;
-                }
-            }
-        }
-        
-        /* response timeout */
-        if (i == RESOLVE_RETRY)
-        {
-            result = -RT_ENOMEM;
-        }
-    }
-
- __exit:
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-
-}
-
-/**
- * set AT socket event notice callback
- *
- * @param event notice event
- * @param cb notice callback
- */
-static void ec20_socket_set_event_cb(at_socket_evt_t event, at_evt_cb_t cb)
-{
-    if (event < sizeof(at_evt_cb_set) / sizeof(at_evt_cb_set[1]))
-    {
-        at_evt_cb_set[event] = cb;
-    }
-}
-
-static void urc_connect_func(const char *data, rt_size_t size)
-{
-    int socket = 0;
-    int result = 0;
-
-    RT_ASSERT(data && size);
-
-    sscanf(data, "+QIOPEN: %d,%d", &socket , &result);
-
-    if (result == 0)
-    {
-        at_socket_event_send(SET_EVENT(socket, EC20_EVENT_CONN_OK));
-    }
-    else
-    {
-        at_tcp_ip_errcode_parse(result);
-        at_socket_event_send(SET_EVENT(socket, EC20_EVENT_CONN_FAIL));
-    }
-}
-
-static void urc_send_func(const char *data, rt_size_t size)
-{
-    RT_ASSERT(data && size);
-
-    if (strstr(data, "SEND OK"))
-    {
-        at_socket_event_send(SET_EVENT(cur_socket, EC20_EVENT_SEND_OK));
-    }
-    else if (strstr(data, "SEND FAIL"))
-    {
-        at_socket_event_send(SET_EVENT(cur_socket, EC20_EVENT_SEND_FAIL));
-    }
-}
-
-static void urc_close_func(const char *data, rt_size_t size)
-{
-    int socket = 0;
-
-    RT_ASSERT(data && size);
-
-    sscanf(data, "+QIURC: \"closed\",%d", &socket);
-
-    /* notice the socket is disconnect by remote */
-    if (at_evt_cb_set[AT_SOCKET_EVT_CLOSED])
-    {
-        at_evt_cb_set[AT_SOCKET_EVT_CLOSED](socket, AT_SOCKET_EVT_CLOSED, NULL, 0);
-    }
-    
-    // /* when TCP socket service is closed, host must send "AT+QICLOSE= <connID>,0" command to close socket */
-    // at_exec_cmd(RT_NULL, "AT+QICLOSE=%d,0\r\n", socket);
-    // rt_thread_mdelay(100);
-}
-
-static void urc_recv_func(const char *data, rt_size_t size)
-{
-    int socket = 0;
-    rt_size_t bfsz = 0, temp_size = 0;
-    rt_int32_t timeout;
-    char *recv_buf = RT_NULL, temp[8];
-
-    RT_ASSERT(data && size);
-    
-    /* get the current socket and receive buffer size by receive data */
-    sscanf(data, "+QIURC: \"recv\",%d,%d", &socket, (int *) &bfsz);
-    /* get receive timeout by receive buffer length */
-    timeout = bfsz;
-
-    if (socket < 0 || bfsz == 0)
-        return;
-
-    recv_buf = rt_calloc(1, bfsz);
-    if (!recv_buf)
-    {
-        LOG_E("no memory for URC receive buffer (%d)!", bfsz);
-        /* read and clean the coming data */
-        while (temp_size < bfsz)
-        {
-            if (bfsz - temp_size > sizeof(temp))
-            {
-                at_client_recv(temp, sizeof(temp), timeout);
-            }
-            else
-            {
-                at_client_recv(temp, bfsz - temp_size, timeout);
-            }
-            temp_size += sizeof(temp);
-        }
-        return;
-    }
-
-    /* sync receive data */
-    if (at_client_recv(recv_buf, bfsz, timeout) != bfsz)
-    {
-        LOG_E("receive size(%d) data failed!", bfsz);
-        rt_free(recv_buf);
-        return;
-    }
-
-    /* notice the receive buffer and buffer size */
-    if (at_evt_cb_set[AT_SOCKET_EVT_RECV])
-    {
-        at_evt_cb_set[AT_SOCKET_EVT_RECV](socket, AT_SOCKET_EVT_RECV, recv_buf, bfsz);
-    }
-}
-
-static void urc_pdpdeact_func(const char *data, rt_size_t size)
-{
-    int connectID = 0;
-
-    RT_ASSERT(data && size);
-
-    sscanf(data, "+QIURC: \"pdpdeact\",%d", &connectID);
-
-    LOG_E("Context (%d) is deactivated.", connectID);
-}
-
-static void urc_dnsqip_func(const char *data, rt_size_t size)
-{
-    int i = 0, j = 0;
-    int result, ip_count, dns_ttl;
-
-    RT_ASSERT(data && size);
-
-    for (i = 0; i < size; i++)
-    {
-        if (*(data + i) == '.')
-            j++;
-    }
-    /* There would be several dns result, we just pickup one */
-    if (j == 3)
-    {
-        sscanf(data, "+QIURC: \"dnsgip\",\"%[^\"]", recv_ip);
-        recv_ip[15] = '\0';
-        at_socket_event_send(EC20_EVENT_DOMAIN_OK);
-    }
-    else
-    {
-        sscanf(data, "+QIURC: \"dnsgip\",%d,%d,%d", &result, &ip_count, &dns_ttl);
-        if (result)
-        {
-            at_tcp_ip_errcode_parse(result);
-        }
-    }
-}
-
-static void urc_func(const char *data, rt_size_t size)
-{
-    RT_ASSERT(data);
-
-    LOG_I("URC data : %.*s", size, data);
-}
-
-static void urc_qiurc_func(const char *data, rt_size_t size)
-{
-    RT_ASSERT(data && size);
-
-//    LOG_D("qiurc : %s", data);
-    switch(*(data+9))
-    {
-    case 'c' : urc_close_func(data, size); break;//+QIURC: "closed"
-    case 'r' : urc_recv_func(data, size); break;//+QIURC: "recv"
-    case 'p' : urc_pdpdeact_func(data, size); break;//+QIURC: "pdpdeact"
-    case 'd' : urc_dnsqip_func(data, size); break;//+QIURC: "dnsgip"
-    default  : urc_func(data, size);      break;//
-    }
-}
-
-static const struct at_urc urc_table[] = {
-        {"SEND OK",     "\r\n",                 urc_send_func},
-        {"SEND FAIL",   "\r\n",                 urc_send_func},
-        {"+QIOPEN:",    "\r\n",                 urc_connect_func},
-        {"+QIURC:",     "\r\n",                 urc_qiurc_func},
-};
-
-#define AT_SEND_CMD(resp, resp_line, timeout, cmd)                                                              \
-    do                                                                                                          \
-    {                                                                                                           \
-        if (at_exec_cmd(at_resp_set_info(resp, 128, resp_line, rt_tick_from_millisecond(timeout)), cmd) < 0)    \
-        {                                                                                                       \
-            result = -RT_ERROR;                                                                                 \
-            goto __exit;                                                                                        \
-        }                                                                                                       \
-    } while(0);                                                                                                 \
-
-static int ec20_netdev_set_info(struct netdev *netdev);
-static int ec20_netdev_check_link_status(struct netdev *netdev); 
-
-/* init for EC20 */
-static void ec20_init_thread_entry(void *parameter)
-{
-#define AT_RETRY                       10
-#define CIMI_RETRY                     10
-#define CSQ_RETRY                      20
-#define CREG_RETRY                     10
-#define CGREG_RETRY                    20
-
-    at_response_t resp = RT_NULL;
-    int i, qi_arg[3];
-    char parsed_data[20];
-    rt_err_t result = RT_EOK;
-
-    resp = at_create_resp(128, 0, rt_tick_from_millisecond(300));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-    LOG_D("Start initializing the EC20 module");
-    /* wait EC20 startup finish, Send AT every 500ms, if receive OK, SYNC success*/
-    if (at_client_wait_connect(EC20_WAIT_CONNECT_TIME))
-    {
-        result = -RT_ETIMEOUT;
-        goto __exit;
-    }
-    /* set response format to ATV1 */
-    AT_SEND_CMD(resp, 0, 300, "ATV1");
-    /* disable echo */
-    AT_SEND_CMD(resp, 0, 300, "ATE0");
-    /* Use AT+CMEE=2 to enable result code and use verbose values */
-    AT_SEND_CMD(resp, 0, 300, "AT+CMEE=2");
-    /* Get the baudrate */
-    AT_SEND_CMD(resp, 0, 300, "AT+IPR?");
-    at_resp_parse_line_args_by_kw(resp, "+IPR:", "+IPR: %d", &i);
-    LOG_D("Baudrate %d", i);
-    /* get module version */
-    AT_SEND_CMD(resp, 0, 300, "ATI");
-    /* show module version */
-    for (i = 0; i < (int) resp->line_counts - 1; i++)
-    {
-        LOG_D("%s", at_resp_get_line(resp, i + 1));
-    }
-    /* Use AT+GSN to query the IMEI of module */
-    AT_SEND_CMD(resp, 0, 300, "AT+GSN");
-    
-    /* check SIM card */
-    AT_SEND_CMD(resp, 2, 5 * 1000, "AT+CPIN?");
-    if (!at_resp_get_line_by_kw(resp, "READY"))
-    {
-        LOG_E("SIM card detection failed");
-        result = -RT_ERROR;
-        goto __exit;
-    }
-    /* waiting for dirty data to be digested */
-    rt_thread_mdelay(10);
-    
-    
-    /* Use AT+CIMI to query the IMSI of SIM card */
-//    AT_SEND_CMD(resp, 2, 300, "AT+CIMI");
-    i = 0;
-    while(at_exec_cmd(at_resp_set_info(resp, 128, 0, rt_tick_from_millisecond(300)), "AT+CIMI") < 0)
-    {
-        i++;
-        LOG_D("AT+CIMI %d", i);
-        if(i > CIMI_RETRY)
-        {
-            LOG_E("Read CIMI failed");
-            result = -RT_ERROR;
-            goto __exit;
-        }
-        rt_thread_mdelay(1000);
-    }
-
-    /* Use AT+QCCID to query ICCID number of SIM card */
-    AT_SEND_CMD(resp, 0, 300, "AT+QCCID");
-    /* check signal strength */
-    for (i = 0; i < CSQ_RETRY; i++)
-    {
-        AT_SEND_CMD(resp, 0, 300, "AT+CSQ");
-        at_resp_parse_line_args_by_kw(resp, "+CSQ:", "+CSQ: %d,%d", &qi_arg[0], &qi_arg[1]);
-        if (qi_arg[0] != 99)
-        {
-            LOG_D("Signal strength: %d  Channel bit error rate: %d", qi_arg[0], qi_arg[1]);
-            break;
-        }
-        rt_thread_mdelay(1000);
-    }
-    if (i == CSQ_RETRY)
-    {
-        LOG_E("Signal strength check failed (%s)", parsed_data);
-        result = -RT_ERROR;
-        goto __exit;
-    }
-    /* check the GSM network is registered */
-    for (i = 0; i < CREG_RETRY; i++)
-    {
-        AT_SEND_CMD(resp, 0, 300, "AT+CREG?");
-        at_resp_parse_line_args_by_kw(resp, "+CREG:", "+CREG: %s", &parsed_data);
-        if (!strncmp(parsed_data, "0,1", sizeof(parsed_data)) || !strncmp(parsed_data, "0,5", sizeof(parsed_data)))
-        {
-            LOG_D("GSM network is registered (%s)", parsed_data);
-            break;
-        }
-        rt_thread_mdelay(1000);
-    }
-    if (i == CREG_RETRY)
-    {
-        LOG_E("The GSM network is register failed (%s)", parsed_data);
-        result = -RT_ERROR;
-        goto __exit;
-    }
-    /* check the GPRS network is registered */
-    for (i = 0; i < CGREG_RETRY; i++)
-    {
-        AT_SEND_CMD(resp, 0, 300, "AT+CGREG?");
-        at_resp_parse_line_args_by_kw(resp, "+CGREG:", "+CGREG: %s", &parsed_data);
-        if (!strncmp(parsed_data, "0,1", sizeof(parsed_data)) || !strncmp(parsed_data, "0,5", sizeof(parsed_data)))
-        {
-            LOG_D("GPRS network is registered (%s)", parsed_data);
-            break;
-        }
-        rt_thread_mdelay(1000);
-    }
-    if (i == CGREG_RETRY)
-    {
-        LOG_E("The GPRS network is register failed (%s)", parsed_data);
-        result = -RT_ERROR;
-        goto __exit;
-    }
-    /*Use AT+CEREG? to query current EPS Network Registration Status*/
-    AT_SEND_CMD(resp, 0, 300, "AT+CEREG?");
-    /* Use AT+COPS? to query current Network Operator */
-    AT_SEND_CMD(resp, 0, 300, "AT+COPS?");
-    at_resp_parse_line_args_by_kw(resp, "+COPS:", "+COPS: %*[^\"]\"%[^\"]", &parsed_data);
-    if(strcmp(parsed_data,"CHINA MOBILE") == 0)
-    {
-        /* "CMCC" */
-        LOG_I("%s", parsed_data);
-        AT_SEND_CMD(resp, 0, 300, QICSGP_CHINA_MOBILE);
-    }
-    else if(strcmp(parsed_data,"CHN-UNICOM") == 0)
-    {
-        /* "UNICOM" */
-        LOG_I("%s", parsed_data);
-        AT_SEND_CMD(resp, 0, 300, QICSGP_CHINA_UNICOM);
-    }
-    else if(strcmp(parsed_data,"CHN-CT") == 0)
-    {
-        AT_SEND_CMD(resp, 0, 300, QICSGP_CHINA_TELECOM);
-        /* "CT" */
-        LOG_I("%s", parsed_data);
-    }
-    /* Enable automatic time zone update via NITZ and update LOCAL time to RTC */
-    AT_SEND_CMD(resp, 0, 300, "AT+CTZU=3");
-    /* Get RTC time */
-    AT_SEND_CMD(resp, 0, 300, "AT+CCLK?");
-
-    /* Deactivate context profile */
-    AT_SEND_CMD(resp, 0, 40 * 1000, "AT+QIDEACT=1");
-    /* Activate context profile */
-    AT_SEND_CMD(resp, 0, 150 * 1000, "AT+QIACT=1");
-    /* Query the status of the context profile */
-    AT_SEND_CMD(resp, 0, 150 * 1000, "AT+QIACT?");
-    at_resp_parse_line_args_by_kw(resp, "+QIACT:", "+QIACT: %*[^\"]\"%[^\"]", &parsed_data);
-    LOG_I("%s", parsed_data);
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    if (!result)
-    {
-        /* set network interface device status and address information */
-        ec20_netdev_set_info(netdev_get_by_name(EC20_NETDEV_NAME));
-        ec20_netdev_check_link_status(netdev_get_by_name(EC20_NETDEV_NAME));
-
-        LOG_I("AT network initialize success!");
-    }
-    else
-    {
-        LOG_E("AT network initialize failed (%d)!", result);
-    }
-
-}
-
-/* EC20 device network initialize */
-void ec20_net_init(void)
-{
-#ifdef PKG_AT_INIT_BY_THREAD
-    rt_thread_t tid;
-    tid = rt_thread_create("ec20_net_init", ec20_init_thread_entry, RT_NULL, EC20_THREAD_STACK_SIZE, EC20_THREAD_PRIORITY, 20);
-    if (tid)
-    {
-        rt_thread_startup(tid);
-    }
-    else
-    {
-        LOG_E("Create AT initialization thread failed!");
-    }
-#else
-    ec20_init_thread_entry(RT_NULL);
-#endif
-}
-
-#ifdef FINSH_USING_MSH
-#include <finsh.h>
-MSH_CMD_EXPORT_ALIAS(ec20_net_init, at_net_init, initialize AT network);
-#endif
-
-static const struct at_device_ops ec20_socket_ops = {
-    ec20_socket_connect,
-    ec20_socket_close,
-    ec20_socket_send,
-    ec20_domain_resolve,
-    ec20_socket_set_event_cb,
-};
-
-/* set ec20 network interface device status and address information */
-static int ec20_netdev_set_info(struct netdev *netdev)
-{
-#define EC20_IEMI_RESP_SIZE      32
-#define EC20_IPADDR_RESP_SIZE    64
-#define EC20_DNS_RESP_SIZE       96
-#define EC20_INFO_RESP_TIMO      rt_tick_from_millisecond(300)
-
-    int result = RT_EOK;
-    at_response_t resp = RT_NULL;
-    ip_addr_t addr;
-
-    if (netdev == RT_NULL)
-    {
-        LOG_E("Input network interface device is NULL.\n");
-        return -RT_ERROR;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    /* set network interface device status */
-    netdev_low_level_set_status(netdev, RT_TRUE);
-    netdev_low_level_set_link_status(netdev, RT_TRUE);
-    netdev_low_level_set_dhcp_status(netdev, RT_TRUE);
-
-    resp = at_create_resp(EC20_IEMI_RESP_SIZE, 0, EC20_INFO_RESP_TIMO);
-    if (resp == RT_NULL)
-    {
-        LOG_E("EC20 set netdev information failed, no memory for response object.");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-
-    /* set network interface device hardware address(IEMI) */
-    {
-        #define EC20_NETDEV_HWADDR_LEN   8
-        #define EC20_IEMI_LEN            15
-
-        char iemi[EC20_IEMI_LEN] = {0};
-        int i = 0, j = 0;
-
-        /* send "AT+GSN" commond to get device IEMI */
-        if (at_exec_cmd(resp, "AT+GSN") < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        if (at_resp_parse_line_args(resp, 2, "%s", iemi) <= 0)
-        {
-            LOG_E("Prase \"AT+GSN\" commands resposne data error!");
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        LOG_D("EC20 IEMI number: %s", iemi);
-
-        netdev->hwaddr_len = EC20_NETDEV_HWADDR_LEN;
-        /* get hardware address by IEMI */
-        for (i = 0, j = 0; i < EC20_NETDEV_HWADDR_LEN && j < EC20_IEMI_LEN; i++, j+=2)
-        {
-            if (j != EC20_IEMI_LEN - 1)
-            {
-                netdev->hwaddr[i] = (iemi[j] - '0') * 10 + (iemi[j + 1] - '0');
-            }
-            else
-            {
-                netdev->hwaddr[i] = (iemi[j] - '0');
-            }
-        }
-    }
-
-    /* set network interface device IP address */
-    {
-        #define IP_ADDR_SIZE_MAX    16
-        char ipaddr[IP_ADDR_SIZE_MAX] = {0};
-        
-        at_resp_set_info(resp, EC20_IPADDR_RESP_SIZE, 0, EC20_INFO_RESP_TIMO);
-
-        /* send "AT+QIACT?" commond to get IP address */
-        if (at_exec_cmd(resp, "AT+QIACT?") < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* parse response data "+QIACT: 1,<context_state>,<context_type>[,<IP_address>]" */
-        if (at_resp_parse_line_args_by_kw(resp, "+QIACT:", "+QIACT: %*[^\"]\"%[^\"]", ipaddr) <= 0)
-        {
-            LOG_E("Prase \"AT+QIACT?\" commands resposne data error!");
-            result = -RT_ERROR;
-            goto __exit;
-        }
-        
-        LOG_D("EC20 IP address: %s", ipaddr);
-
-        /* set network interface address information */
-        inet_aton(ipaddr, &addr);
-        netdev_low_level_set_ipaddr(netdev, &addr);
-    }
-
-    /* set network interface device dns server */
-    {
-        #define DNS_ADDR_SIZE_MAX   16
-        char dns_server1[DNS_ADDR_SIZE_MAX] = {0}, dns_server2[DNS_ADDR_SIZE_MAX] = {0};
-
-        at_resp_set_info(resp, EC20_DNS_RESP_SIZE, 0, EC20_INFO_RESP_TIMO);
-
-        /* send "AT+QIDNSCFG=1" commond to get DNS servers address */
-        if (at_exec_cmd(resp, "AT+QIDNSCFG=1") < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* parse response data "+QIDNSCFG: <contextID>,<pridnsaddr>,<secdnsaddr>" */
-        if (at_resp_parse_line_args_by_kw(resp, "+QIDNSCFG:", "+QIDNSCFG: 1,\"%[^\"]\",\"%[^\"]\"", 
-                dns_server1, dns_server2) <= 0)
-        {
-            LOG_E("Prase \"AT+QIDNSCFG=1\" commands resposne data error!");
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        LOG_D("EC20 primary DNS server address: %s", dns_server1);
-        LOG_D("EC20 secondary DNS server address: %s", dns_server2);
-
-        inet_aton(dns_server1, &addr);
-        netdev_low_level_set_dns_server(netdev, 0, &addr);
-
-        inet_aton(dns_server2, &addr);
-        netdev_low_level_set_dns_server(netdev, 1, &addr);
-    }
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    rt_mutex_release(at_event_lock);
-    
-    return result;
-}
-
-static void ec20_check_link_status_entry(void *parameter)
-{
-#define EC20_LINK_RESP_SIZE     64
-#define EC20_LINK_RESP_TIMO     (3 * RT_TICK_PER_SECOND)
-#define EC20_LINK_DELAY_TIME    (30 * RT_TICK_PER_SECOND)
-
-    int link_stat = 0;
-    at_response_t resp = RT_NULL;
-    struct netdev *netdev = (struct netdev *) parameter;
-    
-    resp = at_create_resp(EC20_LINK_RESP_SIZE, 0, EC20_LINK_RESP_TIMO);
-    if (resp == RT_NULL)
-    {
-        LOG_E("EC20 set check link status failed, no memory for response object.");
-        return;
-    }
-
-    while (1)
-    {
-        rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-        /* send "AT+CGREG" commond  to check netweork interface device link status */
-        if (at_exec_cmd(resp, "AT+CGREG?") < 0)
-        {
-            if (netdev_is_link_up(netdev))
-            {
-                netdev_low_level_set_link_status(netdev, RT_FALSE);
-            }
-            
-            rt_mutex_release(at_event_lock);
-            rt_thread_mdelay(EC20_LINK_DELAY_TIME);
-            continue;
-        }
-        else
-        {
-            at_resp_parse_line_args_by_kw(resp, "+CGREG:", "+CGREG: %*d,%d", &link_stat);
-
-            /* 1 Registered, home network,5 Registered, roaming */
-            if (link_stat == 1 || link_stat == 5)
-            {
-                if (netdev_is_link_up(netdev) == RT_FALSE)
-                {
-                    netdev_low_level_set_link_status(netdev, RT_TRUE);
-                }
-            }
-            else
-            {
-                if (netdev_is_link_up(netdev))
-                {
-                    netdev_low_level_set_link_status(netdev, RT_FALSE);
-                }
-            }
-        }
-
-        rt_mutex_release(at_event_lock);
-        rt_thread_mdelay(EC20_LINK_DELAY_TIME);
-    }
-}
-
-static int ec20_netdev_check_link_status(struct netdev *netdev)
-{
-#define EC20_LINK_THREAD_STACK_SIZE     1024
-#define EC20_LINK_THREAD_PRIORITY       (RT_THREAD_PRIORITY_MAX - 2)
-#define EC20_LINK_THREAD_TICK           20
-
-    rt_thread_t tid;
-
-    if (netdev == RT_NULL)
-    {
-        LOG_E("Input network interface device is NULL.\n");
-        return -RT_ERROR;
-    }
-
-    /* create WIZnet link status Polling thread  */
-    tid = rt_thread_create("ec20_link", ec20_check_link_status_entry, (void *) netdev, 
-            EC20_LINK_THREAD_STACK_SIZE, EC20_LINK_THREAD_PRIORITY, EC20_LINK_THREAD_TICK);
-    if (tid != RT_NULL)
-    {
-        rt_thread_startup(tid);
-    }
-
-    return RT_EOK;
-}
-
-static int ec20_netdev_set_up(struct netdev *netdev)
-{
-    netdev_low_level_set_status(netdev, RT_TRUE);
-    LOG_D("EC20 network interface set up status.");
-    return RT_EOK;
-}
-
-static int ec20_netdev_set_down(struct netdev *netdev)
-{
-    netdev_low_level_set_status(netdev, RT_FALSE);
-    LOG_D("EC20 network interface set down status.");
-    return RT_EOK;
-}
-
-static int ec20_netdev_set_dns_server(struct netdev *netdev, uint8_t dns_num, ip_addr_t *dns_server)
-{
-#define EC20_DNS_RESP_LEN    8
-#define EC20_DNS_RESP_TIMEO  rt_tick_from_millisecond(300)
-
-    at_response_t resp = RT_NULL;
-    int result = RT_EOK;
-
-    RT_ASSERT(netdev);
-    RT_ASSERT(dns_server);
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-    
-    resp = at_create_resp(EC20_DNS_RESP_LEN, 0, EC20_DNS_RESP_TIMEO);
-    if (resp == RT_NULL)
-    {
-        LOG_D("EC20 set dns server failed, no memory for response object.");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-
-    /* send "AT+QIDNSCFG=<pri_dns>[,<sec_dns>]" commond to set dns servers */
-    if (at_exec_cmd(resp, "AT+QIDNSCFG=1,\"%s\"", inet_ntoa(*dns_server)) < 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    netdev_low_level_set_dns_server(netdev, dns_num, dns_server);
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-    
-    rt_mutex_release(at_event_lock);
-    
-    return result;
-}
-
-static int ec20_netdev_ping(struct netdev *netdev, const char *host, size_t data_len, uint32_t timeout, struct netdev_ping_resp *ping_resp)
-{
-#define EC20_PING_RESP_SIZE       128
-#define EC20_PING_IP_SIZE         16
-#define EC20_PING_TIMEO           (5 * RT_TICK_PER_SECOND)
-
-    at_response_t resp = RT_NULL;
-    rt_err_t result = RT_EOK;
-    int response = -1, recv_data_len, ping_time, ttl;
-    char ip_addr[EC20_PING_IP_SIZE] = {0};
-
-    RT_ASSERT(netdev);
-    RT_ASSERT(host);
-    RT_ASSERT(ping_resp);
-    
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    resp = at_create_resp(EC20_PING_RESP_SIZE, 4, EC20_PING_TIMEO);
-    if (resp == RT_NULL)
-    {
-        LOG_D("No memory for response structure!\n");
-        return -RT_ENOMEM;
-    }
-
-    /* send "AT+QPING="<host>"[,[<timeout>][,<pingnum>]]" commond to send ping request */
-    if (at_exec_cmd(resp, "AT+QPING=1,\"%s\",%d,1", host, timeout / RT_TICK_PER_SECOND) < 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    at_resp_parse_line_args_by_kw(resp, "+QPING:", "+QPING:%d", &response);
-    /* Received the ping response from the server */
-    if (response == 0)
-    {
-        if (at_resp_parse_line_args_by_kw(resp, "+QPING:", "+QPING:%d,\"%[^\"]\",%d,%d,%d",
-                    &response, ip_addr, &recv_data_len, &ping_time, &ttl) <= 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-    }
-
-    /* prase response number */
-    switch (response)
-    {
-    case 0:
-        inet_aton(ip_addr, &(ping_resp->ip_addr));
-        ping_resp->data_len = recv_data_len;
-        ping_resp->ticks = ping_time;
-        ping_resp->ttl = ttl;
-        result = RT_EOK;
-        break;
-    case 569:
-        result = -RT_ETIMEOUT;
-        break;
-    default:
-        result = -RT_ERROR;
-        break;
-    }
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    rt_mutex_release(at_event_lock);
-    
-    return result;
-}
-
-void ec20_netdev_netstat(struct netdev *netdev)
-{
-    // TODO
-    return;
-}
-
-const struct netdev_ops ec20_netdev_ops =
-{
-    ec20_netdev_set_up,
-    ec20_netdev_set_down,
-
-    RT_NULL,
-    ec20_netdev_set_dns_server,
-    RT_NULL,
-
-    ec20_netdev_ping,
-    ec20_netdev_netstat,
-};
-
-static int ec20_netdev_add(const char *netdev_name)
-{
-#define ETHERNET_MTU        1500
-#define HWADDR_LEN          6
-    struct netdev *netdev = RT_NULL;
-
-    netdev = (struct netdev *)rt_calloc(1, sizeof(struct netdev));
-    if (netdev == RT_NULL)
-    {
-        return RT_NULL;
-    }
-
-    netdev->mtu = ETHERNET_MTU;
-    netdev->ops = &ec20_netdev_ops;
-    netdev->hwaddr_len = HWADDR_LEN;
-
-#ifdef SAL_USING_AT
-    extern int sal_at_netdev_set_pf_info(struct netdev *netdev);
-    /* set the network interface socket/netdb operations */
-    sal_at_netdev_set_pf_info(netdev);
-#endif
-
-    return netdev_register(netdev, netdev_name, RT_NULL);
-}
-
-static int at_socket_device_init(void)
-{  
-    /* create current AT socket event */
-    at_socket_event = rt_event_create("at_se", RT_IPC_FLAG_FIFO);
-    if (!at_socket_event)
-    {
-        LOG_E("AT client port initialize failed! at_sock_event create failed!");
-        return -RT_ENOMEM;
-    }
-
-    /* create current AT socket lock */
-    at_event_lock = rt_mutex_create("at_se", RT_IPC_FLAG_FIFO);
-    if (!at_event_lock)
-    {
-        LOG_E("AT client port initialize failed! at_sock_lock create failed!");
-        rt_event_delete(at_socket_event);
-        return -RT_ENOMEM;
-    }
-
-    /* initialize AT client */
-    at_client_init(AT_DEVICE_NAME, AT_DEVICE_RECV_BUFF_LEN);
-    
-    /* register URC data execution function  */
-    at_set_urc_table(urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
-
-    /* Add ec20 network inetrface device to the netdev list */
-    if (ec20_netdev_add(EC20_NETDEV_NAME) < 0)
-    {
-        LOG_E("EC20 network interface device(%d) add failed.", EC20_NETDEV_NAME);
-        return -RT_ENOMEM;
-    }
-
-    /* initialize EC20 network */
-    ec20_net_init();
-
-    /* set EC20 AT Socket options */
-    at_socket_device_register(&ec20_socket_ops);
-
-    return RT_EOK;
-}
-INIT_APP_EXPORT(at_socket_device_init);
-
-#endif /* AT_DEVICE_EC20 */

+ 0 - 1169
at_socket_esp8266.c

@@ -1,1169 +0,0 @@
-/*
- * File      : at_socket_esp8266.c
- * This file is part of RT-Thread RTOS
- * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Change Logs:
- * Date           Author       Notes
- * 2018-06-20     chenyong     first version
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include <rtthread.h>
-#include <sys/socket.h>
-
-#include <at.h>
-#include <at_socket.h>
-
-#if !defined(RT_USING_NETDEV)
-#error "This RT-Thread version is older, please check and updata laster RT-Thread!"
-#else
-#include <arpa/inet.h>
-#include <netdev.h>
-#endif /* RT_USING_NETDEV */
-
-#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10200
-#error "This AT Client version is older, please check and update latest AT Client!"
-#endif
-
-#define LOG_TAG              "at.esp8266"
-#include <at_log.h>
-
-#ifdef AT_DEVICE_ESP8266
-
-#define ESP8266_MODULE_SEND_MAX_SIZE   2048
-#define ESP8266_WAIT_CONNECT_TIME      5000
-#define ESP8266_THREAD_STACK_SIZE      1024
-#define ESP8266_THREAD_PRIORITY        (RT_THREAD_PRIORITY_MAX/2)
-
-/* set real event by current socket and current state */
-#define SET_EVENT(socket, event)       (((socket + 1) << 16) | (event))
-
-/* AT socket event type */
-#define ESP8266_EVENT_CONN_OK          (1L << 0)
-#define ESP8266_EVENT_SEND_OK          (1L << 1)
-#define ESP8266_EVENT_RECV_OK          (1L << 2)
-#define ESP8266_EVNET_CLOSE_OK         (1L << 3)
-#define ESP8266_EVENT_CONN_FAIL        (1L << 4)
-#define ESP8266_EVENT_SEND_FAIL        (1L << 5)
-
-#define ESP8266_NETDEV_NAME            "esp8266"
-
-static int cur_socket;
-static int cur_send_bfsz;
-static struct rt_delayed_work esp8266_net_work;
-static rt_event_t at_socket_event;
-static rt_mutex_t at_event_lock;
-static at_evt_cb_t at_evt_cb_set[] = {
-        [AT_SOCKET_EVT_RECV] = NULL,
-        [AT_SOCKET_EVT_CLOSED] = NULL,
-};
-
-static int at_socket_event_send(uint32_t event)
-{
-    return (int) rt_event_send(at_socket_event, event);
-}
-
-static int at_socket_event_recv(uint32_t event, uint32_t timeout, rt_uint8_t option)
-{
-    int result = 0;
-    rt_uint32_t recved;
-
-    result = rt_event_recv(at_socket_event, event, option | RT_EVENT_FLAG_CLEAR, timeout, &recved);
-    if (result != RT_EOK)
-    {
-        return -RT_ETIMEOUT;
-    }
-
-    return recved;
-}
-
-/**
- * close socket by AT commands.
- *
- * @param current socket
- *
- * @return  0: close socket success
- *         -1: send AT commands error
- *         -2: wait socket event timeout
- *         -5: no memory
- */
-static int esp8266_socket_close(int socket)
-{
-    at_response_t resp = RT_NULL;
-    int result = RT_EOK;
-
-    resp = at_create_resp(64, 0, rt_tick_from_millisecond(5000));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    if (at_exec_cmd(resp, "AT+CIPCLOSE=%d", socket) < 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-__exit:
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-/**
- * create TCP/UDP client or server connect by AT commands.
- *
- * @param socket current socket
- * @param ip server or client IP address
- * @param port server or client port
- * @param type connect socket type(tcp, udp)
- * @param is_client connection is client
- *
- * @return   0: connect success
- *          -1: connect failed, send commands error or type error
- *          -2: wait socket event timeout
- *          -5: no memory
- */
-static int esp8266_socket_connect(int socket, char *ip, int32_t port, enum at_socket_type type, rt_bool_t is_client)
-{
-    at_response_t resp = RT_NULL;
-    int result = RT_EOK;
-    rt_bool_t retryed = RT_FALSE;
-
-    RT_ASSERT(ip);
-    RT_ASSERT(port >= 0);
-
-    resp = at_create_resp(128, 0, rt_tick_from_millisecond(5000));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-__retry:
-    if (is_client)
-    {
-        switch (type)
-        {
-        case AT_SOCKET_TCP:
-            /* send AT commands to connect TCP server */
-            if (at_exec_cmd(resp, "AT+CIPSTART=%d,\"TCP\",\"%s\",%d,60", socket, ip, port) < 0)
-            {
-                result = -RT_ERROR;
-            }
-            break;
-
-        case AT_SOCKET_UDP:
-            if (at_exec_cmd(resp, "AT+CIPSTART=%d,\"UDP\",\"%s\",%d", socket, ip, port) < 0)
-            {
-                result = -RT_ERROR;
-            }
-            break;
-
-        default:
-            LOG_E("Not supported connect type : %d.", type);
-            result = -RT_ERROR;
-            goto __exit;
-        }
-    }
-
-    if (result != RT_EOK && !retryed)
-    {
-        LOG_D("socket (%d) connect failed, maybe the socket was not be closed at the last time and now will retry.", socket);
-        if (esp8266_socket_close(socket) < 0)
-        {
-            goto __exit;
-        }
-        retryed = RT_TRUE;
-        result = RT_EOK;
-        goto __retry;
-    }
-
-__exit:
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-/**
- * send data to server or client by AT commands.
- *
- * @param socket current socket
- * @param buff send buffer
- * @param bfsz send buffer size
- * @param type connect socket type(tcp, udp)
- *
- * @return >=0: the size of send success
- *          -1: send AT commands error or send data error
- *          -2: waited socket event timeout
- *          -5: no memory
- */
-static int esp8266_socket_send(int socket, const char *buff, size_t bfsz, enum at_socket_type type)
-{
-    int result = RT_EOK;
-    int event_result = 0;
-    at_response_t resp = RT_NULL;
-    size_t cur_pkt_size = 0, sent_size = 0;
-
-    RT_ASSERT(buff);
-    RT_ASSERT(bfsz > 0);
-
-    resp = at_create_resp(128, 2, rt_tick_from_millisecond(5000));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    /* set current socket for send URC event */
-    cur_socket = socket;
-    /* set AT client end sign to deal with '>' sign.*/
-    at_set_end_sign('>');
-
-    while (sent_size < bfsz)
-    {
-        if (bfsz - sent_size < ESP8266_MODULE_SEND_MAX_SIZE)
-        {
-            cur_pkt_size = bfsz - sent_size;
-        }
-        else
-        {
-            cur_pkt_size = ESP8266_MODULE_SEND_MAX_SIZE;
-        }
-
-        /* send the "AT+CIPSEND" commands to AT server than receive the '>' response on the first line. */
-        if (at_exec_cmd(resp, "AT+CIPSEND=%d,%d", socket, cur_pkt_size) < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* send the real data to server or client */
-        result = (int) at_client_send(buff + sent_size, cur_pkt_size);
-        if (result == 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* waiting result event from AT URC */
-        if (at_socket_event_recv(SET_EVENT(socket, 0), rt_tick_from_millisecond(5 * 1000), RT_EVENT_FLAG_OR) < 0)
-        {
-            LOG_E("socket (%d) send failed, wait connect result timeout.", socket);
-            result = -RT_ETIMEOUT;
-            goto __exit;
-        }
-        /* waiting OK or failed result */
-        if ((event_result = at_socket_event_recv(ESP8266_EVENT_SEND_OK | ESP8266_EVENT_SEND_FAIL, rt_tick_from_millisecond(5 * 1000),
-                RT_EVENT_FLAG_OR)) < 0)
-        {
-            LOG_E("socket (%d) send failed, wait connect OK|FAIL timeout.", socket);
-            result = -RT_ETIMEOUT;
-            goto __exit;
-        }
-        /* check result */
-        if (event_result & ESP8266_EVENT_SEND_FAIL)
-        {
-            LOG_E("socket (%d) send failed, return failed.", socket);
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        if (type == AT_SOCKET_TCP)
-        {
-            cur_pkt_size = cur_send_bfsz;
-        }
-
-        sent_size += cur_pkt_size;
-    }
-
-__exit:
-    /* reset the end sign for data */
-    at_set_end_sign(0);
-
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-/**
- * domain resolve by AT commands.
- *
- * @param name domain name
- * @param ip parsed IP address, it's length must be 16
- *
- * @return  0: domain resolve success
- *         -2: wait socket event timeout
- *         -5: no memory
- */
-static int esp8266_domain_resolve(const char *name, char ip[16])
-{
-#define RESOLVE_RETRY        5
-
-    int i, result = RT_EOK;
-    char recv_ip[16] = { 0 };
-    at_response_t resp = RT_NULL;
-
-    RT_ASSERT(name);
-    RT_ASSERT(ip);
-
-    resp = at_create_resp(128, 0, rt_tick_from_millisecond(20000));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    for (i = 0; i < RESOLVE_RETRY; i++)
-    {
-        if (at_exec_cmd(resp, "AT+CIPDOMAIN=\"%s\"", name) < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* parse the third line of response data, get the IP address */
-        if (at_resp_parse_line_args_by_kw(resp, "+CIPDOMAIN:", "+CIPDOMAIN:%s", recv_ip) < 0)
-        {
-            rt_thread_delay(rt_tick_from_millisecond(100));
-            /* resolve failed, maybe receive an URC CRLF */
-            continue;
-        }
-
-        if (strlen(recv_ip) < 8)
-        {
-            rt_thread_delay(rt_tick_from_millisecond(100));
-            /* resolve failed, maybe receive an URC CRLF */
-            continue;
-        }
-        else
-        {
-            strncpy(ip, recv_ip, 15);
-            ip[15] = '\0';
-            break;
-        }
-    }
-
-__exit:
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-
-}
-
-/**
- * set AT socket event notice callback
- *
- * @param event notice event
- * @param cb notice callback
- */
-static void esp8266_socket_set_event_cb(at_socket_evt_t event, at_evt_cb_t cb)
-{
-    if (event < sizeof(at_evt_cb_set) / sizeof(at_evt_cb_set[1]))
-    {
-        at_evt_cb_set[event] = cb;
-    }
-}
-
-static void urc_send_func(const char *data, rt_size_t size)
-{
-    RT_ASSERT(data && size);
-
-    if (strstr(data, "SEND OK"))
-    {
-        at_socket_event_send(SET_EVENT(cur_socket, ESP8266_EVENT_SEND_OK));
-    }
-    else if (strstr(data, "SEND FAIL"))
-    {
-        at_socket_event_send(SET_EVENT(cur_socket, ESP8266_EVENT_SEND_FAIL));
-    }
-}
-
-static void urc_send_bfsz_func(const char *data, rt_size_t size)
-{
-    int send_bfsz = 0;
-
-    RT_ASSERT(data && size);
-
-    sscanf(data, "Recv %d bytes", &send_bfsz);
-
-    cur_send_bfsz = send_bfsz;
-}
-
-static void urc_close_func(const char *data, rt_size_t size)
-{
-    int socket = 0;
-
-    RT_ASSERT(data && size);
-
-    sscanf(data, "%d,CLOSED", &socket);
-    /* notice the socket is disconnect by remote */
-    if (at_evt_cb_set[AT_SOCKET_EVT_CLOSED])
-    {
-        at_evt_cb_set[AT_SOCKET_EVT_CLOSED](socket, AT_SOCKET_EVT_CLOSED, RT_NULL, 0);
-    }
-}
-
-static void urc_recv_func(const char *data, rt_size_t size)
-{
-    int socket = 0;
-    rt_size_t bfsz = 0, temp_size = 0;
-    rt_int32_t timeout;
-    char *recv_buf = RT_NULL, temp[8];
-
-    RT_ASSERT(data && size);
-
-    /* get the current socket and receive buffer size by receive data */
-    sscanf(data, "+IPD,%d,%d:", &socket, (int *) &bfsz);
-    /* get receive timeout by receive buffer length */
-    timeout = bfsz;
-
-    if (socket < 0 || bfsz == 0)
-        return;
-
-    recv_buf = rt_calloc(1, bfsz);
-    if (!recv_buf)
-    {
-        LOG_E("no memory for URC receive buffer (%d)!", bfsz);
-        /* read and clean the coming data */
-        while (temp_size < bfsz)
-        {
-            if (bfsz - temp_size > sizeof(temp))
-            {
-                at_client_recv(temp, sizeof(temp), timeout);
-            }
-            else
-            {
-                at_client_recv(temp, bfsz - temp_size, timeout);
-            }
-            temp_size += sizeof(temp);
-        }
-        return;
-    }
-
-    /* sync receive data */
-    if (at_client_recv(recv_buf, bfsz, timeout) != bfsz)
-    {
-        LOG_E("receive size(%d) data failed!", bfsz);
-        rt_free(recv_buf);
-        return;
-    }
-
-    /* notice the receive buffer and buffer size */
-    if (at_evt_cb_set[AT_SOCKET_EVT_RECV])
-    {
-        at_evt_cb_set[AT_SOCKET_EVT_RECV](socket, AT_SOCKET_EVT_RECV, recv_buf, bfsz);
-    }
-}
-
-static void urc_busy_p_func(const char *data, rt_size_t size)
-{
-    RT_ASSERT(data && size);
-
-    LOG_D("system is processing a commands and it cannot respond to the current commands.");
-}
-
-static void urc_busy_s_func(const char *data, rt_size_t size)
-{
-    RT_ASSERT(data && size);
-
-    LOG_D("system is sending data and it cannot respond to the current commands.");
-}
-
-static void urc_func(const char *data, rt_size_t size)
-{
-    RT_ASSERT(data && size);
-
-    if (strstr(data, "WIFI CONNECTED"))
-    {
-        netdev_low_level_set_link_status(netdev_get_by_name(ESP8266_NETDEV_NAME), RT_TRUE);
-        rt_work_submit(&(esp8266_net_work.work), RT_TICK_PER_SECOND);
-        LOG_I("ESP8266 WIFI is connected.");
-    }
-    else if (strstr(data, "WIFI DISCONNECT"))
-    {
-        netdev_low_level_set_link_status(netdev_get_by_name(ESP8266_NETDEV_NAME), RT_FALSE);
-        LOG_I("ESP8266 WIFI is disconnect.");
-    }
-}
-
-static struct at_urc urc_table[] = {
-        {"SEND OK",          "\r\n",           urc_send_func},
-        {"SEND FAIL",        "\r\n",           urc_send_func},
-        {"Recv",             "bytes\r\n",      urc_send_bfsz_func},
-        {"",                 ",CLOSED\r\n",    urc_close_func},
-        {"+IPD",             ":",              urc_recv_func},
-        {"busy p",           "\r\n",           urc_busy_p_func},
-        {"busy s",           "\r\n",           urc_busy_s_func},
-        {"WIFI CONNECTED",   "\r\n",           urc_func},
-        {"WIFI DISCONNECT",  "\r\n",           urc_func},
-};
-
-#define AT_SEND_CMD(resp, cmd)                                                                          \
-    do                                                                                                  \
-    {                                                                                                   \
-        if (at_exec_cmd(at_resp_set_info(resp, 256, 0, rt_tick_from_millisecond(5000)), cmd) < 0)       \
-        {                                                                                               \
-            LOG_E("RT AT send commands(%s) error!", cmd);                                               \
-            result = -RT_ERROR;                                                                         \
-            goto __exit;                                                                                \
-        }                                                                                               \
-    } while(0);                                                                                         \
-
-static void exp8266_get_netdev_info(struct rt_work *work, void *work_data)
-{
-#define AT_ADDR_LEN     32
-    at_response_t resp = RT_NULL;
-    char ip[AT_ADDR_LEN], mac[AT_ADDR_LEN];
-    char gateway[AT_ADDR_LEN], netmask[AT_ADDR_LEN];
-    char dns_server1[AT_ADDR_LEN] = {0}, dns_server2[AT_ADDR_LEN] = {0};
-    const char *resp_expr = "%*[^\"]\"%[^\"]\"";
-    const char *resp_dns = "+CIPDNS_CUR:%s";
-    ip_addr_t sal_ip_addr;
-    rt_uint32_t mac_addr[6] = {0};
-    rt_uint32_t num = 0; 
-    rt_uint8_t dhcp_stat = 0;
-    struct netdev *netdev = RT_NULL;
-
-    netdev = (struct netdev *)work_data;
-
-    rt_memset(ip, 0x00, sizeof(ip));
-    rt_memset(mac, 0x00, sizeof(mac));
-    rt_memset(gateway, 0x00, sizeof(gateway));
-    rt_memset(netmask, 0x00, sizeof(netmask));
-
-    resp = at_create_resp(512, 0, rt_tick_from_millisecond(300));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-    /* send mac addr query commond "AT+CIFSR" and wait response */
-    if (at_exec_cmd(resp, "AT+CIFSR") < 0)
-    {
-        LOG_E("AT send \"AT+CIFSR\" commands error!");
-        goto __exit;
-    }
-
-    if (at_resp_parse_line_args(resp, 2, resp_expr, mac) <= 0)
-    {
-        LOG_E("Parse error, current line buff : %s", at_resp_get_line(resp, 2));
-        goto __exit;
-    }
-
-    /* send addr info query commond "AT+CIPSTA?" and wait response */
-    if (at_exec_cmd(resp, "AT+CIPSTA?") < 0)
-    {
-        LOG_E("AT send \"AT+CIPSTA?\" commands error!");
-        goto __exit;
-    }
-
-    if (at_resp_parse_line_args(resp, 1, resp_expr, ip) <= 0 ||
-            at_resp_parse_line_args(resp, 2, resp_expr, gateway) <= 0 ||
-            at_resp_parse_line_args(resp, 3, resp_expr, netmask) <= 0)
-    {
-        LOG_E("Prase \"AT+CIPSTA?\" commands resposne data error!");
-        goto __exit;
-    }
-
-    /* set netdev info */
-    inet_aton(ip, &sal_ip_addr);
-    netdev_low_level_set_ipaddr(netdev, &sal_ip_addr);
-    inet_aton(gateway, &sal_ip_addr);
-    netdev_low_level_set_gw(netdev, &sal_ip_addr);
-    inet_aton(netmask, &sal_ip_addr);
-    netdev_low_level_set_netmask(netdev, &sal_ip_addr);
-    sscanf(mac, "%x:%x:%x:%x:%x:%x", &mac_addr[0], &mac_addr[1], &mac_addr[2], &mac_addr[3], &mac_addr[4], &mac_addr[5]);
-    for (num = 0; num < netdev->hwaddr_len; num++)
-    {
-        netdev->hwaddr[num] = mac_addr[num];
-    }
-
-    /* send dns server query commond "AT+CIPDNS_CUR?" and wait response */
-    if (at_exec_cmd(resp, "AT+CIPDNS_CUR?") < 0)
-    {
-        LOG_W("Get dns server failed! Please check and update your firmware to support the \"AT+CIPDNS_CUR?\" command.");
-        goto __exit;
-    }
-
-    if (at_resp_parse_line_args(resp, 1, resp_dns, dns_server1) <= 0 &&
-            at_resp_parse_line_args(resp, 2, resp_dns, dns_server2) <= 0)
-    {
-        LOG_E("Prase \"AT+CIPDNS_CUR?\" commands resposne data error!");
-        goto __exit;
-    }
-
-    if (strlen(dns_server1) > 0)
-    {
-        inet_aton(dns_server1, &sal_ip_addr);
-        netdev_low_level_set_dns_server(netdev, 0, &sal_ip_addr);
-    }
-
-    if (strlen(dns_server2) > 0)
-    {
-        inet_aton(dns_server2, &sal_ip_addr);
-        netdev_low_level_set_dns_server(netdev, 1, &sal_ip_addr);
-    }
-
-    /* send DHCP query commond " AT+CWDHCP_CUR?" and wait response */
-    if (at_exec_cmd(resp, "AT+CWDHCP_CUR?") < 0)
-    {
-        LOG_E("AT send \"AT+CWDHCP_CUR?\" commands error!");
-        goto __exit;
-    }
-
-    /* parse response data, get the DHCP status */
-    if (at_resp_parse_line_args_by_kw(resp, "+CWDHCP_CUR:", "+CWDHCP_CUR:%d", &dhcp_stat) < 0)
-    {
-        LOG_E("get DHCP status failed!");
-        goto __exit;
-    }
-
-    /* Bit0 - SoftAP DHCP status, Bit1 - Station DHCP status */
-    if (dhcp_stat & 0x02)
-    {
-        netdev_low_level_set_dhcp_status(netdev, RT_TRUE);
-    }
-    else
-    {
-        netdev_low_level_set_dhcp_status(netdev, RT_FALSE);
-    }
-
-__exit:
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-}
-
-static void esp8266_init_thread_entry(void *parameter)
-{
-    at_response_t resp = RT_NULL;
-    rt_err_t result = RT_EOK;
-    rt_size_t i;
-
-    resp = at_create_resp(128, 0, rt_tick_from_millisecond(5000));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-
-    rt_thread_delay(rt_tick_from_millisecond(5000));
-    /* reset module */
-    AT_SEND_CMD(resp, "AT+RST");
-    /* reset waiting delay */
-    rt_thread_delay(rt_tick_from_millisecond(1000));
-    /* disable echo */
-    AT_SEND_CMD(resp, "ATE0");
-    /* set current mode to Wi-Fi station */
-    AT_SEND_CMD(resp, "AT+CWMODE=1");
-    /* get module version */
-    AT_SEND_CMD(resp, "AT+GMR");
-    /* show module version */
-    for (i = 0; i < resp->line_counts - 1; i++)
-    {
-        LOG_D("%s", at_resp_get_line(resp, i + 1));
-    }
-    /* connect to WiFi AP */
-    if (at_exec_cmd(at_resp_set_info(resp, 128, 0, 20 * RT_TICK_PER_SECOND), "AT+CWJAP=\"%s\",\"%s\"",
-            AT_DEVICE_WIFI_SSID, AT_DEVICE_WIFI_PASSWORD) != RT_EOK)
-    {
-        LOG_E("AT network initialize failed, check ssid(%s) and password(%s).", AT_DEVICE_WIFI_SSID, AT_DEVICE_WIFI_PASSWORD);
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    AT_SEND_CMD(resp, "AT+CIPMUX=1");
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    if (!result)
-    {
-        netdev_low_level_set_status(netdev_get_by_name(ESP8266_NETDEV_NAME), RT_TRUE);
-        LOG_I("AT network initialize success!");
-    }
-    else
-    {
-        netdev_low_level_set_status(netdev_get_by_name(ESP8266_NETDEV_NAME), RT_FALSE);
-        LOG_E("AT network initialize failed (%d)!", result);
-    }
-}
-
-int esp8266_net_init(void)
-{
-#ifdef PKG_AT_INIT_BY_THREAD
-    rt_thread_t tid;
-
-    tid = rt_thread_create("esp8266_net_init", esp8266_init_thread_entry, RT_NULL, ESP8266_THREAD_STACK_SIZE, ESP8266_THREAD_PRIORITY, 20);
-    if (tid)
-    {
-        rt_thread_startup(tid);
-    }
-    else
-    {
-        LOG_E("Create AT initialization thread fail!");
-    }
-#else
-    esp8266_init_thread_entry(RT_NULL);
-#endif
-
-    return RT_EOK;
-}
-#ifdef FINSH_USING_MSH
-    #include <finsh.h>
-    MSH_CMD_EXPORT_ALIAS(esp8266_net_init, at_net_init, initialize AT network);
-#endif
-
-static const struct at_device_ops esp8266_socket_ops =
-{
-    esp8266_socket_connect,
-    esp8266_socket_close,
-    esp8266_socket_send,
-    esp8266_domain_resolve,
-    esp8266_socket_set_event_cb,
-};
-
-static int esp8266_netdev_set_up(struct netdev *netdev)
-{
-    netdev_low_level_set_status(netdev, RT_TRUE);
-    LOG_D("esp8266 network interface set up status.");
-    return RT_EOK;
-}
-
-static int esp8266_netdev_set_down(struct netdev *netdev)
-{
-    netdev_low_level_set_status(netdev, RT_FALSE);
-    LOG_D("esp8266 network interface set down status.");
-    return RT_EOK;
-}
-
-static int esp8266_netdev_set_addr_info(struct netdev *netdev, ip_addr_t *ip_addr, ip_addr_t *netmask, ip_addr_t *gw)
-{
-#define RESP_SIZE               128
-#define IPV4_ADDR_STRLEN_MAX    16
-    at_response_t resp = RT_NULL;
-    int result = RT_EOK;
-    char esp8266_ip_addr[IPV4_ADDR_STRLEN_MAX] = {0};
-    char esp8266_gw_addr[IPV4_ADDR_STRLEN_MAX] = {0};
-    char esp8266_netmask_addr[IPV4_ADDR_STRLEN_MAX] = {0};
-
-    RT_ASSERT(netdev);
-    RT_ASSERT(ip_addr || netmask || gw);
-
-    resp = at_create_resp(RESP_SIZE, 0, rt_tick_from_millisecond(300));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-
-    /* Convert numeric IP address into decimal dotted ASCII representation. */
-    if (ip_addr)
-        rt_memcpy(esp8266_ip_addr, inet_ntoa(*ip_addr), IPV4_ADDR_STRLEN_MAX);
-    else
-        rt_memcpy(esp8266_ip_addr, inet_ntoa(netdev->ip_addr), IPV4_ADDR_STRLEN_MAX);
-
-    if (gw)
-        rt_memcpy(esp8266_gw_addr, inet_ntoa(*gw), IPV4_ADDR_STRLEN_MAX);
-    else
-        rt_memcpy(esp8266_gw_addr, inet_ntoa(netdev->gw), IPV4_ADDR_STRLEN_MAX);
-
-    if (netmask)
-        rt_memcpy(esp8266_netmask_addr, inet_ntoa(*netmask), IPV4_ADDR_STRLEN_MAX);
-    else
-        rt_memcpy(esp8266_netmask_addr, inet_ntoa(netdev->netmask), IPV4_ADDR_STRLEN_MAX);
-
-    /* send addr info set commond "AT+CIPSTA_CUR=<ip>[,<gateway>,<netmask>]" and wait response */
-    if (at_exec_cmd(resp, "AT+CIPSTA_CUR=\"%s\",\"%s\",\"%s\"", esp8266_ip_addr, esp8266_gw_addr, esp8266_netmask_addr) < 0)
-    {
-        LOG_D("esp8266 set addr info failed.");
-        result = -RT_ERROR;
-    }
-    else
-    {
-        /* Update netdev information */
-        if (ip_addr)
-            netdev_low_level_set_ipaddr(netdev, ip_addr);
-
-        if (gw)
-            netdev_low_level_set_gw(netdev, gw);
-
-        if (netmask)
-            netdev_low_level_set_netmask(netdev, netmask);
-
-        LOG_D("esp8266 set addr info successfully.");
-    }
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-static int esp8266_netdev_set_dns_server(struct netdev *netdev, uint8_t dns_num, ip_addr_t *dns_server)
-{
-#define RESP_SIZE           128
-    at_response_t resp = RT_NULL;
-    int result = RT_EOK;
-
-    RT_ASSERT(netdev);
-    RT_ASSERT(dns_server);
-
-    resp = at_create_resp(RESP_SIZE, 0, rt_tick_from_millisecond(300));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    /* send dns server set commond "AT+CIPDNS_CUR=<enable>[,<DNS	server0>,<DNS	server1>]" and wait response */
-    if (at_exec_cmd(resp, "AT+CIPDNS_CUR=1,\"%s\"", inet_ntoa(*dns_server)) < 0)
-    {
-        LOG_E("set dns server(%s) failed", inet_ntoa(*dns_server));
-        result = -RT_ERROR;
-    }
-    else
-    {
-        netdev_low_level_set_dns_server(netdev, dns_num, dns_server);
-        LOG_D("esp8266 set dns server successfully.");
-    }
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    rt_mutex_release(at_event_lock);
-
-    return result;
-}
-
-static int esp8266_netdev_set_dhcp(struct netdev *netdev, rt_bool_t is_enabled)
-{
-#define ESP8266_STATION     1
-#define RESP_SIZE           128
-
-    at_response_t resp = RT_NULL;
-    int result = RT_EOK;
-
-    RT_ASSERT(netdev);
-
-    resp = at_create_resp(RESP_SIZE, 0, rt_tick_from_millisecond(300));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-    
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    /* send dhcp set commond "AT+CWDHCP_CUR=<mode>,<en>" and wait response */
-    if (at_exec_cmd(resp, "AT+CWDHCP_CUR=%d,%d", ESP8266_STATION, is_enabled) < 0)
-    {
-        LOG_E("set dhcp status(%d) failed", is_enabled);
-        result = -RT_ERROR;
-        goto __exit;
-    }
-    else
-    {
-        netdev_low_level_set_dhcp_status(netdev, is_enabled);
-        LOG_D("esp8266 set dhcp successfully.");
-    }
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    rt_mutex_release(at_event_lock);
-
-    return result;
-}
-
-static int esp8266_netdev_ping(struct netdev *netdev, const char *host, size_t data_len, uint32_t timeout, struct netdev_ping_resp *ping_resp)
-{
-#define ESP8266_PING_IP_SIZE         16
-
-    at_response_t resp = RT_NULL;
-    rt_err_t result = RT_EOK;
-    int req_time;
-    char ip_addr[ESP8266_PING_IP_SIZE] = {0};
-
-    RT_ASSERT(netdev);
-    RT_ASSERT(host);
-    RT_ASSERT(ping_resp);
-
-    resp = at_create_resp(64, 0, timeout);
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    /* send domain commond "AT+CIPDOMAIN=<domain name>" and wait response */
-    if (at_exec_cmd(resp, "AT+CIPDOMAIN=\"%s\"", host) < 0)
-    {
-        LOG_D("ping: send commond AT+CIPDOMAIN=<domain name> failed");
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    /* parse the third line of response data, get the IP address */
-    if (at_resp_parse_line_args_by_kw(resp, "+CIPDOMAIN:", "+CIPDOMAIN:%s", ip_addr) < 0)
-    {
-        LOG_E("ping: get the IP address failed");
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    /* send ping commond "AT+PING=<IP>" and wait response */
-    if (at_exec_cmd(resp, "AT+PING=\"%s\"", host) < 0)
-    {
-        LOG_D("ping: unknown remote server host");
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    if (at_resp_parse_line_args_by_kw(resp, "+", "+%d", &req_time) < 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    if (req_time)
-    {
-        inet_aton(ip_addr, &(ping_resp->ip_addr));
-        ping_resp->data_len = data_len;
-        ping_resp->ttl = 0;
-        ping_resp->ticks = req_time;
-    }
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    rt_mutex_release(at_event_lock);
-
-    return result;
-}
-
-void esp8266_netdev_netstat(struct netdev *netdev)
-{
-#define ESP8266_NETSTAT_RESP_SIZE         320
-#define ESP8266_NETSTAT_TYPE_SIZE         4
-#define ESP8266_NETSTAT_IPADDR_SIZE       17
-#define ESP8266_NETSTAT_EXPRESSION        "+CIPSTATUS:%*d,\"%[^\"]\",\"%[^\"]\",%d,%d,%*d"
-
-    at_response_t resp = RT_NULL;
-    int remote_port, local_port, i;
-    char *type = RT_NULL;
-    char *ipaddr = RT_NULL;
-
-    type = rt_calloc(1, ESP8266_NETSTAT_TYPE_SIZE);
-    ipaddr = rt_calloc(1, ESP8266_NETSTAT_IPADDR_SIZE);
-    if ((type && ipaddr) == RT_NULL)
-    {
-        LOG_E("No memory for response structure!");
-        goto __exit;
-    }
-
-    resp = at_create_resp(ESP8266_NETSTAT_RESP_SIZE, 0, rt_tick_from_millisecond(5000));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        goto __exit;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    /* send network connection information commond "AT+CIPSTATUS" and wait response */
-    if (at_exec_cmd(resp, "AT+CIPSTATUS") < 0)
-    {
-        LOG_E("netstat: send commond AT+CIPSTATUS failed");
-        goto __exit;
-    }
-
-    for (i = 1; i <= resp->line_counts; i++)
-    {
-        if (strstr(at_resp_get_line(resp, i), "+CIPSTATUS"))
-        {
-            /* parse the third line of response data, get the network connection information */
-            if (at_resp_parse_line_args(resp, i, ESP8266_NETSTAT_EXPRESSION, type, ipaddr, &remote_port, &local_port) < 0)
-                goto __exit;
-            else
-            {
-                LOG_RAW("%s: %s:%d ==> %s:%d\n", type, inet_ntoa(netdev->ip_addr), local_port, ipaddr, remote_port);
-            }
-        }
-    }
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    if (type)
-    {
-        rt_free(type);
-    }
-
-    if (ipaddr)
-    {
-        rt_free(ipaddr);
-    }
-
-    rt_mutex_release(at_event_lock);
-}
-
-const struct netdev_ops esp8266_netdev_ops =
-{
-    esp8266_netdev_set_up,
-    esp8266_netdev_set_down,
-
-    esp8266_netdev_set_addr_info,
-    esp8266_netdev_set_dns_server,
-    esp8266_netdev_set_dhcp,
-
-    esp8266_netdev_ping,
-    esp8266_netdev_netstat,
-};
-
-static struct netdev *esp8266_netdev_add(const char *netdev_name)
-{
-#define ETHERNET_MTU        1500
-#define HWADDR_LEN          6
-    struct netdev *netdev = RT_NULL;
-
-    RT_ASSERT(netdev_name);
-
-    netdev = (struct netdev *) rt_calloc(1, sizeof(struct netdev));
-    if (netdev == RT_NULL)
-    {
-        return RT_NULL;
-    }
-
-    netdev->mtu = ETHERNET_MTU;
-    netdev->ops = &esp8266_netdev_ops;
-    netdev->hwaddr_len = HWADDR_LEN;
-
-#ifdef SAL_USING_AT
-    extern int sal_at_netdev_set_pf_info(struct netdev *netdev);
-    /* set the network interface socket/netdb operations */
-    sal_at_netdev_set_pf_info(netdev);
-#endif
-
-    netdev_register(netdev, netdev_name, RT_NULL);
-
-    return netdev;
-}
-
-static int at_socket_device_init(void)
-{
-    /* create current AT socket event */
-    at_socket_event = rt_event_create("at_se", RT_IPC_FLAG_FIFO);
-    if (at_socket_event == RT_NULL)
-    {
-        LOG_E("RT AT client port initialize failed! at_sock_event create failed!");
-        return -RT_ENOMEM;
-    }
-
-    /* create current AT socket event lock */
-    at_event_lock = rt_mutex_create("at_se", RT_IPC_FLAG_FIFO);
-    if (at_event_lock == RT_NULL)
-    {
-        LOG_E("RT AT client port initialize failed! at_sock_lock create failed!");
-        rt_event_delete(at_socket_event);
-        return -RT_ENOMEM;
-    }
-
-    /* initialize AT client */
-    at_client_init(AT_DEVICE_NAME, AT_DEVICE_RECV_BUFF_LEN);
-
-    /* register URC data execution function  */
-    at_set_urc_table(urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
-
-    /* Add esp8266 to the netdev list */
-    esp8266_netdev_add(ESP8266_NETDEV_NAME);
-
-    /* initialize esp8266 net workqueue */
-    rt_delayed_work_init(&esp8266_net_work, exp8266_get_netdev_info, (void *)netdev_get_by_name(ESP8266_NETDEV_NAME));
-
-    /* initialize esp8266 network */
-    esp8266_net_init();
-
-    /* set esp8266 AT Socket options */
-    at_socket_device_register(&esp8266_socket_ops);
-
-    return RT_EOK;
-}
-INIT_APP_EXPORT(at_socket_device_init);
-
-#endif /* AT_DEVICE_ESP8266 */

+ 0 - 1273
at_socket_m26.c

@@ -1,1273 +0,0 @@
-/*
- * File      : at_socket_m26.c
- * This file is part of RT-Thread RTOS
- * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Change Logs:
- * Date           Author       Notes
- * 2018-06-12     chenyong     first version
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include <rtthread.h>
-#include <sys/socket.h>
-
-#include <at.h>
-#include <at_socket.h>
-
-#if !defined(RT_USING_NETDEV)
-#error "This RT-Thread version is older, please check and updata laster RT-Thread!"
-#else
-#include <arpa/inet.h>
-#include <netdev.h>
-#endif /* RT_USING_NETDEV */
-
-#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10200
-#error "This AT Client version is older, please check and update latest AT Client!"
-#endif
-
-#define LOG_TAG              "at.m26|mc20"
-#include <at_log.h>
-
-#ifdef AT_DEVICE_M26
-
-#define M26_NETDEV_NAME                "m26"
-
-#define M26_MODULE_SEND_MAX_SIZE       1460
-#define M26_WAIT_CONNECT_TIME          5000
-#define M26_THREAD_STACK_SIZE          1024
-#define M26_THREAD_PRIORITY            (RT_THREAD_PRIORITY_MAX/2)
-
-/* set real event by current socket and current state */
-#define SET_EVENT(socket, event)       (((socket + 1) << 16) | (event))
-
-/* AT socket event type */
-#define M26_EVENT_CONN_OK              (1L << 0)
-#define M26_EVENT_SEND_OK              (1L << 1)
-#define M26_EVENT_RECV_OK              (1L << 2)
-#define M26_EVNET_CLOSE_OK             (1L << 3)
-#define M26_EVENT_CONN_FAIL            (1L << 4)
-#define M26_EVENT_SEND_FAIL            (1L << 5)
-
-static int cur_socket;
-static rt_event_t at_socket_event;
-static rt_mutex_t at_event_lock;
-static at_evt_cb_t at_evt_cb_set[] = {
-        [AT_SOCKET_EVT_RECV] = NULL,
-        [AT_SOCKET_EVT_CLOSED] = NULL,
-};
-
-static int at_socket_event_send(uint32_t event)
-{
-    return (int) rt_event_send(at_socket_event, event);
-}
-
-static int at_socket_event_recv(uint32_t event, uint32_t timeout, rt_uint8_t option)
-{
-    int result = 0;
-    rt_uint32_t recved;
-
-    result = rt_event_recv(at_socket_event, event, option | RT_EVENT_FLAG_CLEAR, timeout, &recved);
-    if (result != RT_EOK)
-    {
-        return -RT_ETIMEOUT;
-    }
-
-    return recved;
-}
-
-/**
- * close socket by AT commands.
- *
- * @param current socket
- *
- * @return  0: close socket success
- *         -1: send AT commands error
- *         -2: wait socket event timeout
- *         -5: no memory
- */
-static int m26_socket_close(int socket)
-{
-    int result = 0;
-    at_response_t resp = RT_NULL;
-
-    resp = at_create_resp(128, 0, RT_TICK_PER_SECOND);
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-    cur_socket = socket;
-
-    /* Clear socket close event */
-    at_socket_event_recv(SET_EVENT(socket, M26_EVNET_CLOSE_OK), 0, RT_EVENT_FLAG_OR);
-
-    if (at_exec_cmd(resp, "AT+QICLOSE=%d", socket) < 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    if (at_socket_event_recv(SET_EVENT(socket, M26_EVNET_CLOSE_OK), rt_tick_from_millisecond(300*3), RT_EVENT_FLAG_AND) < 0)
-    {
-        LOG_E("socket (%d) close failed, wait close OK timeout.", socket);
-        result = -RT_ETIMEOUT;
-        goto __exit;
-    }
-
-__exit:
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-
-/**
- * create TCP/UDP client or server connect by AT commands.
- *
- * @param socket current socket
- * @param ip server or client IP address
- * @param port server or client port
- * @param type connect socket type(tcp, udp)
- * @param is_client connection is client
- *
- * @return   0: connect success
- *          -1: connect failed, send commands error or type error
- *          -2: wait socket event timeout
- *          -5: no memory
- */
-static int m26_socket_connect(int socket, char *ip, int32_t port, enum at_socket_type type, rt_bool_t is_client)
-{
-    int result = 0, event_result = 0;
-    rt_bool_t retryed = RT_FALSE;
-    at_response_t resp = RT_NULL;
-
-    RT_ASSERT(ip);
-    RT_ASSERT(port >= 0);
-
-    resp = at_create_resp(128, 0, 5 * RT_TICK_PER_SECOND);
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    /* lock AT socket connect */
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-__retry:
-
-    /* Clear socket connect event */
-    at_socket_event_recv(SET_EVENT(socket, M26_EVENT_CONN_OK | M26_EVENT_CONN_FAIL), 0, RT_EVENT_FLAG_OR);
-
-    if (is_client)
-    {
-        switch (type)
-        {
-        case AT_SOCKET_TCP:
-            /* send AT commands(eg: AT+QIOPEN=0,"TCP","x.x.x.x", 1234) to connect TCP server */
-            if (at_exec_cmd(resp, "AT+QIOPEN=%d,\"TCP\",\"%s\",%d", socket, ip, port) < 0)
-            {
-                result = -RT_ERROR;
-                goto __exit;
-            }
-            break;
-
-        case AT_SOCKET_UDP:
-            if (at_exec_cmd(resp, "AT+QIOPEN=%d,\"UDP\",\"%s\",%d", socket, ip, port) < 0)
-            {
-                result = -RT_ERROR;
-                goto __exit;
-            }
-            break;
-
-        default:
-            LOG_E("Not supported connect type : %d.", type);
-            return -RT_ERROR;
-        }
-    }
-
-    /* waiting result event from AT URC, the device default connection timeout is 75 seconds, but it set to 10 seconds is convenient to use.*/
-    if (at_socket_event_recv(SET_EVENT(socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
-    {
-        LOG_E("socket (%d) connect failed, wait connect result timeout.", socket);
-        result = -RT_ETIMEOUT;
-        goto __exit;
-    }
-    /* waiting OK or failed result */
-    if ((event_result = at_socket_event_recv(M26_EVENT_CONN_OK | M26_EVENT_CONN_FAIL, 1 * RT_TICK_PER_SECOND,
-            RT_EVENT_FLAG_OR)) < 0)
-    {
-        LOG_E("socket (%d) connect failed, wait connect OK|FAIL timeout.", socket);
-        result = -RT_ETIMEOUT;
-        goto __exit;
-    }
-    /* check result */
-    if (event_result & M26_EVENT_CONN_FAIL)
-    {
-        if (!retryed)
-        {
-            LOG_E("socket (%d) connect failed, maybe the socket was not be closed at the last time and now will retry.", socket);
-            if (m26_socket_close(socket) < 0)
-            {
-                goto __exit;
-            }
-            retryed = RT_TRUE;
-            goto __retry;
-        }
-        LOG_E("socket (%d) connect failed, failed to establish a connection.", socket);
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-__exit:
-    /* unlock AT socket connect */
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-static int at_get_send_size(int socket, size_t *size, size_t *acked, size_t *nacked)
-{
-    at_response_t resp = at_create_resp(64, 0, 5 * RT_TICK_PER_SECOND);
-    int result = 0;
-
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-
-    if (at_exec_cmd(resp, "AT+QISACK=%d", socket) < 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    if (at_resp_parse_line_args_by_kw(resp, "+QISACK:", "+QISACK: %d, %d, %d", size, acked, nacked) <= 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-static int at_wait_send_finish(int socket, size_t settings_size)
-{
-    /* get the timeout by the input data size */
-    rt_tick_t timeout = rt_tick_from_millisecond(settings_size);
-    rt_tick_t last_time = rt_tick_get();
-    size_t size = 0, acked = 0, nacked = 0xFFFF;
-
-    while (rt_tick_get() - last_time <= timeout)
-    {
-        at_get_send_size(socket, &size, &acked, &nacked);
-        if (nacked == 0)
-        {
-            return RT_EOK;
-        }
-        rt_thread_delay(rt_tick_from_millisecond(50));
-    }
-
-    return -RT_ETIMEOUT;
-}
-
-/**
- * send data to server or client by AT commands.
- *
- * @param socket current socket
- * @param buff send buffer
- * @param bfsz send buffer size
- * @param type connect socket type(tcp, udp)
- *
- * @return >=0: the size of send success
- *          -1: send AT commands error or send data error
- *          -2: waited socket event timeout
- *          -5: no memory
- */
-static int m26_socket_send(int socket, const char *buff, size_t bfsz, enum at_socket_type type)
-{
-    int result = 0, event_result = 0;
-    at_response_t resp = RT_NULL;
-    size_t cur_pkt_size = 0, sent_size = 0;
-
-    RT_ASSERT(buff);
-
-    resp = at_create_resp(128, 2, 5 * RT_TICK_PER_SECOND);
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    /* Clear socket send event */
-    at_socket_event_recv(SET_EVENT(socket, M26_EVENT_SEND_OK | M26_EVENT_SEND_FAIL), 0, RT_EVENT_FLAG_OR);
-
-    /* set current socket for send URC event */
-    cur_socket = socket;
-    /* set AT client end sign to deal with '>' sign.*/
-    at_set_end_sign('>');
-
-    while (sent_size < bfsz)
-    {
-        if (bfsz - sent_size < M26_MODULE_SEND_MAX_SIZE)
-        {
-            cur_pkt_size = bfsz - sent_size;
-        }
-        else
-        {
-            cur_pkt_size = M26_MODULE_SEND_MAX_SIZE;
-        }
-
-        /* send the "AT+QISEND" commands to AT server than receive the '>' response on the first line. */
-        if (at_exec_cmd(resp, "AT+QISEND=%d,%d", socket, cur_pkt_size) < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* send the real data to server or client */
-        result = (int) at_client_send(buff + sent_size, cur_pkt_size);
-        if (result == 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* waiting result event from AT URC */
-        if (at_socket_event_recv(SET_EVENT(socket, 0), 1 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
-        {
-            LOG_E("socket (%d) send failed, wait connect result timeout.", socket);
-            result = -RT_ETIMEOUT;
-            goto __exit;
-        }
-        /* waiting OK or failed result */
-        if ((event_result = at_socket_event_recv(M26_EVENT_SEND_OK | M26_EVENT_SEND_FAIL, 1 * RT_TICK_PER_SECOND,
-                RT_EVENT_FLAG_OR)) < 0)
-        {
-            LOG_E("socket (%d) send failed, wait connect OK|FAIL timeout.", socket);
-            result = -RT_ETIMEOUT;
-            goto __exit;
-        }
-        /* check result */
-        if (event_result & M26_EVENT_SEND_FAIL)
-        {
-            LOG_E("socket (%d) send failed, return failed.", socket);
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        if (type == AT_SOCKET_TCP)
-        {
-            at_wait_send_finish(socket, cur_pkt_size);
-        }
-
-        sent_size += cur_pkt_size;
-    }
-
-
-__exit:
-    /* reset the end sign for data conflict */
-    at_set_end_sign(0);
-
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-/**
- * domain resolve by AT commands.
- *
- * @param name domain name
- * @param ip parsed IP address, it's length must be 16
- *
- * @return  0: domain resolve success
- *         -1: send AT commands error or response error
- *         -2: wait socket event timeout
- *         -5: no memory
- */
-static int m26_domain_resolve(const char *name, char ip[16])
-{
-#define RESOLVE_RETRY                  5
-
-    int i, result = RT_EOK;
-    char recv_ip[16] = { 0 };
-    at_response_t resp = RT_NULL;
-
-    RT_ASSERT(name);
-    RT_ASSERT(ip);
-
-    /* The maximum response time is 14 seconds, affected by network status */
-    resp = at_create_resp(128, 4, 14 * RT_TICK_PER_SECOND);
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    for(i = 0; i < RESOLVE_RETRY; i++)
-    {
-        if (at_exec_cmd(resp, "AT+QIDNSGIP=\"%s\"", name) < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* parse the third line of response data, get the IP address */
-        if(at_resp_parse_line_args_by_kw(resp, ".", "%s", recv_ip) < 0)
-        {
-            rt_thread_mdelay(100);
-            /* resolve failed, maybe receive an URC CRLF */
-            continue;
-        }
-
-        if (strlen(recv_ip) < 8)
-        {
-            rt_thread_mdelay(100);
-            /* resolve failed, maybe receive an URC CRLF */
-            continue;
-        }
-        else
-        {
-            strncpy(ip, recv_ip, 15);
-            ip[15] = '\0';
-            break;
-        }
-    }
-
-__exit:
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-
-}
-
-/**
- * set AT socket event notice callback
- *
- * @param event notice event
- * @param cb notice callback
- */
-static void m26_socket_set_event_cb(at_socket_evt_t event, at_evt_cb_t cb)
-{
-    if (event < sizeof(at_evt_cb_set) / sizeof(at_evt_cb_set[1]))
-    {
-        at_evt_cb_set[event] = cb;
-    }
-}
-
-static void urc_connect_func(const char *data, rt_size_t size)
-{
-    int socket = 0;
-
-    RT_ASSERT(data && size);
-
-    sscanf(data, "%d%*[^0-9]", &socket);
-
-    if (strstr(data, "CONNECT OK"))
-    {
-        at_socket_event_send(SET_EVENT(socket, M26_EVENT_CONN_OK));
-    }
-    else
-    {
-        at_socket_event_send(SET_EVENT(socket, M26_EVENT_CONN_FAIL));
-    }
-}
-
-static void urc_send_func(const char *data, rt_size_t size)
-{
-    RT_ASSERT(data && size);
-
-    if (strstr(data, "SEND OK"))
-    {
-        at_socket_event_send(SET_EVENT(cur_socket, M26_EVENT_SEND_OK));
-    }
-    else if (strstr(data, "SEND FAIL"))
-    {
-        at_socket_event_send(SET_EVENT(cur_socket, M26_EVENT_SEND_FAIL));
-    }
-}
-
-static void urc_close_func(const char *data, rt_size_t size)
-{
-    int socket = 0;
-
-    RT_ASSERT(data && size);
-
-    if (strstr(data, "CLOSE OK"))
-    {
-        at_socket_event_send(SET_EVENT(cur_socket, M26_EVNET_CLOSE_OK));
-    }
-    else if (strstr(data, "CLOSED"))
-    {
-        sscanf(data, "%d, CLOSED", &socket);
-        /* notice the socket is disconnect by remote */
-        if (at_evt_cb_set[AT_SOCKET_EVT_CLOSED])
-        {
-            at_evt_cb_set[AT_SOCKET_EVT_CLOSED](socket, AT_SOCKET_EVT_CLOSED, NULL, 0);
-        }
-    }
-}
-
-static void urc_recv_func(const char *data, rt_size_t size)
-{
-    int socket = 0;
-    rt_size_t bfsz = 0, temp_size = 0;
-    rt_int32_t timeout;
-    char *recv_buf = RT_NULL, temp[8];
-
-    RT_ASSERT(data && size);
-
-    /* get the current socket and receive buffer size by receive data */
-    sscanf(data, "+RECEIVE: %d, %d", &socket, (int *) &bfsz);
-    /* get receive timeout by receive buffer length */
-    timeout = bfsz;
-
-    if (socket < 0 || bfsz == 0)
-        return;
-
-    recv_buf = rt_calloc(1, bfsz);
-    if (!recv_buf)
-    {
-        LOG_E("no memory for URC receive buffer (%d)!", bfsz);
-        /* read and clean the coming data */
-        while (temp_size < bfsz)
-        {
-            if (bfsz - temp_size > sizeof(temp))
-            {
-                at_client_recv(temp, sizeof(temp), timeout);
-            }
-            else
-            {
-                at_client_recv(temp, bfsz - temp_size, timeout);
-            }
-            temp_size += sizeof(temp);
-        }
-        return;
-    }
-
-    /* sync receive data */
-    if (at_client_recv(recv_buf, bfsz, timeout) != bfsz)
-    {
-        LOG_E("receive size(%d) data failed!", bfsz);
-        rt_free(recv_buf);
-        return;
-    }
-
-    /* notice the receive buffer and buffer size */
-    if (at_evt_cb_set[AT_SOCKET_EVT_RECV])
-    {
-        at_evt_cb_set[AT_SOCKET_EVT_RECV](socket, AT_SOCKET_EVT_RECV, recv_buf, bfsz);
-    }
-}
-
-static void urc_func(const char *data, rt_size_t size)
-{
-    RT_ASSERT(data);
-
-    LOG_I("URC data : %.*s", size, data);
-}
-
-static const struct at_urc urc_table[] = {
-        {"RING",        "\r\n",                 urc_func},
-        {"Call Ready",  "\r\n",                 urc_func},
-        {"RDY",         "\r\n",                 urc_func},
-        {"NO CARRIER",  "\r\n",                 urc_func},
-        {"",            ", CONNECT OK\r\n",     urc_connect_func},
-        {"",            ", CONNECT FAIL\r\n",   urc_connect_func},
-        {"SEND OK",     "\r\n",                 urc_send_func},
-        {"SEND FAIL",   "\r\n",                 urc_send_func},
-        {"",            ", CLOSE OK\r\n",       urc_close_func},
-        {"",            ", CLOSED\r\n",         urc_close_func},
-        {"+RECEIVE:",   "\r\n",                 urc_recv_func},
-};
-
-#define AT_SEND_CMD(resp, resp_line, timeout, cmd)                                                              \
-    do                                                                                                          \
-    {                                                                                                           \
-        if (at_exec_cmd(at_resp_set_info(resp, 128, resp_line, rt_tick_from_millisecond(timeout)), cmd) < 0)    \
-        {                                                                                                       \
-            result = -RT_ERROR;                                                                                 \
-            goto __exit;                                                                                        \
-        }                                                                                                       \
-    } while(0);                                                                                                 \
-
-static int m26_netdev_set_info(struct netdev *netdev);
-static int m26_netdev_check_link_status(struct netdev *netdev);
-
-/* init for M26 or MC20 */
-static void m26_init_thread_entry(void *parameter)
-{
-#define CPIN_RETRY                     10
-#define CSQ_RETRY                      10
-#define CREG_RETRY                     10
-#define CGREG_RETRY                    20
-
-    at_response_t resp = RT_NULL;
-    int i, qimux, qimode;
-    char parsed_data[10];
-    rt_err_t result = RT_EOK;
-
-    resp = at_create_resp(128, 0, rt_tick_from_millisecond(300));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-    LOG_D("Start initializing the M26/MC20 module");
-    /* wait M26 startup finish */
-    if (at_client_wait_connect(M26_WAIT_CONNECT_TIME))
-    {
-        LOG_E("AT device connection error.");
-        result = -RT_ETIMEOUT;
-        goto __exit;
-    }
-    /* disable echo */
-    AT_SEND_CMD(resp, 0, 300, "ATE0");
-    /* get module version */
-    AT_SEND_CMD(resp, 0, 300, "ATI");
-    /* show module version */
-    for (i = 0; i < (int) resp->line_counts - 1; i++)
-    {
-        LOG_D("%s", at_resp_get_line(resp, i + 1));
-    }
-    /* check SIM card */
-    for (i = 0; i < CPIN_RETRY; i++)
-    {
-        at_exec_cmd(at_resp_set_info(resp, 128, 2, 5 * RT_TICK_PER_SECOND), "AT+CPIN?");
-
-        if (at_resp_get_line_by_kw(resp, "READY"))
-        {
-            LOG_D("SIM card detection success");
-            break;
-        }
-        rt_thread_mdelay(1000);
-    }
-    if (i == CPIN_RETRY)
-    {
-        LOG_E("SIM card detection failed!");
-        result = -RT_ERROR;
-        goto __exit;
-    }
-    /* waiting for dirty data to be digested */
-    rt_thread_mdelay(10);
-    /* check signal strength */
-    for (i = 0; i < CSQ_RETRY; i++)
-    {
-        AT_SEND_CMD(resp, 0, 300, "AT+CSQ");
-        at_resp_parse_line_args_by_kw(resp, "+CSQ:", "+CSQ: %s", &parsed_data);
-        if (strncmp(parsed_data, "99,99", sizeof(parsed_data)))
-        {
-            LOG_D("Signal strength: %s", parsed_data);
-            break;
-        }
-        rt_thread_mdelay(1000);
-    }
-    if (i == CSQ_RETRY)
-    {
-        LOG_E("Signal strength check failed (%s)", parsed_data);
-        result = -RT_ERROR;
-        goto __exit;
-    }
-    /* check the GSM network is registered */
-    for (i = 0; i < CREG_RETRY; i++)
-    {
-        AT_SEND_CMD(resp, 0, 300, "AT+CREG?");
-        at_resp_parse_line_args_by_kw(resp, "+CREG:", "+CREG: %s", &parsed_data);
-        if (!strncmp(parsed_data, "0,1", sizeof(parsed_data)) || !strncmp(parsed_data, "0,5", sizeof(parsed_data)))
-        {
-            LOG_D("GSM network is registered (%s)", parsed_data);
-            break;
-        }
-        rt_thread_mdelay(1000);
-    }
-    if (i == CREG_RETRY)
-    {
-        LOG_E("The GSM network is register failed (%s)", parsed_data);
-        result = -RT_ERROR;
-        goto __exit;
-    }
-    /* check the GPRS network is registered */
-    for (i = 0; i < CGREG_RETRY; i++)
-    {
-        AT_SEND_CMD(resp, 0, 300, "AT+CGREG?");
-        at_resp_parse_line_args_by_kw(resp, "+CGREG:", "+CGREG: %s", &parsed_data);
-        if (!strncmp(parsed_data, "0,1", sizeof(parsed_data)) || !strncmp(parsed_data, "0,5", sizeof(parsed_data)))
-        {
-            LOG_D("GPRS network is registered (%s)", parsed_data);
-            break;
-        }
-        rt_thread_mdelay(1000);
-    }
-    if (i == CGREG_RETRY)
-    {
-        LOG_E("The GPRS network is register failed (%s)", parsed_data);
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    AT_SEND_CMD(resp, 0, 300, "AT+QIFGCNT=0");
-    AT_SEND_CMD(resp, 0, 300, "AT+QICSGP=1, \"CMNET\"");
-    AT_SEND_CMD(resp, 0, 300, "AT+QIMODE?");
-
-    at_resp_parse_line_args_by_kw(resp, "+QIMODE:", "+QIMODE: %d", &qimode);
-    if (qimode == 1)
-    {
-        AT_SEND_CMD(resp, 0, 300, "AT+QIMODE=0");
-    }
-
-    /* the device default response timeout is 40 seconds, but it set to 15 seconds is convenient to use. */
-    AT_SEND_CMD(resp, 2, 20 * 1000, "AT+QIDEACT");
-
-    /* Set to multiple connections */
-    AT_SEND_CMD(resp, 0, 300, "AT+QIMUX?");
-    at_resp_parse_line_args_by_kw(resp, "+QIMUX:", "+QIMUX: %d", &qimux);
-    if (qimux == 0)
-    {
-        AT_SEND_CMD(resp, 0, 300, "AT+QIMUX=1");
-    }
-
-    AT_SEND_CMD(resp, 0, 300, "AT+QIREGAPP");
-
-    /* the device default response timeout is 150 seconds, but it set to 20 seconds is convenient to use. */
-    AT_SEND_CMD(resp, 0, 20 * 1000, "AT+QIACT");
-
-    AT_SEND_CMD(resp, 2, 300, "AT+QILOCIP");
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    if (!result)
-    {
-        m26_netdev_set_info(netdev_get_by_name(M26_NETDEV_NAME));
-        m26_netdev_check_link_status(netdev_get_by_name(M26_NETDEV_NAME));
-
-        LOG_I("AT network initialize success!");
-    }
-    else
-    {
-        LOG_E("AT network initialize failed (%d)!", result);
-    }
-}
-
-int m26_net_init(void)
-{
-#ifdef PKG_AT_INIT_BY_THREAD
-    rt_thread_t tid;
-
-    tid = rt_thread_create("m26_net_init", m26_init_thread_entry, RT_NULL, M26_THREAD_STACK_SIZE, M26_THREAD_PRIORITY, 20);
-    if (tid)
-    {
-        rt_thread_startup(tid);
-    }
-    else
-    {
-        LOG_E("Create AT initialization thread fail!");
-    }
-#else
-    m26_init_thread_entry(RT_NULL);
-#endif
-
-    return RT_EOK;
-}
-
-#ifdef FINSH_USING_MSH
-#include <finsh.h>
-MSH_CMD_EXPORT_ALIAS(m26_net_init, at_net_init, initialize AT network);
-#endif
-
-static const struct at_device_ops m26_socket_ops = {
-    m26_socket_connect,
-    m26_socket_close,
-    m26_socket_send,
-    m26_domain_resolve,
-    m26_socket_set_event_cb,
-};
-
-
-/* set m26 network interface device status and address information */
-static int m26_netdev_set_info(struct netdev *netdev)
-{
-#define M26_IEMI_RESP_SIZE      32
-#define M26_IPADDR_RESP_SIZE    32
-#define M26_DNS_RESP_SIZE       96
-#define M26_INFO_RESP_TIMO      rt_tick_from_millisecond(300)
-
-    int result = RT_EOK;
-    at_response_t resp = RT_NULL;
-    ip_addr_t addr;
-
-    if (netdev == RT_NULL)
-    {
-        LOG_E("Input network interface device is NULL.\n");
-        return -RT_ERROR;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    /* set network interface device up status */
-    netdev_low_level_set_status(netdev, RT_TRUE);
-    netdev_low_level_set_dhcp_status(netdev, RT_TRUE);
-
-    resp = at_create_resp(M26_IEMI_RESP_SIZE, 0, M26_INFO_RESP_TIMO);
-    if (resp == RT_NULL)
-    {
-        LOG_E("M26 set IP address failed, no memory for response object.");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-
-    /* set network interface device hardware address(IEMI) */
-    {
-        #define M26_NETDEV_HWADDR_LEN   8
-        #define M26_IEMI_LEN            15
-
-        char iemi[M26_IEMI_LEN] = {0};
-        int i = 0, j = 0;
-
-        /* send "AT+GSN" commond to get device IEMI */
-        if (at_exec_cmd(resp, "AT+GSN") < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        if (at_resp_parse_line_args(resp, 2, "%s", iemi) <= 0)
-        {
-            LOG_E("Prase \"AT+GSN\" commands resposne data error!");
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        LOG_D("M26 IEMI number: %s", iemi);
-
-        netdev->hwaddr_len = M26_NETDEV_HWADDR_LEN;
-        /* get hardware address by IEMI */
-        for (i = 0, j = 0; i < M26_NETDEV_HWADDR_LEN && j < M26_IEMI_LEN; i++, j+=2)
-        {
-            if (j != M26_IEMI_LEN - 1)
-            {
-                netdev->hwaddr[i] = (iemi[j] - '0') * 10 + (iemi[j + 1] - '0');
-            }
-            else
-            {
-                netdev->hwaddr[i] = (iemi[j] - '0');
-            }
-        }
-    }
-
-    /* set network interface device IP address */
-    {
-        #define IP_ADDR_SIZE_MAX    16
-        char ipaddr[IP_ADDR_SIZE_MAX] = {0};
-        
-        at_resp_set_info(resp, M26_IPADDR_RESP_SIZE, 2, M26_INFO_RESP_TIMO);
-
-        /* send "AT+QILOCIP" commond to get IP address */
-        if (at_exec_cmd(resp, "AT+QILOCIP") < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        if (at_resp_parse_line_args_by_kw(resp, ".", "%s", ipaddr) <= 0)
-        {
-            LOG_E("Prase \"AT+QILOCIP\" commands resposne data error!");
-            result = -RT_ERROR;
-            goto __exit;
-        }
-        
-        LOG_D("M26 IP address: %s", ipaddr);
-
-        /* set network interface address information */
-        inet_aton(ipaddr, &addr);
-        netdev_low_level_set_ipaddr(netdev, &addr);
-    }
-
-    /* set network interface device dns server */
-    {
-        #define DNS_ADDR_SIZE_MAX   16
-        char dns_server1[DNS_ADDR_SIZE_MAX] = {0}, dns_server2[DNS_ADDR_SIZE_MAX] = {0};
-
-        at_resp_set_info(resp, M26_DNS_RESP_SIZE, 0, M26_INFO_RESP_TIMO);
-
-        /* send "AT+QIDNSCFG?" commond to get DNS servers address */
-        if (at_exec_cmd(resp, "AT+QIDNSCFG?") < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        if (at_resp_parse_line_args_by_kw(resp, "PrimaryDns:", "PrimaryDns:%s", dns_server1) <= 0 ||
-                at_resp_parse_line_args_by_kw(resp, "SecondaryDns:", "SecondaryDns:%s", dns_server2) <= 0)
-        {
-            LOG_E("Prase \"AT+QIDNSCFG?\" commands resposne data error!");
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        LOG_D("M26 primary DNS server address: %s", dns_server1);
-        LOG_D("M26 secondary DNS server address: %s", dns_server2);
-
-        inet_aton(dns_server1, &addr);
-        netdev_low_level_set_dns_server(netdev, 0, &addr);
-
-        inet_aton(dns_server2, &addr);
-        netdev_low_level_set_dns_server(netdev, 1, &addr);
-    }
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    rt_mutex_release(at_event_lock);
-    
-    return result;
-}
-
-static void check_link_status_entry(void *parameter)
-{
-#define M26_LINK_STATUS_OK   0
-#define M26_LINK_RESP_SIZE   64
-#define M26_LINK_RESP_TIMO   (3 * RT_TICK_PER_SECOND)
-#define M26_LINK_DELAY_TIME  (30 * RT_TICK_PER_SECOND)
-
-    struct netdev *netdev = (struct netdev *)parameter;
-    at_response_t resp = RT_NULL;
-    int link_status;
-
-    resp = at_create_resp(M26_LINK_RESP_SIZE, 0, M26_LINK_RESP_TIMO);
-    if (resp == RT_NULL)
-    {
-        LOG_E("m26 set check link status failed, no memory for response object.");
-        return;
-    }
-
-    while (1)
-    { 
-
-        rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-        
-        /* send "AT+QNSTATUS" commond  to check netweork interface device link status */
-        if (at_exec_cmd(resp, "AT+QNSTATUS") < 0)
-        {
-            rt_mutex_release(at_event_lock);
-            rt_thread_mdelay(M26_LINK_DELAY_TIME);
-
-            continue;
-        }
-        
-        link_status = -1;
-        at_resp_parse_line_args_by_kw(resp, "+QNSTATUS:", "+QNSTATUS: %d", &link_status);
-
-        /* check the network interface device link status  */
-        if ((M26_LINK_STATUS_OK == link_status) != netdev_is_link_up(netdev))
-        {
-            netdev_low_level_set_link_status(netdev, (M26_LINK_STATUS_OK == link_status));
-        }
-
-        rt_mutex_release(at_event_lock);
-        rt_thread_mdelay(M26_LINK_DELAY_TIME);
-    }
-}
-
-static int m26_netdev_check_link_status(struct netdev *netdev)
-{
-#define M26_LINK_THREAD_STACK_SIZE     512
-#define M26_LINK_THREAD_PRIORITY       (RT_THREAD_PRIORITY_MAX - 2)
-#define M26_LINK_THREAD_TICK           20
-
-    rt_thread_t tid;
-    char tname[RT_NAME_MAX];
-
-    if (netdev == RT_NULL)
-    {
-        LOG_E("Input network interface device is NULL.\n");
-        return -RT_ERROR;
-    }
-
-    rt_memset(tname, 0x00, sizeof(tname));
-    rt_snprintf(tname, RT_NAME_MAX, "%s_link", netdev->name);
-
-    tid = rt_thread_create(tname, check_link_status_entry, (void *)netdev, 
-            M26_LINK_THREAD_STACK_SIZE, M26_LINK_THREAD_PRIORITY, M26_LINK_THREAD_TICK);
-    if (tid)
-    {
-        rt_thread_startup(tid);
-    }
-
-    return RT_EOK;
-}
-
-static int m26_netdev_set_up(struct netdev *netdev)
-{
-    netdev_low_level_set_status(netdev, RT_TRUE);
-    LOG_D("The network interface device(%s) set up status", netdev->name);
-
-    return RT_EOK;
-}
-
-static int m26_netdev_set_down(struct netdev *netdev)
-{
-    netdev_low_level_set_status(netdev, RT_FALSE);
-    LOG_D("The network interface device(%s) set down status", netdev->name);
-    return RT_EOK;
-}
-
-static int m26_netdev_set_dns_server(struct netdev *netdev, uint8_t dns_num, ip_addr_t *dns_server)
-{
-#define M26_DNS_RESP_LEN    8
-#define M26_DNS_RESP_TIMEO   rt_tick_from_millisecond(300)
-
-    at_response_t resp = RT_NULL;
-    int result = RT_EOK;
-
-    RT_ASSERT(netdev);
-    RT_ASSERT(dns_server);
-
-    resp = at_create_resp(M26_DNS_RESP_LEN, 0, M26_DNS_RESP_TIMEO);
-    if (resp == RT_NULL)
-    {
-        LOG_D("m26 set dns server failed, no memory for response object.");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    /* send "AT+QIDNSCFG=<pri_dns>[,<sec_dns>]" commond to set dns servers */
-    if (at_exec_cmd(resp, "AT+QIDNSCFG=\"%s\"", inet_ntoa(*dns_server)) < 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    netdev_low_level_set_dns_server(netdev, dns_num, dns_server);
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    rt_mutex_release(at_event_lock);
-
-    return result;
-}
-
-static int m26_netdev_ping(struct netdev *netdev, const char *host, size_t data_len, uint32_t timeout, struct netdev_ping_resp *ping_resp)
-{
-#define M26_PING_RESP_SIZE       128
-#define M26_PING_IP_SIZE         16
-#define M26_PING_TIMEO           (5 * RT_TICK_PER_SECOND)
-
-    int result = RT_EOK;
-    at_response_t resp = RT_NULL;
-    char ip_addr[M26_PING_IP_SIZE] = {0};
-    int response, recv_data_len, time, ttl;
-
-    RT_ASSERT(netdev);
-    RT_ASSERT(host);
-    RT_ASSERT(ping_resp);
-
-    resp = at_create_resp(M26_PING_RESP_SIZE, 5, M26_PING_TIMEO);
-    if (resp == RT_NULL)
-    {
-        LOG_D("m26 set dns server failed, no memory for response object.");
-        return  -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    /* send "AT+QPING="<host>"[,[<timeout>][,<pingnum>]]" commond to send ping request */
-    if (at_exec_cmd(resp, "AT+QPING=\"%s\",%d,1", host, M26_PING_TIMEO / RT_TICK_PER_SECOND) < 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    at_resp_parse_line_args_by_kw(resp, "+QPING:","+QPING:%d", &response);
-    /* Received the ping response from the server */
-    if (response == 0)
-    {
-        if (at_resp_parse_line_args_by_kw(resp, "+QPING:", "+QPING:%d,%[^,],%d,%d,%d",
-                &response, ip_addr, &recv_data_len, &time, &ttl) <= 0)
-        {
-            LOG_D("Prase \"AT+QPING\" commands resposne data error!");
-            result = -RT_ERROR;
-            goto __exit;
-        }   
-    }
-
-
-    /* prase response number */
-    switch (response)
-    {
-    case 0:
-        inet_aton(ip_addr, &(ping_resp->ip_addr));
-        ping_resp->data_len = recv_data_len;
-        ping_resp->ticks = time;
-        ping_resp->ttl = ttl;
-        result = RT_EOK;
-        break;
-    case 1:
-        result = -RT_ETIMEOUT;
-        break;
-    default:
-        result = -RT_ERROR;
-        break;
-    }
-
- __exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    rt_mutex_release(at_event_lock);
-
-    return result;
-}
-
-void m26_netdev_netstat(struct netdev *netdev)
-{ 
-    // TODO netstat support
-}
-
-const struct netdev_ops m26_netdev_ops =
-{
-    m26_netdev_set_up,
-    m26_netdev_set_down,
-
-    RT_NULL, /* not support set ip, netmask, gatway address */
-    m26_netdev_set_dns_server,
-    RT_NULL, /* not support set DHCP status */
-
-    m26_netdev_ping,
-    m26_netdev_netstat,
-};
-
-static int m26_netdev_add(const char *netdev_name)
-{
-#define M26_NETDEV_MTU       1500
-
-    struct netdev *netdev = RT_NULL;
-
-    RT_ASSERT(netdev_name);
-
-    netdev = (struct netdev *) rt_calloc(1, sizeof(struct netdev));
-    if (netdev == RT_NULL)
-    {
-        return RT_NULL;
-    }
-
-    netdev->mtu = M26_NETDEV_MTU;
-    netdev->ops = &m26_netdev_ops;
-
-#ifdef SAL_USING_AT
-    extern int sal_at_netdev_set_pf_info(struct netdev *netdev);
-    /* set the network interface socket/netdb operations */
-    sal_at_netdev_set_pf_info(netdev);
-#endif
-
-    return netdev_register(netdev, netdev_name, RT_NULL);
-}
-
-static int at_socket_device_init(void)
-{
-    /* create current AT socket event */
-    at_socket_event = rt_event_create("at_se", RT_IPC_FLAG_FIFO);
-    if (at_socket_event == RT_NULL)
-    {
-        LOG_E("AT client port initialize failed! at_sock_event create failed!");
-        return -RT_ENOMEM;
-    }
-
-    /* create current AT socket event lock */
-    at_event_lock = rt_mutex_create("at_se", RT_IPC_FLAG_FIFO);
-    if (at_event_lock == RT_NULL)
-    {
-        LOG_E("AT client port initialize failed! at_sock_lock create failed!");
-        rt_event_delete(at_socket_event);
-        return -RT_ENOMEM;
-    }
-
-    /* initialize AT client */
-    at_client_init(AT_DEVICE_NAME, AT_DEVICE_RECV_BUFF_LEN);
-
-    /* register URC data execution function  */
-    at_set_urc_table(urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
-
-    /* add network interface device to netdev list */
-    if (m26_netdev_add(M26_NETDEV_NAME) < 0)
-    {
-        LOG_E("M26 network interface device(%d) add failed.", M26_NETDEV_NAME);
-        return -RT_ENOMEM;
-    }
-
-    /* initialize m26 network */
-    m26_net_init();
-
-    /* set m26 AT Socket options */
-    at_socket_device_register(&m26_socket_ops);
-
-    return RT_EOK;
-}
-INIT_APP_EXPORT(at_socket_device_init);
-
-#endif /* AT_DEVICE_M26 */

+ 0 - 773
at_socket_rw007.c

@@ -1,773 +0,0 @@
-/*
- * File      : at_socket_rw007.c
- * This file is part of RT-Thread RTOS
- * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Change Logs:
- * Date           Author       Notes
- * 2018-06-20     chenyong     first version
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include <rtthread.h>
-#include <sys/socket.h>
-
-#include <at.h>
-#include <at_socket.h>
-
-#if !defined(RT_USING_NETDEV)
-#error "This RT-Thread version is older, please check and updata laster RT-Thread!"
-#else
-#include <arpa/inet.h>
-#include <netdev.h>
-#endif /* RT_USING_NETDEV */
-
-#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10200
-#error "This AT Client version is older, please check and update latest AT Client!"
-#endif
-
-#define LOG_TAG              "at.rw007"
-#include <at_log.h>
-
-#ifdef AT_DEVICE_RW007
-
-#define RW007_NETDEV_NAME    "rw007"
-
-#define RW007_MODULE_SEND_MAX_SIZE   2048
-#define RW007_WAIT_CONNECT_TIME      5000
-#define RW007_THREAD_STACK_SIZE      1024
-#define RW007_THREAD_PRIORITY        (RT_THREAD_PRIORITY_MAX/2)
-
-/* set real event by current socket and current state */
-#define SET_EVENT(socket, event)       (((socket + 1) << 16) | (event))
-
-/* AT socket event type */
-#define RW007_EVENT_CONN_OK          (1L << 0)
-#define RW007_EVENT_SEND_OK          (1L << 1)
-#define RW007_EVENT_RECV_OK          (1L << 2)
-#define RW007_EVNET_CLOSE_OK         (1L << 3)
-#define RW007_EVENT_CONN_FAIL        (1L << 4)
-#define RW007_EVENT_SEND_FAIL        (1L << 5)
-
-static int cur_socket;
-static int cur_send_bfsz;
-static rt_event_t at_socket_event;
-static rt_mutex_t at_event_lock;
-static at_evt_cb_t at_evt_cb_set[] = {
-        [AT_SOCKET_EVT_RECV] = NULL,
-        [AT_SOCKET_EVT_CLOSED] = NULL,
-};
-
-static int at_socket_event_send(uint32_t event)
-{
-    return (int) rt_event_send(at_socket_event, event);
-}
-
-static int at_socket_event_recv(uint32_t event, uint32_t timeout, rt_uint8_t option)
-{
-    int result = 0;
-    rt_uint32_t recved;
-
-    result = rt_event_recv(at_socket_event, event, option | RT_EVENT_FLAG_CLEAR, timeout, &recved);
-    if (result != RT_EOK)
-    {
-        return -RT_ETIMEOUT;
-    }
-
-    return recved;
-}
-
-/**
- * close socket by AT commands.
- *
- * @param current socket
- *
- * @return  0: close socket success
- *         -1: send AT commands error
- *         -2: wait socket event timeout
- *         -5: no memory
- */
-static int rw007_socket_close(int socket)
-{
-    at_response_t resp = RT_NULL;
-    int result = RT_EOK;
-
-    resp = at_create_resp(64, 0, rt_tick_from_millisecond(5000));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    if (at_exec_cmd(resp, "AT+CIPCLOSE=%d", socket) < 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
- __exit:
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-/**
- * create TCP/UDP client or server connect by AT commands.
- *
- * @param socket current socket
- * @param ip server or client IP address
- * @param port server or client port
- * @param type connect socket type(tcp, udp)
- * @param is_client connection is client
- *
- * @return   0: connect success
- *          -1: connect failed, send commands error or type error
- *          -2: wait socket event timeout
- *          -5: no memory
- */
-static int rw007_socket_connect(int socket, char *ip, int32_t port, enum at_socket_type type, rt_bool_t is_client)
-{
-    at_response_t resp = RT_NULL;
-    int result = RT_EOK;
-    rt_bool_t retryed = RT_FALSE;
-
-    RT_ASSERT(ip);
-    RT_ASSERT(port >= 0);
-
-    resp = at_create_resp(128, 0, rt_tick_from_millisecond(5000));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-__retry:
-    if (is_client)
-    {
-        switch (type)
-        {
-        case AT_SOCKET_TCP:
-            /* send AT commands to connect TCP server */
-            if (at_exec_cmd(resp, "AT+CIPSTART=%d,\"TCP\",\"%s\",%d,60", socket, ip, port) < 0)
-            {
-                result = -RT_ERROR;
-            }
-            break;
-
-        case AT_SOCKET_UDP:
-            if (at_exec_cmd(resp, "AT+CIPSTART=%d,\"UDP\",\"%s\",%d", socket, ip, port) < 0)
-            {
-                result = -RT_ERROR;
-            }
-            break;
-
-        default:
-            LOG_E("Not supported connect type : %d.", type);
-            result = -RT_ERROR;
-            goto __exit;
-        }
-    }
-
-    if (result != RT_EOK && !retryed)
-    {
-        LOG_D("socket (%d) connect failed, maybe the socket was not be closed at the last time and now will retry.", socket);
-        if (rw007_socket_close(socket) < 0)
-        {
-            goto __exit;
-        }
-        retryed = RT_TRUE;
-        result = RT_EOK;
-        goto __retry;
-    }
-
-__exit:
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-/**
- * send data to server or client by AT commands.
- *
- * @param socket current socket
- * @param buff send buffer
- * @param bfsz send buffer size
- * @param type connect socket type(tcp, udp)
- *
- * @return >=0: the size of send success
- *          -1: send AT commands error or send data error
- *          -2: waited socket event timeout
- *          -5: no memory
- */
-static int rw007_socket_send(int socket, const char *buff, size_t bfsz, enum at_socket_type type)
-{
-    int result = RT_EOK;
-    int event_result = 0;
-    at_response_t resp = RT_NULL;
-    size_t cur_pkt_size = 0, sent_size = 0;
-
-    RT_ASSERT(buff);
-    RT_ASSERT(bfsz > 0);
-
-    resp = at_create_resp(128, 2, rt_tick_from_millisecond(5000));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    /* set current socket for send URC event */
-    cur_socket = socket;
-    /* set AT client end sign to deal with '>' sign.*/
-    at_set_end_sign('>');
-
-    while (sent_size < bfsz)
-    {
-        if (bfsz - sent_size < RW007_MODULE_SEND_MAX_SIZE)
-        {
-            cur_pkt_size = bfsz - sent_size;
-        }
-        else
-        {
-            cur_pkt_size = RW007_MODULE_SEND_MAX_SIZE;
-        }
-
-        /* send the "AT+CIPSEND" commands to AT server than receive the '>' response on the first line. */
-        if (at_exec_cmd(resp, "AT+CIPSEND=%d,%d", socket, cur_pkt_size) < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* send the real data to server or client */
-        result = (int) at_client_send(buff + sent_size, cur_pkt_size);
-        if (result == 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* waiting result event from AT URC */
-        if (at_socket_event_recv(SET_EVENT(socket, 0), rt_tick_from_millisecond(5 * 1000), RT_EVENT_FLAG_OR) < 0)
-        {
-            LOG_E("socket (%d) send failed, wait connect result timeout.", socket);
-            result = -RT_ETIMEOUT;
-            goto __exit;
-        }
-        /* waiting OK or failed result */
-        if ((event_result = at_socket_event_recv(RW007_EVENT_SEND_OK | RW007_EVENT_SEND_FAIL, rt_tick_from_millisecond(5 * 1000),
-                RT_EVENT_FLAG_OR)) < 0)
-        {
-            LOG_E("socket (%d) send failed, wait connect OK|FAIL timeout.", socket);
-            result = -RT_ETIMEOUT;
-            goto __exit;
-        }
-        /* check result */
-        if (event_result & RW007_EVENT_SEND_FAIL)
-        {
-            LOG_E("socket (%d) send failed, return failed.", socket);
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        if (type == AT_SOCKET_TCP)
-        {
-            cur_pkt_size = cur_send_bfsz;
-        }
-
-        sent_size += cur_pkt_size;
-    }
-
-__exit:
-    /* reset the end sign for data */
-    at_set_end_sign(0);
-
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-/**
- * domain resolve by AT commands.
- *
- * @param name domain name
- * @param ip parsed IP address, it's length must be 16
- *
- * @return  0: domain resolve success
- *         -2: wait socket event timeout
- *         -5: no memory
- */
-static int rw007_domain_resolve(const char *name, char ip[16])
-{
-#define RESOLVE_RETRY        5
-
-    int i, result = RT_EOK;
-    char recv_ip[16] = { 0 };
-    at_response_t resp = RT_NULL;
-
-    RT_ASSERT(name);
-    RT_ASSERT(ip);
-
-    resp = at_create_resp(128, 0, rt_tick_from_millisecond(5000));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    for(i = 0; i < RESOLVE_RETRY; i++)
-    {
-        if (at_exec_cmd(resp, "AT+CIPDOMAIN=\"%s\"", name) < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* parse the third line of response data, get the IP address */
-        if(at_resp_parse_line_args_by_kw(resp, "+CIPDOMAIN:", "+CIPDOMAIN:%s", recv_ip) < 0)
-        {
-            rt_thread_delay(rt_tick_from_millisecond(100));
-            /* resolve failed, maybe receive an URC CRLF */
-            continue;
-        }
-
-        if (strlen(recv_ip) < 8)
-        {
-            rt_thread_delay(rt_tick_from_millisecond(100));
-            /* resolve failed, maybe receive an URC CRLF */
-            continue;
-        }
-        else
-        {
-            strncpy(ip, recv_ip, 15);
-            ip[15] = '\0';
-            break;
-        }
-    }
-
-__exit:
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-
-}
-
-/**
- * set AT socket event notice callback
- *
- * @param event notice event
- * @param cb notice callback
- */
-static void rw007_socket_set_event_cb(at_socket_evt_t event, at_evt_cb_t cb)
-{
-    if (event < sizeof(at_evt_cb_set) / sizeof(at_evt_cb_set[1]))
-    {
-        at_evt_cb_set[event] = cb;
-    }
-}
-
-static void urc_send_func(const char *data, rt_size_t size)
-{
-    RT_ASSERT(data && size);
-
-    if (strstr(data, "SEND OK"))
-    {
-        at_socket_event_send(SET_EVENT(cur_socket, RW007_EVENT_SEND_OK));
-    }
-    else if (strstr(data, "SEND FAIL"))
-    {
-        at_socket_event_send(SET_EVENT(cur_socket, RW007_EVENT_SEND_FAIL));
-    }
-}
-
-static void urc_send_bfsz_func(const char *data, rt_size_t size)
-{
-    int send_bfsz = 0;
-
-    RT_ASSERT(data && size);
-
-    sscanf(data, "Recv %d bytes", &send_bfsz);
-
-    cur_send_bfsz = send_bfsz;
-}
-
-static void urc_close_func(const char *data, rt_size_t size)
-{
-    int socket = 0;
-
-    RT_ASSERT(data && size);
-
-    sscanf(data, "%d,CLOSED", &socket);
-    /* notice the socket is disconnect by remote */
-    if (at_evt_cb_set[AT_SOCKET_EVT_CLOSED])
-    {
-        at_evt_cb_set[AT_SOCKET_EVT_CLOSED](socket, AT_SOCKET_EVT_CLOSED, RT_NULL, 0);
-    }
-}
-
-static void urc_recv_func(const char *data, rt_size_t size)
-{
-    int socket = 0;
-    rt_size_t bfsz = 0, temp_size = 0;
-    rt_int32_t timeout;
-    char *recv_buf = RT_NULL, temp[8];
-
-    RT_ASSERT(data && size);
-
-    /* get the current socket and receive buffer size by receive data */
-    sscanf(data, "+IPD,%d,%d:", &socket, (int *) &bfsz);
-    /* get receive timeout by receive buffer length */
-    timeout = bfsz;
-
-    if (socket < 0 || bfsz == 0)
-        return;
-
-    recv_buf = rt_calloc(1, bfsz);
-    if (!recv_buf)
-    {
-        LOG_E("no memory for URC receive buffer (%d)!", bfsz);
-        /* read and clean the coming data */
-        while (temp_size < bfsz)
-        {
-            if (bfsz - temp_size > sizeof(temp))
-            {
-                at_client_recv(temp, sizeof(temp), timeout);
-            }
-            else
-            {
-                at_client_recv(temp, bfsz - temp_size, timeout);
-            }
-            temp_size += sizeof(temp);
-        }
-        return;
-    }
-
-    /* sync receive data */
-    if (at_client_recv(recv_buf, bfsz, timeout) != bfsz)
-    {
-        LOG_E("receive size(%d) data failed!", bfsz);
-        rt_free(recv_buf);
-        return;
-    }
-
-    /* notice the receive buffer and buffer size */
-    if (at_evt_cb_set[AT_SOCKET_EVT_RECV])
-    {
-        at_evt_cb_set[AT_SOCKET_EVT_RECV](socket, AT_SOCKET_EVT_RECV, recv_buf, bfsz);
-    }
-}
-
-static void urc_busy_p_func(const char *data, rt_size_t size)
-{
-    RT_ASSERT(data && size);
-
-    LOG_D("system is processing a commands and it cannot respond to the current commands.");
-}
-
-static void urc_busy_s_func(const char *data, rt_size_t size)
-{
-    RT_ASSERT(data && size);
-
-    LOG_D("system is sending data and it cannot respond to the current commands.");
-}
-
-static void urc_func(const char *data, rt_size_t size)
-{
-    RT_ASSERT(data && size);
-
-    if(strstr(data, "WIFI CONNECTED"))
-    {
-        LOG_I("RW007 WIFI is connected.");
-    }
-    else if(strstr(data, "WIFI DISCONNECT"))
-    {
-        LOG_I("RW007 WIFI is disconnect.");
-    }
-}
-
-static struct at_urc urc_table[] = {
-        {"SEND OK",          "\r\n",           urc_send_func},
-        {"SEND FAIL",        "\r\n",           urc_send_func},
-        {"Recv",             "bytes\r\n",      urc_send_bfsz_func},
-        {"",                 ",CLOSED\r\n",    urc_close_func},
-        {"+IPD",             ":",              urc_recv_func},
-        {"busy p",           "\r\n",           urc_busy_p_func},
-        {"busy s",           "\r\n",           urc_busy_s_func},
-        {"WIFI CONNECTED",   "\r\n",           urc_func},
-        {"WIFI DISCONNECT",  "\r\n",           urc_func},
-};
-
-#define AT_SEND_CMD(resp, cmd)                                                                          \
-    do                                                                                                  \
-    {                                                                                                   \
-        if (at_exec_cmd(at_resp_set_info(resp, 256, 0, rt_tick_from_millisecond(5000)), cmd) < 0)       \
-        {                                                                                               \
-            LOG_E("RT AT send commands(%s) error!", cmd);                                               \
-            result = -RT_ERROR;                                                                         \
-            goto __exit;                                                                                \
-        }                                                                                               \
-    } while(0);                                                                                         \
-
-static void rw007_init_thread_entry(void *parameter)
-{
-    at_response_t resp = RT_NULL;
-    rt_err_t result = RT_EOK;
-    rt_size_t i;
-
-    resp = at_create_resp(128, 0, rt_tick_from_millisecond(5000));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-
-    rt_thread_delay(rt_tick_from_millisecond(5000));
-    /* reset module */
-    AT_SEND_CMD(resp, "AT+RST");
-    /* reset waiting delay */
-    rt_thread_delay(rt_tick_from_millisecond(1000));
-    /* disable echo */
-    AT_SEND_CMD(resp, "ATE0");
-    /* set current mode to Wi-Fi station */
-    AT_SEND_CMD(resp, "AT+CWMODE=1");
-    /* get module version */
-    AT_SEND_CMD(resp, "AT+GMR");
-    /* show module version */
-    for (i = 0; i < resp->line_counts - 1; i++)
-    {
-        LOG_D("%s", at_resp_get_line(resp, i + 1));
-    }
-    /* connect to WiFi AP */
-    if (at_exec_cmd(at_resp_set_info(resp, 128, 0, 20 * RT_TICK_PER_SECOND), "AT+CWJAP=\"%s\",\"%s\"",
-            AT_DEVICE_WIFI_SSID, AT_DEVICE_WIFI_PASSWORD) != RT_EOK)
-    {
-        LOG_E("AT network initialize failed, check ssid(%s) and password(%s).", AT_DEVICE_WIFI_SSID, AT_DEVICE_WIFI_PASSWORD);
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    AT_SEND_CMD(resp, "AT+CIPMUX=1");
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    if (!result)
-    {
-        LOG_I("AT network initialize success!");
-    }
-    else
-    {
-        LOG_E("AT network initialize failed (%d)!", result);
-    }
-}
-
-int rw007_net_init(void)
-{
-#ifdef PKG_AT_INIT_BY_THREAD
-    rt_thread_t tid;
-
-    tid = rt_thread_create("rw007_net_init", rw007_init_thread_entry, RT_NULL,RW007_THREAD_STACK_SIZE, RW007_THREAD_PRIORITY, 20);
-    if (tid)
-    {
-        rt_thread_startup(tid);
-    }
-    else
-    {
-        LOG_E("Create AT initialization thread fail!");
-    }
-#else
-    rw007_init_thread_entry(RT_NULL);
-#endif
-
-    return RT_EOK;
-}
-
-int rw007_ping(int argc, char **argv)
-{
-    at_response_t resp = RT_NULL;
-    static int icmp_seq;
-    int req_time;
-
-    if (argc != 2)
-    {
-        rt_kprintf("Please input: at_ping <host address>\n");
-        return -RT_ERROR;
-    }
-
-    resp = at_create_resp(64, 0, rt_tick_from_millisecond(5000));
-    if (!resp)
-    {
-        rt_kprintf("No memory for response structure!\n");
-        return -RT_ENOMEM;
-    }
-
-    for(icmp_seq = 1; icmp_seq <= 4; icmp_seq++)
-    {
-        if (at_exec_cmd(resp, "AT+PING=\"%s\"", argv[1]) < 0)
-        {
-            rt_kprintf("ping: unknown remote server host\n");
-            at_delete_resp(resp);
-            return -RT_ERROR;
-        }
-
-        if(at_resp_parse_line_args_by_kw(resp, "+", "+%d", &req_time) < 0)
-        {
-            continue;
-        }
-
-        if (req_time)
-        {
-            rt_kprintf("32 bytes from %s icmp_seq=%d time=%d ms\n", argv[1], icmp_seq, req_time);
-        }
-    }
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return RT_EOK;
-}
-
-#ifdef FINSH_USING_MSH
-#include <finsh.h>
-MSH_CMD_EXPORT_ALIAS(rw007_net_init, at_net_init, initialize AT network);
-MSH_CMD_EXPORT_ALIAS(rw007_ping, at_ping, AT ping network host);
-#endif
-
-static const struct at_device_ops rw007_socket_ops = {
-    rw007_socket_connect,
-    rw007_socket_close,
-    rw007_socket_send,
-    rw007_domain_resolve,
-    rw007_socket_set_event_cb,
-};
-
-static int rw007_netdev_add(const char *netdev_name)
-{
-#define ETHERNET_MTU        1500
-#define HWADDR_LEN          8
-    struct netdev *netdev = RT_NULL;
-    int result = 0;
-
-    RT_ASSERT(netdev_name);
-
-    netdev = (struct netdev *) rt_calloc(1, sizeof(struct netdev));
-    if (netdev == RT_NULL)
-    {
-        return RT_NULL;
-    }
-
-    /* TODO: improve netdev adaptation */
-    netdev->mtu = ETHERNET_MTU;
-    netdev->hwaddr_len = HWADDR_LEN;
-    netdev->ops = RT_NULL;
-
-#ifdef SAL_USING_AT
-    extern int sal_at_netdev_set_pf_info(struct netdev *netdev);
-    /* set the network interface socket/netdb operations */
-    sal_at_netdev_set_pf_info(netdev);
-#endif
-
-    result = netdev_register(netdev, netdev_name, RT_NULL);
-
-    /*TODO: improve netdev adaptation */
-    netdev_low_level_set_status(netdev, RT_TRUE);
-    netdev_low_level_set_link_status(netdev, RT_TRUE);
-    netdev_low_level_set_dhcp_status(netdev, RT_TRUE);
-    netdev->flags |= NETDEV_FLAG_INTERNET_UP;
-
-    return result;
-}
-
-static int at_socket_device_init(void)
-{
-    /* create current AT socket event */
-    at_socket_event = rt_event_create("at_se", RT_IPC_FLAG_FIFO);
-    if (at_socket_event == RT_NULL)
-    {
-        LOG_E("RT AT client port initialize failed! at_sock_event create failed!");
-        return -RT_ENOMEM;
-    }
-
-    /* create current AT socket event lock */
-    at_event_lock = rt_mutex_create("at_se", RT_IPC_FLAG_FIFO);
-    if (at_event_lock == RT_NULL)
-    {
-        LOG_E("RT AT client port initialize failed! at_sock_lock create failed!");
-        rt_event_delete(at_socket_event);
-        return -RT_ENOMEM;
-    }
-
-    /* initialize AT client */
-    at_client_init(AT_DEVICE_NAME, AT_DEVICE_RECV_BUFF_LEN);
-
-    /* register URC data execution function  */
-    at_set_urc_table(urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
-
-    /* add network interface device to netdev list */
-    if (rw007_netdev_add(RW007_NETDEV_NAME) < 0)
-    {
-        LOG_E("RW007 network interface device(%d) add failed.", RW007_NETDEV_NAME);
-        return -RT_ENOMEM;
-    }
-
-    /* initialize rw007 network */
-    rw007_net_init();
-
-    /* set rw007 AT Socket options */
-    at_socket_device_register(&rw007_socket_ops);
-
-    return RT_EOK;
-}
-INIT_APP_EXPORT(at_socket_device_init);
-
-#endif /* AT_DEVICE_RW007 */

+ 0 - 1225
at_socket_sim76xx.c

@@ -1,1225 +0,0 @@
-/*
- * File      : at_socket_sim76xx.c
- * This file is part of RT-Thread RTOS
- * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Change Logs:
- * Date           Author       Notes
- * 2018-12-22    thomasonegd  first version
- * 2019-03-06    thomasonegd  fix udp connection.
- * 2019-03-08    thomasonegd  add power_on & power_off api
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include <rtthread.h>
-#include <sys/socket.h>
-
-#include <at.h>
-#include <at_socket.h>
-
-#if !defined(RT_USING_NETDEV)
-#error "This RT-Thread version is older, please check and updata laster RT-Thread!"
-#else
-#include <arpa/inet.h>
-#include <netdev.h>
-#endif /* RT_USING_NETDEV */
-
-#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10200
-#error "This AT Client version is older, please check and update latest AT Client!"
-#endif
-
-#define LOG_TAG              "at.sim76xx"
-#include <at_log.h>
-
-#ifdef AT_DEVICE_SIM76XX
-
-#define SIM76XX_NETDEV_NAME            "sim76xx"
-
-#define SIM76XX_MODULE_SEND_MAX_SIZE   1500
-#define SIM76XX_WAIT_CONNECT_TIME      5000
-#define SIM76XX_THREAD_STACK_SIZE      1024
-#define SIM76XX_THREAD_PRIORITY        (RT_THREAD_PRIORITY_MAX/2)
-
-#define SIM76XX_MAX_CONNECTIONS        10
-
-/* set real event by current socket and current state */
-#define SET_EVENT(socket, event)       (((socket + 1) << 16) | (event))
-
-/* AT socket event type */
-#define SIM76XX_EVENT_CONN_OK          (1L << 0)
-#define SIM76XX_EVENT_SEND_OK          (1L << 1)
-#define SIM76XX_EVENT_RECV_OK          (1L << 2)
-#define SIM76XX_EVNET_CLOSE_OK         (1L << 3)
-#define SIM76XX_EVENT_CONN_FAIL        (1L << 4)
-#define SIM76XX_EVENT_SEND_FAIL        (1L << 5)
-
-uint8_t at_socket_init = 0;
-
-static int cur_socket;
-static int cur_send_bfsz;
-static rt_event_t at_socket_event;
-static rt_mutex_t at_event_lock;
-static at_evt_cb_t at_evt_cb_set[] = {
-        [AT_SOCKET_EVT_RECV] = NULL,
-        [AT_SOCKET_EVT_CLOSED] = NULL,
-};
-
-static char udp_ipstr[SIM76XX_MAX_CONNECTIONS][16];
-static int udp_port[SIM76XX_MAX_CONNECTIONS];
-
-static void at_tcp_ip_errcode_parse(int result)//Unsolicited TCP/IP command<err> codes
-{
-    switch(result)
-    {
-    case 0   : LOG_D("%d : operation succeeded ",           result); break;
-    case 1 : LOG_E("%d : UNetwork failure",                 result); break;
-    case 2 : LOG_E("%d : Network not opened",               result); break;
-    case 3 : LOG_E("%d : Wrong parameter",                  result); break;
-    case 4 : LOG_E("%d : Operation not supported",          result); break;
-    case 5 : LOG_E("%d : Failed to create socket",          result); break;
-    case 6 : LOG_E("%d : Failed to bind socket",            result); break;
-    case 7 : LOG_E("%d : TCP server is already listening",  result); break;
-    case 8 : LOG_E("%d : Busy",                             result); break;
-    case 9 : LOG_E("%d : Sockets opened",                   result); break;
-    case 10 : LOG_E("%d : Timeout ",                        result); break;
-    case 11 : LOG_E("%d : DNS parse failed for AT+CIPOPEN", result); break;
-    case 255 : LOG_E("%d : Unknown error",                  result); break;
-    }
-}
-
-
-static int at_socket_event_send(uint32_t event)
-{
-    return (int) rt_event_send(at_socket_event, event);
-}
-
-static int at_socket_event_recv(uint32_t event, uint32_t timeout, rt_uint8_t option)
-{
-    int result = 0;
-    rt_uint32_t recved;
-
-    result = rt_event_recv(at_socket_event, event, option | RT_EVENT_FLAG_CLEAR, timeout, &recved);
-    if (result != RT_EOK)
-    {
-        return -RT_ETIMEOUT;
-    }
-
-    return recved;
-}
-
-/**
- * close socket by AT commands.
- *
- * @param current socket
- *
- * @return  0: close socket success
- *         -1: send AT commands error
- *         -2: wait socket event timeout
- *         -5: no memory
- */
-static int sim76xx_socket_close(int socket)
-{
-    at_response_t resp = RT_NULL;
-    int result = RT_EOK;
-    int activated;
-    uint8_t lnk_stat[10];
-    
-    resp = at_create_resp(128, 0, rt_tick_from_millisecond(500));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-    
-    rt_thread_delay(rt_tick_from_millisecond(100));
-    
-    // check socket link_state
-    if (at_exec_cmd(resp,"AT+CIPCLOSE?") < 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-    
-    if(at_resp_parse_line_args_by_kw(resp,"+CIPCLOSE:", "+CIPCLOSE: %d,%d,%d,%d,%d,%d,%d,%d,%d,%d",&lnk_stat[0],&lnk_stat[1],&lnk_stat[1]
-        ,&lnk_stat[2],&lnk_stat[3],&lnk_stat[4],&lnk_stat[5],&lnk_stat[6],&lnk_stat[7],&lnk_stat[8],&lnk_stat[9]) < 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-       
-    if (lnk_stat[socket])
-    {
-        // close tcp or udp socket if connected
-        if (at_exec_cmd(resp, "AT+CIPCLOSE=%d", socket) < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }            
-    }
-    // check the network open or not
-    if (at_exec_cmd(resp,"AT+NETOPEN?") < 0)
-    {
-        result = -RT_ERROR;
-        
-        goto __exit;
-    }
-    
-    if(at_resp_parse_line_args_by_kw(resp, "+NETOPEN:", "+NETOPEN: %d", &activated) < 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-    
-    if (activated)
-    {
-        // if already open,then close it.
-        if (at_exec_cmd(resp,"AT+NETCLOSE") < 0)
-        {
-            result = -RT_ERROR;
-            
-            goto __exit;
-        }
-    }
- __exit:
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-/**
- * open packet network
- */
-static int sim76xx_network_socket_open(void)
-{
-    int result = RT_EOK;
-    at_response_t resp = RT_NULL;
-    int activated;
- 
-    resp = at_create_resp(128, 0, rt_tick_from_millisecond(5000));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-   
-    // check the network open or not
-    if (at_exec_cmd(resp,"AT+NETOPEN?") < 0)
-    {
-        result = -RT_ERROR;
-        
-        goto __exit;
-    }
-    
-    if(at_resp_parse_line_args_by_kw(resp, "+NETOPEN:", "+NETOPEN: %d", &activated) < 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-    
-    if (activated)
-    {//network socket is already opened
-        goto __exit;
-    }else
-    {
-        // if not opened the open it.
-        if (at_exec_cmd(resp,"AT+NETOPEN") < 0)
-        {
-            result = -RT_ERROR;
-            
-            goto __exit;
-        }
-    }    
-__exit:
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-/**
- * create TCP/UDP client or server connect by AT commands.
- *
- * @param socket current socket
- * @param ip server or client IP address
- * @param port server or client port
- * @param type connect socket type(tcp, udp)
- * @param is_client connection is client
- *
- * @return   0: connect success
- *          -1: connect failed, send commands error or type error
- *          -2: wait socket event timeout
- *          -5: no memory
- */
-static int sim76xx_socket_connect(int socket, char *ip, int32_t port, enum at_socket_type type, rt_bool_t is_client)
-{
-    at_response_t resp = RT_NULL;
-    int result = RT_EOK,event_result = 0;
-    rt_bool_t retryed = RT_FALSE;
-
-    RT_ASSERT(ip);
-    RT_ASSERT(port >= 0);
-
-    resp = at_create_resp(128, 0, rt_tick_from_millisecond(5000));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-__retry:
-    if (is_client)
-    {
-        //open network socket first(AT+NETOPEN)
-        sim76xx_network_socket_open();
-        
-        switch (type)
-        {
-        case AT_SOCKET_TCP:        
-            /* send AT commands to connect TCP server */
-            if (at_exec_cmd(resp, "AT+CIPOPEN=%d,\"TCP\",\"%s\",%d", socket, ip, port) < 0)
-            {
-                result = -RT_ERROR;
-            }
-            break;
-
-        case AT_SOCKET_UDP:
-            if (at_exec_cmd(resp, "AT+CIPOPEN=%d,\"UDP\",,,%d", socket, port) < 0)
-            {
-                result = -RT_ERROR;
-            }
-            strcpy(udp_ipstr[socket],ip);
-            udp_port[socket] = port;
-            break;
-
-        default:
-            LOG_E("Not supported connect type : %d.", type);
-            result = -RT_ERROR;
-            goto __exit;
-        }
-    }
-    
-    /* waiting result event from AT URC, the device default connection timeout is 75 seconds, but it set to 10 seconds is convenient to use.*/
-    if (at_socket_event_recv(SET_EVENT(socket, 0), rt_tick_from_millisecond(10 * 1000), RT_EVENT_FLAG_OR) < 0)
-    {
-        LOG_E("socket (%d) connect failed, wait connect result timeout.", socket);
-        result = -RT_ETIMEOUT;
-        goto __exit;
-    }
-    /* waiting OK or failed result */
-    if ((event_result = at_socket_event_recv(SIM76XX_EVENT_CONN_OK | SIM76XX_EVENT_CONN_FAIL, rt_tick_from_millisecond(1 * 1000),
-            RT_EVENT_FLAG_OR)) < 0)
-    {
-        LOG_E("socket (%d) connect failed, wait connect OK|FAIL timeout.", socket);
-        result = -RT_ETIMEOUT;
-        goto __exit;
-    }
-    /* check result */
-    if (event_result & SIM76XX_EVENT_CONN_FAIL)
-    {
-        if (!retryed)
-        {
-            LOG_E("socket (%d) connect failed, maybe the socket was not be closed at the last time and now will retry.", socket);
-            if (sim76xx_socket_close(socket) < 0)
-            {
-                goto __exit;
-            }
-            retryed = RT_TRUE;
-            goto __retry;
-        }
-        LOG_E("socket (%d) connect failed, failed to establish a connection.", socket);
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    if (result != RT_EOK && !retryed)
-    {
-        LOG_D("socket (%d) connect failed, maybe the socket was not be closed at the last time and now will retry.", socket);
-        if (sim76xx_socket_close(socket) < 0)
-        {
-            goto __exit;
-        }
-        retryed = RT_TRUE;
-        result = RT_EOK;
-        goto __retry;
-    }
-
-__exit:
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-/**
- * send data to server or client by AT commands.
- *
- * @param socket current socket
- * @param buff send buffer
- * @param bfsz send buffer size
- * @param type connect socket type(tcp, udp)
- *
- * @return >=0: the size of send success
- *          -1: send AT commands error or send data error
- *          -2: waited socket event timeout
- *          -5: no memory
- */
-static int sim76xx_socket_send(int socket, const char *buff, size_t bfsz, enum at_socket_type type)
-{
-    int result = RT_EOK;
-    int event_result = 0;
-    at_response_t resp = RT_NULL;
-    size_t cur_pkt_size = 0, sent_size = 0;
-
-    RT_ASSERT(buff);
-    RT_ASSERT(bfsz > 0);
-
-    resp = at_create_resp(128, 2, rt_tick_from_millisecond(5000));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    /* set current socket for send URC event */
-    cur_socket = socket;
-    /* set AT client end sign to deal with '>' sign.*/
-    at_set_end_sign('>');
-
-    while (sent_size < bfsz)
-    {
-        if (bfsz - sent_size < SIM76XX_MODULE_SEND_MAX_SIZE)
-        {
-            cur_pkt_size = bfsz - sent_size;
-        }
-        else
-        {
-            cur_pkt_size = SIM76XX_MODULE_SEND_MAX_SIZE;
-        }
-        
-        switch(type)
-        {
-        case AT_SOCKET_TCP:
-            /* send the "AT+CIPSEND" commands to AT server than receive the '>' response on the first line. */
-            if (at_exec_cmd(resp, "AT+CIPSEND=%d,%d", socket, cur_pkt_size) < 0)
-            {
-                result = -RT_ERROR;
-                goto __exit;
-            }
-            break;
-        case AT_SOCKET_UDP:
-            /* send the "AT+CIPSEND" commands to AT server than receive the '>' response on the first line. */
-            if (at_exec_cmd(resp, "AT+CIPSEND=%d,%d,\"%s\",%d", socket, cur_pkt_size,udp_ipstr[socket],udp_port[socket]) < 0)
-            {
-                result = -RT_ERROR;
-                goto __exit;
-            }
-            break;
-        }
-        
-        /* send the real data to server or client */
-        result = (int) at_client_send(buff + sent_size, cur_pkt_size);
-        if (result == 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* waiting result event from AT URC */
-        if (at_socket_event_recv(SET_EVENT(socket, 0), rt_tick_from_millisecond(5 * 1000), RT_EVENT_FLAG_OR) < 0)
-        {
-            LOG_E("socket (%d) send failed, wait connect result timeout.", socket);
-            result = -RT_ETIMEOUT;
-            goto __exit;
-        }
-        /* waiting OK or failed result */
-        if ((event_result = at_socket_event_recv(SIM76XX_EVENT_SEND_OK | SIM76XX_EVENT_SEND_FAIL, rt_tick_from_millisecond(5 * 1000),
-                RT_EVENT_FLAG_OR)) < 0)
-        {
-            LOG_E("socket (%d) send failed, wait connect OK|FAIL timeout.", socket);
-            result = -RT_ETIMEOUT;
-            goto __exit;
-        }
-        /* check result */
-        if (event_result & SIM76XX_EVENT_SEND_FAIL)
-        {
-            LOG_E("socket (%d) send failed, return failed.", socket);
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        if (type == AT_SOCKET_TCP)
-        {
-            cur_pkt_size = cur_send_bfsz;
-        }
-
-        sent_size += cur_pkt_size;
-    }
-
-__exit:
-    /* reset the end sign for data */
-    at_set_end_sign(0);
-
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-/**
- * domain resolve by AT commands.
- *
- * @param name domain name
- * @param ip parsed IP address, it's length must be 16
- *
- * @return  0: domain resolve success
- *         -2: wait socket event timeout
- *         -5: no memory
- */
-static int sim76xx_domain_resolve(const char *name, char ip[16])
-{
-#define RESOLVE_RETRY        5
-
-    int i, result = RT_EOK;
-    char domain[32] = { 0 };
-    char domain_ip[16] = {0};
-    at_response_t resp = RT_NULL;
-
-    RT_ASSERT(name);
-    RT_ASSERT(ip);
-
-    resp = at_create_resp(128, 0, rt_tick_from_millisecond(5000));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    for(i = 0; i < RESOLVE_RETRY; i++)
-    {
-        if (at_exec_cmd(resp, "AT+CDNSGIP=\"%s\"", name) < 0)
-        {
-            rt_thread_delay(rt_tick_from_millisecond(200));
-            /* resolve failed, maybe receive an URC CRLF */
-            continue;
-        }
-
-        /* parse the third line of response data, get the IP address */
-        /* +CDNSGIP: 1,"www.baidu.com","14.215.177.39" */
-        if(at_resp_parse_line_args_by_kw(resp, "+CDNSGIP:", "+CDNSGIP: 1,%[^,],\"%[^\"]", domain,domain_ip) < 0)
-        {
-            rt_thread_delay(rt_tick_from_millisecond(200));
-            /* resolve failed, maybe receive an URC CRLF */
-            continue;
-        }
-
-        if (strlen(domain_ip) < 8)
-        {
-            rt_thread_delay(rt_tick_from_millisecond(200));
-            /* resolve failed, maybe receive an URC CRLF */
-            continue;
-        }
-        else
-        {
-            strncpy(ip, domain_ip, 15);
-            ip[15] = '\0';
-            break;
-        }
-    }
-
-    rt_mutex_release(at_event_lock);
-
-    if (i == RESOLVE_RETRY)
-    {
-        result = -RT_ERROR;        
-    }
-    
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-
-}
-
-/**
- * set AT socket event notice callback
- *
- * @param event notice event
- * @param cb notice callback
- */
-static void sim76xx_socket_set_event_cb(at_socket_evt_t event, at_evt_cb_t cb)
-{
-    if (event < (sizeof(at_evt_cb_set) / sizeof(at_evt_cb_set[1])))
-    {
-        at_evt_cb_set[event] = cb;
-    }
-}
-
-static void urc_send_func(const char *data, rt_size_t size)
-{
-    int socket = 0;
-    int rqst_size;
-    int cnf_size;
-    
-    RT_ASSERT(data && size);
-
-    sscanf(data,"+CIPSEND: %d,%d,%d",&socket,&rqst_size,&cnf_size);
-    
-    cur_send_bfsz = cnf_size;
-    
-    at_socket_event_send(SET_EVENT(socket, SIM76XX_EVENT_SEND_OK));
-}
-
-static void urc_ping_func(const char *data, rt_size_t size)
-{
-    static int icmp_seq = 0;
-    int i, j = 0;
-    int result, recv_len, time, ttl;
-    int sent, rcvd, lost, min, max, avg;
-    char dst_ip[16] = { 0 };
-
-    RT_ASSERT(data);
-
-    for (i=0;i<size;i++)
-    {
-        if(*(data+i) == '.')
-            j++;
-    }
-    if (j != 0)
-    {
-        sscanf(data, "+CPING: %d,%[^,],%d,%d,%d", &result, dst_ip, &recv_len, &time, &ttl);
-        if (result == 1)
-            LOG_I("%d bytes from %s icmp_seq=%d ttl=%d time=%d ms", recv_len, dst_ip, icmp_seq++, ttl, time);
-    }
-    else
-    {
-        sscanf(data, "+CPING: %d,%d,%d,%d,%d,%d,%d", &result, &sent, &rcvd, &lost, &min, &max, &avg);
-        if (result == 3)
-            LOG_I("%d sent %d received %d lost, min=%dms max=%dms average=%dms", sent, rcvd, lost, min, max, avg);
-        if (result == 2)
-            LOG_I("ping requst timeout");            
-    }
-}
-
-
-static void urc_connect_func(const char *data, rt_size_t size)
-{
-    int socket = 0;
-    int result = 0;
-
-    RT_ASSERT(data && size);
-
-    sscanf(data, "+CIPOPEN: %d,%d", &socket , &result);
-
-    if (result == 0)
-    {
-        at_socket_event_send(SET_EVENT(socket, SIM76XX_EVENT_CONN_OK));
-    }
-    else
-    {
-        at_tcp_ip_errcode_parse(result);
-        at_socket_event_send(SET_EVENT(socket, SIM76XX_EVENT_CONN_FAIL));
-    }
-}
-
-static void urc_close_func(const char *data, rt_size_t size)
-{
-    int socket = 0;
-    int reason = 0;
-
-    RT_ASSERT(data && size);
-
-    sscanf(data, "+IPCLOSE %d,%d", &socket, &reason);
-    
-    switch(reason)
-    {
-    case 0:
-        LOG_E("socket is closed by local,active");
-        break;
-    case 1:
-        LOG_E("socket is closed by remote,passive");
-        break;
-    case 2:
-        LOG_E("socket is closed for sending timeout");
-        break;
-    }
-    
-    /* notice the socket is disconnect by remote */
-    if (at_evt_cb_set[AT_SOCKET_EVT_CLOSED])
-    {
-        at_evt_cb_set[AT_SOCKET_EVT_CLOSED](socket, AT_SOCKET_EVT_CLOSED, RT_NULL, 0);
-    }
-}
-
-static void urc_recv_func(const char *data, rt_size_t size)
-{
-    rt_size_t bfsz = 0, temp_size = 0;
-    rt_int32_t timeout;
-    char *recv_buf = RT_NULL, temp[8];
-
-    RT_ASSERT(data && size);
-
-    /* get the current socket and receive buffer size by receive data */
-    sscanf(data, "+IPD%d:",(int *) &bfsz);
-    /* get receive timeout by receive buffer length */
-    timeout = bfsz * 10;
-
-    if (bfsz == 0)
-        return;
-
-    recv_buf = rt_calloc(1, bfsz);
-    if (!recv_buf)
-    {
-        LOG_E("no memory for URC receive buffer (%d)!", bfsz);
-        /* read and clean the coming data */
-        while (temp_size < bfsz)
-        {
-            if (bfsz - temp_size > sizeof(temp))
-            {
-                at_client_recv(temp, sizeof(temp), timeout);
-            }
-            else
-            {
-                at_client_recv(temp, bfsz - temp_size, timeout);
-            }
-            temp_size += sizeof(temp);
-        }
-        return;
-    }
-
-    /* sync receive data */
-    if (at_client_recv(recv_buf, bfsz, timeout) != bfsz)
-    {
-        LOG_E("receive size(%d) data failed!", bfsz);
-        rt_free(recv_buf);
-        return;
-    }
-
-    /* notice the receive buffer and buffer size */
-    if (at_evt_cb_set[AT_SOCKET_EVT_RECV])
-    {
-        at_evt_cb_set[AT_SOCKET_EVT_RECV](cur_socket, AT_SOCKET_EVT_RECV, recv_buf, bfsz);
-    }
-}
-
-static struct at_urc urc_table[] = {
-        {"+CIPSEND:",      "\r\n",           urc_send_func},
-        {"+CIPOPEN:",      "\r\n",           urc_connect_func},
-        {"+CPING:",        "\r\n",           urc_ping_func},
-        {"+IPCLOSE",       "\r\n",           urc_close_func},
-        {"+IPD",           "\r\n",           urc_recv_func},
-};
-
-#define AT_SEND_CMD(resp, cmd)                                                                          \
-    do                                                                                                  \
-    {                                                                                                   \
-        if (at_exec_cmd(at_resp_set_info(resp, 256, 0, rt_tick_from_millisecond(5000)), cmd) < 0)       \
-        {                                                                                               \
-            LOG_E("RT AT send commands(%s) error!", cmd);                                               \
-            result = -RT_ERROR;                                                                         \
-            goto __exit;                                                                                \
-        }                                                                                               \
-    } while(0);                                                                                         \
-
-
-/**
- * power up sim76xx modem
- */
-static void sim76xx_power_on(void)
-{
-    rt_pin_write(AT_DEVICE_POWER_PIN, PIN_HIGH);
-    rt_thread_delay(rt_tick_from_millisecond(300));
-    rt_pin_write(AT_DEVICE_POWER_PIN, PIN_LOW);
-    
-    while (rt_pin_read(AT_DEVICE_STATUS_PIN) == PIN_LOW)
-    {
-        rt_thread_delay(rt_tick_from_millisecond(10));
-    }
-}
-
-static void sim76xx_power_off(void)
-{
-    rt_pin_write(AT_DEVICE_POWER_PIN, PIN_HIGH);
-    rt_thread_delay(rt_tick_from_millisecond(3000));
-    rt_pin_write(AT_DEVICE_POWER_PIN, PIN_LOW);
-    
-    while (rt_pin_read(AT_DEVICE_STATUS_PIN) == PIN_HIGH)
-    {
-        rt_thread_delay(rt_tick_from_millisecond(10));
-    }
-    rt_pin_write(AT_DEVICE_POWER_PIN, PIN_LOW);
-}
-        
-  
-static void sim76xx_init_thread_entry(void *parameter)
-{
-#define CSQ_RETRY                      20
-#define CREG_RETRY                     10
-#define CGREG_RETRY                    20
-#define CGATT_RETRY                    10
-#define CCLK_RETRY                     10
-    
-    at_response_t resp = RT_NULL;
-    rt_err_t result = RT_EOK;
-    rt_size_t i, qi_arg[3];
-    char parsed_data[20];
-
-    resp = at_create_resp(128, 0, rt_tick_from_millisecond(300));
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-    
-    /* power-up sim76xx */
-    sim76xx_power_on();
-        
-    LOG_D("Start initializing the SIM76XXE module");
-    /* wait SIM76XX startup finish, Send AT every 5s, if receive OK, SYNC success*/
-    if (at_client_wait_connect(SIM76XX_WAIT_CONNECT_TIME))
-    {
-        result = -RT_ETIMEOUT;
-        goto __exit;
-    }
-    
-    /* disable echo */
-    AT_SEND_CMD(resp, "ATE0");
-    
-    /* get module version */
-    AT_SEND_CMD(resp, "ATI");
-    
-    /* show module version */
-    for (i = 0; i < (int) resp->line_counts - 1; i++)
-    {
-        LOG_D("%s", at_resp_get_line(resp, i + 1));
-    }
-    /* check SIM card */
-    
-    AT_SEND_CMD(resp, "AT+CPIN?");
-    if (!at_resp_get_line_by_kw(resp, "READY"))
-    {
-        LOG_E("SIM card detection failed");
-        result = -RT_ERROR;
-        goto __exit;
-    }
-    
-    /* waiting for dirty data to be digested */
-    rt_thread_delay(rt_tick_from_millisecond(10));
-    /* check signal strength */
-    for (i = 0; i < CSQ_RETRY; i++)
-    {
-        AT_SEND_CMD(resp, "AT+CSQ");
-        at_resp_parse_line_args_by_kw(resp, "+CSQ:", "+CSQ: %d,%d", &qi_arg[0], &qi_arg[1]);
-        if (qi_arg[0] != 99)
-        {
-            LOG_D("Signal strength: %d  Channel bit error rate: %d", qi_arg[0], qi_arg[1]);
-            break;
-        }
-        rt_thread_delay(rt_tick_from_millisecond(1000));
-    }
-        
-    if (i == CSQ_RETRY)
-    {
-        LOG_E("Signal strength check failed (%s)", parsed_data);
-        result = -RT_ERROR;
-        goto __exit;
-    }
-    
-    //do not show the prompt when receiving data    
-    AT_SEND_CMD(resp, "AT+CIPSRIP=0");
-    
-    /* check the GSM network is registered */
-    for (i = 0; i < CREG_RETRY; i++)
-    {
-        AT_SEND_CMD(resp,"AT+CREG?");
-        at_resp_parse_line_args_by_kw(resp, "+CREG:", "+CREG: %s", &parsed_data);
-        if (!strncmp(parsed_data, "0,1", sizeof(parsed_data)) || !strncmp(parsed_data, "0,5", sizeof(parsed_data)))
-        {
-            LOG_D("GSM network is registered (%s)", parsed_data);
-            break;
-        }
-        rt_thread_delay(rt_tick_from_millisecond(1000));
-    }
-    if (i == CREG_RETRY)
-    {
-        LOG_E("The GSM network is register failed (%s)", parsed_data);
-        result = -RT_ERROR;
-        goto __exit;
-    }
-    /* check the GPRS network is registered */
-    for (i = 0; i < CGREG_RETRY; i++)
-    {
-        AT_SEND_CMD(resp,"AT+CGREG?");
-        at_resp_parse_line_args_by_kw(resp, "+CGREG:", "+CGREG: %s", &parsed_data);
-        if (!strncmp(parsed_data, "0,1", sizeof(parsed_data)) || !strncmp(parsed_data, "0,5", sizeof(parsed_data)))
-        {
-            LOG_D("GPRS network is registered (%s)", parsed_data);
-            break;
-        }
-        rt_thread_delay(rt_tick_from_millisecond(1000));
-    }
-    
-    if (i == CGREG_RETRY)
-    {
-        LOG_E("The GPRS network is register failed (%s)", parsed_data);
-        result = -RT_ERROR;
-        goto __exit;
-    }
-    
-    /* check packet domain attach or detach */
-    for (i = 0;i < CGATT_RETRY; i++)
-    {
-        AT_SEND_CMD(resp,"AT+CGATT?")
-        at_resp_parse_line_args_by_kw(resp,"+CGATT:","+CGATT: %s",&parsed_data);
-        if (!strncmp(parsed_data,"1",1))
-        {
-            LOG_I("Packet domain attach");
-            break;
-        }
-        
-        rt_thread_delay(rt_tick_from_millisecond(1000));
-    }
-    
-    if (i == CGATT_RETRY)
-    {
-        LOG_E("The GPRS network attach failed");
-        result = -RT_ERROR;
-        goto __exit;
-    }
-    
-    /* get real time */
-    int year,month,day,hour,min,sec;
-    
-    for (i = 0;i < CCLK_RETRY;i++)
-    {
-        if (at_exec_cmd(at_resp_set_info(resp, 256, 0, rt_tick_from_millisecond(5000)), "AT+CCLK?") < 0)
-        { 
-            rt_thread_delay(rt_tick_from_millisecond(500));
-            continue;
-        }
-        
-        //+CCLK: "18/12/22,18:33:12+32"
-        if (at_resp_parse_line_args_by_kw(resp,"+CCLK:","+CCLK: \"%d/%d/%d,%d:%d:%d",&year,&month,&day,&hour,&min,&sec) < 0)
-        {
-            rt_thread_delay(rt_tick_from_millisecond(500));
-            continue;
-        }
-        
-        set_date(year + 2000,month,day);
-        set_time(hour,min,sec);
-        
-        break;
-    }
-    
-    if (i == CCLK_RETRY)
-    {
-        LOG_E("The GPRS network attach failed");
-        result = -RT_ERROR;
-        goto __exit;
-    }
-    
-    /* set active PDP context's profile number */
-    AT_SEND_CMD(resp, "AT+CSOCKSETPN=1");
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    if (!result)
-    {
-        LOG_I("AT network initialize success!");
-        at_socket_init = 1;
-    }
-    else
-    {
-        LOG_E("AT network initialize failed (%d)!", result);
-    }
-}
-
-int sim76xx_net_init(void)
-{
-#ifdef PKG_AT_INIT_BY_THREAD
-    rt_thread_t tid;
-
-    tid = rt_thread_create("sim76xx_net_init", sim76xx_init_thread_entry, RT_NULL,SIM76XX_THREAD_STACK_SIZE, SIM76XX_THREAD_PRIORITY, 20);
-    if (tid)
-    {
-        rt_thread_startup(tid);
-    }
-    else
-    {
-        LOG_E("Create AT initialization thread fail!");
-    }
-#else
-    sim76xx_init_thread_entry(RT_NULL);
-#endif
-
-    return RT_EOK;
-}
-
-int sim76xx_ping(int argc, char **argv)
-{
-    at_response_t resp = RT_NULL;
-
-    if (argc != 2)
-    {
-        rt_kprintf("Please input: at_ping <host address>\n");
-        return -RT_ERROR;
-    }
-
-    resp = at_create_resp(64, 0, rt_tick_from_millisecond(5000));
-    if (!resp)
-    {
-        rt_kprintf("No memory for response structure!\n");
-        return -RT_ENOMEM;
-    }
-
-    if (at_exec_cmd(resp, "AT+CPING=\"%s\",1,4,64,1000,10000,255", argv[1]) < 0)
-    {
-        if (resp)
-        {
-            at_delete_resp(resp);
-        }
-        rt_kprintf("AT send ping commands error!\n");
-        return -RT_ERROR;
-    }
-    
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return RT_EOK;
-}
-
-int sim76xx_connect(int argc, char **argv)
-{
-    int32_t port;
-
-    if (argc != 3)
-    {
-        rt_kprintf("Please input: at_connect <host address>\n");
-        return -RT_ERROR;
-    }
-    sscanf(argv[2],"%d",&port);
-    sim76xx_socket_connect(0, argv[1], port, AT_SOCKET_TCP, 1);
-
-    return RT_EOK;
-}
-
-int sim76xx_close(int argc, char **argv)
-{
-    if (sim76xx_socket_close(0) < 0)
-    {
-        rt_kprintf("sim76xx_socket_close fail\n");
-    }
-    else
-    {
-        rt_kprintf("sim76xx_socket_closeed\n");
-    }
-    return RT_EOK;
-}
-
-int sim76xx_send(int argc, char **argv)
-{
-    const char *buff = "1234567890\n";
-    if (sim76xx_socket_send(0, buff, 11, AT_SOCKET_TCP) < 0)
-    {
-        rt_kprintf("sim76xx_socket_send fail\n");
-    }
-
-    return RT_EOK;
-}
-
-int sim76xx_domain(int argc, char **argv)
-{
-    char ip[16];
-    if (sim76xx_domain_resolve("www.baidu.com", ip) < 0)
-    {
-        rt_kprintf("sim76xx_socket_send fail\n");
-    }
-    else
-    {
-        rt_kprintf("baidu.com : %s\n", ip);
-    }
-
-    return RT_EOK;
-}
-
-int sim76xx_ifconfig(void)
-{
-    at_response_t resp = RT_NULL;
-    char resp_arg[AT_CMD_MAX_LEN] = { 0 };
-    rt_err_t result = RT_EOK;
-
-    resp = at_create_resp(128, 2, rt_tick_from_millisecond(300));
-    if (!resp)
-    {
-        rt_kprintf("No memory for response structure!\n");
-        return -RT_ENOMEM;
-    }
-    
-    /* Show PDP address */
-    AT_SEND_CMD(resp, "AT+CGPADDR");
-    at_resp_parse_line_args_by_kw(resp, "+CGPADDR:", "+CGPADDR: %s", &resp_arg);
-    rt_kprintf("IP adress : %s\n", resp_arg);
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-
-#ifdef FINSH_USING_MSH
-#include <finsh.h>
-MSH_CMD_EXPORT_ALIAS(sim76xx_net_init, at_net_init, initialize AT network);
-MSH_CMD_EXPORT_ALIAS(sim76xx_ping, at_ping, AT ping network host);
-MSH_CMD_EXPORT_ALIAS(sim76xx_ifconfig, at_ifconfig, list the information of network interfaces);
-MSH_CMD_EXPORT_ALIAS(sim76xx_connect, at_connect, AT connect network host);
-MSH_CMD_EXPORT_ALIAS(sim76xx_close, at_close, AT close a socket);
-MSH_CMD_EXPORT_ALIAS(sim76xx_send, at_send, AT send a pack);
-MSH_CMD_EXPORT_ALIAS(sim76xx_domain, at_domain, AT domain resolve);
-#endif
-
-static const struct at_device_ops sim76xx_socket_ops = {
-    sim76xx_socket_connect,
-    sim76xx_socket_close,
-    sim76xx_socket_send,
-    sim76xx_domain_resolve,
-    sim76xx_socket_set_event_cb,
-};
-
-static int sim76xx_netdev_add(const char *netdev_name)
-{
-#define ETHERNET_MTU        1500
-#define HWADDR_LEN          8
-    struct netdev *netdev = RT_NULL;
-    int result = 0;
-
-    RT_ASSERT(netdev_name);
-
-    netdev = (struct netdev *) rt_calloc(1, sizeof(struct netdev));
-    if (netdev == RT_NULL)
-    {
-        return RT_NULL;
-    }
-
-    netdev->mtu = ETHERNET_MTU;
-    netdev->hwaddr_len = HWADDR_LEN;
-    netdev->ops = RT_NULL;
-
-#ifdef SAL_USING_AT
-    extern int sal_at_netdev_set_pf_info(struct netdev *netdev);
-    /* set the network interface socket/netdb operations */
-    sal_at_netdev_set_pf_info(netdev);
-#endif
-
-    result = netdev_register(netdev, netdev_name, RT_NULL);
-
-    /*TODO: improve netdev adaptation */
-    netdev_low_level_set_status(netdev, RT_TRUE);
-    netdev_low_level_set_link_status(netdev, RT_TRUE);
-    netdev_low_level_set_dhcp_status(netdev, RT_TRUE);
-    netdev->flags |= NETDEV_FLAG_INTERNET_UP;
-
-    return result;
-}
-
-static int at_socket_device_init(void)
-{
-    /* create current AT socket event */
-    at_socket_event = rt_event_create("at_se", RT_IPC_FLAG_FIFO);
-    if (at_socket_event == RT_NULL)
-    {
-        LOG_E("RT AT client port initialize failed! at_sock_event create failed!");
-        return -RT_ENOMEM;
-    }
-
-    /* create current AT socket event lock */
-    at_event_lock = rt_mutex_create("at_se", RT_IPC_FLAG_FIFO);
-    if (at_event_lock == RT_NULL)
-    {
-        LOG_E("RT AT client port initialize failed! at_sock_lock create failed!");
-        rt_event_delete(at_socket_event);
-        return -RT_ENOMEM;
-    }
-
-    /* initialize AT client */
-    at_client_init(AT_DEVICE_NAME, AT_DEVICE_RECV_BUFF_LEN);
-
-    /* register URC data execution function  */
-    at_set_urc_table(urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
-
-    /* add network interface device to netdev list */
-    if (sim76xx_netdev_add(SIM76XX_NETDEV_NAME) < 0)
-    {
-        LOG_E("SIM76xx network interface device(%d) add failed.", SIM76XX_NETDEV_NAME);
-        return -RT_ENOMEM;
-    }
-
-    /* initialize sim76xx pin config */
-    rt_pin_mode(AT_DEVICE_POWER_PIN, PIN_MODE_OUTPUT);
-    rt_pin_mode(AT_DEVICE_STATUS_PIN, PIN_MODE_INPUT);
-    
-    /* initialize sim76xx network */
-    sim76xx_net_init();
-
-    /* set sim76xx AT Socket options */
-    at_socket_device_register(&sim76xx_socket_ops);
-
-    return RT_EOK;
-}
-INIT_APP_EXPORT(at_socket_device_init);
-
-#endif /* AT_DEVICE_SIM76XX */

+ 0 - 1302
at_socket_sim800c.c

@@ -1,1302 +0,0 @@
-/*
- * File      : at_socket_sim800c.c
- * This file is part of RT-Thread RTOS
- * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Change Logs:
- * Date           Author       Notes
- * 2018-06-12     malongwei     first version
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include <rtthread.h>
-#include <rtdevice.h>
-#include <sys/socket.h>
-
-#include <at.h>
-#include <at_socket.h>
-
-#if !defined(RT_USING_NETDEV)
-#error "This RT-Thread version is older, please check and updata laster RT-Thread!"
-#else
-#include <arpa/inet.h>
-#include <netdev.h>
-#endif /* RT_USING_NETDEV */
-
-#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10200
-#error "This AT Client version is older, please check and update latest AT Client!"
-#endif
-
-#define LOG_TAG              "at.sim800c"
-#include <at_log.h>
-
-#ifdef AT_DEVICE_SIM800C
-
-#define SIM800C_NETDEV_NAME                "sim800c"
-
-#define SIM800C_MODULE_SEND_MAX_SIZE       1000
-#define SIM800C_WAIT_CONNECT_TIME          5000
-#define SIM800C_THREAD_STACK_SIZE          1024
-#define SIM800C_THREAD_PRIORITY            (RT_THREAD_PRIORITY_MAX/2)
-
-/* set real event by current socket and current state */
-#define SET_EVENT(socket, event)       (((socket + 1) << 16) | (event))
-
-/* AT socket event type */
-#define SIM800C_EVENT_CONN_OK              (1L << 0)
-#define SIM800C_EVENT_SEND_OK              (1L << 1)
-#define SIM800C_EVENT_RECV_OK              (1L << 2)
-#define SIM800C_EVNET_CLOSE_OK             (1L << 3)
-#define SIM800C_EVENT_CONN_FAIL            (1L << 4)
-#define SIM800C_EVENT_SEND_FAIL            (1L << 5)
-
-/* AT+CSTT command default*/
-char *CSTT_CHINA_MOBILE  = "AT+CSTT=\"CMNET\"";
-char *CSTT_CHINA_UNICOM  = "AT+CSTT=\"UNINET\"";
-char *CSTT_CHINA_TELECOM = "AT+CSTT=\"CTNET\"";
-
-
-static int cur_socket;
-static rt_event_t at_socket_event;
-static rt_mutex_t at_event_lock;
-static at_evt_cb_t at_evt_cb_set[] = {
-        [AT_SOCKET_EVT_RECV] = NULL,
-        [AT_SOCKET_EVT_CLOSED] = NULL,
-};
-
-static int at_socket_event_send(uint32_t event)
-{
-    return (int) rt_event_send(at_socket_event, event);
-}
-
-static int at_socket_event_recv(uint32_t event, uint32_t timeout, rt_uint8_t option)
-{
-    int result = 0;
-    rt_uint32_t recved;
-
-    result = rt_event_recv(at_socket_event, event, option | RT_EVENT_FLAG_CLEAR, timeout, &recved);
-    if (result != RT_EOK)
-    {
-        return -RT_ETIMEOUT;
-    }
-
-    return recved;
-}
-
-/**
- * close socket by AT commands.
- *
- * @param current socket
- *
- * @return  0: close socket success
- *         -1: send AT commands error
- *         -2: wait socket event timeout
- *         -5: no memory
- */
-static int sim800c_socket_close(int socket)
-{
-    int result = 0;
-    at_response_t resp = RT_NULL;
-
-    resp = at_create_resp(128, 0, RT_TICK_PER_SECOND);
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-    cur_socket = socket;
-
-    /* Clear socket close event */
-    at_socket_event_recv(SET_EVENT(socket, SIM800C_EVNET_CLOSE_OK), 0, RT_EVENT_FLAG_OR);
-
-    if (at_exec_cmd(resp, "AT+CIPCLOSE=%d", socket) < 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    if (at_socket_event_recv(SET_EVENT(socket, SIM800C_EVNET_CLOSE_OK), rt_tick_from_millisecond(300*3), RT_EVENT_FLAG_AND) < 0)
-    {
-        LOG_E("socket (%d) close failed, wait close OK timeout.", socket);
-        result = -RT_ETIMEOUT;
-        goto __exit;
-    }
-
-__exit:
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-
-/**
- * create TCP/UDP client or server connect by AT commands.
- *
- * @param socket current socket
- * @param ip server or client IP address
- * @param port server or client port
- * @param type connect socket type(tcp, udp)
- * @param is_client connection is client
- *
- * @return   0: connect success
- *          -1: connect failed, send commands error or type error
- *          -2: wait socket event timeout
- *          -5: no memory
- */
-static int sim800c_socket_connect(int socket, char *ip, int32_t port, enum at_socket_type type, rt_bool_t is_client)
-{
-    int result = 0, event_result = 0;
-    rt_bool_t retryed = RT_FALSE;
-    at_response_t resp = RT_NULL;
-
-    RT_ASSERT(ip);
-    RT_ASSERT(port >= 0);
-
-    resp = at_create_resp(128, 0, 5 * RT_TICK_PER_SECOND);
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    /* lock AT socket connect */
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-__retry:
-
-    /* Clear socket connect event */
-    at_socket_event_recv(SET_EVENT(socket, SIM800C_EVENT_CONN_OK | SIM800C_EVENT_CONN_FAIL), 0, RT_EVENT_FLAG_OR);
-
-    if (is_client)
-    {
-        switch (type)
-        {
-        case AT_SOCKET_TCP:
-            /* send AT commands(eg: AT+QIOPEN=0,"TCP","x.x.x.x", 1234) to connect TCP server */
-            if (at_exec_cmd(resp, "AT+CIPSTART=%d,\"TCP\",\"%s\",%d", socket, ip, port) < 0)
-            {
-                result = -RT_ERROR;
-                goto __exit;
-            }
-            break;
-
-        case AT_SOCKET_UDP:
-            if (at_exec_cmd(resp, "AT+CIPSTART=%d,\"UDP\",\"%s\",%d", socket, ip, port) < 0)
-            {
-                result = -RT_ERROR;
-                goto __exit;
-            }
-            break;
-
-        default:
-            LOG_E("Not supported connect type : %d.", type);
-            result = -RT_ERROR;
-            goto __exit;
-        }
-    }
-
-    /* waiting result event from AT URC, the device default connection timeout is 75 seconds, but it set to 10 seconds is convenient to use.*/
-    if (at_socket_event_recv(SET_EVENT(socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
-    {
-        LOG_E("socket (%d) connect failed, wait connect result timeout.", socket);
-        result = -RT_ETIMEOUT;
-        goto __exit;
-    }
-    /* waiting OK or failed result */
-    if ((event_result = at_socket_event_recv(SIM800C_EVENT_CONN_OK | SIM800C_EVENT_CONN_FAIL, 1 * RT_TICK_PER_SECOND,
-            RT_EVENT_FLAG_OR)) < 0)
-    {
-        LOG_E("socket (%d) connect failed, wait connect OK|FAIL timeout.", socket);
-        result = -RT_ETIMEOUT;
-        goto __exit;
-    }
-    /* check result */
-    if (event_result & SIM800C_EVENT_CONN_FAIL)
-    {
-        if (!retryed)
-        {
-            LOG_E("socket (%d) connect failed, maybe the socket was not be closed at the last time and now will retry.", socket);
-            if (sim800c_socket_close(socket) < 0)
-            {
-                goto __exit;
-            }
-            retryed = RT_TRUE;
-            goto __retry;
-        }
-        LOG_E("socket (%d) connect failed, failed to establish a connection.", socket);
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-__exit:
-    /* unlock AT socket connect */
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-/**
- * send data to server or client by AT commands.
- *
- * @param socket current socket
- * @param buff send buffer
- * @param bfsz send buffer size
- * @param type connect socket type(tcp, udp)
- *
- * @return >=0: the size of send success
- *          -1: send AT commands error or send data error
- *          -2: waited socket event timeout
- *          -5: no memory
- */
-static int sim800c_socket_send(int socket, const char *buff, size_t bfsz, enum at_socket_type type)
-{
-    int result = 0, event_result = 0;
-    at_response_t resp = RT_NULL;
-    size_t cur_pkt_size = 0, sent_size = 0;
-
-    RT_ASSERT(buff);
-
-    resp = at_create_resp(128, 2, 5 * RT_TICK_PER_SECOND);
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    /* Clear socket connect event */
-    at_socket_event_recv(SET_EVENT(socket, SIM800C_EVENT_SEND_OK | SIM800C_EVENT_SEND_FAIL), 0, RT_EVENT_FLAG_OR);
-
-    /* set current socket for send URC event */
-    cur_socket = socket;
-    /* set AT client end sign to deal with '>' sign.*/
-    at_set_end_sign('>');
-
-    while (sent_size < bfsz)
-    {
-        if (bfsz - sent_size < SIM800C_MODULE_SEND_MAX_SIZE)
-        {
-            cur_pkt_size = bfsz - sent_size;
-        }
-        else
-        {
-            cur_pkt_size = SIM800C_MODULE_SEND_MAX_SIZE;
-        }
-
-        /* send the "AT+QISEND" commands to AT server than receive the '>' response on the first line. */
-        if (at_exec_cmd(resp, "AT+CIPSEND=%d,%d", socket, cur_pkt_size) < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* send the real data to server or client */
-        result = (int) at_client_send(buff + sent_size, cur_pkt_size);
-        if (result == 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* waiting result event from AT URC */
-        if (at_socket_event_recv(SET_EVENT(socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
-        {
-            LOG_E("socket (%d) send failed, wait connect result timeout.", socket);
-            result = -RT_ETIMEOUT;
-            goto __exit;
-        }
-        /* waiting OK or failed result */
-        if ((event_result = at_socket_event_recv(SIM800C_EVENT_SEND_OK | SIM800C_EVENT_SEND_FAIL, 5 * RT_TICK_PER_SECOND,
-                RT_EVENT_FLAG_OR)) < 0)
-        {
-            LOG_E("socket (%d) send failed, wait connect OK|FAIL timeout.", socket);
-            result = -RT_ETIMEOUT;
-            goto __exit;
-        }
-        /* check result */
-        if (event_result & SIM800C_EVENT_SEND_FAIL)
-        {
-            LOG_E("socket (%d) send failed, return failed.", socket);
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        if (type == AT_SOCKET_TCP)
-        {
-            //cur_pkt_size = cur_send_bfsz;
-        }
-
-        sent_size += cur_pkt_size;
-    }
-
-
-__exit:
-    /* reset the end sign for data conflict */
-    at_set_end_sign(0);
-
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-}
-
-/**
- * domain resolve by AT commands.
- *
- * @param name domain name
- * @param ip parsed IP address, it's length must be 16
- *
- * @return  0: domain resolve success
- *         -1: send AT commands error or response error
- *         -2: wait socket event timeout
- *         -5: no memory
- */
-static int sim800c_domain_resolve(const char *name, char ip[16])
-{
-#define RESOLVE_RETRY                  5
-
-    int i, result = RT_EOK;
-    char recv_ip[16] = { 0 };
-    at_response_t resp = RT_NULL;
-
-    RT_ASSERT(name);
-    RT_ASSERT(ip);
-
-    /* The maximum response time is 14 seconds, affected by network status */
-    resp = at_create_resp(128, 4, 14 * RT_TICK_PER_SECOND);
-    if (!resp)
-    {
-        LOG_E("No memory for response structure!");
-        return -RT_ENOMEM;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    for (i = 0; i < RESOLVE_RETRY; i++)
-    {
-        int err_code = 0;
-
-        if (at_exec_cmd(resp, "AT+CDNSGIP=\"%s\"", name) < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* domain name prase error options */
-        if (at_resp_parse_line_args_by_kw(resp, "+CDNSGIP: 0", "+CDNSGIP: 0,%d", &err_code) > 0)
-        {
-            /* 3 - network error, 8 - dns common error */
-            if (err_code == 3 || err_code == 8)
-            {
-                result = -RT_ERROR;
-                goto __exit;
-            }
-        }
-
-        /* parse the third line of response data, get the IP address */
-        if (at_resp_parse_line_args_by_kw(resp, "+CDNSGIP:", "%*[^,],%*[^,],\"%[^\"]", recv_ip) < 0)
-        {
-            rt_thread_mdelay(100);
-            /* resolve failed, maybe receive an URC CRLF */
-            continue;
-        }
-
-        if (strlen(recv_ip) < 8)
-        {
-            rt_thread_mdelay(100);
-            /* resolve failed, maybe receive an URC CRLF */
-            continue;
-        }
-        else
-        {
-            strncpy(ip, recv_ip, 15);
-            ip[15] = '\0';
-            //LOG_I("DNS IP:%s",ip);
-            break;
-        }
-    }
-
-__exit:
-    rt_mutex_release(at_event_lock);
-
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    return result;
-
-}
-
-/**
- * set AT socket event notice callback
- *
- * @param event notice event
- * @param cb notice callback
- */
-static void sim800c_socket_set_event_cb(at_socket_evt_t event, at_evt_cb_t cb)
-{
-    if (event < sizeof(at_evt_cb_set) / sizeof(at_evt_cb_set[1]))
-    {
-        at_evt_cb_set[event] = cb;
-    }
-}
-
-static void urc_connect_func(const char *data, rt_size_t size)
-{
-    int socket = 0;
-
-    RT_ASSERT(data && size);
-
-    sscanf(data, "%d,%*", &socket);
-
-    if (strstr(data, "CONNECT OK"))
-    {
-        at_socket_event_send(SET_EVENT(socket, SIM800C_EVENT_CONN_OK));
-    }
-    else if (strstr(data, "CONNECT FAIL"))
-    {
-        at_socket_event_send(SET_EVENT(socket, SIM800C_EVENT_CONN_FAIL));
-    }
-}
-
-static void urc_send_func(const char *data, rt_size_t size)
-{
-    RT_ASSERT(data && size);
-
-    if (strstr(data, "SEND OK"))
-    {
-        at_socket_event_send(SET_EVENT(cur_socket, SIM800C_EVENT_SEND_OK));
-    }
-    else if (strstr(data, "SEND FAIL"))
-    {
-        at_socket_event_send(SET_EVENT(cur_socket, SIM800C_EVENT_SEND_FAIL));
-    }
-}
-
-static void urc_close_func(const char *data, rt_size_t size)
-{
-    int socket = 0;
-
-    RT_ASSERT(data && size);
-
-    if (strstr(data, "CLOSE OK"))
-    {
-        at_socket_event_send(SET_EVENT(cur_socket, SIM800C_EVNET_CLOSE_OK));
-    }
-    else if (strstr(data, "CLOSED"))
-    {
-        sscanf(data, "%d, CLOSED", &socket);
-        /* notice the socket is disconnect by remote */
-        if (at_evt_cb_set[AT_SOCKET_EVT_CLOSED])
-        {
-            at_evt_cb_set[AT_SOCKET_EVT_CLOSED](socket, AT_SOCKET_EVT_CLOSED, NULL, 0);
-        }
-    }
-}
-
-static void urc_recv_func(const char *data, rt_size_t size)
-{
-    int socket = 0;
-    rt_size_t bfsz = 0, temp_size = 0;
-    rt_int32_t timeout;
-    char *recv_buf = RT_NULL, temp[8];
-
-    RT_ASSERT(data && size);
-
-    /* get the current socket and receive buffer size by receive data */
-    sscanf(data, "+RECEIVE,%d,%d:", &socket, (int *) &bfsz);
-    /* get receive timeout by receive buffer length */
-    timeout = bfsz;
-
-    if (socket < 0 || bfsz == 0)
-        return;
-
-    recv_buf = rt_calloc(1, bfsz);
-    if (!recv_buf)
-    {
-        LOG_E("no memory for URC receive buffer (%d)!", bfsz);
-        /* read and clean the coming data */
-        while (temp_size < bfsz)
-        {
-            if (bfsz - temp_size > sizeof(temp))
-            {
-                at_client_recv(temp, sizeof(temp), timeout);
-            }
-            else
-            {
-                at_client_recv(temp, bfsz - temp_size, timeout);
-            }
-            temp_size += sizeof(temp);
-        }
-        return;
-    }
-
-    /* sync receive data */
-    if (at_client_recv(recv_buf, bfsz, timeout) != bfsz)
-    {
-        LOG_E("receive size(%d) data failed!", bfsz);
-        rt_free(recv_buf);
-        return;
-    }
-
-    /* notice the receive buffer and buffer size */
-    if (at_evt_cb_set[AT_SOCKET_EVT_RECV])
-    {
-        at_evt_cb_set[AT_SOCKET_EVT_RECV](socket, AT_SOCKET_EVT_RECV, recv_buf, bfsz);
-    }
-}
-
-
-static void urc_func(const char *data, rt_size_t size)
-{
-    RT_ASSERT(data);
-
-    LOG_I("URC data : %.*s", size, data);
-}
-
-static const struct at_urc urc_table[] = {
-        {"RDY",         "\r\n",                 urc_func},
-        {"",            ", CONNECT OK\r\n",     urc_connect_func},
-        {"",            ", CONNECT FAIL\r\n",   urc_connect_func},
-        {"",            ", SEND OK\r\n",        urc_send_func},
-        {"",            ", SEND FAIL\r\n",      urc_send_func},
-        {"",            ", CLOSE OK\r\n",       urc_close_func},
-        {"",            ", CLOSED\r\n",         urc_close_func},
-        {"+RECEIVE,",   "\r\n",                 urc_recv_func},
-};
-
-#define AT_SEND_CMD(resp, resp_line, timeout, cmd)                                                              \
-    do                                                                                                          \
-    {                                                                                                           \
-        if (at_exec_cmd(at_resp_set_info(resp, 128, resp_line, rt_tick_from_millisecond(timeout)), cmd) < 0)    \
-        {                                                                                                       \
-            result = -RT_ERROR;                                                                                 \
-            goto __exit;                                                                                        \
-        }                                                                                                       \
-    } while(0);                                                                                                 \
-
-static void sim800c_power_on(void)
-{
-    if (rt_pin_read(AT_DEVICE_STATUS_PIN) == PIN_HIGH)
-        return;
-    rt_pin_write(AT_DEVICE_POWER_PIN, PIN_HIGH);
-    while (rt_pin_read(AT_DEVICE_STATUS_PIN) == PIN_LOW)
-    {
-        rt_thread_mdelay(10);
-    }
-    rt_pin_write(AT_DEVICE_POWER_PIN, PIN_LOW);
-}
-
-static void sim800c_power_off(void)
-{
-    if (rt_pin_read(AT_DEVICE_STATUS_PIN) == PIN_LOW)
-        return;
-    rt_pin_write(AT_DEVICE_POWER_PIN, PIN_HIGH);
-    while (rt_pin_read(AT_DEVICE_STATUS_PIN) == PIN_HIGH)
-    {
-        rt_thread_mdelay(10);
-    }
-    rt_pin_write(AT_DEVICE_POWER_PIN, PIN_LOW);
-}
-
-static int sim800c_netdev_set_info(struct netdev *netdev);
-static int sim800c_netdev_check_link_status(struct netdev *netdev); 
-
-/* init for SIM800C */
-static void sim800c_init_thread_entry(void *parameter)
-{
-#define CPIN_RETRY                     10
-#define CSQ_RETRY                      10
-#define CREG_RETRY                     10
-#define CGREG_RETRY                    20
-
-    at_response_t resp = RT_NULL;
-    int i, qimux;
-    char parsed_data[10];
-    rt_err_t result = RT_EOK;
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    while (1)
-    {
-        result = RT_EOK;
-        rt_memset(parsed_data, 0, sizeof(parsed_data));
-        rt_thread_mdelay(500);
-        sim800c_power_on();
-        rt_thread_mdelay(2000);
-        resp = at_create_resp(128, 0, rt_tick_from_millisecond(300));
-        if (!resp)
-        {
-            LOG_E("No memory for response structure!");
-            result = -RT_ENOMEM;
-            goto __exit;
-        }
-        LOG_D("Start initializing the SIM800C module");
-        /* wait SIM800C startup finish */
-        if (at_client_wait_connect(SIM800C_WAIT_CONNECT_TIME))
-        {
-            result = -RT_ETIMEOUT;
-            goto __exit;
-        }
-        /* disable echo */
-        AT_SEND_CMD(resp, 0, 300, "ATE0");
-        /* get module version */
-        AT_SEND_CMD(resp, 0, 300, "ATI");
-        /* show module version */
-        for (i = 0; i < (int)resp->line_counts - 1; i++)
-        {
-            LOG_D("%s", at_resp_get_line(resp, i + 1));
-        }
-        /* check SIM card */
-        for (i = 0; i < CPIN_RETRY; i++)
-        {
-            at_exec_cmd(at_resp_set_info(resp, 128, 2, 5 * RT_TICK_PER_SECOND), "AT+CPIN?");
-
-            if (at_resp_get_line_by_kw(resp, "READY"))
-            {
-                LOG_D("SIM card detection success");
-                break;
-            }
-            rt_thread_mdelay(1000);
-        }
-        if (i == CPIN_RETRY)
-        {
-            LOG_E("SIM card detection failed!");
-            result = -RT_ERROR;
-            goto __exit;
-        }
-        /* waiting for dirty data to be digested */
-        rt_thread_mdelay(10);
-
-        /* check the GSM network is registered */
-        for (i = 0; i < CREG_RETRY; i++)
-        {
-            AT_SEND_CMD(resp, 0, 300, "AT+CREG?");
-            at_resp_parse_line_args_by_kw(resp, "+CREG:", "+CREG: %s", &parsed_data);
-            if (!strncmp(parsed_data, "0,1", sizeof(parsed_data)) || !strncmp(parsed_data, "0,5", sizeof(parsed_data)))
-            {
-                LOG_D("GSM network is registered (%s)", parsed_data);
-                break;
-            }
-            rt_thread_mdelay(1000);
-        }
-        if (i == CREG_RETRY)
-        {
-            LOG_E("The GSM network is register failed (%s)", parsed_data);
-            result = -RT_ERROR;
-            goto __exit;
-        }
-        /* check the GPRS network is registered */
-        for (i = 0; i < CGREG_RETRY; i++)
-        {
-            AT_SEND_CMD(resp, 0, 300, "AT+CGREG?");
-            at_resp_parse_line_args_by_kw(resp, "+CGREG:", "+CGREG: %s", &parsed_data);
-            if (!strncmp(parsed_data, "0,1", sizeof(parsed_data)) || !strncmp(parsed_data, "0,5", sizeof(parsed_data)))
-            {
-                LOG_D("GPRS network is registered (%s)", parsed_data);
-                break;
-            }
-            rt_thread_mdelay(1000);
-        }
-        if (i == CGREG_RETRY)
-        {
-            LOG_E("The GPRS network is register failed (%s)", parsed_data);
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* check signal strength */
-        for (i = 0; i < CSQ_RETRY; i++)
-        {
-            AT_SEND_CMD(resp, 0, 300, "AT+CSQ");
-            at_resp_parse_line_args_by_kw(resp, "+CSQ:", "+CSQ: %s", &parsed_data);
-            if (strncmp(parsed_data, "99,99", sizeof(parsed_data)))
-            {
-                LOG_D("Signal strength: %s", parsed_data);
-                break;
-            }
-            rt_thread_mdelay(1000);
-        }
-        if (i == CSQ_RETRY)
-        {
-            LOG_E("Signal strength check failed (%s)", parsed_data);
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        /* the device default response timeout is 40 seconds, but it set to 15 seconds is convenient to use. */
-        AT_SEND_CMD(resp, 2, 20 * 1000, "AT+CIPSHUT");
-
-        /* Set to multiple connections */
-        AT_SEND_CMD(resp, 0, 300, "AT+CIPMUX?");
-        at_resp_parse_line_args_by_kw(resp, "+CIPMUX:", "+CIPMUX: %d", &qimux);
-        if (qimux == 0)
-        {
-            AT_SEND_CMD(resp, 0, 300, "AT+CIPMUX=1");
-        }
-
-        AT_SEND_CMD(resp, 0, 300, "AT+COPS?");
-        at_resp_parse_line_args_by_kw(resp, "+COPS:", "+COPS: %*[^\"]\"%[^\"]", &parsed_data);
-        if (strcmp(parsed_data, "CHINA MOBILE") == 0)
-        {
-            /* "CMCC" */
-            LOG_I("%s", parsed_data);
-            AT_SEND_CMD(resp, 0, 300, CSTT_CHINA_MOBILE);
-        }
-        else if (strcmp(parsed_data, "CHN-UNICOM") == 0)
-        {
-            /* "UNICOM" */
-            LOG_I("%s", parsed_data);
-            AT_SEND_CMD(resp, 0, 300, CSTT_CHINA_UNICOM);
-        }
-        else if (strcmp(parsed_data, "CHN-CT") == 0)
-        {
-            AT_SEND_CMD(resp, 0, 300, CSTT_CHINA_TELECOM);
-            /* "CT" */
-            LOG_I("%s", parsed_data);
-        }
-
-        /* the device default response timeout is 150 seconds, but it set to 20 seconds is convenient to use. */
-        AT_SEND_CMD(resp, 0, 20 * 1000, "AT+CIICR");
-
-        AT_SEND_CMD(resp, 2, 300, "AT+CIFSR");
-        if(at_resp_get_line_by_kw(resp, "ERROR") != RT_NULL)
-        {
-            LOG_E("Get the local address failed");
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-    __exit:
-        if (resp)
-        {
-            at_delete_resp(resp);
-        }
-
-        if (!result)
-        {
-            LOG_I("AT network initialize success!");
-            rt_mutex_release(at_event_lock);
-            break;
-        }
-        else
-        {
-            LOG_E("AT network initialize failed (%d)!", result);
-            sim800c_power_off();
-        }
-        
-        rt_thread_mdelay(1000);
-    }
-
-    /* set network interface device status and address information */
-    sim800c_netdev_set_info(netdev_get_by_name(SIM800C_NETDEV_NAME));
-    sim800c_netdev_check_link_status(netdev_get_by_name(SIM800C_NETDEV_NAME));
-}
-
-int sim800c_net_init(void)
-{
-#ifdef PKG_AT_INIT_BY_THREAD
-    rt_thread_t tid;
-
-    tid = rt_thread_create("sim800c_net_init", sim800c_init_thread_entry, RT_NULL, SIM800C_THREAD_STACK_SIZE, SIM800C_THREAD_PRIORITY, 20);
-    if (tid)
-    {
-        rt_thread_startup(tid);
-    }
-    else
-    {
-        LOG_E("Create AT initialization thread fail!");
-    }
-#else
-    sim800c_init_thread_entry(RT_NULL);
-#endif
-
-    return RT_EOK;
-}
-
-#ifdef FINSH_USING_MSH
-#include <finsh.h>
-MSH_CMD_EXPORT_ALIAS(sim800c_net_init, at_net_init, initialize AT network);
-#endif
-
-static const struct at_device_ops sim800c_socket_ops = {
-    sim800c_socket_connect,
-    sim800c_socket_close,
-    sim800c_socket_send,
-    sim800c_domain_resolve,
-    sim800c_socket_set_event_cb,
-};
-
-/* set sim800c network interface device status and address information */
-static int sim800c_netdev_set_info(struct netdev *netdev)
-{
-#define SIM800C_IEMI_RESP_SIZE      32
-#define SIM800C_IPADDR_RESP_SIZE    32
-#define SIM800C_DNS_RESP_SIZE       96
-#define SIM800C_INFO_RESP_TIMO      rt_tick_from_millisecond(300)
-
-    int result = RT_EOK;
-    at_response_t resp = RT_NULL;
-    ip_addr_t addr;
-
-    if (netdev == RT_NULL)
-    {
-        LOG_E("Input network interface device is NULL.\n");
-        return -RT_ERROR;
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    /* set network interface device status */
-    netdev_low_level_set_status(netdev, RT_TRUE);
-    netdev_low_level_set_link_status(netdev, RT_TRUE);
-    netdev_low_level_set_dhcp_status(netdev, RT_TRUE);
-
-    resp = at_create_resp(SIM800C_IEMI_RESP_SIZE, 0, SIM800C_INFO_RESP_TIMO);
-    if (resp == RT_NULL)
-    {
-        LOG_E("SIM800C set IP address failed, no memory for response object.");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-
-    /* set network interface device hardware address(IEMI) */
-    {
-        #define SIM800C_NETDEV_HWADDR_LEN   8
-        #define SIM800C_IEMI_LEN            15
-
-        char iemi[SIM800C_IEMI_LEN] = {0};
-        int i = 0, j = 0;
-
-        /* send "AT+GSN" commond to get device IEMI */
-        if (at_exec_cmd(resp, "AT+GSN") < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        if (at_resp_parse_line_args(resp, 2, "%s", iemi) <= 0)
-        {
-            LOG_E("Prase \"AT+GSN\" commands resposne data error!");
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        LOG_D("SIM800C IEMI number: %s", iemi);
-
-        netdev->hwaddr_len = SIM800C_NETDEV_HWADDR_LEN;
-        /* get hardware address by IEMI */
-        for (i = 0, j = 0; i < SIM800C_NETDEV_HWADDR_LEN && j < SIM800C_IEMI_LEN; i++, j+=2)
-        {
-            if (j != SIM800C_IEMI_LEN - 1)
-            {
-                netdev->hwaddr[i] = (iemi[j] - '0') * 10 + (iemi[j + 1] - '0');
-            }
-            else
-            {
-                netdev->hwaddr[i] = (iemi[j] - '0');
-            }
-        }
-    }
-
-    /* set network interface device IP address */
-    {
-        #define IP_ADDR_SIZE_MAX    16
-        char ipaddr[IP_ADDR_SIZE_MAX] = {0};
-        
-        at_resp_set_info(resp, SIM800C_IPADDR_RESP_SIZE, 2, SIM800C_INFO_RESP_TIMO);
-
-        /* send "AT+CIFSR" commond to get IP address */
-        if (at_exec_cmd(resp, "AT+CIFSR") < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        if (at_resp_parse_line_args_by_kw(resp, ".", "%s", ipaddr) <= 0)
-        {
-            LOG_E("Prase \"AT+CIFSR\" commands resposne data error!");
-            result = -RT_ERROR;
-            goto __exit;
-        }
-        
-        LOG_D("SIM800C IP address: %s", ipaddr);
-
-        /* set network interface address information */
-        inet_aton(ipaddr, &addr);
-        netdev_low_level_set_ipaddr(netdev, &addr);
-    }
-
-    /* set network interface device dns server */
-    {
-        #define DNS_ADDR_SIZE_MAX   16
-        char dns_server1[DNS_ADDR_SIZE_MAX] = {0}, dns_server2[DNS_ADDR_SIZE_MAX] = {0};
-
-        at_resp_set_info(resp, SIM800C_DNS_RESP_SIZE, 0, SIM800C_INFO_RESP_TIMO);
-
-        /* send "AT+CDNSCFG?" commond to get DNS servers address */
-        if (at_exec_cmd(resp, "AT+CDNSCFG?") < 0)
-        {
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        if (at_resp_parse_line_args_by_kw(resp, "PrimaryDns:", "PrimaryDns:%s", dns_server1) <= 0 ||
-                at_resp_parse_line_args_by_kw(resp, "SecondaryDns:", "SecondaryDns:%s", dns_server2) <= 0)
-        {
-            LOG_E("Prase \"AT+CDNSCFG?\" commands resposne data error!");
-            result = -RT_ERROR;
-            goto __exit;
-        }
-
-        LOG_D("SIM800C primary DNS server address: %s", dns_server1);
-        LOG_D("SIM800C secondary DNS server address: %s", dns_server2);
-
-        inet_aton(dns_server1, &addr);
-        netdev_low_level_set_dns_server(netdev, 0, &addr);
-
-        inet_aton(dns_server2, &addr);
-        netdev_low_level_set_dns_server(netdev, 1, &addr);
-    }
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-    
-    rt_mutex_release(at_event_lock);
-    
-    return result;
-}
-
-static void check_link_status_entry(void *parameter)
-{
-#define SIM800C_LINK_STATUS_OK   1
-#define SIM800C_LINK_RESP_SIZE   64
-#define SIM800C_LINK_RESP_TIMO   (3 * RT_TICK_PER_SECOND)
-#define SIM800C_LINK_DELAY_TIME  (30 * RT_TICK_PER_SECOND)
-
-    struct netdev *netdev = (struct netdev *)parameter;
-    at_response_t resp = RT_NULL;
-    int result_code, link_status;
-
-    resp = at_create_resp(SIM800C_LINK_RESP_SIZE, 0, SIM800C_LINK_RESP_TIMO);
-    if (resp == RT_NULL)
-    {
-        LOG_E("sim800c set check link status failed, no memory for response object.");
-        return;
-    }
-
-    while (1)
-    { 
-        rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-        /* send "AT+CGREG?" commond  to check netweork interface device link status */
-        if (at_exec_cmd(resp, "AT+CGREG?") < 0)
-        {
-            rt_mutex_release(at_event_lock);
-            rt_thread_mdelay(SIM800C_LINK_DELAY_TIME);
-
-            continue;
-        }
-        
-        link_status = -1;
-        at_resp_parse_line_args_by_kw(resp, "+CGREG:", "+CGREG: %d,%d", &result_code, &link_status);
-
-        /* check the network interface device link status  */
-        if ((SIM800C_LINK_STATUS_OK == link_status) != netdev_is_link_up(netdev))
-        {
-            netdev_low_level_set_link_status(netdev, (SIM800C_LINK_STATUS_OK == link_status));
-        }
-
-        rt_mutex_release(at_event_lock);
-        rt_thread_mdelay(SIM800C_LINK_DELAY_TIME);
-    }
-}
-
-static int sim800c_netdev_check_link_status(struct netdev *netdev)
-{
-#define SIM800C_LINK_THREAD_STACK_SIZE     512
-#define SIM800C_LINK_THREAD_PRIORITY       (RT_THREAD_PRIORITY_MAX - 2)
-#define SIM800C_LINK_THREAD_TICK           20
-
-    rt_thread_t tid;
-    char tname[RT_NAME_MAX];
-
-    if (netdev == RT_NULL)
-    {
-        LOG_E("Input network interface device is NULL.\n");
-        return -RT_ERROR;
-    }
-
-    rt_memset(tname, 0x00, sizeof(tname));
-    rt_snprintf(tname, RT_NAME_MAX, "%s_link", netdev->name);
-
-    tid = rt_thread_create(tname, check_link_status_entry, (void *)netdev, 
-            SIM800C_LINK_THREAD_STACK_SIZE, SIM800C_LINK_THREAD_PRIORITY, SIM800C_LINK_THREAD_TICK);
-    if (tid)
-    {
-        rt_thread_startup(tid);
-    }
-
-    return RT_EOK;
-}
-
-static int sim800c_netdev_set_up(struct netdev *netdev)
-{
-    netdev_low_level_set_status(netdev, RT_TRUE);
-    LOG_D("The network interface device(%s) set up status", netdev->name);
-
-    return RT_EOK;
-}
-
-static int sim800c_netdev_set_down(struct netdev *netdev)
-{
-    netdev_low_level_set_status(netdev, RT_FALSE);
-    LOG_D("The network interface device(%s) set down status", netdev->name);
-    return RT_EOK;
-}
-
-static int sim800c_netdev_set_dns_server(struct netdev *netdev, uint8_t dns_num, ip_addr_t *dns_server)
-{
-#define SIM800C_DNS_RESP_LEN     8
-#define SIM800C_DNS_RESP_TIMEO   rt_tick_from_millisecond(300)
-
-    at_response_t resp = RT_NULL;
-    int result = RT_EOK;
-
-    RT_ASSERT(netdev);
-    RT_ASSERT(dns_server);
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    resp = at_create_resp(SIM800C_DNS_RESP_LEN, 0, SIM800C_DNS_RESP_TIMEO);
-    if (resp == RT_NULL)
-    {
-        LOG_D("sim800c set dns server failed, no memory for response object.");
-        result = -RT_ENOMEM;
-        goto __exit;
-    }
-
-    /* send "AT+CDNSCFG=<pri_dns>[,<sec_dns>]" commond to set dns servers */
-    if (at_exec_cmd(resp, "AT+CDNSCFG=\"%s\"", inet_ntoa(*dns_server)) < 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    netdev_low_level_set_dns_server(netdev, dns_num, dns_server);
-
-__exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-
-    rt_mutex_release(at_event_lock);
-
-    return result;
-}
-
-static int sim800c_netdev_ping(struct netdev *netdev, const char *host, size_t data_len, uint32_t timeout, struct netdev_ping_resp *ping_resp)
-{
-#define SIM800C_PING_RESP_SIZE         128
-#define SIM800C_PING_IP_SIZE           16
-#define SIM800C_PING_TIMEO             (5 * RT_TICK_PER_SECOND)
-
-#define SIM800C_PING_ERR_TIME          600
-#define SIM800C_PING_ERR_TTL           255
-
-    int result = RT_EOK;
-    at_response_t resp = RT_NULL;
-    char ip_addr[SIM800C_PING_IP_SIZE] = {0};
-    int response, time, ttl, i;
-
-    RT_ASSERT(netdev);
-    RT_ASSERT(host);
-    RT_ASSERT(ping_resp);
-
-    for (i = 0; i < rt_strlen(host) && !isalpha(host[i]); i++);
-
-    if (i < strlen(host))
-    {
-        /* check domain name is usable */
-        if (sim800c_domain_resolve(host, ip_addr) < 0)
-        {
-            return -RT_ERROR;
-        }
-        rt_memset(ip_addr, 0x00, SIM800C_PING_IP_SIZE);
-    }
-
-    rt_mutex_take(at_event_lock, RT_WAITING_FOREVER);
-
-    resp = at_create_resp(SIM800C_PING_RESP_SIZE, 0, SIM800C_PING_TIMEO);
-    if (resp == RT_NULL)
-    {
-        LOG_D("sim800c set dns server failed, no memory for response object.");
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    /* send "AT+CIPPING=<IP addr>[,<retryNum>[,<dataLen>[,<timeout>[,<ttl>]]]]" commond to send ping request */
-    if (at_exec_cmd(resp, "AT+CIPPING=%s,1,%d,%d,64", host, data_len, SIM800C_PING_TIMEO / (RT_TICK_PER_SECOND / 10)) < 0)
-    {
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    if (at_resp_parse_line_args_by_kw(resp, "+CIPPING:", "+CIPPING:%d,\"%[^\"]\",%d,%d",
-             &response, ip_addr, &time, &ttl) <= 0)
-    {
-        LOG_D("Prase \"AT+CIPPING\" commands resposne data error!");
-        result = -RT_ERROR;
-        goto __exit;
-    }
-
-    /* the ping request timeout expires, the response time settting to 600 and ttl setting to 255 */
-    if (time == SIM800C_PING_ERR_TIME && ttl == SIM800C_PING_ERR_TTL)
-    {
-        result = -RT_ETIMEOUT;
-        goto __exit;
-    }
-
-    inet_aton(ip_addr, &(ping_resp->ip_addr));
-    ping_resp->data_len = data_len;
-    /* reply time, in units of 100 ms */
-    ping_resp->ticks = time * 100;
-    ping_resp->ttl = ttl;
-
- __exit:
-    if (resp)
-    {
-        at_delete_resp(resp);
-    }
-    
-     rt_mutex_release(at_event_lock);
-
-    return result;
-}
-
-void sim800c_netdev_netstat(struct netdev *netdev)
-{ 
-    // TODO netstat support
-}
-
-const struct netdev_ops sim800c_netdev_ops =
-{
-    sim800c_netdev_set_up,
-    sim800c_netdev_set_down,
-
-    RT_NULL, /* not support set ip, netmask, gatway address */
-    sim800c_netdev_set_dns_server,
-    RT_NULL, /* not support set DHCP status */
-
-    sim800c_netdev_ping,
-    sim800c_netdev_netstat,
-};
-
-static int sim800c_netdev_add(const char *netdev_name)
-{
-#define SIM800C_NETDEV_MTU       1500
-    struct netdev *netdev = RT_NULL;
-
-    RT_ASSERT(netdev_name);
-
-    netdev = (struct netdev *) rt_calloc(1, sizeof(struct netdev));
-    if (netdev == RT_NULL)
-    {
-        return -RT_ENOMEM;
-    }
-
-    netdev->mtu = SIM800C_NETDEV_MTU;
-    netdev->ops = &sim800c_netdev_ops;
-
-#ifdef SAL_USING_AT
-    extern int sal_at_netdev_set_pf_info(struct netdev *netdev);
-    /* set the network interface socket/netdb operations */
-    sal_at_netdev_set_pf_info(netdev);
-#endif
-
-    return netdev_register(netdev, netdev_name, RT_NULL);
-}
-
-static int at_socket_device_init(void)
-{
-    /* create current AT socket event */
-    at_socket_event = rt_event_create("at_se", RT_IPC_FLAG_FIFO);
-    if (at_socket_event == RT_NULL)
-    {
-        LOG_E("AT client port initialize failed! at_sock_event create failed!");
-        return -RT_ENOMEM;
-    }
-
-    /* create current AT socket event lock */
-    at_event_lock = rt_mutex_create("at_se", RT_IPC_FLAG_FIFO);
-    if (at_event_lock == RT_NULL)
-    {
-        LOG_E("AT client port initialize failed! at_sock_lock create failed!");
-        rt_event_delete(at_socket_event);
-        return -RT_ENOMEM;
-    }
-
-    /* initialize AT client */
-    at_client_init(AT_DEVICE_NAME, AT_DEVICE_RECV_BUFF_LEN);
-
-    /* register URC data execution function  */
-    at_set_urc_table(urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
-
-    /* add network interface device to netdev list */
-    if (sim800c_netdev_add(SIM800C_NETDEV_NAME) < 0)
-    {
-        LOG_E("SIM800C network interface device(%d) add failed.", SIM800C_NETDEV_NAME);
-        return -RT_ENOMEM;
-    }
-
-    /* initialize sim800c network */
-    rt_pin_mode(AT_DEVICE_POWER_PIN, PIN_MODE_OUTPUT);
-    rt_pin_mode(AT_DEVICE_STATUS_PIN, PIN_MODE_INPUT);
-    sim800c_net_init();
-
-    /* set sim800c AT Socket options */
-    at_socket_device_register(&sim800c_socket_ops);
-
-    return RT_EOK;
-}
-INIT_APP_EXPORT(at_socket_device_init);
-
-#endif /* AT_DEVICE_SIM800C */

+ 1040 - 0
class/ec20/at_device_ec20.c

@@ -0,0 +1,1040 @@
+/*
+ * File      : at_device_ec20.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-06-12     chenyong     first version
+ * 2018-08-12     Marcus       port to ec20
+ * 2019-05-13     chenyong     multi AT socket client support
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <at_device_ec20.h>
+
+#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10200
+#error "This AT Client version is older, please check and update latest AT Client!"
+#endif
+
+#define LOG_TAG                        "at.dev"
+#include <at_log.h>
+
+#ifdef AT_DEVICE_USING_EC20
+
+#define EC20_WAIT_CONNECT_TIME          5000
+#define EC20_THREAD_STACK_SIZE          1024
+#define EC20_THREAD_PRIORITY            (RT_THREAD_PRIORITY_MAX/2)
+
+/* AT+QICSGP command default*/
+static char *QICSGP_CHINA_MOBILE = "AT+QICSGP=1,1,\"CMNET\",\"\",\"\",0";
+static char *QICSGP_CHINA_UNICOM = "AT+QICSGP=1,1,\"UNINET\",\"\",\"\",0";
+static char *QICSGP_CHINA_TELECOM = "AT+QICSGP=1,1,\"CTNET\",\"\",\"\",0";
+
+static void at_cme_errcode_parse(int result)
+{
+    switch(result)
+    {
+    case 0   : LOG_E("%d : Phone failure",                result); break;
+    case 1   : LOG_E("%d : No connection to phone",       result); break;
+    case 2   : LOG_E("%d : Phone-adaptor link reserved",  result); break;
+    case 3   : LOG_E("%d : Operation not allowed",        result); break;
+    case 4   : LOG_E("%d : Operation not supported",      result); break;
+    case 5   : LOG_E("%d : PH-SIM PIN required",          result); break;
+    case 6   : LOG_E("%d : PH-FSIM PIN required",         result); break;
+    case 7   : LOG_E("%d : PH-FSIM PUK required",         result); break;
+    case 10  : LOG_E("%d : SIM not inserted",             result); break;
+    case 11  : LOG_E("%d : SIM PIN required",             result); break;
+    case 12  : LOG_E("%d : SIM PUK required",             result); break;
+    case 13  : LOG_E("%d : SIM failure",                  result); break;
+    case 14  : LOG_E("%d : SIM busy",                     result); break;
+    case 15  : LOG_E("%d : SIM wrong",                    result); break;
+    case 16  : LOG_E("%d : Incorrect password",           result); break;
+    case 17  : LOG_E("%d : SIM PIN2 required",            result); break;
+    case 18  : LOG_E("%d : SIM PUK2 required",            result); break;
+    case 20  : LOG_E("%d : Memory full",                  result); break;
+    case 21  : LOG_E("%d : Invalid index",                result); break;
+    case 22  : LOG_E("%d : Not found",                    result); break;
+    case 23  : LOG_E("%d : Memory failure",               result); break;
+    case 24  : LOG_E("%d : Text string too long",         result); break;
+    case 25  : LOG_E("%d : Invalid characters in text string", result); break;
+    case 26  : LOG_E("%d : Dial string too long",         result); break;
+    case 27  : LOG_E("%d : Invalid characters in dial string", result); break;
+    case 30  : LOG_E("%d : No network service",           result); break;
+    case 31  : LOG_E("%d : Network timeout",              result); break;
+    case 32  : LOG_E("%d : Network not allowed - emergency calls only", result); break;
+    case 40  : LOG_E("%d : Network personalization PIN required", result); break;
+    case 41  : LOG_E("%d : Network personalization PUK required", result); break;
+    case 42  : LOG_E("%d : Network subset personalization PIN required", result); break;
+    case 43  : LOG_E("%d : Network subset personalization PUK required", result); break;
+    case 44  : LOG_E("%d : Service provider personalization PIN required", result); break;
+    case 45  : LOG_E("%d : Service provider personalization PUK required", result); break;
+    case 46  : LOG_E("%d : Corporate personalization PIN required", result); break;
+    case 47  : LOG_E("%d : Corporate personalization PUK required", result); break;
+    case 901 : LOG_E("%d : Audio unknown error",          result); break;
+    case 902 : LOG_E("%d : Audio invalid parameters",     result); break;
+    case 903 : LOG_E("%d : Audio operation not supported", result); break;
+    case 904 : LOG_E("%d : Audio device busy",            result); break;
+    default  : LOG_E("%d : Unknown err code",             result); break;
+    }
+}
+
+static void at_cms_errcode_parse(int result)
+{
+    switch(result)
+    {
+    case 300 : LOG_E("%d : ME failure",                   result); break;
+    case 301 : LOG_E("%d : SMS ME reserved",              result); break;
+    case 302 : LOG_E("%d : Operation not allowed",        result); break;
+    case 303 : LOG_E("%d : Operation not supported",      result); break;
+    case 304 : LOG_E("%d : Invalid PDU mode",             result); break;
+    case 305 : LOG_E("%d : Invalid text mode",            result); break;
+    case 310 : LOG_E("%d : SIM not inserted",             result); break;
+    case 311 : LOG_E("%d : SIM pin necessary",            result); break;
+    case 312 : LOG_E("%d : PH SIM pin necessary",         result); break;
+    case 313 : LOG_E("%d : SIM failure",                  result); break;
+    case 314 : LOG_E("%d : SIM busy",                     result); break;
+    case 315 : LOG_E("%d : SIM wrong",                    result); break;
+    case 316 : LOG_E("%d : SIM PUK required",             result); break;
+    case 317 : LOG_E("%d : SIM PIN2 required",            result); break;
+    case 318 : LOG_E("%d : SIM PUK2 required",            result); break;
+    case 320 : LOG_E("%d : Memory failure",               result); break;
+    case 321 : LOG_E("%d : Invalid memory index",         result); break;
+    case 322 : LOG_E("%d : Memory full",                  result); break;
+    case 330 : LOG_E("%d : SMSC address unknown",         result); break;
+    case 331 : LOG_E("%d : No network",                   result); break;
+    case 332 : LOG_E("%d : Network timeout",              result); break;
+    case 500 : LOG_E("%d : Unknown",                      result); break;
+    case 512 : LOG_E("%d : SIM not ready",                result); break;
+    case 513 : LOG_E("%d : Message length exceeds",       result); break;
+    case 514 : LOG_E("%d : Invalid request parameters",   result); break;
+    case 515 : LOG_E("%d : ME storage failure",           result); break;
+    case 517 : LOG_E("%d : Invalid service mode",         result); break;
+    case 528 : LOG_E("%d : More message to send state error", result); break;
+    case 529 : LOG_E("%d : MO SMS is not allow",          result); break;
+    case 530 : LOG_E("%d : GPRS is suspended",            result); break;
+    case 531 : LOG_E("%d : ME storage full",              result); break;
+    default  : LOG_E("%d : Unknown err code",             result); break;
+    }
+}
+
+static void at_mms_errcode_parse(int result)//MMS
+{
+    switch(result)
+    {
+    case 751 : LOG_E("%d : Unknown error",                result); break;
+    case 752 : LOG_E("%d : URL length error",             result); break;
+    case 753 : LOG_E("%d : URL error",                    result); break;
+    case 754 : LOG_E("%d : Invalid proxy type",           result); break;
+    case 755 : LOG_E("%d : Proxy address error",          result); break;
+    case 756 : LOG_E("%d : Invalid parameter",            result); break;
+    case 757 : LOG_E("%d : Recipient address full",       result); break;
+    case 758 : LOG_E("%d : CC recipient address full",    result); break;
+    case 759 : LOG_E("%d : BCC recipient address full",   result); break;
+    case 760 : LOG_E("%d : Attachments full",             result); break;
+    case 761 : LOG_E("%d : File error",                   result); break;
+    case 762 : LOG_E("%d : No recipient",                 result); break;
+    case 763 : LOG_E("%d : File not found",               result); break;
+    case 764 : LOG_E("%d : MMS busy",                     result); break;
+    case 765 : LOG_E("%d : Server response failed",       result); break;
+    case 766 : LOG_E("%d : Error response of HTTP(S) post", result); break;
+    case 767 : LOG_E("%d : Invalid report of HTTP(S) post", result); break;
+    case 768 : LOG_E("%d : PDP activation failed",        result); break;
+    case 769 : LOG_E("%d : PDP deactivated",              result); break;
+    case 770 : LOG_E("%d : Socket creation failed",       result); break;
+    case 771 : LOG_E("%d : Socket connection failed",     result); break;
+    case 772 : LOG_E("%d : Socket read failed",           result); break;
+    case 773 : LOG_E("%d : Socket write failed",          result); break;
+    case 774 : LOG_E("%d : Socket closed",                result); break;
+    case 775 : LOG_E("%d : Timeout",                      result); break;
+    case 776 : LOG_E("%d : Encode data error",            result); break;
+    case 777 : LOG_E("%d : HTTP(S) decode data error",    result); break;
+    default  : LOG_E("%d : Unknown err code",             result); break;
+    }
+}
+
+static void ec20_power_on(struct at_device *device)
+{
+    struct at_device_ec20 *ec20 = RT_NULL;
+
+    ec20 = (struct at_device_ec20 *)device->user_data;
+
+    /* not nead to set pin configuration for ec20 device power on */
+    if (ec20->power_pin == -1 || ec20->power_status_pin == -1)
+    {
+        return;
+    }
+
+    if (rt_pin_read(ec20->power_status_pin) == PIN_HIGH)
+    {
+        return;
+    }
+    rt_pin_write(ec20->power_pin, PIN_HIGH);
+
+    while (rt_pin_read(ec20->power_status_pin) == PIN_LOW)
+    {
+        rt_thread_mdelay(10);
+    }
+    rt_pin_write(ec20->power_pin, PIN_LOW);
+}
+
+static void ec20_power_off(struct at_device *device)
+{
+    struct at_device_ec20 *ec20 = RT_NULL;
+
+    ec20 = (struct at_device_ec20 *)device->user_data;
+
+    /* not nead to set pin configuration for ec20 device power on */
+    if (ec20->power_pin == -1 || ec20->power_status_pin == -1)
+    {
+        return;
+    }
+
+    if (rt_pin_read(ec20->power_status_pin) == PIN_LOW)
+    {
+        return;
+    }
+    rt_pin_write(ec20->power_pin, PIN_HIGH);
+
+    while (rt_pin_read(ec20->power_status_pin) == PIN_HIGH)
+    {
+        rt_thread_mdelay(10);
+    }
+    rt_pin_write(ec20->power_pin, PIN_LOW);
+}
+
+/* =============================  ec20 network interface operations ============================= */
+
+/* set ec20 network interface device status and address information */
+static int ec20_netdev_set_info(struct netdev *netdev)
+{
+#define EC20_IEMI_RESP_SIZE      32
+#define EC20_IPADDR_RESP_SIZE    64
+#define EC20_DNS_RESP_SIZE       96
+#define EC20_INFO_RESP_TIMO      rt_tick_from_millisecond(300)
+
+    int result = RT_EOK;
+    ip_addr_t addr;
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    if (netdev == RT_NULL)
+    {
+        LOG_E("input network interface device is NULL.");
+        return -RT_ERROR;
+    }
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get ec20 device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+
+    /* set network interface device status */
+    netdev_low_level_set_status(netdev, RT_TRUE);
+    netdev_low_level_set_link_status(netdev, RT_TRUE);
+    netdev_low_level_set_dhcp_status(netdev, RT_TRUE);
+
+    resp = at_create_resp(EC20_IEMI_RESP_SIZE, 0, EC20_INFO_RESP_TIMO);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for ec20 device(%s) response structure.", device->name);
+        result = -RT_ENOMEM;
+        goto __exit;
+    }
+
+    /* set network interface device hardware address(IEMI) */
+    {
+        #define EC20_NETDEV_HWADDR_LEN   8
+        #define EC20_IEMI_LEN            15
+
+        char iemi[EC20_IEMI_LEN] = {0};
+        int i = 0, j = 0;
+
+        /* send "AT+GSN" commond to get device IEMI */
+        if (at_obj_exec_cmd(device->client, resp, "AT+GSN") < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        if (at_resp_parse_line_args(resp, 2, "%s", iemi) <= 0)
+        {
+            LOG_E("ec20 device(%s) prase \"AT+GSN\" commands resposne data error.", device->name);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        LOG_D("ec20 deevice(%s) IEMI number: %s", device->name, iemi);
+
+        netdev->hwaddr_len = EC20_NETDEV_HWADDR_LEN;
+        /* get hardware address by IEMI */
+        for (i = 0, j = 0; i < EC20_NETDEV_HWADDR_LEN && j < EC20_IEMI_LEN; i++, j+=2)
+        {
+            if (j != EC20_IEMI_LEN - 1)
+            {
+                netdev->hwaddr[i] = (iemi[j] - '0') * 10 + (iemi[j + 1] - '0');
+            }
+            else
+            {
+                netdev->hwaddr[i] = (iemi[j] - '0');
+            }
+        }
+    }
+
+    /* set network interface device IP address */
+    {
+        #define IP_ADDR_SIZE_MAX    16
+        char ipaddr[IP_ADDR_SIZE_MAX] = {0};
+        
+        resp = at_resp_set_info(resp, EC20_IPADDR_RESP_SIZE, 0, EC20_INFO_RESP_TIMO);
+
+        /* send "AT+QIACT?" commond to get IP address */
+        if (at_obj_exec_cmd(device->client, resp, "AT+QIACT?") < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* parse response data "+QIACT: 1,<context_state>,<context_type>[,<IP_address>]" */
+        if (at_resp_parse_line_args_by_kw(resp, "+QIACT:", "+QIACT: %*[^\"]\"%[^\"]", ipaddr) <= 0)
+        {
+            LOG_E("Prase \"AT+QIACT?\" commands resposne data error!");
+            result = -RT_ERROR;
+            goto __exit;
+        }
+        
+        LOG_D("ec20 device(%s) IP address: %s", device->name, ipaddr);
+
+        /* set network interface address information */
+        inet_aton(ipaddr, &addr);
+        netdev_low_level_set_ipaddr(netdev, &addr);
+    }
+
+    /* set network interface device dns server */
+    {
+        #define DNS_ADDR_SIZE_MAX   16
+        char dns_server1[DNS_ADDR_SIZE_MAX] = {0}, dns_server2[DNS_ADDR_SIZE_MAX] = {0};
+
+        resp = at_resp_set_info(resp, EC20_DNS_RESP_SIZE, 0, EC20_INFO_RESP_TIMO);
+
+        /* send "AT+QIDNSCFG=1" commond to get DNS servers address */
+        if (at_obj_exec_cmd(device->client, resp, "AT+QIDNSCFG=1") < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* parse response data "+QIDNSCFG: <contextID>,<pridnsaddr>,<secdnsaddr>" */
+        if (at_resp_parse_line_args_by_kw(resp, "+QIDNSCFG:", "+QIDNSCFG: 1,\"%[^\"]\",\"%[^\"]\"", 
+                dns_server1, dns_server2) <= 0)
+        {
+            LOG_E("ec20 device(%s) prase \"AT+QIDNSCFG=1\" commands resposne data error.", device->name);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        LOG_D("ec20 device(%s) primary DNS server address: %s", device->name, dns_server1);
+        LOG_D("ec20 devcie(%s) secondary DNS server address: %s", device->name, dns_server2);
+
+        inet_aton(dns_server1, &addr);
+        netdev_low_level_set_dns_server(netdev, 0, &addr);
+
+        inet_aton(dns_server2, &addr);
+        netdev_low_level_set_dns_server(netdev, 1, &addr);
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+    
+    return result;
+}
+
+static void ec20_check_link_status_entry(void *parameter)
+{
+#define EC20_LINK_RESP_SIZE     64
+#define EC20_LINK_RESP_TIMO     (3 * RT_TICK_PER_SECOND)
+#define EC20_LINK_DELAY_TIME    (30 * RT_TICK_PER_SECOND)
+
+    int link_stat = 0;
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+    struct netdev *netdev = (struct netdev *) parameter;
+    
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get ec20 device by netdev name(%s) failed.", netdev->name);
+        return;
+    }
+
+    resp = at_create_resp(EC20_LINK_RESP_SIZE, 0, EC20_LINK_RESP_TIMO);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for ec20 device(%s) response structure.", device->name);
+        return;
+    }
+
+    while (1)
+    {
+        /* send "AT+CGREG" commond  to check netweork interface device link status */
+        if (at_obj_exec_cmd(device->client, resp, "AT+CGREG?") < 0)
+        {
+            if (netdev_is_link_up(netdev))
+            {
+                netdev_low_level_set_link_status(netdev, RT_FALSE);
+            }
+            
+            rt_thread_mdelay(EC20_LINK_DELAY_TIME);
+            continue;
+        }
+        else
+        {
+            at_resp_parse_line_args_by_kw(resp, "+CGREG:", "+CGREG: %*d,%d", &link_stat);
+
+            /* 1 Registered, home network,5 Registered, roaming */
+            if (link_stat == 1 || link_stat == 5)
+            {
+                if (netdev_is_link_up(netdev) == RT_FALSE)
+                {
+                    netdev_low_level_set_link_status(netdev, RT_TRUE);
+                }
+            }
+            else
+            {
+                if (netdev_is_link_up(netdev))
+                {
+                    netdev_low_level_set_link_status(netdev, RT_FALSE);
+                }
+            }
+        }
+
+        rt_thread_mdelay(EC20_LINK_DELAY_TIME);
+    }
+}
+
+static int ec20_netdev_check_link_status(struct netdev *netdev)
+{
+#define EC20_LINK_THREAD_TICK           20
+#define EC20_LINK_THREAD_STACK_SIZE     1024
+#define EC20_LINK_THREAD_PRIORITY       (RT_THREAD_PRIORITY_MAX - 2)
+
+    rt_thread_t tid;
+
+    if (netdev == RT_NULL)
+    {
+        LOG_E("input network interface device is NULL.\n");
+        return -RT_ERROR;
+    }
+
+    /* create ec20 link status polling thread  */
+    tid = rt_thread_create("ec20_link", ec20_check_link_status_entry, (void *) netdev, 
+            EC20_LINK_THREAD_STACK_SIZE, EC20_LINK_THREAD_PRIORITY, EC20_LINK_THREAD_TICK);
+    if (tid != RT_NULL)
+    {
+        rt_thread_startup(tid);
+    }
+
+    return RT_EOK;
+}
+
+static int ec20_net_init(struct at_device *device);
+
+static int ec20_netdev_set_up(struct netdev *netdev)
+{
+    struct at_device *device = RT_NULL;
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get ec20 device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+
+    if (device->is_init == RT_FALSE)
+    {
+        ec20_net_init(device);
+        device->is_init = RT_TRUE;
+
+        netdev_low_level_set_status(netdev, RT_TRUE);
+        LOG_D("the network interface device(%s) set up status.", netdev->name);
+    }
+
+    return RT_EOK;
+}
+
+static int ec20_netdev_set_down(struct netdev *netdev)
+{
+    struct at_device *device = RT_NULL;
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get ec20 device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+
+    if (device->is_init == RT_TRUE)
+    {
+        ec20_power_off(device);
+        device->is_init = RT_FALSE;
+
+        netdev_low_level_set_status(netdev, RT_FALSE);
+        LOG_D("the network interface device(%s) set down status.", netdev->name);
+    }
+
+    return RT_EOK;
+}
+
+static int ec20_netdev_set_dns_server(struct netdev *netdev, uint8_t dns_num, ip_addr_t *dns_server)
+{
+#define EC20_DNS_RESP_LEN    8
+#define EC20_DNS_RESP_TIMEO  rt_tick_from_millisecond(300)
+
+    int result = RT_EOK;
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    RT_ASSERT(netdev);
+    RT_ASSERT(dns_server);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get ec20 device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+    
+    resp = at_create_resp(EC20_DNS_RESP_LEN, 0, EC20_DNS_RESP_TIMEO);
+    if (resp == RT_NULL)
+    {
+        LOG_D("no memory for ec20 device(%s) response structure.", device->name);
+        result = -RT_ENOMEM;
+        goto __exit;
+    }
+
+    /* send "AT+QIDNSCFG=<pri_dns>[,<sec_dns>]" commond to set dns servers */
+    if (at_obj_exec_cmd(device->client, resp, "AT+QIDNSCFG=1,\"%s\"", inet_ntoa(*dns_server)) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    netdev_low_level_set_dns_server(netdev, dns_num, dns_server);
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+    
+    return result;
+}
+
+#ifdef NETDEV_USING_PING
+static int ec20_netdev_ping(struct netdev *netdev, const char *host, 
+        size_t data_len, uint32_t timeout, struct netdev_ping_resp *ping_resp)
+{
+#define EC20_PING_RESP_SIZE       128
+#define EC20_PING_IP_SIZE         16
+#define EC20_PING_TIMEO           (5 * RT_TICK_PER_SECOND)
+
+    rt_err_t result = RT_EOK;
+    int response = -1, recv_data_len, ping_time, ttl;
+    char ip_addr[EC20_PING_IP_SIZE] = {0};
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    RT_ASSERT(netdev);
+    RT_ASSERT(host);
+    RT_ASSERT(ping_resp);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get ec20 device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+
+    resp = at_create_resp(EC20_PING_RESP_SIZE, 4, EC20_PING_TIMEO);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for ec20 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    /* send "AT+QPING="<host>"[,[<timeout>][,<pingnum>]]" commond to send ping request */
+    if (at_obj_exec_cmd(device->client, resp, "AT+QPING=1,\"%s\",%d,1", host, timeout / RT_TICK_PER_SECOND) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    at_resp_parse_line_args_by_kw(resp, "+QPING:", "+QPING:%d", &response);
+    /* Received the ping response from the server */
+    if (response == 0)
+    {
+        if (at_resp_parse_line_args_by_kw(resp, "+QPING:", "+QPING:%d,\"%[^\"]\",%d,%d,%d",
+                    &response, ip_addr, &recv_data_len, &ping_time, &ttl) <= 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+    }
+
+    /* prase response number */
+    switch (response)
+    {
+    case 0:
+        inet_aton(ip_addr, &(ping_resp->ip_addr));
+        ping_resp->data_len = recv_data_len;
+        ping_resp->ticks = ping_time;
+        ping_resp->ttl = ttl;
+        result = RT_EOK;
+        break;
+    case 569:
+        result = -RT_ETIMEOUT;
+        break;
+    default:
+        result = -RT_ERROR;
+        break;
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+    
+    return result;
+}
+#endif /* NETDEV_USING_PING */
+
+#ifdef NETDEV_USING_NETSTAT
+static void ec20_netdev_netstat(struct netdev *netdev)
+{
+    // TODO
+}
+#endif /* NETDEV_USING_NETSTAT */
+
+const struct netdev_ops ec20_netdev_ops =
+{
+    ec20_netdev_set_up,
+    ec20_netdev_set_down,
+
+    RT_NULL,
+    ec20_netdev_set_dns_server,
+    RT_NULL,
+
+#ifdef NETDEV_USING_PING
+    ec20_netdev_ping,
+#endif
+#ifdef NETDEV_USING_NETSTAT
+    ec20_netdev_netstat,
+#endif
+};
+
+static struct netdev *ec20_netdev_add(const char *netdev_name)
+{
+#define ETHERNET_MTU        1500
+#define HWADDR_LEN          8
+    struct netdev *netdev = RT_NULL;
+
+    netdev = (struct netdev *)rt_calloc(1, sizeof(struct netdev));
+    if (netdev == RT_NULL)
+    {
+        LOG_E("no memory for ec20 device(%s) netdev structure.", netdev->name);
+        return RT_NULL;
+    }
+
+    netdev->mtu = ETHERNET_MTU;
+    netdev->ops = &ec20_netdev_ops;
+    netdev->hwaddr_len = HWADDR_LEN;
+
+#ifdef SAL_USING_AT
+    extern int sal_at_netdev_set_pf_info(struct netdev *netdev);
+    /* set the network interface socket/netdb operations */
+    sal_at_netdev_set_pf_info(netdev);
+#endif
+
+    netdev_register(netdev, netdev_name, RT_NULL);
+
+    return netdev;
+}
+
+/* =============================  ec20 device operations ============================= */
+
+#define AT_SEND_CMD(client, resp, resp_line, timeout, cmd)                                         \
+    do {                                                                                           \
+        (resp) = at_resp_set_info((resp), 128, (resp_line), rt_tick_from_millisecond(timeout));    \
+        if (at_obj_exec_cmd((client), (resp), (cmd)) < 0)                                          \
+        {                                                                                          \
+            result = -RT_ERROR;                                                                    \
+            goto __exit;                                                                          \
+        }                                                                                          \
+    } while(0)                                                                                     \
+
+/* initialize for ec20 */
+static void ec20_init_thread_entry(void *parameter)
+{
+#define INIT_RETRY                     5
+#define CIMI_RETRY                     10
+#define CSQ_RETRY                      20
+#define CREG_RETRY                     10
+#define CGREG_RETRY                    20
+
+    int i, qi_arg[3] = {0};
+    int retry_num = INIT_RETRY;
+    char parsed_data[20] = {0};
+    rt_err_t result = RT_EOK;
+    at_response_t resp = RT_NULL;
+    struct at_device *device = (struct at_device *) parameter;
+    struct at_client *client = device->client;
+
+    resp = at_create_resp(128, 0, rt_tick_from_millisecond(300));
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for ec20 device(%s) response structure.", device->name);
+        return;
+    }
+
+    LOG_D("start initializing the ec20 device(%s).", device->name);
+
+    while (retry_num--)
+    {
+        /* power on the ec20 device */
+        ec20_power_on(device);
+        rt_thread_mdelay(1000);
+
+        /* wait ec20 startup finish, send AT every 500ms, if receive OK, SYNC success*/
+        if (at_client_obj_wait_connect(client, EC20_WAIT_CONNECT_TIME))
+        {
+            result = -RT_ETIMEOUT;
+            goto __exit;
+        }
+
+        /* set response format to ATV1 */
+        AT_SEND_CMD(client, resp, 0, 300, "ATV1");
+        /* disable echo */
+        AT_SEND_CMD(client, resp, 0, 300, "ATE0");
+        /* Use AT+CMEE=2 to enable result code and use verbose values */
+        AT_SEND_CMD(client, resp, 0, 300, "AT+CMEE=2");
+        /* Get the baudrate */
+        AT_SEND_CMD(client, resp, 0, 300, "AT+IPR?");
+        at_resp_parse_line_args_by_kw(resp, "+IPR:", "+IPR: %d", &i);
+        LOG_D("ec20 device(%s) baudrate %d", device->name, i);
+        /* get module version */
+        AT_SEND_CMD(client, resp, 0, 300, "ATI");
+        /* show module version */
+        for (i = 0; i < (int) resp->line_counts - 1; i++)
+        {
+            LOG_D("%s", at_resp_get_line(resp, i + 1));
+        }
+        /* Use AT+GSN to query the IMEI of module */
+        AT_SEND_CMD(client, resp, 0, 300, "AT+GSN");
+        
+        /* check SIM card */
+        AT_SEND_CMD(client, resp, 2, 5 * 1000, "AT+CPIN?");
+        if (!at_resp_get_line_by_kw(resp, "READY"))
+        {
+            LOG_E("ec20 device(%s) SIM card detection failed.", device->name);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+        /* waiting for dirty data to be digested */
+        rt_thread_mdelay(10);
+        
+        
+        /* Use AT+CIMI to query the IMSI of SIM card */
+        // AT_SEND_CMD(client, resp, 2, 300, "AT+CIMI");
+        i = 0;
+        resp = at_resp_set_info(resp, 128, 0, rt_tick_from_millisecond(300));
+        while(at_obj_exec_cmd(device->client, resp, "AT+CIMI") < 0)
+        {
+            i++;
+            if(i > CIMI_RETRY)
+            {
+                LOG_E("ec20 device(%s) read CIMI failed.", device->name);
+                result = -RT_ERROR;
+                goto __exit;
+            }
+            rt_thread_mdelay(1000);
+        }
+
+        /* Use AT+QCCID to query ICCID number of SIM card */
+        AT_SEND_CMD(client, resp, 0, 300, "AT+QCCID");
+        /* check signal strength */
+        for (i = 0; i < CSQ_RETRY; i++)
+        {
+            AT_SEND_CMD(client, resp, 0, 300, "AT+CSQ");
+            at_resp_parse_line_args_by_kw(resp, "+CSQ:", "+CSQ: %d,%d", &qi_arg[0], &qi_arg[1]);
+            if (qi_arg[0] != 99)
+            {
+                LOG_D("ec20 device(%s) signal strength: %d, channel bit error rate: %d", 
+                        device->name, qi_arg[0], qi_arg[1]);
+                break;
+            }
+            rt_thread_mdelay(1000);
+        }
+        if (i == CSQ_RETRY)
+        {
+            LOG_E("ec20 device(%s) signal strength check failed (%s)", device->name, parsed_data);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+        /* check the GSM network is registered */
+        for (i = 0; i < CREG_RETRY; i++)
+        {
+            AT_SEND_CMD(client, resp, 0, 300, "AT+CREG?");
+            at_resp_parse_line_args_by_kw(resp, "+CREG:", "+CREG: %s", &parsed_data);
+            if (!rt_strncmp(parsed_data, "0,1", sizeof(parsed_data)) || 
+                    !rt_strncmp(parsed_data, "0,5", sizeof(parsed_data)))
+            {
+                LOG_D("ec20 device(%s) GSM network is registered(%s)", device->name, parsed_data);
+                break;
+            }
+            rt_thread_mdelay(1000);
+        }
+        if (i == CREG_RETRY)
+        {
+            LOG_E("ec20 device(%s) GSM network is register failed (%s)", device->name, parsed_data);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+        /* check the GPRS network is registered */
+        for (i = 0; i < CGREG_RETRY; i++)
+        {
+            AT_SEND_CMD(client, resp, 0, 300, "AT+CGREG?");
+            at_resp_parse_line_args_by_kw(resp, "+CGREG:", "+CGREG: %s", &parsed_data);
+            if (!rt_strncmp(parsed_data, "0,1", sizeof(parsed_data)) || 
+                    !rt_strncmp(parsed_data, "0,5", sizeof(parsed_data)))
+            {
+                LOG_D("ec20 device(%s) GPRS network is registered(%s)", device->name, parsed_data);
+                break;
+            }
+            rt_thread_mdelay(1000);
+        }
+        if (i == CGREG_RETRY)
+        {
+            LOG_E("ec20 device(%s) GPRS network is register failed (%s)", device->name, parsed_data);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+        /*Use AT+CEREG? to query current EPS Network Registration Status*/
+        AT_SEND_CMD(client, resp, 0, 300, "AT+CEREG?");
+        /* Use AT+COPS? to query current Network Operator */
+        AT_SEND_CMD(client, resp, 0, 300, "AT+COPS?");
+        at_resp_parse_line_args_by_kw(resp, "+COPS:", "+COPS: %*[^\"]\"%[^\"]", &parsed_data);
+        if(rt_strcmp(parsed_data,"CHINA MOBILE") == 0)
+        {
+            /* "CMCC" */
+            LOG_I("ec20 device(%s) network operator: %s", device->name, parsed_data);
+            AT_SEND_CMD(client, resp, 0, 300, QICSGP_CHINA_MOBILE);
+        }
+        else if(strcmp(parsed_data,"CHN-UNICOM") == 0)
+        {
+            /* "UNICOM" */
+            LOG_I("ec20 device(%s) network operator: %s", device->name, parsed_data);
+            AT_SEND_CMD(client, resp, 0, 300, QICSGP_CHINA_UNICOM);
+        }
+        else if(rt_strcmp(parsed_data,"CHN-CT") == 0)
+        {
+            /* "CT" */
+            LOG_I("ec20 device(%s) network operator: %s", device->name, parsed_data);
+            AT_SEND_CMD(client, resp, 0, 300, QICSGP_CHINA_TELECOM);
+        }
+        /* Enable automatic time zone update via NITZ and update LOCAL time to RTC */
+        AT_SEND_CMD(client, resp, 0, 300, "AT+CTZU=3");
+        /* Get RTC time */
+        AT_SEND_CMD(client, resp, 0, 300, "AT+CCLK?");
+
+        /* Deactivate context profile */
+        AT_SEND_CMD(client, resp, 0, 40 * 1000, "AT+QIDEACT=1");
+        /* Activate context profile */
+        AT_SEND_CMD(client, resp, 0, 150 * 1000, "AT+QIACT=1");
+        /* Query the status of the context profile */
+        AT_SEND_CMD(client, resp, 0, 150 * 1000, "AT+QIACT?");
+        at_resp_parse_line_args_by_kw(resp, "+QIACT:", "+QIACT: %*[^\"]\"%[^\"]", &parsed_data);
+        LOG_I("ec20 device(%s) IP address: %s", device->name, parsed_data);
+        result = RT_EOK;
+
+    __exit:
+        if (result == RT_EOK)
+        {
+            break;
+        }
+        else
+        {
+            /* power off the ec20 device */
+            ec20_power_off(device);
+            rt_thread_mdelay(1000);
+
+            LOG_I("ec20 device(%s) initialize retry...", device->name);
+        }
+    }
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    if (result == RT_EOK)
+    {
+        /* set network interface device status and address information */
+        ec20_netdev_set_info(device->netdev);
+        ec20_netdev_check_link_status(device->netdev);
+
+        LOG_I("ec20 device(%s) network initialize success.", device->name);
+    }
+    else
+    {
+        LOG_E("ec20 device(%s) network initialize failed(%d).", device->name, result);
+    }
+
+}
+
+/* ec20 device network initialize */
+static int ec20_net_init(struct at_device *device)
+{
+#ifdef AT_DEVICE_EC20_INIT_ASYN
+    rt_thread_t tid;
+    tid = rt_thread_create("ec20_net_init", ec20_init_thread_entry, (void *) device,
+            EC20_THREAD_STACK_SIZE, EC20_THREAD_PRIORITY, 20);
+    if (tid)
+    {
+        rt_thread_startup(tid);
+    }
+    else
+    {
+        LOG_E("create ec20 device(%s) initialization thread failed.", device->name);
+        return -RT_ERROR;
+    }
+#else
+    ec20_init_thread_entry(device);
+#endif /* AT_DEVICE_EC20_INIT_ASYN */
+    
+    return RT_EOK;
+}
+
+static int ec20_init(struct at_device *device)
+{
+    struct at_device_ec20 *ec20 = (struct at_device_ec20 *) device->user_data;
+
+    /* initialize AT client */
+    at_client_init(ec20->client_name, ec20->recv_line_num);
+
+    device->client = at_client_get(ec20->client_name);
+    if (device->client == RT_NULL)
+    {
+        LOG_E("ec20 device(%s) initialize failed, get AT client(%s) failed.", ec20->device_name, ec20->client_name);
+        return -RT_ERROR;
+    }
+
+    /* register URC data execution function  */
+#ifdef AT_USING_SOCKET
+    ec20_socket_init(device);
+#endif
+
+    /* add ec20 device to the netdev list */
+    device->netdev = ec20_netdev_add(ec20->device_name);
+    if (device->netdev == RT_NULL)
+    {
+        LOG_E("ec20 device(%s) initialize failed, get network interface device failed.", ec20->device_name);
+        return -RT_ERROR;
+    }
+
+    /* initialize ec20 pin configuration */
+    if (ec20->power_pin != -1 && ec20->power_status_pin != -1)
+    {
+        rt_pin_mode(ec20->power_pin, PIN_MODE_OUTPUT);
+        rt_pin_mode(ec20->power_status_pin, PIN_MODE_INPUT);
+    }
+    
+    /* initialize ec20 device network */
+    return ec20_netdev_set_up(device->netdev);
+}
+
+static int ec20_deinit(struct at_device *device)
+{
+    return ec20_netdev_set_down(device->netdev);
+}
+
+static int ec20_control(struct at_device *device, int cmd, void *arg)
+{
+    int result = -RT_ERROR;
+
+    RT_ASSERT(device);
+
+    switch (cmd)
+    {
+    case AT_DEVICE_CTRL_POWER_ON:
+    case AT_DEVICE_CTRL_POWER_OFF:
+    case AT_DEVICE_CTRL_RESET:
+    case AT_DEVICE_CTRL_LOW_POWER:
+    case AT_DEVICE_CTRL_SLEEP:
+    case AT_DEVICE_CTRL_WAKEUP:
+    case AT_DEVICE_CTRL_NET_CONN:
+    case AT_DEVICE_CTRL_NET_DISCONN:
+    case AT_DEVICE_CTRL_SET_WIFI_INFO:
+    case AT_DEVICE_CTRL_GET_SIGNAL:
+    case AT_DEVICE_CTRL_GET_GPS:
+    case AT_DEVICE_CTRL_GET_VER:
+        LOG_W("ec20 not support the control command(%d).", cmd);
+        break;
+    default:
+        LOG_E("input error control command(%d).", cmd);
+        break;
+    }
+
+    return result;
+}
+
+const struct at_device_ops ec20_device_ops = 
+{
+    ec20_init,
+    ec20_deinit,
+    ec20_control,
+};
+
+static int ec20_device_class_register(void)
+{
+    struct at_device_class *class = RT_NULL;
+
+    class = (struct at_device_class *) rt_calloc(1, sizeof(struct at_device_class));
+    if (class == RT_NULL)
+    {
+        LOG_E("no memory for ec20 device class create.");
+        return -RT_ENOMEM;
+    }
+
+    /* fill ec20 device class object */
+#ifdef AT_USING_SOCKET
+    ec20_socket_class_register(class);
+#endif
+    class->device_ops = &ec20_device_ops;
+    
+    return at_device_class_register(class, AT_DEVICE_CLASS_EC20);
+}
+INIT_DEVICE_EXPORT(ec20_device_class_register);
+
+#endif /* AT_DEVICE_USING_EC20 */

+ 67 - 0
class/ec20/at_device_ec20.h

@@ -0,0 +1,67 @@
+/*
+ * File      : at_device_ec20.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-05-16     chenyong     first version
+ */
+
+#ifndef __AT_DEVICE_EC20_H__
+#define __AT_DEVICE_EC20_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+
+#include <at_device.h>
+
+/* The maximum number of sockets supported by the ec20 device */
+#define AT_DEVICE_EC20_SOCKETS_NUM  5
+
+struct at_device_ec20
+{     
+    char *device_name;
+    char *client_name;
+
+    int power_pin;
+    int power_status_pin;
+    size_t recv_line_num;
+    struct at_device device;
+
+    void *socket_data;
+    void *user_data;
+};
+
+#ifdef AT_USING_SOCKET
+
+/* ec20 device socket initialize */
+int ec20_socket_init(struct at_device *device);
+
+/* ec20 device class socket register */
+int ec20_socket_class_register(struct at_device_class *class);
+
+#endif /* AT_USING_SOCKET */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AT_DEVICE_EC20_H__ */

+ 1007 - 0
class/ec20/at_socket_ec20.c

@@ -0,0 +1,1007 @@
+/*
+ * File      : at_socket_ec20.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-06-12     chenyong     first version
+ * 2018-08-12     Marcus       port to ec20
+ * 2019-05-13     chenyong     multi AT socket client support
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <at_device_ec20.h>
+
+#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10300
+#error "This AT Client version is older, please check and update latest AT Client!"
+#endif
+
+#define LOG_TAG                        "at.skt"
+#include <at_log.h>
+
+#if defined(AT_DEVICE_USING_EC20) && defined(AT_USING_SOCKET)
+
+#define EC20_MODULE_SEND_MAX_SIZE       1460
+
+/* set real event by current socket and current state */
+#define SET_EVENT(socket, event)       (((socket + 1) << 16) | (event))
+
+/* AT socket event type */
+#define EC20_EVENT_CONN_OK             (1L << 0)
+#define EC20_EVENT_SEND_OK             (1L << 1)
+#define EC20_EVENT_RECV_OK             (1L << 2)
+#define EC20_EVNET_CLOSE_OK            (1L << 3)
+#define EC20_EVENT_CONN_FAIL           (1L << 4)
+#define EC20_EVENT_SEND_FAIL           (1L << 5)
+#define EC20_EVENT_DOMAIN_OK           (1L << 6)
+
+static at_evt_cb_t at_evt_cb_set[] = {
+        [AT_SOCKET_EVT_RECV] = NULL,
+        [AT_SOCKET_EVT_CLOSED] = NULL,
+};
+    
+static void at_tcp_ip_errcode_parse(int result)//TCP/IP_QIGETERROR
+{
+    switch(result)
+    {
+    case 0   : LOG_D("%d : Operation successful",         result); break;
+    case 550 : LOG_E("%d : Unknown error",                result); break;
+    case 551 : LOG_E("%d : Operation blocked",            result); break;
+    case 552 : LOG_E("%d : Invalid parameters",           result); break;
+    case 553 : LOG_E("%d : Memory not enough",            result); break;
+    case 554 : LOG_E("%d : Create socket failed",         result); break;
+    case 555 : LOG_E("%d : Operation not supported",      result); break;
+    case 556 : LOG_E("%d : Socket bind failed",           result); break;
+    case 557 : LOG_E("%d : Socket listen failed",         result); break;
+    case 558 : LOG_E("%d : Socket write failed",          result); break;
+    case 559 : LOG_E("%d : Socket read failed",           result); break;
+    case 560 : LOG_E("%d : Socket accept failed",         result); break;
+    case 561 : LOG_E("%d : Open PDP context failed",      result); break;
+    case 562 : LOG_E("%d : Close PDP context failed",     result); break;
+    case 563 : LOG_W("%d : Socket identity has been used", result); break;
+    case 564 : LOG_E("%d : DNS busy",                     result); break;
+    case 565 : LOG_E("%d : DNS parse failed",             result); break;
+    case 566 : LOG_E("%d : Socket connect failed",        result); break;
+    // case 567 : LOG_W("%d : Socket has been closed",       result); break;
+    case 567 : break;
+    case 568 : LOG_E("%d : Operation busy",               result); break;
+    case 569 : LOG_E("%d : Operation timeout",            result); break;
+    case 570 : LOG_E("%d : PDP context broken down",      result); break;
+    case 571 : LOG_E("%d : Cancel send",                  result); break;
+    case 572 : LOG_E("%d : Operation not allowed",        result); break;
+    case 573 : LOG_E("%d : APN not configured",           result); break;
+    case 574 : LOG_E("%d : Port busy",                    result); break;
+    default  : LOG_E("%d : Unknown err code",             result); break;
+    }
+}
+
+static void at_http_errcode_parse(int result)//HTTP
+{
+    switch(result)
+    {
+    case 0   : LOG_D("%d : Operation successful",         result); break;
+    case 701 : LOG_E("%d : HTTP(S) unknown error",        result); break;
+    case 702 : LOG_E("%d : HTTP(S) timeout",              result); break;
+    case 703 : LOG_E("%d : HTTP(S) busy",                 result); break;
+    case 704 : LOG_E("%d : HTTP(S) UART busy",            result); break;
+    case 705 : LOG_E("%d : HTTP(S) no GET/POST requests", result); break;
+    case 706 : LOG_E("%d : HTTP(S) network busy",         result); break;
+    case 707 : LOG_E("%d : HTTP(S) network open failed",  result); break;
+    case 708 : LOG_E("%d : HTTP(S) network no configuration", result); break;
+    case 709 : LOG_E("%d : HTTP(S) network deactivated",  result); break;
+    case 710 : LOG_E("%d : HTTP(S) network error",        result); break;
+    case 711 : LOG_E("%d : HTTP(S) URL error",            result); break;
+    case 712 : LOG_E("%d : HTTP(S) empty URL",            result); break;
+    case 713 : LOG_E("%d : HTTP(S) IP address error",     result); break;
+    case 714 : LOG_E("%d : HTTP(S) DNS error",            result); break;
+    case 715 : LOG_E("%d : HTTP(S) socket create error",  result); break;
+    case 716 : LOG_E("%d : HTTP(S) socket connect error", result); break;
+    case 717 : LOG_E("%d : HTTP(S) socket read error",    result); break;
+    case 718 : LOG_E("%d : HTTP(S) socket write error",   result); break;
+    case 719 : LOG_E("%d : HTTP(S) socket closed",        result); break;
+    case 720 : LOG_E("%d : HTTP(S) data encode error",    result); break;
+    case 721 : LOG_E("%d : HTTP(S) data decode error",    result); break;
+    case 722 : LOG_E("%d : HTTP(S) read timeout",         result); break;
+    case 723 : LOG_E("%d : HTTP(S) response failed",      result); break;
+    case 724 : LOG_E("%d : Incoming call busy",           result); break;
+    case 725 : LOG_E("%d : Voice call busy",              result); break;
+    case 726 : LOG_E("%d : Input timeout",                result); break;
+    case 727 : LOG_E("%d : Wait data timeout",            result); break;
+    case 728 : LOG_E("%d : Wait HTTP(S) response timeout", result); break;
+    case 729 : LOG_E("%d : Memory allocation failed",     result); break;
+    case 730 : LOG_E("%d : Invalid parameter",            result); break;
+    default  : LOG_E("%d : Unknown err code",             result); break;
+    }
+}
+
+static void at_http_rsponsecode_parse(int result)//HTTP
+{
+    switch(result)
+    {
+    case 200 : LOG_D("%d : OK",                           result); break;
+    case 400 : LOG_E("%d : Bad request",                  result); break;
+    case 403 : LOG_E("%d : Forbidden",                    result); break;
+    case 404 : LOG_E("%d : Not found",                    result); break;
+    case 409 : LOG_E("%d : Conflict",                     result); break;
+    case 411 : LOG_E("%d : Length required",              result); break;
+    case 500 : LOG_E("%d : Internal server error",        result); break;
+    case 502 : LOG_E("%d : Bad gate way",                 result); break;
+    default  : LOG_E("%d : Unknown err code",             result); break;
+    }
+}
+
+static void at_ftp_errcode_parse(int result)//FTP
+{
+    switch(result)
+    {
+    case 0   : LOG_D("%d : Operation successful",         result); break;
+    case 601 : LOG_E("%d : Unknown error",                result); break;
+    case 602 : LOG_E("%d : FTP(S) server blocked",        result); break;
+    case 603 : LOG_E("%d : FTP(S) server busy",           result); break;
+    case 604 : LOG_E("%d : DNS parse failed",             result); break;
+    case 605 : LOG_E("%d : Network error",                result); break;
+    case 606 : LOG_E("%d : Control connection closed.",   result); break;
+    case 607 : LOG_E("%d : Data connection closed",       result); break;
+    case 608 : LOG_E("%d : Socket closed by peer",        result); break;
+    case 609 : LOG_E("%d : Timeout error",                result); break;
+    case 610 : LOG_E("%d : Invalid parameter",            result); break;
+    case 611 : LOG_E("%d : Failed to open file",          result); break;
+    case 612 : LOG_E("%d : File position invalid",        result); break;
+    case 613 : LOG_E("%d : File error",                   result); break;
+    case 614 : LOG_E("%d : Service not available, closing control connection", result); break;
+    case 615 : LOG_E("%d : Open data connection failed",  result); break;
+    case 616 : LOG_E("%d : Connection closed; transfer aborted", result); break;
+    case 617 : LOG_E("%d : Requested file action not taken", result); break;
+    case 618 : LOG_E("%d : Requested action aborted: local error in processing", result); break;
+    case 619 : LOG_E("%d : Requested action not taken: insufficient system storage", result); break;
+    case 620 : LOG_E("%d : Syntax error, command unrecognized", result); break;
+    case 621 : LOG_E("%d : Syntax error in parameters or arguments", result); break;
+    case 622 : LOG_E("%d : Command not implemented",      result); break;
+    case 623 : LOG_E("%d : Bad sequence of commands",     result); break;
+    case 624 : LOG_E("%d : Command parameter not implemented", result); break;
+    case 625 : LOG_E("%d : Not logged in",                result); break;
+    case 626 : LOG_E("%d : Need account for storing files", result); break;
+    case 627 : LOG_E("%d : Requested action not taken",   result); break;
+    case 628 : LOG_E("%d : Requested action aborted: page type unknown", result); break;
+    case 629 : LOG_E("%d : Requested file action aborted", result); break;
+    case 630 : LOG_E("%d : Requested file name invalid",  result); break;
+    case 631 : LOG_E("%d : SSL authentication failed",    result); break;
+    default  : LOG_E("%d : Unknown err code",             result); break;
+    }
+}
+
+static void at_ftp_protocol_errcode_parse(int result)//FTP_Protocol
+{
+    switch(result)
+    {
+    case 421 : LOG_E("%d : Service not available, closing control connection", result); break;
+    case 425 : LOG_E("%d : Open data connection failed",  result); break;
+    case 426 : LOG_E("%d : Connection closed; transfer aborted", result); break;
+    case 450 : LOG_E("%d : Requested file action not taken", result); break;
+    case 451 : LOG_E("%d : Requested action aborted: local error in processing", result); break;
+    case 452 : LOG_E("%d : Requested action not taken: insufficient system storage", result); break;
+    case 500 : LOG_E("%d : Syntax error, command unrecognized", result); break;
+    case 501 : LOG_E("%d : Syntax error in parameters or arguments", result); break;
+    case 502 : LOG_E("%d : Command not implemented",      result); break;
+    case 503 : LOG_E("%d : Bad sequence of commands",     result); break;
+    case 504 : LOG_E("%d : Command parameter not implemented", result); break;
+    case 530 : LOG_E("%d : Not logged in",                result); break;
+    case 532 : LOG_E("%d : Need account for storing files", result); break;
+    case 550 : LOG_E("%d : Requested action not taken: file unavailable", result); break;
+    case 551 : LOG_E("%d : Requested action aborted: page type unknown", result); break;
+    case 552 : LOG_E("%d : Requested file action aborted: exceeded storage allocation", result); break;
+    case 553 : LOG_E("%d : Requested action not taken: file name not allowed", result); break;
+    default  : LOG_E("%d : Unknown err code",             result); break;
+    }
+}
+
+static void at_smtp_errcode_parse(int result)//Email
+{
+    switch(result)
+    {
+    case 651 : LOG_E("%d : Unknown error",                result); break;
+    case 652 : LOG_E("%d : The SMTP server is busy, such as uploading the body or sending an email.", result); break;
+    case 653 : LOG_E("%d : Failed to get IP address according to the domain name.", result); break;
+    case 654 : LOG_E("%d : Network error, such as failed to activate GPRS/CSD context, failed to establish the TCP connection with the SMTP server or failed to send an email to the SMTP server, etc.", result); break;
+    case 655 : LOG_E("%d : Unsupported authentication type", result); break;
+    case 656 : LOG_E("%d : The connection for the SMTP server is closed by peer.", result); break;
+    case 657 : LOG_E("%d : GPRS/CSD context is deactivated.", result); break;
+    case 658 : LOG_E("%d : Timeout",                      result); break;
+    case 659 : LOG_E("%d : No recipient for the SMTP server", result); break;
+    case 660 : LOG_E("%d : Failed to send an email",      result); break;
+    case 661 : LOG_E("%d : Failed to open a file",        result); break;
+    case 662 : LOG_E("%d : No enough memory for the attachment", result); break;
+    case 663 : LOG_E("%d : Failed to save the attachment", result); break;
+    case 664 : LOG_E("%d : The input parameter is wrong", result); break;
+    case 665 : LOG_E("%d : SSL authentication failed",    result); break;
+    case 666 : LOG_E("%d : Service not available, closing transmission channel", result); break;
+    case 667 : LOG_E("%d : Requested mail action not taken: mailbox unavailable", result); break;
+    case 668 : LOG_E("%d : Requested action aborted: local error in processing", result); break;
+    case 669 : LOG_E("%d : Requested action not taken: insufficient system storage", result); break;
+    case 670 : LOG_E("%d : Syntax error, command unrecognized", result); break;
+    case 671 : LOG_E("%d : Syntax error in parameters or arguments", result); break;
+    case 672 : LOG_E("%d : Command not implemented",      result); break;
+    case 673 : LOG_E("%d : Bad sequence of commands",     result); break;
+    case 674 : LOG_E("%d : Command parameter not implemented", result); break;
+    case 675 : LOG_E("%d : <domain> does not accept mail (see RFC1846)", result); break;
+    case 676 : LOG_E("%d : Access denied",                result); break;
+    case 677 : LOG_E("%d : Authentication failed",        result); break;
+    case 678 : LOG_E("%d : Requested action not taken: mailbox unavailable", result); break;
+    case 679 : LOG_E("%d : User not local; please try <forward-path>", result); break;
+    case 680 : LOG_E("%d : Requested mail action aborted: exceeded storage allocation", result); break;
+    case 681 : LOG_E("%d : Requested action not taken: mailbox name not allowed", result); break;
+    case 682 : LOG_E("%d : Transaction failed",           result); break;
+    default  : LOG_E("%d : Unknown err code",             result); break;
+    }
+}
+
+static void at_smtp_protocol_errcode_parse(int result)//Email_Protocol
+{
+    switch(result)
+    {
+    case 421 : LOG_E("%d : Service not available, closing transmission channel", result); break;
+    case 450 : LOG_E("%d : Requested mail action not taken: mailbox unavailable", result); break;
+    case 451 : LOG_E("%d : Requested action aborted: local error in processing", result); break;
+    case 452 : LOG_E("%d : Requested action not taken: insufficient system storage", result); break;
+    case 500 : LOG_E("%d : Syntax error, command unrecognized", result); break;
+    case 501 : LOG_E("%d : Syntax error in parameters or arguments", result); break;
+    case 502 : LOG_E("%d : Command not implemented",      result); break;
+    case 503 : LOG_E("%d : Bad sequence of commands",     result); break;
+    case 504 : LOG_E("%d : Command parameter not implemented", result); break;
+    case 521 : LOG_E("%d : <domain> does not accept mail (see RFC1846)", result); break;
+    case 530 : LOG_E("%d : Access denied",                result); break;
+    case 535 : LOG_E("%d : Authentication failed",        result); break;
+    case 550 : LOG_E("%d : Requested action not taken: mailbox unavailable", result); break;
+    case 551 : LOG_E("%d : User not local; please try <forward-path>", result); break;
+    case 552 : LOG_E("%d : Requested mail action aborted: exceeded storage allocation", result); break;
+    case 553 : LOG_E("%d : Requested action not taken: mailbox name not allowed", result); break;
+    case 554 : LOG_E("%d : Transaction failed",           result); break;
+    default  : LOG_E("%d : Unknown err code",             result); break;
+    }
+}
+
+static int ec20_socket_event_send(struct at_device *device, uint32_t event)
+{
+    return (int) rt_event_send(device->socket_event, event);
+}
+
+static int ec20_socket_event_recv(struct at_device *device, uint32_t event, uint32_t timeout, rt_uint8_t option)
+{
+    int result = RT_EOK;
+    rt_uint32_t recved;
+
+    result = rt_event_recv(device->socket_event, event, option | RT_EVENT_FLAG_CLEAR, timeout, &recved);
+    if (result != RT_EOK)
+    {
+        return -RT_ETIMEOUT;
+    }
+
+    return recved;
+}
+
+/**
+ * close socket by AT commands.
+ *
+ * @param current socket
+ *
+ * @return  0: close socket success
+ *         -1: send AT commands error
+ *         -2: wait socket event timeout
+ *         -5: no memory
+ */
+static int ec20_socket_close(struct at_socket *socket)
+{
+    int result = RT_EOK;
+    at_response_t resp = RT_NULL;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+    
+    resp = at_create_resp(64, 0, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for ec20 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    /* default connection timeout is 10 seconds, but it set to 1 seconds is convenient to use.*/
+    result = at_obj_exec_cmd(device->client, resp, "AT+QICLOSE=%d,1", device_socket);
+    
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+/**
+ * create TCP/UDP client or server connect by AT commands.
+ *
+ * @param socket current socket
+ * @param ip server or client IP address
+ * @param port server or client port
+ * @param type connect socket type(tcp, udp)
+ * @param is_client connection is client
+ *
+ * @return   0: connect success
+ *          -1: connect failed, send commands error or type error
+ *          -2: wait socket event timeout
+ *          -5: no memory
+ */
+static int ec20_socket_connect(struct at_socket *socket, char *ip, int32_t port, 
+    enum at_socket_type type, rt_bool_t is_client)
+{
+    uint32_t event = 0;
+    rt_bool_t retryed = RT_FALSE;
+    at_response_t resp = RT_NULL;
+    int result = 0, event_result = 0;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+
+    RT_ASSERT(ip);
+    RT_ASSERT(port >= 0);
+
+    resp = at_create_resp(128, 0, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for ec20 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+__retry:  
+    /* clear socket connect event */
+    event = SET_EVENT(device_socket, EC20_EVENT_CONN_OK | EC20_EVENT_CONN_FAIL);
+    ec20_socket_event_recv(device, event, 0, RT_EVENT_FLAG_OR);
+
+    if (is_client)
+    {
+        switch (type)
+        {
+        case AT_SOCKET_TCP:
+            /* send AT commands(AT+QIOPEN=<contextID>,<socket>,"<TCP/UDP>","<IP_address>/<domain_name>", */
+            /* <remote_port>,<local_port>,<access_mode>) to connect TCP server */
+            /* contextID   = 1 : use same contextID as AT+QICSGP & AT+QIACT */
+            /* local_port  = 0 : local port assigned automatically */
+            /* access_mode = 1 : Direct push mode */
+            if (at_obj_exec_cmd(device->client, resp, 
+                    "AT+QIOPEN=1,%d,\"TCP\",\"%s\",%d,0,1", device_socket, ip, port) < 0)
+            {
+                result = -RT_ERROR;
+                goto __exit;
+            }
+            break;
+
+        case AT_SOCKET_UDP:
+            if (at_obj_exec_cmd(device->client, resp, 
+                    "AT+QIOPEN=1,%d,\"UDP\",\"%s\",%d,0,1", device_socket, ip, port) < 0)
+            {
+                result = -RT_ERROR;
+                goto __exit;
+            }
+            break;
+
+        default:
+            LOG_E("ec20 device(%s) not supported connect type : %d.", device->name, type);
+            return -RT_ERROR;
+        }
+    }
+
+    /* waiting result event from AT URC, the device default connection timeout is 75 seconds, but it set to 10 seconds is convenient to use.*/
+    if (ec20_socket_event_recv(device, SET_EVENT(device_socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
+    {
+        LOG_E("ec20 device(%s) socket(%d) connect failed, wait connect result timeout.", device->name, device_socket);
+        result = -RT_ETIMEOUT;
+        goto __exit;
+    }
+    /* waiting OK or failed result */
+    event_result = ec20_socket_event_recv(device, 
+        EC20_EVENT_CONN_OK | EC20_EVENT_CONN_FAIL, 1 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR);
+    if (event_result < 0)
+    {
+        LOG_E("ec20 device(%s) socket(%d) connect failed, wait connect OK|FAIL timeout.", device->name, device_socket);
+        result = -RT_ETIMEOUT;
+        goto __exit;
+    }
+    /* check result */
+    if (event_result & EC20_EVENT_CONN_FAIL)
+    {
+        if (retryed == RT_FALSE)
+        {
+            LOG_D("ec20 device(%s) socket(%d) connect failed, maybe the socket was not be closed at the last time and now will retry.", 
+                    device->name, device_socket);
+            /* default connection timeout is 10 seconds, but it set to 1 seconds is convenient to use.*/
+            if (ec20_socket_close(socket) < 0)
+            {
+                result = -RT_ERROR;
+                goto __exit;
+            }
+            retryed = RT_TRUE;
+            goto __retry;
+        }
+        LOG_E("ec20 device(%s) socket(%d) connect failed.", device->name, device_socket);
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+static int at_get_send_size(struct at_socket *socket, size_t *size, size_t *acked, size_t *nacked)
+{
+    int result = 0;
+    at_response_t resp = RT_NULL;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+
+    resp = at_create_resp(128, 0, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for ec20 device(%s) response structure.", device->name);
+        result = -RT_ENOMEM;
+        goto __exit;
+    }
+
+    if (at_obj_exec_cmd(device->client, resp, "AT+QISEND=%d,0", device_socket) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    if (at_resp_parse_line_args_by_kw(resp, "+QISEND:", "+QISEND: %d,%d,%d", size, acked, nacked) <= 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+static int at_wait_send_finish(struct at_socket *socket, size_t settings_size)
+{
+    /* get the timeout by the input data size */
+    rt_tick_t timeout = rt_tick_from_millisecond(settings_size);
+    rt_tick_t last_time = rt_tick_get();
+    size_t size = 0, acked = 0, nacked = 0xFFFF;
+
+    while (rt_tick_get() - last_time <= timeout)
+    {
+        at_get_send_size(socket, &size, &acked, &nacked);
+        if (nacked == 0)
+        {
+            return RT_EOK;
+        }
+        rt_thread_mdelay(50);
+    }
+
+    return -RT_ETIMEOUT;
+}
+
+/**
+ * send data to server or client by AT commands.
+ *
+ * @param socket current socket
+ * @param buff send buffer
+ * @param bfsz send buffer size
+ * @param type connect socket type(tcp, udp)
+ *
+ * @return >=0: the size of send success
+ *          -1: send AT commands error or send data error
+ *          -2: waited socket event timeout
+ *          -5: no memory
+ */
+static int ec20_socket_send(struct at_socket *socket, const char *buff, size_t bfsz, enum at_socket_type type)
+{
+    uint32_t event = 0;
+    int result = 0, event_result = 0;
+    size_t cur_pkt_size = 0, sent_size = 0;
+    at_response_t resp = RT_NULL;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+    struct at_device_ec20 *ec20 = (struct at_device_ec20 *) device->user_data;
+    rt_mutex_t lock = device->client->lock;
+
+    RT_ASSERT(buff);
+
+    resp = at_create_resp(128, 2, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for ec20 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    rt_mutex_take(lock, RT_WAITING_FOREVER);
+
+    /* set current socket for send URC event */
+    ec20->user_data = (void *) device_socket;
+
+    /* clear socket send event */
+    event = SET_EVENT(device_socket, EC20_EVENT_SEND_OK | EC20_EVENT_SEND_FAIL);
+    ec20_socket_event_recv(device, event, 0, RT_EVENT_FLAG_OR);
+
+    /* set AT client end sign to deal with '>' sign.*/
+    at_obj_set_end_sign(device->client, '>');
+
+    while (sent_size < bfsz)
+    {
+        if (bfsz - sent_size < EC20_MODULE_SEND_MAX_SIZE)
+        {
+            cur_pkt_size = bfsz - sent_size;
+        }
+        else
+        {
+            cur_pkt_size = EC20_MODULE_SEND_MAX_SIZE;
+        }
+
+        /* send the "AT+QISEND" commands to AT server than receive the '>' response on the first line. */
+        if (at_obj_exec_cmd(device->client, resp, "AT+QISEND=%d,%d", device_socket, cur_pkt_size) < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* send the real data to server or client */
+        result = (int) at_client_send(buff + sent_size, cur_pkt_size);
+        if (result == 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* waiting result event from AT URC */
+        if (ec20_socket_event_recv(device, SET_EVENT(device_socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
+        {
+            result = -RT_ETIMEOUT;
+            goto __exit;
+        }
+        /* waiting OK or failed result */
+        event_result = ec20_socket_event_recv(device, 
+            EC20_EVENT_SEND_OK | EC20_EVENT_SEND_FAIL, 1 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR);
+        if (event_result < 0)
+        {
+            LOG_E("ec20 device(%s) socket (%d) send failed, wait connect OK|FAIL timeout.", device->name, device_socket);
+            result = -RT_ETIMEOUT;
+            goto __exit;
+        }
+        /* check result */
+        if (event_result & EC20_EVENT_SEND_FAIL)
+        {
+            LOG_E("ec20 device(%s) socket (%d) send failed.", device->name, device_socket);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        if (type == AT_SOCKET_TCP)
+        {
+            // at_wait_send_finish(socket, cur_pkt_size);
+            rt_thread_mdelay(10);
+        }
+
+        sent_size += cur_pkt_size;
+    }
+
+__exit:
+    /* reset the end sign for data conflict */
+    at_obj_set_end_sign(device->client, 0);
+
+    rt_mutex_release(lock);
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+/**
+ * domain resolve by AT commands.
+ *
+ * @param name domain name
+ * @param ip parsed IP address, it's length must be 16
+ *
+ * @return  0: domain resolve success
+ *         -1: send AT commands error or response error
+ *         -2: wait socket event timeout
+ *         -5: no memory
+ */
+static int ec20_domain_resolve(const char *name, char ip[16])
+{
+#define RESOLVE_RETRY                  3
+
+    int i, result;
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    RT_ASSERT(name);
+    RT_ASSERT(ip);
+
+    device = at_device_get_first_initialized();
+    if (device == RT_NULL)
+    {
+        LOG_E("get first initialization ec20 device failed.");
+        return -RT_ERROR;
+    } 
+
+    /* the maximum response time is 60 seconds, but it set to 10 seconds is convenient to use. */
+    resp = at_create_resp(128, 0, 10 * RT_TICK_PER_SECOND);
+    if (!resp)
+    {
+        LOG_E("no memory for ec20 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+    
+    /* clear EC20_EVENT_DOMAIN_OK */
+    ec20_socket_event_recv(device, EC20_EVENT_DOMAIN_OK, 0, RT_EVENT_FLAG_OR);
+
+    result = at_obj_exec_cmd(device->client, resp, "AT+QIDNSGIP=1,\"%s\"", name);
+    if (result < 0)
+    {
+        goto __exit;
+    }
+    
+    if (result == RT_EOK)
+    {
+        for(i = 0; i < RESOLVE_RETRY; i++)
+        {
+            /* waiting result event from AT URC, the device default connection timeout is 60 seconds.*/
+            if (ec20_socket_event_recv(device, EC20_EVENT_DOMAIN_OK, 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
+            {
+                continue;
+            }
+            else
+            {
+                struct at_device_ec20 *ec20 = (struct at_device_ec20 *) device->user_data;
+                char *recv_ip = (char *) ec20->socket_data;
+
+                if (rt_strlen(recv_ip) < 8)
+                {
+                    rt_thread_mdelay(100);
+                    /* resolve failed, maybe receive an URC CRLF */
+                    result = -RT_ERROR;
+                    continue;
+                }
+                else
+                {
+                    rt_strncpy(ip, recv_ip, 15);
+                    ip[15] = '\0';
+                    result = RT_EOK;
+                    break;
+                }
+            }
+        }
+        
+        /* response timeout */
+        if (i == RESOLVE_RETRY)
+        {
+            result = -RT_ENOMEM;
+        }
+    }
+
+ __exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+
+}
+
+/**
+ * set AT socket event notice callback
+ *
+ * @param event notice event
+ * @param cb notice callback
+ */
+static void ec20_socket_set_event_cb(at_socket_evt_t event, at_evt_cb_t cb)
+{
+    if (event < sizeof(at_evt_cb_set) / sizeof(at_evt_cb_set[1]))
+    {
+        at_evt_cb_set[event] = cb;
+    }
+}
+
+static void urc_connect_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0, result = 0;
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get ec20 device by client name(%s) failed.", client_name);
+        return;
+    }
+
+    sscanf(data, "+QIOPEN: %d,%d", &device_socket , &result);
+
+    if (result == 0)
+    {
+        ec20_socket_event_send(device, SET_EVENT(device_socket, EC20_EVENT_CONN_OK));
+    }
+    else
+    {
+        at_tcp_ip_errcode_parse(result);
+        ec20_socket_event_send(device, SET_EVENT(device_socket, EC20_EVENT_CONN_FAIL));
+    }
+}
+
+static void urc_send_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0;
+    struct at_device *device = RT_NULL;
+    struct at_device_ec20 *ec20 = RT_NULL;
+    char *client_name = client->device->parent.name;
+    
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get ec20 device by client name(%s) failed.", client_name);
+        return;
+    }
+    ec20 = (struct at_device_ec20 *) device->user_data;
+    device_socket = (int) ec20->user_data;
+
+    if (rt_strstr(data, "SEND OK"))
+    {
+        ec20_socket_event_send(device, SET_EVENT(device_socket, EC20_EVENT_SEND_OK));
+    }
+    else if (rt_strstr(data, "SEND FAIL"))
+    {
+        ec20_socket_event_send(device, SET_EVENT(device_socket, EC20_EVENT_SEND_FAIL));
+    }
+}
+
+static void urc_close_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0;
+    struct at_socket *socket = RT_NULL;
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get ec20 device by client name(%s) failed.", client_name);
+        return;
+    }
+
+    sscanf(data, "+QIURC: \"closed\",%d", &device_socket);
+    /* get at socket object by device socket descriptor */
+    socket = &(device->sockets[device_socket]);
+
+    /* notice the socket is disconnect by remote */
+    if (at_evt_cb_set[AT_SOCKET_EVT_CLOSED])
+    {
+        at_evt_cb_set[AT_SOCKET_EVT_CLOSED](socket, AT_SOCKET_EVT_CLOSED, NULL, 0);
+    }
+}
+
+static void urc_recv_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0;
+    rt_int32_t timeout;
+    rt_size_t bfsz = 0, temp_size = 0;
+    char *recv_buf = RT_NULL, temp[8] = {0};
+    struct at_socket *socket = RT_NULL;
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+    
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get ec20 device by client name(%s) failed.", client_name);
+        return;
+    }
+
+    /* get the current socket and receive buffer size by receive data */
+    sscanf(data, "+QIURC: \"recv\",%d,%d", &device_socket, (int *) &bfsz);
+    /* get receive timeout by receive buffer length */
+    timeout = bfsz;
+
+    if (device_socket < 0 || bfsz == 0)
+    {
+        return;
+    }
+
+    recv_buf = (char *) rt_calloc(1, bfsz);
+    if (recv_buf == RT_NULL)
+    {
+        LOG_E("no memory for ec20 device(%s) URC receive buffer (%d).", device->name, bfsz);
+        /* read and clean the coming data */
+        while (temp_size < bfsz)
+        {
+            if (bfsz - temp_size > sizeof(temp))
+            {
+                at_client_obj_recv(client, temp, sizeof(temp), timeout);
+            }
+            else
+            {
+                at_client_obj_recv(client, temp, bfsz - temp_size, timeout);
+            }
+            temp_size += sizeof(temp);
+        }
+        return;
+    }
+
+    /* sync receive data */
+    if (at_client_obj_recv(client, recv_buf, bfsz, timeout) != bfsz)
+    {
+        LOG_E("ec20 device(%s) receive size(%d) data failed.", device->name, bfsz);
+        rt_free(recv_buf);
+        return;
+    }
+    
+    /* get at socket object by device socket descriptor */
+    socket = &(device->sockets[device_socket]);
+
+    /* notice the receive buffer and buffer size */
+    if (at_evt_cb_set[AT_SOCKET_EVT_RECV])
+    {
+        at_evt_cb_set[AT_SOCKET_EVT_RECV](socket, AT_SOCKET_EVT_RECV, recv_buf, bfsz);
+    }
+}
+
+static void urc_pdpdeact_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int connectID = 0;
+
+    RT_ASSERT(data && size);
+
+    sscanf(data, "+QIURC: \"pdpdeact\",%d", &connectID);
+
+    LOG_E("context (%d) is deactivated.", connectID);
+}
+
+static void urc_dnsqip_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int i = 0, j = 0;
+    char recv_ip[16] = {0};
+    int result, ip_count, dns_ttl;
+    struct at_device *device = RT_NULL;
+    struct at_device_ec20 *ec20 = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get ec20 device by client name(%s) failed.", client_name);
+        return;
+    }
+    ec20 = (struct at_device_ec20 *) device->user_data;
+
+    for (i = 0; i < size; i++)
+    {
+        if (*(data + i) == '.')
+            j++;
+    }
+    /* There would be several dns result, we just pickup one */
+    if (j == 3)
+    {
+        sscanf(data, "+QIURC: \"dnsgip\",\"%[^\"]", recv_ip);
+        recv_ip[15] = '\0';
+
+        /* set ec20 information socket data */
+        if (ec20->socket_data == RT_NULL)
+        {
+            ec20->socket_data = rt_calloc(1, sizeof(recv_ip));
+            if (ec20->socket_data == RT_NULL)
+            {
+                return;
+            }
+        }
+        rt_memcpy(ec20->socket_data, recv_ip, sizeof(recv_ip));
+        
+
+        ec20_socket_event_send(device, EC20_EVENT_DOMAIN_OK);
+    }
+    else
+    {
+        sscanf(data, "+QIURC: \"dnsgip\",%d,%d,%d", &result, &ip_count, &dns_ttl);
+        if (result)
+        {
+            at_tcp_ip_errcode_parse(result);
+        }
+    }
+}
+
+static void urc_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    RT_ASSERT(data);
+
+    LOG_I("URC data : %.*s", size, data);
+}
+
+static void urc_qiurc_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    RT_ASSERT(data && size);
+
+    switch(*(data + 9))
+    {
+    case 'c' : urc_close_func(client, data, size); break;//+QIURC: "closed"
+    case 'r' : urc_recv_func(client, data, size); break;//+QIURC: "recv"
+    case 'p' : urc_pdpdeact_func(client, data, size); break;//+QIURC: "pdpdeact"
+    case 'd' : urc_dnsqip_func(client, data, size); break;//+QIURC: "dnsgip"
+    default  : urc_func(client, data, size);      break;
+    }
+}
+
+static const struct at_urc urc_table[] = 
+{
+    {"SEND OK",     "\r\n",                 urc_send_func},
+    {"SEND FAIL",   "\r\n",                 urc_send_func},
+    {"+QIOPEN:",    "\r\n",                 urc_connect_func},
+    {"+QIURC:",     "\r\n",                 urc_qiurc_func},
+};
+
+static const struct at_socket_ops ec20_socket_ops = 
+{
+    ec20_socket_connect,
+    ec20_socket_close,
+    ec20_socket_send,
+    ec20_domain_resolve,
+    ec20_socket_set_event_cb,
+};
+
+int ec20_socket_init(struct at_device *device)
+{
+    RT_ASSERT(device);
+
+    /* register URC data execution function  */
+    at_obj_set_urc_table(device->client, urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
+
+    return RT_EOK;
+}
+
+int ec20_socket_class_register(struct at_device_class *class)
+{
+    RT_ASSERT(class);
+
+    class->socket_num = AT_DEVICE_EC20_SOCKETS_NUM;
+    class->socket_ops = &ec20_socket_ops;
+
+    return RT_EOK;
+}
+
+
+#endif /* AT_DEVICE_USING_EC20 && AT_USING_SOCKET */

+ 929 - 0
class/esp8266/at_device_esp8266.c

@@ -0,0 +1,929 @@
+/*
+ * File      : at_socket_esp8266.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-06-20     chenyong     first version
+ * 2019-05-09     chenyong     multi AT socket client support
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <at_device_esp8266.h>
+
+#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10300
+#error "This AT Client version is older, please check and update latest AT Client!"
+#endif
+
+#define LOG_TAG                        "at.dev"
+
+#include <at_log.h>
+
+#ifdef AT_DEVICE_USING_ESP8266
+
+#define ESP8266_WAIT_CONNECT_TIME      5000
+#define ESP8266_THREAD_STACK_SIZE      1024
+#define ESP8266_THREAD_PRIORITY        (RT_THREAD_PRIORITY_MAX / 2)
+
+/* =============================  esp8266 network interface operations ============================= */
+
+static void esp8266_get_netdev_info(struct rt_work *work, void *work_data)
+{
+#define AT_ADDR_LEN     32
+    at_response_t resp = RT_NULL;
+    char ip[AT_ADDR_LEN] = {0}, mac[AT_ADDR_LEN] = {0};
+    char gateway[AT_ADDR_LEN] = {0}, netmask[AT_ADDR_LEN] = {0};
+    char dns_server1[AT_ADDR_LEN] = {0}, dns_server2[AT_ADDR_LEN] = {0};
+    const char *resp_expr = "%*[^\"]\"%[^\"]\"";
+    const char *resp_dns = "+CIPDNS_CUR:%s";
+    ip_addr_t ip_addr;
+    rt_uint32_t mac_addr[6] = {0};
+    rt_uint32_t num = 0; 
+    rt_uint8_t dhcp_stat = 0;
+    struct rt_delayed_work *delay_work = (struct rt_delayed_work *)work;
+    struct at_device *device = (struct at_device *)work_data;
+    struct netdev *netdev = device->netdev;
+    struct at_client *client = device->client;
+
+    if (delay_work)
+    {
+        rt_free(delay_work);
+    }
+
+    resp = at_create_resp(512, 0, rt_tick_from_millisecond(300));
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for esp8266 device(%d) response structure.", device->name);
+        return;
+    }
+    
+    /* send mac addr query commond "AT+CIFSR" and wait response */
+    if (at_obj_exec_cmd(client, resp, "AT+CIFSR") < 0)
+    {
+        goto __exit;
+    }
+
+    if (at_resp_parse_line_args_by_kw(resp, "STAMAC", resp_expr, mac) <= 0)
+    {
+        LOG_E("esp8266 device(%s) parse \"AT+CIFSR\" command response data error.", device->name);
+        goto __exit;
+    }
+
+    /* send addr info query commond "AT+CIPSTA?" and wait response */
+    if (at_obj_exec_cmd(client, resp, "AT+CIPSTA?") < 0)
+    {
+        LOG_E("esp8266 device(%s) send \"AT+CIPSTA?\" commands error.", device->name);
+        goto __exit;
+    }
+
+    if (at_resp_parse_line_args_by_kw(resp, "ip", resp_expr, ip) <= 0 ||
+            at_resp_parse_line_args_by_kw(resp, "gateway", resp_expr, gateway) <= 0 ||
+            at_resp_parse_line_args_by_kw(resp, "netmask", resp_expr, netmask) <= 0)
+    {
+        LOG_E("esp8266 device(%s) prase \"AT+CIPSTA?\" command resposne data error.", device->name);
+        goto __exit;
+    }
+
+    /* set netdev info */
+    inet_aton(ip, &ip_addr);
+    netdev_low_level_set_ipaddr(netdev, &ip_addr);
+    inet_aton(gateway, &ip_addr);
+    netdev_low_level_set_gw(netdev, &ip_addr);
+    inet_aton(netmask, &ip_addr);
+    netdev_low_level_set_netmask(netdev, &ip_addr);
+    sscanf(mac, "%x:%x:%x:%x:%x:%x", 
+            &mac_addr[0], &mac_addr[1], &mac_addr[2], &mac_addr[3], &mac_addr[4], &mac_addr[5]);
+    for (num = 0; num < netdev->hwaddr_len; num++)
+    {
+        netdev->hwaddr[num] = mac_addr[num];
+    }
+
+    /* send dns server query commond "AT+CIPDNS_CUR?" and wait response */
+    if (at_obj_exec_cmd(device->client, resp, "AT+CIPDNS_CUR?") < 0)
+    {
+        LOG_W("please check and update device(%s) firmware to support the \"AT+CIPDNS_CUR?\" command.", device->name);
+        goto __exit;
+    }
+
+    if (at_resp_parse_line_args(resp, 1, resp_dns, dns_server1) <= 0 &&
+            at_resp_parse_line_args(resp, 2, resp_dns, dns_server2) <= 0)
+    {
+        LOG_E("esp8266 device(%d) prase \"AT+CIPDNS_CUR?\" commands resposne data error.", device->name);
+        goto __exit;
+    }
+
+    if (rt_strlen(dns_server1) > 0)
+    {
+        inet_aton(dns_server1, &ip_addr);
+        netdev_low_level_set_dns_server(netdev, 0, &ip_addr);
+    }
+
+    if (rt_strlen(dns_server2) > 0)
+    {
+        inet_aton(dns_server2, &ip_addr);
+        netdev_low_level_set_dns_server(netdev, 1, &ip_addr);
+    }
+
+    /* send DHCP query commond " AT+CWDHCP_CUR?" and wait response */
+    if (at_obj_exec_cmd(client, resp, "AT+CWDHCP_CUR?") < 0)
+    {
+        goto __exit;
+    }
+
+    /* parse response data, get the DHCP status */
+    if (at_resp_parse_line_args_by_kw(resp, "+CWDHCP_CUR:", "+CWDHCP_CUR:%d", &dhcp_stat) < 0)
+    {
+        LOG_E("esp8266 device(%s) get DHCP status failed.", device->name);
+        goto __exit;
+    }
+
+    /* Bit0 - SoftAP DHCP status, Bit1 - Station DHCP status */
+    netdev_low_level_set_dhcp_status(netdev, dhcp_stat & 0x02 ? RT_TRUE : RT_FALSE);
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+}
+
+static int esp8266_net_init(struct at_device *device);
+
+static int esp8266_netdev_set_up(struct netdev *netdev)
+{
+    struct at_device *device = RT_NULL;
+    
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get esp8266 device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+    
+    if (device->is_init == RT_FALSE)
+    {
+        esp8266_net_init(device);
+        netdev_low_level_set_status(netdev, RT_TRUE);
+        LOG_D("the network interface device(%s) set up status", netdev->name);
+    }
+
+    return RT_EOK;
+}
+
+static int esp8266_netdev_set_down(struct netdev *netdev)
+{
+    struct at_device *device = RT_NULL;
+    
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get esp8266 device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+    
+    if (device->is_init == RT_TRUE)
+    {
+        device->is_init = RT_FALSE;
+        netdev_low_level_set_status(netdev, RT_FALSE);
+        LOG_D("the network interface device(%s) set down status", netdev->name);        
+    }
+
+    return RT_EOK;
+}
+
+static int esp8266_netdev_set_addr_info(struct netdev *netdev, ip_addr_t *ip_addr, ip_addr_t *netmask, ip_addr_t *gw)
+{
+#define IPADDR_RESP_SIZE       128
+#define IPADDR_SIZE            16
+
+    int result = RT_EOK;
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+    char esp8266_ip_addr[IPADDR_SIZE] = {0};
+    char esp8266_gw_addr[IPADDR_SIZE] = {0};
+    char esp8266_netmask_addr[IPADDR_SIZE] = {0};
+
+    RT_ASSERT(netdev);
+    RT_ASSERT(ip_addr || netmask || gw);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get esp8266 device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+
+    resp = at_create_resp(IPADDR_RESP_SIZE, 0, rt_tick_from_millisecond(300));
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for esp8266 device(%s) response structure.", device->name);
+        result = -RT_ENOMEM;
+        goto __exit;
+    }
+
+    /* Convert numeric IP address into decimal dotted ASCII representation. */
+    if (ip_addr)
+        rt_memcpy(esp8266_ip_addr, inet_ntoa(*ip_addr), IPADDR_SIZE);
+    else
+        rt_memcpy(esp8266_ip_addr, inet_ntoa(netdev->ip_addr), IPADDR_SIZE);
+
+    if (gw)
+        rt_memcpy(esp8266_gw_addr, inet_ntoa(*gw), IPADDR_SIZE);
+    else
+        rt_memcpy(esp8266_gw_addr, inet_ntoa(netdev->gw), IPADDR_SIZE);
+
+    if (netmask)
+        rt_memcpy(esp8266_netmask_addr, inet_ntoa(*netmask), IPADDR_SIZE);
+    else
+        rt_memcpy(esp8266_netmask_addr, inet_ntoa(netdev->netmask), IPADDR_SIZE);
+
+    /* send addr info set commond "AT+CIPSTA_CUR=<ip>[,<gateway>,<netmask>]" and wait response */
+    if (at_obj_exec_cmd(device->client, resp, "AT+CIPSTA_CUR=\"%s\",\"%s\",\"%s\"", 
+            esp8266_ip_addr, esp8266_gw_addr, esp8266_netmask_addr) < 0)
+    {
+        LOG_E("esp8266 device(%s) set address information failed.", device->name);
+        result = -RT_ERROR;
+    }
+    else
+    {
+        /* Update netdev information */
+        if (ip_addr)
+            netdev_low_level_set_ipaddr(netdev, ip_addr);
+
+        if (gw)
+            netdev_low_level_set_gw(netdev, gw);
+
+        if (netmask)
+            netdev_low_level_set_netmask(netdev, netmask);
+
+        LOG_D("esp8266 device(%s) set address information successfully.", device->name);
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+static int esp8266_netdev_set_dns_server(struct netdev *netdev, uint8_t dns_num, ip_addr_t *dns_server)
+{
+#define DNS_RESP_SIZE           128
+
+    int result = RT_EOK;
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    RT_ASSERT(netdev);
+    RT_ASSERT(dns_server);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get esp8266 device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+
+    resp = at_create_resp(DNS_RESP_SIZE, 0, rt_tick_from_millisecond(300));
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for esp8266 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    /* send dns server set commond "AT+CIPDNS_CUR=<enable>[,<DNS	server0>,<DNS	server1>]" and wait response */
+    if (at_obj_exec_cmd(device->client, resp, "AT+CIPDNS_CUR=1,\"%s\"", inet_ntoa(*dns_server)) < 0)
+    {
+        LOG_E("esp8266 device(%s) set DNS server(%s) failed.", device->name, inet_ntoa(*dns_server));
+        result = -RT_ERROR;
+    }
+    else
+    {
+        netdev_low_level_set_dns_server(netdev, dns_num, dns_server);
+        LOG_D("esp8266 device(%s) set DNS server(%s) successfully.", device->name, inet_ntoa(*dns_server));
+    }
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+static int esp8266_netdev_set_dhcp(struct netdev *netdev, rt_bool_t is_enabled)
+{
+#define ESP8266_STATION     1
+#define RESP_SIZE           128
+
+    int result = RT_EOK;
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    RT_ASSERT(netdev);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get AT device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+
+    resp = at_create_resp(RESP_SIZE, 0, rt_tick_from_millisecond(300));
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for esp8266 device(%s) response structure.",device->name);
+        return -RT_ENOMEM;
+    }
+
+    /* send dhcp set commond "AT+CWDHCP_CUR=<mode>,<en>" and wait response */
+    if (at_obj_exec_cmd(device->client, resp, "AT+CWDHCP_CUR=%d,%d", ESP8266_STATION, is_enabled) < 0)
+    {
+        LOG_E("esp8266 device(%s) set DHCP status(%d) failed.", device->name, is_enabled);
+        result = -RT_ERROR;
+        goto __exit;
+    }
+    else
+    {
+        netdev_low_level_set_dhcp_status(netdev, is_enabled);
+        LOG_D("esp8266 device(%d) set DHCP status(%d) successfully.", device->name, is_enabled);
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+#ifdef NETDEV_USING_PING
+static int esp8266_netdev_ping(struct netdev *netdev, const char *host, 
+                size_t data_len, uint32_t timeout, struct netdev_ping_resp *ping_resp)
+{
+#define ESP8266_PING_IP_SIZE         16
+
+    rt_err_t result = RT_EOK;
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+    char ip_addr[ESP8266_PING_IP_SIZE] = {0};
+    int req_time;
+
+    RT_ASSERT(netdev);
+    RT_ASSERT(host);
+    RT_ASSERT(ping_resp);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get esp8266 device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+
+    resp = at_create_resp(64, 0, timeout);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for esp8266 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    /* send domain commond "AT+CIPDOMAIN=<domain name>" and wait response */
+    if (at_obj_exec_cmd(device->client, resp, "AT+CIPDOMAIN=\"%s\"", host) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    /* parse the third line of response data, get the IP address */
+    if (at_resp_parse_line_args_by_kw(resp, "+CIPDOMAIN:", "+CIPDOMAIN:%s", ip_addr) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    /* send ping commond "AT+PING=<IP>" and wait response */
+    if (at_obj_exec_cmd(device->client, resp, "AT+PING=\"%s\"", host) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    if (at_resp_parse_line_args_by_kw(resp, "+", "+%d", &req_time) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    if (req_time)
+    {
+        inet_aton(ip_addr, &(ping_resp->ip_addr));
+        ping_resp->data_len = data_len;
+        ping_resp->ttl = 0;
+        ping_resp->ticks = req_time;
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+#endif /* NETDEV_USING_PING */
+
+#ifdef NETDEV_USING_NETSTAT
+void esp8266_netdev_netstat(struct netdev *netdev)
+{
+#define ESP8266_NETSTAT_RESP_SIZE         320
+#define ESP8266_NETSTAT_TYPE_SIZE         4
+#define ESP8266_NETSTAT_IPADDR_SIZE       17
+#define ESP8266_NETSTAT_EXPRESSION        "+CIPSTATUS:%*d,\"%[^\"]\",\"%[^\"]\",%d,%d,%*d"
+
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+    int remote_port, local_port, i;
+    char *type = RT_NULL;
+    char *ipaddr = RT_NULL;
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get esp8266 device by netdev name(%s) failed.", netdev->name);
+        return;
+    }
+
+    type = (char *) rt_calloc(1, ESP8266_NETSTAT_TYPE_SIZE);
+    ipaddr = (char *) rt_calloc(1, ESP8266_NETSTAT_IPADDR_SIZE);
+    if ((type && ipaddr) == RT_NULL)
+    {
+        LOG_E("no memory for esp8266 device(%s) response structure.", device->name);
+        goto __exit;
+    }
+
+    resp = at_create_resp(ESP8266_NETSTAT_RESP_SIZE, 0, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for esp8266 device(%s) response structure.", device->name);
+        goto __exit;
+    }
+
+    /* send network connection information commond "AT+CIPSTATUS" and wait response */
+    if (at_obj_exec_cmd(device->client, resp, "AT+CIPSTATUS") < 0)
+    {
+        goto __exit;
+    }
+
+    for (i = 1; i <= resp->line_counts; i++)
+    {
+        if (strstr(at_resp_get_line(resp, i), "+CIPSTATUS"))
+        {
+            /* parse the third line of response data, get the network connection information */
+            if (at_resp_parse_line_args(resp, i, ESP8266_NETSTAT_EXPRESSION, type, ipaddr, &remote_port, &local_port) < 0)
+            {
+                goto __exit;
+            }
+            else
+            {
+                LOG_RAW("%s: %s:%d ==> %s:%d\n", type, inet_ntoa(netdev->ip_addr), local_port, ipaddr, remote_port);
+            }
+        }
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    if (type)
+    {
+        rt_free(type);
+    }
+
+    if (ipaddr)
+    {
+        rt_free(ipaddr);
+    }
+}
+#endif /* NETDEV_USING_NETSTAT */
+
+static const struct netdev_ops esp8266_netdev_ops =
+{
+    esp8266_netdev_set_up,
+    esp8266_netdev_set_down,
+
+    esp8266_netdev_set_addr_info,
+    esp8266_netdev_set_dns_server,
+    esp8266_netdev_set_dhcp,
+
+#ifdef NETDEV_USING_PING
+    esp8266_netdev_ping,
+#endif
+#ifdef NETDEV_USING_NETSTAT
+    esp8266_netdev_netstat,
+#endif
+};
+
+static struct netdev *esp8266_netdev_add(const char *netdev_name)
+{
+#define ETHERNET_MTU        1500
+#define HWADDR_LEN          6
+    struct netdev *netdev = RT_NULL;
+
+    RT_ASSERT(netdev_name);
+
+    netdev = (struct netdev *) rt_calloc(1, sizeof(struct netdev));
+    if (netdev == RT_NULL)
+    {
+        LOG_E("no memory for esp8266 device(%s) netdev structure.", netdev_name);
+        return RT_NULL;
+    }
+
+    netdev->mtu = ETHERNET_MTU;
+    netdev->ops = &esp8266_netdev_ops;
+    netdev->hwaddr_len = HWADDR_LEN;
+
+#ifdef SAL_USING_AT
+    extern int sal_at_netdev_set_pf_info(struct netdev *netdev);
+    /* set the network interface socket/netdb operations */
+    sal_at_netdev_set_pf_info(netdev);
+#endif
+
+    netdev_register(netdev, netdev_name, RT_NULL);
+
+    return netdev;
+}
+
+/* =============================  esp8266 device operations ============================= */
+
+#define AT_SEND_CMD(client, resp, cmd)                                     \
+    do {                                                                   \
+        (resp) = at_resp_set_info((resp), 256, 0, 5 * RT_TICK_PER_SECOND); \
+        if (at_obj_exec_cmd((client), (resp), (cmd)) < 0)                  \
+        {                                                                  \
+            result = -RT_ERROR;                                            \
+            goto __exit;                                                   \
+        }                                                                  \
+    } while(0)                                                             \
+
+static void esp8266_netdev_start_delay_work(struct at_device *device)
+{
+    struct rt_delayed_work *net_work = RT_NULL;
+    net_work = (struct rt_delayed_work *)rt_calloc(1, sizeof(struct rt_delayed_work));
+    if (net_work == RT_NULL)
+    {
+        return;
+    }
+
+    rt_delayed_work_init(net_work, esp8266_get_netdev_info, (void *)device);
+    rt_work_submit(&(net_work->work), RT_TICK_PER_SECOND);
+}
+
+static void esp8266_init_thread_entry(void *parameter)
+{
+#define INIT_RETRY    5
+
+    struct at_device *device = (struct at_device *) parameter;
+    struct at_device_esp8266 *esp8266 = (struct at_device_esp8266 *) device->user_data;
+    struct at_client *client = device->client;
+    at_response_t resp = RT_NULL;
+    rt_err_t result = RT_EOK;
+    rt_size_t i = 0, retry_num = INIT_RETRY;
+
+    LOG_D("esp8266 device(%s) initialize start.", device->name);
+    
+    /* wait esp8266 device startup finish */
+    if (at_client_obj_wait_connect(client, ESP8266_WAIT_CONNECT_TIME))
+    {
+        return;
+    }
+
+    resp = at_create_resp(128, 0, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for esp8266 device(%d) response structure.", device->name);
+        return;
+    }
+    
+    while (retry_num--)
+    {
+        /* reset module */
+        AT_SEND_CMD(client, resp, "AT+RST");
+        /* reset waiting delay */
+        rt_thread_mdelay(1000);
+        /* disable echo */
+        AT_SEND_CMD(client, resp, "ATE0");
+        /* set current mode to Wi-Fi station */
+        AT_SEND_CMD(client, resp, "AT+CWMODE=1");
+        /* get module version */
+        AT_SEND_CMD(client, resp, "AT+GMR");
+        /* show module version */
+        for (i = 0; i < resp->line_counts - 1; i++)
+        {
+            LOG_D("%s", at_resp_get_line(resp, i + 1));
+        }
+
+        AT_SEND_CMD(client, resp, "AT+CIPMUX=1");
+
+        /* connect to WiFi AP */
+        if (at_obj_exec_cmd(client, at_resp_set_info(resp, 128, 0, 20 * RT_TICK_PER_SECOND), 
+                    "AT+CWJAP=\"%s\",\"%s\"", esp8266->wifi_ssid, esp8266->wifi_password) != RT_EOK)
+        {
+            LOG_E("AT device(%s) network initialize failed, check ssid(%s) and password(%s).", 
+                    device->name, esp8266->wifi_ssid, esp8266->wifi_password);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+    __exit:
+        if (result == RT_EOK)
+        {
+            break;
+        }
+        else
+        {            
+            rt_thread_mdelay(1000);
+            LOG_I("esp8266 device(%s) initialize retry...", device->name);
+        }
+    }
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    if (result != RT_EOK)
+    {
+        netdev_low_level_set_status(device->netdev, RT_FALSE);
+        LOG_E("esp8266 device(%s) network initialize failed(%d).", device->name, result);
+    }
+    else
+    {
+        device->is_init = RT_TRUE;
+        netdev_low_level_set_status(device->netdev, RT_TRUE);
+        netdev_low_level_set_link_status(device->netdev, RT_TRUE);
+        esp8266_netdev_start_delay_work(device);
+        LOG_I("esp8266 device(%s) network initialize successfully.", device->name);
+    }
+}
+
+static int esp8266_net_init(struct at_device *device)
+{
+#ifdef AT_DEVICE_ESP8266_INIT_ASYN
+    rt_thread_t tid;
+
+    tid = rt_thread_create("esp8266_net_init", esp8266_init_thread_entry, (void *) device,
+            ESP8266_THREAD_STACK_SIZE, ESP8266_THREAD_PRIORITY, 20);
+    if (tid)
+    {
+        rt_thread_startup(tid);
+    }
+    else
+    {
+        LOG_E("create esp8266 device(%s) initialize thread failed.", device->name);
+        return -RT_ERROR;
+    }
+#else
+    esp8266_init_thread_entry(device);
+#endif /* AT_DEVICE_ESP8266_INIT_ASYN */
+
+    return RT_EOK;
+}
+
+static void urc_busy_p_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    LOG_D("system is processing a commands and it cannot respond to the current commands.");
+}
+
+static void urc_busy_s_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    LOG_D("system is sending data and it cannot respond to the current commands.");
+}
+
+static void urc_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(client && data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get esp8266 device by client name(%s) failed.", client_name);
+        return;
+    }
+
+    if (rt_strstr(data, "WIFI CONNECTED"))
+    {
+        LOG_I("esp8266 device(%s) WIFI is connected.", device->name);
+
+        if (device->is_init)
+        {
+            netdev_low_level_set_link_status(device->netdev, RT_TRUE);
+            
+            esp8266_netdev_start_delay_work(device);
+        }
+    }
+    else if (rt_strstr(data, "WIFI DISCONNECT"))
+    {
+        LOG_I("esp8266 device(%s) WIFI is disconnect.", device->name);
+
+        if (device->is_init)
+        {
+            netdev_low_level_set_link_status(device->netdev, RT_FALSE);
+        }
+    }
+}
+
+static const struct at_urc urc_table[] = 
+{
+    {"busy p",           "\r\n",           urc_busy_p_func},
+    {"busy s",           "\r\n",           urc_busy_s_func},
+    {"WIFI CONNECTED",   "\r\n",           urc_func},
+    {"WIFI DISCONNECT",  "\r\n",           urc_func},
+};
+
+static int esp8266_init(struct at_device *device)
+{
+    struct at_device_esp8266 *esp8266 = (struct at_device_esp8266 *) device->user_data;
+    
+    /* initialize AT client */
+    at_client_init(esp8266->client_name, esp8266->recv_line_num);
+
+    device->client = at_client_get(esp8266->client_name);
+    if (device->client == RT_NULL)
+    {
+        LOG_E("esp8266 device(%s) initialize failed, get AT client(%s) failed.", 
+                esp8266->device_name, esp8266->client_name);
+        return -RT_ERROR;
+    }
+
+    /* register URC data execution function  */
+    at_obj_set_urc_table(device->client, urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
+
+#ifdef AT_USING_SOCKET
+    esp8266_socket_init(device);
+#endif
+
+    /* add esp8266 device to the netdev list */
+    device->netdev = esp8266_netdev_add(esp8266->device_name);
+    if (device->netdev == RT_NULL)
+    {
+        LOG_E("esp8266 device(%s) initialize failed, get network interface device failed.", esp8266->device_name);
+        return -RT_ERROR;
+    }
+
+    /* initialize esp8266 device network */
+    return esp8266_netdev_set_up(device->netdev);
+}
+
+static int esp8266_deinit(struct at_device *device)
+{
+    return esp8266_netdev_set_down(device->netdev);
+}
+
+/* reset eap8266 device and initialize device network again */
+static int esp8266_reset(struct at_device *device)
+{
+    int result = RT_EOK;
+    struct at_client *client = device->client;
+
+    /* send "AT+RST" commonds to esp8266 device */
+    result = at_obj_exec_cmd(client, RT_NULL, "AT+RST");
+    rt_thread_mdelay(1000);
+
+    /* waiting 10 seconds for esp8266 device reset */
+    device->is_init = RT_FALSE;
+    if (at_client_obj_wait_connect(client, ESP8266_WAIT_CONNECT_TIME))
+    {
+        return -RT_ETIMEOUT;
+    }
+
+    /* initialize esp8266 device network */
+    esp8266_net_init(device);
+    
+    device->is_init = RT_TRUE;
+
+    return result;
+}
+
+/* change eap8266 wifi ssid and password information */
+static int esp8266_wifi_info_set(struct at_device *device, struct at_device_ssid_pwd *info)
+{
+    int result = RT_EOK;
+    struct at_response *resp = RT_NULL;
+
+    if (info->ssid == RT_NULL || info->password == RT_NULL)
+    {
+        LOG_E("input esp8266 wifi ssid(%s) and password(%s) error.", info->ssid, info->password);
+         return -RT_ERROR;
+    }
+
+    resp = at_create_resp(128, 0, 20 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for esp8266 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+    
+    /* connect to input wifi ap */
+    if (at_obj_exec_cmd(device->client, resp, "AT+CWJAP=\"%s\",\"%s\"", info->ssid, info->password) != RT_EOK)
+    {
+        LOG_E("esp8266 device(%s) wifi connect failed, check ssid(%s) and password(%s).",  
+                device->name, info->ssid, info->password);
+        result = -RT_ERROR;
+    }
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+static int esp8266_control(struct at_device *device, int cmd, void *arg)
+{
+    int result = -RT_ERROR;
+
+    RT_ASSERT(device);
+
+    switch (cmd)
+    {
+    case AT_DEVICE_CTRL_POWER_ON:
+    case AT_DEVICE_CTRL_POWER_OFF:
+    case AT_DEVICE_CTRL_LOW_POWER:
+    case AT_DEVICE_CTRL_SLEEP:
+    case AT_DEVICE_CTRL_WAKEUP:
+    case AT_DEVICE_CTRL_NET_CONN:
+    case AT_DEVICE_CTRL_NET_DISCONN:
+    case AT_DEVICE_CTRL_GET_SIGNAL:
+    case AT_DEVICE_CTRL_GET_GPS:
+    case AT_DEVICE_CTRL_GET_VER:
+        LOG_W("esp8266 not support the control command(%d).", cmd);
+        break;
+    case AT_DEVICE_CTRL_RESET:
+        result = esp8266_reset(device);
+        break;
+    case AT_DEVICE_CTRL_SET_WIFI_INFO:
+        result = esp8266_wifi_info_set(device, (struct at_device_ssid_pwd *) arg);
+        break;
+    default:
+        LOG_E("input error control command(%d).", cmd);
+        break;
+    }
+
+    return result;
+}
+
+static const struct at_device_ops esp8266_device_ops = 
+{
+    esp8266_init,
+    esp8266_deinit,
+    esp8266_control,
+};
+
+static int esp8266_device_class_register(void)
+{
+    struct at_device_class *class = RT_NULL;
+
+    class = (struct at_device_class *) rt_calloc(1, sizeof(struct at_device_class));
+    if (class == RT_NULL)
+    {
+        LOG_E("no memory for esp8266 device class create.");
+        return -RT_ENOMEM;
+    }
+
+    /* fill ESP8266 device class object */
+#ifdef AT_USING_SOCKET
+    esp8266_socket_class_register(class);
+#endif
+    class->device_ops = &esp8266_device_ops;
+
+    return at_device_class_register(class, AT_DEVICE_CLASS_ESP8266);
+}
+INIT_DEVICE_EXPORT(esp8266_device_class_register);
+
+#endif /* AT_DEVICE_USING_ESP8266 */

+ 66 - 0
class/esp8266/at_device_esp8266.h

@@ -0,0 +1,66 @@
+/*
+ * File      : at_device_esp8266.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-05-16     chenyong     first version
+ */
+
+#ifndef __AT_DEVICE_ESP8266_H__
+#define __AT_DEVICE_ESP8266_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+
+#include <at_device.h>
+
+/* The maximum number of sockets supported by the esp8266 device */
+#define AT_DEVICE_ESP8266_SOCKETS_NUM  5
+
+struct at_device_esp8266
+{     
+    char *device_name;
+    char *client_name;
+
+    char *wifi_ssid;
+    char *wifi_password;
+    size_t recv_line_num;
+    struct at_device device;
+
+    void *user_data;
+};
+
+#ifdef AT_USING_SOCKET
+
+/* esp8266 device socket initialize */
+int esp8266_socket_init(struct at_device *device);
+
+/* esp8266 device class socket register */
+int esp8266_socket_class_register(struct at_device_class *class);
+
+#endif /* AT_USING_SOCKET */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AT_DEVICE_ESP8266_H__ */

+ 559 - 0
class/esp8266/at_socket_esp8266.c

@@ -0,0 +1,559 @@
+/*
+ * File      : at_socket_esp8266.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-06-20     chenyong     first version
+ * 2019-05-09     chenyong     multi AT socket client support
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <at_device_esp8266.h>
+
+#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10300
+#error "This AT Client version is older, please check and update latest AT Client!"
+#endif
+
+#define LOG_TAG                       "at.skt"
+#include <at_log.h>
+
+#if defined(AT_DEVICE_USING_ESP8266) && defined(AT_USING_SOCKET)
+
+#define ESP8266_MODULE_SEND_MAX_SIZE   2048
+/* set real event by current socket and current state */
+#define SET_EVENT(socket, event)       (((socket + 1) << 16) | (event))
+
+/* AT socket event type */
+#define ESP8266_EVENT_CONN_OK          (1L << 0)
+#define ESP8266_EVENT_SEND_OK          (1L << 1)
+#define ESP8266_EVENT_RECV_OK          (1L << 2)
+#define ESP8266_EVNET_CLOSE_OK         (1L << 3)
+#define ESP8266_EVENT_CONN_FAIL        (1L << 4)
+#define ESP8266_EVENT_SEND_FAIL        (1L << 5)
+
+static at_evt_cb_t at_evt_cb_set[] = {
+        [AT_SOCKET_EVT_RECV] = NULL,
+        [AT_SOCKET_EVT_CLOSED] = NULL,
+};
+
+static int esp8266_socket_event_send(struct at_device *device, uint32_t event)
+{
+    return (int) rt_event_send(device->socket_event, event);
+}
+
+static int esp8266_socket_event_recv(struct at_device *device, uint32_t event, uint32_t timeout, rt_uint8_t option)
+{
+    int result = 0;
+    rt_uint32_t recved;
+
+    result = rt_event_recv(device->socket_event, event, option | RT_EVENT_FLAG_CLEAR, timeout, &recved);
+    if (result != RT_EOK)
+    {
+        return -RT_ETIMEOUT;
+    }
+
+    return recved;
+}
+
+/**
+ * close socket by AT commands.
+ *
+ * @param current socket
+ *
+ * @return  0: close socket success
+ *         -1: send AT commands error
+ *         -2: wait socket event timeout
+ *         -5: no memory
+ */
+static int esp8266_socket_close(struct at_socket *socket)
+{
+    int result = RT_EOK;
+    at_response_t resp = RT_NULL;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+
+    resp = at_create_resp(64, 0, rt_tick_from_millisecond(300));
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for esp8266 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    result = at_obj_exec_cmd(device->client, resp, "AT+CIPCLOSE=%d", device_socket);
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+    
+    return result;
+}
+
+/**
+ * create TCP/UDP client or server connect by AT commands.
+ *
+ * @param socket current socket
+ * @param ip server or client IP address
+ * @param port server or client port
+ * @param type connect socket type(tcp, udp)
+ * @param is_client connection is client
+ *
+ * @return   0: connect success
+ *          -1: connect failed, send commands error or type error
+ *          -2: wait socket event timeout
+ *          -5: no memory
+ */
+static int esp8266_socket_connect(struct at_socket *socket, char *ip, int32_t port, enum at_socket_type type, rt_bool_t is_client)
+{
+    int result = RT_EOK;
+    rt_bool_t retryed = RT_FALSE;
+    at_response_t resp = RT_NULL;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+
+    RT_ASSERT(ip);
+    RT_ASSERT(port >= 0);
+
+    resp = at_create_resp(128, 0, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for esp8266 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+__retry:
+    if (is_client)
+    {
+        switch (type)
+        {
+        case AT_SOCKET_TCP:
+            /* send AT commands to connect TCP server */
+            if (at_obj_exec_cmd(device->client, resp, 
+                    "AT+CIPSTART=%d,\"TCP\",\"%s\",%d,60", device_socket, ip, port) < 0)
+            {
+                result = -RT_ERROR;
+            }
+            break;
+
+        case AT_SOCKET_UDP:
+            if (at_obj_exec_cmd(device->client, resp, 
+                    "AT+CIPSTART=%d,\"UDP\",\"%s\",%d", device_socket, ip, port) < 0)
+            {
+                result = -RT_ERROR;
+            }
+            break;
+
+        default:
+            LOG_E("esp8266 device(%s) not supported connect type %d.", device->name, type);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+    }
+
+    if (result != RT_EOK && retryed == RT_FALSE)
+    {
+        LOG_D("esp8266 device(%s) socket (%d) connect failed, maybe the socket was not be closed at the last time and now will retry.", 
+                device->name, device_socket);
+        if (esp8266_socket_close(socket) < 0)
+        {
+            goto __exit;
+        }
+        retryed = RT_TRUE;
+        result = RT_EOK;
+        goto __retry;
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+/**
+ * send data to server or client by AT commands.
+ *
+ * @param socket current socket
+ * @param buff send buffer
+ * @param bfsz send buffer size
+ * @param type connect socket type(tcp, udp)
+ *
+ * @return >=0: the size of send success
+ *          -1: send AT commands error or send data error
+ *          -2: waited socket event timeout
+ *          -5: no memory
+ */
+static int esp8266_socket_send(struct at_socket *socket, const char *buff, size_t bfsz, enum at_socket_type type)
+{
+    int result = RT_EOK;
+    int event_result = 0;
+    size_t cur_pkt_size = 0, sent_size = 0;
+    at_response_t resp = RT_NULL;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+    struct at_device_esp8266 *esp8266 = (struct at_device_esp8266 *) device->user_data;
+    rt_mutex_t lock = device->client->lock;
+
+    RT_ASSERT(buff);
+    RT_ASSERT(bfsz > 0);
+
+    resp = at_create_resp(128, 2, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for esp8266 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    rt_mutex_take(lock, RT_WAITING_FOREVER);
+
+    /* set current socket for send URC event */
+    esp8266->user_data = (void *) device_socket;
+
+    /* set AT client end sign to deal with '>' sign */
+    at_obj_set_end_sign(device->client, '>');
+
+    while (sent_size < bfsz)
+    {
+        if (bfsz - sent_size < ESP8266_MODULE_SEND_MAX_SIZE)
+        {
+            cur_pkt_size = bfsz - sent_size;
+        }
+        else
+        {
+            cur_pkt_size = ESP8266_MODULE_SEND_MAX_SIZE;
+        }
+
+        /* send the "AT+CIPSEND" commands to AT server than receive the '>' response on the first line */
+        if (at_obj_exec_cmd(device->client, resp, "AT+CIPSEND=%d,%d", device_socket, cur_pkt_size) < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* send the real data to server or client */
+        result = (int) at_client_obj_send(device->client, buff + sent_size, cur_pkt_size);
+        if (result == 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* waiting result event from AT URC */
+        if (esp8266_socket_event_recv(device, SET_EVENT(device_socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
+        {
+            LOG_E("esp8266 device(%s) socket(%d) send failed, wait connect result timeout.", device->name, device_socket);
+            result = -RT_ETIMEOUT;
+            goto __exit;
+        }
+        /* waiting OK or failed result */
+        event_result = esp8266_socket_event_recv(device, ESP8266_EVENT_SEND_OK | ESP8266_EVENT_SEND_FAIL, 
+                            5 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR);
+        if (event_result  < 0)
+        {
+            LOG_E("esp8266 device(%s) socket(%d) send failed, wait connect OK|FAIL timeout.", device->name, device_socket);
+            result = -RT_ETIMEOUT;
+            goto __exit;
+        }
+        /* check result */
+        if (event_result & ESP8266_EVENT_SEND_FAIL)
+        {
+            LOG_E("esp8266 device(%s) socket(%d) send failed.", device->name, device_socket);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        sent_size += cur_pkt_size;
+    }
+
+__exit:
+    /* reset the end sign for data */
+    at_obj_set_end_sign(device->client, 0);
+
+    rt_mutex_release(lock);
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+/**
+ * domain resolve by AT commands.
+ *
+ * @param name domain name
+ * @param ip parsed IP address, it's length must be 16
+ *
+ * @return  0: domain resolve success
+ *         -2: wait socket event timeout
+ *         -5: no memory
+ */
+static int esp8266_domain_resolve(const char *name, char ip[16])
+{
+#define RESOLVE_RETRY        5
+
+    int i, result = RT_EOK;
+    char recv_ip[16] = { 0 };
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    RT_ASSERT(name);
+    RT_ASSERT(ip);
+
+    device = at_device_get_first_initialized();
+    if (device == RT_NULL)
+    {
+        LOG_E("get first initialization esp8266 device failed.");
+        return -RT_ERROR;
+    }
+
+    resp = at_create_resp(128, 0, 20 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for esp8266 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    for (i = 0; i < RESOLVE_RETRY; i++)
+    {
+        if (at_obj_exec_cmd(device->client, resp, "AT+CIPDOMAIN=\"%s\"", name) < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* parse the third line of response data, get the IP address */
+        if (at_resp_parse_line_args_by_kw(resp, "+CIPDOMAIN:", "+CIPDOMAIN:%s", recv_ip) < 0)
+        {
+            rt_thread_mdelay(100);
+            /* resolve failed, maybe receive an URC CRLF */
+            continue;
+        }
+
+        if (rt_strlen(recv_ip) < 8)
+        {
+            rt_thread_mdelay(100);
+            /* resolve failed, maybe receive an URC CRLF */
+            continue;
+        }
+        else
+        {
+            rt_strncpy(ip, recv_ip, 15);
+            ip[15] = '\0';
+            break;
+        }
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+
+}
+
+/**
+ * set AT socket event notice callback
+ *
+ * @param event notice event
+ * @param cb notice callback
+ */
+static void esp8266_socket_set_event_cb(at_socket_evt_t event, at_evt_cb_t cb)
+{
+    if (event < sizeof(at_evt_cb_set) / sizeof(at_evt_cb_set[1]))
+    {
+        at_evt_cb_set[event] = cb;
+    }
+}
+
+static const struct at_socket_ops esp8266_socket_ops =
+{
+    esp8266_socket_connect,
+    esp8266_socket_close,
+    esp8266_socket_send,
+    esp8266_domain_resolve,
+    esp8266_socket_set_event_cb,
+};
+
+static void urc_send_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0;
+    struct at_device *device = RT_NULL;
+    struct at_device_esp8266 *esp8266 = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get esp8266 device by client name(%s) failed.", client_name);
+        return;
+    }
+    esp8266 = (struct at_device_esp8266 *) device->user_data;
+    device_socket = (int) esp8266->user_data;
+
+    if (rt_strstr(data, "SEND OK"))
+    {
+        esp8266_socket_event_send(device, SET_EVENT(device_socket, ESP8266_EVENT_SEND_OK));
+    }
+    else if (rt_strstr(data, "SEND FAIL"))
+    {
+        esp8266_socket_event_send(device, SET_EVENT(device_socket, ESP8266_EVENT_SEND_FAIL));
+    }
+}
+
+static void urc_send_bfsz_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    static int cur_send_bfsz = 0;
+
+    RT_ASSERT(data && size);
+
+    sscanf(data, "Recv %d bytes", &cur_send_bfsz);
+}
+
+static void urc_close_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int index = 0;
+    struct at_socket *socket = RT_NULL;
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name; 
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get esp8266 device by client name(%s) failed.", client_name);
+        return;
+    }
+
+    sscanf(data, "%d,CLOSED", &index);
+    socket = &(device->sockets[index]);
+
+    /* notice the socket is disconnect by remote */
+    if (at_evt_cb_set[AT_SOCKET_EVT_CLOSED])
+    {
+        at_evt_cb_set[AT_SOCKET_EVT_CLOSED](socket, AT_SOCKET_EVT_CLOSED, RT_NULL, 0);
+    }
+}
+
+static void urc_recv_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0;
+    rt_int32_t timeout = 0;
+    rt_size_t bfsz = 0, temp_size = 0;
+    char *recv_buf = RT_NULL, temp[8] = {0};
+    struct at_socket *socket = RT_NULL;
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name; 
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get esp8266 device by client name(%s) failed.", client_name);
+        return;
+    }
+
+    /* get the at deveice socket and receive buffer size by receive data */
+    sscanf(data, "+IPD,%d,%d:", &device_socket, (int *) &bfsz);
+
+    /* get receive timeout by receive buffer length */
+    timeout = bfsz;
+
+    if (device_socket < 0 || bfsz == 0)
+        return;
+
+    recv_buf = (char *) rt_calloc(1, bfsz);
+    if (recv_buf == RT_NULL)
+    {
+        LOG_E("no memory for esp8266 device(%s) URC receive buffer(%d).", device->name, bfsz);
+        /* read and clean the coming data */
+        while (temp_size < bfsz)
+        {
+            if (bfsz - temp_size > sizeof(temp))
+            {
+                at_client_obj_recv(client, temp, sizeof(temp), timeout);
+            }
+            else
+            {
+                at_client_obj_recv(client, temp, bfsz - temp_size, timeout);
+            }
+            temp_size += sizeof(temp);
+        }
+        return;
+    }
+
+    /* sync receive data */
+    if (at_client_obj_recv(client, recv_buf, bfsz, timeout) != bfsz)
+    {
+        LOG_E("esp8266 device(%s) receive size(%d) data failed.", device->name, bfsz);
+        rt_free(recv_buf);
+        return;
+    }
+
+    /* get at socket object by device socket descriptor */
+    socket = &(device->sockets[device_socket]);
+
+    /* notice the receive buffer and buffer size */
+    if (at_evt_cb_set[AT_SOCKET_EVT_RECV])
+    {
+        at_evt_cb_set[AT_SOCKET_EVT_RECV](socket, AT_SOCKET_EVT_RECV, recv_buf, bfsz);
+    }
+}
+
+static const struct at_urc urc_table[] = 
+{
+    {"SEND OK",          "\r\n",           urc_send_func},
+    {"SEND FAIL",        "\r\n",           urc_send_func},
+    {"Recv",             "bytes\r\n",      urc_send_bfsz_func},
+    {"",                 ",CLOSED\r\n",    urc_close_func},
+    {"+IPD",             ":",              urc_recv_func},
+};
+
+int esp8266_socket_init(struct at_device *device)
+{
+    RT_ASSERT(device);
+
+    /* register URC data execution function  */
+    at_obj_set_urc_table(device->client, urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
+
+    return RT_EOK;
+}
+
+int esp8266_socket_class_register(struct at_device_class *class)
+{
+    RT_ASSERT(class);
+
+    class->socket_num = AT_DEVICE_ESP8266_SOCKETS_NUM;
+    class->socket_ops = &esp8266_socket_ops;
+
+    return RT_EOK;
+}
+
+#endif /* AT_DEVICE_USING_ESP8266 && AT_USING_SOCKET */

+ 881 - 0
class/m26/at_device_m26.c

@@ -0,0 +1,881 @@
+/*
+ * File      : at_device_m26.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-06-12     chenyong     first version
+ * 2019-05-12     chenyong     multi AT socket client support
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <at_device_m26.h>
+
+#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10300
+#error "This AT Client version is older, please check and update latest AT Client!"
+#endif
+
+#define LOG_TAG                        "at.dev"
+#include <at_log.h>
+
+#ifdef AT_DEVICE_USING_M26
+
+#define M26_WAIT_CONNECT_TIME          5000
+#define M26_THREAD_STACK_SIZE          1024
+#define M26_THREAD_PRIORITY            (RT_THREAD_PRIORITY_MAX/2)
+
+static void m26_power_on(struct at_device *device)
+{
+    struct at_device_m26 *m26 = RT_NULL;
+
+    m26 = (struct at_device_m26 *) device->user_data;
+
+    /* not nead to set pin configuration for m26 device power on */
+    if (m26->power_pin == -1 || m26->power_status_pin == -1)
+    {
+        return;
+    }
+
+    if (rt_pin_read(m26->power_status_pin) == PIN_HIGH)
+    {
+        return;
+    }
+    rt_pin_write(m26->power_pin, PIN_HIGH);
+
+    while (rt_pin_read(m26->power_status_pin) == PIN_LOW)
+    {
+        rt_thread_mdelay(10);
+    }
+    rt_pin_write(m26->power_pin, PIN_LOW);
+}
+
+static void m26_power_off(struct at_device *device)
+{
+    struct at_device_m26 *m26 = RT_NULL;
+
+    m26 = (struct at_device_m26 *) device->user_data;
+
+    /* not nead to set pin configuration for m26 device power on */
+    if (m26->power_pin == -1 || m26->power_status_pin == -1)
+    {
+        return;
+    }
+
+    if (rt_pin_read(m26->power_status_pin) == PIN_LOW)
+    {
+        return;
+    }
+    rt_pin_write(m26->power_pin, PIN_HIGH);
+
+    while (rt_pin_read(m26->power_status_pin) == PIN_HIGH)
+    {
+        rt_thread_mdelay(10);
+    }
+    rt_pin_write(m26->power_pin, PIN_LOW);
+}
+
+/* =============================  m26 network interface operations ============================= */
+
+/* set m26 network interface device status and address information */
+static int m26_netdev_set_info(struct netdev *netdev)
+{
+#define M26_IEMI_RESP_SIZE      32
+#define M26_IPADDR_RESP_SIZE    32
+#define M26_DNS_RESP_SIZE       96
+#define M26_INFO_RESP_TIMO      rt_tick_from_millisecond(300)
+
+    int result = RT_EOK;
+    ip_addr_t addr;
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+    struct at_client *client = RT_NULL;
+
+    if (netdev == RT_NULL)
+    {
+        LOG_E("input network interface device is NULL.");
+        return -RT_ERROR;
+    }
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get m26 deivce by netdev name failed.", netdev->name);
+        return -RT_ERROR;
+    }
+    client = device->client;
+
+    /* set network interface device up status */
+    netdev_low_level_set_status(netdev, RT_TRUE);
+    netdev_low_level_set_dhcp_status(netdev, RT_TRUE);
+
+    resp = at_create_resp(M26_IEMI_RESP_SIZE, 0, M26_INFO_RESP_TIMO);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for m26 device(%s) response structure.", netdev->name);
+        result = -RT_ENOMEM;
+        goto __exit;
+    }
+
+    /* set network interface device hardware address(IEMI) */
+    {
+        #define M26_NETDEV_HWADDR_LEN   8
+        #define M26_IEMI_LEN            15
+
+        char iemi[M26_IEMI_LEN] = {0};
+        int i = 0, j = 0;
+
+        /* send "AT+GSN" commond to get device IEMI */
+        if (at_obj_exec_cmd(client, resp, "AT+GSN") < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        if (at_resp_parse_line_args(resp, 2, "%s", iemi) <= 0)
+        {
+            LOG_E("m26 device(%s) prase \"AT+GSN\" commands resposne data error.", device->name);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        LOG_D("m26 device(%s) IEMI number: %s", device->name, iemi);
+
+        netdev->hwaddr_len = M26_NETDEV_HWADDR_LEN;
+        /* get hardware address by IEMI */
+        for (i = 0, j = 0; i < M26_NETDEV_HWADDR_LEN && j < M26_IEMI_LEN; i++, j+=2)
+        {
+            if (j != M26_IEMI_LEN - 1)
+            {
+                netdev->hwaddr[i] = (iemi[j] - '0') * 10 + (iemi[j + 1] - '0');
+            }
+            else
+            {
+                netdev->hwaddr[i] = (iemi[j] - '0');
+            }
+        }
+    }
+
+    /* set network interface device IP address */
+    {
+        #define IP_ADDR_SIZE_MAX    16
+        char ipaddr[IP_ADDR_SIZE_MAX] = {0};
+        
+        at_resp_set_info(resp, M26_IPADDR_RESP_SIZE, 2, M26_INFO_RESP_TIMO);
+
+        /* send "AT+QILOCIP" commond to get IP address */
+        if (at_obj_exec_cmd(client, resp, "AT+QILOCIP") < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        if (at_resp_parse_line_args_by_kw(resp, ".", "%s", ipaddr) <= 0)
+        {
+            LOG_E("m26 device(%s) prase \"AT+QILOCIP\" commands resposne data error.", device->name);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+        
+        LOG_D("m26 device(%s) IP address: %s", device->name, ipaddr);
+
+        /* set network interface address information */
+        inet_aton(ipaddr, &addr);
+        netdev_low_level_set_ipaddr(netdev, &addr);
+    }
+
+    /* set network interface device dns server */
+    {
+        #define DNS_ADDR_SIZE_MAX   16
+        char dns_server1[DNS_ADDR_SIZE_MAX] = {0}, dns_server2[DNS_ADDR_SIZE_MAX] = {0};
+
+        at_resp_set_info(resp, M26_DNS_RESP_SIZE, 0, M26_INFO_RESP_TIMO);
+
+        /* send "AT+QIDNSCFG?" commond to get DNS servers address */
+        if (at_obj_exec_cmd(client, resp, "AT+QIDNSCFG?") < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        if (at_resp_parse_line_args_by_kw(resp, "PrimaryDns:", "PrimaryDns:%s", dns_server1) <= 0 ||
+                at_resp_parse_line_args_by_kw(resp, "SecondaryDns:", "SecondaryDns:%s", dns_server2) <= 0)
+        {
+            LOG_E("Prase \"AT+QIDNSCFG?\" commands resposne data error!");
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        LOG_D("m26 device(%s) primary DNS server address: %s", device->name, dns_server1);
+        LOG_D("m26 device(%s) secondary DNS server address: %s", device->name, dns_server2);
+
+        inet_aton(dns_server1, &addr);
+        netdev_low_level_set_dns_server(netdev, 0, &addr);
+
+        inet_aton(dns_server2, &addr);
+        netdev_low_level_set_dns_server(netdev, 1, &addr);
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+    
+    return result;
+}
+
+static void check_link_status_entry(void *parameter)
+{
+#define M26_LINK_STATUS_OK   0
+#define M26_LINK_RESP_SIZE   64
+#define M26_LINK_RESP_TIMO   (3 * RT_TICK_PER_SECOND)
+#define M26_LINK_DELAY_TIME  (30 * RT_TICK_PER_SECOND)
+
+    struct netdev *netdev = (struct netdev *)parameter;
+    struct at_device *device = RT_NULL;
+    at_response_t resp = RT_NULL;
+    int link_status;
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get m26 deivce by netdev name failed.", netdev->name);
+        return;
+    }
+
+    resp = at_create_resp(M26_LINK_RESP_SIZE, 0, M26_LINK_RESP_TIMO);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for m26 device(%s) response object.", netdev->name);
+        return;
+    }
+
+   while (1)
+    { 
+        
+        /* send "AT+QNSTATUS" commond  to check netweork interface device link status */
+        if (at_obj_exec_cmd(device->client, resp, "AT+QNSTATUS") < 0)
+        {
+            rt_thread_mdelay(M26_LINK_DELAY_TIME);
+
+           continue;
+        }
+        
+        link_status = -1;
+        at_resp_parse_line_args_by_kw(resp, "+QNSTATUS:", "+QNSTATUS: %d", &link_status);
+
+        /* check the network interface device link status  */
+        if ((M26_LINK_STATUS_OK == link_status) != netdev_is_link_up(netdev))
+        {
+            netdev_low_level_set_link_status(netdev, (M26_LINK_STATUS_OK == link_status));
+        }
+
+        rt_thread_mdelay(M26_LINK_DELAY_TIME);
+    }
+}
+
+static int m26_netdev_check_link_status(struct netdev *netdev)
+{
+#define M26_LINK_THREAD_TICK           20
+#define M26_LINK_THREAD_STACK_SIZE     512
+#define M26_LINK_THREAD_PRIORITY       (RT_THREAD_PRIORITY_MAX - 2)
+
+    rt_thread_t tid;
+    char tname[RT_NAME_MAX] = {0};
+
+    if (netdev == RT_NULL)
+    {
+        LOG_E("input network interface device is NULL.");
+        return -RT_ERROR;
+    }
+
+    rt_snprintf(tname, RT_NAME_MAX, "%s_link", netdev->name);
+
+    tid = rt_thread_create(tname, check_link_status_entry, (void *)netdev, 
+            M26_LINK_THREAD_STACK_SIZE, M26_LINK_THREAD_PRIORITY, M26_LINK_THREAD_TICK);
+    if (tid)
+    {
+        rt_thread_startup(tid);
+    }
+
+    return RT_EOK;
+}
+
+static int m26_net_init(struct at_device *device);
+
+static int m26_netdev_set_up(struct netdev *netdev)
+{
+    struct at_device *device = RT_NULL;
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get m26 device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+
+    if (device->is_init == RT_FALSE)
+    {
+        m26_net_init(device);
+        device->is_init = RT_TRUE;
+
+        netdev_low_level_set_status(netdev, RT_TRUE);
+        LOG_D("the network interface device(%s) set up status.", netdev->name);
+    }
+
+    return RT_EOK;
+}
+
+static int m26_netdev_set_down(struct netdev *netdev)
+{
+    struct at_device *device = RT_NULL;
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get m26 device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+
+    if (device->is_init == RT_TRUE)
+    {
+        m26_power_off(device);
+        device->is_init = RT_FALSE;
+
+        netdev_low_level_set_status(netdev, RT_FALSE);
+        LOG_D("the network interface device(%s) set down status.", netdev->name);
+    }
+
+    return RT_EOK;
+}
+
+static int m26_netdev_set_dns_server(struct netdev *netdev, uint8_t dns_num, ip_addr_t *dns_server)
+{
+#define M26_DNS_RESP_LEN    8
+#define M26_DNS_RESP_TIMEO   rt_tick_from_millisecond(300)
+
+    int result = RT_EOK;
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    RT_ASSERT(netdev);
+    RT_ASSERT(dns_server);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get m26 deivce by netdev name failed.", netdev->name);
+        return - RT_ERROR;
+    }
+
+    resp = at_create_resp(M26_DNS_RESP_LEN, 0, M26_DNS_RESP_TIMEO);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for m26 device(%s) response object.", netdev->name);
+        return -RT_ENOMEM;
+    }
+
+    /* send "AT+QIDNSCFG=<pri_dns>[,<sec_dns>]" commond to set dns servers */
+    if (at_exec_cmd(resp, "AT+QIDNSCFG=\"%s\"", inet_ntoa(*dns_server)) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    netdev_low_level_set_dns_server(netdev, dns_num, dns_server);
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+    return result;
+}
+
+#ifdef NETDEV_USING_PING
+static int m26_netdev_ping(struct netdev *netdev, const char *host, 
+            size_t data_len, uint32_t timeout, struct netdev_ping_resp *ping_resp)
+{
+#define M26_PING_RESP_SIZE       128
+#define M26_PING_IP_SIZE         16
+#define M26_PING_TIMEO           (5 * RT_TICK_PER_SECOND)
+
+    int result = RT_EOK;
+    at_response_t resp = RT_NULL;
+    char ip_addr[M26_PING_IP_SIZE] = {0};
+    int response, recv_data_len, time, ttl;
+    struct at_device *device = RT_NULL;
+
+    RT_ASSERT(netdev);
+    RT_ASSERT(host);
+    RT_ASSERT(ping_resp);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get m26 deivce by netdev name failed.", netdev->name);
+        return - RT_ERROR;
+    }
+
+    resp = at_create_resp(M26_PING_RESP_SIZE, 5, M26_PING_TIMEO);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for m26 device(%s) response object.", netdev->name);
+        return  -RT_ENOMEM;
+    }
+    /* send "AT+QPING="<host>"[,[<timeout>][,<pingnum>]]" commond to send ping request */
+    if (at_obj_exec_cmd(device->client, resp, "AT+QPING=\"%s\",%d,1", host, M26_PING_TIMEO / RT_TICK_PER_SECOND) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    at_resp_parse_line_args_by_kw(resp, "+QPING:","+QPING:%d", &response);
+    /* Received the ping response from the server */
+    if (response == 0)
+    {
+        if (at_resp_parse_line_args_by_kw(resp, "+QPING:", "+QPING:%d,%[^,],%d,%d,%d",
+                &response, ip_addr, &recv_data_len, &time, &ttl) <= 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }   
+    }
+
+    /* prase response number */
+    switch (response)
+    {
+    case 0:
+        inet_aton(ip_addr, &(ping_resp->ip_addr));
+        ping_resp->data_len = recv_data_len;
+        ping_resp->ticks = time;
+        ping_resp->ttl = ttl;
+        result = RT_EOK;
+        break;
+    case 1:
+        result = -RT_ETIMEOUT;
+        break;
+    default:
+        result = -RT_ERROR;
+        break;
+    }
+
+ __exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+#endif /* NETDEV_USING_PING */
+
+#ifdef NETDEV_USING_NETSTAT
+static void m26_netdev_netstat(struct netdev *netdev)
+{ 
+    // TODO netstat support
+}
+#endif /* NETDEV_USING_NETSTAT */
+
+const struct netdev_ops m26_netdev_ops =
+{
+    m26_netdev_set_up,
+    m26_netdev_set_down,
+
+    RT_NULL, /* not support set ip, netmask, gatway address */
+    m26_netdev_set_dns_server,
+    RT_NULL, /* not support set DHCP status */
+
+#ifdef NETDEV_USING_PING
+    m26_netdev_ping,
+#endif
+#ifdef NETDEV_USING_NETSTAT
+    m26_netdev_netstat,
+#endif
+};
+
+static struct netdev *m26_netdev_add(const char *netdev_name)
+{
+#define M26_NETDEV_MTU       1500
+
+    struct netdev *netdev = RT_NULL;
+
+    RT_ASSERT(netdev_name);
+
+    netdev = (struct netdev *) rt_calloc(1, sizeof(struct netdev));
+    if (netdev == RT_NULL)
+    {
+        LOG_E("no memory for m26 device(%s) netdev structure.", netdev_name);
+        return RT_NULL;
+    }
+
+    netdev->mtu = M26_NETDEV_MTU;
+    netdev->ops = &m26_netdev_ops;
+
+#ifdef SAL_USING_AT
+    extern int sal_at_netdev_set_pf_info(struct netdev *netdev);
+    /* set the network interface socket/netdb operations */
+    sal_at_netdev_set_pf_info(netdev);
+#endif
+
+    netdev_register(netdev, netdev_name, RT_NULL);
+
+    return netdev;
+}
+
+/* =============================  m26 device operations ============================= */
+
+#define AT_SEND_CMD(client, resp, resp_line, timeout, cmd)                                         \
+    do {                                                                                           \
+        (resp) = at_resp_set_info((resp), 128, (resp_line), rt_tick_from_millisecond(timeout));    \
+        if (at_obj_exec_cmd((client),(resp), (cmd)) < 0)                                           \
+        {                                                                                          \
+            result = -RT_ERROR;                                                                    \
+            goto __exit;                                                                           \
+        }                                                                                          \
+    } while(0);                                                                                    \
+
+/* init for m26 or mc20 */
+static void m26_init_thread_entry(void *parameter)
+{
+#define INIT_RETRY                     5
+#define CPIN_RETRY                     10
+#define CSQ_RETRY                      10
+#define CREG_RETRY                     10
+#define CGREG_RETRY                    20
+
+    at_response_t resp = RT_NULL;
+    int i, qimux, qimode;
+    int retry_num = INIT_RETRY;
+    char parsed_data[10];
+    rt_err_t result = RT_EOK;
+    struct at_device *device = (struct at_device *)parameter;
+    struct at_client *client = device->client;
+
+    resp = at_create_resp(128, 0, rt_tick_from_millisecond(300));
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for m26 device(%s) response structure.", device->name);
+        return;
+    }
+
+    LOG_D("start initializing the m26/mc20 device(%s)", device->name);
+
+    while (retry_num--)
+    {
+        /* power on the m26 device */
+        m26_power_on(device);
+        rt_thread_mdelay(1000);
+
+        /* wait m26|mc20 startup finish */
+        if (at_client_obj_wait_connect(client, M26_WAIT_CONNECT_TIME))
+        {
+            result = -RT_ETIMEOUT;
+            goto __exit;
+        }
+        
+        /* disable echo */
+        AT_SEND_CMD(client, resp, 0, 300, "ATE0");
+        /* get module version */
+        AT_SEND_CMD(client, resp, 0, 300, "ATI");
+        /* show module version */
+        for (i = 0; i < (int) resp->line_counts - 1; i++)
+        {
+            LOG_D("%s", at_resp_get_line(resp, i + 1));
+        }
+        /* check SIM card */
+        for (i = 0; i < CPIN_RETRY; i++)
+        {
+            AT_SEND_CMD(client, resp, 2, 5 * RT_TICK_PER_SECOND, "AT+CPIN?");
+
+            if (at_resp_get_line_by_kw(resp, "READY"))
+            {
+                LOG_D("m26 device(%s) SIM card detection success.", device->name);
+                break;
+            }
+            rt_thread_mdelay(1000);
+        }
+        if (i == CPIN_RETRY)
+        {
+            LOG_E("SIM card detection failed!");
+            result = -RT_ERROR;
+            goto __exit;
+        }
+        /* waiting for dirty data to be digested */
+        rt_thread_mdelay(10);
+        /* check signal strength */
+        for (i = 0; i < CSQ_RETRY; i++)
+        {
+            AT_SEND_CMD(client, resp, 0, 300, "AT+CSQ");
+            at_resp_parse_line_args_by_kw(resp, "+CSQ:", "+CSQ: %s", &parsed_data);
+            if (rt_strncmp(parsed_data, "99,99", sizeof(parsed_data)))
+            {
+                LOG_D("m26 device(%s) signal strength: %s", device->name, parsed_data);
+                break;
+            }
+            rt_thread_mdelay(1000);
+        }
+        if (i == CSQ_RETRY)
+        {
+            LOG_E("m26 device(%s) signal strength check failed(%s).", device->name, parsed_data);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+        /* check the GSM network is registered */
+        for (i = 0; i < CREG_RETRY; i++)
+        {
+            AT_SEND_CMD(client, resp, 0, 300, "AT+CREG?");
+            at_resp_parse_line_args_by_kw(resp, "+CREG:", "+CREG: %s", &parsed_data);
+            if (!rt_strncmp(parsed_data, "0,1", sizeof(parsed_data)) || 
+                    !rt_strncmp(parsed_data, "0,5", sizeof(parsed_data)))
+            {
+                LOG_D("m26 device(%s) GSM network is registered(%s).", device->name, parsed_data);
+                break;
+            }
+            rt_thread_mdelay(1000);
+        }
+        if (i == CREG_RETRY)
+        {
+            LOG_E("m26 device(%s) GSM network is register failed(%s)", device->name, parsed_data);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+        /* check the GPRS network is registered */
+        for (i = 0; i < CGREG_RETRY; i++)
+        {
+            AT_SEND_CMD(client, resp, 0, 300, "AT+CGREG?");
+            at_resp_parse_line_args_by_kw(resp, "+CGREG:", "+CGREG: %s", &parsed_data);
+            if (!rt_strncmp(parsed_data, "0,1", sizeof(parsed_data)) || 
+                    !rt_strncmp(parsed_data, "0,5", sizeof(parsed_data)))
+            {
+                LOG_D("m26 device(%s) GPRS network is registered(%s).", device->name, parsed_data);
+                break;
+            }
+            rt_thread_mdelay(1000);
+        }
+        if (i == CGREG_RETRY)
+        {
+            LOG_E("m26 device(%s) GPRS network is register failed(%s).", device->name, parsed_data);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        AT_SEND_CMD(client, resp, 0, 300, "AT+QIFGCNT=0");
+        AT_SEND_CMD(client, resp, 0, 300, "AT+QICSGP=1, \"CMNET\"");
+        AT_SEND_CMD(client, resp, 0, 300, "AT+QIMODE?");
+
+        at_resp_parse_line_args_by_kw(resp, "+QIMODE:", "+QIMODE: %d", &qimode);
+        if (qimode == 1)
+        {
+            AT_SEND_CMD(client, resp, 0, 300, "AT+QIMODE=0");
+        }
+
+        /* the device default response timeout is 40 seconds, but it set to 15 seconds is convenient to use. */
+        AT_SEND_CMD(client, resp, 2, 20 * 1000, "AT+QIDEACT");
+
+        /* Set to multiple connections */
+        AT_SEND_CMD(client, resp, 0, 300, "AT+QIMUX?");
+        at_resp_parse_line_args_by_kw(resp, "+QIMUX:", "+QIMUX: %d", &qimux);
+        if (qimux == 0)
+        {
+            AT_SEND_CMD(client, resp, 0, 300, "AT+QIMUX=1");
+        }
+
+        AT_SEND_CMD(client, resp, 0, 300, "AT+QIREGAPP");
+
+        /* the device default response timeout is 150 seconds, but it set to 20 seconds is convenient to use. */
+        AT_SEND_CMD(client, resp, 0, 20 * 1000, "AT+QIACT");
+
+        AT_SEND_CMD(client, resp, 2, 300, "AT+QILOCIP");
+        result = RT_EOK;
+
+    __exit:
+        if (result == RT_EOK)
+        {
+            break;
+        }
+        else
+        {
+            /* power off the m26 device */
+            m26_power_off(device);
+            rt_thread_mdelay(1000);
+
+            LOG_I("m26 device(%s) initialize retry...", device->name);
+        }    
+    }
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    if (result == RT_EOK)
+    {
+        m26_netdev_set_info(device->netdev);
+        m26_netdev_check_link_status(device->netdev);
+
+        LOG_I("m26 device(%s) network initialize successfully.", device->name);
+    }
+    else
+    {
+        LOG_E("m26 device(%s) network initialize failed(%d).", device->name, result);
+    }
+}
+
+static int m26_net_init(struct at_device *device)
+{
+#ifdef AT_DEVICE_M26_INIT_ASYN
+    rt_thread_t tid;
+
+    tid = rt_thread_create("m26_net_init", m26_init_thread_entry, (void *)device, 
+            M26_THREAD_STACK_SIZE, M26_THREAD_PRIORITY, 20);
+    if (tid)
+    {
+        rt_thread_startup(tid);
+    }
+    else
+    {
+        LOG_E("create m26 device(%s) initialization thread failed.", device->name);
+        return -RT_ERROR;
+    }
+#else
+    m26_init_thread_entry(device);
+#endif /* AT_DEVICE_M26_INIT_ASYN */
+    
+    return RT_EOK;
+}
+
+static void urc_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    RT_ASSERT(data);
+
+    LOG_I("URC data : %.*s", size, data);
+}
+
+static const struct at_urc urc_table[] = {
+        {"RING",        "\r\n",                 urc_func},
+        {"Call Ready",  "\r\n",                 urc_func},
+        {"RDY",         "\r\n",                 urc_func},
+        {"NO CARRIER",  "\r\n",                 urc_func},
+};
+
+static int m26_init(struct at_device *device)
+{
+    struct at_device_m26 *m26 = (struct at_device_m26 *) device->user_data;
+
+    /* initialize AT client */
+    at_client_init(m26->client_name, m26->recv_line_num);
+
+    device->client = at_client_get(m26->client_name);
+    if (device->client == RT_NULL)
+    {
+        LOG_E("m26 device(%s) initialize failed, get AT client(%s) failed.", m26->device_name, m26->client_name);
+        return -RT_ERROR;
+    }
+    
+    /* register URC data execution function  */
+    at_obj_set_urc_table(device->client, urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
+    
+#ifdef AT_USING_SOCKET
+    m26_socket_init(device);
+#endif
+
+    /* add m26 netdev to the netdev list */
+    device->netdev = m26_netdev_add(m26->device_name);
+    if (device->netdev == RT_NULL)
+    {
+        LOG_E("m26 device(%s) initialize failed, get network interface device failed.", m26->device_name);
+        return -RT_ERROR;
+    }
+    
+    /* initialize m26 pin configuration */
+    if (m26->power_pin != -1 && m26->power_status_pin != -1)
+    {
+        rt_pin_mode(m26->power_pin, PIN_MODE_OUTPUT);
+        rt_pin_mode(m26->power_status_pin, PIN_MODE_INPUT);
+    }
+    
+    /* initialize m26 device network */
+    return m26_netdev_set_up(device->netdev);
+}
+
+static int m26_deinit(struct at_device *device)
+{
+    return m26_netdev_set_down(device->netdev);
+}
+
+static int m26_control(struct at_device *device, int cmd, void *arg)
+{
+    int result = -RT_ERROR;
+
+    RT_ASSERT(device);
+
+    switch (cmd)
+    {
+    case AT_DEVICE_CTRL_POWER_ON:
+    case AT_DEVICE_CTRL_POWER_OFF:
+    case AT_DEVICE_CTRL_RESET:
+    case AT_DEVICE_CTRL_LOW_POWER:
+    case AT_DEVICE_CTRL_SLEEP:
+    case AT_DEVICE_CTRL_WAKEUP:
+    case AT_DEVICE_CTRL_NET_CONN:
+    case AT_DEVICE_CTRL_NET_DISCONN:
+    case AT_DEVICE_CTRL_SET_WIFI_INFO:
+    case AT_DEVICE_CTRL_GET_SIGNAL:
+    case AT_DEVICE_CTRL_GET_GPS:
+    case AT_DEVICE_CTRL_GET_VER:
+        LOG_W("m26 not support the control command(%d).", cmd);
+        break;
+    default:
+        LOG_E("input error control command(%d).", cmd);
+        break;
+    }
+
+    return result;
+}
+static const struct at_device_ops m26_device_ops = 
+{
+    m26_init,
+    m26_deinit,
+    m26_control,
+};
+
+static int m26_device_class_register(void)
+{
+    struct at_device_class *class = RT_NULL;
+
+    class = (struct at_device_class *) rt_calloc(1, sizeof(struct at_device_class));
+    if (class == RT_NULL)
+    {
+        LOG_E("no memory for m26 device class create.");
+        return -RT_ENOMEM;
+    }
+
+    /* fill m26 device class object */
+#ifdef AT_USING_SOCKET
+    m26_socket_class_register(class);
+#endif
+    class->device_ops = &m26_device_ops;
+
+    return at_device_class_register(class, AT_DEVICE_CLASS_M26_MC20);
+}
+INIT_DEVICE_EXPORT(m26_device_class_register);
+
+#endif /* AT_DEVICE_USING_M26 */

+ 66 - 0
class/m26/at_device_m26.h

@@ -0,0 +1,66 @@
+/*
+ * File      : at_device_m26.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-05-16     chenyong     first version
+ */
+
+#ifndef __AT_DEVICE_M26_H__
+#define __AT_DEVICE_M26_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+
+#include <at_device.h>
+
+/* The maximum number of sockets supported by the m26 device */
+#define AT_DEVICE_M26_SOCKETS_NUM      6
+
+struct at_device_m26
+{     
+    char *device_name;
+    char *client_name;
+
+    int power_pin;
+    int power_status_pin;
+    size_t recv_line_num;
+    struct at_device device;
+
+    void *user_data;
+};
+
+#ifdef AT_USING_SOCKET
+
+/* m26 device socket initialize */
+int m26_socket_init(struct at_device *device);
+
+/* m26 device class socket register */
+int m26_socket_class_register(struct at_device_class *class);
+
+#endif /* AT_USING_SOCKET */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AT_DEVICE_M26_H__ */

+ 702 - 0
class/m26/at_socket_m26.c

@@ -0,0 +1,702 @@
+/*
+ * File      : at_socket_m26.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-06-12     chenyong     first version
+ * 2019-05-12     chenyong     multi AT socket client support
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <at_device_m26.h>
+
+#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10300
+#error "This AT Client version is older, please check and update latest AT Client!"
+#endif
+
+#define LOG_TAG                        "at.dev"
+#include <at_log.h>
+
+#if defined(AT_DEVICE_USING_M26) && defined(AT_USING_SOCKET)
+
+#define M26_MODULE_SEND_MAX_SIZE       1460
+
+/* set real event by current socket and current state */
+#define SET_EVENT(socket, event)       (((socket + 1) << 16) | (event))
+
+/* AT socket event type */
+#define M26_EVENT_CONN_OK              (1L << 0)
+#define M26_EVENT_SEND_OK              (1L << 1)
+#define M26_EVENT_RECV_OK              (1L << 2)
+#define M26_EVNET_CLOSE_OK             (1L << 3)
+#define M26_EVENT_CONN_FAIL            (1L << 4)
+#define M26_EVENT_SEND_FAIL            (1L << 5)
+
+static at_evt_cb_t at_evt_cb_set[] = 
+{
+    [AT_SOCKET_EVT_RECV] = NULL,
+    [AT_SOCKET_EVT_CLOSED] = NULL,
+};
+
+static int m26_socket_event_send(struct at_device *device, uint32_t event)
+{
+    return (int) rt_event_send(device->socket_event, event);
+}
+
+static int m26_socket_event_recv(struct at_device *device, uint32_t event, uint32_t timeout, rt_uint8_t option)
+{
+    int result = 0;
+    rt_uint32_t recved = 0;
+
+    result = rt_event_recv(device->socket_event, event, option | RT_EVENT_FLAG_CLEAR, timeout, &recved);
+    if (result != RT_EOK)
+    {
+        return -RT_ETIMEOUT;
+    }
+
+    return recved;
+}
+
+/**
+ * close socket by AT commands.
+ *
+ * @param current socket
+ *
+ * @return  0: close socket success
+ *         -1: send AT commands error
+ *         -2: wait socket event timeout
+ *         -5: no memory
+ */
+static int m26_socket_close(struct at_socket *socket)
+{
+    int result = 0;
+    at_response_t resp = RT_NULL;
+    int device_socke = (int) socket->user_data;
+    struct at_device *device  = (struct at_device *) socket->device;
+    
+    resp = at_create_resp(64, 0, rt_tick_from_millisecond(300));
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for m26 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    /* clear socket close event */
+    m26_socket_event_recv(device, SET_EVENT(device_socke, M26_EVNET_CLOSE_OK), 0, RT_EVENT_FLAG_OR);
+
+    if (at_obj_exec_cmd(device->client, resp, "AT+QICLOSE=%d", device_socke) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    if (m26_socket_event_recv(device, SET_EVENT(device_socke, M26_EVNET_CLOSE_OK), 
+            rt_tick_from_millisecond(300 * 3), RT_EVENT_FLAG_AND) < 0)
+    {
+        LOG_E("m26 device(%s) socket(%d) close failed, wait close OK timeout.", device->name, device_socke);
+        result = -RT_ETIMEOUT;
+        goto __exit;
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+/**
+ * create TCP/UDP client or server connect by AT commands.
+ *
+ * @param socket current socket
+ * @param ip server or client IP address
+ * @param port server or client port
+ * @param type connect socket type(tcp, udp)
+ * @param is_client connection is client
+ *
+ * @return   0: connect success
+ *          -1: connect failed, send commands error or type error
+ *          -2: wait socket event timeout
+ *          -5: no memory
+ */
+static int m26_socket_connect(struct at_socket *socket, char *ip, int32_t port, enum at_socket_type type, rt_bool_t is_client)
+{
+    rt_bool_t retryed = RT_FALSE;
+    at_response_t resp = RT_NULL;
+    int result = 0, event_result = 0;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+
+    resp = at_create_resp(128, 0, rt_tick_from_millisecond(300));
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for m26 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    RT_ASSERT(ip);
+    RT_ASSERT(port >= 0);
+
+__retry:
+
+    /* clear socket connect event */
+    event_result = SET_EVENT(device_socket, M26_EVENT_CONN_OK | M26_EVENT_CONN_FAIL);
+    m26_socket_event_recv(device, event_result, 0, RT_EVENT_FLAG_OR);
+
+    if (is_client)
+    {
+        switch (type)
+        {
+        case AT_SOCKET_TCP:
+            /* send AT commands(eg: AT+QIOPEN=0,"TCP","x.x.x.x", 1234) to connect TCP server */
+            if (at_obj_exec_cmd(device->client, resp, 
+                    "AT+QIOPEN=%d,\"TCP\",\"%s\",%d", device_socket, ip, port) < 0)
+            {
+                result = -RT_ERROR;
+                goto __exit;
+            }
+            break;
+
+        case AT_SOCKET_UDP:
+            if (at_obj_exec_cmd(device->client, resp, 
+                    "AT+QIOPEN=%d,\"UDP\",\"%s\",%d", device_socket, ip, port) < 0)
+            {
+                result = -RT_ERROR;
+                goto __exit;
+            }
+            break;
+
+        default:
+            LOG_E("m26 device(%s) not supported connect type : %d.", device->name, type);
+            return -RT_ERROR;
+        }
+    }
+
+    /* waiting result event from AT URC, the device default connection timeout is 75 seconds, but it set to 10 seconds is convenient to use.*/
+    if (m26_socket_event_recv(device, SET_EVENT(device_socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
+    {
+        LOG_E("m26 device(%s) socket(%d) connect failed, wait connect result timeout.", device->name, device_socket);
+        result = -RT_ETIMEOUT;
+        goto __exit;
+    }
+    /* waiting OK or failed result */
+    if ((event_result = m26_socket_event_recv(device, M26_EVENT_CONN_OK | M26_EVENT_CONN_FAIL, 
+            1 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR)) < 0)
+    {
+        LOG_E("m26 device(%s) socket(%d) connect failed, wait connect OK|FAIL timeout.", device->name, device_socket);
+        result = -RT_ETIMEOUT;
+        goto __exit;
+    }
+    /* check result */
+    if (event_result & M26_EVENT_CONN_FAIL)
+    {
+        if (retryed == RT_FALSE)
+        {
+            LOG_D("m26 device(%s) socket(%d) connect failed, maybe the socket was not be closed and now will retry.", 
+                    device->name, device_socket);
+            if (m26_socket_close(socket) < 0)
+            {
+                goto __exit;
+            }
+            retryed = RT_TRUE;
+            goto __retry;
+        }
+        LOG_E("m26 device(%s) socket(%d) connect failed, failed to establish a connection.", device->name, device_socket);
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+static int at_get_send_size(struct at_socket *socket, size_t *size, size_t *acked, size_t *nacked)
+{
+    int result = 0;
+    at_response_t resp = RT_NULL;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+
+    resp = at_create_resp(64, 0, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for m26 device(%s) response structure!", device->name);
+        result = -RT_ENOMEM;
+        goto __exit;
+    }
+
+    if (at_obj_exec_cmd(device->client, resp, "AT+QISACK=%d", device_socket) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    if (at_resp_parse_line_args_by_kw(resp, "+QISACK:", "+QISACK: %d, %d, %d", size, acked, nacked) <= 0)
+    {
+        LOG_E("m26 device(%s) prase \"AT+QISACK\" commands resposne data error!", device->name);
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+static int at_wait_send_finish(struct at_socket *socket, size_t settings_size)
+{
+    /* get the timeout by the input data size */
+    rt_tick_t timeout = rt_tick_from_millisecond(settings_size);
+    rt_tick_t last_time = rt_tick_get();
+    size_t size = 0, acked = 0, nacked = 0xFFFF;
+
+    while (rt_tick_get() - last_time <= timeout)
+    {
+        at_get_send_size(socket, &size, &acked, &nacked);
+        if (nacked == 0)
+        {
+            return RT_EOK;
+        }
+        rt_thread_mdelay(50);
+    }
+
+    return -RT_ETIMEOUT;
+}
+
+/**
+ * send data to server or client by AT commands.
+ *
+ * @param socket current socket
+ * @param buff send buffer
+ * @param bfsz send buffer size
+ * @param type connect socket type(tcp, udp)
+ *
+ * @return >=0: the size of send success
+ *          -1: send AT commands error or send data error
+ *          -2: waited socket event timeout
+ *          -5: no memory
+ */
+static int m26_socket_send(struct at_socket *socket, const char *buff, size_t bfsz, enum at_socket_type type)
+{
+    int result = 0, event_result = 0;
+    size_t pkt_size = 0, sent_size = 0;
+    at_response_t resp = RT_NULL;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+    struct at_device_m26 *m26 = (struct at_device_m26 *) device->user_data;
+    rt_mutex_t lock = device->client->lock;
+
+    RT_ASSERT(buff);
+
+    resp = at_create_resp(128, 2, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for m26 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    rt_mutex_take(lock, RT_WAITING_FOREVER);
+
+    /* Clear socket send event */
+    event_result = SET_EVENT(device_socket, M26_EVENT_SEND_OK | M26_EVENT_SEND_FAIL);
+    m26_socket_event_recv(device, event_result, 0, RT_EVENT_FLAG_OR);
+
+    /* set current socket for send URC event */
+    m26->user_data = (void *) device_socket;
+    /* set AT client end sign to deal with '>' sign.*/
+    at_obj_set_end_sign(device->client, '>');
+
+    while (sent_size < bfsz)
+    {
+        if (bfsz - sent_size < M26_MODULE_SEND_MAX_SIZE)
+        {
+            pkt_size = bfsz - sent_size;
+        }
+        else
+        {
+            pkt_size = M26_MODULE_SEND_MAX_SIZE;
+        }
+
+        /* send the "AT+QISEND" commands to AT server than receive the '>' response on the first line. */
+        if (at_obj_exec_cmd(device->client, resp, "AT+QISEND=%d,%d", device_socket, pkt_size) < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* send the real data to server or client */
+        result = (int) at_client_obj_send(device->client, buff + sent_size, pkt_size);
+        if (result == 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* waiting result event from AT URC */
+        if (m26_socket_event_recv(device, SET_EVENT(device_socket, 0), 15 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
+        {
+            LOG_E("m26 device(%s) socket(%d) send failed, wait connect result timeout.", device->name, device_socket);
+            result = -RT_ETIMEOUT;
+            goto __exit;
+        }
+        /* waiting OK or failed result */
+        if ((event_result = m26_socket_event_recv(device, M26_EVENT_SEND_OK | M26_EVENT_SEND_FAIL, 
+                1 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR)) < 0)
+        {
+            LOG_E("m26 device(%s) socket(%d) send failed, wait connect OK|FAIL timeout.", device->name, device_socket);
+            result = -RT_ETIMEOUT;
+            goto __exit;
+        }
+        /* check result */
+        if (event_result & M26_EVENT_SEND_FAIL)
+        {
+            LOG_E("m26 device(%s) socket(%d) send failed.", device->name, device_socket);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        if (type == AT_SOCKET_TCP)
+        {
+            at_wait_send_finish(socket, pkt_size);
+        }
+
+        sent_size += pkt_size;
+    }
+
+__exit:
+    /* reset the end sign for data conflict */
+    at_obj_set_end_sign(device->client, 0);
+
+    rt_mutex_release(lock);
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+/**
+ * domain resolve by AT commands.
+ *
+ * @param name domain name
+ * @param ip parsed IP address, it's length must be 16
+ *
+ * @return  0: domain resolve success
+ *         -1: send AT commands error or response error
+ *         -2: wait socket event timeout
+ *         -5: no memory
+ */
+static int m26_domain_resolve(const char *name, char ip[16])
+{
+#define RESOLVE_RETRY                  5
+
+    int i, result = RT_EOK;
+    char recv_ip[16] = { 0 };
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    RT_ASSERT(name);
+    RT_ASSERT(ip);
+
+    device = at_device_get_first_initialized();
+    if (device == RT_NULL)
+    {
+        LOG_E("get first initialization m26 device failed.");
+        return -RT_ERROR;
+    }
+
+    /* The maximum response time is 14 seconds, affected by network status */
+    resp = at_create_resp(128, 4, 14 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for m26 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    for(i = 0; i < RESOLVE_RETRY; i++)
+    {
+        if (at_obj_exec_cmd(device->client, resp, "AT+QIDNSGIP=\"%s\"", name) < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* parse the third line of response data, get the IP address */
+        if(at_resp_parse_line_args_by_kw(resp, ".", "%s", recv_ip) < 0)
+        {
+            rt_thread_mdelay(100);
+            /* resolve failed, maybe receive an URC CRLF */
+            continue;
+        }
+
+        if (rt_strlen(recv_ip) < 8)
+        {
+            rt_thread_mdelay(100);
+            /* resolve failed, maybe receive an URC CRLF */
+            continue;
+        }
+        else
+        {
+            rt_thread_mdelay(10);
+            rt_strncpy(ip, recv_ip, 15);
+            ip[15] = '\0';
+            break;
+        }
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+
+}
+
+/**
+ * set AT socket event notice callback
+ *
+ * @param event notice event
+ * @param cb notice callback
+ */
+static void m26_socket_set_event_cb(at_socket_evt_t event, at_evt_cb_t cb)
+{
+    if (event < sizeof(at_evt_cb_set) / sizeof(at_evt_cb_set[1]))
+    {
+        at_evt_cb_set[event] = cb;
+    }
+}
+
+static void urc_connect_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0;
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get m26 device by client name(%s) failed.", client_name);
+        return;
+    }
+
+    sscanf(data, "%d%*[^0-9]", &device_socket);
+    
+    if (rt_strstr(data, "CONNECT OK"))
+    {
+        m26_socket_event_send(device, SET_EVENT(device_socket, M26_EVENT_CONN_OK));
+    }
+    else
+    {
+        m26_socket_event_send(device, SET_EVENT(device_socket, M26_EVENT_CONN_FAIL));
+    }
+}
+
+static void urc_send_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0;
+    struct at_device *device = RT_NULL;
+    struct at_device_m26 *m26 = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get m26 device by client name(%s) failed.", client_name);
+        return;
+    }
+    m26 = (struct at_device_m26 *) device->user_data;
+    device_socket = (int) m26->user_data;
+
+    if (rt_strstr(data, "SEND OK"))
+    {
+        m26_socket_event_send(device, SET_EVENT(device_socket, M26_EVENT_SEND_OK));
+    }
+    else if (rt_strstr(data, "SEND FAIL"))
+    {
+        m26_socket_event_send(device, SET_EVENT(device_socket, M26_EVENT_SEND_FAIL));
+    }
+}
+
+static void urc_close_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0;
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get m26 device by client name(%s) failed.", client_name);
+        return;      
+    }
+
+    sscanf(data, "%d%*s", &device_socket);
+
+    if (rt_strstr(data, "CLOSE OK"))
+    {
+        m26_socket_event_send(device, SET_EVENT(device_socket, M26_EVNET_CLOSE_OK));
+    }
+    else if (rt_strstr(data, "CLOSED"))
+    {
+        struct at_socket *socket = RT_NULL;
+
+        /* get at socket object by device socket descriptor */
+        socket = &(device->sockets[device_socket]);
+
+        /* notice the socket is disconnect by remote */
+        if (at_evt_cb_set[AT_SOCKET_EVT_CLOSED])
+        {
+            at_evt_cb_set[AT_SOCKET_EVT_CLOSED](socket, AT_SOCKET_EVT_CLOSED, NULL, 0);
+        }
+    }
+}
+
+static void urc_recv_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0;
+    rt_int32_t timeout;
+    rt_size_t bfsz = 0, temp_size = 0;
+    char *recv_buf = RT_NULL, temp[8] = {0};
+    struct at_socket *socket = RT_NULL;
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+    
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get m26 device by client name(%s) failed.", client_name);
+        return;
+    }
+
+    /* get the current socket and receive buffer size by receive data */
+    sscanf(data, "+RECEIVE: %d, %d", &device_socket, (int *) &bfsz);
+
+    /* get receive timeout by receive buffer length */
+    timeout = bfsz;
+
+    if (device_socket < 0 || bfsz == 0)
+    {
+        return;
+    }
+
+    recv_buf = (char *) rt_calloc(1, bfsz);
+    if (recv_buf == RT_NULL)
+    {
+        LOG_E("no memory for m26 device(%s) urc receive buffer (%d).", device->name, bfsz);
+        /* read and clean the coming data */
+        while (temp_size < bfsz)
+        {
+            if (bfsz - temp_size > sizeof(temp))
+            {
+                at_client_obj_recv(client, temp, sizeof(temp), timeout);
+            }
+            else
+            {
+                at_client_obj_recv(client, temp, bfsz - temp_size, timeout);
+            }
+            temp_size += sizeof(temp);
+        }
+        return;
+    }
+
+    /* sync receive data */
+    if (at_client_obj_recv(client, recv_buf, bfsz, timeout) != bfsz)
+    {
+        LOG_E("m26 device(%s) receive size(%d) data failed.",  device->name, bfsz);
+        rt_free(recv_buf);
+        return;
+    }
+
+    /* get at socket object by device socket descriptor */
+    socket = &(device->sockets[device_socket]);
+
+    /* notice the receive buffer and buffer size */
+    if (at_evt_cb_set[AT_SOCKET_EVT_RECV])
+    {
+        at_evt_cb_set[AT_SOCKET_EVT_RECV](socket, AT_SOCKET_EVT_RECV, recv_buf, bfsz);
+    }
+}
+
+static const struct at_urc urc_table[] = 
+{
+    {"",            ", CONNECT OK\r\n",     urc_connect_func},
+    {"",            ", CONNECT FAIL\r\n",   urc_connect_func},
+    {"SEND OK",     "\r\n",                 urc_send_func},
+    {"SEND FAIL",   "\r\n",                 urc_send_func},
+    {"",            ", CLOSE OK\r\n",       urc_close_func},
+    {"",            ", CLOSED\r\n",         urc_close_func},
+    {"+RECEIVE:",   "\r\n",                 urc_recv_func},
+};
+
+static const struct at_socket_ops m26_socket_ops = 
+{
+    m26_socket_connect,
+    m26_socket_close,
+    m26_socket_send,
+    m26_domain_resolve,
+    m26_socket_set_event_cb,
+};
+
+int m26_socket_init(struct at_device *device)
+{
+    RT_ASSERT(device);
+
+    /* register URC data execution function  */
+    at_obj_set_urc_table(device->client, urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
+
+    return RT_EOK;
+}
+
+int m26_socket_class_register(struct at_device_class *class)
+{
+    RT_ASSERT(class);
+
+    class->socket_num = AT_DEVICE_M26_SOCKETS_NUM;
+    class->socket_ops = &m26_socket_ops;
+
+    return RT_EOK;
+}
+
+
+#endif /* AT_DEVICE_USING_M26 && AT_USING_SOCKET */

+ 403 - 0
class/rw007/at_device_rw007.c

@@ -0,0 +1,403 @@
+/*
+ * File      : at_socket_rw007.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-06-20     chenyong     first version
+ * 2019-05-12     chenyong     multi AT socket client support
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <at_device_rw007.h>
+
+#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10300
+#error "This AT Client version is older, please check and update latest AT Client!"
+#endif
+
+#define LOG_TAG                        "at.dev"
+
+#include <at_log.h>
+
+#ifdef AT_DEVICE_USING_RW007
+
+#define RW007_WAIT_CONNECT_TIME        5000
+#define RW007_THREAD_STACK_SIZE        1024
+#define RW007_THREAD_PRIORITY          (RT_THREAD_PRIORITY_MAX / 2)
+
+/* =============================  rw007 network interface operations ============================= */
+
+static struct netdev *rw007_netdev_add(const char *netdev_name)
+{
+#define ETHERNET_MTU        1500
+#define HWADDR_LEN          6
+    struct netdev *netdev = RT_NULL;
+
+    RT_ASSERT(netdev_name);
+
+    netdev = (struct netdev *) rt_calloc(1, sizeof(struct netdev));
+    if (netdev == RT_NULL)
+    {
+        return RT_NULL;
+    }
+
+    /* TODO: improve netdev adaptation */
+    netdev->mtu = ETHERNET_MTU;
+    netdev->hwaddr_len = HWADDR_LEN;
+    netdev->ops = RT_NULL;
+
+#ifdef SAL_USING_AT
+    extern int sal_at_netdev_set_pf_info(struct netdev *netdev);
+    /* set the network interface socket/netdb operations */
+    sal_at_netdev_set_pf_info(netdev);
+#endif
+
+    netdev_register(netdev, netdev_name, RT_NULL);
+
+    /*TODO: improve netdev adaptation */
+    netdev_low_level_set_status(netdev, RT_TRUE);
+    netdev_low_level_set_link_status(netdev, RT_TRUE);
+    netdev_low_level_set_dhcp_status(netdev, RT_TRUE);
+    netdev->flags |= NETDEV_FLAG_INTERNET_UP;
+
+    return netdev;
+}
+
+/* =============================  rw007 device operations ============================= */
+
+#define AT_SEND_CMD(client, resp, cmd)                                     \
+    do {                                                                   \
+        (resp) = at_resp_set_info((resp), 256, 0, 5 * RT_TICK_PER_SECOND); \
+        if (at_obj_exec_cmd((client), (resp), (cmd)) < 0)                  \
+        {                                                                  \
+            result = -RT_ERROR;                                            \
+            goto __exit;                                                   \
+        }                                                                  \
+    } while(0)                                                             \
+
+static void rw007_init_thread_entry(void *parameter)
+{
+#define INIT_RETRY    5
+
+    struct at_device *device = (struct at_device *) parameter;
+    struct at_device_rw007 *rw007 = (struct at_device_rw007 *) device->user_data;
+    struct at_client *client = device->client;
+    at_response_t resp = RT_NULL;
+    rt_err_t result = RT_EOK;
+    rt_size_t i = 0, retry_num = INIT_RETRY;
+
+    /* wait rw007 device startup finish */
+    if (at_client_obj_wait_connect(client, RW007_WAIT_CONNECT_TIME))
+    {
+        return;
+    }
+
+    resp = at_create_resp(128, 0, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for rw007 device(%d) response structure.", device->name);
+        return;
+    }
+
+    while (retry_num--)
+    {
+        /* reset module */
+        AT_SEND_CMD(client, resp, "AT+RST");
+        /* reset waiting delay */
+        rt_thread_mdelay(1000);
+        /* disable echo */
+        AT_SEND_CMD(client, resp, "ATE0");
+        /* set current mode to Wi-Fi station */
+        AT_SEND_CMD(client, resp, "AT+CWMODE=1");
+        /* get module version */
+        AT_SEND_CMD(client, resp, "AT+GMR");
+        /* show module version */
+        for (i = 0; i < resp->line_counts - 1; i++)
+        {
+            LOG_D("%s", at_resp_get_line(resp, i + 1));
+        }
+        /* connect to WiFi AP */
+        if (at_obj_exec_cmd(client, at_resp_set_info(resp, 128, 0, 20 * RT_TICK_PER_SECOND), 
+                    "AT+CWJAP=\"%s\",\"%s\"", rw007->wifi_ssid, rw007->wifi_password) != RT_EOK)
+        {
+            LOG_E("rw007 device(%s) network initialize failed, check ssid(%s) and password(%s).", 
+                    device->name, rw007->wifi_ssid, rw007->wifi_password);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        AT_SEND_CMD(client, resp, "AT+CIPMUX=1");
+
+    __exit:
+        if (result == RT_EOK)
+        {
+            break;
+        }
+        else
+        {
+            rt_thread_mdelay(1000);
+            LOG_I("rw007 device(%s) initialize retry...", device->name);
+        }
+    }
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    if (result != RT_EOK)
+    {
+        netdev_low_level_set_status(device->netdev, RT_FALSE);
+        LOG_E("rw007 device(%s) network initialize failed(%d).", device->name, result);
+    }
+    else
+    {
+        netdev_low_level_set_status(device->netdev, RT_TRUE);
+        LOG_I("rw007 device(%s) network initialize successfully.", device->name);
+    }
+}
+
+int rw007_net_init(struct at_device *device)
+{
+#ifdef AT_DEVICE_RW007_INIT_ASYN
+    rt_thread_t tid;
+
+    tid = rt_thread_create("rw007_net_init", rw007_init_thread_entry, 
+                (void *)device, RW007_THREAD_STACK_SIZE, RW007_THREAD_PRIORITY, 20);
+    if (tid)
+    {
+        rt_thread_startup(tid);
+    }
+    else
+    {
+        LOG_E("create rw007 device(%s) initialization thread failed.", device->name);
+        return -RT_ERROR;
+    }
+#else
+    rw007_init_thread_entry(device);
+#endif /* AT_DEVICE_RW007_INIT_ASYN */
+
+    return RT_EOK;
+}
+
+static void urc_busy_p_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    LOG_D("system is processing a commands and it cannot respond to the current commands.");
+}
+
+static void urc_busy_s_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    LOG_D("system is sending data and it cannot respond to the current commands.");
+}
+
+static void urc_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(client && data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get rw007 device by client name(%s) failed.", client_name);
+        return;
+    }
+
+    if (rt_strstr(data, "WIFI CONNECTED"))
+    {
+        LOG_I("rw007 device(%s) WIFI is connected.", device->name);
+    }
+    else if (rt_strstr(data, "WIFI DISCONNECT"))
+    {
+        LOG_I("rw007 device(%s) WIFI is disconnect.", device->name);
+    }
+}
+
+static struct at_urc urc_table[] = {
+        {"busy p",           "\r\n",           urc_busy_p_func},
+        {"busy s",           "\r\n",           urc_busy_s_func},
+        {"WIFI CONNECTED",   "\r\n",           urc_func},
+        {"WIFI DISCONNECT",  "\r\n",           urc_func},
+};
+
+static int rw007_init(struct at_device *device)
+{
+    struct at_device_rw007 *rw007 = (struct at_device_rw007 *) device->user_data;
+
+    /* initialize AT client */
+    at_client_init(rw007->client_name, rw007->recv_line_num);
+
+    device->client = at_client_get(rw007->client_name);
+    if (device->client == RT_NULL)
+    {
+        LOG_E("rw007 device(%s) initialize failed, get AT client(%s) failed.", 
+                rw007->device_name, rw007->client_name);
+        return -RT_ERROR;
+    }
+
+    /* register URC data execution function  */
+    at_obj_set_urc_table(device->client, urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
+
+#ifdef AT_USING_SOCKET
+    rw007_socket_init(device);
+#endif
+
+    /* add rw007 device to the netdev list */
+    device->netdev = rw007_netdev_add(rw007->device_name);
+    if (device->netdev == RT_NULL)
+    {
+        LOG_E("rw007 device(%s) initialize failed, get network interface device failed.", rw007->device_name);
+        return -RT_ERROR;
+    }
+
+    /* initialize rw007 device network */
+    return rw007_net_init(device);
+}
+
+static int rw007_deinit(struct at_device *device)
+{
+    // TODO add netdev operation
+    device->is_init = RT_FALSE;
+    return RT_EOK;
+}
+
+/* reset eap8266 device and initialize device network again */
+static int rw007_reset(struct at_device *device)
+{
+    int result = RT_EOK;
+    struct at_client *client = device->client;
+
+    /* send "AT+RST" commonds to rw007 device */
+    result = at_obj_exec_cmd(client, RT_NULL, "AT+RST");
+    rt_thread_delay(1000);
+
+    /* waiting 10 seconds for rw007 device reset */
+    device->is_init = RT_FALSE;
+    if (at_client_obj_wait_connect(client, RW007_WAIT_CONNECT_TIME))
+    {
+        return -RT_ETIMEOUT;
+    }
+
+    /* initialize rw007 device network */
+    rw007_net_init(device);
+    
+    device->is_init = RT_TRUE;
+
+    return result;
+}
+
+/* change eap8266 wifi ssid and password information */
+static int rw007_wifi_info_set(struct at_device *device, struct at_device_ssid_pwd *info)
+{
+    int result = RT_EOK;
+    struct at_response *resp = RT_NULL;
+
+    if (info->ssid == RT_NULL || info->password == RT_NULL)
+    {
+        LOG_E("input rwoo7 wifi ssid(%s) and password(%s) error.", info->ssid, info->password);
+         return -RT_ERROR;
+    }
+
+    resp = at_create_resp(128, 0, 20 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for rw007 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    /* connect to input wifi ap */
+    if (at_obj_exec_cmd(device->client, resp, "AT+CWJAP=\"%s\",\"%s\"", info->ssid, info->password) != RT_EOK)
+    {
+        LOG_E("rw007 device(%s) wifi connect failed, check ssid(%s) and password(%s).",  
+                device->name, info->ssid, info->password);
+        result = -RT_ERROR;
+    }
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+static int rw007_control(struct at_device *device, int cmd, void *arg)
+{
+    int result = -RT_ERROR;
+
+    RT_ASSERT(device);
+
+    switch (cmd)
+    {
+    case AT_DEVICE_CTRL_POWER_ON:
+    case AT_DEVICE_CTRL_POWER_OFF:
+    case AT_DEVICE_CTRL_LOW_POWER:
+    case AT_DEVICE_CTRL_SLEEP:
+    case AT_DEVICE_CTRL_WAKEUP:
+    case AT_DEVICE_CTRL_NET_CONN:
+    case AT_DEVICE_CTRL_NET_DISCONN:
+    case AT_DEVICE_CTRL_GET_SIGNAL:
+    case AT_DEVICE_CTRL_GET_GPS:
+    case AT_DEVICE_CTRL_GET_VER:
+        LOG_W("rw007 not support the control command(%d).", cmd);
+        break;
+    case AT_DEVICE_CTRL_RESET:
+        result = rw007_reset(device);
+        break;
+    case AT_DEVICE_CTRL_SET_WIFI_INFO:
+        result = rw007_wifi_info_set(device, (struct at_device_ssid_pwd *) arg);
+        break;
+    default:
+        LOG_E("input error control command(%d).", cmd);
+        break;
+    }
+
+    return result;
+}
+
+const struct at_device_ops rw007_device_ops = 
+{
+    rw007_init,
+    rw007_deinit,
+    rw007_control,
+};
+
+static int rw007_device_class_register(void)
+{
+    struct at_device_class *class = RT_NULL;
+
+    class = (struct at_device_class *) rt_calloc(1, sizeof(struct at_device_class));
+    if (class == RT_NULL)
+    {
+        LOG_E("no memory for rw007 device class create.");
+        return -RT_ENOMEM;
+    }
+
+    /* fill rw007 device class object */
+#ifdef AT_USING_SOCKET
+    rw007_socket_class_register(class);
+#endif
+    class->device_ops = &rw007_device_ops;
+
+    return at_device_class_register(class, AT_DEVICE_CLASS_RW007);
+}
+INIT_DEVICE_EXPORT(rw007_device_class_register);
+
+#endif /* AT_DEVICE_USING_RW007 */

+ 66 - 0
class/rw007/at_device_rw007.h

@@ -0,0 +1,66 @@
+/*
+ * File      : at_device_RW007.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-05-16     chenyong     first version
+ */
+
+#ifndef __AT_DEVICE_RW007_H__
+#define __AT_DEVICE_RW007_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+
+#include <at_device.h>
+
+/* The maximum number of sockets supported by the rw007 device */
+#define AT_DEVICE_RW007_SOCKETS_NUM  5
+
+struct at_device_rw007
+{     
+    char *device_name;
+    char *client_name;
+
+    char *wifi_ssid;
+    char *wifi_password;
+    size_t recv_line_num;
+    struct at_device device;
+
+    void *user_data;
+};
+
+#ifdef AT_USING_SOCKET
+
+/* rw007 device socket initialize */
+int rw007_socket_init(struct at_device *device);
+
+/* rw007 device class socket register */
+int rw007_socket_class_register(struct at_device_class *class);
+
+#endif /* AT_USING_SOCKET */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AT_DEVICE_RW007_H__ */

+ 561 - 0
class/rw007/at_socket_rw007.c

@@ -0,0 +1,561 @@
+/*
+ * File      : at_socket_rw007.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-06-20     chenyong     first version
+ * 2019-05-12     chenyong     multi AT socket client support
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <at_device_rw007.h>
+
+#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10300
+#error "This AT Client version is older, please check and update latest AT Client!"
+#endif
+
+#define LOG_TAG                       "at.skt"
+#include <at_log.h>
+
+#if defined(AT_DEVICE_USING_RW007) && defined(AT_USING_SOCKET)
+
+#define RW007_MODULE_SEND_MAX_SIZE     2048
+/* set real event by current socket and current state */
+#define SET_EVENT(socket, event)       (((socket + 1) << 16) | (event))
+
+/* AT socket event type */
+#define RW007_EVENT_CONN_OK            (1L << 0)
+#define RW007_EVENT_SEND_OK            (1L << 1)
+#define RW007_EVENT_RECV_OK            (1L << 2)
+#define RW007_EVNET_CLOSE_OK           (1L << 3)
+#define RW007_EVENT_CONN_FAIL          (1L << 4)
+#define RW007_EVENT_SEND_FAIL          (1L << 5)
+
+static at_evt_cb_t at_evt_cb_set[] = {
+        [AT_SOCKET_EVT_RECV] = NULL,
+        [AT_SOCKET_EVT_CLOSED] = NULL,
+};
+
+static int rw007_socket_event_send(struct at_device *device, uint32_t event)
+{
+    return (int) rt_event_send(device->socket_event, event);
+}
+
+static int rw007_socket_event_recv(struct at_device *device, uint32_t event, uint32_t timeout, rt_uint8_t option)
+{
+    int result = RT_EOK;
+    rt_uint32_t recved;
+
+    result = rt_event_recv(device->socket_event, event, option | RT_EVENT_FLAG_CLEAR, timeout, &recved);
+    if (result != RT_EOK)
+    {
+        return -RT_ETIMEOUT;
+    }
+
+    return recved;
+}
+
+/**
+ * close socket by AT commands.
+ *
+ * @param current socket
+ *
+ * @return  0: close socket success
+ *         -1: send AT commands error
+ *         -2: wait socket event timeout
+ *         -5: no memory
+ */
+static int rw007_socket_close(struct at_socket *socket)
+{
+    int result = RT_EOK;
+    at_response_t resp = RT_NULL;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+
+    resp = at_create_resp(64, 0, RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for rw007 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    result = at_obj_exec_cmd(device->client, resp, "AT+CIPCLOSE=%d", device_socket);
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+    
+    return result;
+}
+
+/**
+ * create TCP/UDP client or server connect by AT commands.
+ *
+ * @param socket current socket
+ * @param ip server or client IP address
+ * @param port server or client port
+ * @param type connect socket type(tcp, udp)
+ * @param is_client connection is client
+ *
+ * @return   0: connect success
+ *          -1: connect failed, send commands error or type error
+ *          -2: wait socket event timeout
+ *          -5: no memory
+ */
+static int rw007_socket_connect(struct at_socket *socket, char *ip, int32_t port, enum at_socket_type type, rt_bool_t is_client)
+{
+    int result = RT_EOK;
+    rt_bool_t retryed = RT_FALSE;
+    at_response_t resp = RT_NULL;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+
+    RT_ASSERT(ip);
+    RT_ASSERT(port >= 0);
+
+    resp = at_create_resp(128, 0, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for rw007 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+__retry:
+    if (is_client)
+    {
+        switch (type)
+        {
+        case AT_SOCKET_TCP:
+            /* send AT commands to connect TCP server */
+            if (at_obj_exec_cmd(device->client, resp, 
+                    "AT+CIPSTART=%d,\"TCP\",\"%s\",%d,60", device_socket, ip, port) < 0)
+            {
+                result = -RT_ERROR;
+            }
+            break;
+
+        case AT_SOCKET_UDP:
+            if (at_obj_exec_cmd(device->client, resp, 
+                    "AT+CIPSTART=%d,\"UDP\",\"%s\",%d", device_socket, ip, port) < 0)
+            {
+                result = -RT_ERROR;
+            }
+            break;
+
+        default:
+            LOG_E("rw007 device(%s) not supported connect type %d.", device->name, type);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+    }
+
+    if (result != RT_EOK && retryed == RT_FALSE)
+    {
+        LOG_D("rw007 device(%s) socket (%d) connect failed, maybe the socket was not be closed at the last time and now will retry.", 
+                device->name, socket);
+        if (rw007_socket_close(socket) < 0)
+        {
+            goto __exit;
+        }
+        retryed = RT_TRUE;
+        result = RT_EOK;
+        goto __retry;
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+/**
+ * send data to server or client by AT commands.
+ *
+ * @param socket current socket
+ * @param buff send buffer
+ * @param bfsz send buffer size
+ * @param type connect socket type(tcp, udp)
+ *
+ * @return >=0: the size of send success
+ *          -1: send AT commands error or send data error
+ *          -2: waited socket event timeout
+ *          -5: no memory
+ */
+static int rw007_socket_send(struct at_socket *socket, const char *buff, size_t bfsz, enum at_socket_type type)
+{
+    int result = RT_EOK;
+    int event_result = 0;
+    size_t cur_pkt_size = 0, sent_size = 0;
+    at_response_t resp = RT_NULL;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+    struct at_device_rw007 *rw007 = (struct at_device_rw007 *) device->user_data;
+    rt_mutex_t lock = device->client->lock;
+
+    RT_ASSERT(buff);
+    RT_ASSERT(bfsz > 0);
+
+    resp = at_create_resp(128, 2, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for rw007 device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    rt_mutex_take(lock, RT_WAITING_FOREVER);
+
+    /* set current socket for send URC event */
+    rw007->user_data = (void *) device_socket;
+
+    /* set AT client end sign to deal with '>' sign */
+    at_obj_set_end_sign(device->client, '>');
+
+    while (sent_size < bfsz)
+    {
+        if (bfsz - sent_size < RW007_MODULE_SEND_MAX_SIZE)
+        {
+            cur_pkt_size = bfsz - sent_size;
+        }
+        else
+        {
+            cur_pkt_size = RW007_MODULE_SEND_MAX_SIZE;
+        }
+
+        /* send the "AT+CIPSEND" commands to AT server than receive the '>' response on the first line */
+        if (at_obj_exec_cmd(device->client, resp, "AT+CIPSEND=%d,%d", device_socket, cur_pkt_size) < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* send the real data to server or client */
+        result = (int) at_client_obj_send(device->client, buff + sent_size, cur_pkt_size);
+        if (result == 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* waiting result event from AT URC */
+        if (rw007_socket_event_recv(device, SET_EVENT(device_socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
+        {
+            LOG_E("rw007 device(%s) socket (%d) send failed, wait connect result timeout.", device->name, device_socket);
+            result = -RT_ETIMEOUT;
+            goto __exit;
+        }
+        /* waiting OK or failed result */
+        event_result = rw007_socket_event_recv(device, RW007_EVENT_SEND_OK | RW007_EVENT_SEND_FAIL, 
+                            5 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR);
+        if (event_result  < 0)
+        {
+            LOG_E("rw007 device(%s) socket (%d) send failed, wait connect OK|FAIL timeout.", device->name, device_socket);
+            result = -RT_ETIMEOUT;
+            goto __exit;
+        }
+        /* check result */
+        if (event_result & RW007_EVENT_SEND_FAIL)
+        {
+            LOG_E("rw007 device(%s) socket (%d) send failed.", device->name, device_socket);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        sent_size += cur_pkt_size;
+    }
+
+__exit:
+    /* reset the end sign for data */
+    at_obj_set_end_sign(device->client, 0);
+
+    rt_mutex_release(lock);
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+/**
+ * domain resolve by AT commands.
+ *
+ * @param name domain name
+ * @param ip parsed IP address, it's length must be 16
+ *
+ * @return  0: domain resolve success
+ *         -2: wait socket event timeout
+ *         -5: no memory
+ */
+static int rw007_domain_resolve(const char *name, char ip[16])
+{
+#define RESOLVE_RETRY        5
+
+    int i, result = RT_EOK;
+    char recv_ip[16] = { 0 };
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    RT_ASSERT(name);
+    RT_ASSERT(ip);
+
+    device = at_device_get_first_initialized();
+    if (device == RT_NULL)
+    {
+        LOG_E("get first initialization rw007 device failed.");
+        return -RT_ERROR;
+    }
+
+    resp = at_create_resp(128, 0, 20 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for rw007 device response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    for (i = 0; i < RESOLVE_RETRY; i++)
+    {
+        if (at_obj_exec_cmd(device->client, resp, "AT+CIPDOMAIN=\"%s\"", name) < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* parse the third line of response data, get the IP address */
+        if (at_resp_parse_line_args_by_kw(resp, "+CIPDOMAIN:", "+CIPDOMAIN:%s", recv_ip) < 0)
+        {
+            rt_thread_mdelay(100);
+            /* resolve failed, maybe receive an URC CRLF */
+            continue;
+        }
+
+        if (rt_strlen(recv_ip) < 8)
+        {
+            rt_thread_mdelay(100);
+            /* resolve failed, maybe receive an URC CRLF */
+            continue;
+        }
+        else
+        {
+            rt_strncpy(ip, recv_ip, 15);
+            ip[15] = '\0';
+            break;
+        }
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+
+}
+
+/**
+ * set AT socket event notice callback
+ *
+ * @param event notice event
+ * @param cb notice callback
+ */
+static void rw007_socket_set_event_cb(at_socket_evt_t event, at_evt_cb_t cb)
+{
+    if (event < sizeof(at_evt_cb_set) / sizeof(at_evt_cb_set[1]))
+    {
+        at_evt_cb_set[event] = cb;
+    }
+}
+
+static const struct at_socket_ops rw007_socket_ops =
+{
+    rw007_socket_connect,
+    rw007_socket_close,
+    rw007_socket_send,
+    rw007_domain_resolve,
+    rw007_socket_set_event_cb,
+};
+
+static void urc_send_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0;
+    struct at_device *device = RT_NULL;
+    struct at_device_rw007 *rw007 = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get rw007 device by client name(%s) failed.", client_name);
+        return;
+    }
+    rw007 = (struct at_device_rw007 *) device->user_data;
+    device_socket = (int) rw007->user_data;
+
+    if (rt_strstr(data, "SEND OK"))
+    {
+        rw007_socket_event_send(device, SET_EVENT(device_socket, RW007_EVENT_SEND_OK));
+    }
+    else if (rt_strstr(data, "SEND FAIL"))
+    {
+        rw007_socket_event_send(device, SET_EVENT(device_socket, RW007_EVENT_SEND_FAIL));
+    }
+}
+
+static void urc_send_bfsz_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    static int cur_send_bfsz = 0;
+
+    RT_ASSERT(data && size);
+
+    sscanf(data, "Recv %d bytes", &cur_send_bfsz);
+}
+
+static void urc_close_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0;
+    struct at_socket *socket = RT_NULL;
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name; 
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+       LOG_E("get rw007 device by client name(%s) failed.", client_name);
+        return;
+    }
+
+    sscanf(data, "%d,CLOSED", &device_socket);
+    /* get at socket object by device socket descriptor */
+    socket = &(device->sockets[device_socket]);
+
+    /* notice the socket is disconnect by remote */
+    if (at_evt_cb_set[AT_SOCKET_EVT_CLOSED])
+    {
+        at_evt_cb_set[AT_SOCKET_EVT_CLOSED](socket, AT_SOCKET_EVT_CLOSED, RT_NULL, 0);
+    }
+}
+
+static void urc_recv_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0;
+    rt_int32_t timeout = 0;
+    rt_size_t bfsz = 0, temp_size = 0;
+    char *recv_buf = RT_NULL, temp[8] = {0};
+    struct at_socket *socket = RT_NULL;
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name; 
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get rw007 device by client name(%s) failed.", client_name);
+        return;
+    }
+
+    /* get the current socket and receive buffer size by receive data */
+    sscanf(data, "+IPD,%d,%d:", &device_socket, (int *) &bfsz);
+    /* get receive timeout by receive buffer length */
+    timeout = bfsz;
+
+    if (device_socket < 0 || bfsz == 0)
+    {
+        return;
+    }
+
+    recv_buf = (char *) rt_calloc(1, bfsz);
+    if (recv_buf == RT_NULL)
+    {
+        LOG_E("no memory for rw007 device(%s) URC receive buffer (%d).", device->name, bfsz);
+        /* read and clean the coming data */
+        while (temp_size < bfsz)
+        {
+            if (bfsz - temp_size > sizeof(temp))
+            {
+                at_client_obj_recv(client, temp, sizeof(temp), timeout);
+            }
+            else
+            {
+                at_client_obj_recv(client, temp, bfsz - temp_size, timeout);
+            }
+            temp_size += sizeof(temp);
+        }
+        return;
+    }
+
+    /* sync receive data */
+    if (at_client_obj_recv(client, recv_buf, bfsz, timeout) != bfsz)
+    {
+        LOG_E("rw007 device(%s) receive size(%d) data failed.", device->name, bfsz);
+        rt_free(recv_buf);
+        return;
+    }
+
+    /* get at socket object by device socket descriptor */
+    socket = &(device->sockets[device_socket]);
+
+    /* notice the receive buffer and buffer size */
+    if (at_evt_cb_set[AT_SOCKET_EVT_RECV])
+    {
+        at_evt_cb_set[AT_SOCKET_EVT_RECV](socket, AT_SOCKET_EVT_RECV, recv_buf, bfsz);
+    }
+}
+
+static struct at_urc urc_table[] = 
+{
+    {"SEND OK",          "\r\n",           urc_send_func},
+    {"SEND FAIL",        "\r\n",           urc_send_func},
+    {"Recv",             "bytes\r\n",      urc_send_bfsz_func},
+    {"",                 ",CLOSED\r\n",    urc_close_func},
+    {"+IPD",             ":",              urc_recv_func},
+};
+
+int rw007_socket_init(struct at_device *device)
+{
+    RT_ASSERT(device);
+
+    /* register URC data execution function  */
+    at_obj_set_urc_table(device->client, urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
+
+    return RT_EOK;
+}
+
+int rw007_socket_class_register(struct at_device_class *class)
+{
+    RT_ASSERT(class);
+
+    class->socket_num = AT_DEVICE_RW007_SOCKETS_NUM;
+    class->socket_ops = &rw007_socket_ops;
+
+    return RT_EOK;
+}
+
+#endif /* AT_DEVICE_USING_RW007 && AT_USING_SOCKET */

+ 610 - 0
class/sim76xx/at_device_sim76xx.c

@@ -0,0 +1,610 @@
+/*
+ * File      : at_socket_sim76xx.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-12-22    thomasonegd  first version
+ * 2019-03-06    thomasonegd  fix udp connection.
+ * 2019-03-08    thomasonegd  add power_on & power_off api
+ * 2019-05-14    chenyong     multi AT socket client support
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <at_device_sim76xx.h>
+
+#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10300
+#error "This AT Client version is older, please check and update latest AT Client!"
+#endif
+
+#define LOG_TAG                        "at.dev"
+#include <at_log.h>
+
+#ifdef AT_DEVICE_USING_SIM76XX
+
+#define SIM76XX_WAIT_CONNECT_TIME      5000
+#define SIM76XX_THREAD_STACK_SIZE      1024
+#define SIM76XX_THREAD_PRIORITY        (RT_THREAD_PRIORITY_MAX / 2)
+
+/**
+ * power up sim76xx modem
+ */
+static void sim76xx_power_on(struct at_device *device)
+{
+    struct at_device_sim76xx *sim76xx = RT_NULL;
+
+    sim76xx = (struct at_device_sim76xx *) device->user_data;
+
+    /* not nead to set pin configuration for m26 device power on */
+    if (sim76xx->power_pin == -1 || sim76xx->power_status_pin == -1)
+    {
+        return;
+    }
+
+    if (rt_pin_read(sim76xx->power_status_pin) == PIN_HIGH)
+    {
+        return;
+    }
+    rt_pin_write(sim76xx->power_pin, PIN_HIGH);
+
+    while (rt_pin_read(sim76xx->power_status_pin) == PIN_LOW)
+    {
+        rt_thread_mdelay(10);
+    }
+    rt_pin_write(sim76xx->power_pin, PIN_LOW);
+}
+
+static void sim76xx_power_off(struct at_device *device)
+{
+    struct at_device_sim76xx *sim76xx = RT_NULL;
+
+    sim76xx = (struct at_device_sim76xx *) device->user_data;
+
+    /* not nead to set pin configuration for m26 device power on */
+    if (sim76xx->power_pin == -1 || sim76xx->power_status_pin == -1)
+    {
+        return;
+    }
+
+    if (rt_pin_read(sim76xx->power_status_pin) == PIN_LOW)
+    {
+        return;
+    }
+    rt_pin_write(sim76xx->power_pin, PIN_HIGH);
+
+    while (rt_pin_read(sim76xx->power_status_pin) == PIN_HIGH)
+    {
+        rt_thread_mdelay(10);
+    }
+    rt_pin_write(sim76xx->power_pin, PIN_LOW);
+}
+
+/* =============================  sim76xx network interface operations ============================= */
+
+static struct netdev *sim76xx_netdev_add(const char *netdev_name)
+{
+#define ETHERNET_MTU 1500
+#define HWADDR_LEN 8
+    struct netdev *netdev = RT_NULL;
+
+    RT_ASSERT(netdev_name);
+
+    netdev = (struct netdev *)rt_calloc(1, sizeof(struct netdev));
+    if (netdev == RT_NULL)
+    {
+        LOG_E("no memory for sim76xx device(%s) netdev structure.", netdev_name);
+        return RT_NULL;
+    }
+
+    netdev->mtu = ETHERNET_MTU;
+    netdev->hwaddr_len = HWADDR_LEN;
+    netdev->ops = RT_NULL;
+
+#ifdef SAL_USING_AT
+    extern int sal_at_netdev_set_pf_info(struct netdev * netdev);
+    /* set the network interface socket/netdb operations */
+    sal_at_netdev_set_pf_info(netdev);
+#endif
+
+    netdev_register(netdev, netdev_name, RT_NULL);
+
+    /*TODO: improve netdev adaptation */
+    netdev_low_level_set_status(netdev, RT_TRUE);
+    netdev_low_level_set_link_status(netdev, RT_TRUE);
+    netdev_low_level_set_dhcp_status(netdev, RT_TRUE);
+    netdev->flags |= NETDEV_FLAG_INTERNET_UP;
+
+    return netdev;
+}
+
+/* =============================  sim76xx device operations ============================= */
+
+#define AT_SEND_CMD(client, resp, cmd)                                          \
+    do {                                                                        \
+        (resp) = at_resp_set_info((resp), 256, 0, 5 * RT_TICK_PER_SECOND);      \
+        if (at_obj_exec_cmd((client), (resp), (cmd)) < 0)                       \
+        {                                                                       \
+            result = -RT_ERROR;                                                 \
+            goto __exit;                                                        \
+        }                                                                       \
+    } while(0)                                                                  \
+
+
+static void sim76xx_init_thread_entry(void *parameter)
+{
+#define INIT_RETRY                     5
+#define CSQ_RETRY                      20
+#define CREG_RETRY                     10
+#define CGREG_RETRY                    20
+#define CGATT_RETRY                    10
+#define CCLK_RETRY                     10
+
+    at_response_t resp = RT_NULL;
+    rt_err_t result = RT_EOK;
+    rt_size_t i, qi_arg[3] = {0};
+    int retry_num = INIT_RETRY;
+    char parsed_data[20] = {0};
+    struct at_device *device = (struct at_device *)parameter;
+    struct at_client *client = device->client;
+
+    resp = at_create_resp(128, 0, rt_tick_from_millisecond(300));
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for sim76xx device(%s) response structure.", device->name);
+        return;
+    }
+
+    LOG_D("start initializing the sim76xx device(%s).", device->name);
+
+    while (retry_num--)
+    {
+        /* power-up sim76xx */
+        sim76xx_power_on(device);
+        rt_thread_mdelay(1000);
+
+        /* wait SIM76XX startup finish, Send AT every 5s, if receive OK, SYNC success*/
+        if (at_client_wait_connect(SIM76XX_WAIT_CONNECT_TIME))
+        {
+            result = -RT_ETIMEOUT;
+            goto __exit;
+        }
+
+        /* disable echo */
+        AT_SEND_CMD(client, resp, "ATE0");
+
+        /* get module version */
+        AT_SEND_CMD(client, resp, "ATI");
+
+        /* show module version */
+        for (i = 0; i < (int)resp->line_counts - 1; i++)
+        {
+            LOG_D("%s", at_resp_get_line(resp, i + 1));
+        }
+        /* check SIM card */
+
+        AT_SEND_CMD(client, resp, "AT+CPIN?");
+        if (!at_resp_get_line_by_kw(resp, "READY"))
+        {
+            LOG_E("sim76xx device(%s) SIM card detection failed.", device->name);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* waiting for dirty data to be digested */
+        rt_thread_mdelay(10);
+        /* check signal strength */
+        for (i = 0; i < CSQ_RETRY; i++)
+        {
+            AT_SEND_CMD(client, resp, "AT+CSQ");
+            at_resp_parse_line_args_by_kw(resp, "+CSQ:", "+CSQ: %d,%d", &qi_arg[0], &qi_arg[1]);
+            if (qi_arg[0] != 99)
+            {
+                LOG_D("sim76xx device(%s) signal strength: %d  Channel bit error rate: %d", device->name, qi_arg[0], qi_arg[1]);
+                break;
+            }
+            rt_thread_mdelay(1000);
+        }
+
+        if (i == CSQ_RETRY)
+        {
+            LOG_E("sim76xx device(%s) signal strength check failed (%s).", device->name, parsed_data);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* do not show the prompt when receiving data */
+        AT_SEND_CMD(client, resp, "AT+CIPSRIP=0");
+
+        /* check the GSM network is registered */
+        for (i = 0; i < CREG_RETRY; i++)
+        {
+            AT_SEND_CMD(client, resp, "AT+CREG?");
+            at_resp_parse_line_args_by_kw(resp, "+CREG:", "+CREG: %s", &parsed_data);
+            if (!strncmp(parsed_data, "0,1", sizeof(parsed_data)) || !strncmp(parsed_data, "0,5", sizeof(parsed_data)))
+            {
+                LOG_D("sim76xx device(%s) GSM network is registered(%s).", device->name, parsed_data);
+                break;
+            }
+            rt_thread_mdelay(1000);
+        }
+        if (i == CREG_RETRY)
+        {
+            LOG_E("sim76xx device(%s) GSM network is register failed(%s).", device->name, parsed_data);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+        /* check the GPRS network is registered */
+        for (i = 0; i < CGREG_RETRY; i++)
+        {
+            AT_SEND_CMD(client, resp, "AT+CGREG?");
+            at_resp_parse_line_args_by_kw(resp, "+CGREG:", "+CGREG: %s", &parsed_data);
+            if (!strncmp(parsed_data, "0,1", sizeof(parsed_data)) || !strncmp(parsed_data, "0,5", sizeof(parsed_data)))
+            {
+                LOG_D("sim76xx device(%s) GPRS network is registered(%s).", device->name, parsed_data);
+                break;
+            }
+            rt_thread_mdelay(1000);
+        }
+
+        if (i == CGREG_RETRY)
+        {
+            LOG_E("sim76xx device(%s) GPRS network is register failed(%s).", device->name, parsed_data);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* check packet domain attach or detach */
+        for (i = 0; i < CGATT_RETRY; i++)
+        {
+            AT_SEND_CMD(client, resp, "AT+CGATT?");
+            at_resp_parse_line_args_by_kw(resp, "+CGATT:", "+CGATT: %s", &parsed_data);
+            if (!strncmp(parsed_data, "1", 1))
+            {
+                LOG_I("sim76xx device(%s) Packet domain attach.", device->name);
+                break;
+            }
+
+            rt_thread_mdelay(1000);
+        }
+
+        if (i == CGATT_RETRY)
+        {
+            LOG_E("sim76xx device(%s) GPRS network attach failed.", device->name);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* get real time */
+        int year, month, day, hour, min, sec;
+
+        for (i = 0; i < CCLK_RETRY; i++)
+        {
+            if (at_obj_exec_cmd(device->client, at_resp_set_info(resp, 256, 0, 5 * RT_TICK_PER_SECOND), "AT+CCLK?") < 0)
+            {
+                rt_thread_mdelay(500);
+                continue;
+            }
+
+            /* +CCLK: "18/12/22,18:33:12+32" */
+            if (at_resp_parse_line_args_by_kw(resp, "+CCLK:", "+CCLK: \"%d/%d/%d,%d:%d:%d", &year, &month, &day, &hour, &min, &sec) < 0)
+            {
+                rt_thread_mdelay(500);
+                continue;
+            }
+
+            set_date(year + 2000, month, day);
+            set_time(hour, min, sec);
+
+            break;
+        }
+
+        if (i == CCLK_RETRY)
+        {
+            LOG_E("sim76xx device(%s) GPRS network attach failed.", device->name);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* set active PDP context's profile number */
+        AT_SEND_CMD(client, resp, "AT+CSOCKSETPN=1");
+
+    __exit:
+        if (result == RT_EOK)
+        {
+            break;
+        }
+        else
+        {
+            /* power off the sim76xx device */
+            sim76xx_power_off(device);
+            rt_thread_mdelay(1000);
+
+            LOG_I("sim76xx device(%s) initialize retry...", device->name);
+        }
+    }
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    if (result == RT_EOK)
+    {
+        LOG_I("sim76xx devuce(%s) network initialize success!", device->name);
+    }
+    else
+    {
+        LOG_E("sim76xx device(%s) network initialize failed(%d)!", device->name, result);
+    }
+}
+
+int sim76xx_net_init(struct at_device *device)
+{
+#ifdef AT_DEVICE_SIM76XX_INIT_ASYN
+    rt_thread_t tid;
+
+    tid = rt_thread_create("sim76xx_net_init", sim76xx_init_thread_entry, (void *)device,
+                           SIM76XX_THREAD_STACK_SIZE, SIM76XX_THREAD_PRIORITY, 20);
+    if (tid)
+    {
+        rt_thread_startup(tid);
+    }
+    else
+    {
+        LOG_E("create sim76xx device(%s) initialization thread failed.", device->name);
+        return -RT_ERROR;
+    }
+#else
+    sim76xx_init_thread_entry(device);
+#endif /* AT_DEVICE_SIM76XX_INIT_ASYN */
+
+    return RT_EOK;
+}
+
+int sim76xx_ping(int argc, char **argv)
+{
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    if (argc != 2)
+    {
+        rt_kprintf("Please input: at_ping <host address>\n");
+        return -RT_ERROR;
+    }
+
+    device = at_device_get_first_initialized();
+    if (device == RT_NULL)
+    {
+        rt_kprintf("get first initialized sim76xx device failed.\n");
+        return -RT_ERROR;
+    }
+
+    resp = at_create_resp(64, 0, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        rt_kprintf("no memory for sim76xx device(%s) response structure.\n", device->name);
+        return -RT_ENOMEM;
+    }
+
+    if (at_obj_exec_cmd(device->client, resp, "AT+CPING=\"%s\",1,4,64,1000,10000,255", argv[1]) < 0)
+    {
+        if (resp)
+        {
+            at_delete_resp(resp);
+        }
+        rt_kprintf("sim76xx device(%s) send ping commands error.\n", device->name);
+        return -RT_ERROR;
+    }
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return RT_EOK;
+}
+
+int sim76xx_ifconfig(void)
+{
+    at_response_t resp = RT_NULL;
+    char resp_arg[AT_CMD_MAX_LEN] = {0};
+    rt_err_t result = RT_EOK;
+    struct at_device *device = RT_NULL;
+
+    device = at_device_get_first_initialized();
+    if (device == RT_NULL)
+    {
+        rt_kprintf("get first initialized sim76xx device failed.\n");
+        return -RT_ERROR;
+    }
+
+    resp = at_create_resp(128, 2, rt_tick_from_millisecond(300));
+    if (resp == RT_NULL)
+    {
+        rt_kprintf("no memory for sim76xx device(%s) response structure.\n", device->name);
+        return -RT_ENOMEM;
+    }
+
+    /* Show PDP address */
+    AT_SEND_CMD(device->client, resp, "AT+CGPADDR");
+    at_resp_parse_line_args_by_kw(resp, "+CGPADDR:", "+CGPADDR: %s", &resp_arg);
+    rt_kprintf("IP adress : %s\n", resp_arg);
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+#ifdef FINSH_USING_MSH
+#include <finsh.h>
+MSH_CMD_EXPORT_ALIAS(sim76xx_net_init, at_net_init, initialize AT network);
+MSH_CMD_EXPORT_ALIAS(sim76xx_ping, at_ping, AT ping network host);
+MSH_CMD_EXPORT_ALIAS(sim76xx_ifconfig, at_ifconfig, list the information of network interfaces);
+#endif
+
+static void urc_ping_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    static int icmp_seq = 0;
+    int i, j = 0;
+    int result, recv_len, time, ttl;
+    int sent, rcvd, lost, min, max, avg;
+    char dst_ip[16] = {0};
+
+    RT_ASSERT(data);
+
+    for (i = 0; i < size; i++)
+    {
+        if (*(data + i) == '.')
+            j++;
+    }
+    if (j != 0)
+    {
+        sscanf(data, "+CPING: %d,%[^,],%d,%d,%d", &result, dst_ip, &recv_len, &time, &ttl);
+        if (result == 1)
+            LOG_I("%d bytes from %s icmp_seq=%d ttl=%d time=%d ms", recv_len, dst_ip, icmp_seq++, ttl, time);
+    }
+    else
+    {
+        sscanf(data, "+CPING: %d,%d,%d,%d,%d,%d,%d", &result, &sent, &rcvd, &lost, &min, &max, &avg);
+        if (result == 3)
+            LOG_I("%d sent %d received %d lost, min=%dms max=%dms average=%dms", sent, rcvd, lost, min, max, avg);
+        if (result == 2)
+            LOG_I("ping requst timeout");
+    }
+}
+
+/* sim76xx device URC table for the device control */
+static struct at_urc urc_table[] = 
+{
+        {"+CPING:",        "\r\n",           urc_ping_func},
+};
+
+static int sim76xx_init(struct at_device *device)
+{
+    struct at_device_sim76xx *sim76xx = (struct at_device_sim76xx *) device->user_data;
+
+    /* initialize AT client */
+    at_client_init(sim76xx->client_name, sim76xx->recv_line_num);
+
+    device->client = at_client_get(sim76xx->client_name);
+    if (device->client == RT_NULL)
+    {
+        LOG_E("sim76xx device(%s) initialize failed, get AT client(%s) failed.", sim76xx->device_name, sim76xx->client_name);
+        return -RT_ERROR;
+    }
+
+    /* register URC data execution function  */
+    at_obj_set_urc_table(device->client, urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
+
+#ifdef AT_USING_SOCKET
+    sim76xx_socket_init(device);
+#endif
+
+    /* add sim76xx device to the netdev list */
+    device->netdev = sim76xx_netdev_add(sim76xx->device_name);
+    if (device->netdev == RT_NULL)
+    {
+        LOG_E("sim76xx device(%s) initialize failed, get network interface device failed.", sim76xx->device_name);
+        return -RT_ERROR;
+    }
+
+    /* initialize sim76xx pin configuration */
+    if (sim76xx->power_pin != -1 && sim76xx->power_status_pin != -1)
+    {
+        rt_pin_mode(sim76xx->power_pin, PIN_MODE_OUTPUT);
+        rt_pin_mode(sim76xx->power_status_pin, PIN_MODE_INPUT);
+    }
+
+    /* initialize sim76xx device network */
+    sim76xx_net_init(device);
+
+    return RT_EOK;
+}
+
+static int sim76xx_deinit(struct at_device *device)
+{
+    // TODO netdev operation
+    device->is_init = RT_FALSE;
+    return RT_EOK;
+}
+
+static int sim76xx_control(struct at_device *device, int cmd, void *arg)
+{
+    int result = -RT_ERROR;
+
+    RT_ASSERT(device);
+
+    switch (cmd)
+    {
+    case AT_DEVICE_CTRL_POWER_ON:
+    case AT_DEVICE_CTRL_POWER_OFF:
+    case AT_DEVICE_CTRL_RESET:
+    case AT_DEVICE_CTRL_LOW_POWER:
+    case AT_DEVICE_CTRL_SLEEP:
+    case AT_DEVICE_CTRL_WAKEUP:
+    case AT_DEVICE_CTRL_NET_CONN:
+    case AT_DEVICE_CTRL_NET_DISCONN:
+    case AT_DEVICE_CTRL_SET_WIFI_INFO:
+    case AT_DEVICE_CTRL_GET_SIGNAL:
+    case AT_DEVICE_CTRL_GET_GPS:
+    case AT_DEVICE_CTRL_GET_VER:
+        LOG_W("sim76xx not support the control command(%d).", cmd);
+        break;
+    default:
+        LOG_E("input error control command(%d).", cmd);
+        break;
+    }
+
+    return result;
+}
+
+const struct at_device_ops sim76xx_device_ops =
+{
+    sim76xx_init,
+    sim76xx_deinit,
+    sim76xx_control,
+};
+
+static int sim76xx_device_class_register(void)
+{
+    struct at_device_class *class = RT_NULL;
+
+    class = (struct at_device_class *)rt_calloc(1, sizeof(struct at_device_class));
+    if (class == RT_NULL)
+    {
+        LOG_E("no memory for sim76xx device class create.");
+        return -RT_ENOMEM;
+    }
+
+    /* fill sim76xx device class object */
+#ifdef AT_USING_SOCKET
+    sim76xx_socket_class_register(class);
+#endif
+    class->device_ops = &sim76xx_device_ops;
+
+    return at_device_class_register(class, AT_DEVICE_CLASS_SIM76XX);
+}
+INIT_DEVICE_EXPORT(sim76xx_device_class_register);
+
+#endif /* AT_DEVICE_SIM76XX */

+ 66 - 0
class/sim76xx/at_device_sim76xx.h

@@ -0,0 +1,66 @@
+/*
+ * File      : at_device_sim76xx.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-05-16     chenyong     first version
+ */
+
+#ifndef __AT_DEVICE_SIM76XX_H__
+#define __AT_DEVICE_SIM76XX_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+
+#include <at_device.h>
+
+/* The maximum number of sockets supported by the sim76xx device */
+#define AT_DEVICE_SIM76XX_SOCKETS_NUM      10
+
+struct at_device_sim76xx
+{     
+    char *device_name;
+    char *client_name;
+
+    int power_pin;
+    int power_status_pin;
+    size_t recv_line_num;
+    struct at_device device;
+
+    void *user_data;
+};
+
+#ifdef AT_USING_SOCKET
+
+/* sim76xx device socket initialize */
+int sim76xx_socket_init(struct at_device *device);
+
+/* sim76xx device class socket register */
+int sim76xx_socket_class_register(struct at_device_class *class);
+
+#endif /* AT_USING_SOCKET */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AT_DEVICE_SIM76XX_H__ */

+ 882 - 0
class/sim76xx/at_socket_sim76xx.c

@@ -0,0 +1,882 @@
+/*
+ * File      : at_socket_sim76xx.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-12-22    thomasonegd  first version
+ * 2019-03-06    thomasonegd  fix udp connection.
+ * 2019-03-08    thomasonegd  add power_on & power_off api
+ * 2019-05-14    chenyong     multi AT socket client support
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <at_device_sim76xx.h>
+
+#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10300
+#error "This AT Client version is older, please check and update latest AT Client!"
+#endif
+
+#define LOG_TAG                        "at.skt"
+#include <at_log.h>
+
+#ifdef AT_DEVICE_USING_SIM76XX
+
+#define SIM76XX_MODULE_SEND_MAX_SIZE   1500
+#define SIM76XX_MAX_CONNECTIONS        10
+
+/* set real event by current socket and current state */
+#define SET_EVENT(socket, event)       (((socket + 1) << 16) | (event))
+
+/* AT socket event type */
+#define SIM76XX_EVENT_CONN_OK          (1L << 0)
+#define SIM76XX_EVENT_SEND_OK          (1L << 1)
+#define SIM76XX_EVENT_RECV_OK          (1L << 2)
+#define SIM76XX_EVNET_CLOSE_OK         (1L << 3)
+#define SIM76XX_EVENT_CONN_FAIL        (1L << 4)
+#define SIM76XX_EVENT_SEND_FAIL        (1L << 5)
+
+static at_evt_cb_t at_evt_cb_set[] = 
+{
+    [AT_SOCKET_EVT_RECV] = NULL,
+    [AT_SOCKET_EVT_CLOSED] = NULL,
+};
+
+static char udp_ipstr[SIM76XX_MAX_CONNECTIONS][16];
+static int udp_port[SIM76XX_MAX_CONNECTIONS];
+
+/* unsolicited TCP/IP command<err> codes */
+static void at_tcp_ip_errcode_parse(int result) 
+{
+    switch(result)
+    {
+    case 0   : LOG_D("%d : operation succeeded ",           result); break;
+    case 1 : LOG_E("%d : UNetwork failure",                 result); break;
+    case 2 : LOG_E("%d : Network not opened",               result); break;
+    case 3 : LOG_E("%d : Wrong parameter",                  result); break;
+    case 4 : LOG_E("%d : Operation not supported",          result); break;
+    case 5 : LOG_E("%d : Failed to create socket",          result); break;
+    case 6 : LOG_E("%d : Failed to bind socket",            result); break;
+    case 7 : LOG_E("%d : TCP server is already listening",  result); break;
+    case 8 : LOG_E("%d : Busy",                             result); break;
+    case 9 : LOG_E("%d : Sockets opened",                   result); break;
+    case 10 : LOG_E("%d : Timeout ",                        result); break;
+    case 11 : LOG_E("%d : DNS parse failed for AT+CIPOPEN", result); break;
+    case 255 : LOG_E("%d : Unknown error",                  result); break;
+    }
+}
+
+static int sim76xx_socket_event_send(struct at_device *device, uint32_t event)
+{
+    return (int)rt_event_send(device->socket_event, event);
+}
+
+static int sim76xx_socket_event_recv(struct at_device *device, uint32_t event, uint32_t timeout, rt_uint8_t option)
+{
+    int result = RT_EOK;
+    rt_uint32_t recved;
+
+    result = rt_event_recv(device->socket_event, event, option | RT_EVENT_FLAG_CLEAR, timeout, &recved);
+    if (result != RT_EOK)
+    {
+        return -RT_ETIMEOUT;
+    }
+
+    return recved;
+}
+
+/**
+ * close socket by AT commands.
+ *
+ * @param current socket
+ *
+ * @return  0: close socket success
+ *         -1: send AT commands error
+ *         -2: wait socket event timeout
+ *         -5: no memory
+ */
+static int sim76xx_socket_close(struct at_socket *socket)
+{
+    int result = RT_EOK;
+    int activated = 0;
+    uint8_t lnk_stat[10] = {0};
+    at_response_t resp = RT_NULL;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+
+    resp = at_create_resp(64, 0, RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for sim76xx device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    rt_thread_mdelay(100);
+
+    /* check socket link_state */
+    if (at_obj_exec_cmd(device->client, resp, "AT+CIPCLOSE?") < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    if (at_resp_parse_line_args_by_kw(resp, "+CIPCLOSE:", "+CIPCLOSE: %d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+                                      &lnk_stat[0], &lnk_stat[1], &lnk_stat[1], &lnk_stat[2], &lnk_stat[3], &lnk_stat[4],
+                                      &lnk_stat[5], &lnk_stat[6], &lnk_stat[7], &lnk_stat[8], &lnk_stat[9]) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    if (lnk_stat[device_socket])
+    {
+        /* close tcp or udp socket if connected */
+        if (at_obj_exec_cmd(device->client, resp, "AT+CIPCLOSE=%d", device_socket) < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+    }
+    /* check the network open or not */
+    if (at_obj_exec_cmd(device->client, resp, "AT+NETOPEN?") < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    if (at_resp_parse_line_args_by_kw(resp, "+NETOPEN:", "+NETOPEN: %d", &activated) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    if (activated)
+    {
+        /* if already open,then close it */
+        if (at_obj_exec_cmd(device->client, resp, "AT+NETCLOSE") < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+    }
+
+ __exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+/**
+ * open packet network
+ */
+static int sim76xx_network_socket_open(struct at_socket *socket)
+{
+    int result = RT_EOK, activated = 0;
+    at_response_t resp = RT_NULL;
+    struct at_device *device = (struct at_device *) socket->device;
+
+    resp = at_create_resp(128, 0, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for sim76xx device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    /* check the network open or not */
+    if (at_obj_exec_cmd(device->client, resp, "AT+NETOPEN?") < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    if (at_resp_parse_line_args_by_kw(resp, "+NETOPEN:", "+NETOPEN: %d", &activated) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    if (activated)
+    {
+        /* network socket is already opened */
+        goto __exit;
+    }
+    else
+    {
+        /* if not opened the open it */
+        if (at_obj_exec_cmd(device->client, resp, "AT+NETOPEN") < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+/**
+ * create TCP/UDP client or server connect by AT commands.
+ *
+ * @param socket current socket
+ * @param ip server or client IP address
+ * @param port server or client port
+ * @param type connect socket type(tcp, udp)
+ * @param is_client connection is client
+ *
+ * @return   0: connect success
+ *          -1: connect failed, send commands error or type error
+ *          -2: wait socket event timeout
+ *          -5: no memory
+ */
+static int sim76xx_socket_connect(struct at_socket *socket, char *ip, int32_t port, enum at_socket_type type, rt_bool_t is_client)
+{
+    int result = RT_EOK, event_result = 0;
+    rt_bool_t retryed = RT_FALSE;
+    at_response_t resp = RT_NULL;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+    rt_mutex_t lock = device->client->lock;
+
+    RT_ASSERT(ip);
+    RT_ASSERT(port >= 0);
+
+    resp = at_create_resp(128, 0, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for sim76xx device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    rt_mutex_take(lock, RT_WAITING_FOREVER);
+
+__retry:
+    if (is_client)
+    {
+        /* open network socket first(AT+NETOPEN) */
+        sim76xx_network_socket_open(socket);
+
+        switch (type)
+        {
+        case AT_SOCKET_TCP:
+            /* send AT commands to connect TCP server */
+            if (at_obj_exec_cmd(device->client, resp, "AT+CIPOPEN=%d,\"TCP\",\"%s\",%d", device_socket, ip, port) < 0)
+            {
+                result = -RT_ERROR;
+            }
+            break;
+
+        case AT_SOCKET_UDP:
+            if (at_obj_exec_cmd(device->client, resp, "AT+CIPOPEN=%d,\"UDP\",,,%d", device_socket, port) < 0)
+            {
+                result = -RT_ERROR;
+            }
+            strcpy(udp_ipstr[device_socket], ip);
+            udp_port[device_socket] = port;
+            break;
+
+        default:
+            LOG_E("Not supported connect type : %d.", type);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+    }
+
+    /* waiting result event from AT URC, the device default connection timeout is 75 seconds, but it set to 10 seconds is convenient to use.*/
+    if (sim76xx_socket_event_recv(device, SET_EVENT(device_socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
+    {
+        LOG_E("sim76xx device(%s) socket(%d) connect failed, wait connect result timeout.", device->name, device_socket);
+        result = -RT_ETIMEOUT;
+        goto __exit;
+    }
+    /* waiting OK or failed result */
+    event_result = sim76xx_socket_event_recv(device, SIM76XX_EVENT_CONN_OK | SIM76XX_EVENT_CONN_FAIL,
+                                        1 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR);
+    if (event_result < 0)
+    {
+        LOG_E("sim76xx device(%s) socket(%d) connect failed, wait connect OK|FAIL timeout.", device->name, socket);
+        result = -RT_ETIMEOUT;
+        goto __exit;
+    }
+    /* check result */
+    if (event_result & SIM76XX_EVENT_CONN_FAIL)
+    {
+        if (!retryed)
+        {
+            LOG_E("socket (%d) connect failed, maybe the socket was not be closed at the last time and now will retry.", socket);
+            if (sim76xx_socket_close(socket) < 0)
+            {
+			    result = -RT_ERROR;
+                goto __exit;
+            }
+            retryed = RT_TRUE;
+            goto __retry;
+        }
+        LOG_E("socket (%d) connect failed, failed to establish a connection.", socket);
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    if (result != RT_EOK && !retryed)
+    {
+        LOG_D("socket (%d) connect failed, maybe the socket was not be closed at the last time and now will retry.", socket);
+        if (sim76xx_socket_close(socket) < 0)
+        {
+            goto __exit;
+        }
+        retryed = RT_TRUE;
+        result = RT_EOK;
+        goto __retry;
+    }
+
+__exit:
+    rt_mutex_release(lock);
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+/**
+ * send data to server or client by AT commands.
+ *
+ * @param socket current socket
+ * @param buff send buffer
+ * @param bfsz send buffer size
+ * @param type connect socket type(tcp, udp)
+ *
+ * @return >=0: the size of send success
+ *          -1: send AT commands error or send data error
+ *          -2: waited socket event timeout
+ *          -5: no memory
+ */
+static int sim76xx_socket_send(struct at_socket *socket, const char *buff, size_t bfsz, enum at_socket_type type)
+{
+    int result = RT_EOK;
+    int event_result = 0;
+    size_t cur_pkt_size = 0, sent_size = 0;
+    at_response_t resp = RT_NULL;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+    struct at_device_sim76xx *sim76xx = (struct at_device_sim76xx *) device->user_data;
+    rt_mutex_t lock = device->client->lock;
+
+    RT_ASSERT(buff);
+    RT_ASSERT(bfsz > 0);
+
+    resp = at_create_resp(128, 2, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for sim76xx device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    rt_mutex_take(lock, RT_WAITING_FOREVER);
+
+    /* set current socket for send URC event */
+    sim76xx->user_data = (void *) device_socket;
+    /* set AT client end sign to deal with '>' sign.*/
+    at_obj_set_end_sign(device->client, '>');
+
+    while (sent_size < bfsz)
+    {
+        if (bfsz - sent_size < SIM76XX_MODULE_SEND_MAX_SIZE)
+        {
+            cur_pkt_size = bfsz - sent_size;
+        }
+        else
+        {
+            cur_pkt_size = SIM76XX_MODULE_SEND_MAX_SIZE;
+        }
+        
+        switch (socket->type)
+        {
+        case AT_SOCKET_TCP:
+            /* send the "AT+CIPSEND" commands to AT server than receive the '>' response on the first line. */
+            if (at_obj_exec_cmd(device->client,  resp, "AT+CIPSEND=%d,%d", device_socket, cur_pkt_size) < 0)
+            {
+                result = -RT_ERROR;
+                goto __exit;
+            }
+            break;
+        case AT_SOCKET_UDP:
+            /* send the "AT+CIPSEND" commands to AT server than receive the '>' response on the first line. */
+            if (at_obj_exec_cmd(device->client,  resp, "AT+CIPSEND=%d,%d,\"%s\",%d", 
+                    device_socket, cur_pkt_size, udp_ipstr[device_socket], udp_port[device_socket]) < 0)
+            {
+                result = -RT_ERROR;
+                goto __exit;
+            }
+            break;
+        }
+        
+        /* send the real data to server or client */
+        result = (int) at_client_send(buff + sent_size, cur_pkt_size);
+        if (result == 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* waiting result event from AT URC */
+        if (sim76xx_socket_event_recv(device, SET_EVENT(device_socket, 0), 5 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
+        {
+            LOG_E("sim76xx device(%s) socket (%d) send failed, wait connect result timeout.", device->name, device_socket);
+            result = -RT_ETIMEOUT;
+            goto __exit;
+        }
+        /* waiting OK or failed result */
+        event_result = sim76xx_socket_event_recv(device, SIM76XX_EVENT_SEND_OK | SIM76XX_EVENT_SEND_FAIL,
+                                                 5 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR);
+        if (event_result < 0)
+        {
+            LOG_E("sim76xx device(%s) socket(%d) send failed, wait connect OK|FAIL timeout.", device->name, device_socket);
+            result = -RT_ETIMEOUT;
+            goto __exit;
+        }
+        /* check result */
+        if (event_result & SIM76XX_EVENT_SEND_FAIL)
+        {
+            LOG_E("sim76xx device(%s) socket(%d) send failed.", device->name, device_socket);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        if (type == AT_SOCKET_TCP)
+        {
+            //cur_pkt_size = cur_send_bfsz;
+        }
+
+        sent_size += cur_pkt_size;
+    }
+
+__exit:
+    /* reset the end sign for data */
+    at_obj_set_end_sign(device->client, 0);
+
+    rt_mutex_release(lock);
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+/**
+ * domain resolve by AT commands.
+ *
+ * @param name domain name
+ * @param ip parsed IP address, it's length must be 16
+ *
+ * @return  0: domain resolve success
+ *         -2: wait socket event timeout
+ *         -5: no memory
+ */
+static int sim76xx_domain_resolve(const char *name, char ip[16])
+{
+#define RESOLVE_RETRY        5
+
+    int i, result = RT_EOK;
+    char domain[32] = {0};
+    char domain_ip[16] = {0};
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    RT_ASSERT(name);
+    RT_ASSERT(ip);
+
+    device = at_device_get_first_initialized();
+    if (device == RT_NULL)
+    {
+        LOG_E("get first initialized sim76xx device failed.");
+        return -RT_ERROR;
+    }
+
+    resp = at_create_resp(128, 0, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for sim76xx device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    for (i = 0; i < RESOLVE_RETRY; i++)
+    {
+        if (at_obj_exec_cmd(device->client, resp, "AT+CDNSGIP=\"%s\"", name) < 0)
+        {
+            rt_thread_mdelay(200);
+            /* resolve failed, maybe receive an URC CRLF */
+            continue;
+        }
+
+        /* parse the third line of response data, get the IP address */
+        /* +CDNSGIP: 1,"www.baidu.com","14.215.177.39" */
+        if (at_resp_parse_line_args_by_kw(resp, "+CDNSGIP:", "+CDNSGIP: 1,%[^,],\"%[^\"]", domain, domain_ip) < 0)
+        {
+            rt_thread_mdelay(200);
+            /* resolve failed, maybe receive an URC CRLF */
+            continue;
+        }
+
+        if (rt_strlen(domain_ip) < 8)
+        {
+            rt_thread_mdelay(200);
+            /* resolve failed, maybe receive an URC CRLF */
+            continue;
+        }
+        else
+        {
+            rt_strncpy(ip, domain_ip, 15);
+            ip[15] = '\0';
+            break;
+        }
+    }
+
+    if (i == RESOLVE_RETRY)
+    {
+        result = -RT_ERROR;
+    }
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+/**
+ * set AT socket event notice callback
+ *
+ * @param event notice event
+ * @param cb notice callback
+ */
+static void sim76xx_socket_set_event_cb(at_socket_evt_t event, at_evt_cb_t cb)
+{
+    if (event < (sizeof(at_evt_cb_set) / sizeof(at_evt_cb_set[1])))
+    {
+        at_evt_cb_set[event] = cb;
+    }
+}
+
+static void urc_send_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0, rqst_size, cnf_size;
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get sim76xx device by client name(%s) failed.", client_name);
+        return;
+    }
+
+    sscanf(data, "+CIPSEND: %d,%d,%d", &device_socket, &rqst_size, &cnf_size);
+
+    //cur_send_bfsz = cnf_size;
+
+    sim76xx_socket_event_send(device, SET_EVENT(device_socket, SIM76XX_EVENT_SEND_OK));
+}
+
+static void urc_ping_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    static int icmp_seq = 0;
+    int i, j = 0;
+    int result, recv_len, time, ttl;
+    int sent, rcvd, lost, min, max, avg;
+    char dst_ip[16] = {0};
+
+    RT_ASSERT(data);
+
+    for (i = 0; i < size; i++)
+    {
+        if (*(data + i) == '.')
+            j++;
+    }
+    if (j != 0)
+    {
+        sscanf(data, "+CPING: %d,%[^,],%d,%d,%d", &result, dst_ip, &recv_len, &time, &ttl);
+        if (result == 1)
+            LOG_I("%d bytes from %s icmp_seq=%d ttl=%d time=%d ms", recv_len, dst_ip, icmp_seq++, ttl, time);
+    }
+    else
+    {
+        sscanf(data, "+CPING: %d,%d,%d,%d,%d,%d,%d", &result, &sent, &rcvd, &lost, &min, &max, &avg);
+        if (result == 3)
+            LOG_I("%d sent %d received %d lost, min=%dms max=%dms average=%dms", sent, rcvd, lost, min, max, avg);
+        if (result == 2)
+            LOG_I("ping requst timeout");
+    }
+}
+
+static void urc_connect_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0, result = 0;
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get sim76xx device by client name(%s) failed.", client_name);
+        return;
+    }
+
+    sscanf(data, "+CIPOPEN: %d,%d", &device_socket, &result);
+
+    if (result == 0)
+    {
+        sim76xx_socket_event_send(device, SET_EVENT(device_socket, SIM76XX_EVENT_CONN_OK));
+    }
+    else
+    {
+        at_tcp_ip_errcode_parse(result);
+        sim76xx_socket_event_send(device, SET_EVENT(device_socket, SIM76XX_EVENT_CONN_FAIL));
+    }
+}
+
+static void urc_close_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0, reason = 0;
+    struct at_socket *socket = RT_NULL;
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get sim76xx device by client name(%s) failed.", device->name);
+        return;
+    }
+
+    sscanf(data, "+IPCLOSE %d,%d", &device_socket, &reason);
+
+    switch (reason)
+    {
+    case 0:
+        LOG_E("socket is closed by local,active");
+        break;
+    case 1:
+        LOG_E("socket is closed by remote,passive");
+        break;
+    case 2:
+        LOG_E("socket is closed for sending timeout");
+        break;
+    }
+
+    /* get AT socket object by device socket descriptor */
+    socket = &(device->sockets[device_socket]);
+
+    /* notice the socket is disconnect by remote */
+    if (at_evt_cb_set[AT_SOCKET_EVT_CLOSED])
+    {
+        at_evt_cb_set[AT_SOCKET_EVT_CLOSED](socket, AT_SOCKET_EVT_CLOSED, RT_NULL, 0);
+    }
+}
+
+static void urc_recv_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    rt_size_t bfsz = 0, temp_size = 0;
+    rt_int32_t timeout;
+    char *recv_buf = RT_NULL, temp[8] = {0};
+    int device_socket = 0;
+    struct at_socket *socket = RT_NULL;
+    struct at_device *device = RT_NULL;
+    struct at_device_sim76xx *sim76xx = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get sim76xx device by client name(%s) failed.", client_name);
+        return;
+    }
+    sim76xx = (struct at_device_sim76xx *) device->user_data;
+    device_socket = (int) sim76xx->user_data;
+
+    /* get the current socket and receive buffer size by receive data */
+    sscanf(data, "+IPD%d:", (int *)&bfsz);
+    /* get receive timeout by receive buffer length */
+    timeout = bfsz * 10;
+
+    if (bfsz == 0)
+        return;
+
+    recv_buf = (char *) rt_calloc(1, bfsz);
+    if (recv_buf == RT_NULL)
+    {
+        LOG_E("no memory for sim76xx device(%s) URC receive buffer(%d).", device->name, bfsz);
+        /* read and clean the coming data */
+        while (temp_size < bfsz)
+        {
+            if (bfsz - temp_size > sizeof(temp))
+
+
+            {
+                at_client_obj_recv(client, temp, sizeof(temp), timeout);
+            }
+            else
+            {
+                at_client_obj_recv(client, temp, bfsz - temp_size, timeout);
+            }
+            temp_size += sizeof(temp);
+        }
+        return;
+    }
+
+    /* sync receive data */
+    if (at_client_obj_recv(client, recv_buf, bfsz, timeout) != bfsz)
+    {
+        LOG_E("sim76xx device(%s) receive size(%d) data failed.", device->name, bfsz);
+        rt_free(recv_buf);
+        return;
+    }
+
+    /* get AT socket object by device socket descriptor */
+    socket = &(device->sockets[device_socket]);
+
+    /* notice the receive buffer and buffer size */
+    if (at_evt_cb_set[AT_SOCKET_EVT_RECV])
+    {
+        at_evt_cb_set[AT_SOCKET_EVT_RECV](socket, AT_SOCKET_EVT_RECV, recv_buf, bfsz);
+    }
+}
+
+static struct at_urc urc_table[] = 
+{
+    {"+CIPSEND:",      "\r\n",           urc_send_func},
+    {"+CIPOPEN:",      "\r\n",           urc_connect_func},
+    {"+CPING:",        "\r\n",           urc_ping_func},
+    {"+IPCLOSE",       "\r\n",           urc_close_func},
+    {"+IPD",           "\r\n",           urc_recv_func},
+};
+
+int sim76xx_connect(int argc, char **argv)
+{
+    int32_t port;
+
+    if (argc != 3)
+    {
+        rt_kprintf("Please input: at_connect <host address>\n");
+        return -RT_ERROR;
+    }
+    sscanf(argv[2], "%d", &port);
+    sim76xx_socket_connect(at_get_socket(0), argv[1], port, AT_SOCKET_TCP, 1);
+
+    return RT_EOK;
+}
+
+int sim76xx_close(int argc, char **argv)
+{
+    if (sim76xx_socket_close(at_get_socket(0)) < 0)
+    {
+        rt_kprintf("sim76xx_socket_close fail\n");
+    }
+    else
+    {
+        rt_kprintf("sim76xx_socket_closeed\n");
+    }
+    return RT_EOK;
+}
+
+int sim76xx_send(int argc, char **argv)
+{
+    const char *buff = "1234567890\n";
+    if (sim76xx_socket_send(at_get_socket(0), buff, 11, AT_SOCKET_TCP) < 0)
+    {
+        rt_kprintf("sim76xx_socket_send fail\n");
+    }
+
+    return RT_EOK;
+}
+
+int sim76xx_domain(int argc, char **argv)
+{
+    char ip[16];
+    if (sim76xx_domain_resolve("www.baidu.com", ip) < 0)
+    {
+        rt_kprintf("sim76xx_socket_send fail\n");
+    }
+    else
+    {
+        rt_kprintf("baidu.com : %s\n", ip);
+    }
+
+    return RT_EOK;
+}
+
+#ifdef FINSH_USING_MSH
+#include <finsh.h>
+MSH_CMD_EXPORT_ALIAS(sim76xx_connect, at_connect, AT connect network host);
+MSH_CMD_EXPORT_ALIAS(sim76xx_close, at_close, AT close a socket);
+MSH_CMD_EXPORT_ALIAS(sim76xx_send, at_send, AT send a pack);
+MSH_CMD_EXPORT_ALIAS(sim76xx_domain, at_domain, AT domain resolve);
+#endif
+
+static const struct at_socket_ops sim76xx_socket_ops = 
+{
+    sim76xx_socket_connect,
+    sim76xx_socket_close,
+    sim76xx_socket_send,
+    sim76xx_domain_resolve,
+    sim76xx_socket_set_event_cb,
+};
+
+int sim76xx_socket_init(struct at_device *device)
+{
+    RT_ASSERT(device);
+
+    /* register URC data execution function  */
+    at_obj_set_urc_table(device->client, urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
+
+    return RT_EOK;
+}
+
+int sim76xx_socket_class_register(struct at_device_class *class)
+{
+    RT_ASSERT(class);
+
+    class->socket_num = AT_DEVICE_SIM76XX_SOCKETS_NUM;
+    class->socket_ops = &sim76xx_socket_ops;
+
+    return RT_EOK;
+}
+
+#endif /* AT_DEVICE_SIM76XX */

+ 971 - 0
class/sim800c/at_device_sim800c.c

@@ -0,0 +1,971 @@
+/*
+ * File      : at_socket_sim800c.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-06-12     malongwei    first version
+ * 2019-05-13     chenyong     multi AT socket client support
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <at_device_sim800c.h>
+
+#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10200
+#error "This AT Client version is older, please check and update latest AT Client!"
+#endif
+
+#define LOG_TAG                        "at.dev"
+#include <at_log.h>
+
+#ifdef AT_DEVICE_USING_SIM800C
+
+#define SIM800C_WAIT_CONNECT_TIME      5000
+#define SIM800C_THREAD_STACK_SIZE      1024
+#define SIM800C_THREAD_PRIORITY        (RT_THREAD_PRIORITY_MAX/2)
+
+/* AT+CSTT command default*/
+static char *CSTT_CHINA_MOBILE  = "AT+CSTT=\"CMNET\"";
+static char *CSTT_CHINA_UNICOM  = "AT+CSTT=\"UNINET\"";
+static char *CSTT_CHINA_TELECOM = "AT+CSTT=\"CTNET\"";
+
+static void sim800c_power_on(struct at_device *device)
+{
+    struct at_device_sim800c *sim800c = RT_NULL;
+
+    sim800c = (struct at_device_sim800c *) device->user_data;
+
+    /* not nead to set pin configuration for m26 device power on */
+    if (sim800c->power_pin == -1 || sim800c->power_status_pin == -1)
+    {
+        return;
+    }
+
+    if (rt_pin_read(sim800c->power_status_pin) == PIN_HIGH)
+    {
+        return;
+    }
+    rt_pin_write(sim800c->power_pin, PIN_HIGH);
+
+    while (rt_pin_read(sim800c->power_status_pin) == PIN_LOW)
+    {
+        rt_thread_mdelay(10);
+    }
+    rt_pin_write(sim800c->power_pin, PIN_LOW);
+}
+
+static void sim800c_power_off(struct at_device *device)
+{
+    struct at_device_sim800c *sim800c = RT_NULL;
+
+    sim800c = (struct at_device_sim800c *) device->user_data;
+
+    /* not nead to set pin configuration for m26 device power on */
+    if (sim800c->power_pin == -1 || sim800c->power_status_pin == -1)
+    {
+        return;
+    }
+
+    if (rt_pin_read(sim800c->power_status_pin) == PIN_LOW)
+    {
+        return;
+    }
+    rt_pin_write(sim800c->power_pin, PIN_HIGH);
+
+    while (rt_pin_read(sim800c->power_status_pin) == PIN_HIGH)
+    {
+        rt_thread_mdelay(10);
+    }
+    rt_pin_write(sim800c->power_pin, PIN_LOW);
+}
+
+/* =============================  sim76xx network interface operations ============================= */
+
+/* set sim800c network interface device status and address information */
+static int sim800c_netdev_set_info(struct netdev *netdev)
+{
+#define SIM800C_IEMI_RESP_SIZE      32
+#define SIM800C_IPADDR_RESP_SIZE    32
+#define SIM800C_DNS_RESP_SIZE       96
+#define SIM800C_INFO_RESP_TIMO      rt_tick_from_millisecond(300)
+
+    int result = RT_EOK;
+    ip_addr_t addr;
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    if (netdev == RT_NULL)
+    {
+        LOG_E("input network interface device is NULL.");
+        return -RT_ERROR;
+    }
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get sim800c device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+
+    /* set network interface device status */
+    netdev_low_level_set_status(netdev, RT_TRUE);
+    netdev_low_level_set_link_status(netdev, RT_TRUE);
+    netdev_low_level_set_dhcp_status(netdev, RT_TRUE);
+
+    resp = at_create_resp(SIM800C_IEMI_RESP_SIZE, 0, SIM800C_INFO_RESP_TIMO);
+    if (resp == RT_NULL)
+    {
+        LOG_E("sim800c device(%s) set IP address failed, no memory for response object.", device->name);
+        result = -RT_ENOMEM;
+        goto __exit;
+    }
+
+    /* set network interface device hardware address(IEMI) */
+    {
+        #define SIM800C_NETDEV_HWADDR_LEN   8
+        #define SIM800C_IEMI_LEN            15
+
+        char iemi[SIM800C_IEMI_LEN] = {0};
+        int i = 0, j = 0;
+
+        /* send "AT+GSN" commond to get device IEMI */
+        if (at_obj_exec_cmd(device->client, resp, "AT+GSN") < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        if (at_resp_parse_line_args(resp, 2, "%s", iemi) <= 0)
+        {
+            LOG_E("sim800c device(%s) prase \"AT+GSN\" commands resposne data error.", device->name);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        LOG_D("sim800c device(%s) IEMI number: %s", device->name, iemi);
+
+        netdev->hwaddr_len = SIM800C_NETDEV_HWADDR_LEN;
+        /* get hardware address by IEMI */
+        for (i = 0, j = 0; i < SIM800C_NETDEV_HWADDR_LEN && j < SIM800C_IEMI_LEN; i++, j += 2)
+        {
+            if (j != SIM800C_IEMI_LEN - 1)
+            {
+                netdev->hwaddr[i] = (iemi[j] - '0') * 10 + (iemi[j + 1] - '0');
+            }
+            else
+            {
+                netdev->hwaddr[i] = (iemi[j] - '0');
+            }
+        }
+    }
+
+    /* set network interface device IP address */
+    {
+        #define IP_ADDR_SIZE_MAX    16
+        char ipaddr[IP_ADDR_SIZE_MAX] = {0};
+
+        at_resp_set_info(resp, SIM800C_IPADDR_RESP_SIZE, 2, SIM800C_INFO_RESP_TIMO);
+
+        /* send "AT+CIFSR" commond to get IP address */
+        if (at_obj_exec_cmd(device->client, resp, "AT+CIFSR") < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        if (at_resp_parse_line_args_by_kw(resp, ".", "%s", ipaddr) <= 0)
+        {
+            LOG_E("sim800c device(%s) prase \"AT+CIFSR\" commands resposne data error!", device->name);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        LOG_D("sim800c device(%s) IP address: %s", device->name, ipaddr);
+
+        /* set network interface address information */
+        inet_aton(ipaddr, &addr);
+        netdev_low_level_set_ipaddr(netdev, &addr);
+    }
+
+    /* set network interface device dns server */
+    {
+        #define DNS_ADDR_SIZE_MAX   16
+        char dns_server1[DNS_ADDR_SIZE_MAX] = {0}, dns_server2[DNS_ADDR_SIZE_MAX] = {0};
+
+        at_resp_set_info(resp, SIM800C_DNS_RESP_SIZE, 0, SIM800C_INFO_RESP_TIMO);
+
+        /* send "AT+CDNSCFG?" commond to get DNS servers address */
+        if (at_obj_exec_cmd(device->client, resp, "AT+CDNSCFG?") < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        if (at_resp_parse_line_args_by_kw(resp, "PrimaryDns:", "PrimaryDns:%s", dns_server1) <= 0 ||
+            at_resp_parse_line_args_by_kw(resp, "SecondaryDns:", "SecondaryDns:%s", dns_server2) <= 0)
+        {
+            LOG_E("Prase \"AT+CDNSCFG?\" commands resposne data error!");
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        LOG_D("sim800c device(%s) primary DNS server address: %s", device->name, dns_server1);
+        LOG_D("sim800c device(%s) secondary DNS server address: %s", device->name, dns_server2);
+
+        inet_aton(dns_server1, &addr);
+        netdev_low_level_set_dns_server(netdev, 0, &addr);
+
+        inet_aton(dns_server2, &addr);
+        netdev_low_level_set_dns_server(netdev, 1, &addr);
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+    
+    return result;
+}
+
+static void check_link_status_entry(void *parameter)
+{
+#define SIM800C_LINK_STATUS_OK   1
+#define SIM800C_LINK_RESP_SIZE   64
+#define SIM800C_LINK_RESP_TIMO   (3 * RT_TICK_PER_SECOND)
+#define SIM800C_LINK_DELAY_TIME  (30 * RT_TICK_PER_SECOND)
+
+    at_response_t resp = RT_NULL;
+    int result_code, link_status;
+    struct at_device *device = RT_NULL;
+    struct netdev *netdev = (struct netdev *)parameter;
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get sim800c device by netdev name(%s) failed.", netdev->name);
+        return;
+    }
+
+    resp = at_create_resp(SIM800C_LINK_RESP_SIZE, 0, SIM800C_LINK_RESP_TIMO);
+    if (resp == RT_NULL)
+    {
+        LOG_E("sim800c device(%s) set check link status failed, no memory for response object.", device->name);
+        return;
+    }
+
+    while (1)
+    {
+        /* send "AT+CGREG?" commond  to check netweork interface device link status */
+        if (at_obj_exec_cmd(device->client, resp, "AT+CGREG?") < 0)
+        {
+            rt_thread_mdelay(SIM800C_LINK_DELAY_TIME);
+
+            continue;
+        }
+
+        link_status = -1;
+        at_resp_parse_line_args_by_kw(resp, "+CGREG:", "+CGREG: %d,%d", &result_code, &link_status);
+
+        /* check the network interface device link status  */
+        if ((SIM800C_LINK_STATUS_OK == link_status) != netdev_is_link_up(netdev))
+        {
+            netdev_low_level_set_link_status(netdev, (SIM800C_LINK_STATUS_OK == link_status));
+        }
+
+        rt_thread_mdelay(SIM800C_LINK_DELAY_TIME);
+    }
+}
+
+static int sim800c_netdev_check_link_status(struct netdev *netdev)
+{
+#define SIM800C_LINK_THREAD_TICK           20
+#define SIM800C_LINK_THREAD_STACK_SIZE     512
+#define SIM800C_LINK_THREAD_PRIORITY       (RT_THREAD_PRIORITY_MAX - 2)
+
+    rt_thread_t tid;
+    char tname[RT_NAME_MAX] = {0};
+
+    if (netdev == RT_NULL)
+    {
+        LOG_E("input network interface device is NULL.\n");
+        return -RT_ERROR;
+    }
+
+    rt_snprintf(tname, RT_NAME_MAX, "%s_link", netdev->name);
+
+    tid = rt_thread_create(tname, check_link_status_entry, (void *) netdev, 
+            SIM800C_LINK_THREAD_STACK_SIZE, SIM800C_LINK_THREAD_PRIORITY, SIM800C_LINK_THREAD_TICK);
+    if (tid)
+    {
+        rt_thread_startup(tid);
+    }
+
+    return RT_EOK;
+}
+
+static int sim800c_net_init(struct at_device *device);
+
+static int sim800c_netdev_set_up(struct netdev *netdev)
+{
+    struct at_device *device = RT_NULL;
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get sim800c device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+
+    if (device->is_init == RT_FALSE)
+    {
+        sim800c_net_init(device);
+        device->is_init = RT_TRUE;
+
+        netdev_low_level_set_status(netdev, RT_TRUE);
+        LOG_D("the network interface device(%s) set up status.", netdev->name);
+    }
+
+    return RT_EOK;
+}
+
+static int sim800c_netdev_set_down(struct netdev *netdev)
+{
+    struct at_device *device = RT_NULL;
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get sim800c device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+
+    if (device->is_init == RT_TRUE)
+    {
+        sim800c_power_off(device);
+        device->is_init = RT_FALSE;
+
+        netdev_low_level_set_status(netdev, RT_FALSE);
+        LOG_D("the network interface device(%s) set down status.", netdev->name);
+    }
+
+    return RT_EOK;
+}
+
+static int sim800c_netdev_set_dns_server(struct netdev *netdev, uint8_t dns_num, ip_addr_t *dns_server)
+{
+#define SIM800C_DNS_RESP_LEN     8
+#define SIM800C_DNS_RESP_TIMEO   rt_tick_from_millisecond(300)
+
+    int result = RT_EOK;
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    RT_ASSERT(netdev);
+    RT_ASSERT(dns_server);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get sim800c device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+
+    resp = at_create_resp(SIM800C_DNS_RESP_LEN, 0, SIM800C_DNS_RESP_TIMEO);
+    if (resp == RT_NULL)
+    {
+        LOG_D("sim800c set dns server failed, no memory for response object.");
+        result = -RT_ENOMEM;
+        goto __exit;
+    }
+
+    /* send "AT+CDNSCFG=<pri_dns>[,<sec_dns>]" commond to set dns servers */
+    if (at_obj_exec_cmd(device->client, resp, "AT+CDNSCFG=\"%s\"", inet_ntoa(*dns_server)) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    netdev_low_level_set_dns_server(netdev, dns_num, dns_server);
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+static int sim800c_ping_domain_resolve(struct at_device *device, const char *name, char ip[16])
+{
+    int result = RT_EOK;
+    char recv_ip[16] = { 0 };
+    at_response_t resp = RT_NULL;
+
+    /* The maximum response time is 14 seconds, affected by network status */
+    resp = at_create_resp(128, 4, 14 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for sim800c device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    if (at_obj_exec_cmd(device->client, resp, "AT+CDNSGIP=\"%s\"", name) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    /* parse the third line of response data, get the IP address */
+    if (at_resp_parse_line_args_by_kw(resp, "+CDNSGIP:", "%*[^,],%*[^,],\"%[^\"]", recv_ip) < 0)
+    {
+        rt_thread_mdelay(100);
+        /* resolve failed, maybe receive an URC CRLF */
+    }
+
+    if (rt_strlen(recv_ip) < 8)
+    {
+        rt_thread_mdelay(100);
+        /* resolve failed, maybe receive an URC CRLF */
+    }
+    else
+    {
+        rt_strncpy(ip, recv_ip, 15);
+        ip[15] = '\0';
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+#ifdef NETDEV_USING_PING
+static int sim800c_netdev_ping(struct netdev *netdev, const char *host, 
+        size_t data_len, uint32_t timeout, struct netdev_ping_resp *ping_resp)
+{
+#define SIM800C_PING_RESP_SIZE         128
+#define SIM800C_PING_IP_SIZE           16
+#define SIM800C_PING_TIMEO             (5 * RT_TICK_PER_SECOND)
+
+#define SIM800C_PING_ERR_TIME          600
+#define SIM800C_PING_ERR_TTL           255
+
+    int result = RT_EOK;
+    int response, time, ttl, i, err_code = 0;
+    char ip_addr[SIM800C_PING_IP_SIZE] = {0};
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    RT_ASSERT(netdev);
+    RT_ASSERT(host);
+    RT_ASSERT(ping_resp);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, netdev->name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get sim800c device by netdev name(%s) failed.", netdev->name);
+        return -RT_ERROR;
+    }
+
+    for (i = 0; i < rt_strlen(host) && !isalpha(host[i]); i++);
+
+    if (i < strlen(host))
+    {
+        /* check domain name is usable */
+        if (sim800c_ping_domain_resolve(device, host, ip_addr) < 0)
+        {
+            return -RT_ERROR;
+        }
+        rt_memset(ip_addr, 0x00, SIM800C_PING_IP_SIZE);
+    }
+
+    resp = at_create_resp(SIM800C_PING_RESP_SIZE, 0, SIM800C_PING_TIMEO);
+    if (resp == RT_NULL)
+    {
+        LOG_E("sim800c device(%s) set dns server failed, no memory for response object.", device->name);
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    /* domain name prase error options */
+    if (at_resp_parse_line_args_by_kw(resp, "+CDNSGIP: 0", "+CDNSGIP: 0,%d", &err_code) > 0)
+    {
+        /* 3 - network error, 8 - dns common error */
+        if (err_code == 3 || err_code == 8)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+    }
+
+    /* send "AT+CIPPING=<IP addr>[,<retryNum>[,<dataLen>[,<timeout>[,<ttl>]]]]" commond to send ping request */
+    if (at_obj_exec_cmd(device->client, resp, "AT+CIPPING=%s,1,%d,%d,64", 
+            host, data_len, SIM800C_PING_TIMEO / (RT_TICK_PER_SECOND / 10)) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    if (at_resp_parse_line_args_by_kw(resp, "+CIPPING:", "+CIPPING:%d,\"%[^\"]\",%d,%d",
+             &response, ip_addr, &time, &ttl) <= 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    /* the ping request timeout expires, the response time settting to 600 and ttl setting to 255 */
+    if (time == SIM800C_PING_ERR_TIME && ttl == SIM800C_PING_ERR_TTL)
+    {
+        result = -RT_ETIMEOUT;
+        goto __exit;
+    }
+
+    inet_aton(ip_addr, &(ping_resp->ip_addr));
+    ping_resp->data_len = data_len;
+    /* reply time, in units of 100 ms */
+    ping_resp->ticks = time * 100;
+    ping_resp->ttl = ttl;
+
+ __exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+#endif /* NETDEV_USING_PING */
+
+#ifdef NETDEV_USING_NETSTAT
+void sim800c_netdev_netstat(struct netdev *netdev)
+{ 
+    // TODO netstat support
+}
+#endif /* NETDEV_USING_NETSTAT */
+
+const struct netdev_ops sim800c_netdev_ops =
+{
+    sim800c_netdev_set_up,
+    sim800c_netdev_set_down,
+
+    RT_NULL, /* not support set ip, netmask, gatway address */
+    sim800c_netdev_set_dns_server,
+    RT_NULL, /* not support set DHCP status */
+
+#ifdef NETDEV_USING_PING
+    sim800c_netdev_ping,
+#endif
+#ifdef NETDEV_USING_NETSTAT
+    sim800c_netdev_netstat,
+#endif
+};
+
+static struct netdev *sim800c_netdev_add(const char *netdev_name)
+{
+#define SIM800C_NETDEV_MTU       1500
+    struct netdev *netdev = RT_NULL;
+
+    RT_ASSERT(netdev_name);
+
+    netdev = (struct netdev *) rt_calloc(1, sizeof(struct netdev));
+    if (netdev == RT_NULL)
+    {
+        LOG_E("no memory for sim800c device(%s) netdev structure.", netdev_name);
+        return RT_NULL;
+    }
+
+    netdev->mtu = SIM800C_NETDEV_MTU;
+    netdev->ops = &sim800c_netdev_ops;
+
+#ifdef SAL_USING_AT
+    extern int sal_at_netdev_set_pf_info(struct netdev *netdev);
+    /* set the network interface socket/netdb operations */
+    sal_at_netdev_set_pf_info(netdev);
+#endif
+
+    netdev_register(netdev, netdev_name, RT_NULL);
+
+    return netdev;
+}
+
+/* =============================  sim76xx device operations ============================= */
+
+#define AT_SEND_CMD(client, resp, resp_line, timeout, cmd)                                         \
+    do {                                                                                           \
+        (resp) = at_resp_set_info((resp), 128, (resp_line), rt_tick_from_millisecond(timeout));    \
+        if (at_obj_exec_cmd((client), (resp), (cmd)) < 0)                                          \
+        {                                                                                          \
+            result = -RT_ERROR;                                                                    \
+            goto __exit;                                                                           \
+        }                                                                                          \
+    } while(0)                                                                                     \
+
+/* init for sim800c */
+static void sim800c_init_thread_entry(void *parameter)
+{
+#define INIT_RETRY                     5
+#define CPIN_RETRY                     10
+#define CSQ_RETRY                      10
+#define CREG_RETRY                     10
+#define CGREG_RETRY                    20
+
+    int i, qimux, retry_num = INIT_RETRY;
+    char parsed_data[10] = {0};
+    rt_err_t result = RT_EOK;
+    at_response_t resp = RT_NULL;
+    struct at_device *device = (struct at_device *)parameter;
+    struct at_client *client = device->client;
+
+    resp = at_create_resp(128, 0, rt_tick_from_millisecond(300));
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for sim800c device(%s) response structure.", device->name);
+        return;
+    }
+
+    LOG_D("start initializing the sim800c device(%s)", device->name);
+
+    while (retry_num--)
+    {
+        rt_memset(parsed_data, 0, sizeof(parsed_data));
+        rt_thread_mdelay(500);
+        sim800c_power_on(device);
+        rt_thread_mdelay(1000);
+
+        /* wait sim800c startup finish */
+        if (at_client_obj_wait_connect(client, SIM800C_WAIT_CONNECT_TIME))
+        {
+            result = -RT_ETIMEOUT;
+            goto __exit;
+        }
+
+        /* disable echo */
+        AT_SEND_CMD(client, resp, 0, 300, "ATE0");
+        /* get module version */
+        AT_SEND_CMD(client, resp, 0, 300, "ATI");
+        /* show module version */
+        for (i = 0; i < (int)resp->line_counts - 1; i++)
+        {
+            LOG_D("%s", at_resp_get_line(resp, i + 1));
+        }
+        /* check SIM card */
+        for (i = 0; i < CPIN_RETRY; i++)
+        {
+            AT_SEND_CMD(client, resp, 2, 5 * RT_TICK_PER_SECOND, "AT+CPIN?");
+
+            if (at_resp_get_line_by_kw(resp, "READY"))
+            {
+                LOG_D("sim800c device(%s) SIM card detection success.", device->name);
+                break;
+            }
+            rt_thread_mdelay(1000);
+        }
+        if (i == CPIN_RETRY)
+        {
+            LOG_E("sim800c device(%s) SIM card detection failed.", device->name);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+        /* waiting for dirty data to be digested */
+        rt_thread_mdelay(10);
+
+        /* check the GSM network is registered */
+        for (i = 0; i < CREG_RETRY; i++)
+        {
+            AT_SEND_CMD(client, resp, 0, 300, "AT+CREG?");
+            at_resp_parse_line_args_by_kw(resp, "+CREG:", "+CREG: %s", &parsed_data);
+            if (!strncmp(parsed_data, "0,1", sizeof(parsed_data)) ||
+                !strncmp(parsed_data, "0,5", sizeof(parsed_data)))
+            {
+                LOG_D("sim800c device(%s) GSM network is registered(%s),", device->name, parsed_data);
+                break;
+            }
+            rt_thread_mdelay(1000);
+        }
+        if (i == CREG_RETRY)
+        {
+            LOG_E("sim800c device(%s) GSM network is register failed(%s).", device->name, parsed_data);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+        /* check the GPRS network is registered */
+        for (i = 0; i < CGREG_RETRY; i++)
+        {
+            AT_SEND_CMD(client, resp, 0, 300, "AT+CGREG?");
+            at_resp_parse_line_args_by_kw(resp, "+CGREG:", "+CGREG: %s", &parsed_data);
+            if (!strncmp(parsed_data, "0,1", sizeof(parsed_data)) ||
+                !strncmp(parsed_data, "0,5", sizeof(parsed_data)))
+            {
+                LOG_D("sim800c device(%s) GPRS network is registered(%s).", device->name, parsed_data);
+                break;
+            }
+            rt_thread_mdelay(1000);
+        }
+        if (i == CGREG_RETRY)
+        {
+            LOG_E("sim800c device(%s) GPRS network is register failed(%s).", device->name, parsed_data);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* check signal strength */
+        for (i = 0; i < CSQ_RETRY; i++)
+        {
+            AT_SEND_CMD(client, resp, 0, 300, "AT+CSQ");
+            at_resp_parse_line_args_by_kw(resp, "+CSQ:", "+CSQ: %s", &parsed_data);
+            if (strncmp(parsed_data, "99,99", sizeof(parsed_data)))
+            {
+                LOG_D("sim800c device(%s) signal strength: %s", device->name, parsed_data);
+                break;
+            }
+            rt_thread_mdelay(1000);
+        }
+        if (i == CSQ_RETRY)
+        {
+            LOG_E("sim800c device(%s) signal strength check failed (%s)", device->name, parsed_data);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* the device default response timeout is 40 seconds, but it set to 15 seconds is convenient to use. */
+        AT_SEND_CMD(client, resp, 2, 20 * 1000, "AT+CIPSHUT");
+
+        /* Set to multiple connections */
+        AT_SEND_CMD(client, resp, 0, 300, "AT+CIPMUX?");
+        at_resp_parse_line_args_by_kw(resp, "+CIPMUX:", "+CIPMUX: %d", &qimux);
+        if (qimux == 0)
+        {
+            AT_SEND_CMD(client, resp, 0, 300, "AT+CIPMUX=1");
+        }
+
+        AT_SEND_CMD(client, resp, 0, 300, "AT+COPS?");
+        at_resp_parse_line_args_by_kw(resp, "+COPS:", "+COPS: %*[^\"]\"%[^\"]", &parsed_data);
+        if (rt_strcmp(parsed_data, "CHINA MOBILE") == 0)
+        {
+            /* "CMCC" */
+            LOG_I("sim800c device(%s) network operator: %s", device->name, parsed_data);
+            AT_SEND_CMD(client, resp, 0, 300, CSTT_CHINA_MOBILE);
+        }
+        else if (rt_strcmp(parsed_data, "CHN-UNICOM") == 0)
+        {
+            /* "UNICOM" */
+            LOG_I("sim800c device(%s) network operator: %s", device->name, parsed_data);
+            AT_SEND_CMD(client, resp, 0, 300, CSTT_CHINA_UNICOM);
+        }
+        else if (rt_strcmp(parsed_data, "CHN-CT") == 0)
+        {
+            AT_SEND_CMD(client, resp, 0, 300, CSTT_CHINA_TELECOM);
+            /* "CT" */
+            LOG_I("sim800c device(%s) network operator: %s", device->name, parsed_data);
+        }
+
+        /* the device default response timeout is 150 seconds, but it set to 20 seconds is convenient to use. */
+        AT_SEND_CMD(client, resp, 0, 20 * 1000, "AT+CIICR");
+
+        AT_SEND_CMD(client, resp, 2, 300, "AT+CIFSR");
+        if (at_resp_get_line_by_kw(resp, "ERROR") != RT_NULL)
+        {
+            LOG_E("sim800c device(%s) get the local address failed.", device->name);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+        result = RT_EOK;
+
+    __exit:
+        if (result == RT_EOK)
+        {
+            break;
+        }
+        else
+        {
+            /* power off the sim800c device */
+            sim800c_power_off(device);
+            rt_thread_mdelay(1000);
+
+            LOG_I("sim800c device(%s) initialize retry...", device->name);
+        }
+    }
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    if (result == RT_EOK)
+    {
+        /* set network interface device status and address information */
+        sim800c_netdev_set_info(device->netdev);
+        sim800c_netdev_check_link_status(device->netdev);
+
+        LOG_I("sim800c device(%s) network initialize success!", device->name);
+
+    }
+    else
+    {
+        LOG_E("sim800c device(%s) network initialize failed(%d)!", device->name, result);
+    }
+}
+
+static int sim800c_net_init(struct at_device *device)
+{
+#ifdef AT_DEVICE_SIM800C_INIT_ASYN
+    rt_thread_t tid;
+
+    tid = rt_thread_create("sim800c_net_init", sim800c_init_thread_entry, (void *)device,
+                SIM800C_THREAD_STACK_SIZE, SIM800C_THREAD_PRIORITY, 20);
+    if (tid)
+    {
+        rt_thread_startup(tid);
+    }
+    else
+    {
+        LOG_E("create sim800c device(%s) initialization thread failed.", device->name);
+        return -RT_ERROR;
+    }
+#else
+    sim800c_init_thread_entry(device);
+#endif /* AT_DEVICE_SIM800C_INIT_ASYN */
+
+    return RT_EOK;
+}
+
+static void urc_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    RT_ASSERT(data);
+
+    LOG_I("URC data : %.*s", size, data);
+}
+
+/* sim800c device URC table for the device control */
+static const struct at_urc urc_table[] = 
+{
+        {"RDY",         "\r\n",                 urc_func},
+};
+
+static int sim800c_init(struct at_device *device)
+{
+    struct at_device_sim800c *sim800c = (struct at_device_sim800c *) device->user_data;
+
+    /* initialize AT client */
+    at_client_init(sim800c->client_name, sim800c->recv_line_num);
+
+    device->client = at_client_get(sim800c->client_name);
+    if (device->client == RT_NULL)
+    {
+        LOG_E("sim800c device(%s) initialize failed, get AT client(%s) failed.", sim800c->device_name, sim800c->client_name);
+        return -RT_ERROR;
+    }
+
+    /* register URC data execution function  */
+    at_obj_set_urc_table(device->client, urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
+
+#ifdef AT_USING_SOCKET
+    sim800c_socket_init(device);
+#endif
+
+    /* add sim800c device to the netdev list */
+    device->netdev = sim800c_netdev_add(sim800c->device_name);
+    if (device->netdev == RT_NULL)
+    {
+        LOG_E("sim800c device(%s) initialize failed, get network interface device failed.", sim800c->device_name);
+        return -RT_ERROR;
+    }
+
+    /* initialize sim800c pin configuration */
+    if (sim800c->power_pin != -1 && sim800c->power_status_pin != -1)
+    {
+        rt_pin_mode(sim800c->power_pin, PIN_MODE_OUTPUT);
+        rt_pin_mode(sim800c->power_status_pin, PIN_MODE_INPUT);
+    }
+
+    /* initialize sim800c device network */
+    return sim800c_netdev_set_up(device->netdev);
+}
+
+static int sim800c_deinit(struct at_device *device)
+{
+    return sim800c_netdev_set_down(device->netdev);
+}
+
+static int sim800c_control(struct at_device *device, int cmd, void *arg)
+{
+    int result = -RT_ERROR;
+
+    RT_ASSERT(device);
+
+    switch (cmd)
+    {
+    case AT_DEVICE_CTRL_POWER_ON:
+    case AT_DEVICE_CTRL_POWER_OFF:
+    case AT_DEVICE_CTRL_RESET:
+    case AT_DEVICE_CTRL_LOW_POWER:
+    case AT_DEVICE_CTRL_SLEEP:
+    case AT_DEVICE_CTRL_WAKEUP:
+    case AT_DEVICE_CTRL_NET_CONN:
+    case AT_DEVICE_CTRL_NET_DISCONN:
+    case AT_DEVICE_CTRL_SET_WIFI_INFO:
+    case AT_DEVICE_CTRL_GET_SIGNAL:
+    case AT_DEVICE_CTRL_GET_GPS:
+    case AT_DEVICE_CTRL_GET_VER:
+        LOG_W("sim800c not support the control command(%d).", cmd);
+        break;
+    default:
+        LOG_E("input error control command(%d).", cmd);
+        break;
+    }
+
+    return result;
+}
+
+const struct at_device_ops sim800c_device_ops = 
+{
+    sim800c_init,
+    sim800c_deinit,
+    sim800c_control,
+};
+
+static int sim800c_device_class_register(void)
+{
+    struct at_device_class *class = RT_NULL;
+
+    class = (struct at_device_class *) rt_calloc(1, sizeof(struct at_device_class));
+    if (class == RT_NULL)
+    {
+        LOG_E("no memory for sim800c device class create.");
+        return -RT_ENOMEM;
+    }
+
+    /* fill sim800c device class object */
+#ifdef AT_USING_SOCKET
+    sim800c_socket_class_register(class);
+#endif
+    class->device_ops = &sim800c_device_ops;
+
+    return at_device_class_register(class, AT_DEVICE_CLASS_SIM800C);
+}
+INIT_DEVICE_EXPORT(sim800c_device_class_register);
+
+#endif /* AT_DEVICE_USING_SIM800C */

+ 66 - 0
class/sim800c/at_device_sim800c.h

@@ -0,0 +1,66 @@
+/*
+ * File      : at_device_sim800c.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-05-16     chenyong     first version
+ */
+
+#ifndef __AT_DEVICE_SIM800C_H__
+#define __AT_DEVICE_SIM800C_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+
+#include <at_device.h>
+
+/* The maximum number of sockets supported by the sim800c device */
+#define AT_DEVICE_SIM800C_SOCKETS_NUM      6
+
+struct at_device_sim800c
+{     
+    char *device_name;
+    char *client_name;
+
+    int power_pin;
+    int power_status_pin;
+    size_t recv_line_num;
+    struct at_device device;
+
+    void *user_data;
+};
+
+#ifdef AT_USING_SOCKET
+
+/* sim800c device socket initialize */
+int sim800c_socket_init(struct at_device *device);
+
+/* sim800c device class socket register */
+int sim800c_socket_class_register(struct at_device_class *class);
+
+#endif /* AT_USING_SOCKET */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AT_DEVICE_SIM800C_H__ */

+ 658 - 0
class/sim800c/at_socket_sim800c.c

@@ -0,0 +1,658 @@
+/*
+ * File      : at_socket_sim800c.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-06-12     malongwei    first version
+ * 2019-05-13     chenyong     multi AT socket client support
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <at_device_sim800c.h>
+
+#if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10200
+#error "This AT Client version is older, please check and update latest AT Client!"
+#endif
+
+#define LOG_TAG                        "at.skt"
+#include <at_log.h>
+
+#if defined(AT_DEVICE_USING_SIM800C) && defined(AT_USING_SOCKET)
+
+#define SIM800C_MODULE_SEND_MAX_SIZE   1000
+
+/* set real event by current socket and current state */
+#define SET_EVENT(socket, event)       (((socket + 1) << 16) | (event))
+
+/* AT socket event type */
+#define SIM800C_EVENT_CONN_OK          (1L << 0)
+#define SIM800C_EVENT_SEND_OK          (1L << 1)
+#define SIM800C_EVENT_RECV_OK          (1L << 2)
+#define SIM800C_EVNET_CLOSE_OK         (1L << 3)
+#define SIM800C_EVENT_CONN_FAIL        (1L << 4)
+#define SIM800C_EVENT_SEND_FAIL        (1L << 5)
+
+static at_evt_cb_t at_evt_cb_set[] = {
+        [AT_SOCKET_EVT_RECV] = NULL,
+        [AT_SOCKET_EVT_CLOSED] = NULL,
+};
+
+static int sim800c_socket_event_send(struct at_device *device, uint32_t event)
+{
+    return (int) rt_event_send(device->socket_event, event);
+}
+
+static int sim800c_socket_event_recv(struct at_device *device, uint32_t event, uint32_t timeout, rt_uint8_t option)
+{
+    int result = RT_EOK;
+    rt_uint32_t recved;
+
+    result = rt_event_recv(device->socket_event, event, option | RT_EVENT_FLAG_CLEAR, timeout, &recved);
+    if (result != RT_EOK)
+    {
+        return -RT_ETIMEOUT;
+    }
+
+    return recved;
+}
+
+/**
+ * close socket by AT commands.
+ *
+ * @param current socket
+ *
+ * @return  0: close socket success
+ *         -1: send AT commands error
+ *         -2: wait socket event timeout
+ *         -5: no memory
+ */
+static int sim800c_socket_close(struct at_socket *socket)
+{
+    uint32_t event = 0;
+    int result = RT_EOK;
+    at_response_t resp = RT_NULL;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+    
+    resp = at_create_resp(64, 0, rt_tick_from_millisecond(300));
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for sim800c device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    /* clear socket close event */
+    event = SET_EVENT(device_socket, SIM800C_EVNET_CLOSE_OK);
+    sim800c_socket_event_recv(device, event, 0, RT_EVENT_FLAG_OR);
+    
+    if (at_obj_exec_cmd(device->client, resp, "AT+CIPCLOSE=%d", device_socket) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    if (sim800c_socket_event_recv(device, event, rt_tick_from_millisecond(300*3), RT_EVENT_FLAG_AND) < 0)
+    {
+        LOG_E("sim800c device(%s) socket(%d) close failed, wait close OK timeout.", device->name, device_socket);
+        result = -RT_ETIMEOUT;
+        goto __exit;
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+    
+    return result;
+}
+
+
+/**
+ * create TCP/UDP client or server connect by AT commands.
+ *
+ * @param socket current socket
+ * @param ip server or client IP address
+ * @param port server or client port
+ * @param type connect socket type(tcp, udp)
+ * @param is_client connection is client
+ *
+ * @return   0: connect success
+ *          -1: connect failed, send commands error or type error
+ *          -2: wait socket event timeout
+ *          -5: no memory
+ */
+static int sim800c_socket_connect(struct at_socket *socket, char *ip, int32_t port, enum at_socket_type type, rt_bool_t is_client)
+{
+    uint32_t event = 0;
+    rt_bool_t retryed = RT_FALSE;
+    at_response_t resp = RT_NULL;
+    int result = RT_EOK, event_result = 0;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+
+    RT_ASSERT(ip);
+    RT_ASSERT(port >= 0);
+
+    resp = at_create_resp(128, 0, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for sim800c device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+__retry:
+
+    /* clear socket connect event */
+    event = SET_EVENT(device_socket, SIM800C_EVENT_CONN_OK | SIM800C_EVENT_CONN_FAIL);
+    sim800c_socket_event_recv(device, event, 0, RT_EVENT_FLAG_OR);
+
+    if (is_client)
+    {
+        switch (type)
+        {
+        case AT_SOCKET_TCP:
+            /* send AT commands(eg: AT+QIOPEN=0,"TCP","x.x.x.x", 1234) to connect TCP server */
+            if (at_obj_exec_cmd(device->client, RT_NULL, 
+                    "AT+CIPSTART=%d,\"TCP\",\"%s\",%d", device_socket, ip, port) < 0)
+            {
+                result = -RT_ERROR;
+                goto __exit;
+            }
+            break;
+
+        case AT_SOCKET_UDP:
+            if (at_obj_exec_cmd(device->client, RT_NULL, 
+                    "AT+CIPSTART=%d,\"UDP\",\"%s\",%d", device_socket, ip, port) < 0)
+            {
+                result = -RT_ERROR;
+                goto __exit;
+            }
+            break;
+
+        default:
+            LOG_E("sim800c device(%s) not supported connect type : %d.", device->name, type);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+    }
+
+    /* waiting result event from AT URC, the device default connection timeout is 75 seconds, but it set to 10 seconds is convenient to use */
+    if (sim800c_socket_event_recv(device, SET_EVENT(device_socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
+    {
+        LOG_E("sim800c device(%s) socket(%d) connect failed, wait connect result timeout.",device->name, device_socket);
+        result = -RT_ETIMEOUT;
+        goto __exit;
+    }
+    /* waiting OK or failed result */
+    event_result = sim800c_socket_event_recv(device, 
+            SIM800C_EVENT_CONN_OK | SIM800C_EVENT_CONN_FAIL, 1 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR);
+    if (event_result < 0)
+    {
+        LOG_E("sim800c device(%s) socket(%d) connect failed, wait connect OK|FAIL timeout.", device->name, device_socket);
+        result = -RT_ETIMEOUT;
+        goto __exit;
+    }
+    /* check result */
+    if (event_result & SIM800C_EVENT_CONN_FAIL)
+    {
+        if (retryed == RT_FALSE)
+        {
+            LOG_D("sim800c device(%s) socket(%d) connect failed, maybe the socket was not be closed at the last time and now will retry.", 
+                    device->name, device_socket);
+            if (sim800c_socket_close(socket) < 0)
+            {
+                result = -RT_ERROR;
+                goto __exit;
+            }
+            retryed = RT_TRUE;
+            goto __retry;
+        }
+        LOG_E("sim800c device(%s) socket(%d) connect failed.", device->name, device_socket);
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+    
+    return result;
+}
+
+/**
+ * send data to server or client by AT commands.
+ *
+ * @param socket current socket
+ * @param buff send buffer
+ * @param bfsz send buffer size
+ * @param type connect socket type(tcp, udp)
+ *
+ * @return >=0: the size of send success
+ *          -1: send AT commands error or send data error
+ *          -2: waited socket event timeout
+ *          -5: no memory
+ */
+static int sim800c_socket_send(struct at_socket *socket, const char *buff, size_t bfsz, enum at_socket_type type)
+{
+    uint32_t event = 0;
+    int result = RT_EOK, event_result = 0;
+    size_t cur_pkt_size = 0, sent_size = 0;
+    at_response_t resp = RT_NULL;
+    int device_socket = (int) socket->user_data;
+    struct at_device *device = (struct at_device *) socket->device;
+    rt_mutex_t lock = device->client->lock;
+
+    RT_ASSERT(buff);
+
+    resp = at_create_resp(128, 2, 5 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for sim800c device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    rt_mutex_take(lock, RT_WAITING_FOREVER);
+
+    /* clear socket connect event */
+    event = SET_EVENT(device_socket, SIM800C_EVENT_SEND_OK | SIM800C_EVENT_SEND_FAIL);
+    sim800c_socket_event_recv(device, event, 0, RT_EVENT_FLAG_OR);
+
+    /* set AT client end sign to deal with '>' sign.*/
+    at_obj_set_end_sign(device->client, '>');
+
+    while (sent_size < bfsz)
+    {
+        if (bfsz - sent_size < SIM800C_MODULE_SEND_MAX_SIZE)
+        {
+            cur_pkt_size = bfsz - sent_size;
+        }
+        else
+        {
+            cur_pkt_size = SIM800C_MODULE_SEND_MAX_SIZE;
+        }
+
+        /* send the "AT+QISEND" commands to AT server than receive the '>' response on the first line. */
+        if (at_obj_exec_cmd(device->client, resp, "AT+CIPSEND=%d,%d", device_socket, cur_pkt_size) < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* send the real data to server or client */
+        result = (int) at_client_obj_send(device->client, buff + sent_size, cur_pkt_size);
+        if (result == 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* waiting result event from AT URC */
+        if (sim800c_socket_event_recv(device, SET_EVENT(device_socket, 0), 15 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
+        {
+            LOG_E("sim800c device(%s) socket(%d) send failed, wait connect result timeout.", device->name, device_socket);
+            result = -RT_ETIMEOUT;
+            goto __exit;
+        }
+        /* waiting OK or failed result */
+        event_result = sim800c_socket_event_recv(device, 
+                SIM800C_EVENT_SEND_OK | SIM800C_EVENT_SEND_FAIL, 5 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR);
+        if (event_result < 0)
+        {
+            LOG_E("simm800c device(%s) socket(%d) send failed, wait connect OK|FAIL timeout.", device->name, device_socket);
+            result = -RT_ETIMEOUT;
+            goto __exit;
+        }
+        /* check result */
+        if (event_result & SIM800C_EVENT_SEND_FAIL)
+        {
+            LOG_E("simm800c device(%s) socket(%d) send failed.",device->name, device_socket);
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        sent_size += cur_pkt_size;
+    }
+
+__exit:
+    /* reset the end sign for data conflict */
+    at_obj_set_end_sign(device->client, 0);
+
+    rt_mutex_release(lock);
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+
+/**
+ * domain resolve by AT commands.
+ *
+ * @param name domain name
+ * @param ip parsed IP address, it's length must be 16
+ *
+ * @return  0: domain resolve success
+ *         -1: send AT commands error or response error
+ *         -2: wait socket event timeout
+ *         -5: no memory
+ */
+static int sim800c_domain_resolve(const char *name, char ip[16])
+{
+#define RESOLVE_RETRY                  5
+
+    int i, result = RT_EOK;
+    char recv_ip[16] = { 0 };
+    at_response_t resp = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    RT_ASSERT(name);
+    RT_ASSERT(ip);
+
+    device = at_device_get_first_initialized();
+    if (device == RT_NULL)
+    {
+        LOG_E("get first initialization sim800c device failed.");
+        return -RT_ERROR;
+    }
+
+    /* The maximum response time is 14 seconds, affected by network status */
+    resp = at_create_resp(128, 4, 14 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for sim800c device(%s) response structure.", device->name);
+        return -RT_ENOMEM;
+    }
+
+    for (i = 0; i < RESOLVE_RETRY; i++)
+    {
+        int err_code = 0;
+
+        if (at_obj_exec_cmd(device->client, resp, "AT+CDNSGIP=\"%s\"", name) < 0)
+        {
+            result = -RT_ERROR;
+            goto __exit;
+        }
+
+        /* domain name prase error options */
+        if (at_resp_parse_line_args_by_kw(resp, "+CDNSGIP: 0", "+CDNSGIP: 0,%d", &err_code) > 0)
+        {
+            /* 3 - network error, 8 - dns common error */
+            if (err_code == 3 || err_code == 8)
+            {
+                result = -RT_ERROR;
+                goto __exit;
+            }
+        }
+
+        /* parse the third line of response data, get the IP address */
+        if (at_resp_parse_line_args_by_kw(resp, "+CDNSGIP:", "%*[^,],%*[^,],\"%[^\"]", recv_ip) < 0)
+        {
+            rt_thread_mdelay(100);
+            /* resolve failed, maybe receive an URC CRLF */
+            continue;
+        }
+
+        if (rt_strlen(recv_ip) < 8)
+        {
+            rt_thread_mdelay(100);
+            /* resolve failed, maybe receive an URC CRLF */
+            continue;
+        }
+        else
+        {
+            rt_thread_mdelay(10);
+            rt_strncpy(ip, recv_ip, 15);
+            ip[15] = '\0';
+            break;
+        }
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+
+}
+
+/**
+ * set AT socket event notice callback
+ *
+ * @param event notice event
+ * @param cb notice callback
+ */
+static void sim800c_socket_set_event_cb(at_socket_evt_t event, at_evt_cb_t cb)
+{
+    if (event < sizeof(at_evt_cb_set) / sizeof(at_evt_cb_set[1]))
+    {
+        at_evt_cb_set[event] = cb;
+    }
+}
+
+static void urc_connect_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0;
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get sim800c device by client name(%s) failed.", client_name);
+        return;
+    }
+
+    /* get the current socket by receive data */
+    sscanf(data, "%d,%*s", &device_socket);
+
+    if (strstr(data, "CONNECT OK"))
+    {
+        sim800c_socket_event_send(device, SET_EVENT(device_socket, SIM800C_EVENT_CONN_OK));
+    }
+    else if (strstr(data, "CONNECT FAIL"))
+    {
+        sim800c_socket_event_send(device, SET_EVENT(device_socket, SIM800C_EVENT_CONN_FAIL));
+    }
+}
+
+static void urc_send_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0;
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get sim800c device by client name(%s) failed.", client_name);
+        return;
+    }
+
+    /* get the current socket by receive data */
+    sscanf(data, "%d,%*s", &device_socket);
+
+    if (rt_strstr(data, "SEND OK"))
+    {
+        sim800c_socket_event_send(device, SET_EVENT(device_socket, SIM800C_EVENT_SEND_OK));
+    }
+    else if (rt_strstr(data, "SEND FAIL"))
+    {
+        sim800c_socket_event_send(device, SET_EVENT(device_socket, SIM800C_EVENT_SEND_FAIL));
+    }
+}
+
+static void urc_close_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0;
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get sim800c device by client name(%s) failed.", client_name);
+        return;
+    }
+
+    /* get the current socket by receive data */
+    sscanf(data, "%d,%*s", &device_socket);
+
+    if (rt_strstr(data, "CLOSE OK"))
+    {
+        sim800c_socket_event_send(device, SET_EVENT(device_socket, SIM800C_EVNET_CLOSE_OK));
+    }
+    else if (rt_strstr(data, "CLOSED"))
+    {
+        struct at_socket *socket = RT_NULL;
+
+        /* get AT socket object by device socket descriptor */
+        socket = &(device->sockets[device_socket]);
+
+        /* notice the socket is disconnect by remote */
+        if (at_evt_cb_set[AT_SOCKET_EVT_CLOSED])
+        {
+            at_evt_cb_set[AT_SOCKET_EVT_CLOSED](socket, AT_SOCKET_EVT_CLOSED, RT_NULL, 0);
+        }
+    }
+}
+
+static void urc_recv_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int device_socket = 0;
+    rt_int32_t timeout;
+    rt_size_t bfsz = 0, temp_size = 0;
+    char *recv_buf = RT_NULL, temp[8] = {0};
+    struct at_socket *socket = RT_NULL;
+    struct at_device *device = RT_NULL;
+    char *client_name = client->device->parent.name;
+
+    RT_ASSERT(data && size);
+
+    /* get the current socket and receive buffer size by receive data */
+    sscanf(data, "+RECEIVE,%d,%d:", &device_socket, (int *) &bfsz);
+    /* get receive timeout by receive buffer length */
+    timeout = bfsz;
+
+    if (device_socket < 0 || bfsz == 0)
+    {
+        return;
+    }
+
+    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
+    if (device == RT_NULL)
+    {
+        LOG_E("get m26 device by client name(%s) failed.", client_name);
+        return;
+    }
+
+    recv_buf = (char *) rt_calloc(1, bfsz);
+    if (recv_buf == RT_NULL)
+    {
+        LOG_E("no memory for sim800c device(%s) URC receive buffer (%d).", device->name, bfsz);
+        /* read and clean the coming data */
+        while (temp_size < bfsz)
+        {
+            if (bfsz - temp_size > sizeof(temp))
+            {
+                at_client_obj_recv(client, temp, sizeof(temp), timeout);
+            }
+            else
+            {
+                at_client_obj_recv(client, temp, bfsz - temp_size, timeout);
+            }
+            temp_size += sizeof(temp);
+        }
+        return;
+    }
+
+    /* sync receive data */
+    if (at_client_obj_recv(client, recv_buf, bfsz, timeout) != bfsz)
+    {
+        LOG_E("sim800c device(%s) receive size(%d) data failed.", device->name, bfsz);
+        rt_free(recv_buf);
+        return;
+    }
+
+    /* get AT socket object by device socket descriptor */
+    socket = &(device->sockets[device_socket]);
+
+    /* notice the receive buffer and buffer size */
+    if (at_evt_cb_set[AT_SOCKET_EVT_RECV])
+    {
+        at_evt_cb_set[AT_SOCKET_EVT_RECV](socket, AT_SOCKET_EVT_RECV, recv_buf, bfsz);
+    }
+}
+
+/* sim800c device URC table for the socket data */
+static const struct at_urc urc_table[] = 
+{
+    {"",            ", CONNECT OK\r\n",     urc_connect_func},
+    {"",            ", CONNECT FAIL\r\n",   urc_connect_func},
+    {"",            ", SEND OK\r\n",        urc_send_func},
+    {"",            ", SEND FAIL\r\n",      urc_send_func},
+    {"",            ", CLOSE OK\r\n",       urc_close_func},
+    {"",            ", CLOSED\r\n",         urc_close_func},
+    {"+RECEIVE,",   "\r\n",                 urc_recv_func},
+};
+
+static const struct at_socket_ops sim800c_socket_ops = 
+{
+    sim800c_socket_connect,
+    sim800c_socket_close,
+    sim800c_socket_send,
+    sim800c_domain_resolve,
+    sim800c_socket_set_event_cb,
+};
+
+int sim800c_socket_init(struct at_device *device)
+{
+    RT_ASSERT(device);
+
+    /* register URC data execution function  */
+    at_obj_set_urc_table(device->client, urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
+
+    return RT_EOK;
+}
+
+int sim800c_socket_class_register(struct at_device_class *class)
+{
+    RT_ASSERT(class);
+
+    class->socket_num = AT_DEVICE_SIM800C_SOCKETS_NUM;
+    class->socket_ops = &sim800c_socket_ops;
+
+    return RT_EOK;
+}
+
+#endif /* AT_DEVICE_USING_SIM800C && AT_USING_SOCKET */

+ 135 - 0
inc/at_device.h

@@ -0,0 +1,135 @@
+/*
+ * File      : at_device.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-05-08     chenyong     first version
+ */
+
+#ifndef __AT_DEVICE_H__
+#define __AT_DEVICE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <at.h>
+#include <at_socket.h>
+
+#if !defined(RT_USING_NETDEV)
+#error "This RT-Thread version is older, please check and updata laster RT-Thread!"
+#else
+#include <arpa/inet.h>
+#include <netdev.h>
+#endif /* RT_USING_NETDEV */
+
+#define AT_DEVICE_SW_VERSION           "2.0.0"
+#define AT_DEVICE_SW_VERSION_NUM       0x20000
+
+/* AT device class ID */
+#define AT_DEVICE_CLASS_ESP8266        0x01U
+#define AT_DEVICE_CLASS_M26_MC20       0x02U
+#define AT_DEVICE_CLASS_EC20           0x03U
+#define AT_DEVICE_CLASS_SIM800C        0x04U
+#define AT_DEVICE_CLASS_SIM76XX        0x05U
+#define AT_DEVICE_CLASS_RW007          0x06U
+
+/* Options and Commands for AT device control opreations */
+#define AT_DEVICE_CTRL_POWER_ON        0x01L
+#define AT_DEVICE_CTRL_POWER_OFF       0x02L
+#define AT_DEVICE_CTRL_RESET           0x03L
+#define AT_DEVICE_CTRL_LOW_POWER       0x04L
+#define AT_DEVICE_CTRL_SLEEP           0x05L
+#define AT_DEVICE_CTRL_WAKEUP          0x06L
+#define AT_DEVICE_CTRL_NET_CONN        0x07L
+#define AT_DEVICE_CTRL_NET_DISCONN     0x08L
+#define AT_DEVICE_CTRL_SET_WIFI_INFO   0x09L
+#define AT_DEVICE_CTRL_GET_SIGNAL      0x0AL
+#define AT_DEVICE_CTRL_GET_GPS         0x0BL
+#define AT_DEVICE_CTRL_GET_VER         0x0CL
+
+/* Name type */
+#define AT_DEVICE_NAMETYPE_DEVICE      0x01
+#define AT_DEVICE_NAMETYPE_NETDEV      0x02
+#define AT_DEVICE_NAMETYPE_CLIENT      0x03
+
+struct at_device;
+
+/* AT device wifi ssid and password information */
+struct at_device_ssid_pwd
+{
+    char *ssid;
+    char *password;
+};
+
+/* AT device operations */
+struct at_device_ops
+{
+    int (*init)(struct at_device *device);
+    int (*deinit)(struct at_device *device);
+    int (*control)(struct at_device *device, int cmd, void *arg);
+};
+
+struct at_device_class
+{
+    uint16_t class_id;                           /* AT device class ID */
+    const struct at_device_ops *device_ops;      /* AT device operaiotns */
+#ifdef AT_USING_SOCKET
+    uint32_t socket_num;                         /* The maximum number of sockets support */
+    const struct at_socket_ops *socket_ops;      /* AT device socket operations */
+#endif
+    rt_slist_t list;                             /* AT device class list */
+};
+
+struct at_device
+{
+    char name[RT_NAME_MAX];                      /* AT device name */
+    rt_bool_t is_init;                           /* AT device initialization completed */
+    struct at_device_class *class;               /* AT device class object */
+    struct at_client *client;                    /* AT Client object for AT device */
+    struct netdev *netdev;                       /* Network interface device for AT device */
+#ifdef AT_USING_SOCKET
+    rt_event_t socket_event;                     /* AT device socket event */
+    struct at_socket *sockets;                   /* AT device sockets list */
+#endif
+    rt_slist_t list;                             /* AT device list */
+
+    void *user_data;                             /* User-specific data */
+};
+
+/* Get AT device object */
+struct at_device *at_device_get_first_initialized(void);
+struct at_device *at_device_get_by_name(int type, const char *name);
+#ifdef AT_USING_SOCKET
+struct at_device *at_device_get_by_socket(int at_socket);
+#endif
+
+/* AT device control operaions */
+int at_device_control(struct at_device *device, int cmd, void *arg);
+/* Register AT device class object */
+int at_device_class_register(struct at_device_class *class, uint16_t class_id);
+/* Register AT device object */
+int at_device_register(struct at_device *device, const char *device_name,
+                        const char *at_client_name, uint16_t class_id, void *user_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AT_DEVICE_H__ */

+ 1 - 1
at_client_sample.c → samples/at_sample_client.c

@@ -1,5 +1,5 @@
 /*
- * File      : at_client_sample.c
+ * File      : at_sample_client.c
  * This file is part of RT-Thread RTOS
  * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
  *

+ 52 - 0
samples/at_sample_ec20.c

@@ -0,0 +1,52 @@
+/*
+ * File      : at_sample_ec20.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-05-13     chenyong     first version
+ */
+
+#include <at_device_ec20.h>
+
+#define LOG_TAG                        "at.sample"
+#include <at_log.h>
+
+#define EC20_SAMPLE_DEIVCE_NAME        "e0"
+
+static struct at_device_ec20 e0 =
+{
+    EC20_SAMPLE_DEIVCE_NAME,
+    EC20_SAMPLE_CLIENT_NAME,
+
+    EC20_SAMPLE_POWER_PIN,
+    EC20_SAMPLE_STATUS_PIN,
+    EC20_SAMPLE_RECV_BUFF_LEN,
+};
+
+static int ec20_device_register(void)
+{
+    struct at_device_ec20 *ec20 = &e0;
+
+    return at_device_register(&(ec20->device),
+                              ec20->device_name,
+                              ec20->client_name,
+                              AT_DEVICE_CLASS_EC20,
+                              (void *) ec20);
+}
+INIT_APP_EXPORT(ec20_device_register);

+ 52 - 0
samples/at_sample_esp8266.c

@@ -0,0 +1,52 @@
+/*
+ * File      : at_sample_esp8266.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-05-10     chenyong     first version
+ */
+
+#include <at_device_esp8266.h>
+
+#define LOG_TAG                        "at.sample"
+#include <at_log.h>
+
+#define ESP8266_SAMPLE_DEIVCE_NAME     "esp0"
+
+static struct at_device_esp8266 esp0 =
+{
+    ESP8266_SAMPLE_DEIVCE_NAME,
+    ESP8266_SAMPLE_CLIENT_NAME,
+
+    ESP8266_SAMPLE_WIFI_SSID,
+    ESP8266_SAMPLE_WIFI_PASSWORD,
+    ESP8266_SAMPLE_RECV_BUFF_LEN,
+};
+
+static int esp8266_device_register(void)
+{
+    struct at_device_esp8266 *esp8266 = &esp0;
+
+    return at_device_register(&(esp8266->device),
+                              esp8266->device_name,
+                              esp8266->client_name,
+                              AT_DEVICE_CLASS_ESP8266,
+                              (void *) esp8266);
+}
+INIT_APP_EXPORT(esp8266_device_register);

+ 52 - 0
samples/at_sample_m26.c

@@ -0,0 +1,52 @@
+/*
+ * File      : at_sample_m26.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-05-13     chenyong     first version
+ */
+
+#include <at_device_m26.h>
+
+#define LOG_TAG                        "at.sample"
+#include <at_log.h>
+
+#define M26_SAMPLE_DEIVCE_NAME        "m0"
+
+static struct at_device_m26 m0 =
+{
+    M26_SAMPLE_DEIVCE_NAME,
+    M26_SAMPLE_CLIENT_NAME,
+
+    M26_SAMPLE_POWER_PIN,
+    M26_SAMPLE_STATUS_PIN,
+    M26_SAMPLE_RECV_BUFF_LEN,
+};
+
+static int m26_device_register(void)
+{
+    struct at_device_m26 *m26 = &m0;
+
+    return at_device_register(&(m26->device),
+                              m26->device_name,
+                              m26->client_name,
+                              AT_DEVICE_CLASS_M26_MC20,
+                              (void *) m26);
+}
+INIT_APP_EXPORT(m26_device_register);

+ 52 - 0
samples/at_sample_rw007.c

@@ -0,0 +1,52 @@
+/*
+ * File      : at_sample_rw007.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-05-13     chenyong     first version
+ */
+
+#include <at_device_rw007.h>
+
+#define LOG_TAG                        "at.sample"
+#include <at_log.h>
+
+#define RW007_SAMPLE_DEIVCE_NAME       "r0"
+
+static struct at_device_rw007 r0 =
+{
+    RW007_SAMPLE_DEIVCE_NAME,
+    RW007_SAMPLE_CLIENT_NAME,
+
+    RW007_SAMPLE_WIFI_SSID,
+    RW007_SAMPLE_WIFI_PASSWORD,
+    RW007_SAMPLE_RECV_BUFF_LEN,
+};
+
+static int rw007_device_register(void)
+{
+    struct at_device_rw007 *rw007 = &r0;
+
+    return at_device_register(&(rw007->device),
+                              rw007->device_name,
+                              rw007->client_name,
+                              AT_DEVICE_CLASS_RW007,
+                              (void *) rw007);
+}
+INIT_APP_EXPORT(rw007_device_register);

+ 52 - 0
samples/at_sample_sim76xx.c

@@ -0,0 +1,52 @@
+/*
+ * File      : at_sample_sim76xx.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-05-13     chenyong     first version
+ */
+
+#include <at_device_sim76xx.h>
+
+#define LOG_TAG                        "at.sample"
+#include <at_log.h>
+
+#define SIM76XX_SAMPLE_DEIVCE_NAME     "sim1"
+
+static struct at_device_sim76xx sim1 =
+{
+    SIM76XX_SAMPLE_DEIVCE_NAME,
+    SIM76XX_SAMPLE_CLIENT_NAME,
+
+    SIM76XX_SAMPLE_POWER_PIN,
+    SIM76XX_SAMPLE_STATUS_PIN,
+    SIM76XX_SAMPLE_RECV_BUFF_LEN,
+};
+
+static int sim76xx_device_register(void)
+{
+    struct at_device_sim76xx *sim76xx = &sim1;
+
+    return at_device_register(&(sim76xx->device),
+                              sim76xx->device_name,
+                              sim76xx->client_name,
+                              AT_DEVICE_CLASS_SIM76XX,
+                              (void *) sim76xx);
+}
+INIT_APP_EXPORT(sim76xx_device_register);

+ 52 - 0
samples/at_sample_sim800c.c

@@ -0,0 +1,52 @@
+/*
+ * File      : at_sample_sim800c.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-05-13     chenyong     first version
+ */
+
+#include <at_device_sim800c.h>
+
+#define LOG_TAG                        "at.sample"
+#include <at_log.h>
+
+#define SIM800C_SAMPLE_DEIVCE_NAME     "sim0"
+
+static struct at_device_sim800c sim0 =
+{
+    SIM800C_SAMPLE_DEIVCE_NAME,
+    SIM800C_SAMPLE_CLIENT_NAME,
+
+    SIM800C_SAMPLE_POWER_PIN,
+    SIM800C_SAMPLE_STATUS_PIN,
+    SIM800C_SAMPLE_RECV_BUFF_LEN,
+};
+
+static int sim800c_device_register(void)
+{
+    struct at_device_sim800c *sim800c = &sim0;
+
+    return at_device_register(&(sim800c->device),
+                              sim800c->device_name,
+                              sim800c->client_name,
+                              AT_DEVICE_CLASS_SIM800C,
+                              (void *) sim800c);
+}
+INIT_APP_EXPORT(sim800c_device_register);

+ 330 - 0
src/at_device.c

@@ -0,0 +1,330 @@
+/*
+ * File      : at_device.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-05-08     chenyong     first version
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <at_device.h>
+
+#define DBG_TAG              "at.dev"
+#define DBG_LVL              DBG_INFO
+#include <rtdbg.h>
+
+/* The global list of at device */
+static struct at_device *at_device_list = RT_NULL;
+/* The global list of at device class */
+static struct at_device_class *at_device_class_list = RT_NULL;
+
+/**
+ * This function will get the first initialized AT device.
+ *
+ * @return the AT device structure pointer
+ */
+struct at_device *at_device_get_first_initialized(void)
+{
+    rt_base_t level;
+    rt_slist_t *node = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    level = rt_hw_interrupt_disable();
+
+    for (node = &(at_device_list->list); node; node = rt_slist_next(node))
+    {
+        device = rt_slist_entry(node, struct at_device, list);
+        if (device && device->is_init == RT_TRUE)
+        {
+           rt_hw_interrupt_enable(level);
+           return device;
+        }
+    }
+
+    rt_hw_interrupt_enable(level);
+    
+    return RT_NULL;
+}
+
+/**
+ * This function will get AT device by device name.
+ *
+ * @param type the name type
+ * @param name the device name or the client name
+ *
+ * @return the AT device structure pointer
+ */
+struct at_device *at_device_get_by_name(int type, const char *name)
+{
+    rt_base_t level;
+    rt_slist_t *node = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    RT_ASSERT(name);
+
+    level = rt_hw_interrupt_disable();
+
+    for (node = &(at_device_list->list); node; node = rt_slist_next(node))
+    {
+        device = rt_slist_entry(node, struct at_device, list);
+        if (device)
+        {
+            if (((type == AT_DEVICE_NAMETYPE_DEVICE) || (type == AT_DEVICE_NAMETYPE_NETDEV)) && 
+                (rt_strncmp(device->name, name, rt_strlen(name)) == 0))
+            {
+                rt_hw_interrupt_enable(level);
+                return device;
+            }
+            else if ((type == AT_DEVICE_NAMETYPE_CLIENT) && 
+                (rt_strncmp(device->client->device->parent.name, name, rt_strlen(name)) == 0))
+            {                
+                rt_hw_interrupt_enable(level);
+                return device;
+            }
+        }
+    }
+
+    rt_hw_interrupt_enable(level);
+    
+    return RT_NULL;
+}
+
+#ifdef AT_USING_SOCKET
+/**
+ * This function will get AT device by ip address.
+ * 
+ * @param ip_addr input ip address
+ * network
+ * @return != NULL: network interface device object
+ *            NULL: get failed 
+ */
+struct at_device *at_device_get_by_ipaddr(ip_addr_t *ip_addr)
+{
+    rt_base_t level;
+    rt_slist_t *node = RT_NULL;
+    struct at_device *device = RT_NULL;
+
+    level = rt_hw_interrupt_disable();
+
+    for (node = &(at_device_list->list); node; node = rt_slist_next(node))
+    {
+        device = rt_slist_entry(node, struct at_device, list);
+        if (device && ip_addr_cmp(ip_addr, &(device->netdev->ip_addr)))
+        {
+           rt_hw_interrupt_enable(level);
+           return device;
+        }
+    }
+
+    rt_hw_interrupt_enable(level);
+    
+    return RT_NULL; 
+    
+}
+#endif /* AT_USING_SOCKET */
+
+
+/**
+ * This function will perform a variety of control functions on AT devices.
+ *
+ * @param device the pointer of AT device structure
+ * @param cmd the command sent to AT device
+ * @param arg the argument of command
+ *
+ * @return = 0: perform successfully
+ *         < 0: perform failed      
+ */
+int at_device_control(struct at_device *device, int cmd, void *arg)
+{
+    if (device->class->device_ops->control)
+    {
+        return device->class->device_ops->control(device, cmd, arg);
+    }
+    else
+    {
+        LOG_W("AT device(%s) not support control operations.", device->name);
+        return RT_EOK;
+    }
+}
+
+/**
+ * This function registers an AT device class with specified device class ID.
+ *
+ * @param class the pointer of AT device class structure
+ * @param class_id AT device class ID
+ *
+ * @return 0: register successfully
+ */
+int at_device_class_register(struct at_device_class *class, uint16_t class_id)
+{
+    rt_base_t level;
+
+    RT_ASSERT(class);
+
+    /* Fill AT device class */
+    class->class_id = class_id;
+
+    /* Initialize current AT device class single list */
+    rt_slist_init(&(class->list));
+
+    level = rt_hw_interrupt_disable();
+
+    /* Add current AT device class to list */
+    if (at_device_class_list == RT_NULL)
+    {
+        at_device_class_list = class;
+    }
+    else
+    {
+        /* Tail insertion */
+        rt_slist_append(&(at_device_class_list->list), &(class->list));
+    }
+
+    rt_hw_interrupt_enable(level);
+
+    return RT_EOK;
+}
+
+/* Get AT device class by client ID */
+static struct at_device_class *at_device_class_get(uint16_t class_id)
+{
+    rt_base_t level;
+    rt_slist_t *node = RT_NULL;
+    struct at_device_class *class = RT_NULL;
+
+    if (at_device_class_list == RT_NULL)
+    {
+        return RT_NULL;
+    }
+
+    level = rt_hw_interrupt_disable();
+
+    /* Get AT device class by class ID */
+    for (node = (&at_device_class_list->list); node; node = rt_slist_next(node))
+    {
+        class = rt_slist_entry(node, struct at_device_class, list);
+        if (class && class->class_id == class_id)
+        {
+            rt_hw_interrupt_enable(level);
+            return class;
+        }
+    }
+
+    rt_hw_interrupt_enable(level);
+
+    return RT_NULL;
+}
+
+/**
+ * This function registers an AT device with specified device name and AT client name.
+ *
+ * @param device the pointer of AT device structure
+ * @param device_name AT device name
+ * @param at_client_name AT device client name
+ * @param class_id AT device class ID
+ * @param user_data user-specific data
+ *
+ * @return = 0: register successfully
+ *         < 0: register failed
+ */
+int at_device_register(struct at_device *device, const char *device_name,
+                        const char *at_client_name, uint16_t class_id, void *user_data)
+{
+    rt_base_t level;
+    int result = 0;
+    static int device_counts = 0;
+    char name[RT_NAME_MAX] = {0};
+    struct at_device_class *class = RT_NULL;
+
+    RT_ASSERT(device);
+    RT_ASSERT(device_name);
+    RT_ASSERT(at_client_name);
+
+    class = at_device_class_get(class_id);
+    if (class == RT_NULL)
+    {
+        LOG_E("get AT device class(%d) failed.", class_id);
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+    /* Fill AT device object*/
+#ifdef AT_USING_SOCKET
+    device->sockets = (struct at_socket *) rt_calloc(class->socket_num, sizeof(struct at_socket));
+    if (device->sockets == RT_NULL)
+    {
+        LOG_E("no memory for AT Socket number(%d) create.", class->socket_num);
+        result = -RT_ENOMEM;
+        goto __exit;
+    }
+
+    /* create AT device socket event */
+    rt_snprintf(name, RT_NAME_MAX, "at_se%d", device_counts++);
+    device->socket_event = rt_event_create(name, RT_IPC_FLAG_FIFO);
+    if (device->socket_event == RT_NULL)
+    {
+        LOG_E("no memory for AT device(%s) socket event create.", device_name);
+        result = -RT_ENOMEM;
+        goto __exit;
+    }
+#endif /* AT_USING_SOCKET */
+
+    rt_memcpy(device->name, device_name, rt_strlen(device_name));
+    device->class = class;
+    device->user_data = user_data;
+
+    /* Initialize current AT device single list */
+    rt_slist_init(&(device->list));
+
+    level = rt_hw_interrupt_disable();
+
+    /* Add current AT device to device list */
+    if (at_device_list == RT_NULL)
+    {
+        at_device_list = device;
+    }
+    else
+    {
+        /* Tail insertion */
+        rt_slist_append(&(at_device_list->list), &(device->list));
+    }
+
+    rt_hw_interrupt_enable(level);
+  
+    /* Initialize AT device */
+    result = class->device_ops->init(device);
+    if (result < 0)
+    {
+        goto __exit;
+    }
+
+__exit:
+    if (result < 0)
+    {
+        device->is_init = RT_FALSE;
+    }
+    else
+    {
+        device->is_init = RT_TRUE;
+    }
+
+    return RT_EOK;
+}