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 "logger_types.h"
54 static oc_log_ctx_t *logCtx = 0;
56 static oc_log_level LEVEL_XTABLE[] = {OC_LOG_DEBUG, OC_LOG_INFO, OC_LOG_WARNING, OC_LOG_ERROR, OC_LOG_FATAL};
59 static const uint16_t LINE_BUFFER_SIZE = (16 * 2) + 16 + 1; // Show 16 bytes, 2 chars/byte, spaces between bytes, null termination
61 // Convert LogLevel to platform-specific severity level. Store in PROGMEM on Arduino
64 static const char *LEVEL[] =
65 {"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
68 static android_LogPriority LEVEL[] =
69 {ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL};
71 #elif defined (__linux__) || defined (__APPLE__)
72 static const char *LEVEL[] __attribute__ ((unused)) =
73 {"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
78 PROGMEM const char level0[] = "DEBUG";
79 PROGMEM const char level1[] = "INFO";
80 PROGMEM const char level2[] = "WARNING";
81 PROGMEM const char level3[] = "ERROR";
82 PROGMEM const char level4[] = "FATAL";
84 PROGMEM const char * const LEVEL[] = {level0, level1, level2, level3, level4};
86 static void OCLogString(LogLevel level, PROGMEM const char * tag, PROGMEM const char * logStr);
87 #ifdef ARDUINO_ARCH_AVR
88 //Mega2560 and other 8-bit AVR microcontrollers
89 #define GET_PROGMEM_BUFFER(buffer, addr) { strcpy_P(buffer, (char*)pgm_read_word(addr));}
90 #elif defined ARDUINO_ARCH_SAM
91 //Arduino Due and other 32-bit ARM micro-controllers
92 #define GET_PROGMEM_BUFFER(buffer, addr) { strcpy_P(buffer, (char*)pgm_read_dword(addr));}
94 #define GET_PROGMEM_BUFFER(buffer, addr) { buffer[0] = '\0';}
101 void OCLogConfig(oc_log_ctx_t *ctx)
113 #if defined(__linux__) || defined(__APPLE__)
114 if (logCtx && logCtx->destroy)
116 logCtx->destroy(logCtx);
122 * Output a variable argument list log string with the specified priority level.
123 * Only defined for Linux and Android
125 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
126 * @param tag - Module name
127 * @param format - variadic log string
129 void OCLogv(LogLevel level, const char * tag, const char * format, ...)
131 if (!format || !tag) {
134 char buffer[MAX_LOG_V_BUFFER_SIZE] = {};
136 va_start(args, format);
137 vsnprintf(buffer, sizeof buffer - 1, format, args);
139 OCLog(level, tag, buffer);
143 * Output a log string with the specified priority level.
144 * Only defined for Linux and Android
146 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
147 * @param tag - Module name
148 * @param logStr - log string
150 void OCLog(LogLevel level, const char * tag, const char * logStr)
160 printf("%s: %s: %s\n", LEVEL[level], tag, logStr);
162 __android_log_write(LEVEL[level], tag, logStr);
165 #elif defined __linux__ || defined __APPLE__
166 if (logCtx && logCtx->write_level)
168 logCtx->write_level(logCtx, LEVEL_XTABLE[level], logStr);
176 #if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
177 struct timespec when = { .tv_sec = 0, .tv_nsec = 0 };
178 clockid_t clk = CLOCK_REALTIME;
179 #ifdef CLOCK_REALTIME_COARSE
180 clk = CLOCK_REALTIME_COARSE;
182 if (!clock_gettime(clk, &when))
184 min = (when.tv_sec / 60) % 60;
185 sec = when.tv_sec % 60;
186 ms = when.tv_nsec / 1000000;
190 if (!gettimeofday(&now, NULL))
192 min = (now.tv_sec / 60) % 60;
193 sec = now.tv_sec % 60;
194 ms = now.tv_usec * 1000;
197 printf("%02d:%02d.%03d %s: %s: %s\n", min, sec, ms, LEVEL[level], tag, logStr);
203 * Output the contents of the specified buffer (in hex) with the specified priority level.
205 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
206 * @param tag - Module name
207 * @param buffer - pointer to buffer of bytes
208 * @param bufferSize - max number of byte in buffer
210 void OCLogBuffer(LogLevel level, const char * tag, const uint8_t * buffer, uint16_t bufferSize)
212 if (!buffer || !tag || (bufferSize == 0))
217 // No idea why the static initialization won't work here, it seems the compiler is convinced
218 // that this is a variable-sized object.
219 char lineBuffer[LINE_BUFFER_SIZE];
220 memset(lineBuffer, 0, sizeof lineBuffer);
223 for (i = 0; i < bufferSize; i++)
225 // Format the buffer data into a line
226 snprintf(&lineBuffer[lineIndex*3], sizeof(lineBuffer)-lineIndex*3, "%02X ", buffer[i]);
228 // Output 16 values per line
231 OCLog(level, tag, lineBuffer);
232 memset(lineBuffer, 0, sizeof lineBuffer);
236 // Output last values in the line, if any
239 OCLog(level, tag, lineBuffer);
246 * Initialize the serial logger for Arduino
247 * Only defined for Arduino
251 Serial.begin(115200);
255 * Output a log string with the specified priority level.
256 * Only defined for Arduino. Only uses PROGMEM strings
257 * for the tag parameter
259 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
260 * @param tag - Module name
261 * @param logStr - log string
263 void OCLogString(LogLevel level, PROGMEM const char * tag, const char * logStr)
270 char buffer[LINE_BUFFER_SIZE];
272 GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
273 Serial.print(buffer);
276 Serial.print(F(": "));
277 while ((c = pgm_read_byte(tag)))
282 Serial.print(F(": "));
284 Serial.println(logStr);
288 * Output the contents of the specified buffer (in hex) with the specified
291 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
292 * @param tag - Module name
293 * @param buffer - pointer to buffer of bytes
294 * @param bufferSize - max number of byte in buffer
296 void OCLogBuffer(LogLevel level, PROGMEM const char * tag,
297 const uint8_t * buffer, size_t bufferSize)
299 if (!buffer || !tag || (bufferSize == 0))
304 char lineBuffer[LINE_BUFFER_SIZE] = {0};
305 uint8_t lineIndex = 0;
306 for (uint8_t i = 0; i < bufferSize; i++)
308 // Format the buffer data into a line
309 snprintf(&lineBuffer[lineIndex*3], sizeof(lineBuffer)-lineIndex*3, "%02X ", buffer[i]);
311 // Output 16 values per line
314 OCLogString(level, tag, lineBuffer);
315 memset(lineBuffer, 0, sizeof lineBuffer);
319 // Output last values in the line, if any
322 OCLogString(level, tag, lineBuffer);
327 * Output a log string with the specified priority level.
328 * Only defined for Arduino. Uses PROGMEM strings
330 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
331 * @param tag - Module name
332 * @param logStr - log string
334 void OCLog(LogLevel level, PROGMEM const char *tag, const int lineNum,
335 PROGMEM const char *logStr)
341 char buffer[LINE_BUFFER_SIZE] = {0};
342 GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
343 Serial.print(buffer);
345 Serial.print(F(": "));
346 while ((c = pgm_read_byte(tag)))
351 Serial.print(F(": "));
352 Serial.print(lineNum);
353 Serial.print(F(": "));
354 while ((c = pgm_read_byte(logStr)))
363 * Output a variable argument list log string with the specified priority level.
364 * Only defined for Arduino as depicted below.
366 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
367 * @param tag - Module name
368 * @param format - variadic log string
370 void OCLogv(LogLevel level, PROGMEM const char *tag, const int lineNum,
371 PROGMEM const char *format, ...)
373 char buffer[LINE_BUFFER_SIZE];
375 va_start(ap, format);
376 GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
377 Serial.print(buffer);
380 Serial.print(F(": "));
381 while ((c = pgm_read_byte(tag)))
386 Serial.print(F(": "));
387 Serial.print(lineNum);
388 Serial.print(F(": "));
391 vsnprintf_P(buffer, sizeof(buffer), format, ap);
393 vsnprintf(buffer, sizeof(buffer), format, ap);
395 for (char *p = &buffer[0]; *p; p++)
397 // emulate cooked mode for newlines
408 * Output a variable argument list log string with the specified priority level.
409 * Only defined for Arduino as depicted below.
411 * @param level - DEBUG, INFO, WARNING, ERROR, FATAL
412 * @param tag - Module name
413 * @param format - variadic log string
415 void OCLogv(LogLevel level, const char *tag, const __FlashStringHelper *format, ...)
417 char buffer[LINE_BUFFER_SIZE];
419 va_start(ap, format);
420 // strcpy_P(buffer, (char*)pgm_read_word(&(LEVEL[level])));
421 // Serial.print(buffer);
423 Serial.print(LEVEL[level]);
425 Serial.print(F(": "));
427 /*while ((c = pgm_read_byte(tag))) {
432 Serial.print(F(": "));
435 vsnprintf_P(buffer, sizeof(buffer), (const char *)format, ap); // progmem for AVR
437 vsnprintf(buffer, sizeof(buffer), (const char *)format, ap); // for the rest of the world
439 for (char *p = &buffer[0]; *p; p++)
441 // emulate cooked mode for newlines
444 // Serial.write('\r');