esp_flasher_scene_browse.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. #include "../esp_flasher_app_i.h"
  2. #include "../esp_flasher_worker.h"
  3. enum SubmenuIndex {
  4. SubmenuIndexS3Mode,
  5. SubmenuIndexBoot,
  6. SubmenuIndexPart,
  7. SubmenuIndexNvs,
  8. SubmenuIndexBootApp0,
  9. SubmenuIndexAppA,
  10. SubmenuIndexAppB,
  11. SubmenuIndexCustom,
  12. SubmenuIndexFlash,
  13. };
  14. static void esp_flasher_scene_browse_callback(void* context, uint32_t index) {
  15. EspFlasherApp* app = context;
  16. scene_manager_set_scene_state(app->scene_manager, EspFlasherSceneBrowse, index);
  17. // browse for files
  18. FuriString* predefined_filepath = furi_string_alloc_set_str(ESP_APP_FOLDER);
  19. FuriString* selected_filepath = furi_string_alloc();
  20. DialogsFileBrowserOptions browser_options;
  21. dialog_file_browser_set_basic_options(&browser_options, ".bin", &I_Text_10x10);
  22. // TODO refactor
  23. switch(index) {
  24. case SubmenuIndexS3Mode:
  25. // toggle S3 mode
  26. app->selected_flash_options[SelectedFlashS3Mode] =
  27. !app->selected_flash_options[SelectedFlashS3Mode];
  28. view_dispatcher_send_custom_event(app->view_dispatcher, EspFlasherEventRefreshSubmenu);
  29. break;
  30. case SubmenuIndexBoot:
  31. app->selected_flash_options[SelectedFlashBoot] =
  32. !app->selected_flash_options[SelectedFlashBoot];
  33. if(app->selected_flash_options[SelectedFlashBoot]) {
  34. if(dialog_file_browser_show(
  35. app->dialogs, selected_filepath, predefined_filepath, &browser_options)) {
  36. strncpy(
  37. app->bin_file_path_boot,
  38. furi_string_get_cstr(selected_filepath),
  39. sizeof(app->bin_file_path_boot));
  40. }
  41. }
  42. if(app->bin_file_path_boot[0] == '\0') {
  43. // if user didn't select a file, leave unselected
  44. app->selected_flash_options[SelectedFlashBoot] = false;
  45. }
  46. view_dispatcher_send_custom_event(app->view_dispatcher, EspFlasherEventRefreshSubmenu);
  47. break;
  48. case SubmenuIndexPart:
  49. app->selected_flash_options[SelectedFlashPart] =
  50. !app->selected_flash_options[SelectedFlashPart];
  51. if(dialog_file_browser_show(
  52. app->dialogs, selected_filepath, predefined_filepath, &browser_options)) {
  53. strncpy(
  54. app->bin_file_path_part,
  55. furi_string_get_cstr(selected_filepath),
  56. sizeof(app->bin_file_path_part));
  57. }
  58. if(app->bin_file_path_part[0] == '\0') {
  59. // if user didn't select a file, leave unselected
  60. app->selected_flash_options[SelectedFlashPart] = false;
  61. }
  62. view_dispatcher_send_custom_event(app->view_dispatcher, EspFlasherEventRefreshSubmenu);
  63. break;
  64. case SubmenuIndexNvs:
  65. app->selected_flash_options[SelectedFlashNvs] =
  66. !app->selected_flash_options[SelectedFlashNvs];
  67. if(dialog_file_browser_show(
  68. app->dialogs, selected_filepath, predefined_filepath, &browser_options)) {
  69. strncpy(
  70. app->bin_file_path_nvs,
  71. furi_string_get_cstr(selected_filepath),
  72. sizeof(app->bin_file_path_nvs));
  73. }
  74. if(app->bin_file_path_nvs[0] == '\0') {
  75. // if user didn't select a file, leave unselected
  76. app->selected_flash_options[SelectedFlashNvs] = false;
  77. }
  78. view_dispatcher_send_custom_event(app->view_dispatcher, EspFlasherEventRefreshSubmenu);
  79. break;
  80. case SubmenuIndexBootApp0:
  81. app->selected_flash_options[SelectedFlashBootApp0] =
  82. !app->selected_flash_options[SelectedFlashBootApp0];
  83. if(dialog_file_browser_show(
  84. app->dialogs, selected_filepath, predefined_filepath, &browser_options)) {
  85. strncpy(
  86. app->bin_file_path_boot_app0,
  87. furi_string_get_cstr(selected_filepath),
  88. sizeof(app->bin_file_path_boot_app0));
  89. }
  90. if(app->bin_file_path_boot_app0[0] == '\0') {
  91. // if user didn't select a file, leave unselected
  92. app->selected_flash_options[SelectedFlashBootApp0] = false;
  93. }
  94. view_dispatcher_send_custom_event(app->view_dispatcher, EspFlasherEventRefreshSubmenu);
  95. break;
  96. case SubmenuIndexAppA:
  97. app->selected_flash_options[SelectedFlashAppA] =
  98. !app->selected_flash_options[SelectedFlashAppA];
  99. if(dialog_file_browser_show(
  100. app->dialogs, selected_filepath, predefined_filepath, &browser_options)) {
  101. strncpy(
  102. app->bin_file_path_app_a,
  103. furi_string_get_cstr(selected_filepath),
  104. sizeof(app->bin_file_path_app_a));
  105. }
  106. if(app->bin_file_path_app_a[0] == '\0') {
  107. // if user didn't select a file, leave unselected
  108. app->selected_flash_options[SelectedFlashAppA] = false;
  109. }
  110. view_dispatcher_send_custom_event(app->view_dispatcher, EspFlasherEventRefreshSubmenu);
  111. break;
  112. case SubmenuIndexAppB:
  113. app->selected_flash_options[SelectedFlashAppB] =
  114. !app->selected_flash_options[SelectedFlashAppB];
  115. if(dialog_file_browser_show(
  116. app->dialogs, selected_filepath, predefined_filepath, &browser_options)) {
  117. strncpy(
  118. app->bin_file_path_app_b,
  119. furi_string_get_cstr(selected_filepath),
  120. sizeof(app->bin_file_path_app_b));
  121. }
  122. if(app->bin_file_path_app_b[0] == '\0') {
  123. // if user didn't select a file, leave unselected
  124. app->selected_flash_options[SelectedFlashAppB] = false;
  125. }
  126. view_dispatcher_send_custom_event(app->view_dispatcher, EspFlasherEventRefreshSubmenu);
  127. break;
  128. case SubmenuIndexCustom:
  129. app->selected_flash_options[SelectedFlashCustom] =
  130. !app->selected_flash_options[SelectedFlashCustom];
  131. if(dialog_file_browser_show(
  132. app->dialogs, selected_filepath, predefined_filepath, &browser_options)) {
  133. strncpy(
  134. app->bin_file_path_custom,
  135. furi_string_get_cstr(selected_filepath),
  136. sizeof(app->bin_file_path_custom));
  137. }
  138. if(app->bin_file_path_custom[0] == '\0') {
  139. // if user didn't select a file, leave unselected
  140. app->selected_flash_options[SelectedFlashCustom] = false;
  141. }
  142. view_dispatcher_send_custom_event(app->view_dispatcher, EspFlasherEventRefreshSubmenu);
  143. break;
  144. case SubmenuIndexFlash:
  145. // count how many options are selected
  146. app->num_selected_flash_options = 0;
  147. for(bool* option = &app->selected_flash_options[SelectedFlashBoot];
  148. option < &app->selected_flash_options[NUM_FLASH_OPTIONS];
  149. ++option) {
  150. if(*option) {
  151. ++app->num_selected_flash_options;
  152. }
  153. }
  154. if(app->num_selected_flash_options) {
  155. // only start next scene if at least one option is selected
  156. scene_manager_next_scene(app->scene_manager, EspFlasherSceneConsoleOutput);
  157. }
  158. break;
  159. }
  160. furi_string_free(selected_filepath);
  161. furi_string_free(predefined_filepath);
  162. }
  163. #define STR_SELECT "[x]"
  164. #define STR_UNSELECT "[ ]"
  165. #define STR_BOOT "Bootloader (" TOSTRING(ESP_ADDR_BOOT) ")"
  166. #define STR_BOOT_S3 "Bootloader (" TOSTRING(ESP_ADDR_BOOT_S3) ")"
  167. #define STR_PART "Part Table (" TOSTRING(ESP_ADDR_PART) ")"
  168. #define STR_NVS "NVS (" TOSTRING(ESP_ADDR_NVS) ")"
  169. #define STR_BOOT_APP0 "boot_app0 (" TOSTRING(ESP_ADDR_BOOT_APP0) ")"
  170. #define STR_APP_A "FirmwareA(" TOSTRING(ESP_ADDR_APP_A) ")"
  171. #define STR_APP_B "FirmwareB(" TOSTRING(ESP_ADDR_APP_B) ")"
  172. #define STR_CUSTOM "Custom"
  173. #define STR_FLASH_S3 "[>] FLASH (ESP32-S3)"
  174. #define STR_FLASH "[>] FLASH"
  175. static void _refresh_submenu(EspFlasherApp* app) {
  176. Submenu* submenu = app->submenu;
  177. submenu_reset(app->submenu);
  178. submenu_set_header(submenu, "Browse for files to flash");
  179. submenu_add_item(
  180. submenu,
  181. app->selected_flash_options[SelectedFlashS3Mode] ? "[x] Using ESP32-S3" :
  182. "[ ] Select if using S3",
  183. SubmenuIndexS3Mode,
  184. esp_flasher_scene_browse_callback,
  185. app);
  186. const char* strSelectBootloader = STR_UNSELECT " " STR_BOOT;
  187. if(app->selected_flash_options[SelectedFlashS3Mode]) {
  188. if(app->selected_flash_options[SelectedFlashBoot]) {
  189. strSelectBootloader = STR_SELECT " " STR_BOOT_S3;
  190. } else {
  191. strSelectBootloader = STR_UNSELECT " " STR_BOOT_S3;
  192. }
  193. } else {
  194. if(app->selected_flash_options[SelectedFlashBoot]) {
  195. strSelectBootloader = STR_SELECT " " STR_BOOT;
  196. } else {
  197. strSelectBootloader = STR_UNSELECT " " STR_BOOT;
  198. }
  199. }
  200. submenu_add_item(
  201. submenu, strSelectBootloader, SubmenuIndexBoot, esp_flasher_scene_browse_callback, app);
  202. submenu_add_item(
  203. submenu,
  204. app->selected_flash_options[SelectedFlashPart] ? STR_SELECT " " STR_PART :
  205. STR_UNSELECT " " STR_PART,
  206. SubmenuIndexPart,
  207. esp_flasher_scene_browse_callback,
  208. app);
  209. submenu_add_item(
  210. submenu,
  211. app->selected_flash_options[SelectedFlashNvs] ? STR_SELECT " " STR_NVS :
  212. STR_UNSELECT " " STR_NVS,
  213. SubmenuIndexNvs,
  214. esp_flasher_scene_browse_callback,
  215. app);
  216. submenu_add_item(
  217. submenu,
  218. app->selected_flash_options[SelectedFlashBootApp0] ? STR_SELECT " " STR_BOOT_APP0 :
  219. STR_UNSELECT " " STR_BOOT_APP0,
  220. SubmenuIndexBootApp0,
  221. esp_flasher_scene_browse_callback,
  222. app);
  223. submenu_add_item(
  224. submenu,
  225. app->selected_flash_options[SelectedFlashAppA] ? STR_SELECT " " STR_APP_A :
  226. STR_UNSELECT " " STR_APP_A,
  227. SubmenuIndexAppA,
  228. esp_flasher_scene_browse_callback,
  229. app);
  230. submenu_add_item(
  231. submenu,
  232. app->selected_flash_options[SelectedFlashAppB] ? STR_SELECT " " STR_APP_B :
  233. STR_UNSELECT " " STR_APP_B,
  234. SubmenuIndexAppB,
  235. esp_flasher_scene_browse_callback,
  236. app);
  237. // TODO: custom addr
  238. //submenu_add_item(
  239. // submenu, app->selected_flash_options[SelectedFlashCustom] ? STR_SELECT " " STR_CUSTOM : STR_UNSELECT " " STR_CUSTOM, SubmenuIndexCustom, esp_flasher_scene_browse_callback, app);
  240. submenu_add_item(
  241. submenu,
  242. app->selected_flash_options[SelectedFlashS3Mode] ? STR_FLASH_S3 : STR_FLASH,
  243. SubmenuIndexFlash,
  244. esp_flasher_scene_browse_callback,
  245. app);
  246. submenu_set_selected_item(
  247. submenu, scene_manager_get_scene_state(app->scene_manager, EspFlasherSceneBrowse));
  248. view_dispatcher_switch_to_view(app->view_dispatcher, EspFlasherAppViewSubmenu);
  249. }
  250. void esp_flasher_scene_browse_on_enter(void* context) {
  251. EspFlasherApp* app = context;
  252. memset(app->selected_flash_options, 0, sizeof(app->selected_flash_options));
  253. app->bin_file_path_boot[0] = '\0';
  254. app->bin_file_path_part[0] = '\0';
  255. app->bin_file_path_nvs[0] = '\0';
  256. app->bin_file_path_boot_app0[0] = '\0';
  257. app->bin_file_path_app_a[0] = '\0';
  258. app->bin_file_path_app_b[0] = '\0';
  259. app->bin_file_path_custom[0] = '\0';
  260. _refresh_submenu(app);
  261. }
  262. bool esp_flasher_scene_browse_on_event(void* context, SceneManagerEvent event) {
  263. EspFlasherApp* app = context;
  264. bool consumed = false;
  265. if(event.type == SceneManagerEventTypeCustom) {
  266. if(event.event == EspFlasherEventRefreshSubmenu) {
  267. _refresh_submenu(app);
  268. consumed = true;
  269. }
  270. }
  271. return consumed;
  272. }
  273. void esp_flasher_scene_browse_on_exit(void* context) {
  274. EspFlasherApp* app = context;
  275. submenu_reset(app->submenu);
  276. }