REDAC HybridController
Firmware for LUCIDAC/REDAC Teensy
Loading...
Searching...
No Matches
logging.h
Go to the documentation of this file.
1// Copyright (c) 2023 anabrid GmbH
2// Contact: https://www.anabrid.com/licensing/
3// SPDX-License-Identifier: MIT OR GPL-2.0-or-later
4
5#pragma once
6
7// TODO: Move "utils/logging.h" somewhere more appropriate, given the new dependency from the protocol
8
9// NOTE: Variadic macros and __PRETTY_FUNCTION__ are GNU specific extensions!
10// If you find __PRETTY_FUNCTION__ to verbose, see probably https://stackoverflow.com/a/64384924
11
12#include <Arduino.h>
13
14#include <array>
15#include <ostream>
16#include <type_traits>
17#include <vector>
18
19#ifndef ARDUINO
20#define LOG_TARGET Serial
21#else
23#define LOG_TARGET msg::Log::get()
24#endif
25
26// The actual logging call (but see also printf below)
27// The actual logging call
28#ifdef ARDUINO
29#include "StreamUtils.h" // ArduinoSreamUtils
30#define __LOG(message) LOG_TARGET.println(message);
31#else
32#define __LOG(message) std::cerr << message;
33#endif
34
35// A logging macro, which accepts an optional LOG_FLAG (e.g. ANABRID_DEBUG_INIT) and a message.
36#define LOG(LOG_FLAG, message) LOG_##LOG_FLAG(message)
37#define LOG_ERROR(message) __LOG(message)
38#define LOG_ALWAYS(message) __LOG(message)
39
40// Unfortunately, we need to define the actual logging macro for each LOG_FLAG we want to use.
41// Possibly, we can do some macro magic in the future.
42// But probably not, because checking for the defined'ness of a macro inside another macro is not possible.
43// -> Reply: Just use if(LOG_FLAG), since LOG_FLAG is known at compile time, if(false) can be optimized away.
44
45#ifdef ANABRID_DEBUG
46#define LOG_ANABRID_DEBUG(message) __LOG(message)
47#else
48#define LOG_ANABRID_DEBUG(message) ((void)0)
49#endif
50
51#ifdef ANABRID_DEBUG_INIT
52#define LOG_ANABRID_DEBUG_INIT(message) __LOG(message)
53#else
54#define LOG_ANABRID_DEBUG_INIT(message) ((void)0)
55#endif
56
57#ifdef ANABRID_DEBUG_STATE
58#define LOG_ANABRID_DEBUG_STATE(message) __LOG(message)
59#else
60#define LOG_ANABRID_DEBUG_STATE(message) ((void)0)
61#endif
62
63#ifdef ANABRID_DEBUG_DAQ
64#define LOG_ANABRID_DEBUG_DAQ(message) __LOG(message)
65#else
66#define LOG_ANABRID_DEBUG_DAQ(message) ((void)0)
67#endif
68
69#ifdef ANABRID_PEDANTIC
70#define LOG_ANABRID_PEDANTIC(message) __LOG(message)
71#else
72#define LOG_ANABRID_PEDANTIC(message) ((void)0)
73#endif
74
75#ifdef ANABRID_DEBUG_CALIBRATION
76#define LOG_ANABRID_DEBUG_CALIBRATION(message) __LOG(message)
77#else
78#define LOG_ANABRID_DEBUG_CALIBRATION(message) ((void)0)
79#endif
80
81// moved here from main in order to use at other places
82#define _ERROR_OUT_ \
83 while (true) { \
84 digitalToggle(13); \
85 delay(100); \
86 }
87
88// a bit more convenient logging
89
90// Format Strings
91#define LOGV(message, ...) \
92 { LOG_TARGET.printf("# " message "\n", __VA_ARGS__); }
93#define LOGMEV(message, ...) \
94 { LOG_TARGET.printf("# %s: " message "\n", __PRETTY_FUNCTION__, __VA_ARGS__); }
95
96// stream oriented logging for "Printable" classes
97#define LOG2(a, b) \
98 { \
99 LOG_TARGET.print("# "); \
100 LOG_TARGET.print(a); \
101 LOG_TARGET.println(b); \
102 }
103#define LOG3(a, b, c) \
104 { \
105 LOG_TARGET.print("# "); \
106 LOG_TARGET.print(a); \
107 LOG_TARGET.print(b); \
108 LOG_TARGET.println(c); \
109 }
110#define LOG4(a, b, c, d) \
111 { \
112 LOG_TARGET.print("# "); \
113 LOG_TARGET.print(a); \
114 LOG_TARGET.print(b); \
115 LOG_TARGET.print(c); \
116 LOG_TARGET.println(d); \
117 }
118#define LOG5(a, b, c, d, e) \
119 { \
120 LOG_TARGET.print("# "); \
121 LOG_TARGET.print(a); \
122 LOG_TARGET.print(b); \
123 LOG_TARGET.print(c); \
124 LOG_TARGET.print(d); \
125 LOG_TARGET.println(e); \
126 }
127
128// arbitrary length logging or "Printable" classes
129#define LOG_START(message) \
130 { \
131 LOG_TARGET.print("# "); \
132 LOG_TARGET.print(message); \
133 }
134#define LOG_ITEM(message) LOG_TARGET.print(message);
135#define LOG_END(message) LOG_TARGET.println(message);
136
137// Log something which calls like foo(JsonObject& x) without hazzle, within LOG_START ... LOG_END.
138// #define LOG_JSON(functioncall) { StaticJsonDocument<200> tmp; functioncall(tmp.to<JsonObject>());
139// serializeJson(tmp, Serial); }
140
141// #undef LOG_TARGET // was only an internal helper
142
143template <typename T, size_t size> std::ostream &operator<<(std::ostream &os, const std::array<T, size> &arr) {
144 if (arr.empty())
145 os << "[ ]";
146 else {
147 os << "[ ";
148 for (size_t i = 0; i < arr.size() - 1; i++) {
149 if constexpr (std::is_same<T, uint8_t>::value)
150 os << +arr[i] << ", ";
151 else
152 os << arr[i] << ", ";
153 }
154 if constexpr (std::is_same<T, uint8_t>::value)
155 os << +arr.back() << " ]";
156 else
157 os << arr.back() << " ]";
158 }
159 return os;
160}
161
162template <typename T> std::ostream &operator<<(std::ostream &os, const std::vector<T> &vec) {
163 if (vec.empty())
164 os << "[ ]";
165 else {
166 os << "[ ";
167 for (size_t i = 0; i < vec.size() - 1; i++) {
168 if constexpr (std::is_same<T, uint8_t>::value)
169 os << +vec[i] << ", ";
170 else
171 os << vec[i] << ", ";
172 }
173 if constexpr (std::is_same<T, uint8_t>::value)
174 os << +vec.back() << " ]";
175 else
176 os << vec.back() << " ]";
177 }
178
179 return os;
180}
std::ostream & operator<<(std::ostream &os, const std::array< T, size > &arr)
Definition logging.h:143