New logger & removed old unused files

This commit is contained in:
Martin Bauer 2021-08-10 22:47:47 +02:00
parent 28c85f749c
commit ce12c846f6
18 changed files with 179 additions and 534 deletions

View File

@ -3,19 +3,12 @@
#ifndef PLATFORM_NATIVE #ifndef PLATFORM_NATIVE
// ---------------------------------- Arduino ------------------------------------------------------------- // ---------------------------------- Arduino -------------------------------------------------------------
#include "Logger.h"
#include <Arduino.h> #include <Arduino.h>
inline void _assert(const char *expression, const char *message, const char *file, int line) inline void _assert(const char *expression, const char *message, const char *file, int line)
{ {
Serial.print("Assert "); LOG_WARNING("Assert %s:%d '%s' failed.\n%s", file, line, expression, message);
Serial.print(file);
Serial.print(" : ");
Serial.print(line);
Serial.print(" '");
Serial.print(expression);
Serial.println("' failed.");
Serial.println(message);
} }
template <typename T> template <typename T>

View File

@ -3,6 +3,7 @@
#include <esp_http_server.h> #include <esp_http_server.h>
#include <functional> #include <functional>
#include "Dtypes.h" #include "Dtypes.h"
#include "Logger.h"
constexpr int MAX_URI_HANDLERS = 25; constexpr int MAX_URI_HANDLERS = 25;
@ -53,7 +54,7 @@ public:
.handler = rawCallback, .handler = rawCallback,
.user_ctx = (void *)(&handlerCallbacks_[nextFreeHandler_])}; .user_ctx = (void *)(&handlerCallbacks_[nextFreeHandler_])};
if (httpd_register_uri_handler(server_, &uri_endpoint_cfg) != ESP_OK) 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_; ++nextFreeHandler_;
} }

View File

@ -1,5 +1,6 @@
#include "FilesystemAbstraction.h" #include "FilesystemAbstraction.h"
#include "WebDAV.h" #include "WebDAV.h"
#include "Logger.h"
namespace webdav_constants namespace webdav_constants
{ {
@ -93,7 +94,7 @@ size_t webdavFileListingSpiffs(char *buffer, size_t maxLength,
toBuffer(MULTISTATUS_END); toBuffer(MULTISTATUS_END);
if (incomplete) 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; return bytesWritten;
} }
@ -122,7 +123,7 @@ std::function<void(httpd_req_t *)> webdavHandler(const char *uriPrefix,
case HTTP_GET: case HTTP_GET:
{ {
auto filename = uriToFileName(uri, spiffsFolder); 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"); auto file = portablefs::open(filename.c_str(), "r");
if (file.available()) if (file.available())
{ {
@ -154,14 +155,14 @@ std::function<void(httpd_req_t *)> webdavHandler(const char *uriPrefix,
} }
case HTTP_OPTIONS: case HTTP_OPTIONS:
{ {
Serial.println("Options request"); LOG_INFO("Options request");
httpd_resp_set_status(req, "204 No Content"); httpd_resp_set_status(req, "204 No Content");
httpd_resp_set_hdr(req, "Access-Control-Allow-Methods", "GET, PROPFIND, DELETE, OPTIONS"); httpd_resp_set_hdr(req, "Access-Control-Allow-Methods", "GET, PROPFIND, DELETE, OPTIONS");
httpd_resp_send(req, "", 0); httpd_resp_send(req, "", 0);
break; break;
} }
default: 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); httpd_resp_send_404(req);
} }
}; };

View File

@ -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_);
}

View File

@ -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 <class... Args>
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>(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_;
};

View File

