at_client.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926
  1. /*
  2. * File : at_client.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. *
  20. * Change Logs:
  21. * Date Author Notes
  22. * 2018-03-30 chenyong first version
  23. * 2018-04-12 chenyong add client implement
  24. * 2018-08-17 chenyong multiple client support
  25. */
  26. #include <at.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #define AT_RESP_END_OK "OK"
  31. #define AT_RESP_END_ERROR "ERROR"
  32. #define AT_RESP_END_FAIL "FAIL"
  33. #define AT_END_CR_LF "\r\n"
  34. static struct at_client at_client_table[AT_CLIENT_NUM_MAX] = { 0 };
  35. extern rt_size_t at_vprintfln(rt_device_t device, const char *format, va_list args);
  36. extern void at_print_raw_cmd(const char *type, const char *cmd, rt_size_t size);
  37. extern const char *at_get_last_cmd(rt_size_t *cmd_size);
  38. /**
  39. * Create response object.
  40. *
  41. * @param buf_size the maximum response buffer size
  42. * @param line_num the number of setting response lines
  43. * = 0: the response data will auto return when received 'OK' or 'ERROR'
  44. * != 0: the response data will return when received setting lines number data
  45. * @param timeout the maximum response time
  46. *
  47. * @return != RT_NULL: response object
  48. * = RT_NULL: no memory
  49. */
  50. at_response_t at_create_resp(rt_size_t buf_size, rt_size_t line_num, rt_int32_t timeout)
  51. {
  52. at_response_t resp = RT_NULL;
  53. resp = (at_response_t) rt_calloc(1, sizeof(struct at_response));
  54. if (resp == RT_NULL)
  55. {
  56. LOG_E("AT create response object failed! No memory for response object!");
  57. return RT_NULL;
  58. }
  59. resp->buf = (char *) rt_calloc(1, buf_size);
  60. if (resp->buf == RT_NULL)
  61. {
  62. LOG_E("AT create response object failed! No memory for response buffer!");
  63. rt_free(resp);
  64. return RT_NULL;
  65. }
  66. resp->buf_size = buf_size;
  67. resp->line_num = line_num;
  68. resp->line_counts = 0;
  69. resp->timeout = timeout;
  70. return resp;
  71. }
  72. /**
  73. * Delete and free response object.
  74. *
  75. * @param resp response object
  76. */
  77. void at_delete_resp(at_response_t resp)
  78. {
  79. if (resp && resp->buf)
  80. {
  81. rt_free(resp->buf);
  82. }
  83. if (resp)
  84. {
  85. rt_free(resp);
  86. resp = RT_NULL;
  87. }
  88. }
  89. /**
  90. * Set response object information
  91. *
  92. * @param resp response object
  93. * @param buf_size the maximum response buffer size
  94. * @param line_num the number of setting response lines
  95. * = 0: the response data will auto return when received 'OK' or 'ERROR'
  96. * != 0: the response data will return when received setting lines number data
  97. * @param timeout the maximum response time
  98. *
  99. * @return != RT_NULL: response object
  100. * = RT_NULL: no memory
  101. */
  102. at_response_t at_resp_set_info(at_response_t resp, rt_size_t buf_size, rt_size_t line_num, rt_int32_t timeout)
  103. {
  104. RT_ASSERT(resp);
  105. if (resp->buf_size != buf_size)
  106. {
  107. resp->buf_size = buf_size;
  108. resp->buf = (char *) rt_realloc(resp->buf, buf_size);
  109. if (!resp->buf)
  110. {
  111. LOG_D("No memory for realloc response buffer size(%d).", buf_size);
  112. return RT_NULL;
  113. }
  114. }
  115. resp->line_num = line_num;
  116. resp->timeout = timeout;
  117. return resp;
  118. }
  119. /**
  120. * Get one line AT response buffer by line number.
  121. *
  122. * @param resp response object
  123. * @param resp_line line number, start from '1'
  124. *
  125. * @return != RT_NULL: response line buffer
  126. * = RT_NULL: input response line error
  127. */
  128. const char *at_resp_get_line(at_response_t resp, rt_size_t resp_line)
  129. {
  130. char *resp_buf = resp->buf;
  131. char *resp_line_buf = RT_NULL;
  132. rt_size_t line_num = 1;
  133. RT_ASSERT(resp);
  134. if (resp_line > resp->line_counts || resp_line <= 0)
  135. {
  136. LOG_E("AT response get line failed! Input response line(%d) error!", resp_line);
  137. return RT_NULL;
  138. }
  139. for (line_num = 1; line_num <= resp->line_counts; line_num++)
  140. {
  141. if (resp_line == line_num)
  142. {
  143. resp_line_buf = resp_buf;
  144. return resp_line_buf;
  145. }
  146. resp_buf += strlen(resp_buf) + 1;
  147. }
  148. return RT_NULL;
  149. }
  150. /**
  151. * Get one line AT response buffer by keyword
  152. *
  153. * @param resp response object
  154. * @param keyword query keyword
  155. *
  156. * @return != RT_NULL: response line buffer
  157. * = RT_NULL: no matching data
  158. */
  159. const char *at_resp_get_line_by_kw(at_response_t resp, const char *keyword)
  160. {
  161. char *resp_buf = resp->buf;
  162. char *resp_line_buf = RT_NULL;
  163. rt_size_t line_num = 1;
  164. RT_ASSERT(resp);
  165. RT_ASSERT(keyword);
  166. for (line_num = 1; line_num <= resp->line_counts; line_num++)
  167. {
  168. if (strstr(resp_buf, keyword))
  169. {
  170. resp_line_buf = resp_buf;
  171. return resp_line_buf;
  172. }
  173. resp_buf += strlen(resp_buf) + 1;
  174. }
  175. return RT_NULL;
  176. }
  177. /**
  178. * Get and parse AT response buffer arguments by line number.
  179. *
  180. * @param resp response object
  181. * @param resp_line line number, start from '1'
  182. * @param resp_expr response buffer expression
  183. *
  184. * @return -1 : input response line number error or get line buffer error
  185. * 0 : parsed without match
  186. * >0 : the number of arguments successfully parsed
  187. */
  188. int at_resp_parse_line_args(at_response_t resp, rt_size_t resp_line, const char *resp_expr, ...)
  189. {
  190. va_list args;
  191. int resp_args_num = 0;
  192. const char *resp_line_buf = RT_NULL;
  193. RT_ASSERT(resp);
  194. RT_ASSERT(resp_expr);
  195. if ((resp_line_buf = at_resp_get_line(resp, resp_line)) == RT_NULL)
  196. {
  197. return -1;
  198. }
  199. va_start(args, resp_expr);
  200. resp_args_num = vsscanf(resp_line_buf, resp_expr, args);
  201. va_end(args);
  202. return resp_args_num;
  203. }
  204. /**
  205. * Get and parse AT response buffer arguments by keyword.
  206. *
  207. * @param resp response object
  208. * @param keyword query keyword
  209. * @param resp_expr response buffer expression
  210. *
  211. * @return -1 : input keyword error or get line buffer error
  212. * 0 : parsed without match
  213. * >0 : the number of arguments successfully parsed
  214. */
  215. int at_resp_parse_line_args_by_kw(at_response_t resp, const char *keyword, const char *resp_expr, ...)
  216. {
  217. va_list args;
  218. int resp_args_num = 0;
  219. const char *resp_line_buf = RT_NULL;
  220. RT_ASSERT(resp);
  221. RT_ASSERT(resp_expr);
  222. if ((resp_line_buf = at_resp_get_line_by_kw(resp, keyword)) == RT_NULL)
  223. {
  224. return -1;
  225. }
  226. va_start(args, resp_expr);
  227. resp_args_num = vsscanf(resp_line_buf, resp_expr, args);
  228. va_end(args);
  229. return resp_args_num;
  230. }
  231. /**
  232. * Send commands to AT server and wait response.
  233. *
  234. * @param client current AT client object
  235. * @param resp AT response object, using RT_NULL when you don't care response
  236. * @param cmd_expr AT commands expression
  237. *
  238. * @return 0 : success
  239. * -1 : response status error
  240. * -2 : wait timeout
  241. */
  242. int at_obj_exec_cmd(at_client_t client, at_response_t resp, const char *cmd_expr, ...)
  243. {
  244. va_list args;
  245. rt_size_t cmd_size = 0;
  246. rt_err_t result = RT_EOK;
  247. const char *cmd = RT_NULL;
  248. RT_ASSERT(cmd_expr);
  249. if (client == RT_NULL)
  250. {
  251. LOG_E("input AT Client object is NULL, please create or get AT Client object!");
  252. return -RT_ERROR;
  253. }
  254. rt_mutex_take(client->lock, RT_WAITING_FOREVER);
  255. client->resp_status = AT_RESP_OK;
  256. client->resp = resp;
  257. va_start(args, cmd_expr);
  258. at_vprintfln(client->device, cmd_expr, args);
  259. va_end(args);
  260. if (resp != RT_NULL)
  261. {
  262. resp->line_counts = 0;
  263. if (rt_sem_take(client->resp_notice, resp->timeout) != RT_EOK)
  264. {
  265. cmd = at_get_last_cmd(&cmd_size);
  266. LOG_E("execute command (%.*s) timeout (%d ticks)!", cmd_size, cmd, resp->timeout);
  267. client->resp_status = AT_RESP_TIMEOUT;
  268. result = -RT_ETIMEOUT;
  269. goto __exit;
  270. }
  271. if (client->resp_status != AT_RESP_OK)
  272. {
  273. cmd = at_get_last_cmd(&cmd_size);
  274. LOG_E("execute command (%.*s) failed!", cmd_size, cmd);
  275. result = -RT_ERROR;
  276. goto __exit;
  277. }
  278. }
  279. __exit:
  280. client->resp = RT_NULL;
  281. rt_mutex_release(client->lock);
  282. return result;
  283. }
  284. /**
  285. * Waiting for connection to external devices.
  286. *
  287. * @param client current AT client object
  288. * @param timeout millisecond for timeout
  289. *
  290. * @return 0 : success
  291. * -2 : timeout
  292. * -5 : no memory
  293. */
  294. int at_client_obj_wait_connect(at_client_t client, rt_uint32_t timeout)
  295. {
  296. rt_err_t result = RT_EOK;
  297. at_response_t resp = RT_NULL;
  298. rt_tick_t start_time = 0;
  299. if (client == RT_NULL)
  300. {
  301. LOG_E("input AT Client object is NULL, please create or get AT Client object!");
  302. return -RT_ERROR;
  303. }
  304. resp = at_create_resp(16, 0, rt_tick_from_millisecond(500));
  305. if (resp == RT_NULL)
  306. {
  307. LOG_E("No memory for response object!");
  308. return -RT_ENOMEM;
  309. }
  310. rt_mutex_take(client->lock, RT_WAITING_FOREVER);
  311. client->resp = resp;
  312. start_time = rt_tick_get();
  313. while (1)
  314. {
  315. /* Check whether it is timeout */
  316. if (rt_tick_get() - start_time > timeout)
  317. {
  318. LOG_E("wait connect timeout (%d millisecond)!", timeout);
  319. result = -RT_ETIMEOUT;
  320. break;
  321. }
  322. /* Check whether it is already connected */
  323. resp->line_counts = 0;
  324. rt_device_write(client->device, 0, "AT\r\n", 4);
  325. if (rt_sem_take(client->resp_notice, resp->timeout) != RT_EOK)
  326. continue;
  327. else
  328. break;
  329. }
  330. at_delete_resp(resp);
  331. client->resp = RT_NULL;
  332. rt_mutex_release(client->lock);
  333. return result;
  334. }
  335. /**
  336. * Send data to AT server, send data don't have end sign(eg: \r\n).
  337. *
  338. * @param client current AT client object
  339. * @param buf send data buffer
  340. * @param size send fixed data size
  341. *
  342. * @return >0: send data size
  343. * =0: send failed
  344. */
  345. rt_size_t at_client_obj_send(at_client_t client, const char *buf, rt_size_t size)
  346. {
  347. RT_ASSERT(buf);
  348. if (client == RT_NULL)
  349. {
  350. LOG_E("input AT Client object is NULL, please create or get AT Client object!");
  351. return 0;
  352. }
  353. #ifdef AT_PRINT_RAW_CMD
  354. at_print_raw_cmd("send", buf, size);
  355. #endif
  356. return rt_device_write(client->device, 0, buf, size);
  357. }
  358. static rt_err_t at_client_getchar(at_client_t client, char *ch, rt_int32_t timeout)
  359. {
  360. rt_err_t result = RT_EOK;
  361. while (rt_device_read(client->device, 0, ch, 1) == 0)
  362. {
  363. rt_sem_control(client->rx_notice, RT_IPC_CMD_RESET, RT_NULL);
  364. result = rt_sem_take(client->rx_notice, rt_tick_from_millisecond(timeout));
  365. if (result != RT_EOK)
  366. {
  367. return result;
  368. }
  369. }
  370. return RT_EOK;
  371. }
  372. /**
  373. * AT client receive fixed-length data.
  374. *
  375. * @param client current AT client object
  376. * @param buf receive data buffer
  377. * @param size receive fixed data size
  378. * @param timeout receive data timeout (ms)
  379. *
  380. * @note this function can only be used in execution function of URC data
  381. *
  382. * @return >0: receive data size
  383. * =0: receive failed
  384. */
  385. rt_size_t at_client_obj_recv(at_client_t client, char *buf, rt_size_t size, rt_int32_t timeout)
  386. {
  387. rt_size_t read_idx = 0;
  388. rt_err_t result = RT_EOK;
  389. char ch;
  390. RT_ASSERT(buf);
  391. if (client == RT_NULL)
  392. {
  393. LOG_E("input AT Client object is NULL, please create or get AT Client object!");
  394. return 0;
  395. }
  396. while (1)
  397. {
  398. if (read_idx < size)
  399. {
  400. result = at_client_getchar(client, &ch, timeout);
  401. if (result != RT_EOK)
  402. {
  403. LOG_E("AT Client receive failed, uart device get data error(%d)", result);
  404. return 0;
  405. }
  406. buf[read_idx++] = ch;
  407. }
  408. else
  409. {
  410. break;
  411. }
  412. }
  413. #ifdef AT_PRINT_RAW_CMD
  414. at_print_raw_cmd("urc_recv", buf, size);
  415. #endif
  416. return read_idx;
  417. }
  418. /**
  419. * AT client set end sign.
  420. *
  421. * @param client current AT client object
  422. * @param ch the end sign, can not be used when it is '\0'
  423. */
  424. void at_obj_set_end_sign(at_client_t client, char ch)
  425. {
  426. if (client == RT_NULL)
  427. {
  428. LOG_E("input AT Client object is NULL, please create or get AT Client object!");
  429. return;
  430. }
  431. client->end_sign = ch;
  432. }
  433. /**
  434. * set URC(Unsolicited Result Code) table
  435. *
  436. * @param client current AT client object
  437. * @param table URC table
  438. * @param size table size
  439. */
  440. void at_obj_set_urc_table(at_client_t client, const struct at_urc *urc_table, rt_size_t table_sz)
  441. {
  442. rt_size_t idx;
  443. if (client == RT_NULL)
  444. {
  445. LOG_E("input AT Client object is NULL, please create or get AT Client object!");
  446. return;
  447. }
  448. for (idx = 0; idx < table_sz; idx++)
  449. {
  450. RT_ASSERT(urc_table[idx].cmd_prefix);
  451. RT_ASSERT(urc_table[idx].cmd_suffix);
  452. }
  453. client->urc_table = urc_table;
  454. client->urc_table_size = table_sz;
  455. }
  456. /**
  457. * get AT client object by AT device name.
  458. *
  459. * @dev_name AT client device name
  460. *
  461. * @return AT client object
  462. */
  463. at_client_t at_client_get(const char *dev_name)
  464. {
  465. int idx = 0;
  466. RT_ASSERT(dev_name);
  467. for (idx = 0; idx < AT_CLIENT_NUM_MAX; idx++)
  468. {
  469. if (rt_strcmp(at_client_table[idx].device->parent.name, dev_name) == 0)
  470. {
  471. return &at_client_table[idx];
  472. }
  473. }
  474. return RT_NULL;
  475. }
  476. /**
  477. * get first AT client object in the table.
  478. *
  479. * @return AT client object
  480. */
  481. at_client_t at_client_get_first(void)
  482. {
  483. if (at_client_table[0].device == RT_NULL)
  484. {
  485. return RT_NULL;
  486. }
  487. return &at_client_table[0];
  488. }
  489. static const struct at_urc *get_urc_obj(at_client_t client)
  490. {
  491. rt_size_t i, prefix_len, suffix_len;
  492. rt_size_t buf_sz;
  493. char *buffer = RT_NULL;
  494. if (client->urc_table == RT_NULL)
  495. {
  496. return RT_NULL;
  497. }
  498. buffer = client->recv_buffer;
  499. buf_sz = client->cur_recv_len;
  500. for (i = 0; i < client->urc_table_size; i++)
  501. {
  502. prefix_len = strlen(client->urc_table[i].cmd_prefix);
  503. suffix_len = strlen(client->urc_table[i].cmd_suffix);
  504. if (buf_sz < prefix_len + suffix_len)
  505. {
  506. continue;
  507. }
  508. if ((prefix_len ? !strncmp(buffer, client->urc_table[i].cmd_prefix, prefix_len) : 1)
  509. && (suffix_len ? !strncmp(buffer + buf_sz - suffix_len, client->urc_table[i].cmd_suffix, suffix_len) : 1))
  510. {
  511. return &client->urc_table[i];
  512. }
  513. }
  514. return RT_NULL;
  515. }
  516. static int at_recv_readline(at_client_t client)
  517. {
  518. rt_size_t read_len = 0;
  519. char ch = 0, last_ch = 0;
  520. rt_bool_t is_full = RT_FALSE;
  521. memset(client->recv_buffer, 0x00, client->recv_bufsz);
  522. client->cur_recv_len = 0;
  523. while (1)
  524. {
  525. at_client_getchar(client, &ch, RT_WAITING_FOREVER);
  526. if (read_len < client->recv_bufsz)
  527. {
  528. client->recv_buffer[read_len++] = ch;
  529. client->cur_recv_len = read_len;
  530. }
  531. else
  532. {
  533. is_full = RT_TRUE;
  534. }
  535. /* is newline or URC data */
  536. if ((ch == '\n' && last_ch == '\r') || (client->end_sign != 0 && ch == client->end_sign)
  537. || get_urc_obj(client))
  538. {
  539. if (is_full)
  540. {
  541. LOG_E("read line failed. The line data length is out of buffer size(%d)!", client->recv_bufsz);
  542. memset(client->recv_buffer, 0x00, client->recv_bufsz);
  543. client->cur_recv_len = 0;
  544. return -RT_EFULL;
  545. }
  546. break;
  547. }
  548. last_ch = ch;
  549. }
  550. #ifdef AT_PRINT_RAW_CMD
  551. at_print_raw_cmd("recvline", client->recv_buffer, read_len);
  552. #endif
  553. return read_len;
  554. }
  555. static void client_parser(at_client_t client)
  556. {
  557. int resp_buf_len = 0;
  558. const struct at_urc *urc;
  559. rt_size_t line_counts = 0;
  560. while(1)
  561. {
  562. if (at_recv_readline(client) > 0)
  563. {
  564. if ((urc = get_urc_obj(client)) != RT_NULL)
  565. {
  566. /* current receive is request, try to execute related operations */
  567. if (urc->func != RT_NULL)
  568. {
  569. urc->func(client->recv_buffer, client->cur_recv_len);
  570. }
  571. }
  572. else if (client->resp != RT_NULL)
  573. {
  574. /* current receive is response */
  575. client->recv_buffer[client->cur_recv_len - 1] = '\0';
  576. if (resp_buf_len + client->cur_recv_len < client->resp->buf_size)
  577. {
  578. /* copy response lines, separated by '\0' */
  579. memcpy(client->resp->buf + resp_buf_len, client->recv_buffer, client->cur_recv_len);
  580. resp_buf_len += client->cur_recv_len;
  581. line_counts++;
  582. }
  583. else
  584. {
  585. client->resp_status = AT_RESP_BUFF_FULL;
  586. LOG_E("Read response buffer failed. The Response buffer size is out of buffer size(%d)!", client->resp->buf_size);
  587. }
  588. /* check response result */
  589. if (memcmp(client->recv_buffer, AT_RESP_END_OK, strlen(AT_RESP_END_OK)) == 0
  590. && client->resp->line_num == 0)
  591. {
  592. /* get the end data by response result, return response state END_OK. */
  593. client->resp_status = AT_RESP_OK;
  594. }
  595. else if (strstr(client->recv_buffer, AT_RESP_END_ERROR)
  596. || (memcmp(client->recv_buffer, AT_RESP_END_FAIL, strlen(AT_RESP_END_FAIL)) == 0))
  597. {
  598. client->resp_status = AT_RESP_ERROR;
  599. }
  600. else if (line_counts == client->resp->line_num && client->resp->line_num)
  601. {
  602. /* get the end data by response line, return response state END_OK.*/
  603. client->resp_status = AT_RESP_OK;
  604. }
  605. else
  606. {
  607. continue;
  608. }
  609. client->resp->line_counts = line_counts;
  610. client->resp = RT_NULL;
  611. rt_sem_release(client->resp_notice);
  612. resp_buf_len = 0, line_counts = 0;
  613. }
  614. else
  615. {
  616. // log_d("unrecognized line: %.*s", client->cur_recv_len, client->recv_buffer);
  617. }
  618. }
  619. }
  620. }
  621. static rt_err_t at_client_rx_ind(rt_device_t dev, rt_size_t size)
  622. {
  623. int idx = 0;
  624. for (idx = 0; idx < AT_CLIENT_NUM_MAX; idx++)
  625. {
  626. if (at_client_table[idx].device == dev && size > 0)
  627. {
  628. rt_sem_release(at_client_table[idx].rx_notice);
  629. }
  630. }
  631. return RT_EOK;
  632. }
  633. /* initialize the client object parameters */
  634. static int at_client_para_init(at_client_t client)
  635. {
  636. #define AT_CLIENT_LOCK_NAME "at_c"
  637. #define AT_CLIENT_SEM_NAME "at_cs"
  638. #define AT_CLIENT_RESP_NAME "at_cr"
  639. #define AT_CLIENT_THREAD_NAME "at_clnt"
  640. int result = RT_EOK;
  641. static int at_client_num = 0;
  642. char name[RT_NAME_MAX];
  643. client->status = AT_STATUS_UNINITIALIZED;
  644. client->cur_recv_len = 0;
  645. client->recv_buffer = (char *) rt_calloc(1, client->recv_bufsz);
  646. if (client->recv_buffer == RT_NULL)
  647. {
  648. LOG_E("AT client initialize failed! No memory for receive buffer.");
  649. result = -RT_ENOMEM;
  650. goto __exit;
  651. }
  652. rt_snprintf(name, RT_NAME_MAX, "%s%d", AT_CLIENT_LOCK_NAME, at_client_num);
  653. client->lock = rt_mutex_create(name, RT_IPC_FLAG_FIFO);
  654. if (client->lock == RT_NULL)
  655. {
  656. LOG_E("AT client initialize failed! at_client_recv_lock create failed!");
  657. result = -RT_ENOMEM;
  658. goto __exit;
  659. }
  660. rt_snprintf(name, RT_NAME_MAX, "%s%d", AT_CLIENT_SEM_NAME, at_client_num);
  661. client->rx_notice = rt_sem_create(name, 0, RT_IPC_FLAG_FIFO);
  662. if (client->rx_notice == RT_NULL)
  663. {
  664. LOG_E("AT client initialize failed! at_client_notice semaphore create failed!");
  665. result = -RT_ENOMEM;
  666. goto __exit;
  667. }
  668. rt_snprintf(name, RT_NAME_MAX, "%s%d", AT_CLIENT_RESP_NAME, at_client_num);
  669. client->resp_notice = rt_sem_create(name, 0, RT_IPC_FLAG_FIFO);
  670. if (client->resp_notice == RT_NULL)
  671. {
  672. LOG_E("AT client initialize failed! at_client_resp semaphore create failed!");
  673. result = -RT_ENOMEM;
  674. goto __exit;
  675. }
  676. client->urc_table = RT_NULL;
  677. client->urc_table_size = 0;
  678. rt_snprintf(name, RT_NAME_MAX, "%s%d", AT_CLIENT_THREAD_NAME, at_client_num);
  679. client->parser = rt_thread_create(name,
  680. (void (*)(void *parameter))client_parser,
  681. client,
  682. 1024 + 512,
  683. RT_THREAD_PRIORITY_MAX / 3 - 1,
  684. 5);
  685. if (client->parser == RT_NULL)
  686. {
  687. result = -RT_ENOMEM;
  688. goto __exit;
  689. }
  690. __exit:
  691. if (result != RT_EOK)
  692. {
  693. if (client->lock)
  694. {
  695. rt_mutex_delete(client->lock);
  696. }
  697. if (client->rx_notice)
  698. {
  699. rt_sem_delete(client->rx_notice);
  700. }
  701. if (client->resp_notice)
  702. {
  703. rt_sem_delete(client->resp_notice);
  704. }
  705. if (client->device)
  706. {
  707. rt_device_close(client->device);
  708. }
  709. if (client->recv_buffer)
  710. {
  711. rt_free(client->recv_buffer);
  712. }
  713. rt_memset(client, 0x00, sizeof(struct at_client));
  714. }
  715. else
  716. {
  717. at_client_num++;
  718. }
  719. return result;
  720. }
  721. /**
  722. * AT client initialize.
  723. *
  724. * @param dev_name AT client device name
  725. * @param recv_bufsz the maximum number of receive buffer length
  726. *
  727. * @return 0 : initialize success
  728. * -1 : initialize failed
  729. * -5 : no memory
  730. */
  731. int at_client_init(const char *dev_name, rt_size_t recv_bufsz)
  732. {
  733. int idx = 0;
  734. int result = RT_EOK;
  735. rt_err_t open_result = RT_EOK;
  736. at_client_t client = RT_NULL;
  737. RT_ASSERT(dev_name);
  738. RT_ASSERT(recv_bufsz > 0);
  739. for (idx = 0; idx < AT_CLIENT_NUM_MAX && at_client_table[idx].device; idx++);
  740. if (idx >= AT_CLIENT_NUM_MAX)
  741. {
  742. LOG_E("AT client initialize failed! Check the maximum number(%d) of AT client.", AT_CLIENT_NUM_MAX);
  743. result = -RT_EFULL;
  744. goto __exit;
  745. }
  746. client = &at_client_table[idx];
  747. client->recv_bufsz = recv_bufsz;
  748. /* find and open command device */
  749. client->device = rt_device_find(dev_name);
  750. if (client->device)
  751. {
  752. RT_ASSERT(client->device->type == RT_Device_Class_Char);
  753. /* using DMA mode first */
  754. open_result = rt_device_open(client->device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX);
  755. /* using interrupt mode when DMA mode not supported */
  756. if (open_result == -RT_EIO)
  757. {
  758. open_result = rt_device_open(client->device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
  759. }
  760. RT_ASSERT(open_result == RT_EOK);
  761. rt_device_set_rx_indicate(client->device, at_client_rx_ind);
  762. }
  763. else
  764. {
  765. LOG_E("AT client initialize failed! Not find the device(%s).", dev_name);
  766. result = -RT_ERROR;
  767. goto __exit;
  768. }
  769. result = at_client_para_init(client);
  770. if (result != RT_EOK)
  771. {
  772. goto __exit;
  773. }
  774. __exit:
  775. if (result == RT_EOK)
  776. {
  777. client->status = AT_STATUS_INITIALIZED;
  778. rt_thread_startup(client->parser);
  779. LOG_I("AT client(V%s) on device %s initialize success.", AT_SW_VERSION, dev_name);
  780. }
  781. else
  782. {
  783. LOG_E("AT client(V%s) on device %s initialize failed(%d).", AT_SW_VERSION, dev_name, result);
  784. }
  785. return result;
  786. }