ether2ser 0.1.0
Ethernet <-> synchronous V.24 bridge firmware for RP2040 + W5500
Loading...
Searching...
No Matches
log.c
Go to the documentation of this file.
1#include <inttypes.h>
2#include <stdarg.h>
3#include <stdbool.h>
4#include <stdint.h>
5#include <stdio.h>
6#include <string.h>
7
8#include "common.h"
9#include "hardware/sync.h" // __dmb, __sev
10
11#define LOG_QUEUE_DEPTH 128U
12#define LOG_QUEUE_MASK (LOG_QUEUE_DEPTH - 1U)
13#define LOG_LINE_MAX 160U
14
15static inline void log_wake_core1(void)
16{
17#if defined(__arm__) || defined(__thumb__)
18#if defined(__clang__) && defined(__has_builtin)
19#if __has_builtin(__builtin_arm_sev)
20 __builtin_arm_sev();
21#else
22 __asm volatile("sev" ::: "memory");
23#endif
24#else
25 __asm volatile("sev" ::: "memory");
26#endif
27#elif defined(__riscv)
28 __sev();
29#else
30 // Host/unit-test build: no-op.
31#endif
32}
33
34#if (LOG_QUEUE_DEPTH & LOG_QUEUE_MASK) != 0
35#error "LOG_QUEUE_DEPTH must be power of two"
36#endif
37
38typedef struct
39{
40 char line[LOG_LINE_MAX];
42
43typedef struct
44{
46 volatile uint16_t head; // producer writes, consumer reads
47 volatile uint16_t tail; // consumer writes, producer reads
48 volatile uint32_t dropped;
49 volatile uint32_t high_water_mark;
53
55 .head = 0U,
56 .tail = 0U,
57 .dropped = 0U,
58 .high_water_mark = 0U,
59 .log_emitted = false};
60
65
70
71void log_write(log_level_t level, const char* fmt, ...)
72{
74 {
75 return;
76 }
77
78 char line[LOG_LINE_MAX];
79 va_list args;
80 va_start(args, fmt);
81 int written = vsnprintf(line, sizeof(line), fmt, args);
82 va_end(args);
83
84 if (written < 0)
85 {
86 return;
87 }
88 line[LOG_LINE_MAX - 1U] = '\0';
89
90 uint16_t head = global_logstate.head;
91 uint16_t next = (uint16_t)((head + 1U) & LOG_QUEUE_MASK);
92
93 if (next == global_logstate.tail)
94 {
96 return;
97 }
98
99 memcpy(global_logstate.queue[head].line, line, LOG_LINE_MAX);
100 __dmb(); // publish data before index update
101 global_logstate.head = next;
102 uint16_t depth = (uint16_t)((next - global_logstate.tail) & LOG_QUEUE_MASK);
103 if ((uint32_t)depth > global_logstate.high_water_mark)
104 {
106 }
107 if (level > LOG_LEVEL_PLAIN)
108 {
110 }
111 // wake core1 if sleeping
113}
114
116{
117 bool wrote = false;
119 {
120 uint16_t tail = global_logstate.tail;
121 __dmb();
122 (void)fputs(global_logstate.queue[tail].line, stdout);
123 global_logstate.tail = (uint16_t)((tail + 1U) & LOG_QUEUE_MASK);
124 wrote = true;
125 }
126 if (wrote)
127 {
128 (void)fflush(stdout);
129 }
130}
131
133{
134 uint32_t dropped = global_logstate.dropped;
136 return dropped;
137}
138
140{
142}
143
145{
146 bool flag = global_logstate.log_emitted;
148 return flag;
149}
log_level_t
Log verbosity levels.
Definition common.h:87
@ LOG_LEVEL_PLAIN
Definition common.h:88
@ LOG_LEVEL_INFO
Definition common.h:90
static void log_wake_core1(void)
Definition log.c:15
void log_write(log_level_t level, const char *fmt,...)
Emit one formatted log message if level is enabled.
Definition log.c:71
log_level_t get_loglevel(void)
Get current global log level.
Definition log.c:61
void log_core1_drain(void)
Definition log.c:115
bool log_take_emitted_flag(void)
Atomically read and clear "log emitted" flag.
Definition log.c:144
uint32_t log_take_dropped_count(void)
Definition log.c:132
void set_loglevel(log_level_t level)
Set current global log level.
Definition log.c:66
#define LOG_QUEUE_DEPTH
Definition log.c:11
static global_log_state_t global_logstate
Definition log.c:54
#define LOG_LINE_MAX
Definition log.c:13
uint32_t log_get_high_water_mark(void)
Definition log.c:139
#define LOG_QUEUE_MASK
Definition log.c:12
log_entry_t queue[LOG_QUEUE_DEPTH]
Definition log.c:51
log_level_t current_log_level
Definition log.c:45
volatile uint32_t dropped
Definition log.c:48
volatile uint16_t tail
Definition log.c:47
bool log_emitted
Definition log.c:50
volatile uint32_t high_water_mark
Definition log.c:49
volatile uint16_t head
Definition log.c:46
Definition log.c:39
char line[LOG_LINE_MAX]
Definition log.c:40