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