diff options
author | joaquim.org <joaquim.org@gmail.com> | 2021-07-11 14:06:06 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-11 15:06:06 +0200 |
commit | 084123b752c74f7b8a6da23cb9bce0ac4efa3715 (patch) | |
tree | aaef45602ba4b4168341053c16685dec9e4a9c71 /src/components | |
parent | 61a4642221fc9fcab6889221e7bf9c29778589f2 (diff) |
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
Diffstat (limited to 'src/components')
-rw-r--r-- | src/components/fs/FS.cpp | 197 | ||||
-rw-r--r-- | src/components/fs/FS.h | 71 | ||||
-rw-r--r-- | src/components/settings/Settings.cpp | 100 | ||||
-rw-r--r-- | src/components/settings/Settings.h | 58 |
4 files changed, 314 insertions, 112 deletions
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 <cstring> +#include <littlefs/lfs.h> +#include <lvgl/lvgl.h> + +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<Pinetime::Controllers::FS*>(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<Pinetime::Controllers::FS*>(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<Pinetime::Controllers::FS*>(c->context)); + const size_t address = startAddress + (block * blockSize) + off; + lfs.flashDriver.Read(address, static_cast<uint8_t*>(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<lfs_file_t*>(file_p); + FS* filesys = static_cast<FS*>(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<FS*>(drv->user_data); + lfs_file_t* file = static_cast<lfs_file_t*>(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<FS*>(drv->user_data); + lfs_file_t* file = static_cast<lfs_file_t*>(file_p); + filesys->FileRead(file, static_cast<uint8_t*>(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<FS*>(drv->user_data); + lfs_file_t* file = static_cast<lfs_file_t*>(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 <cstdint> +#include "drivers/SpiNorFlash.h" +#include <littlefs/lfs.h> + +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); + + }; + } +} diff --git a/src/components/settings/Settings.cpp b/src/components/settings/Settings.cpp index 071940b8..37c09f91 100644 --- a/src/components/settings/Settings.cpp +++ b/src/components/settings/Settings.cpp @@ -4,108 +4,44 @@ using namespace Pinetime::Controllers; -struct SettingsHeader { - uint8_t isActive; // 0xF1 = Block is active, 0xF0 = Block is inactive - uint16_t version; // Current version, to verify if the saved data is for the current Version -}; - -#define HEADER_SIZE sizeof(SettingsHeader) - -Settings::Settings(Pinetime::Drivers::SpiNorFlash& spiNorFlash) : spiNorFlash {spiNorFlash} { +Settings::Settings(Pinetime::Controllers::FS& fs) : fs {fs} { } void Settings::Init() { // Load default settings from Flash - LoadSettingsFromFlash(); + LoadSettingsFromFile(); } void Settings::SaveSettings() { // verify if is necessary to save if (settingsChanged) { - SaveSettingsToFlash(); + SaveSettingsToFile(); } settingsChanged = false; } -bool Settings::FindHeader() { - SettingsHeader settingsHeader; - uint8_t bufferHead[sizeof(settingsHeader)]; - - for (uint8_t block = 0; block < 10; block++) { +void Settings::LoadSettingsFromFile() { + SettingsData bufferSettings; + lfs_file_t settingsFile; - spiNorFlash.Read(settingsBaseAddr + (block * 0x1000), bufferHead, sizeof(settingsHeader)); - std::memcpy(&settingsHeader, bufferHead, sizeof(settingsHeader)); - if (settingsHeader.isActive == 0xF1 && settingsHeader.version == settingsVersion) { - settingsFlashBlock = block; - return true; - } + if ( fs.FileOpen(&settingsFile, "/settings.dat", LFS_O_RDWR | LFS_O_CREAT) != LFS_ERR_OK) { + return; } - return false; -} - -void Settings::ReadSettingsData() { - uint8_t bufferSettings[sizeof(settings)]; - spiNorFlash.Read(settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings)); - std::memcpy(&settings, bufferSettings, sizeof(settings)); -} - -void Settings::EraseBlock() { - - spiNorFlash.SectorErase(settingsBaseAddr + (settingsFlashBlock * 0x1000)); -} - -void Settings::SetHeader(bool state) { - SettingsHeader settingsHeader; - uint8_t bufferHead[sizeof(settingsHeader)]; - settingsHeader.isActive = state ? 0xF1 : 0xF0; - settingsHeader.version = settingsVersion; - - std::memcpy(bufferHead, &settingsHeader, sizeof(settingsHeader)); - spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000), bufferHead, sizeof(settingsHeader)); -} - -void Settings::SaveSettingsData() { - uint8_t bufferSettings[sizeof(settings)]; - std::memcpy(bufferSettings, &settings, sizeof(settings)); - spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings)); -} - -void Settings::LoadSettingsFromFlash() { - - if (settingsFlashBlock == 99) { - // Find current Block, if can't find use default settings and set block to 0 ans save ! - if (FindHeader()) { - ReadSettingsData(); - } else { - SaveSettingsToFlash(); - } - } else { - // Read Settings from flash... - // never used :) - ReadSettingsData(); + fs.FileRead(&settingsFile, reinterpret_cast<uint8_t*>(&bufferSettings), sizeof(settings)); + fs.FileClose(&settingsFile); + if ( bufferSettings.version == settingsVersion ) { + settings = bufferSettings; } } -void Settings::SaveSettingsToFlash() { - - // calculate where to save... - // mark current to inactive - // erase the new location and save - // set settingsFlashBlock - - // if first time hever, only saves to block 0 and set settingsFlashBlock +void Settings::SaveSettingsToFile() { + lfs_file_t settingsFile; - if (settingsFlashBlock != 99) { - SetHeader(false); + if ( fs.FileOpen(&settingsFile, "/settings.dat", LFS_O_RDWR | LFS_O_CREAT) != LFS_ERR_OK) { + return; } - - settingsFlashBlock++; - if (settingsFlashBlock > 9) - settingsFlashBlock = 0; - - EraseBlock(); - SetHeader(true); - SaveSettingsData(); + fs.FileWrite(&settingsFile, reinterpret_cast<uint8_t*>(&settings), sizeof(settings)); + fs.FileClose(&settingsFile); } diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 4409425b..577455eb 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -2,25 +2,26 @@ #include <cstdint> #include "components/datetime/DateTimeController.h" #include "components/brightness/BrightnessController.h" -#include "drivers/SpiNorFlash.h" +#include "components/fs/FS.h" #include "drivers/Cst816s.h" namespace Pinetime { namespace Controllers { class Settings { public: - enum class ClockType { H24, H12 }; - enum class Vibration { ON, OFF }; - enum class WakeUpMode { None, SingleTap, DoubleTap, RaiseWrist }; + enum class ClockType : uint8_t { H24, H12 }; + enum class Vibration : uint8_t { ON, OFF }; + enum class WakeUpMode : uint8_t { None, SingleTap, DoubleTap, RaiseWrist }; - Settings(Pinetime::Drivers::SpiNorFlash& spiNorFlash); + Settings(Pinetime::Controllers::FS& fs); void Init(); void SaveSettings(); void SetClockFace(uint8_t face) { - if (face != settings.clockFace) + if (face != settings.clockFace) { settingsChanged = true; + } settings.clockFace = face; }; uint8_t GetClockFace() const { @@ -42,8 +43,9 @@ namespace Pinetime { }; void SetClockType(ClockType clocktype) { - if (clocktype != settings.clockType) + if (clocktype != settings.clockType) { settingsChanged = true; + } settings.clockType = clocktype; }; ClockType GetClockType() const { @@ -51,8 +53,9 @@ namespace Pinetime { }; void SetVibrationStatus(Vibration status) { - if (status != settings.vibrationStatus) + if (status != settings.vibrationStatus) { settingsChanged = true; + } settings.vibrationStatus = status; }; Vibration GetVibrationStatus() const { @@ -60,8 +63,9 @@ namespace Pinetime { }; void SetScreenTimeOut(uint32_t timeout) { - if (timeout != settings.screenTimeOut) + if (timeout != settings.screenTimeOut) { settingsChanged = true; + } settings.screenTimeOut = timeout; }; uint32_t GetScreenTimeOut() const { @@ -69,8 +73,9 @@ namespace Pinetime { }; void setWakeUpMode(WakeUpMode wakeUp) { - if (wakeUp != settings.wakeUpMode) + if (wakeUp != settings.wakeUpMode) { settingsChanged = true; + } settings.wakeUpMode = wakeUp; }; WakeUpMode getWakeUpMode() const { @@ -78,8 +83,9 @@ namespace Pinetime { }; void SetBrightness(Controllers::BrightnessController::Levels level) { - if (level != settings.brightLevel) + if (level != settings.brightLevel) { settingsChanged = true; + } settings.brightLevel = level; }; Controllers::BrightnessController::Levels GetBrightness() const { @@ -87,25 +93,29 @@ namespace Pinetime { }; void SetStepsGoal( uint32_t goal ) { - if ( goal != settings.stepsGoal ) + if ( goal != settings.stepsGoal ) { settingsChanged = true; + } settings.stepsGoal = goal; }; uint32_t GetStepsGoal() const { return settings.stepsGoal; }; private: - Pinetime::Drivers::SpiNorFlash& spiNorFlash; + Pinetime::Controllers::FS& fs; + + static constexpr uint32_t settingsVersion = 0x0001; struct SettingsData { + uint32_t version = settingsVersion; + uint32_t stepsGoal = 10000; + uint32_t screenTimeOut = 15000; + ClockType clockType = ClockType::H24; Vibration vibrationStatus = Vibration::ON; uint8_t clockFace = 0; - uint32_t stepsGoal = 10000; - uint32_t screenTimeOut = 15000; - WakeUpMode wakeUpMode = WakeUpMode::None; Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium; @@ -117,20 +127,8 @@ namespace Pinetime { uint8_t appMenu = 0; uint8_t settingsMenu = 0; - // There are 10 blocks of reserved flash to save settings - // to minimize wear, the recording is done in a rotating way by the 10 blocks - uint8_t settingsFlashBlock = 99; // default to indicate it needs to find the active block - - static constexpr uint32_t settingsBaseAddr = 0x3F6000; // Flash Settings Location - static constexpr uint16_t settingsVersion = 0x0100; // Flash Settings Version - - bool FindHeader(); - void ReadSettingsData(); - void EraseBlock(); - void SetHeader(bool state); - void SaveSettingsData(); - void LoadSettingsFromFlash(); - void SaveSettingsToFlash(); + void LoadSettingsFromFile(); + void SaveSettingsToFile(); }; } }
\ No newline at end of file |