arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Macros Modules Pages
AudioLoggerSTD.h
1#pragma once
2
3#include "AudioToolsConfig.h"
4#if defined(ARDUINO) && !defined(IS_MIN_DESKTOP)
5#include "Print.h"
6#endif
7
8#include "AudioTools/Concurrency/LockGuard.h"
9#if defined(RP2040)
10#include "AudioTools/Concurrency/RP2040/MutexRP2040.h"
11#elif defined(ESP32)
12#include "AudioTools/Concurrency/RTOS/MutexRTOS.h"
13#include "esp_log.h"
14#endif
15
16#if USE_AUDIO_LOGGING
17
18namespace audio_tools {
19
20#if defined(ESP32)
21static MutexRTOS audio_logger_mutex;
22#elif defined(RP2040)
23static MutexRP2040 audio_logger_mutex;
24#else
25static MutexBase audio_logger_mutex; // no locking
26#endif
27
35class AudioLogger {
36 public:
42 enum LogLevel { Debug, Info, Warning, Error };
43
45 void begin(Print& out, LogLevel level = LOG_LEVEL) {
46 this->log_print_ptr = &out;
47 this->log_level = level;
48 }
49
50 // defines the log level
51 void setLogLevel(LogLevel level) { this->log_level = level; }
52
54 bool isLogging(LogLevel level = Info) {
55 return log_print_ptr != nullptr && level >= log_level;
56 }
57
58 AudioLogger& prefix(const char* file, int line, LogLevel current_level) {
59 printPrefix(file, line, current_level);
60 return *this;
61 }
62
63 void println() {
64#if defined(IS_DESKTOP) || defined(IS_DESKTOP_WITH_TIME_ONLY)
65 fprintf(stderr, "%s\n", print_buffer);
66 fflush(stderr);
67#else
68 log_print_ptr->println(print_buffer);
69 log_print_ptr->flush();
70#endif
71 print_buffer[0] = 0;
72 }
73
74 char* str() { return print_buffer; }
75
77 static AudioLogger& instance() {
78 static AudioLogger* ptr;
79 if (ptr == nullptr) {
80 ptr = new AudioLogger;
81 }
82 return *ptr;
83 }
84
85 LogLevel level() { return log_level; }
86
87 void print(const char* c) { log_print_ptr->print(c); }
88
89 void printChar(char c) { log_print_ptr->print(c); }
90
91 void printCharHex(char c) {
92 char tmp[5];
93 unsigned char val = c;
94 snprintf(tmp, 5, "%02X ", val);
95 log_print_ptr->print(tmp);
96 }
97
98 protected:
99 Print* log_print_ptr = &LOG_STREAM;
100 LogLevel log_level = LOG_LEVEL;
101 char print_buffer[LOG_PRINTF_BUFFER_SIZE];
102
103 AudioLogger() {}
104
105 const char* levelName(LogLevel level) const {
106 switch (level) {
107 case Debug:
108 return "D";
109 case Info:
110 return "I";
111 case Warning:
112 return "W";
113 case Error:
114 return "E";
115 }
116 return "";
117 }
118
119 int printPrefix(const char* file, int line, LogLevel current_level) const {
120 const char* file_name = strrchr(file, '/') ? strrchr(file, '/') + 1 : file;
121 const char* level_code = levelName(current_level);
122 int len = log_print_ptr->print("[");
123 len += log_print_ptr->print(level_code);
124 len += log_print_ptr->print("] ");
125 len += log_print_ptr->print(file_name);
126 len += log_print_ptr->print(" : ");
127 len += log_print_ptr->print(line);
128 len += log_print_ptr->print(" - ");
129 return len;
130 }
131};
132
133static AudioLogger& AudioToolsLogger = AudioLogger::instance();
134using AudioToolsLogLevel = AudioLogger::LogLevel;
135
137class CustomLogLevel {
138 public:
139 AudioLogger::LogLevel getActual() { return actual; }
140
142 void set(AudioLogger::LogLevel level) {
143 active = true;
144 original = AudioLogger::instance().level();
145 actual = level;
146 }
147
149 void set() {
150 if (active) {
151 AudioLogger::instance().begin(Serial, actual);
152 }
153 }
155 void reset() {
156 if (active) {
157 AudioLogger::instance().begin(Serial, original);
158 }
159 }
160
161 protected:
162 bool active = false;
163 AudioLogger::LogLevel original;
164 AudioLogger::LogLevel actual;
165};
166
167} // namespace audio_tools
168
169// #define LOG_OUT(level, fmt, ...)
170// {AudioLogger::instance().prefix(__FILE__,__LINE__, level);cont char PROGMEM
171// *fmt_P=F(fmt); snprintf_P(AudioLogger::instance().str(),
172// LOG_PRINTF_BUFFER_SIZE, fmt, ##__VA_ARGS__);
173// AudioLogger::instance().println();}
174#define LOG_OUT_PGMEM(level, fmt, ...) \
175 { \
176 LockGuard guard{audio_logger_mutex}; \
177 AudioLogger::instance().prefix(__FILE__, __LINE__, level); \
178 snprintf(AudioLogger::instance().str(), LOG_PRINTF_BUFFER_SIZE, PSTR(fmt), \
179 ##__VA_ARGS__); \
180 AudioLogger::instance().println(); \
181 }
182
183#define LOG_OUT(level, fmt, ...) \
184 { \
185 LockGuard guard{audio_logger_mutex}; \
186 AudioLogger::instance().prefix(__FILE__, __LINE__, level); \
187 snprintf(AudioLogger::instance().str(), LOG_PRINTF_BUFFER_SIZE, fmt, \
188 ##__VA_ARGS__); \
189 AudioLogger::instance().println(); \
190 }
191#define LOG_MIN(level) \
192 { \
193 LockGuard guard{audio_logger_mutex}; \
194 AudioLogger::instance().prefix(__FILE__, __LINE__, level); \
195 AudioLogger::instance().println(); \
196 }
197
198#ifdef LOG_NO_MSG
199#define LOGD(fmt, ...) \
200 if (AudioLogger::instance().level() <= AudioLogger::Debug) { \
201 LOG_MIN(AudioLogger::Debug); \
202 }
203#define LOGI(fmt, ...) \
204 if (AudioLogger::instance().level() <= AudioLogger::Info) { \
205 LOG_MIN(AudioLogger::Info); \
206 }
207#define LOGW(fmt, ...) \
208 if (AudioLogger::instance().level() <= AudioLogger::Warning) { \
209 LOG_MIN(AudioLogger::Warning); \
210 }
211#define LOGE(fmt, ...) \
212 if (AudioLogger::instance().level() <= AudioLogger::Error) { \
213 LOG_MIN(AudioLogger::Error); \
214 }
215#else
216// Log statments which store the fmt string in Progmem
217#define LOGD(fmt, ...) \
218 if (AudioLogger::instance().level() <= AudioLogger::Debug) { \
219 LOG_OUT_PGMEM(AudioLogger::Debug, fmt, ##__VA_ARGS__); \
220 }
221#define LOGI(fmt, ...) \
222 if (AudioLogger::instance().level() <= AudioLogger::Info) { \
223 LOG_OUT_PGMEM(AudioLogger::Info, fmt, ##__VA_ARGS__); \
224 }
225#define LOGW(fmt, ...) \
226 if (AudioLogger::instance().level() <= AudioLogger::Warning) { \
227 LOG_OUT_PGMEM(AudioLogger::Warning, fmt, ##__VA_ARGS__); \
228 }
229#define LOGE(fmt, ...) \
230 if (AudioLogger::instance().level() <= AudioLogger::Error) { \
231 LOG_OUT_PGMEM(AudioLogger::Error, fmt, ##__VA_ARGS__); \
232 }
233#endif
234
235// Just log file and line
236#if defined(NO_TRACED) || defined(NO_TRACE)
237#define TRACED()
238#else
239#define TRACED() \
240 if (AudioLogger::instance().level() <= AudioLogger::Debug) { \
241 LOG_OUT(AudioLogger::Debug, LOG_METHOD); \
242 }
243#endif
244
245#if defined(NO_TRACEI) || defined(NO_TRACE)
246#define TRACEI()
247#else
248#define TRACEI() \
249 if (AudioLogger::instance().level() <= AudioLogger::Info) { \
250 LOG_OUT(AudioLogger::Info, LOG_METHOD); \
251 }
252#endif
253
254#if defined(NO_TRACEW) || defined(NO_TRACE)
255#define TRACEW()
256#else
257#define TRACEW() \
258 if (AudioLogger::instance().level() <= AudioLogger::Warning) { \
259 LOG_OUT(AudioLogger::Warning, LOG_METHOD); \
260 }
261#endif
262
263#if defined(NO_TRACEE) || defined(NO_TRACE)
264#define TRACEE()
265#else
266#define TRACEE() \
267 if (AudioLogger::instance().level() <= AudioLogger::Error) { \
268 LOG_OUT(AudioLogger::Error, LOG_METHOD); \
269 }
270#endif
271
272#else
273
274// Switch off logging
275#define LOGD(...)
276#define LOGI(...)
277#define LOGW(...)
278#define LOGE(...)
279#define TRACED()
280#define TRACEI()
281#define TRACEW()
282#define TRACEE()
283
284#endif
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10