stk_demo.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. /*================================================================
  2. Copyright (c) 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
  3. Quectel Wireless Solution Proprietary and Confidential.
  4. =================================================================*/
  5. /*=================================================================
  6. EDIT HISTORY FOR MODULE
  7. This section contains comments describing changes made to the module.
  8. Notice that changes are listed in reverse chronological order.
  9. WHEN WHO WHAT, WHERE, WHY
  10. ------------ ------- -------------------------------------------------------------------------------
  11. =================================================================*/
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <stdlib.h>
  15. #include "ql_api_stk.h"
  16. #include "ql_api_osi.h"
  17. #include "ql_power.h"
  18. #include "ql_log.h"
  19. #define QL_STK_DEMO_LOG_LEVEL QL_LOG_LEVEL_INFO
  20. #define QL_STK_DEMO_LOG(msg, ...) QL_LOG(QL_STK_DEMO_LOG_LEVEL, "ql_STK_DEMO", msg, ##__VA_ARGS__)
  21. #define QL_STK_DEMO_LOG_PUSH(msg, ...) QL_LOG_PUSH("ql_STK_DEMO", msg, ##__VA_ARGS__)
  22. #define QL_STK_ALPHABET_SET (QL_STK_ALPHABET_SET_UCS2)
  23. #ifndef ARR_SIZE
  24. #define ARR_SIZE(a) (sizeof((a)) / sizeof((a[0])))
  25. #endif
  26. typedef enum
  27. {
  28. MAIN_MENU = 0x00,
  29. SUB_MENU = 0x01,
  30. } ql_stk_menu_e;
  31. static ql_task_t stk_task = NULL;
  32. static ql_stk_alphabet_set_e stk_alphabet = QL_STK_ALPHABET_SET;
  33. ql_stk_setup_menu_s menu_info = {0};
  34. ql_stk_select_item_s submenu_info = {0};
  35. static const ql_stk_errcode_e (*get_item_list_fp[])(uint8_t nSim, uint8_t item_identifier, ql_stk_item_s *info) = {
  36. [MAIN_MENU] = ql_stk_acquire_setup_menu_item_list, [SUB_MENU] = ql_stk_acquire_sub_menu_item_list};
  37. static bool hex_to_string(uint8_t const *data, uint16_t length, char *hexString)
  38. {
  39. uint16_t i = 0;
  40. for(i=0; i<length; i++)
  41. {
  42. sprintf(&hexString[i*2], "%02X", data[i]);
  43. }
  44. return true;
  45. }
  46. void user_stk_event_callback(uint8_t nSim, uint32_t ind_type, void *ctx)
  47. {
  48. ql_event_t event = {0};
  49. QL_STK_DEMO_LOG("nSim:%d, ind:%#02X", nSim, ind_type);
  50. switch (ind_type)
  51. {
  52. case QUEC_STK_PROACTIVE_CMD_IND: {
  53. QL_STK_DEMO_LOG("QUEC_STK_PROACTIVE_CMD_IND");
  54. ql_stk_proactive_cmd_s *cmd = (ql_stk_proactive_cmd_s *)ctx;
  55. event.id = QUEC_STK_PROACTIVE_CMD_IND;
  56. event.param1 = nSim;
  57. event.param2 = cmd->proactive_cmd_id;
  58. ql_rtos_event_send(stk_task, &event);
  59. break;
  60. }
  61. case QUEC_STK_TIMEOUT_IND: {
  62. QL_STK_DEMO_LOG("QUEC_STK_TIMEOUT_IND");
  63. ql_stk_timeout_s *cmd = (ql_stk_timeout_s *)ctx;
  64. event.id = QUEC_STK_TIMEOUT_IND;
  65. event.param1 = nSim;
  66. event.param2 = cmd->proactive_cmd_id;
  67. ql_rtos_event_send(stk_task, &event);
  68. break;
  69. }
  70. case QUEC_STK_SIM_LOST_IND: {
  71. QL_STK_DEMO_LOG("QUEC_STK_SIM_LOST_IND");
  72. event.id = QUEC_STK_SIM_LOST_IND;
  73. event.param1 = nSim;
  74. ql_rtos_event_send(stk_task, &event);
  75. break;
  76. }
  77. case QUEC_STK_NO_PROACTIVE_CMD_IND: {
  78. QL_STK_DEMO_LOG("QUEC_STK_NO_PROACTIVE_CMD_IND");
  79. event.id = QUEC_STK_NO_PROACTIVE_CMD_IND;
  80. event.param1 = nSim;
  81. ql_rtos_event_send(stk_task, &event);
  82. break;
  83. }
  84. default:
  85. break;
  86. }
  87. }
  88. static void stk_item_list_info(uint8_t nSim, ql_stk_menu_e menu_type, uint8_t *id_arr, uint8_t id_total)
  89. {
  90. ql_stk_item_s item_info = {0};
  91. uint8_t *str_buffer = calloc(1, QL_STK_STRING_LENGTH_MAX);
  92. if (str_buffer == NULL)
  93. {
  94. return;
  95. }
  96. item_info.item_text.text = str_buffer;
  97. item_info.item_text.length = QL_STK_STRING_LENGTH_MAX;
  98. char *item_buffer = calloc(1, QL_STK_STRING_LENGTH_MAX * 2 + 1);
  99. if (item_buffer == NULL)
  100. {
  101. return;
  102. }
  103. for (size_t i = 0; i < id_total; i++)
  104. {
  105. item_info.item_text.length = QL_STK_STRING_LENGTH_MAX;
  106. ql_stk_errcode_e err = get_item_list_fp[menu_type](nSim, id_arr[i], &item_info);
  107. if (err == QL_STK_SUCCESS)
  108. {
  109. if (stk_alphabet == QL_STK_ALPHABET_SET_UCS2)
  110. {
  111. hex_to_string(item_info.item_text.text, item_info.item_text.length, item_buffer);
  112. }
  113. else
  114. {
  115. memcpy(item_buffer, item_info.item_text.text, strlen((const char *)item_info.item_text.text));
  116. }
  117. if (MAIN_MENU == menu_type)
  118. {
  119. QL_STK_DEMO_LOG(" |%d : %s", id_arr[i], item_buffer);
  120. }
  121. else
  122. {
  123. QL_STK_DEMO_LOG(" ||%d : %s", id_arr[i], item_buffer);
  124. }
  125. }
  126. }
  127. free(str_buffer);
  128. str_buffer = NULL;
  129. free(item_buffer);
  130. item_buffer = NULL;
  131. }
  132. static void stk_setup_menu_info(uint8_t nSim)
  133. {
  134. uint8_t *str_buffer = calloc(1, QL_STK_STRING_LENGTH_MAX);
  135. if (str_buffer == NULL)
  136. {
  137. return;
  138. }
  139. menu_info.title.text = str_buffer;
  140. menu_info.title.length = QL_STK_STRING_LENGTH_MAX;
  141. /* get proactive command SET UP MENU */
  142. ql_stk_errcode_e err = ql_stk_acquire_setup_menu_info(nSim, &menu_info);
  143. if (QL_STK_SUCCESS != err)
  144. {
  145. QL_STK_DEMO_LOG("failed to get setup menu info, error:%d", err);
  146. return;
  147. }
  148. /* command details */
  149. QL_STK_DEMO_LOG("qualifier:%d", menu_info.qualifier);
  150. char *title_buffer = calloc(1, QL_STK_STRING_LENGTH_MAX * 2 + 1);
  151. if (title_buffer == NULL)
  152. {
  153. return;
  154. }
  155. if (stk_alphabet == QL_STK_ALPHABET_SET_UCS2)
  156. {
  157. hex_to_string(menu_info.title.text, menu_info.title.length, title_buffer);
  158. }
  159. else
  160. {
  161. memcpy(title_buffer, menu_info.title.text, strlen((const char *)menu_info.title.text));
  162. }
  163. QL_STK_DEMO_LOG("------- Title:%s -------", title_buffer);
  164. free(str_buffer);
  165. str_buffer = NULL;
  166. free(title_buffer);
  167. title_buffer = NULL;
  168. stk_item_list_info(nSim, MAIN_MENU, menu_info.item_id, menu_info.num_items);
  169. }
  170. static void stk_select_item_info(uint8_t nSim)
  171. {
  172. uint8_t *str_buffer = calloc(1, QL_STK_STRING_LENGTH_MAX);
  173. if (str_buffer == NULL)
  174. {
  175. return;
  176. }
  177. submenu_info.title.text = str_buffer;
  178. submenu_info.title.length = QL_STK_STRING_LENGTH_MAX;
  179. /* get proactive command SELECT ITEM */
  180. ql_stk_errcode_e err = ql_stk_acquire_sub_menu_info(nSim, &submenu_info);
  181. if (QL_STK_SUCCESS != err)
  182. {
  183. QL_STK_DEMO_LOG("failed to get sub menu info, error:%d", err);
  184. return;
  185. }
  186. /* command details */
  187. QL_STK_DEMO_LOG("qualifier:%d",submenu_info.qualifier);
  188. char *title_buffer = calloc(1, QL_STK_STRING_LENGTH_MAX * 2 + 1);
  189. if (title_buffer == NULL)
  190. {
  191. return;
  192. }
  193. if (stk_alphabet == QL_STK_ALPHABET_SET_UCS2)
  194. {
  195. hex_to_string(submenu_info.title.text, submenu_info.title.length, title_buffer);
  196. }
  197. else
  198. {
  199. memcpy(title_buffer, submenu_info.title.text, strlen((const char *)submenu_info.title.text));
  200. }
  201. QL_STK_DEMO_LOG("======= Title:%s =======", title_buffer);
  202. free(str_buffer);
  203. str_buffer = NULL;
  204. free(title_buffer);
  205. title_buffer = NULL;
  206. stk_item_list_info(nSim, SUB_MENU, submenu_info.item_id, submenu_info.num_items);
  207. }
  208. static void stk_display_text_info(uint8_t nSim)
  209. {
  210. ql_stk_display_text_s display_text_info = {0};
  211. uint8_t *str_buffer = calloc(1, QL_STK_STRING_LENGTH_MAX);
  212. if (str_buffer == NULL)
  213. {
  214. return;
  215. }
  216. display_text_info.text_string.text = str_buffer;
  217. display_text_info.text_string.length = QL_STK_STRING_LENGTH_MAX;
  218. /* DISPLAY TEXT */
  219. ql_stk_errcode_e err = ql_stk_acquire_display_text_info(nSim, &display_text_info);
  220. if (QL_STK_SUCCESS != err)
  221. {
  222. QL_STK_DEMO_LOG("failed to get sub menu info, error:%d", err);
  223. return;
  224. }
  225. /* command details */
  226. QL_STK_DEMO_LOG("qualifier:%d", display_text_info.qualifier);
  227. char *text_buffer = calloc(1, QL_STK_STRING_LENGTH_MAX * 2 + 1);
  228. if (text_buffer == NULL)
  229. {
  230. return;
  231. }
  232. if (stk_alphabet == QL_STK_ALPHABET_SET_UCS2)
  233. {
  234. hex_to_string(display_text_info.text_string.text, display_text_info.text_string.length, text_buffer);
  235. }
  236. else
  237. {
  238. memcpy(text_buffer, display_text_info.text_string.text, strlen((const char *)display_text_info.text_string.text));
  239. }
  240. QL_STK_DEMO_LOG("******* text:%s *******", text_buffer);
  241. free(str_buffer);
  242. str_buffer = NULL;
  243. free(text_buffer);
  244. text_buffer = NULL;
  245. }
  246. void stk_proactive_cmd_handler(uint8_t nSim, uint8_t proactive_cmd)
  247. {
  248. QL_STK_DEMO_LOG("get proactive command:'%02x' on sim:%d", proactive_cmd, nSim);
  249. switch (proactive_cmd)
  250. {
  251. case QL_STK_PROACTIVE_CMD_SETUP_MENU: {
  252. stk_setup_menu_info(nSim);
  253. /* response proactive command with result '00' */
  254. ql_stk_send_command_result(nSim, proactive_cmd, QL_STK_PERFORMED_SUCCESSFULLY, 0, NULL);
  255. break;
  256. }
  257. case QL_STK_PROACTIVE_CMD_SELECT_ITEM:
  258. stk_select_item_info(nSim);
  259. /* select an item, send terminal response(ok) with item ID */
  260. //ql_stk_send_command_result(nSim, proactive_cmd, QL_STK_PERFORMED_SUCCESSFULLY, submenu_info.item_id[0], NULL);
  261. ql_stk_send_command_result(nSim, QSTK_TERMINATE_STK_SESSION, QL_STK_PROACTIVE_SIM_SESSION_TERMINATED_BY_THE_USER, 0, NULL);
  262. break;
  263. case QL_STK_PROACTIVE_CMD_DISPLAY_TEXT:
  264. stk_display_text_info(nSim);
  265. ql_stk_send_command_result(nSim, proactive_cmd, QL_STK_PERFORMED_SUCCESSFULLY, 0, NULL);
  266. break;
  267. default:
  268. /* terminate current command */
  269. ql_stk_send_command_result(nSim, QSTK_TERMINATE_STK_SESSION, QL_STK_PROACTIVE_SIM_SESSION_TERMINATED_BY_THE_USER, 0, NULL);
  270. break;
  271. }
  272. }
  273. static void stk_app_thread(void *arg)
  274. {
  275. QlOSStatus err = 0;
  276. uint8_t nSim = 0;
  277. ql_stk_errcode_e ret = QL_STK_SUCCESS;
  278. ql_stk_mode_e stk_mode = QL_STK_MODE_DISABLE;
  279. ql_stk_alphabet_set_e stk_alphabet_type = QL_STK_ALPHABET_SET_GSM;
  280. uint16_t stk_auto_response_timeout = 300;
  281. ql_stk_profile_s profile = {0};
  282. char profile_str[100] = {0};
  283. QL_STK_DEMO_LOG("========== stk demo start ==========");
  284. ql_stk_register_cb(user_stk_event_callback);
  285. ql_stk_cfg_get(&stk_mode, &stk_alphabet_type, &stk_auto_response_timeout);
  286. QL_STK_DEMO_LOG("get stk config mode:%d alphabet type:%d auto response timeout:%d",
  287. stk_mode, stk_alphabet_type, stk_auto_response_timeout);
  288. if (QL_STK_MODE_DISABLE == stk_mode)
  289. {
  290. /* config stk function */
  291. ret = ql_stk_cfg_set(QL_STK_MODE_ENABLE, QL_STK_ALPHABET_SET_UCS2, QL_STK_AUTO_RESPONSE_TIMEOUT_DEF);
  292. QL_STK_DEMO_LOG("ql_stk_cfg_set ret:%d", ret);
  293. ql_power_reset(RESET_NORMAL);
  294. goto exit;
  295. }
  296. /* get TERMINAL PROFILE data */
  297. ql_stk_get_terminal_profile(nSim, &profile);
  298. hex_to_string(profile.profile_buf, profile.profile_len, profile_str);
  299. QL_STK_DEMO_LOG("profile:%s", profile_str);
  300. while (1)
  301. {
  302. ql_event_t event = {0};
  303. ql_event_try_wait(&event);
  304. QL_STK_DEMO_LOG("get event: 0x%08x/0x%08x/0x%08x/0x%08x", event.id, event.param1, event.param2, event.param3);
  305. switch (event.id)
  306. {
  307. case QUEC_STK_PROACTIVE_CMD_IND: {
  308. uint8_t nSim = event.param1;
  309. uint8_t proactive_cmd = event.param2;
  310. stk_proactive_cmd_handler(nSim, proactive_cmd);
  311. break;
  312. }
  313. case QUEC_STK_TIMEOUT_IND: {
  314. break;
  315. }
  316. case QUEC_STK_SIM_LOST_IND: {
  317. break;
  318. }
  319. case QUEC_STK_NO_PROACTIVE_CMD_IND: {
  320. uint8_t nSim = event.param1;
  321. static bool select_setup_menu = true; /* avoid loopback */
  322. ql_stk_state_e state;
  323. ql_stk_proactive_cmd_e cur_cmd;
  324. if ((true == select_setup_menu) && (0 != menu_info.item_id[0]))
  325. {
  326. select_setup_menu = false;
  327. ql_stk_get_stk_proactive_cmd(nSim, &cur_cmd, &state);
  328. QL_STK_DEMO_LOG("command:%d state:%d", cur_cmd, state);
  329. /**
  330. * allow to select setup menu item while TERMINAL_RSP_STATE and none proactive command,
  331. * this will cause a ENVELOPE (MENU SELECTION) command to SIM
  332. *
  333. */
  334. if ((QL_STK_PROACTIVE_CMD_TERMINAL_RSP_STATE == state) && (QL_STK_PROACTIVE_CMD_NONE == cur_cmd))
  335. {
  336. // depend on SIM's MENU
  337. // QL_STK_DEMO_LOG("select setup menu item:%d", menu_info.item_id[0]);
  338. // ql_stk_send_command_result(nSim, QSTK_SIM_ENVELOPE_MENU_SELECTION, QL_STK_PERFORMED_SUCCESSFULLY, menu_info.item_id[0], NULL);
  339. }
  340. }
  341. break;
  342. }
  343. default:
  344. break;
  345. }
  346. ql_rtos_task_sleep_s(1);
  347. }
  348. exit:
  349. err = ql_rtos_task_delete(NULL);
  350. if (err != QL_OSI_SUCCESS)
  351. {
  352. QL_STK_DEMO_LOG("task deleted failed");
  353. }
  354. return;
  355. }
  356. int ql_stk_app_init(void)
  357. {
  358. QlOSStatus err = QL_OSI_SUCCESS;
  359. err = ql_rtos_task_create(&stk_task, 8 * 1024, 23, "stk_app", stk_app_thread, NULL, 5);
  360. if (err != QL_OSI_SUCCESS)
  361. {
  362. QL_STK_DEMO_LOG("stk_app init failed");
  363. }
  364. return err;
  365. }