aboutsummaryrefslogtreecommitdiffstats
path: root/arduino/libraries/FileSystem/src/InternalFS.cpp
diff options
context:
space:
mode:
authorClyne Sullivan <tullivan99@gmail.com>2019-02-28 17:04:22 -0500
committerClyne Sullivan <tullivan99@gmail.com>2019-02-28 17:04:22 -0500
commitd6869d1ec4bd24cd2c3eafa534f0849b25ec5607 (patch)
tree79e54ed27b39c31864895535d11399708d5a45c0 /arduino/libraries/FileSystem/src/InternalFS.cpp
parent614ee97bf3a2270c413527a7f35c54cbecd9e601 (diff)
added basic code
Diffstat (limited to 'arduino/libraries/FileSystem/src/InternalFS.cpp')
-rwxr-xr-xarduino/libraries/FileSystem/src/InternalFS.cpp460
1 files changed, 460 insertions, 0 deletions
diff --git a/arduino/libraries/FileSystem/src/InternalFS.cpp b/arduino/libraries/FileSystem/src/InternalFS.cpp
new file mode 100755
index 0000000..0bf356c
--- /dev/null
+++ b/arduino/libraries/FileSystem/src/InternalFS.cpp
@@ -0,0 +1,460 @@
+/**************************************************************************/
+/*!
+ @file InternalFS.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, Adafruit Industries (adafruit.com)
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the copyright holders nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/**************************************************************************/
+
+#include <Arduino.h>
+#include <string.h>
+#include "InternalFS.h"
+#include "flash/flash_nrf5x.h"
+
+#ifdef NRF52840_XXAA
+#define LFS_FLASH_ADDR 0xED000
+#else
+#define LFS_FLASH_ADDR 0x6D000
+#endif
+
+#define LFS_FLASH_TOTAL_SIZE (7*FLASH_NRF52_PAGE_SIZE)
+#define LFS_BLOCK_SIZE 128
+
+//--------------------------------------------------------------------+
+// LFS Disk IO
+//--------------------------------------------------------------------+
+
+#if !CFG_DEBUG
+
+#define VERIFY_LFS(...) _GET_3RD_ARG(__VA_ARGS__, VERIFY_ERR_2ARGS, VERIFY_ERR_1ARGS)(__VA_ARGS__, NULL)
+#define PRINT_LFS_ERR(_err)
+
+#else
+
+#define VERIFY_LFS(...) _GET_3RD_ARG(__VA_ARGS__, VERIFY_ERR_2ARGS, VERIFY_ERR_1ARGS)(__VA_ARGS__, dbg_strerr_lfs)
+#define PRINT_LFS_ERR(_err) VERIFY_MESS(_err, dbg_strerr_lfs)
+
+static const char* dbg_strerr_lfs (int32_t err)
+{
+ switch ( err )
+ {
+ case LFS_ERR_OK:
+ return "LFS_ERR_OK";
+
+ case LFS_ERR_IO:
+ return "LFS_ERR_IO";
+
+ case LFS_ERR_CORRUPT:
+ return "LFS_ERR_CORRUPT";
+
+ case LFS_ERR_NOENT:
+ return "LFS_ERR_NOENT";
+
+ case LFS_ERR_EXIST:
+ return "LFS_ERR_EXIST";
+
+ case LFS_ERR_NOTDIR:
+ return "LFS_ERR_NOTDIR";
+
+ case LFS_ERR_ISDIR:
+ return "LFS_ERR_ISDIR";
+
+ case LFS_ERR_NOTEMPTY:
+ return "LFS_ERR_NOTEMPTY";
+
+ case LFS_ERR_BADF:
+ return "LFS_ERR_BADF";
+
+ case LFS_ERR_INVAL:
+ return "LFS_ERR_INVAL";
+
+ case LFS_ERR_NOSPC:
+ return "LFS_ERR_NOSPC";
+
+ case LFS_ERR_NOMEM:
+ return "LFS_ERR_NOMEM";
+
+ default:
+ {
+ static char errcode[10];
+ sprintf(errcode, "%d", err);
+ return errcode;
+ }
+ }
+}
+
+#endif
+
+static inline uint32_t lba2addr(uint32_t block)
+{
+ return ((uint32_t) LFS_FLASH_ADDR) + block * LFS_BLOCK_SIZE;
+}
+
+static int _iflash_read (const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size)
+{
+ (void) c;
+
+ uint32_t addr = lba2addr(block) + off;
+ flash_nrf5x_read(buffer, addr, size);
+
+ return 0;
+}
+
+// Program a region in a block. The block must have previously
+// been erased. Negative error codes are propogated to the user.
+// May return LFS_ERR_CORRUPT if the block should be considered bad.
+static int _iflash_prog (const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer,
+ lfs_size_t size)
+{
+ (void) c;
+
+ uint32_t addr = lba2addr(block) + off;
+ flash_nrf5x_write(addr, buffer, size);
+
+ return 0;
+}
+
+// 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 LFS_ERR_CORRUPT if the block should be considered bad.
+static int _iflash_erase (const struct lfs_config *c, lfs_block_t block)
+{
+ (void) c;
+
+ uint32_t addr = lba2addr(block);
+
+ // implement as write 0xff to whole block address
+ for(int i=0; i <LFS_BLOCK_SIZE; i++)
+ {
+ flash_nrf5x_write8(addr + i, 0xFF);
+ }
+
+ // flash_nrf5x_flush();
+
+ return 0;
+}
+
+// Sync the state of the underlying block device. Negative error codes
+// are propogated to the user.
+static int _iflash_sync (const struct lfs_config *c)
+{
+ (void) c;
+ flash_nrf5x_flush();
+ return 0;
+}
+
+//--------------------------------------------------------------------+
+// Implementation
+//--------------------------------------------------------------------+
+LittleFS InternalFS;
+
+LittleFS::LittleFS (void)
+{
+ varclr(&_lfs_cfg);
+ _lfs_cfg.context = NULL;
+ _lfs_cfg.read = _iflash_read;
+ _lfs_cfg.prog = _iflash_prog;
+ _lfs_cfg.erase = _iflash_erase;
+ _lfs_cfg.sync = _iflash_sync;
+
+ _lfs_cfg.read_size = LFS_BLOCK_SIZE;
+ _lfs_cfg.prog_size = LFS_BLOCK_SIZE;
+ _lfs_cfg.block_size = LFS_BLOCK_SIZE;
+ _lfs_cfg.block_count = LFS_FLASH_TOTAL_SIZE / LFS_BLOCK_SIZE;
+ _lfs_cfg.lookahead = 128;
+
+ _begun = false;
+}
+
+LittleFS::~LittleFS ()
+{
+
+}
+
+bool LittleFS::begin (void)
+{
+ if ( _begun ) return true;
+ _begun = true;
+
+ int err = lfs_mount(&_lfs, &_lfs_cfg);
+
+ // reformat if we can't mount the filesystem
+ if ( LFS_ERR_CORRUPT == err )
+ {
+ LOG_LV1("IFLASH", "Format internal file system");
+ this->format(false);
+ }
+
+ return true;
+}
+
+bool LittleFS::format (bool eraseall)
+{
+ if ( eraseall )
+ {
+ for ( uint32_t addr = LFS_FLASH_ADDR; addr < LFS_FLASH_ADDR + LFS_FLASH_TOTAL_SIZE; addr += FLASH_NRF52_PAGE_SIZE )
+ {
+ flash_nrf5x_erase(addr);
+ }
+ }
+
+ VERIFY_LFS(lfs_format(&_lfs, &_lfs_cfg), false);
+ VERIFY_LFS(lfs_mount(&_lfs, &_lfs_cfg), false);
+
+ return true;
+}
+
+BluefruitFS::File LittleFS::_open_file (char const *filepath, uint8_t mode)
+{
+ BluefruitFS::File file(*this);
+
+ int flags = (mode == FILE_READ) ? LFS_O_RDONLY :
+ (mode == FILE_WRITE) ? (LFS_O_RDWR | LFS_O_CREAT) : 0;
+
+ if ( flags )
+ {
+ lfs_file_t* fhdl = (lfs_file_t*) rtos_malloc(sizeof(lfs_file_t));
+ VERIFY(fhdl, file);
+
+ int rc = lfs_file_open(&_lfs, fhdl, filepath, flags);
+
+ if ( rc )
+ {
+ rtos_free(fhdl);
+ PRINT_LFS_ERR(rc);
+ }
+ else
+ {
+ // move to end of file
+ if ( mode == FILE_WRITE ) lfs_file_seek(&_lfs, fhdl, 0, LFS_SEEK_END);
+
+ file._hdl = fhdl;
+ file._is_dir = false;
+
+ file._path = (char*) rtos_malloc(strlen(filepath) + 1);
+ strcpy(file._path, filepath);
+ }
+ }
+
+ return file;
+}
+
+BluefruitFS::File LittleFS::_open_dir (char const *filepath)
+{
+ BluefruitFS::File file(*this);
+
+ lfs_dir_t* fhdl = (lfs_dir_t*) rtos_malloc(sizeof(lfs_dir_t));
+ int rc = lfs_dir_open(&_lfs, fhdl, filepath);
+
+ if ( rc )
+ {
+ rtos_free(fhdl);
+ PRINT_LFS_ERR(rc);
+ }
+ else
+ {
+ file._hdl = fhdl;
+ file._is_dir = true;
+
+ file._path = (char*) rtos_malloc(strlen(filepath) + 1);
+ strcpy(file._path, filepath);
+ }
+
+ return file;
+}
+
+BluefruitFS::File LittleFS::open (char const *filepath, uint8_t mode)
+{
+ BluefruitFS::File file(*this);
+ struct lfs_info info;
+
+ int rc = lfs_stat(&_lfs, filepath, &info);
+ if ( LFS_ERR_OK == rc )
+ {
+ // file existed, open file or directory accordingly
+ file = (info.type == LFS_TYPE_REG) ? _open_file(filepath, mode) : _open_dir(filepath);
+ }
+ else if ( LFS_ERR_NOENT == rc )
+ {
+ // file not existed, only proceed with FILE_WRITE mode
+ if ( mode == FILE_WRITE ) file = _open_file(filepath, mode);
+ }
+ else
+ {
+ PRINT_LFS_ERR(rc);
+ }
+
+ return file;
+}
+
+bool LittleFS::exists (char const *filepath)
+{
+ struct lfs_info info;
+ return 0 == lfs_stat(&_lfs, filepath, &info);
+}
+
+bool LittleFS::mkdir (char const *filepath)
+{
+ const char* slash = filepath;
+ if ( slash[0] == '/' ) slash++; // skip root '/'
+
+ while ( NULL != (slash = strchr(slash, '/')) )
+ {
+ char parent[slash - filepath + 1] = { 0 };
+ memcpy(parent, filepath, slash - filepath);
+
+ // make intermediate parent
+ int rc = lfs_mkdir(&_lfs, parent);
+ if ( rc != LFS_ERR_OK && rc != LFS_ERR_EXIST )
+ {
+ PRINT_LFS_ERR(rc);
+ return false;
+ }
+
+ slash++;
+ }
+
+ int rc = lfs_mkdir(&_lfs, filepath);
+ if ( rc != LFS_ERR_OK && rc != LFS_ERR_EXIST )
+ {
+ PRINT_LFS_ERR(rc);
+ return false;
+ }
+
+ return true;
+}
+
+bool LittleFS::remove (char const *filepath)
+{
+ VERIFY_LFS(lfs_remove(&_lfs, filepath), false);
+ return true;
+}
+
+bool LittleFS::rmdir (char const *filepath)
+{
+ VERIFY_LFS(lfs_remove(&_lfs, filepath));
+ return true;
+}
+
+bool LittleFS::rmdir_r (char const *filepath)
+{
+ /* adafruit: lfs is modified to remove non-empty folder,
+ According to below issue, comment these 2 line won't corrupt filesystem
+ https://github.com/ARMmbed/littlefs/issues/43 */
+ VERIFY_LFS(lfs_remove(&_lfs, filepath));
+ return true;
+}
+
+//--------------------------------------------------------------------+
+// FILE API
+//--------------------------------------------------------------------+
+size_t LittleFS::_f_write (void* fhdl, uint8_t const *buf, size_t size)
+{
+ lfs_ssize_t wrcount = lfs_file_write(&_lfs, (lfs_file_t*) fhdl, buf, size);
+ VERIFY(wrcount > 0, 0);
+ return wrcount;
+}
+
+void LittleFS::_f_flush (void* fhdl)
+{
+ VERIFY_LFS(lfs_file_sync(&_lfs, (lfs_file_t* ) fhdl),);
+}
+
+int LittleFS::_f_read (void* fhdl, void *buf, uint16_t nbyte)
+{
+ return lfs_file_read(&_lfs, (lfs_file_t*) fhdl, buf, nbyte);
+}
+
+bool LittleFS::_f_seek (void* fhdl, uint32_t pos)
+{
+ return lfs_file_seek(&_lfs, (lfs_file_t*) fhdl, pos, LFS_SEEK_SET) >= 0;
+}
+
+uint32_t LittleFS::_f_position (void* fhdl)
+{
+ return lfs_file_tell(&_lfs, (lfs_file_t*) fhdl);
+}
+
+uint32_t LittleFS::_f_size (void* fhdl)
+{
+ return lfs_file_size(&_lfs, (lfs_file_t*) fhdl);
+}
+
+void LittleFS::_f_close (void* fhdl, bool is_dir)
+{
+ if ( is_dir )
+ {
+ lfs_dir_close(&_lfs, (lfs_dir_t *) fhdl);
+ }
+ else
+ {
+ lfs_file_close(&_lfs, (lfs_file_t*) fhdl);
+ }
+}
+
+File LittleFS::_f_openNextFile (void* fhdl, char const* cwd, uint8_t mode)
+{
+ BluefruitFS::File file(*this);
+ struct lfs_info info;
+
+ int rc;
+
+ // lfs_dir_read return 0 when reaching end of directory, 1 if found an entry
+ // skip "." and ".." entries
+ do
+ {
+ rc = lfs_dir_read(&_lfs, (lfs_dir_t *) fhdl, &info);
+ } while ( rc == 1 && (!strcmp(".", info.name) || !strcmp("..", info.name)) );
+
+ if ( rc == 1 )
+ {
+ // string cat name with current folder
+ char filepath[strlen(cwd) + 1 + strlen(info.name) + 1];
+
+ strcpy(filepath, cwd);
+ if ( !(cwd[0] == '/' && cwd[1] == 0) ) strcat(filepath, "/"); // only add '/' if cwd is not root
+ strcat(filepath, info.name);
+
+ file = (info.type == LFS_TYPE_REG) ? _open_file(filepath, mode) : _open_dir(filepath);
+ }
+ else if ( rc < 0 )
+ {
+ PRINT_LFS_ERR(rc);
+ }
+
+ return file;
+}
+
+void LittleFS::_f_rewindDirectory (void* fhdl)
+{
+ VERIFY_LFS(lfs_dir_rewind(&_lfs, (lfs_dir_t* ) fhdl),);
+}