1 //******************************************************************
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
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
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
39 // Pull in _POSIX_TIMERS feature test macro to check for
40 // clock_gettime() support.
44 // if we have unistd.h, we're a Unix system
51 #include "oic_logger.h"
52 #include "oic_console_logger.h"
55 static oic_log_ctx_t *logCtx = 0;
58 static oic_log_level LEVEL_XTABLE[] =
59 { OIC_LOG_DEBUG, OIC_LOG_INFO, OIC_LOG_WARNING, OIC_LOG_ERROR, OIC_LOG_FATAL };
64 static const uint16_t LINE_BUFFER_SIZE = (16 * 2) + 16 +
65 1; // Show 16 bytes, 2 chars/byte, spaces between bytes, null termination
67 // Convert LogLevel to platform-specific severity level. Store in PROGMEM on Arduino
70 static const char *LEVEL[] =
71 { "DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
74 static android_LogPriority LEVEL[] =
75 { ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL};
77 #elif defined (__linux__) || defined (__APPLE__)
78 static const char *LEVEL[] __attribute__ ((unused)) =
79 { "DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
84 PROGMEM const char level0[] = "DEBUG";
85 PROGMEM const char level1[] = "INFO";
86 PROGMEM const char level2[] = "WARNING";
87 PROGMEM const char level3[] = "ERROR";
88 PROGMEM const char level4[] = "FATAL";
90 PROGMEM const char *const LEVEL[] =
91 { level0, level1, level2, level3, level4};
93 static void OICLogString(LogLevel level, PROGMEM const char *tag, PROGMEM const char *logStr);
94 #ifdef ARDUINO_ARCH_AVR
95 //Mega2560 and other 8-bit AVR microcontrollers
96 #define GET_PROGMEM_BUFFER(buffer, addr) { strcpy_P(buffer, (char*)pgm_read_word(addr));}
97 #elif defined ARDUINO_ARCH_SAM
98 //Arduino Due and other 32-bit ARM micro-controllers
99 #define GET_PROGMEM_BUFFER(buffer, addr) { strcpy_P(buffer, (char*)pgm_read_dword(addr));}
101 #define GET_PROGMEM_BUFFER(buffer, addr) { buffer[0] = '\0';}
103 #endif // __ANDROID__
107 void OICLogConfig(oic_log_ctx_t *ctx)
117 void OICLogShutdown()
119 #if defined(__linux__) || defined(__APPLE__)
120 if (logCtx && logCtx->destroy)
122 logCtx->destroy(logCtx);
128 * Output a log string with the specified priority level.
129 * Only defined for Linux and Android
131 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
132 * @param tag - Module name
133 * @param logStr - log string
135 void OICLog(LogLevel level, const char *tag, const char *logStr)
145 printf("%s: %s: %s\n", LEVEL[level], tag, logStr);
147 __android_log_write(LEVEL[level], tag, logStr);
150 #elif defined __linux__ || defined __APPLE__
151 if (logCtx && logCtx->write_level)
153 logCtx->write_level(logCtx, LEVEL_XTABLE[level], logStr);
161 #if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
162 struct timespec when = { 0, 0 };
163 clockid_t clk = CLOCK_REALTIME;
164 #ifdef CLOCK_REALTIME_COARSE
165 clk = CLOCK_REALTIME_COARSE;
167 if (!clock_gettime(clk, &when))
169 min = (when.tv_sec / 60) % 60;
170 sec = when.tv_sec % 60;
171 ms = when.tv_nsec / 1000000;
175 if (!gettimeofday(&now, NULL))
177 min = (now.tv_sec / 60) % 60;
178 sec = now.tv_sec % 60;
179 ms = now.tv_usec * 1000;
182 printf("%02d:%02d.%03d %s: %s: %s\n", min, sec, ms, LEVEL[level], tag, logStr);
188 * Output a variable argument list log string with the specified priority level.
189 * Only defined for Linux and Android
191 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
192 * @param tag - Module name
193 * @param format - variadic log string
195 void OICLogv(LogLevel level, const char *tag, const char *format, ...)
201 char buffer[MAX_LOG_V_BUFFER_SIZE] = {};
203 va_start(args, format);
204 vsnprintf(buffer, sizeof buffer - 1, format, args);
206 OICLog(level, tag, buffer);
210 * Output the contents of the specified buffer (in hex) with the specified priority level.
212 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
213 * @param tag - Module name
214 * @param buffer - pointer to buffer of bytes
215 * @param bufferSize - max number of byte in buffer
217 void OICLogBuffer(LogLevel level, const char *tag, const uint8_t *buffer, uint16_t bufferSize)
219 if (!buffer || !tag || (bufferSize == 0))
224 // I've got no idea why static initialization doesn't work here. It seems that the compiler
225 // seems to think that this is a variable-sized object
226 char lineBuffer[LINE_BUFFER_SIZE];
227 memset(lineBuffer, 0, sizeof lineBuffer);
230 for (i = 0; i < bufferSize; i++)
232 // Format the buffer data into a line
233 snprintf(&lineBuffer[lineIndex*3], sizeof(lineBuffer)-lineIndex*3, "%02X ", buffer[i]);
235 // Output 16 values per line
236 if (((i + 1) % 16) == 0)
238 OICLog(level, tag, lineBuffer);
239 memset(lineBuffer, 0, sizeof lineBuffer);
243 // Output last values in the line, if any
246 OICLog(level, tag, lineBuffer);
253 * Initialize the serial logger for Arduino
254 * Only defined for Arduino
258 Serial.begin(115200);
262 * Output a log string with the specified priority level.
263 * Only defined for Arduino. Only uses PROGMEM strings
264 * for the tag parameter
266 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
267 * @param tag - Module name
268 * @param logStr - log string
270 void OICLogString(LogLevel level, PROGMEM const char * tag,
278 char buffer[LINE_BUFFER_SIZE] = {};
279 strcpy_P(buffer, (char*)pgm_read_word(&(LEVEL[level])));
280 Serial.print(buffer);
283 Serial.print(F(": "));
284 while ((c = pgm_read_byte(tag)))
289 Serial.print(F(": "));
291 Serial.println(logStr);
295 * Output the contents of the specified buffer (in hex) with the specified
298 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
299 * @param tag - Module name
300 * @param buffer - pointer to buffer of bytes
301 * @param bufferSize - max number of byte in buffer
303 void OICLogBuffer(LogLevel level, PROGMEM const char * tag,
304 const uint8_t * buffer, uint16_t bufferSize)
306 if (!buffer || !tag || (bufferSize == 0))
311 char lineBuffer[LINE_BUFFER_SIZE] = {0};
312 uint8_t lineIndex = 0;
313 for (uint8_t i = 0; i < bufferSize; i++)
315 // Format the buffer data into a line
316 snprintf(&lineBuffer[lineIndex*3], sizeof(lineBuffer)-lineIndex*3, "%02X ", buffer[i]);
318 // Output 16 values per line
321 OICLogString(level, tag, lineBuffer);
322 memset(lineBuffer, 0, sizeof lineBuffer);
326 // Output last values in the line, if any
329 OICLogString(level, tag, lineBuffer);
334 * Output a log string with the specified priority level.
335 * Only defined for Arduino. Uses PROGMEM strings
337 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
338 * @param tag - Module name
339 * @param logStr - log string
341 void OICLog(LogLevel level, PROGMEM const char *tag, const int16_t lineNum,
342 PROGMEM const char *logStr)
348 char buffer[LINE_BUFFER_SIZE] = {0};
349 GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
350 Serial.print(buffer);
352 Serial.print(F(": "));
353 while ((c = pgm_read_byte(tag)))
358 Serial.print(F(": "));
359 Serial.print(lineNum);
360 Serial.print(F(": "));
361 while ((c = pgm_read_byte(logStr)))
370 * Output a variable argument list log string with the specified priority level.
371 * Only defined for Arduino as depicted below.
373 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
374 * @param tag - Module name
375 * @param format - variadic log string
377 void OICLogv(LogLevel level, PROGMEM const char *tag, const int16_t lineNum,
378 PROGMEM const char *format, ...)
380 char buffer[LINE_BUFFER_SIZE];
382 va_start(ap, format);
383 GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
384 Serial.print(buffer);
387 Serial.print(F(": "));
388 while ((c = pgm_read_byte(tag))) {
392 Serial.print(F(": "));
393 Serial.print(lineNum);
394 Serial.print(F(": "));
397 vsnprintf_P(buffer, sizeof(buffer), format, ap);
399 vsnprintf(buffer, sizeof(buffer), format, ap);
401 for (char *p = &buffer[0]; *p; p++)
403 // emulate cooked mode for newlines
414 * Output a variable argument list log string with the specified priority level.
415 * Only defined for Arduino as depicted below.
417 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
418 * @param tag - Module name
419 * @param format - variadic log string
421 void OICLogv(LogLevel level, const char *tag, const __FlashStringHelper *format, ...)
423 char buffer[LINE_BUFFER_SIZE];
425 va_start(ap, format);
426 // strcpy_P(buffer, (char*)pgm_read_word(&(LEVEL[level])));
427 // Serial.print(buffer);
429 Serial.print(LEVEL[level]);
431 Serial.print(F(": "));
433 /*while ((c = pgm_read_byte(tag))) {
438 Serial.print(F(": "));
441 vsnprintf_P(buffer, sizeof(buffer), (const char *)format, ap); // progmem for AVR
443 vsnprintf(buffer, sizeof(buffer), (const char *)format, ap); // for the rest of the world
445 for (char *p = &buffer[0]; *p; p++)
447 // emulate cooked mode for newlines
450 // Serial.write('\r');