ql_wifi_app.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. /**
  2. @file
  3. ql_wifi_app.c
  4. @brief
  5. Quectel wifi app api.
  6. */
  7. /*============================================================================
  8. Copyright (c) 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
  9. Quectel Wireless Solution Proprietary and Confidential.
  10. =============================================================================*/
  11. /*===========================================================================
  12. EDIT HISTORY FOR MODULE
  13. This section contains comments describing changes made to the module.
  14. Notice that changes are listed in reverse chronological order.
  15. WHEN WHO WHAT, WHERE, WHY
  16. ---------- ------------ ----------------------------------------------------
  17. =============================================================================*/
  18. /*===========================================================================
  19. * include files
  20. ===========================================================================*/
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <lwip/inet.h>
  25. #include "netif/etharp.h"
  26. #include "ql_osi_def.h"
  27. #include "ql_api_osi.h"
  28. #include "ql_log.h"
  29. #include "quec_common.h"
  30. #include "ql_api_wifi.h"
  31. #include "ql_wifi_app.h"
  32. #include "ql_wifi_msg.h"
  33. #include "ql_wifi_net.h"
  34. #include "ql_wifi_uart.h"
  35. #include "ql_wifi_spi.h"
  36. /*========================================================================
  37. * Macro Definition
  38. *========================================================================*/
  39. #define QL_WIFI_LOG_LEVEL QL_LOG_LEVEL_INFO
  40. #define QL_WIFI_APP_LOG(msg, ...) QL_LOG(QL_WIFI_LOG_LEVEL, "wifi_app", msg, ##__VA_ARGS__)
  41. #define QL_WIFI_APP_TASK_EVENT_CNT 5
  42. #define QL_WIFI_APP_MSG_QUEUE_CNT 10
  43. #define QL_WIFI_APP_AP_DISABLE 0x01
  44. #define QL_WIFI_APP_STA_DISABLE 0x02
  45. /*========================================================================
  46. * Enumeration Definition
  47. *========================================================================*/
  48. typedef enum
  49. {
  50. QL_WIFI_APP_SCAN_CMD_TYPE_START = 1,
  51. QL_WIFI_APP_SCAN_CMD_TYPE_AP_DATA,
  52. QL_WIFI_APP_SCAN_CMD_TYPE_END
  53. } ql_wifi_app_scan_cmd_type_e;
  54. /*========================================================================
  55. * Type Definition
  56. *=========================================================================*/
  57. typedef struct
  58. {
  59. ql_wifi_app_scan_cmd_type_e cmd_type;
  60. char num;
  61. ql_wifi_app_ap_info_s ap_info;
  62. } ql_wifi_app_scan_info_s;
  63. typedef struct
  64. {
  65. ql_task_t task;
  66. ql_queue_t msg_queue;
  67. ql_wifi_app_sta_status_cb sta_status_cb;
  68. ql_wifi_app_scan_result_cb scan_start_cb;
  69. ql_wifi_app_output_data_msg_cb output_data_msg_cb;
  70. ql_wifi_app_user_ap_info_s ap_info;
  71. } ql_wifi_app_manager_s;
  72. #pragma pack(1)
  73. typedef struct
  74. {
  75. char dhcp;
  76. char ip_str[QL_WIFI_IPV4_MAX_LEN];
  77. char netmask_str[QL_WIFI_IPV4_MAX_LEN];
  78. char gw_str[QL_WIFI_IPV4_MAX_LEN];
  79. char ssid[QL_WIFI_SSID_MAX_LEN];
  80. char password[QL_WIFI_PASSWORD_MAX_LEN];
  81. } ql_wifi_app_start_info_s;
  82. #pragma pack()
  83. /*========================================================================
  84. * Global Variable
  85. *========================================================================*/
  86. ql_wifi_app_manager_s ql_wifi_app_manager = {0};
  87. ql_mutex_t ql_wifi_app_mutex = NULL;
  88. ql_wifi_app_scan_result_s ql_wifi_app_scan_result = {0};
  89. static int ql_wifi_app_scan_num = 0;
  90. /*========================================================================
  91. * function Definition
  92. *========================================================================*/
  93. ql_wifi_app_errcode_e ql_wifi_app_get_user_ap_info(ql_wifi_app_user_ap_info_s *info)
  94. {
  95. ql_wifi_app_manager_s *manager = &ql_wifi_app_manager;
  96. if(!info)
  97. {
  98. return QL_WIFI_APP_INVALID_PARAM_ERR;
  99. }
  100. memcpy(info,&(manager->ap_info),sizeof(ql_wifi_app_user_ap_info_s));
  101. return QL_WIFI_APP_SUCCESS;
  102. }
  103. ql_wifi_app_errcode_e ql_wifi_app_set_user_ap_info(ql_wifi_app_user_ap_info_s *info)
  104. {
  105. ql_wifi_app_manager_s *manager = &ql_wifi_app_manager;
  106. if(!info)
  107. {
  108. return QL_WIFI_APP_INVALID_PARAM_ERR;
  109. }
  110. memcpy(&(manager->ap_info),info,sizeof(ql_wifi_app_user_ap_info_s));
  111. return QL_WIFI_APP_SUCCESS;
  112. }
  113. ql_wifi_app_errcode_e ql_wifi_app_scan(ql_wifi_app_scan_result_cb cb)
  114. {
  115. ql_wifi_app_manager_s *manager = &ql_wifi_app_manager;
  116. // Set wifi app scan result callback
  117. if (cb)
  118. {
  119. ql_rtos_mutex_try_lock(ql_wifi_app_mutex);
  120. if (ql_wifi_app_scan_result.ApList != NULL)
  121. {
  122. return QL_WIFI_APP_SCAN_WORKING_ERR;
  123. }
  124. manager->scan_start_cb = cb;
  125. // Send wifi control command
  126. if (manager->output_data_msg_cb)
  127. {
  128. ql_wifi_msg_output_data_info_s info = {.cmd = QL_WIFI_APP_SCAN_START_CMD, .data = NULL, .data_len = 0};
  129. manager->output_data_msg_cb(&info);
  130. }
  131. ql_rtos_mutex_unlock(ql_wifi_app_mutex);
  132. }
  133. else
  134. {
  135. return QL_WIFI_APP_CB_NULL_ERR;
  136. }
  137. return QL_WIFI_APP_SUCCESS;
  138. }
  139. ql_wifi_app_errcode_e ql_wifi_app_sta_enable(ql_wifi_app_sta_status_cb sta_status_cb)
  140. {
  141. int ret = 0;
  142. ql_wifi_app_errcode_e err = QL_WIFI_APP_SUCCESS;
  143. ql_wifi_app_manager_s *manager = &ql_wifi_app_manager;
  144. ql_wifi_app_start_info_s start = {0};
  145. int val_len = 0;
  146. char dhcp = 0;
  147. ip4_addr_t ip = {0};
  148. ip4_addr_t netmask = {0};
  149. ip4_addr_t gw = {0};
  150. memset(&start, 0, sizeof(ql_wifi_app_start_info_s));
  151. // Get ssid & password
  152. ql_wifi_app_user_ap_info_s *ap_user_info = (ql_wifi_app_user_ap_info_s *)calloc(1,sizeof(ql_wifi_app_user_ap_info_s));
  153. if(!ap_user_info)
  154. {
  155. QL_WIFI_APP_LOG("calloc faild!");
  156. err = QL_WIFI_APP_NO_MEM_ERR;
  157. goto exit;
  158. }
  159. ret = ql_wifi_app_get_user_ap_info(ap_user_info);
  160. if(ret != QL_WIFI_APP_SUCCESS)
  161. {
  162. QL_WIFI_APP_LOG("get ssid/password faild!");
  163. err = QL_WIFI_APP_INVALID_AP_USER_INFO_ERR;
  164. free(ap_user_info);
  165. goto exit;
  166. }
  167. memcpy(&(start.ssid),ap_user_info->ssid,QL_WIFI_SSID_MAX_LEN);
  168. memcpy(&(start.password),ap_user_info->password,QL_WIFI_PASSWORD_MAX_LEN);
  169. free(ap_user_info);
  170. // Get dhcp flag
  171. val_len = sizeof(char);
  172. ret = ql_wifi_opt_get(QL_WIFI_OPT_DHCP, &dhcp, &val_len);
  173. if (ret != QL_WIFI_SUCCESS)
  174. {
  175. QL_WIFI_APP_LOG("get dhcp faild!");
  176. err = QL_WIFI_APP_INVALID_DHCP_ERR;
  177. goto exit;
  178. }
  179. start.dhcp = dhcp;
  180. // Get static ip information when dhcp is not enable.
  181. if (!dhcp)
  182. {
  183. // Get static ip
  184. val_len = sizeof(ip4_addr_t);
  185. ret = ql_wifi_opt_get(QL_WIFI_OPT_IP, &ip, &val_len);
  186. if (ret != QL_WIFI_SUCCESS)
  187. {
  188. QL_WIFI_APP_LOG("get ip faild!");
  189. err = QL_WIFI_APP_INVALID_IP_ERR;
  190. goto exit;
  191. }
  192. // Get static netmask
  193. val_len = sizeof(ip4_addr_t);
  194. ret = ql_wifi_opt_get(QL_WIFI_OPT_NETMASK, &netmask, &val_len);
  195. if (ret != QL_WIFI_SUCCESS)
  196. {
  197. QL_WIFI_APP_LOG("get netmask faild!");
  198. err = QL_WIFI_APP_INVALID_NETMASK_ERR;
  199. goto exit;
  200. }
  201. // Get static gateway
  202. val_len = sizeof(ip4_addr_t);
  203. ret = ql_wifi_opt_get(QL_WIFI_OPT_GW, &gw, &val_len);
  204. if (ret != QL_WIFI_SUCCESS)
  205. {
  206. QL_WIFI_APP_LOG("get gw faild!");
  207. err = QL_WIFI_APP_INVALID_GW_ERR;
  208. goto exit;
  209. }
  210. // Copy ip information to data field.
  211. memcpy(start.ip_str, inet_ntoa(ip), QL_WIFI_IPV4_MAX_LEN);
  212. memcpy(start.netmask_str, inet_ntoa(netmask), QL_WIFI_IPV4_MAX_LEN);
  213. memcpy(start.gw_str, inet_ntoa(gw), QL_WIFI_IPV4_MAX_LEN);
  214. QL_WIFI_APP_LOG("ip:%s", start.ip_str);
  215. QL_WIFI_APP_LOG("netmask:%s", start.netmask_str);
  216. QL_WIFI_APP_LOG("gw:%s", start.gw_str);
  217. }
  218. // Send wifi control command
  219. ql_rtos_mutex_try_lock(ql_wifi_app_mutex);
  220. if (manager->output_data_msg_cb)
  221. {
  222. ql_wifi_msg_output_data_info_s info = {.cmd = QL_WIFI_APP_STA_ENABLE_CMD, .data = (unsigned char *)&start, .data_len = sizeof(ql_wifi_app_start_info_s)};
  223. manager->output_data_msg_cb(&info);
  224. }
  225. // Set wifi sta status notify callback
  226. manager->sta_status_cb = sta_status_cb;
  227. ql_rtos_mutex_unlock(ql_wifi_app_mutex);
  228. exit:
  229. QL_WIFI_APP_LOG("exit");
  230. return err;
  231. }
  232. ql_wifi_app_errcode_e ql_wifi_app_sta_disable(void *argv)
  233. {
  234. ql_wifi_app_manager_s *manager = &ql_wifi_app_manager;
  235. unsigned char data = QL_WIFI_APP_STA_DISABLE;
  236. ql_rtos_mutex_try_lock(ql_wifi_app_mutex);
  237. // Send wifi control command
  238. if (manager->output_data_msg_cb)
  239. {
  240. ql_wifi_msg_output_data_info_s info = {.cmd = QL_WIFI_APP_STA_DISABLE_CMD, .data = &data, .data_len = 1};
  241. manager->output_data_msg_cb(&info);
  242. }
  243. ql_rtos_mutex_unlock(ql_wifi_app_mutex);
  244. return QL_WIFI_APP_SUCCESS;
  245. }
  246. ql_wifi_app_errcode_e ql_wifi_app_reset(void *argv)
  247. {
  248. ql_wifi_app_manager_s *manager = &ql_wifi_app_manager;
  249. unsigned char data = QUEC_WIFI_APP_RESET_CMD;
  250. ql_rtos_mutex_try_lock(ql_wifi_app_mutex);
  251. // Send wifi control command
  252. if (manager->output_data_msg_cb)
  253. {
  254. ql_wifi_msg_output_data_info_s info = {.cmd = QUEC_WIFI_APP_RESET_CMD, .data = &data, .data_len = 1};
  255. manager->output_data_msg_cb(&info);
  256. }
  257. ql_rtos_mutex_unlock(ql_wifi_app_mutex);
  258. return QL_WIFI_APP_SUCCESS;
  259. }
  260. static void ql_wifi_app_notify_recv(void *ctx)
  261. {
  262. ql_wifi_msg_cmd_info_s *info = (ql_wifi_msg_cmd_info_s *)ctx;
  263. // Receive wifi app msg command.
  264. QuecOSStatus err;
  265. ql_wifi_msg_cmd_info_s cmd_info = {0};
  266. ql_wifi_app_manager_s *manager = &ql_wifi_app_manager;
  267. cmd_info.msg_id = info->msg_id;
  268. cmd_info.msg_info = info->msg_info;
  269. ql_rtos_mutex_try_lock(ql_wifi_app_mutex);
  270. err = ql_rtos_queue_release(manager->msg_queue, sizeof(ql_wifi_msg_cmd_info_s), (uint8 *)&cmd_info, QL_NO_WAIT);
  271. if (err)
  272. {
  273. QL_WIFI_APP_LOG("release failed");
  274. }
  275. ql_rtos_mutex_unlock(ql_wifi_app_mutex);
  276. }
  277. static void ql_wifi_app_wifiscan_result_handler(void *argv)
  278. {
  279. ql_wifi_app_scan_info_s *scan_ptr = (ql_wifi_app_scan_info_s *)argv;
  280. ql_wifi_app_manager_s *manager = &ql_wifi_app_manager;
  281. ql_rtos_mutex_try_lock(ql_wifi_app_mutex);
  282. // Initialize the parameter when receiving start command
  283. if (scan_ptr->cmd_type == QL_WIFI_APP_SCAN_CMD_TYPE_START)
  284. {
  285. if (ql_wifi_app_scan_result.ApList != NULL)
  286. {
  287. free(ql_wifi_app_scan_result.ApList);
  288. ql_wifi_app_scan_result.ApList = NULL;
  289. ql_wifi_app_scan_num = 0;
  290. }
  291. ql_wifi_app_scan_result.ApList = malloc(sizeof(ql_wifi_app_ap_info_s) * scan_ptr->num);
  292. if (ql_wifi_app_scan_result.ApList == NULL)
  293. {
  294. QL_WIFI_APP_LOG("malloc failed");
  295. ql_rtos_mutex_unlock(ql_wifi_app_mutex);
  296. return;
  297. }
  298. ql_wifi_app_scan_result.ApNum = 0;
  299. ql_wifi_app_scan_num = 0;
  300. QL_WIFI_APP_LOG("scan start");
  301. }
  302. // Get AP lists
  303. else if (scan_ptr->cmd_type == QL_WIFI_APP_SCAN_CMD_TYPE_AP_DATA)
  304. {
  305. if (ql_wifi_app_scan_result.ApList == NULL)
  306. {
  307. QL_WIFI_APP_LOG("ApList is NULL");
  308. ql_rtos_mutex_unlock(ql_wifi_app_mutex);
  309. return;
  310. }
  311. memcpy(&ql_wifi_app_scan_result.ApList[ql_wifi_app_scan_num], &scan_ptr->ap_info, sizeof(ql_wifi_app_ap_info_s));
  312. ql_wifi_app_scan_num++;
  313. }
  314. // Command end
  315. else if (scan_ptr->cmd_type == QL_WIFI_APP_SCAN_CMD_TYPE_END)
  316. {
  317. if (ql_wifi_app_scan_result.ApList == NULL)
  318. {
  319. QL_WIFI_APP_LOG("ApList is NULL");
  320. ql_rtos_mutex_unlock(ql_wifi_app_mutex);
  321. return;
  322. }
  323. QL_WIFI_APP_LOG("scan end");
  324. ql_wifi_app_scan_result.ApNum = ql_wifi_app_scan_num;
  325. // Result notification
  326. if (manager->scan_start_cb)
  327. {
  328. manager->scan_start_cb((void *)&ql_wifi_app_scan_result);
  329. }
  330. free(ql_wifi_app_scan_result.ApList);
  331. ql_wifi_app_scan_result.ApList = NULL;
  332. ql_wifi_app_scan_result.ApNum = 0;
  333. ql_wifi_app_scan_num = 0;
  334. }
  335. else
  336. {
  337. if (ql_wifi_app_scan_result.ApList)
  338. {
  339. free(ql_wifi_app_scan_result.ApList);
  340. }
  341. ql_wifi_app_scan_result.ApList = NULL;
  342. ql_wifi_app_scan_result.ApNum = 0;
  343. ql_wifi_app_scan_num = 0;
  344. QL_WIFI_APP_LOG("NULL");
  345. }
  346. ql_rtos_mutex_unlock(ql_wifi_app_mutex);
  347. }
  348. static void ql_wifi_app_thread(void *argv)
  349. {
  350. QuecOSStatus err;
  351. ql_wifi_msg_cmd_info_s cmd_info = {0};
  352. ql_wifi_app_manager_s *manager = &ql_wifi_app_manager;
  353. // Create message queue
  354. err = ql_rtos_queue_create(&manager->msg_queue, sizeof(ql_wifi_msg_cmd_info_s), QL_WIFI_APP_MSG_QUEUE_CNT);
  355. if (err)
  356. {
  357. goto exit;
  358. }
  359. // Handle QL_WIFI_APP_SCAN_START_CMD && QL_WIFI_APP_EVENT_NOTIFY && QL_WIFI_APP_STA_STATUS_CMD from ql_wifi_msg.c
  360. if (QL_WIFI_MSG_SUCCESS != ql_wifi_msg_app_notify_cb_register(ql_wifi_app_notify_recv))
  361. {
  362. QL_WIFI_APP_LOG("msg app cb reg err");
  363. goto exit;
  364. }
  365. // Handle QL_WIFI_APP_STA_STATUS_CMD from ql_wifi_net.c && ql_api_wifi.c
  366. if (QL_WIFI_NET_SUCCESS != ql_wifi_net_app_notify_cb_register(ql_wifi_app_notify_recv))
  367. {
  368. QL_WIFI_APP_LOG("net app cb reg err");
  369. goto exit;
  370. }
  371. while (1)
  372. {
  373. memset(&cmd_info, 0, sizeof(ql_wifi_msg_cmd_info_s));
  374. err = ql_rtos_queue_wait(manager->msg_queue, (uint8 *)&cmd_info, sizeof(ql_wifi_msg_cmd_info_s), QL_WAIT_FOREVER);
  375. if (err != kNoErr)
  376. {
  377. QL_WIFI_APP_LOG("msg_queue wait error err= %d", err);
  378. goto exit;
  379. }
  380. QL_WIFI_APP_LOG("msg_id: %d", cmd_info.msg_id);
  381. switch (cmd_info.msg_id)
  382. {
  383. case QL_WIFI_APP_SCAN_START_CMD: {
  384. ql_wifi_app_wifiscan_result_handler(cmd_info.msg_info);
  385. break;
  386. }
  387. case QL_WIFI_APP_EVENT_NOTIFY: {
  388. break;
  389. }
  390. case QL_WIFI_APP_STA_STATUS_CMD: {
  391. // Wifi connect status notification
  392. char *p = (char *)cmd_info.msg_info;
  393. int status = p[0];
  394. QL_WIFI_APP_LOG("status=%d", status);
  395. ql_rtos_mutex_try_lock(ql_wifi_app_mutex);
  396. if (manager->sta_status_cb != NULL)
  397. {
  398. manager->sta_status_cb(&status);
  399. }
  400. ql_rtos_mutex_unlock(ql_wifi_app_mutex);
  401. break;
  402. }
  403. default: {
  404. QL_WIFI_APP_LOG("cmd_info.msg_id=%d error", cmd_info.msg_id);
  405. break;
  406. }
  407. }
  408. if (cmd_info.msg_info != NULL)
  409. {
  410. free(cmd_info.msg_info);
  411. cmd_info.msg_info = NULL;
  412. }
  413. }
  414. exit:
  415. ql_rtos_mutex_try_lock(ql_wifi_app_mutex);
  416. memset(manager, 0, sizeof(ql_wifi_app_manager_s));
  417. ql_rtos_mutex_unlock(ql_wifi_app_mutex);
  418. ql_rtos_task_delete(NULL);
  419. return;
  420. }
  421. ql_wifi_app_errcode_e ql_wifi_app_init(void *argv)
  422. {
  423. int ret = 0;
  424. ql_wifi_app_errcode_e err = QL_WIFI_APP_SUCCESS;
  425. ql_wifi_app_manager_s *manager = &ql_wifi_app_manager;
  426. // Create mutex.Never delete.
  427. if (NULL == ql_wifi_app_mutex)
  428. {
  429. ret = ql_rtos_mutex_create(&(ql_wifi_app_mutex));
  430. if (ret != 0)
  431. {
  432. err = QL_WIFI_APP_MUTEX_CREATE_ERR;
  433. goto exit;
  434. }
  435. }
  436. ql_rtos_mutex_try_lock(ql_wifi_app_mutex);
  437. if (manager->task)
  438. {
  439. return QL_WIFI_APP_SUCCESS;
  440. }
  441. memset(manager, 0, sizeof(ql_wifi_app_manager_s));
  442. // Uart is used for sending wifi control command
  443. ret = ql_wifi_uart_init(NULL);
  444. if (ret != 0)
  445. {
  446. err = QL_WIFI_APP_INIT_UART_ERR;
  447. goto exit;
  448. }
  449. // Spi is used for sending or receiving 802.3 data streams
  450. ret = ql_wifi_spi_init(NULL);
  451. if (ret != 0)
  452. {
  453. err = QL_WIFI_APP_INIT_SPI_ERR;
  454. goto exit;
  455. }
  456. // Msg is used for parsing user protocol
  457. ret = ql_wifi_msg_init(NULL);
  458. if (ret != 0)
  459. {
  460. err = QL_WIFI_APP_INIT_MSG_ERR;
  461. goto exit;
  462. }
  463. // Net is used for handling netcard
  464. ret = ql_wifi_net_init(NULL);
  465. if (ret != 0)
  466. {
  467. err = QL_WIFI_APP_INIT_NET_ERR;
  468. goto exit;
  469. }
  470. // Register wifi command output handler
  471. manager->output_data_msg_cb = ql_wifi_uart_output_data_msg;
  472. // Register 802.3 data streams output handler
  473. ql_wifi_linkoutput_cb_register(ql_wifi_spi_output_data_msg);
  474. QL_WIFI_APP_LOG("ql_wifi_app_init");
  475. ret = ql_rtos_task_create(&manager->task, 4096, APP_PRIORITY_REALTIME, "ql_wifi_app",
  476. ql_wifi_app_thread, NULL, QL_WIFI_APP_TASK_EVENT_CNT);
  477. if (ret != QL_OSI_SUCCESS)
  478. {
  479. QL_WIFI_APP_LOG("wifi app init err");
  480. err = QL_WIFI_APP_INIT_TASK_ERR;
  481. goto exit;
  482. }
  483. ql_rtos_mutex_unlock(ql_wifi_app_mutex);
  484. return err;
  485. exit:
  486. ql_rtos_mutex_unlock(ql_wifi_app_mutex);
  487. ql_wifi_uart_deinit(NULL);
  488. ql_wifi_spi_deinit(NULL);
  489. ql_wifi_net_deint(NULL);
  490. ql_wifi_msg_deinit(NULL);
  491. return err;
  492. }
  493. ql_wifi_app_errcode_e ql_wifi_app_deinit(void *argv)
  494. {
  495. return QL_WIFI_APP_SUCCESS;
  496. }