/* * MTG RFID Companion - In-memory Serial Log Ring Buffer */ #include "serial_log.h" #include #include #include #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #define LOG_BUFFER_SIZE (16 * 1024) static vprintf_like_t s_prev_vprintf = NULL; static char s_ring_buffer[LOG_BUFFER_SIZE]; static uint32_t s_write_idx = 0; static uint32_t s_total_bytes = 0; static portMUX_TYPE s_log_mux = portMUX_INITIALIZER_UNLOCKED; static int serial_log_vprintf(const char *fmt, va_list args) { int ret = 0; /* Maintain original console/UART output */ if (s_prev_vprintf != NULL) { va_list copy1; va_copy(copy1, args); ret = s_prev_vprintf(fmt, copy1); va_end(copy1); } else { va_list copy1; va_copy(copy1, args); ret = vprintf(fmt, copy1); va_end(copy1); } /* Format message into local buffer */ char line_buf[512]; va_list copy2; va_copy(copy2, args); int written = vsnprintf(line_buf, sizeof(line_buf), fmt, copy2); va_end(copy2); if (written > 0) { size_t len = (size_t)written; if (len >= sizeof(line_buf)) { len = sizeof(line_buf) - 1; } portENTER_CRITICAL(&s_log_mux); size_t space_to_end = LOG_BUFFER_SIZE - s_write_idx; if (len <= space_to_end) { memcpy(&s_ring_buffer[s_write_idx], line_buf, len); s_write_idx = (s_write_idx + len) % LOG_BUFFER_SIZE; } else { memcpy(&s_ring_buffer[s_write_idx], line_buf, space_to_end); memcpy(&s_ring_buffer[0], line_buf + space_to_end, len - space_to_end); s_write_idx = (uint32_t)(len - space_to_end); } s_total_bytes += (uint32_t)len; portEXIT_CRITICAL(&s_log_mux); } return ret; } esp_err_t serial_log_init(void) { portENTER_CRITICAL(&s_log_mux); s_total_bytes = 0; s_write_idx = 0; memset(s_ring_buffer, 0, sizeof(s_ring_buffer)); portEXIT_CRITICAL(&s_log_mux); s_prev_vprintf = esp_log_set_vprintf(serial_log_vprintf); return ESP_OK; } size_t serial_log_read(uint32_t from_offset, char *dest, size_t max_len, uint32_t *next_offset) { if (!dest || max_len == 0) { if (next_offset) { *next_offset = from_offset; } return 0; } size_t copied = 0; portENTER_CRITICAL(&s_log_mux); uint32_t total = s_total_bytes; uint32_t oldest = (total > LOG_BUFFER_SIZE) ? (total - LOG_BUFFER_SIZE) : 0; if (from_offset < oldest || from_offset == 0) { from_offset = oldest; } if (from_offset >= total) { if (next_offset) { *next_offset = total; } dest[0] = '\0'; portEXIT_CRITICAL(&s_log_mux); return 0; } uint32_t to_read = total - from_offset; if (to_read > (uint32_t)(max_len - 1)) { to_read = (uint32_t)(max_len - 1); } size_t start_idx = from_offset % LOG_BUFFER_SIZE; size_t chunk1 = LOG_BUFFER_SIZE - start_idx; if (to_read <= chunk1) { memcpy(dest, &s_ring_buffer[start_idx], to_read); } else { memcpy(dest, &s_ring_buffer[start_idx], chunk1); memcpy(dest + chunk1, &s_ring_buffer[0], to_read - chunk1); } copied = to_read; dest[copied] = '\0'; if (next_offset) { *next_offset = from_offset + (uint32_t)to_read; } portEXIT_CRITICAL(&s_log_mux); return copied; } void serial_log_clear(void) { portENTER_CRITICAL(&s_log_mux); s_total_bytes = 0; s_write_idx = 0; memset(s_ring_buffer, 0, sizeof(s_ring_buffer)); portEXIT_CRITICAL(&s_log_mux); } uint32_t serial_log_get_total_bytes(void) { uint32_t total; portENTER_CRITICAL(&s_log_mux); total = s_total_bytes; portEXIT_CRITICAL(&s_log_mux); return total; }