Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.
Upstream: https://github.com/ARMmbed/DAPLink
Diff: source/daplink/drag-n-drop/file_stream.c
- Revision:
- 0:01f31e923fe2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/daplink/drag-n-drop/file_stream.c Tue Apr 07 12:55:42 2020 +0200 @@ -0,0 +1,366 @@ +/** + * @file file_stream.c + * @brief Implementation of file_stream.h + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <string.h> + +#include "file_stream.h" +#include "util.h" +#include "intelhex.h" +#include "flash_decoder.h" +#include "error.h" +#include "cmsis_os2.h" +#include "compiler.h" +#include "validation.h" + +typedef enum { + STREAM_STATE_CLOSED, + STREAM_STATE_OPEN, + STREAM_STATE_END, + STREAM_STATE_ERROR +} stream_state_t; + +typedef bool (*stream_detect_cb_t)(const uint8_t *data, uint32_t size); +typedef error_t (*stream_open_cb_t)(void *state); +typedef error_t (*stream_write_cb_t)(void *state, const uint8_t *data, uint32_t size); +typedef error_t (*stream_close_cb_t)(void *state); + +typedef struct { + stream_detect_cb_t detect; + stream_open_cb_t open; + stream_write_cb_t write; + stream_close_cb_t close; +} stream_t; + +typedef struct { + uint8_t vector_buf[FLASH_DECODER_MIN_SIZE]; + uint8_t buf_pos; + uint32_t flash_addr; +} bin_state_t; + +typedef struct { + bool parsing_complete; + uint8_t bin_buffer[256]; +} hex_state_t; + +typedef union { + bin_state_t bin; + hex_state_t hex; +} shared_state_t; + +static bool detect_bin(const uint8_t *data, uint32_t size); +static error_t open_bin(void *state); +static error_t write_bin(void *state, const uint8_t *data, uint32_t size); +static error_t close_bin(void *state); + +static bool detect_hex(const uint8_t *data, uint32_t size); +static error_t open_hex(void *state); +static error_t write_hex(void *state, const uint8_t *data, uint32_t size); +static error_t close_hex(void *state); + +stream_t stream[] = { + {detect_bin, open_bin, write_bin, close_bin}, // STREAM_TYPE_BIN + {detect_hex, open_hex, write_hex, close_hex}, // STREAM_TYPE_HEX +}; +COMPILER_ASSERT(ARRAY_SIZE(stream) == STREAM_TYPE_COUNT); +// STREAM_TYPE_NONE must not be included in count +COMPILER_ASSERT(STREAM_TYPE_NONE > STREAM_TYPE_COUNT); + +static shared_state_t shared_state; +static stream_state_t state = STREAM_STATE_CLOSED; +static stream_t *current_stream = 0; + +// Thread variables (STUB these if RTX is not used) +static osThreadId_t stream_thread_tid = 0; +static void stream_thread_set(void) +{ + stream_thread_tid = osThreadGetId(); +} +static void stream_thread_assert(void) +{ + util_assert(osThreadGetId() == stream_thread_tid); +} + +stream_type_t stream_start_identify(const uint8_t *data, uint32_t size) +{ + stream_type_t i; + + for (i = STREAM_TYPE_START; i < STREAM_TYPE_COUNT; i++) { + if (stream[i].detect(data, size)) { + return i; + } + } + + return STREAM_TYPE_NONE; +} + +// Identify the file type from its extension +stream_type_t stream_type_from_name(const vfs_filename_t filename) +{ + // 8.3 file names must be in upper case + if (0 == strncmp("BIN", &filename[8], 3)) { + return STREAM_TYPE_BIN; + } else if (0 == strncmp("HEX", &filename[8], 3)) { + return STREAM_TYPE_HEX; + } else { + return STREAM_TYPE_NONE; + } +} + +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; +} + +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_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; +} + +/* Binary file processing */ + +static bool detect_bin(const uint8_t *data, uint32_t size) +{ + return FLASH_DECODER_TYPE_UNKNOWN != flash_decoder_detect_type(data, size, 0, false); +} + +static error_t open_bin(void *state) +{ + error_t status; + status = flash_decoder_open(); + return status; +} + +static error_t write_bin(void *state, const uint8_t *data, uint32_t size) +{ + error_t status; + bin_state_t *bin_state = (bin_state_t *)state; + + if (bin_state->buf_pos < FLASH_DECODER_MIN_SIZE) { + flash_decoder_type_t flash_type; + uint32_t size_left; + uint32_t copy_size; + uint32_t start_addr; + const flash_intf_t *flash_intf; + // Buffer Data + size_left = FLASH_DECODER_MIN_SIZE - bin_state->buf_pos; + copy_size = MIN(size_left, size); + memcpy(bin_state->vector_buf + bin_state->buf_pos, data, copy_size); + bin_state->buf_pos += copy_size; + + if (bin_state->buf_pos < FLASH_DECODER_MIN_SIZE) { + // Not enough data to determine type + return ERROR_SUCCESS; + } + + data += copy_size; + size -= copy_size; + // Determine type + flash_type = flash_decoder_detect_type(bin_state->vector_buf, bin_state->buf_pos, 0, false); + + if (FLASH_DECODER_TYPE_UNKNOWN == flash_type) { + return ERROR_FD_UNSUPPORTED_UPDATE; + } + + // Determine flash addresss + status = flash_decoder_get_flash(flash_type, 0, false, &start_addr, &flash_intf); + + if (ERROR_SUCCESS != status) { + return status; + } + + bin_state->flash_addr = start_addr; + // Pass on data to the decoder + status = flash_decoder_write(bin_state->flash_addr, bin_state->vector_buf, bin_state->buf_pos); + + if (ERROR_SUCCESS != status) { + return status; + } + + bin_state->flash_addr += bin_state->buf_pos; + } + + // Write data + status = flash_decoder_write(bin_state->flash_addr, data, size); + + if (ERROR_SUCCESS != status) { + return status; + } + + bin_state->flash_addr += size; + // There is no way to determine the end of a binary + // file so any point could be the end + return ERROR_SUCCESS_DONE_OR_CONTINUE; +} + +static error_t close_bin(void *state) +{ + error_t status; + status = flash_decoder_close(); + return status; +} + +/* Hex file processing */ + +static bool detect_hex(const uint8_t *data, uint32_t size) +{ + return 1 == validate_hexfile(data); +} + +static error_t open_hex(void *state) +{ + error_t status; + hex_state_t *hex_state = (hex_state_t *)state; + memset(hex_state, 0, sizeof(*hex_state)); + reset_hex_parser(); + hex_state->parsing_complete = false; + status = flash_decoder_open(); + return status; +} + +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; +} + +static error_t close_hex(void *state) +{ + error_t status; + status = flash_decoder_close(); + return status; +}