-
Notifications
You must be signed in to change notification settings - Fork 1
/
log.c
371 lines (329 loc) · 11.4 KB
/
log.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
/*
* Copyright STREAMIT BV, 2010.
*
* Project : SIR
* Module : Log
* File name $Workfile: Log.c $
* Last Save $Date: 2003/08/16 15:01:19 $
* $Revision: 0.1 $
* Creation Date : 2003/08/16 15:01:19
*
* Description : Keeps track of log messages
* As an initial implementation this module
* outputs messages to the serial port and uses
* no buffering. (As a result logging delays execution
* as long as the serial write takes)
* At a later stage this module will have a logging
* queue. This will not have much impact on execution
* time. It will output messages to either a serial port
* or telnet client.
*
*/
/*--------------------------------------------------------------------------*/
/* Include files */
/*--------------------------------------------------------------------------*/
#define LOG_MODULE LOG_LOG_MODULE
#include <stdio.h>
#include <string.h>
#include <sys/thread.h>
#include <sys/heap.h>
#include <sys/device.h>
#include <sys/osdebug.h>
//#pragma text:appcode
#include "uart0driver.h"
//#include "settings.h"
#include "log.h"
/*--------------------------------------------------------------------------*/
/* Constant definitions */
/*--------------------------------------------------------------------------*/
/*!\brief Max length of address */
#define MAX_OFFSET_LEN 8
/*!\brief Max byte values printed on a line */
#define BYTES_PER_LINE 16
/*!\brief Max number of characters hex dump takes: 2 digits plus trailing blank */
#define HEX_DUMP_LEN (BYTES_PER_LINE*3)
/*!\brief Number of characters hex dump + ascii take: 3 chars, 2 blanks, 1 char */
#define DATA_DUMP_LEN (HEX_DUMP_LEN + 2 + BYTES_PER_LINE)
/*!\brief Number of characters per line: address, 2 blanks, data dump */
#define MAX_LINE_LEN (MAX_OFFSET_LEN + 2 + DATA_DUMP_LEN)
#define LEVEL_MASK 0x07 // b0...b2
#define NAME_MASK 0xF8 // b3..b7
/*--------------------------------------------------------------------------*/
/* Type declarations */
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/* Local variables */
/*--------------------------------------------------------------------------*/
/*!\brief The current log level */
static TLogLevel g_tLevel;
/*!\brief Stream to output the log data to */
static FILE *g_tStream;
/*--------------------------------------------------------------------------*/
/* Global variables */
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/* Local functions */
/*--------------------------------------------------------------------------*/
/*!
* \brief Return the prefix-level for the given log level.
*
* \param tLevel [in] The log level.
*
* \return Pointer to a string in program space.
*/
static PGM_P LogPrefixLevel_P(TLogLevel tLevel)
{
switch (tLevel)
{
case LOG_EMERG_LEV :return(PSTR("\n#Emerg "));
case LOG_ALERT_LEV :return(PSTR("\n#Alert "));
case LOG_CRIT_LEV :return(PSTR("\n#Crit "));
case LOG_ERR_LEV :return(PSTR("\n#Err "));
case LOG_WARNING_LEV :return(PSTR("\n#Warn "));
case LOG_NOTICE_LEV :return(PSTR("\n#Notic "));
case LOG_INFO_LEV :return(PSTR("\n#Info "));
case LOG_DEBUG_LEV :return(PSTR("\n#Debug "));
default :return(PSTR("\n"));
}
}
/*!
* \brief Return the prefix-name for the given log module.
*
* \param tLevel [in] The log module.
*
* \return Pointer to a string in program space.
*/
static PGM_P LogPrefixName_P(TLogLevel tLevel)
{
switch (tLevel)
{
case LOG_AUDIO_MODULE :return(PSTR("AU: "));
case LOG_CHANNEL_MODULE :return(PSTR("CH: "));
case LOG_COMAND_MODULE :return(PSTR("CM: "));
case LOG_DISPLAY_MODULE :return(PSTR("DP: "));
case LOG_FAT_MODULE :return(PSTR("FA: "));
case LOG_FLASH_MODULE :return(PSTR("FL: "));
case LOG_HTTP_MODULE :return(PSTR("HT: "));
case LOG_INET_MODULE :return(PSTR("IN: "));
case LOG_KEYBOARD_MODULE :return(PSTR("KB: "));
case LOG_LED_MODULE :return(PSTR("LE: "));
case LOG_LOG_MODULE :return(PSTR("LG: "));
case LOG_MAIN_MODULE :return(PSTR("SY: "));
case LOG_MENU_MODULE :return(PSTR("ME: "));
case LOG_MMC_MODULE :return(PSTR("MM: "));
case LOG_MMCDRV_MODULE :return(PSTR("MD: "));
case LOG_PARSE_MODULE :return(PSTR("PA: "));
case LOG_PLAYER_MODULE :return(PSTR("PL: "));
case LOG_REMCON_MODULE :return(PSTR("RC: "));
case LOG_RTC_MODULE :return(PSTR("RT: "));
case LOG_SELFTEST_MODULE :return(PSTR("ST: "));
case LOG_SESSION_MODULE :return(PSTR("SE: "));
case LOG_SETTINGS_MODULE :return(PSTR("SG: "));
case LOG_SPIDRV_MODULE :return(PSTR("SP: "));
case LOG_STREAMER_MODULE :return(PSTR("SR: "));
case LOG_UART0DRIVER_MODULE :return(PSTR("UA: "));
case LOG_UPDATE_MODULE :return(PSTR("UD: "));
case LOG_UTIL_MODULE :return(PSTR("UT: "));
case LOG_VERSION_MODULE :return(PSTR("VE: "));
case LOG_VS10XX_MODULE :return(PSTR("VS: "));
case LOG_WATCHDOG_MODULE :return(PSTR("WD: "));
default :return(PSTR("?? <DMK> "));
}
}
/*--------------------------------------------------------------------------*/
/* Global functions */
/*--------------------------------------------------------------------------*/
/*!
* \brief Initialises this module
*
* \param -
*
* \return -
*/
void LogInit(void)
{
/* Set default level */
g_tLevel = LOG_DEBUG_LEV;
LogOpen();
}
/*!
* \brief Opens the module for use.
*
* \param -
*
* \return -
*/
void LogOpen(void)
{
/* Associate our stream with a device */
g_tStream = Uart0DriverGetStream();
}
/*!
* \brief Closes the module.
*
* All interface functions from this module will result in void
* operations.
*
* \param -
*
* \return -
*/
void LogClose(void)
{
FILE *tPrevStream = g_tStream;
/* Don't allow adding of new output. */
g_tStream = NULL;
/* Finish all current output. */
fflush(tPrevStream);
}
/*!
* \brief Log a message to the log medium using a fixed string.
*
* The fixed string must reside in program space. It is parsed
* using the rules of (s)printf.
*
* \param tLevel priority level of the message.
* \param szMsg format string of the message.
* \param ... arguments to the format string.
*/
void LogMsg_P(TLogLevel tLevel, PGM_P szMsg, ...)
{
va_list ap;
if (g_tStream)
{
/* Log the string if the message is more important than the current level */
if ((tLevel&LEVEL_MASK) <= g_tLevel)
{
fputs_P(LogPrefixLevel_P(tLevel&LEVEL_MASK), g_tStream);
fputs_P(LogPrefixName_P(tLevel&NAME_MASK), g_tStream);
va_start(ap, szMsg);
vfprintf_P(g_tStream, szMsg, ap);
va_end(ap);
}
}
}
void LogChar_P(const char bChar)
{
if (g_tStream)
{
fputc(bChar, g_tStream);
}
}
/*!
* \brief Set the priority level
*
* \param tNewLevel New priority level
*
* \return The previous priority level
*/
TLogLevel LogSetLevel(TLogLevel tNewLevel)
{
TLogLevel tPrevLevel = g_tLevel;
if (tNewLevel <= LOG_DEBUG_LEV)
{
g_tLevel = tNewLevel;
}
return(tPrevLevel);
}
/*!
* \brief Print a block of memory
*
* Prints out 16 bytes of data per line
* Every line starts with the address (offset),
* the data in hex and that same data in ascii.
*
* \param tStream The stream to print to
* \param cp The data
* \param length The length of the data
*
* \return none
*/
void HexDump(FILE *tStream, CONST u_char *cp, size_t length)
{
register unsigned int address, i, hex_pos, ascii_pos, l;
unsigned int address_len;
unsigned char c;
char line[MAX_LINE_LEN + 1];
static CONST char binhex[16] =
{
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
if (tStream != NULL)
{
/*
* How many digits do we need for the address?
* We use at least 4 digits or more as needed
*/
if (((length - 1) & 0xF0000000) != 0)
{
address_len = 8;
}
else if (((length - 1) & 0x0F000000) != 0)
{
address_len = 7;
}
else if (((length - 1) & 0x00F00000) != 0)
{
address_len = 6;
}
else if (((length - 1) & 0x000F0000) != 0)
{
address_len = 5;
}
else
{
address_len = 4;
}
address = 0;
i = 0;
hex_pos = 0;
ascii_pos = 0;
while (i < length)
{
if ((i & 15) == 0)
{
/*
* Start of a new line.
*/
memset(line, ' ', sizeof(line));
hex_pos = 0;
ascii_pos = 0;
l = address_len;
do
{
l--;
c = (address >> (l*4)) & 0xF;
line[hex_pos++] = binhex[c];
} while (l != 0);
/* 2 spaces */
hex_pos += 2;
/*
* Offset in line of ASCII dump.
*/
ascii_pos = hex_pos + HEX_DUMP_LEN + 2;
}
c = *cp++;
/* Dump the hex value */
line[hex_pos++] = binhex[c >> 4];
line[hex_pos++] = binhex[c & 0xF];
hex_pos++;
/* Print the ascii value */
line[ascii_pos++] = (c >= ' ' && c < 127) ? c : '.';
i++;
if ((i & 15) == 0 || i == length)
{
/*
* We'll be starting a new line, or
* we're finished printing this buffer;
* dump out the line we've constructed,
* and advance the offset.
*/
line[ascii_pos] = '\0';
fputs(line, tStream);
fputc('\n', tStream);
address += BYTES_PER_LINE;
}
}
}
}