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 // Pull in _POSIX_TIMERS feature test macro to check for
34 // clock_gettime() support.
38 // if we have unistd.h, we're a Unix system
49 #include "logger_types.h"
52 static oc_log_ctx_t *logCtx = 0;
56 #define LINE_BUFFER_SIZE (16 * 2) + 16 + 1 // Show 16 bytes, 2 chars/byte, spaces between bytes, null termination
58 static const uint16_t LINE_BUFFER_SIZE = (16 * 2) + 16 + 1; // Show 16 bytes, 2 chars/byte, spaces between bytes, null termination
59 #endif //defined(_MSC_VER)
62 #elif defined __linux__ || defined __APPLE__ || defined _WIN32
63 static oc_log_level LEVEL_XTABLE[] = {OC_LOG_DEBUG, OC_LOG_INFO,
64 OC_LOG_WARNING, OC_LOG_ERROR, OC_LOG_FATAL};
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__) || defined(__msys_nt__)
78 static const char * LEVEL[] __attribute__ ((unused)) = {"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
79 #elif defined(_MSC_VER)
80 static const char * LEVEL[] = {"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
84 #include "oic_string.h"
86 PROGMEM const char level0[] = "DEBUG";
87 PROGMEM const char level1[] = "INFO";
88 PROGMEM const char level2[] = "WARNING";
89 PROGMEM const char level3[] = "ERROR";
90 PROGMEM const char level4[] = "FATAL";
92 PROGMEM const char * const LEVEL[] = {level0, level1, level2, level3, level4};
94 static void OCLogString(LogLevel level, PROGMEM const char * tag, PROGMEM const char * logStr);
95 #ifdef ARDUINO_ARCH_AVR
96 //Mega2560 and other 8-bit AVR microcontrollers
97 #define GET_PROGMEM_BUFFER(buffer, addr) { OICStrcpy(buffer, sizeof(buffer), (char*)pgm_read_word(addr));}
98 #elif defined ARDUINO_ARCH_SAM
99 //Arduino Due and other 32-bit ARM micro-controllers
100 #define GET_PROGMEM_BUFFER(buffer, addr) { OICStrcpy(buffer, sizeof(buffer), (char*)pgm_read_dword(addr));}
102 #define GET_PROGMEM_BUFFER(buffer, addr) { buffer[0] = '\0';}
104 #else // !defined(__ANDROID__) && !defined(ARDUINO)
105 static const char *LEVEL[] __attribute__ ((unused)) =
106 {"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
112 * Output the contents of the specified buffer (in hex) with the specified priority level.
114 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
115 * @param tag - Module name
116 * @param buffer - pointer to buffer of bytes
117 * @param bufferSize - max number of byte in buffer
119 void OCLogBuffer(LogLevel level, const char * tag, const uint8_t * buffer, uint16_t bufferSize)
121 if (!buffer || !tag || (bufferSize == 0))
126 // No idea why the static initialization won't work here, it seems the compiler is convinced
127 // that this is a variable-sized object.
128 char lineBuffer[LINE_BUFFER_SIZE];
129 memset(lineBuffer, 0, sizeof lineBuffer);
132 for (i = 0; i < bufferSize; i++)
134 // Format the buffer data into a line
135 snprintf(&lineBuffer[lineIndex*3], sizeof(lineBuffer)-lineIndex*3, "%02X ", buffer[i]);
137 // Output 16 values per line
140 OCLogv(level, tag, "%s", lineBuffer);
141 memset(lineBuffer, 0, sizeof lineBuffer);
145 // Output last values in the line, if any
148 OCLogv(level, tag, "%s", lineBuffer);
152 void OCLogConfig(oc_log_ctx_t *ctx)
164 #if defined(__linux__) || defined(__APPLE__) || defined(_WIN32)
165 if (logCtx && logCtx->destroy)
167 logCtx->destroy(logCtx);
173 * Output a variable argument list log string with the specified priority level.
174 * Only defined for Linux and Android
176 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
177 * @param tag - Module name
178 * @param format - variadic log string
180 void OCLogv(LogLevel level, const char * tag, const char * format, ...)
182 if (!format || !tag) {
185 char buffer[MAX_LOG_V_BUFFER_SIZE] = {0};
187 va_start(args, format);
188 vsnprintf(buffer, sizeof buffer - 1, format, args);
190 OCLog(level, tag, buffer);
194 * Output a log string with the specified priority level.
195 * Only defined for Linux and Android
197 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
198 * @param tag - Module name
199 * @param logStr - log string
201 void OCLog(LogLevel level, const char * tag, const char * logStr)
211 printf("%s: %s: %s\n", LEVEL[level], tag, logStr);
213 __android_log_write(LEVEL[level], tag, logStr);
217 if (logCtx && logCtx->write_level)
219 logCtx->write_level(logCtx, LEVEL_XTABLE[level], logStr);
227 #if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
228 struct timespec when = { .tv_sec = 0, .tv_nsec = 0 };
229 clockid_t clk = CLOCK_REALTIME;
230 #ifdef CLOCK_REALTIME_COARSE
231 clk = CLOCK_REALTIME_COARSE;
233 if (!clock_gettime(clk, &when))
235 min = (when.tv_sec / 60) % 60;
236 sec = when.tv_sec % 60;
237 ms = when.tv_nsec / 1000000;
239 #elif defined(_WIN32)
240 SYSTEMTIME systemTime = {0};
241 GetLocalTime(&systemTime);
242 min = (int)systemTime.wMinute;
243 sec = (int)systemTime.wSecond;
244 ms = (int)systemTime.wMilliseconds;
247 if (!gettimeofday(&now, NULL))
249 min = (now.tv_sec / 60) % 60;
250 sec = now.tv_sec % 60;
251 ms = now.tv_usec * 1000;
254 printf("%02d:%02d.%03d %s: %s: %s\n", min, sec, ms, LEVEL[level], tag, logStr);
262 * Initialize the serial logger for Arduino
263 * Only defined for Arduino
267 Serial.begin(115200);
271 * Output a log string with the specified priority level.
272 * Only defined for Arduino. Only uses PROGMEM strings
273 * for the tag parameter
275 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
276 * @param tag - Module name
277 * @param logStr - log string
279 void OCLogString(LogLevel level, PROGMEM const char * tag, const char * logStr)
286 char buffer[LINE_BUFFER_SIZE];
288 GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
289 Serial.print(buffer);
292 Serial.print(F(": "));
293 while ((c = pgm_read_byte(tag)))
298 Serial.print(F(": "));
300 Serial.println(logStr);
304 * Output the contents of the specified buffer (in hex) with the specified
307 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
308 * @param tag - Module name
309 * @param buffer - pointer to buffer of bytes
310 * @param bufferSize - max number of byte in buffer
312 void OCLogBuffer(LogLevel level, PROGMEM const char * tag,
313 const uint8_t * buffer, size_t bufferSize)
315 if (!buffer || !tag || (bufferSize == 0))
320 char lineBuffer[LINE_BUFFER_SIZE] = {0};
321 uint8_t lineIndex = 0;
322 for (uint8_t i = 0; i < bufferSize; i++)
324 // Format the buffer data into a line
325 snprintf(&lineBuffer[lineIndex*3], sizeof(lineBuffer)-lineIndex*3, "%02X ", buffer[i]);
327 // Output 16 values per line
330 OCLogString(level, tag, lineBuffer);
331 memset(lineBuffer, 0, sizeof lineBuffer);
335 // Output last values in the line, if any
338 OCLogString(level, tag, lineBuffer);
343 * Output a log string with the specified priority level.
344 * Only defined for Arduino. Uses PROGMEM strings
346 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
347 * @param tag - Module name
348 * @param logStr - log string
350 void OCLog(LogLevel level, PROGMEM const char *tag, const int lineNum,
351 PROGMEM const char *logStr)
357 char buffer[LINE_BUFFER_SIZE] = {0};
358 GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
359 Serial.print(buffer);
361 Serial.print(F(": "));
362 while ((c = pgm_read_byte(tag)))
367 Serial.print(F(": "));
368 Serial.print(lineNum);
369 Serial.print(F(": "));
370 while ((c = pgm_read_byte(logStr)))
379 * Output a variable argument list log string with the specified priority level.
380 * Only defined for Arduino as depicted below.
382 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
383 * @param tag - Module name
384 * @param format - variadic log string
386 void OCLogv(LogLevel level, PROGMEM const char *tag, const int lineNum,
387 PROGMEM const char *format, ...)
389 char buffer[LINE_BUFFER_SIZE];
391 va_start(ap, format);
392 GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
393 Serial.print(buffer);
396 Serial.print(F(": "));
397 while ((c = pgm_read_byte(tag)))
402 Serial.print(F(": "));
403 Serial.print(lineNum);
404 Serial.print(F(": "));
407 vsnprintf_P(buffer, sizeof(buffer), format, ap);
409 vsnprintf(buffer, sizeof(buffer), format, ap);
411 for (char *p = &buffer[0]; *p; p++)
413 // emulate cooked mode for newlines
424 * Output a variable argument list log string with the specified priority level.
425 * Only defined for Arduino as depicted below.
427 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
428 * @param tag - Module name
429 * @param format - variadic log string
431 void OCLogv(LogLevel level, const char *tag, const __FlashStringHelper *format, ...)
433 char buffer[LINE_BUFFER_SIZE];
435 va_start(ap, format);
436 // strcpy_P(buffer, (char*)pgm_read_word(&(LEVEL[level])));
437 // Serial.print(buffer);
439 Serial.print(LEVEL[level]);
441 Serial.print(F(": "));
443 /*while ((c = pgm_read_byte(tag))) {
448 Serial.print(F(": "));
451 vsnprintf_P(buffer, sizeof(buffer), (const char *)format, ap); // progmem for AVR
453 vsnprintf(buffer, sizeof(buffer), (const char *)format, ap); // for the rest of the world
455 for (char *p = &buffer[0]; *p; p++)
457 // emulate cooked mode for newlines
460 // Serial.write('\r');