Skip to content

Commit

Permalink
Added asyncfat support for FAT filesystem
Browse files Browse the repository at this point in the history
Filesystem not yet integrated into system shell.
  • Loading branch information
sean-lawless committed Mar 18, 2024
1 parent 2e80edc commit d507f05
Show file tree
Hide file tree
Showing 15 changed files with 4,442 additions and 15 deletions.
3 changes: 3 additions & 0 deletions Lab20 Mass Storage/applications/console/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ APP = ../../boards/rpi/app.o \
../../boards/peripherals/ethernet/lan78xx.o \
../../boards/peripherals/uart/16550.o \
../../boards/peripherals/uart/16C650.o \
../../fat/asyncfatfs.o \
../../fat/fat_standard.o \
../../fat/sdcard.o \
../../system/character.o \
../../system/console.o \
../../system/os.o \
Expand Down
1 change: 1 addition & 0 deletions Lab20 Mass Storage/applications/console/configure.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
#define ENABLE_USB_ETHER (TRUE && ENABLE_USB) /* enable Ethernet */
#define ENABLE_USB_STORAGE (TRUE && ENABLE_USB) /*enable Mass Storage*/
#define ENABLE_USB_TASK (FALSE && ENABLE_USB) /* USB intr task */
#define ENABLE_FAT (TRUE && ENABLE_USB_STORAGE) /* file system*/

/* DO NOT EDIT BELOW : Derived configurations */
#define ENABLE_ETHER ENABLE_USB_ETHER /* enable Ethernet */
Expand Down
14 changes: 11 additions & 3 deletions Lab20 Mass Storage/applications/console/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ i8 MountedPartition = 0;
i8 PartitionToMount = -1;
struct partition partitions[4];

void read_sector_callback(u8 *buffer, int buffLen)
void read_sector_callback(u8 *buffer, int buffLen, void *unused)
{
int i;

Expand Down Expand Up @@ -222,12 +222,20 @@ int MountFilesystem(char *command)
else
PartitionToMount = 0;

// Create the polling task and initialize the FAT file system
#if ENABLE_OS
TaskNew(MAX_TASKS - 4, FatPoll, NULL);
#endif
FatInit();

/*
// Seek to first block, the MBR
MassStorageSeek(0);
// Read the Master Boot Record (MBR)
if (MassStorageRead(ReadSector, 512, read_sector_callback) <= 0)
if (MassStorageRead(ReadSector, 512, read_sector_callback, NULL) <= 0)
puts("MassStorageRead failed");
*/
}
else
puts("USB not initialized");
Expand Down Expand Up @@ -257,7 +265,7 @@ int ReadFilesystem(const char *command)
}

// Read the sector
if (MassStorageRead(ReadSector, 512, read_sector_callback) <= 0)
if (MassStorageRead(ReadSector, 512, read_sector_callback, NULL) <= 0)
puts("MassStorageRead failed");
}
else
Expand Down
21 changes: 21 additions & 0 deletions Lab20 Mass Storage/fat/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2015 Nicholas Sherlock

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
77 changes: 77 additions & 0 deletions Lab20 Mass Storage/fat/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
## AsyncFatFS

When paired with a simple asynchronous read-block/write-block API for an SD card, this library provides an
asynchronous FAT16/FAT32 filesystem for embedded devices. Filesystem operations do not wait for the SD card
to become ready, but instead either provide a callback to notify you of operation completion, or return a
status code that indicates that the operation should be retried later.

A special optional feature of this filesystem is a high-speed contiguous append file mode, provided by the "freefile"
support. In this mode, the largest contiguous free block on the volume is pre-allocated during filesystem
initialisation into a file called "freespac.e". One file can be created which slowly grows from the beginning
of this contiguous region, stealing the first part of the freefile's space. Because the freefile is contiguous,
the FAT entries for the file need never be read. This saves on buffer space and reduces latency during file
extend operations.

### Implementing AsyncFatFS

Compile and link your app against `lib/asyncfatfs.c` and `lib/fat_standard.c`.

If you will not be using the "freefile" feature, remove the define "AFATFS_USE_FREEFILE" in `asyncfatfs.c`.

The header `lib/sdcard.h` describes the functions that you must provide in your app to provide the necessary SD card
read/write primitives, the minimum are:

```cpp
/**
* Read the 512-byte block with the given index into the given 512-byte buffer.
*
* When the read completes, your callback will be called. If the read was successful, the buffer pointer will be the
* same buffer you originally passed in, otherwise the buffer will be set to NULL.
*
* You must keep the pointer to the buffer valid until the operation completes!
*
* Returns:
* true - The operation was successfully queued for later completion, your callback will be called later
* false - The operation could not be started due to the card being busy (try again later).
*/
bool sdcard_readBlock(uint32_t blockIndex, uint8_t *buffer, sdcard_operationCompleteCallback_c callback, uint32_t callbackData);

/**
* Write the 512-byte block from the given buffer into the block with the given index.
*
* If the write does not complete immediately, your callback will be called later. If the write was successful, the
* buffer pointer will be the same buffer you originally passed in, otherwise the buffer will be set to NULL.
*
* Returns:
* SDCARD_OPERATION_IN_PROGRESS - Your buffer is currently being transmitted to the card and your callback will be
* called later to report the completion. The buffer pointer must remain valid until
* that time.
* SDCARD_OPERATION_SUCCESS - Your buffer has been transmitted to the card now.
* SDCARD_OPERATION_BUSY - The card is already busy and cannot accept your write
* SDCARD_OPERATION_FAILURE - Your write was rejected by the card, card will be reset
*/
sdcardOperationStatus_e sdcard_writeBlock(uint32_t blockIndex, uint8_t *buffer, sdcard_operationCompleteCallback_c callback, uint32_t callbackData);

/**
* Will be called by afatfs_poll() periodically for the SD card to perform in-progress transfers.
*
* Returns true if the card is ready to accept new commands.
*/
bool sdcard_poll();
```
The header `asyncfatfs.h` lists the filesystem functions that AsyncFatFS provides for you. The documentation for these
is inline in `asyncfatfs.c`.
To start up the filesystem, first call `afatfs_init()`.
You must periodically call `afatfs_poll()` so that the filesystem can perform any queued work. This will in turn call
`sdcard_poll()` for you, which you can use to perform any pending transactions with the SD card.
You can use the testcases in the `test/` directory as a guide to how to use the filesystem. AsyncFatFS is also used in
Cleanflight / Betaflight's "blackbox" logging system: [filesystem consumer code](https://github.com/betaflight/betaflight/blob/master/src/main/blackbox/blackbox_io.c),
[SDCard SPI driver code](https://github.com/betaflight/betaflight/blob/master/src/main/drivers/sdcard_spi.c).
You'll notice that since most filesystem operations will fail and ask you to retry when the card is busy, it becomes
natural to call it using a state-machine from your app's main loop - where you only advance to the next state once the
current operation succeeds, calling afatfs_poll() in-between so that the filesystem can complete its queued tasks.
Loading

0 comments on commit d507f05

Please sign in to comment.