diff --git a/.clang-format b/.clang-format index 8ba7304c4686d7bf03150814f7a17554ba424175..7abb256cdd1d5fc9f2a79f19dfa70d6f55c6fe63 100644 --- a/.clang-format +++ b/.clang-format @@ -9,6 +9,7 @@ AllowShortFunctionsOnASingleLine: Inline AlwaysBreakTemplateDeclarations: Yes BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Custom +NamespaceIndentation: All BraceWrapping: AfterFunction: false ... diff --git a/host/host_central_mast/lib/ResendManager/ResendManager.cpp b/host/host_central_mast/lib/ResendManager/ResendManager.cpp index 1c8eb125fc9721b8a816b221231682e2c1135711..64d6557ab417c4535f6ab7801f0ce12b566d0021 100644 --- a/host/host_central_mast/lib/ResendManager/ResendManager.cpp +++ b/host/host_central_mast/lib/ResendManager/ResendManager.cpp @@ -14,7 +14,7 @@ void ResendManager::init() { } uint ResendManager::getLastResendFileId() const { // get the next file id to be resend - auto filesInDirectory = getFilesInDirectory(resendDirectoryPath); + auto filesInDirectory = SDUtilities::getFilesInDirectory(resendDirectoryPath); // convert the file names to uint std::list<uint> fileUintIDs; @@ -38,24 +38,24 @@ uint ResendManager::getLastResendFileId() const { // get the next file id to be } void ResendManager::createResendDirectory() const { // create directory if it doesn't exist - createDirectory("/resend"); + SDUtilities::createDirectory("/resend"); } void ResendManager::storeForResend(const String &messageToBeSend) { // create file String filename = String(nextResendFileId); - writeFile(messageToBeSend, resendDirectoryPath + "/" + filename); + SDUtilities::writeFile(messageToBeSend, resendDirectoryPath + "/" + filename); ResendManager::incrementCount(); } std::optional<ResendPointType> ResendManager::loadNextToBeResendMessage() { // get first file in resend directory - auto filename = getFirstFileNameInDirectory(resendDirectoryPath.c_str()); + auto filename = SDUtilities::getFirstFileNameInDirectory(resendDirectoryPath.c_str()); if (filename.has_value()) { // read file - auto message = readFile(resendDirectoryPath + "/" + filename.value().c_str()); + auto message = SDUtilities::readFile(resendDirectoryPath + "/" + filename.value().c_str()); return ResendPointType{message, filename.value()}; } return std::nullopt; diff --git a/host/host_central_mast/lib/Utilities/Definitions.h b/host/host_central_mast/lib/Utilities/Definitions.h index bef879733ecd8ef4c37e313649f5c50522ca136e..dbde5553937a775e79c74e2d6607a492322d0410 100644 --- a/host/host_central_mast/lib/Utilities/Definitions.h +++ b/host/host_central_mast/lib/Utilities/Definitions.h @@ -24,13 +24,16 @@ #define LED_PIN 12 // See all AT commands, if wanted -#define DUMP_AT_COMMANDS +//#define DUMP_AT_COMMANDS #define TAG_ESPNOW "ESPNOW" #define TAG_MAIN "MAIN" #define TAG_SD "SD" #define TAG_GSM "GSM" #define TAG_TIMEMANAGER "TIMEMANAGER" +#define TAG_SDUTILITIES "SDUTILITIES" + +#define SD_CARD_FAIL_COUNTER 100 // global definition of RTC. Initialised in main extern ESP32Time rtc; diff --git a/host/host_central_mast/lib/Utilities/SDCardLogger.cpp b/host/host_central_mast/lib/Utilities/SDCardLogger.cpp index 3decfc2c466696354b7cecfad71bab5aa979e0db..f3ee7a6e184227867b81d90d30505c9308343098 100644 --- a/host/host_central_mast/lib/Utilities/SDCardLogger.cpp +++ b/host/host_central_mast/lib/Utilities/SDCardLogger.cpp @@ -5,42 +5,55 @@ #include "SDCardLogger.h" namespace SDCardLogger { -char log_print_buffer[512]; -bool printToSerial = false; -void printDebugToSerial(bool printToSerialAsWell) { - printToSerial = printToSerialAsWell; -} -int vprintf_into_sd(const char *szFormat, va_list args) { - String logstring = "[" + rtc.getDateTime() + "] "; - logstring += szFormat; - // write evaluated format string into buffer - int ret = vsnprintf(log_print_buffer, sizeof(log_print_buffer), logstring.c_str(), args); - - String date = rtc.getDate(); - String filename = "/log_" + date + ".txt"; - - // output is now in buffer. write to file. - if (ret >= 0) { - if (!SD.exists(filename)) { - File writeLog = SD.open(filename, FILE_WRITE); - if (!writeLog) - Serial.println("Couldn't open " + filename + " for writing"); - delay(50); - writeLog.close(); + + char log_print_buffer[512]; + bool printToSerial = false; + + void printDebugToSerial(bool printToSerialAsWell) { + printToSerial = printToSerialAsWell; + } + int vprintf_into_sd(const char *szFormat, va_list args) { + String logstring = "[" + rtc.getDateTime() + "] "; + logstring += szFormat; + + if (!SDUtilities::isSDAvailable()) { + if (printToSerial) { + logstring += " (SD card not available)\n"; + vprintf(logstring.c_str(), args); + } + return 1; } + // write evaluated format string into buffer + int ret = vsnprintf(log_print_buffer, sizeof(log_print_buffer), logstring.c_str(), args); + + String date = rtc.getDate(); + String filename = "/log_" + date + ".txt"; + + // output is now in buffer. write to file. + if (ret >= 0) { + if (!SD.exists(filename)) { + File writeLog = SD.open(filename, FILE_WRITE); + if (!writeLog) { + Serial.println("Couldn't open " + filename + " for writing"); + SDUtilities::setSDAvailable(false); + return 1; + } + delay(50); + writeLog.close(); + } - File logFile = SD.open(filename, FILE_APPEND); + File logFile = SD.open(filename, FILE_APPEND); - // debug output - if (printToSerial) { - vprintf(logstring.c_str(), args); + // debug output + if (printToSerial) { + vprintf(logstring.c_str(), args); + } + logFile.write((uint8_t *)log_print_buffer, (size_t)ret); + // to be safe in case of crashes: flush the output + logFile.flush(); + logFile.close(); } - logFile.write((uint8_t *)log_print_buffer, (size_t)ret); - // to be safe in case of crashes: flush the output - logFile.flush(); - logFile.close(); + return ret; } - return ret; -} } // namespace SDCardLogger diff --git a/host/host_central_mast/lib/Utilities/SDCardLogger.h b/host/host_central_mast/lib/Utilities/SDCardLogger.h index bf6615caee3f7766b1052b6a84a317e51c7cde78..635a12e025e4c80c524ea58f1698b0bd7e892a4b 100644 --- a/host/host_central_mast/lib/Utilities/SDCardLogger.h +++ b/host/host_central_mast/lib/Utilities/SDCardLogger.h @@ -7,10 +7,12 @@ #include "Definitions.h" #include "SD.h" +#include "Utilities.h" namespace SDCardLogger { -void printDebugToSerial(bool printToSerialAsWell); -int vprintf_into_sd(const char *szFormat, va_list args); + void printDebugToSerial(bool printToSerialAsWell); + int vprintf_into_sd(const char *szFormat, va_list args); + void sdNotAvailable(bool sdNotAvailable); }; // namespace SDCardLogger #endif // HOST_CENTRAL_MAST_SDCARDLOGGER_H diff --git a/host/host_central_mast/lib/Utilities/Utilities.cpp b/host/host_central_mast/lib/Utilities/Utilities.cpp index 20059901e68c099351901d047b5d41ad8e431c4a..316d33c95d27260f7b3c0ca299ed049db6305bce 100644 --- a/host/host_central_mast/lib/Utilities/Utilities.cpp +++ b/host/host_central_mast/lib/Utilities/Utilities.cpp @@ -4,162 +4,238 @@ #include "Utilities.h" -void setupSDCard() { - SPI.begin(SD_SCLK, SD_MISO, SD_MOSI, SD_CS); - if (!SD.begin(SD_CS)) { - esp_log_write(ESP_LOG_ERROR, TAG_SD, "Card MOUNT FAIL\n"); - // TODO: Error handling - } else { - uint32_t cardSize = SD.cardSize() / (1024 * 1024); - String sdcardSizeString = "SDCard Size: " + String(cardSize) + "MB"; - esp_log_write(ESP_LOG_DEBUG, TAG_SD, "%s\n", sdcardSizeString.c_str()); +namespace SDUtilities { + + bool SDAvailable = true; + + void setSDAvailable(bool sdAvailable) { + SDAvailable = sdAvailable; } -} -void saveStringToSDCard(const std::string &dataString); -std::list<String> getFilesInDirectory(const String &dirname) { - std::list<String> files; - File dir = openDirectory(dirname); - while (true) { - File nextFile = dir.openNextFile(); - if (!nextFile) { - break; + // Used to try to remount SD card if it fails more than x times (100) + int sdFailCounter = 0; + + bool isSDAvailable() { + return SDAvailable; + } + + void tryRemountingSD() { + try { + setupSDCard(SD_MISO, SD_MOSI, SD_SCLK, SD_CS); + setSDAvailable(true); + } catch (SDSetupException &e) { + esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "Couldn't remount SD card: %s\n", e.what()); + } + sdFailCounter = 0; + } + + bool checkSDAvailability(const String &errorMessage) { + if (!isSDAvailable()) { + sdFailCounter++; + if (sdFailCounter % SD_CARD_FAIL_COUNTER == 0) { + esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "SD card not available. Trying to remount...\n"); + tryRemountingSD(); + } + String message = errorMessage + " (SD card not available, failed " + sdFailCounter + " times)\n"; + esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "%s", message.c_str()); + // if re-mount was successful, this will be true + return isSDAvailable(); + } + return true; + }; + + std::list<String> getFilesInDirectory(const String &dirname) { + if (!checkSDAvailability("Couldn't get files in directory " + dirname)) { + return {}; } - if (!nextFile.isDirectory()) { - files.emplace_back(nextFile.name()); + std::list<String> files; + File dir = openDirectory(dirname); + while (true) { + File nextFile = dir.openNextFile(); + if (!nextFile) { + break; + } + if (!nextFile.isDirectory()) { + files.emplace_back(nextFile.name()); + } + nextFile.close(); } - nextFile.close(); + return files; } - return files; -} -std::optional<String> getLastFileInDirectory(const String &dirname) { + std::optional<String> getLastFileInDirectory(const String &dirname) { - File root = openDirectory(dirname); - root.rewindDirectory(); + if (!checkSDAvailability("Couldn't get last file in directory " + dirname)) { + return std::nullopt; + } + + File root = openDirectory(dirname); + root.rewindDirectory(); - File file = root.openNextFile(); - while (file) { - File nextFile = root.openNextFile(); - if (!nextFile) { - break; + File file = root.openNextFile(); + while (file) { + File nextFile = root.openNextFile(); + if (!nextFile) { + break; + } + file = nextFile; + } + // log + if (file) { + esp_log_write(ESP_LOG_INFO, TAG_SDUTILITIES, "Last file name: %s\n", file.name()); + return file.name(); + } else { + esp_log_write(ESP_LOG_INFO, TAG_SDUTILITIES, "No file found\n"); + return std::nullopt; } - file = nextFile; - } - // log - if (file) { - esp_log_write(ESP_LOG_INFO, "getLastFileInDirectory", "Last file name: %s\n", file.name()); - return file.name(); - } else { - esp_log_write(ESP_LOG_INFO, "getLastFileInDirectory", "No file found\n"); - return std::nullopt; - } -} -File openDirectory(const String &dirname) { - File root = SD.open(dirname); - if (!root) { - esp_log_write(ESP_LOG_ERROR, "openDirectory", "Failed to open directory\n"); - throw; } - if (!root.isDirectory()) { - esp_log_write(ESP_LOG_ERROR, "openDirectory", "Not a directory\n"); - throw; + File openDirectory(const String &dirname) { + + if (!checkSDAvailability("Couldn't open directory " + dirname)) { + throw; + } + + File root = SD.open(dirname); + if (!root) { + esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "Failed to open directory\n"); + throw; + } + if (!root.isDirectory()) { + esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "Not a directory\n"); + throw; + } + return root; } - return root; -} -std::optional<String> getFirstFileNameInDirectory(const String &dirname) { - File root = openDirectory(dirname); - root.rewindDirectory(); + std::optional<String> getFirstFileNameInDirectory(const String &dirname) { - File file = root.openNextFile(); - if (file) { - esp_log_write(ESP_LOG_INFO, "getFirstFileNameInDirectory", "file found: %s\n", file.name()); - return file.name(); - } else { - esp_log_write(ESP_LOG_INFO, "getFirstFileNameInDirectory", "no file found\n"); - return std::nullopt; + if (!checkSDAvailability("Couldn't get first file in directory " + dirname)) { + return std::nullopt; + } + + File root = openDirectory(dirname); + root.rewindDirectory(); + + File file = root.openNextFile(); + if (file) { + esp_log_write(ESP_LOG_INFO, TAG_SDUTILITIES, "file found: %s\n", file.name()); + return file.name(); + } else { + esp_log_write(ESP_LOG_INFO, TAG_SDUTILITIES, "no file found\n"); + return std::nullopt; + } } -} -File openForWrite(const String &filePath) { - File file = SD.open(filePath, FILE_WRITE); - if (!file) { - esp_log_write(ESP_LOG_ERROR, "SD", "Failed to open file for writing\n"); - throw; + File openForWrite(const String &filePath) { + + if (!checkSDAvailability("Couldn't open file " + filePath + " for writing")) { + throw; + } + + File file = SD.open(filePath, FILE_WRITE); + if (!file) { + esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "Failed to open file for writing\n"); + throw; + } + return file; } - return file; -} -File openForRead(const String &filePath) { - File file = SD.open(filePath, FILE_READ); - if (!file) { - esp_log_write(ESP_LOG_ERROR, "SD", "Failed to open file for reading\n"); - throw; + File openForRead(const String &filePath) { + + if (!checkSDAvailability("Couldn't open file " + filePath + " for reading")) { + throw; + } + + File file = SD.open(filePath, FILE_READ); + if (!file) { + esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "Failed to open file for reading\n"); + throw; + } + return file; } - return file; -} -void writeFile(const String &messageToBeSend, const String &filePath) { - File file = openForWrite(filePath); - if (file.print(messageToBeSend)) { - esp_log_write(ESP_LOG_INFO, "SD", "File written %s\n", filePath.c_str()); - } else { - esp_log_write(ESP_LOG_ERROR, "SD", "Write failed %s\n", filePath.c_str()); - throw; + void writeFile(const String &messageToBeSend, const String &filePath) { + + if (!checkSDAvailability("Couldn't write to file " + filePath)) { + throw; + } + + File file = openForWrite(filePath); + if (file.print(messageToBeSend)) { + esp_log_write(ESP_LOG_INFO, TAG_SDUTILITIES, "File written %s\n", filePath.c_str()); + } else { + esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "Write failed %s\n", filePath.c_str()); + throw; + } + file.close(); } - file.close(); -} -String readFile(const String &filePath) { - File file = openForRead(filePath); - String ret; + String readFile(const String &filePath) { + + if (!checkSDAvailability("Couldn't read file " + filePath)) { + throw; + } + + File file = openForRead(filePath); + + String ret; - while (file.available()) { - ret += (char)file.read(); + while (file.available()) { + ret += (char)file.read(); + } + + file.close(); + return ret; } - file.close(); - return ret; -} + void createDirectory(const String &dirname) { + + if (!checkSDAvailability("Couldn't create directory " + dirname)) { + throw; + } -void createDirectory(const String &dirname) { - if (!SD.exists(dirname)) { - SD.mkdir(dirname); - esp_log_write(ESP_LOG_INFO, "createDirectory", "Created directory: %s\n", dirname.c_str()); - } else { - esp_log_write(ESP_LOG_WARN, "createDirectory", "Directory already exists\n"); + if (!SD.exists(dirname)) { + SD.mkdir(dirname); + esp_log_write(ESP_LOG_INFO, TAG_SDUTILITIES, "Created directory: %s\n", dirname.c_str()); + } else { + esp_log_write(ESP_LOG_WARN, TAG_SDUTILITIES, "Directory already exists\n"); + } } -} -void setupSDCard(int MISO, int MOSI, int SCLK, int CS) { - SPI.begin(SCLK, MISO, MOSI, CS); - if (!SD.begin(CS)) { - esp_log_write(ESP_LOG_ERROR, "Utilities", "Card MOUNT FAIL\n"); - throw SDSetupException("Card MOUNT FAIL"); - } else { - uint32_t cardSize = SD.cardSize() / (1024 * 1024); - String sdcardSizeString = "SDCard Size: " + String(cardSize) + "MB"; - esp_log_write(ESP_LOG_DEBUG, "Utilities", "%s\n", sdcardSizeString.c_str()); + void setupSDCard(int MISO, int MOSI, int SCLK, int CS) { + SPI.begin(SCLK, MISO, MOSI, CS); + if (!SD.begin(CS)) { + esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "Card MOUNT FAIL\n"); + throw SDSetupException("Card MOUNT FAIL"); + } else { + uint32_t cardSize = SD.cardSize() / (1024 * 1024); + String sdcardSizeString = "SDCard Size: " + String(cardSize) + "MB"; + esp_log_write(ESP_LOG_DEBUG, TAG_SDUTILITIES, "%s\n", sdcardSizeString.c_str()); + } } -} -void saveStringToSDCard(const std::string &dataString) { - File dataFile = SD.open("/datalog.txt", FILE_APPEND); + void saveStringToSDCard(const std::string &dataString) { - // if the file is available, write to it: - if (dataFile) { - if (dataString.length() > 0) { - dataFile.println(dataString.c_str()); + if (!checkSDAvailability("Couldn't save string to SD card")) { + throw SDCardException("Couldn't save string to SD card"); + } + + File dataFile = SD.open("/datalog.txt", FILE_APPEND); + + // if the file is available, write to it: + if (dataFile) { + if (dataString.length() > 0) { + dataFile.println(dataString.c_str()); + } + dataFile.close(); + } + // if the file isn't open, pop up an error: + else { + esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "error opening datalog.txt\n"); + throw SDCardException("error opening datalog.txt"); } - dataFile.close(); - } - // if the file isn't open, pop up an error: - else { - esp_log_write(ESP_LOG_ERROR, "Utilities", "error opening datalog.txt\n"); - throw SDCardException("error opening datalog.txt"); } -} +} // namespace SDUtilities // I don't think this does anything. Copied from the example void turnOffLEDs() { // Set LED OFF diff --git a/host/host_central_mast/lib/Utilities/Utilities.h b/host/host_central_mast/lib/Utilities/Utilities.h index dae9e62d88f82b3d1a0b7f145d51f3001ffe5b68..dc18e3459e0fabe83c64f2e09a4a9ae3bf8c45f6 100644 --- a/host/host_central_mast/lib/Utilities/Utilities.h +++ b/host/host_central_mast/lib/Utilities/Utilities.h @@ -9,21 +9,26 @@ #include "SD.h" #include "SDCardException.h" #include "SDSetupException.h" +#include "WiFi.h" #include <Arduino.h> #include <Definitions.h> #include <WString.h> #include <list> -#include "WiFi.h" -File openDirectory(const String &dirname); -std::list<String> getFilesInDirectory(const String &dirname); -std::optional<String> getFirstFileNameInDirectory(const String &dirname); -std::optional<String> getLastFileInDirectory(const String &dirname); -void writeFile(const String &messageToBeSend, const String &filePath); -String readFile(const String &filePath); -void createDirectory(const String &dirname); -void setupSDCard(int MISO, int MOSI, int SCLK, int CS); -void saveStringToSDCard(const std::string &dataString); +namespace SDUtilities { + File openDirectory(const String &dirname); + std::list<String> getFilesInDirectory(const String &dirname); + std::optional<String> getFirstFileNameInDirectory(const String &dirname); + std::optional<String> getLastFileInDirectory(const String &dirname); + void writeFile(const String &messageToBeSend, const String &filePath); + String readFile(const String &filePath); + void createDirectory(const String &dirname); + void setupSDCard(int MISO, int MOSI, int SCLK, int CS); + void saveStringToSDCard(const std::string &dataString); + void setSDAvailable(bool sdAvailable); + bool isSDAvailable(); +} // namespace SDUtilities + void turnOffLEDs(); String getMacAddressAsString(const uint8_t *mac); String documentToLineProtocolString(const DynamicJsonDocument &doc); diff --git a/host/host_central_mast/src/main.cpp b/host/host_central_mast/src/main.cpp index 2cdbcfb1cc73e8ef057d5f672444e544153bf5f3..f58fa1c40856d2fef8709c785c7308b50a97618e 100644 --- a/host/host_central_mast/src/main.cpp +++ b/host/host_central_mast/src/main.cpp @@ -76,6 +76,14 @@ void on_data_recv(const uint8_t *mac, const uint8_t *incomingData, int len) { DynamicJsonDocument doc = parseReceivedJsonData(data); + // TODO: Respond to the client. Maybe do that before parsing anything + response response = {}; + response.type = dataAck; + esp_read_mac(response.mac, ESP_MAC_WIFI_STA); + response.time = rtc.getEpoch(); + esp_err_t success = esp_now_send(mac, (uint8_t *)&response, sizeof(response)); + esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW, (success == ESP_OK) ? "Response sent\n" : "Failed to respond\n"); + String macAddress = getMacAddressAsString(mac); // add timestamp and mac address @@ -88,7 +96,11 @@ void on_data_recv(const uint8_t *mac, const uint8_t *incomingData, int len) { std::string dataString{}; serializeJson(doc, dataString); - saveStringToSDCard(dataString); + try { + SDUtilities::saveStringToSDCard(dataString); + } catch (const std::exception &e) { + esp_log_write(ESP_LOG_ERROR, TAG_ESPNOW, "Failed to save data to SD card: %s", e.what()); + } String lineData = documentToLineProtocolString(doc); @@ -97,17 +109,11 @@ void on_data_recv(const uint8_t *mac, const uint8_t *incomingData, int len) { xSemaphoreTake(xMutex, portMAX_DELAY); queue.push(lineData); xSemaphoreGive(xMutex); - - response response = {}; - response.type = dataAck; - esp_read_mac(response.mac, ESP_MAC_WIFI_STA); - response.time = rtc.getEpoch(); - esp_err_t success = esp_now_send(mac, (uint8_t *)&response, sizeof(response)); - esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW, (success == ESP_OK) ? "Response sent\n" : "Failed to respond\n"); } -[[noreturn]] void esp_loop(){ - while (true){} +[[noreturn]] void esp_loop() { + while (true) { + } } [[noreturn]] void ESPNOWReceiveTask(void *parameter) { @@ -150,7 +156,12 @@ void setup() { // Set console baud rate Serial.begin(115200); delay(10); - setupSDCard(SD_MISO, SD_MOSI, SD_SCLK, SD_CS); + try { + SDUtilities::setupSDCard(SD_MISO, SD_MOSI, SD_SCLK, SD_CS); + } catch (const SDSetupException &e) { + SDUtilities::setSDAvailable(false); + esp_log_write(ESP_LOG_ERROR, TAG_MAIN, "SD Card setup failed: %s\n", e.what()); + } SDCardLogger::printDebugToSerial(true); @@ -255,5 +266,5 @@ void loop() { connectionManager.modemPowerOff(); - delay(60000); + delay(10000); }