@ -7,8 +7,10 @@ class Scale
public: public:
bool measure(uint16_t &measurementOut) bool measure(uint16_t &measurementOut)
{ {
long value = hx711_.read_average(CONFIG_MEASUREMENT_AVG_COUNT) - offset_; long value = hx711_.read_average(CONFIG_MEASUREMENT_AVG_COUNT);
Serial.println(value); LOG_TRACE("rv %ld\n", value);
value -= offset_;
if (value < 0) if (value < 0)
measurementOut = (int16_t)(-(value >> valueRightShift_ )); measurementOut = (int16_t)(-(value >> valueRightShift_ ));
else else
@ -24,9 +26,9 @@ public:
void tare(uint32_t numMeasurementsToAverage = 50) void tare(uint32_t numMeasurementsToAverage = 50)
{ {
hx711_.read_average(3); auto v1 = hx711_.read_average(3);
offset_ = hx711_.read_average(numMeasurementsToAverage); 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_; } const long &offset() const { return offset_; }

View File

@ -1,139 +0,0 @@
#include "SessionChunk.h"
template<typename Measurement_T, typename Reader, typename Writer, uint32_t CHUNK_SIZE>
class MeasurementSession {
public:
typedef SessionChunk<Measurement_T, CHUNK_SIZE> 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<typename Encoder_T>
void serialize(Encoder_T & encoder, uint32_t startIdx) const
{
const uint32_t lastIdx = currentChunk->getStartIndex() + currentChunk->numMeasurements();
if( lastIdx <= startIdx) {
encoder.template sendArray<Measurement_T>(nullptr, 0);
return;
}
Chunk_T::sendHeader(encoder, currentChunk->getStartTime(), startIdx);
encoder.template sendArrayHeader<Measurement_T>(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<Measurement_T>(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<Measurement_T>(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;
};

View File

@ -5,6 +5,7 @@
#include <NTPClient.h> #include <NTPClient.h>
#include "AutoStartStop.h" #include "AutoStartStop.h"
#include "Logger.h"
template <typename SessionT> template <typename SessionT>
class SessionManager class SessionManager
@ -32,7 +33,8 @@ public:
void enableAutoStop(bool enable) { autoStop_.enable(enable); } void enableAutoStop(bool enable) { autoStop_.enable(enable); }
bool autoStartEnabled() const { return autoStart_.enabled(); }; bool autoStartEnabled() const { return autoStart_.enabled(); };
bool autoStopEnabled() const { return autoStop_.enabled(); } bool autoStopEnabled() const { return autoStop_.enabled(); }
unsigned long getNtpTime() { return timeClient_.getEpochTime(); }
private: private:
void onMeasurementTaken(MeasurementType measurement); void onMeasurementTaken(MeasurementType measurement);
@ -69,10 +71,10 @@ void SessionManager<SessionT>::tare()
{ {
if (measuring_) if (measuring_)
stopMeasurements(); stopMeasurements();
Serial.println("Beginning tare"); LOG_INFO("Beginning tare");
scale_.begin(scaleDoutPin_, scaleSckPin_, valueRightShift_); scale_.begin(scaleDoutPin_, scaleSckPin_, valueRightShift_);
scale_.tare(CONFIG_TARE_AVG_COUNT); scale_.tare(CONFIG_TARE_AVG_COUNT);
Serial.println("Finished tare"); LOG_INFO("Finished tare");
} }
template <typename SessionT> template <typename SessionT>
@ -135,7 +137,7 @@ void SessionManager<SessionT>::iteration()
else else
{ {
const long skipped = (cycleDuration / CONFIG_MEASURE_DELAY); 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) for (int i = 0; i < skipped; ++i)
onMeasurementTaken(measurement); onMeasurementTaken(measurement);
@ -154,7 +156,7 @@ void SessionManager<SessionT>::onMeasurementTaken(MeasurementType measurement)
bool autoStop = autoStop_.autoStop(measurement); bool autoStop = autoStop_.autoStop(measurement);
if (autoStop) if (autoStop)
{ {
Serial.println("Auto stop"); LOG_INFO("Auto stop");
stopMeasurements(); stopMeasurements();
return; return;
} }
@ -162,7 +164,7 @@ void SessionManager<SessionT>::onMeasurementTaken(MeasurementType measurement)
bool addPointSuccessful = session_.addPoint(measurement); bool addPointSuccessful = session_.addPoint(measurement);
if (!addPointSuccessful) if (!addPointSuccessful)
{ {
Serial.println("Maximum time of session reached - stopping"); LOG_INFO("Maximum time of session reached - stopping");
stopMeasurements(); stopMeasurements();
return; return;
} }
@ -171,7 +173,7 @@ void SessionManager<SessionT>::onMeasurementTaken(MeasurementType measurement)
{ {
if (autoStart_.autoStart(measurement)) if (autoStart_.autoStart(measurement))
{ {
Serial.println("Auto start"); LOG_INFO("Auto start");
startMeasurements(); startMeasurements();
return; return;
} }

View File

@ -1,6 +1,8 @@
#include "Dtypes.h" #include "Dtypes.h"
#include "SessionChunk.h" #include "SessionChunk.h"
#include "FilesystemAbstraction.h" #include "FilesystemAbstraction.h"
#include "Logger.h"
template <typename Measurement_T, uint32_t MAX_SIZE> template <typename Measurement_T, uint32_t MAX_SIZE>
class SimpleMeasurementSession class SimpleMeasurementSession
@ -37,7 +39,7 @@ public:
if (success && (chunk->numMeasurements() % saveInterval_) == 0) if (success && (chunk->numMeasurements() % saveInterval_) == 0)
saveToFileSystem(); saveToFileSystem();
if (!success) if (!success)
Serial.println("Failed to add point"); LOG_WARNING("Failed to add point");
return success; return success;
} }
@ -79,9 +81,9 @@ private:
// todo: check this! free doesn't mean that the file writing actually works ok // todo: check this! free doesn't mean that the file writing actually works ok
// use error codes of write instead? anyway: test it! // 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); 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()); String filename = String(CONFIG_DATA_PATH) + "/" + String(chunk->getStartTime());
if (portablefs::exists(filename.c_str())) if (portablefs::exists(filename.c_str()))
@ -104,7 +106,7 @@ private:
StreamingMsgPackEncoder<portablefs::File> encoder(&file); StreamingMsgPackEncoder<portablefs::File> encoder(&file);
chunk->serialize(encoder); chunk->serialize(encoder);
} }
Serial.printf(" %ld saveToFileSystem done\n", millis()); LOG_INFO(" %ld saveToFileSystem done", millis());
} }
void deleteUntilBytesFree(size_t requiredSpace) void deleteUntilBytesFree(size_t requiredSpace)
@ -132,7 +134,7 @@ private:
} }
assert(nextSessionToDelete > 0); assert(nextSessionToDelete > 0);
assert(nextSessionToDelete < uint32_t(-1)); 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()); portablefs::remove(filenameToDelete.c_str());
auto newFreeBytes = portablefs::totalBytes() - portablefs::usedBytes(); auto newFreeBytes = portablefs::totalBytes() - portablefs::usedBytes();
assert(newFreeBytes > freeBytes); assert(newFreeBytes > freeBytes);

View File

@ -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<const uint8_t *>(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<WriterAdaptor> &encoder() { return encoder_; }
private:
File f_;
WriterAdaptor adaptor_;
StreamingMsgPackEncoder<WriterAdaptor> 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<File> &encoder() { return encoder_; }
private:
File f_;
StreamingMsgPackEncoder<File> 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_;
};

View File

@ -60,7 +60,7 @@ public:
{ {
auto len = strlen_P(s); auto len = strlen_P(s);
if( len >= 255 ) { if( len >= 255 ) {
Serial.println(F("ERROR: StreamingMsgPackEncoder::string255 - string too long")); LOG_WARNING("ERROR: StreamingMsgPackEncoder::string255 - string too long");
return; return;
} }
byte castedLen = (byte)(len); byte castedLen = (byte)(len);

View File

@ -1,237 +0,0 @@
#include <ESPAsyncWebServer.h>
#include "FilesystemAbstraction.h"
#define FLASH_TEXT(name) const char *name
namespace webdav_constants
{
FLASH_TEXT(MULTISTATUS_START) = "<?xml version=\"1.0\" ?><D:multistatus xmlns:D=\"DAV:\">";
FLASH_TEXT(MULTISTATUS_END) = "</D:multistatus>";
FLASH_TEXT(RESPONSE_START) = "<D:response>";
FLASH_TEXT(RESPONSE_END) = "</D:response>\n";
FLASH_TEXT(HREF_START) = "<D:href>";
FLASH_TEXT(HREF_END) = "</D:href>";
FLASH_TEXT(PROPSTAT_START) = "<D:propstat>";
FLASH_TEXT(PROPSTAT_END) = "</D:propstat>";
FLASH_TEXT(PROP_START) = "<D:prop>";
FLASH_TEXT(PROP_END) = "</D:prop>";
FLASH_TEXT(RESOURCETYPE_START) = "<D:resourcetype>";
FLASH_TEXT(RESOURCETYPE_END) = "</D:resourcetype>";
FLASH_TEXT(RESOURCE_COLLECTION) = "<D:collection/>";
FLASH_TEXT(HTTP_204_NO_CONTENT) = "HTTP/1.1 204 No Content";
FLASH_TEXT(CONTENTLEN_START) = "<D:getcontentlength>";
FLASH_TEXT(CONTENTLEN_END) = "</D:getcontentlength>";
FLASH_TEXT(CREATEDATE_START) = "<D:creationdate>";
FLASH_TEXT(CREATEDATE_END) = "</D:creationdate>";
FLASH_TEXT(MODDATE_START) = "<D:getlastmodified>";
FLASH_TEXT(MODDATE_END) = "</D:getlastmodified>";
FLASH_TEXT(STATUS_OK) = "<D:status>HTTP/1.1 200 OK</D:status>";
} // 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_;
};

View File

@ -1,4 +1,5 @@
#include "WifiManager.h" #include "WifiManager.h"
#include "Logger.h"
void WifiManager::begin(const String &hostname, const String & wifiStaModeName) void WifiManager::begin(const String &hostname, const String & wifiStaModeName)
{ {
@ -21,7 +22,7 @@ void WifiManager::startWifi()
// station mode // station mode
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFi.begin(staSSID.c_str(), staPassword.c_str()); 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()); WiFi.setHostname(hostname_.c_str());
int connectCounter = 0; int connectCounter = 0;
bool successful = true; bool successful = true;
@ -29,7 +30,7 @@ void WifiManager::startWifi()
while (WiFi.status() != WL_CONNECTED) 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()); WiFi.begin(staSSID.c_str(), staPassword.c_str());
connectCounter += 1; connectCounter += 1;
@ -51,13 +52,13 @@ void WifiManager::startWifi()
if (apPassword.length() > 0) 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()); WiFi.softAP(wifiStaModeName_.c_str(), apPassword.c_str());
state_ = AP_SECURE; state_ = AP_SECURE;
} }
else 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()); WiFi.softAP(wifiStaModeName_.c_str());
state_ = AP_PROVISIONING; state_ = AP_PROVISIONING;
} }
@ -92,7 +93,7 @@ void WifiManager::iteration()
if (state_ == STA && WiFi.status() != WL_CONNECTED) if (state_ == STA && WiFi.status() != WL_CONNECTED)
{ {
startWifi(); startWifi();
Serial.println("Connection lost - Restarting WIFI"); LOG_WARNING("Connection lost - Restarting WIFI");
} }
} }

