Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.

Upstream: https://github.com/ARMmbed/DAPLink

Revision:
0:01f31e923fe2
diff -r 000000000000 -r 01f31e923fe2 source/daplink/drag-n-drop/vfs_manager.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/daplink/drag-n-drop/vfs_manager.c	Tue Apr 07 12:55:42 2020 +0200
@@ -0,0 +1,839 @@
+/**
+ * @file    vfs_manager.c
+ * @brief   Implementation of vfs_manager.h
+ *
+ * DAPLink Interface Firmware
+ * Copyright (c) 2009-2019, 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 <ctype.h>
+
+#include "main.h"
+#include "cmsis_os2.h"
+#include "rl_usb.h"
+#include "virtual_fs.h"
+#include "vfs_manager.h"
+#include "daplink_debug.h"
+#include "info.h"
+#include "settings.h"
+#include "daplink.h"
+#include "util.h"
+#include "version_git.h"
+#include "IO_Config.h"
+#include "file_stream.h"
+#include "error.h"
+
+// Set to 1 to enable debugging
+#define DEBUG_VFS_MANAGER     0
+
+#if DEBUG_VFS_MANAGER
+#define vfs_mngr_printf    debug_msg
+#else
+#define vfs_mngr_printf(...)
+#endif
+
+#define INVALID_TIMEOUT_MS  0xFFFFFFFF
+#define MAX_EVENT_TIME_MS   60000
+
+#define CONNECT_DELAY_MS 0
+#define RECONNECT_DELAY_MS 2500    // Must be above 1s for windows (more for linux)
+// TRANSFER_IN_PROGRESS
+#define DISCONNECT_DELAY_TRANSFER_TIMEOUT_MS 20000
+// TRANSFER_CAN_BE_FINISHED
+#define DISCONNECT_DELAY_TRANSFER_IDLE_MS 500
+// TRANSFER_NOT_STARTED || TRASNFER_FINISHED
+#define DISCONNECT_DELAY_MS 500
+
+// Make sure none of the delays exceed the max time
+COMPILER_ASSERT(CONNECT_DELAY_MS < MAX_EVENT_TIME_MS);
+COMPILER_ASSERT(RECONNECT_DELAY_MS < MAX_EVENT_TIME_MS);
+COMPILER_ASSERT(DISCONNECT_DELAY_TRANSFER_TIMEOUT_MS < MAX_EVENT_TIME_MS);
+COMPILER_ASSERT(DISCONNECT_DELAY_TRANSFER_IDLE_MS < MAX_EVENT_TIME_MS);
+COMPILER_ASSERT(DISCONNECT_DELAY_MS < MAX_EVENT_TIME_MS);
+
+typedef enum {
+    TRANSFER_NOT_STARTED,
+    TRANSFER_IN_PROGRESS,
+    TRANSFER_CAN_BE_FINISHED,
+    TRASNFER_FINISHED,
+} transfer_state_t;
+
+typedef struct {
+    vfs_file_t file_to_program;     // A pointer to the directory entry of the file being programmed
+    vfs_sector_t start_sector;      // Start sector of the file being programmed by stream
+    vfs_sector_t file_start_sector; // Start sector of the file being programmed by vfs
+    vfs_sector_t file_next_sector;  // Expected next sector of the file
+    vfs_sector_t last_ooo_sector;   // Last out of order sector within the file
+    uint32_t size_processed;        // The number of bytes processed by the stream
+    uint32_t file_size;             // Size of the file indicated by root dir.  Only allowed to increase
+    uint32_t size_transferred;      // The number of bytes transferred
+    transfer_state_t transfer_state;// Transfer state
+    bool stream_open;               // State of the stream
+    bool stream_started;            // Stream processing started. This only gets reset remount
+    bool stream_finished;           // Stream processing is done. This only gets reset remount
+    bool stream_optional_finish;    // True if the stream processing can be considered done
+    bool file_info_optional_finish; // True if the file transfer can be considered done
+    bool transfer_timeout;          // Set if the transfer was finished because of a timeout. This only gets reset remount
+    stream_type_t stream;           // Current stream or STREAM_TYPE_NONE is stream is closed.  This only gets reset remount
+} file_transfer_state_t;
+
+typedef enum {
+    VFS_MNGR_STATE_DISCONNECTED,
+    VFS_MNGR_STATE_RECONNECTING,
+    VFS_MNGR_STATE_CONNECTED
+} vfs_mngr_state_t;
+
+static const file_transfer_state_t default_transfer_state = {
+    VFS_FILE_INVALID,
+    VFS_INVALID_SECTOR,
+    VFS_INVALID_SECTOR,
+    VFS_INVALID_SECTOR,
+    VFS_INVALID_SECTOR,
+    0,
+    0,
+    0,
+    TRANSFER_NOT_STARTED,
+    false,
+    false,
+    false,
+    false,
+    false,
+    false,
+    STREAM_TYPE_NONE,
+};
+
+//Compile option not to include MSC at all, these will be dummy variables
+#ifndef MSC_ENDPOINT
+BOOL USBD_MSC_MediaReady = __FALSE;
+BOOL USBD_MSC_ReadOnly = __FALSE;
+U32 USBD_MSC_MemorySize;
+U32 USBD_MSC_BlockSize;
+U32 USBD_MSC_BlockGroup;
+U32 USBD_MSC_BlockCount;
+U8 *USBD_MSC_BlockBuf;
+#endif
+
+static uint32_t usb_buffer[VFS_SECTOR_SIZE / sizeof(uint32_t)];
+static error_t fail_reason = ERROR_SUCCESS;
+static file_transfer_state_t file_transfer_state;
+
+// These variables can be access from multiple threads
+// so access to them must be synchronized
+static vfs_mngr_state_t vfs_state;
+static vfs_mngr_state_t vfs_state_next;
+static uint32_t time_usb_idle;
+
+static osMutexId_t sync_mutex;
+static osThreadId_t sync_thread = 0;
+
+// Synchronization functions
+static void sync_init(void);
+static void sync_assert_usb_thread(void);
+static void sync_lock(void);
+static void sync_unlock(void);
+
+static bool changing_state(void);
+static void build_filesystem(void);
+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);
+static void file_data_handler(uint32_t sector, const uint8_t *buf, uint32_t num_of_sectors);
+static bool ready_for_state_change(void);
+static void abort_remount(void);
+
+static void transfer_update_file_info(vfs_file_t file, uint32_t start_sector, uint32_t size, stream_type_t stream);
+static void transfer_reset_file_info(void);
+static void transfer_stream_open(stream_type_t stream, uint32_t start_sector);
+static void transfer_stream_data(uint32_t sector, const uint8_t *data, uint32_t size);
+static void transfer_update_state(error_t status);
+
+
+void vfs_mngr_fs_enable(bool enable)
+{
+    sync_lock();
+
+    if (enable) {
+        if (VFS_MNGR_STATE_DISCONNECTED == vfs_state_next) {
+            vfs_state_next = VFS_MNGR_STATE_CONNECTED;
+        }
+    } else {
+        vfs_state_next = VFS_MNGR_STATE_DISCONNECTED;
+    }
+
+    sync_unlock();
+}
+
+void vfs_mngr_fs_remount(void)
+{
+    sync_lock();
+
+    // Only start a remount if in the connected state and not in a transition
+    if (!changing_state() && (VFS_MNGR_STATE_CONNECTED == vfs_state)) {
+        vfs_state_next = VFS_MNGR_STATE_RECONNECTING;
+    }
+
+    sync_unlock();
+}
+
+void vfs_mngr_init(bool enable)
+{
+    sync_assert_usb_thread();
+    build_filesystem();
+
+    if (enable) {
+        vfs_state = VFS_MNGR_STATE_CONNECTED;
+        vfs_state_next = VFS_MNGR_STATE_CONNECTED;
+        USBD_MSC_MediaReady = 1;
+    } else {
+        vfs_state = VFS_MNGR_STATE_DISCONNECTED;
+        vfs_state_next = VFS_MNGR_STATE_DISCONNECTED;
+        USBD_MSC_MediaReady = 0;
+    }
+}
+
+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;
+    }
+
+    if (!change_state) {
+        sync_unlock();
+        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;
+}
+
+error_t vfs_mngr_get_transfer_status()
+{
+    sync_assert_usb_thread();
+    return fail_reason;
+}
+
+void usbd_msc_init(void)
+{
+    sync_init();
+    build_filesystem();
+    vfs_state = VFS_MNGR_STATE_DISCONNECTED;
+    vfs_state_next = VFS_MNGR_STATE_DISCONNECTED;
+    time_usb_idle = 0;
+    USBD_MSC_MediaReady = 0;
+}
+
+void usbd_msc_read_sect(uint32_t sector, uint8_t *buf, uint32_t num_of_sectors)
+{
+    sync_assert_usb_thread();
+
+    // dont proceed if we're not ready
+    if (!USBD_MSC_MediaReady) {
+        return;
+    }
+
+    // indicate msc activity
+    main_blink_msc_led(MAIN_LED_FLASH);
+    vfs_read(sector, buf, num_of_sectors);
+}
+
+void usbd_msc_write_sect(uint32_t sector, uint8_t *buf, uint32_t num_of_sectors)
+{
+    sync_assert_usb_thread();
+
+    if (!USBD_MSC_MediaReady) {
+        return;
+    }
+
+    // Restart the disconnect counter on every packet
+    // so the device does not detach in the middle of a
+    // transfer.
+    time_usb_idle = 0;
+
+    if (TRASNFER_FINISHED == file_transfer_state.transfer_state) {
+        return;
+    }
+
+    // indicate msc activity
+    main_blink_msc_led(MAIN_LED_FLASH);
+    vfs_write(sector, buf, num_of_sectors);
+    if (TRASNFER_FINISHED == file_transfer_state.transfer_state) {
+        return;
+    }
+    file_data_handler(sector, buf, num_of_sectors);
+}
+
+static void sync_init(void)
+{
+    sync_thread = osThreadGetId();
+    sync_mutex = osMutexNew(NULL);
+}
+
+static void sync_assert_usb_thread(void)
+{
+    util_assert(osThreadGetId() == sync_thread);
+}
+
+static void sync_lock(void)
+{
+    osMutexAcquire(sync_mutex, 0);
+}
+
+static void sync_unlock(void)
+{
+    osMutexRelease(sync_mutex);
+}
+
+static bool changing_state()
+{
+    return vfs_state != vfs_state_next;
+}
+
+static void build_filesystem()
+{
+    // Update anything that could have changed file system state
+    file_transfer_state = default_transfer_state;
+    vfs_user_build_filesystem();
+    vfs_set_file_change_callback(file_change_handler);
+    // Set mass storage parameters
+    USBD_MSC_MemorySize = vfs_get_total_size();
+    USBD_MSC_BlockSize  = VFS_SECTOR_SIZE;
+    USBD_MSC_BlockGroup = 1;
+    USBD_MSC_BlockCount = USBD_MSC_MemorySize / USBD_MSC_BlockSize;
+    USBD_MSC_BlockBuf   = (uint8_t *)usb_buffer;
+}
+
+// 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_mngr_printf("vfs_manager file_change_handler(name=%*s, file=%p, change=%i)\r\n", 11, filename, file, change);
+    vfs_user_file_change_handler(filename, change, file, new_file_data);
+    if (TRASNFER_FINISHED == file_transfer_state.transfer_state) {
+        // If the transfer is finished stop further processing
+        return;
+    }
+
+    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);
+            stream = stream_type_from_name(filename);
+            transfer_update_file_info(file, sector, size, stream);
+        }
+    }
+
+    if (VFS_FILE_CREATED == change) {
+        stream_type_t stream;
+
+        if (STREAM_TYPE_NONE != stream_type_from_name(filename)) {
+            // Check for a know file extension to detect the current file being
+            // transferred.  Ignore hidden files since MAC uses hidden files with
+            // the same extension to keep track of transfer info in some cases.
+            if (!(VFS_FILE_ATTR_HIDDEN & vfs_file_get_attr(new_file_data))) {
+                stream = stream_type_from_name(filename);
+                uint32_t size = vfs_file_get_size(new_file_data);
+                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 (file == file_transfer_state.file_to_program) {
+            // The file that was being transferred has been deleted
+            transfer_reset_file_info();
+        }
+    }
+}
+
+// Handler for file data arriving over USB.  This function is responsible
+// for detecting the start of a BIN/HEX file and performing programming
+static void file_data_handler(uint32_t sector, const uint8_t *buf, uint32_t num_of_sectors)
+{
+    stream_type_t stream;
+    uint32_t size;
+
+    // this is the key for starting a file write - we dont care what file types are sent
+    //  just look for something unique (NVIC table, hex, srec, etc) until root dir is updated
+    if (!file_transfer_state.stream_started) {
+        // look for file types we can program
+        stream = stream_start_identify((uint8_t *)buf, VFS_SECTOR_SIZE * num_of_sectors);
+
+        if (STREAM_TYPE_NONE != stream) {
+            transfer_stream_open(stream, sector);
+        }
+    }
+
+    if (file_transfer_state.stream_started) {
+        // Ignore sectors coming before this file
+        if (sector < file_transfer_state.start_sector) {
+            return;
+        }
+
+        // sectors must be in order
+        if (sector != file_transfer_state.file_next_sector) {
+            vfs_mngr_printf("vfs_manager file_data_handler sector=%i\r\n", sector);
+
+            if (sector < file_transfer_state.file_next_sector) {
+                vfs_mngr_printf("    sector out of order! lowest ooo = %i\r\n",
+                                file_transfer_state.last_ooo_sector);
+
+                if (VFS_INVALID_SECTOR == file_transfer_state.last_ooo_sector) {
+                    file_transfer_state.last_ooo_sector = sector;
+                }
+
+                file_transfer_state.last_ooo_sector =
+                    MIN(file_transfer_state.last_ooo_sector, sector);
+            } else {
+                vfs_mngr_printf("    sector not part of file transfer\r\n");
+            }
+
+            vfs_mngr_printf("    discarding data - size transferred=0x%x, data=%x,%x,%x,%x,...\r\n",
+                            file_transfer_state.size_transferred, buf[0], buf[1], buf[2], buf[3]);
+            return;
+        }
+
+        // This sector could be part of the file so record it
+        size = VFS_SECTOR_SIZE * num_of_sectors;
+        file_transfer_state.size_transferred += size;
+        file_transfer_state.file_next_sector = sector + num_of_sectors;
+
+        // If stream processing is done then discard the data
+        if (file_transfer_state.stream_finished) {
+            vfs_mngr_printf("vfs_manager file_data_handler\r\n    sector=%i, size=%i\r\n", sector, size);
+            vfs_mngr_printf("    discarding data - size transferred=0x%x, data=%x,%x,%x,%x,...\r\n",
+                            file_transfer_state.size_transferred, buf[0], buf[1], buf[2], buf[3]);
+            transfer_update_state(ERROR_SUCCESS);
+            return;
+        }
+
+        transfer_stream_data(sector, buf, size);
+    }
+}
+
+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;
+}
+
+// Abort a remount if one is pending
+void abort_remount(void)
+{
+    sync_lock();
+
+    // Only abort a remount if in the connected state and reconnecting is the next state
+    if ((VFS_MNGR_STATE_RECONNECTING == vfs_state_next) && (VFS_MNGR_STATE_CONNECTED == vfs_state)) {
+        vfs_state_next = VFS_MNGR_STATE_CONNECTED;
+    }
+
+    sync_unlock();
+}
+
+// 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.file_start_sector) {
+        file_transfer_state.file_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 either grow or be smaller than the size already transferred
+    if ((size < file_transfer_state.file_size) && (size < file_transfer_state.size_transferred) && (size > 0)) {
+        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.file_start_sector)) {
+        vfs_mngr_printf("    error: starting sector changed from %i to %i\r\n", file_transfer_state.file_start_sector, start_sector);
+        transfer_update_state(ERROR_ERROR_DURING_TRANSFER);
+        return;
+    }
+
+    // Check - stream must be the same
+    if ((stream != STREAM_TYPE_NONE) && (stream != file_transfer_state.stream)) {
+        vfs_mngr_printf("    error: changed types during transfer from %i to %i\r\n", file_transfer_state.stream, stream);
+        transfer_update_state(ERROR_ERROR_DURING_TRANSFER);
+        return;
+    }
+
+    // Update values - Size is the only value that can change
+    file_transfer_state.file_size = size;
+    vfs_mngr_printf("    updated size=%i\r\n", size);
+
+    transfer_update_state(ERROR_SUCCESS);
+}
+
+// Reset the transfer information or error if transfer is already in progress
+static void transfer_reset_file_info()
+{
+    vfs_mngr_printf("vfs_manager transfer_reset_file_info()\r\n");
+    //check if the data started streaming; size can be updated on matching start sector and stream type
+    if(file_transfer_state.stream_started){
+        //file, start sector and size has to be updated
+        file_transfer_state.file_to_program = VFS_FILE_INVALID;
+        file_transfer_state.file_start_sector = VFS_INVALID_SECTOR;
+        file_transfer_state.file_size = 0;
+    }else{
+          file_transfer_state = default_transfer_state;
+          abort_remount();
+    }
+
+}
+
+// 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 transfer from %i to %i\r\n", file_transfer_state.stream, 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_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);
+}
+
+// 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
+    // 4. Matching start sector set by stream and vfs changes
+    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) &&
+        (file_transfer_state.start_sector == file_transfer_state.file_start_sector);
+    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 %i, size=%i\r\n",
+                        file_transfer_state.file_to_program, file_transfer_state.start_sector,
+                        file_transfer_state.file_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();
+    }
+}