Firmware SDK
twr_log.c
1 #include <twr_log.h>
2 #include <twr_error.h>
3 
4 typedef struct
5 {
6  bool initialized;
7  twr_log_level_t level;
8  twr_log_timestamp_t timestamp;
9  twr_tick_t tick_last;
10  char buffer[TWR_LOG_BUFFER_SIZE];
11 
12 } twr_log_t;
13 
14 #ifndef RELEASE
15 
16 static twr_log_t _twr_log = { .initialized = false };
17 
18 void application_error(twr_error_t code);
19 
20 static void _twr_log_message(twr_log_level_t level, char id, const char *format, va_list ap);
21 
23 {
24  if (_twr_log.initialized)
25  {
26  return;
27  }
28 
29  memset(&_twr_log, 0, sizeof(_twr_log));
30 
31  _twr_log.level = level;
32  _twr_log.timestamp = timestamp;
33 
35  twr_uart_write(TWR_LOG_UART, "\r\n", 2);
36 
37  _twr_log.initialized = true;
38 }
39 
40 void twr_log_dump(const void *buffer, size_t length, const char *format, ...)
41 {
42  va_list ap;
43 
44  if (_twr_log.level > TWR_LOG_LEVEL_DUMP)
45  {
46  return;
47  }
48 
49  va_start(ap, format);
50  _twr_log_message(TWR_LOG_LEVEL_DUMP, 'X', format, ap);
51  va_end(ap);
52 
53  size_t offset_base = 0;
54 
55  for (; offset_base < sizeof(_twr_log.buffer); offset_base++)
56  {
57  if (_twr_log.buffer[offset_base] == '>')
58  {
59  break;
60  }
61  }
62 
63  offset_base += 2;
64 
65  size_t position;
66 
67  size_t offset;
68 
69  if (buffer != NULL && length != 0)
70  {
71  for (position = 0; position < length; position += TWR_LOG_DUMP_WIDTH)
72  {
73  offset = offset_base + snprintf(_twr_log.buffer + offset_base, sizeof(_twr_log.buffer) - offset_base, "%3d: ", position);
74 
75  char *ptr_hex = _twr_log.buffer + offset;
76 
77  offset += (TWR_LOG_DUMP_WIDTH * 3 + 2 + 1);
78 
79  char *ptr_text = _twr_log.buffer + offset;
80 
81  offset += TWR_LOG_DUMP_WIDTH;
82 
83  uint32_t line_size;
84 
85  uint32_t i;
86 
87  if ((position + TWR_LOG_DUMP_WIDTH) <= length)
88  {
89  line_size = TWR_LOG_DUMP_WIDTH;
90  }
91  else
92  {
93  line_size = length - position;
94  }
95 
96  for (i = 0; i < line_size; i++)
97  {
98  uint8_t value = ((uint8_t *) buffer)[position + i];
99 
100  if (i == (TWR_LOG_DUMP_WIDTH / 2))
101  {
102  *ptr_hex++ = '|';
103  *ptr_hex++ = ' ';
104  }
105 
106  snprintf(ptr_hex, 4, "%02X ", value);
107 
108  ptr_hex += 3;
109 
110  if (value < 32 || value > 126)
111  {
112  *ptr_text++ = '.';
113  }
114  else
115  {
116  *ptr_text++ = value;
117  }
118  }
119 
120  for (; i < TWR_LOG_DUMP_WIDTH; i++)
121  {
122  if (i == (TWR_LOG_DUMP_WIDTH / 2))
123  {
124  *ptr_hex++ = '|';
125  *ptr_hex++ = ' ';
126  }
127 
128  strcpy(ptr_hex, " ");
129 
130  ptr_hex += 3;
131 
132  *ptr_text++ = ' ';
133  }
134 
135  _twr_log.buffer[offset++] = '\r';
136  _twr_log.buffer[offset++] = '\n';
137 
138  twr_uart_write(TWR_LOG_UART, _twr_log.buffer, offset);
139  }
140  }
141 }
142 
143 void twr_log_debug(const char *format, ...)
144 {
145  va_list ap;
146 
147  va_start(ap, format);
148  _twr_log_message(TWR_LOG_LEVEL_DEBUG, 'D', format, ap);
149  va_end(ap);
150 }
151 
152 void twr_log_info(const char *format, ...)
153 {
154  va_list ap;
155 
156  va_start(ap, format);
157  _twr_log_message(TWR_LOG_LEVEL_INFO, 'I', format, ap);
158  va_end(ap);
159 }
160 
161 void twr_log_warning(const char *format, ...)
162 {
163  va_list ap;
164 
165  va_start(ap, format);
166  _twr_log_message(TWR_LOG_LEVEL_WARNING, 'W', format, ap);
167  va_end(ap);
168 }
169 
170 void twr_log_error(const char *format, ...)
171 {
172  va_list ap;
173 
174  va_start(ap, format);
175  _twr_log_message(TWR_LOG_LEVEL_ERROR, 'E', format, ap);
176  va_end(ap);
177 }
178 
179 static void _twr_log_message(twr_log_level_t level, char id, const char *format, va_list ap)
180 {
181  if (!_twr_log.initialized)
182  {
183  application_error(TWR_ERROR_LOG_NOT_INITIALIZED);
184  }
185 
186  if (_twr_log.level > level)
187  {
188  return;
189  }
190 
191  size_t offset;
192 
193  if (_twr_log.timestamp == TWR_LOG_TIMESTAMP_ABS)
194  {
195  twr_tick_t tick_now = twr_tick_get();
196 
197  uint32_t timestamp_abs = tick_now / 10;
198 
199  offset = sprintf(_twr_log.buffer, "# %lu.%02lu <%c> ", timestamp_abs / 100, timestamp_abs % 100, id);
200  }
201  else if (_twr_log.timestamp == TWR_LOG_TIMESTAMP_REL)
202  {
203  twr_tick_t tick_now = twr_tick_get();
204 
205  uint32_t timestamp_rel = (tick_now - _twr_log.tick_last) / 10;
206 
207  offset = sprintf(_twr_log.buffer, "# +%lu.%02lu <%c> ", timestamp_rel / 100, timestamp_rel % 100, id);
208 
209  _twr_log.tick_last = tick_now;
210  }
211  else
212  {
213  strcpy(_twr_log.buffer, "# <!> ");
214 
215  _twr_log.buffer[3] = id;
216 
217  offset = 6;
218  }
219 
220  offset += vsnprintf(&_twr_log.buffer[offset], sizeof(_twr_log.buffer) - offset - 1, format, ap);
221 
222  if (offset >= sizeof(_twr_log.buffer))
223  {
224  offset = sizeof(_twr_log.buffer) - 3 - 3; // space for ...\r\n
225  _twr_log.buffer[offset++] = '.';
226  _twr_log.buffer[offset++] = '.';
227  _twr_log.buffer[offset++] = '.';
228  }
229 
230  _twr_log.buffer[offset++] = '\r';
231  _twr_log.buffer[offset++] = '\n';
232 
233  twr_uart_write(TWR_LOG_UART, _twr_log.buffer, offset);
234 }
235 
236 #endif
void void void void void twr_log_error(const char *format,...) __attribute__((format(printf
Log ERROR message (annotated in log as <E>)
twr_log_level_t
Log level.
Definition: twr_log.h:24
void void void void twr_log_warning(const char *format,...) __attribute__((format(printf
Log WARNING message (annotated in log as <W>)
void void twr_log_debug(const char *format,...) __attribute__((format(printf
Log DEBUG message (annotated in log as <D>)
twr_log_timestamp_t
Log timestamp.
Definition: twr_log.h:48
void twr_log_init(twr_log_level_t level, twr_log_timestamp_t timestamp)
Initialize logging facility.
Definition: twr_log.c:22
void twr_log_dump(const void *buffer, size_t length, const char *format,...) __attribute__((format(printf
Log DUMP message (annotated in log as <X>)
void void void twr_log_info(const char *format,...) __attribute__((format(printf
Log INFO message (annotated in log as )
@ TWR_LOG_LEVEL_DUMP
Logging DUMP.
Definition: twr_log.h:26
@ TWR_LOG_LEVEL_WARNING
Log level WARNING.
Definition: twr_log.h:35
@ TWR_LOG_LEVEL_ERROR
Log level ERROR.
Definition: twr_log.h:38
@ TWR_LOG_LEVEL_INFO
Log level INFO.
Definition: twr_log.h:32
@ TWR_LOG_LEVEL_DEBUG
Log level DEBUG.
Definition: twr_log.h:29
@ TWR_LOG_TIMESTAMP_REL
Timestamp logging enabled (relative time format)
Definition: twr_log.h:56
@ TWR_LOG_TIMESTAMP_ABS
Timestamp logging enabled (absolute time format)
Definition: twr_log.h:53
twr_tick_t twr_tick_get(void)
Get absolute timestamp since start of program.
Definition: twr_tick.c:7
uint64_t twr_tick_t
Timestamp data type.
Definition: twr_tick.h:16
void twr_uart_init(twr_uart_channel_t channel, twr_uart_baudrate_t baudrate, twr_uart_setting_t setting)
Initialize UART channel.
Definition: twr_uart.c:54
size_t twr_uart_write(twr_uart_channel_t channel, const void *buffer, size_t length)
Write data to UART channel (blocking call)
Definition: twr_uart.c:314
@ TWR_UART_BAUDRATE_115200
UART baudrat 115200 bps.
Definition: twr_uart.h:43
@ TWR_UART_SETTING_8N1
8N1: 8 data bits, none parity bit, 1 stop bit
Definition: twr_uart.h:70