[Simulator] Minor UI changes fixing the IOT-1087.
[platform/upstream/iotivity.git] / resource / csdk / logger / 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 // Defining _POSIX_C_SOURCE macro with 199309L (or greater) as value
22 // causes header files to expose definitions
23 // corresponding to the POSIX.1b, Real-time extensions
24 // (IEEE Std 1003.1b-1993) specification
25 //
26 // For this specific file, see use of clock_gettime,
27 // Refer to http://pubs.opengroup.org/stage7tc1/functions/clock_gettime.html
28 // and to http://man7.org/linux/man-pages/man2/clock_gettime.2.html
29 #ifndef _POSIX_C_SOURCE
30 #define _POSIX_C_SOURCE 200809L
31 #endif
32
33 // Platform check can be extended to check and/or define more, or could be
34 // moved into a config.h
35 #if !defined(__ARDUINO__) && !defined(ARDUINO)
36 #define HAVE_UNISTD_H 1
37 #endif
38
39 // Pull in _POSIX_TIMERS feature test macro to check for
40 // clock_gettime() support.
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43
44 // if we have unistd.h, we're a Unix system
45 #include <time.h>
46 #include <sys/time.h>
47 #endif
48
49 #include "logger.h"
50 #include "string.h"
51 #include "logger_types.h"
52
53 #ifndef __TIZEN__
54 static oc_log_ctx_t *logCtx = 0;
55 #endif
56 #ifdef __ANDROID__
57 #elif defined __linux__ || defined __APPLE__
58 static oc_log_level LEVEL_XTABLE[] = {OC_LOG_DEBUG, OC_LOG_INFO,
59                                       OC_LOG_WARNING, OC_LOG_ERROR, OC_LOG_FATAL};
60 #endif
61
62 // Show 16 bytes, 2 chars/byte, spaces between bytes, null termination
63 static const uint16_t LINE_BUFFER_SIZE = (16 * 2) + 16 + 1;
64
65 // Convert LogLevel to platform-specific severity level.  Store in PROGMEM on Arduino
66 #ifdef __ANDROID__
67 #ifdef ADB_SHELL
68     static const char *LEVEL[] =
69     {"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
70
71 #else
72     static android_LogPriority LEVEL[] =
73     {ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL};
74 #endif
75 #elif defined (__linux__) || defined (__APPLE__)
76     static const char *LEVEL[] __attribute__ ((unused)) =
77     {"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
78 #elif defined ARDUINO
79 #include <stdarg.h>
80 #include "Arduino.h"
81
82     PROGMEM const char level0[] = "DEBUG";
83     PROGMEM const char level1[] = "INFO";
84     PROGMEM const char level2[] = "WARNING";
85     PROGMEM const char level3[] = "ERROR";
86     PROGMEM const char level4[] = "FATAL";
87
88     PROGMEM const char * const LEVEL[]  = {level0, level1, level2, level3, level4};
89
90     static void OCLogString(LogLevel level, PROGMEM const char * tag, PROGMEM const char * logStr);
91 #ifdef ARDUINO_ARCH_AVR
92     //Mega2560 and other 8-bit AVR microcontrollers
93     #define GET_PROGMEM_BUFFER(buffer, addr) { strcpy_P(buffer, (char*)pgm_read_word(addr));}
94 #elif defined ARDUINO_ARCH_SAM
95     //Arduino Due and other 32-bit ARM micro-controllers
96     #define GET_PROGMEM_BUFFER(buffer, addr) { strcpy_P(buffer, (char*)pgm_read_dword(addr));}
97 #else
98     #define GET_PROGMEM_BUFFER(buffer, addr) { buffer[0] = '\0';}
99 #endif
100 #endif // __ANDROID__
101
102 #ifndef ARDUINO
103
104 /**
105  * Output the contents of the specified buffer (in hex) with the specified priority level.
106  *
107  * @param level      - DEBUG, INFO, WARNING, ERROR, FATAL
108  * @param tag        - Module name
109  * @param buffer     - pointer to buffer of bytes
110  * @param bufferSize - max number of byte in buffer
111  */
112 void OCLogBuffer(LogLevel level, const char * tag, const uint8_t * buffer, uint16_t bufferSize)
113 {
114     if (!buffer || !tag || (bufferSize == 0))
115     {
116         return;
117     }
118
119     // No idea why the static initialization won't work here, it seems the compiler is convinced
120     // that this is a variable-sized object.
121     char lineBuffer[LINE_BUFFER_SIZE];
122     memset(lineBuffer, 0, sizeof lineBuffer);
123     int lineIndex = 0;
124     int i;
125     for (i = 0; i < bufferSize; i++)
126     {
127         // Format the buffer data into a line
128         snprintf(&lineBuffer[lineIndex*3], sizeof(lineBuffer)-lineIndex*3, "%02X ", buffer[i]);
129         lineIndex++;
130         // Output 16 values per line
131         if (((i+1)%16) == 0)
132         {
133             OCLogv(level, tag, "%s", lineBuffer);
134             memset(lineBuffer, 0, sizeof lineBuffer);
135             lineIndex = 0;
136         }
137     }
138     // Output last values in the line, if any
139     if (bufferSize % 16)
140     {
141         OCLogv(level, tag, "%s", lineBuffer);
142     }
143 }
144 #ifndef __TIZEN__
145 void OCLogConfig(oc_log_ctx_t *ctx)
146 {
147     logCtx = ctx;
148 }
149
150 void OCLogInit()
151 {
152
153 }
154
155 void OCLogShutdown()
156 {
157 #if defined(__linux__) || defined(__APPLE__)
158     if (logCtx && logCtx->destroy)
159     {
160         logCtx->destroy(logCtx);
161     }
162 #endif
163 }
164
165 /**
166  * Output a variable argument list log string with the specified priority level.
167  * Only defined for Linux and Android
168  *
169  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
170  * @param tag    - Module name
171  * @param format - variadic log string
172  */
173 void OCLogv(LogLevel level, const char * tag, const char * format, ...)
174 {
175     if (!format || !tag) {
176         return;
177     }
178     char buffer[MAX_LOG_V_BUFFER_SIZE] = {};
179     va_list args;
180     va_start(args, format);
181     vsnprintf(buffer, sizeof buffer - 1, format, args);
182     va_end(args);
183     OCLog(level, tag, buffer);
184 }
185
186 /**
187  * Output a log string with the specified priority level.
188  * Only defined for Linux and Android
189  *
190  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
191  * @param tag    - Module name
192  * @param logStr - log string
193  */
194 void OCLog(LogLevel level, const char * tag, const char * logStr)
195 {
196     if (!logStr || !tag)
197     {
198        return;
199     }
200
201    #ifdef __ANDROID__
202
203    #ifdef ADB_SHELL
204        printf("%s: %s: %s\n", LEVEL[level], tag, logStr);
205    #else
206        __android_log_write(LEVEL[level], tag, logStr);
207    #endif
208
209    #elif defined __linux__ || defined __APPLE__
210        if (logCtx && logCtx->write_level)
211        {
212            logCtx->write_level(logCtx, LEVEL_XTABLE[level], logStr);
213
214        }
215        else
216        {
217            int min = 0;
218            int sec = 0;
219            int ms = 0;
220    #if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
221            struct timespec when = { .tv_sec = 0, .tv_nsec = 0 };
222            clockid_t clk = CLOCK_REALTIME;
223    #ifdef CLOCK_REALTIME_COARSE
224            clk = CLOCK_REALTIME_COARSE;
225    #endif
226            if (!clock_gettime(clk, &when))
227            {
228                min = (when.tv_sec / 60) % 60;
229                sec = when.tv_sec % 60;
230                ms = when.tv_nsec / 1000000;
231            }
232    #else
233            struct timeval now;
234            if (!gettimeofday(&now, NULL))
235            {
236                min = (now.tv_sec / 60) % 60;
237                sec = now.tv_sec % 60;
238                ms = now.tv_usec * 1000;
239            }
240    #endif
241            printf("%02d:%02d.%03d %s: %s: %s\n", min, sec, ms, LEVEL[level], tag, logStr);
242        }
243    #endif
244    }
245 #endif //__TIZEN__
246 #endif //ARDUINO
247 #ifdef ARDUINO
248 /**
249  * Initialize the serial logger for Arduino
250  * Only defined for Arduino
251  */
252 void OCLogInit()
253 {
254     Serial.begin(115200);
255 }
256
257 /**
258  * Output a log string with the specified priority level.
259  * Only defined for Arduino.  Only uses PROGMEM strings
260  * for the tag parameter
261  *
262  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
263  * @param tag    - Module name
264  * @param logStr - log string
265  */
266 void OCLogString(LogLevel level, PROGMEM const char * tag, 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     Serial.println(logStr);
288 }
289
290 /**
291  * Output the contents of the specified buffer (in hex) with the specified
292  * priority level.
293  *
294  * @param level      - DEBUG, INFO, WARNING, ERROR, FATAL
295  * @param tag        - Module name
296  * @param buffer     - pointer to buffer of bytes
297  * @param bufferSize - max number of byte in buffer
298  */
299  void OCLogBuffer(LogLevel level, PROGMEM const char * tag,
300                   const uint8_t * buffer, size_t bufferSize)
301  {
302      if (!buffer || !tag || (bufferSize == 0))
303      {
304          return;
305      }
306
307      char lineBuffer[LINE_BUFFER_SIZE] = {0};
308      uint8_t lineIndex = 0;
309      for (uint8_t i = 0; i < bufferSize; i++)
310      {
311         // Format the buffer data into a line
312         snprintf(&lineBuffer[lineIndex*3], sizeof(lineBuffer)-lineIndex*3, "%02X ", buffer[i]);
313         lineIndex++;
314          // Output 16 values per line
315          if (((i+1)%16) == 0)
316          {
317              OCLogString(level, tag, lineBuffer);
318              memset(lineBuffer, 0, sizeof lineBuffer);
319              lineIndex = 0;
320          }
321      }
322      // Output last values in the line, if any
323      if (bufferSize % 16)
324      {
325          OCLogString(level, tag, lineBuffer);
326      }
327  }
328
329 /**
330  * Output a log string with the specified priority level.
331  * Only defined for Arduino.  Uses PROGMEM strings
332  *
333  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
334  * @param tag    - Module name
335  * @param logStr - log string
336  */
337 void OCLog(LogLevel level, PROGMEM const char *tag, const int lineNum,
338            PROGMEM const char *logStr)
339 {
340     if (!logStr || !tag)
341     {
342         return;
343     }
344     char buffer[LINE_BUFFER_SIZE] = {0};
345     GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
346     Serial.print(buffer);
347     char c;
348     Serial.print(F(": "));
349     while ((c = pgm_read_byte(tag)))
350     {
351         Serial.write(c);
352         tag++;
353     }
354     Serial.print(F(": "));
355     Serial.print(lineNum);
356     Serial.print(F(": "));
357     while ((c = pgm_read_byte(logStr)))
358     {
359         Serial.write(c);
360         logStr++;
361     }
362     Serial.println();
363 }
364
365 /**
366  * Output a variable argument list log string with the specified priority level.
367  * Only defined for Arduino as depicted below.
368  *
369  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
370  * @param tag    - Module name
371  * @param format - variadic log string
372  */
373 void OCLogv(LogLevel level, PROGMEM const char *tag, const int lineNum,
374                 PROGMEM const char *format, ...)
375 {
376     char buffer[LINE_BUFFER_SIZE];
377     va_list ap;
378     va_start(ap, format);
379     GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
380     Serial.print(buffer);
381
382     char c;
383     Serial.print(F(": "));
384     while ((c = pgm_read_byte(tag)))
385     {
386      Serial.write(c);
387      tag++;
388      }
389     Serial.print(F(": "));
390     Serial.print(lineNum);
391     Serial.print(F(": "));
392
393 #ifdef __AVR__
394     vsnprintf_P(buffer, sizeof(buffer), format, ap);
395 #else
396     vsnprintf(buffer, sizeof(buffer), format, ap);
397 #endif
398     for (char *p = &buffer[0]; *p; p++)
399     {
400         // emulate cooked mode for newlines
401         if (*p == '\n')
402         {
403             Serial.write('\r');
404         }
405         Serial.write(*p);
406     }
407     Serial.println();
408     va_end(ap);
409 }
410 /**
411  * Output a variable argument list log string with the specified priority level.
412  * Only defined for Arduino as depicted below.
413  *
414  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
415  * @param tag    - Module name
416  * @param format - variadic log string
417  */
418 void OCLogv(LogLevel level, const char *tag, const __FlashStringHelper *format, ...)
419 {
420     char buffer[LINE_BUFFER_SIZE];
421     va_list ap;
422     va_start(ap, format);
423     // strcpy_P(buffer, (char*)pgm_read_word(&(LEVEL[level])));
424     // Serial.print(buffer);
425
426     Serial.print(LEVEL[level]);
427     // char c;
428     Serial.print(F(": "));
429
430     /*while ((c = pgm_read_byte(tag))) {
431      Serial.write(c);
432      tag++;
433      }*/
434     Serial.print(tag);
435     Serial.print(F(": "));
436
437 #ifdef __AVR__
438     vsnprintf_P(buffer, sizeof(buffer), (const char *)format, ap); // progmem for AVR
439 #else
440     vsnprintf(buffer, sizeof(buffer), (const char *)format, ap); // for the rest of the world
441 #endif
442     for (char *p = &buffer[0]; *p; p++)
443     {
444         // emulate cooked mode for newlines
445         if (*p == '\n')
446         {
447             // Serial.write('\r');
448             Serial.print('\r');
449         }
450         //Serial.write(*p);
451         Serial.print(p);
452     }
453     Serial.println();
454     va_end(ap);
455 }
456
457 #endif //ARDUINO