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:
6:15b73dae124e
Actually use count argument

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sissors 0:dabe3383ef23 1 #ifndef USBFILESYSTEM_H
Sissors 0:dabe3383ef23 2 #define USBFILESYSTEM_H
Sissors 0:dabe3383ef23 3
Sissors 0:dabe3383ef23 4 #include "FATFileSystem.h"
Sissors 0:dabe3383ef23 5 #include "USBMSD.h"
Sissors 0:dabe3383ef23 6 #include "FATFileHandle.h"
Sissors 0:dabe3383ef23 7
Sissors 0:dabe3383ef23 8 class FATFileSystem_ds : public FATFileSystem {
Sissors 0:dabe3383ef23 9 public:
Sissors 0:dabe3383ef23 10 FATFileSystem_ds(const char* n) : FATFileSystem(n) {};
Sissors 0:dabe3383ef23 11
Sissors 0:dabe3383ef23 12 protected:
Sissors 0:dabe3383ef23 13 virtual int disk_status_fat( void ) = 0;
Sissors 0:dabe3383ef23 14 virtual int disk_status( void ) {return disk_status_fat();}
Sissors 0:dabe3383ef23 15 };
Sissors 0:dabe3383ef23 16
Sissors 0:dabe3383ef23 17 class USBMSD_ds : public USBMSD {
Sissors 0:dabe3383ef23 18 public:
Sissors 0:dabe3383ef23 19 USBMSD_ds() {};
Sissors 0:dabe3383ef23 20
Sissors 0:dabe3383ef23 21 protected:
Sissors 0:dabe3383ef23 22 virtual int disk_status_msd( void ) = 0;
Sissors 0:dabe3383ef23 23 virtual int disk_status( void ) {return disk_status_msd();}
Sissors 0:dabe3383ef23 24 };
Sissors 0:dabe3383ef23 25
Sissors 0:dabe3383ef23 26 /** Class which combines FATFileSystem with USBMSD device
Sissors 0:dabe3383ef23 27 *
Sissors 0:dabe3383ef23 28 * The functions to be implemented by the child class are the same as
Sissors 0:dabe3383ef23 29 * those that have to be implemented when using FATFileSystem/USBMSD.
Sissors 0:dabe3383ef23 30 * However there are some caveats: _disk_status() and _disk_write MUST
Sissors 0:dabe3383ef23 31 * be named with the '_' in front of it. You are not allowed to have a
Sissors 0:dabe3383ef23 32 * function without the '_'. Those functions may not be inherited, but
Sissors 0:dabe3383ef23 33 * with this version of C++ I cannot prevent the child from doing so.
Sissors 0:dabe3383ef23 34 *
Sissors 0:dabe3383ef23 35 * Next the size of a disk sector must be 512 bytes. This is because
Sissors 0:dabe3383ef23 36 * FATFileSystem only accepts that. If disk_size is not implemented
Sissors 0:dabe3383ef23 37 * this is done automatically.
Sissors 0:dabe3383ef23 38 *
Sissors 0:dabe3383ef23 39 * What the library does is block write access locally when USB writes,
Sissors 0:dabe3383ef23 40 * and USB write access is blocked when with fopen a file is opened for
Sissors 0:dabe3383ef23 41 * write locally. This way they can't both write at the same time. Read
Sissors 0:dabe3383ef23 42 * access is not blocked.
Sissors 0:dabe3383ef23 43 *
Sissors 0:dabe3383ef23 44 * The final issue to take into account is caching: FATFileSystem will not
Sissors 0:dabe3383ef23 45 * re-open a file if you read twice the same data from it. So if USBMSD
Sissors 0:dabe3383ef23 46 * changed it, it will not show up different. If you close the file and
Sissors 0:dabe3383ef23 47 * call fopen again it will work. The USBMSD part has the
Sissors 0:dabe3383ef23 48 * same issue, but worse. Windows at least will only load everything once!
Sissors 0:dabe3383ef23 49 * So if you open a file, and then change it manually, you will never find
Sissors 0:dabe3383ef23 50 * out until the device is disconnected. If the disk is write protected
Sissors 0:dabe3383ef23 51 * it will not tell you so. It will write/delete what you want, only when
Sissors 0:dabe3383ef23 52 * you reconnect the device will it show it didn't actually do anything!
Sissors 0:dabe3383ef23 53 *
Sissors 0:dabe3383ef23 54 * See the program's wiki for more documentation!
Sissors 0:dabe3383ef23 55 */
Sissors 0:dabe3383ef23 56 class USBFileSystem : public FATFileSystem_ds, public USBMSD_ds {
Sissors 0:dabe3383ef23 57 public:
Sissors 0:dabe3383ef23 58 /**
Sissors 0:dabe3383ef23 59 * Constructor for USBFileSystem
Sissors 0:dabe3383ef23 60 *
Sissors 0:dabe3383ef23 61 * @param n - Name for the file system
Sissors 0:dabe3383ef23 62 */
Sissors 0:dabe3383ef23 63 USBFileSystem(const char* n);
Sissors 0:dabe3383ef23 64
Sissors 0:dabe3383ef23 65 /** Attach a function to be called when locally the filesystem is occupied/freed
Sissors 0:dabe3383ef23 66 *
Sissors 0:dabe3383ef23 67 * The function is called with 'true' as argument when it is freed, false when it is occupied
Sissors 0:dabe3383ef23 68 *
Sissors 0:dabe3383ef23 69 * @param function - Function to be called, must have void as return type, and a single boolean argument
Sissors 0:dabe3383ef23 70 */
Sissors 0:dabe3383ef23 71 void attachLocal(void (*function)(bool));
Sissors 0:dabe3383ef23 72
Sissors 0:dabe3383ef23 73 /** Attach a function to be called when USB occupies/frees the filesystem
Sissors 0:dabe3383ef23 74 *
Sissors 0:dabe3383ef23 75 * The function is called with 'true' as argument when it is freed, false when it is occupied
Sissors 0:dabe3383ef23 76 *
Sissors 0:dabe3383ef23 77 * @param function - Function to be called, must have void as return type, and a single boolean argument
Sissors 0:dabe3383ef23 78 */
Sissors 0:dabe3383ef23 79 void attachUSB(void (*function)(bool));
Sissors 0:dabe3383ef23 80
Sissors 0:dabe3383ef23 81 /** Check if locally files are opened for write
Sissors 0:dabe3383ef23 82 *
Sissors 0:dabe3383ef23 83 * @return - true if none are opened for write, false otherwise
Sissors 0:dabe3383ef23 84 */
Sissors 0:dabe3383ef23 85 bool localSafe( void );
Sissors 0:dabe3383ef23 86
Sissors 0:dabe3383ef23 87 /** Check if via USB files files are being written
Sissors 0:dabe3383ef23 88 *
Sissors 0:dabe3383ef23 89 * @return - true if none are being written, false otherwise
Sissors 0:dabe3383ef23 90 */
Sissors 0:dabe3383ef23 91 bool usbSafe( void );
Sissors 0:dabe3383ef23 92
Sissors 1:4ba08d11e36e 93 /** Sets the USB mode
Sissors 1:4ba08d11e36e 94 *
Sissors 2:9af05743d551 95 * Argument = 0: USB is write protected when not available.
Sissors 2:9af05743d551 96 * Argument = 1: USB is disconnected when not available (default).
Sissors 1:4ba08d11e36e 97 *
Sissors 1:4ba08d11e36e 98 * @param mode - USB safety mode
Sissors 1:4ba08d11e36e 99 */
Sissors 1:4ba08d11e36e 100 void usbMode( int mode );
Sissors 1:4ba08d11e36e 101
Sissors 0:dabe3383ef23 102
Sissors 0:dabe3383ef23 103 protected:
Sissors 0:dabe3383ef23 104 //Functions to be implemented by child:
Sissors 0:dabe3383ef23 105 virtual int disk_initialize() { return 0; }
Sissors 0:dabe3383ef23 106 virtual int _disk_status() { return 0; }
Sissors 6:15b73dae124e 107 virtual int disk_read(uint8_t * buffer, uint64_t sector, uint8_t count) { return 0;}
Sissors 6:15b73dae124e 108 virtual int _disk_write(const uint8_t * buffer, uint64_t sector, uint8_t count) = 0;
Sissors 0:dabe3383ef23 109 virtual int disk_sync() { return 0; }
Sissors 0:dabe3383ef23 110 virtual uint64_t disk_sectors() = 0;
Sissors 0:dabe3383ef23 111 virtual uint64_t disk_size() {return 512 * disk_sectors();}
Sissors 0:dabe3383ef23 112
Sissors 0:dabe3383ef23 113 //Not to be implemented by child:
Sissors 0:dabe3383ef23 114 virtual FileHandle* open(const char* name, int flags);
Sissors 0:dabe3383ef23 115 void localOpen( bool open );
Sissors 0:dabe3383ef23 116 void usbFree( void );
Sissors 0:dabe3383ef23 117
Sissors 0:dabe3383ef23 118 private:
Sissors 0:dabe3383ef23 119 virtual int disk_status_fat(void);
Sissors 0:dabe3383ef23 120 virtual int disk_status_msd(void);
Sissors 6:15b73dae124e 121 virtual int disk_write(const uint8_t * buffer, uint64_t sector, uint8_t count);
Sissors 0:dabe3383ef23 122
Sissors 0:dabe3383ef23 123 int local_count;
Sissors 1:4ba08d11e36e 124 int usbmode;
Sissors 0:dabe3383ef23 125 Timeout usb_write;
Sissors 0:dabe3383ef23 126 bool usbfree;
Sissors 0:dabe3383ef23 127
Sissors 0:dabe3383ef23 128 void (*localFunction)(bool);
Sissors 0:dabe3383ef23 129 void (*usbFunction)(bool);
Sissors 0:dabe3383ef23 130
Sissors 0:dabe3383ef23 131 friend class USBFileHandle;
Sissors 0:dabe3383ef23 132
Sissors 0:dabe3383ef23 133 };
Sissors 0:dabe3383ef23 134
Sissors 0:dabe3383ef23 135
Sissors 0:dabe3383ef23 136 class USBFileHandle : public FATFileHandle {
Sissors 0:dabe3383ef23 137 public:
Sissors 0:dabe3383ef23 138 USBFileHandle(FIL fh, USBFileSystem *p, bool write) : FATFileHandle(fh) {
Sissors 0:dabe3383ef23 139 _p = p;
Sissors 0:dabe3383ef23 140 _write = write;
Sissors 0:dabe3383ef23 141 }
Sissors 0:dabe3383ef23 142
Sissors 0:dabe3383ef23 143 protected:
Sissors 0:dabe3383ef23 144 USBFileSystem *_p;
Sissors 0:dabe3383ef23 145 bool _write;
Sissors 0:dabe3383ef23 146
Sissors 0:dabe3383ef23 147 virtual int close() {
Sissors 0:dabe3383ef23 148 int retval = FATFileHandle::close();
Sissors 0:dabe3383ef23 149 if (_write)
Sissors 0:dabe3383ef23 150 _p->localOpen(false);
Sissors 0:dabe3383ef23 151 return retval;
Sissors 0:dabe3383ef23 152 }
Sissors 0:dabe3383ef23 153 };
Sissors 0:dabe3383ef23 154
Sissors 0:dabe3383ef23 155
Sissors 0:dabe3383ef23 156
Sissors 0:dabe3383ef23 157
Sissors 0:dabe3383ef23 158
Sissors 0:dabe3383ef23 159 #endif