Class that combined FATFileSystem with a USBMSD device, similar to LocalFileSystem

Dependencies:   USBDevice

Dependents:   SD_USB_FS_HelloWorld S25FL216K_USBFileSystem USBFileSystem_RAMDISK_HelloWorld

Introduction

USBFileSystem is a combination of FATFileSystem and USB-MSD (Mass-Storage Device). This way it allows you to create a filesystem that is both accessible on your PC with the USB cable plugged in, and on the device itself. This is very similar to LocalFileSystem, only you can use any Serial Flash, SD, etc as storage medium.

If your code works with either FATFileSystem or USBMSD it will with very little modification also work with USBFileSystem.

Basic functionality

Since both FATFileSystem and USBMSD write binary data to a the storage medium, if both are writing somewhere at the same time we have a problem. This library makes the medium read only for the local side, if USB is writing, and vice versa. Local is considered to be writing as long as you have opened a file for write. USB is considered writing as soon as a write command comes from USB, and this continues for a short time after the last write command. This is needed because I cannot know when the last sector is written by USB, so I have to wait a little while to see if more data is written.

Reading

You can still read when the other one is writing. This can result in issues. Using the functions given you can easily make sure that won't happen. However regardless if you do that or not, it is a good idea to make sure your program can handle unexpected situations. For example if you open a file locally, and you get a NULL pointer, do not immediatly go into an error condition, but just try it again.

USB MSD on your PC

