flip_wifi_callback.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. #ifndef FLIP_WIFI_CALLBACK_H
  2. #define FLIP_WIFI_CALLBACK_H
  3. FlipWiFiApp *app_instance;
  4. static void callback_submenu_choices(void *context, uint32_t index);
  5. // array to store each SSID
  6. char *ssid_list[64];
  7. uint32_t ssid_index = 0;
  8. static void flip_wifi_redraw_submenu_saved(FlipWiFiApp *app)
  9. {
  10. // re draw the saved submenu
  11. submenu_reset(app->submenu_wifi_saved);
  12. submenu_set_header(app->submenu_wifi_saved, "Saved APs");
  13. submenu_add_item(app->submenu_wifi_saved, "[Add Network]", FlipWiFiSubmenuIndexWiFiSavedAddSSID, callback_submenu_choices, app);
  14. for (uint32_t i = 0; i < app->wifi_playlist.count; i++)
  15. {
  16. submenu_add_item(app->submenu_wifi_saved, app->wifi_playlist.ssids[i], FlipWiFiSubmenuIndexWiFiSavedStart + i, callback_submenu_choices, app);
  17. }
  18. }
  19. static uint32_t callback_to_submenu_main(void *context)
  20. {
  21. if (!context)
  22. {
  23. FURI_LOG_E(TAG, "Context is NULL");
  24. return VIEW_NONE;
  25. }
  26. UNUSED(context);
  27. ssid_index = 0;
  28. return FlipWiFiViewSubmenuMain;
  29. }
  30. static uint32_t callback_to_submenu_scan(void *context)
  31. {
  32. if (!context)
  33. {
  34. FURI_LOG_E(TAG, "Context is NULL");
  35. return VIEW_NONE;
  36. }
  37. UNUSED(context);
  38. ssid_index = 0;
  39. return FlipWiFiViewSubmenuScan;
  40. }
  41. static uint32_t callback_to_submenu_saved(void *context)
  42. {
  43. if (!context)
  44. {
  45. FURI_LOG_E(TAG, "Context is NULL");
  46. return VIEW_NONE;
  47. }
  48. UNUSED(context);
  49. ssid_index = 0;
  50. return FlipWiFiViewSubmenuSaved;
  51. }
  52. void popup_callback_saved(void *context)
  53. {
  54. FlipWiFiApp *app = (FlipWiFiApp *)context;
  55. if (!app)
  56. {
  57. FURI_LOG_E(TAG, "HelloWorldApp is NULL");
  58. return;
  59. }
  60. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuSaved);
  61. }
  62. void popup_callback_main(void *context)
  63. {
  64. FlipWiFiApp *app = (FlipWiFiApp *)context;
  65. if (!app)
  66. {
  67. FURI_LOG_E(TAG, "HelloWorldApp is NULL");
  68. return;
  69. }
  70. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuMain);
  71. }
  72. // Callback for drawing the main screen
  73. static void flip_wifi_view_draw_callback_scan(Canvas *canvas, void *model)
  74. {
  75. UNUSED(model);
  76. canvas_clear(canvas);
  77. canvas_set_font(canvas, FontPrimary);
  78. canvas_draw_str(canvas, 0, 10, ssid_list[ssid_index]);
  79. canvas_draw_icon(canvas, 0, 53, &I_ButtonBACK_10x8);
  80. canvas_draw_str_aligned(canvas, 12, 54, AlignLeft, AlignTop, "Back");
  81. canvas_draw_icon(canvas, 96, 53, &I_ButtonRight_4x7);
  82. canvas_draw_str_aligned(canvas, 103, 54, AlignLeft, AlignTop, "Add");
  83. }
  84. static void flip_wifi_view_draw_callback_saved(Canvas *canvas, void *model)
  85. {
  86. UNUSED(model);
  87. canvas_clear(canvas);
  88. canvas_set_font(canvas, FontPrimary);
  89. canvas_draw_str(canvas, 0, 10, app_instance->wifi_playlist.ssids[ssid_index]);
  90. canvas_set_font(canvas, FontSecondary);
  91. char password[64];
  92. snprintf(password, sizeof(password), "Pass: %s", app_instance->wifi_playlist.passwords[ssid_index]);
  93. canvas_draw_str(canvas, 0, 20, password);
  94. canvas_draw_icon(canvas, 0, 54, &I_ButtonLeft_4x7);
  95. canvas_draw_str_aligned(canvas, 7, 54, AlignLeft, AlignTop, "Delete");
  96. canvas_draw_icon(canvas, 37, 53, &I_ButtonBACK_10x8);
  97. canvas_draw_str_aligned(canvas, 49, 54, AlignLeft, AlignTop, "Back");
  98. canvas_draw_icon(canvas, 73, 54, &I_ButtonOK_7x7);
  99. canvas_draw_str_aligned(canvas, 81, 54, AlignLeft, AlignTop, "Set");
  100. canvas_draw_icon(canvas, 100, 54, &I_ButtonRight_4x7);
  101. canvas_draw_str_aligned(canvas, 107, 54, AlignLeft, AlignTop, "Edit");
  102. }
  103. // Input callback for the view (async input handling)
  104. bool flip_wifi_view_input_callback_scan(InputEvent *event, void *context)
  105. {
  106. FlipWiFiApp *app = (FlipWiFiApp *)context;
  107. if (event->type == InputTypePress && event->key == InputKeyRight)
  108. {
  109. // switch to text input to set password
  110. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInputScan);
  111. return true;
  112. }
  113. return false;
  114. }
  115. // Input callback for the view (async input handling)
  116. bool flip_wifi_view_input_callback_saved(InputEvent *event, void *context)
  117. {
  118. FlipWiFiApp *app = (FlipWiFiApp *)context;
  119. if (!app)
  120. {
  121. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  122. return false;
  123. }
  124. if (event->type == InputTypePress && event->key == InputKeyRight)
  125. {
  126. // set text input buffer as the selected password
  127. strncpy(app->uart_text_input_temp_buffer_password_saved, app->wifi_playlist.passwords[ssid_index], app->uart_text_input_buffer_size_password_saved);
  128. // switch to text input to set password
  129. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInputSaved);
  130. return true;
  131. }
  132. else if (event->type == InputTypePress && event->key == InputKeyOk)
  133. {
  134. // save the settings
  135. if (app->wifi_playlist.ssids[ssid_index] == NULL || app->wifi_playlist.passwords[ssid_index] == NULL)
  136. {
  137. return false;
  138. }
  139. save_settings(app->wifi_playlist.ssids[ssid_index], app->wifi_playlist.passwords[ssid_index]);
  140. flipper_http_save_wifi(app->wifi_playlist.ssids[ssid_index], app->wifi_playlist.passwords[ssid_index]);
  141. flipper_http_connect_wifi();
  142. popup_set_header(app->popup, "[SUCCESS]", 0, 0, AlignLeft, AlignTop);
  143. popup_set_text(app->popup, "All FlipperHTTP apps will now\nuse the selected network.", 0, 40, AlignLeft, AlignTop);
  144. view_set_previous_callback(popup_get_view(app->popup), callback_to_submenu_saved);
  145. popup_set_callback(app->popup, popup_callback_saved);
  146. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewPopup);
  147. return true;
  148. }
  149. else if (event->type == InputTypePress && event->key == InputKeyLeft)
  150. {
  151. // delete the selected ssid and password
  152. free(app->wifi_playlist.ssids[ssid_index]);
  153. free(app->wifi_playlist.passwords[ssid_index]);
  154. free(ssid_list[ssid_index]);
  155. // shift the remaining ssids and passwords
  156. for (uint32_t i = ssid_index; i < app->wifi_playlist.count - 1; i++)
  157. {
  158. app->wifi_playlist.ssids[i] = app->wifi_playlist.ssids[i + 1];
  159. app->wifi_playlist.passwords[i] = app->wifi_playlist.passwords[i + 1];
  160. ssid_list[i] = ssid_list[i + 1];
  161. }
  162. app->wifi_playlist.count--;
  163. // save the playlist to storage
  164. save_playlist(&app->wifi_playlist);
  165. // re draw the saved submenu
  166. flip_wifi_redraw_submenu_saved(app);
  167. // switch back to the saved view
  168. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuSaved);
  169. return true;
  170. }
  171. return false;
  172. }
  173. // Function to trim leading and trailing whitespace
  174. // Returns the trimmed start pointer and updates the length
  175. char *trim_whitespace(char *start, size_t *length)
  176. {
  177. // Trim leading whitespace
  178. while (*length > 0 && isspace((unsigned char)*start))
  179. {
  180. start++;
  181. (*length)--;
  182. }
  183. // Trim trailing whitespace
  184. while (*length > 0 && isspace((unsigned char)start[*length - 1]))
  185. {
  186. (*length)--;
  187. }
  188. return start;
  189. }
  190. bool flip_wifi_handle_scan(FlipWiFiApp *app)
  191. {
  192. if (fhttp.last_response == NULL || fhttp.last_response[0] == '\0')
  193. {
  194. FURI_LOG_E(TAG, "Failed to receive WiFi scan");
  195. return false;
  196. }
  197. uint32_t ssid_count = 0;
  198. char *current_position = fhttp.last_response;
  199. char *next_comma = NULL;
  200. // Manually split the string on commas
  201. while ((next_comma = strchr(current_position, ',')) != NULL)
  202. {
  203. // Calculate length of the SSID
  204. size_t ssid_length = next_comma - current_position;
  205. // Trim leading and trailing whitespace
  206. size_t trimmed_length = ssid_length;
  207. char *trim_start = trim_whitespace(current_position, &trimmed_length);
  208. // Handle empty SSIDs resulting from consecutive commas
  209. if (trimmed_length == 0)
  210. {
  211. current_position = next_comma + 1; // Move past the comma
  212. continue;
  213. }
  214. // Allocate memory for the SSID and copy it
  215. ssid_list[ssid_count] = malloc(trimmed_length + 1);
  216. if (ssid_list[ssid_count] == NULL)
  217. {
  218. FURI_LOG_E(TAG, "Memory allocation failed");
  219. return false;
  220. }
  221. strncpy(ssid_list[ssid_count], trim_start, trimmed_length);
  222. ssid_list[ssid_count][trimmed_length] = '\0'; // Null-terminate the string
  223. ssid_count++;
  224. if (ssid_count >= MAX_WIFI_NETWORKS)
  225. {
  226. FURI_LOG_E(TAG, "Maximum SSID limit reached");
  227. break;
  228. }
  229. current_position = next_comma + 1; // Move past the comma
  230. }
  231. // Handle the last SSID after the last comma (if any)
  232. if (*current_position != '\0' && ssid_count < MAX_WIFI_NETWORKS)
  233. {
  234. size_t ssid_length = strlen(current_position);
  235. // Trim leading and trailing whitespace
  236. size_t trimmed_length = ssid_length;
  237. char *trim_start = trim_whitespace(current_position, &trimmed_length);
  238. // Handle empty SSIDs
  239. if (trimmed_length > 0)
  240. {
  241. ssid_list[ssid_count] = malloc(trimmed_length + 1);
  242. if (ssid_list[ssid_count] == NULL)
  243. {
  244. FURI_LOG_E(TAG, "Memory allocation failed for the last SSID");
  245. return false;
  246. }
  247. strncpy(ssid_list[ssid_count], trim_start, trimmed_length);
  248. ssid_list[ssid_count][trimmed_length] = '\0'; // Null-terminate the string
  249. ssid_count++;
  250. }
  251. }
  252. // Add each SSID as a submenu item
  253. submenu_set_header(app->submenu_wifi_scan, "WiFi Nearby");
  254. for (uint32_t i = 0; i < ssid_count; i++)
  255. {
  256. char *ssid_item = ssid_list[i];
  257. if (ssid_item == NULL)
  258. {
  259. // skip any NULL entries
  260. continue;
  261. }
  262. char ssid[64];
  263. snprintf(ssid, sizeof(ssid), "%s", ssid_item);
  264. submenu_add_item(app->submenu_wifi_scan, ssid, FlipWiFiSubmenuIndexWiFiScanStart + i, callback_submenu_choices, app);
  265. }
  266. return true;
  267. }
  268. static void callback_submenu_choices(void *context, uint32_t index)
  269. {
  270. FlipWiFiApp *app = (FlipWiFiApp *)context;
  271. if (!app)
  272. {
  273. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  274. return;
  275. }
  276. switch (index)
  277. {
  278. case FlipWiFiSubmenuIndexWiFiScan:
  279. if (fhttp.state == INACTIVE)
  280. {
  281. popup_set_header(app->popup, "[ERROR]", 0, 0, AlignLeft, AlignTop);
  282. popup_set_text(app->popup, "WiFi Devboard Disconnected.\nPlease reconnect the board.", 0, 40, AlignLeft, AlignTop);
  283. view_set_previous_callback(popup_get_view(app->popup), callback_to_submenu_main);
  284. popup_set_callback(app->popup, popup_callback_main);
  285. // switch to the popup view
  286. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewPopup);
  287. }
  288. // scan for wifi
  289. if (!flipper_http_scan_wifi())
  290. {
  291. FURI_LOG_E(TAG, "Failed to scan for WiFi");
  292. return;
  293. }
  294. else // start the async feed request
  295. {
  296. furi_timer_start(fhttp.get_timeout_timer, TIMEOUT_DURATION_TICKS);
  297. fhttp.state = RECEIVING;
  298. }
  299. while (fhttp.state == RECEIVING && furi_timer_is_running(fhttp.get_timeout_timer) > 0)
  300. {
  301. // Wait for the feed to be received
  302. furi_delay_ms(100);
  303. }
  304. furi_timer_stop(fhttp.get_timeout_timer);
  305. // set each SSID as a submenu item
  306. if (fhttp.state != IDLE || fhttp.last_response == NULL)
  307. {
  308. FURI_LOG_E(TAG, "Failed to receive WiFi scan");
  309. return;
  310. }
  311. else
  312. {
  313. submenu_reset(app->submenu_wifi_scan);
  314. submenu_set_header(app->submenu_wifi_scan, "WiFi Nearby");
  315. if (flip_wifi_handle_scan(app))
  316. {
  317. // switch to the submenu
  318. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuScan);
  319. }
  320. FURI_LOG_E(TAG, "Failed to handle WiFi scan");
  321. return;
  322. }
  323. break;
  324. case FlipWiFiSubmenuIndexWiFiSaved:
  325. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuSaved);
  326. break;
  327. case FlipWiFiSubmenuIndexAbout:
  328. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewAbout);
  329. break;
  330. case FlipWiFiSubmenuIndexWiFiSavedAddSSID:
  331. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInputSavedAddSSID);
  332. break;
  333. case 100 ... 163:
  334. ssid_index = index - FlipWiFiSubmenuIndexWiFiScanStart;
  335. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewWiFiScan);
  336. break;
  337. case 200 ... 263:
  338. ssid_index = index - FlipWiFiSubmenuIndexWiFiSavedStart;
  339. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewWiFiSaved);
  340. break;
  341. default:
  342. break;
  343. }
  344. }
  345. static void flip_wifi_text_updated_password_scan(void *context)
  346. {
  347. FlipWiFiApp *app = (FlipWiFiApp *)context;
  348. if (!app)
  349. {
  350. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  351. return;
  352. }
  353. // store the entered text
  354. strncpy(app->uart_text_input_buffer_password_scan, app->uart_text_input_temp_buffer_password_scan, app->uart_text_input_buffer_size_password_scan);
  355. // Ensure null-termination
  356. app->uart_text_input_buffer_password_scan[app->uart_text_input_buffer_size_password_scan - 1] = '\0';
  357. // add the SSID and password_scan to the playlist
  358. app->wifi_playlist.ssids[app->wifi_playlist.count] = strdup(ssid_list[ssid_index]);
  359. app->wifi_playlist.passwords[app->wifi_playlist.count] = strdup(app->uart_text_input_buffer_password_scan);
  360. app->wifi_playlist.count++;
  361. // save the playlist to storage
  362. save_playlist(&app->wifi_playlist);
  363. flip_wifi_redraw_submenu_saved(app);
  364. // switch to back to the scan view
  365. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuScan);
  366. }
  367. static void flip_wifi_text_updated_password_saved(void *context)
  368. {
  369. FlipWiFiApp *app = (FlipWiFiApp *)context;
  370. if (!app)
  371. {
  372. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  373. return;
  374. }
  375. // store the entered text
  376. strncpy(app->uart_text_input_buffer_password_saved, app->uart_text_input_temp_buffer_password_saved, app->uart_text_input_buffer_size_password_saved);
  377. // Ensure null-termination
  378. app->uart_text_input_buffer_password_saved[app->uart_text_input_buffer_size_password_saved - 1] = '\0';
  379. // update the password_saved in the playlist
  380. app->wifi_playlist.passwords[ssid_index] = strdup(app->uart_text_input_buffer_password_saved);
  381. // save the playlist to storage
  382. save_playlist(&app->wifi_playlist);
  383. // switch to back to the saved view
  384. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuSaved);
  385. }
  386. static void flip_wifi_text_updated_add_ssid(void *context)
  387. {
  388. FlipWiFiApp *app = (FlipWiFiApp *)context;
  389. if (!app)
  390. {
  391. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  392. return;
  393. }
  394. // store the entered text
  395. strncpy(app->uart_text_input_buffer_add_ssid, app->uart_text_input_temp_buffer_add_ssid, app->uart_text_input_buffer_size_add_ssid);
  396. // Ensure null-termination
  397. app->uart_text_input_buffer_add_ssid[app->uart_text_input_buffer_size_add_ssid - 1] = '\0';
  398. // do nothing for now, go to the next text input to set the password
  399. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInputSavedAddPassword);
  400. }
  401. static void flip_wifi_text_updated_add_password(void *context)
  402. {
  403. FlipWiFiApp *app = (FlipWiFiApp *)context;
  404. if (!app)
  405. {
  406. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  407. return;
  408. }
  409. // store the entered text
  410. strncpy(app->uart_text_input_buffer_add_password, app->uart_text_input_temp_buffer_add_password, app->uart_text_input_buffer_size_add_password);
  411. // Ensure null-termination
  412. app->uart_text_input_buffer_add_password[app->uart_text_input_buffer_size_add_password - 1] = '\0';
  413. // add the SSID and password_scan to the playlist
  414. app->wifi_playlist.ssids[app->wifi_playlist.count] = strdup(app->uart_text_input_buffer_add_ssid);
  415. app->wifi_playlist.passwords[app->wifi_playlist.count] = strdup(app->uart_text_input_buffer_add_password);
  416. app->wifi_playlist.count++;
  417. // save the playlist to storage
  418. save_playlist(&app->wifi_playlist);
  419. flip_wifi_redraw_submenu_saved(app);
  420. // switch to back to the saved view
  421. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuSaved);
  422. }
  423. #endif // FLIP_WIFI_CALLBACK_H