Browse Source

🐞 fix(socket): 修复esp32多socket连接时的异常

1. 调整device->user_data; 到struct at_device_esp32 节省user_data使用
2. 增加设备hostname操作
3. 增加ap扫描操作
4. 补全server模式下urc操作
5. 调整esp32_socket_event_send中暂存的socket为urc_socket
6. 增加server模式下关闭listen操作
7. 避免使用 &(device->sockets[device_socket]); 操作未初始化的socket句柄
蒙蒙plus 1 month ago
parent
commit
cea8ddf0d9

+ 91 - 6
class/esp32/at_device_esp32.c

@@ -431,7 +431,7 @@ static int esp32_netdev_ping(struct netdev *netdev, const char *host,
         goto __exit;
     }
 
-    if (at_resp_parse_line_args_by_kw(resp, "+", (esp32_get_at_version() <= ESP32_DEFAULT_AT_VERSION_NUM) ? 
+    if (at_resp_parse_line_args_by_kw(resp, "+", (esp32_get_at_version() <= ESP32_DEFAULT_AT_VERSION_NUM) ?
                                       "+%d" : "+PING:%d", &req_time) < 0)
     {
         result = -RT_ERROR;
@@ -615,7 +615,7 @@ static void esp32_init_thread_entry(void *parameter)
 #define INIT_RETRY    5
 
     struct at_device *device = (struct at_device *) parameter;
-    struct at_device_esp32 *esp32 = (struct at_device_esp32 *) device->user_data;
+    struct at_device_esp32 *esp32 = (struct at_device_esp32 *)rt_container_of(device, struct at_device_esp32, device);
     struct at_client *client = device->client;
     at_response_t resp = RT_NULL;
     rt_err_t result = RT_EOK;
@@ -784,7 +784,7 @@ static const struct at_urc urc_table[] =
 
 static int esp32_init(struct at_device *device)
 {
-    struct at_device_esp32 *esp32 = (struct at_device_esp32 *) device->user_data;
+    struct at_device_esp32 *esp32 = rt_container_of(device, struct at_device_esp32, device);
 
     /* initialize AT client */
 #if RT_VER_NUM >= 0x50100
@@ -823,8 +823,27 @@ static int esp32_deinit(struct at_device *device)
 {
     return esp32_netdev_set_down(device->netdev);
 }
+/**
+ * Set the host name of the ESP32 device.
+ *
+ * @param device    Pointer to the AT device structure.
+ * @param host_name Host name string to set for the ESP32 device.
+ *
+ * @return RT_EOK on success, -RT_ERROR on failure.
+ */
+static int esp32_set_host_name(struct at_device *device, const char *host_name)
+{
+    int result = RT_EOK;
+    struct at_client *client = device->client;
+    if (host_name == RT_NULL || device->is_init == RT_FALSE)
+    {
+        return -RT_ERROR;
+    }
+    result = at_obj_exec_cmd(client, RT_NULL, "AT+CWHOSTNAME=\"%s\"", host_name);
+    return result;
+}
 
-/* reset eap8266 device and initialize device network again */
+/* reset esp32 device and initialize device network again */
 static int esp32_reset(struct at_device *device)
 {
     int result = RT_EOK;
@@ -849,7 +868,7 @@ static int esp32_reset(struct at_device *device)
     return result;
 }
 
-/* change eap8266 wifi ssid and password information */
+/* change esp32 wifi ssid and password information */
 static int esp32_wifi_info_set(struct at_device *device, struct at_device_ssid_pwd *info)
 {
     int result = RT_EOK;
@@ -910,6 +929,9 @@ static int esp32_control(struct at_device *device, int cmd, void *arg)
     case AT_DEVICE_CTRL_SET_WIFI_INFO:
         result = esp32_wifi_info_set(device, (struct at_device_ssid_pwd *) arg);
         break;
+    case AT_DEVICE_CTRL_SET_HOST_NAME:
+        result = esp32_set_host_name(device, (const char *)arg);
+        break;
     default:
         LOG_E("input error control cmd(%d).", cmd);
         break;
@@ -972,7 +994,6 @@ unsigned int esp32_at_version_to_hex(const char *str)
     {
         if (rt_sscanf(version_start, "AT version:%d.%d.%d.%d", &numbers[0], &numbers[1], &numbers[2], &numbers[3]) == 4)
         {
-
             hex_number = (numbers[0] << 24) | (numbers[1] << 16) | (numbers[2] << 8) | numbers[3];
         }
         else
@@ -999,4 +1020,68 @@ unsigned int esp32_get_at_version(void)
 {
     return ESP32_GMR_AT_VERSION;
 }
+int esp32_scan_ap(struct at_device *device, at_ap_info_t *ap_info, uint8_t num)
+{
+
+    int result = RT_EOK;
+    struct at_client *client = device->client;
+    struct at_response *resp = RT_NULL;
+    uint8_t ap_count = 0;
+
+    RT_ASSERT(device && ap_info && num);
+
+    resp = at_create_resp(2048, 0, 20 * RT_TICK_PER_SECOND);
+    if (resp == RT_NULL)
+    {
+        LOG_E("no memory for resp create.");
+        return 0;
+    }
+
+    if (at_obj_exec_cmd(client, resp, "AT+CWLAP") < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+    //+CWLAP:(3,"HONOR 20",-51,"22:a6:f3:40:da:3d",1)
+
+    at_ap_info_t *ap_info_ptr;
+    for (int i = 1; i <= resp->line_counts && ap_count < num; i++)
+    {
+        ap_info_ptr = &ap_info[ap_count];
+        char mac[32];
+        int temp_ecn, temp_rssi, temp_channel;
+        if (at_resp_parse_line_args(resp, i,
+                                    "%*[^(](%d,\"%31[^\"]\",%d,\"%31[^\"]\",%d)",
+                                    &temp_ecn, ap_info_ptr->ssid, &temp_rssi,
+                                    mac, &temp_channel) == 5)
+        {
+            ap_info_ptr->ecn = (uint8_t)temp_ecn;
+            ap_info_ptr->rssi = (int8_t)temp_rssi;
+            ap_info_ptr->channel = (uint8_t)temp_channel;
+            rt_uint32_t mac_addr[6] = {0};
+            rt_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 (int j = 0; j < 6; j++)
+            {
+                ap_info_ptr->mac[j] = (uint8_t)mac_addr[j];
+            }
+            ap_count++;
+        }
+    }
+__exit:
+
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+    if (result != RT_EOK)
+    {
+        return 0;
+    }
+    else
+    {
+        return ap_count;
+    }
+}
 #endif /* AT_DEVICE_USING_ESP32 */

+ 11 - 1
class/esp32/at_device_esp32.h

@@ -34,9 +34,17 @@ struct at_device_esp32
     size_t recv_line_num;
     struct at_device device;
 
+    uint16_t urc_socket;
     void *user_data;
 };
-
+typedef struct at_AP_INFO
+{
+    uint8_t ecn;       /* 加密方式 */
+    char ssid[32];     /* 无线网络名称,最多31字节 + 终止符 */
+    int8_t rssi;       /* 信号强度 */
+    uint8_t mac[6];    /* MAC地址 */
+    uint8_t channel;   /* 频道 */
+} at_ap_info_t;
 #ifdef AT_USING_SOCKET
 
 /* esp32 device socket initialize */
@@ -52,6 +60,8 @@ unsigned int esp32_at_version_to_hex(const char *str);
 unsigned int esp32_get_at_version(void);
 #endif /* AT_USING_SOCKET */
 
+/* scan the AP information */
+int esp32_scan_ap(struct at_device *device, at_ap_info_t *ap_info, uint8_t num);
 #ifdef __cplusplus
 }
 #endif

+ 117 - 15
class/esp32/at_socket_esp32.c

@@ -32,10 +32,12 @@
 #define ESP32_EVENT_SEND_FAIL        (1L << 5)
 
 static at_evt_cb_t at_evt_cb_set[] = {
-        [AT_SOCKET_EVT_RECV] = NULL,
+        [AT_SOCKET_EVT_RECV]   = NULL,
         [AT_SOCKET_EVT_CLOSED] = NULL,
+#ifdef AT_USING_SOCKET_SERVER
+        [AT_SOCKET_EVT_CONNECTED] = NULL,
+#endif
 };
-
 static int esp32_socket_event_send(struct at_device *device, uint32_t event)
 {
     return (int) rt_event_send(device->socket_event, event);
@@ -79,8 +81,21 @@ static int esp32_socket_close(struct at_socket *socket)
         return -RT_ENOMEM;
     }
 
-    result = at_obj_exec_cmd(device->client, resp, "AT+CIPCLOSE=%d", device_socket);
-
+#ifdef AT_USING_SOCKET_SERVER
+    if (socket->listen.is_listen)
+    {
+        result = at_obj_exec_cmd(device->client, resp, "AT+CIPSERVER=0");
+    }
+    else
+#endif
+    /* Note: Upstream at_closesocket sets state to AT_SOCKET_CLOSED before calling
+        * this function. Checking == AT_SOCKET_CLOSED here ensures we send CIPCLOSE
+        * during normal close flow while avoiding duplicate commands if already closed.
+        */
+    if (socket->state == AT_SOCKET_CLOSED)
+    {
+        result = at_obj_exec_cmd(device->client, resp, "AT+CIPCLOSE=%d", device_socket);
+    }
     if (resp)
     {
         at_delete_resp(resp);
@@ -172,6 +187,81 @@ __exit:
     return result;
 }
 
+#ifdef AT_USING_SOCKET_SERVER
+static void urc_connected_func(struct at_client *client, const char *data, rt_size_t size)
+{
+    int socket;
+    struct at_device *device             = RT_NULL;
+    char socket_info[AT_SOCKET_INFO_LEN] = {0};
+    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 device(%s) failed.", client_name);
+        return;
+    }
+
+    rt_sscanf(data, "%d,CONNECT", &socket);
+    rt_memset(&socket_info[0], 0, AT_SOCKET_INFO_LEN);
+    rt_sprintf(&socket_info[0], "SOCKET:%d", socket);
+
+    /* notice at socket to alloc a new socket */
+    if (at_evt_cb_set[AT_SOCKET_EVT_CONNECTED])
+    {
+        at_evt_cb_set[AT_SOCKET_EVT_CONNECTED](RT_NULL, AT_SOCKET_EVT_CONNECTED, &socket_info[0], AT_SOCKET_INFO_LEN);
+    }
+}
+/**
+ * Listen for incoming connections on a TCP server socket using AT commands.
+ *
+ * @param socket current socket
+ * @param backlog waiting to handle work, useless in "at mode"
+ *
+ * @return   0: listen success
+ *          -1: listen failed, send commands error or type error
+ */
+int esp32_socket_listen(struct at_socket *socket, int backlog)
+{
+    int result               = RT_EOK;
+    at_response_t resp       = RT_NULL;
+    struct at_device *device = RT_NULL;
+    int listen_port;
+
+    listen_port = (int)socket->listen.port;
+
+    device = socket->device;
+    if (device == RT_NULL)
+    {
+        LOG_E("get first init 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 resp create.");
+        return -RT_ENOMEM;
+    }
+
+    /* AT+CIPSERVER=1,<port> */
+    if (at_obj_exec_cmd(device->client, resp, "AT+CIPSERVER=1,%d", listen_port) < 0)
+    {
+        result = -RT_ERROR;
+        goto __exit;
+    }
+
+__exit:
+    if (resp)
+    {
+        at_delete_resp(resp);
+    }
+
+    return result;
+}
+#endif
 /**
  * send data to server or client by AT commands.
  *
@@ -193,13 +283,13 @@ static int esp32_socket_send(struct at_socket *socket, const char *buff, size_t
     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_esp32 *esp32 = (struct at_device_esp32 *) device->user_data;
+    struct at_device_esp32 *esp32 = rt_container_of(device, struct at_device_esp32, device);
     rt_mutex_t lock = at_device_get_client_lock(device);
 
     RT_ASSERT(buff);
     RT_ASSERT(bfsz > 0);
 
-    resp = at_create_resp(128, 2, 5 * RT_TICK_PER_SECOND);
+    resp = at_create_resp(128, 0, 5 * RT_TICK_PER_SECOND);
     if (resp == RT_NULL)
     {
         LOG_E("no memory for resp create.");
@@ -209,7 +299,7 @@ static int esp32_socket_send(struct at_socket *socket, const char *buff, size_t
     rt_mutex_take(lock, RT_WAITING_FOREVER);
 
     /* set current socket for send URC event */
-    esp32->user_data = (void *) device_socket;
+    esp32->urc_socket = device_socket;
 
     /* set AT client end sign to deal with '>' sign */
     at_obj_set_end_sign(device->client, '>');
@@ -356,7 +446,6 @@ __exit:
     }
 
     return result;
-
 }
 
 /**
@@ -383,6 +472,9 @@ static const struct at_socket_ops esp32_socket_ops =
 #if defined(AT_SW_VERSION_NUM) && AT_SW_VERSION_NUM > 0x10300
     RT_NULL,
 #endif
+#ifdef AT_USING_SOCKET_SERVER
+    esp32_socket_listen,
+#endif
 };
 
 static void urc_send_func(struct at_client *client, const char *data, rt_size_t size)
@@ -400,8 +492,8 @@ static void urc_send_func(struct at_client *client, const char *data, rt_size_t
         LOG_E("get device(%s) failed.", client_name);
         return;
     }
-    esp32 = (struct at_device_esp32 *) device->user_data;
-    device_socket = (int) esp32->user_data;
+    esp32         = rt_container_of(device, struct at_device_esp32, device);
+    device_socket = esp32->urc_socket;
 
     if (rt_strstr(data, "SEND OK"))
     {
@@ -424,7 +516,7 @@ static void urc_send_bfsz_func(struct at_client *client, const char *data, rt_si
 
 static void urc_close_func(struct at_client *client, const char *data, rt_size_t size)
 {
-    int index = 0;
+    int device_socket = 0;
     struct at_socket *socket = RT_NULL;
     struct at_device *device = RT_NULL;
     char *client_name = client->device->parent.name;
@@ -438,8 +530,12 @@ static void urc_close_func(struct at_client *client, const char *data, rt_size_t
         return;
     }
 
-    rt_sscanf(data, "%d,CLOSED", &index);
-    socket = &(device->sockets[index]);
+    rt_sscanf(data, "%d,CLOSED", &device_socket);
+#ifdef AT_USING_SOCKET_SERVER
+    socket = at_get_base_socket(device_socket);
+#else
+    socket = at_get_socket(device_socket);
+#endif
 
     /* notice the socket is disconnect by remote */
     if (at_evt_cb_set[AT_SOCKET_EVT_CLOSED])
@@ -505,8 +601,11 @@ static void urc_recv_func(struct at_client *client, const char *data, rt_size_t
     }
 
     /* get at socket object by device socket descriptor */
-    socket = &(device->sockets[device_socket]);
-
+#ifdef AT_USING_SOCKET_SERVER
+    socket = at_get_base_socket(device_socket);
+#else
+    socket = at_get_socket(device_socket);
+#endif
     /* notice the receive buffer and buffer size */
     if (at_evt_cb_set[AT_SOCKET_EVT_RECV])
     {
@@ -521,6 +620,9 @@ static const struct at_urc urc_table[] =
     {"Recv",             "bytes\r\n",      urc_send_bfsz_func},
     {"",                 ",CLOSED\r\n",    urc_close_func},
     {"+IPD",             ":",              urc_recv_func},
+#ifdef AT_USING_SOCKET_SERVER
+    {"", ",CONNECT\r\n", urc_connected_func},
+#endif
 };
 
 int esp32_socket_init(struct at_device *device)

+ 1 - 1
inc/at_device.h

@@ -71,7 +71,7 @@ extern "C" {
 #define AT_DEVICE_CTRL_GET_SIGNAL      0x0AL
 #define AT_DEVICE_CTRL_GET_GPS         0x0BL
 #define AT_DEVICE_CTRL_GET_VER         0x0CL
-
+#define AT_DEVICE_CTRL_SET_HOST_NAME   0x0DL
 /* Name type */
 #define AT_DEVICE_NAMETYPE_DEVICE      0x01
 #define AT_DEVICE_NAMETYPE_NETDEV      0x02

+ 1 - 1
samples/at_sample_esp32.c

@@ -33,6 +33,6 @@ static int esp32_device_register(void)
                               esp32->device_name,
                               esp32->client_name,
                               AT_DEVICE_CLASS_ESP32,
-                              (void *) esp32);
+                              (void *) NULL);
 }
 INIT_APP_EXPORT(esp32_device_register);