153 lines
3.8 KiB
C
153 lines
3.8 KiB
C
/*
|
|
* MTG RFID Companion - In-memory Serial Log Ring Buffer
|
|
*/
|
|
|
|
#include "serial_log.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#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;
|
|
}
|