196 lines
7.7 KiB
C++
196 lines
7.7 KiB
C++
#pragma once
|
|
|
|
/// @file
|
|
|
|
#include <AH/PrintStream/PrintStream.hpp>
|
|
#include <AH/Settings/SettingsWrapper.hpp>
|
|
|
|
#ifndef FLUSH_ON_EVERY_DEBUG_STATEMENT
|
|
#if !(defined(ESP32) || defined(ESP8266))
|
|
|
|
/// Should the output stream be flushed after each debug statement?
|
|
/// Enabling this feature can slow things down significantly, and is not
|
|
/// supported on ESP32 / ESP8266.
|
|
///
|
|
/// @todo I should probably use Streams instead of Prints, so Espressif boards
|
|
/// can flush as well.
|
|
#define FLUSH_ON_EVERY_DEBUG_STATEMENT 0
|
|
|
|
#else
|
|
|
|
#define FLUSH_ON_EVERY_DEBUG_STATEMENT 0
|
|
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(ESP32)
|
|
#include <mutex>
|
|
#elif defined(ARDUINO_ARCH_MBED)
|
|
#include <mutex>
|
|
#include <rtos/Mutex.h>
|
|
#endif
|
|
|
|
// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
#ifdef ARDUINO
|
|
|
|
// Uncomment this line to override Arduino debug output
|
|
// #define DEBUG_OUT Serial
|
|
|
|
#else
|
|
|
|
// Uncomment this line to override PC tests debug output
|
|
// #define DEBUG_OUT std::cout
|
|
|
|
#endif
|
|
|
|
// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
#if FLUSH_ON_EVERY_DEBUG_STATEMENT
|
|
#define DEBUG_ENDL endl
|
|
#else
|
|
#define DEBUG_ENDL "\r\n"
|
|
#endif
|
|
|
|
#if (defined(ESP32) || defined(ESP8266)) && FLUSH_ON_EVERY_DEBUG_STATEMENT
|
|
#error "ESP32 and ESP8266 don't support flushing `Print` objects"
|
|
#endif
|
|
|
|
// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
#define DEBUG_STR_HELPER(x) #x
|
|
#define DEBUG_STR(x) DEBUG_STR_HELPER(x)
|
|
|
|
#define DEBUG_FUNC_LOCATION \
|
|
'[' << __PRETTY_FUNCTION__ << F(" @ line " DEBUG_STR(__LINE__) "]:\t")
|
|
#define DEBUG_LOCATION "[" __FILE__ ":" DEBUG_STR(__LINE__) "]:\t"
|
|
|
|
// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
#if defined(ESP32)
|
|
#define DEBUG_LOCK_MUTEX std::lock_guard<std::mutex> lock(AH::debugmutex);
|
|
BEGIN_AH_NAMESPACE
|
|
extern std::mutex debugmutex;
|
|
END_AH_NAMESPACE
|
|
#elif defined(ARDUINO_ARCH_MBED)
|
|
#define DEBUG_LOCK_MUTEX std::lock_guard<rtos::Mutex> lock(AH::debugmutex);
|
|
BEGIN_AH_NAMESPACE
|
|
extern rtos::Mutex debugmutex;
|
|
END_AH_NAMESPACE
|
|
#else
|
|
#define DEBUG_LOCK_MUTEX
|
|
#endif
|
|
|
|
// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
/// Macro for printing an expression as a string, followed by its value.
|
|
/// The expression string is saved in PROGMEM using the `F(...)` macro.
|
|
/// @ingroup AH_Debug
|
|
#define NAMEDVALUE(x) F(DEBUG_STR(x) " = ") << x
|
|
|
|
#ifdef DEBUG_OUT // Debugging enabled ==========================================
|
|
|
|
/// Print an expression to the debug output if debugging is enabled.
|
|
/// @ingroup AH_Debug
|
|
#define DEBUG(x) \
|
|
do { \
|
|
DEBUG_LOCK_MUTEX \
|
|
DEBUG_OUT << x << DEBUG_ENDL; \
|
|
} while (0)
|
|
|
|
/// Print an expression and its location (file and line number) to the debug
|
|
/// output if debugging is enabled.
|
|
/// The location is saved in PROGMEM using the `F(...)` macro.
|
|
/// @ingroup AH_Debug
|
|
#define DEBUGREF(x) \
|
|
do { \
|
|
DEBUG_LOCK_MUTEX \
|
|
DEBUG_OUT << F(DEBUG_LOCATION) << x << DEBUG_ENDL; \
|
|
} while (0)
|
|
|
|
/// Print an expression and its function (function name and line number) to the
|
|
/// debug output if debugging is enabled.
|
|
/// The function name is saved in RAM.
|
|
/// @ingroup AH_Debug
|
|
#define DEBUGFN(x) \
|
|
do { \
|
|
DEBUG_LOCK_MUTEX \
|
|
DEBUG_OUT << DEBUG_FUNC_LOCATION << x << DEBUG_ENDL; \
|
|
} while (0)
|
|
|
|
#ifdef ARDUINO
|
|
|
|
/// Print an expression and the time since startup to the debug output if
|
|
/// debugging is enabled.
|
|
/// Format: `[hours:minutes:seconds.milliseconds]`
|
|
/// @ingroup AH_Debug
|
|
#define DEBUGTIME(x) \
|
|
do { \
|
|
DEBUG_LOCK_MUTEX \
|
|
unsigned long t = millis(); \
|
|
unsigned long h = t / (60UL * 60 * 1000); \
|
|
unsigned long m = (t / (60UL * 1000)) % 60; \
|
|
unsigned long s = (t / (1000UL)) % 60; \
|
|
unsigned long ms = t % 1000; \
|
|
const char *ms_zeros = ms > 99 ? "" : (ms > 9 ? "0" : "00"); \
|
|
DEBUG_OUT << '[' << h << ':' << m << ':' << s << '.' << ms_zeros << ms \
|
|
<< "]:\t" << x << DEBUG_ENDL; \
|
|
} while (0)
|
|
|
|
#else // !ARDUINO
|
|
|
|
#include <chrono>
|
|
|
|
BEGIN_AH_NAMESPACE
|
|
extern const decltype(std::chrono::high_resolution_clock::now()) start_time;
|
|
END_AH_NAMESPACE
|
|
|
|
#define DEBUGTIME(x) \
|
|
do { \
|
|
USING_AH_NAMESPACE; \
|
|
using namespace std::chrono; \
|
|
auto now = high_resolution_clock::now(); \
|
|
unsigned long t = \
|
|
duration_cast<milliseconds>(now - start_time).count(); \
|
|
unsigned long h = t / (60UL * 60 * 1000); \
|
|
unsigned long m = (t / (60UL * 1000)) % 60; \
|
|
unsigned long s = (t / (1000UL)) % 60; \
|
|
unsigned long ms = t % 1000; \
|
|
const char *ms_zeros = ms > 99 ? "" : (ms > 9 ? "0" : "00"); \
|
|
DEBUG_OUT << '[' << h << ':' << m << ':' << s << '.' << ms_zeros << ms \
|
|
<< "]:\t" << x << DEBUG_ENDL; \
|
|
} while (0)
|
|
|
|
#endif // ARDUINO
|
|
|
|
#include "DebugVal.hpp"
|
|
|
|
/// Print multiple expressions and their values to the debug output if debugging
|
|
/// is enabled.
|
|
/// For example, `DEBUGVAL(1 + 1, digitalRead(2))` could print `1 + 1 = 2,
|
|
/// digitalRead(2) = 0`.
|
|
/// A maximum of 10 expressions is supported.
|
|
/// The expression strings are saved in PROGMEM using the `F(...)` macro.
|
|
/// @ingroup AH_Debug
|
|
#define DEBUGVAL(...) DEBUGVALN(COUNT(__VA_ARGS__))(__VA_ARGS__)
|
|
|
|
#else // Debugging disabled ====================================================
|
|
|
|
#define DEBUG(x) \
|
|
do { \
|
|
} while (0)
|
|
#define DEBUGREF(x) \
|
|
do { \
|
|
} while (0)
|
|
#define DEBUGFN(x) \
|
|
do { \
|
|
} while (0)
|
|
#define DEBUGTIME(x) \
|
|
do { \
|
|
} while (0)
|
|
#define DEBUGVAL(...) \
|
|
do { \
|
|
} while (0)
|
|
|
|
#endif
|