// Update the tranfer state with new information static void transfer_stream_data(uint32_t sector, const uint8_t *data, uint32_t size) { error_t status; vfs_mngr_printf("vfs_manager transfer_stream_data(sector=%i, size=%i)\r\n", sector, size); vfs_mngr_printf(" size processed=0x%x, data=%x,%x,%x,%x,...\r\n", file_transfer_state.size_processed, data[0], data[1], data[2], data[3]); if (file_transfer_state.stream_finished) { util_assert(0); return; } util_assert(size % VFS_SECTOR_SIZE == 0); util_assert(file_transfer_state.stream_open); status = stream_write((uint8_t *)data, size); vfs_mngr_printf(" stream_write ret=%i\r\n", status); if (ERROR_SUCCESS_DONE == status) { // Override status so ERROR_SUCCESS_DONE // does not get passed into transfer_update_state status = stream_close(); vfs_mngr_printf(" stream_close ret=%i\r\n", status); file_transfer_state.stream_open = false; file_transfer_state.stream_finished = true; file_transfer_state.stream_optional_finish = true; } else if (ERROR_SUCCESS_DONE_OR_CONTINUE == status) { status = ERROR_SUCCESS; file_transfer_state.stream_optional_finish = true; } else { file_transfer_state.stream_optional_finish = false; } file_transfer_state.size_processed += size; transfer_update_state(status); }
error_t stream_write(const uint8_t *data, uint32_t size) { error_t status; // Stream must be open already if (state != STREAM_STATE_OPEN) { util_assert(0); return ERROR_INTERNAL; } // Check thread after checking state since the stream thread is // set only if stream_open has been called stream_thread_assert(); // Write to stream status = current_stream->write(&shared_state, data, size); if (ERROR_SUCCESS_DONE == status) { state = STREAM_STATE_END; } else if ((ERROR_SUCCESS_DONE_OR_CONTINUE == status) || (ERROR_SUCCESS == status)) { // Stream should remain in the open state util_assert(STREAM_STATE_OPEN == state); } else { state = STREAM_STATE_ERROR; } return status; }
error_t stream_open(stream_type_t stream_type) { error_t status; // Stream must not be open already if (state != STREAM_STATE_CLOSED) { util_assert(0); return ERROR_INTERNAL; } // Stream must be of a supported type if (stream_type >= STREAM_TYPE_COUNT) { util_assert(0); return ERROR_INTERNAL; } stream_thread_set(); // Initialize all variables memset(&shared_state, 0, sizeof(shared_state)); state = STREAM_STATE_OPEN; current_stream = &stream[stream_type]; // Initialize the specified stream status = current_stream->open(&shared_state); if (ERROR_SUCCESS != status) { state = STREAM_STATE_ERROR; } return status; }
// Update the tranfer state with new information static void transfer_stream_open(stream_type_t stream, uint32_t start_sector) { error_t status; util_assert(!file_transfer_state.stream_open); util_assert(start_sector != VFS_INVALID_SECTOR); vfs_mngr_printf("vfs_manager transfer_update_stream_open(stream=%i, start_sector=%i)\r\n", stream, start_sector); // Initialize the starting sector if it has not been set if (VFS_INVALID_SECTOR == file_transfer_state.start_sector) { file_transfer_state.start_sector = start_sector; if (start_sector != VFS_INVALID_SECTOR) { vfs_mngr_printf(" start_sector=%i\r\n", start_sector); } } // Initialize the stream if it has not been set if (STREAM_TYPE_NONE == file_transfer_state.stream) { file_transfer_state.stream = stream; if (stream != STREAM_TYPE_NONE) { vfs_mngr_printf(" stream=%i\r\n", stream); } } // Check - Starting sector must be the same if (start_sector != file_transfer_state.start_sector) { vfs_mngr_printf(" error: starting sector changed from %i to %i\r\n", file_transfer_state.start_sector, start_sector); transfer_update_state(ERROR_ERROR_DURING_TRANSFER); return; } // Check - stream must be the same if (stream != file_transfer_state.stream) { vfs_mngr_printf(" error: changed types during tranfer from %i to %i\r\n", stream, file_transfer_state.stream); transfer_update_state(ERROR_ERROR_DURING_TRANSFER); return; } // Open stream status = stream_open(stream); vfs_mngr_printf(" stream_open stream=%i ret %i\r\n", stream, status); if (ERROR_SUCCESS == status) { file_transfer_state.file_next_sector = start_sector; file_transfer_state.stream_open = true; file_transfer_state.stream_started = true; } transfer_update_state(status); }
// Update the tranfer state with new information static void transfer_update_stream_data(uint32_t current_sector, uint32_t size, error_t status) { util_assert(file_transfer_state.stream_open); util_assert(size % VFS_SECTOR_SIZE == 0); util_assert(file_transfer_state.file_next_sector == current_sector); file_transfer_state.size_processed += size; file_transfer_state.file_next_sector = current_sector + size / VFS_SECTOR_SIZE; // Update status file_transfer_state.status = status; transfer_check_for_completion(); }
error_t flash_manager_init(const flash_intf_t *flash_intf) { error_t status; // Assert that interface has been properly uninitialized flash_manager_printf("flash_manager_init()\r\n"); if (state != STATE_CLOSED) { util_assert(0); return ERROR_INTERNAL; } // Check for a valid flash interface if (!flash_intf_valid(flash_intf)) { util_assert(0); return ERROR_INTERNAL; } // Initialize variables memset(buf, 0xFF, sizeof(buf)); buf_empty = true; current_sector_valid = false; current_write_block_addr = 0; current_write_block_size = 0; current_sector_addr = 0; current_sector_size = 0; last_addr = 0; intf = flash_intf; // Initialize flash status = intf->init(); flash_manager_printf(" intf->init ret=%i\r\n", status); if (ERROR_SUCCESS != status) { return status; } if (!page_erase_enabled) { // Erase flash and unint if there are errors status = intf->erase_chip(); flash_manager_printf(" intf->erase_chip ret=%i\r\n", status); if (ERROR_SUCCESS != status) { intf->uninit(); return status; } } state = STATE_OPEN; return status; }
flash_decoder_type_t flash_decoder_detect_type(const uint8_t *data, uint32_t size, uint32_t addr, bool addr_valid) { daplink_info_t info; util_assert(size >= FLASH_DECODER_MIN_SIZE); // Check if this is a daplink image memcpy(&info, data + DAPLINK_INFO_OFFSET, sizeof(info)); if (DAPLINK_HIC_ID == info.hic_id) { if (DAPLINK_BUILD_KEY_IF == info.build_key) { // Interface update return FLASH_DECODER_TYPE_INTERFACE; } else if (DAPLINK_BUILD_KEY_BL == info.build_key) { // Bootloader update return FLASH_DECODER_TYPE_BOOTLOADER; } else { return FLASH_DECODER_TYPE_UNKNOWN; } } // Check if a valid vector table for the target can be found if (validate_bin_nvic(data)) { return FLASH_DECODER_TYPE_TARGET; } // If an address is specified then the data can be decoded if (addr_valid) { // TODO - future improvement - make sure address is within target's flash return FLASH_DECODER_TYPE_TARGET; } return FLASH_DECODER_TYPE_UNKNOWN; }
__declspec(naked) code *code_calloc() { if (sizeof(code) != 0x24) util_assert("code",__LINE__); __asm { mov EAX,code_list test EAX,EAX je L20 mov ECX,[EAX] mov code_list,ECX jmp L29 L20: push sizeof(code) call mem_fmalloc ;add ESP,4 L29: xor ECX,ECX mov DWORD PTR [EAX],0 mov 4[EAX],ECX ;these pair mov 8[EAX],ECX mov 12[EAX],ECX mov 16[EAX],ECX mov 20[EAX],ECX mov 24[EAX],ECX mov 28[EAX],ECX mov 32[EAX],ECX ret } }
error_t flash_decoder_close(void) { error_t status = ERROR_SUCCESS; decoder_state_t prev_state = state; flash_decoder_printf("flash_decoder_close()\r\n"); if (DECODER_STATE_CLOSED == state) { util_assert(0); return ERROR_INTERNAL; } state = DECODER_STATE_CLOSED; if (flash_initialized) { status = flash_manager_uninit(); flash_decoder_printf(" flash_manager_uninit ret %i\r\n", status); } if ((DECODER_STATE_DONE != prev_state) && (flash_type != FLASH_DECODER_TYPE_TARGET) && (status == ERROR_SUCCESS)) { status = ERROR_IAP_UPDT_INCOMPLETE; } return status; }
static bool ready_for_state_change(void) { uint32_t timeout_ms = INVALID_TIMEOUT_MS; util_assert(vfs_state != vfs_state_next); if (VFS_MNGR_STATE_CONNECTED == vfs_state) { switch (file_transfer_state.transfer_state) { case TRANSFER_NOT_STARTED: case TRASNFER_FINISHED: timeout_ms = DISCONNECT_DELAY_MS; break; case TRANSFER_IN_PROGRESS: timeout_ms = DISCONNECT_DELAY_TRANSFER_TIMEOUT_MS; break; case TRANSFER_CAN_BE_FINISHED: timeout_ms = DISCONNECT_DELAY_TRANSFER_IDLE_MS; break; default: util_assert(0); timeout_ms = DISCONNECT_DELAY_MS; break; } } else if ((VFS_MNGR_STATE_DISCONNECTED == vfs_state) && (VFS_MNGR_STATE_CONNECTED == vfs_state_next)) { timeout_ms = CONNECT_DELAY_MS; } else if ((VFS_MNGR_STATE_RECONNECTING == vfs_state) && (VFS_MNGR_STATE_CONNECTED == vfs_state_next)) { timeout_ms = RECONNECT_DELAY_MS; } else if ((VFS_MNGR_STATE_RECONNECTING == vfs_state) && (VFS_MNGR_STATE_DISCONNECTED == vfs_state_next)) { timeout_ms = 0; } if (INVALID_TIMEOUT_MS == timeout_ms) { util_assert(0); timeout_ms = 0; } return time_usb_idle > timeout_ms ? true : false; }
static error_t setup_next_sector(uint32_t addr) { uint32_t min_prog_size; uint32_t sector_size; error_t status; min_prog_size = intf->program_page_min_size(addr); sector_size = intf->erase_sector_size(addr); if ((min_prog_size <= 0) || (sector_size <= 0)) { // Either of these conditions could cause divide by 0 error util_assert(0); return ERROR_INTERNAL; } // Assert required size and alignment util_assert(sizeof(buf) >= min_prog_size); util_assert(sizeof(buf) % min_prog_size == 0); util_assert(sector_size >= min_prog_size); util_assert(sector_size % min_prog_size == 0); // Setup global variables current_sector_addr = ROUND_DOWN(addr, sector_size); current_sector_size = sector_size; current_write_block_addr = current_sector_addr; current_write_block_size = MIN(sector_size, sizeof(buf)); if(page_erase_enabled) { // Erase the current sector status = intf->erase_sector(current_sector_addr); flash_manager_printf(" intf->erase_sector(addr=0x%x) ret=%i\r\n", current_sector_addr); if (ERROR_SUCCESS != status) { intf->uninit(); return status; } } // Clear out buffer in case block size changed memset(buf, 0xFF, current_write_block_size); flash_manager_printf(" setup_next_sector(addr=0x%x) sect_addr=0x%x, write_addr=0x%x,\r\n", addr, current_sector_addr, current_write_block_addr); flash_manager_printf(" actual_write_size=0x%x, sector_size=0x%x, min_write=0x%x\r\n", current_write_block_size, current_sector_size, min_prog_size); return ERROR_SUCCESS; }
static error_t write_hex(void *state, const uint8_t *data, uint32_t size) { error_t status = ERROR_SUCCESS; hex_state_t *hex_state = (hex_state_t *)state; hexfile_parse_status_t parse_status = HEX_PARSE_UNINIT; uint32_t bin_start_address = 0; // Decoded from the hex file, the binary buffer data starts at this address uint32_t bin_buf_written = 0; // The amount of data in the binary buffer starting at address above uint32_t block_amt_parsed = 0; // amount of data parsed in the block on the last call while (1) { // try to decode a block of hex data into bin data parse_status = parse_hex_blob(data, size, &block_amt_parsed, hex_state->bin_buffer, sizeof(hex_state->bin_buffer), &bin_start_address, &bin_buf_written); // the entire block of hex was decoded. This is a simple state if (HEX_PARSE_OK == parse_status) { if (bin_buf_written > 0) { status = flash_decoder_write(bin_start_address, hex_state->bin_buffer, bin_buf_written); } break; } else if (HEX_PARSE_UNALIGNED == parse_status) { if (bin_buf_written > 0) { status = flash_decoder_write(bin_start_address, hex_state->bin_buffer, bin_buf_written); if (ERROR_SUCCESS != status) { break; } } // incrememntal offset to finish the block size -= block_amt_parsed; data += block_amt_parsed; } else if (HEX_PARSE_EOF == parse_status) { if (bin_buf_written > 0) { status = flash_decoder_write(bin_start_address, hex_state->bin_buffer, bin_buf_written); } if (ERROR_SUCCESS == status) { status = ERROR_SUCCESS_DONE; } break; } else if (HEX_PARSE_CKSUM_FAIL == parse_status) { status = ERROR_HEX_CKSUM; break; } else if ((HEX_PARSE_UNINIT == parse_status) || (HEX_PARSE_FAILURE == parse_status)) { util_assert(HEX_PARSE_UNINIT != parse_status); status = ERROR_HEX_PARSER; break; } } return status; }
// Update the tranfer state with new information static void transfer_update_stream_open(stream_type_t stream, uint32_t start_sector, error_t status) { util_assert(!file_transfer_state.stream_open); vfs_user_printf("virtual_fs_user transfer_update_stream_open(stream=%i, start_sector=%i, status=%i)\r\n", stream, start_sector, status); // Status should still be at it's default of ERROR_SUCCESS util_assert(ERROR_SUCCESS == file_transfer_state.status); // Initialize the starting sector if it has not been set if (VFS_INVALID_SECTOR == file_transfer_state.start_sector) { file_transfer_state.start_sector = start_sector; } // Initialize the stream if it has not been set if (STREAM_TYPE_NONE == file_transfer_state.stream) { file_transfer_state.stream = stream; } // Check - Starting sector must be the same if (start_sector != file_transfer_state.start_sector) { vfs_user_printf(" error: starting sector changed from %i to %i\r\n", file_transfer_state.start_sector, start_sector); file_transfer_state.status = ERROR_ERROR_DURING_TRANSFER; } // Check - stream must be the same if (stream != file_transfer_state.stream) { vfs_user_printf(" error: changed types during tranfer from %i to %i\r\n", stream, file_transfer_state.stream); file_transfer_state.status = ERROR_ERROR_DURING_TRANSFER; } // Check - were there any errors with the open if (ERROR_SUCCESS == file_transfer_state.status) { file_transfer_state.status = status; } if (ERROR_SUCCESS == status) { file_transfer_state.file_next_sector = start_sector; file_transfer_state.stream_open = true; } transfer_check_for_completion(); }
// Callback to handle changes to the root directory. Should be used with vfs_set_file_change_callback static void file_change_handler(const vfs_filename_t filename, vfs_file_change_t change, vfs_file_t file, vfs_file_t new_file_data) { vfs_user_printf("virtual_fs_user file_change_handler(name=%*s, change=%i)\r\n", 11, filename, change); if (VFS_FILE_CHANGED == change) { if (file == file_transfer_state.file_to_program) { stream_type_t stream; uint32_t size = vfs_file_get_size(new_file_data); vfs_sector_t sector = vfs_file_get_start_sector(new_file_data); vfs_user_printf(" file properties changed, size=%i\r\n", 11, size); stream = stream_type_from_name(filename); transfer_update_file_info(file, sector, size, stream); } } if (VFS_FILE_CREATED == change) { stream_type_t stream; if (!memcmp(filename, daplink_mode_file_name, sizeof(vfs_filename_t))) { if (daplink_is_interface()) { config_ram_set_hold_in_bl(true); } else { // Do nothing - bootloader will go to interface by default } vfs_user_remount(); } else if (!memcmp(filename, "AUTO_RSTCFG", sizeof(vfs_filename_t))) { config_set_auto_rst(true); vfs_user_remount(); } else if (!memcmp(filename, "HARD_RSTCFG", sizeof(vfs_filename_t))) { config_set_auto_rst(false); vfs_user_remount(); } else if (!memcmp(filename, "ASSERT ACT", sizeof(vfs_filename_t))) { // Test asserts util_assert(0); } else if (!memcmp(filename, "REFRESH ACT", sizeof(vfs_filename_t))) { // Remount to update the drive vfs_user_remount(); } else if (STREAM_TYPE_NONE != stream_type_from_name(filename)) { stream = stream_type_from_name(filename); uint32_t size = vfs_file_get_size(new_file_data); vfs_user_printf(" found file to decode, type=%i\r\n", stream); vfs_sector_t sector = vfs_file_get_start_sector(new_file_data); transfer_update_file_info(file, sector, size, stream); } } if (VFS_FILE_DELETED == change) { if (!memcmp(filename, assert_file, sizeof(vfs_filename_t))) { util_assert_clear(); } } }
error_t stream_close(void) { error_t status; // Stream must not be closed already if (STREAM_STATE_CLOSED == state) { util_assert(0); return ERROR_INTERNAL; } // Check thread after checking state since the stream thread is // set only if stream_open has been called stream_thread_assert(); // Close stream status = current_stream->close(&shared_state); state = STREAM_STATE_CLOSED; return status; }
error_t flash_manager_uninit(void) { error_t flash_uninit_error; error_t flash_write_error = ERROR_SUCCESS; flash_manager_printf("flash_manager_uninit()\r\n"); if (STATE_CLOSED == state) { util_assert(0); return ERROR_INTERNAL; } // Write out current page if ((STATE_OPEN == state) && (!buf_empty)) { flash_write_error = intf->program_page(current_write_block_addr, buf, current_write_block_size); flash_manager_printf(" intf->program_page(addr=0x%x, size=0x%x) ret=%i\r\n", current_write_block_addr, current_write_block_size, flash_write_error); } // Close flash interface (even if there was an error during program_page) flash_uninit_error = intf->uninit(); flash_manager_printf(" intf->uninit() ret=%i\r\n", flash_uninit_error); // Reset variables to catch accidental use memset(buf, 0xFF, sizeof(buf)); buf_empty = true; current_sector_valid = false; current_write_block_addr = 0; current_write_block_size = 0; current_sector_addr = 0; current_sector_size = 0; last_addr = 0; state = STATE_CLOSED; // Make sure an error from a page write or from an // uninit gets propagated if (flash_uninit_error != ERROR_SUCCESS) { return flash_uninit_error; } if (flash_write_error != ERROR_SUCCESS) { return flash_write_error; } return ERROR_SUCCESS; }
error_t flash_decoder_open(void) { flash_decoder_printf("flash_decoder_open()\r\n"); // Stream must not be open already if (state != DECODER_STATE_CLOSED) { util_assert(0); return ERROR_INTERNAL; } memset(flash_buf, 0xff, sizeof(flash_buf)); state = DECODER_STATE_OPEN; flash_type = FLASH_DECODER_TYPE_UNKNOWN; flash_buf_pos = 0; initial_addr = 0; current_addr = 0; flash_initialized = false; initial_addr_set = false; return ERROR_SUCCESS; }
// Check if the current transfer is still in progress, done, or if an error has occurred static void transfer_check_for_completion() { bool file_fully_processed; bool size_nonzero; util_assert(!file_transfer_state.transfer_finished); // Check for completion of transfer file_fully_processed = file_transfer_state.size_processed >= file_transfer_state.file_size; size_nonzero = file_transfer_state.file_size > 0; if ((ERROR_SUCCESS_DONE == file_transfer_state.status) && file_fully_processed && size_nonzero) { // Full filesize has been transfered and the end of the stream has been reached. // Mark the transfer as finished and set result to success. vfs_user_printf("virtual_fs_user transfer_check_for_completion transfer successful\r\n"); fail_reason = ERROR_SUCCESS; file_transfer_state.transfer_finished = true; } else if ((ERROR_SUCCESS_DONE_OR_CONTINUE == file_transfer_state.status) && file_fully_processed && size_nonzero) { // Full filesize has been transfered but the stream could not determine the end of the file. // Set the result to success but let the filetransfer time out. vfs_user_printf("virtual_fs_user transfer_check_for_completion transfer successful, checking for more data\r\n"); fail_reason = ERROR_SUCCESS; } else if ((ERROR_SUCCESS == file_transfer_state.status) || (ERROR_SUCCESS_DONE == file_transfer_state.status) || (ERROR_SUCCESS_DONE_OR_CONTINUE == file_transfer_state.status)) { fail_reason = ERROR_TRANSFER_IN_PROGRESS; // Transfer still in progress } else { // An error has occurred vfs_user_printf("virtual_fs_user transfer_check_for_completion error=%i,\r\n" " file_finished=%i, size_processed=%i file_size=%i\r\n", file_transfer_state.status, file_fully_processed, file_transfer_state.size_processed, file_transfer_state.file_size); fail_reason = file_transfer_state.status; file_transfer_state.transfer_finished = true; } // Always start remounting vfs_user_remount(); }
static void sync_assert_usb_thread(void) { util_assert(os_tsk_self() == sync_thread); }
error_t flash_decoder_get_flash(flash_decoder_type_t type, uint32_t addr, bool addr_valid, uint32_t *start_addr, const flash_intf_t **flash_intf) { error_t status = ERROR_SUCCESS; uint32_t flash_start_local; const flash_intf_t *flash_intf_local = 0; if ((0 == start_addr) || (0 == flash_intf)) { util_assert(0); return ERROR_INTERNAL; } *start_addr = 0; *flash_intf = 0; flash_start_local = 0; flash_intf_local = 0; if (daplink_is_bootloader()) { if (FLASH_DECODER_TYPE_INTERFACE == type) { if (addr_valid && (DAPLINK_ROM_IF_START != addr)) { // Address is wrong so display error message status = ERROR_FD_INTF_UPDT_ADDR_WRONG; flash_start_local = 0; flash_intf_local = 0; } else { // Setup for update flash_start_local = DAPLINK_ROM_IF_START; flash_intf_local = flash_intf_iap_protected; } } else if (FLASH_DECODER_TYPE_TARGET == type) { // "Target" update in this case would be a 3rd party interface application flash_start_local = DAPLINK_ROM_IF_START; flash_intf_local = flash_intf_iap_protected; } } else if (daplink_is_interface()) { if (FLASH_DECODER_TYPE_BOOTLOADER == type) { if (addr_valid && (DAPLINK_ROM_BL_START != addr)) { // Address is wrong so display error message status = ERROR_FD_BL_UPDT_ADDR_WRONG; flash_start_local = 0; flash_intf_local = 0; } else { // Setup for update flash_start_local = DAPLINK_ROM_BL_START; flash_intf_local = flash_intf_iap_protected; } } else if (FLASH_DECODER_TYPE_TARGET == type) { flash_start_local = target_device.flash_start; flash_intf_local = flash_intf_target; } } else { status = ERROR_FD_UNSUPPORTED_UPDATE; } // Don't allow bootloader updates unless automation is allowed if (!config_get_automation_allowed() && (FLASH_DECODER_TYPE_BOOTLOADER == type)) { status = ERROR_FD_UNSUPPORTED_UPDATE; } if (ERROR_SUCCESS != status) { return status; } if (0 == flash_intf_local) { util_assert(0); return ERROR_INTERNAL; } *start_addr = flash_start_local; *flash_intf = flash_intf_local; return status; }
static void stream_thread_assert(void) { util_assert(osThreadGetId() == stream_thread_tid); }
static uint32_t target_flash_program_page_min_size(uint32_t addr) { uint32_t size = 256; util_assert(target_device.sector_size >= size); return size; }
// Update the tranfer state with file information static void transfer_update_file_info(vfs_file_t file, uint32_t start_sector, uint32_t size, stream_type_t stream) { vfs_mngr_printf("vfs_manager transfer_update_file_info(file=%p, start_sector=%i, size=%i)\r\n", file, start_sector, size); if (TRASNFER_FINISHED == file_transfer_state.transfer_state) { util_assert(0); return; } // Initialize the directory entry if it has not been set if (VFS_FILE_INVALID == file_transfer_state.file_to_program) { file_transfer_state.file_to_program = file; if (file != VFS_FILE_INVALID) { vfs_mngr_printf(" file_to_program=%p\r\n", file); } } // Initialize the starting sector if it has not been set if (VFS_INVALID_SECTOR == file_transfer_state.start_sector) { file_transfer_state.start_sector = start_sector; if (start_sector != VFS_INVALID_SECTOR) { vfs_mngr_printf(" start_sector=%i\r\n", start_sector); } } // Initialize the stream if it has not been set if (STREAM_TYPE_NONE == file_transfer_state.stream) { file_transfer_state.stream = stream; if (stream != STREAM_TYPE_NONE) { vfs_mngr_printf(" stream=%i\r\n", stream); } } // Check - File size must be the same or bigger if (size < file_transfer_state.file_size) { vfs_mngr_printf(" error: file size changed from %i to %i\r\n", file_transfer_state.file_size, size); transfer_update_state(ERROR_ERROR_DURING_TRANSFER); return; } // Check - Starting sector must be the same - this is optional for file info since it may not be present initially if ((VFS_INVALID_SECTOR != start_sector) && (start_sector != file_transfer_state.start_sector)) { vfs_mngr_printf(" error: starting sector changed from %i to %i\r\n", file_transfer_state.start_sector, start_sector); transfer_update_state(ERROR_ERROR_DURING_TRANSFER); return; } // Check - stream must be the same if (stream != file_transfer_state.stream) { vfs_mngr_printf(" error: changed types during transfer from %i to %i\r\n", stream, file_transfer_state.stream); transfer_update_state(ERROR_ERROR_DURING_TRANSFER); return; } // Update values - Size is the only value that can change and it can only increase. if (size > file_transfer_state.file_size) { file_transfer_state.file_size = size; vfs_mngr_printf(" updated size=%i\r\n", size); } transfer_update_state(ERROR_SUCCESS); }
error_t flash_manager_data(uint32_t addr, const uint8_t *data, uint32_t size) { uint32_t size_left; uint32_t copy_size; uint32_t pos; error_t status = ERROR_SUCCESS; flash_manager_printf("flash_manager_data(addr=0x%x size=0x%x)\r\n", addr, size); if (state != STATE_OPEN) { util_assert(0); return ERROR_INTERNAL; } // Setup the current sector if it is not setup already if (!current_sector_valid) { status = setup_next_sector(addr); if (ERROR_SUCCESS != status) { state = STATE_ERROR; return status; } current_sector_valid = true; last_addr = addr; } //non-increasing address support if (ROUND_DOWN(addr, current_write_block_size) != ROUND_DOWN(last_addr, current_write_block_size)) { status = flush_current_block(addr); if (ERROR_SUCCESS != status) { state = STATE_ERROR; return status; } } if (ROUND_DOWN(addr, current_sector_size) != ROUND_DOWN(last_addr, current_sector_size)) { status = setup_next_sector(addr); if (ERROR_SUCCESS != status) { state = STATE_ERROR; return status; } } while (true) { // flush if necessary if (addr >= current_write_block_addr + current_write_block_size) { status = flush_current_block(addr); if (ERROR_SUCCESS != status) { state = STATE_ERROR; return status; } } // Check for end if (size <= 0) { break; } // Change sector if necessary if (addr >= current_sector_addr + current_sector_size) { status = setup_next_sector(addr); if (ERROR_SUCCESS != status) { state = STATE_ERROR; return status; } // check is at sector boundary if (addr != current_write_block_addr) { current_write_block_addr = addr & 0xFFFFFFF0; // 16 bytes alignment } } // write buffer pos = addr - current_write_block_addr; size_left = current_write_block_size - pos; copy_size = MIN(size, size_left); memcpy(buf + pos, data, copy_size); buf_empty = copy_size == 0; // Update variables addr += copy_size; data += copy_size; size -= copy_size; } last_addr = addr; return status; }
void vfs_mngr_periodic(uint32_t elapsed_ms) { bool change_state; vfs_mngr_state_t vfs_state_local; vfs_mngr_state_t vfs_state_local_prev; sync_assert_usb_thread(); sync_lock(); // Return immediately if the desired state has been reached if (!changing_state()) { sync_unlock(); return; } change_state = ready_for_state_change(); if (time_usb_idle < MAX_EVENT_TIME_MS) { time_usb_idle += elapsed_ms; } sync_unlock(); if (!change_state) { return; } vfs_mngr_printf("vfs_mngr_periodic()\r\n"); vfs_mngr_printf(" time_usb_idle=%i\r\n", time_usb_idle); vfs_mngr_printf(" transfer_state=%i\r\n", file_transfer_state.transfer_state); // Transistion to new state vfs_state_local_prev = vfs_state; vfs_state = vfs_state_next; switch (vfs_state) { case VFS_MNGR_STATE_RECONNECTING: // Transition back to the connected state vfs_state_next = VFS_MNGR_STATE_CONNECTED; break; default: // No state change logic required in other states break; } vfs_state_local = vfs_state; time_usb_idle = 0; sync_unlock(); // Processing when leaving a state vfs_mngr_printf(" state %i->%i\r\n", vfs_state_local_prev, vfs_state_local); switch (vfs_state_local_prev) { case VFS_MNGR_STATE_DISCONNECTED: // No action needed break; case VFS_MNGR_STATE_RECONNECTING: // No action needed break; case VFS_MNGR_STATE_CONNECTED: // Close ongoing transfer if there is one if (file_transfer_state.transfer_state != TRASNFER_FINISHED) { vfs_mngr_printf(" transfer timeout\r\n"); file_transfer_state.transfer_timeout = true; transfer_update_state(ERROR_SUCCESS); } util_assert(TRASNFER_FINISHED == file_transfer_state.transfer_state); vfs_user_disconnecting(); break; } // Processing when entering a state switch (vfs_state_local) { case VFS_MNGR_STATE_DISCONNECTED: USBD_MSC_MediaReady = 0; break; case VFS_MNGR_STATE_RECONNECTING: USBD_MSC_MediaReady = 0; break; case VFS_MNGR_STATE_CONNECTED: build_filesystem(); USBD_MSC_MediaReady = 1; break; } return; }
// Check if the current transfer is still in progress, done, or if an error has occurred static void transfer_update_state(error_t status) { bool transfer_timeout; bool transfer_started; bool transfer_can_be_finished; bool transfer_must_be_finished; bool out_of_order_sector; error_t local_status = status; util_assert((status != ERROR_SUCCESS_DONE) && (status != ERROR_SUCCESS_DONE_OR_CONTINUE)); if (TRASNFER_FINISHED == file_transfer_state.transfer_state) { util_assert(0); return; } // Update file info status. The end of a file is never known for sure since // what looks like a complete file could be part of a file getting flushed to disk. // The criteria for an successful optional finish is // 1. A file has been detected // 2. The size of the file indicated in the root dir has been transferred // 3. The file size is greater than zero file_transfer_state.file_info_optional_finish = (file_transfer_state.file_to_program != VFS_FILE_INVALID) && (file_transfer_state.size_transferred >= file_transfer_state.file_size) && (file_transfer_state.file_size > 0); transfer_timeout = file_transfer_state.transfer_timeout; transfer_started = (VFS_FILE_INVALID != file_transfer_state.file_to_program) || (STREAM_TYPE_NONE != file_transfer_state.stream); // The transfer can be finished if both file and stream processing // can be considered complete transfer_can_be_finished = file_transfer_state.file_info_optional_finish && file_transfer_state.stream_optional_finish; // The transfer must be fnished if stream processing is for sure complete // and file processing can be considered complete transfer_must_be_finished = file_transfer_state.stream_finished && file_transfer_state.file_info_optional_finish; out_of_order_sector = false; if (file_transfer_state.last_ooo_sector != VFS_INVALID_SECTOR) { util_assert(file_transfer_state.start_sector != VFS_INVALID_SECTOR); uint32_t sector_offset = (file_transfer_state.last_ooo_sector - file_transfer_state.start_sector) * VFS_SECTOR_SIZE; if (sector_offset < file_transfer_state.size_processed) { // The out of order sector was within the range of data already // processed. out_of_order_sector = true; } } // Set the transfer state and set the status if necessary if (local_status != ERROR_SUCCESS) { file_transfer_state.transfer_state = TRASNFER_FINISHED; } else if (transfer_timeout) { if (out_of_order_sector) { local_status = ERROR_OOO_SECTOR; } else if (!transfer_started) { local_status = ERROR_SUCCESS; } else if (transfer_can_be_finished) { local_status = ERROR_SUCCESS; } else { local_status = ERROR_TRANSFER_TIMEOUT; } file_transfer_state.transfer_state = TRASNFER_FINISHED; } else if (transfer_must_be_finished) { file_transfer_state.transfer_state = TRASNFER_FINISHED; } else if (transfer_can_be_finished) { file_transfer_state.transfer_state = TRANSFER_CAN_BE_FINISHED; } else if (transfer_started) { file_transfer_state.transfer_state = TRANSFER_IN_PROGRESS; } if (TRASNFER_FINISHED == file_transfer_state.transfer_state) { vfs_mngr_printf("vfs_manager transfer_update_state(status=%i)\r\n", status); vfs_mngr_printf(" file=%p, start_sect= %i, size=%i\r\n", file_transfer_state.file_to_program, file_transfer_state.start_sector, file_transfer_state.file_size); vfs_mngr_printf(" stream=%i, size_processed=%i, opt_finish=%i, timeout=%i\r\n", file_transfer_state.stream, file_transfer_state.size_processed, file_transfer_state.file_info_optional_finish, transfer_timeout); // Close the file stream if it is open if (file_transfer_state.stream_open) { error_t close_status; close_status = stream_close(); vfs_mngr_printf(" stream closed ret=%i\r\n", close_status); file_transfer_state.stream_open = false; if (ERROR_SUCCESS == local_status) { local_status = close_status; } } // Set the fail reason fail_reason = local_status; vfs_mngr_printf(" Transfer finished, status: %i=%s\r\n", fail_reason, error_get_string(fail_reason)); } // If this state change is not from aborting a transfer // due to a remount then trigger a remount if (!transfer_timeout) { vfs_mngr_fs_remount(); } }
error_t flash_manager_data(uint32_t addr, const uint8_t *data, uint32_t size) { uint32_t size_left; uint32_t copy_size; uint32_t pos; error_t status = ERROR_SUCCESS; flash_manager_printf("flash_manager_data(addr=0x%x size=0x%x)\r\n", addr, size); if (state != STATE_OPEN) { util_assert(0); return ERROR_INTERNAL; } // Enforce that addresses are sequential. Currently flash manager // only supports sequential addresses. In the future flash manager // could be updated to support this. if (addr < last_addr) { util_assert(0); state = STATE_ERROR; return ERROR_INTERNAL; } // Setup the current sector if it is not setup already if (!current_sector_valid) { status = setup_next_sector(addr); if (ERROR_SUCCESS != status) { state = STATE_ERROR; return status; } current_sector_valid = true; } while (true) { // flush if necessary if (addr >= current_write_block_addr + current_write_block_size) { // Write out current buffer status = intf->program_page(current_write_block_addr, buf, current_write_block_size); flash_manager_printf(" intf->program_page(addr=0x%x, size=0x%x) ret=%i\r\n", current_write_block_addr, current_write_block_size, status); if (ERROR_SUCCESS != status) { state = STATE_ERROR; return status; } // Setup for next page memset(buf, 0xFF, current_write_block_size); buf_empty = true; current_write_block_addr += current_write_block_size; } // Check for end if (size <= 0) { break; } // Change sector if necessary if (addr >= current_sector_addr + current_sector_size) { status = setup_next_sector(addr); if (ERROR_SUCCESS != status) { state = STATE_ERROR; return status; } } // write buffer pos = addr - current_write_block_addr; size_left = current_write_block_size - pos; copy_size = MIN(size, size_left); memcpy(buf + pos, data, copy_size); buf_empty = copy_size == 0; // Update variables addr += copy_size; data += copy_size; size -= copy_size; } last_addr = addr; return status; }
void HardFault_Handler() { util_assert(0); NVIC_SystemReset(); while (1); // Wait for reset }
error_t flash_decoder_write(uint32_t addr, const uint8_t *data, uint32_t size) { error_t status; flash_decoder_printf("flash_decoder_write(addr=0x%x, size=0x%x)\r\n", addr, size); if (DECODER_STATE_OPEN != state) { util_assert(0); return ERROR_INTERNAL; } // Set the initial address the first time through if (!initial_addr_set) { initial_addr = addr; current_addr = initial_addr; flash_decoder_printf(" initial_addr=0x%x\r\n", initial_addr); initial_addr_set = true; } if (!flash_initialized) { uint32_t copy_size; bool flash_type_known = false; bool sequential; // Check if the data is sequential sequential = addr == current_addr; current_addr += size; // Buffer data until the flash type is known if (sequential) { // Copy data into buffer copy_size = MIN(size, sizeof(flash_buf) - flash_buf_pos); memcpy(&flash_buf[flash_buf_pos], data, copy_size); flash_buf_pos += copy_size; flash_decoder_printf(" buffering %i bytes\r\n", copy_size); // Update vars so they no longer include the buffered data data += copy_size; size -= copy_size; addr += copy_size; // If enough data has been buffered then determine the type if (flash_buf_pos >= sizeof(flash_buf)) { util_assert(sizeof(flash_buf) == flash_buf_pos); // Determine flash type and get info for it flash_type = flash_decoder_detect_type(flash_buf, flash_buf_pos, initial_addr, true); flash_decoder_printf(" Buffering complete, setting flash_type=%i\r\n", flash_type); flash_type_known = true; } } else { flash_type = FLASH_DECODER_TYPE_TARGET; flash_decoder_printf(" Non sequential addr, setting flash_type=%i\r\n", flash_type); flash_type_known = true; } // If flash type is known initialize the flash manager if (flash_type_known) { const flash_intf_t *flash_intf; uint32_t flash_start_addr; status = flash_decoder_get_flash(flash_type, initial_addr, true, &flash_start_addr, &flash_intf); if (ERROR_SUCCESS != status) { state = DECODER_STATE_ERROR; return status; } flash_decoder_printf(" flash_start_addr=0x%x\r\n", flash_start_addr); // Initialize flash manager util_assert(!flash_initialized); status = flash_manager_init(flash_intf); flash_decoder_printf(" flash_manager_init ret %i\r\n", status); if (ERROR_SUCCESS != status) { state = DECODER_STATE_ERROR; return status; } flash_initialized = true; } // If flash has been initalized then write out buffered data if (flash_initialized) { status = flash_manager_data(initial_addr, flash_buf, flash_buf_pos); flash_decoder_printf(" Flushing buffer initial_addr=0x%x, flash_buf_pos=%i, flash_manager_data ret=%i\r\n", initial_addr, flash_buf_pos, status); if (ERROR_SUCCESS != status) { state = DECODER_STATE_ERROR; return status; } } } // Write data as normal if flash has been initialized if (flash_initialized) { status = flash_manager_data(addr, data, size); flash_decoder_printf(" Writing data, addr=0x%x, size=0x%x, flash_manager_data ret %i\r\n", addr, size, status); if (ERROR_SUCCESS != status) { state = DECODER_STATE_ERROR; return status; } } // Check if this is the end of data if (flash_decoder_is_at_end(addr, data, size)) { flash_decoder_printf(" End of transfer detected - addr 0x%08x, size 0x%08x\r\n", addr, size); state = DECODER_STATE_DONE; return ERROR_SUCCESS_DONE; } return ERROR_SUCCESS; }