esp_flasher_worker.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. #include "esp_flasher_worker.h"
  2. FuriStreamBuffer* flash_rx_stream; // TODO make safe
  3. EspFlasherApp* global_app; // TODO make safe
  4. FuriTimer* timer; // TODO make
  5. static uint32_t _remaining_time = 0;
  6. static void _timer_callback(void* context) {
  7. UNUSED(context);
  8. if(_remaining_time > 0) {
  9. _remaining_time--;
  10. }
  11. }
  12. static esp_loader_error_t _flash_file(EspFlasherApp* app, char* filepath, uint32_t addr) {
  13. // TODO cleanup
  14. esp_loader_error_t err;
  15. static uint8_t payload[1024];
  16. File* bin_file = storage_file_alloc(app->storage);
  17. char user_msg[256];
  18. // open file
  19. if(!storage_file_open(bin_file, filepath, FSAM_READ, FSOM_OPEN_EXISTING)) {
  20. storage_file_close(bin_file);
  21. storage_file_free(bin_file);
  22. dialog_message_show_storage_error(app->dialogs, "Cannot open file");
  23. return ESP_LOADER_ERROR_FAIL;
  24. }
  25. uint64_t size = storage_file_size(bin_file);
  26. loader_port_debug_print("Erasing flash...this may take a while\n");
  27. err = esp_loader_flash_start(addr, size, sizeof(payload));
  28. if(err != ESP_LOADER_SUCCESS) {
  29. storage_file_close(bin_file);
  30. storage_file_free(bin_file);
  31. snprintf(user_msg, sizeof(user_msg), "Erasing flash failed with error %d\n", err);
  32. loader_port_debug_print(user_msg);
  33. return err;
  34. }
  35. loader_port_debug_print("Start programming\n");
  36. uint64_t last_updated = size;
  37. while(size > 0) {
  38. if((last_updated - size) > 50000) {
  39. // inform user every 50k bytes
  40. // TODO: draw a progress bar next update
  41. snprintf(user_msg, sizeof(user_msg), "%llu bytes left.\n", size);
  42. loader_port_debug_print(user_msg);
  43. last_updated = size;
  44. }
  45. size_t to_read = MIN(size, sizeof(payload));
  46. uint16_t num_bytes = storage_file_read(bin_file, payload, to_read);
  47. err = esp_loader_flash_write(payload, num_bytes);
  48. if(err != ESP_LOADER_SUCCESS) {
  49. snprintf(user_msg, sizeof(user_msg), "Packet could not be written! Error: %u\n", err);
  50. storage_file_close(bin_file);
  51. storage_file_free(bin_file);
  52. loader_port_debug_print(user_msg);
  53. return err;
  54. }
  55. size -= num_bytes;
  56. }
  57. loader_port_debug_print("Finished programming\n");
  58. // TODO verify
  59. storage_file_close(bin_file);
  60. storage_file_free(bin_file);
  61. return ESP_LOADER_SUCCESS;
  62. }
  63. typedef struct {
  64. SelectedFlashOptions selected;
  65. const char* description;
  66. char* path;
  67. uint32_t addr;
  68. } FlashItem;
  69. static void _flash_all_files(EspFlasherApp* app) {
  70. esp_loader_error_t err;
  71. const int num_steps = app->num_selected_flash_options;
  72. #define NUM_FLASH_ITEMS 6
  73. FlashItem items[NUM_FLASH_ITEMS] = {
  74. {SelectedFlashBoot,
  75. "bootloader",
  76. app->bin_file_path_boot,
  77. app->selected_flash_options[SelectedFlashS3Mode] ? ESP_ADDR_BOOT_S3 : ESP_ADDR_BOOT},
  78. {SelectedFlashPart, "partition table", app->bin_file_path_part, ESP_ADDR_PART},
  79. {SelectedFlashNvs, "NVS", app->bin_file_path_nvs, ESP_ADDR_NVS},
  80. {SelectedFlashBootApp0, "boot_app0", app->bin_file_path_boot_app0, ESP_ADDR_BOOT_APP0},
  81. {SelectedFlashApp, "firmware", app->bin_file_path_app, ESP_ADDR_APP},
  82. {SelectedFlashCustom, "custom data", app->bin_file_path_custom, 0x0},
  83. /* if you add more entries, update NUM_FLASH_ITEMS above! */
  84. };
  85. char user_msg[256];
  86. int current_step = 1;
  87. for(FlashItem* item = &items[0]; item < &items[NUM_FLASH_ITEMS]; ++item) {
  88. if(app->selected_flash_options[item->selected]) {
  89. snprintf(
  90. user_msg,
  91. sizeof(user_msg),
  92. "Flashing %s (%d/%d) to address 0x%lx\n",
  93. item->description,
  94. current_step++,
  95. num_steps,
  96. item->addr);
  97. loader_port_debug_print(user_msg);
  98. err = _flash_file(app, item->path, item->addr);
  99. if(err) {
  100. break;
  101. }
  102. }
  103. }
  104. }
  105. static int32_t esp_flasher_flash_bin(void* context) {
  106. EspFlasherApp* app = (void*)context;
  107. esp_loader_error_t err;
  108. app->flash_worker_busy = true;
  109. // alloc global objects
  110. flash_rx_stream = furi_stream_buffer_alloc(RX_BUF_SIZE, 1);
  111. timer = furi_timer_alloc(_timer_callback, FuriTimerTypePeriodic, app);
  112. // turn on flipper blue LED for duration of flash
  113. notification_message(app->notification, &sequence_set_only_blue_255);
  114. loader_port_debug_print("Connecting\n");
  115. esp_loader_connect_args_t connect_config = ESP_LOADER_CONNECT_DEFAULT();
  116. err = esp_loader_connect(&connect_config);
  117. if(err != ESP_LOADER_SUCCESS) {
  118. char err_msg[256];
  119. snprintf(
  120. err_msg,
  121. sizeof(err_msg),
  122. "Cannot connect to target. Error: %u\nMake sure the device is in bootloader/reflash mode, then try again.\n",
  123. err);
  124. loader_port_debug_print(err_msg);
  125. }
  126. #if 0 // still getting packet drops with this
  127. // higher BR
  128. if(!err) {
  129. loader_port_debug_print("Increasing speed for faster flash\n");
  130. err = esp_loader_change_transmission_rate(230400);
  131. if (err != ESP_LOADER_SUCCESS) {
  132. char err_msg[256];
  133. snprintf(
  134. err_msg,
  135. sizeof(err_msg),
  136. "Cannot change transmission rate. Error: %u\n",
  137. err);
  138. loader_port_debug_print(err_msg);
  139. }
  140. furi_hal_uart_set_br(FuriHalUartIdUSART1, 230400);
  141. }
  142. #endif
  143. if(!err) {
  144. loader_port_debug_print("Connected\n");
  145. _flash_all_files(app);
  146. #if 0
  147. loader_port_debug_print("Restoring transmission rate\n");
  148. furi_hal_uart_set_br(FuriHalUartIdUSART1, 115200);
  149. #endif
  150. loader_port_debug_print("Done flashing. Please reset the board manually if it doesn't auto-reset.\n");
  151. // auto-reset for supported boards
  152. loader_port_reset_target();
  153. // short buzz to alert user
  154. notification_message(app->notification, &sequence_set_vibro_on);
  155. loader_port_delay_ms(50);
  156. notification_message(app->notification, &sequence_reset_vibro);
  157. }
  158. // turn off flipper blue LED
  159. notification_message(app->notification, &sequence_reset_blue);
  160. // done
  161. app->flash_worker_busy = false;
  162. // cleanup
  163. furi_stream_buffer_free(flash_rx_stream);
  164. flash_rx_stream = NULL;
  165. furi_timer_free(timer);
  166. return 0;
  167. }
  168. static void _initDTR(void) {
  169. furi_hal_gpio_init(&gpio_ext_pc3, GpioModeOutputPushPull, GpioPullDown, GpioSpeedVeryHigh);
  170. }
  171. static void _initRTS(void) {
  172. furi_hal_gpio_init(&gpio_ext_pb2, GpioModeOutputPushPull, GpioPullDown, GpioSpeedVeryHigh);
  173. }
  174. static void _setDTR(bool state) {
  175. furi_hal_gpio_write(&gpio_ext_pc3, state);
  176. }
  177. static void _setRTS(bool state) {
  178. furi_hal_gpio_write(&gpio_ext_pb2, state);
  179. }
  180. static int32_t esp_flasher_reset(void* context) {
  181. EspFlasherApp* app = (void*)context;
  182. app->flash_worker_busy = true;
  183. _setDTR(false);
  184. _initDTR();
  185. _setRTS(false);
  186. _initRTS();
  187. if (app->reset) {
  188. loader_port_debug_print("Resetting board\n");
  189. loader_port_reset_target();
  190. } else if (app->boot) {
  191. loader_port_debug_print("Entering bootloader\n");
  192. loader_port_enter_bootloader();
  193. }
  194. // done
  195. app->flash_worker_busy = false;
  196. app->reset = false;
  197. app->boot = false;
  198. return 0;
  199. }
  200. void esp_flasher_worker_start_thread(EspFlasherApp* app) {
  201. global_app = app;
  202. app->flash_worker = furi_thread_alloc();
  203. furi_thread_set_name(app->flash_worker, "EspFlasherFlashWorker");
  204. furi_thread_set_stack_size(app->flash_worker, 2048);
  205. furi_thread_set_context(app->flash_worker, app);
  206. if (app->reset || app->boot) {
  207. furi_thread_set_callback(app->flash_worker, esp_flasher_reset);
  208. } else {
  209. furi_thread_set_callback(app->flash_worker, esp_flasher_flash_bin);
  210. }
  211. furi_thread_start(app->flash_worker);
  212. }
  213. void esp_flasher_worker_stop_thread(EspFlasherApp* app) {
  214. furi_thread_join(app->flash_worker);
  215. furi_thread_free(app->flash_worker);
  216. }
  217. esp_loader_error_t loader_port_read(uint8_t* data, uint16_t size, uint32_t timeout) {
  218. size_t read = furi_stream_buffer_receive(flash_rx_stream, data, size, pdMS_TO_TICKS(timeout));
  219. if(read < size) {
  220. return ESP_LOADER_ERROR_TIMEOUT;
  221. } else {
  222. return ESP_LOADER_SUCCESS;
  223. }
  224. }
  225. esp_loader_error_t loader_port_write(const uint8_t* data, uint16_t size, uint32_t timeout) {
  226. UNUSED(timeout);
  227. esp_flasher_uart_tx((uint8_t*)data, size);
  228. return ESP_LOADER_SUCCESS;
  229. }
  230. void loader_port_reset_target(void) {
  231. _setDTR(true);
  232. loader_port_delay_ms(SERIAL_FLASHER_RESET_HOLD_TIME_MS);
  233. _setDTR(false);
  234. }
  235. void loader_port_enter_bootloader(void) {
  236. _setDTR(true);
  237. loader_port_delay_ms(SERIAL_FLASHER_RESET_HOLD_TIME_MS);
  238. _setRTS(true);
  239. _setDTR(false);
  240. loader_port_delay_ms(SERIAL_FLASHER_BOOT_HOLD_TIME_MS);
  241. _setRTS(false);
  242. }
  243. void loader_port_delay_ms(uint32_t ms) {
  244. furi_delay_ms(ms);
  245. }
  246. void loader_port_start_timer(uint32_t ms) {
  247. _remaining_time = ms;
  248. furi_timer_start(timer, pdMS_TO_TICKS(1));
  249. }
  250. uint32_t loader_port_remaining_time(void) {
  251. return _remaining_time;
  252. }
  253. extern void esp_flasher_console_output_handle_rx_data_cb(
  254. uint8_t* buf,
  255. size_t len,
  256. void* context); // TODO cleanup
  257. void loader_port_debug_print(const char* str) {
  258. if(global_app)
  259. esp_flasher_console_output_handle_rx_data_cb((uint8_t*)str, strlen(str), global_app);
  260. }
  261. void loader_port_spi_set_cs(uint32_t level) {
  262. UNUSED(level);
  263. // unimplemented
  264. }
  265. void esp_flasher_worker_handle_rx_data_cb(uint8_t* buf, size_t len, void* context) {
  266. UNUSED(context);
  267. if(flash_rx_stream) {
  268. furi_stream_buffer_send(flash_rx_stream, buf, len, 0);
  269. } else {
  270. // done flashing
  271. if(global_app) esp_flasher_console_output_handle_rx_data_cb(buf, len, global_app);
  272. }
  273. }