Skip to content
Snippets Groups Projects
Commit 5cd2ff0c authored by swym's avatar swym
Browse files

feat(fatfs): global FLASH lock

- implement de-initialization
- wrap filesystem operations in semaphore

- Introduce EpicFileSystem object and move epic_file_FOO(...) imlementations into
  efs_FOO(EpicFileSystem*, ...) functions.
- epic_file_FOO(...) functions are now wrappers around the _fs_ functions, but lock and unlock the global filesystem object before&after calls.
  This way, all efs_ functions can assume that the necessary lock has been acquired.
- libff: don't use FF_FS_REENTRANT, our own FS lock is enough
parent b1f671d5
Branches
No related tags found
No related merge requests found
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "modules/modules.h" #include "modules/modules.h"
#include "modules/log.h" #include "modules/log.h"
#include "modules/stream.h" #include "modules/stream.h"
#include "modules/filesystem.h"
#include "api/interrupt-sender.h" #include "api/interrupt-sender.h"
#include <Heart.h> #include <Heart.h>
......
/*
* support routines for FatFs
*/
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <ff.h>
#include <FreeRTOS.h>
#include <semphr.h>
#include "modules.h"
#include "epicardium.h"
#ifndef EPIC_FAT_STATIC_SEMAPHORE
#define EPIC_FAT_STATIC_SEMAPHORE 0
#endif
static const TCHAR *rcstrings =
_T("OK\0DISK_ERR\0INT_ERR\0NOT_READY\0NO_FILE\0NO_PATH\0INVALID_NAME\0")
_T("DENIED\0EXIST\0INVALID_OBJECT\0WRITE_PROTECTED\0INVALID_DRIVE\0")
_T("NOT_ENABLED\0NO_FILESYSTEM\0MKFS_ABORTED\0TIMEOUT\0LOCKED\0")
_T("NOT_ENOUGH_CORE\0TOO_MANY_OPEN_FILES\0INVALID_PARAMETER\0");
static bool mount(void);
DIR dir;
FATFS FatFs;
#if (EPIC_FAT_STATIC_SEMAPHORE == 1)
StaticSemaphore_t xSemaphoreBuffer;
#endif
static volatile bool s_fatfs_initiaized = false;
void fatfs_init()
{
if (mount()) {
s_fatfs_initiaized = true;
printf("FatFs mounted\n");
}
}
const char *f_get_rc_string(FRESULT rc)
{
FRESULT i;
const char *p = rcstrings;
for (i = 0; i != rc && *p; i++) {
while (*p++)
;
}
return p;
}
static bool mount()
{
FRESULT res;
res = f_mount(&FatFs, "/", 0);
if (res != FR_OK) {
printf("f_mount error %s\n", f_get_rc_string(res));
return false;
}
res = f_opendir(&dir, "0:");
if (res != FR_OK) {
printf("f_opendir error %s\n", f_get_rc_string(res));
return false;
}
return true;
}
/*------------------------------------------------------------------------*/
/* Create a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to create a new
/ synchronization object for the volume, such as semaphore and mutex.
/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR.
*/
/*
* Return value:
* - 1: Function succeeded
* - 0: Could not create the sync object
*/
int ff_cre_syncobj(BYTE vol, FF_SYNC_t *sobj)
{
#if (EPIC_FAT_STATIC_SEMAPHORE == 1)
*sobj = xSemaphoreCreateMutexStatic(&xSemaphoreBuffer);
#else
*sobj = xSemaphoreCreateMutex();
#endif //EPIC_FAT_STATIC_SEMAPHORE
return (int)(*sobj != NULL);
}
/*------------------------------------------------------------------------*/
/* Delete a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to delete a synchronization
/ object that created with ff_cre_syncobj() function. When a 0 is returned,
/ the f_mount() function fails with FR_INT_ERR.
*/
/*
* Return value:
* - 1: Function succeeded
* - 0: Could not delete due to an error
*/
int ff_del_syncobj(FF_SYNC_t sobj)
{
/* FreeRTOS */
vSemaphoreDelete(sobj);
return 1;
}
/*------------------------------------------------------------------------*/
/* Request Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on entering file functions to lock the volume.
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
*/
/*
* Return value:
* - 1: Got a grant to access the volume
* - 0: Could not get a grant
*/
int ff_req_grant(FF_SYNC_t sobj)
{
/* FreeRTOS */
return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE);
}
/*------------------------------------------------------------------------*/
/* Release Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leaving file functions to unlock the volume.
*/
void ff_rel_grant(FF_SYNC_t sobj)
{
/* FreeRTOS */
xSemaphoreGive(sobj);
}
#ifndef EPICARDIUM_MODULE_FILESYSTEM_INCLUDED
#define EPICARDIUM_MODULE_FILESYSTEM_INCLUDED
/* ---------- FAT fs ------------------------------------------------------ */
#include <stdbool.h>
#include "epicardium.h"
/* Number of bits to use for indexing into our internal pool of files/directories
* This indirectly specifies the size of the pool as 1^EPIC_FAT_FD_INDEX_BITS
* Increase if number of open file descriptors is not enough, but be aware of
* memory usage of the pool!
*/
#define EPIC_FAT_FD_INDEX_BITS 6
#define EPIC_FAT_STATIC_SEMAPHORE 1
#define EPIC_FAT_MAX_OPENED (1 << (EPIC_FAT_FD_INDEX_BITS))
typedef struct EpicFileSystem EpicFileSystem;
/**
* module initialization - to be called once at startup before any FreeRTOS tasks
* have been started
*
* calls fatfs_attach
*/
void fatfs_init(void);
/**
* initialize and mount the FLASH storage
*/
int fatfs_attach(void);
/** close all opened FDs, sync and deinitialize FLASH layer */
void fatfs_detach(void);
/**
* lock global filesystem
*
* Upon successful return, the filesystem has to be re-locked with epic_fs_unlock_global
* In case of error, the filesystem will be left in a locked state.
*/
bool efs_lock_global(EpicFileSystem** fs, int* ec);
void efs_unlock_global(EpicFileSystem* fs);
#endif//EPICARDIUM_MODULE_FILESYSTEM_INCLUDED
/*
* Implementation of efs_ API functions for a FatFS specific
* EpicFileSystem
*/
#include <errno.h> #include <errno.h>
#include <stddef.h> #include <stddef.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ff.h> #include <ff.h>
#include <diskio.h>
#include <FreeRTOS.h>
#include <semphr.h>
#include "modules.h" #include "modules/filesystem.h"
#include "epicardium.h" #include "epicardium.h"
#include "card10.h"
#include "modules/log.h"
#define SSLOG_INFO(...) LOG_INFO("fatfs", __VA_ARGS__)
#define SSLOG_ERR(...) LOG_ERR("fatfs", __VA_ARGS__)
#ifndef EPIC_FAT_STATIC_SEMAPHORE
#define EPIC_FAT_STATIC_SEMAPHORE 0
#endif
/* clang-format off */
#define EPIC_FAT_FD_GENERATION_BITS (31 - (EPIC_FAT_FD_INDEX_BITS)) #define EPIC_FAT_FD_GENERATION_BITS (31 - (EPIC_FAT_FD_INDEX_BITS))
#define EPIC_FAT_MAX_OPENED (1 << (EPIC_FAT_FD_INDEX_BITS))
#define EPIC_FAT_FD_INDEX_MASK (uint32_t)((1u << EPIC_FAT_FD_INDEX_BITS) - 1) #define EPIC_FAT_FD_INDEX_MASK (uint32_t)((1u << EPIC_FAT_FD_INDEX_BITS) - 1)
#define EPIC_FAT_FD_INDEX(fd) ((uint32_t)(fd)&EPIC_FAT_FD_INDEX_MASK) #define EPIC_FAT_FD_INDEX(fd) ((uint32_t)(fd)&EPIC_FAT_FD_INDEX_MASK)
#define EPIC_FAT_FD_GENERATION(fd) ((uint32_t)(fd) >> EPIC_FAT_FD_INDEX_BITS) #define EPIC_FAT_FD_GENERATION(fd) ((uint32_t)(fd) >> EPIC_FAT_FD_INDEX_BITS)
#define EPIC_FAT_FD_MAX_GENERATION \ #define EPIC_FAT_FD_MAX_GENERATION (uint32_t)((1u << EPIC_FAT_FD_GENERATION_BITS) - 1)
(uint32_t)((1u << EPIC_FAT_FD_GENERATION_BITS) - 1) #define EPIC_FAT_FD(idx, gen) (int)(((uint32_t)(gen) << EPIC_FAT_FD_INDEX_BITS) \
#define EPIC_FAT_FD(idx, gen) \ | ((uint32_t)(idx)&EPIC_FAT_FD_INDEX_MASK))
(int)(((uint32_t)(gen) << EPIC_FAT_FD_INDEX_BITS) | \ /* clang-format on */
((uint32_t)(idx)&EPIC_FAT_FD_INDEX_MASK))
// this table converts from FRESULT to POSIX errno
const int fresult_to_errno_table[20] = {
[FR_OK] = 0,
[FR_DISK_ERR] = EIO,
[FR_INT_ERR] = EIO,
[FR_NOT_READY] = EBUSY,
[FR_NO_FILE] = ENOENT,
[FR_NO_PATH] = ENOENT,
[FR_INVALID_NAME] = EINVAL,
[FR_DENIED] = EACCES,
[FR_EXIST] = EEXIST,
[FR_INVALID_OBJECT] = EINVAL,
[FR_WRITE_PROTECTED] = EROFS,
[FR_INVALID_DRIVE] = ENODEV,
[FR_NOT_ENABLED] = ENODEV,
[FR_NO_FILESYSTEM] = ENODEV,
[FR_MKFS_ABORTED] = EIO,
[FR_TIMEOUT] = EIO,
[FR_LOCKED] = EIO,
[FR_NOT_ENOUGH_CORE] = ENOMEM,
[FR_TOO_MANY_OPEN_FILES] = EMFILE,
[FR_INVALID_PARAMETER] = EINVAL,
};
struct FatObject { struct FatObject {
uint32_t generation; uint32_t generation;
...@@ -52,34 +48,192 @@ struct FatObject { ...@@ -52,34 +48,192 @@ struct FatObject {
}; };
}; };
static int struct EpicFileSystem {
get_fat_object(int i, enum epic_stat_type expected, struct FatObject **res); struct FatObject pool[EPIC_FAT_MAX_OPENED];
uint32_t generationCount;
bool initialized;
FATFS FatFs;
};
// this table converts from FRESULT to POSIX errno
static const int s_libffToErrno[20];
static const char *f_get_rc_string(FRESULT rc);
static bool globalLockAccquire();
static void globalLockRelease();
static void efs_close_all(EpicFileSystem *fs);
static bool efs_get_opened(
EpicFileSystem *fs,
int i,
enum epic_stat_type expected,
struct FatObject **res,
int *rc
);
static EpicFileSystem s_globalFileSystem;
static struct FatObject s_openedObjects[EPIC_FAT_MAX_OPENED]; #if (EPIC_FAT_STATIC_SEMAPHORE == 1)
static uint32_t s_fatfs_generationCount = 1; static StaticSemaphore_t s_globalLockBuffer;
#endif
int get_fat_object(int fd, enum epic_stat_type expected, struct FatObject **res) static SemaphoreHandle_t s_globalLock = NULL;
bool globalLockAccquire()
{ {
uint32_t index = EPIC_FAT_FD_INDEX(fd); return (int)(xSemaphoreTake(s_globalLock, FF_FS_TIMEOUT) == pdTRUE);
uint32_t generation = EPIC_FAT_FD_GENERATION(fd); }
if (index >= EPIC_FAT_MAX_OPENED) {
*res = NULL; void globalLockRelease()
return EBADF; {
xSemaphoreGive(s_globalLock);
}
void fatfs_init()
{
static volatile bool s_initCalled = false;
//this has to be called vefore any tasks have been started!
// ...not 100% water-tight though, since tick count might be zero even after vTaskStartScheduler
// has been called...
assert(xTaskGetTickCount() == configINITIAL_TICK_COUNT);
assert(!s_initCalled);
s_initCalled = true;
#if (EPIC_FAT_STATIC_SEMAPHORE == 1)
s_globalLock = xSemaphoreCreateMutexStatic(&s_globalLockBuffer);
#else
s_globalLock = xSemaphoreCreateMutex();
#endif
fatfs_attach();
}
/*
* NOTE about attach/detach:
*
* while in detach, we're calling diskio_deinitialize (a function that is
* originally not present in libff's diskio.h), we do not need to call
* diskio_initialize in attach, since it will implicitly be called by
* any f_ operation, via libff's find_volume for volumes that have not
* been mounted yet.
*
*/
int fatfs_attach()
{
FRESULT ff_res;
int rc = 0;
if (globalLockAccquire()) {
EpicFileSystem *fs = &s_globalFileSystem;
if (!fs->initialized) {
ff_res = f_mount(&fs->FatFs, "/", 0);
if (ff_res == FR_OK) {
fs->initialized = true;
SSLOG_INFO("FatFs mounted\n");
} else {
SSLOG_ERR(
"f_mount error %s\n",
f_get_rc_string(ff_res)
);
rc = -s_libffToErrno[ff_res];
}
}
globalLockRelease();
} else {
SSLOG_ERR("Failed to lock\n");
}
return rc;
}
void fatfs_detach()
{
FRESULT ff_res;
int rc;
EpicFileSystem *fs;
if (efs_lock_global(&fs, &rc)) {
efs_close_all(fs);
//unmount by passing NULL as fs object, will destroy our sync object via ff_del_syncobj
ff_res = f_mount(NULL, "/", 0);
if (ff_res != FR_OK) {
SSLOG_ERR(
"f_mount (unmount) error %s\n",
f_get_rc_string(ff_res)
);
}
fs->initialized = false;
disk_deinitialize();
SSLOG_INFO("detached\n");
efs_unlock_global(fs);
}
}
const char *f_get_rc_string(FRESULT rc)
{
static const TCHAR *rcstrings =
_T("OK\0DISK_ERR\0INT_ERR\0NOT_READY\0NO_FILE\0NO_PATH\0INVALID_NAME\0")
_T("DENIED\0EXIST\0INVALID_OBJECT\0WRITE_PROTECTED\0INVALID_DRIVE\0")
_T("NOT_ENABLED\0NO_FILESYSTEM\0MKFS_ABORTED\0TIMEOUT\0LOCKED\0")
_T("NOT_ENOUGH_CORE\0TOO_MANY_OPEN_FILES\0INVALID_PARAMETER\0");
FRESULT i;
const char *p = rcstrings;
for (i = 0; i != rc && *p; i++) {
while (*p++)
;
}
return p;
}
bool efs_lock_global(EpicFileSystem **fs, int *rc)
{
*fs = NULL;
if (!globalLockAccquire()) {
*rc = -EBUSY;
return false;
}
if (!s_globalFileSystem.initialized) {
globalLockRelease();
*rc = -ENODEV;
return false;
}
*fs = &s_globalFileSystem;
*rc = 0;
return true;
} }
if (generation >= EPIC_FAT_FD_MAX_GENERATION) {
*res = NULL; void efs_unlock_global(EpicFileSystem *fs)
return EBADF; {
(void)fs;
globalLockRelease();
} }
if (s_openedObjects[index].type != expected) {
*res = NULL; bool efs_get_opened(
return EBADF; EpicFileSystem *fs,
int fd,
enum epic_stat_type expected,
struct FatObject **obj,
int *rc
) {
uint32_t index = EPIC_FAT_FD_INDEX(fd);
uint32_t generation = EPIC_FAT_FD_GENERATION(fd);
*obj = NULL;
*rc = -EBADF;
if (index >= EPIC_FAT_MAX_OPENED ||
generation >= EPIC_FAT_FD_MAX_GENERATION) {
return false;
} }
if (s_openedObjects[index].generation != generation) { if (fs->pool[index].type != expected ||
*res = NULL; fs->pool[index].generation != generation) {
return EBADF; return false;
} }
*res = &s_openedObjects[index];
return 0; *obj = &fs->pool[index];
*rc = 0;
return true;
} }
/* here we're trying to mirror glibc's behaviour: /* here we're trying to mirror glibc's behaviour:
...@@ -126,7 +280,7 @@ static inline bool parse_mode(const char *mstring, int *mode) ...@@ -126,7 +280,7 @@ static inline bool parse_mode(const char *mstring, int *mode)
return true; return true;
} }
int epic_file_open(const char *filename, const char *modeString) int efs_open(EpicFileSystem *fs, const char *filename, const char *modeString)
{ {
struct FatObject *o = NULL; struct FatObject *o = NULL;
uint32_t index, generation; uint32_t index, generation;
...@@ -135,18 +289,19 @@ int epic_file_open(const char *filename, const char *modeString) ...@@ -135,18 +289,19 @@ int epic_file_open(const char *filename, const char *modeString)
//find free object to use //find free object to use
for (index = 0; index < EPIC_FAT_MAX_OPENED; ++index) { for (index = 0; index < EPIC_FAT_MAX_OPENED; ++index) {
if (s_openedObjects[index].type == EPICSTAT_NONE) { if (fs->pool[index].type == EPICSTAT_NONE) {
break; break;
} }
} }
if (index == EPIC_FAT_MAX_OPENED) { if (index == EPIC_FAT_MAX_OPENED) {
return -fresult_to_errno_table[FR_TOO_MANY_OPEN_FILES]; return -s_libffToErrno[FR_TOO_MANY_OPEN_FILES];
} }
generation = s_fatfs_generationCount++;
generation = fs->generationCount++;
if (generation == EPIC_FAT_FD_MAX_GENERATION) { if (generation == EPIC_FAT_FD_MAX_GENERATION) {
s_fatfs_generationCount = 1; fs->generationCount = 1;
} }
o = &s_openedObjects[index]; o = &fs->pool[index];
if (!parse_mode(modeString, &mode)) { if (!parse_mode(modeString, &mode)) {
return -EINVAL; return -EINVAL;
...@@ -154,8 +309,9 @@ int epic_file_open(const char *filename, const char *modeString) ...@@ -154,8 +309,9 @@ int epic_file_open(const char *filename, const char *modeString)
res = f_open(&o->file, filename, mode); res = f_open(&o->file, filename, mode);
if (res != FR_OK) { if (res != FR_OK) {
return -fresult_to_errno_table[res]; return -s_libffToErrno[res];
} }
o->type = EPICSTAT_FILE; o->type = EPICSTAT_FILE;
o->generation = generation; o->generation = generation;
...@@ -167,86 +323,93 @@ int epic_file_open(const char *filename, const char *modeString) ...@@ -167,86 +323,93 @@ int epic_file_open(const char *filename, const char *modeString)
return EPIC_FAT_FD(index, generation); return EPIC_FAT_FD(index, generation);
} }
int epic_file_close(int fd) int efs_close(EpicFileSystem *fs, int fd)
{ {
int res; int res;
struct FatObject *o; struct FatObject *o;
res = get_fat_object(fd, EPICSTAT_FILE, &o); if (efs_get_opened(fs, fd, EPICSTAT_FILE, &o, &res)) {
if (res) {
return -res;
}
res = f_close(&o->file); res = f_close(&o->file);
if (res != FR_OK) { if (res != FR_OK) {
return -fresult_to_errno_table[res]; return -s_libffToErrno[res];
} }
o->type = EPICSTAT_NONE; o->type = EPICSTAT_NONE;
o->generation = 0; o->generation = 0;
return 0; }
return res;
}
void efs_close_all(EpicFileSystem *fs)
{
for (int i = 0; i < EPIC_FAT_MAX_OPENED; ++i) {
switch (fs->pool[i].type) {
case EPICSTAT_FILE:
f_close(&fs->pool[i].file);
break;
case EPICSTAT_DIR:
//NYI
break;
case EPICSTAT_NONE:
break;
}
fs->pool[i].type = EPICSTAT_NONE;
fs->pool[i].generation = 0;
}
} }
int epic_file_read(int fd, void *buf, size_t nbytes) int efs_read(EpicFileSystem *fs, int fd, void *buf, size_t nbytes)
{ {
unsigned int nread = 0; unsigned int nread = 0;
int res; int res;
struct FatObject *o; struct FatObject *o;
res = get_fat_object(fd, EPICSTAT_FILE, &o); if (efs_get_opened(fs, fd, EPICSTAT_FILE, &o, &res)) {
if (res) {
return -res;
}
res = f_read(&o->file, buf, nbytes, &nread); res = f_read(&o->file, buf, nbytes, &nread);
if (res != FR_OK) { if (res != FR_OK) {
return -fresult_to_errno_table[res]; return -s_libffToErrno[res];
}
res = (int)nread;
} }
return (int)nread; return res;
} }
int epic_file_write(int fd, const void *buf, size_t nbytes) int efs_write(EpicFileSystem *fs, int fd, const void *buf, size_t nbytes)
{ {
unsigned int nwritten = 0; unsigned int nwritten = 0;
int res; int res;
struct FatObject *o; struct FatObject *o;
res = get_fat_object(fd, EPICSTAT_FILE, &o); if (efs_get_opened(fs, fd, EPICSTAT_FILE, &o, &res)) {
if (res) {
return -res;
}
res = f_write(&o->file, buf, nbytes, &nwritten); res = f_write(&o->file, buf, nbytes, &nwritten);
if (res != FR_OK) { if (res != FR_OK) {
return -fresult_to_errno_table[res]; res = -s_libffToErrno[res];
} else {
res = (int)nwritten;
} }
}
return (int)nwritten; return res;
} }
int epic_file_flush(int fd) int efs_flush(EpicFileSystem *fs, int fd)
{ {
int res; int res = 0;
struct FatObject *o; struct FatObject *o;
res = get_fat_object(fd, EPICSTAT_FILE, &o); if (efs_get_opened(fs, fd, EPICSTAT_FILE, &o, &res)) {
if (res) {
return -res;
}
res = f_sync(&o->file); res = f_sync(&o->file);
if (res != FR_OK) { if (res != FR_OK) {
return -fresult_to_errno_table[res]; res = -s_libffToErrno[res];
}
} }
return 0; return res;
} }
int epic_file_seek(int fd, long offset, int whence) int efs_seek(EpicFileSystem *fs, int fd, long offset, int whence)
{ {
int res; int res = 0;
struct FatObject *o; struct FatObject *o;
res = get_fat_object(fd, EPICSTAT_FILE, &o); if (efs_get_opened(fs, fd, EPICSTAT_FILE, &o, &res)) {
if (res) {
return -res;
}
switch (whence) { switch (whence) {
case SEEK_SET: case SEEK_SET:
res = f_lseek(&o->file, offset); res = f_lseek(&o->file, offset);
...@@ -262,39 +425,56 @@ int epic_file_seek(int fd, long offset, int whence) ...@@ -262,39 +425,56 @@ int epic_file_seek(int fd, long offset, int whence)
default: default:
return -EINVAL; return -EINVAL;
} }
if (res != FR_OK) { res = -s_libffToErrno[res];
return -fresult_to_errno_table[res];
} }
return res;
return 0;
} }
int epic_file_tell(int fd) int efs_tell(EpicFileSystem *fs, int fd)
{ {
int res; int res;
struct FatObject *o; struct FatObject *o;
res = get_fat_object(fd, EPICSTAT_FILE, &o); if (efs_get_opened(fs, fd, EPICSTAT_FILE, &o, &res)) {
if (res) {
return -res;
}
//f_tell simply accesses fp->fptr so no errors are expected - return directly //f_tell simply accesses fp->fptr so no errors are expected - return directly
return f_tell(&o->file); res = f_tell(&o->file);
}
return res;
} }
int epic_file_stat(const char *filename, struct epic_stat *stat) int efs_stat(EpicFileSystem *fs, const char *filename, struct epic_stat *stat)
{ {
int res; int res = 0;
FILINFO finfo; FILINFO finfo;
res = f_stat(filename, &finfo); res = f_stat(filename, &finfo);
if (res != FR_OK) { if (res == 0) {
return -fresult_to_errno_table[res];
}
if (finfo.fattrib & AM_DIR) { if (finfo.fattrib & AM_DIR) {
stat->type = EPICSTAT_DIR; stat->type = EPICSTAT_DIR;
} else { } else {
stat->type = EPICSTAT_FILE; stat->type = EPICSTAT_FILE;
} }
return 0;
} }
return -s_libffToErrno[res];
}
static const int s_libffToErrno[20] = {
[FR_OK] = 0,
[FR_DISK_ERR] = EIO,
[FR_INT_ERR] = EIO,
[FR_NOT_READY] = EBUSY,
[FR_NO_FILE] = ENOENT,
[FR_NO_PATH] = ENOENT,
[FR_INVALID_NAME] = EINVAL,
[FR_DENIED] = EACCES,
[FR_EXIST] = EEXIST,
[FR_INVALID_OBJECT] = EINVAL,
[FR_WRITE_PROTECTED] = EROFS,
[FR_INVALID_DRIVE] = ENODEV,
[FR_NOT_ENABLED] = ENODEV,
[FR_NO_FILESYSTEM] = ENODEV,
[FR_MKFS_ABORTED] = EIO,
[FR_TIMEOUT] = EIO,
[FR_LOCKED] = EIO,
[FR_NOT_ENOUGH_CORE] = ENOMEM,
[FR_TOO_MANY_OPEN_FILES] = EMFILE,
[FR_INVALID_PARAMETER] = EINVAL,
};
/**
* Implemention of the epicardium epic_file_ api that operates on
* the global EpicFileSystem instance
*
* All functions lock & unlock the global FS object
*
*/
#include "modules/filesystem.h"
#include "epicardium.h"
extern int
efs_open(EpicFileSystem *fs, const char *filename, const char *modeString);
extern int efs_close(EpicFileSystem *fs, int fd);
extern int efs_read(EpicFileSystem *fs, int fd, void *buf, size_t nbytes);
extern int
efs_write(EpicFileSystem *fs, int fd, const void *buf, size_t nbytes);
extern int efs_flush(EpicFileSystem *fs, int fd);
extern int efs_seek(EpicFileSystem *fs, int fd, long offset, int whence);
extern int efs_tell(EpicFileSystem *fs, int fd);
extern int
efs_stat(EpicFileSystem *fs, const char *filename, struct epic_stat *stat);
int epic_file_open(const char *filename, const char *mode)
{
EpicFileSystem *fs;
int res;
if (efs_lock_global(&fs, &res)) {
res = efs_open(fs, filename, mode);
efs_unlock_global(fs);
}
return res;
}
int epic_file_close(int fd)
{
EpicFileSystem *fs;
int res;
if (efs_lock_global(&fs, &res)) {
res = efs_close(fs, fd);
efs_unlock_global(fs);
}
return res;
}
int epic_file_read(int fd, void *buf, size_t nbytes)
{
EpicFileSystem *fs;
int res;
if (efs_lock_global(&fs, &res)) {
res = efs_read(fs, fd, buf, nbytes);
efs_unlock_global(fs);
}
return res;
}
int epic_file_write(int fd, const void *buf, size_t nbytes)
{
EpicFileSystem *fs;
int res;
if (efs_lock_global(&fs, &res)) {
res = efs_write(fs, fd, buf, nbytes);
efs_unlock_global(fs);
}
return res;
}
int epic_file_flush(int fd)
{
EpicFileSystem *fs;
int res;
if (efs_lock_global(&fs, &res)) {
res = efs_flush(fs, fd);
efs_unlock_global(fs);
}
return res;
}
int epic_file_seek(int fd, long offset, int whence)
{
EpicFileSystem *fs;
int res;
if (efs_lock_global(&fs, &res)) {
res = efs_seek(fs, fd, offset, whence);
efs_unlock_global(fs);
}
return res;
}
int epic_file_tell(int fd)
{
EpicFileSystem *fs;
int res;
if (efs_lock_global(&fs, &res)) {
res = efs_tell(fs, fd);
efs_unlock_global(fs);
}
return res;
}
int epic_file_stat(const char *filename, struct epic_stat *stat)
{
EpicFileSystem *fs;
int res;
if (efs_lock_global(&fs, &res)) {
res = efs_stat(fs, filename, stat);
efs_unlock_global(fs);
}
return res;
}
module_sources = files( module_sources = files(
'display.c', 'display.c',
'fatfs.c', 'filesystem_fat.c',
'fatfs_fileops.c', 'filesystem_fileops.c',
'leds.c', 'leds.c',
'log.c', 'log.c',
'pmic.c', 'pmic.c',
......
#ifndef MODULES_H #ifndef MODULES_H
#define MODULES_H #define MODULES_H
/* ---------- FAT fs ------------------------------------------------------ */
/* Number of bits to use for indexing into our internal pool of files/directories
* This indirectly specifies the size of the pool as 1^EPIC_FAT_FD_INDEX_BITS
* Increase if number of open file descriptors is not enough, but be aware of
* memory usage of the pool!
*/
#define EPIC_FAT_FD_INDEX_BITS 8
#define EPIC_FAT_STATIC_SEMAPHORE 1
void fatfs_init(void);
/* ---------- Serial ------------------------------------------------------- */ /* ---------- Serial ------------------------------------------------------- */
#define SERIAL_READ_BUFFER_SIZE 128 #define SERIAL_READ_BUFFER_SIZE 128
void vSerialTask(void *pvParameters); void vSerialTask(void *pvParameters);
......
...@@ -7,8 +7,9 @@ ...@@ -7,8 +7,9 @@
/* storage control modules to the FatFs module with a defined API. */ /* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#include "diskio.h" /* FatFs lower layer API */ #include <stdbool.h>
#include "diskio.h" /* FatFs lower layer API */
/* Definitions of physical drive number for each drive */ /* Definitions of physical drive number for each drive */
#define DEV_FLASH 0 /* Example: Map MMC/SD card to physical drive 1 */ #define DEV_FLASH 0 /* Example: Map MMC/SD card to physical drive 1 */
#define DEV_SD 1 /* Example: Map MMC/SD card to physical drive 1 */ #define DEV_SD 1 /* Example: Map MMC/SD card to physical drive 1 */
...@@ -19,8 +20,9 @@ ...@@ -19,8 +20,9 @@
/*local vaiables*/ /*local vaiables*/
static uint8_t rtc_en; static uint8_t rtc_en;
static bool s_diskio_initialized = false;
#if SDHC #if SDHC //TODO: implement deinitialization with SDHC as well
/* # of times to check for a card, should be > 1 to detect both SD and MMC */ /* # of times to check for a card, should be > 1 to detect both SD and MMC */
#define INIT_CARD_RETRIES 10 #define INIT_CARD_RETRIES 10
...@@ -47,18 +49,13 @@ extern int mx25_ready(void); ...@@ -47,18 +49,13 @@ extern int mx25_ready(void);
/* Get Drive Status */ /* Get Drive Status */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
DSTATUS disk_status ( DSTATUS disk_status(BYTE pdrv /* Physical drive nmuber to identify the drive */
BYTE pdrv /* Physical drive nmuber to identify the drive */ ) {
)
{
#if 0
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
#endif
DSTATUS status = 0; DSTATUS status = 0;
if(pdrv == 0) { if (!s_diskio_initialized) {
status = STA_NOINIT | STA_NODISK;
} else if (pdrv == 0) {
if (mx25_ready()) { if (mx25_ready()) {
status = RES_OK; status = RES_OK;
} }
...@@ -75,19 +72,17 @@ DSTATUS disk_status ( ...@@ -75,19 +72,17 @@ DSTATUS disk_status (
return status; return status;
} }
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Inidialize a Drive */ /* Inidialize a Drive */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
DSTATUS disk_initialize ( DSTATUS
BYTE pdrv /* Physical drive nmuber to identify the drive */ disk_initialize(BYTE pdrv /* Physical drive nmuber to identify the drive */
) ) {
{
DSTATUS status = STA_NOINIT; DSTATUS status = STA_NOINIT;
rtc_en = 0; rtc_en = 0;
s_diskio_initialized = true;
#if (FF_FS_NORTC == 0) #if (FF_FS_NORTC == 0)
//Initialize RTC //Initialize RTC
if (MXC_RTC->cn & MXC_F_RTC_CN_WE) { if (MXC_RTC->cn & MXC_F_RTC_CN_WE) {
...@@ -110,7 +105,8 @@ DSTATUS disk_initialize ( ...@@ -110,7 +105,8 @@ DSTATUS disk_initialize (
#if SDHC #if SDHC
if (pdrv == 1) { if (pdrv == 1) {
if (SDHC_Card_Inserted() && (SDHC_Lib_InitCard(INIT_CARD_RETRIES) == E_NO_ERROR)) { if (SDHC_Card_Inserted() &&
(SDHC_Lib_InitCard(INIT_CARD_RETRIES) == E_NO_ERROR)) {
/* Card initialized and ready for work */ /* Card initialized and ready for work */
init_done = 1; init_done = 1;
status = 0; status = 0;
...@@ -123,7 +119,14 @@ DSTATUS disk_initialize ( ...@@ -123,7 +119,14 @@ DSTATUS disk_initialize (
return status; return status;
} }
void disk_deinitialize()
{
if (s_diskio_initialized) {
mx25_sync();
mx25_stop(); //XXX: or should we not?
s_diskio_initialized = false;
}
}
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Read Sector(s) */ /* Read Sector(s) */
...@@ -134,15 +137,20 @@ DRESULT disk_read ( ...@@ -134,15 +137,20 @@ DRESULT disk_read (
BYTE *buff, /* Data buffer to store read data */ BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Start sector in LBA */ DWORD sector, /* Start sector in LBA */
UINT count /* Number of sectors to read */ UINT count /* Number of sectors to read */
) ) {
{
DRESULT status = RES_ERROR; DRESULT status = RES_ERROR;
if(pdrv == 0) { if (!s_diskio_initialized) {
status = STA_NOINIT | STA_NODISK;
} else if (pdrv == 0) {
int sector_offset; int sector_offset;
status = RES_OK; status = RES_OK;
for(sector_offset = 0; sector_offset < count; sector_offset++) { for (sector_offset = 0; sector_offset < count;
if(mx25_read(sector + sector_offset, (uint8_t*)buff + SECTOR_SIZE * sector_offset) == 1) { sector_offset++) {
if (mx25_read(
sector + sector_offset,
(uint8_t *)buff +
SECTOR_SIZE * sector_offset) == 1) {
status = RES_ERROR; status = RES_ERROR;
break; break;
} }
...@@ -150,7 +158,8 @@ DRESULT disk_read ( ...@@ -150,7 +158,8 @@ DRESULT disk_read (
} }
#if SDHC #if SDHC
if (pdrv == 1) { if (pdrv == 1) {
if (SDHC_Lib_Read(buff, sector, count, SDHC_LIB_SINGLE_DATA) == E_NO_ERROR) { if (SDHC_Lib_Read(buff, sector, count, SDHC_LIB_SINGLE_DATA) ==
E_NO_ERROR) {
status = RES_OK; status = RES_OK;
} }
} }
...@@ -159,8 +168,6 @@ DRESULT disk_read ( ...@@ -159,8 +168,6 @@ DRESULT disk_read (
return status; return status;
} }
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Write Sector(s) */ /* Write Sector(s) */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
...@@ -170,15 +177,20 @@ DRESULT disk_write ( ...@@ -170,15 +177,20 @@ DRESULT disk_write (
const BYTE *buff, /* Data to be written */ const BYTE *buff, /* Data to be written */
DWORD sector, /* Start sector in LBA */ DWORD sector, /* Start sector in LBA */
UINT count /* Number of sectors to write */ UINT count /* Number of sectors to write */
) ) {
{
DRESULT status = RES_ERROR; DRESULT status = RES_ERROR;
if(pdrv == 0) { if (!s_diskio_initialized) {
status = STA_NOINIT | STA_NODISK;
} else if (pdrv == 0) {
int sector_offset; int sector_offset;
status = RES_OK; status = RES_OK;
for(sector_offset = 0; sector_offset < count; sector_offset++) { for (sector_offset = 0; sector_offset < count;
if(mx25_write(sector + sector_offset, (uint8_t*)buff + SECTOR_SIZE * sector_offset) == 1) { sector_offset++) {
if (mx25_write(
sector + sector_offset,
(uint8_t *)buff +
SECTOR_SIZE * sector_offset) == 1) {
status = RES_ERROR; status = RES_ERROR;
break; break;
} }
...@@ -187,7 +199,9 @@ DRESULT disk_write ( ...@@ -187,7 +199,9 @@ DRESULT disk_write (
#if SDHC #if SDHC
if (pdrv == 1) { if (pdrv == 1) {
if (SDHC_Lib_Write(sector, (void *)buff, count, SDHC_LIB_SINGLE_DATA) != E_NO_ERROR) { if (SDHC_Lib_Write(
sector, (void *)buff, count, SDHC_LIB_SINGLE_DATA) !=
E_NO_ERROR) {
status = RES_ERROR; status = RES_ERROR;
} else { } else {
status = RES_OK; status = RES_OK;
...@@ -198,8 +212,6 @@ DRESULT disk_write ( ...@@ -198,8 +212,6 @@ DRESULT disk_write (
return status; return status;
} }
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */ /* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
...@@ -208,11 +220,12 @@ DRESULT disk_ioctl ( ...@@ -208,11 +220,12 @@ DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */ BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */ BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */ void *buff /* Buffer to send/receive control data */
) ) {
{
DRESULT status = RES_PARERR; DRESULT status = RES_PARERR;
if(pdrv == 0) { if (!s_diskio_initialized) {
status = STA_NOINIT | STA_NODISK;
} else if (pdrv == 0) {
switch (cmd) { switch (cmd) {
case CTRL_SYNC: case CTRL_SYNC:
/* Mandatory */ /* Mandatory */
...@@ -262,7 +275,8 @@ DRESULT disk_ioctl ( ...@@ -262,7 +275,8 @@ DRESULT disk_ioctl (
return status; return status;
} }
DWORD get_fattime(void) { DWORD get_fattime(void)
{
if (rtc_en) { if (rtc_en) {
DWORD result; DWORD result;
uint32_t seconds; uint32_t seconds;
...@@ -298,8 +312,7 @@ DWORD get_fattime(void) { ...@@ -298,8 +312,7 @@ DWORD get_fattime(void) {
result |= minute << 5; result |= minute << 5;
result |= half_seconds; result |= half_seconds;
return result; return result;
} } else {
else {
return RES_NOTRDY; return RES_NOTRDY;
} }
} }
...@@ -318,7 +331,8 @@ static DRESULT get_sector_count(void *buff) ...@@ -318,7 +331,8 @@ static DRESULT get_sector_count(void *buff)
if (init_done) { if (init_done) {
if (SDHC_Lib_GetCSD(&csd) == E_NO_ERROR) { if (SDHC_Lib_GetCSD(&csd) == E_NO_ERROR) {
*((DWORD *)buff) = SDHC_Lib_GetCapacity(&csd) / FF_MIN_SS; *((DWORD *)buff) =
SDHC_Lib_GetCapacity(&csd) / FF_MIN_SS;
status = RES_OK; status = RES_OK;
} }
} else { } else {
......
...@@ -34,6 +34,7 @@ typedef enum { ...@@ -34,6 +34,7 @@ typedef enum {
/* Prototypes for disk control functions */ /* Prototypes for disk control functions */
DSTATUS disk_initialize (BYTE pdrv); DSTATUS disk_initialize (BYTE pdrv);
void disk_deinitialize(void);
DSTATUS disk_status (BYTE pdrv); DSTATUS disk_status (BYTE pdrv);
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
......
...@@ -248,10 +248,10 @@ ...@@ -248,10 +248,10 @@
/ lock control is independent of re-entrancy. */ / lock control is independent of re-entrancy. */
#define FF_FS_REENTRANT 1 #define FF_FS_REENTRANT 0
#define FF_FS_TIMEOUT 1000 #define FF_FS_TIMEOUT 1000
//in FreeRTOS, SemaphoreHandle_t is a typedef for QueueHandle_t, which is just a typedef for: //in FreeRTOS, SemaphoreHandle_t is a typedef for QueueHandle_t, which is just a typedef for:
#define FF_SYNC_t struct QueueDefinition * //#define FF_SYNC_t struct QueueDefinition *
/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
/ module itself. Note that regardless of this option, file access to different / module itself. Note that regardless of this option, file access to different
......
...@@ -61,6 +61,7 @@ Q(encoding) ...@@ -61,6 +61,7 @@ Q(encoding)
Q(file) Q(file)
Q(FileIO) Q(FileIO)
Q(flush) Q(flush)
Q(usbstorage)
Q(mode) Q(mode)
Q(r) Q(r)
Q(read) Q(read)
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#define MICROPY_PY_URE_SUB (1) #define MICROPY_PY_URE_SUB (1)
#define MICROPY_PY_UTIME_MP_HAL (1) #define MICROPY_PY_UTIME_MP_HAL (1)
#define MICROPY_PY_IO_FILEIO (1) #define MICROPY_PY_IO_FILEIO (1)
#define MICROPY_PY_UERRNO (1)
/* Modules */ /* Modules */
#define MODULE_UTIME_ENABLED (1) #define MODULE_UTIME_ENABLED (1)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment