iotivity 0.9.0
[platform/upstream/iotivity.git] / resource / csdk / connectivity / common / src / logger.c
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include "logger.h"
22 #include "string.h"
23 #include "oic_logger.h"
24 #include "oic_console_logger.h"
25
26 static oic_log_ctx_t *logCtx = 0;
27
28 static oic_log_level LEVEL_XTABLE[] =
29 { OIC_LOG_DEBUG, OIC_LOG_INFO, OIC_LOG_WARNING, OIC_LOG_ERROR, OIC_LOG_FATAL };
30
31 static const uint16_t LINE_BUFFER_SIZE = (16 * 2) + 16 + 1; // Show 16 bytes, 2 chars/byte, spaces between bytes, null termination
32
33 // Convert LogLevel to platform-specific severity level.  Store in PROGMEM on Arduino
34 #ifdef __ANDROID__
35 static android_LogPriority LEVEL[] =
36 {   ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL};
37 #elif defined __linux__
38 static const char * LEVEL[] __attribute__ ((unused)) =
39 {   "DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
40 #elif defined ARDUINO
41 #include <stdarg.h>
42
43 PROGMEM const char level0[] = "DEBUG";
44 PROGMEM const char level1[] = "INFO";
45 PROGMEM const char level2[] = "WARNING";
46 PROGMEM const char level3[] = "ERROR";
47 PROGMEM const char level4[] = "FATAL";
48
49 PROGMEM const char * const LEVEL[] =
50 {   level0, level1, level2, level3, level4};
51
52 static void OICLogString(LogLevel level, PROGMEM const char * tag, PROGMEM const char * logStr);
53 #ifdef ARDUINO_ARCH_AVR
54 //Mega2560 and other 8-bit AVR microcontrollers
55 #define GET_PROGMEM_BUFFER(buffer, addr) { strcpy_P(buffer, (char*)pgm_read_word(addr));}
56 #elif defined ARDUINO_ARCH_SAM
57 //Arduino Due and other 32-bit ARM micro-controllers
58 #define GET_PROGMEM_BUFFER(buffer, addr) { strcpy_P(buffer, (char*)pgm_read_dword(addr));}
59 #else
60 #define GET_PROGMEM_BUFFER(buffer, addr) { buffer[0] = '\0';}
61 #endif
62 #endif // __ANDROID__
63 #ifndef ARDUINO
64
65 void OICLogConfig(oic_log_ctx_t *ctx)
66 {
67     logCtx = ctx;
68 }
69
70 void OICLogInit()
71 {
72
73 }
74
75 void OICLogShutdown()
76 {
77 #ifdef __linux__
78     if (logCtx && logCtx->destroy)
79     {
80         logCtx->destroy(logCtx);
81     }
82 #endif
83 }
84
85 /**
86  * Output a log string with the specified priority level.
87  * Only defined for Linux and Android
88  *
89  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
90  * @param tag    - Module name
91  * @param logStr - log string
92  */
93 void OICLog(LogLevel level, const char * tag, const char * logStr)
94 {
95     if (!logStr || !tag)
96     {
97         return;
98     }
99
100 #ifdef __ANDROID__
101     __android_log_write(LEVEL[level], tag, logStr);
102 #elif defined __linux__
103     if (logCtx && logCtx->write_level)
104     {
105         logCtx->write_level(logCtx, LEVEL_XTABLE[level], logStr);
106
107     }
108     else
109     {
110         printf("%s: %s: %s\n", LEVEL[level], tag, logStr);
111     }
112 #endif
113 }
114
115 /**
116  * Output a variable argument list log string with the specified priority level.
117  * Only defined for Linux and Android
118  *
119  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
120  * @param tag    - Module name
121  * @param format - variadic log string
122  */
123 void OICLogv(LogLevel level, const char * tag, const char * format, ...)
124 {
125     if (!format || !tag)
126     {
127         return;
128     }
129     char buffer[MAX_LOG_V_BUFFER_SIZE];
130     memset(buffer, 0, sizeof buffer);
131     va_list args;
132     va_start(args, format);
133     vsnprintf(buffer, sizeof buffer - 1, format, args);
134     va_end(args);
135     OICLog(level, tag, buffer);
136 }
137
138 /**
139  * Output the contents of the specified buffer (in hex) with the specified priority level.
140  *
141  * @param level      - DEBUG, INFO, WARNING, ERROR, FATAL
142  * @param tag        - Module name
143  * @param buffer     - pointer to buffer of bytes
144  * @param bufferSize - max number of byte in buffer
145  */
146 void OICLogBuffer(LogLevel level, const char * tag, const uint8_t * buffer, uint16_t bufferSize)
147 {
148     if (!buffer || !tag || (bufferSize == 0))
149     {
150         return;
151     }
152
153     char lineBuffer[LINE_BUFFER_SIZE];
154     memset(lineBuffer, 0, sizeof lineBuffer);
155     int lineIndex = 0;
156     int i;
157     for (i = 0; i < bufferSize; i++)
158     {
159         // Format the buffer data into a line
160         snprintf(&lineBuffer[lineIndex*3], sizeof(lineBuffer)-lineIndex*3, "%02X ", buffer[i]);
161         lineIndex++;
162         // Output 16 values per line
163         if (((i + 1) % 16) == 0)
164         {
165             OICLog(level, tag, lineBuffer);
166             memset(lineBuffer, 0, sizeof lineBuffer);
167             lineIndex = 0;
168         }
169     }
170     // Output last values in the line, if any
171     if (bufferSize % 16)
172     {
173         OICLog(level, tag, lineBuffer);
174     }
175 }
176
177 #else
178 /**
179  * Initialize the serial logger for Arduino
180  * Only defined for Arduino
181  */
182 void OICLogInit()
183 {
184     Serial.begin(115200);
185 }
186
187 /**
188  * Output a log string with the specified priority level.
189  * Only defined for Arduino.  Only uses PROGMEM strings
190  * for the tag parameter
191  *
192  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
193  * @param tag    - Module name
194  * @param logStr - log string
195  */
196 void OICLogString(LogLevel level, PROGMEM const char * tag, const char * logStr)
197 {
198     if (!logStr || !tag)
199     {
200         return;
201     }
202
203     char buffer[LINE_BUFFER_SIZE];
204
205     GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
206     Serial.print(buffer);
207
208     char c;
209     Serial.print(F(": "));
210     while ((c = pgm_read_byte(tag)))
211     {
212         Serial.write(c);
213         tag++;
214     }
215     Serial.print(F(": "));
216
217     Serial.println(logStr);
218 }
219
220 /**
221  * Output the contents of the specified buffer (in hex) with the specified priority level.
222  *
223  * @param level      - DEBUG, INFO, WARNING, ERROR, FATAL
224  * @param tag        - Module name
225  * @param buffer     - pointer to buffer of bytes
226  * @param bufferSize - max number of byte in buffer
227  */
228 void OICLogBuffer(LogLevel level, PROGMEM const char * tag, const uint8_t * buffer, uint16_t bufferSize)
229 {
230     if (!buffer || !tag || (bufferSize == 0))
231     {
232         return;
233     }
234
235     char lineBuffer[LINE_BUFFER_SIZE] =
236     {   0};
237     uint8_t lineIndex = 0;
238     for (uint8_t i = 0; i < bufferSize; i++)
239     {
240         // Format the buffer data into a line
241         snprintf(&lineBuffer[lineIndex*3], sizeof(lineBuffer)-lineIndex*3, "%02X ", buffer[i]);
242         lineIndex++;
243         // Output 16 values per line
244         if (((i+1)%16) == 0)
245         {
246             OICLogString(level, tag, lineBuffer);
247             memset(lineBuffer, 0, sizeof lineBuffer);
248             lineIndex = 0;
249         }
250     }
251     // Output last values in the line, if any
252     if (bufferSize % 16)
253     {
254         OICLogString(level, tag, lineBuffer);
255     }
256 }
257
258 /**
259  * Output a log string with the specified priority level.
260  * Only defined for Arduino.  Uses PROGMEM strings
261  *
262  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
263  * @param tag    - Module name
264  * @param logStr - log string
265  */
266 void OICLog(LogLevel level, PROGMEM const char * tag, PROGMEM const char * logStr)
267 {
268     if (!logStr || !tag)
269     {
270         return;
271     }
272
273     char buffer[LINE_BUFFER_SIZE];
274
275     GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
276     Serial.print(buffer);
277
278     char c;
279     Serial.print(F(": "));
280     while ((c = pgm_read_byte(tag)))
281     {
282         Serial.write(c);
283         tag++;
284     }
285     Serial.print(F(": "));
286
287     while ((c = pgm_read_byte(logStr)))
288     {
289         Serial.write(c);
290         logStr++;
291     }
292     Serial.println();
293 }
294
295 /**
296  * Output a variable argument list log string with the specified priority level.
297  * Only defined for Arduino as depicted below.
298  *
299  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
300  * @param tag    - Module name
301  * @param format - variadic log string
302  */
303 void OICLogv(LogLevel level, PROGMEM const char * tag, const char * format, ...)
304 {
305     char buffer[LINE_BUFFER_SIZE];
306     va_list ap;
307     va_start(ap, format);
308
309     GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
310     Serial.print(buffer);
311
312     char c;
313     Serial.print(F(": "));
314
315     while ((c = pgm_read_byte(tag)))
316     {
317         Serial.write(c);
318         tag++;
319     }
320     Serial.print(F(": "));
321
322     vsnprintf(buffer, sizeof(buffer), format, ap);
323     for(char *p = &buffer[0]; *p; p++) // emulate cooked mode for newlines
324     {
325         if(*p == '\n')
326         {
327             Serial.write('\r');
328         }
329         Serial.write(*p);
330     }
331     Serial.println();
332     va_end(ap);
333 }
334 /**
335  * Output a variable argument list log string with the specified priority level.
336  * Only defined for Arduino as depicted below.
337  *
338  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
339  * @param tag    - Module name
340  * @param format - variadic log string
341  */
342 void OICLogv(LogLevel level, PROGMEM const char * tag, const __FlashStringHelper *format, ...)
343 {
344     char buffer[LINE_BUFFER_SIZE];
345     va_list ap;
346     va_start(ap, format);
347
348     GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
349     Serial.print(buffer);
350
351     char c;
352     Serial.print(F(": "));
353
354     while ((c = pgm_read_byte(tag)))
355     {
356         Serial.write(c);
357         tag++;
358     }
359     Serial.print(F(": "));
360
361 #ifdef __AVR__
362     vsnprintf_P(buffer, sizeof(buffer), (const char *)format, ap); // progmem for AVR
363 #else
364     vsnprintf(buffer, sizeof(buffer), (const char *)format, ap); // for the rest of the world
365 #endif
366     for(char *p = &buffer[0]; *p; p++) // emulate cooked mode for newlines
367     {
368         if(*p == '\n')
369         {
370             Serial.write('\r');
371         }
372         Serial.write(*p);
373     }
374     Serial.println();
375     va_end(ap);
376 }
377
378 #endif
379