mirror of
https://github.com/Ai-Thinker-Open/Ai-Thinker-Open_RTL8710BX_ALIOS_SDK.git
synced 2025-07-31 19:31:05 +00:00
rel_1.6.0 init
This commit is contained in:
commit
27b3e2883d
19359 changed files with 8093121 additions and 0 deletions
1
Living_SDK/3rdparty/experimental/ramfs/README
vendored
Normal file
1
Living_SDK/3rdparty/experimental/ramfs/README
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
This software component is used to help users port third-party programs, but WITHOUT ANY WARRANTY. The entire risk as to the quality and performance of the program is with you. Should the program prove defective, you assume the cost of all necessary servicing, repair or correction. The use of third-party programs must also follow its own permissive license.
|
759
Living_SDK/3rdparty/experimental/ramfs/ramfs.c
vendored
Normal file
759
Living_SDK/3rdparty/experimental/ramfs/ramfs.c
vendored
Normal file
|
@ -0,0 +1,759 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "k_api.h"
|
||||
#include "ramfs.h"
|
||||
|
||||
#define LL_NODE_META_SIZE (sizeof(ll_node_t*) + sizeof(ll_node_t*))
|
||||
#define LL_PREV_P_OFFSET(ll_p) (ll_p->n_size)
|
||||
#define LL_NEXT_P_OFFSET(ll_p) (ll_p->n_size + sizeof(ll_node_t*))
|
||||
|
||||
static ramfs_ent_t* ramfs_ent_get(const char * fn);
|
||||
static ramfs_ent_t* ramfs_ent_new(const char * fn);
|
||||
static void * ll_ins_head(ll_t * ll_p);
|
||||
static void ll_rem(ll_t * ll_p, void * node_p);
|
||||
static void * ll_get_head(ll_t * ll_p);
|
||||
static void * ll_get_tail(ll_t * ll_p);
|
||||
static void * ll_get_next(ll_t * ll_p, void * n_act);
|
||||
static void * ll_get_prev(ll_t * ll_p, void * n_act);
|
||||
static void node_set_prev(ll_t * ll_p, ll_node_t* act, ll_node_t* prev);
|
||||
static void node_set_next(ll_t * ll_p, ll_node_t* act, ll_node_t* next);
|
||||
static void node_set_prev(ll_t * ll_p, ll_node_t* act, ll_node_t* prev);
|
||||
static void node_set_next(ll_t * ll_p, ll_node_t* act, ll_node_t* next);
|
||||
static void ll_init(ll_t * ll_p, uint32_t n_size);
|
||||
|
||||
static ll_t file_ll;
|
||||
static bool inited = false;
|
||||
|
||||
/**
|
||||
* Create a driver for ufs and initialize it.
|
||||
*/
|
||||
void ramfs_init(void)
|
||||
{
|
||||
ll_init(&file_ll, sizeof(ramfs_ent_t));
|
||||
|
||||
inited = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the state of the ufs
|
||||
* @return true if ufs is initialized and can be used else false
|
||||
*/
|
||||
bool ramfs_ready(void)
|
||||
{
|
||||
return inited;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a file in ufs
|
||||
* @param file_p pointer to a ramfs_file_t variable
|
||||
* @param fn name of the file. There are no directories so e.g. "myfile.txt"
|
||||
* @param mode element of 'fs_mode_t' enum or its 'OR' connection (e.g. FS_MODE_WR | FS_MODE_RD)
|
||||
* @return RAMFS_RES_OK: no error, the file is opened
|
||||
* any error from lv__fs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_open (void * file_p, const char * fn, ramfs_mode_t mode)
|
||||
{
|
||||
ramfs_file_t * fp = file_p; /*Convert type*/
|
||||
ramfs_ent_t* ent = ramfs_ent_get(fn);
|
||||
|
||||
fp->ent = NULL;
|
||||
|
||||
/*If the file not exists ...*/
|
||||
if( ent == NULL) {
|
||||
if((mode & RAMFS_MODE_WR) != 0) { /*Create the file if opened for write*/
|
||||
ent = ramfs_ent_new(fn);
|
||||
if(ent == NULL) return RAMFS_RES_FULL; /*No space for the new file*/
|
||||
} else {
|
||||
return RAMFS_RES_NOT_EX; /*Can not read not existing file*/
|
||||
}
|
||||
}
|
||||
|
||||
/*Can not write already opened and const data files*/
|
||||
if((mode & RAMFS_MODE_WR) != 0) {
|
||||
if(ent->oc != 0) return RAMFS_RES_LOCKED;
|
||||
if(ent->const_data != 0) return RAMFS_RES_DENIED;
|
||||
}
|
||||
|
||||
/*No error, the file can be opened*/
|
||||
fp->ent = ent;
|
||||
fp->ent->ar = mode & RAMFS_MODE_RD ? 1 : 0;
|
||||
fp->ent->aw = mode & RAMFS_MODE_WR ? 1 : 0;
|
||||
fp->rwp = 0;
|
||||
ent->oc ++;
|
||||
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a file with a constant data
|
||||
* @param fn name of the file (directories are not supported)
|
||||
* @param const_p pointer to a constant data
|
||||
* @param len length of the data pointed by 'const_p' in bytes
|
||||
* @return RAMFS_RES_OK: no error, the file is read
|
||||
* any error from lv__fs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_create_const(const char * fn, const void * const_p, uint32_t len)
|
||||
{
|
||||
ramfs_file_t file;
|
||||
ramfs_res_t res;
|
||||
|
||||
/*Error if the file already exists*/
|
||||
res = ramfs_open(&file, fn, RAMFS_MODE_RD);
|
||||
if(res == RAMFS_RES_OK) {
|
||||
ramfs_close(&file);
|
||||
return RAMFS_RES_DENIED;
|
||||
}
|
||||
|
||||
ramfs_close(&file);
|
||||
|
||||
res = ramfs_open(&file, fn, RAMFS_MODE_WR);
|
||||
if(res != RAMFS_RES_OK) return res;
|
||||
|
||||
ramfs_ent_t* ent = file.ent;
|
||||
|
||||
if(ent->data_d != NULL) return RAMFS_RES_DENIED;
|
||||
|
||||
ent->data_d = (void *) const_p;
|
||||
ent->size = len;
|
||||
ent->const_data = 1;
|
||||
|
||||
res = ramfs_close(&file);
|
||||
if(res != RAMFS_RES_OK) return res;
|
||||
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close an opened file
|
||||
* @param file_p pointer to an 'ufs_file_t' variable. (opened with ramfs_open)
|
||||
* @return RAMFS_RES_OK: no error, the file is read
|
||||
* any error from lv__fs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_close (void * file_p)
|
||||
{
|
||||
ramfs_file_t * fp = file_p; /*Convert type*/
|
||||
|
||||
if(fp->ent == NULL) return RAMFS_RES_OK;
|
||||
|
||||
/*Decrement the Open counter*/
|
||||
if(fp->ent->oc > 0) {
|
||||
fp->ent->oc--;
|
||||
}
|
||||
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a file. The file can not be opened.
|
||||
* @param fn '\0' terminated string
|
||||
* @return RAMFS_RES_OK: no error, the file is removed
|
||||
* RAMFS_RES_DENIED: the file was opened, remove failed
|
||||
*/
|
||||
ramfs_res_t ramfs_remove(const char * fn)
|
||||
{
|
||||
ramfs_ent_t* ent = ramfs_ent_get(fn);
|
||||
|
||||
/*Can not be deleted is opened*/
|
||||
if(ent->oc != 0) return RAMFS_RES_DENIED;
|
||||
|
||||
ll_rem(&file_ll, ent);
|
||||
krhino_mm_free(ent->fn_d);
|
||||
ent->fn_d = NULL;
|
||||
if(ent->const_data == 0){
|
||||
krhino_mm_free(ent->data_d);
|
||||
ent->data_d = NULL;
|
||||
}
|
||||
|
||||
krhino_mm_free(ent);
|
||||
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data from an opened file
|
||||
* @param file_p pointer to an 'ufs_file_t' variable. (opened with ramfs_open )
|
||||
* @param buf pointer to a memory block where to store the read data
|
||||
* @param btr number of Bytes To Read
|
||||
* @param br the real number of read bytes (Byte Read)
|
||||
* @return RAMFS_RES_OK: no error, the file is read
|
||||
* any error from lv__fs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_read (void * file_p, void * buf, uint32_t btr, uint32_t * br)
|
||||
{
|
||||
ramfs_file_t * fp = file_p; /*Convert type*/
|
||||
|
||||
ramfs_ent_t* ent = fp->ent;
|
||||
*br = 0;
|
||||
|
||||
if(ent->data_d == NULL || ent->size == 0) { /*Don't read empty files*/
|
||||
return RAMFS_RES_OK;
|
||||
} else if(fp->ent->ar == 0) { /*The file is not opened for read*/
|
||||
return RAMFS_RES_DENIED;
|
||||
}
|
||||
|
||||
/*No error, read the file*/
|
||||
if(fp->rwp + btr > ent->size) { /*Check too much bytes read*/
|
||||
*br = ent->size - fp->rwp;
|
||||
} else {
|
||||
*br = btr;
|
||||
}
|
||||
|
||||
/*Read the data*/
|
||||
uint8_t * data8_p;
|
||||
if(ent->const_data == 0) {
|
||||
data8_p = (uint8_t*) ent->data_d;
|
||||
} else {
|
||||
data8_p = ent->data_d;
|
||||
}
|
||||
|
||||
data8_p += fp->rwp;
|
||||
memcpy(buf, data8_p, *br);
|
||||
|
||||
fp->rwp += *br; /*Refresh the read write pointer*/
|
||||
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to an opened file
|
||||
* @param file_p pointer to an 'ufs_file_t' variable. (opened with ramfs_open)
|
||||
* @param buf pointer to a memory block which content will be written
|
||||
* @param btw the number Bytes To Write
|
||||
* @param bw The real number of written bytes (Byte Written)
|
||||
* @return RAMFS_RES_OK: no error, the file is read
|
||||
* any error from lv__fs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_write (void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
|
||||
{
|
||||
ramfs_file_t * fp = file_p; /*Convert type*/
|
||||
*bw = 0;
|
||||
|
||||
if(fp->ent->aw == 0) return RAMFS_RES_DENIED; /*Not opened for write*/
|
||||
|
||||
ramfs_ent_t* ent = fp->ent;
|
||||
|
||||
/*Reallocate data array if it necessary*/
|
||||
uint32_t new_size = fp->rwp + btw;
|
||||
if(new_size > ent->size) {
|
||||
uint8_t* new_data = krhino_mm_realloc(ent->data_d, new_size);
|
||||
if(new_data == NULL) return RAMFS_RES_FULL; /*Cannot allocate the new memory*/
|
||||
|
||||
ent->data_d = new_data;
|
||||
ent->size = new_size;
|
||||
}
|
||||
|
||||
/*Write the file*/
|
||||
uint8_t * data8_p = (uint8_t*) ent->data_d;
|
||||
data8_p += fp->rwp;
|
||||
memcpy(data8_p, buf, btw);
|
||||
*bw = btw;
|
||||
fp->rwp += *bw;
|
||||
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the read write pointer. Also expand the file size if necessary.
|
||||
* @param file_p pointer to an 'ufs_file_t' variable. (opened with ramfs_open )
|
||||
* @param pos the new position of read write pointer
|
||||
* @return RAMFS_RES_OK: no error, the file is read
|
||||
* any error from lv__fs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_seek (void * file_p, uint32_t pos)
|
||||
{
|
||||
ramfs_file_t * fp = file_p; /*Convert type*/
|
||||
ramfs_ent_t* ent = fp->ent;
|
||||
|
||||
/*Simply move the rwp before EOF*/
|
||||
if(pos < ent->size) {
|
||||
fp->rwp = pos;
|
||||
} else { /*Expand the file size*/
|
||||
if(fp->ent->aw == 0) return RAMFS_RES_DENIED; /*Not opened for write*/
|
||||
|
||||
uint8_t* new_data = krhino_mm_realloc(ent->data_d, pos);
|
||||
if(new_data == NULL) return RAMFS_RES_FULL; /*Out of memory*/
|
||||
|
||||
ent->data_d = new_data;
|
||||
ent->size = pos;
|
||||
fp->rwp = pos;
|
||||
}
|
||||
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the position of the read write pointer
|
||||
* @param file_p pointer to an 'ufs_file_t' variable. (opened with ramfs_open )
|
||||
* @param pos_p pointer to to store the result
|
||||
* @return RAMFS_RES_OK: no error, the file is read
|
||||
* any error from lv__fs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_tell (void * file_p, uint32_t * pos_p)
|
||||
{
|
||||
ramfs_file_t * fp = file_p; /*Convert type*/
|
||||
|
||||
*pos_p = fp->rwp;
|
||||
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate the file size to the current position of the read write pointer
|
||||
* @param file_p pointer to an 'ufs_file_t' variable. (opened with ramfs_open )
|
||||
* @return RAMFS_RES_OK: no error, the file is read
|
||||
* any error from lv__fs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_trunc (void * file_p)
|
||||
{
|
||||
ramfs_file_t * fp = file_p; /*Convert type*/
|
||||
ramfs_ent_t* ent = fp->ent;
|
||||
|
||||
if(fp->ent->aw == 0) return RAMFS_RES_DENIED; /*Not opened for write*/
|
||||
|
||||
void * new_data = krhino_mm_realloc(ent->data_d, fp->rwp);
|
||||
if(new_data == NULL) return RAMFS_RES_FULL; /*Out of memory*/
|
||||
|
||||
ent->data_d = new_data;
|
||||
ent->size = fp->rwp;
|
||||
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the size of the file in bytes
|
||||
* @param file_p file_p pointer to an 'ufs_file_t' variable. (opened with ramfs_open )
|
||||
* @param size_p pointer to store the size
|
||||
* @return RAMFS_RES_OK: no error, the file is read
|
||||
* any error from lv__fs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_size (void * file_p, uint32_t * size_p)
|
||||
{
|
||||
ramfs_file_t * fp = file_p; /*Convert type*/
|
||||
ramfs_ent_t* ent = fp->ent;
|
||||
|
||||
*size_p = ent->size;
|
||||
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* get access info
|
||||
* @param path uFS doesn't support folders so it has to be ""
|
||||
* @param mode the info to get
|
||||
* @return RAMFS_RES_OK or any error from ramfs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_access(const char * path, int mode)
|
||||
{
|
||||
ramfs_ent_t* ent = ramfs_ent_get(path);
|
||||
|
||||
/*If the file not exists ...*/
|
||||
if( ent == NULL) {
|
||||
return RAMFS_RES_DENIED; /*Can not read not existing file*/
|
||||
} else if((mode & F_OK ) != 0){
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
|
||||
/*Can not write already opened and const data files*/
|
||||
if((mode & R_OK ) != 0) {
|
||||
if(ent->ar == 0) {
|
||||
return RAMFS_RES_DENIED;
|
||||
} else {
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if((mode & W_OK) != 0) {
|
||||
if(ent->aw == 0) {
|
||||
return RAMFS_RES_DENIED;
|
||||
} else {
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a directory
|
||||
* @param path the path of file
|
||||
* @return RAMFS_RES_OK or any error from ramfs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_mkdir(const char * path)
|
||||
{
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a ramfs_read_dir_t variable to directory reading
|
||||
* @param rddir_p pointer to a 'ramfs_dir_t' variable
|
||||
* @param path the path of file
|
||||
* @return RAMFS_RES_OK or any error from ramfs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_dir_open(void * rddir_p, const char * path)
|
||||
{
|
||||
ramfs_dir_t * ramfs_rddir_p = rddir_p;
|
||||
|
||||
ramfs_rddir_p->last_ent = NULL;
|
||||
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the next file name
|
||||
* @param dir_p pointer to an initialized 'ramfs_dir_t' variable
|
||||
* @param fn pointer to buffer to sore the file name
|
||||
* @return RAMFS_RES_OK or any error from ramfs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_dir_read(void * dir_p, char * fn)
|
||||
{
|
||||
ramfs_dir_t * ufs_dir_p = dir_p;
|
||||
|
||||
if(ufs_dir_p->last_ent == NULL) {
|
||||
ufs_dir_p->last_ent = ll_get_head(&file_ll);
|
||||
} else {
|
||||
ufs_dir_p->last_ent = ll_get_next(&file_ll, ufs_dir_p->last_ent);
|
||||
}
|
||||
|
||||
if(ufs_dir_p->last_ent != NULL) {
|
||||
strcpy(fn, ufs_dir_p->last_ent->fn_d);
|
||||
} else {
|
||||
fn[0] = '\0';
|
||||
}
|
||||
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the directory reading
|
||||
* @param rddir_p pointer to an initialized 'ramfs_dir_t' variable
|
||||
* @return RAMFS_RES_OK or any error from ramfs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_dir_close(void * rddir_p)
|
||||
{
|
||||
(void)rddir_p;
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the size of a drive
|
||||
* @param total_p pointer to store the total size [kB]
|
||||
* @param free_p pointer to store the free site [kB]
|
||||
* @return RAMFS_RES_OK or any error from 'ramfs_res_t'
|
||||
*/
|
||||
ramfs_res_t ramfs_free (uint32_t * total_p, uint32_t * free_p)
|
||||
{
|
||||
return RAMFS_RES_OK;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Gives the ramfs_entry from a filename
|
||||
* @param fn filename ('\0' terminated string)
|
||||
* @return pointer to the dynamically allocated entry with 'fn' filename.
|
||||
* NULL if no entry found with that name.
|
||||
*/
|
||||
static ramfs_ent_t* ramfs_ent_get(const char * fn)
|
||||
{
|
||||
ramfs_ent_t* fp;
|
||||
|
||||
LL_READ(file_ll, fp) {
|
||||
if(strcmp(fp->fn_d, fn) == 0) {
|
||||
return fp;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new entry with 'fn' filename
|
||||
* @param fn filename ('\0' terminated string)
|
||||
* @return pointer to the dynamically allocated new entry.
|
||||
* NULL if no space for the entry.
|
||||
*/
|
||||
static ramfs_ent_t* ramfs_ent_new(const char * fn)
|
||||
{
|
||||
ramfs_ent_t* new_ent = NULL;
|
||||
new_ent = ll_ins_head(&file_ll); /*Create a new file*/
|
||||
if(new_ent == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new_ent->fn_d = krhino_mm_alloc(strlen(fn) + 1); /*Save the name*/
|
||||
strcpy(new_ent->fn_d, fn);
|
||||
new_ent->data_d = NULL;
|
||||
new_ent->size = 0;
|
||||
new_ent->oc = 0;
|
||||
new_ent->const_data = 0;
|
||||
|
||||
return new_ent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize linked list
|
||||
* @param ll_dsc pointer to ll_dsc variable
|
||||
* @param n_size the size of 1 node in bytes
|
||||
*/
|
||||
void ll_init(ll_t * ll_p, uint32_t n_size)
|
||||
{
|
||||
ll_p->head = NULL;
|
||||
ll_p->tail = NULL;
|
||||
|
||||
if(n_size & 0x3) {
|
||||
n_size &= ~0x3;
|
||||
n_size += 4;
|
||||
}
|
||||
|
||||
ll_p->n_size = n_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new head to a linked list
|
||||
* @param ll_p pointer to linked list
|
||||
* @return pointer to the new head
|
||||
*/
|
||||
void * ll_ins_head(ll_t * ll_p)
|
||||
{
|
||||
ll_node_t* n_new;
|
||||
|
||||
n_new = krhino_mm_alloc(ll_p->n_size + LL_NODE_META_SIZE);
|
||||
|
||||
if(n_new != NULL) {
|
||||
node_set_prev(ll_p, n_new, NULL); /*No prev. before the new head*/
|
||||
node_set_next(ll_p, n_new, ll_p->head); /*After new comes the old head*/
|
||||
|
||||
if(ll_p->head != NULL) { /*If there is old head then before it goes the new*/
|
||||
node_set_prev(ll_p, ll_p->head, n_new);
|
||||
}
|
||||
|
||||
ll_p->head = n_new; /*Set the new head in the dsc.*/
|
||||
if(ll_p->tail == NULL) {/*If there is no tail (1. node) set the tail too*/
|
||||
ll_p->tail = n_new;
|
||||
}
|
||||
}
|
||||
|
||||
return n_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new tail to a linked list
|
||||
* @param ll_p pointer to linked list
|
||||
* @return pointer to the new tail
|
||||
*/
|
||||
void * ll_ins_tail(ll_t * ll_p)
|
||||
{
|
||||
ll_node_t* n_new;
|
||||
|
||||
n_new = krhino_mm_alloc(ll_p->n_size + LL_NODE_META_SIZE);
|
||||
|
||||
if(n_new != NULL) {
|
||||
node_set_next(ll_p, n_new, NULL); /*No next after the new tail*/
|
||||
node_set_prev(ll_p, n_new, ll_p->tail); /*The prev. before new is tho old tail*/
|
||||
if(ll_p->tail != NULL) { /*If there is old tail then the new comes after it*/
|
||||
node_set_next(ll_p, ll_p->tail, n_new);
|
||||
}
|
||||
|
||||
ll_p->tail = n_new; /*Set the new tail in the dsc.*/
|
||||
if(ll_p->head == NULL) { /*If there is no head (1. node) set the head too*/
|
||||
ll_p->head = n_new;
|
||||
}
|
||||
}
|
||||
|
||||
return n_new;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove the node 'node_p' from 'll_p' linked list.
|
||||
* It Dose not free the the memory of node.
|
||||
* @param ll_p pointer to the linked list of 'node_p'
|
||||
* @param node_p pointer to node in 'll_p' linked list
|
||||
*/
|
||||
void ll_rem(ll_t * ll_p, void * node_p)
|
||||
{
|
||||
if(ll_get_head(ll_p) == node_p) {
|
||||
/*The new head will be the node after 'n_act'*/
|
||||
ll_p->head = ll_get_next(ll_p, node_p);
|
||||
if(ll_p->head == NULL) {
|
||||
ll_p->tail = NULL;
|
||||
}
|
||||
else {
|
||||
node_set_prev(ll_p, ll_p->head, NULL);
|
||||
}
|
||||
}
|
||||
else if(ll_get_tail(ll_p) == node_p) {
|
||||
/*The new tail will be the node before 'n_act'*/
|
||||
ll_p->tail = ll_get_prev(ll_p, node_p);
|
||||
if(ll_p->tail == NULL) {
|
||||
ll_p->head = NULL;
|
||||
}
|
||||
else {
|
||||
node_set_next(ll_p, ll_p->tail, NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ll_node_t* n_prev = ll_get_prev(ll_p, node_p);
|
||||
ll_node_t* n_next = ll_get_next(ll_p, node_p);
|
||||
|
||||
node_set_next(ll_p, n_prev, n_next);
|
||||
node_set_prev(ll_p, n_next, n_prev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and free all elements from a linked list. The list remain valid but become empty.
|
||||
* @param ll_p pointer to linked list
|
||||
*/
|
||||
void ll_clear(ll_t * ll_p)
|
||||
{
|
||||
void * i;
|
||||
void * i_next;
|
||||
|
||||
i = ll_get_head(ll_p);
|
||||
i_next = NULL;
|
||||
|
||||
while(i != NULL) {
|
||||
i_next = ll_get_next(ll_p, i);
|
||||
|
||||
ll_rem(ll_p, i);
|
||||
krhino_mm_free(i);
|
||||
|
||||
i = i_next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a node to a new linked list
|
||||
* @param ll_ori_p pointer to the original (old) linked list
|
||||
* @param ll_new_p pointer to the new linked list
|
||||
* @param node pointer to a node
|
||||
*/
|
||||
void ll_chg_list(ll_t * ll_ori_p, ll_t * ll_new_p, void * node)
|
||||
{
|
||||
ll_rem(ll_ori_p, node);
|
||||
|
||||
/*Set node as head*/
|
||||
node_set_prev(ll_new_p, node, NULL);
|
||||
node_set_next(ll_new_p, node, ll_new_p->head);
|
||||
|
||||
if(ll_new_p->head != NULL) { /*If there is old head then before it goes the new*/
|
||||
node_set_prev(ll_new_p, ll_new_p->head, node);
|
||||
}
|
||||
|
||||
ll_new_p->head = node; /*Set the new head in the dsc.*/
|
||||
if(ll_new_p->tail == NULL) { /*If there is no tail (first node) set the tail too*/
|
||||
ll_new_p->tail = node;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return with head node of the linked list
|
||||
* @param ll_p pointer to linked list
|
||||
* @return pointer to the head of 'll_p'
|
||||
*/
|
||||
void * ll_get_head(ll_t * ll_p)
|
||||
{
|
||||
void * head = NULL;
|
||||
|
||||
if(ll_p != NULL) {
|
||||
head = ll_p->head;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return with tail node of the linked list
|
||||
* @param ll_p pointer to linked list
|
||||
* @return pointer to the head of 'll_p'
|
||||
*/
|
||||
void * ll_get_tail(ll_t * ll_p)
|
||||
{
|
||||
void * tail = NULL;
|
||||
|
||||
if(ll_p != NULL) {
|
||||
tail = ll_p->tail;
|
||||
}
|
||||
|
||||
return tail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return with the pointer of the next node after 'n_act'
|
||||
* @param ll_p pointer to linked list
|
||||
* @param n_act pointer a node
|
||||
* @return pointer to the next node
|
||||
*/
|
||||
void * ll_get_next(ll_t * ll_p, void * n_act)
|
||||
{
|
||||
void * next = NULL;
|
||||
|
||||
if(ll_p != NULL) {
|
||||
ll_node_t* n_act_d = n_act;
|
||||
memcpy(&next, n_act_d + LL_NEXT_P_OFFSET(ll_p), sizeof(void *));
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return with the pointer of the previous node after 'n_act'
|
||||
* @param ll_p pointer to linked list
|
||||
* @param n_act pointer a node
|
||||
* @return pointer to the previous node
|
||||
*/
|
||||
void * ll_get_prev(ll_t * ll_p, void * n_act)
|
||||
{
|
||||
void * prev = NULL;
|
||||
|
||||
if(ll_p != NULL) {
|
||||
ll_node_t* n_act_d = n_act;
|
||||
memcpy(&prev, n_act_d + LL_PREV_P_OFFSET(ll_p), sizeof(void *));
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
void ll_swap(ll_t * ll_p, void * n1_p, void * n2_p)
|
||||
{
|
||||
(void)(ll_p);
|
||||
(void)(n1_p);
|
||||
(void)(n2_p);
|
||||
/*TODO*/
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Set the 'pervious node pointer' of a node
|
||||
* @param ll_p pointer to linked list
|
||||
* @param act pointer to a node which prev. node pointer should be set
|
||||
* @param prev pointer to a node which should be the previous node before 'act'
|
||||
*/
|
||||
static void node_set_prev(ll_t * ll_p, ll_node_t* act, ll_node_t* prev)
|
||||
{
|
||||
memcpy(act + LL_PREV_P_OFFSET(ll_p), &prev, sizeof(ll_node_t*));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the 'next node pointer' of a node
|
||||
* @param ll_p pointer to linked list
|
||||
* @param act pointer to a node which next node pointer should be set
|
||||
* @param next pointer to a node which should be the next node before 'act'
|
||||
*/
|
||||
static void node_set_next(ll_t * ll_p, ll_node_t* act, ll_node_t* next)
|
||||
{
|
||||
memcpy(act + LL_NEXT_P_OFFSET(ll_p), &next, sizeof(ll_node_t*));
|
||||
}
|
255
Living_SDK/3rdparty/experimental/ramfs/ramfs.h
vendored
Normal file
255
Living_SDK/3rdparty/experimental/ramfs/ramfs.h
vendored
Normal file
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
|
||||
*/
|
||||
|
||||
#ifndef LV_UFS_H
|
||||
#define LV_UFS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define RAMFS_LETTER 'U'
|
||||
#define R_OK 4 /* Test for read permission. */
|
||||
#define W_OK 2 /* Test for write permission. */
|
||||
#define X_OK 1 /* Test for execute permission. */
|
||||
#define F_OK 0 /* Test for existence. */
|
||||
|
||||
#define LL_READ(list, i) for(i = ll_get_head(&list); i != NULL; i = ll_get_next(&list, i))
|
||||
#define LL_READ_BACK(list, i) for(i = ll_get_tail(&list); i != NULL; i = ll_get_prev(&list, i))
|
||||
|
||||
/*Description of a file entry */
|
||||
typedef struct
|
||||
{
|
||||
char * fn_d;
|
||||
void * data_d;
|
||||
uint32_t size; /*Data length in bytes*/
|
||||
uint16_t oc; /*Open Count*/
|
||||
uint8_t const_data :1;
|
||||
uint8_t ar :1; /*1: Access for read is enabled */
|
||||
uint8_t aw :1; /*1: Access for write is enabled */
|
||||
}ramfs_ent_t;
|
||||
|
||||
/*File descriptor, used to handle opening an entry more times simultaneously
|
||||
Contains unique informations about the specific opening*/
|
||||
typedef struct
|
||||
{
|
||||
ramfs_ent_t* ent; /*Pointer to the entry*/
|
||||
uint32_t rwp; /*Read Write Pointer*/
|
||||
|
||||
}ramfs_file_t;
|
||||
|
||||
/* Read directory descriptor.
|
||||
* It is used to to iterate through the entries in a directory*/
|
||||
typedef struct
|
||||
{
|
||||
ramfs_ent_t * last_ent;
|
||||
}ramfs_dir_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RAMFS_RES_OK = 0,
|
||||
RAMFS_RES_HW_ERR, /*Low level hardware error*/
|
||||
RAMFS_RES_FS_ERR, /*Error in the file system structure */
|
||||
RAMFS_RES_NOT_EX, /*Driver, file or directory is not exists*/
|
||||
RAMFS_RES_FULL, /*Disk full*/
|
||||
RAMFS_RES_LOCKED, /*The file is already opened*/
|
||||
RAMFS_RES_DENIED, /*Access denied. Check 'fs_open' modes and write protect*/
|
||||
RAMFS_RES_BUSY, /*The file system now can't handle it, try later*/
|
||||
RAMFS_RES_TOUT, /*Process time outed*/
|
||||
RAMFS_RES_NOT_IMP, /*Requested function is not implemented*/
|
||||
RAMFS_RES_OUT_OF_MEM, /*Not enough memory for an internal operation*/
|
||||
RAMFS_RES_INV_PARAM, /*Invalid parameter among arguments*/
|
||||
RAMFS_RES_UNKNOWN, /*Other unknown error*/
|
||||
}ramfs_res_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RAMFS_MODE_WR = 0x01,
|
||||
RAMFS_MODE_RD = 0x02,
|
||||
}ramfs_mode_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t total_size;
|
||||
uint32_t free_cnt;
|
||||
uint32_t free_size;
|
||||
uint32_t free_biggest_size;
|
||||
uint32_t used_cnt;
|
||||
uint8_t used_pct;
|
||||
uint8_t frag_pct;
|
||||
}lv_mem_monitor_t;
|
||||
|
||||
/*Dummy type to make handling easier*/
|
||||
typedef uint8_t ll_node_t;
|
||||
|
||||
/*Description of a linked list*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t n_size;
|
||||
ll_node_t* head;
|
||||
ll_node_t* tail;
|
||||
}ll_t;
|
||||
|
||||
/**
|
||||
* Create a driver for ufs and initialize it.
|
||||
*/
|
||||
void ramfs_init(void);
|
||||
|
||||
/**
|
||||
* Give the state of the ufs
|
||||
* @return true if ufs is initialized and can be used else false
|
||||
*/
|
||||
bool ramfs_ready(void);
|
||||
|
||||
/**
|
||||
* Open a file in ufs
|
||||
* @param file_p pointer to a ramfs_file_t variable
|
||||
* @param fn name of the file. There are no directories so e.g. "myfile.txt"
|
||||
* @param mode element of 'fs_mode_t' enum or its 'OR' connection (e.g. FS_MODE_WR | FS_MODE_RD)
|
||||
* @return RAMFS_RES_OK: no error, the file is opened
|
||||
* any error from ramfs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_open (void * file_p, const char * fn, ramfs_mode_t mode);
|
||||
|
||||
/**
|
||||
* Create a file with a constant data
|
||||
* @param fn name of the file (directories are not supported)
|
||||
* @param const_p pointer to a constant data
|
||||
* @param len length of the data pointed by 'const_p' in bytes
|
||||
* @return RAMFS_RES_OK: no error, the file is read
|
||||
* any error from ramfs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_create_const(const char * fn, const void * const_p, uint32_t len);
|
||||
|
||||
/**
|
||||
* Close an opened file
|
||||
* @param file_p pointer to an 'ufs_file_t' variable. (opened with ramfs_open)
|
||||
* @return RAMFS_RES_OK: no error, the file is read
|
||||
* any error from ramfs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_close (void * file_p);
|
||||
|
||||
/**
|
||||
* Remove a file. The file can not be opened.
|
||||
* @param fn '\0' terminated string
|
||||
* @return RAMFS_RES_OK: no error, the file is removed
|
||||
* RAMFS_RES_DENIED: the file was opened, remove failed
|
||||
*/
|
||||
ramfs_res_t ramfs_remove(const char * fn);
|
||||
|
||||
/**
|
||||
* Read data from an opened file
|
||||
* @param file_p pointer to an 'ufs_file_t' variable. (opened with ramfs_open )
|
||||
* @param buf pointer to a memory block where to store the read data
|
||||
* @param btr number of Bytes To Read
|
||||
* @param br the real number of read bytes (Byte Read)
|
||||
* @return RAMFS_RES_OK: no error, the file is read
|
||||
* any error from ramfs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_read (void * file_p, void * buf, uint32_t btr, uint32_t * br);
|
||||
|
||||
/**
|
||||
* Write data to an opened file
|
||||
* @param file_p pointer to an 'ufs_file_t' variable. (opened with ramfs_open)
|
||||
* @param buf pointer to a memory block which content will be written
|
||||
* @param btw the number Bytes To Write
|
||||
* @param bw The real number of written bytes (Byte Written)
|
||||
* @return RAMFS_RES_OK: no error, the file is read
|
||||
* any error from ramfs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_write (void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
|
||||
|
||||
/**
|
||||
* Set the read write pointer. Also expand the file size if necessary.
|
||||
* @param file_p pointer to an 'ufs_file_t' variable. (opened with ramfs_open )
|
||||
* @param pos the new position of read write pointer
|
||||
* @return RAMFS_RES_OK: no error, the file is read
|
||||
* any error from ramfs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_seek (void * file_p, uint32_t pos);
|
||||
|
||||
/**
|
||||
* Give the position of the read write pointer
|
||||
* @param file_p pointer to an 'ufs_file_t' variable. (opened with ramfs_open )
|
||||
* @param pos_p pointer to to store the result
|
||||
* @return RAMFS_RES_OK: no error, the file is read
|
||||
* any error from ramfs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_tell (void * file_p, uint32_t * pos_p);
|
||||
|
||||
/**
|
||||
* Truncate the file size to the current position of the read write pointer
|
||||
* @param file_p pointer to an 'ufs_file_t' variable. (opened with ramfs_open )
|
||||
* @return RAMFS_RES_OK: no error, the file is read
|
||||
* any error from ramfs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_trunc (void * file_p);
|
||||
|
||||
/**
|
||||
* Give the size of the file in bytes
|
||||
* @param file_p file_p pointer to an 'ufs_file_t' variable. (opened with ramfs_open )
|
||||
* @param size_p pointer to store the size
|
||||
* @return RAMFS_RES_OK: no error, the file is read
|
||||
* any error from ramfs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_size (void * file_p, uint32_t * size_p);
|
||||
|
||||
/**
|
||||
* get access info
|
||||
* @param path uFS doesn't support folders so it has to be ""
|
||||
* @param mode the info to get
|
||||
* @return RAMFS_RES_OK or any error from lv__fs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_access(const char * path, int mode);
|
||||
|
||||
/**
|
||||
* Create a directory
|
||||
* @param path uFS doesn't support folders so it has to be ""
|
||||
* @return RAMFS_RES_OK or any error from lv__fs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_mkdir(const char * path);
|
||||
|
||||
/**
|
||||
* Initialize a ramfs_read_dir_t variable to directory reading
|
||||
* @param rddir_p pointer to a 'ufs_read_dir_t' variable
|
||||
* @param path uFS doesn't support folders so it has to be ""
|
||||
* @return RAMFS_RES_OK or any error from ramfs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_dir_open(void * rddir_p, const char * path);
|
||||
|
||||
/**
|
||||
* Read the next file name
|
||||
* @param dir_p pointer to an initialized 'ufs_read_dir_t' variable
|
||||
* @param fn pointer to buffer to sore the file name
|
||||
* @return RAMFS_RES_OK or any error from ramfs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_dir_read(void * dir_p, char * fn);
|
||||
|
||||
/**
|
||||
* Close the directory reading
|
||||
* @param rddir_p pointer to an initialized 'ufs_read_dir_t' variable
|
||||
* @return RAMFS_RES_OK or any error from ramfs_res_t enum
|
||||
*/
|
||||
ramfs_res_t ramfs_dir_close(void * rddir_p);
|
||||
|
||||
/**
|
||||
* Give the size of a drive
|
||||
* @param total_p pointer to store the total size [kB]
|
||||
* @param free_p pointer to store the free site [kB]
|
||||
* @return RAMFS_RES_OK or any error from 'fs_res_t'
|
||||
*/
|
||||
ramfs_res_t ramfs_free (uint32_t * total_p, uint32_t * free_p);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
15
Living_SDK/3rdparty/experimental/ramfs/ramfs.mk
vendored
Normal file
15
Living_SDK/3rdparty/experimental/ramfs/ramfs.mk
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
NAME := ramfs
|
||||
|
||||
$(NAME)_TYPE := kernel
|
||||
$(NAME)_SOURCES += ramfs.c
|
||||
|
||||
#default gcc
|
||||
ifeq ($(COMPILER),)
|
||||
$(NAME)_CFLAGS += -Wall -Werror
|
||||
else ifeq ($(COMPILER),gcc)
|
||||
$(NAME)_CFLAGS += -Wall -Werror
|
||||
endif
|
||||
|
||||
GLOBAL_INCLUDES += .
|
||||
GLOBAL_INCLUDES += include
|
||||
GLOBAL_DEFINES += AOS_RAMFS
|
1
Living_SDK/3rdparty/experimental/spiffs/README
vendored
Normal file
1
Living_SDK/3rdparty/experimental/spiffs/README
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
This software component is used to help users port third-party programs, but WITHOUT ANY WARRANTY. The entire risk as to the quality and performance of the program is with you. Should the program prove defective, you assume the cost of all necessary servicing, repair or correction. The use of third-party programs must also follow its own permissive license.
|
20
Living_SDK/3rdparty/experimental/spiffs/include/aos_spiffs.h
vendored
Normal file
20
Living_SDK/3rdparty/experimental/spiffs/include/aos_spiffs.h
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
|
||||
*/
|
||||
|
||||
#ifndef FS_SPIFFS_H
|
||||
#define FS_SPIFFS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int vfs_spiffs_register(void);
|
||||
int vfs_spiffs_unregister(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
408
Living_SDK/3rdparty/experimental/spiffs/include/spiffs_config.h
vendored
Normal file
408
Living_SDK/3rdparty/experimental/spiffs/include/spiffs_config.h
vendored
Normal file
|
@ -0,0 +1,408 @@
|
|||
/*
|
||||
* spiffs_config.h
|
||||
*
|
||||
* Created on: Jul 3, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#ifndef SPIFFS_CONFIG_H_
|
||||
#define SPIFFS_CONFIG_H_
|
||||
|
||||
// ----------- 8< ------------
|
||||
// Following includes are for the linux test build of spiffs
|
||||
// These may/should/must be removed/altered/replaced in your target
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <aos/aos.h>
|
||||
|
||||
// ----------- >8 ------------
|
||||
|
||||
/**************************************************************/
|
||||
/* Customer definations */
|
||||
// Set SPIFFS partition
|
||||
#ifdef CONFIG_SPIFFS_PARTITION
|
||||
#define SPIFFS_CFG_PARTITION CONFIG_SPIFFS_PARTITION
|
||||
#else
|
||||
#define SPIFFS_CFG_PARTITION HAL_PARTITION_SPIFFS
|
||||
#endif
|
||||
|
||||
// Set needed types
|
||||
typedef int32_t s32_t;
|
||||
typedef uint32_t u32_t;
|
||||
typedef int16_t s16_t;
|
||||
typedef uint16_t u16_t;
|
||||
typedef int8_t s8_t;
|
||||
typedef uint8_t u8_t;
|
||||
|
||||
struct spiffs_t;
|
||||
extern void _spiffs_lock(struct spiffs_t *fs);
|
||||
extern void _spiffs_unlock(struct spiffs_t *fs);
|
||||
|
||||
// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level
|
||||
// These should be defined on a multithreaded system
|
||||
|
||||
// define this to enter a mutex if you're running on a multithreaded system
|
||||
#define SPIFFS_LOCK(fs) _spiffs_lock(fs)
|
||||
// define this to exit a mutex if you're running on a multithreaded system
|
||||
#define SPIFFS_UNLOCK(fs) _spiffs_unlock(fs)
|
||||
|
||||
// Enable if only one spiffs instance with constant configuration will exist
|
||||
// on the target. This will reduce calculations, flash and memory accesses.
|
||||
// Parts of configuration must be defined below instead of at time of mount.
|
||||
#define SPIFFS_SINGLETON 0
|
||||
|
||||
// Instead of giving parameters in config struct, singleton build must
|
||||
// give parameters in defines below.
|
||||
#ifdef CONFIG_SPIFFS_PHYS_SZ
|
||||
#define CFG_SPIFFS_PHYS_SZ CONFIG_SPIFFS_PHYS_SZ
|
||||
#else
|
||||
#define CFG_SPIFFS_PHYS_SZ (1024 * 1024)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPIFFS_PHYS_ERASE_SZ
|
||||
#define CFG_SPIFFS_PHYS_ERASE_SZ CONFIG_SPIFFS_PHYS_ERASE_SZ
|
||||
#else
|
||||
#define CFG_SPIFFS_PHYS_ERASE_SZ (64 * 1024)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPIFFS_PHYS_ADDR
|
||||
#define CFG_SPIFFS_PHYS_ADDR CONFIG_SPIFFS_PHYS_ADDR
|
||||
#else
|
||||
#define CFG_SPIFFS_PHYS_ADDR 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPIFFS_LOG_PAGE_SZ
|
||||
#define CFG_SPIFFS_LOG_PAGE_SZ CONFIG_SPIFFS_LOG_PAGE_SZ
|
||||
#else
|
||||
#define CFG_SPIFFS_LOG_PAGE_SZ 256
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPIFFS_LOG_BLOCK_SZ
|
||||
#define CFG_SPIFFS_LOG_BLOCK_SZ CONFIG_SPIFFS_LOG_BLOCK_SZ
|
||||
#else
|
||||
#define CFG_SPIFFS_LOG_BLOCK_SZ (64 * 1024)
|
||||
#endif
|
||||
|
||||
// Set max open file
|
||||
#ifdef CONFIG_SPIFFS_MAX_FILES
|
||||
#define CFG_SPIFFS_MAX_FILES CONFIG_SPIFFS_MAX_FILES
|
||||
#else
|
||||
#define CFG_SPIFFS_MAX_FILES 4
|
||||
#endif
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
// compile time switches
|
||||
#define SPIFFS_TAG "SPIFFS"
|
||||
|
||||
// Set generic spiffs debug output call.
|
||||
#ifndef SPIFFS_DBG
|
||||
#define SPIFFS_DBG(...) //LOGD(SPIFFS_TAG, __VA_ARGS__)
|
||||
#endif
|
||||
// Set spiffs debug output call for garbage collecting.
|
||||
#ifndef SPIFFS_GC_DBG
|
||||
#define SPIFFS_GC_DBG(...) //LOGD(SPIFFS_TAG, __VA_ARGS__)
|
||||
#endif
|
||||
// Set spiffs debug output call for caching.
|
||||
#ifndef SPIFFS_CACHE_DBG
|
||||
#define SPIFFS_CACHE_DBG(...) //LOGD(SPIFFS_TAG, __VA_ARGS__)
|
||||
#endif
|
||||
// Set spiffs debug output call for system consistency checks.
|
||||
#ifndef SPIFFS_CHECK_DBG
|
||||
#define SPIFFS_CHECK_DBG(...) //LOGD(SPIFFS_TAG, __VA_ARGS__)
|
||||
#endif
|
||||
// Set spiffs debug output call for all api invocations.
|
||||
#ifndef SPIFFS_API_DBG
|
||||
#define SPIFFS_API_DBG(...) //LOGD(SPIFFS_TAG, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Defines spiffs debug print formatters
|
||||
// some general signed number
|
||||
#ifndef _SPIPRIi
|
||||
#define _SPIPRIi "%d"
|
||||
#endif
|
||||
// address
|
||||
#ifndef _SPIPRIad
|
||||
#define _SPIPRIad "%08x"
|
||||
#endif
|
||||
// block
|
||||
#ifndef _SPIPRIbl
|
||||
#define _SPIPRIbl "%04x"
|
||||
#endif
|
||||
// page
|
||||
#ifndef _SPIPRIpg
|
||||
#define _SPIPRIpg "%04x"
|
||||
#endif
|
||||
// span index
|
||||
#ifndef _SPIPRIsp
|
||||
#define _SPIPRIsp "%04x"
|
||||
#endif
|
||||
// file descriptor
|
||||
#ifndef _SPIPRIfd
|
||||
#define _SPIPRIfd "%d"
|
||||
#endif
|
||||
// file object id
|
||||
#ifndef _SPIPRIid
|
||||
#define _SPIPRIid "%04x"
|
||||
#endif
|
||||
// file flags
|
||||
#ifndef _SPIPRIfl
|
||||
#define _SPIPRIfl "%02x"
|
||||
#endif
|
||||
|
||||
|
||||
// Enable/disable API functions to determine exact number of bytes
|
||||
// for filedescriptor and cache buffers. Once decided for a configuration,
|
||||
// this can be disabled to reduce flash.
|
||||
#ifndef SPIFFS_BUFFER_HELP
|
||||
#define SPIFFS_BUFFER_HELP 0
|
||||
#endif
|
||||
|
||||
// Enables/disable memory read caching of nucleus file system operations.
|
||||
// If enabled, memory area must be provided for cache in SPIFFS_mount.
|
||||
#ifndef SPIFFS_CACHE
|
||||
#define SPIFFS_CACHE 1
|
||||
#endif
|
||||
#if SPIFFS_CACHE
|
||||
// Enables memory write caching for file descriptors in hydrogen
|
||||
#ifndef SPIFFS_CACHE_WR
|
||||
#define SPIFFS_CACHE_WR 1
|
||||
#endif
|
||||
|
||||
// Enable/disable statistics on caching. Debug/test purpose only.
|
||||
#ifndef SPIFFS_CACHE_STATS
|
||||
#define SPIFFS_CACHE_STATS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Always check header of each accessed page to ensure consistent state.
|
||||
// If enabled it will increase number of reads, will increase flash.
|
||||
#ifndef SPIFFS_PAGE_CHECK
|
||||
#define SPIFFS_PAGE_CHECK 1
|
||||
#endif
|
||||
|
||||
// Define maximum number of gc runs to perform to reach desired free pages.
|
||||
#ifndef SPIFFS_GC_MAX_RUNS
|
||||
#define SPIFFS_GC_MAX_RUNS 5
|
||||
#endif
|
||||
|
||||
// Enable/disable statistics on gc. Debug/test purpose only.
|
||||
#ifndef SPIFFS_GC_STATS
|
||||
#define SPIFFS_GC_STATS 1
|
||||
#endif
|
||||
|
||||
// Garbage collecting examines all pages in a block which and sums up
|
||||
// to a block score. Deleted pages normally gives positive score and
|
||||
// used pages normally gives a negative score (as these must be moved).
|
||||
// To have a fair wear-leveling, the erase age is also included in score,
|
||||
// whose factor normally is the most positive.
|
||||
// The larger the score, the more likely it is that the block will
|
||||
// picked for garbage collection.
|
||||
|
||||
// Garbage collecting heuristics - weight used for deleted pages.
|
||||
#ifndef SPIFFS_GC_HEUR_W_DELET
|
||||
#define SPIFFS_GC_HEUR_W_DELET (5)
|
||||
#endif
|
||||
// Garbage collecting heuristics - weight used for used pages.
|
||||
#ifndef SPIFFS_GC_HEUR_W_USED
|
||||
#define SPIFFS_GC_HEUR_W_USED (-1)
|
||||
#endif
|
||||
// Garbage collecting heuristics - weight used for time between
|
||||
// last erased and erase of this block.
|
||||
#ifndef SPIFFS_GC_HEUR_W_ERASE_AGE
|
||||
#define SPIFFS_GC_HEUR_W_ERASE_AGE (50)
|
||||
#endif
|
||||
|
||||
// Object name maximum length. Note that this length include the
|
||||
// zero-termination character, meaning maximum string of characters
|
||||
// can at most be SPIFFS_OBJ_NAME_LEN - 1.
|
||||
#ifndef SPIFFS_OBJ_NAME_LEN
|
||||
#define SPIFFS_OBJ_NAME_LEN (32)
|
||||
#endif
|
||||
|
||||
// Maximum length of the metadata associated with an object.
|
||||
// Setting to non-zero value enables metadata-related API but also
|
||||
// changes the on-disk format, so the change is not backward-compatible.
|
||||
//
|
||||
// Do note: the meta length must never exceed
|
||||
// logical_page_size - (SPIFFS_OBJ_NAME_LEN + 64)
|
||||
//
|
||||
// This is derived from following:
|
||||
// logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) +
|
||||
// spiffs_object_ix_header fields + at least some LUT entries)
|
||||
#ifndef SPIFFS_OBJ_META_LEN
|
||||
#define SPIFFS_OBJ_META_LEN (0)
|
||||
#endif
|
||||
|
||||
// Size of buffer allocated on stack used when copying data.
|
||||
// Lower value generates more read/writes. No meaning having it bigger
|
||||
// than logical page size.
|
||||
#ifndef SPIFFS_COPY_BUFFER_STACK
|
||||
#define SPIFFS_COPY_BUFFER_STACK (256)
|
||||
#endif
|
||||
|
||||
// Enable this to have an identifiable spiffs filesystem. This will look for
|
||||
// a magic in all sectors to determine if this is a valid spiffs system or
|
||||
// not on mount point. If not, SPIFFS_format must be called prior to mounting
|
||||
// again.
|
||||
#ifndef SPIFFS_USE_MAGIC
|
||||
#define SPIFFS_USE_MAGIC (1)
|
||||
#endif
|
||||
|
||||
#if SPIFFS_USE_MAGIC
|
||||
// Only valid when SPIFFS_USE_MAGIC is enabled. If SPIFFS_USE_MAGIC_LENGTH is
|
||||
// enabled, the magic will also be dependent on the length of the filesystem.
|
||||
// For example, a filesystem configured and formatted for 4 megabytes will not
|
||||
// be accepted for mounting with a configuration defining the filesystem as 2
|
||||
// megabytes.
|
||||
#ifndef SPIFFS_USE_MAGIC_LENGTH
|
||||
#define SPIFFS_USE_MAGIC_LENGTH (1)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Enable this if your target needs aligned data for index tables
|
||||
#ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
|
||||
#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 0
|
||||
#endif
|
||||
|
||||
// Enable this if you want the HAL callbacks to be called with the spiffs struct
|
||||
#ifndef SPIFFS_HAL_CALLBACK_EXTRA
|
||||
#define SPIFFS_HAL_CALLBACK_EXTRA 0
|
||||
#endif
|
||||
|
||||
// Enable this if you want to add an integer offset to all file handles
|
||||
// (spiffs_file). This is useful if running multiple instances of spiffs on
|
||||
// same target, in order to recognise to what spiffs instance a file handle
|
||||
// belongs.
|
||||
// NB: This adds config field fh_ix_offset in the configuration struct when
|
||||
// mounting, which must be defined.
|
||||
#ifndef SPIFFS_FILEHDL_OFFSET
|
||||
#define SPIFFS_FILEHDL_OFFSET 0
|
||||
#endif
|
||||
|
||||
// Enable this to compile a read only version of spiffs.
|
||||
// This will reduce binary size of spiffs. All code comprising modification
|
||||
// of the file system will not be compiled. Some config will be ignored.
|
||||
// HAL functions for erasing and writing to spi-flash may be null. Cache
|
||||
// can be disabled for even further binary size reduction (and ram savings).
|
||||
// Functions modifying the fs will return SPIFFS_ERR_RO_NOT_IMPL.
|
||||
// If the file system cannot be mounted due to aborted erase operation and
|
||||
// SPIFFS_USE_MAGIC is enabled, SPIFFS_ERR_RO_ABORTED_OPERATION will be
|
||||
// returned.
|
||||
// Might be useful for e.g. bootloaders and such.
|
||||
#ifndef SPIFFS_READ_ONLY
|
||||
#define SPIFFS_READ_ONLY 0
|
||||
#endif
|
||||
|
||||
// Enable this to add a temporal file cache using the fd buffer.
|
||||
// The effects of the cache is that SPIFFS_open will find the file faster in
|
||||
// certain cases. It will make it a lot easier for spiffs to find files
|
||||
// opened frequently, reducing number of readings from the spi flash for
|
||||
// finding those files.
|
||||
// This will grow each fd by 6 bytes. If your files are opened in patterns
|
||||
// with a degree of temporal locality, the system is optimized.
|
||||
// Examples can be letting spiffs serve web content, where one file is the css.
|
||||
// The css is accessed for each html file that is opened, meaning it is
|
||||
// accessed almost every second time a file is opened. Another example could be
|
||||
// a log file that is often opened, written, and closed.
|
||||
// The size of the cache is number of given file descriptors, as it piggybacks
|
||||
// on the fd update mechanism. The cache lives in the closed file descriptors.
|
||||
// When closed, the fd know the whereabouts of the file. Instead of forgetting
|
||||
// this, the temporal cache will keep handling updates to that file even if the
|
||||
// fd is closed. If the file is opened again, the location of the file is found
|
||||
// directly. If all available descriptors become opened, all cache memory is
|
||||
// lost.
|
||||
#ifndef SPIFFS_TEMPORAL_FD_CACHE
|
||||
#define SPIFFS_TEMPORAL_FD_CACHE 1
|
||||
#endif
|
||||
|
||||
// Temporal file cache hit score. Each time a file is opened, all cached files
|
||||
// will lose one point. If the opened file is found in cache, that entry will
|
||||
// gain SPIFFS_TEMPORAL_CACHE_HIT_SCORE points. One can experiment with this
|
||||
// value for the specific access patterns of the application. However, it must
|
||||
// be between 1 (no gain for hitting a cached entry often) and 255.
|
||||
#ifndef SPIFFS_TEMPORAL_CACHE_HIT_SCORE
|
||||
#define SPIFFS_TEMPORAL_CACHE_HIT_SCORE 4
|
||||
#endif
|
||||
|
||||
// Enable to be able to map object indices to memory.
|
||||
// This allows for faster and more deterministic reading if cases of reading
|
||||
// large files and when changing file offset by seeking around a lot.
|
||||
// When mapping a file's index, the file system will be scanned for index pages
|
||||
// and the info will be put in memory provided by user. When reading, the
|
||||
// memory map can be looked up instead of searching for index pages on the
|
||||
// medium. This way, user can trade memory against performance.
|
||||
// Whole, parts of, or future parts not being written yet can be mapped. The
|
||||
// memory array will be owned by spiffs and updated accordingly during garbage
|
||||
// collecting or when modifying the indices. The latter is invoked by when the
|
||||
// file is modified in some way. The index buffer is tied to the file
|
||||
// descriptor.
|
||||
#ifndef SPIFFS_IX_MAP
|
||||
#define SPIFFS_IX_MAP 1
|
||||
#endif
|
||||
|
||||
// By default SPIFFS in some cases relies on the property of NOR flash that bits
|
||||
// cannot be set from 0 to 1 by writing and that controllers will ignore such
|
||||
// bit changes. This results in fewer reads as SPIFFS can in some cases perform
|
||||
// blind writes, with all bits set to 1 and only those it needs reset set to 0.
|
||||
// Most of the chips and controllers allow this behavior, so the default is to
|
||||
// use this technique. If your controller is one of the rare ones that don't,
|
||||
// turn this option on and SPIFFS will perform a read-modify-write instead.
|
||||
#ifndef SPIFFS_NO_BLIND_WRITES
|
||||
#define SPIFFS_NO_BLIND_WRITES 0
|
||||
#endif
|
||||
|
||||
// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function
|
||||
// in the api. This function will visualize all filesystem using given printf
|
||||
// function.
|
||||
#ifndef SPIFFS_TEST_VISUALISATION
|
||||
#define SPIFFS_TEST_VISUALISATION 0
|
||||
#endif
|
||||
#if SPIFFS_TEST_VISUALISATION
|
||||
#ifndef spiffs_printf
|
||||
#define spiffs_printf(...) LOGD(SPIFFS_TAG, __VA_ARGS__)
|
||||
#endif
|
||||
// spiffs_printf argument for a free page
|
||||
#ifndef SPIFFS_TEST_VIS_FREE_STR
|
||||
#define SPIFFS_TEST_VIS_FREE_STR "_"
|
||||
#endif
|
||||
// spiffs_printf argument for a deleted page
|
||||
#ifndef SPIFFS_TEST_VIS_DELE_STR
|
||||
#define SPIFFS_TEST_VIS_DELE_STR "/"
|
||||
#endif
|
||||
// spiffs_printf argument for an index page for given object id
|
||||
#ifndef SPIFFS_TEST_VIS_INDX_STR
|
||||
#define SPIFFS_TEST_VIS_INDX_STR(id) "i"
|
||||
#endif
|
||||
// spiffs_printf argument for a data page for given object id
|
||||
#ifndef SPIFFS_TEST_VIS_DATA_STR
|
||||
#define SPIFFS_TEST_VIS_DATA_STR(id) "d"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Types depending on configuration such as the amount of flash bytes
|
||||
// given to spiffs file system in total (spiffs_file_system_size),
|
||||
// the logical block size (log_block_size), and the logical page size
|
||||
// (log_page_size)
|
||||
|
||||
// Block index type. Make sure the size of this type can hold
|
||||
// the highest number of all blocks - i.e. spiffs_file_system_size / log_block_size
|
||||
typedef u16_t spiffs_block_ix;
|
||||
// Page index type. Make sure the size of this type can hold
|
||||
// the highest page number of all pages - i.e. spiffs_file_system_size / log_page_size
|
||||
typedef u16_t spiffs_page_ix;
|
||||
// Object id type - most significant bit is reserved for index flag. Make sure the
|
||||
// size of this type can hold the highest object id on a full system,
|
||||
// i.e. 2 + (spiffs_file_system_size / (2*log_page_size))*2
|
||||
typedef u16_t spiffs_obj_id;
|
||||
// Object span index type. Make sure the size of this type can
|
||||
// hold the largest possible span index on the system -
|
||||
// i.e. (spiffs_file_system_size / log_page_size) - 1
|
||||
typedef u16_t spiffs_span_ix;
|
||||
|
||||
#endif /* SPIFFS_CONFIG_H_ */
|
20
Living_SDK/3rdparty/experimental/spiffs/spiffs.mk
vendored
Normal file
20
Living_SDK/3rdparty/experimental/spiffs/spiffs.mk
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
NAME := spiffs
|
||||
|
||||
$(NAME)_TYPE := kernel
|
||||
|
||||
$(NAME)_SOURCES += spiffs_port.c \
|
||||
spiffs/spiffs_cache.c \
|
||||
spiffs/spiffs_check.c \
|
||||
spiffs/spiffs_gc.c \
|
||||
spiffs/spiffs_hydrogen.c \
|
||||
spiffs/spiffs_nucleus.c
|
||||
|
||||
#default gcc
|
||||
ifeq ($(COMPILER),)
|
||||
$(NAME)_CFLAGS += -Wall -Werror
|
||||
else ifeq ($(COMPILER),gcc)
|
||||
$(NAME)_CFLAGS += -Wall -Werror
|
||||
endif
|
||||
|
||||
GLOBAL_INCLUDES += include spiffs/include
|
||||
GLOBAL_DEFINES += AOS_SPIFFS
|
373
Living_SDK/3rdparty/experimental/spiffs/spiffs/default/spiffs_config.h
vendored
Normal file
373
Living_SDK/3rdparty/experimental/spiffs/spiffs/default/spiffs_config.h
vendored
Normal file
|
@ -0,0 +1,373 @@
|
|||
/*
|
||||
* spiffs_config.h
|
||||
*
|
||||
* Created on: Jul 3, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#ifndef SPIFFS_CONFIG_H_
|
||||
#define SPIFFS_CONFIG_H_
|
||||
|
||||
// ----------- 8< ------------
|
||||
// Following includes are for the linux test build of spiffs
|
||||
// These may/should/must be removed/altered/replaced in your target
|
||||
#include "params_test.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#ifdef _SPIFFS_TEST
|
||||
#include "testrunner.h"
|
||||
#endif
|
||||
// ----------- >8 ------------
|
||||
|
||||
// compile time switches
|
||||
|
||||
// Set generic spiffs debug output call.
|
||||
#ifndef SPIFFS_DBG
|
||||
#define SPIFFS_DBG(_f, ...) //printf(_f, ## __VA_ARGS__)
|
||||
#endif
|
||||
// Set spiffs debug output call for garbage collecting.
|
||||
#ifndef SPIFFS_GC_DBG
|
||||
#define SPIFFS_GC_DBG(_f, ...) //printf(_f, ## __VA_ARGS__)
|
||||
#endif
|
||||
// Set spiffs debug output call for caching.
|
||||
#ifndef SPIFFS_CACHE_DBG
|
||||
#define SPIFFS_CACHE_DBG(_f, ...) //printf(_f, ## __VA_ARGS__)
|
||||
#endif
|
||||
// Set spiffs debug output call for system consistency checks.
|
||||
#ifndef SPIFFS_CHECK_DBG
|
||||
#define SPIFFS_CHECK_DBG(_f, ...) //printf(_f, ## __VA_ARGS__)
|
||||
#endif
|
||||
// Set spiffs debug output call for all api invocations.
|
||||
#ifndef SPIFFS_API_DBG
|
||||
#define SPIFFS_API_DBG(_f, ...) //printf(_f, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Defines spiffs debug print formatters
|
||||
// some general signed number
|
||||
#ifndef _SPIPRIi
|
||||
#define _SPIPRIi "%d"
|
||||
#endif
|
||||
// address
|
||||
#ifndef _SPIPRIad
|
||||
#define _SPIPRIad "%08x"
|
||||
#endif
|
||||
// block
|
||||
#ifndef _SPIPRIbl
|
||||
#define _SPIPRIbl "%04x"
|
||||
#endif
|
||||
// page
|
||||
#ifndef _SPIPRIpg
|
||||
#define _SPIPRIpg "%04x"
|
||||
#endif
|
||||
// span index
|
||||
#ifndef _SPIPRIsp
|
||||
#define _SPIPRIsp "%04x"
|
||||
#endif
|
||||
// file descriptor
|
||||
#ifndef _SPIPRIfd
|
||||
#define _SPIPRIfd "%d"
|
||||
#endif
|
||||
// file object id
|
||||
#ifndef _SPIPRIid
|
||||
#define _SPIPRIid "%04x"
|
||||
#endif
|
||||
// file flags
|
||||
#ifndef _SPIPRIfl
|
||||
#define _SPIPRIfl "%02x"
|
||||
#endif
|
||||
|
||||
|
||||
// Enable/disable API functions to determine exact number of bytes
|
||||
// for filedescriptor and cache buffers. Once decided for a configuration,
|
||||
// this can be disabled to reduce flash.
|
||||
#ifndef SPIFFS_BUFFER_HELP
|
||||
#define SPIFFS_BUFFER_HELP 0
|
||||
#endif
|
||||
|
||||
// Enables/disable memory read caching of nucleus file system operations.
|
||||
// If enabled, memory area must be provided for cache in SPIFFS_mount.
|
||||
#ifndef SPIFFS_CACHE
|
||||
#define SPIFFS_CACHE 1
|
||||
#endif
|
||||
#if SPIFFS_CACHE
|
||||
// Enables memory write caching for file descriptors in hydrogen
|
||||
#ifndef SPIFFS_CACHE_WR
|
||||
#define SPIFFS_CACHE_WR 1
|
||||
#endif
|
||||
|
||||
// Enable/disable statistics on caching. Debug/test purpose only.
|
||||
#ifndef SPIFFS_CACHE_STATS
|
||||
#define SPIFFS_CACHE_STATS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Always check header of each accessed page to ensure consistent state.
|
||||
// If enabled it will increase number of reads, will increase flash.
|
||||
#ifndef SPIFFS_PAGE_CHECK
|
||||
#define SPIFFS_PAGE_CHECK 1
|
||||
#endif
|
||||
|
||||
// Define maximum number of gc runs to perform to reach desired free pages.
|
||||
#ifndef SPIFFS_GC_MAX_RUNS
|
||||
#define SPIFFS_GC_MAX_RUNS 5
|
||||
#endif
|
||||
|
||||
// Enable/disable statistics on gc. Debug/test purpose only.
|
||||
#ifndef SPIFFS_GC_STATS
|
||||
#define SPIFFS_GC_STATS 1
|
||||
#endif
|
||||
|
||||
// Garbage collecting examines all pages in a block which and sums up
|
||||
// to a block score. Deleted pages normally gives positive score and
|
||||
// used pages normally gives a negative score (as these must be moved).
|
||||
// To have a fair wear-leveling, the erase age is also included in score,
|
||||
// whose factor normally is the most positive.
|
||||
// The larger the score, the more likely it is that the block will
|
||||
// picked for garbage collection.
|
||||
|
||||
// Garbage collecting heuristics - weight used for deleted pages.
|
||||
#ifndef SPIFFS_GC_HEUR_W_DELET
|
||||
#define SPIFFS_GC_HEUR_W_DELET (5)
|
||||
#endif
|
||||
// Garbage collecting heuristics - weight used for used pages.
|
||||
#ifndef SPIFFS_GC_HEUR_W_USED
|
||||
#define SPIFFS_GC_HEUR_W_USED (-1)
|
||||
#endif
|
||||
// Garbage collecting heuristics - weight used for time between
|
||||
// last erased and erase of this block.
|
||||
#ifndef SPIFFS_GC_HEUR_W_ERASE_AGE
|
||||
#define SPIFFS_GC_HEUR_W_ERASE_AGE (50)
|
||||
#endif
|
||||
|
||||
// Object name maximum length. Note that this length include the
|
||||
// zero-termination character, meaning maximum string of characters
|
||||
// can at most be SPIFFS_OBJ_NAME_LEN - 1.
|
||||
#ifndef SPIFFS_OBJ_NAME_LEN
|
||||
#define SPIFFS_OBJ_NAME_LEN (32)
|
||||
#endif
|
||||
|
||||
// Maximum length of the metadata associated with an object.
|
||||
// Setting to non-zero value enables metadata-related API but also
|
||||
// changes the on-disk format, so the change is not backward-compatible.
|
||||
//
|
||||
// Do note: the meta length must never exceed
|
||||
// logical_page_size - (SPIFFS_OBJ_NAME_LEN + 64)
|
||||
//
|
||||
// This is derived from following:
|
||||
// logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) +
|
||||
// spiffs_object_ix_header fields + at least some LUT entries)
|
||||
#ifndef SPIFFS_OBJ_META_LEN
|
||||
#define SPIFFS_OBJ_META_LEN (0)
|
||||
#endif
|
||||
|
||||
// Size of buffer allocated on stack used when copying data.
|
||||
// Lower value generates more read/writes. No meaning having it bigger
|
||||
// than logical page size.
|
||||
#ifndef SPIFFS_COPY_BUFFER_STACK
|
||||
#define SPIFFS_COPY_BUFFER_STACK (64)
|
||||
#endif
|
||||
|
||||
// Enable this to have an identifiable spiffs filesystem. This will look for
|
||||
// a magic in all sectors to determine if this is a valid spiffs system or
|
||||
// not on mount point. If not, SPIFFS_format must be called prior to mounting
|
||||
// again.
|
||||
#ifndef SPIFFS_USE_MAGIC
|
||||
#define SPIFFS_USE_MAGIC (0)
|
||||
#endif
|
||||
|
||||
#if SPIFFS_USE_MAGIC
|
||||
// Only valid when SPIFFS_USE_MAGIC is enabled. If SPIFFS_USE_MAGIC_LENGTH is
|
||||
// enabled, the magic will also be dependent on the length of the filesystem.
|
||||
// For example, a filesystem configured and formatted for 4 megabytes will not
|
||||
// be accepted for mounting with a configuration defining the filesystem as 2
|
||||
// megabytes.
|
||||
#ifndef SPIFFS_USE_MAGIC_LENGTH
|
||||
#define SPIFFS_USE_MAGIC_LENGTH (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level
|
||||
// These should be defined on a multithreaded system
|
||||
|
||||
// define this to enter a mutex if you're running on a multithreaded system
|
||||
#ifndef SPIFFS_LOCK
|
||||
#define SPIFFS_LOCK(fs)
|
||||
#endif
|
||||
// define this to exit a mutex if you're running on a multithreaded system
|
||||
#ifndef SPIFFS_UNLOCK
|
||||
#define SPIFFS_UNLOCK(fs)
|
||||
#endif
|
||||
|
||||
// Enable if only one spiffs instance with constant configuration will exist
|
||||
// on the target. This will reduce calculations, flash and memory accesses.
|
||||
// Parts of configuration must be defined below instead of at time of mount.
|
||||
#ifndef SPIFFS_SINGLETON
|
||||
#define SPIFFS_SINGLETON 0
|
||||
#endif
|
||||
|
||||
#if SPIFFS_SINGLETON
|
||||
// Instead of giving parameters in config struct, singleton build must
|
||||
// give parameters in defines below.
|
||||
#ifndef SPIFFS_CFG_PHYS_SZ
|
||||
#define SPIFFS_CFG_PHYS_SZ(ignore) (1024*1024*2)
|
||||
#endif
|
||||
#ifndef SPIFFS_CFG_PHYS_ERASE_SZ
|
||||
#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore) (65536)
|
||||
#endif
|
||||
#ifndef SPIFFS_CFG_PHYS_ADDR
|
||||
#define SPIFFS_CFG_PHYS_ADDR(ignore) (0)
|
||||
#endif
|
||||
#ifndef SPIFFS_CFG_LOG_PAGE_SZ
|
||||
#define SPIFFS_CFG_LOG_PAGE_SZ(ignore) (256)
|
||||
#endif
|
||||
#ifndef SPIFFS_CFG_LOG_BLOCK_SZ
|
||||
#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore) (65536)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Enable this if your target needs aligned data for index tables
|
||||
#ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
|
||||
#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 0
|
||||
#endif
|
||||
|
||||
// Enable this if you want the HAL callbacks to be called with the spiffs struct
|
||||
#ifndef SPIFFS_HAL_CALLBACK_EXTRA
|
||||
#define SPIFFS_HAL_CALLBACK_EXTRA 0
|
||||
#endif
|
||||
|
||||
// Enable this if you want to add an integer offset to all file handles
|
||||
// (spiffs_file). This is useful if running multiple instances of spiffs on
|
||||
// same target, in order to recognise to what spiffs instance a file handle
|
||||
// belongs.
|
||||
// NB: This adds config field fh_ix_offset in the configuration struct when
|
||||
// mounting, which must be defined.
|
||||
#ifndef SPIFFS_FILEHDL_OFFSET
|
||||
#define SPIFFS_FILEHDL_OFFSET 0
|
||||
#endif
|
||||
|
||||
// Enable this to compile a read only version of spiffs.
|
||||
// This will reduce binary size of spiffs. All code comprising modification
|
||||
// of the file system will not be compiled. Some config will be ignored.
|
||||
// HAL functions for erasing and writing to spi-flash may be null. Cache
|
||||
// can be disabled for even further binary size reduction (and ram savings).
|
||||
// Functions modifying the fs will return SPIFFS_ERR_RO_NOT_IMPL.
|
||||
// If the file system cannot be mounted due to aborted erase operation and
|
||||
// SPIFFS_USE_MAGIC is enabled, SPIFFS_ERR_RO_ABORTED_OPERATION will be
|
||||
// returned.
|
||||
// Might be useful for e.g. bootloaders and such.
|
||||
#ifndef SPIFFS_READ_ONLY
|
||||
#define SPIFFS_READ_ONLY 0
|
||||
#endif
|
||||
|
||||
// Enable this to add a temporal file cache using the fd buffer.
|
||||
// The effects of the cache is that SPIFFS_open will find the file faster in
|
||||
// certain cases. It will make it a lot easier for spiffs to find files
|
||||
// opened frequently, reducing number of readings from the spi flash for
|
||||
// finding those files.
|
||||
// This will grow each fd by 6 bytes. If your files are opened in patterns
|
||||
// with a degree of temporal locality, the system is optimized.
|
||||
// Examples can be letting spiffs serve web content, where one file is the css.
|
||||
// The css is accessed for each html file that is opened, meaning it is
|
||||
// accessed almost every second time a file is opened. Another example could be
|
||||
// a log file that is often opened, written, and closed.
|
||||
// The size of the cache is number of given file descriptors, as it piggybacks
|
||||
// on the fd update mechanism. The cache lives in the closed file descriptors.
|
||||
// When closed, the fd know the whereabouts of the file. Instead of forgetting
|
||||
// this, the temporal cache will keep handling updates to that file even if the
|
||||
// fd is closed. If the file is opened again, the location of the file is found
|
||||
// directly. If all available descriptors become opened, all cache memory is
|
||||
// lost.
|
||||
#ifndef SPIFFS_TEMPORAL_FD_CACHE
|
||||
#define SPIFFS_TEMPORAL_FD_CACHE 1
|
||||
#endif
|
||||
|
||||
// Temporal file cache hit score. Each time a file is opened, all cached files
|
||||
// will lose one point. If the opened file is found in cache, that entry will
|
||||
// gain SPIFFS_TEMPORAL_CACHE_HIT_SCORE points. One can experiment with this
|
||||
// value for the specific access patterns of the application. However, it must
|
||||
// be between 1 (no gain for hitting a cached entry often) and 255.
|
||||
#ifndef SPIFFS_TEMPORAL_CACHE_HIT_SCORE
|
||||
#define SPIFFS_TEMPORAL_CACHE_HIT_SCORE 4
|
||||
#endif
|
||||
|
||||
// Enable to be able to map object indices to memory.
|
||||
// This allows for faster and more deterministic reading if cases of reading
|
||||
// large files and when changing file offset by seeking around a lot.
|
||||
// When mapping a file's index, the file system will be scanned for index pages
|
||||
// and the info will be put in memory provided by user. When reading, the
|
||||
// memory map can be looked up instead of searching for index pages on the
|
||||
// medium. This way, user can trade memory against performance.
|
||||
// Whole, parts of, or future parts not being written yet can be mapped. The
|
||||
// memory array will be owned by spiffs and updated accordingly during garbage
|
||||
// collecting or when modifying the indices. The latter is invoked by when the
|
||||
// file is modified in some way. The index buffer is tied to the file
|
||||
// descriptor.
|
||||
#ifndef SPIFFS_IX_MAP
|
||||
#define SPIFFS_IX_MAP 1
|
||||
#endif
|
||||
|
||||
// By default SPIFFS in some cases relies on the property of NOR flash that bits
|
||||
// cannot be set from 0 to 1 by writing and that controllers will ignore such
|
||||
// bit changes. This results in fewer reads as SPIFFS can in some cases perform
|
||||
// blind writes, with all bits set to 1 and only those it needs reset set to 0.
|
||||
// Most of the chips and controllers allow this behavior, so the default is to
|
||||
// use this technique. If your controller is one of the rare ones that don't,
|
||||
// turn this option on and SPIFFS will perform a read-modify-write instead.
|
||||
#ifndef SPIFFS_NO_BLIND_WRITES
|
||||
#define SPIFFS_NO_BLIND_WRITES 0
|
||||
#endif
|
||||
|
||||
// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function
|
||||
// in the api. This function will visualize all filesystem using given printf
|
||||
// function.
|
||||
#ifndef SPIFFS_TEST_VISUALISATION
|
||||
#define SPIFFS_TEST_VISUALISATION 1
|
||||
#endif
|
||||
#if SPIFFS_TEST_VISUALISATION
|
||||
#ifndef spiffs_printf
|
||||
#define spiffs_printf(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
// spiffs_printf argument for a free page
|
||||
#ifndef SPIFFS_TEST_VIS_FREE_STR
|
||||
#define SPIFFS_TEST_VIS_FREE_STR "_"
|
||||
#endif
|
||||
// spiffs_printf argument for a deleted page
|
||||
#ifndef SPIFFS_TEST_VIS_DELE_STR
|
||||
#define SPIFFS_TEST_VIS_DELE_STR "/"
|
||||
#endif
|
||||
// spiffs_printf argument for an index page for given object id
|
||||
#ifndef SPIFFS_TEST_VIS_INDX_STR
|
||||
#define SPIFFS_TEST_VIS_INDX_STR(id) "i"
|
||||
#endif
|
||||
// spiffs_printf argument for a data page for given object id
|
||||
#ifndef SPIFFS_TEST_VIS_DATA_STR
|
||||
#define SPIFFS_TEST_VIS_DATA_STR(id) "d"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Types depending on configuration such as the amount of flash bytes
|
||||
// given to spiffs file system in total (spiffs_file_system_size),
|
||||
// the logical block size (log_block_size), and the logical page size
|
||||
// (log_page_size)
|
||||
|
||||
// Block index type. Make sure the size of this type can hold
|
||||
// the highest number of all blocks - i.e. spiffs_file_system_size / log_block_size
|
||||
typedef u16_t spiffs_block_ix;
|
||||
// Page index type. Make sure the size of this type can hold
|
||||
// the highest page number of all pages - i.e. spiffs_file_system_size / log_page_size
|
||||
typedef u16_t spiffs_page_ix;
|
||||
// Object id type - most significant bit is reserved for index flag. Make sure the
|
||||
// size of this type can hold the highest object id on a full system,
|
||||
// i.e. 2 + (spiffs_file_system_size / (2*log_page_size))*2
|
||||
typedef u16_t spiffs_obj_id;
|
||||
// Object span index type. Make sure the size of this type can
|
||||
// hold the largest possible span index on the system -
|
||||
// i.e. (spiffs_file_system_size / log_page_size) - 1
|
||||
typedef u16_t spiffs_span_ix;
|
||||
|
||||
#endif /* SPIFFS_CONFIG_H_ */
|
816
Living_SDK/3rdparty/experimental/spiffs/spiffs/include/spiffs.h
vendored
Normal file
816
Living_SDK/3rdparty/experimental/spiffs/spiffs/include/spiffs.h
vendored
Normal file
|
@ -0,0 +1,816 @@
|
|||
/*
|
||||
* spiffs.h
|
||||
*
|
||||
* Created on: May 26, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#ifndef SPIFFS_H_
|
||||
#define SPIFFS_H_
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "spiffs_config.h"
|
||||
|
||||
#define SPIFFS_OK 0
|
||||
#define SPIFFS_ERR_NOT_MOUNTED -10000
|
||||
#define SPIFFS_ERR_FULL -10001
|
||||
#define SPIFFS_ERR_NOT_FOUND -10002
|
||||
#define SPIFFS_ERR_END_OF_OBJECT -10003
|
||||
#define SPIFFS_ERR_DELETED -10004
|
||||
#define SPIFFS_ERR_NOT_FINALIZED -10005
|
||||
#define SPIFFS_ERR_NOT_INDEX -10006
|
||||
#define SPIFFS_ERR_OUT_OF_FILE_DESCS -10007
|
||||
#define SPIFFS_ERR_FILE_CLOSED -10008
|
||||
#define SPIFFS_ERR_FILE_DELETED -10009
|
||||
#define SPIFFS_ERR_BAD_DESCRIPTOR -10010
|
||||
#define SPIFFS_ERR_IS_INDEX -10011
|
||||
#define SPIFFS_ERR_IS_FREE -10012
|
||||
#define SPIFFS_ERR_INDEX_SPAN_MISMATCH -10013
|
||||
#define SPIFFS_ERR_DATA_SPAN_MISMATCH -10014
|
||||
#define SPIFFS_ERR_INDEX_REF_FREE -10015
|
||||
#define SPIFFS_ERR_INDEX_REF_LU -10016
|
||||
#define SPIFFS_ERR_INDEX_REF_INVALID -10017
|
||||
#define SPIFFS_ERR_INDEX_FREE -10018
|
||||
#define SPIFFS_ERR_INDEX_LU -10019
|
||||
#define SPIFFS_ERR_INDEX_INVALID -10020
|
||||
#define SPIFFS_ERR_NOT_WRITABLE -10021
|
||||
#define SPIFFS_ERR_NOT_READABLE -10022
|
||||
#define SPIFFS_ERR_CONFLICTING_NAME -10023
|
||||
#define SPIFFS_ERR_NOT_CONFIGURED -10024
|
||||
|
||||
#define SPIFFS_ERR_NOT_A_FS -10025
|
||||
#define SPIFFS_ERR_MOUNTED -10026
|
||||
#define SPIFFS_ERR_ERASE_FAIL -10027
|
||||
#define SPIFFS_ERR_MAGIC_NOT_POSSIBLE -10028
|
||||
|
||||
#define SPIFFS_ERR_NO_DELETED_BLOCKS -10029
|
||||
|
||||
#define SPIFFS_ERR_FILE_EXISTS -10030
|
||||
|
||||
#define SPIFFS_ERR_NOT_A_FILE -10031
|
||||
#define SPIFFS_ERR_RO_NOT_IMPL -10032
|
||||
#define SPIFFS_ERR_RO_ABORTED_OPERATION -10033
|
||||
#define SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS -10034
|
||||
#define SPIFFS_ERR_PROBE_NOT_A_FS -10035
|
||||
#define SPIFFS_ERR_NAME_TOO_LONG -10036
|
||||
|
||||
#define SPIFFS_ERR_IX_MAP_UNMAPPED -10037
|
||||
#define SPIFFS_ERR_IX_MAP_MAPPED -10038
|
||||
#define SPIFFS_ERR_IX_MAP_BAD_RANGE -10039
|
||||
|
||||
#define SPIFFS_ERR_SEEK_BOUNDS -10040
|
||||
|
||||
|
||||
#define SPIFFS_ERR_INTERNAL -10050
|
||||
|
||||
#define SPIFFS_ERR_TEST -10100
|
||||
|
||||
|
||||
// spiffs file descriptor index type. must be signed
|
||||
typedef s16_t spiffs_file;
|
||||
// spiffs file descriptor flags
|
||||
typedef u16_t spiffs_flags;
|
||||
// spiffs file mode
|
||||
typedef u16_t spiffs_mode;
|
||||
// object type
|
||||
typedef u8_t spiffs_obj_type;
|
||||
|
||||
struct spiffs_t;
|
||||
|
||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* spi read call function type */
|
||||
typedef s32_t (*spiffs_read)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *dst);
|
||||
/* spi write call function type */
|
||||
typedef s32_t (*spiffs_write)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *src);
|
||||
/* spi erase call function type */
|
||||
typedef s32_t (*spiffs_erase)(struct spiffs_t *fs, u32_t addr, u32_t size);
|
||||
|
||||
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* spi read call function type */
|
||||
typedef s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst);
|
||||
/* spi write call function type */
|
||||
typedef s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src);
|
||||
/* spi erase call function type */
|
||||
typedef s32_t (*spiffs_erase)(u32_t addr, u32_t size);
|
||||
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* file system check callback report operation */
|
||||
typedef enum {
|
||||
SPIFFS_CHECK_LOOKUP = 0,
|
||||
SPIFFS_CHECK_INDEX,
|
||||
SPIFFS_CHECK_PAGE
|
||||
} spiffs_check_type;
|
||||
|
||||
/* file system check callback report type */
|
||||
typedef enum {
|
||||
SPIFFS_CHECK_PROGRESS = 0,
|
||||
SPIFFS_CHECK_ERROR,
|
||||
SPIFFS_CHECK_FIX_INDEX,
|
||||
SPIFFS_CHECK_FIX_LOOKUP,
|
||||
SPIFFS_CHECK_DELETE_ORPHANED_INDEX,
|
||||
SPIFFS_CHECK_DELETE_PAGE,
|
||||
SPIFFS_CHECK_DELETE_BAD_FILE
|
||||
} spiffs_check_report;
|
||||
|
||||
/* file system check callback function */
|
||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||
typedef void (*spiffs_check_callback)(struct spiffs_t *fs, spiffs_check_type type, spiffs_check_report report,
|
||||
u32_t arg1, u32_t arg2);
|
||||
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_report report,
|
||||
u32_t arg1, u32_t arg2);
|
||||
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* file system listener callback operation */
|
||||
typedef enum {
|
||||
/* the file has been created */
|
||||
SPIFFS_CB_CREATED = 0,
|
||||
/* the file has been updated or moved to another page */
|
||||
SPIFFS_CB_UPDATED,
|
||||
/* the file has been deleted */
|
||||
SPIFFS_CB_DELETED
|
||||
} spiffs_fileop_type;
|
||||
|
||||
/* file system listener callback function */
|
||||
typedef void (*spiffs_file_callback)(struct spiffs_t *fs, spiffs_fileop_type op, spiffs_obj_id obj_id, spiffs_page_ix pix);
|
||||
|
||||
#ifndef SPIFFS_DBG
|
||||
#define SPIFFS_DBG(...) \
|
||||
printf(__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef SPIFFS_GC_DBG
|
||||
#define SPIFFS_GC_DBG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef SPIFFS_CACHE_DBG
|
||||
#define SPIFFS_CACHE_DBG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef SPIFFS_CHECK_DBG
|
||||
#define SPIFFS_CHECK_DBG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* Any write to the filehandle is appended to end of the file */
|
||||
#define SPIFFS_APPEND (1<<0)
|
||||
#define SPIFFS_O_APPEND SPIFFS_APPEND
|
||||
/* If the opened file exists, it will be truncated to zero length before opened */
|
||||
#define SPIFFS_TRUNC (1<<1)
|
||||
#define SPIFFS_O_TRUNC SPIFFS_TRUNC
|
||||
/* If the opened file does not exist, it will be created before opened */
|
||||
#define SPIFFS_CREAT (1<<2)
|
||||
#define SPIFFS_O_CREAT SPIFFS_CREAT
|
||||
/* The opened file may only be read */
|
||||
#define SPIFFS_RDONLY (1<<3)
|
||||
#define SPIFFS_O_RDONLY SPIFFS_RDONLY
|
||||
/* The opened file may only be written */
|
||||
#define SPIFFS_WRONLY (1<<4)
|
||||
#define SPIFFS_O_WRONLY SPIFFS_WRONLY
|
||||
/* The opened file may be both read and written */
|
||||
#define SPIFFS_RDWR (SPIFFS_RDONLY | SPIFFS_WRONLY)
|
||||
#define SPIFFS_O_RDWR SPIFFS_RDWR
|
||||
/* Any writes to the filehandle will never be cached but flushed directly */
|
||||
#define SPIFFS_DIRECT (1<<5)
|
||||
#define SPIFFS_O_DIRECT SPIFFS_DIRECT
|
||||
/* If SPIFFS_O_CREAT and SPIFFS_O_EXCL are set, SPIFFS_open() shall fail if the file exists */
|
||||
#define SPIFFS_EXCL (1<<6)
|
||||
#define SPIFFS_O_EXCL SPIFFS_EXCL
|
||||
|
||||
#define SPIFFS_SEEK_SET (0)
|
||||
#define SPIFFS_SEEK_CUR (1)
|
||||
#define SPIFFS_SEEK_END (2)
|
||||
|
||||
#define SPIFFS_TYPE_FILE (1)
|
||||
#define SPIFFS_TYPE_DIR (2)
|
||||
#define SPIFFS_TYPE_HARD_LINK (3)
|
||||
#define SPIFFS_TYPE_SOFT_LINK (4)
|
||||
|
||||
#ifndef SPIFFS_LOCK
|
||||
#define SPIFFS_LOCK(fs)
|
||||
#endif
|
||||
|
||||
#ifndef SPIFFS_UNLOCK
|
||||
#define SPIFFS_UNLOCK(fs)
|
||||
#endif
|
||||
|
||||
// phys structs
|
||||
|
||||
// spiffs spi configuration struct
|
||||
typedef struct {
|
||||
// physical read function
|
||||
spiffs_read hal_read_f;
|
||||
// physical write function
|
||||
spiffs_write hal_write_f;
|
||||
// physical erase function
|
||||
spiffs_erase hal_erase_f;
|
||||
#if SPIFFS_SINGLETON == 0
|
||||
// physical size of the spi flash
|
||||
u32_t phys_size;
|
||||
// physical offset in spi flash used for spiffs,
|
||||
// must be on block boundary
|
||||
u32_t phys_addr;
|
||||
// physical size when erasing a block
|
||||
u32_t phys_erase_block;
|
||||
|
||||
// logical size of a block, must be on physical
|
||||
// block size boundary and must never be less than
|
||||
// a physical block
|
||||
u32_t log_block_size;
|
||||
// logical size of a page, must be at least
|
||||
// log_block_size / 8
|
||||
u32_t log_page_size;
|
||||
|
||||
#endif
|
||||
#if SPIFFS_FILEHDL_OFFSET
|
||||
// an integer offset added to each file handle
|
||||
u16_t fh_ix_offset;
|
||||
#endif
|
||||
} spiffs_config;
|
||||
|
||||
typedef struct spiffs_t {
|
||||
// file system configuration
|
||||
spiffs_config cfg;
|
||||
// number of logical blocks
|
||||
u32_t block_count;
|
||||
|
||||
// cursor for free blocks, block index
|
||||
spiffs_block_ix free_cursor_block_ix;
|
||||
// cursor for free blocks, entry index
|
||||
int free_cursor_obj_lu_entry;
|
||||
// cursor when searching, block index
|
||||
spiffs_block_ix cursor_block_ix;
|
||||
// cursor when searching, entry index
|
||||
int cursor_obj_lu_entry;
|
||||
|
||||
// primary work buffer, size of a logical page
|
||||
u8_t *lu_work;
|
||||
// secondary work buffer, size of a logical page
|
||||
u8_t *work;
|
||||
// file descriptor memory area
|
||||
u8_t *fd_space;
|
||||
// available file descriptors
|
||||
u32_t fd_count;
|
||||
|
||||
// last error
|
||||
s32_t err_code;
|
||||
|
||||
// current number of free blocks
|
||||
u32_t free_blocks;
|
||||
// current number of busy pages
|
||||
u32_t stats_p_allocated;
|
||||
// current number of deleted pages
|
||||
u32_t stats_p_deleted;
|
||||
// flag indicating that garbage collector is cleaning
|
||||
u8_t cleaning;
|
||||
// max erase count amongst all blocks
|
||||
spiffs_obj_id max_erase_count;
|
||||
|
||||
#if SPIFFS_GC_STATS
|
||||
u32_t stats_gc_runs;
|
||||
#endif
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
// cache memory
|
||||
void *cache;
|
||||
// cache size
|
||||
u32_t cache_size;
|
||||
#if SPIFFS_CACHE_STATS
|
||||
u32_t cache_hits;
|
||||
u32_t cache_misses;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// check callback function
|
||||
spiffs_check_callback check_cb_f;
|
||||
// file callback function
|
||||
spiffs_file_callback file_cb_f;
|
||||
// mounted flag
|
||||
u8_t mounted;
|
||||
// user data
|
||||
void *user_data;
|
||||
// config magic
|
||||
u32_t config_magic;
|
||||
} spiffs;
|
||||
|
||||
/* spiffs file status struct */
|
||||
typedef struct {
|
||||
spiffs_obj_id obj_id;
|
||||
u32_t size;
|
||||
spiffs_obj_type type;
|
||||
spiffs_page_ix pix;
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||
#if SPIFFS_OBJ_META_LEN
|
||||
u8_t meta[SPIFFS_OBJ_META_LEN];
|
||||
#endif
|
||||
} spiffs_stat;
|
||||
|
||||
struct spiffs_dirent {
|
||||
spiffs_obj_id obj_id;
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||
spiffs_obj_type type;
|
||||
u32_t size;
|
||||
spiffs_page_ix pix;
|
||||
#if SPIFFS_OBJ_META_LEN
|
||||
u8_t meta[SPIFFS_OBJ_META_LEN];
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
spiffs *fs;
|
||||
spiffs_block_ix block;
|
||||
int entry;
|
||||
} spiffs_DIR;
|
||||
|
||||
#if SPIFFS_IX_MAP
|
||||
|
||||
typedef struct {
|
||||
// buffer with looked up data pixes
|
||||
spiffs_page_ix *map_buf;
|
||||
// precise file byte offset
|
||||
u32_t offset;
|
||||
// start data span index of lookup buffer
|
||||
spiffs_span_ix start_spix;
|
||||
// end data span index of lookup buffer
|
||||
spiffs_span_ix end_spix;
|
||||
} spiffs_ix_map;
|
||||
|
||||
#endif
|
||||
|
||||
// functions
|
||||
|
||||
#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
|
||||
/**
|
||||
* Special function. This takes a spiffs config struct and returns the number
|
||||
* of blocks this file system was formatted with. This function relies on
|
||||
* that following info is set correctly in given config struct:
|
||||
*
|
||||
* phys_addr, log_page_size, and log_block_size.
|
||||
*
|
||||
* Also, hal_read_f must be set in the config struct.
|
||||
*
|
||||
* One must be sure of the correct page size and that the physical address is
|
||||
* correct in the probed file system when calling this function. It is not
|
||||
* checked if the phys_addr actually points to the start of the file system,
|
||||
* so one might get a false positive if entering a phys_addr somewhere in the
|
||||
* middle of the file system at block boundary. In addition, it is not checked
|
||||
* if the page size is actually correct. If it is not, weird file system sizes
|
||||
* will be returned.
|
||||
*
|
||||
* If this function detects a file system it returns the assumed file system
|
||||
* size, which can be used to set the phys_size.
|
||||
*
|
||||
* Otherwise, it returns an error indicating why it is not regarded as a file
|
||||
* system.
|
||||
*
|
||||
* Note: this function is not protected with SPIFFS_LOCK and SPIFFS_UNLOCK
|
||||
* macros. It returns the error code directly, instead of as read by
|
||||
* SPIFFS_errno.
|
||||
*
|
||||
* @param config essential parts of the physical and logical
|
||||
* configuration of the file system.
|
||||
*/
|
||||
s32_t SPIFFS_probe_fs(spiffs_config *config);
|
||||
#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
|
||||
|
||||
/**
|
||||
* Initializes the file system dynamic parameters and mounts the filesystem.
|
||||
* If SPIFFS_USE_MAGIC is enabled the mounting may fail with SPIFFS_ERR_NOT_A_FS
|
||||
* if the flash does not contain a recognizable file system.
|
||||
* In this case, SPIFFS_format must be called prior to remounting.
|
||||
* @param fs the file system struct
|
||||
* @param config the physical and logical configuration of the file system
|
||||
* @param work a memory work buffer comprising 2*config->log_page_size
|
||||
* bytes used throughout all file system operations
|
||||
* @param fd_space memory for file descriptors
|
||||
* @param fd_space_size memory size of file descriptors
|
||||
* @param cache memory for cache, may be null
|
||||
* @param cache_size memory size of cache
|
||||
* @param check_cb_f callback function for reporting during consistency checks
|
||||
*/
|
||||
s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
|
||||
u8_t *fd_space, u32_t fd_space_size,
|
||||
void *cache, u32_t cache_size,
|
||||
spiffs_check_callback check_cb_f);
|
||||
|
||||
/**
|
||||
* Unmounts the file system. All file handles will be flushed of any
|
||||
* cached writes and closed.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
void SPIFFS_unmount(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Creates a new file.
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the new file
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
* Opens/creates a file.
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the new file
|
||||
* @param flags the flags for the open command, can be combinations of
|
||||
* SPIFFS_O_APPEND, SPIFFS_O_TRUNC, SPIFFS_O_CREAT, SPIFFS_O_RDONLY,
|
||||
* SPIFFS_O_WRONLY, SPIFFS_O_RDWR, SPIFFS_O_DIRECT, SPIFFS_O_EXCL
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
* Opens a file by given dir entry.
|
||||
* Optimization purposes, when traversing a file system with SPIFFS_readdir
|
||||
* a normal SPIFFS_open would need to traverse the filesystem again to find
|
||||
* the file, whilst SPIFFS_open_by_dirent already knows where the file resides.
|
||||
* @param fs the file system struct
|
||||
* @param e the dir entry to the file
|
||||
* @param flags the flags for the open command, can be combinations of
|
||||
* SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
|
||||
* SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
|
||||
* SPIFFS_CREAT will have no effect in this case.
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
* Opens a file by given page index.
|
||||
* Optimization purposes, opens a file by directly pointing to the page
|
||||
* index in the spi flash.
|
||||
* If the page index does not point to a file header SPIFFS_ERR_NOT_A_FILE
|
||||
* is returned.
|
||||
* @param fs the file system struct
|
||||
* @param page_ix the page index
|
||||
* @param flags the flags for the open command, can be combinations of
|
||||
* SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
|
||||
* SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
|
||||
* SPIFFS_CREAT will have no effect in this case.
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
* Reads from given filehandle.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle
|
||||
* @param buf where to put read data
|
||||
* @param len how much to read
|
||||
* @returns number of bytes read, or -1 if error
|
||||
*/
|
||||
s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
|
||||
|
||||
/**
|
||||
* Writes to given filehandle.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle
|
||||
* @param buf the data to write
|
||||
* @param len how much to write
|
||||
* @returns number of bytes written, or -1 if error
|
||||
*/
|
||||
s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
|
||||
|
||||
/**
|
||||
* Moves the read/write file offset. Resulting offset is returned or negative if error.
|
||||
* lseek(fs, fd, 0, SPIFFS_SEEK_CUR) will thus return current offset.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle
|
||||
* @param offs how much/where to move the offset
|
||||
* @param whence if SPIFFS_SEEK_SET, the file offset shall be set to offset bytes
|
||||
* if SPIFFS_SEEK_CUR, the file offset shall be set to its current location plus offset
|
||||
* if SPIFFS_SEEK_END, the file offset shall be set to the size of the file plus offse, which should be negative
|
||||
*/
|
||||
s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence);
|
||||
|
||||
/**
|
||||
* Removes a file by path
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the file to remove
|
||||
*/
|
||||
s32_t SPIFFS_remove(spiffs *fs, const char *path);
|
||||
|
||||
/**
|
||||
* Removes a file by filehandle
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to remove
|
||||
*/
|
||||
s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Gets file status by path
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the file to stat
|
||||
* @param s the stat struct to populate
|
||||
*/
|
||||
s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s);
|
||||
|
||||
/**
|
||||
* Gets file status by filehandle
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to stat
|
||||
* @param s the stat struct to populate
|
||||
*/
|
||||
s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s);
|
||||
|
||||
/**
|
||||
* Flushes all pending write operations from cache for given file
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to flush
|
||||
*/
|
||||
s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Closes a filehandle. If there are pending write operations, these are finalized before closing.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to close
|
||||
*/
|
||||
s32_t SPIFFS_close(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Renames a file
|
||||
* @param fs the file system struct
|
||||
* @param old path of file to rename
|
||||
* @param newPath new path of file
|
||||
*/
|
||||
s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newPath);
|
||||
|
||||
#if SPIFFS_OBJ_META_LEN
|
||||
/**
|
||||
* Updates file's metadata
|
||||
* @param fs the file system struct
|
||||
* @param path path to the file
|
||||
* @param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long.
|
||||
*/
|
||||
s32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta);
|
||||
|
||||
/**
|
||||
* Updates file's metadata
|
||||
* @param fs the file system struct
|
||||
* @param fh file handle of the file
|
||||
* @param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long.
|
||||
*/
|
||||
s32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns last error of last file operation.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_errno(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Clears last error.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
void SPIFFS_clearerr(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Opens a directory stream corresponding to the given name.
|
||||
* The stream is positioned at the first entry in the directory.
|
||||
* On hydrogen builds the name argument is ignored as hydrogen builds always correspond
|
||||
* to a flat file structure - no directories.
|
||||
* @param fs the file system struct
|
||||
* @param name the name of the directory
|
||||
* @param d pointer the directory stream to be populated
|
||||
*/
|
||||
spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d);
|
||||
|
||||
/**
|
||||
* Closes a directory stream
|
||||
* @param d the directory stream to close
|
||||
*/
|
||||
s32_t SPIFFS_closedir(spiffs_DIR *d);
|
||||
|
||||
/**
|
||||
* Reads a directory into given spifs_dirent struct.
|
||||
* @param d pointer to the directory stream
|
||||
* @param e the dirent struct to be populated
|
||||
* @returns null if error or end of stream, else given dirent is returned
|
||||
*/
|
||||
struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e);
|
||||
|
||||
/**
|
||||
* Runs a consistency check on given filesystem.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_check(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Returns number of total bytes available and number of used bytes.
|
||||
* This is an estimation, and depends on if there a many files with little
|
||||
* data or few files with much data.
|
||||
* NB: If used number of bytes exceeds total bytes, a SPIFFS_check should
|
||||
* run. This indicates a power loss in midst of things. In worst case
|
||||
* (repeated powerlosses in mending or gc) you might have to delete some files.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param total total number of bytes in filesystem
|
||||
* @param used used number of bytes in filesystem
|
||||
*/
|
||||
s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used);
|
||||
|
||||
/**
|
||||
* Formats the entire file system. All data will be lost.
|
||||
* The filesystem must not be mounted when calling this.
|
||||
*
|
||||
* NB: formatting is awkward. Due to backwards compatibility, SPIFFS_mount
|
||||
* MUST be called prior to formatting in order to configure the filesystem.
|
||||
* If SPIFFS_mount succeeds, SPIFFS_unmount must be called before calling
|
||||
* SPIFFS_format.
|
||||
* If SPIFFS_mount fails, SPIFFS_format can be called directly without calling
|
||||
* SPIFFS_unmount first.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_format(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Returns nonzero if spiffs is mounted, or zero if unmounted.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
u8_t SPIFFS_mounted(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Tries to find a block where most or all pages are deleted, and erase that
|
||||
* block if found. Does not care for wear levelling. Will not move pages
|
||||
* around.
|
||||
* If parameter max_free_pages are set to 0, only blocks with only deleted
|
||||
* pages will be selected.
|
||||
*
|
||||
* NB: the garbage collector is automatically called when spiffs needs free
|
||||
* pages. The reason for this function is to give possibility to do background
|
||||
* tidying when user knows the system is idle.
|
||||
*
|
||||
* Use with care.
|
||||
*
|
||||
* Setting max_free_pages to anything larger than zero will eventually wear
|
||||
* flash more as a block containing free pages can be erased.
|
||||
*
|
||||
* Will set err_no to SPIFFS_OK if a block was found and erased,
|
||||
* SPIFFS_ERR_NO_DELETED_BLOCK if no matching block was found,
|
||||
* or other error.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param max_free_pages maximum number allowed free pages in block
|
||||
*/
|
||||
s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages);
|
||||
|
||||
/**
|
||||
* Will try to make room for given amount of bytes in the filesystem by moving
|
||||
* pages and erasing blocks.
|
||||
* If it is physically impossible, err_no will be set to SPIFFS_ERR_FULL. If
|
||||
* there already is this amount (or more) of free space, SPIFFS_gc will
|
||||
* silently return. It is recommended to call SPIFFS_info before invoking
|
||||
* this method in order to determine what amount of bytes to give.
|
||||
*
|
||||
* NB: the garbage collector is automatically called when spiffs needs free
|
||||
* pages. The reason for this function is to give possibility to do background
|
||||
* tidying when user knows the system is idle.
|
||||
*
|
||||
* Use with care.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param size amount of bytes that should be freed
|
||||
*/
|
||||
s32_t SPIFFS_gc(spiffs *fs, u32_t size);
|
||||
|
||||
/**
|
||||
* Check if EOF reached.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to check
|
||||
*/
|
||||
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Get position in file.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to check
|
||||
*/
|
||||
s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Registers a callback function that keeps track on operations on file
|
||||
* headers. Do note, that this callback is called from within internal spiffs
|
||||
* mechanisms. Any operations on the actual file system being callbacked from
|
||||
* in this callback will mess things up for sure - do not do this.
|
||||
* This can be used to track where files are and move around during garbage
|
||||
* collection, which in turn can be used to build location tables in ram.
|
||||
* Used in conjuction with SPIFFS_open_by_page this may improve performance
|
||||
* when opening a lot of files.
|
||||
* Must be invoked after mount.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param cb_func the callback on file operations
|
||||
*/
|
||||
s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func);
|
||||
|
||||
#if SPIFFS_IX_MAP
|
||||
|
||||
/**
|
||||
* Maps the first level index lookup to a given memory map.
|
||||
* This will make reading big files faster, as the memory map will be used for
|
||||
* looking up data pages instead of searching for the indices on the physical
|
||||
* medium. When mapping, all affected indicies are found and the information is
|
||||
* copied to the array.
|
||||
* Whole file or only parts of it may be mapped. The index map will cover file
|
||||
* contents from argument offset until and including arguments (offset+len).
|
||||
* It is valid to map a longer range than the current file size. The map will
|
||||
* then be populated when the file grows.
|
||||
* On garbage collections and file data page movements, the map array will be
|
||||
* automatically updated. Do not tamper with the map array, as this contains
|
||||
* the references to the data pages. Modifying it from outside will corrupt any
|
||||
* future readings using this file descriptor.
|
||||
* The map will no longer be used when the file descriptor closed or the file
|
||||
* is unmapped.
|
||||
* This can be useful to get faster and more deterministic timing when reading
|
||||
* large files, or when seeking and reading a lot within a file.
|
||||
* @param fs the file system struct
|
||||
* @param fh the file handle of the file to map
|
||||
* @param map a spiffs_ix_map struct, describing the index map
|
||||
* @param offset absolute file offset where to start the index map
|
||||
* @param len length of the mapping in actual file bytes
|
||||
* @param map_buf the array buffer for the look up data - number of required
|
||||
* elements in the array can be derived from function
|
||||
* SPIFFS_bytes_to_ix_map_entries given the length
|
||||
*/
|
||||
s32_t SPIFFS_ix_map(spiffs *fs, spiffs_file fh, spiffs_ix_map *map,
|
||||
u32_t offset, u32_t len, spiffs_page_ix *map_buf);
|
||||
|
||||
/**
|
||||
* Unmaps the index lookup from this filehandle. All future readings will
|
||||
* proceed as normal, requiring reading of the first level indices from
|
||||
* physical media.
|
||||
* The map and map buffer given in function SPIFFS_ix_map will no longer be
|
||||
* referenced by spiffs.
|
||||
* It is not strictly necessary to unmap a file before closing it, as closing
|
||||
* a file will automatically unmap it.
|
||||
* @param fs the file system struct
|
||||
* @param fh the file handle of the file to unmap
|
||||
*/
|
||||
s32_t SPIFFS_ix_unmap(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Moves the offset for the index map given in function SPIFFS_ix_map. Parts or
|
||||
* all of the map buffer will repopulated.
|
||||
* @param fs the file system struct
|
||||
* @param fh the mapped file handle of the file to remap
|
||||
* @param offset new absolute file offset where to start the index map
|
||||
*/
|
||||
s32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offs);
|
||||
|
||||
/**
|
||||
* Utility function to get number of spiffs_page_ix entries a map buffer must
|
||||
* contain on order to map given amount of file data in bytes.
|
||||
* See function SPIFFS_ix_map and SPIFFS_ix_map_entries_to_bytes.
|
||||
* @param fs the file system struct
|
||||
* @param bytes number of file data bytes to map
|
||||
* @return needed number of elements in a spiffs_page_ix array needed to
|
||||
* map given amount of bytes in a file
|
||||
*/
|
||||
s32_t SPIFFS_bytes_to_ix_map_entries(spiffs *fs, u32_t bytes);
|
||||
|
||||
/**
|
||||
* Utility function to amount of file data bytes that can be mapped when
|
||||
* mapping a file with buffer having given number of spiffs_page_ix entries.
|
||||
* See function SPIFFS_ix_map and SPIFFS_bytes_to_ix_map_entries.
|
||||
* @param fs the file system struct
|
||||
* @param map_page_ix_entries number of entries in a spiffs_page_ix array
|
||||
* @return amount of file data in bytes that can be mapped given a map
|
||||
* buffer having given amount of spiffs_page_ix entries
|
||||
*/
|
||||
s32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries);
|
||||
|
||||
#endif // SPIFFS_IX_MAP
|
||||
|
||||
|
||||
#if SPIFFS_TEST_VISUALISATION
|
||||
/**
|
||||
* Prints out a visualization of the filesystem.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_vis(spiffs *fs);
|
||||
#endif
|
||||
|
||||
#if SPIFFS_BUFFER_HELP
|
||||
/**
|
||||
* Returns number of bytes needed for the filedescriptor buffer given
|
||||
* amount of file descriptors.
|
||||
*/
|
||||
u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs);
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
/**
|
||||
* Returns number of bytes needed for the cache buffer given
|
||||
* amount of cache pages.
|
||||
*/
|
||||
u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
#endif
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SPIFFS_H_ */
|
842
Living_SDK/3rdparty/experimental/spiffs/spiffs/include/spiffs_nucleus.h
vendored
Normal file
842
Living_SDK/3rdparty/experimental/spiffs/spiffs/include/spiffs_nucleus.h
vendored
Normal file
|
@ -0,0 +1,842 @@
|
|||
/*
|
||||
* spiffs_nucleus.h
|
||||
*
|
||||
* Created on: Jun 15, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
/* SPIFFS layout
|
||||
*
|
||||
* spiffs is designed for following spi flash characteristics:
|
||||
* - only big areas of data (blocks) can be erased
|
||||
* - erasing resets all bits in a block to ones
|
||||
* - writing pulls ones to zeroes
|
||||
* - zeroes cannot be pulled to ones, without erase
|
||||
* - wear leveling
|
||||
*
|
||||
* spiffs is also meant to be run on embedded, memory constraint devices.
|
||||
*
|
||||
* Entire area is divided in blocks. Entire area is also divided in pages.
|
||||
* Each block contains same number of pages. A page cannot be erased, but a
|
||||
* block can be erased.
|
||||
*
|
||||
* Entire area must be block_size * x
|
||||
* page_size must be block_size / (2^y) where y > 2
|
||||
*
|
||||
* ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes
|
||||
*
|
||||
* BLOCK 0 PAGE 0 object lookup 1
|
||||
* PAGE 1 object lookup 2
|
||||
* ...
|
||||
* PAGE n-1 object lookup n
|
||||
* PAGE n object data 1
|
||||
* PAGE n+1 object data 2
|
||||
* ...
|
||||
* PAGE n+m-1 object data m
|
||||
*
|
||||
* BLOCK 1 PAGE n+m object lookup 1
|
||||
* PAGE n+m+1 object lookup 2
|
||||
* ...
|
||||
* PAGE 2n+m-1 object lookup n
|
||||
* PAGE 2n+m object data 1
|
||||
* PAGE 2n+m object data 2
|
||||
* ...
|
||||
* PAGE 2n+2m-1 object data m
|
||||
* ...
|
||||
*
|
||||
* n is number of object lookup pages, which is number of pages needed to index all pages
|
||||
* in a block by object id
|
||||
* : block_size / page_size * sizeof(obj_id) / page_size
|
||||
* m is number data pages, which is number of pages in block minus number of lookup pages
|
||||
* : block_size / page_size - block_size / page_size * sizeof(obj_id) / page_size
|
||||
* thus, n+m is total number of pages in a block
|
||||
* : block_size / page_size
|
||||
*
|
||||
* ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256
|
||||
*
|
||||
* Object lookup pages contain object id entries. Each entry represent the corresponding
|
||||
* data page.
|
||||
* Assuming a 16 bit object id, an object id being 0xffff represents a free page.
|
||||
* An object id being 0x0000 represents a deleted page.
|
||||
*
|
||||
* ex: page 0 : lookup : 0008 0001 0aaa ffff ffff ffff ffff ffff ..
|
||||
* page 1 : lookup : ffff ffff ffff ffff ffff ffff ffff ffff ..
|
||||
* page 2 : data : data for object id 0008
|
||||
* page 3 : data : data for object id 0001
|
||||
* page 4 : data : data for object id 0aaa
|
||||
* ...
|
||||
*
|
||||
*
|
||||
* Object data pages can be either object index pages or object content.
|
||||
* All object data pages contains a data page header, containing object id and span index.
|
||||
* The span index denotes the object page ordering amongst data pages with same object id.
|
||||
* This applies to both object index pages (when index spans more than one page of entries),
|
||||
* and object data pages.
|
||||
* An object index page contains page entries pointing to object content page. The entry index
|
||||
* in a object index page correlates to the span index in the actual object data page.
|
||||
* The first object index page (span index 0) is called object index header page, and also
|
||||
* contains object flags (directory/file), size, object name etc.
|
||||
*
|
||||
* ex:
|
||||
* BLOCK 1
|
||||
* PAGE 256: objectl lookup page 1
|
||||
* [*123] [ 123] [ 123] [ 123]
|
||||
* [ 123] [*123] [ 123] [ 123]
|
||||
* [free] [free] [free] [free] ...
|
||||
* PAGE 257: objectl lookup page 2
|
||||
* [free] [free] [free] [free] ...
|
||||
* PAGE 258: object index page (header)
|
||||
* obj.id:0123 span.ix:0000 flags:INDEX
|
||||
* size:1600 name:ex.txt type:file
|
||||
* [259] [260] [261] [262]
|
||||
* PAGE 259: object data page
|
||||
* obj.id:0123 span.ix:0000 flags:DATA
|
||||
* PAGE 260: object data page
|
||||
* obj.id:0123 span.ix:0001 flags:DATA
|
||||
* PAGE 261: object data page
|
||||
* obj.id:0123 span.ix:0002 flags:DATA
|
||||
* PAGE 262: object data page
|
||||
* obj.id:0123 span.ix:0003 flags:DATA
|
||||
* PAGE 263: object index page
|
||||
* obj.id:0123 span.ix:0001 flags:INDEX
|
||||
* [264] [265] [fre] [fre]
|
||||
* [fre] [fre] [fre] [fre]
|
||||
* PAGE 264: object data page
|
||||
* obj.id:0123 span.ix:0004 flags:DATA
|
||||
* PAGE 265: object data page
|
||||
* obj.id:0123 span.ix:0005 flags:DATA
|
||||
*
|
||||
*/
|
||||
#ifndef SPIFFS_NUCLEUS_H_
|
||||
#define SPIFFS_NUCLEUS_H_
|
||||
|
||||
#define _SPIFFS_ERR_CHECK_FIRST (SPIFFS_ERR_INTERNAL - 1)
|
||||
#define SPIFFS_ERR_CHECK_OBJ_ID_MISM (SPIFFS_ERR_INTERNAL - 1)
|
||||
#define SPIFFS_ERR_CHECK_SPIX_MISM (SPIFFS_ERR_INTERNAL - 2)
|
||||
#define SPIFFS_ERR_CHECK_FLAGS_BAD (SPIFFS_ERR_INTERNAL - 3)
|
||||
#define _SPIFFS_ERR_CHECK_LAST (SPIFFS_ERR_INTERNAL - 4)
|
||||
|
||||
// visitor result, continue searching
|
||||
#define SPIFFS_VIS_COUNTINUE (SPIFFS_ERR_INTERNAL - 20)
|
||||
// visitor result, continue searching after reloading lu buffer
|
||||
#define SPIFFS_VIS_COUNTINUE_RELOAD (SPIFFS_ERR_INTERNAL - 21)
|
||||
// visitor result, stop searching
|
||||
#define SPIFFS_VIS_END (SPIFFS_ERR_INTERNAL - 22)
|
||||
|
||||
// updating an object index contents
|
||||
#define SPIFFS_EV_IX_UPD (0)
|
||||
// creating a new object index
|
||||
#define SPIFFS_EV_IX_NEW (1)
|
||||
// deleting an object index
|
||||
#define SPIFFS_EV_IX_DEL (2)
|
||||
// moving an object index without updating contents
|
||||
#define SPIFFS_EV_IX_MOV (3)
|
||||
// updating an object index header data only, not the table itself
|
||||
#define SPIFFS_EV_IX_UPD_HDR (4)
|
||||
|
||||
#define SPIFFS_OBJ_ID_IX_FLAG ((spiffs_obj_id)(1<<(8*sizeof(spiffs_obj_id)-1)))
|
||||
|
||||
#define SPIFFS_UNDEFINED_LEN (u32_t)(-1)
|
||||
|
||||
#define SPIFFS_OBJ_ID_DELETED ((spiffs_obj_id)0)
|
||||
#define SPIFFS_OBJ_ID_FREE ((spiffs_obj_id)-1)
|
||||
|
||||
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__)
|
||||
/* For GCC, clang and TI compilers */
|
||||
#define SPIFFS_PACKED __attribute__((packed))
|
||||
#elif defined(__ICCARM__) || defined(__CC_ARM)
|
||||
/* For IAR ARM and Keil MDK-ARM compilers */
|
||||
#define SPIFFS_PACKED
|
||||
|
||||
#else
|
||||
/* Unknown compiler */
|
||||
#define SPIFFS_PACKED
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if SPIFFS_USE_MAGIC
|
||||
#if !SPIFFS_USE_MAGIC_LENGTH
|
||||
#define SPIFFS_MAGIC(fs, bix) \
|
||||
((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs)))
|
||||
#else // SPIFFS_USE_MAGIC_LENGTH
|
||||
#define SPIFFS_MAGIC(fs, bix) \
|
||||
((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs) ^ ((fs)->block_count - (bix))))
|
||||
#endif // SPIFFS_USE_MAGIC_LENGTH
|
||||
#endif // SPIFFS_USE_MAGIC
|
||||
|
||||
#define SPIFFS_CONFIG_MAGIC (0x20090315)
|
||||
|
||||
#if SPIFFS_SINGLETON == 0
|
||||
#define SPIFFS_CFG_LOG_PAGE_SZ(fs) \
|
||||
((fs)->cfg.log_page_size)
|
||||
#define SPIFFS_CFG_LOG_BLOCK_SZ(fs) \
|
||||
((fs)->cfg.log_block_size)
|
||||
#define SPIFFS_CFG_PHYS_SZ(fs) \
|
||||
((fs)->cfg.phys_size)
|
||||
#define SPIFFS_CFG_PHYS_ERASE_SZ(fs) \
|
||||
((fs)->cfg.phys_erase_block)
|
||||
#define SPIFFS_CFG_PHYS_ADDR(fs) \
|
||||
((fs)->cfg.phys_addr)
|
||||
#endif
|
||||
|
||||
// total number of pages
|
||||
#define SPIFFS_MAX_PAGES(fs) \
|
||||
( SPIFFS_CFG_PHYS_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// total number of pages per block, including object lookup pages
|
||||
#define SPIFFS_PAGES_PER_BLOCK(fs) \
|
||||
( SPIFFS_CFG_LOG_BLOCK_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// number of object lookup pages per block
|
||||
#define SPIFFS_OBJ_LOOKUP_PAGES(fs) \
|
||||
(MAX(1, (SPIFFS_PAGES_PER_BLOCK(fs) * sizeof(spiffs_obj_id)) / SPIFFS_CFG_LOG_PAGE_SZ(fs)) )
|
||||
// checks if page index belongs to object lookup
|
||||
#define SPIFFS_IS_LOOKUP_PAGE(fs,pix) \
|
||||
(((pix) % SPIFFS_PAGES_PER_BLOCK(fs)) < SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||||
// number of object lookup entries in all object lookup pages
|
||||
#define SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) \
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||||
// converts a block to physical address
|
||||
#define SPIFFS_BLOCK_TO_PADDR(fs, block) \
|
||||
( SPIFFS_CFG_PHYS_ADDR(fs) + (block)* SPIFFS_CFG_LOG_BLOCK_SZ(fs) )
|
||||
// converts a object lookup entry to page index
|
||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, block, entry) \
|
||||
((block)*SPIFFS_PAGES_PER_BLOCK(fs) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry))
|
||||
// converts a object lookup entry to physical address of corresponding page
|
||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, block, entry) \
|
||||
(SPIFFS_BLOCK_TO_PADDR(fs, block) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// converts a page to physical address
|
||||
#define SPIFFS_PAGE_TO_PADDR(fs, page) \
|
||||
( SPIFFS_CFG_PHYS_ADDR(fs) + (page) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// converts a physical address to page
|
||||
#define SPIFFS_PADDR_TO_PAGE(fs, addr) \
|
||||
( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) / SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// gives index in page for a physical address
|
||||
#define SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr) \
|
||||
( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) % SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// returns containing block for given page
|
||||
#define SPIFFS_BLOCK_FOR_PAGE(fs, page) \
|
||||
( (page) / SPIFFS_PAGES_PER_BLOCK(fs) )
|
||||
// returns starting page for block
|
||||
#define SPIFFS_PAGE_FOR_BLOCK(fs, block) \
|
||||
( (block) * SPIFFS_PAGES_PER_BLOCK(fs) )
|
||||
// converts page to entry in object lookup page
|
||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, page) \
|
||||
( (page) % SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs) )
|
||||
// returns data size in a data page
|
||||
#define SPIFFS_DATA_PAGE_SIZE(fs) \
|
||||
( SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header) )
|
||||
// returns physical address for block's erase count,
|
||||
// always in the physical last entry of the last object lookup page
|
||||
#define SPIFFS_ERASE_COUNT_PADDR(fs, bix) \
|
||||
( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id) )
|
||||
// returns physical address for block's magic,
|
||||
// always in the physical second last entry of the last object lookup page
|
||||
#define SPIFFS_MAGIC_PADDR(fs, bix) \
|
||||
( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id)*2 )
|
||||
// checks if there is any room for magic in the object luts
|
||||
#define SPIFFS_CHECK_MAGIC_POSSIBLE(fs) \
|
||||
( (SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) % (SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(spiffs_obj_id))) * sizeof(spiffs_obj_id) \
|
||||
<= (SPIFFS_CFG_LOG_PAGE_SZ(fs)-sizeof(spiffs_obj_id)*2) )
|
||||
|
||||
// define helpers object
|
||||
|
||||
// entries in an object header page index
|
||||
#define SPIFFS_OBJ_HDR_IX_LEN(fs) \
|
||||
((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header))/sizeof(spiffs_page_ix))
|
||||
// entries in an object page index
|
||||
#define SPIFFS_OBJ_IX_LEN(fs) \
|
||||
((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix))/sizeof(spiffs_page_ix))
|
||||
// object index entry for given data span index
|
||||
#define SPIFFS_OBJ_IX_ENTRY(fs, spix) \
|
||||
((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? (spix) : (((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))%SPIFFS_OBJ_IX_LEN(fs)))
|
||||
// object index span index number for given data span index or entry
|
||||
#define SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, spix) \
|
||||
((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? 0 : (1+((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))/SPIFFS_OBJ_IX_LEN(fs)))
|
||||
// get data span index for object index span index
|
||||
#define SPIFFS_DATA_SPAN_IX_FOR_OBJ_IX_SPAN_IX(fs, spix) \
|
||||
( (spix) == 0 ? 0 : (SPIFFS_OBJ_HDR_IX_LEN(fs) + (((spix)-1) * SPIFFS_OBJ_IX_LEN(fs))) )
|
||||
|
||||
#if SPIFFS_FILEHDL_OFFSET
|
||||
#define SPIFFS_FH_OFFS(fs, fh) ((fh) != 0 ? ((fh) + (fs)->cfg.fh_ix_offset) : 0)
|
||||
#define SPIFFS_FH_UNOFFS(fs, fh) ((fh) != 0 ? ((fh) - (fs)->cfg.fh_ix_offset) : 0)
|
||||
#else
|
||||
#define SPIFFS_FH_OFFS(fs, fh) (fh)
|
||||
#define SPIFFS_FH_UNOFFS(fs, fh) (fh)
|
||||
#endif
|
||||
|
||||
|
||||
#define SPIFFS_OP_T_OBJ_LU (0<<0)
|
||||
#define SPIFFS_OP_T_OBJ_LU2 (1<<0)
|
||||
#define SPIFFS_OP_T_OBJ_IX (2<<0)
|
||||
#define SPIFFS_OP_T_OBJ_DA (3<<0)
|
||||
#define SPIFFS_OP_C_DELE (0<<2)
|
||||
#define SPIFFS_OP_C_UPDT (1<<2)
|
||||
#define SPIFFS_OP_C_MOVS (2<<2)
|
||||
#define SPIFFS_OP_C_MOVD (3<<2)
|
||||
#define SPIFFS_OP_C_FLSH (4<<2)
|
||||
#define SPIFFS_OP_C_READ (5<<2)
|
||||
#define SPIFFS_OP_C_WRTHRU (6<<2)
|
||||
|
||||
#define SPIFFS_OP_TYPE_MASK (3<<0)
|
||||
#define SPIFFS_OP_COM_MASK (7<<2)
|
||||
|
||||
|
||||
// if 0, this page is written to, else clean
|
||||
#define SPIFFS_PH_FLAG_USED (1<<0)
|
||||
// if 0, writing is finalized, else under modification
|
||||
#define SPIFFS_PH_FLAG_FINAL (1<<1)
|
||||
// if 0, this is an index page, else a data page
|
||||
#define SPIFFS_PH_FLAG_INDEX (1<<2)
|
||||
// if 0, page is deleted, else valid
|
||||
#define SPIFFS_PH_FLAG_DELET (1<<7)
|
||||
// if 0, this index header is being deleted
|
||||
#define SPIFFS_PH_FLAG_IXDELE (1<<6)
|
||||
|
||||
|
||||
#define SPIFFS_CHECK_MOUNT(fs) \
|
||||
((fs)->mounted != 0)
|
||||
|
||||
#define SPIFFS_CHECK_CFG(fs) \
|
||||
((fs)->config_magic == SPIFFS_CONFIG_MAGIC)
|
||||
|
||||
#define SPIFFS_CHECK_RES(res) \
|
||||
do { \
|
||||
if ((res) < SPIFFS_OK) return (res); \
|
||||
} while (0);
|
||||
|
||||
#define SPIFFS_API_CHECK_MOUNT(fs) \
|
||||
if (!SPIFFS_CHECK_MOUNT((fs))) { \
|
||||
(fs)->err_code = SPIFFS_ERR_NOT_MOUNTED; \
|
||||
return SPIFFS_ERR_NOT_MOUNTED; \
|
||||
}
|
||||
|
||||
#define SPIFFS_API_CHECK_CFG(fs) \
|
||||
if (!SPIFFS_CHECK_CFG((fs))) { \
|
||||
(fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; \
|
||||
return SPIFFS_ERR_NOT_CONFIGURED; \
|
||||
}
|
||||
|
||||
#define SPIFFS_API_CHECK_RES(fs, res) \
|
||||
if ((res) < SPIFFS_OK) { \
|
||||
(fs)->err_code = (res); \
|
||||
return (res); \
|
||||
}
|
||||
|
||||
#define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \
|
||||
if ((res) < SPIFFS_OK) { \
|
||||
(fs)->err_code = (res); \
|
||||
SPIFFS_UNLOCK(fs); \
|
||||
return (res); \
|
||||
}
|
||||
|
||||
#define SPIFFS_VALIDATE_OBJIX(ph, objid, spix) \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_INDEX) != 0) return SPIFFS_ERR_NOT_INDEX; \
|
||||
if (((objid) & SPIFFS_OBJ_ID_IX_FLAG) == 0) return SPIFFS_ERR_NOT_INDEX; \
|
||||
if ((ph).span_ix != (spix)) return SPIFFS_ERR_INDEX_SPAN_MISMATCH;
|
||||
//if ((spix) == 0 && ((ph).flags & SPIFFS_PH_FLAG_IXDELE) == 0) return SPIFFS_ERR_DELETED;
|
||||
|
||||
#define SPIFFS_VALIDATE_DATA(ph, objid, spix) \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_INDEX) == 0) return SPIFFS_ERR_IS_INDEX; \
|
||||
if ((objid) & SPIFFS_OBJ_ID_IX_FLAG) return SPIFFS_ERR_IS_INDEX; \
|
||||
if ((ph).span_ix != (spix)) return SPIFFS_ERR_DATA_SPAN_MISMATCH;
|
||||
|
||||
|
||||
// check id, only visit matching objec ids
|
||||
#define SPIFFS_VIS_CHECK_ID (1<<0)
|
||||
// report argument object id to visitor - else object lookup id is reported
|
||||
#define SPIFFS_VIS_CHECK_PH (1<<1)
|
||||
// stop searching at end of all look up pages
|
||||
#define SPIFFS_VIS_NO_WRAP (1<<2)
|
||||
|
||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
|
||||
(_fs)->cfg.hal_write_f((_fs), (_paddr), (_len), (_src))
|
||||
#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
|
||||
(_fs)->cfg.hal_read_f((_fs), (_paddr), (_len), (_dst))
|
||||
#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
|
||||
(_fs)->cfg.hal_erase_f((_fs), (_paddr), (_len))
|
||||
|
||||
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
|
||||
(_fs)->cfg.hal_write_f((_paddr), (_len), (_src))
|
||||
#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
|
||||
(_fs)->cfg.hal_read_f((_paddr), (_len), (_dst))
|
||||
#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
|
||||
(_fs)->cfg.hal_erase_f((_paddr), (_len))
|
||||
|
||||
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
|
||||
#define SPIFFS_CACHE_FLAG_DIRTY (1<<0)
|
||||
#define SPIFFS_CACHE_FLAG_WRTHRU (1<<1)
|
||||
#define SPIFFS_CACHE_FLAG_OBJLU (1<<2)
|
||||
#define SPIFFS_CACHE_FLAG_OBJIX (1<<3)
|
||||
#define SPIFFS_CACHE_FLAG_DATA (1<<4)
|
||||
#define SPIFFS_CACHE_FLAG_TYPE_WR (1<<7)
|
||||
|
||||
#define SPIFFS_CACHE_PAGE_SIZE(fs) \
|
||||
(sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs))
|
||||
|
||||
#define spiffs_get_cache(fs) \
|
||||
((spiffs_cache *)((fs)->cache))
|
||||
|
||||
#define spiffs_get_cache_page_hdr(fs, c, ix) \
|
||||
((spiffs_cache_page *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])))
|
||||
|
||||
#define spiffs_get_cache_page(fs, c, ix) \
|
||||
((u8_t *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])) + sizeof(spiffs_cache_page))
|
||||
|
||||
// cache page struct
|
||||
typedef struct {
|
||||
// cache flags
|
||||
u8_t flags;
|
||||
// cache page index
|
||||
u8_t ix;
|
||||
// last access of this cache page
|
||||
u32_t last_access;
|
||||
union {
|
||||
// type read cache
|
||||
struct {
|
||||
// read cache page index
|
||||
spiffs_page_ix pix;
|
||||
};
|
||||
#if SPIFFS_CACHE_WR
|
||||
// type write cache
|
||||
struct {
|
||||
// write cache
|
||||
spiffs_obj_id obj_id;
|
||||
// offset in cache page
|
||||
u32_t offset;
|
||||
// size of cache page
|
||||
u16_t size;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
} spiffs_cache_page;
|
||||
|
||||
// cache struct
|
||||
typedef struct {
|
||||
u8_t cpage_count;
|
||||
u32_t last_access;
|
||||
u32_t cpage_use_map;
|
||||
u32_t cpage_use_mask;
|
||||
u8_t *cpages;
|
||||
} spiffs_cache;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// spiffs nucleus file descriptor
|
||||
typedef struct {
|
||||
// the filesystem of this descriptor
|
||||
spiffs *fs;
|
||||
// number of file descriptor - if 0, the file descriptor is closed
|
||||
spiffs_file file_nbr;
|
||||
// object id - if SPIFFS_OBJ_ID_ERASED, the file was deleted
|
||||
spiffs_obj_id obj_id;
|
||||
// size of the file
|
||||
u32_t size;
|
||||
// cached object index header page index
|
||||
spiffs_page_ix objix_hdr_pix;
|
||||
// cached offset object index page index
|
||||
spiffs_page_ix cursor_objix_pix;
|
||||
// cached offset object index span index
|
||||
spiffs_span_ix cursor_objix_spix;
|
||||
// current absolute offset
|
||||
u32_t offset;
|
||||
// current file descriptor offset (cached)
|
||||
u32_t fdoffset;
|
||||
// fd flags
|
||||
spiffs_flags flags;
|
||||
#if SPIFFS_CACHE_WR
|
||||
spiffs_cache_page *cache_page;
|
||||
#endif
|
||||
#if SPIFFS_TEMPORAL_FD_CACHE
|
||||
// djb2 hash of filename
|
||||
u32_t name_hash;
|
||||
// hit score (score == 0 indicates never used fd)
|
||||
u16_t score;
|
||||
#endif
|
||||
#if SPIFFS_IX_MAP
|
||||
// spiffs index map, if 0 it means unmapped
|
||||
spiffs_ix_map *ix_map;
|
||||
#endif
|
||||
} spiffs_fd;
|
||||
|
||||
|
||||
// object structs
|
||||
|
||||
// page header, part of each page except object lookup pages
|
||||
// NB: this is always aligned when the data page is an object index,
|
||||
// as in this case struct spiffs_page_object_ix is used
|
||||
typedef struct SPIFFS_PACKED {
|
||||
// object id
|
||||
spiffs_obj_id obj_id;
|
||||
// object span index
|
||||
spiffs_span_ix span_ix;
|
||||
// flags
|
||||
u8_t flags;
|
||||
} spiffs_page_header;
|
||||
|
||||
// object index header page header
|
||||
typedef struct SPIFFS_PACKED
|
||||
#if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
|
||||
__attribute(( aligned(sizeof(spiffs_page_ix)) ))
|
||||
#endif
|
||||
{
|
||||
// common page header
|
||||
spiffs_page_header p_hdr;
|
||||
// alignment
|
||||
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
|
||||
// size of object
|
||||
u32_t size;
|
||||
// type of object
|
||||
spiffs_obj_type type;
|
||||
// name of object
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||
#if SPIFFS_OBJ_META_LEN
|
||||
// metadata. not interpreted by SPIFFS in any way.
|
||||
u8_t meta[SPIFFS_OBJ_META_LEN];
|
||||
#endif
|
||||
} spiffs_page_object_ix_header;
|
||||
|
||||
// object index page header
|
||||
typedef struct SPIFFS_PACKED {
|
||||
spiffs_page_header p_hdr;
|
||||
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
|
||||
} spiffs_page_object_ix;
|
||||
|
||||
// callback func for object lookup visitor
|
||||
typedef s32_t (*spiffs_visitor_f)(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,
|
||||
const void *user_const_p, void *user_var_p);
|
||||
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
#define _spiffs_rd(fs, op, fh, addr, len, dst) \
|
||||
spiffs_phys_rd((fs), (op), (fh), (addr), (len), (dst))
|
||||
#define _spiffs_wr(fs, op, fh, addr, len, src) \
|
||||
spiffs_phys_wr((fs), (op), (fh), (addr), (len), (src))
|
||||
#else
|
||||
#define _spiffs_rd(fs, op, fh, addr, len, dst) \
|
||||
spiffs_phys_rd((fs), (addr), (len), (dst))
|
||||
#define _spiffs_wr(fs, op, fh, addr, len, src) \
|
||||
spiffs_phys_wr((fs), (addr), (len), (src))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_phys_rd(
|
||||
spiffs *fs,
|
||||
#if SPIFFS_CACHE
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
#endif
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *dst);
|
||||
|
||||
s32_t spiffs_phys_wr(
|
||||
spiffs *fs,
|
||||
#if SPIFFS_CACHE
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
#endif
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *src);
|
||||
|
||||
s32_t spiffs_phys_cpy(
|
||||
spiffs *fs,
|
||||
spiffs_file fh,
|
||||
u32_t dst,
|
||||
u32_t src,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_phys_count_free_blocks(
|
||||
spiffs *fs);
|
||||
|
||||
s32_t spiffs_obj_lu_find_entry_visitor(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix starting_block,
|
||||
int starting_lu_entry,
|
||||
u8_t flags,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_visitor_f v,
|
||||
const void *user_const_p,
|
||||
void *user_var_p,
|
||||
spiffs_block_ix *block_ix,
|
||||
int *lu_entry);
|
||||
|
||||
s32_t spiffs_erase_block(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix);
|
||||
|
||||
#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH
|
||||
s32_t spiffs_probe(
|
||||
spiffs_config *cfg);
|
||||
#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_obj_lu_scan(
|
||||
spiffs *fs);
|
||||
|
||||
s32_t spiffs_obj_lu_find_free_obj_id(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id *obj_id,
|
||||
const u8_t *conflicting_name);
|
||||
|
||||
s32_t spiffs_obj_lu_find_free(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix starting_block,
|
||||
int starting_lu_entry,
|
||||
spiffs_block_ix *block_ix,
|
||||
int *lu_entry);
|
||||
|
||||
s32_t spiffs_obj_lu_find_id(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix starting_block,
|
||||
int starting_lu_entry,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_block_ix *block_ix,
|
||||
int *lu_entry);
|
||||
|
||||
s32_t spiffs_obj_lu_find_id_and_span(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_span_ix spix,
|
||||
spiffs_page_ix exclusion_pix,
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
s32_t spiffs_obj_lu_find_id_and_span_by_phdr(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_span_ix spix,
|
||||
spiffs_page_ix exclusion_pix,
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_page_allocate_data(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_page_header *ph,
|
||||
u8_t *data,
|
||||
u32_t len,
|
||||
u32_t page_offs,
|
||||
u8_t finalize,
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
s32_t spiffs_page_move(
|
||||
spiffs *fs,
|
||||
spiffs_file fh,
|
||||
u8_t *page_data,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_page_header *page_hdr,
|
||||
spiffs_page_ix src_pix,
|
||||
spiffs_page_ix *dst_pix);
|
||||
|
||||
s32_t spiffs_page_delete(
|
||||
spiffs *fs,
|
||||
spiffs_page_ix pix);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_object_create(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
const u8_t name[],
|
||||
const u8_t meta[],
|
||||
spiffs_obj_type type,
|
||||
spiffs_page_ix *objix_hdr_pix);
|
||||
|
||||
s32_t spiffs_object_update_index_hdr(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_page_ix objix_hdr_pix,
|
||||
u8_t *new_objix_hdr_data,
|
||||
const u8_t name[],
|
||||
const u8_t meta[],
|
||||
u32_t size,
|
||||
spiffs_page_ix *new_pix);
|
||||
|
||||
#if SPIFFS_IX_MAP
|
||||
|
||||
s32_t spiffs_populate_ix_map(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd,
|
||||
u32_t vec_entry_start,
|
||||
u32_t vec_entry_end);
|
||||
|
||||
#endif
|
||||
|
||||
void spiffs_cb_object_event(
|
||||
spiffs *fs,
|
||||
spiffs_page_object_ix *objix,
|
||||
int ev,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_span_ix spix,
|
||||
spiffs_page_ix new_pix,
|
||||
u32_t new_size);
|
||||
|
||||
s32_t spiffs_object_open_by_id(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_fd *f,
|
||||
spiffs_flags flags,
|
||||
spiffs_mode mode);
|
||||
|
||||
s32_t spiffs_object_open_by_page(
|
||||
spiffs *fs,
|
||||
spiffs_page_ix pix,
|
||||
spiffs_fd *f,
|
||||
spiffs_flags flags,
|
||||
spiffs_mode mode);
|
||||
|
||||
s32_t spiffs_object_append(
|
||||
spiffs_fd *fd,
|
||||
u32_t offset,
|
||||
u8_t *data,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_object_modify(
|
||||
spiffs_fd *fd,
|
||||
u32_t offset,
|
||||
u8_t *data,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_object_read(
|
||||
spiffs_fd *fd,
|
||||
u32_t offset,
|
||||
u32_t len,
|
||||
u8_t *dst);
|
||||
|
||||
s32_t spiffs_object_truncate(
|
||||
spiffs_fd *fd,
|
||||
u32_t new_len,
|
||||
u8_t remove_object);
|
||||
|
||||
s32_t spiffs_object_find_object_index_header_by_name(
|
||||
spiffs *fs,
|
||||
const u8_t name[SPIFFS_OBJ_NAME_LEN],
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_gc_check(
|
||||
spiffs *fs,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_gc_erase_page_stats(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix);
|
||||
|
||||
s32_t spiffs_gc_find_candidate(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix **block_candidate,
|
||||
int *candidate_count,
|
||||
char fs_crammed);
|
||||
|
||||
s32_t spiffs_gc_clean(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix);
|
||||
|
||||
s32_t spiffs_gc_quick(
|
||||
spiffs *fs, u16_t max_free_pages);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_fd_find_new(
|
||||
spiffs *fs,
|
||||
spiffs_fd **fd,
|
||||
const char *name);
|
||||
|
||||
s32_t spiffs_fd_return(
|
||||
spiffs *fs,
|
||||
spiffs_file f);
|
||||
|
||||
s32_t spiffs_fd_get(
|
||||
spiffs *fs,
|
||||
spiffs_file f,
|
||||
spiffs_fd **fd);
|
||||
|
||||
#if SPIFFS_TEMPORAL_FD_CACHE
|
||||
void spiffs_fd_temporal_cache_rehash(
|
||||
spiffs *fs,
|
||||
const char *old_path,
|
||||
const char *new_path);
|
||||
#endif
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
void spiffs_cache_init(
|
||||
spiffs *fs);
|
||||
|
||||
void spiffs_cache_drop_page(
|
||||
spiffs *fs,
|
||||
spiffs_page_ix pix);
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd);
|
||||
|
||||
void spiffs_cache_fd_release(
|
||||
spiffs *fs,
|
||||
spiffs_cache_page *cp);
|
||||
|
||||
spiffs_cache_page *spiffs_cache_page_get_by_fd(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
s32_t spiffs_lookup_consistency_check(
|
||||
spiffs *fs,
|
||||
u8_t check_all_objects);
|
||||
|
||||
s32_t spiffs_page_consistency_check(
|
||||
spiffs *fs);
|
||||
|
||||
s32_t spiffs_object_index_consistency_check(
|
||||
spiffs *fs);
|
||||
|
||||
// memcpy macro,
|
||||
// checked in test builds, otherwise plain memcpy (unless already defined)
|
||||
#ifdef _SPIFFS_TEST
|
||||
#define _SPIFFS_MEMCPY(__d, __s, __l) do { \
|
||||
intptr_t __a1 = (intptr_t)((u8_t*)(__s)); \
|
||||
intptr_t __a2 = (intptr_t)((u8_t*)(__s)+(__l)); \
|
||||
intptr_t __b1 = (intptr_t)((u8_t*)(__d)); \
|
||||
intptr_t __b2 = (intptr_t)((u8_t*)(__d)+(__l)); \
|
||||
if (__a1 <= __b2 && __b1 <= __a2) { \
|
||||
printf("FATAL OVERLAP: memcpy from %lx..%lx to %lx..%lx\n", __a1, __a2, __b1, __b2); \
|
||||
ERREXIT(); \
|
||||
} \
|
||||
memcpy((__d),(__s),(__l)); \
|
||||
} while (0)
|
||||
#else
|
||||
#ifndef _SPIFFS_MEMCPY
|
||||
#define _SPIFFS_MEMCPY(__d, __s, __l) do{memcpy((__d),(__s),(__l));}while(0)
|
||||
#endif
|
||||
#endif //_SPIFFS_TEST
|
||||
|
||||
#endif /* SPIFFS_NUCLEUS_H_ */
|
319
Living_SDK/3rdparty/experimental/spiffs/spiffs/spiffs_cache.c
vendored
Normal file
319
Living_SDK/3rdparty/experimental/spiffs/spiffs/spiffs_cache.c
vendored
Normal file
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
* spiffs_cache.c
|
||||
*
|
||||
* Created on: Jun 23, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#include "spiffs.h"
|
||||
#include "spiffs_nucleus.h"
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
|
||||
// returns cached page for give page index, or null if no such cached page
|
||||
static spiffs_cache_page *spiffs_cache_page_get(spiffs *fs, spiffs_page_ix pix) {
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) return 0;
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->cpage_use_map & (1<<i)) &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
||||
cp->pix == pix ) {
|
||||
//SPIFFS_CACHE_DBG("CACHE_GET: have cache page "_SPIPRIi" for "_SPIPRIpg"\n", i, pix);
|
||||
cp->last_access = cache->last_access;
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
//SPIFFS_CACHE_DBG("CACHE_GET: no cache for "_SPIPRIpg"\n", pix);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// frees cached page
|
||||
static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, ix);
|
||||
if (cache->cpage_use_map & (1<<ix)) {
|
||||
if (write_back &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) {
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, ix);
|
||||
SPIFFS_CACHE_DBG("CACHE_FREE: write cache page "_SPIPRIi" pix "_SPIPRIpg"\n", ix, cp->pix);
|
||||
res = SPIFFS_HAL_WRITE(fs, SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);
|
||||
}
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) {
|
||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page "_SPIPRIi" objid "_SPIPRIid"\n", ix, cp->obj_id);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page "_SPIPRIi" pix "_SPIPRIpg"\n", ix, cp->pix);
|
||||
}
|
||||
cache->cpage_use_map &= ~(1 << ix);
|
||||
cp->flags = 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// removes the oldest accessed cached page
|
||||
static s32_t spiffs_cache_page_remove_oldest(spiffs *fs, u8_t flag_mask, u8_t flags) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) != cache->cpage_use_mask) {
|
||||
// at least one free cpage
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
// all busy, scan thru all to find the cpage which has oldest access
|
||||
int i;
|
||||
int cand_ix = -1;
|
||||
u32_t oldest_val = 0;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->last_access - cp->last_access) > oldest_val &&
|
||||
(cp->flags & flag_mask) == flags) {
|
||||
oldest_val = cache->last_access - cp->last_access;
|
||||
cand_ix = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (cand_ix >= 0) {
|
||||
res = spiffs_cache_page_free(fs, cand_ix, 1);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// allocates a new cached page and returns it, or null if all cache pages are busy
|
||||
static spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs) {
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
if (cache->cpage_use_map == 0xffffffff) {
|
||||
// out of cache memory
|
||||
return 0;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
if ((cache->cpage_use_map & (1<<i)) == 0) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
cache->cpage_use_map |= (1<<i);
|
||||
cp->last_access = cache->last_access;
|
||||
//SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page "_SPIPRIi"\n", i);
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
// out of cache entries
|
||||
return 0;
|
||||
}
|
||||
|
||||
// drops the cache page for give page index
|
||||
void spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix) {
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
|
||||
if (cp) {
|
||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
|
||||
// reads from spi flash or the cache
|
||||
s32_t spiffs_phys_rd(
|
||||
spiffs *fs,
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *dst) {
|
||||
(void)fh;
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, SPIFFS_PADDR_TO_PAGE(fs, addr));
|
||||
cache->last_access++;
|
||||
if (cp) {
|
||||
// we've already got one, you see
|
||||
#if SPIFFS_CACHE_STATS
|
||||
fs->cache_hits++;
|
||||
#endif
|
||||
cp->last_access = cache->last_access;
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
||||
_SPIFFS_MEMCPY(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
|
||||
} else {
|
||||
if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) {
|
||||
// for second layer lookup functions, we do not cache in order to prevent shredding
|
||||
return SPIFFS_HAL_READ(fs, addr, len, dst);
|
||||
}
|
||||
#if SPIFFS_CACHE_STATS
|
||||
fs->cache_misses++;
|
||||
#endif
|
||||
// this operation will always free one cache page (unless all already free),
|
||||
// the result code stems from the write operation of the possibly freed cache page
|
||||
res = spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
|
||||
|
||||
cp = spiffs_cache_page_allocate(fs);
|
||||
if (cp) {
|
||||
cp->flags = SPIFFS_CACHE_FLAG_WRTHRU;
|
||||
cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
|
||||
SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page "_SPIPRIi" for pix "_SPIPRIpg "\n", cp->ix, cp->pix);
|
||||
|
||||
s32_t res2 = SPIFFS_HAL_READ(fs,
|
||||
addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs),
|
||||
spiffs_get_cache_page(fs, cache, cp->ix));
|
||||
if (res2 != SPIFFS_OK) {
|
||||
// honor read failure before possible write failure (bad idea?)
|
||||
res = res2;
|
||||
}
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
||||
_SPIFFS_MEMCPY(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
|
||||
} else {
|
||||
// this will never happen, last resort for sake of symmetry
|
||||
s32_t res2 = SPIFFS_HAL_READ(fs, addr, len, dst);
|
||||
if (res2 != SPIFFS_OK) {
|
||||
// honor read failure before possible write failure (bad idea?)
|
||||
res = res2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// writes to spi flash and/or the cache
|
||||
s32_t spiffs_phys_wr(
|
||||
spiffs *fs,
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *src) {
|
||||
(void)fh;
|
||||
spiffs_page_ix pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
|
||||
|
||||
if (cp && (op & SPIFFS_OP_COM_MASK) != SPIFFS_OP_C_WRTHRU) {
|
||||
// have a cache page
|
||||
// copy in data to cache page
|
||||
|
||||
if ((op & SPIFFS_OP_COM_MASK) == SPIFFS_OP_C_DELE &&
|
||||
(op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) {
|
||||
// page is being deleted, wipe from cache - unless it is a lookup page
|
||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||
}
|
||||
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
||||
_SPIFFS_MEMCPY(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len);
|
||||
|
||||
cache->last_access++;
|
||||
cp->last_access = cache->last_access;
|
||||
|
||||
if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU) {
|
||||
// page is being updated, no write-cache, just pass thru
|
||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||
} else {
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
} else {
|
||||
// no cache page, no write cache - just write thru
|
||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||
}
|
||||
}
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
// returns the cache page that this fd refers, or null if no cache page
|
||||
spiffs_cache_page *spiffs_cache_page_get_by_fd(spiffs *fs, spiffs_fd *fd) {
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) {
|
||||
// all cpages free, no cpage cannot be assigned to obj_id
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->cpage_use_map & (1<<i)) &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) &&
|
||||
cp->obj_id == fd->obj_id) {
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// allocates a new cache page and refers this to given fd - flushes an old cache
|
||||
// page if all cache is busy
|
||||
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd) {
|
||||
// before this function is called, it is ensured that there is no already existing
|
||||
// cache page with same object id
|
||||
spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_allocate(fs);
|
||||
if (cp == 0) {
|
||||
// could not get cache page
|
||||
return 0;
|
||||
}
|
||||
|
||||
cp->flags = SPIFFS_CACHE_FLAG_TYPE_WR;
|
||||
cp->obj_id = fd->obj_id;
|
||||
fd->cache_page = cp;
|
||||
SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page "_SPIPRIi" for fd "_SPIPRIfd ":"_SPIPRIid "\n", cp->ix, fd->file_nbr, fd->obj_id);
|
||||
return cp;
|
||||
}
|
||||
|
||||
// unrefers all fds that this cache page refers to and releases the cache page
|
||||
void spiffs_cache_fd_release(spiffs *fs, spiffs_cache_page *cp) {
|
||||
if (cp == 0) return;
|
||||
u32_t i;
|
||||
spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
|
||||
for (i = 0; i < fs->fd_count; i++) {
|
||||
spiffs_fd *cur_fd = &fds[i];
|
||||
if (cur_fd->file_nbr != 0 && cur_fd->cache_page == cp) {
|
||||
cur_fd->cache_page = 0;
|
||||
}
|
||||
}
|
||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||
|
||||
cp->obj_id = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// initializes the cache
|
||||
void spiffs_cache_init(spiffs *fs) {
|
||||
if (fs->cache == 0) return;
|
||||
u32_t sz = fs->cache_size;
|
||||
u32_t cache_mask = 0;
|
||||
int i;
|
||||
int cache_entries =
|
||||
(sz - sizeof(spiffs_cache)) / (SPIFFS_CACHE_PAGE_SIZE(fs));
|
||||
if (cache_entries <= 0) return;
|
||||
|
||||
for (i = 0; i < cache_entries; i++) {
|
||||
cache_mask <<= 1;
|
||||
cache_mask |= 1;
|
||||
}
|
||||
|
||||
spiffs_cache cache;
|
||||
memset(&cache, 0, sizeof(spiffs_cache));
|
||||
cache.cpage_count = cache_entries;
|
||||
cache.cpages = (u8_t *)((u8_t *)fs->cache + sizeof(spiffs_cache));
|
||||
|
||||
cache.cpage_use_map = 0xffffffff;
|
||||
cache.cpage_use_mask = cache_mask;
|
||||
_SPIFFS_MEMCPY(fs->cache, &cache, sizeof(spiffs_cache));
|
||||
|
||||
spiffs_cache *c = spiffs_get_cache(fs);
|
||||
|
||||
memset(c->cpages, 0, c->cpage_count * SPIFFS_CACHE_PAGE_SIZE(fs));
|
||||
|
||||
c->cpage_use_map &= ~(c->cpage_use_mask);
|
||||
for (i = 0; i < cache.cpage_count; i++) {
|
||||
spiffs_get_cache_page_hdr(fs, c, i)->ix = i;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SPIFFS_CACHE
|
1008
Living_SDK/3rdparty/experimental/spiffs/spiffs/spiffs_check.c
vendored
Normal file
1008
Living_SDK/3rdparty/experimental/spiffs/spiffs/spiffs_check.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
606
Living_SDK/3rdparty/experimental/spiffs/spiffs/spiffs_gc.c
vendored
Normal file
606
Living_SDK/3rdparty/experimental/spiffs/spiffs/spiffs_gc.c
vendored
Normal file
|
@ -0,0 +1,606 @@
|
|||
#include "spiffs.h"
|
||||
#include "spiffs_nucleus.h"
|
||||
|
||||
#if !SPIFFS_READ_ONLY
|
||||
|
||||
// Erases a logical block and updates the erase counter.
|
||||
// If cache is enabled, all pages that might be cached in this block
|
||||
// is dropped.
|
||||
static s32_t spiffs_gc_erase_block(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix) {
|
||||
s32_t res;
|
||||
|
||||
SPIFFS_GC_DBG("gc: erase block "_SPIPRIbl"\n", bix);
|
||||
res = spiffs_erase_block(fs, bix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
{
|
||||
u32_t i;
|
||||
for (i = 0; i < SPIFFS_PAGES_PER_BLOCK(fs); i++) {
|
||||
spiffs_cache_drop_page(fs, SPIFFS_PAGE_FOR_BLOCK(fs, bix) + i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
// Searches for blocks where all entries are deleted - if one is found,
|
||||
// the block is erased. Compared to the non-quick gc, the quick one ensures
|
||||
// that no updates are needed on existing objects on pages that are erased.
|
||||
s32_t spiffs_gc_quick(
|
||||
spiffs *fs, u16_t max_free_pages) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
u32_t blocks = fs->block_count;
|
||||
spiffs_block_ix cur_block = 0;
|
||||
u32_t cur_block_addr = 0;
|
||||
int cur_entry = 0;
|
||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
||||
|
||||
SPIFFS_GC_DBG("gc_quick: running\n");
|
||||
#if SPIFFS_GC_STATS
|
||||
fs->stats_gc_runs++;
|
||||
#endif
|
||||
|
||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
|
||||
// find fully deleted blocks
|
||||
// check each block
|
||||
while (res == SPIFFS_OK && blocks--) {
|
||||
u16_t deleted_pages_in_block = 0;
|
||||
u16_t free_pages_in_block = 0;
|
||||
|
||||
int obj_lookup_page = 0;
|
||||
// check each object lookup page
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each entry
|
||||
while (res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page &&
|
||||
cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
||||
deleted_pages_in_block++;
|
||||
} else if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
||||
// kill scan, go for next block
|
||||
free_pages_in_block++;
|
||||
if (free_pages_in_block > max_free_pages) {
|
||||
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
|
||||
res = 1; // kill object lu loop
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// kill scan, go for next block
|
||||
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
|
||||
res = 1; // kill object lu loop
|
||||
break;
|
||||
}
|
||||
cur_entry++;
|
||||
} // per entry
|
||||
obj_lookup_page++;
|
||||
} // per object lookup page
|
||||
if (res == 1) res = SPIFFS_OK;
|
||||
|
||||
if (res == SPIFFS_OK &&
|
||||
deleted_pages_in_block + free_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs) &&
|
||||
free_pages_in_block <= max_free_pages) {
|
||||
// found a fully deleted block
|
||||
fs->stats_p_deleted -= deleted_pages_in_block;
|
||||
res = spiffs_gc_erase_block(fs, cur_block);
|
||||
return res;
|
||||
}
|
||||
|
||||
cur_entry = 0;
|
||||
cur_block++;
|
||||
cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
|
||||
} // per block
|
||||
|
||||
if (res == SPIFFS_OK) {
|
||||
res = SPIFFS_ERR_NO_DELETED_BLOCKS;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Checks if garbage collecting is necessary. If so a candidate block is found,
|
||||
// cleansed and erased
|
||||
s32_t spiffs_gc_check(
|
||||
spiffs *fs,
|
||||
u32_t len) {
|
||||
s32_t res;
|
||||
s32_t free_pages =
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count-2)
|
||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
||||
int tries = 0;
|
||||
|
||||
if (fs->free_blocks > 3 &&
|
||||
(s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs);
|
||||
// if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) {
|
||||
// SPIFFS_GC_DBG("gc: full freeblk:"_SPIPRIi" needed:"_SPIPRIi" free:"_SPIPRIi" dele:"_SPIPRIi"\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
|
||||
// return SPIFFS_ERR_FULL;
|
||||
// }
|
||||
if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted)) {
|
||||
SPIFFS_GC_DBG("gc_check: full freeblk:"_SPIPRIi" needed:"_SPIPRIi" free:"_SPIPRIi" dele:"_SPIPRIi"\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
|
||||
return SPIFFS_ERR_FULL;
|
||||
}
|
||||
|
||||
do {
|
||||
SPIFFS_GC_DBG("\ngc_check #"_SPIPRIi": run gc free_blocks:"_SPIPRIi" pfree:"_SPIPRIi" pallo:"_SPIPRIi" pdele:"_SPIPRIi" ["_SPIPRIi"] len:"_SPIPRIi" of "_SPIPRIi"\n",
|
||||
tries,
|
||||
fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted),
|
||||
len, (u32_t)(free_pages*SPIFFS_DATA_PAGE_SIZE(fs)));
|
||||
|
||||
spiffs_block_ix *cands;
|
||||
int count;
|
||||
spiffs_block_ix cand;
|
||||
s32_t prev_free_pages = free_pages;
|
||||
// if the fs is crammed, ignore block age when selecting candidate - kind of a bad state
|
||||
res = spiffs_gc_find_candidate(fs, &cands, &count, free_pages <= 0);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (count == 0) {
|
||||
SPIFFS_GC_DBG("gc_check: no candidates, return\n");
|
||||
return (s32_t)needed_pages < free_pages ? SPIFFS_OK : SPIFFS_ERR_FULL;
|
||||
}
|
||||
#if SPIFFS_GC_STATS
|
||||
fs->stats_gc_runs++;
|
||||
#endif
|
||||
cand = cands[0];
|
||||
fs->cleaning = 1;
|
||||
//SPIFFS_GC_DBG("gcing: cleaning block "_SPIPRIi"\n", cand);
|
||||
res = spiffs_gc_clean(fs, cand);
|
||||
fs->cleaning = 0;
|
||||
if (res < 0) {
|
||||
SPIFFS_GC_DBG("gc_check: cleaning block "_SPIPRIi", result "_SPIPRIi"\n", cand, res);
|
||||
} else {
|
||||
SPIFFS_GC_DBG("gc_check: cleaning block "_SPIPRIi", result "_SPIPRIi"\n", cand, res);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
res = spiffs_gc_erase_page_stats(fs, cand);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
res = spiffs_gc_erase_block(fs, cand);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
free_pages =
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
|
||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
||||
|
||||
if (prev_free_pages <= 0 && prev_free_pages == free_pages) {
|
||||
// abort early to reduce wear, at least tried once
|
||||
SPIFFS_GC_DBG("gc_check: early abort, no result on gc when fs crammed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
} while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 ||
|
||||
(s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)));
|
||||
|
||||
free_pages =
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
|
||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
||||
if ((s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
|
||||
res = SPIFFS_ERR_FULL;
|
||||
}
|
||||
|
||||
SPIFFS_GC_DBG("gc_check: finished, "_SPIPRIi" dirty, blocks "_SPIPRIi" free, "_SPIPRIi" pages free, "_SPIPRIi" tries, res "_SPIPRIi"\n",
|
||||
fs->stats_p_allocated + fs->stats_p_deleted,
|
||||
fs->free_blocks, free_pages, tries, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Updates page statistics for a block that is about to be erased
|
||||
s32_t spiffs_gc_erase_page_stats(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
int obj_lookup_page = 0;
|
||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
||||
int cur_entry = 0;
|
||||
u32_t dele = 0;
|
||||
u32_t allo = 0;
|
||||
|
||||
// check each object lookup page
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each entry
|
||||
while (res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
||||
} else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
||||
dele++;
|
||||
} else {
|
||||
allo++;
|
||||
}
|
||||
cur_entry++;
|
||||
} // per entry
|
||||
obj_lookup_page++;
|
||||
} // per object lookup page
|
||||
SPIFFS_GC_DBG("gc_check: wipe pallo:"_SPIPRIi" pdele:"_SPIPRIi"\n", allo, dele);
|
||||
fs->stats_p_allocated -= allo;
|
||||
fs->stats_p_deleted -= dele;
|
||||
return res;
|
||||
}
|
||||
|
||||
// Finds block candidates to erase
|
||||
s32_t spiffs_gc_find_candidate(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix **block_candidates,
|
||||
int *candidate_count,
|
||||
char fs_crammed) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
u32_t blocks = fs->block_count;
|
||||
spiffs_block_ix cur_block = 0;
|
||||
u32_t cur_block_addr = 0;
|
||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
||||
int cur_entry = 0;
|
||||
|
||||
// using fs->work area as sorted candidate memory, (spiffs_block_ix)cand_bix/(s32_t)score
|
||||
int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(s32_t)));
|
||||
*candidate_count = 0;
|
||||
memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
||||
|
||||
// divide up work area into block indices and scores
|
||||
spiffs_block_ix *cand_blocks = (spiffs_block_ix *)fs->work;
|
||||
s32_t *cand_scores = (s32_t *)(fs->work + max_candidates * sizeof(spiffs_block_ix));
|
||||
|
||||
// align cand_scores on s32_t boundary
|
||||
cand_scores = (s32_t*)(((intptr_t)cand_scores + sizeof(intptr_t) - 1) & ~(sizeof(intptr_t) - 1));
|
||||
|
||||
*block_candidates = cand_blocks;
|
||||
|
||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
|
||||
// check each block
|
||||
while (res == SPIFFS_OK && blocks--) {
|
||||
u16_t deleted_pages_in_block = 0;
|
||||
u16_t used_pages_in_block = 0;
|
||||
|
||||
int obj_lookup_page = 0;
|
||||
// check each object lookup page
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each entry
|
||||
while (res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page &&
|
||||
cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
||||
// when a free entry is encountered, scan logic ensures that all following entries are free also
|
||||
res = 1; // kill object lu loop
|
||||
break;
|
||||
} else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
||||
deleted_pages_in_block++;
|
||||
} else {
|
||||
used_pages_in_block++;
|
||||
}
|
||||
cur_entry++;
|
||||
} // per entry
|
||||
obj_lookup_page++;
|
||||
} // per object lookup page
|
||||
if (res == 1) res = SPIFFS_OK;
|
||||
|
||||
// calculate score and insert into candidate table
|
||||
// stoneage sort, but probably not so many blocks
|
||||
if (res == SPIFFS_OK /*&& deleted_pages_in_block > 0*/) {
|
||||
// read erase count
|
||||
spiffs_obj_id erase_count;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0,
|
||||
SPIFFS_ERASE_COUNT_PADDR(fs, cur_block),
|
||||
sizeof(spiffs_obj_id), (u8_t *)&erase_count);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
spiffs_obj_id erase_age;
|
||||
if (fs->max_erase_count > erase_count) {
|
||||
erase_age = fs->max_erase_count - erase_count;
|
||||
} else {
|
||||
erase_age = SPIFFS_OBJ_ID_FREE - (erase_count - fs->max_erase_count);
|
||||
}
|
||||
|
||||
s32_t score =
|
||||
deleted_pages_in_block * SPIFFS_GC_HEUR_W_DELET +
|
||||
used_pages_in_block * SPIFFS_GC_HEUR_W_USED +
|
||||
erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE);
|
||||
int cand_ix = 0;
|
||||
SPIFFS_GC_DBG("gc_check: bix:"_SPIPRIbl" del:"_SPIPRIi" use:"_SPIPRIi" score:"_SPIPRIi"\n", cur_block, deleted_pages_in_block, used_pages_in_block, score);
|
||||
while (cand_ix < max_candidates) {
|
||||
if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) {
|
||||
cand_blocks[cand_ix] = cur_block;
|
||||
cand_scores[cand_ix] = score;
|
||||
break;
|
||||
} else if (cand_scores[cand_ix] < score) {
|
||||
int reorder_cand_ix = max_candidates - 2;
|
||||
while (reorder_cand_ix >= cand_ix) {
|
||||
cand_blocks[reorder_cand_ix + 1] = cand_blocks[reorder_cand_ix];
|
||||
cand_scores[reorder_cand_ix + 1] = cand_scores[reorder_cand_ix];
|
||||
reorder_cand_ix--;
|
||||
}
|
||||
cand_blocks[cand_ix] = cur_block;
|
||||
cand_scores[cand_ix] = score;
|
||||
break;
|
||||
}
|
||||
cand_ix++;
|
||||
}
|
||||
(*candidate_count)++;
|
||||
}
|
||||
|
||||
cur_entry = 0;
|
||||
cur_block++;
|
||||
cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
|
||||
} // per block
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
FIND_OBJ_DATA,
|
||||
MOVE_OBJ_DATA,
|
||||
MOVE_OBJ_IX,
|
||||
FINISHED
|
||||
} spiffs_gc_clean_state;
|
||||
|
||||
typedef struct {
|
||||
spiffs_gc_clean_state state;
|
||||
spiffs_obj_id cur_obj_id;
|
||||
spiffs_span_ix cur_objix_spix;
|
||||
spiffs_page_ix cur_objix_pix;
|
||||
spiffs_page_ix cur_data_pix;
|
||||
int stored_scan_entry_index;
|
||||
u8_t obj_id_found;
|
||||
} spiffs_gc;
|
||||
|
||||
// Empties given block by moving all data into free pages of another block
|
||||
// Strategy:
|
||||
// loop:
|
||||
// scan object lookup for object data pages
|
||||
// for first found id, check spix and load corresponding object index page to memory
|
||||
// push object scan lookup entry index
|
||||
// rescan object lookup, find data pages with same id and referenced by same object index
|
||||
// move data page, update object index in memory
|
||||
// when reached end of lookup, store updated object index
|
||||
// pop object scan lookup entry index
|
||||
// repeat loop until end of object lookup
|
||||
// scan object lookup again for remaining object index pages, move to new page in other block
|
||||
//
|
||||
s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
const int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
// this is the global localizer being pushed and popped
|
||||
int cur_entry = 0;
|
||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
||||
spiffs_gc gc; // our stack frame/state
|
||||
spiffs_page_ix cur_pix = 0;
|
||||
spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
|
||||
spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
|
||||
|
||||
SPIFFS_GC_DBG("gc_clean: cleaning block "_SPIPRIbl"\n", bix);
|
||||
|
||||
memset(&gc, 0, sizeof(spiffs_gc));
|
||||
gc.state = FIND_OBJ_DATA;
|
||||
|
||||
if (fs->free_cursor_block_ix == bix) {
|
||||
// move free cursor to next block, cannot use free pages from the block we want to clean
|
||||
fs->free_cursor_block_ix = (bix+1)%fs->block_count;
|
||||
fs->free_cursor_obj_lu_entry = 0;
|
||||
SPIFFS_GC_DBG("gc_clean: move free cursor to block "_SPIPRIbl"\n", fs->free_cursor_block_ix);
|
||||
}
|
||||
|
||||
while (res == SPIFFS_OK && gc.state != FINISHED) {
|
||||
SPIFFS_GC_DBG("gc_clean: state = "_SPIPRIi" entry:"_SPIPRIi"\n", gc.state, cur_entry);
|
||||
gc.obj_id_found = 0; // reset (to no found data page)
|
||||
|
||||
// scan through lookup pages
|
||||
int obj_lookup_page = cur_entry / entries_per_page;
|
||||
u8_t scan = 1;
|
||||
// check each object lookup page
|
||||
while (scan && res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each object lookup entry
|
||||
while (scan && res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, cur_entry);
|
||||
|
||||
// act upon object id depending on gc state
|
||||
switch (gc.state) {
|
||||
case FIND_OBJ_DATA:
|
||||
// find a data page
|
||||
if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&
|
||||
((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) {
|
||||
// found a data page, stop scanning and handle in switch case below
|
||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA state:"_SPIPRIi" - found obj id "_SPIPRIid"\n", gc.state, obj_id);
|
||||
gc.obj_id_found = 1;
|
||||
gc.cur_obj_id = obj_id;
|
||||
gc.cur_data_pix = cur_pix;
|
||||
scan = 0;
|
||||
}
|
||||
break;
|
||||
case MOVE_OBJ_DATA:
|
||||
// evacuate found data pages for corresponding object index we have in memory,
|
||||
// update memory representation
|
||||
if (obj_id == gc.cur_obj_id) {
|
||||
spiffs_page_header p_hdr;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA found data page "_SPIPRIid":"_SPIPRIsp" @ "_SPIPRIpg"\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix);
|
||||
if (SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix) != gc.cur_objix_spix) {
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA no objix spix match, take in another run\n");
|
||||
} else {
|
||||
spiffs_page_ix new_data_pix;
|
||||
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
|
||||
// move page
|
||||
res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_data_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA move objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg" to "_SPIPRIpg"\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix, new_data_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// move wipes obj_lu, reload it
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else {
|
||||
// page is deleted but not deleted in lookup, scrap it -
|
||||
// might seem unnecessary as we will erase this block, but
|
||||
// we might get aborted
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wipe objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
new_data_pix = SPIFFS_OBJ_ID_FREE;
|
||||
}
|
||||
// update memory representation of object index page with new data page
|
||||
if (gc.cur_objix_spix == 0) {
|
||||
// update object index header page
|
||||
((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[p_hdr.span_ix] = new_data_pix;
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page "_SPIPRIpg" to objix_hdr entry "_SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));
|
||||
} else {
|
||||
// update object index page
|
||||
((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)] = new_data_pix;
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page "_SPIPRIpg" to objix entry "_SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MOVE_OBJ_IX:
|
||||
// find and evacuate object index pages
|
||||
if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&
|
||||
(obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
|
||||
// found an index object id
|
||||
spiffs_page_header p_hdr;
|
||||
spiffs_page_ix new_pix;
|
||||
// load header
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
|
||||
// move page
|
||||
res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX move objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg" to "_SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
spiffs_cb_object_event(fs, (spiffs_page_object_ix *)&p_hdr,
|
||||
SPIFFS_EV_IX_MOV, obj_id, p_hdr.span_ix, new_pix, 0);
|
||||
// move wipes obj_lu, reload it
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else {
|
||||
// page is deleted but not deleted in lookup, scrap it -
|
||||
// might seem unnecessary as we will erase this block, but
|
||||
// we might get aborted
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX wipe objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
if (res == SPIFFS_OK) {
|
||||
spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0,
|
||||
SPIFFS_EV_IX_DEL, obj_id, p_hdr.span_ix, cur_pix, 0);
|
||||
}
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
scan = 0;
|
||||
break;
|
||||
} // switch gc state
|
||||
cur_entry++;
|
||||
} // per entry
|
||||
obj_lookup_page++; // no need to check scan variable here, obj_lookup_page is set in start of loop
|
||||
} // per object lookup page
|
||||
if (res != SPIFFS_OK) break;
|
||||
|
||||
// state finalization and switch
|
||||
switch (gc.state) {
|
||||
case FIND_OBJ_DATA:
|
||||
if (gc.obj_id_found) {
|
||||
// handle found data page -
|
||||
// find out corresponding obj ix page and load it to memory
|
||||
spiffs_page_header p_hdr;
|
||||
spiffs_page_ix objix_pix;
|
||||
gc.stored_scan_entry_index = cur_entry; // push cursor
|
||||
cur_entry = 0; // restart scan from start
|
||||
gc.state = MOVE_OBJ_DATA;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
gc.cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix);
|
||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA find objix span_ix:"_SPIPRIsp"\n", gc.cur_objix_spix);
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix, 0, &objix_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// on borked systems we might get an ERR_NOT_FOUND here -
|
||||
// this is handled by simply deleting the page as it is not referenced
|
||||
// from anywhere
|
||||
SPIFFS_GC_DBG("gc_clean: FIND_OBJ_DATA objix not found! Wipe page "_SPIPRIpg"\n", gc.cur_data_pix);
|
||||
res = spiffs_page_delete(fs, gc.cur_data_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// then we restore states and continue scanning for data pages
|
||||
cur_entry = gc.stored_scan_entry_index; // pop cursor
|
||||
gc.state = FIND_OBJ_DATA;
|
||||
break; // done
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA found object index at page "_SPIPRIpg"\n", objix_pix);
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// cannot allow a gc if the presumed index in fact is no index, a
|
||||
// check must run or lot of data may be lost
|
||||
SPIFFS_VALIDATE_OBJIX(objix->p_hdr, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix);
|
||||
gc.cur_objix_pix = objix_pix;
|
||||
} else {
|
||||
// no more data pages found, passed thru all block, start evacuating object indices
|
||||
gc.state = MOVE_OBJ_IX;
|
||||
cur_entry = 0; // restart entry scan index
|
||||
}
|
||||
break;
|
||||
case MOVE_OBJ_DATA: {
|
||||
// store modified objix (hdr) page residing in memory now that all
|
||||
// data pages belonging to this object index and residing in the block
|
||||
// we want to evacuate
|
||||
spiffs_page_ix new_objix_pix;
|
||||
gc.state = FIND_OBJ_DATA;
|
||||
cur_entry = gc.stored_scan_entry_index; // pop cursor
|
||||
if (gc.cur_objix_spix == 0) {
|
||||
// store object index header page
|
||||
res = spiffs_object_update_index_hdr(fs, 0, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_pix, fs->work, 0, 0, 0, &new_objix_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix_hdr page, "_SPIPRIpg":"_SPIPRIsp"\n", new_objix_pix, 0);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else {
|
||||
// store object index page
|
||||
res = spiffs_page_move(fs, 0, fs->work, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, gc.cur_objix_pix, &new_objix_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix page, "_SPIPRIpg":"_SPIPRIsp"\n", new_objix_pix, objix->p_hdr.span_ix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,
|
||||
SPIFFS_EV_IX_UPD, gc.cur_obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MOVE_OBJ_IX:
|
||||
// scanned thru all block, no more object indices found - our work here is done
|
||||
gc.state = FINISHED;
|
||||
break;
|
||||
default:
|
||||
cur_entry = 0;
|
||||
break;
|
||||
} // switch gc.state
|
||||
SPIFFS_GC_DBG("gc_clean: state-> "_SPIPRIi"\n", gc.state);
|
||||
} // while state != FINISHED
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif // !SPIFFS_READ_ONLY
|
1451
Living_SDK/3rdparty/experimental/spiffs/spiffs/spiffs_hydrogen.c
vendored
Normal file
1451
Living_SDK/3rdparty/experimental/spiffs/spiffs/spiffs_hydrogen.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
2364
Living_SDK/3rdparty/experimental/spiffs/spiffs/spiffs_nucleus.c
vendored
Normal file
2364
Living_SDK/3rdparty/experimental/spiffs/spiffs/spiffs_nucleus.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
548
Living_SDK/3rdparty/experimental/spiffs/spiffs_port.c
vendored
Normal file
548
Living_SDK/3rdparty/experimental/spiffs/spiffs_port.c
vendored
Normal file
|
@ -0,0 +1,548 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "spiffs_config.h"
|
||||
#include "spiffs.h"
|
||||
#include "spiffs_nucleus.h"
|
||||
#include <hal/hal.h>
|
||||
#include <vfs_inode.h>
|
||||
#include <vfs_register.h>
|
||||
|
||||
static const char* spiffs_mnt_path = "/spiffs";
|
||||
|
||||
typedef struct {
|
||||
spiffs *fs;
|
||||
aos_mutex_t lock;
|
||||
spiffs_config *cfg;
|
||||
uint8_t *work;
|
||||
uint32_t work_sz;
|
||||
uint8_t *fds;
|
||||
uint32_t fds_sz;
|
||||
#if SPIFFS_CACHE
|
||||
uint8_t *cache;
|
||||
uint32_t cache_sz;
|
||||
#endif
|
||||
} spiffs_mgr_t;
|
||||
|
||||
typedef struct {
|
||||
aos_dir_t dir;
|
||||
spiffs_DIR d;
|
||||
aos_dirent_t cur_dirent;
|
||||
}spiffs_dir_t;
|
||||
|
||||
static spiffs_mgr_t *g_spiffs_mgr = NULL;
|
||||
|
||||
static int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst)
|
||||
{
|
||||
return hal_flash_read((hal_partition_t)SPIFFS_CFG_PARTITION, &addr, dst, size);
|
||||
}
|
||||
|
||||
static int32_t spiffs_hal_write(uint32_t addr, uint32_t size, uint8_t *dst)
|
||||
{
|
||||
return hal_flash_write((hal_partition_t)SPIFFS_CFG_PARTITION, &addr, dst, size);
|
||||
}
|
||||
|
||||
static int32_t spiffs_hal_erase(uint32_t addr, uint32_t size)
|
||||
{
|
||||
return hal_flash_erase((hal_partition_t)SPIFFS_CFG_PARTITION, addr, size);
|
||||
}
|
||||
|
||||
void _spiffs_lock(spiffs *fs)
|
||||
{
|
||||
aos_mutex_lock(&(((spiffs_mgr_t *)(fs->user_data))->lock), AOS_WAIT_FOREVER);
|
||||
}
|
||||
|
||||
void _spiffs_unlock(spiffs *fs)
|
||||
{
|
||||
aos_mutex_unlock(&(((spiffs_mgr_t *)(fs->user_data))->lock));
|
||||
}
|
||||
|
||||
static char* translate_relative_path(const char *path)
|
||||
{
|
||||
int len, prefix_len;
|
||||
char *relpath, *p;
|
||||
|
||||
if (!path)
|
||||
return NULL;
|
||||
|
||||
len = strlen(path);
|
||||
prefix_len = strlen(spiffs_mnt_path);
|
||||
if (strncmp(spiffs_mnt_path, path, prefix_len) != 0)
|
||||
return NULL;
|
||||
|
||||
len = len - prefix_len;
|
||||
relpath = (char *)aos_malloc(len + 1);
|
||||
if (!relpath)
|
||||
return NULL;
|
||||
|
||||
memset(relpath, 0, len + 1);
|
||||
if (len > 0) {
|
||||
p = (char *)(path + prefix_len + 1);
|
||||
memcpy(relpath, p, len - 1);
|
||||
}
|
||||
|
||||
relpath[len] = '\0';
|
||||
|
||||
return relpath;
|
||||
}
|
||||
|
||||
static int _spiffs_ret_to_err(int ret)
|
||||
{
|
||||
switch (ret) {
|
||||
case SPIFFS_OK:
|
||||
return 0;
|
||||
case SPIFFS_ERR_NOT_MOUNTED:
|
||||
case SPIFFS_ERR_NOT_A_FS:
|
||||
return -ENODEV;
|
||||
case SPIFFS_ERR_FULL:
|
||||
return -ENOSPC;
|
||||
case SPIFFS_ERR_BAD_DESCRIPTOR:
|
||||
return -EBADF;
|
||||
case SPIFFS_ERR_MOUNTED:
|
||||
case SPIFFS_ERR_FILE_EXISTS:
|
||||
return -EEXIST;
|
||||
case SPIFFS_ERR_NOT_FOUND:
|
||||
case SPIFFS_ERR_NOT_A_FILE:
|
||||
case SPIFFS_ERR_DELETED:
|
||||
case SPIFFS_ERR_FILE_DELETED:
|
||||
return -ENOENT;
|
||||
case SPIFFS_ERR_NAME_TOO_LONG:
|
||||
return -ENAMETOOLONG;
|
||||
case SPIFFS_ERR_RO_NOT_IMPL:
|
||||
case SPIFFS_ERR_RO_ABORTED_OPERATION:
|
||||
return -EROFS;
|
||||
default:
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
|
||||
static int _spiffs_mode_conv(int flags)
|
||||
{
|
||||
int acc_mode, res = 0;
|
||||
acc_mode = flags & O_ACCMODE;
|
||||
if (acc_mode == O_RDONLY) {
|
||||
res |= SPIFFS_O_RDONLY;
|
||||
} else if (acc_mode == O_WRONLY) {
|
||||
res |= SPIFFS_O_WRONLY;
|
||||
} else if (acc_mode == O_RDWR) {
|
||||
res |= SPIFFS_O_RDWR;
|
||||
}
|
||||
|
||||
if ((flags & O_CREAT) && (flags & O_EXCL)) {
|
||||
res |= SPIFFS_O_CREAT | SPIFFS_O_EXCL;
|
||||
} else if ((flags & O_CREAT) && (flags & O_TRUNC)) {
|
||||
res |= SPIFFS_O_CREAT | SPIFFS_O_TRUNC;
|
||||
} else if (flags & O_APPEND) {
|
||||
res |= SPIFFS_O_CREAT | SPIFFS_O_APPEND;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _spiffs_open(file_t *fp, const char *path, int flags)
|
||||
{
|
||||
int fd;
|
||||
char *relpath = NULL;
|
||||
|
||||
relpath = translate_relative_path(path);
|
||||
if (!relpath)
|
||||
return -EINVAL;
|
||||
|
||||
fd = SPIFFS_open(g_spiffs_mgr->fs, relpath, _spiffs_mode_conv(flags), 0);
|
||||
if (fd > 0) {
|
||||
fp->f_arg = (void *)fd;
|
||||
fd = 0;
|
||||
} else {
|
||||
fd = _spiffs_ret_to_err(SPIFFS_errno(g_spiffs_mgr->fs));
|
||||
SPIFFS_clearerr(g_spiffs_mgr->fs);
|
||||
}
|
||||
|
||||
aos_free(relpath);
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int _spiffs_close(file_t *fp)
|
||||
{
|
||||
int fd;
|
||||
int ret = SPIFFS_ERR_FILE_CLOSED;
|
||||
|
||||
fd = (int)(fp->f_arg);
|
||||
ret = SPIFFS_close(g_spiffs_mgr->fs, fd);
|
||||
if (ret < 0) {
|
||||
ret = _spiffs_ret_to_err(SPIFFS_errno(g_spiffs_mgr->fs));
|
||||
SPIFFS_clearerr(g_spiffs_mgr->fs);
|
||||
} else {
|
||||
fp->f_arg = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t _spiffs_read(file_t *fp, char *buf, size_t len)
|
||||
{
|
||||
ssize_t nbytes;
|
||||
int fd;
|
||||
|
||||
fd = (int)(fp->f_arg);
|
||||
nbytes = SPIFFS_read(g_spiffs_mgr->fs, fd, buf, len);
|
||||
if (nbytes < 0) {
|
||||
nbytes = _spiffs_ret_to_err(SPIFFS_errno(g_spiffs_mgr->fs));
|
||||
SPIFFS_clearerr(g_spiffs_mgr->fs);
|
||||
}
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
static ssize_t _spiffs_write(file_t *fp, const char *buf, size_t len)
|
||||
{
|
||||
ssize_t nbytes;
|
||||
int fd;
|
||||
|
||||
fd = (int)(fp->f_arg);
|
||||
nbytes = SPIFFS_write(g_spiffs_mgr->fs, fd, (void *)buf, len);
|
||||
if (nbytes < 0) {
|
||||
nbytes = _spiffs_ret_to_err(SPIFFS_errno(g_spiffs_mgr->fs));
|
||||
SPIFFS_clearerr(g_spiffs_mgr->fs);
|
||||
}
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
static off_t _spiffs_lseek(file_t *fp, off_t off, int whence)
|
||||
{
|
||||
off_t ret;
|
||||
int fd;
|
||||
|
||||
fd = (int)(fp->f_arg);
|
||||
ret = SPIFFS_lseek(g_spiffs_mgr->fs, fd, off, whence);
|
||||
if (ret < 0) {
|
||||
ret = _spiffs_ret_to_err(SPIFFS_errno(g_spiffs_mgr->fs));
|
||||
SPIFFS_clearerr(g_spiffs_mgr->fs);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _spiffs_sync(file_t *fp)
|
||||
{
|
||||
int ret, fd;
|
||||
|
||||
fd = (int)(fp->f_arg);
|
||||
ret = SPIFFS_fflush(g_spiffs_mgr->fs, fd);
|
||||
if (ret < 0) {
|
||||
ret = _spiffs_ret_to_err(SPIFFS_errno(g_spiffs_mgr->fs));
|
||||
SPIFFS_clearerr(g_spiffs_mgr->fs);
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _spiffs_stat(file_t *fp, const char *path, struct stat *st)
|
||||
{
|
||||
int ret;
|
||||
spiffs_stat s;
|
||||
char *relpath = NULL;
|
||||
|
||||
relpath = translate_relative_path(path);
|
||||
if (!relpath)
|
||||
return -EINVAL;
|
||||
|
||||
ret = SPIFFS_stat(g_spiffs_mgr->fs, relpath, &s);
|
||||
if (ret < 0) {
|
||||
ret = _spiffs_ret_to_err(SPIFFS_errno(g_spiffs_mgr->fs));
|
||||
SPIFFS_clearerr(g_spiffs_mgr->fs);
|
||||
} else {
|
||||
st->st_size = s.size;
|
||||
st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO |
|
||||
((s.type == SPIFFS_TYPE_DIR)?S_IFDIR:S_IFREG);
|
||||
}
|
||||
|
||||
aos_free(relpath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _spiffs_unlink(file_t *fp, const char *path)
|
||||
{
|
||||
int ret;
|
||||
char *relpath = NULL;
|
||||
|
||||
relpath = translate_relative_path(path);
|
||||
if (!relpath)
|
||||
return -EINVAL;
|
||||
|
||||
ret = SPIFFS_remove(g_spiffs_mgr->fs, relpath);
|
||||
if (ret < 0) {
|
||||
ret = _spiffs_ret_to_err(SPIFFS_errno(g_spiffs_mgr->fs));
|
||||
SPIFFS_clearerr(g_spiffs_mgr->fs);
|
||||
}
|
||||
|
||||
aos_free(relpath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _spiffs_rename(file_t *fp, const char *oldpath, const char *newpath)
|
||||
{
|
||||
int ret;
|
||||
char *oldname = NULL;
|
||||
char *newname = NULL;
|
||||
|
||||
oldname = translate_relative_path(oldpath);
|
||||
if (!oldname)
|
||||
return -EINVAL;
|
||||
|
||||
newname = translate_relative_path(newpath);
|
||||
if (!newname) {
|
||||
aos_free(oldname);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = SPIFFS_rename(g_spiffs_mgr->fs, oldname, newname);
|
||||
if (ret < 0) {
|
||||
ret = _spiffs_ret_to_err(SPIFFS_errno(g_spiffs_mgr->fs));
|
||||
SPIFFS_clearerr(g_spiffs_mgr->fs);
|
||||
}
|
||||
|
||||
aos_free(oldname);
|
||||
aos_free(newname);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static aos_dir_t* _spiffs_opendir(file_t *fp, const char *path)
|
||||
{
|
||||
spiffs_dir_t *dp = NULL;
|
||||
char *relpath = NULL;
|
||||
|
||||
relpath = translate_relative_path(path);
|
||||
if (!relpath)
|
||||
return NULL;
|
||||
|
||||
dp = (spiffs_dir_t *)aos_malloc(sizeof(spiffs_dir_t) + SPIFFS_OBJ_NAME_LEN);
|
||||
if (!dp) {
|
||||
aos_free(relpath);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(dp, 0, sizeof(spiffs_dir_t) + SPIFFS_OBJ_NAME_LEN);
|
||||
if (!SPIFFS_opendir(g_spiffs_mgr->fs, relpath, &dp->d)) {
|
||||
aos_free(relpath);
|
||||
aos_free(dp);
|
||||
SPIFFS_clearerr(g_spiffs_mgr->fs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
aos_free(relpath);
|
||||
return (aos_dir_t *)dp;
|
||||
}
|
||||
|
||||
static aos_dirent_t* _spiffs_readdir(file_t *fp, aos_dir_t *dir)
|
||||
{
|
||||
spiffs_dir_t *dp;
|
||||
struct spiffs_dirent e;
|
||||
aos_dirent_t *out_dirent;
|
||||
|
||||
dp = (spiffs_dir_t *)dir;
|
||||
if (!dp)
|
||||
return NULL;
|
||||
|
||||
if (!SPIFFS_readdir(&dp->d, &e)) {
|
||||
SPIFFS_clearerr(g_spiffs_mgr->fs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (e.name[0] == 0)
|
||||
return NULL;
|
||||
|
||||
dp->cur_dirent.d_ino = 0;
|
||||
dp->cur_dirent.d_type = e.type;
|
||||
|
||||
strncpy(dp->cur_dirent.d_name, (char *)e.name, SPIFFS_OBJ_NAME_LEN);
|
||||
dp->cur_dirent.d_name[SPIFFS_OBJ_NAME_LEN] = '\0';
|
||||
|
||||
out_dirent = &dp->cur_dirent;
|
||||
return out_dirent;
|
||||
}
|
||||
|
||||
static int _spiffs_closedir(file_t *fp, aos_dir_t *dir)
|
||||
{
|
||||
int ret;
|
||||
spiffs_dir_t *dp = (spiffs_dir_t *)dir;
|
||||
|
||||
if (!dp)
|
||||
return -EINVAL;
|
||||
|
||||
ret = SPIFFS_closedir(&dp->d);
|
||||
if (ret < 0) {
|
||||
ret = _spiffs_ret_to_err(SPIFFS_errno(g_spiffs_mgr->fs));
|
||||
SPIFFS_clearerr(g_spiffs_mgr->fs);
|
||||
}
|
||||
|
||||
aos_free(dp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _spiffs_deinit(void)
|
||||
{
|
||||
if (!g_spiffs_mgr)
|
||||
return;
|
||||
|
||||
if (g_spiffs_mgr->fs) {
|
||||
SPIFFS_unmount(g_spiffs_mgr->fs);
|
||||
aos_free(g_spiffs_mgr->fs);
|
||||
}
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
if (g_spiffs_mgr->cache)
|
||||
aos_free(g_spiffs_mgr->cache);
|
||||
#endif
|
||||
|
||||
if (g_spiffs_mgr->fds)
|
||||
aos_free(g_spiffs_mgr->fds);
|
||||
|
||||
if (g_spiffs_mgr->work)
|
||||
aos_free(g_spiffs_mgr->work);
|
||||
|
||||
if (g_spiffs_mgr->cfg)
|
||||
aos_free(g_spiffs_mgr->cfg);
|
||||
|
||||
aos_mutex_free(&g_spiffs_mgr->lock);
|
||||
aos_free(g_spiffs_mgr);
|
||||
g_spiffs_mgr = NULL;
|
||||
}
|
||||
|
||||
static int _spiffs_init(void)
|
||||
{
|
||||
if (g_spiffs_mgr)
|
||||
return 0;
|
||||
|
||||
g_spiffs_mgr = (spiffs_mgr_t *)aos_malloc(sizeof(spiffs_mgr_t));
|
||||
if (!g_spiffs_mgr)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(g_spiffs_mgr, 0, sizeof(spiffs_mgr_t));
|
||||
|
||||
/* init spiffs lock */
|
||||
if (aos_mutex_new(&g_spiffs_mgr->lock) != 0)
|
||||
goto err;
|
||||
|
||||
/* init spiffs work buffer */
|
||||
g_spiffs_mgr->work_sz = CFG_SPIFFS_LOG_PAGE_SZ * 2;
|
||||
g_spiffs_mgr->work = (uint8_t *)aos_malloc(g_spiffs_mgr->work_sz);
|
||||
if (g_spiffs_mgr->work == NULL)
|
||||
goto err;
|
||||
memset(g_spiffs_mgr->work, 0, g_spiffs_mgr->work_sz);
|
||||
|
||||
/* init spiffs fds */
|
||||
g_spiffs_mgr->fds_sz = sizeof(spiffs_fd) * CFG_SPIFFS_MAX_FILES;
|
||||
g_spiffs_mgr->fds = (uint8_t *)aos_malloc(g_spiffs_mgr->fds_sz);
|
||||
if (g_spiffs_mgr->fds == NULL)
|
||||
goto err;
|
||||
memset(g_spiffs_mgr->fds, 0, g_spiffs_mgr->fds_sz);
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
/* init spiffs cache */
|
||||
g_spiffs_mgr->cache_sz = sizeof(spiffs_cache) + CFG_SPIFFS_MAX_FILES *
|
||||
(sizeof(spiffs_cache_page) + CFG_SPIFFS_LOG_PAGE_SZ);
|
||||
g_spiffs_mgr->cache = (uint8_t *)aos_malloc(g_spiffs_mgr->cache_sz);
|
||||
if (g_spiffs_mgr->cache == NULL)
|
||||
goto err;
|
||||
memset(g_spiffs_mgr->cache, 0, g_spiffs_mgr->cache_sz);
|
||||
#endif
|
||||
|
||||
/* init spiffs config */
|
||||
g_spiffs_mgr->cfg = (spiffs_config *)aos_malloc(sizeof(spiffs_config));
|
||||
if (g_spiffs_mgr->cfg == NULL)
|
||||
goto err;
|
||||
memset(g_spiffs_mgr->cfg, 0, sizeof(spiffs_config));
|
||||
|
||||
g_spiffs_mgr->cfg->hal_read_f = spiffs_hal_read;
|
||||
g_spiffs_mgr->cfg->hal_write_f = spiffs_hal_write;
|
||||
g_spiffs_mgr->cfg->hal_erase_f = spiffs_hal_erase;
|
||||
|
||||
#if SPIFFS_SINGLETON == 0
|
||||
g_spiffs_mgr->cfg->phys_size = CFG_SPIFFS_PHYS_SZ;
|
||||
g_spiffs_mgr->cfg->phys_addr = CFG_SPIFFS_PHYS_ADDR;
|
||||
g_spiffs_mgr->cfg->phys_erase_block = CFG_SPIFFS_PHYS_ERASE_SZ;
|
||||
g_spiffs_mgr->cfg->log_block_size = CFG_SPIFFS_LOG_BLOCK_SZ;
|
||||
g_spiffs_mgr->cfg->log_page_size = CFG_SPIFFS_LOG_PAGE_SZ;
|
||||
#endif
|
||||
|
||||
#if SPIFFS_FILEHDL_OFFSET
|
||||
g_spiffs_mgr->cfg->fh_ix_offset = SPIFFS_FILEHDL_OFFSET;
|
||||
#endif
|
||||
|
||||
/* init spiffs fs struct */
|
||||
g_spiffs_mgr->fs = (spiffs *)aos_malloc(sizeof(spiffs));
|
||||
if (g_spiffs_mgr->fs == NULL)
|
||||
goto err;
|
||||
memset(g_spiffs_mgr->fs, 0, sizeof(spiffs));
|
||||
|
||||
g_spiffs_mgr->fs->user_data = (void *)g_spiffs_mgr->fs;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
_spiffs_deinit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const fs_ops_t spiffs_ops = {
|
||||
.open = &_spiffs_open,
|
||||
.close = &_spiffs_close,
|
||||
.read = &_spiffs_read,
|
||||
.write = &_spiffs_write,
|
||||
.lseek = &_spiffs_lseek,
|
||||
.sync = &_spiffs_sync,
|
||||
.stat = &_spiffs_stat,
|
||||
.unlink = &_spiffs_unlink,
|
||||
.rename = &_spiffs_rename,
|
||||
.opendir = &_spiffs_opendir,
|
||||
.readdir = &_spiffs_readdir,
|
||||
.closedir = &_spiffs_closedir,
|
||||
.mkdir = NULL,
|
||||
.ioctl = NULL
|
||||
};
|
||||
|
||||
int vfs_spiffs_register(void)
|
||||
{
|
||||
int ret = SPIFFS_OK;
|
||||
|
||||
ret = _spiffs_init();
|
||||
if (ret != SPIFFS_OK)
|
||||
return ret;
|
||||
|
||||
// first try to mount
|
||||
ret = SPIFFS_mount(g_spiffs_mgr->fs, g_spiffs_mgr->cfg,
|
||||
g_spiffs_mgr->work, g_spiffs_mgr->fds, g_spiffs_mgr->fds_sz,
|
||||
g_spiffs_mgr->cache, g_spiffs_mgr->cache_sz, 0);
|
||||
|
||||
if (ret != SPIFFS_OK) {
|
||||
if (ret == SPIFFS_ERR_NOT_A_FS) {
|
||||
if (SPIFFS_format(g_spiffs_mgr->fs) == SPIFFS_OK) {
|
||||
// second try to mount (already formatted)
|
||||
ret = SPIFFS_mount(g_spiffs_mgr->fs, g_spiffs_mgr->cfg,
|
||||
g_spiffs_mgr->work, g_spiffs_mgr->fds, g_spiffs_mgr->fds_sz,
|
||||
g_spiffs_mgr->cache, g_spiffs_mgr->cache_sz, 0);
|
||||
if (ret != SPIFFS_OK)
|
||||
goto err;
|
||||
} else
|
||||
goto err;
|
||||
} else
|
||||
goto err;
|
||||
}
|
||||
|
||||
return aos_register_fs(spiffs_mnt_path, &spiffs_ops, NULL);
|
||||
|
||||
err:
|
||||
_spiffs_deinit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vfs_spiffs_unregister(void)
|
||||
{
|
||||
SPIFFS_unmount(g_spiffs_mgr->fs);
|
||||
_spiffs_deinit();
|
||||
return aos_unregister_fs(spiffs_mnt_path);
|
||||
}
|
83
Living_SDK/3rdparty/experimental/uffs/README
vendored
Normal file
83
Living_SDK/3rdparty/experimental/uffs/README
vendored
Normal file
|
@ -0,0 +1,83 @@
|
|||
This software component is used to help users port third-party programs, but WITHOUT ANY WARRANTY. The entire risk as to the quality and performance of the program is with you. Should the program prove defective, you assume the cost of all necessary servicing, repair or correction. The use of third-party programs must also follow its own permissive license.
|
||||
|
||||
how to use uffs under AliOS-Things
|
||||
|
||||
There are four steps.
|
||||
1. get uffs zipball from official repo.
|
||||
the repo of official repo is here.
|
||||
https://github.com/rickyzheng/uffs
|
||||
then you can download the zipball for master branch
|
||||
https://codeload.github.com/rickyzheng/uffs/zip/master
|
||||
|
||||
decompress the uffs-master.zip, and copy the inc/ and uffs/ directories to aos/kernel/modules/fs/uffs
|
||||
also you need copy the uffs_config.h to the inc/ directory.
|
||||
(you can find the uffs_config.h in uffs-master.zip, you can choose the one under posix sub-directory, or you can define it by yourself).
|
||||
|
||||
2. add uffs source file to build system.
|
||||
for GCC:
|
||||
(1) declare uffs source file to the uffs.mk(aos/kerner/modules/fs/uffs/uffs.mk).
|
||||
Example:
|
||||
$(NAME)_SOURCES += uffs/uffs_badblock.c \
|
||||
uffs/uffs_blockinfo.c \
|
||||
uffs/uffs_buf.c \
|
||||
uffs/uffs_crc.c \
|
||||
uffs/uffs_debug.c \
|
||||
uffs/uffs_device.c \
|
||||
uffs/uffs_ecc.c \
|
||||
uffs/uffs_fd.c \
|
||||
uffs/uffs_find.c \
|
||||
uffs/uffs_flash.c \
|
||||
uffs/uffs_fs.c \
|
||||
uffs/uffs_init.c \
|
||||
uffs/uffs_mem.c \
|
||||
uffs/uffs_mtb.c \
|
||||
uffs/uffs_pool.c \
|
||||
uffs/uffs_public.c \
|
||||
uffs/uffs_tree.c \
|
||||
uffs/uffs_utils.c \
|
||||
uffs/uffs_version.c
|
||||
|
||||
(2) declare uffs include file to uffs.mk(aos/kerner/modules/fs/uffs/uffs.mk).
|
||||
Example:
|
||||
GLOBAL_INCLUDES += inc
|
||||
|
||||
(3) declare uffs dependences.
|
||||
you can declare the dependence in your example's makefile ("example_name".mk) or platform's makefile ("platform_name".mk)
|
||||
Example:
|
||||
$(NAME)_COMPONENTS += modules.fs.uffs
|
||||
|
||||
for MDK or IAR:
|
||||
(1) add uffs source files to the IDE project.
|
||||
|
||||
(2) add uffs include file to the IDE project.
|
||||
|
||||
(3) add uffs porting file to the IDE project.
|
||||
file list:
|
||||
uffs_aos.c
|
||||
uffs_port.c
|
||||
uffs_port.h
|
||||
aos_uffs.h
|
||||
|
||||
3. add nand driver and compile
|
||||
In order to use uffs, you should provide a nand driver which is needed by uffs.
|
||||
you also should implement the NAND HAL interface based on your nand driver.
|
||||
the HAL interface is declared in "aos/include/hal/soc/nand.h".
|
||||
then you can use AliOS GCC build system or IDE like MDK or IAR to compile.
|
||||
|
||||
!!! Note !!!: for hal_nand_init interface, you should initialize the nand device
|
||||
include config the page data size, spare size, block size, zone size and so on. (the detail parameters you can check the struct defination)
|
||||
|
||||
4. use uffs in your code
|
||||
the uffs interface had already been attached to AliOS-Things vfs layer. vfs layer provide a lot of file operation functions,
|
||||
you can use these functions to access the uffs. the function defination is located in "aos/include/aos/vfs.h".
|
||||
Example:
|
||||
*1. call vfs_uffs_register to mount the uffs. (MUST DO)
|
||||
2. call aos_open("/uffs/uffs.txt", O_RDWR) to open a uffs.txt file.
|
||||
3. call aos_close(fd) to close the file.
|
||||
4. call vfs_uffs_unregister to unmount the uffs.
|
||||
|
||||
!!! None !!!: in AliOS-Things, the mount path for uffs self is "/", and the mount path for vfs layer is "/uffs". there are different!
|
||||
For example:
|
||||
if you call aos_open("/uffs/uffs.txt", O_RDWR), it's equal to call uffs_open("/uffs.txt", O_RDWR);
|
||||
|
||||
we suggest that you can use the aos_* function to access filesystem.
|
20
Living_SDK/3rdparty/experimental/uffs/include/aos_uffs.h
vendored
Normal file
20
Living_SDK/3rdparty/experimental/uffs/include/aos_uffs.h
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
|
||||
*/
|
||||
|
||||
#ifndef FS_UFFS_H
|
||||
#define FS_UFFS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int vfs_uffs_register(void);
|
||||
int vfs_uffs_unregister(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
37
Living_SDK/3rdparty/experimental/uffs/include/uffs_port.h
vendored
Normal file
37
Living_SDK/3rdparty/experimental/uffs/include/uffs_port.h
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
|
||||
*/
|
||||
|
||||
#ifndef UFFS_VFS_H
|
||||
#define UFFS_VFS_H
|
||||
|
||||
#include "uffs_config.h"
|
||||
#include "uffs/uffs_public.h"
|
||||
|
||||
#include <vfs_inode.h>
|
||||
#include <vfs_register.h>
|
||||
|
||||
#ifndef CONFIG_UFFS_ECC_MODE
|
||||
#define CONFIG_UFFS_ECC_MODE UFFS_ECC_NONE
|
||||
#endif
|
||||
|
||||
#if CONFIG_UFFS_ECC_MODE == UFFS_ECC_NONE
|
||||
#define CONFIG_UFFS_LAYOUT UFFS_LAYOUT_UFFS
|
||||
|
||||
#elif CONFIG_UFFS_ECC_MODE == UFFS_ECC_SOFT
|
||||
#define CONFIG_UFFS_LAYOUT UFFS_LAYOUT_UFFS
|
||||
|
||||
#elif CONFIG_UFFS_ECC_MODE == UFFS_ECC_HW_AUTO
|
||||
#define CONFIG_UFFS_LAYOUT UFFS_LAYOUT_FLASH
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_UFFS_START_BLOCK
|
||||
#define CONFIG_UFFS_START_BLOCK 0
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_UFFS_END_BLOCK
|
||||
#define CONFIG_UFFS_END_BLOCK 0xffffffff
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
15
Living_SDK/3rdparty/experimental/uffs/uffs.mk
vendored
Normal file
15
Living_SDK/3rdparty/experimental/uffs/uffs.mk
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
NAME := uffs
|
||||
|
||||
$(NAME)_TYPE := kernel
|
||||
|
||||
$(NAME)_SOURCES += uffs_aos.c uffs_port.c
|
||||
|
||||
#default gcc
|
||||
ifeq ($(COMPILER),)
|
||||
$(NAME)_CFLAGS += -Wall -Werror -Wno-strict-aliasing -Wno-uninitialized
|
||||
else ifeq ($(COMPILER),gcc)
|
||||
$(NAME)_CFLAGS += -Wall -Werror -Wno-strict-aliasing -Wno-uninitialized
|
||||
endif
|
||||
|
||||
GLOBAL_INCLUDES += include
|
||||
GLOBAL_DEFINES += AOS_UFFS
|
79
Living_SDK/3rdparty/experimental/uffs/uffs_aos.c
vendored
Normal file
79
Living_SDK/3rdparty/experimental/uffs/uffs_aos.c
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
|
||||
*/
|
||||
#include "uffs_port.h"
|
||||
#include "uffs/uffs_os.h"
|
||||
#include <aos/aos.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define PFX "os : "
|
||||
#define UFFS_TAG "uffs"
|
||||
|
||||
int uffs_SemCreate(OSSEM *sem)
|
||||
{
|
||||
return aos_mutex_new((aos_mutex_t *)sem);
|
||||
}
|
||||
|
||||
int uffs_SemWait(OSSEM sem)
|
||||
{
|
||||
return aos_mutex_lock((aos_mutex_t *)(&sem), AOS_WAIT_FOREVER);
|
||||
}
|
||||
|
||||
int uffs_SemSignal(OSSEM sem)
|
||||
{
|
||||
return aos_mutex_unlock((aos_mutex_t *)(&sem));
|
||||
}
|
||||
|
||||
int uffs_SemDelete(OSSEM *sem)
|
||||
{
|
||||
aos_mutex_free((aos_mutex_t *)sem);
|
||||
*sem = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uffs_OSGetTaskId(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int uffs_GetCurDateTime(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 0
|
||||
static void * sys_malloc(struct uffs_DeviceSt *dev, unsigned int size)
|
||||
{
|
||||
uffs_Perror(UFFS_MSG_NORMAL, "system memory alloc %d bytes", size);
|
||||
return aos_malloc(size);
|
||||
}
|
||||
|
||||
static URET sys_free(struct uffs_DeviceSt *dev, void *p)
|
||||
{
|
||||
aos_free(p);
|
||||
return U_SUCC;
|
||||
}
|
||||
|
||||
void uffs_MemSetupSystemAllocator(uffs_MemAllocator *allocator)
|
||||
{
|
||||
allocator->malloc = sys_malloc;
|
||||
allocator->free = sys_free;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void output_dbg_msg(const char *msg);
|
||||
static struct uffs_DebugMsgOutputSt m_dbg_ops = {
|
||||
output_dbg_msg,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void output_dbg_msg(const char *msg)
|
||||
{
|
||||
LOGD(UFFS_TAG, "%s", msg);
|
||||
}
|
||||
|
||||
void uffs_SetupDebugOutput(void)
|
||||
{
|
||||
uffs_InitDebugMessageOutput(&m_dbg_ops, UFFS_MSG_NOISY);
|
||||
}
|
666
Living_SDK/3rdparty/experimental/uffs/uffs_port.c
vendored
Normal file
666
Living_SDK/3rdparty/experimental/uffs/uffs_port.c
vendored
Normal file
|
@ -0,0 +1,666 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "uffs/uffs_fd.h"
|
||||
#include "uffs/uffs_mtb.h"
|
||||
#include "uffs/uffs_flash.h"
|
||||
|
||||
#include "uffs_port.h"
|
||||
#include <hal/hal.h>
|
||||
|
||||
#define UFFS_NAME_LEN 256
|
||||
|
||||
static const char *uffs_mnt_path = "/uffs";
|
||||
|
||||
typedef struct {
|
||||
nand_dev_t *dev;
|
||||
struct uffs_StorageAttrSt *storage;
|
||||
uffs_Device *udev;
|
||||
uffs_MountTable *mtb;
|
||||
} uffs_mgr_t;
|
||||
|
||||
static uffs_mgr_t *g_uffs_mgr = NULL;
|
||||
|
||||
typedef struct {
|
||||
aos_dir_t dir;
|
||||
uffs_DIR *d;
|
||||
aos_dirent_t cur_dirent;
|
||||
} uffs_dir_t;
|
||||
|
||||
static int nand_erase_block(uffs_Device *dev, uint32_t block)
|
||||
{
|
||||
nand_addr_t addr;
|
||||
|
||||
addr.zone = block / (((nand_dev_t *)(dev->_private))->config.zone_size);
|
||||
addr.block = block - (addr.zone) * ((((nand_dev_t *)(dev->_private))->config.zone_size));
|
||||
hal_nand_erase_block(dev->_private, &addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nand_read_page(uffs_Device *dev, uint32_t block, uint32_t page, uint8_t *data,
|
||||
int data_len, uint8_t *ecc,uint8_t *spare, int spare_len)
|
||||
{
|
||||
nand_addr_t addr;
|
||||
int page_count, page_size, ret;
|
||||
uint8_t *spare_buffer, *data_buffer = NULL;
|
||||
|
||||
addr.zone = block / (((nand_dev_t *)(dev->_private))->config.zone_size);
|
||||
addr.block = block - (addr.zone) * ((((nand_dev_t *)(dev->_private))->config.zone_size));
|
||||
addr.page = page;
|
||||
|
||||
page_size = ((nand_dev_t *)(dev->_private))->config.page_size;
|
||||
page_count = data_len / page_size + ((data_len % page_size) > 0 ? 1 : 0);
|
||||
|
||||
if (data == NULL && spare == NULL) {
|
||||
spare_buffer = (uint8_t *)aos_malloc(dev->attr->spare_size);
|
||||
if (!spare_buffer) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
memset(spare_buffer, 0, dev->attr->spare_size);
|
||||
hal_nand_read_spare(dev->_private, &addr, spare_buffer, dev->attr->spare_size);
|
||||
|
||||
ret = *(spare_buffer + dev->attr->block_status_offs) == 0xFF ?
|
||||
UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK;
|
||||
|
||||
aos_free(spare_buffer);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
if (data && data_len > 0) {
|
||||
data_buffer = (uint8_t *)aos_malloc(page_size);
|
||||
if (!data_buffer)
|
||||
return -EIO;
|
||||
memset(data_buffer, 0, page_size);
|
||||
hal_nand_read_page(dev->_private, &addr, data_buffer, page_count);
|
||||
memcpy(data, data_buffer, data_len);
|
||||
aos_free(data_buffer);
|
||||
}
|
||||
|
||||
if (spare && spare_len > 0)
|
||||
hal_nand_read_spare(dev->_private, &addr, spare, spare_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nand_write_page(uffs_Device *dev, uint32_t block, uint32_t page,
|
||||
const uint8_t *data, int data_len, const uint8_t *spare, int spare_len)
|
||||
{
|
||||
nand_addr_t addr;
|
||||
int page_count, page_size;
|
||||
uint8_t *spare_buffer, *data_buffer = NULL;
|
||||
|
||||
addr.zone = block / (((nand_dev_t *)(dev->_private))->config.zone_size);
|
||||
addr.block = block - (addr.zone) * ((((nand_dev_t *)(dev->_private))->config.zone_size));
|
||||
addr.page = page;
|
||||
|
||||
page_size = ((nand_dev_t *)(dev->_private))->config.page_size;
|
||||
page_count = data_len / page_size + ((data_len % page_size) > 0 ? 1 : 0);
|
||||
|
||||
if (data == NULL && spare == NULL) {
|
||||
spare_buffer = (uint8_t *)aos_malloc(UFFS_MAX_SPARE_SIZE);
|
||||
if (!spare_buffer)
|
||||
return -EIO;
|
||||
memset(spare_buffer, 0, UFFS_MAX_SPARE_SIZE);
|
||||
*(spare_buffer + dev->attr->block_status_offs) = 0x00;
|
||||
hal_nand_write_spare(dev->_private, &addr, spare_buffer, dev->attr->spare_size);
|
||||
aos_free(spare_buffer);
|
||||
}
|
||||
|
||||
if (data && data_len > 0) {
|
||||
data_buffer = (uint8_t *)aos_malloc(page_size);
|
||||
if (!data_buffer)
|
||||
return -EIO;
|
||||
memset(data_buffer, 0xff, page_size);
|
||||
memcpy(data_buffer, data, data_len);
|
||||
hal_nand_write_page(dev->_private, &addr, data_buffer, page_count);
|
||||
aos_free(data_buffer);
|
||||
}
|
||||
|
||||
if (spare && spare_len > 0) {
|
||||
hal_nand_write_spare(dev->_private, &addr, (uint8_t *)spare, spare_len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const uffs_FlashOps uffs_nand_ops =
|
||||
{
|
||||
.ReadPage = &nand_read_page,
|
||||
.WritePage = &nand_write_page,
|
||||
.EraseBlock = &nand_erase_block
|
||||
};
|
||||
|
||||
static char* translate_relative_path(const char *path)
|
||||
{
|
||||
int len, prefix_len;
|
||||
char *relpath, *p;
|
||||
|
||||
if (!path)
|
||||
return NULL;
|
||||
|
||||
len = strlen(path);
|
||||
prefix_len = strlen(uffs_mnt_path);
|
||||
if (strncmp(uffs_mnt_path, path, prefix_len) != 0)
|
||||
return NULL;
|
||||
|
||||
len = len - prefix_len;
|
||||
relpath = (char *)aos_malloc(len + 1);
|
||||
if (!relpath)
|
||||
return NULL;
|
||||
|
||||
memset(relpath, 0, len + 1);
|
||||
if (len > 0) {
|
||||
p = (char *)(path + prefix_len);
|
||||
memcpy(relpath, p, len);
|
||||
}
|
||||
|
||||
relpath[len] = '\0';
|
||||
|
||||
return relpath;
|
||||
}
|
||||
|
||||
static int _uffs_ret_to_err(int ret)
|
||||
{
|
||||
switch (ret) {
|
||||
case UENOERR:
|
||||
return 0;
|
||||
case UEACCES:
|
||||
return -EACCES;
|
||||
case UEEXIST:
|
||||
return -EEXIST;
|
||||
case UEINVAL:
|
||||
return -EINVAL;
|
||||
case UEMFILE:
|
||||
return -ENFILE;
|
||||
case UENOENT:
|
||||
return -ENOENT;
|
||||
case UEBADF:
|
||||
return -EBADF;
|
||||
case UENOMEM:
|
||||
return -ENOMEM;
|
||||
case UEIOERR:
|
||||
case UETIME:
|
||||
return -EIO;
|
||||
case UENOTDIR:
|
||||
return -ENOTDIR;
|
||||
case UEISDIR:
|
||||
return -EISDIR;
|
||||
case UEUNKNOWN_ERR:
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
static int _uffs_mode_conv(int flags)
|
||||
{
|
||||
int acc_mode, res = 0;
|
||||
acc_mode = flags & O_ACCMODE;
|
||||
if (acc_mode == O_RDONLY) {
|
||||
res |= UO_RDONLY;
|
||||
} else if (acc_mode == O_WRONLY) {
|
||||
res |= UO_WRONLY;
|
||||
} else if (acc_mode == O_RDWR) {
|
||||
res |= UO_RDWR;
|
||||
}
|
||||
|
||||
if ((flags & O_CREAT) && (flags & O_EXCL)) {
|
||||
res |= UO_CREATE | UO_EXCL;
|
||||
} else if ((flags & O_CREAT) && (flags & O_TRUNC)) {
|
||||
res |= UO_CREATE | UO_TRUNC;
|
||||
} else if (flags & O_APPEND) {
|
||||
res |= UO_CREATE | UO_APPEND;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _uffs_open(file_t *fp, const char *path, int flags)
|
||||
{
|
||||
int fd;
|
||||
char *relpath = NULL;
|
||||
|
||||
relpath = translate_relative_path(path);
|
||||
if (!relpath)
|
||||
return -EINVAL;
|
||||
|
||||
fd = uffs_open(relpath, _uffs_mode_conv(flags));
|
||||
if (fd > 0) {
|
||||
fp->f_arg = (void *)fd;
|
||||
fd = 0;
|
||||
} else {
|
||||
fd = _uffs_ret_to_err(uffs_get_error());
|
||||
}
|
||||
|
||||
aos_free(relpath);
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int _uffs_close(file_t *fp)
|
||||
{
|
||||
int fd, ret;
|
||||
|
||||
fd = (int)(fp->f_arg);
|
||||
ret = uffs_close(fd);
|
||||
if (ret < 0) {
|
||||
ret = _uffs_ret_to_err(uffs_get_error());
|
||||
} else {
|
||||
fp->f_arg = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t _uffs_read(file_t *fp, char *buf, size_t len)
|
||||
{
|
||||
ssize_t nbytes;
|
||||
int fd;
|
||||
|
||||
fd = (int)(fp->f_arg);
|
||||
nbytes = uffs_read(fd, buf, len);
|
||||
if (nbytes < 0) {
|
||||
nbytes = _uffs_ret_to_err(uffs_get_error());
|
||||
}
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
static ssize_t _uffs_write(file_t *fp, const char *buf, size_t len)
|
||||
{
|
||||
ssize_t nbytes;
|
||||
int fd;
|
||||
|
||||
fd = (int)(fp->f_arg);
|
||||
nbytes = uffs_write(fd, (void *)buf, len);
|
||||
if (nbytes < 0) {
|
||||
nbytes = _uffs_ret_to_err(uffs_get_error());
|
||||
}
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
static off_t _uffs_lseek(file_t *fp, off_t off, int whence)
|
||||
{
|
||||
off_t ret;
|
||||
int fd;
|
||||
|
||||
fd = (int)(fp->f_arg);
|
||||
ret = uffs_seek(fd, off, whence);
|
||||
if (ret < 0) {
|
||||
ret = _uffs_ret_to_err(uffs_get_error());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _uffs_sync(file_t *fp)
|
||||
{
|
||||
int ret, fd;
|
||||
|
||||
fd = (int)(fp->f_arg);
|
||||
ret = uffs_flush(fd);
|
||||
if (ret < 0) {
|
||||
ret = _uffs_ret_to_err(uffs_get_error());
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _uffs_stat(file_t *fp, const char *path, struct stat *st)
|
||||
{
|
||||
int ret;
|
||||
struct uffs_stat s;
|
||||
char *relpath = NULL;
|
||||
|
||||
relpath = translate_relative_path(path);
|
||||
if (!relpath)
|
||||
return -EINVAL;
|
||||
|
||||
ret = uffs_stat(relpath, &s);
|
||||
if (ret < 0) {
|
||||
ret = _uffs_ret_to_err(uffs_get_error());
|
||||
} else {
|
||||
st->st_size = s.st_size;
|
||||
st->st_mode = s.st_mode;
|
||||
}
|
||||
|
||||
aos_free(relpath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _uffs_unlink(file_t *fp, const char *path)
|
||||
{
|
||||
int ret;
|
||||
struct uffs_stat s;
|
||||
char *relpath = NULL;
|
||||
|
||||
relpath = translate_relative_path(path);
|
||||
if (!relpath)
|
||||
return -EINVAL;
|
||||
|
||||
if (uffs_lstat(relpath, &s) < 0) {
|
||||
aos_free(relpath);
|
||||
return _uffs_ret_to_err(uffs_get_error());
|
||||
}
|
||||
|
||||
switch(s.st_mode & US_IFMT) {
|
||||
case US_IFREG:
|
||||
ret = uffs_remove(relpath);
|
||||
break;
|
||||
case US_IFDIR:
|
||||
ret = uffs_rmdir(relpath);
|
||||
break;
|
||||
default:
|
||||
aos_free(relpath);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
ret = _uffs_ret_to_err(uffs_get_error());
|
||||
}
|
||||
|
||||
aos_free(relpath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _uffs_rename(file_t *fp, const char *oldpath, const char *newpath)
|
||||
{
|
||||
int ret;
|
||||
char *oldname = NULL;
|
||||
char *newname = NULL;
|
||||
|
||||
oldname = translate_relative_path(oldpath);
|
||||
if (!oldname)
|
||||
return -EINVAL;
|
||||
|
||||
newname = translate_relative_path(newpath);
|
||||
if (!newname) {
|
||||
aos_free(oldname);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = uffs_rename(oldname, newname);
|
||||
if (ret < 0) {
|
||||
ret = _uffs_ret_to_err(uffs_get_error());
|
||||
}
|
||||
|
||||
aos_free(oldname);
|
||||
aos_free(newname);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static aos_dir_t* _uffs_opendir(file_t *fp, const char *path)
|
||||
{
|
||||
uffs_dir_t *dp = NULL;
|
||||
char *relpath = NULL;
|
||||
uffs_DIR *dir = NULL;
|
||||
|
||||
relpath = translate_relative_path(path);
|
||||
if (!relpath)
|
||||
return NULL;
|
||||
|
||||
dp = (uffs_dir_t *)aos_malloc(sizeof(uffs_dir_t) + UFFS_NAME_LEN);
|
||||
if (!dp) {
|
||||
aos_free(relpath);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(dp, 0, sizeof(uffs_dir_t) + UFFS_NAME_LEN);
|
||||
dir = uffs_opendir(relpath);
|
||||
if (!dir) {
|
||||
aos_free(relpath);
|
||||
aos_free(dp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dp->d = dir;
|
||||
aos_free(relpath);
|
||||
return (aos_dir_t *)dp;
|
||||
}
|
||||
|
||||
static aos_dirent_t* _uffs_readdir(file_t *fp, aos_dir_t *dir)
|
||||
{
|
||||
uffs_dir_t *dp;
|
||||
struct uffs_dirent *e;
|
||||
aos_dirent_t *out_dirent;
|
||||
|
||||
dp = (uffs_dir_t *)dir;
|
||||
if (!dp)
|
||||
return NULL;
|
||||
|
||||
e = uffs_readdir(dp->d);
|
||||
if (!e) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (e->d_name[0] == 0)
|
||||
return NULL;
|
||||
|
||||
dp->cur_dirent.d_ino = 0;
|
||||
dp->cur_dirent.d_type = e->d_type;
|
||||
|
||||
strncpy(dp->cur_dirent.d_name, (char *)e->d_name, UFFS_NAME_LEN);
|
||||
dp->cur_dirent.d_name[UFFS_NAME_LEN] = '\0';
|
||||
|
||||
out_dirent = &dp->cur_dirent;
|
||||
return out_dirent;
|
||||
}
|
||||
|
||||
static int _uffs_closedir(file_t *fp, aos_dir_t *dir)
|
||||
{
|
||||
int ret;
|
||||
uffs_dir_t *dp = (uffs_dir_t *)dir;
|
||||
|
||||
if (!dp)
|
||||
return -EINVAL;
|
||||
|
||||
ret = uffs_closedir(dp->d);
|
||||
if (ret < 0) {
|
||||
ret = _uffs_ret_to_err(uffs_get_error());
|
||||
}
|
||||
|
||||
aos_free(dp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _uffs_mkdir(file_t *fp, const char *path)
|
||||
{
|
||||
int ret;
|
||||
char *relpath = NULL;
|
||||
|
||||
relpath = translate_relative_path(path);
|
||||
if (!relpath)
|
||||
return -EINVAL;
|
||||
|
||||
ret = uffs_mkdir(relpath);
|
||||
if (ret < 0) {
|
||||
ret = _uffs_ret_to_err(uffs_get_error());
|
||||
}
|
||||
|
||||
aos_free(relpath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const fs_ops_t uffs_ops = {
|
||||
.open = &_uffs_open,
|
||||
.close = &_uffs_close,
|
||||
.read = &_uffs_read,
|
||||
.write = &_uffs_write,
|
||||
.lseek = &_uffs_lseek,
|
||||
.sync = &_uffs_sync,
|
||||
.stat = &_uffs_stat,
|
||||
.unlink = &_uffs_unlink,
|
||||
.rename = &_uffs_rename,
|
||||
.opendir = &_uffs_opendir,
|
||||
.readdir = &_uffs_readdir,
|
||||
.closedir = &_uffs_closedir,
|
||||
.mkdir = &_uffs_mkdir,
|
||||
.ioctl = NULL
|
||||
};
|
||||
|
||||
static URET _uffs_device_init(uffs_Device *dev)
|
||||
{
|
||||
dev->attr->_private = NULL;
|
||||
dev->ops = (struct uffs_FlashOpsSt *)&uffs_nand_ops;
|
||||
|
||||
return U_SUCC;
|
||||
}
|
||||
|
||||
static URET _uffs_device_release(uffs_Device *dev)
|
||||
{
|
||||
return U_SUCC;
|
||||
}
|
||||
|
||||
static int _uffs_fs_init(uffs_mgr_t *mgr)
|
||||
{
|
||||
int ret;
|
||||
/* init low level nand device */
|
||||
ret = hal_nand_init(mgr->dev);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* init storage attribute struct */
|
||||
mgr->storage->page_data_size = mgr->dev->config.page_size;
|
||||
mgr->storage->pages_per_block = mgr->dev->config.block_size;
|
||||
mgr->storage->spare_size = mgr->dev->config.spare_area_size;
|
||||
mgr->storage->ecc_opt = CONFIG_UFFS_ECC_MODE;
|
||||
mgr->storage->ecc_size = 0;
|
||||
mgr->storage->block_status_offs = mgr->storage->ecc_size;
|
||||
mgr->storage->layout_opt = CONFIG_UFFS_LAYOUT;
|
||||
mgr->storage->total_blocks = mgr->dev->config.zone_number * mgr->dev->config.zone_size;
|
||||
|
||||
/* init uffs device struct */
|
||||
mgr->udev->attr = mgr->storage;
|
||||
mgr->udev->Init = _uffs_device_init;
|
||||
mgr->udev->Release = _uffs_device_release;
|
||||
mgr->udev->_private = mgr->dev;
|
||||
#if CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 0
|
||||
uffs_MemSetupSystemAllocator(&mgr->udev->mem);
|
||||
#endif
|
||||
|
||||
/* init uffs mount table */
|
||||
mgr->mtb->mount = "/";
|
||||
mgr->mtb->dev = mgr->udev;
|
||||
mgr->mtb->start_block = (mgr->storage->total_blocks > CONFIG_UFFS_START_BLOCK) ?
|
||||
CONFIG_UFFS_START_BLOCK : mgr->storage->total_blocks - 1;
|
||||
mgr->mtb->end_block = (mgr->storage->total_blocks > CONFIG_UFFS_END_BLOCK) ?
|
||||
CONFIG_UFFS_END_BLOCK : mgr->storage->total_blocks - 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _uffs_deinit(void)
|
||||
{
|
||||
if (!g_uffs_mgr)
|
||||
return;
|
||||
|
||||
if (g_uffs_mgr->dev) {
|
||||
hal_nand_finalize(g_uffs_mgr->dev);
|
||||
aos_free(g_uffs_mgr->dev);
|
||||
}
|
||||
|
||||
if (g_uffs_mgr->storage) {
|
||||
aos_free(g_uffs_mgr->storage);
|
||||
}
|
||||
|
||||
if (g_uffs_mgr->udev) {
|
||||
aos_free(g_uffs_mgr->udev);
|
||||
}
|
||||
|
||||
if (g_uffs_mgr->mtb) {
|
||||
aos_free(g_uffs_mgr->mtb);
|
||||
}
|
||||
|
||||
aos_free(g_uffs_mgr);
|
||||
g_uffs_mgr = NULL;
|
||||
}
|
||||
|
||||
static int _uffs_init(void)
|
||||
{
|
||||
if (g_uffs_mgr)
|
||||
return 0;
|
||||
|
||||
g_uffs_mgr = (uffs_mgr_t *)aos_malloc(sizeof(uffs_mgr_t));
|
||||
if (!g_uffs_mgr)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(g_uffs_mgr, 0, sizeof(uffs_mgr_t));
|
||||
|
||||
/* nand flash device */
|
||||
g_uffs_mgr->dev = (nand_dev_t *)aos_malloc(sizeof(nand_dev_t));
|
||||
if (!g_uffs_mgr->dev)
|
||||
goto err;
|
||||
memset(g_uffs_mgr->dev, 0, sizeof(nand_dev_t));
|
||||
|
||||
/* uffs storage attribute struct */
|
||||
g_uffs_mgr->storage = (struct uffs_StorageAttrSt *)aos_malloc(sizeof(struct uffs_StorageAttrSt));
|
||||
if (!g_uffs_mgr->storage)
|
||||
goto err;
|
||||
memset(g_uffs_mgr->storage, 0, sizeof(struct uffs_StorageAttrSt));
|
||||
|
||||
/* uffs device */
|
||||
g_uffs_mgr->udev = (uffs_Device *)aos_malloc(sizeof(uffs_Device));
|
||||
if (!g_uffs_mgr->udev)
|
||||
goto err;
|
||||
memset(g_uffs_mgr->udev, 0, sizeof(uffs_Device));
|
||||
|
||||
/* uffs mount table */
|
||||
g_uffs_mgr->mtb = (uffs_MountTable *)aos_malloc(sizeof(uffs_MountTable));
|
||||
if (!g_uffs_mgr->mtb)
|
||||
goto err;
|
||||
memset(g_uffs_mgr->mtb, 0, sizeof(uffs_MountTable));
|
||||
|
||||
if (_uffs_fs_init(g_uffs_mgr) == 0)
|
||||
return 0;
|
||||
|
||||
err:
|
||||
_uffs_deinit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int vfs_uffs_register(void)
|
||||
{
|
||||
int ret = U_SUCC;
|
||||
uffs_SetupDebugOutput();
|
||||
|
||||
ret = _uffs_init();
|
||||
if (ret != U_SUCC) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = uffs_InitFileSystemObjects();
|
||||
if (ret != U_SUCC) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = uffs_RegisterMountTable(g_uffs_mgr->mtb);
|
||||
if (ret != U_SUCC) {
|
||||
uffs_ReleaseFileSystemObjects();
|
||||
goto err;
|
||||
}
|
||||
|
||||
// first try to mount
|
||||
ret = uffs_Mount(g_uffs_mgr->mtb->mount);
|
||||
if (ret != U_SUCC) {
|
||||
uffs_UnRegisterMountTable(g_uffs_mgr->mtb);
|
||||
uffs_ReleaseFileSystemObjects();
|
||||
goto err;
|
||||
}
|
||||
|
||||
return aos_register_fs(uffs_mnt_path, &uffs_ops, NULL);
|
||||
|
||||
err:
|
||||
_uffs_deinit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vfs_uffs_unregister(void)
|
||||
{
|
||||
uffs_UnMount(g_uffs_mgr->mtb->mount);
|
||||
uffs_UnRegisterMountTable(g_uffs_mgr->mtb);
|
||||
uffs_ReleaseFileSystemObjects();
|
||||
_uffs_deinit();
|
||||
return aos_unregister_fs(uffs_mnt_path);
|
||||
}
|
4
Living_SDK/3rdparty/experimental/yaffs2/NOTICE.bak
vendored
Normal file
4
Living_SDK/3rdparty/experimental/yaffs2/NOTICE.bak
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
YAFFS2移植到AliOS-Things详细步骤见:
|
||||
https://yq.aliyun.com/articles/418865
|
||||
|
||||
此目录下yaffs_alios.c为AliOS-Things适配YAFFS2的操作系统相关接口,yaffs_install_drv.c和yaffs_install_drv.h对接nand flash驱动的示例对接文件。
|
8
Living_SDK/3rdparty/experimental/yaffs2/README
vendored
Normal file
8
Living_SDK/3rdparty/experimental/yaffs2/README
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
This software component is used to help users port third-party programs, but WITHOUT ANY WARRANTY. The entire risk as to the quality and performance of the program is with you. Should the program prove defective, you assume the cost of all necessary servicing, repair or correction. The use of third-party programs must also follow its own permissive license.
|
||||
|
||||
YAFFS2移植到AliOS-Things详细步骤见:
|
||||
https://yq.aliyun.com/articles/418865
|
||||
|
||||
此目录下yaffs_alios.c为AliOS-Things适配YAFFS2的操作系统相关接口,yaffs_install_drv.c和yaffs_install_drv.h对接nand flash驱动的示例对接文件。
|
||||
|
||||
This directory include all the yaffs2 porting files.
|
101
Living_SDK/3rdparty/experimental/yaffs2/yaffs_alios.c
vendored
Normal file
101
Living_SDK/3rdparty/experimental/yaffs2/yaffs_alios.c
vendored
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
|
||||
*/
|
||||
|
||||
#include "yaffs_osglue.h"
|
||||
#include "k_api.h"
|
||||
|
||||
#define YAFFS_BG_TASK_STACKSIZE 1024
|
||||
|
||||
static kmutex_t yaffs_mutex;
|
||||
static ktask_t yaffs_bg_task_obj;
|
||||
cpu_stack_t yaffs_bg_task_buf[YAFFS_BG_TASK_STACKSIZE];
|
||||
|
||||
void yaffsfs_Lock(void)
|
||||
{
|
||||
krhino_mutex_lock(&yaffs_mutex, RHINO_WAIT_FOREVER);
|
||||
}
|
||||
|
||||
void yaffsfs_Unlock(void)
|
||||
{
|
||||
krhino_mutex_unlock(&yaffs_mutex);
|
||||
}
|
||||
|
||||
u32 yaffsfs_CurrentTime(void)
|
||||
{
|
||||
return krhino_sys_time_get();
|
||||
}
|
||||
|
||||
static int yaffsfs_lastError;
|
||||
|
||||
int yaffsfs_GetLastError(void)
|
||||
{
|
||||
return yaffsfs_lastError;
|
||||
}
|
||||
|
||||
void yaffsfs_SetError(int err)
|
||||
{
|
||||
yaffsfs_lastError = err;
|
||||
}
|
||||
|
||||
void *yaffsfs_malloc(size_t size)
|
||||
{
|
||||
return krhino_mm_alloc(size);
|
||||
}
|
||||
|
||||
void yaffsfs_free(void *ptr)
|
||||
{
|
||||
krhino_mm_free(ptr);
|
||||
}
|
||||
|
||||
int yaffsfs_CheckMemRegion(const void *addr, size_t size, int write_request)
|
||||
{
|
||||
/* add code according to the hardware configuration */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bg_gc_func(void *dummy)
|
||||
{
|
||||
struct yaffs_dev *dev;
|
||||
int urgent = 0;
|
||||
int result = 0;
|
||||
int next_urgent = 0;
|
||||
|
||||
(void)dummy;
|
||||
|
||||
/* Sleep for a bit to allow start up */
|
||||
krhino_task_sleep(2);
|
||||
|
||||
while (1) {
|
||||
/* Iterate through devices, do bg gc updating ungency */
|
||||
yaffs_dev_rewind();
|
||||
next_urgent = 0;
|
||||
|
||||
while ((dev = yaffs_next_dev()) != NULL) {
|
||||
result = yaffs_do_background_gc_reldev(dev, urgent);
|
||||
if (result > 0)
|
||||
next_urgent = 1;
|
||||
}
|
||||
|
||||
urgent = next_urgent;
|
||||
|
||||
if (next_urgent) {
|
||||
krhino_task_sleep(1);
|
||||
} else {
|
||||
krhino_task_sleep(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void yaffsfs_OSInitialisation(void)
|
||||
{
|
||||
krhino_mutex_create(&yaffs_mutex, "mutex");
|
||||
|
||||
krhino_task_create(&yaffs_bg_task_obj, "yaffs_bg_task", 0, 20,
|
||||
50, yaffs_bg_task_buf, YAFFS_BG_TASK_STACKSIZE, bg_gc_func, 1);
|
||||
}
|
||||
|
||||
void yaffs_bug_fn(const char *file_name, int line_no)
|
||||
{
|
||||
printf("yaffs bug detected %s:%d\n", file_name, line_no);
|
||||
}
|
99
Living_SDK/3rdparty/experimental/yaffs2/yaffs_install_drv.c
vendored
Normal file
99
Living_SDK/3rdparty/experimental/yaffs2/yaffs_install_drv.c
vendored
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
|
||||
*/
|
||||
|
||||
#include "yportenv.h"
|
||||
#include "yaffs_guts.h"
|
||||
#include "yaffs_install_drv.h"
|
||||
|
||||
static int nand_WriteChunk(struct yaffs_dev *dev, int nand_chunk,
|
||||
const u8 *data, int data_len,
|
||||
const u8 *oob, int oob_len)
|
||||
{
|
||||
/* add code according to your nand driver */
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
static int nand_ReadChunk(struct yaffs_dev *dev, int nand_chunk,
|
||||
u8 *data, int data_len,
|
||||
u8 *oob, int oob_len,
|
||||
enum yaffs_ecc_result *ecc_result)
|
||||
{
|
||||
/* add code according to your nand driver */
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
static int nand_EraseBlock(struct yaffs_dev *dev, int block_no)
|
||||
{
|
||||
/* add code according to your nand driver */
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
static int nand_MarkBad(struct yaffs_dev *dev, int block_no)
|
||||
{
|
||||
/* add code according to your nand driver */
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
static int nand_CheckBad(struct yaffs_dev *dev, int block_no)
|
||||
{
|
||||
/* add code according to your nand driver */
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
static int nand_Initialise(struct yaffs_dev *dev)
|
||||
{
|
||||
/* add code according to your nand driver */
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
struct yaffs_dev *yaffs_install_drv(const char *name)
|
||||
{
|
||||
struct yaffs_dev *dev = NULL;
|
||||
struct yaffs_param *param;
|
||||
struct yaffs_driver *drv;
|
||||
|
||||
if(name == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev = malloc(sizeof(*dev));
|
||||
|
||||
if(dev == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
|
||||
dev->param.name = name;
|
||||
|
||||
drv = &dev->drv;
|
||||
|
||||
drv->drv_write_chunk_fn = nand_WriteChunk;
|
||||
drv->drv_read_chunk_fn = nand_ReadChunk;
|
||||
drv->drv_erase_fn = nand_EraseBlock;
|
||||
drv->drv_mark_bad_fn = nand_MarkBad;
|
||||
drv->drv_check_bad_fn = nand_CheckBad;
|
||||
drv->drv_initialise_fn = nand_Initialise;
|
||||
|
||||
param = &dev->param;
|
||||
|
||||
param->total_bytes_per_chunk = 2048;
|
||||
param->chunks_per_block = 64;
|
||||
param->start_block = 0;
|
||||
param->end_block = 8192;
|
||||
param->is_yaffs2 = 1;
|
||||
param->use_nand_ecc=1;
|
||||
|
||||
param->n_reserved_blocks = 5;
|
||||
param->wide_tnodes_disabled=0;
|
||||
param->refresh_period = 1000;
|
||||
param->n_caches = 10; // Use caches
|
||||
|
||||
param->enable_xattr = 1;
|
||||
|
||||
yaffs_add_device(dev);
|
||||
|
||||
return dev;
|
||||
}
|
13
Living_SDK/3rdparty/experimental/yaffs2/yaffs_install_drv.h
vendored
Normal file
13
Living_SDK/3rdparty/experimental/yaffs2/yaffs_install_drv.h
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_INSTALL_DRV_H__
|
||||
#define __YAFFS_INSTALL_DRV_H__
|
||||
|
||||
struct yaffs_dev;
|
||||
|
||||
struct yaffs_dev *yflash2_install_drv(const char *name);
|
||||
|
||||
#endif
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue