#include "EggDuino.h" namespace { constexpr size_t kLogCapacity = 80; constexpr size_t kLogLineLength = 160; constexpr size_t kIncomingLogCapacity = 128; constexpr size_t kIncomingLogLineLength = SERIALCOMMAND_BUFFER + 24; char g_logLines[kLogCapacity][kLogLineLength]; uint32_t g_logSeq[kLogCapacity]; size_t g_logWritePos = 0; uint32_t g_nextLogSeq = 1; char g_incomingLogLines[kIncomingLogCapacity][kIncomingLogLineLength]; uint32_t g_incomingLogSeq[kIncomingLogCapacity]; size_t g_incomingLogWritePos = 0; uint32_t g_nextIncomingLogSeq = 1; void appendJsonEscaped(String &out, const char *text) { out += "\""; for (size_t i = 0; text[i] != '\0'; ++i) { const char c = text[i]; switch (c) { case '\\': out += "\\\\"; break; case '"': out += "\\\""; break; case '\n': out += "\\n"; break; case '\r': out += "\\r"; break; case '\t': out += "\\t"; break; default: if (static_cast(c) < 0x20) { out += '?'; } else { out += c; } break; } } out += "\""; } const char *transportLabel(ProtocolTransport transport) { switch (transport) { case PROTOCOL_TRANSPORT_BLE: return "BLE"; case PROTOCOL_TRANSPORT_WIFI: return "WIFI"; case PROTOCOL_TRANSPORT_SERIAL: default: return "SERIAL"; } } } // namespace void Log(const String &message) { snprintf( g_logLines[g_logWritePos], kLogLineLength, "[%010lu] %s", static_cast(millis()), message.c_str() ); g_logSeq[g_logWritePos] = g_nextLogSeq++; g_logWritePos = (g_logWritePos + 1) % kLogCapacity; } void Log(const char *message) { Log(String(message)); } String buildLogsJson(uint32_t sinceSeq) { String output; output.reserve(2048); output += "{\"logs\":["; uint32_t lastSeq = sinceSeq; bool first = true; for (size_t i = 0; i < kLogCapacity; ++i) { const size_t idx = (g_logWritePos + i) % kLogCapacity; const uint32_t seq = g_logSeq[idx]; if (seq == 0 || seq <= sinceSeq) { continue; } if (!first) { output += ","; } first = false; output += "{\"seq\":"; output += String(seq); output += ",\"text\":"; appendJsonEscaped(output, g_logLines[idx]); output += "}"; lastSeq = seq; } output += "],\"lastSeq\":"; output += String(lastSeq); output += "}"; return output; } void captureIncomingPrintLine(const char *line, ProtocolTransport transport) { if ((line == NULL) || (line[0] == '\0')) { return; } snprintf( g_incomingLogLines[g_incomingLogWritePos], kIncomingLogLineLength, "[%010lu] %s %s", static_cast(millis()), transportLabel(transport), line ); g_incomingLogSeq[g_incomingLogWritePos] = g_nextIncomingLogSeq++; g_incomingLogWritePos = (g_incomingLogWritePos + 1) % kIncomingLogCapacity; } String buildIncomingPrintLogText() { String output; output.reserve(4096); for (size_t i = 0; i < kIncomingLogCapacity; ++i) { const size_t idx = (g_incomingLogWritePos + i) % kIncomingLogCapacity; if (g_incomingLogSeq[idx] == 0) { continue; } output += g_incomingLogLines[idx]; output += "\n"; } return output; } void clearIncomingPrintLog() { for (size_t i = 0; i < kIncomingLogCapacity; ++i) { g_incomingLogSeq[i] = 0; g_incomingLogLines[i][0] = '\0'; } g_incomingLogWritePos = 0; g_nextIncomingLogSeq = 1; }