at_socket_n21.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2020-05-22 shuobatian first version
  9. */
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <at_device_n21.h>
  13. #if !defined(AT_SW_VERSION_NUM) || AT_SW_VERSION_NUM < 0x10300
  14. #error "This AT Client version is older, please check and update latest AT Client!"
  15. #endif
  16. #define LOG_TAG "at.skt"
  17. #include <at_log.h>
  18. #if defined(AT_DEVICE_USING_N21) && defined(AT_USING_SOCKET)
  19. #define N21_MODULE_SEND_MAX_SIZE 1000
  20. /* set real event by current socket and current state */
  21. #define SET_EVENT(socket, event) (((socket + 1) << 16) | (event))
  22. /* AT socket event type */
  23. #define N21_EVENT_CONN_OK (1L << 0)
  24. #define N21_EVENT_SEND_OK (1L << 1)
  25. #define N21_EVENT_RECV_OK (1L << 2)
  26. #define N21_EVNET_CLOSE_OK (1L << 3)
  27. #define N21_EVENT_CONN_FAIL (1L << 4)
  28. #define N21_EVENT_SEND_FAIL (1L << 5)
  29. static at_evt_cb_t at_evt_cb_set[] = {
  30. [AT_SOCKET_EVT_RECV] = NULL,
  31. [AT_SOCKET_EVT_CLOSED] = NULL,
  32. };
  33. static int n21_socket_event_send(struct at_device *device, uint32_t event)
  34. {
  35. return (int)rt_event_send(device->socket_event, event);
  36. }
  37. static int n21_socket_event_recv(struct at_device *device, uint32_t event, uint32_t timeout, rt_uint8_t option)
  38. {
  39. int result = RT_EOK;
  40. rt_uint32_t recved;
  41. result = rt_event_recv(device->socket_event, event, option | RT_EVENT_FLAG_CLEAR, timeout, &recved);
  42. if (result != RT_EOK)
  43. {
  44. return -RT_ETIMEOUT;
  45. }
  46. return recved;
  47. }
  48. /**
  49. * close socket by AT commands.
  50. *
  51. * @param current socket
  52. *
  53. * @return 0: close socket success
  54. * -1: send AT commands error
  55. * -2: wait socket event timeout
  56. * -5: no memory
  57. */
  58. static int n21_socket_close(struct at_socket *socket)
  59. {
  60. uint32_t event = 0;
  61. int result = RT_EOK;
  62. int device_socket = (int)socket->user_data;
  63. enum at_socket_type type_socket = socket->type;
  64. struct at_device *device = (struct at_device *)socket->device;
  65. /* clear socket close event */
  66. event = SET_EVENT(device_socket, N21_EVNET_CLOSE_OK);
  67. n21_socket_event_recv(device, event, 0, RT_EVENT_FLAG_OR);
  68. if (type_socket == AT_SOCKET_TCP)
  69. {
  70. if (at_obj_exec_cmd(device->client, NULL, "AT+TCPCLOSE=%d", device_socket) < 0)
  71. {
  72. result = -RT_ERROR;
  73. goto __exit;
  74. }
  75. }
  76. else if (type_socket == AT_SOCKET_UDP)
  77. {
  78. if (at_obj_exec_cmd(device->client, NULL, "AT+UDPCLOSE=%d", device_socket) < 0)
  79. {
  80. result = -RT_ERROR;
  81. goto __exit;
  82. }
  83. }
  84. if (n21_socket_event_recv(device, event, rt_tick_from_millisecond(300 * 3), RT_EVENT_FLAG_AND) < 0)
  85. {
  86. LOG_E("n21 device(%s) socket(%d) close failed, wait close OK timeout.", device->name, device_socket);
  87. result = -RT_ETIMEOUT;
  88. goto __exit;
  89. }
  90. __exit:
  91. return result;
  92. }
  93. /**
  94. * create TCP/UDP client or server connect by AT commands.
  95. *
  96. * @param socket current socket
  97. * @param ip server or client IP address
  98. * @param port server or client port
  99. * @param type connect socket type(tcp, udp)
  100. * @param is_client connection is client
  101. *
  102. * @return 0: connect success
  103. * -1: connect failed, send commands error or type error
  104. * -2: wait socket event timeout
  105. * -5: no memory
  106. */
  107. static int n21_socket_connect(struct at_socket *socket, char *ip, int32_t port, enum at_socket_type type, rt_bool_t is_client)
  108. {
  109. uint32_t event = 0;
  110. rt_bool_t retryed = RT_FALSE;
  111. at_response_t resp = RT_NULL;
  112. int result = RT_EOK, event_result = 0;
  113. int device_socket = (int)socket->user_data;
  114. struct at_device *device = (struct at_device *)socket->device;
  115. RT_ASSERT(ip);
  116. RT_ASSERT(port >= 0);
  117. resp = at_create_resp(128, 0, 5 * RT_TICK_PER_SECOND);
  118. if (resp == RT_NULL)
  119. {
  120. LOG_E("no memory for n21 device(%s) response structure.", device->name);
  121. return -RT_ENOMEM;
  122. }
  123. __retry:
  124. /* clear socket connect event */
  125. event = SET_EVENT(device_socket, N21_EVENT_CONN_OK | N21_EVENT_CONN_FAIL);
  126. n21_socket_event_recv(device, event, 0, RT_EVENT_FLAG_OR);
  127. if (is_client)
  128. {
  129. switch (type)
  130. {
  131. case AT_SOCKET_TCP:
  132. /* send AT commands(eg: AT+TCPSETUP=<n>,<ip>,<port>) to connect TCP server */
  133. if (at_obj_exec_cmd(device->client, RT_NULL,
  134. "AT+TCPSETUP=%d,%s,%d", device_socket, ip, port) < 0)
  135. {
  136. result = -RT_ERROR;
  137. goto __exit;
  138. }
  139. break;
  140. /* send AT commands(eg: AT+UDPSETUP=<n>,<ip>,<port>) to connect TCP server */
  141. case AT_SOCKET_UDP:
  142. if (at_obj_exec_cmd(device->client, RT_NULL,
  143. "AT+UDPSETUP=%d,%s,%d", device_socket, ip, port) < 0)
  144. {
  145. result = -RT_ERROR;
  146. goto __exit;
  147. }
  148. break;
  149. default:
  150. LOG_E("n21 device(%s) not supported connect type : %d.", device->name, type);
  151. result = -RT_ERROR;
  152. goto __exit;
  153. }
  154. }
  155. /* waiting result event from AT URC, the device default connection timeout is 75 seconds, but it set to 10 seconds is convenient to use */
  156. if (n21_socket_event_recv(device, SET_EVENT(device_socket, 0), 10 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR) < 0)
  157. {
  158. LOG_E("n21 device(%s) socket(%d) connect failed, wait connect result timeout.", device->name, device_socket);
  159. result = -RT_ETIMEOUT;
  160. goto __exit;
  161. }
  162. /* waiting OK or failed result */
  163. event_result = n21_socket_event_recv(device,
  164. N21_EVENT_CONN_OK | N21_EVENT_CONN_FAIL, 1 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR);
  165. if (event_result < 0)
  166. {
  167. LOG_E("n21 device(%s) socket(%d) connect failed, wait connect OK|FAIL timeout.", device->name, device_socket);
  168. result = -RT_ETIMEOUT;
  169. goto __exit;
  170. }
  171. /* check result */
  172. if (event_result & N21_EVENT_CONN_FAIL)
  173. {
  174. if (retryed == RT_FALSE)
  175. {
  176. LOG_D("n21 device(%s) socket(%d) connect failed, maybe the socket was not be closed at the last time and now will retry.",
  177. device->name, device_socket);
  178. if (n21_socket_close(socket) < 0)
  179. {
  180. result = -RT_ERROR;
  181. goto __exit;
  182. }
  183. retryed = RT_TRUE;
  184. goto __retry;
  185. }
  186. LOG_E("n21 device(%s) socket(%d) connect failed.", device->name, device_socket);
  187. result = -RT_ERROR;
  188. goto __exit;
  189. }
  190. __exit:
  191. if (resp)
  192. {
  193. at_delete_resp(resp);
  194. }
  195. return result;
  196. }
  197. /**
  198. * send data to server or client by AT commands.
  199. *
  200. * @param socket current socket
  201. * @param buff send buffer
  202. * @param bfsz send buffer size
  203. * @param type connect socket type(tcp, udp)
  204. *
  205. * @return >=0: the size of send success
  206. * -1: send AT commands error or send data error
  207. * -2: waited socket event timeout
  208. * -5: no memory
  209. */
  210. static int n21_socket_send(struct at_socket *socket, const char *buff, size_t bfsz, enum at_socket_type type)
  211. {
  212. uint32_t event = 0;
  213. int result = RT_EOK, event_result = 0;
  214. size_t cur_pkt_size = 0, sent_size = 0;
  215. at_response_t resp = RT_NULL;
  216. int device_socket = (int)socket->user_data;
  217. struct at_device *device = (struct at_device *)socket->device;
  218. rt_mutex_t lock = at_device_get_client_lock(device);
  219. RT_ASSERT(buff);
  220. resp = at_create_resp(128, 2, 10 * RT_TICK_PER_SECOND);
  221. if (resp == RT_NULL)
  222. {
  223. LOG_E("no memory for n21 device(%s) response structure.", device->name);
  224. return -RT_ENOMEM;
  225. }
  226. rt_mutex_take(lock, RT_WAITING_FOREVER);
  227. /* clear socket connect event */
  228. event = SET_EVENT(device_socket, N21_EVENT_SEND_OK | N21_EVENT_SEND_FAIL);
  229. n21_socket_event_recv(device, event, 0, RT_EVENT_FLAG_OR);
  230. /* set AT client end sign to deal with '>' sign.*/
  231. at_obj_set_end_sign(device->client, '>');
  232. while (sent_size < bfsz)
  233. {
  234. if (bfsz - sent_size < N21_MODULE_SEND_MAX_SIZE)
  235. {
  236. cur_pkt_size = bfsz - sent_size;
  237. }
  238. else
  239. {
  240. cur_pkt_size = N21_MODULE_SEND_MAX_SIZE;
  241. }
  242. /* send the "AT+QISEND" commands to AT server than receive the '>' response on the first line. */
  243. if (type == AT_SOCKET_TCP)
  244. {
  245. if (at_obj_exec_cmd(device->client, resp, "AT+TCPSEND=%d,%d", device_socket, cur_pkt_size) < 0)
  246. {
  247. result = -RT_ERROR;
  248. goto __exit;
  249. }
  250. }
  251. else if (type == AT_SOCKET_UDP)
  252. {
  253. if (at_obj_exec_cmd(device->client, resp, "AT+UDPSEND=%d,%d", device_socket, cur_pkt_size) < 0)
  254. {
  255. result = -RT_ERROR;
  256. goto __exit;
  257. }
  258. }
  259. rt_thread_mdelay(100); //n21 要求收到> 等待50-100ms 发送数据
  260. /* send the real data to server or client */
  261. result = (int)at_client_obj_send(device->client, buff + sent_size, cur_pkt_size);
  262. if (result == 0)
  263. {
  264. result = -RT_ERROR;
  265. goto __exit;
  266. }
  267. /* waiting OK or failed result */
  268. event_result = n21_socket_event_recv(device,
  269. N21_EVENT_SEND_OK | N21_EVENT_SEND_FAIL, 5 * RT_TICK_PER_SECOND, RT_EVENT_FLAG_OR);
  270. if (event_result < 0)
  271. {
  272. LOG_E("n21 device(%s) socket(%d) send failed, wait connect OK|FAIL timeout.", device->name, device_socket);
  273. result = -RT_ETIMEOUT;
  274. goto __exit;
  275. }
  276. /* check result */
  277. if (event_result & N21_EVENT_SEND_FAIL)
  278. {
  279. LOG_E("n21 device(%s) socket(%d) send failed.", device->name, device_socket);
  280. result = -RT_ERROR;
  281. goto __exit;
  282. }
  283. sent_size += cur_pkt_size;
  284. }
  285. __exit:
  286. /* reset the end sign for data conflict */
  287. at_obj_set_end_sign(device->client, 0);
  288. rt_mutex_release(lock);
  289. if (resp)
  290. {
  291. at_delete_resp(resp);
  292. }
  293. return result;
  294. }
  295. /**
  296. * domain resolve by AT commands.
  297. *
  298. * @param name domain name
  299. * @param ip parsed IP address, it's length must be 16
  300. *
  301. * @return 0: domain resolve success
  302. * -1: send AT commands error or response error
  303. * -2: wait socket event timeout
  304. * -5: no memory
  305. */
  306. static int n21_domain_resolve(const char *name, char ip[16])
  307. {
  308. #define RESOLVE_RETRY 5
  309. int i, result = RT_EOK;
  310. char recv_ip[16] = {0};
  311. at_response_t resp = RT_NULL;
  312. struct at_device *device = RT_NULL;
  313. RT_ASSERT(name);
  314. RT_ASSERT(ip);
  315. device = at_device_get_first_initialized();
  316. if (device == RT_NULL)
  317. {
  318. LOG_E("get first initialization n21 device failed.");
  319. return -RT_ERROR;
  320. }
  321. /* The maximum response time is 14 seconds, affected by network status */
  322. resp = at_create_resp(128, 4, 14 * RT_TICK_PER_SECOND);
  323. if (resp == RT_NULL)
  324. {
  325. LOG_E("no memory for n21 device(%s) response structure.", device->name);
  326. return -RT_ENOMEM;
  327. }
  328. for (i = 0; i < RESOLVE_RETRY; i++)
  329. {
  330. int err_code = 0;
  331. if (at_obj_exec_cmd(device->client, resp, "AT+CDNSGIP=\"%s\"", name) < 0)
  332. {
  333. result = -RT_ERROR;
  334. goto __exit;
  335. }
  336. /* domain name prase error options */
  337. if (at_resp_parse_line_args_by_kw(resp, "+CDNSGIP: 0", "+CDNSGIP: 0,%d", &err_code) > 0)
  338. {
  339. /* 3 - network error, 8 - dns common error */
  340. if (err_code == 3 || err_code == 8)
  341. {
  342. result = -RT_ERROR;
  343. goto __exit;
  344. }
  345. }
  346. /* parse the third line of response data, get the IP address */
  347. if (at_resp_parse_line_args_by_kw(resp, "+CDNSGIP:", "%*[^,],%*[^,],\"%[^\"]", recv_ip) < 0)
  348. {
  349. rt_thread_mdelay(100);
  350. /* resolve failed, maybe receive an URC CRLF */
  351. continue;
  352. }
  353. if (rt_strlen(recv_ip) < 8)
  354. {
  355. rt_thread_mdelay(100);
  356. /* resolve failed, maybe receive an URC CRLF */
  357. continue;
  358. }
  359. else
  360. {
  361. rt_thread_mdelay(10);
  362. rt_strncpy(ip, recv_ip, 15);
  363. ip[15] = '\0';
  364. break;
  365. }
  366. }
  367. __exit:
  368. if (resp)
  369. {
  370. at_delete_resp(resp);
  371. }
  372. return result;
  373. }
  374. /**
  375. * set AT socket event notice callback
  376. *
  377. * @param event notice event
  378. * @param cb notice callback
  379. */
  380. static void n21_socket_set_event_cb(at_socket_evt_t event, at_evt_cb_t cb)
  381. {
  382. if (event < sizeof(at_evt_cb_set) / sizeof(at_evt_cb_set[1]))
  383. {
  384. at_evt_cb_set[event] = cb;
  385. }
  386. }
  387. static void urc_connect_func(struct at_client *client, const char *data, rt_size_t size)
  388. {
  389. int device_socket = 0;
  390. struct at_device *device = RT_NULL;
  391. char *client_name = client->device->parent.name;
  392. char constat[16] = {0};
  393. RT_ASSERT(data && size);
  394. device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
  395. if (device == RT_NULL)
  396. {
  397. LOG_E("get n21 device by client name(%s) failed.", client_name);
  398. return;
  399. }
  400. /* get the current socket by receive data */
  401. rt_sscanf(data, "%*[^ ]%d,%s\r\n", &device_socket, constat);
  402. LOG_D("data:%s", data);
  403. LOG_D("socket:%d,constat:%s", device_socket, constat);
  404. if (strstr(constat, "OK"))
  405. {
  406. LOG_D("socket %d:connect ok!", device_socket);
  407. n21_socket_event_send(device, SET_EVENT(device_socket, N21_EVENT_CONN_OK));
  408. }
  409. else if (strstr(constat, "FAIL"))
  410. {
  411. LOG_D("socket %d:connect fail!", device_socket);
  412. n21_socket_event_send(device, SET_EVENT(device_socket, N21_EVENT_CONN_FAIL));
  413. }
  414. }
  415. static void urc_send_func(struct at_client *client, const char *data, rt_size_t size)
  416. {
  417. int device_socket = 0;
  418. struct at_device *device = RT_NULL;
  419. char *client_name = client->device->parent.name;
  420. RT_ASSERT(data && size);
  421. device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
  422. if (device == RT_NULL)
  423. {
  424. LOG_E("get n21 device by client name(%s) failed.", client_name);
  425. return;
  426. }
  427. /* get the current socket by receive data */
  428. rt_sscanf(data, "%*[^ ] %d,%*d", &device_socket);
  429. if (rt_strstr(data, "OPERATION"))
  430. {
  431. LOG_E("input data timeout!");
  432. n21_socket_event_send(device, SET_EVENT(device_socket, N21_EVENT_SEND_FAIL));
  433. }
  434. else if (rt_strstr(data, "ERROR")) //链路号错误
  435. {
  436. n21_socket_event_send(device, SET_EVENT(device_socket, N21_EVENT_SEND_FAIL));
  437. }
  438. else //没有错误就是成功
  439. {
  440. n21_socket_event_send(device, SET_EVENT(device_socket, N21_EVENT_SEND_OK));
  441. }
  442. }
  443. static void urc_close_func(struct at_client *client, const char *data, rt_size_t size)
  444. {
  445. int device_socket = 0;
  446. struct at_device *device = RT_NULL;
  447. char *client_name = client->device->parent.name;
  448. RT_ASSERT(data && size);
  449. device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
  450. if (device == RT_NULL)
  451. {
  452. LOG_E("get n21 device by client name(%s) failed.", client_name);
  453. return;
  454. }
  455. /* get the current socket by receive data */
  456. /* +TCPCLOSE: 1,OK */
  457. rt_sscanf(data, "%*[^ ]%d,%*s", &device_socket);
  458. if (rt_strstr(data, "OK"))
  459. {
  460. n21_socket_event_send(device, SET_EVENT(device_socket, N21_EVNET_CLOSE_OK));
  461. }
  462. else if (rt_strstr(data, "Link Closed"))
  463. {
  464. struct at_socket *socket = RT_NULL;
  465. /* get AT socket object by device socket descriptor */
  466. socket = &(device->sockets[device_socket]);
  467. /* notice the socket is disconnect by remote */
  468. if (at_evt_cb_set[AT_SOCKET_EVT_CLOSED])
  469. {
  470. at_evt_cb_set[AT_SOCKET_EVT_CLOSED](socket, AT_SOCKET_EVT_CLOSED, RT_NULL, 0);
  471. }
  472. }
  473. }
  474. static void urc_recv_func(struct at_client *client, const char *data, rt_size_t size)
  475. {
  476. int device_socket = 0;
  477. rt_size_t bfsz = 0;
  478. int data_index = size - 1;
  479. char *recv_buf = RT_NULL;
  480. struct at_socket *socket = RT_NULL;
  481. struct at_device *device = RT_NULL;
  482. char *client_name = client->device->parent.name;
  483. RT_ASSERT(data && size);
  484. /* get the current socket and receive buffer size by receive data */
  485. rt_sscanf(data, "%*[^ ] %d,%d,", &device_socket, (int *)&bfsz);
  486. recv_buf = (char *)rt_calloc(1, bfsz + 1);
  487. if (recv_buf == RT_NULL)
  488. {
  489. LOG_E("no memory for n21 device(%s) URC receive buffer (%d).", device->name, bfsz);
  490. return;
  491. }
  492. data_index -= 2; //"\r\n"移除
  493. recv_buf[bfsz] = '\0';
  494. for (int i = bfsz - 1; i >= 0; i--)
  495. {
  496. recv_buf[i] = data[data_index];
  497. data_index--;
  498. }
  499. /* get receive timeout by receive buffer length */
  500. LOG_D("recv socket:%d", device_socket);
  501. if (device_socket < 0 || bfsz == 0)
  502. {
  503. return;
  504. }
  505. device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
  506. if (device == RT_NULL)
  507. {
  508. LOG_E("get n21 device by client name(%s) failed.", client_name);
  509. return;
  510. }
  511. /* get AT socket object by device socket descriptor */
  512. socket = &(device->sockets[device_socket]);
  513. /* notice the receive buffer and buffer size */
  514. if (at_evt_cb_set[AT_SOCKET_EVT_RECV])
  515. {
  516. at_evt_cb_set[AT_SOCKET_EVT_RECV](socket, AT_SOCKET_EVT_RECV, recv_buf, bfsz);
  517. }
  518. }
  519. /* n21 device URC table for the socket data */
  520. static const struct at_urc urc_table[] =
  521. {
  522. {"+TCPSETUP:", "\r\n", urc_connect_func},
  523. {"+UDPSETUP:", "\r\n", urc_connect_func},
  524. {"+TCPSEND:", "\r\n", urc_send_func},
  525. {"+UDPSEND:", "\r\n", urc_send_func},
  526. {"+TCPCLOSE:", "\r\n", urc_close_func},
  527. {"+UDPCLOSE:", "\r\n", urc_close_func},
  528. {"+TCPRECV:", "\r\n", urc_recv_func},
  529. {"+UDPRECV:", "\r\n", urc_recv_func},
  530. };
  531. static const struct at_socket_ops n21_socket_ops =
  532. {
  533. n21_socket_connect,
  534. n21_socket_close,
  535. n21_socket_send,
  536. n21_domain_resolve,
  537. n21_socket_set_event_cb,
  538. #if defined(AT_SW_VERSION_NUM) && AT_SW_VERSION_NUM > 0x10300
  539. RT_NULL,
  540. #endif
  541. };
  542. int n21_socket_init(struct at_device *device)
  543. {
  544. RT_ASSERT(device);
  545. /* register URC data execution function */
  546. at_obj_set_urc_table(device->client, urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
  547. return RT_EOK;
  548. }
  549. int n21_socket_class_register(struct at_device_class *class)
  550. {
  551. RT_ASSERT(class);
  552. class->socket_num = AT_DEVICE_N21_SOCKETS_NUM;
  553. class->socket_ops = &n21_socket_ops;
  554. return RT_EOK;
  555. }
  556. #endif /* AT_DEVICE_USING_n21 && AT_USING_SOCKET */