Control Surface  1.1.0
MIDI Control Surface library for Arduino
Debug.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 /// @file
4 
6 AH_DIAGNOSTIC_WERROR() // Enable errors on warnings
7 
8 #include <AH/PrintStream/PrintStream.hpp>
10 
11 #ifndef FLUSH_ON_EVERY_DEBUG_STATEMENT
12 #if !(defined(ESP32) || defined(ESP8266))
13 
14 /// Should the output stream be flushed after each debug statement?
15 /// Enabling this feature can slow things down significantly, and is not
16 /// supported on ESP32 / ESP8266.
17 ///
18 /// @todo I should probably use Streams instead of Prints, so Espressif boards
19 /// can flush as well.
20 #define FLUSH_ON_EVERY_DEBUG_STATEMENT 0
21 
22 #else
23 
24 #define FLUSH_ON_EVERY_DEBUG_STATEMENT 0
25 
26 #endif
27 #endif
28 
29 // :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
30 
31 #ifdef ARDUINO
32 
33 // Uncomment this line to override Arduino debug output
34 // #define DEBUG_OUT Serial
35 
36 #else
37 
38 // Uncomment this line to override PC tests debug output
39 // #define DEBUG_OUT std::cout
40 
41 #endif
42 
43 // :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
44 
45 #if FLUSH_ON_EVERY_DEBUG_STATEMENT
46 #define DEBUG_ENDL endl
47 #else
48 #define DEBUG_ENDL "\r\n"
49 #endif
50 
51 #if (defined(ESP32) || defined(ESP8266)) && FLUSH_ON_EVERY_DEBUG_STATEMENT
52 #error "ESP32 and ESP8266 don't support flushing `Print` objects"
53 #endif
54 
55 // :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
56 
57 #define DEBUG_STR_HELPER(x) #x
58 #define DEBUG_STR(x) DEBUG_STR_HELPER(x)
59 
60 #define DEBUG_FUNC_LOCATION \
61  '[' << __PRETTY_FUNCTION__ << F(" @ line " DEBUG_STR(__LINE__) "]:\t")
62 #define DEBUG_LOCATION "[" __FILE__ ":" DEBUG_STR(__LINE__) "]:\t"
63 
64 // :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
65 
66 /// Macro for printing an expression as a string, followed by its value.
67 /// The expression string is saved in PROGMEM using the `F(...)` macro.
68 /// @ingroup AH_Debug
69 #define NAMEDVALUE(x) F(DEBUG_STR(x) " = ") << x
70 
71 #ifdef DEBUG_OUT // Debugging enabled ==========================================
72 
73 /// Print an expression to the debug output if debugging is enabled.
74 /// @ingroup AH_Debug
75 #define DEBUG(x) \
76  do { \
77  DEBUG_OUT << x << DEBUG_ENDL; \
78  } while (0)
79 
80 /// Print an expression and its location (file and line number) to the debug
81 /// output if debugging is enabled.
82 /// The location is saved in PROGMEM using the `F(...)` macro.
83 /// @ingroup AH_Debug
84 #define DEBUGREF(x) \
85  do { \
86  DEBUG_OUT << F(DEBUG_LOCATION) << x << DEBUG_ENDL; \
87  } while (0)
88 
89 /// Print an expression and its function (function name and line number) to the
90 /// debug output if debugging is enabled.
91 /// The function name is saved in RAM.
92 /// @ingroup AH_Debug
93 #define DEBUGFN(x) \
94  do { \
95  DEBUG_OUT << DEBUG_FUNC_LOCATION << x << DEBUG_ENDL; \
96  } while (0)
97 
98 #ifdef ARDUINO
99 
100 /// Print an expression and the time since startup to the debug output if
101 /// debugging is enabled.
102 /// Format: `[hours:minutes:seconds.milliseconds]`
103 /// @ingroup AH_Debug
104 #define DEBUGTIME(x) \
105  do { \
106  unsigned long t = millis(); \
107  unsigned long h = t / (60UL * 60 * 1000); \
108  unsigned long m = (t / (60UL * 1000)) % 60; \
109  unsigned long s = (t / (1000UL)) % 60; \
110  unsigned long ms = t % 1000; \
111  const char *ms_zeros = ms > 99 ? "" : (ms > 9 ? "0" : "00"); \
112  DEBUG_OUT << '[' << h << ':' << m << ':' << s << '.' << ms_zeros << ms \
113  << "]:\t" << x << DEBUG_ENDL; \
114  } while (0)
115 
116 #else // !ARDUINO
117 
118 #include <chrono>
119 
121 extern const decltype(std::chrono::high_resolution_clock::now()) start_time;
123 
124 #define DEBUGTIME(x) \
125  do { \
126  USING_AH_NAMESPACE; \
127  using namespace std::chrono; \
128  auto now = high_resolution_clock::now(); \
129  unsigned long t = \
130  duration_cast<milliseconds>(now - start_time).count(); \
131  unsigned long h = t / (60UL * 60 * 1000); \
132  unsigned long m = (t / (60UL * 1000)) % 60; \
133  unsigned long s = (t / (1000UL)) % 60; \
134  unsigned long ms = t % 1000; \
135  const char *ms_zeros = ms > 99 ? "" : (ms > 9 ? "0" : "00"); \
136  DEBUG_OUT << '[' << h << ':' << m << ':' << s << '.' << ms_zeros << ms \
137  << "]:\t" << x << DEBUG_ENDL; \
138  } while (0)
139 
140 #endif // ARDUINO
141 
142 #include "DebugVal.hpp"
143 
144 /// Print multiple expressions and their values to the debug output if debugging
145 /// is enabled.
146 /// For example, `DEBUGVAL(1 + 1, digitalRead(2))` could print `1 + 1 = 2,
147 /// digitalRead(2) = 0`.
148 /// A maximum of 10 expressions is supported.
149 /// The expression strings are saved in PROGMEM using the `F(...)` macro.
150 /// @ingroup AH_Debug
151 #define DEBUGVAL(...) DEBUGVALN(COUNT(__VA_ARGS__))(__VA_ARGS__)
152 
153 #else // Debugging disabled ====================================================
154 
155 #define DEBUG(x) \
156  do { \
157  } while (0)
158 #define DEBUGREF(x) \
159  do { \
160  } while (0)
161 #define DEBUGFN(x) \
162  do { \
163  } while (0)
164 #define DEBUGTIME(x) \
165  do { \
166  } while (0)
167 #define DEBUGVAL(...) \
168  do { \
169  } while (0)
170 
171 #endif
172 
Warnings.hpp
SettingsWrapper.hpp
AH_DIAGNOSTIC_POP
#define AH_DIAGNOSTIC_POP()
Definition: Warnings.hpp:17
AH_DIAGNOSTIC_WERROR
#define AH_DIAGNOSTIC_WERROR()
Definition: Warnings.hpp:16
BEGIN_AH_NAMESPACE
#define BEGIN_AH_NAMESPACE
Definition: AH/Settings/NamespaceSettings.hpp:9
DebugVal.hpp
END_AH_NAMESPACE
#define END_AH_NAMESPACE
Definition: AH/Settings/NamespaceSettings.hpp:10