fatfs.c 7.73 KB
Newer Older
swym's avatar
swym committed
1
2
3
4
/*
 * support routines for FatFs
 */

5
6
#include <errno.h>
#include <stddef.h>
swym's avatar
swym committed
7
8
#include <stdio.h>
#include <stdbool.h>
9
10
#include <stdlib.h>

swym's avatar
swym committed
11
12
13
14
15
#include <ff.h>

#include <FreeRTOS.h>
#include <semphr.h>

16
17
18
19
20
21
#include "modules.h"

#ifndef EPIC_FAT_STATIC_SEMAPHORE
#define EPIC_FAT_STATIC_SEMAPHORE 0
#endif

22
static const TCHAR *rcstrings =
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
    _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");

// 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,
};

enum FatObjectType { FO_Nil, FO_File, FO_Dir };
struct FatObject {
    enum FatObjectType type;
    union {
        FIL file;
        DIR dir;
    };
};
60

swym's avatar
swym committed
61
static bool mount(void);
62
63
static int
get_fat_object(int i, enum FatObjectType expected, struct FatObject **res);
swym's avatar
swym committed
64
65
66

DIR dir;
FATFS FatFs;
67
68
69
70
71
static struct FatObject s_openedObjects[EPIC_FAT_MAX_OPENED];

#if (EPIC_FAT_STATIC_SEMAPHORE == 1)
StaticSemaphore_t xSemaphoreBuffer;
#endif
swym's avatar
swym committed
72
73

static volatile struct {
74
    bool initiaized;
Rahix's avatar
Rahix committed
75
} s_state = {
76
    .initiaized = false,
swym's avatar
swym committed
77
78
};

79
80
void fatfs_init()
{
81
82
83
84
    if (mount()) {
        s_state.initiaized = true;
        printf("FatFs mounted\n");
    }
85
86
87
88
}

const char *f_get_rc_string(FRESULT rc)
{
89
90
91
92
93
94
95
96
    FRESULT i;
    const char *p = rcstrings;

    for (i = 0; i != rc && *p; i++) {
        while (*p++)
            ;
    }
    return p;
97
98
99
}

static bool mount()
swym's avatar
swym committed
100
{
101
102
103
104
105
106
107
108
109
110
111
112
113
114
    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;
swym's avatar
swym committed
115
}
116

117
118
119
120
121
122
123
/*------------------------------------------------------------------------*/
/* 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.
*/
swym's avatar
swym committed
124

Rahix's avatar
Rahix committed
125
126
127
128
129
130
/*
 * Return value:
 *   - 1: Function succeeded
 *   - 0: Could not create the sync object
 */
int ff_cre_syncobj(BYTE vol, FF_SYNC_t *sobj)
swym's avatar
swym committed
131
{
132
133
134
135
136
137
138
#if (EPIC_FAT_STATIC_SEMAPHORE == 1)
    *sobj = xSemaphoreCreateMutexStatic(&xSemaphoreBuffer);
#else
    *sobj = xSemaphoreCreateMutex();
#endif //EPIC_FAT_STATIC_SEMAPHORE

    return (int)(*sobj != NULL);
swym's avatar
swym committed
139
140
141
142
143
144
145
146
147
148
}

/*------------------------------------------------------------------------*/
/* 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.
*/

Rahix's avatar
Rahix committed
149
150
151
152
153
154
/*
 * Return value:
 *   - 1: Function succeeded
 *   - 0: Could not delete due to an error
 */
int ff_del_syncobj(FF_SYNC_t sobj)
swym's avatar
swym committed
155
{
156
157
158
    /* FreeRTOS */
    vSemaphoreDelete(sobj);
    return 1;
swym's avatar
swym committed
159
160
161
162
163
164
165
166
167
}

/*------------------------------------------------------------------------*/
/* 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.
*/

Rahix's avatar
Rahix committed
168
169
170
171
172
173
/*
 * Return value:
 *   - 1: Got a grant to access the volume
 *   - 0: Could not get a grant
 */
