#include "QmcServices.h" #include #include #include #ifndef BOARD_ID #define BOARD_ID "NODE" #endif #ifndef NODE_LABEL #define NODE_LABEL BOARD_ID #endif #ifndef LOG_AP_IP_OCTET #define LOG_AP_IP_OCTET 25 #endif namespace { tbeam::TBeamClock clockService(Wire1); tbeam::TBeamStorage storageService(::Serial); tbeam::TBeamWeb webService(::Serial); bool servicesStarted = false; uint32_t lastFlushMs = 0; uint32_t lastClockUpdateMs = 0; char logPath[128] = {}; void openRunLog() { if (!storageService.ready()) { return; } char runId[64] = {}; tbeam::DateTime rtc; int64_t epoch = 0; if (clockService.readValidRtc(rtc, &epoch)) { tbeam::TBeamClock::makeRunId(rtc, BOARD_ID, runId, sizeof(runId)); } else { snprintf(runId, sizeof(runId), "%s_%lu", BOARD_ID, static_cast(millis() / 1000)); } snprintf(logPath, sizeof(logPath), "/logs/qmc63xx/%s.log", runId); if (!storageService.openLog(logPath)) { ::Serial.printf("[qmc-services] log open failed: %s\n", storageService.lastError()); logPath[0] = '\0'; return; } storageService.println("# test: qmc63xx"); storageService.print("# board_id: "); storageService.println(BOARD_ID); storageService.print("# node_label: "); storageService.println(NODE_LABEL); storageService.print("# log_path: "); storageService.println(logPath); if (clockService.valid()) { char iso[32] = {}; tbeam::TBeamClock::formatIsoUtc(clockService.lastRtc(), iso, sizeof(iso)); storageService.print("# rtc_utc: "); storageService.println(iso); } storageService.println("# serial_tee: enabled"); storageService.flush(); } } // namespace QmcSerialTee QmcSerial; void QmcSerialTee::begin(unsigned long baud) { ::Serial.begin(baud); } size_t QmcSerialTee::write(uint8_t value) { const size_t serialWritten = ::Serial.write(value); if (servicesStarted && storageService.isLogOpen()) { storageService.write(&value, 1); } return serialWritten; } size_t QmcSerialTee::write(const uint8_t* buffer, size_t size) { const size_t serialWritten = ::Serial.write(buffer, size); if (servicesStarted && storageService.isLogOpen()) { storageService.write(buffer, size); } return serialWritten; } void QmcSerialTee::flush() { ::Serial.flush(); if (servicesStarted && storageService.isLogOpen()) { storageService.flush(); } } void qmcServicesBegin() { if (servicesStarted) { return; } tbeam::ClockConfig clockConfig; clockConfig.beginWire = false; clockService.begin(clockConfig); clockService.update(); tbeam::StorageConfig storageConfig; storageConfig.logDir = "/logs/qmc63xx"; storageConfig.enablePinDumps = false; storageService.begin(storageConfig); openRunLog(); tbeam::WebConfig webConfig; webConfig.ssidPrefix = "GPSQA"; webConfig.boardId = BOARD_ID; webConfig.password = nullptr; webConfig.ipOctet = LOG_AP_IP_OCTET; webConfig.enableDelete = true; webService.begin(storageService, webConfig); servicesStarted = true; ::Serial.printf("[qmc-services] board=%s label=%s\n", BOARD_ID, NODE_LABEL); if (clockService.valid()) { char iso[32] = {}; tbeam::TBeamClock::formatIsoUtc(clockService.lastRtc(), iso, sizeof(iso)); ::Serial.printf("[qmc-services] rtc=%s\n", iso); } else { ::Serial.printf("[qmc-services] rtc invalid: %s\n", clockService.lastError()); } ::Serial.printf("[qmc-services] log=%s\n", logPath[0] ? logPath : "(not open)"); if (webService.ready()) { ::Serial.printf("[qmc-services] web=http://%s/ ssid=%s\n", webService.ip().toString().c_str(), webService.ssid()); } else { ::Serial.printf("[qmc-services] web unavailable: %s\n", webService.lastError()); } } void qmcServicesUpdate() { if (!servicesStarted) { return; } const uint32_t now = millis(); storageService.update(); webService.update(); if (now - lastClockUpdateMs >= 1000) { lastClockUpdateMs = now; clockService.update(); } if (now - lastFlushMs >= 2000) { lastFlushMs = now; storageService.flush(); } } const char* qmcServicesLogPath() { return logPath; }