sflash_diskio.c 5.69 KB
Newer Older
1
2
3
4
#include <stdint.h>
#include <stdbool.h>
#include "std.h"

5
#include "py/mpconfig.h"
6
#include "py/obj.h"
7
8
9
10
#include "simplelink.h"
#include "diskio.h"
#include "sflash_diskio.h"
#include "debug.h"
11
#include "modnetwork.h"
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "modwlan.h"

#define SFLASH_TIMEOUT_MAX_MS               5500
#define SFLASH_WAIT_TIME_MS                 5

static _u8 sflash_block_name[] =  "__NNN__.fsb";
static _u8 *sflash_block_cache;
static bool sflash_init_done = false;
static bool sflash_cache_is_dirty;
static uint32_t sflash_ublock;
static uint32_t sflash_prblock;


static void print_block_name (_u32 ublock) {
    char _sblock[4];
    snprintf (_sblock, sizeof(_sblock), "%03u", ublock);
    memcpy (&sflash_block_name[2], _sblock, 3);
}

static bool sflash_access (_u32 mode, _i32 (* sl_FsFunction)(_i32 FileHdl, _u32 Offset, _u8* pData, _u32 Len)) {
    _i32 fileHandle;
    bool retval = false;

    // wlan must be enabled in order to access the serial flash
36
37
    sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER);

38
39
40
41
42
43
    if (0 == sl_FsOpen(sflash_block_name, mode, NULL, &fileHandle)) {
        if (SFLASH_BLOCK_SIZE == sl_FsFunction (fileHandle, 0, sflash_block_cache, SFLASH_BLOCK_SIZE)) {
            retval = true;
        }
        sl_FsClose (fileHandle, NULL, NULL, 0);
    }
44
    sl_LockObjUnlock (&wlan_LockObj);
45
46
47
48
49
50
51
52
53
54
    return retval;
}

DRESULT sflash_disk_init (void) {
    _i32 fileHandle;
    SlFsFileInfo_t FsFileInfo;

    if (!sflash_init_done) {
        // Allocate space for the block cache
        ASSERT ((sflash_block_cache = mem_Malloc(SFLASH_BLOCK_SIZE)) != NULL);
55
        sflash_init_done = true;
56
57
        sflash_prblock = UINT32_MAX;
        sflash_cache_is_dirty = false;
58

59
60
61
62
63
64
65
66
67
68
69
        // In order too speed up booting, check the last block, if exists, then
        // it means that the file system has been already created
        print_block_name (SFLASH_BLOCK_COUNT - 1);
        sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER);
        if (!sl_FsGetInfo(sflash_block_name, 0, &FsFileInfo)) {
            sl_LockObjUnlock (&wlan_LockObj);
            return RES_OK;
        }
        sl_LockObjUnlock (&wlan_LockObj);

        // Proceed to format the memory
70
71
        for (int i = 0; i < SFLASH_BLOCK_COUNT; i++) {
            print_block_name (i);
72
            sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER);
73
            // Create the block file if it doesn't exist
74
            if (sl_FsGetInfo(sflash_block_name, 0, &FsFileInfo) != 0) {
75
76
                if (!sl_FsOpen(sflash_block_name, FS_MODE_OPEN_CREATE(SFLASH_BLOCK_SIZE, 0), NULL, &fileHandle)) {
                    sl_FsClose(fileHandle, NULL, NULL, 0);
77
                    sl_LockObjUnlock (&wlan_LockObj);
78
79
80
81
82
83
84
                    memset(sflash_block_cache, 0xFF, SFLASH_BLOCK_SIZE);
                    if (!sflash_access(FS_MODE_OPEN_WRITE, sl_FsWrite)) {
                        return RES_ERROR;
                    }
                }
                else {
                    // Unexpected failure while creating the file
85
                    sl_LockObjUnlock (&wlan_LockObj);
86
87
88
                    return RES_ERROR;
                }
            }
89
            sl_LockObjUnlock (&wlan_LockObj);
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
        }
    }
    return RES_OK;
}

DRESULT sflash_disk_status(void) {
    if (!sflash_init_done) {
        return STA_NOINIT;
    }
    return 0;
}

DRESULT sflash_disk_read(BYTE *buff, DWORD sector, UINT count) {
    uint32_t secindex;

    if (!sflash_init_done) {
        return STA_NOINIT;
    }

109
    if ((sector + count > SFLASH_SECTOR_COUNT) || (count == 0)) {
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
        return RES_PARERR;
    }

    for (int i = 0; i < count; i++) {
        secindex = (sector + i) % SFLASH_SECTORS_PER_BLOCK;
        sflash_ublock = (sector + i) / SFLASH_SECTORS_PER_BLOCK;
        // See if it's time to read a new block
        if (sflash_prblock != sflash_ublock) {
            if (sflash_disk_flush() != RES_OK) {
                return RES_ERROR;
            }
            sflash_prblock = sflash_ublock;
            print_block_name (sflash_ublock);
            if (!sflash_access(FS_MODE_OPEN_READ, sl_FsRead)) {
                return RES_ERROR;
            }
        }
        // Copy the requested sector from the block cache
        memcpy (buff, &sflash_block_cache[(secindex * SFLASH_SECTOR_SIZE)], SFLASH_SECTOR_SIZE);
        buff += SFLASH_BLOCK_SIZE;
    }
    return RES_OK;
}

DRESULT sflash_disk_write(const BYTE *buff, DWORD sector, UINT count) {
    uint32_t secindex;
    int32_t index = 0;

    if (!sflash_init_done) {
        return STA_NOINIT;
    }

142
143
    if ((sector + count > SFLASH_SECTOR_COUNT) || (count == 0)) {
        sflash_disk_flush();
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
        return RES_PARERR;
    }

    do {
        secindex = (sector + index) % SFLASH_SECTORS_PER_BLOCK;
        sflash_ublock = (sector + index) / SFLASH_SECTORS_PER_BLOCK;
        // Check if it's a different block than last time
        if (sflash_prblock != sflash_ublock) {
            if (sflash_disk_flush() != RES_OK) {
                return RES_ERROR;
            }
            sflash_prblock = sflash_ublock;
            print_block_name (sflash_ublock);
            // Read the block into the cache
            if (!sflash_access(FS_MODE_OPEN_READ, sl_FsRead)) {
                return RES_ERROR;
            }
        }
        // Copy the input sector to the block cache
        memcpy (&sflash_block_cache[(secindex * SFLASH_SECTOR_SIZE)], buff, SFLASH_SECTOR_SIZE);
        buff += SFLASH_BLOCK_SIZE;
        sflash_cache_is_dirty = true;
    } while (++index < count);

    return RES_OK;
}

DRESULT sflash_disk_flush (void) {
    // Write back the cache if it's dirty
    if (sflash_cache_is_dirty) {
        if (!sflash_access(FS_MODE_OPEN_WRITE, sl_FsWrite)) {
            return RES_ERROR;
        }
        sflash_cache_is_dirty = false;
    }
    return RES_OK;
}