When you write to / read from a USB drive Windows (and I expect other OS's too) will cache everything. The result is that once you read a file on your PC, it will never change, even if your mbed does change the data. And if you write/delete a file when the mbed is locally using the file system, it will be read only, however your PC will tell you data was succesfully written/removed.

If this is a problem for your device, you can disconnect the USB part when the mbed is writing to the storage medium locally. The library can do this automatically for you.

Required code

The virtual functions that need to be implemented by you are:

virtual int disk_initialize() { return 0; }
virtual int _disk_status() { return 0; }
virtual int disk_read(uint8_t * buffer, uint64_t sector) { return 0;}
virtual int _disk_write(const uint8_t * buffer, uint64_t sector) = 0;
virtual int disk_sync() { return 0; }
virtual uint64_t disk_sectors() = 0;

Some of those are optional, but disk_read, _disk_write and disk_sectors have to be defined in the child class.

Sector size

The sector size must be 512 bytes. In USBMSD this requirement isn't present, but FATFileSystem has this requirement!

Function name

Note the '_' at the beginning of _disk_status and _disk_write. You may not inherit it without the '_', that will break the library. Since the parent libraries made it virtual I cannot block it from happening, so just watch out.

Available functions for the user

The USBFileSystem library allows for some extra functions the user can use. The API documentation lists them, but summarized: You can attach functions which are called once either USB is writing to the storage medium, or when this is done locally. There are two functions which will tell you if currently USB/local is writing to the storage medium, and you can set the usbMode. Set it to mode 0 and USB is read only when the storage is used locally, set it to mode 1 and it is disconnected (default and recommended).

Besides that there are of course the standard USB functions (connect/disconnect for example), and you can use 'fopen', 'mkdir', etc similar to FATFileSystem.

Hello World

Currently available:

RAM-disk for KL25Z and LPC1768 (this one disappeared for some reason, I re-published it, should still work):

Import programUSBFileSystem_RAMDISK_HelloWorld

RAMDisk example for the USBFileSystem

Wi-Go serial flash:

Import programS25FL216K_HelloWorld

Helloworld program for the S25FL216K flash memory in combination with USBFileSystem

SD card (different from others):

Import programSD_USB_FS_HelloWorld

SD USB MSD helloworld

Note that this one is not mine, if you have problems with it check if there are updates for the library.

Committer:
Sissors
Date:
Sun Jan 18 21:43:06 2015 +0000
Revision:
8:a9e1dffac4bd
Parent:
7:da1f3328a496
Actually use count argument

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sissors 7:da1f3328a496 1 /* mbed Microcontroller Library
Sissors 7:da1f3328a496 2 * Copyright (c) 2006-2012 ARM Limited
Sissors 7:da1f3328a496 3 *
Sissors 7:da1f3328a496 4 * Permission is hereby granted, free of charge, to any person obtaining a copy
Sissors 7:da1f3328a496 5 * of this software and associated documentation files (the "Software"), to deal
Sissors 7:da1f3328a496 6 * in the Software without restriction, including without limitation the rights
Sissors 7:da1f3328a496 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Sissors 7:da1f3328a496 8 * copies of the Software, and to permit persons to whom the Software is
Sissors 7:da1f3328a496 9 * furnished to do so, subject to the following conditions:
Sissors 7:da1f3328a496 10 *
Sissors 7:da1f3328a496 11 * The above copyright notice and this permission notice shall be included in
Sissors 7:da1f3328a496 12 * all copies or substantial portions of the Software.
Sissors 7:da1f3328a496 13 *
Sissors 7:da1f3328a496 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Sissors 7:da1f3328a496 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Sissors 7:da1f3328a496 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Sissors 7:da1f3328a496 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Sissors 7:da1f3328a496 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Sissors 7:da1f3328a496 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Sissors 7:da1f3328a496 20 * SOFTWARE.
Sissors 7:da1f3328a496 21 */
Sissors 7:da1f3328a496 22 #include "mbed.h"
Sissors 7:da1f3328a496 23
Sissors 7:da1f3328a496 24 #include "ffconf.h"
Sissors 7:da1f3328a496 25 #include "mbed_debug.h"
Sissors 7:da1f3328a496 26
Sissors 7:da1f3328a496 27 #include "FATFileSystem.h"
Sissors 7:da1f3328a496 28 #include "FATFileHandle.h"
Sissors 7:da1f3328a496 29 #include "FATDirHandle.h"
Sissors 7:da1f3328a496 30
Sissors 7:da1f3328a496 31 DWORD get_fattime(void) {
Sissors 7:da1f3328a496 32 time_t rawtime;
Sissors 7:da1f3328a496 33 time(&rawtime);
Sissors 7:da1f3328a496 34 struct tm *ptm = localtime(&rawtime);
Sissors 7:da1f3328a496 35 return (DWORD)(ptm->tm_year - 80) << 25
Sissors 7:da1f3328a496 36 | (DWORD)(ptm->tm_mon + 1 ) << 21
Sissors 7:da1f3328a496 37 | (DWORD)(ptm->tm_mday ) << 16
Sissors 7:da1f3328a496 38 | (DWORD)(ptm->tm_hour ) << 11
Sissors 7:da1f3328a496 39 | (DWORD)(ptm->tm_min ) << 5
Sissors 7:da1f3328a496 40 | (DWORD)(ptm->tm_sec/2 );
Sissors 7:da1f3328a496 41 }
Sissors 7:da1f3328a496 42
Sissors 7:da1f3328a496 43 FATFileSystem *FATFileSystem::_ffs[_VOLUMES] = {0};
Sissors 7:da1f3328a496 44
Sissors 7:da1f3328a496 45 FATFileSystem::FATFileSystem(const char* n) : FileSystemLike(n) {
Sissors 7:da1f3328a496 46 debug_if(FFS_DBG, "FATFileSystem(%s)\n", n);
Sissors 7:da1f3328a496 47 for(int i=0; i<_VOLUMES; i++) {
Sissors 7:da1f3328a496 48 if(_ffs[i] == 0) {
Sissors 7:da1f3328a496 49 _ffs[i] = this;
Sissors 7:da1f3328a496 50 _fsid = i;
Sissors 7:da1f3328a496 51 debug_if(FFS_DBG, "Mounting [%s] on ffs drive [%d]\n", _name, _fsid);
Sissors 7:da1f3328a496 52 f_mount(i, &_fs);
Sissors 7:da1f3328a496 53 return;
Sissors 7:da1f3328a496 54 }
Sissors 7:da1f3328a496 55 }
Sissors 7:da1f3328a496 56 error("Couldn't create %s in FATFileSystem::FATFileSystem\n", n);
Sissors 7:da1f3328a496 57 }
Sissors 7:da1f3328a496 58
Sissors 7:da1f3328a496 59 FATFileSystem::~FATFileSystem() {
Sissors 7:da1f3328a496 60 for (int i=0; i<_VOLUMES; i++) {
Sissors 7:da1f3328a496 61 if (_ffs[i] == this) {
Sissors 7:da1f3328a496 62 _ffs[i] = 0;
Sissors 7:da1f3328a496 63 f_mount(i, NULL);
Sissors 7:da1f3328a496 64 }
Sissors 7:da1f3328a496 65 }
Sissors 7:da1f3328a496 66 }
Sissors 7:da1f3328a496 67
Sissors 7:da1f3328a496 68 FileHandle *FATFileSystem::open(const char* name, int flags) {
Sissors 7:da1f3328a496 69 debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%d]\n", name, _name, _fsid);
Sissors 7:da1f3328a496 70 char n[64];
Sissors 7:da1f3328a496 71 sprintf(n, "%d:/%s", _fsid, name);
Sissors 7:da1f3328a496 72
Sissors 7:da1f3328a496 73 /* POSIX flags -> FatFS open mode */
Sissors 7:da1f3328a496 74 BYTE openmode;
Sissors 7:da1f3328a496 75 if (flags & O_RDWR) {
Sissors 7:da1f3328a496 76 openmode = FA_READ|FA_WRITE;
Sissors 7:da1f3328a496 77 } else if(flags & O_WRONLY) {
Sissors 7:da1f3328a496 78 openmode = FA_WRITE;
Sissors 7:da1f3328a496 79 } else {
Sissors 7:da1f3328a496 80 openmode = FA_READ;
Sissors 7:da1f3328a496 81 }
Sissors 7:da1f3328a496 82 if(flags & O_CREAT) {
Sissors 7:da1f3328a496 83 if(flags & O_TRUNC) {
Sissors 7:da1f3328a496 84 openmode |= FA_CREATE_ALWAYS;
Sissors 7:da1f3328a496 85 } else {
Sissors 7:da1f3328a496 86 openmode |= FA_OPEN_ALWAYS;
Sissors 7:da1f3328a496 87 }
Sissors 7:da1f3328a496 88 }
Sissors 7:da1f3328a496 89
Sissors 7:da1f3328a496 90 FIL fh;
Sissors 7:da1f3328a496 91 FRESULT res = f_open(&fh, n, openmode);
Sissors 7:da1f3328a496 92 if (res) {
Sissors 7:da1f3328a496 93 debug_if(FFS_DBG, "f_open('w') failed: %d\n", res);
Sissors 7:da1f3328a496 94 return NULL;
Sissors 7:da1f3328a496 95 }
Sissors 7:da1f3328a496 96 if (flags & O_APPEND) {
Sissors 7:da1f3328a496 97 f_lseek(&fh, fh.fsize);
Sissors 7:da1f3328a496 98 }
Sissors 7:da1f3328a496 99 return new FATFileHandle(fh);
Sissors 7:da1f3328a496 100 }
Sissors 7:da1f3328a496 101
Sissors 7:da1f3328a496 102 int FATFileSystem::remove(const char *filename) {
Sissors 7:da1f3328a496 103 FRESULT res = f_unlink(filename);
Sissors 7:da1f3328a496 104 if (res) {
Sissors 7:da1f3328a496 105 debug_if(FFS_DBG, "f_unlink() failed: %d\n", res);
Sissors 7:da1f3328a496 106 return -1;
Sissors 7:da1f3328a496 107 }
Sissors 7:da1f3328a496 108 return 0;
Sissors 7:da1f3328a496 109 }
Sissors 7:da1f3328a496 110
Sissors 7:da1f3328a496 111 int FATFileSystem::rename(const char *oldname, const char *newname) {
Sissors 7:da1f3328a496 112 FRESULT res = f_rename(oldname, newname);
Sissors 7:da1f3328a496 113 if (res) {
Sissors 7:da1f3328a496 114 debug_if(FFS_DBG, "f_rename() failed: %d\n", res);
Sissors 7:da1f3328a496 115 return -1;
Sissors 7:da1f3328a496 116 }
Sissors 7:da1f3328a496 117 return 0;
Sissors 7:da1f3328a496 118 }
Sissors 7:da1f3328a496 119
Sissors 7:da1f3328a496 120 int FATFileSystem::format() {
Sissors 7:da1f3328a496 121 FRESULT res = f_mkfs(_fsid, 0, 512); // Logical drive number, Partitioning rule, Allocation unit size (bytes per cluster)
Sissors 7:da1f3328a496 122 if (res) {
Sissors 7:da1f3328a496 123 debug_if(FFS_DBG, "f_mkfs() failed: %d\n", res);
Sissors 7:da1f3328a496 124 return -1;
Sissors 7:da1f3328a496 125 }
Sissors 7:da1f3328a496 126 return 0;
Sissors 7:da1f3328a496 127 }
Sissors 7:da1f3328a496 128
Sissors 7:da1f3328a496 129 DirHandle *FATFileSystem::opendir(const char *name) {
Sissors 7:da1f3328a496 130 FATFS_DIR dir;
Sissors 7:da1f3328a496 131 FRESULT res = f_opendir(&dir, name);
Sissors 7:da1f3328a496 132 if (res != 0) {
Sissors 7:da1f3328a496 133 return NULL;
Sissors 7:da1f3328a496 134 }
Sissors 7:da1f3328a496 135 return new FATDirHandle(dir);
Sissors 7:da1f3328a496 136 }
Sissors 7:da1f3328a496 137
Sissors 7:da1f3328a496 138 int FATFileSystem::mkdir(const char *name, mode_t mode) {
Sissors 7:da1f3328a496 139 FRESULT res = f_mkdir(name);
Sissors 7:da1f3328a496 140 return res == 0 ? 0 : -1;
Sissors 7:da1f3328a496 141 }
Sissors 7:da1f3328a496 142
Sissors 7:da1f3328a496 143 int FATFileSystem::mount() {
Sissors 7:da1f3328a496 144 FRESULT res = f_mount(_fsid, &_fs);
Sissors 7:da1f3328a496 145 return res == 0 ? 0 : -1;
Sissors 7:da1f3328a496 146 }
Sissors 7:da1f3328a496 147
Sissors 7:da1f3328a496 148 int FATFileSystem::unmount() {
Sissors 7:da1f3328a496 149 if (disk_sync())
Sissors 7:da1f3328a496 150 return -1;
Sissors 7:da1f3328a496 151 FRESULT res = f_mount(_fsid, NULL);
Sissors 7:da1f3328a496 152 return res == 0 ? 0 : -1;
Sissors 7:da1f3328a496 153 }