forked from bblanchon/ArduinoTrace
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ArduinoTrace.h
206 lines (174 loc) · 6.36 KB
/
ArduinoTrace.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// ArduinoTrace - github.com/bblanchon/ArduinoTrace
// Copyright Benoit Blanchon 2018-2021
// 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
#endif
#ifndef ARDUINOTRACE_FUNCTION_NAME_IN_FLASH
#if defined(ESP8266)
#define ARDUINOTRACE_FUNCTION_NAME_IN_FLASH 1
#else
#define ARDUINOTRACE_FUNCTION_NAME_IN_FLASH 0
#endif
#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();
}
};
template <typename TSerial>
inline void pause(TSerial &serial) {
while (serial.read() != '\n') delay(10);
}
} // 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
#if ARDUINOTRACE_FUNCTION_NAME_IN_FLASH
#define ARDUINOTRACE_FUNCTION_NAME \
reinterpret_cast<const __FlashStringHelper *>(__PRETTY_FUNCTION__)
#else
#define ARDUINOTRACE_FUNCTION_NAME __PRETTY_FUNCTION__
#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_INITIALIZE(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_INITIALIZE(__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__), \
ARDUINOTRACE_FUNCTION_NAME)
// 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)
#define BREAK() \
do { \
ARDUINOTRACE_PRINT(__COUNTER__, __FILE__, \
ARDUINOTRACE_TRACE_PREFIX(__LINE__), \
"BREAK! (press [enter] to continue)"); \
ArduinoTrace::pause(ARDUINOTRACE_SERIAL); \
} while (false)
#else // ie ARDUINOTRACE_ENABLE == 0
#define ARDUINOTRACE_INIT(bauds)
#define TRACE()
#define DUMP(variable)
#define BREAK()
#endif