This commit is contained in:
Elara 2024-10-04 23:57:58 +01:00 committed by GitHub
commit c2ffdb65fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 267 additions and 10 deletions

View file

@ -1,6 +1,11 @@
#include "components/settings/Settings.h" #include "components/settings/Settings.h"
#include "libs/QCBOR/inc/qcbor/qcbor.h"
#include <qcbor/qcbor_spiffy_decode.h>
#include <qcbor/qcbor_encode.h>
#include <qcbor/UsefulBuf.h>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <vector>
using namespace Pinetime::Controllers; using namespace Pinetime::Controllers;
@ -23,25 +28,273 @@ void Settings::SaveSettings() {
} }
void Settings::LoadSettingsFromFile() { void Settings::LoadSettingsFromFile() {
SettingsData bufferSettings; MigrateToCBOR();
lfs_file_t settingsFile;
if (fs.FileOpen(&settingsFile, "/settings.dat", LFS_O_RDONLY) != LFS_ERR_OK) { lfs_info cborFileInfo;
if (fs.Stat("/settings.cbor", &cborFileInfo) != LFS_ERR_OK) {
return; return;
} }
fs.FileRead(&settingsFile, reinterpret_cast<uint8_t*>(&bufferSettings), sizeof(settings));
fs.FileClose(&settingsFile); std::vector<uint8_t> cborBuf(cborFileInfo.size);
if (bufferSettings.version == settingsVersion) { lfs_file_t settingsFile;
settings = bufferSettings; if (fs.FileOpen(&settingsFile, "/settings.cbor", LFS_O_RDONLY) != LFS_ERR_OK) {
return;
} }
fs.FileRead(&settingsFile, cborBuf.data(), cborFileInfo.size);
fs.FileClose(&settingsFile);
SettingsData bufferSettings;
QCBORDecodeContext decodeCtx;
UsefulBufC encodedCbor = {cborBuf.data(), cborFileInfo.size};
// To avoid creating a uint64_t every time a value needs to be
// decoded, this variable will be reused for all uint64_t decoding.
uint64_t tmpVal = 0;
QCBORDecode_Init(&decodeCtx, encodedCbor, QCBOR_DECODE_MODE_NORMAL);
QCBORDecode_EnterMap(&decodeCtx, nullptr);
QCBORDecode_GetUInt64InMapSZ(&decodeCtx, "StepsGoal", &tmpVal);
if (QCBORDecode_GetError(&decodeCtx) != QCBOR_SUCCESS) {
CleanUpQcbor(&decodeCtx);
return;
}
bufferSettings.stepsGoal = tmpVal;
QCBORDecode_GetUInt64InMapSZ(&decodeCtx, "ScreenTimeout", &tmpVal);
if (QCBORDecode_GetError(&decodeCtx) != QCBOR_SUCCESS) {
CleanUpQcbor(&decodeCtx);
return;
}
bufferSettings.screenTimeOut = tmpVal;
QCBORDecode_GetUInt64InMapSZ(&decodeCtx, "ClockType", &tmpVal);
if (QCBORDecode_GetError(&decodeCtx) != QCBOR_SUCCESS) {
CleanUpQcbor(&decodeCtx);
return;
}
// There are only two possible clock types, ensure the value is within bounds.
if (tmpVal < 2) {
bufferSettings.clockType = static_cast<ClockType>(tmpVal);
}
QCBORDecode_GetUInt64InMapSZ(&decodeCtx, "NotificationStatus", &tmpVal);
if (QCBORDecode_GetError(&decodeCtx) != QCBOR_SUCCESS) {
CleanUpQcbor(&decodeCtx);
return;
}
// There are only three possible notification statuses, ensure the value is within bounds.
if (tmpVal < 3) {
bufferSettings.notificationStatus = static_cast<Notification>(tmpVal);
}
QCBORDecode_GetUInt64InMapSZ(&decodeCtx, "ClockFace", &tmpVal);
if (QCBORDecode_GetError(&decodeCtx) != QCBOR_SUCCESS) {
CleanUpQcbor(&decodeCtx);
return;
}
// There are only four possible clock faces, ensure the value is within bounds.
if (tmpVal < 6) {
bufferSettings.clockFace = tmpVal;
}
QCBORDecode_GetUInt64InMapSZ(&decodeCtx, "ChimesOption", &tmpVal);
if (QCBORDecode_GetError(&decodeCtx) != QCBOR_SUCCESS) {
CleanUpQcbor(&decodeCtx);
return;
}
// There are only three possible chimes options, ensure the value is within bounds.
if (tmpVal < 3) {
bufferSettings.chimesOption = static_cast<ChimesOption>(tmpVal);
}
// Enter PTS colors map
QCBORDecode_EnterMapFromMapSZ(&decodeCtx, "PTS");
if (QCBORDecode_GetError(&decodeCtx) != QCBOR_SUCCESS) {
CleanUpQcbor(&decodeCtx);
return;
}
QCBORDecode_GetUInt64InMapSZ(&decodeCtx, "ColorTime", &tmpVal);
if (QCBORDecode_GetError(&decodeCtx) != QCBOR_SUCCESS) {
CleanUpQcbor(&decodeCtx);
return;
}
// There are eighteen possible colors, ensure the value is within bounds.
if (tmpVal < 18) {
bufferSettings.PTS.ColorTime = static_cast<Colors>(tmpVal);
}
QCBORDecode_GetUInt64InMapSZ(&decodeCtx, "ColorBar", &tmpVal);
if (QCBORDecode_GetError(&decodeCtx) != QCBOR_SUCCESS) {
CleanUpQcbor(&decodeCtx);
return;
}
// There are eighteen possible colors, ensure the value is within bounds.
if (tmpVal < 18) {
bufferSettings.PTS.ColorBar = static_cast<Colors>(tmpVal);
}
QCBORDecode_GetUInt64InMapSZ(&decodeCtx, "ColorBG", &tmpVal);
if (QCBORDecode_GetError(&decodeCtx) != QCBOR_SUCCESS) {
CleanUpQcbor(&decodeCtx);
return;
}
// There are eighteen possible colors, ensure the value is within bounds.
if (tmpVal < 18) {
bufferSettings.PTS.ColorBG = static_cast<Colors>(tmpVal);
}
QCBORDecode_GetUInt64InMapSZ(&decodeCtx, "GaugeStyle", &tmpVal);
if (QCBORDecode_GetError(&decodeCtx) != QCBOR_SUCCESS) {
CleanUpQcbor(&decodeCtx);
return;
}
// There are eighteen possible colors, ensure the value is within bounds.
if (tmpVal < 3) {
bufferSettings.PTS.gaugeStyle = static_cast<PTSGaugeStyle>(tmpVal);
}
// Exit PTS colors map
QCBORDecode_ExitMap(&decodeCtx);
// Enter Infineat settings map
QCBORDecode_EnterMapFromMapSZ(&decodeCtx, "Infineat");
if (QCBORDecode_GetError(&decodeCtx) != QCBOR_SUCCESS) {
CleanUpQcbor(&decodeCtx);
return;
}
bool tmpShowSideCover = true;
QCBORDecode_GetBoolInMapSZ(&decodeCtx, "ShowSideCover", &tmpShowSideCover);
if (QCBORDecode_GetError(&decodeCtx) != QCBOR_SUCCESS) {
CleanUpQcbor(&decodeCtx);
return;
}
bufferSettings.watchFaceInfineat.showSideCover = tmpShowSideCover;
QCBORDecode_GetUInt64InMapSZ(&decodeCtx, "ColorIndex", &tmpVal);
if (QCBORDecode_GetError(&decodeCtx) != QCBOR_SUCCESS) {
CleanUpQcbor(&decodeCtx);
return;
}
bufferSettings.watchFaceInfineat.colorIndex = tmpVal;
// Exit Infineat settings map
QCBORDecode_ExitMap(&decodeCtx);
QCBORDecode_GetUInt64InMapSZ(&decodeCtx, "WakeupMode", &tmpVal);
if (QCBORDecode_GetError(&decodeCtx) != QCBOR_SUCCESS) {
CleanUpQcbor(&decodeCtx);
return;
}
bufferSettings.wakeUpMode = std::bitset<4>(tmpVal);
QCBORDecode_GetUInt64InMapSZ(&decodeCtx, "ShakeWakeThreshold", &tmpVal);
if (QCBORDecode_GetError(&decodeCtx) != QCBOR_SUCCESS) {
CleanUpQcbor(&decodeCtx);
return;
}
bufferSettings.shakeWakeThreshold = tmpVal;
QCBORDecode_GetUInt64InMapSZ(&decodeCtx, "BrightLevel", &tmpVal);
if (QCBORDecode_GetError(&decodeCtx) != QCBOR_SUCCESS) {
CleanUpQcbor(&decodeCtx);
return;
}
// There are three possible brightness levels, ensure the value is within bounds.
if (tmpVal < 3) {
bufferSettings.brightLevel = static_cast<Controllers::BrightnessController::Levels>(tmpVal);
}
settings = bufferSettings;
CleanUpQcbor(&decodeCtx);
} }
void Settings::SaveSettingsToFile() { void Settings::SaveSettingsToFile() {
lfs_file_t settingsFile; lfs_file_t settingsFile;
if (fs.FileOpen(&settingsFile, "/settings.dat", LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) { if (fs.FileOpen(&settingsFile, "/settings.cbor", LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) {
return; return;
} }
fs.FileWrite(&settingsFile, reinterpret_cast<uint8_t*>(&settings), sizeof(settings));
UsefulBufC encodedSize;
encodedSize = Encode({NULL, SIZE_MAX});
std::vector<uint8_t> cborBuf(encodedSize.len);
UsefulBuf encodedCborBuf;
encodedCborBuf.len = encodedSize.len;
encodedCborBuf.ptr = cborBuf.data();
UsefulBufC encodedCbor = Encode(encodedCborBuf);
fs.FileWrite(&settingsFile, cborBuf.data(), encodedSize.len);
fs.FileClose(&settingsFile); fs.FileClose(&settingsFile);
} }
UsefulBufC Settings::Encode(UsefulBuf buffer) {
QCBOREncodeContext encodeCtx;
QCBOREncode_Init(&encodeCtx, buffer);
QCBOREncode_OpenMap(&encodeCtx);
QCBOREncode_AddUInt64ToMap(&encodeCtx, "StepsGoal", settings.stepsGoal);
QCBOREncode_AddUInt64ToMap(&encodeCtx, "ScreenTimeout", settings.screenTimeOut);
QCBOREncode_AddUInt64ToMap(&encodeCtx, "ClockType", static_cast<uint64_t>(settings.clockType));
QCBOREncode_AddUInt64ToMap(&encodeCtx, "NotificationStatus", static_cast<uint64_t>(settings.notificationStatus));
QCBOREncode_AddUInt64ToMap(&encodeCtx, "ClockFace", settings.clockFace);
QCBOREncode_AddUInt64ToMap(&encodeCtx, "ChimesOption", static_cast<uint64_t>(settings.chimesOption));
QCBOREncode_OpenMapInMap(&encodeCtx, "PTS");
QCBOREncode_AddUInt64ToMap(&encodeCtx, "ColorTime", static_cast<uint64_t>(settings.PTS.ColorTime));
QCBOREncode_AddUInt64ToMap(&encodeCtx, "ColorBar", static_cast<uint64_t>(settings.PTS.ColorBar));
QCBOREncode_AddUInt64ToMap(&encodeCtx, "ColorBG", static_cast<uint64_t>(settings.PTS.ColorBG));
QCBOREncode_AddUInt64ToMap(&encodeCtx, "GaugeStyle", static_cast<uint64_t>(settings.PTS.gaugeStyle));
QCBOREncode_CloseMap(&encodeCtx);
QCBOREncode_OpenMapInMap(&encodeCtx, "Infineat");
QCBOREncode_AddBoolToMap(&encodeCtx, "ShowSideCover", settings.watchFaceInfineat.showSideCover);
QCBOREncode_AddUInt64ToMap(&encodeCtx, "ColorIndex", settings.watchFaceInfineat.colorIndex);
QCBOREncode_CloseMap(&encodeCtx);
QCBOREncode_AddUInt64ToMap(&encodeCtx, "WakeupMode", settings.wakeUpMode.to_ulong());
QCBOREncode_AddUInt64ToMap(&encodeCtx, "ShakeWakeThreshold", settings.shakeWakeThreshold);
QCBOREncode_AddUInt64ToMap(&encodeCtx, "BrightLevel", static_cast<uint64_t>(settings.brightLevel));
QCBOREncode_CloseMap(&encodeCtx);
UsefulBufC encodedCbor;
QCBOREncode_Finish(&encodeCtx, &encodedCbor);
return encodedCbor;
}
void Settings::MigrateToCBOR() {
lfs_info oldSettingsInfo;
if (fs.Stat("/settings.dat", &oldSettingsInfo) != LFS_ERR_OK) {
return;
}
SettingsData bufferSettings;
lfs_file_t settingsFile;
if (fs.FileOpen(&settingsFile, "/settings.dat", LFS_O_RDONLY) != LFS_ERR_OK) {
return;
}
fs.FileRead(&settingsFile, reinterpret_cast<uint8_t*>(&bufferSettings), sizeof(bufferSettings));
fs.FileClose(&settingsFile);
if ( bufferSettings.version == settingsVersion ) {
settings = bufferSettings;
}
SaveSettingsToFile();
fs.FileDelete("/settings.dat");
}
void Settings::CleanUpQcbor(QCBORDecodeContext* decodeCtx) {
QCBORDecode_ExitMap(decodeCtx);
QCBORDecode_Finish(decodeCtx);
}

View file

@ -2,6 +2,7 @@
#include <cstdint> #include <cstdint>
#include <bitset> #include <bitset>
#include "components/brightness/BrightnessController.h" #include "components/brightness/BrightnessController.h"
#include "libs/QCBOR/inc/qcbor/qcbor.h"
#include "components/fs/FS.h" #include "components/fs/FS.h"
#include "displayapp/apps/Apps.h" #include "displayapp/apps/Apps.h"
@ -340,6 +341,9 @@ namespace Pinetime {
void LoadSettingsFromFile(); void LoadSettingsFromFile();
void SaveSettingsToFile(); void SaveSettingsToFile();
void MigrateToCBOR();
UsefulBufC Encode(UsefulBuf buffer);
void CleanUpQcbor(QCBORDecodeContext* decodeCtx);
}; };
} }
} }