01dd7804b8
This is to keep the top-level directory clean, to make it clear what is core and what is a port, and to allow the repository to grow with new ports in a sustainable way.
183 lines
5.7 KiB
C
183 lines
5.7 KiB
C
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
|
|
#include "py/mpconfig.h"
|
|
#include "py/obj.h"
|
|
#include "lib/oofatfs/ff.h"
|
|
#include "lib/oofatfs/diskio.h"
|
|
#include "simplelink.h"
|
|
#include "sflash_diskio.h"
|
|
#include "debug.h"
|
|
#include "modnetwork.h"
|
|
#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
|
|
sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER);
|
|
|
|
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);
|
|
}
|
|
sl_LockObjUnlock (&wlan_LockObj);
|
|
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);
|
|
sflash_init_done = true;
|
|
sflash_prblock = UINT32_MAX;
|
|
sflash_cache_is_dirty = false;
|
|
|
|
// 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
|
|
for (int i = 0; i < SFLASH_BLOCK_COUNT; i++) {
|
|
print_block_name (i);
|
|
sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER);
|
|
// Create the block file if it doesn't exist
|
|
if (sl_FsGetInfo(sflash_block_name, 0, &FsFileInfo) != 0) {
|
|
if (!sl_FsOpen(sflash_block_name, FS_MODE_OPEN_CREATE(SFLASH_BLOCK_SIZE, 0), NULL, &fileHandle)) {
|
|
sl_FsClose(fileHandle, NULL, NULL, 0);
|
|
sl_LockObjUnlock (&wlan_LockObj);
|
|
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
|
|
sl_LockObjUnlock (&wlan_LockObj);
|
|
return RES_ERROR;
|
|
}
|
|
}
|
|
sl_LockObjUnlock (&wlan_LockObj);
|
|
}
|
|
}
|
|
return RES_OK;
|
|
}
|
|
|
|
DRESULT sflash_disk_status(void) {
|
|
if (!sflash_init_done) {
|
|
return STA_NOINIT;
|
|
}
|
|
return RES_OK;
|
|
}
|
|
|
|
DRESULT sflash_disk_read(BYTE *buff, DWORD sector, UINT count) {
|
|
uint32_t secindex;
|
|
|
|
if (!sflash_init_done) {
|
|
return STA_NOINIT;
|
|
}
|
|
|
|
if ((sector + count > SFLASH_SECTOR_COUNT) || (count == 0)) {
|
|
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_SECTOR_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;
|
|
}
|
|
|
|
if ((sector + count > SFLASH_SECTOR_COUNT) || (count == 0)) {
|
|
sflash_disk_flush();
|
|
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_SECTOR_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;
|
|
}
|
|
|