View File

@ -86,11 +86,11 @@ bool SessionAPI<T>::handleMessage(websockets::WebsocketsClient &client, MessageC
switch (code) switch (code)
{ {
case MessageCode::START_SESSION: case MessageCode::START_SESSION:
Serial.println("SessionAPI: starting measurement session"); LOG_INFO("SessionAPI: starting measurement session");
this->sessionManager_.startMeasurements(); this->sessionManager_.startMeasurements();
return true; return true;
case MessageCode::STOP_SESSION: case MessageCode::STOP_SESSION:
Serial.println("SessionAPI: stopping measurement session"); LOG_INFO("SessionAPI: stopping measurement session");
this->sessionManager_.stopMeasurements(); this->sessionManager_.stopMeasurements();
return true; return true;
case MessageCode::TARE: case MessageCode::TARE:

View File

@ -48,15 +48,14 @@ public:
if (server_.poll()) 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_] = server_.accept();
clients_[nextFreeClient_].onMessage(onMessage); clients_[nextFreeClient_].onMessage(onMessage);
this->onClientConnectImpl(clients_[nextFreeClient_]); this->onClientConnectImpl(clients_[nextFreeClient_]);
nextFreeClient_ = (nextFreeClient_ + 1) % MAX_WEBSOCKET_CONNECTIONS; nextFreeClient_ = (nextFreeClient_ + 1) % MAX_WEBSOCKET_CONNECTIONS;
for (int i = 0; i < MAX_WEBSOCKET_CONNECTIONS; ++i) for (int i = 0; i < MAX_WEBSOCKET_CONNECTIONS; ++i)
Serial.print((clients_[i].available()) ? "x" : "o"); LOG_INFO((clients_[i].available()) ? "x" : "o");
Serial.print("\n");
} }
for (int i = 0; i < MAX_WEBSOCKET_CONNECTIONS; ++i) for (int i = 0; i < MAX_WEBSOCKET_CONNECTIONS; ++i)

