From dd4b6f2b73490dfd85dce8f10ef45ddad1d054d9 Mon Sep 17 00:00:00 2001 From: DevMiner Date: Tue, 26 Mar 2024 17:25:52 +0100 Subject: [PATCH] refactor(configuration): move platform specific code for FS access into an abstraction --- src/FSHelper.cpp | 97 ++++++++++ src/FSHelper.h | 68 +++++++ src/configuration/Configuration.cpp | 278 +++++++--------------------- 3 files changed, 235 insertions(+), 208 deletions(-) create mode 100644 src/FSHelper.cpp create mode 100644 src/FSHelper.h diff --git a/src/FSHelper.cpp b/src/FSHelper.cpp new file mode 100644 index 000000000..3bdf005b0 --- /dev/null +++ b/src/FSHelper.cpp @@ -0,0 +1,97 @@ +/* + SlimeVR Code is placed under the MIT license + Copyright (c) 2024 TheDevMinerTV + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "./FSHelper.h" + +#include + +namespace SlimeVR { +namespace Utils { +SlimeVR::Logging::Logger m_Logger("FSHelper"); + +bool ensureDirectory(const char* directory) { + if (!LittleFS.exists(directory)) { + if (!LittleFS.mkdir(directory)) { + m_Logger.error("Failed to create directory: %s", directory); + return false; + } + } + +#ifdef ESP32 + auto dir = LittleFS.open(directory); + auto isDirectory = dir.isDirectory(); + dir.close(); +#else + auto dir = LittleFS.openDir(directory); + auto isDirectory = dir.isDirectory(); +#endif + + if (!isDirectory) { + if (!LittleFS.remove(directory)) { + m_Logger.error("Failed to remove directory: %s", directory); + return false; + } + + if (!LittleFS.mkdir(directory)) { + m_Logger.error("Failed to create directory: %s", directory); + return false; + } + } + + return true; +} + +File openFile(const char* path, const char* mode) { + return File(LittleFS.open(path, mode)); +} + +void forEachFile(const char* directory, std::function callback) { + if (!ensureDirectory(directory)) { + return; + } + +#ifdef ESP32 + auto dir = LittleFS.open(directory); + while (auto f = dir.openNextFile()) { + if (f.isDirectory()) { + continue; + } + + callback(File(f)); + } + + dir.close(); +#else + auto dir = LittleFS.openDir(directory); + while (dir.next()) { + auto fd = dir.openFile("r"); + if (!fd.isFile()) { + continue; + } + + callback(File(fd)); + } +#endif +} +} // namespace Utils +} // namespace SlimeVR diff --git a/src/FSHelper.h b/src/FSHelper.h new file mode 100644 index 000000000..e99dd0617 --- /dev/null +++ b/src/FSHelper.h @@ -0,0 +1,68 @@ +/* + SlimeVR Code is placed under the MIT license + Copyright (c) 2024 TheDevMinerTV + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef UTILS_FSHELPER_H +#define UTILS_FSHELPER_H + +#include +#include + +#include + +namespace SlimeVR { +namespace Utils { + +class File { +public: + File(fs::File file) + : m_File(file) {} + + ~File() { + if (m_File) { + m_File.close(); + } + } + + const char* name() const { return m_File.name(); } + size_t size() const { return m_File.size(); } + bool isDirectory() { return m_File.isDirectory(); } + bool seek(size_t pos) { return m_File.seek(pos); } + bool read(uint8_t* buffer, size_t size) { return m_File.read(buffer, size); } + bool write(const uint8_t* buffer, size_t size) { + return m_File.write(buffer, size); + } + void close() { return m_File.close(); } + +private: + fs::File m_File; +}; + +bool ensureDirectory(const char* directory); + +File openFile(const char* path, const char* mode); + +void forEachFile(const char* directory, std::function callback); +} // namespace Utils +} // namespace SlimeVR + +#endif diff --git a/src/configuration/Configuration.cpp b/src/configuration/Configuration.cpp index 773d2e637..03e2190d4 100644 --- a/src/configuration/Configuration.cpp +++ b/src/configuration/Configuration.cpp @@ -26,6 +26,7 @@ #include "Configuration.h" #include "consts.h" #include "utils.h" +#include "../FSHelper.h" #define DIR_CALIBRATIONS "/calibrations" #define DIR_TEMPERATURE_CALIBRATIONS "/tempcalibrations" @@ -57,7 +58,7 @@ namespace SlimeVR { if (LittleFS.exists("/config.bin")) { m_Logger.trace("Found configuration file"); - File file = LittleFS.open("/config.bin", "r"); + auto file = LittleFS.open("/config.bin", "r"); file.read((uint8_t*)&m_Config.version, sizeof(int32_t)); @@ -154,213 +155,74 @@ namespace SlimeVR { m_Calibrations[sensorID] = config; } - void Configuration::loadCalibrations() { -#ifdef ESP32 - { - File calibrations = LittleFS.open(DIR_CALIBRATIONS); - if (!calibrations) { - m_Logger.warn("No calibration data found, creating new directory..."); - - if (!LittleFS.mkdir(DIR_CALIBRATIONS)) { - m_Logger.error("Failed to create directory: " DIR_CALIBRATIONS); - return; - } - - calibrations = LittleFS.open(DIR_CALIBRATIONS); - } - - if (!calibrations.isDirectory()) { - calibrations.close(); - - m_Logger.warn("Found file instead of directory: " DIR_CALIBRATIONS); - - if (!LittleFS.remove(DIR_CALIBRATIONS)) { - m_Logger.error("Failed to remove directory: " DIR_CALIBRATIONS); - return; - } - - if (!LittleFS.mkdir(DIR_CALIBRATIONS)) { - m_Logger.error("Failed to create directory: " DIR_CALIBRATIONS); - return; - } - - calibrations = LittleFS.open(DIR_CALIBRATIONS); - } - - m_Logger.debug("Found calibration data directory"); - - while (File f = calibrations.openNextFile()) { - if (f.isDirectory()) { - continue; - } - - m_Logger.trace("Found calibration data file: %s", f.name()); - - uint8_t sensorId = strtoul(f.name(), nullptr, 10); - CalibrationConfig calibrationConfig; - f.read((uint8_t*)&calibrationConfig, sizeof(CalibrationConfig)); - f.close(); - - m_Logger.debug("Found sensor calibration for %s at index %d", calibrationConfigTypeToString(calibrationConfig.type), sensorId); - - setCalibration(sensorId, calibrationConfig); - } - - calibrations.close(); - } -#else - { - if (!LittleFS.exists(DIR_CALIBRATIONS)) { - m_Logger.warn("No calibration data found, creating new directory..."); - - if (!LittleFS.mkdir(DIR_CALIBRATIONS)) { - m_Logger.error("Failed to create directory: " DIR_CALIBRATIONS); - return; - } - - // There's no calibrations here, so we're done - return; - } - - Dir calibrations = LittleFS.openDir(DIR_CALIBRATIONS); - while (calibrations.next()) { - File f = calibrations.openFile("r"); - if (!f.isFile()) { - continue; - } - - CalibrationConfig calibrationConfig; - f.read((uint8_t*)&calibrationConfig, sizeof(CalibrationConfig)); - - uint8_t sensorId = strtoul(calibrations.fileName().c_str(), nullptr, 10); - m_Logger.debug("Found sensor calibration for %s at index %d", calibrationConfigTypeToString(calibrationConfig.type), sensorId); - - setCalibration(sensorId, calibrationConfig); - } - } -#endif - } - - bool Configuration::loadTemperatureCalibration(uint8_t sensorId, GyroTemperatureCalibrationConfig& config) { -#ifdef ESP32 - { - File calibrations = LittleFS.open(DIR_TEMPERATURE_CALIBRATIONS); - if (!calibrations) { - m_Logger.warn("No temperature calibration data found, creating new directory..."); - - if (!LittleFS.mkdir(DIR_TEMPERATURE_CALIBRATIONS)) { - m_Logger.error("Failed to create directory: " DIR_TEMPERATURE_CALIBRATIONS); - return false; - } - - calibrations = LittleFS.open(DIR_TEMPERATURE_CALIBRATIONS); - } - - if (!calibrations.isDirectory()) { - calibrations.close(); - - m_Logger.warn("Found file instead of directory: " DIR_TEMPERATURE_CALIBRATIONS); - - if (!LittleFS.remove(DIR_TEMPERATURE_CALIBRATIONS)) { - m_Logger.error("Failed to remove directory: " DIR_TEMPERATURE_CALIBRATIONS); - return false; - } - - if (!LittleFS.mkdir(DIR_TEMPERATURE_CALIBRATIONS)) { - m_Logger.error("Failed to create directory: " DIR_TEMPERATURE_CALIBRATIONS); - return false; - } - - return false; - } - - calibrations.close(); - - m_Logger.debug("Found temperature calibration data directory"); - - char path[32]; - sprintf(path, DIR_TEMPERATURE_CALIBRATIONS"/%d", sensorId); - if (LittleFS.exists(path)) { - File f = LittleFS.open(path, "r"); - if (f.isDirectory()) { - return false; - } - - if (f.size() == sizeof(GyroTemperatureCalibrationConfig)) { - CalibrationConfigType storedConfigType; - f.read((uint8_t*)&storedConfigType, sizeof(CalibrationConfigType)); - if (storedConfigType != config.type) { - f.close(); - m_Logger.debug( - "Found incompatible sensor temperature calibration (expected %s, found %s) sensorId:%d, skipping", - calibrationConfigTypeToString(config.type), - calibrationConfigTypeToString(storedConfigType), - sensorId - ); - return false; - } - - f.seek(0); - f.read((uint8_t*)&config, sizeof(GyroTemperatureCalibrationConfig)); - f.close(); - m_Logger.debug("Found sensor temperature calibration for %s sensorId:%d", calibrationConfigTypeToString(config.type), sensorId); - return true; - } else { - m_Logger.debug("Found incompatible sensor temperature calibration (size mismatch) sensorId:%d, skipping", sensorId); - } - } - return false; - } -#else - { - if (!LittleFS.exists(DIR_TEMPERATURE_CALIBRATIONS)) { - m_Logger.warn("No temperature calibration data found, creating new directory..."); - - if (!LittleFS.mkdir(DIR_TEMPERATURE_CALIBRATIONS)) { - m_Logger.error("Failed to create directory: " DIR_TEMPERATURE_CALIBRATIONS); - return false; - } - - // There's no calibrations here, so we're done - return false; - } - - char path[32]; - sprintf(path, DIR_TEMPERATURE_CALIBRATIONS"/%d", sensorId); - if (LittleFS.exists(path)) { - File f = LittleFS.open(path, "r"); - if (!f.isFile()) { - return false; - } - - if (f.size() == sizeof(GyroTemperatureCalibrationConfig)) { - CalibrationConfigType storedConfigType; - f.read((uint8_t*)&storedConfigType, sizeof(CalibrationConfigType)); - if (storedConfigType != config.type) { - f.close(); - m_Logger.debug( - "Found incompatible sensor temperature calibration (expected %s, found %s) sensorId:%d, skipping", - calibrationConfigTypeToString(config.type), - calibrationConfigTypeToString(storedConfigType), - sensorId - ); - return false; - } - - f.seek(0); - f.read((uint8_t*)&config, sizeof(GyroTemperatureCalibrationConfig)); - f.close(); - m_Logger.debug("Found sensor temperature calibration for %s sensorId:%d", calibrationConfigTypeToString(config.type), sensorId); - return true; - } else { - m_Logger.debug("Found incompatible sensor temperature calibration (size mismatch) sensorId:%d, skipping", sensorId); - } - } - - return false; - } -#endif - } + void Configuration::loadCalibrations() { + SlimeVR::Utils::forEachFile(DIR_CALIBRATIONS, [&](SlimeVR::Utils::File f) { + CalibrationConfig calibrationConfig; + f.read((uint8_t*)&calibrationConfig, sizeof(CalibrationConfig)); + + uint8_t sensorId = strtoul(f.name(), nullptr, 10); + m_Logger.debug( + "Found sensor calibration for %s at index %d", + calibrationConfigTypeToString(calibrationConfig.type), + sensorId + ); + + setCalibration(sensorId, calibrationConfig); + }); + } + + bool Configuration::loadTemperatureCalibration( + uint8_t sensorId, + GyroTemperatureCalibrationConfig& config + ) { + if (!SlimeVR::Utils::ensureDirectory(DIR_TEMPERATURE_CALIBRATIONS)) { + return false; + } + + char path[32]; + sprintf(path, DIR_TEMPERATURE_CALIBRATIONS "/%d", sensorId); + + if (!LittleFS.exists(path)) { + return false; + } + + auto f = SlimeVR::Utils::openFile(path, "r"); + if (f.isDirectory()) { + return false; + } + + if (f.size() != sizeof(GyroTemperatureCalibrationConfig)) { + m_Logger.debug( + "Found incompatible sensor temperature calibration (size mismatch) " + "sensorId:%d, skipping", + sensorId + ); + return false; + } + + CalibrationConfigType storedConfigType; + f.read((uint8_t*)&storedConfigType, sizeof(CalibrationConfigType)); + + if (storedConfigType != config.type) { + m_Logger.debug( + "Found incompatible sensor temperature calibration (expected %s, " + "found %s) sensorId:%d, skipping", + calibrationConfigTypeToString(config.type), + calibrationConfigTypeToString(storedConfigType), + sensorId + ); + return false; + } + + f.seek(0); + f.read((uint8_t*)&config, sizeof(GyroTemperatureCalibrationConfig)); + m_Logger.debug( + "Found sensor temperature calibration for %s sensorId:%d", + calibrationConfigTypeToString(config.type), + sensorId + ); + return true; + } bool Configuration::saveTemperatureCalibration(uint8_t sensorId, const GyroTemperatureCalibrationConfig& config) { if (config.type == CalibrationConfigType::NONE) {