lib/littlefs: Add littlefs v1.7.2 source.
This commit is contained in:
parent
e1c7b1cb43
commit
669d1d20ab
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,501 @@
|
|||
/*
|
||||
* The little filesystem
|
||||
*
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#ifndef LFS1_H
|
||||
#define LFS1_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
/// Version info ///
|
||||
|
||||
// Software library version
|
||||
// Major (top-nibble), incremented on backwards incompatible changes
|
||||
// Minor (bottom-nibble), incremented on feature additions
|
||||
#define LFS1_VERSION 0x00010007
|
||||
#define LFS1_VERSION_MAJOR (0xffff & (LFS1_VERSION >> 16))
|
||||
#define LFS1_VERSION_MINOR (0xffff & (LFS1_VERSION >> 0))
|
||||
|
||||
// Version of On-disk data structures
|
||||
// Major (top-nibble), incremented on backwards incompatible changes
|
||||
// Minor (bottom-nibble), incremented on feature additions
|
||||
#define LFS1_DISK_VERSION 0x00010001
|
||||
#define LFS1_DISK_VERSION_MAJOR (0xffff & (LFS1_DISK_VERSION >> 16))
|
||||
#define LFS1_DISK_VERSION_MINOR (0xffff & (LFS1_DISK_VERSION >> 0))
|
||||
|
||||
|
||||
/// Definitions ///
|
||||
|
||||
// Type definitions
|
||||
typedef uint32_t lfs1_size_t;
|
||||
typedef uint32_t lfs1_off_t;
|
||||
|
||||
typedef int32_t lfs1_ssize_t;
|
||||
typedef int32_t lfs1_soff_t;
|
||||
|
||||
typedef uint32_t lfs1_block_t;
|
||||
|
||||
// Max name size in bytes
|
||||
#ifndef LFS1_NAME_MAX
|
||||
#define LFS1_NAME_MAX 255
|
||||
#endif
|
||||
|
||||
// Max file size in bytes
|
||||
#ifndef LFS1_FILE_MAX
|
||||
#define LFS1_FILE_MAX 2147483647
|
||||
#endif
|
||||
|
||||
// Possible error codes, these are negative to allow
|
||||
// valid positive return values
|
||||
enum lfs1_error {
|
||||
LFS1_ERR_OK = 0, // No error
|
||||
LFS1_ERR_IO = -5, // Error during device operation
|
||||
LFS1_ERR_CORRUPT = -52, // Corrupted
|
||||
LFS1_ERR_NOENT = -2, // No directory entry
|
||||
LFS1_ERR_EXIST = -17, // Entry already exists
|
||||
LFS1_ERR_NOTDIR = -20, // Entry is not a dir
|
||||
LFS1_ERR_ISDIR = -21, // Entry is a dir
|
||||
LFS1_ERR_NOTEMPTY = -39, // Dir is not empty
|
||||
LFS1_ERR_BADF = -9, // Bad file number
|
||||
LFS1_ERR_FBIG = -27, // File too large
|
||||
LFS1_ERR_INVAL = -22, // Invalid parameter
|
||||
LFS1_ERR_NOSPC = -28, // No space left on device
|
||||
LFS1_ERR_NOMEM = -12, // No more memory available
|
||||
};
|
||||
|
||||
// File types
|
||||
enum lfs1_type {
|
||||
LFS1_TYPE_REG = 0x11,
|
||||
LFS1_TYPE_DIR = 0x22,
|
||||
LFS1_TYPE_SUPERBLOCK = 0x2e,
|
||||
};
|
||||
|
||||
// File open flags
|
||||
enum lfs1_open_flags {
|
||||
// open flags
|
||||
LFS1_O_RDONLY = 1, // Open a file as read only
|
||||
LFS1_O_WRONLY = 2, // Open a file as write only
|
||||
LFS1_O_RDWR = 3, // Open a file as read and write
|
||||
LFS1_O_CREAT = 0x0100, // Create a file if it does not exist
|
||||
LFS1_O_EXCL = 0x0200, // Fail if a file already exists
|
||||
LFS1_O_TRUNC = 0x0400, // Truncate the existing file to zero size
|
||||
LFS1_O_APPEND = 0x0800, // Move to end of file on every write
|
||||
|
||||
// internally used flags
|
||||
LFS1_F_DIRTY = 0x10000, // File does not match storage
|
||||
LFS1_F_WRITING = 0x20000, // File has been written since last flush
|
||||
LFS1_F_READING = 0x40000, // File has been read since last flush
|
||||
LFS1_F_ERRED = 0x80000, // An error occured during write
|
||||
};
|
||||
|
||||
// File seek flags
|
||||
enum lfs1_whence_flags {
|
||||
LFS1_SEEK_SET = 0, // Seek relative to an absolute position
|
||||
LFS1_SEEK_CUR = 1, // Seek relative to the current file position
|
||||
LFS1_SEEK_END = 2, // Seek relative to the end of the file
|
||||
};
|
||||
|
||||
|
||||
// Configuration provided during initialization of the littlefs
|
||||
struct lfs1_config {
|
||||
// Opaque user provided context that can be used to pass
|
||||
// information to the block device operations
|
||||
void *context;
|
||||
|
||||
// Read a region in a block. Negative error codes are propogated
|
||||
// to the user.
|
||||
int (*read)(const struct lfs1_config *c, lfs1_block_t block,
|
||||
lfs1_off_t off, void *buffer, lfs1_size_t size);
|
||||
|
||||
// Program a region in a block. The block must have previously
|
||||
// been erased. Negative error codes are propogated to the user.
|
||||
// May return LFS1_ERR_CORRUPT if the block should be considered bad.
|
||||
int (*prog)(const struct lfs1_config *c, lfs1_block_t block,
|
||||
lfs1_off_t off, const void *buffer, lfs1_size_t size);
|
||||
|
||||
// Erase a block. A block must be erased before being programmed.
|
||||
// The state of an erased block is undefined. Negative error codes
|
||||
// are propogated to the user.
|
||||
// May return LFS1_ERR_CORRUPT if the block should be considered bad.
|
||||
int (*erase)(const struct lfs1_config *c, lfs1_block_t block);
|
||||
|
||||
// Sync the state of the underlying block device. Negative error codes
|
||||
// are propogated to the user.
|
||||
int (*sync)(const struct lfs1_config *c);
|
||||
|
||||
// Minimum size of a block read. This determines the size of read buffers.
|
||||
// This may be larger than the physical read size to improve performance
|
||||
// by caching more of the block device.
|
||||
lfs1_size_t read_size;
|
||||
|
||||
// Minimum size of a block program. This determines the size of program
|
||||
// buffers. This may be larger than the physical program size to improve
|
||||
// performance by caching more of the block device.
|
||||
// Must be a multiple of the read size.
|
||||
lfs1_size_t prog_size;
|
||||
|
||||
// Size of an erasable block. This does not impact ram consumption and
|
||||
// may be larger than the physical erase size. However, this should be
|
||||
// kept small as each file currently takes up an entire block.
|
||||
// Must be a multiple of the program size.
|
||||
lfs1_size_t block_size;
|
||||
|
||||
// Number of erasable blocks on the device.
|
||||
lfs1_size_t block_count;
|
||||
|
||||
// Number of blocks to lookahead during block allocation. A larger
|
||||
// lookahead reduces the number of passes required to allocate a block.
|
||||
// The lookahead buffer requires only 1 bit per block so it can be quite
|
||||
// large with little ram impact. Should be a multiple of 32.
|
||||
lfs1_size_t lookahead;
|
||||
|
||||
// Optional, statically allocated read buffer. Must be read sized.
|
||||
void *read_buffer;
|
||||
|
||||
// Optional, statically allocated program buffer. Must be program sized.
|
||||
void *prog_buffer;
|
||||
|
||||
// Optional, statically allocated lookahead buffer. Must be 1 bit per
|
||||
// lookahead block.
|
||||
void *lookahead_buffer;
|
||||
|
||||
// Optional, statically allocated buffer for files. Must be program sized.
|
||||
// If enabled, only one file may be opened at a time.
|
||||
void *file_buffer;
|
||||
};
|
||||
|
||||
// Optional configuration provided during lfs1_file_opencfg
|
||||
struct lfs1_file_config {
|
||||
// Optional, statically allocated buffer for files. Must be program sized.
|
||||
// If NULL, malloc will be used by default.
|
||||
void *buffer;
|
||||
};
|
||||
|
||||
// File info structure
|
||||
struct lfs1_info {
|
||||
// Type of the file, either LFS1_TYPE_REG or LFS1_TYPE_DIR
|
||||
uint8_t type;
|
||||
|
||||
// Size of the file, only valid for REG files
|
||||
lfs1_size_t size;
|
||||
|
||||
// Name of the file stored as a null-terminated string
|
||||
char name[LFS1_NAME_MAX+1];
|
||||
};
|
||||
|
||||
|
||||
/// littlefs data structures ///
|
||||
typedef struct lfs1_entry {
|
||||
lfs1_off_t off;
|
||||
|
||||
struct lfs1_disk_entry {
|
||||
uint8_t type;
|
||||
uint8_t elen;
|
||||
uint8_t alen;
|
||||
uint8_t nlen;
|
||||
union {
|
||||
struct {
|
||||
lfs1_block_t head;
|
||||
lfs1_size_t size;
|
||||
} file;
|
||||
lfs1_block_t dir[2];
|
||||
} u;
|
||||
} d;
|
||||
} lfs1_entry_t;
|
||||
|
||||
typedef struct lfs1_cache {
|
||||
lfs1_block_t block;
|
||||
lfs1_off_t off;
|
||||
uint8_t *buffer;
|
||||
} lfs1_cache_t;
|
||||
|
||||
typedef struct lfs1_file {
|
||||
struct lfs1_file *next;
|
||||
lfs1_block_t pair[2];
|
||||
lfs1_off_t poff;
|
||||
|
||||
lfs1_block_t head;
|
||||
lfs1_size_t size;
|
||||
|
||||
const struct lfs1_file_config *cfg;
|
||||
uint32_t flags;
|
||||
lfs1_off_t pos;
|
||||
lfs1_block_t block;
|
||||
lfs1_off_t off;
|
||||
lfs1_cache_t cache;
|
||||
} lfs1_file_t;
|
||||
|
||||
typedef struct lfs1_dir {
|
||||
struct lfs1_dir *next;
|
||||
lfs1_block_t pair[2];
|
||||
lfs1_off_t off;
|
||||
|
||||
lfs1_block_t head[2];
|
||||
lfs1_off_t pos;
|
||||
|
||||
struct lfs1_disk_dir {
|
||||
uint32_t rev;
|
||||
lfs1_size_t size;
|
||||
lfs1_block_t tail[2];
|
||||
} d;
|
||||
} lfs1_dir_t;
|
||||
|
||||
typedef struct lfs1_superblock {
|
||||
lfs1_off_t off;
|
||||
|
||||
struct lfs1_disk_superblock {
|
||||
uint8_t type;
|
||||
uint8_t elen;
|
||||
uint8_t alen;
|
||||
uint8_t nlen;
|
||||
lfs1_block_t root[2];
|
||||
uint32_t block_size;
|
||||
uint32_t block_count;
|
||||
uint32_t version;
|
||||
char magic[8];
|
||||
} d;
|
||||
} lfs1_superblock_t;
|
||||
|
||||
typedef struct lfs1_free {
|
||||
lfs1_block_t off;
|
||||
lfs1_block_t size;
|
||||
lfs1_block_t i;
|
||||
lfs1_block_t ack;
|
||||
uint32_t *buffer;
|
||||
} lfs1_free_t;
|
||||
|
||||
// The littlefs type
|
||||
typedef struct lfs1 {
|
||||
const struct lfs1_config *cfg;
|
||||
|
||||
lfs1_block_t root[2];
|
||||
lfs1_file_t *files;
|
||||
lfs1_dir_t *dirs;
|
||||
|
||||
lfs1_cache_t rcache;
|
||||
lfs1_cache_t pcache;
|
||||
|
||||
lfs1_free_t free;
|
||||
bool deorphaned;
|
||||
bool moving;
|
||||
} lfs1_t;
|
||||
|
||||
|
||||
/// Filesystem functions ///
|
||||
|
||||
// Format a block device with the littlefs
|
||||
//
|
||||
// Requires a littlefs object and config struct. This clobbers the littlefs
|
||||
// object, and does not leave the filesystem mounted. The config struct must
|
||||
// be zeroed for defaults and backwards compatibility.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_format(lfs1_t *lfs1, const struct lfs1_config *config);
|
||||
|
||||
// Mounts a littlefs
|
||||
//
|
||||
// Requires a littlefs object and config struct. Multiple filesystems
|
||||
// may be mounted simultaneously with multiple littlefs objects. Both
|
||||
// lfs1 and config must be allocated while mounted. The config struct must
|
||||
// be zeroed for defaults and backwards compatibility.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_mount(lfs1_t *lfs1, const struct lfs1_config *config);
|
||||
|
||||
// Unmounts a littlefs
|
||||
//
|
||||
// Does nothing besides releasing any allocated resources.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_unmount(lfs1_t *lfs1);
|
||||
|
||||
/// General operations ///
|
||||
|
||||
// Removes a file or directory
|
||||
//
|
||||
// If removing a directory, the directory must be empty.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_remove(lfs1_t *lfs1, const char *path);
|
||||
|
||||
// Rename or move a file or directory
|
||||
//
|
||||
// If the destination exists, it must match the source in type.
|
||||
// If the destination is a directory, the directory must be empty.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_rename(lfs1_t *lfs1, const char *oldpath, const char *newpath);
|
||||
|
||||
// Find info about a file or directory
|
||||
//
|
||||
// Fills out the info structure, based on the specified file or directory.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_stat(lfs1_t *lfs1, const char *path, struct lfs1_info *info);
|
||||
|
||||
|
||||
/// File operations ///
|
||||
|
||||
// Open a file
|
||||
//
|
||||
// The mode that the file is opened in is determined by the flags, which
|
||||
// are values from the enum lfs1_open_flags that are bitwise-ored together.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_file_open(lfs1_t *lfs1, lfs1_file_t *file,
|
||||
const char *path, int flags);
|
||||
|
||||
// Open a file with extra configuration
|
||||
//
|
||||
// The mode that the file is opened in is determined by the flags, which
|
||||
// are values from the enum lfs1_open_flags that are bitwise-ored together.
|
||||
//
|
||||
// The config struct provides additional config options per file as described
|
||||
// above. The config struct must be allocated while the file is open, and the
|
||||
// config struct must be zeroed for defaults and backwards compatibility.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_file_opencfg(lfs1_t *lfs1, lfs1_file_t *file,
|
||||
const char *path, int flags,
|
||||
const struct lfs1_file_config *config);
|
||||
|
||||
// Close a file
|
||||
//
|
||||
// Any pending writes are written out to storage as though
|
||||
// sync had been called and releases any allocated resources.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_file_close(lfs1_t *lfs1, lfs1_file_t *file);
|
||||
|
||||
// Synchronize a file on storage
|
||||
//
|
||||
// Any pending writes are written out to storage.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_file_sync(lfs1_t *lfs1, lfs1_file_t *file);
|
||||
|
||||
// Read data from file
|
||||
//
|
||||
// Takes a buffer and size indicating where to store the read data.
|
||||
// Returns the number of bytes read, or a negative error code on failure.
|
||||
lfs1_ssize_t lfs1_file_read(lfs1_t *lfs1, lfs1_file_t *file,
|
||||
void *buffer, lfs1_size_t size);
|
||||
|
||||
// Write data to file
|
||||
//
|
||||
// Takes a buffer and size indicating the data to write. The file will not
|
||||
// actually be updated on the storage until either sync or close is called.
|
||||
//
|
||||
// Returns the number of bytes written, or a negative error code on failure.
|
||||
lfs1_ssize_t lfs1_file_write(lfs1_t *lfs1, lfs1_file_t *file,
|
||||
const void *buffer, lfs1_size_t size);
|
||||
|
||||
// Change the position of the file
|
||||
//
|
||||
// The change in position is determined by the offset and whence flag.
|
||||
// Returns the old position of the file, or a negative error code on failure.
|
||||
lfs1_soff_t lfs1_file_seek(lfs1_t *lfs1, lfs1_file_t *file,
|
||||
lfs1_soff_t off, int whence);
|
||||
|
||||
// Truncates the size of the file to the specified size
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_file_truncate(lfs1_t *lfs1, lfs1_file_t *file, lfs1_off_t size);
|
||||
|
||||
// Return the position of the file
|
||||
//
|
||||
// Equivalent to lfs1_file_seek(lfs1, file, 0, LFS1_SEEK_CUR)
|
||||
// Returns the position of the file, or a negative error code on failure.
|
||||
lfs1_soff_t lfs1_file_tell(lfs1_t *lfs1, lfs1_file_t *file);
|
||||
|
||||
// Change the position of the file to the beginning of the file
|
||||
//
|
||||
// Equivalent to lfs1_file_seek(lfs1, file, 0, LFS1_SEEK_CUR)
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_file_rewind(lfs1_t *lfs1, lfs1_file_t *file);
|
||||
|
||||
// Return the size of the file
|
||||
//
|
||||
// Similar to lfs1_file_seek(lfs1, file, 0, LFS1_SEEK_END)
|
||||
// Returns the size of the file, or a negative error code on failure.
|
||||
lfs1_soff_t lfs1_file_size(lfs1_t *lfs1, lfs1_file_t *file);
|
||||
|
||||
|
||||
/// Directory operations ///
|
||||
|
||||
// Create a directory
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_mkdir(lfs1_t *lfs1, const char *path);
|
||||
|
||||
// Open a directory
|
||||
//
|
||||
// Once open a directory can be used with read to iterate over files.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_dir_open(lfs1_t *lfs1, lfs1_dir_t *dir, const char *path);
|
||||
|
||||
// Close a directory
|
||||
//
|
||||
// Releases any allocated resources.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_dir_close(lfs1_t *lfs1, lfs1_dir_t *dir);
|
||||
|
||||
// Read an entry in the directory
|
||||
//
|
||||
// Fills out the info structure, based on the specified file or directory.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_dir_read(lfs1_t *lfs1, lfs1_dir_t *dir, struct lfs1_info *info);
|
||||
|
||||
// Change the position of the directory
|
||||
//
|
||||
// The new off must be a value previous returned from tell and specifies
|
||||
// an absolute offset in the directory seek.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_dir_seek(lfs1_t *lfs1, lfs1_dir_t *dir, lfs1_off_t off);
|
||||
|
||||
// Return the position of the directory
|
||||
//
|
||||
// The returned offset is only meant to be consumed by seek and may not make
|
||||
// sense, but does indicate the current position in the directory iteration.
|
||||
//
|
||||
// Returns the position of the directory, or a negative error code on failure.
|
||||
lfs1_soff_t lfs1_dir_tell(lfs1_t *lfs1, lfs1_dir_t *dir);
|
||||
|
||||
// Change the position of the directory to the beginning of the directory
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_dir_rewind(lfs1_t *lfs1, lfs1_dir_t *dir);
|
||||
|
||||
|
||||
/// Miscellaneous littlefs specific operations ///
|
||||
|
||||
// Traverse through all blocks in use by the filesystem
|
||||
//
|
||||
// The provided callback will be called with each block address that is
|
||||
// currently in use by the filesystem. This can be used to determine which
|
||||
// blocks are in use or how much of the storage is available.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_traverse(lfs1_t *lfs1, int (*cb)(void*, lfs1_block_t), void *data);
|
||||
|
||||
// Prunes any recoverable errors that may have occured in the filesystem
|
||||
//
|
||||
// Not needed to be called by user unless an operation is interrupted
|
||||
// but the filesystem is still mounted. This is already called on first
|
||||
// allocation.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs1_deorphan(lfs1_t *lfs1);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* lfs1 util functions
|
||||
*
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#include "lfs1_util.h"
|
||||
|
||||
// Only compile if user does not provide custom config
|
||||
#ifndef LFS1_CONFIG
|
||||
|
||||
|
||||
// Software CRC implementation with small lookup table
|
||||
void lfs1_crc(uint32_t *restrict crc, const void *buffer, size_t size) {
|
||||
static const uint32_t rtable[16] = {
|
||||
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
|
||||
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
|
||||
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
|
||||
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
|
||||
};
|
||||
|
||||
const uint8_t *data = buffer;
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
*crc = (*crc >> 4) ^ rtable[(*crc ^ (data[i] >> 0)) & 0xf];
|
||||
*crc = (*crc >> 4) ^ rtable[(*crc ^ (data[i] >> 4)) & 0xf];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* lfs1 utility functions
|
||||
*
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#ifndef LFS1_UTIL_H
|
||||
#define LFS1_UTIL_H
|
||||
|
||||
// Users can override lfs1_util.h with their own configuration by defining
|
||||
// LFS1_CONFIG as a header file to include (-DLFS1_CONFIG=lfs1_config.h).
|
||||
//
|
||||
// If LFS1_CONFIG is used, none of the default utils will be emitted and must be
|
||||
// provided by the config file. To start I would suggest copying lfs1_util.h and
|
||||
// modifying as needed.
|
||||
#ifdef LFS1_CONFIG
|
||||
#define LFS1_STRINGIZE(x) LFS1_STRINGIZE2(x)
|
||||
#define LFS1_STRINGIZE2(x) #x
|
||||
#include LFS1_STRINGIZE(LFS1_CONFIG)
|
||||
#else
|
||||
|
||||
// System includes
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef LFS1_NO_MALLOC
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifndef LFS1_NO_ASSERT
|
||||
#include <assert.h>
|
||||
#endif
|
||||
#if !defined(LFS1_NO_DEBUG) || !defined(LFS1_NO_WARN) || !defined(LFS1_NO_ERROR)
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
// Macros, may be replaced by system specific wrappers. Arguments to these
|
||||
// macros must not have side-effects as the macros can be removed for a smaller
|
||||
// code footprint
|
||||
|
||||
// Logging functions
|
||||
#ifndef LFS1_NO_DEBUG
|
||||
#define LFS1_DEBUG(fmt, ...) \
|
||||
printf("lfs1 debug:%d: " fmt "\n", __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LFS1_DEBUG(fmt, ...)
|
||||
#endif
|
||||
|
||||
#ifndef LFS1_NO_WARN
|
||||
#define LFS1_WARN(fmt, ...) \
|
||||
printf("lfs1 warn:%d: " fmt "\n", __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LFS1_WARN(fmt, ...)
|
||||
#endif
|
||||
|
||||
#ifndef LFS1_NO_ERROR
|
||||
#define LFS1_ERROR(fmt, ...) \
|
||||
printf("lfs1 error:%d: " fmt "\n", __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LFS1_ERROR(fmt, ...)
|
||||
#endif
|
||||
|
||||
// Runtime assertions
|
||||
#ifndef LFS1_NO_ASSERT
|
||||
#define LFS1_ASSERT(test) assert(test)
|
||||
#else
|
||||
#define LFS1_ASSERT(test)
|
||||
#endif
|
||||
|
||||
|
||||
// Builtin functions, these may be replaced by more efficient
|
||||
// toolchain-specific implementations. LFS1_NO_INTRINSICS falls back to a more
|
||||
// expensive basic C implementation for debugging purposes
|
||||
|
||||
// Min/max functions for unsigned 32-bit numbers
|
||||
static inline uint32_t lfs1_max(uint32_t a, uint32_t b) {
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
static inline uint32_t lfs1_min(uint32_t a, uint32_t b) {
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
// Find the next smallest power of 2 less than or equal to a
|
||||
static inline uint32_t lfs1_npw2(uint32_t a) {
|
||||
#if !defined(LFS1_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
|
||||
return 32 - __builtin_clz(a-1);
|
||||
#else
|
||||
uint32_t r = 0;
|
||||
uint32_t s;
|
||||
a -= 1;
|
||||
s = (a > 0xffff) << 4; a >>= s; r |= s;
|
||||
s = (a > 0xff ) << 3; a >>= s; r |= s;
|
||||
s = (a > 0xf ) << 2; a >>= s; r |= s;
|
||||
s = (a > 0x3 ) << 1; a >>= s; r |= s;
|
||||
return (r | (a >> 1)) + 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Count the number of trailing binary zeros in a
|
||||
// lfs1_ctz(0) may be undefined
|
||||
static inline uint32_t lfs1_ctz(uint32_t a) {
|
||||
#if !defined(LFS1_NO_INTRINSICS) && defined(__GNUC__)
|
||||
return __builtin_ctz(a);
|
||||
#else
|
||||
return lfs1_npw2((a & -a) + 1) - 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Count the number of binary ones in a
|
||||
static inline uint32_t lfs1_popc(uint32_t a) {
|
||||
#if !defined(LFS1_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
|
||||
return __builtin_popcount(a);
|
||||
#else
|
||||
a = a - ((a >> 1) & 0x55555555);
|
||||
a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
|
||||
return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Find the sequence comparison of a and b, this is the distance
|
||||
// between a and b ignoring overflow
|
||||
static inline int lfs1_scmp(uint32_t a, uint32_t b) {
|
||||
return (int)(unsigned)(a - b);
|
||||
}
|
||||
|
||||
// Convert from 32-bit little-endian to native order
|
||||
static inline uint32_t lfs1_fromle32(uint32_t a) {
|
||||
#if !defined(LFS1_NO_INTRINSICS) && ( \
|
||||
(defined( BYTE_ORDER ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
|
||||
(defined(__BYTE_ORDER ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
|
||||
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
|
||||
return a;
|
||||
#elif !defined(LFS1_NO_INTRINSICS) && ( \
|
||||
(defined( BYTE_ORDER ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \
|
||||
(defined(__BYTE_ORDER ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \
|
||||
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
||||
return __builtin_bswap32(a);
|
||||
#else
|
||||
return (((uint8_t*)&a)[0] << 0) |
|
||||
(((uint8_t*)&a)[1] << 8) |
|
||||
(((uint8_t*)&a)[2] << 16) |
|
||||
(((uint8_t*)&a)[3] << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Convert to 32-bit little-endian from native order
|
||||
static inline uint32_t lfs1_tole32(uint32_t a) {
|
||||
return lfs1_fromle32(a);
|
||||
}
|
||||
|
||||
// Calculate CRC-32 with polynomial = 0x04c11db7
|
||||
void lfs1_crc(uint32_t *crc, const void *buffer, size_t size);
|
||||
|
||||
// Allocate memory, only used if buffers are not provided to littlefs
|
||||
static inline void *lfs1_malloc(size_t size) {
|
||||
#ifndef LFS1_NO_MALLOC
|
||||
return malloc(size);
|
||||
#else
|
||||
(void)size;
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Deallocate memory, only used if buffers are not provided to littlefs
|
||||
static inline void lfs1_free(void *p) {
|
||||
#ifndef LFS1_NO_MALLOC
|
||||
free(p);
|
||||
#else
|
||||
(void)p;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
Loading…
Reference in New Issue