-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
178 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
// ArduinoTrace - github.com/bblanchon/ArduinoTrace | ||
// Copyright Benoit Blanchon 2018-2019 | ||
// MIT License | ||
// | ||
// A simple tracing macro to debug you program. | ||
// | ||
// Recipe to find where the code crashes: | ||
// 1. sprinkle your code with TRACE() | ||
// 2. run the program | ||
// 3. view all traces in the Serial monitor | ||
// | ||
// Each trace includes the: | ||
// * the filename | ||
// * the line number | ||
// * the current function | ||
// * the template parameters (if any) | ||
|
||
#pragma once | ||
|
||
#include <Arduino.h> | ||
|
||
#ifndef ARDUINOTRACE_ENABLE | ||
#define ARDUINOTRACE_ENABLE 1 | ||
#endif | ||
|
||
#if ARDUINOTRACE_ENABLE == 1 | ||
|
||
#ifndef ARDUINOTRACE_SERIAL | ||
#define ARDUINOTRACE_SERIAL Serial | ||
#endif | ||
|
||
#ifndef ARDUINOTRACE_ENABLE_PROGMEM | ||
#ifdef PROGMEM | ||
#define ARDUINOTRACE_ENABLE_PROGMEM 1 | ||
#else | ||
#define ARDUINOTRACE_ENABLE_PROGMEM 0 | ||
#endif | ||
#endif | ||
|
||
#ifndef ARDUINOTRACE_ENABLE_FULLPATH | ||
#define ARDUINOTRACE_ENABLE_FULLPATH 0 | ||
#else | ||
#define ARDUINOTRACE_ENABLE_FULLPATH 1 | ||
#endif | ||
|
||
namespace ArduinoTrace { | ||
constexpr size_t strlen(const char *str) { | ||
return str[0] ? strlen(str + 1) + 1 : 0; | ||
} | ||
|
||
template <char... chars> | ||
struct string { | ||
#if ARDUINOTRACE_ENABLE_PROGMEM | ||
const __FlashStringHelper *data() { | ||
static const char buffer[] PROGMEM = {chars...}; | ||
return reinterpret_cast<const __FlashStringHelper *>(buffer); | ||
} | ||
#else | ||
const char *data() { | ||
static const char buffer[] = {chars...}; | ||
return buffer; | ||
} | ||
#endif | ||
}; | ||
|
||
template <typename TSourceString, size_t remainingLength, | ||
char... collectedChars> | ||
struct string_maker { | ||
using result = | ||
typename string_maker<TSourceString, remainingLength - 1, | ||
TSourceString::data()[remainingLength - 1], | ||
collectedChars...>::result; | ||
}; | ||
|
||
#if ARDUINOTRACE_ENABLE_FULLPATH == 0 | ||
template <typename TSourceString, size_t remainingLength, | ||
char... collectedChars> | ||
struct string_maker<TSourceString, remainingLength, '/', collectedChars...> { | ||
using result = string<collectedChars..., '\0'>; | ||
}; | ||
|
||
template <typename TSourceString, size_t remainingLength, | ||
char... collectedChars> | ||
struct string_maker<TSourceString, remainingLength, '\\', collectedChars...> { | ||
using result = string<collectedChars..., '\0'>; | ||
}; | ||
#endif | ||
|
||
template <typename TSourceString, char... collectedChars> | ||
struct string_maker<TSourceString, 0, collectedChars...> { | ||
using result = string<collectedChars..., '\0'>; | ||
}; | ||
|
||
template <typename TStringSource> | ||
using make_string = | ||
typename string_maker<TStringSource, strlen(TStringSource::data())>::result; | ||
|
||
struct Initializer { | ||
template <typename TSerial> | ||
Initializer(TSerial &serial, int bauds) { | ||
serial.begin(bauds); | ||
while (!serial) continue; | ||
} | ||
}; | ||
|
||
template <typename TFilename, typename TPrefix> | ||
struct Printer { | ||
template <typename TSerial, typename TValue> | ||
Printer(TSerial &serial, const TValue &content) { | ||
serial.print(make_string<TFilename>{}.data()); | ||
serial.print(make_string<TPrefix>{}.data()); | ||
serial.println(content); | ||
serial.flush(); | ||
} | ||
}; | ||
} // namespace ArduinoTrace | ||
|
||
#define ARDUINOTRACE_STRINGIFY(X) #X | ||
#define ARDUINOTRACE_CONCAT(X, Y) X##Y | ||
|
||
#if ARDUINOTRACE_ENABLE_PROGMEM | ||
#define ARDUINOTRACE_FLASHIFY(X) F(X) | ||
#else | ||
#define ARDUINOTRACE_FLASHIFY(X) X | ||
#endif | ||
|
||
#define ARDUINOTRACE_PRINT(id, file, prefix, content) \ | ||
{ \ | ||
struct __filename { \ | ||
constexpr static char const *data() { return file; } \ | ||
}; \ | ||
struct __prefix { \ | ||
constexpr static char const *data() { return prefix; } \ | ||
}; \ | ||
ArduinoTrace::Printer<__filename, __prefix> __tracer(ARDUINOTRACE_SERIAL, \ | ||
content); \ | ||
} | ||
|
||
#define ARDUINOTRACE_INIITIALIZE(id, bauds) \ | ||
ArduinoTrace::Initializer ARDUINOTRACE_CONCAT(__initializer, id)( \ | ||
ARDUINOTRACE_SERIAL, bauds); | ||
|
||
#define ARDUINOTRACE_TRACE_PREFIX(line) ":" ARDUINOTRACE_STRINGIFY(line) ": " | ||
|
||
#define ARDUINOTRACE_DUMP_PREFIX(line, variable) \ | ||
":" ARDUINOTRACE_STRINGIFY(line) ": " #variable " = " | ||
|
||
// Initializes the Serial port | ||
// | ||
// Use this macro only if you want to call TRACE() at global scope, | ||
// in other cases, call Serial.begin() in your setup() function, as usual. | ||
#define ARDUINOTRACE_INIT(bauds) ARDUINOTRACE_INIITIALIZE(__COUNTER__, bauds); | ||
|
||
// Adds a trace in the Serial port | ||
// | ||
// Call this macro anywhere, including at global scope. | ||
// However, if you use it at global scope, you need to call ARDUINOTRACE_INIT() | ||
// first, otherwise, the Serial port will not be ready. | ||
#define TRACE() \ | ||
ARDUINOTRACE_PRINT(__COUNTER__, __FILE__, \ | ||
ARDUINOTRACE_TRACE_PREFIX(__LINE__), __PRETTY_FUNCTION__) | ||
|
||
// Prints the value of a variable. | ||
// | ||
// This function will print the name and the value of the variable to the | ||
// Serial. If you use it at global scope, you need to call ARDUINOTRACE_INIT() | ||
// first, otherwise, the Serial port will not be ready. | ||
#define DUMP(variable) \ | ||
ARDUINOTRACE_PRINT(__COUNTER__, __FILE__, \ | ||
ARDUINOTRACE_DUMP_PREFIX(__LINE__, variable), variable) | ||
|
||
#else // ie ARDUINOTRACE_ENABLE == 0 | ||
|
||
#define ARDUINOTRACE_INIT(bauds) | ||
#define TRACE() | ||
#define DUMP(variable) | ||
|
||
#endif |