flip_wifi_callback.h 17 KB

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