From 084123b752c74f7b8a6da23cb9bce0ac4efa3715 Mon Sep 17 00:00:00 2001 From: "joaquim.org" Date: Sun, 11 Jul 2021 14:06:06 +0100 Subject: Using littlefs (#438) * add submodule littlefs * base fs * Save settings using littlefs * Small fixes and suggestions from PR * More small fixes from PR suggestions * Code clean up * Change SpiNorFlash functions to be private in FS --- src/components/fs/FS.cpp | 197 +++++++++++++++++++++++++++++++++++++++++++++++ src/components/fs/FS.h | 71 +++++++++++++++++ 2 files changed, 268 insertions(+) create mode 100644 src/components/fs/FS.cpp create mode 100644 src/components/fs/FS.h (limited to 'src/components/fs') diff --git a/src/components/fs/FS.cpp b/src/components/fs/FS.cpp new file mode 100644 index 00000000..857e6bf9 --- /dev/null +++ b/src/components/fs/FS.cpp @@ -0,0 +1,197 @@ +#include "FS.h" +#include +#include +#include + +using namespace Pinetime::Controllers; + +FS::FS(Pinetime::Drivers::SpiNorFlash& driver) : + flashDriver{ driver }, + lfsConfig{ + .context = this, + .read = SectorRead, + .prog = SectorProg, + .erase = SectorErase, + .sync = SectorSync, + + .read_size = 16, + .prog_size = 8, + .block_size = blockSize, + .block_count = size / blockSize, + .block_cycles = 1000u, + + .cache_size = 16, + .lookahead_size = 16, + + .name_max = 50, + .attr_max = 50, + } +{ } + + +void FS::Init() { + + // try mount + int err = lfs_mount(&lfs, &lfsConfig); + + // reformat if we can't mount the filesystem + // this should only happen on the first boot + if (err != LFS_ERR_OK) { + lfs_format(&lfs, &lfsConfig); + err = lfs_mount(&lfs, &lfsConfig); + if (err != LFS_ERR_OK) { + return; + } + } + +#ifndef PINETIME_IS_RECOVERY + VerifyResource(); + LVGLFileSystemInit(); +#endif + +} + +void FS::VerifyResource() { + // validate the resource metadata + resourcesValid = true; +} + +int FS::FileOpen(lfs_file_t* file_p, const char* fileName, const int flags) { + return lfs_file_open(&lfs, file_p, fileName, flags); +} + +int FS::FileClose(lfs_file_t* file_p) { + return lfs_file_close(&lfs, file_p); +} + +int FS::FileRead(lfs_file_t* file_p, uint8_t* buff, uint32_t size) { + return lfs_file_read(&lfs, file_p, buff, size); +} + +int FS::FileWrite(lfs_file_t* file_p, const uint8_t* buff, uint32_t size) { + return lfs_file_write(&lfs, file_p, buff, size); +} + +int FS::FileSeek(lfs_file_t* file_p, uint32_t pos) { + return lfs_file_seek(&lfs, file_p, pos, LFS_SEEK_SET); +} + +int FS::FileDelete(const char* fileName) { + return lfs_remove(&lfs, fileName); +} + + +int FS::DirCreate(const char* path) { + return lfs_mkdir(&lfs, path); +} + +// Delete directory and all files inside +int FS::DirDelete(const char* path) { + + lfs_dir_t lfs_dir; + lfs_info entryInfo; + + int err; + err = lfs_dir_open(&lfs, &lfs_dir, path); + if (err) { + return err; + } + while (lfs_dir_read(&lfs, &lfs_dir, &entryInfo)) { + lfs_remove(&lfs, entryInfo.name); + } + lfs_dir_close(&lfs, &lfs_dir); + return LFS_ERR_OK; +} + +/* + + ----------- Interface between littlefs and SpiNorFlash ----------- + +*/ +int FS::SectorSync(const struct lfs_config* c) { + return 0; +} + +int FS::SectorErase(const struct lfs_config* c, lfs_block_t block) { + Pinetime::Controllers::FS& lfs = *(static_cast(c->context)); + const size_t address = startAddress + (block * blockSize); + lfs.flashDriver.SectorErase(address); + return lfs.flashDriver.EraseFailed() ? -1 : 0; +} + +int FS::SectorProg(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, const void* buffer, lfs_size_t size) { + Pinetime::Controllers::FS& lfs = *(static_cast(c->context)); + const size_t address = startAddress + (block * blockSize) + off; + lfs.flashDriver.Write(address, (uint8_t*) buffer, size); + return lfs.flashDriver.ProgramFailed() ? -1 : 0; +} + +int FS::SectorRead(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, void* buffer, lfs_size_t size) { + Pinetime::Controllers::FS& lfs = *(static_cast(c->context)); + const size_t address = startAddress + (block * blockSize) + off; + lfs.flashDriver.Read(address, static_cast(buffer), size); + return 0; +} + +/* + + ----------- LVGL filesystem integration ----------- + +*/ + +namespace { + lv_fs_res_t lvglOpen(lv_fs_drv_t* drv, void* file_p, const char* path, lv_fs_mode_t mode) { + + lfs_file_t* file = static_cast(file_p); + FS* filesys = static_cast(drv->user_data); + filesys->FileOpen(file, path, LFS_O_RDONLY); + + if (file->type == 0) { + return LV_FS_RES_FS_ERR; + } + else { + return LV_FS_RES_OK; + } + } + + lv_fs_res_t lvglClose(lv_fs_drv_t* drv, void* file_p) { + FS* filesys = static_cast(drv->user_data); + lfs_file_t* file = static_cast(file_p); + filesys->FileClose(file); + + return LV_FS_RES_OK; + } + + lv_fs_res_t lvglRead(lv_fs_drv_t* drv, void* file_p, void* buf, uint32_t btr, uint32_t* br) { + FS* filesys = static_cast(drv->user_data); + lfs_file_t* file = static_cast(file_p); + filesys->FileRead(file, static_cast(buf), btr); + *br = btr; + return LV_FS_RES_OK; + } + + lv_fs_res_t lvglSeek(lv_fs_drv_t* drv, void* file_p, uint32_t pos) { + FS* filesys = static_cast(drv->user_data); + lfs_file_t* file = static_cast(file_p); + filesys->FileSeek(file, pos); + return LV_FS_RES_OK; + } +} + +void FS::LVGLFileSystemInit() { + + lv_fs_drv_t fs_drv; + lv_fs_drv_init(&fs_drv); + + fs_drv.file_size = sizeof(lfs_file_t); + fs_drv.letter = 'F'; + fs_drv.open_cb = lvglOpen; + fs_drv.close_cb = lvglClose; + fs_drv.read_cb = lvglRead; + fs_drv.seek_cb = lvglSeek; + + fs_drv.user_data = this; + + lv_fs_drv_register(&fs_drv); + +} \ No newline at end of file diff --git a/src/components/fs/FS.h b/src/components/fs/FS.h new file mode 100644 index 00000000..1f2eb7e0 --- /dev/null +++ b/src/components/fs/FS.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include "drivers/SpiNorFlash.h" +#include + +namespace Pinetime { + namespace Controllers { + class FS { + public: + FS(Pinetime::Drivers::SpiNorFlash&); + + void Init(); + void LVGLFileSystemInit(); + + int FileOpen(lfs_file_t* file_p, const char* fileName, const int flags); + int FileClose(lfs_file_t* file_p); + int FileRead(lfs_file_t* file_p, uint8_t* buff, uint32_t size); + int FileWrite(lfs_file_t* file_p, const uint8_t* buff, uint32_t size); + int FileSeek(lfs_file_t* file_p, uint32_t pos); + + int FileDelete(const char* fileName); + + int DirCreate(const char* path); + int DirDelete(const char* path); + + void VerifyResource(); + + private: + + Pinetime::Drivers::SpiNorFlash& flashDriver; + + /* + * External Flash MAP (4 MBytes) + * + * 0x000000 +---------------------------------------+ + * | Bootloader Assets | + * | 256 KBytes | + * | | + * 0x040000 +---------------------------------------+ + * | OTA | + * | 464 KBytes | + * | | + * | | + * | | + * 0x0B4000 +---------------------------------------+ + * | File System | + * | | + * | | + * | | + * | | + * 0x400000 +---------------------------------------+ + * + */ + static constexpr size_t startAddress = 0x0B4000; + static constexpr size_t size = 0x3C0000; + static constexpr size_t blockSize = 4096; + + bool resourcesValid = false; + const struct lfs_config lfsConfig; + + lfs_t lfs; + + static int SectorSync(const struct lfs_config* c); + static int SectorErase(const struct lfs_config* c, lfs_block_t block); + static int SectorProg(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, const void* buffer, lfs_size_t size); + static int SectorRead(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, void* buffer, lfs_size_t size); + + }; + } +} -- cgit v1.2.3