A fork of https://github.com/crosspoint-reader/crosspoint-reader
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at records-reader 103 lines 3.5 kB view raw
1#include "Logging.h" 2 3#include <string> 4 5#define MAX_ENTRY_LEN 256 6#define MAX_LOG_LINES 16 7 8// Simple ring buffer log, useful for error reporting when we encounter a crash 9RTC_NOINIT_ATTR char logMessages[MAX_LOG_LINES][MAX_ENTRY_LEN]; 10RTC_NOINIT_ATTR size_t logHead = 0; 11// Magic word written alongside logHead to detect uninitialized RTC memory. 12// RTC_NOINIT_ATTR is not zeroed on cold boot, so logHead may appear in-range 13// (0..MAX_LOG_LINES-1) by chance even though logMessages is garbage. The magic 14// value is only set by clearLastLogs(), so its absence means the buffer was 15// never properly initialized. 16RTC_NOINIT_ATTR uint32_t rtcLogMagic; 17static constexpr uint32_t LOG_RTC_MAGIC = 0xDEADBEEF; 18 19void addToLogRingBuffer(const char* message) { 20 // Add the message to the ring buffer, overwriting old messages if necessary. 21 // If the magic is wrong or logHead is out of range (RTC_NOINIT_ATTR garbage 22 // on cold boot), clear the entire buffer so subsequent reads are safe. 23 if (rtcLogMagic != LOG_RTC_MAGIC || logHead >= MAX_LOG_LINES) { 24 memset(logMessages, 0, sizeof(logMessages)); 25 logHead = 0; 26 rtcLogMagic = LOG_RTC_MAGIC; 27 } 28 strncpy(logMessages[logHead], message, MAX_ENTRY_LEN - 1); 29 logMessages[logHead][MAX_ENTRY_LEN - 1] = '\0'; 30 logHead = (logHead + 1) % MAX_LOG_LINES; 31} 32 33// Since logging can take a large amount of flash, we want to make the format string as short as possible. 34// This logPrintf prepend the timestamp, level and origin to the user-provided message, so that the user only needs to 35// provide the format string for the message itself. 36void logPrintf(const char* level, const char* origin, const char* format, ...) { 37 va_list args; 38 va_start(args, format); 39 char buf[MAX_ENTRY_LEN]; 40 char* c = buf; 41 // add timestamp, level and origin 42 { 43 unsigned long ms = millis(); 44 int len = snprintf(c, sizeof(buf), "[%lu] [%s] [%s] ", ms, level, origin); 45 // error while writing => return 46 if (len < 0) { 47 va_end(args); 48 return; 49 } 50 // clamp c to be in buffer range 51 c += std::min(len, MAX_ENTRY_LEN); 52 } 53 // add the user message 54 { 55 int len = vsnprintf(c, sizeof(buf) - (c - buf), format, args); 56 if (len < 0) { 57 va_end(args); 58 return; 59 } 60 } 61 va_end(args); 62 if (logSerial) { 63 logSerial.print(buf); 64 } 65 addToLogRingBuffer(buf); 66} 67 68std::string getLastLogs() { 69 if (rtcLogMagic != LOG_RTC_MAGIC) { 70 return {}; 71 } 72 std::string output; 73 for (size_t i = 0; i < MAX_LOG_LINES; i++) { 74 size_t idx = (logHead + i) % MAX_LOG_LINES; 75 if (logMessages[idx][0] != '\0') { 76 const size_t len = strnlen(logMessages[idx], MAX_ENTRY_LEN); 77 output.append(logMessages[idx], len); 78 } 79 } 80 return output; 81} 82 83// Checks whether the RTC log state is consistent: rtcLogMagic must equal 84// LOG_RTC_MAGIC and logHead must be in 0..MAX_LOG_LINES-1. Returns true if 85// corruption is detected, in which case rtcLogMagic is still invalid and 86// logMessages may contain garbage. Callers (e.g. HalSystem::begin on the 87// panic-reboot path) must call clearLastLogs() after a true result to fully 88// reinitialize the ring buffer and stamp the magic before getLastLogs() is used. 89bool sanitizeLogHead() { 90 if (rtcLogMagic != LOG_RTC_MAGIC || logHead >= MAX_LOG_LINES) { 91 logHead = 0; 92 return true; 93 } 94 return false; 95} 96 97void clearLastLogs() { 98 for (size_t i = 0; i < MAX_LOG_LINES; i++) { 99 logMessages[i][0] = '\0'; 100 } 101 logHead = 0; 102 rtcLogMagic = LOG_RTC_MAGIC; 103}