at_socket_a9g.c 17 KB

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