View File

@ -35,21 +35,21 @@ bool WifiAPI::handleMessage(websockets::WebsocketsClient &client, MessageCode co
} }
if (json.containsKey("reset_to_provisioning") && json["reset_to_provisioning"].as<bool>()) if (json.containsKey("reset_to_provisioning") && json["reset_to_provisioning"].as<bool>())
{ {
Serial.println("wifi: reset_to_provisioning"); LOG_INFO("wifi: reset_to_provisioning");
wifiManager_.resetToApProvisioning(); wifiManager_.resetToApProvisioning();
restartScheduled_ = true; restartScheduled_ = true;
return true; return true;
} }
else if (json.containsKey("ap_password")) else if (json.containsKey("ap_password"))
{ {
Serial.println("wifi: ap_password"); LOG_INFO("wifi: ap_password");
wifiManager_.setApCredentials(json["ap_password"].as<const char *>()); wifiManager_.setApCredentials(json["ap_password"].as<const char *>());
restartScheduled_ = true; restartScheduled_ = true;
return true; return true;
} }
else if (json.containsKey("sta_ssid") && json.containsKey("sta_password")) 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<const char *>(), // wifiManager_.setStaCredentials(json["sta_ssid"].as<const char *>(), //
json["sta_password"].as<const char *>()); json["sta_password"].as<const char *>());
restartScheduled_ = true; restartScheduled_ = true;