int ff_req_grant(FF_SYNC_t sobj)
swym's avatar
swym committed
174
{
175
176
    /* FreeRTOS */
    return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE);
swym's avatar
swym committed
177
178
179
180
181
182
183
184
}

/*------------------------------------------------------------------------*/
/* Release Grant to Access the Volume                                     */
/*------------------------------------------------------------------------*/
/* This function is called on leaving file functions to unlock the volume.
*/

Rahix's avatar
Rahix committed
185
void ff_rel_grant(FF_SYNC_t sobj)
swym's avatar
swym committed
186
{
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
    /* FreeRTOS */
    xSemaphoreGive(sobj);
}

int get_fat_object(int i, enum FatObjectType expected, struct FatObject **res)
{
    if (i < 0 || i >= EPIC_FAT_MAX_OPENED) {
        *res = NULL;
        return EBADF;
    }
    if (s_openedObjects[i].type != expected) {
        *res = NULL;
        return EBADF;
    }
    *res = &s_openedObjects[i];
    return 0;
}

int32_t epic_open(const char *filename, const char *modeString)
{
    struct FatObject *o = NULL;
    const char *mode_s  = modeString;
    int i;
    int mode = 0;

    //find free object to use
    for (i = 0; i < EPIC_FAT_MAX_OPENED; ++i) {
        if (s_openedObjects[i].type == FO_Nil) {
            break;
        }
    }
    if (i == EPIC_FAT_MAX_OPENED) {
        return -fresult_to_errno_table[FR_TOO_MANY_OPEN_FILES];
    }
    o = &s_openedObjects[i];

    while (*mode_s) {
        switch (*mode_s++) {
        case 'r':
            mode |= FA_READ;
            break;
        case 'w':
            mode |= FA_WRITE | FA_CREATE_ALWAYS;
            break;
        case 'x':
            mode |= FA_WRITE | FA_CREATE_NEW;
            break;
        case 'a':
            mode |= FA_WRITE | FA_OPEN_ALWAYS;
            break;
        case '+':
            mode |= FA_READ | FA_WRITE;
            break;
        }
    }

    int res = f_open(&o->file, filename, mode);
    if (res != FR_OK) {
        return -fresult_to_errno_table[res];
    }
    o->type = FO_File;

    // for 'a' mode, we must begin at the end of the file
    if ((mode & FA_OPEN_ALWAYS) != 0) {
        f_lseek(&o->file, f_size(&o->file));
    }

    return i;
}

int32_t epic_close(int32_t fd)
{
    int res;
    struct FatObject *o;
    res = get_fat_object(fd, FO_File, &o);
    if (res) {
        return -res;
    }

    res = f_close(&o->file);
    if (res != FR_OK) {
        return -fresult_to_errno_table[res];
    }

    o->type = FO_Nil;
    return 0;
swym's avatar
swym committed
273
}
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328


int32_t epic_read(int32_t fd, void *buf, uint32_t nbytes)
{
    unsigned int nread = 0;

    int res;
    struct FatObject *o;
    res = get_fat_object(fd, FO_File, &o);
    if (res) {
        return -res;
    }

    res = f_read(&o->file, buf, nbytes, &nread);
    if (res != FR_OK) {
        return -fresult_to_errno_table[res];
    }

    return nread;
}

int32_t epic_write(int32_t fd, const void *buf, uint32_t nbytes)
{
    unsigned int nwritten = 0;

    int res;
    struct FatObject *o;
    res = get_fat_object(fd, FO_File, &o);
    if (res) {
        return -res;
    }
    res = f_write(&o->file, buf, nbytes, &nwritten);
    if (res != FR_OK) {
        return -fresult_to_errno_table[res];
    }

    return nwritten;
}

int32_t epic_flush(int32_t fd) {

    int res;
    struct FatObject *o;
    res = get_fat_object(fd, FO_File, &o);
    if (res) {
        return -res;
    }
    res = f_sync(&o->file);
    if (res != FR_OK) {
        return -fresult_to_errno_table[res];
    }

    return 0;
}