at_client.c 24 KB

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