diff --git a/firmware/lib/basic/Dtypes.h b/firmware/lib/basic/Dtypes.h index 5d83f8f..71f7806 100644 --- a/firmware/lib/basic/Dtypes.h +++ b/firmware/lib/basic/Dtypes.h @@ -3,19 +3,12 @@ #ifndef PLATFORM_NATIVE // ---------------------------------- Arduino ------------------------------------------------------------- - +#include "Logger.h" #include inline void _assert(const char *expression, const char *message, const char *file, int line) { - Serial.print("Assert "); - Serial.print(file); - Serial.print(" : "); - Serial.print(line); - Serial.print(" '"); - Serial.print(expression); - Serial.println("' failed."); - Serial.println(message); + LOG_WARNING("Assert %s:%d '%s' failed.\n%s", file, line, expression, message); } template diff --git a/firmware/lib/esphttp/EspHttp.h b/firmware/lib/esphttp/EspHttp.h index 07e0c3e..ad0bd50 100644 --- a/firmware/lib/esphttp/EspHttp.h +++ b/firmware/lib/esphttp/EspHttp.h @@ -3,6 +3,7 @@ #include #include #include "Dtypes.h" +#include "Logger.h" constexpr int MAX_URI_HANDLERS = 25; @@ -53,7 +54,7 @@ public: .handler = rawCallback, .user_ctx = (void *)(&handlerCallbacks_[nextFreeHandler_])}; if (httpd_register_uri_handler(server_, &uri_endpoint_cfg) != ESP_OK) - Serial.println("Failed to register url handler"); + LOG_WARNING("Failed to register url handler"); ++nextFreeHandler_; } diff --git a/firmware/lib/esphttp/WebDAV.cpp b/firmware/lib/esphttp/WebDAV.cpp index 5bf583e..214373a 100644 --- a/firmware/lib/esphttp/WebDAV.cpp +++ b/firmware/lib/esphttp/WebDAV.cpp @@ -1,5 +1,6 @@ #include "FilesystemAbstraction.h" #include "WebDAV.h" +#include "Logger.h" namespace webdav_constants { @@ -93,7 +94,7 @@ size_t webdavFileListingSpiffs(char *buffer, size_t maxLength, toBuffer(MULTISTATUS_END); if (incomplete) - Serial.println("WebDAV listing response is incomplete, because buffer was too small"); + LOG_WARNING("WebDAV listing response is incomplete, because buffer was too small"); return bytesWritten; } @@ -122,7 +123,7 @@ std::function webdavHandler(const char *uriPrefix, case HTTP_GET: { auto filename = uriToFileName(uri, spiffsFolder); - Serial.printf("GET filename %s\n", filename.c_str()); + LOG_INFO("GET filename %s", filename.c_str()); auto file = portablefs::open(filename.c_str(), "r"); if (file.available()) { @@ -154,14 +155,14 @@ std::function webdavHandler(const char *uriPrefix, } case HTTP_OPTIONS: { - Serial.println("Options request"); + LOG_INFO("Options request"); httpd_resp_set_status(req, "204 No Content"); httpd_resp_set_hdr(req, "Access-Control-Allow-Methods", "GET, PROPFIND, DELETE, OPTIONS"); httpd_resp_send(req, "", 0); break; } default: - Serial.printf("Sending 404 %d uri %s\n", req->method, req->uri); + LOG_INFO("Sending 404 %d uri %s", req->method, req->uri); httpd_resp_send_404(req); } }; diff --git a/firmware/lib/logging/Logger.cpp b/firmware/lib/logging/Logger.cpp new file mode 100644 index 0000000..fc1ef3d --- /dev/null +++ b/firmware/lib/logging/Logger.cpp @@ -0,0 +1,50 @@ +#include "Logger.h" + +constexpr size_t LOG_SIZE = 1024 * 1024 * 2; + +static Logger *theLogger = nullptr; + +Logger *Logger::getInstance() +{ + return theLogger; +} + +void Logger::init() +{ + theLogger = new Logger(); + Serial.begin(115200); + while (!Serial) + { + } +} + +Logger::Logger() +{ + data_ = (char *)heap_caps_malloc(LOG_SIZE, MALLOC_CAP_SPIRAM); + totalSize_ = LOG_SIZE; + currentSize_ = 0; + + // write header placeholder + const auto millisPlaceholder = 0; + memcpy(&data_[currentSize_], &millisPlaceholder, sizeof(millisPlaceholder)); + currentSize_ += sizeof(millisPlaceholder); + + NtpTimeT ntpPlaceholder = 0; + memcpy(&data_[currentSize_], &ntpPlaceholder, sizeof(ntpPlaceholder)); + currentSize_ += sizeof(ntpPlaceholder); +} + +void Logger::setNtpTime(NtpTimeT ntpTime) +{ + auto data = getInstance()->data_; + + const auto millisTime = millis(); + memcpy(&data[0], &millisTime, sizeof(millisTime)); + memcpy(&data[sizeof(millisTime)], &ntpTime, sizeof(ntpTime)); +} + + +Logger::~Logger() +{ + free(data_); +} \ No newline at end of file diff --git a/firmware/lib/logging/Logger.h b/firmware/lib/logging/Logger.h new file mode 100644 index 0000000..68285b0 --- /dev/null +++ b/firmware/lib/logging/Logger.h @@ -0,0 +1,62 @@ +#pragma once + +#include "Arduino.h" + +#define LOG_INFO(...) \ + { \ + Logger::getInstance()->log(__VA_ARGS__); \ + } + +#define LOG_TRACE(...) \ + { \ + Logger::getInstance()->log(__VA_ARGS__); \ + } + +#define LOG_WARNING(...) \ + { \ + Logger::getInstance()->log(__VA_ARGS__); \ + } + +class Logger +{ +public: + using NtpTimeT = unsigned long; + + ~Logger(); + + template + inline bool log(const char *formatStr, Args &&...args) + { + const auto time = millis(); + + if (totalSize_ - currentSize_ <= sizeof(time)) + return false; + + memcpy(&data_[currentSize_], &time, sizeof(time)); + currentSize_ += time; + + const auto spaceLeft = totalSize_ - currentSize_; + auto charsWritten = snprintf(&data_[currentSize_], spaceLeft, formatStr, + std::forward(args)...); + Serial.println(&data_[currentSize_]); + + if (charsWritten < spaceLeft) + { + currentSize_ += charsWritten; + return true; + } + else + return false; + } + + static Logger *getInstance(); + static void init(); + static void setNtpTime(NtpTimeT time); + +private: + Logger(); + + char *data_; + size_t totalSize_; + size_t currentSize_; +}; diff --git a/firmware/lib/scale/Scale.h b/firmware/lib/scale/Scale.h index 5ef5c6d..9343286 100644 --- a/firmware/lib/scale/Scale.h +++ b/firmware/lib/scale/Scale.h @@ -7,8 +7,10 @@ class Scale public: bool measure(uint16_t &measurementOut) { - long value = hx711_.read_average(CONFIG_MEASUREMENT_AVG_COUNT) - offset_; - Serial.println(value); + long value = hx711_.read_average(CONFIG_MEASUREMENT_AVG_COUNT); + LOG_TRACE("rv %ld\n", value); + value -= offset_; + if (value < 0) measurementOut = (int16_t)(-(value >> valueRightShift_ )); else @@ -24,9 +26,9 @@ public: void tare(uint32_t numMeasurementsToAverage = 50) { - hx711_.read_average(3); + auto v1 = hx711_.read_average(3); offset_ = hx711_.read_average(numMeasurementsToAverage); - Serial.printf("Tare offset %ld\n", offset_); + LOG_INFO("Init reading %ld, Tare offset %ld\n", v1, offset_); } const long &offset() const { return offset_; } diff --git a/firmware/lib/session/MeasurementSession.h b/firmware/lib/session/MeasurementSession.h deleted file mode 100644 index 08c828b..0000000 --- a/firmware/lib/session/MeasurementSession.h +++ /dev/null @@ -1,139 +0,0 @@ -#include "SessionChunk.h" - - -template -class MeasurementSession { -public: - typedef SessionChunk Chunk_T; - - MeasurementSession() - : currentChunk(&chunks[0]), - otherChunk(&chunks[1]) {} - - void init(uint32_t epochStartTime) { - currentChunk = &chunks[0]; - otherChunk = &chunks[1]; - currentChunk->init(epochStartTime, 0); - otherChunk->init(0, 0); - } - - bool addPoint(Measurement_T measurement) { - const bool successful = currentChunk->addPoint(measurement); - if (!successful) { - Serial.println("Starting session rotate"); - rotate(); - const bool secondInsertSuccess = currentChunk->addPoint(measurement); - assert_msg(secondInsertSuccess, "Session: insertion after rotation failed"); - // TODO check that there is place for file - remove old files - } - return true; - } - - void finalize() { - if( otherChunkFilled() ) - saveChunkToFile(otherChunk); - if( currentChunk->numMeasurements() > 0) { - saveChunkToFile(currentChunk); - } - currentChunk->init(0, 0); - otherChunk->init(0, 0); - } - - uint32_t numMeasurements() const { - return currentChunk->getStartIndex() + currentChunk->numMeasurements(); - } - - template - void serialize(Encoder_T & encoder, uint32_t startIdx) const - { - const uint32_t lastIdx = currentChunk->getStartIndex() + currentChunk->numMeasurements(); - if( lastIdx <= startIdx) { - encoder.template sendArray(nullptr, 0); - return; - } - - Chunk_T::sendHeader(encoder, currentChunk->getStartTime(), startIdx); - encoder.template sendArrayHeader(lastIdx - startIdx); - while(startIdx < lastIdx) - startIdx = serializeChunk(encoder, startIdx); - assert_msg(startIdx == lastIdx, "Not all data was sent"); - } - - uint32_t getStartTime() const { - return currentChunk->getStartTime(); - } -private: - void rotate() { - if( otherChunkFilled() ) - saveChunkToFile(otherChunk); - swapChunks(); - - currentChunk->init(otherChunk->getStartTime(), otherChunk->getStartIndex() + CHUNK_SIZE); - } - - bool otherChunkFilled() const { - return otherChunk->numMeasurements() > 0; - } - - void swapChunks() { - Chunk_T *tmp = currentChunk; - currentChunk = otherChunk; - otherChunk = tmp; - } - - void saveChunkToFile(Chunk_T *chunk) const { - const uint32_t chunkNr = chunk->getStartIndex() / CHUNK_SIZE; - const auto fileName = chunkFileName(chunkNr, chunk->getStartTime()); - Serial.print("Writing session to file "); - Serial.println(fileName); - Writer writer(fileName); - chunk->serialize(writer.encoder()); - }; - - template< typename Encoder_T> - uint32_t serializeChunk(Encoder_T & encoder, uint32_t startIdx) const { - assert_msg( startIdx < currentChunk->getStartIndex() + currentChunk->numMeasurements(), - "serializeChunk: invalid startIdx" ); - - if( startIdx >= currentChunk->getStartIndex() ) { - const auto localStartIdx = startIdx - currentChunk->getStartIndex(); - const auto numElements = currentChunk->numMeasurements() - localStartIdx; - assert_msg(numElements <= currentChunk->numMeasurements(), "Internal problem in serializeChunk"); - encoder.sendArrayPartialContents( currentChunk->getDataPointer() + localStartIdx, numElements ); - return currentChunk->getStartIndex() + currentChunk->numMeasurements(); - } else if( startIdx >= otherChunk->getStartIndex() && otherChunkFilled() ) { - encoder.sendArrayPartialContents( otherChunk->getDataPointer(), otherChunk->numMeasurements() ); - assert_msg( otherChunk->numMeasurements(), CHUNK_SIZE ); - return otherChunk->getStartIndex() + otherChunk->numMeasurements(); - } else { - if( encoder.getSizeCountMode() ) { - encoder.template sendArrayPartialContents(nullptr, CHUNK_SIZE); - } else { - const uint32_t chunkNr = startIdx / CHUNK_SIZE; - const auto chunkFileNameStr = chunkFileName(chunkNr, currentChunk->getStartTime()); - Reader reader(chunkFileNameStr); - reader.seek(Chunk_T::valueOffset()); - - const uint32_t PART_SIZE = 32; -#ifndef ARDUINO - static_assert((PART_SIZE < CHUNK_SIZE) && (CHUNK_SIZE % PART_SIZE == 0)); -#endif - Measurement_T buffer[PART_SIZE]; - for(uint32_t i = 0; i < CHUNK_SIZE; i += PART_SIZE) - { - reader.readBytes((char*) buffer, sizeof(Measurement_T) * PART_SIZE); - encoder.template sendArrayPartialContents(buffer, PART_SIZE); - } - } - return startIdx + CHUNK_SIZE; - } - } - - static String chunkFileName(uint32_t chunkNr, uint32_t startTime) { - return("/dat/" + toString(startTime) + String("_") + toString(chunkNr)); - } - - Chunk_T chunks[2]; - Chunk_T *currentChunk; - Chunk_T *otherChunk; -}; diff --git a/firmware/lib/session/SessionManager.h b/firmware/lib/session/SessionManager.h index 51f9667..65ee357 100644 --- a/firmware/lib/session/SessionManager.h +++ b/firmware/lib/session/SessionManager.h @@ -5,6 +5,7 @@ #include #include "AutoStartStop.h" +#include "Logger.h" template class SessionManager @@ -32,7 +33,8 @@ public: void enableAutoStop(bool enable) { autoStop_.enable(enable); } bool autoStartEnabled() const { return autoStart_.enabled(); }; bool autoStopEnabled() const { return autoStop_.enabled(); } - + + unsigned long getNtpTime() { return timeClient_.getEpochTime(); } private: void onMeasurementTaken(MeasurementType measurement); @@ -69,10 +71,10 @@ void SessionManager::tare() { if (measuring_) stopMeasurements(); - Serial.println("Beginning tare"); + LOG_INFO("Beginning tare"); scale_.begin(scaleDoutPin_, scaleSckPin_, valueRightShift_); scale_.tare(CONFIG_TARE_AVG_COUNT); - Serial.println("Finished tare"); + LOG_INFO("Finished tare"); } template @@ -135,7 +137,7 @@ void SessionManager::iteration() else { const long skipped = (cycleDuration / CONFIG_MEASURE_DELAY); - Serial.printf("Measurements skipped: %ld, cycleDuration %ld\n", skipped, cycleDuration); + LOG_WARNING("Measurements skipped: %ld, cycleDuration %ld", skipped, cycleDuration); for (int i = 0; i < skipped; ++i) onMeasurementTaken(measurement); @@ -154,7 +156,7 @@ void SessionManager::onMeasurementTaken(MeasurementType measurement) bool autoStop = autoStop_.autoStop(measurement); if (autoStop) { - Serial.println("Auto stop"); + LOG_INFO("Auto stop"); stopMeasurements(); return; } @@ -162,7 +164,7 @@ void SessionManager::onMeasurementTaken(MeasurementType measurement) bool addPointSuccessful = session_.addPoint(measurement); if (!addPointSuccessful) { - Serial.println("Maximum time of session reached - stopping"); + LOG_INFO("Maximum time of session reached - stopping"); stopMeasurements(); return; } @@ -171,7 +173,7 @@ void SessionManager::onMeasurementTaken(MeasurementType measurement) { if (autoStart_.autoStart(measurement)) { - Serial.println("Auto start"); + LOG_INFO("Auto start"); startMeasurements(); return; } diff --git a/firmware/lib/session/SimpleMeasurementSession.h b/firmware/lib/session/SimpleMeasurementSession.h index c40261a..2d1984d 100644 --- a/firmware/lib/session/SimpleMeasurementSession.h +++ b/firmware/lib/session/SimpleMeasurementSession.h @@ -1,6 +1,8 @@ #include "Dtypes.h" #include "SessionChunk.h" #include "FilesystemAbstraction.h" +#include "Logger.h" + template class SimpleMeasurementSession @@ -37,7 +39,7 @@ public: if (success && (chunk->numMeasurements() % saveInterval_) == 0) saveToFileSystem(); if (!success) - Serial.println("Failed to add point"); + LOG_WARNING("Failed to add point"); return success; } @@ -79,9 +81,9 @@ private: // todo: check this! free doesn't mean that the file writing actually works ok // use error codes of write instead? anyway: test it! - Serial.printf("%ld saveToFileSystem start\n", millis()); + LOG_INFO("%ld saveToFileSystem start", millis()); deleteUntilBytesFree(CONFIG_SESSION_MAX_SIZE); - Serial.printf(" %ld after deleteUntilBytesFree()\n", millis()); + LOG_INFO(" %ld after deleteUntilBytesFree()", millis()); String filename = String(CONFIG_DATA_PATH) + "/" + String(chunk->getStartTime()); if (portablefs::exists(filename.c_str())) @@ -104,7 +106,7 @@ private: StreamingMsgPackEncoder encoder(&file); chunk->serialize(encoder); } - Serial.printf(" %ld saveToFileSystem done\n", millis()); + LOG_INFO(" %ld saveToFileSystem done", millis()); } void deleteUntilBytesFree(size_t requiredSpace) @@ -132,7 +134,7 @@ private: } assert(nextSessionToDelete > 0); assert(nextSessionToDelete < uint32_t(-1)); - Serial.printf("Removing old session %s to make space\n", filenameToDelete.c_str()); + LOG_INFO("Removing old session %s to make space", filenameToDelete.c_str()); portablefs::remove(filenameToDelete.c_str()); auto newFreeBytes = portablefs::totalBytes() - portablefs::usedBytes(); assert(newFreeBytes > freeBytes); diff --git a/firmware/lib/session/SpiffsStorage.h b/firmware/lib/session/SpiffsStorage.h deleted file mode 100644 index 0053c96..0000000 --- a/firmware/lib/session/SpiffsStorage.h +++ /dev/null @@ -1,90 +0,0 @@ -#pragma once -#include "StreamingMsgPackEncoder.h" -#include "FilesystemAbstraction.h" - -#ifdef USE_ESP32 - -struct WriterAdaptor -{ - File * f; - void write(const char * ptr, size_t size) { - f->write(reinterpret_cast(ptr), size); - } -}; - -class SpiffsStorageWriter { -public: - SpiffsStorageWriter(const String &fileName) : - f_(SPIFFS.open(fileName, "w")), - adaptor_{&f_}, - encoder_(&adaptor_), - fileName_(fileName) - { - bool success = f_; - Serial.println(success); - } - ~SpiffsStorageWriter() { - f_.close(); - Serial.println(fileName_); - Serial.println(SPIFFS.exists(fileName_)); - } - StreamingMsgPackEncoder &encoder() { return encoder_; } - -private: - File f_; - WriterAdaptor adaptor_; - StreamingMsgPackEncoder encoder_; - String fileName_; -}; - -#else - -class SpiffsStorageWriter { -public: - SpiffsStorageWriter(const String &fileName) : - f_(SPIFFS.open(fileName, "w")), - encoder_(&f_), - fileName_(fileName) - { - bool success = f_; - Serial.println(success); - } - ~SpiffsStorageWriter() { - f_.close(); - Serial.println(fileName_); - Serial.println(SPIFFS.exists(fileName_)); - } - StreamingMsgPackEncoder &encoder() { return encoder_; } - -private: - File f_; - StreamingMsgPackEncoder encoder_; - String fileName_; -}; - -#endif - - - - - -class SpiffsStorageReader -{ -public: - SpiffsStorageReader(const String &fileName) : - f_(SPIFFS.open(fileName, "r")) - {} - ~SpiffsStorageReader() { - f_.close(); - } - - uint32_t readBytes(char *buffer, size_t length) { - return f_.readBytes(buffer, length); - } - - bool seek(uint32_t pos) { - return f_.seek(pos); - } -private: - File f_; -}; \ No newline at end of file diff --git a/firmware/lib/session/StreamingMsgPackEncoder.h b/firmware/lib/session/StreamingMsgPackEncoder.h index 82f0343..ba39e40 100644 --- a/firmware/lib/session/StreamingMsgPackEncoder.h +++ b/firmware/lib/session/StreamingMsgPackEncoder.h @@ -60,7 +60,7 @@ public: { auto len = strlen_P(s); if( len >= 255 ) { - Serial.println(F("ERROR: StreamingMsgPackEncoder::string255 - string too long")); + LOG_WARNING("ERROR: StreamingMsgPackEncoder::string255 - string too long"); return; } byte castedLen = (byte)(len); diff --git a/firmware/lib/webdav/AsyncWebDav.h b/firmware/lib/webdav/AsyncWebDav.h deleted file mode 100644 index a45fbd4..0000000 --- a/firmware/lib/webdav/AsyncWebDav.h +++ /dev/null @@ -1,237 +0,0 @@ -#include -#include "FilesystemAbstraction.h" - - -#define FLASH_TEXT(name) const char *name - -namespace webdav_constants -{ - FLASH_TEXT(MULTISTATUS_START) = ""; - FLASH_TEXT(MULTISTATUS_END) = ""; - FLASH_TEXT(RESPONSE_START) = ""; - FLASH_TEXT(RESPONSE_END) = "\n"; - FLASH_TEXT(HREF_START) = ""; - FLASH_TEXT(HREF_END) = ""; - FLASH_TEXT(PROPSTAT_START) = ""; - FLASH_TEXT(PROPSTAT_END) = ""; - FLASH_TEXT(PROP_START) = ""; - FLASH_TEXT(PROP_END) = ""; - FLASH_TEXT(RESOURCETYPE_START) = ""; - FLASH_TEXT(RESOURCETYPE_END) = ""; - FLASH_TEXT(RESOURCE_COLLECTION) = ""; - FLASH_TEXT(HTTP_204_NO_CONTENT) = "HTTP/1.1 204 No Content"; - - FLASH_TEXT(CONTENTLEN_START) = ""; - FLASH_TEXT(CONTENTLEN_END) = ""; - FLASH_TEXT(CREATEDATE_START) = ""; - FLASH_TEXT(CREATEDATE_END) = ""; - FLASH_TEXT(MODDATE_START) = ""; - FLASH_TEXT(MODDATE_END) = ""; - FLASH_TEXT(STATUS_OK) = "HTTP/1.1 200 OK"; -} // namespace webdav_constants - -class WebdavFileListCallback -{ -public: - WebdavFileListCallback(const String &path) - : path_(path), headerWritten_(false), finished_(false) - { - dir_ = portablefs::openDir(path); - } - - size_t operator()(uint8_t *buffer, size_t maxLen, size_t index) - { - Serial.printf("%ld index %u\n", millis(), index); - - using namespace webdav_constants; - uint8_t *bufferStart = buffer; - - if (finished_) - return 0; - - if (!headerWritten_) - { - toBuffer(buffer, MULTISTATUS_START); - headerWritten_ = true; - } - - bool fileFound = false; - Serial.printf("%ld (0)\n", millis()); - while (dir_.next()) - { - if (isFirstFileOfTrainingGroup()) - { - fileFound = true; - break; - } - } - - if (fileFound) - { - //toBuffer(buffer, path_.c_str()); - toBuffer(buffer, RESPONSE_START); - toBuffer(buffer, HREF_START); - Serial.printf("%ld (1)\n", millis()); - const auto fileName = dir_.fileName(); - const auto fileNameWithoutDir = fileName.substring(fileName.lastIndexOf("/") + 1); - String fileBaseName = fileNameWithoutDir.substring(0, fileNameWithoutDir.indexOf('_')); - fileBaseName += ".st"; - Serial.printf("%ld (2)\n", millis()); - toBuffer(buffer, fileBaseName.c_str()); - toBuffer(buffer, HREF_END); - toBuffer(buffer, PROPSTAT_START); - toBuffer(buffer, PROP_START); - if (dir_.isDirectory()) - { - toBuffer(buffer, RESOURCETYPE_START); - toBuffer(buffer, RESOURCE_COLLECTION); - toBuffer(buffer, RESOURCETYPE_END); - } - else - { - toBuffer(buffer, CONTENTLEN_START); - String fileSizeStr(getFileSize(fileName)); - //toBuffer(buffer, fileSizeStr.c_str()); - toBuffer(buffer, "1"); - toBuffer(buffer, CONTENTLEN_END); - } - Serial.printf("%ld (3)\n", millis()); - - toBuffer(buffer, PROP_END); - toBuffer(buffer, STATUS_OK); - toBuffer(buffer, PROPSTAT_END); - toBuffer(buffer, webdav_constants::RESPONSE_END); - } - else - { - toBuffer(buffer, MULTISTATUS_END); - finished_ = true; - } - - - size_t bytesWritten = buffer - bufferStart; - assert_msg(bytesWritten < maxLen, "Written too much!"); - Serial.printf("%ld Bytes written %u\n", millis(), bytesWritten); - //Serial.print("Max bytes "); - //Serial.println(maxLen); - return bytesWritten; - } - -private: - bool isFirstFileOfTrainingGroup() - { - return !dir_.isDirectory() && dir_.fileName().endsWith("_0"); - } - - size_t getFileSize(const String &fileZero) - { - size_t size = 0; - auto fileBase = fileZero.substring(0, fileZero.indexOf('_')); - auto newDirInstance = portablefs::openDir(path_); - while (newDirInstance.next()) - if (newDirInstance.isFile() && newDirInstance.fileName().startsWith(fileBase)) - size += newDirInstance.fileSize(); - return size; - } - - void toBuffer(uint8_t *&buffer, const char *text) - { - auto len = strlen(text); - memcpy(buffer, text, len); - buffer += len; - } - - portablefs::Dir dir_; - const String path_; - bool headerWritten_; - bool finished_; -}; - -bool deleteMeasurementFiles(const String &stName, const String &folder) -{ - String baseName = folder + "/" + stName.substring(0, stName.indexOf(".")); - int counter = 0; - { - auto d = portablefs::openDir(folder); - while (d.next()) - if (d.isFile() && d.fileName().startsWith(baseName)) - ++counter; - } - if (counter == 0) - return false; - - for (int i = 0; i < counter; ++i) - { - const String pathToDelete = baseName + "_" + String(i); - if (!SPIFFS.remove(pathToDelete)) - return false; - } - return true; -} - -class SpiffsWebDavHandler : public AsyncWebHandler -{ -public: - SpiffsWebDavHandler(const String &prefix, const String &folder) - : prefix_(prefix), folder_(folder) - { - } - - virtual bool canHandle(AsyncWebServerRequest *request) override final - { - Serial.print("Can handle for url : "); - Serial.println(request->url()); - return request->url().startsWith(prefix_); - } - - virtual void handleRequest(AsyncWebServerRequest *request) override final - { - if (request->url() == prefix_ + "/" && (request->method() == HTTP_GET || request->method() == HTTP_PROPFIND)) - { - // send chunked response - it is too large to send in one go - auto response = request->beginChunkedResponse("application/xml", - WebdavFileListCallback(folder_)); - request->send(response); - } /* - else if(request->url() == prefix_ + "/" && request->method() == HTTP_GET) { - AsyncResponseStream * response = request->beginResponseStream("text/plain", 1460*10); - Dir dir = SPIFFS.openDir(folder_); - Serial.print("Opening folder "); - Serial.println(folder_); - while (dir.next()) { - Serial.print(" File: "); - Serial.println(dir.fileName()); - response->println(dir.fileName()); - } - request->send(response); - }*/ - else if (request->method() == HTTP_GET) - { - auto path = folder_ + request->url().substring(prefix_.length()); - if (SPIFFS.exists(path)) - request->send(SPIFFS, path, "application/x-msgpack"); - else - request->send(404, "text/plain", "Webdav: File not found"); - } - else if (request->method() == HTTP_DELETE) - { - auto stFileName = request->url().substring(prefix_.length() + 1); - Serial.print("HTTP_DELETE for "); - Serial.println(stFileName); - bool deleteSuccessful = deleteMeasurementFiles(stFileName, folder_); - if (deleteSuccessful) - request->send(204, "text/plain", "Success"); - else - request->send(404, "text/plain", "Webdav: File to delete not found"); - } - else - { - request->send(404, "text/plain", "Webdav: Invalid request"); - } - } - virtual bool isRequestHandlerTrivial() override final { return false; } - -private: - String prefix_; - String folder_; -}; diff --git a/firmware/lib/wifimanager/WifiManager.cpp b/firmware/lib/wifimanager/WifiManager.cpp index 4def673..78b1c07 100644 --- a/firmware/lib/wifimanager/WifiManager.cpp +++ b/firmware/lib/wifimanager/WifiManager.cpp @@ -1,4 +1,5 @@ #include "WifiManager.h" +#include "Logger.h" void WifiManager::begin(const String &hostname, const String & wifiStaModeName) { @@ -21,7 +22,7 @@ void WifiManager::startWifi() // station mode WiFi.mode(WIFI_STA); WiFi.begin(staSSID.c_str(), staPassword.c_str()); - Serial.printf("Starting WiFi station mode to ssid %s, hostname %s\n", staSSID.c_str(), hostname_.c_str()); + LOG_INFO("Starting WiFi station mode to ssid %s, hostname %s", staSSID.c_str(), hostname_.c_str()); WiFi.setHostname(hostname_.c_str()); int connectCounter = 0; bool successful = true; @@ -29,7 +30,7 @@ void WifiManager::startWifi() while (WiFi.status() != WL_CONNECTED) { - Serial.printf("WiFI connection problem %d\n", WiFi.status()); + LOG_INFO("WiFI connection problem %d", WiFi.status()); WiFi.begin(staSSID.c_str(), staPassword.c_str()); connectCounter += 1; @@ -51,13 +52,13 @@ void WifiManager::startWifi() if (apPassword.length() > 0) { - Serial.printf("Secured AP mode, name %s\n", wifiStaModeName_.c_str()); + LOG_INFO("Secured AP mode, name %s\n", wifiStaModeName_.c_str()); WiFi.softAP(wifiStaModeName_.c_str(), apPassword.c_str()); state_ = AP_SECURE; } else { - Serial.printf("Provisioning AP mode, name %s\n", wifiStaModeName_.c_str()); + LOG_INFO("Provisioning AP mode, name %s\n", wifiStaModeName_.c_str()); WiFi.softAP(wifiStaModeName_.c_str()); state_ = AP_PROVISIONING; } @@ -92,7 +93,7 @@ void WifiManager::iteration() if (state_ == STA && WiFi.status() != WL_CONNECTED) { startWifi(); - Serial.println("Connection lost - Restarting WIFI"); + LOG_WARNING("Connection lost - Restarting WIFI"); } } diff --git a/firmware/src/SessionAPI.h b/firmware/src/SessionAPI.h index ab32caf..0f9ef9b 100644 --- a/firmware/src/SessionAPI.h +++ b/firmware/src/SessionAPI.h @@ -86,11 +86,11 @@ bool SessionAPI::handleMessage(websockets::WebsocketsClient &client, MessageC switch (code) { case MessageCode::START_SESSION: - Serial.println("SessionAPI: starting measurement session"); + LOG_INFO("SessionAPI: starting measurement session"); this->sessionManager_.startMeasurements(); return true; case MessageCode::STOP_SESSION: - Serial.println("SessionAPI: stopping measurement session"); + LOG_INFO("SessionAPI: stopping measurement session"); this->sessionManager_.stopMeasurements(); return true; case MessageCode::TARE: diff --git a/firmware/src/WebsocketServer.h b/firmware/src/WebsocketServer.h index 3244d6a..f7e69ce 100644 --- a/firmware/src/WebsocketServer.h +++ b/firmware/src/WebsocketServer.h @@ -48,15 +48,14 @@ public: if (server_.poll()) { - Serial.printf("new websocket connection, storing at pos %d - occupancy: ", nextFreeClient_); + LOG_INFO("new websocket connection, storing at pos %d - occupancy: ", nextFreeClient_); clients_[nextFreeClient_] = server_.accept(); clients_[nextFreeClient_].onMessage(onMessage); this->onClientConnectImpl(clients_[nextFreeClient_]); nextFreeClient_ = (nextFreeClient_ + 1) % MAX_WEBSOCKET_CONNECTIONS; for (int i = 0; i < MAX_WEBSOCKET_CONNECTIONS; ++i) - Serial.print((clients_[i].available()) ? "x" : "o"); - Serial.print("\n"); + LOG_INFO((clients_[i].available()) ? "x" : "o"); } for (int i = 0; i < MAX_WEBSOCKET_CONNECTIONS; ++i) diff --git a/firmware/src/WifiAPI.cpp b/firmware/src/WifiAPI.cpp index 1f778d2..1f639e9 100644 --- a/firmware/src/WifiAPI.cpp +++ b/firmware/src/WifiAPI.cpp @@ -35,21 +35,21 @@ bool WifiAPI::handleMessage(websockets::WebsocketsClient &client, MessageCode co } if (json.containsKey("reset_to_provisioning") && json["reset_to_provisioning"].as()) { - Serial.println("wifi: reset_to_provisioning"); + LOG_INFO("wifi: reset_to_provisioning"); wifiManager_.resetToApProvisioning(); restartScheduled_ = true; return true; } else if (json.containsKey("ap_password")) { - Serial.println("wifi: ap_password"); + LOG_INFO("wifi: ap_password"); wifiManager_.setApCredentials(json["ap_password"].as()); restartScheduled_ = true; return true; } else if (json.containsKey("sta_ssid") && json.containsKey("sta_password")) { - Serial.println("wifi: sta_ssid"); + LOG_INFO("wifi: sta_ssid"); wifiManager_.setStaCredentials(json["sta_ssid"].as(), // json["sta_password"].as()); restartScheduled_ = true; diff --git a/firmware/src/WifiAPI.h b/firmware/src/WifiAPI.h index eafd30b..b7437b6 100644 --- a/firmware/src/WifiAPI.h +++ b/firmware/src/WifiAPI.h @@ -36,7 +36,7 @@ void WifiAPI::iteration(TServer &server) { if (restartScheduled_) { - Serial.print("Restart triggered by WifiAPI"); + LOG_INFO("Restart triggered by WifiAPI"); ESP.restart(); } reportScanResultIfAvailable(server); diff --git a/firmware/src/firmware_main.cpp b/firmware/src/firmware_main.cpp index 8147084..d68a0f7 100644 --- a/firmware/src/firmware_main.cpp +++ b/firmware/src/firmware_main.cpp @@ -14,19 +14,20 @@ #include "WifiManager.h" #include "MockScale.h" #include "Scale.h" -#include "MeasurementSession.h" #include "SessionManager.h" -#include "SpiffsStorage.h" #include "SimpleMeasurementSession.h" #include "EspHttp.h" #include "WebDAV.h" #include "UserDB.h" +#include "Logger.h" + // Api #include "WebsocketServer.h" #include "SessionAPI.h" #include "WifiAPI.h" + using Session_T = SimpleMeasurementSession; SessionManager sessionManager; @@ -55,20 +56,19 @@ String getIdSuffix() bool firmwareUpdate() { esp_http_client_config_t config; - Serial.println((char *)certificate_pem); memset(&config, 0, sizeof(esp_http_client_config_t)); config.url = UPDATE_URL; config.cert_pem = (char *)certificate_pem; - Serial.println("Starting firmware upgrade"); + LOG_INFO("Starting firmware upgrade"); esp_err_t ret = esp_https_ota(&config); if (ret == ESP_OK) { - Serial.println("Firmware upgrade successful - restarting"); + LOG_INFO("Firmware upgrade successful - restarting"); esp_restart(); } else { - Serial.println("Firmware upgrade failed"); + LOG_WARNING("Firmware upgrade failed"); return false; } return true; @@ -108,23 +108,23 @@ void httpSetup(SessionManager *sessionManager, WifiManager *wifiManage httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); httpd_resp_send(req, "Session started", -1); sessionManager->startMeasurements(); - Serial.println("Started session"); + LOG_INFO("RestAPI: Started session"); }; auto cbStopSession = [sessionManager](httpd_req_t *req) { httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); httpd_resp_send(req, "Session stopped", -1); sessionManager->stopMeasurements(); - Serial.println("Stopped session"); + LOG_INFO("RestAPI: Stopped session"); }; auto cbRestart = [](httpd_req_t *req) { - Serial.println("Restarted requested"); + LOG_INFO("RestAPI: Restarted requested"); ESP.restart(); }; auto cbTare = [sessionManager](httpd_req_t *req) { - Serial.println("Tare"); + LOG_INFO("RestAPI: Tare"); sessionManager->tare(); }; auto cbFirmwareUpdate = [](httpd_req_t *req) @@ -409,11 +409,11 @@ void httpSetup(SessionManager *sessionManager, WifiManager *wifiManage espHttpServer.on("/webdav/*?", HTTP_PROPFIND, webdav); espHttpServer.on("/webdav/*?", HTTP_DELETE, webdav); espHttpServer.on("/webdav/*?", HTTP_OPTIONS, webdav); - Serial.println("HTTP setup done"); + LOG_INFO("HTTP setup done"); } else { - Serial.println("HTTP setup with limited API in provisioning mode"); + LOG_INFO("HTTP setup with limited API in provisioning mode"); } } @@ -421,49 +421,47 @@ void mdnsSetup(const String &fullHostname) { if (!MDNS.begin(fullHostname.c_str())) { - Serial.println("Error setting up MDNS responder!"); + LOG_INFO("Error setting up MDNS responder!"); while (true) { delay(1000); } } - Serial.printf("mDNS started %s\n", fullHostname.c_str()); + LOG_INFO("mDNS started %s", fullHostname.c_str()); MDNS.addService("swimtracker", "tcp", 81); } void setup() { // Serial - Serial.begin(115200); - while (!Serial) - { - } + Logger::init(); // File system auto millisBeforeSpiffsInit = millis(); bool spiffsResult = SPIFFS.begin(true); if (!spiffsResult) - Serial.println("Failed to mount/format SPIFFS file system"); + LOG_WARNING("Failed to mount/format SPIFFS file system"); ESP_ERROR_CHECK(esp_event_loop_create_default()); auto spiffsSetupTimeSecs = (millis() - millisBeforeSpiffsInit) / 1000; userStorage.init(); - Serial.printf("Spiffs size: %d MB, setup time %d secs\n", portablefs::totalBytes() / 1024 / 1024, spiffsSetupTimeSecs); + LOG_INFO("Spiffs size: %d MB, setup time %ld secs", portablefs::totalBytes() / 1024 / 1024, spiffsSetupTimeSecs); // WiFi Preferences prefs; String uniqueName = "swimtracker" + getIdSuffix(); String configuredHostname = prefs.getString("hostname", CONFIG_HOSTNAME + getIdSuffix()); wifiManager.begin(configuredHostname, uniqueName); - Serial.print("Connected to WiFi. IP:"); - Serial.println(WiFi.localIP()); - Serial.printf("WIFI state: %s\n", wifiManager.stateStr()); + const auto ip = WiFi.localIP(); + LOG_INFO("Connected to WiFi. IP: %u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); + LOG_INFO("WIFI state: %s", wifiManager.stateStr()); mdnsSetup(configuredHostname); sessionManagerSetup(); + Logger::setNtpTime(sessionManager.getNtpTime()); sessionManager.tare(); // HTTP & Websocket server