diff --git a/include/config/extern/configManager.h b/include/config/extern/configManager.h index dea9bb5..162de57 100644 --- a/include/config/extern/configManager.h +++ b/include/config/extern/configManager.h @@ -46,7 +46,6 @@ class configManager void setValuesFromConfig(); bool validateStringNotEmpty(const std::string &value); void parseConfig(); - void parseComplexConfig(std::ifstream &configFile, const std::string §ion); enum class DriveMode { @@ -142,6 +141,12 @@ class configManager void readMaintenanceData(); void writeMaintenanceData(); + + // VEX API helper functions + std::string readFileToString(const std::string &filename); + bool writeStringToFile(const std::string &filename, const std::string &content, bool append = false); + bool fileExists(const std::string &filename); + int getFileSize(const std::string &filename); }; /// @brief Manages configuration settings. diff --git a/include/vex.h b/include/vex.h index 68ae838..7617535 100644 --- a/include/vex.h +++ b/include/vex.h @@ -1,4 +1,3 @@ -#include #include #include "v5_cpp.h" diff --git a/src/config/extern/configManager.cpp b/src/config/extern/configManager.cpp index 907cea9..9b76bcc 100644 --- a/src/config/extern/configManager.cpp +++ b/src/config/extern/configManager.cpp @@ -1,5 +1,5 @@ #include "vex.h" -#include +#include std::array createControllerButtonArray(const vex::controller &controller) { @@ -308,4 +308,100 @@ Log::Level configManager::stringToLogLevel(const std::string &str) logHandler("configManager::stringToLogLevel", "Invalid log level", Log::Level::Error, 5); return Log::Level::Info; // Default return to avoid compilation error } +} + +// VEX API helper functions +std::string configManager::readFileToString(const std::string &filename) +{ + if (!Brain.SDcard.isInserted()) + { + logHandler("readFileToString", "SD card not inserted", Log::Level::Error); + return ""; + } + + if (!Brain.SDcard.exists(filename.c_str())) + { + logHandler("readFileToString", "File does not exist: " + filename, Log::Level::Warn); + return ""; + } + + int size = Brain.SDcard.size(filename.c_str()); + if (size <= 0) + { + logHandler("readFileToString", "File is empty or invalid size: " + filename, Log::Level::Warn); + return ""; + } + + // Allocate buffer for file content + std::unique_ptr buffer(new char[size + 1]); + if (!buffer) + { + logHandler("readFileToString", "Failed to allocate buffer for file: " + filename, Log::Level::Error); + return ""; + } + + // Load file into buffer + int bytesRead = Brain.SDcard.loadfile(filename.c_str(), buffer.get(), size); + if (bytesRead <= 0) + { + logHandler("readFileToString", "Failed to read file: " + filename, Log::Level::Error); + return ""; + } + + // Null terminate the buffer + buffer[bytesRead] = '\0'; + + return std::string(buffer.get()); +} + +bool configManager::writeStringToFile(const std::string &filename, const std::string &content, bool append) +{ + if (!Brain.SDcard.isInserted()) + { + logHandler("writeStringToFile", "SD card not inserted", Log::Level::Error); + return false; + } + + int bytesWritten = 0; + if (append) + { + bytesWritten = Brain.SDcard.appendfile(filename.c_str(), const_cast(content.c_str()), content.length()); + } + else + { + bytesWritten = Brain.SDcard.savefile(filename.c_str(), const_cast(content.c_str()), content.length()); + } + + if (bytesWritten != static_cast(content.length())) + { + logHandler("writeStringToFile", "Failed to write complete content to file: " + filename, Log::Level::Error); + return false; + } + + return true; +} + +bool configManager::fileExists(const std::string &filename) +{ + if (!Brain.SDcard.isInserted()) + { + return false; + } + + return Brain.SDcard.exists(filename.c_str()); +} + +int configManager::getFileSize(const std::string &filename) +{ + if (!Brain.SDcard.isInserted()) + { + return -1; + } + + if (!Brain.SDcard.exists(filename.c_str())) + { + return -1; + } + + return Brain.SDcard.size(filename.c_str()); } \ No newline at end of file diff --git a/src/config/extern/sdcard.cpp b/src/config/extern/sdcard.cpp index 1ea8acd..884fb10 100644 --- a/src/config/extern/sdcard.cpp +++ b/src/config/extern/sdcard.cpp @@ -1,5 +1,5 @@ #include "vex.h" -#include +#include /** * @brief Resets or initializes the configuration file based on user input. @@ -29,14 +29,9 @@ void configManager::resetOrInitializeConfig(std::string_view message) if (resetcfg == "Yes") { primaryController.Screen.print("Resetting config file..."); - std::ofstream configFile(configFileName); - if (!configFile) - { - logHandler("resetOrInitializeConfig", "Could not create config.", Log::Level::Warn, 3); - return; - } - // Write default configuration - configFile << R"( + + // Create default configuration content + std::string configContent = R"( # Config File: MOTOR_CONFIG { FRONT_LEFT_MOTOR { @@ -80,9 +75,13 @@ void configManager::resetOrInitializeConfig(std::string_view message) DRIVEMODE=Split LEFTDEADZONE=10 RIGHTDEADZONE=10 - VERSION=)" << Version - << "\n"; - configFile.close(); + VERSION=)" + Version + "\n"; + + if (!writeStringToFile(configFileName, configContent)) + { + logHandler("resetOrInitializeConfig", "Could not create config.", Log::Level::Warn, 3); + return; + } logHandler("resetConfig", "Successfully reset config file.", Log::Level::Debug); } @@ -101,14 +100,11 @@ void configManager::resetOrInitializeConfig(std::string_view message) */ void configManager::writeMaintenanceData() { - std::ofstream maintenanceFile(maintenanceFileName); - if (maintenanceFile.is_open()) - { - maintenanceFile << "ODOMETER=" << odometer << "\n"; - maintenanceFile << "LAST_SERVICE=" << lastService << "\n"; - maintenanceFile << "SERVICE_INTERVAL=" << serviceInterval << "\n"; - maintenanceFile.close(); - } + std::string content = "ODOMETER=" + std::to_string(odometer) + "\n"; + content += "LAST_SERVICE=" + std::to_string(lastService) + "\n"; + content += "SERVICE_INTERVAL=" + std::to_string(serviceInterval) + "\n"; + + writeStringToFile(maintenanceFileName, content); } /** @@ -129,28 +125,25 @@ void configManager::setDriveMode(const configManager::DriveMode &mode) driveMode = mode; // Update in-memory // Also write to config file - std::ofstream configFile(configFileName, std::ios::app); - if (configFile.is_open()) + std::string content = "DRIVEMODE="; + switch (mode) { - configFile << "DRIVEMODE="; - switch (mode) - { - case DriveMode::LeftArcade: - configFile << "LeftArcade"; - break; - case DriveMode::RightArcade: - configFile << "RightArcade"; - break; - case DriveMode::SplitArcade: - configFile << "SplitArcade"; - break; - case DriveMode::Tank: - configFile << "Tank"; - break; - } - configFile << "\n"; - configFile.close(); + case DriveMode::LeftArcade: + content += "LeftArcade"; + break; + case DriveMode::RightArcade: + content += "RightArcade"; + break; + case DriveMode::SplitArcade: + content += "SplitArcade"; + break; + case DriveMode::Tank: + content += "Tank"; + break; } + content += "\n"; + + writeStringToFile(configFileName, content, true); // append = true } /** @@ -169,31 +162,33 @@ void configManager::setDriveMode(const configManager::DriveMode &mode) */ void configManager::readMaintenanceData() { - std::ifstream maintenanceFile(maintenanceFileName); - if (maintenanceFile.is_open()) + std::string fileContent = readFileToString(maintenanceFileName); + if (fileContent.empty()) + { + return; // File doesn't exist or is empty + } + + std::istringstream stream(fileContent); + std::string line; + while (std::getline(stream, line)) { - std::string line; - while (std::getline(maintenanceFile, line)) + std::istringstream iss(line); + std::string key, value; + if (std::getline(iss, key, '=') && std::getline(iss, value)) { - std::istringstream iss(line); - std::string key, value; - if (std::getline(iss, key, '=') && std::getline(iss, value)) + if (key == "ODOMETER") { - if (key == "ODOMETER") - { - odometer = stringToNumber(value); - } - else if (key == "LAST_SERVICE") - { - lastService = stringToNumber(value); - } - else if (key == "SERVICE_INTERVAL") - { - serviceInterval = stringToNumber(value); - } + odometer = stringToNumber(value); + } + else if (key == "LAST_SERVICE") + { + lastService = stringToNumber(value); + } + else if (key == "SERVICE_INTERVAL") + { + serviceInterval = stringToNumber(value); } } - maintenanceFile.close(); } } @@ -318,15 +313,16 @@ T configManager::stringToNumber(std::string_view str) */ void configManager::setValuesFromConfig() { - std::ifstream configFile(configFileName); - if (!configFile) + std::string fileContent = readFileToString(configFileName); + if (fileContent.empty()) { logHandler("setValForConfig", "Could not open config file. Reason Unknown.", Log::Level::Warn, 4); return; } + std::istringstream stream(fileContent); std::string configLine; - while (std::getline(configFile, configLine)) + while (std::getline(stream, configLine)) { if (configLine.empty() || configLine[0] == ';' || configLine[0] == '#') { @@ -419,7 +415,7 @@ void configManager::setValuesFromConfig() else if (key == "MOTOR_CONFIG" || key == "INERTIAL" || key == "TRIPORT_CONFIG") { std::string section = key; - while (std::getline(configFile, configLine) && configLine != "}") + while (std::getline(stream, configLine) && configLine != "}") { if (configLine.empty() || configLine.starts_with(';') || configLine.starts_with('#')) { @@ -427,10 +423,10 @@ void configManager::setValuesFromConfig() } std::string name = configLine; - std::getline(configFile, configLine); // Skip the opening brace + std::getline(stream, configLine); // Skip the opening brace std::string port, gearRatio, reversedStr; - while (std::getline(configFile, configLine) && configLine != "}") + while (std::getline(stream, configLine) && configLine != "}") { std::istringstream iss(configLine); std::string configKey, configValue; @@ -472,7 +468,6 @@ void configManager::setValuesFromConfig() resetOrInitializeConfig(std::format("Invalid line in config file: {}. Do you want to reset the config?", configLine)); } } - configFile.close(); } // Method to parse the config file @@ -504,7 +499,7 @@ void configManager::parseConfig() if (Brain.SDcard.isInserted()) { - if (!Brain.SDcard.exists(configFileName.c_str())) + if (!fileExists(configFileName)) { resetOrInitializeConfig("Missing config file. Create it?"); } diff --git a/src/display/gifplayer/gifplayer.cpp b/src/display/gifplayer/gifplayer.cpp index d832b67..402edfb 100644 --- a/src/display/gifplayer/gifplayer.cpp +++ b/src/display/gifplayer/gifplayer.cpp @@ -15,20 +15,41 @@ int emu_open(const char *path, int) emu_offset = 0; emu_size = 0; - FILE *f = fopen(path, "rb"); - fseek(f, 0, SEEK_END); - emu_size = ftell(f); - fseek(f, 0, SEEK_SET); // same as rewind(f); + // Check if SD card is inserted + if (!Brain.SDcard.isInserted()) + { + return -1; + } + + // Check if file exists + if (!Brain.SDcard.exists(path)) + { + return -1; + } + + // Get file size + emu_size = Brain.SDcard.size(path); + if (emu_size <= 0) + { + return -1; + } emu_memory = static_cast(malloc(emu_size + 1)); if (!emu_memory) { - fclose(f); return -1; } - fread(emu_memory, emu_size, 1, f); - fclose(f); + // Load file using VEX API + int bytesRead = Brain.SDcard.loadfile(path, reinterpret_cast(emu_memory), emu_size); + if (bytesRead <= 0) + { + free(emu_memory); + emu_memory = nullptr; + return -1; + } + + emu_size = bytesRead; // Update size to actual bytes read return 1; } diff --git a/src/display/logging.cpp b/src/display/logging.cpp index 3231c84..75cd0a2 100644 --- a/src/display/logging.cpp +++ b/src/display/logging.cpp @@ -1,5 +1,4 @@ #include "vex.h" -#include /** * @brief Converts a given Log::Level enumeration value to its corresponding string representation. @@ -250,19 +249,30 @@ void SD_Card_Logging(const Log::Level &level, const std::string &functionName, c return; } - std::ofstream LogFile("log.rtf", std::ios_base::out | std::ios_base::app); if (ConfigManager.getLogToFile()) { - if (!LogFile) + if (!Brain.SDcard.isInserted()) { logFileCreationFailed = true; - logHandler("logHandler", "Could not create logfile.", Log::Level::Warn, 3); + logHandler("logHandler", "Could not create logfile - SD card not inserted.", Log::Level::Warn, 3); + ConfigManager.setLogToFile(false); + return; + } + + // Prepare log content + std::string logContent = "{\\rtf1\\ansi\\deff0 {\\colortbl;\\red0\\green0\\blue0;\\red255\\green0\\blue0;\\red0\\green255\\blue0;\\red0\\green0\\blue255;\\red255\\green255\\blue0;\\red255\\green0\\blue255;\\red0\\green255\\blue255;}\n"; + logContent += "\\cf" + std::to_string(rtfColors[static_cast(level)]) + " "; + logContent += "[" + LogToString(level) + "] > Time: " + std::to_string(Brain.Timer.time(vex::timeUnits::sec)) + " > Module: " + functionName + " > " + message + "\\line\n"; + logContent += "}\n"; + + // Write to SD card using VEX API (append mode) + int bytesWritten = Brain.SDcard.appendfile("log.rtf", const_cast(logContent.c_str()), logContent.length()); + if (bytesWritten != static_cast(logContent.length())) + { + logFileCreationFailed = true; + logHandler("logHandler", "Could not write to logfile.", Log::Level::Warn, 3); ConfigManager.setLogToFile(false); return; } - LogFile << "{\\rtf1\\ansi\\deff0 {\\colortbl;\\red0\\green0\\blue0;\\red255\\green0\\blue0;\\red0\\green255\\blue0;\\red0\\green0\\blue255;\\red255\\green255\\blue0;\\red255\\green0\\blue255;\\red0\\green255\\blue255;}\n"; - LogFile << "\\cf" << rtfColors[static_cast(level)] << " "; - LogFile << "[" << LogToString(level) << "] > Time: " << Brain.Timer.time(vex::timeUnits::sec) << " > Module: " << functionName << " > " << message << "\\line\n"; - LogFile << "}\n"; } } \ No newline at end of file