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
This commit is contained in:
@@ -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)];
|
||||
void Settings::LoadSettingsFromFile() {
|
||||
SettingsData bufferSettings;
|
||||
lfs_file_t settingsFile;
|
||||
|
||||
for (uint8_t block = 0; block < 10; block++) {
|
||||
|
||||
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() {
|
||||
void Settings::SaveSettingsToFile() {
|
||||
lfs_file_t settingsFile;
|
||||
|
||||
// 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
|
||||
|
||||
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);
|
||||
}
|
||||
|
@@ -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();
|
||||
};
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user