flip_trader_callback.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. #include <callback/flip_trader_callback.h>
  2. // hold the price of the asset
  3. char asset_price[64];
  4. bool sent_get_request = false;
  5. bool get_request_success = false;
  6. bool request_processed = false;
  7. void flip_trader_request_error(Canvas *canvas)
  8. {
  9. if (fhttp.last_response != NULL)
  10. {
  11. if (strstr(fhttp.last_response, "[ERROR] Not connected to Wifi. Failed to reconnect.") != NULL)
  12. {
  13. canvas_clear(canvas);
  14. canvas_draw_str(canvas, 0, 10, "[ERROR] Not connected to Wifi.");
  15. canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
  16. canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
  17. }
  18. else if (strstr(fhttp.last_response, "[ERROR] Failed to connect to Wifi.") != NULL)
  19. {
  20. canvas_clear(canvas);
  21. canvas_draw_str(canvas, 0, 10, "[ERROR] Not connected to Wifi.");
  22. canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
  23. canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
  24. }
  25. else if (strstr(fhttp.last_response, "[ERROR] WiFi SSID or Password is empty") != NULL)
  26. {
  27. canvas_clear(canvas);
  28. canvas_draw_str(canvas, 0, 10, "[ERROR] Not connected to Wifi.");
  29. canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
  30. canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
  31. }
  32. else
  33. {
  34. canvas_clear(canvas);
  35. FURI_LOG_E(TAG, "Received an error: %s", fhttp.last_response);
  36. canvas_draw_str(canvas, 0, 10, "[ERROR] Unusual error...");
  37. canvas_draw_str(canvas, 0, 60, "Press BACK and retry.");
  38. }
  39. }
  40. else
  41. {
  42. canvas_clear(canvas);
  43. canvas_draw_str(canvas, 0, 10, "[ERROR] Unknown error.");
  44. canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
  45. canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
  46. }
  47. }
  48. bool send_price_request()
  49. {
  50. if (fhttp.state == INACTIVE)
  51. {
  52. return false;
  53. }
  54. if (!sent_get_request && fhttp.state == IDLE)
  55. {
  56. sent_get_request = true;
  57. char url[128];
  58. char *headers = jsmn("Content-Type", "application/json");
  59. snprintf(
  60. fhttp.file_path,
  61. sizeof(fhttp.file_path),
  62. STORAGE_EXT_PATH_PREFIX "/apps_data/flip_trader/price.txt");
  63. fhttp.save_received_data = true;
  64. snprintf(url, 128, "https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=%s&apikey=2X90WLEFMP43OJKE", asset_names[asset_index]);
  65. get_request_success = flipper_http_get_request_with_headers(url, headers);
  66. free(headers);
  67. if (!get_request_success)
  68. {
  69. FURI_LOG_E(TAG, "Failed to send GET request");
  70. fhttp.state = ISSUE;
  71. return false;
  72. }
  73. fhttp.state = RECEIVING;
  74. }
  75. return true;
  76. }
  77. void process_asset_price()
  78. {
  79. if (!request_processed)
  80. {
  81. // load the received data from the saved file
  82. FuriString *price_data = flipper_http_load_from_file(fhttp.file_path);
  83. if (price_data == NULL)
  84. {
  85. FURI_LOG_E(TAG, "Failed to load received data from file.");
  86. fhttp.state = ISSUE;
  87. return;
  88. }
  89. char *data_cstr = (char *)furi_string_get_cstr(price_data);
  90. if (data_cstr == NULL)
  91. {
  92. FURI_LOG_E(TAG, "Failed to get C-string from FuriString.");
  93. furi_string_free(price_data);
  94. fhttp.state = ISSUE;
  95. return;
  96. }
  97. request_processed = true;
  98. char *global_quote = get_json_value("Global Quote", data_cstr, MAX_TOKENS);
  99. if (global_quote == NULL)
  100. {
  101. FURI_LOG_E(TAG, "Failed to get Global Quote");
  102. fhttp.state = ISSUE;
  103. furi_string_free(price_data);
  104. free(global_quote);
  105. free(data_cstr);
  106. return;
  107. }
  108. char *price = get_json_value("05. price", global_quote, MAX_TOKENS);
  109. if (price == NULL)
  110. {
  111. FURI_LOG_E(TAG, "Failed to get price");
  112. fhttp.state = ISSUE;
  113. furi_string_free(price_data);
  114. free(global_quote);
  115. free(price);
  116. free(data_cstr);
  117. return;
  118. }
  119. // store the price "Asset: $price"
  120. snprintf(asset_price, 64, "%s: $%s", asset_names[asset_index], price);
  121. fhttp.state = IDLE;
  122. furi_string_free(price_data);
  123. free(global_quote);
  124. free(price);
  125. free(data_cstr);
  126. }
  127. }
  128. // Callback for drawing the main screen
  129. void flip_trader_view_draw_callback(Canvas *canvas, void *model)
  130. {
  131. if (!canvas)
  132. {
  133. return;
  134. }
  135. UNUSED(model);
  136. canvas_set_font(canvas, FontSecondary);
  137. if (fhttp.state == INACTIVE)
  138. {
  139. canvas_draw_str(canvas, 0, 7, "Wifi Dev Board disconnected.");
  140. canvas_draw_str(canvas, 0, 17, "Please connect to the board.");
  141. canvas_draw_str(canvas, 0, 32, "If your board is connected,");
  142. canvas_draw_str(canvas, 0, 42, "make sure you have flashed");
  143. canvas_draw_str(canvas, 0, 52, "your WiFi Devboard with the");
  144. canvas_draw_str(canvas, 0, 62, "latest FlipperHTTP flash.");
  145. return;
  146. }
  147. canvas_draw_str(canvas, 0, 10, "Loading...");
  148. // canvas_draw_str(canvas, 0, 10, asset_names[asset_index]);
  149. // start the process
  150. if (!send_price_request())
  151. {
  152. flip_trader_request_error(canvas);
  153. }
  154. // wait until the request is processed
  155. if (!sent_get_request || !get_request_success || fhttp.state == RECEIVING)
  156. {
  157. return;
  158. }
  159. // check status
  160. if (fhttp.state == ISSUE || fhttp.last_response == NULL)
  161. {
  162. flip_trader_request_error(canvas);
  163. }
  164. // success, process the data
  165. process_asset_price();
  166. canvas_clear(canvas);
  167. canvas_draw_str(canvas, 0, 10, asset_price);
  168. }
  169. // Input callback for the view (async input handling)
  170. bool flip_trader_view_input_callback(InputEvent *event, void *context)
  171. {
  172. FlipTraderApp *app = (FlipTraderApp *)context;
  173. if (event->type == InputTypePress && event->key == InputKeyBack)
  174. {
  175. // Exit the app when the back button is pressed
  176. view_dispatcher_stop(app->view_dispatcher);
  177. return true;
  178. }
  179. return false;
  180. }
  181. void callback_submenu_choices(void *context, uint32_t index)
  182. {
  183. FlipTraderApp *app = (FlipTraderApp *)context;
  184. if (!app)
  185. {
  186. FURI_LOG_E(TAG, "FlipTraderApp is NULL");
  187. return;
  188. }
  189. switch (index)
  190. {
  191. // view the assets submenu
  192. case FlipTradeSubmenuIndexAssets:
  193. view_dispatcher_switch_to_view(app->view_dispatcher, FlipTraderViewAssetsSubmenu);
  194. break;
  195. // view the about screen
  196. case FlipTraderSubmenuIndexAbout:
  197. view_dispatcher_switch_to_view(app->view_dispatcher, FlipTraderViewAbout);
  198. break;
  199. // view the wifi settings screen
  200. case FlipTraderSubmenuIndexSettings:
  201. view_dispatcher_switch_to_view(app->view_dispatcher, FlipTraderViewWiFiSettings);
  202. break;
  203. default:
  204. // handle FlipTraderSubmenuIndexAssetStartIndex + index
  205. if (index >= FlipTraderSubmenuIndexAssetStartIndex)
  206. {
  207. asset_index = index - FlipTraderSubmenuIndexAssetStartIndex;
  208. view_dispatcher_switch_to_view(app->view_dispatcher, FlipTraderViewMain);
  209. }
  210. else
  211. {
  212. FURI_LOG_E(TAG, "Unknown submenu index");
  213. }
  214. break;
  215. }
  216. }
  217. void text_updated_ssid(void *context)
  218. {
  219. FlipTraderApp *app = (FlipTraderApp *)context;
  220. if (!app)
  221. {
  222. FURI_LOG_E(TAG, "FlipTraderApp is NULL");
  223. return;
  224. }
  225. // store the entered text
  226. strncpy(app->uart_text_input_buffer_ssid, app->uart_text_input_temp_buffer_ssid, app->uart_text_input_buffer_size_ssid);
  227. // Ensure null-termination
  228. app->uart_text_input_buffer_ssid[app->uart_text_input_buffer_size_ssid - 1] = '\0';
  229. // update the variable item text
  230. if (app->variable_item_ssid)
  231. {
  232. variable_item_set_current_value_text(app->variable_item_ssid, app->uart_text_input_buffer_ssid);
  233. }
  234. // save settings
  235. save_settings(app->uart_text_input_buffer_ssid, app->uart_text_input_buffer_password);
  236. // save wifi settings to devboard
  237. if (strlen(app->uart_text_input_buffer_ssid) > 0 && strlen(app->uart_text_input_buffer_password) > 0)
  238. {
  239. if (!flipper_http_save_wifi(app->uart_text_input_buffer_ssid, app->uart_text_input_buffer_password))
  240. {
  241. FURI_LOG_E(TAG, "Failed to save wifi settings");
  242. }
  243. }
  244. // switch to the settings view
  245. view_dispatcher_switch_to_view(app->view_dispatcher, FlipTraderViewWiFiSettings);
  246. }
  247. void text_updated_password(void *context)
  248. {
  249. FlipTraderApp *app = (FlipTraderApp *)context;
  250. if (!app)
  251. {
  252. FURI_LOG_E(TAG, "FlipTraderApp is NULL");
  253. return;
  254. }
  255. // store the entered text
  256. strncpy(app->uart_text_input_buffer_password, app->uart_text_input_temp_buffer_password, app->uart_text_input_buffer_size_password);
  257. // Ensure null-termination
  258. app->uart_text_input_buffer_password[app->uart_text_input_buffer_size_password - 1] = '\0';
  259. // update the variable item text
  260. if (app->variable_item_password)
  261. {
  262. variable_item_set_current_value_text(app->variable_item_password, app->uart_text_input_buffer_password);
  263. }
  264. // save settings
  265. save_settings(app->uart_text_input_buffer_ssid, app->uart_text_input_buffer_password);
  266. // save wifi settings to devboard
  267. if (strlen(app->uart_text_input_buffer_ssid) > 0 && strlen(app->uart_text_input_buffer_password) > 0)
  268. {
  269. if (!flipper_http_save_wifi(app->uart_text_input_buffer_ssid, app->uart_text_input_buffer_password))
  270. {
  271. FURI_LOG_E(TAG, "Failed to save wifi settings");
  272. }
  273. }
  274. // switch to the settings view
  275. view_dispatcher_switch_to_view(app->view_dispatcher, FlipTraderViewWiFiSettings);
  276. }
  277. uint32_t callback_to_submenu(void *context)
  278. {
  279. if (!context)
  280. {
  281. FURI_LOG_E(TAG, "Context is NULL");
  282. return VIEW_NONE;
  283. }
  284. UNUSED(context);
  285. sent_get_request = false;
  286. get_request_success = false;
  287. request_processed = false;
  288. asset_index = 0;
  289. return FlipTraderViewMainSubmenu;
  290. }
  291. uint32_t callback_to_wifi_settings(void *context)
  292. {
  293. if (!context)
  294. {
  295. FURI_LOG_E(TAG, "Context is NULL");
  296. return VIEW_NONE;
  297. }
  298. UNUSED(context);
  299. return FlipTraderViewWiFiSettings;
  300. }
  301. uint32_t callback_to_assets_submenu(void *context)
  302. {
  303. if (!context)
  304. {
  305. FURI_LOG_E(TAG, "Context is NULL");
  306. return VIEW_NONE;
  307. }
  308. UNUSED(context);
  309. sent_get_request = false;
  310. get_request_success = false;
  311. request_processed = false;
  312. asset_index = 0;
  313. return FlipTraderViewAssetsSubmenu;
  314. }
  315. void settings_item_selected(void *context, uint32_t index)
  316. {
  317. FlipTraderApp *app = (FlipTraderApp *)context;
  318. if (!app)
  319. {
  320. FURI_LOG_E(TAG, "FlipTraderApp is NULL");
  321. return;
  322. }
  323. switch (index)
  324. {
  325. case 0: // Input SSID
  326. view_dispatcher_switch_to_view(app->view_dispatcher, FlipTraderViewTextInputSSID);
  327. break;
  328. case 1: // Input Password
  329. view_dispatcher_switch_to_view(app->view_dispatcher, FlipTraderViewTextInputPassword);
  330. break;
  331. default:
  332. FURI_LOG_E(TAG, "Unknown configuration item index");
  333. break;
  334. }
  335. }