View File

@ -36,7 +36,7 @@ void WifiAPI::iteration(TServer &server)
{ {
if (restartScheduled_) if (restartScheduled_)
{ {
Serial.print("Restart triggered by WifiAPI"); LOG_INFO("Restart triggered by WifiAPI");
ESP.restart(); ESP.restart();
} }
reportScanResultIfAvailable(server); reportScanResultIfAvailable(server);

View File

@ -14,19 +14,20 @@
#include "WifiManager.h" #include "WifiManager.h"
#include "MockScale.h" #include "MockScale.h"
#include "Scale.h" #include "Scale.h"
#include "MeasurementSession.h"
#include "SessionManager.h" #include "SessionManager.h"
#include "SpiffsStorage.h"
#include "SimpleMeasurementSession.h" #include "SimpleMeasurementSession.h"
#include "EspHttp.h" #include "EspHttp.h"
#include "WebDAV.h" #include "WebDAV.h"
#include "UserDB.h" #include "UserDB.h"
#include "Logger.h"
// Api // Api
#include "WebsocketServer.h" #include "WebsocketServer.h"
#include "SessionAPI.h" #include "SessionAPI.h"
#include "WifiAPI.h" #include "WifiAPI.h"
using Session_T = SimpleMeasurementSession<MeasurementT, CONFIG_SESSION_MAX_SIZE>; using Session_T = SimpleMeasurementSession<MeasurementT, CONFIG_SESSION_MAX_SIZE>;
SessionManager<Session_T> sessionManager; SessionManager<Session_T> sessionManager;
@ -55,20 +56,19 @@ String getIdSuffix()
bool firmwareUpdate() bool firmwareUpdate()
{ {
esp_http_client_config_t config; esp_http_client_config_t config;
Serial.println((char *)certificate_pem);
memset(&config, 0, sizeof(esp_http_client_config_t)); memset(&config, 0, sizeof(esp_http_client_config_t));
config.url = UPDATE_URL; config.url = UPDATE_URL;
config.cert_pem = (char *)certificate_pem; config.cert_pem = (char *)certificate_pem;
Serial.println("Starting firmware upgrade"); LOG_INFO("Starting firmware upgrade");
esp_err_t ret = esp_https_ota(&config); esp_err_t ret = esp_https_ota(&config);
if (ret == ESP_OK) if (ret == ESP_OK)
{ {
Serial.println("Firmware upgrade successful - restarting"); LOG_INFO("Firmware upgrade successful - restarting");
esp_restart(); esp_restart();
} }
else else
{ {
Serial.println("Firmware upgrade failed"); LOG_WARNING("Firmware upgrade failed");
return false; return false;
} }
return true; return true;
@ -108,23 +108,23 @@ void httpSetup(SessionManager<SessionT> *sessionManager, WifiManager *wifiManage
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
httpd_resp_send(req, "Session started", -1); httpd_resp_send(req, "Session started", -1);
sessionManager->startMeasurements(); sessionManager->startMeasurements();
Serial.println("Started session"); LOG_INFO("RestAPI: Started session");
}; };
auto cbStopSession = [sessionManager](httpd_req_t *req) auto cbStopSession = [sessionManager](httpd_req_t *req)
{ {
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
httpd_resp_send(req, "Session stopped", -1); httpd_resp_send(req, "Session stopped", -1);
sessionManager->stopMeasurements(); sessionManager->stopMeasurements();
Serial.println("Stopped session"); LOG_INFO("RestAPI: Stopped session");
}; };
auto cbRestart = [](httpd_req_t *req) auto cbRestart = [](httpd_req_t *req)
{ {
Serial.println("Restarted requested"); LOG_INFO("RestAPI: Restarted requested");
ESP.restart(); ESP.restart();
}; };
auto cbTare = [sessionManager](httpd_req_t *req) auto cbTare = [sessionManager](httpd_req_t *req)
{ {
Serial.println("Tare"); LOG_INFO("RestAPI: Tare");
sessionManager->tare(); sessionManager->tare();
}; };
auto cbFirmwareUpdate = [](httpd_req_t *req) auto cbFirmwareUpdate = [](httpd_req_t *req)
@ -409,11 +409,11 @@ void httpSetup(SessionManager<SessionT> *sessionManager, WifiManager *wifiManage
espHttpServer.on("/webdav/*?", HTTP_PROPFIND, webdav); espHttpServer.on("/webdav/*?", HTTP_PROPFIND, webdav);
espHttpServer.on("/webdav/*?", HTTP_DELETE, webdav); espHttpServer.on("/webdav/*?", HTTP_DELETE, webdav);
espHttpServer.on("/webdav/*?", HTTP_OPTIONS, webdav); espHttpServer.on("/webdav/*?", HTTP_OPTIONS, webdav);
Serial.println("HTTP setup done"); LOG_INFO("HTTP setup done");
} }
else 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())) if (!MDNS.begin(fullHostname.c_str()))
{ {
Serial.println("Error setting up MDNS responder!"); LOG_INFO("Error setting up MDNS responder!");
while (true) while (true)
{ {
delay(1000); delay(1000);
} }
} }
Serial.printf("mDNS started %s\n", fullHostname.c_str()); LOG_INFO("mDNS started %s", fullHostname.c_str());
MDNS.addService("swimtracker", "tcp", 81); MDNS.addService("swimtracker", "tcp", 81);
} }
void setup() void setup()
{ {
// Serial // Serial
Serial.begin(115200); Logger::init();
while (!Serial)
{
}
// File system // File system
auto millisBeforeSpiffsInit = millis(); auto millisBeforeSpiffsInit = millis();
bool spiffsResult = SPIFFS.begin(true); bool spiffsResult = SPIFFS.begin(true);
if (!spiffsResult) 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()); ESP_ERROR_CHECK(esp_event_loop_create_default());
auto spiffsSetupTimeSecs = (millis() - millisBeforeSpiffsInit) / 1000; auto spiffsSetupTimeSecs = (millis() - millisBeforeSpiffsInit) / 1000;
userStorage.init(); 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 // WiFi
Preferences prefs; Preferences prefs;
String uniqueName = "swimtracker" + getIdSuffix(); String uniqueName = "swimtracker" + getIdSuffix();
String configuredHostname = prefs.getString("hostname", CONFIG_HOSTNAME + getIdSuffix()); String configuredHostname = prefs.getString("hostname", CONFIG_HOSTNAME + getIdSuffix());
wifiManager.begin(configuredHostname, uniqueName); wifiManager.begin(configuredHostname, uniqueName);
Serial.print("Connected to WiFi. IP:"); const auto ip = WiFi.localIP();
Serial.println(WiFi.localIP()); LOG_INFO("Connected to WiFi. IP: %u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
Serial.printf("WIFI state: %s\n", wifiManager.stateStr()); LOG_INFO("WIFI state: %s", wifiManager.stateStr());
mdnsSetup(configuredHostname); mdnsSetup(configuredHostname);
sessionManagerSetup(); sessionManagerSetup();
Logger::setNtpTime(sessionManager.getNtpTime());
sessionManager.tare(); sessionManager.tare();
// HTTP & Websocket server // HTTP & Websocket server