| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- #include "flasher.h"
- #include <furi.h>
- #include <storage/storage.h>
- #include "uf2.h"
- #include "swd.h"
- #include "board.h"
- #include "target.h"
- #include "rp2040.h"
- #define TAG "VgmFlasher"
- #define W25Q128_CAPACITY (0x1000000UL)
- #define W25Q128_PAGE_SIZE (0x100UL)
- #define W25Q128_SECTOR_SIZE (0x1000UL)
- #define PROGRESS_VERIFY_WEIGHT (4U)
- #define PROGRESS_ERASE_WEIGHT (6U)
- #define PROGRESS_PROGRAM_WEIGHT (90U)
- #define FLASHER_ATTEMPT_COUNT (10UL)
- typedef struct {
- FlasherCallback callback;
- void* context;
- } Flasher;
- static Flasher flasher;
- bool flasher_init(void) {
- FURI_LOG_D(TAG, "Attaching the target");
- board_init();
- swd_init();
- if(!target_attach(RP2040_CORE0_ADDR)) {
- FURI_LOG_E(TAG, "Failed to attach target");
- flasher_deinit();
- return false;
- }
- return true;
- }
- void flasher_deinit(void) {
- FURI_LOG_D(TAG, "Detaching target and restoring pins");
- target_detach();
- swd_deinit();
- board_reset();
- board_deinit();
- }
- void flasher_set_callback(FlasherCallback callback, void* context) {
- flasher.callback = callback;
- flasher.context = context;
- }
- static inline bool flasher_init_chip(void) {
- return rp2040_init();
- }
- static inline bool flasher_erase_sector(uint32_t address) {
- return rp2040_flash_erase_sector(address);
- }
- static inline bool flasher_program_page(uint32_t address, const void* data, size_t data_size) {
- return rp2040_flash_program_page(address, data, data_size);
- }
- static void flasher_emit_progress(uint8_t start, uint8_t weight, uint8_t progress) {
- furi_assert(flasher.callback);
- FlasherEvent event = {
- .type = FlasherEventTypeProgress,
- .progress = start + ((uint32_t)weight * progress) / 100U,
- };
- flasher.callback(event, flasher.context);
- }
- static void flasher_emit_error(FlasherError error) {
- furi_assert(flasher.callback);
- FlasherEvent event = {
- .type = FlasherEventTypeError,
- .error = error,
- };
- flasher.callback(event, flasher.context);
- }
- static void flasher_emit_success(void) {
- furi_assert(flasher.callback);
- FlasherEvent event = {
- .type = FlasherEventTypeSuccess,
- };
- flasher.callback(event, flasher.context);
- }
- static bool flasher_prepare_target(void) {
- bool success = false;
- for(uint32_t i = 0; i < FLASHER_ATTEMPT_COUNT; ++i) {
- if(flasher_init()) {
- success = true;
- break;
- }
- furi_delay_ms(10);
- }
- if(!success) {
- flasher_emit_error(FlasherErrorDisconnect);
- }
- return success;
- }
- static bool flasher_prepare_file(File* file, const char* file_path) {
- bool success = false;
- do {
- if(!flasher_init_chip()) {
- FURI_LOG_E(TAG, "Failed to initialise chip");
- flasher_emit_error(FlasherErrorDisconnect);
- break;
- }
- if(!storage_file_open(file, file_path, FSAM_READ, FSOM_OPEN_EXISTING)) {
- FURI_LOG_E(TAG, "Failed to open firmware file: %s", file_path);
- flasher_emit_error(FlasherErrorBadFile);
- break;
- }
- success = true;
- } while(false);
- return success;
- }
- static bool flasher_verify_file(File* file, size_t* data_size) {
- bool success = false;
- do {
- uint32_t block_count;
- if(!uf2_get_block_count(file, &block_count)) {
- FURI_LOG_E(TAG, "Failed to get block count");
- flasher_emit_error(FlasherErrorBadFile);
- break;
- }
- uint32_t blocks_verified;
- uint8_t prev_progress = UINT8_MAX;
- for(blocks_verified = 0; blocks_verified < block_count; ++blocks_verified) {
- if(!uf2_verify_block(file, RP2040_FAMILY_ID, W25Q128_PAGE_SIZE)) break;
- const uint8_t verify_progress = (blocks_verified * 100UL) / block_count;
- if(verify_progress != prev_progress) {
- prev_progress = verify_progress;
- flasher_emit_progress(0, PROGRESS_VERIFY_WEIGHT, verify_progress);
- FURI_LOG_D(TAG, "Verifying file: %u%%", verify_progress);
- }
- }
- if(blocks_verified < block_count) {
- FURI_LOG_E(TAG, "Failed to verify all blocks");
- flasher_emit_error(FlasherErrorBadFile);
- break;
- }
- const size_t size_total = block_count * W25Q128_PAGE_SIZE;
- if(size_total > W25Q128_CAPACITY) {
- FURI_LOG_E(TAG, "File is too large to fit on the flash");
- flasher_emit_error(FlasherErrorBadFile);
- break;
- }
- if(!storage_file_seek(file, 0, true)) {
- FURI_LOG_E(TAG, "Failed to rewind the file");
- flasher_emit_error(FlasherErrorBadFile);
- break;
- }
- *data_size = size_total;
- success = true;
- } while(false);
- return success;
- }
- static bool flasher_erase_flash(size_t erase_size) {
- uint8_t prev_progress = UINT8_MAX;
- size_t size_erased;
- for(size_erased = 0; size_erased < erase_size;) {
- if(!flasher_erase_sector(size_erased)) {
- FURI_LOG_E(TAG, "Failed to erase flash sector at address 0x%zX", size_erased);
- flasher_emit_error(FlasherErrorDisconnect);
- break;
- }
- size_erased += MIN(erase_size - size_erased, W25Q128_SECTOR_SIZE);
- const uint8_t erase_progress = (size_erased * 100UL) / erase_size;
- if(erase_progress != prev_progress) {
- prev_progress = erase_progress;
- flasher_emit_progress(PROGRESS_VERIFY_WEIGHT, PROGRESS_ERASE_WEIGHT, erase_progress);
- FURI_LOG_D(TAG, "Erasing flash: %u%%", erase_progress);
- }
- }
- return size_erased == erase_size;
- }
- static bool flasher_program_flash(File* file, size_t data_size) {
- uint8_t prev_progress = UINT8_MAX;
- size_t size_programmed;
- for(size_programmed = 0; size_programmed < data_size;) {
- uint8_t buf[W25Q128_PAGE_SIZE];
- if(!uf2_read_block(file, buf, W25Q128_PAGE_SIZE)) {
- FURI_LOG_E(TAG, "Failed to read UF2 block");
- flasher_emit_error(FlasherErrorBadFile);
- break;
- }
- if(!flasher_program_page(size_programmed, buf, W25Q128_PAGE_SIZE)) {
- FURI_LOG_E(TAG, "Failed to program flash page at address 0x%zX", size_programmed);
- flasher_emit_error(FlasherErrorDisconnect);
- break;
- }
- size_programmed += W25Q128_PAGE_SIZE;
- const uint8_t program_progress = (size_programmed * 100UL) / data_size;
- if(program_progress != prev_progress) {
- prev_progress = program_progress;
- flasher_emit_progress(
- PROGRESS_VERIFY_WEIGHT + PROGRESS_ERASE_WEIGHT,
- PROGRESS_PROGRAM_WEIGHT,
- program_progress);
- FURI_LOG_D(TAG, "Programming flash: %u%%", program_progress);
- }
- }
- return size_programmed == data_size;
- }
- void flasher_start(const char* file_path) {
- FURI_LOG_D(TAG, "Flashing firmware from file: %s", file_path);
- Storage* storage = furi_record_open(RECORD_STORAGE);
- File* file = storage_file_alloc(storage);
- size_t data_size;
- do {
- if(!flasher_prepare_target()) break;
- if(!flasher_prepare_file(file, file_path)) break;
- if(!flasher_verify_file(file, &data_size)) break;
- if(!flasher_erase_flash(data_size)) break;
- if(!flasher_program_flash(file, data_size)) break;
- flasher_emit_success();
- } while(false);
- storage_file_free(file);
- furi_record_close(RECORD_STORAGE);
- }
|