circuitpython/ports/cc3200/fatfs/src/drivers/sflash_diskio.c
Damien George 01dd7804b8 ports: Make new ports/ sub-directory and move all ports there.
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.
2017-09-06 13:40:51 +10:00

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