at_socket_m26.c 19 KB

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