esp_flasher_scene_browse.c 12 KB

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