/
ellersseer
/
MyCheat
Обзор
Документация
Войти
/
ellersseer
/
MyCheat
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
2
CI/CD
Аналитика
Безопасность
master
src/log_buffer.cpp
131 строка
3 KB
Dmitry Zhiltsov
feat(log): Добавить временные метки в логах #TSKMCHT-5
20 фев 2026, 22:19
20 фев 2026, 22:19
ba5c458
Код
Авторство
О чём код?
#include "log_buffer.h" #include <ESPAsyncWebServer.h> // Global instance LogCapture logCapture; void LogCapture::begin() { _mutex = xSemaphoreCreateMutex(); _ready = (_mutex != nullptr); } void LogCapture::setEventSource(AsyncEventSource* src) { _eventSource = src; } void LogCapture::_formatUptime(char* buf, size_t len) { unsigned long ms = millis(); unsigned long sec = ms / 1000; snprintf(buf, len, "[%02lu:%02lu:%02lu.%03lu] ", sec / 3600, (sec % 3600) / 60, sec % 60, ms % 1000); } // Write a single char to Serial, ring buffer, and line buffer. // Must be called with _mutex held (or in !_ready path). void LogCapture::_writeCharLocked(char c) { // Inject timestamp at start of each new line if (_atLineStart && c != '\n' && c != '\r') { _atLineStart = false; char ts[16]; _formatUptime(ts, sizeof(ts)); Serial.print(ts); for (int i = 0; ts[i]; i++) { _buffer[_head] = ts[i]; _head = (_head + 1) % LOG_BUFFER_SIZE; if (_count < LOG_BUFFER_SIZE) _count++; if (_linePos < sizeof(_lineBuffer) - 1) _lineBuffer[_linePos++] = ts[i]; } } Serial.write((uint8_t)c); _buffer[_head] = c; _head = (_head + 1) % LOG_BUFFER_SIZE; if (_count < LOG_BUFFER_SIZE) _count++; if (c == '\n') { _atLineStart = true; pushLine(); } else if (_linePos < sizeof(_lineBuffer) - 1) { _lineBuffer[_linePos++] = c; } } size_t LogCapture::write(uint8_t c) { if (!_ready) { // Before mutex is created — just Serial with timestamp if (_atLineStart && c != '\n' && c != '\r') { _atLineStart = false; char ts[16]; _formatUptime(ts, sizeof(ts)); Serial.print(ts); } Serial.write(c); if (c == '\n') _atLineStart = true; return 1; } if (xSemaphoreTake(_mutex, pdMS_TO_TICKS(5)) == pdTRUE) { _writeCharLocked(c); xSemaphoreGive(_mutex); } else { Serial.write(c); } return 1; } size_t LogCapture::write(const uint8_t* buf, size_t size) { if (!_ready || size == 0) { for (size_t i = 0; i < size; i++) write(buf[i]); return size; } if (xSemaphoreTake(_mutex, pdMS_TO_TICKS(5)) == pdTRUE) { for (size_t i = 0; i < size; i++) { _writeCharLocked((char)buf[i]); } xSemaphoreGive(_mutex); } else { Serial.write(buf, size); } return size; } void LogCapture::pushLine() { if (_linePos == 0) return; _lineBuffer[_linePos] = '\0'; if (_eventSource && _eventSource->count() > 0) { _eventSource->try_send(_lineBuffer, "log"); } _linePos = 0; } String LogCapture::getContent() const { if (!_ready || _count == 0) return String(); String result; result.reserve(_count); if (xSemaphoreTake(_mutex, pdMS_TO_TICKS(100)) == pdTRUE) { if (_count < LOG_BUFFER_SIZE) { // Buffer hasn't wrapped yet — data starts at 0 for (size_t i = 0; i < _count; i++) { result += _buffer[i]; } } else { // Buffer wrapped — oldest byte is at _head for (size_t i = 0; i < LOG_BUFFER_SIZE; i++) { result += _buffer[(_head + i) % LOG_BUFFER_SIZE]; } } xSemaphoreGive(_mutex); } return result; }