new logger
This commit is contained in:
parent
4ecb91ba39
commit
9cc314ad7c
@ -1,166 +0,0 @@
|
|||||||
/*
|
|
||||||
* swo_log.h
|
|
||||||
*
|
|
||||||
* Created on: 20.01.2025
|
|
||||||
* Author: Kilian
|
|
||||||
*
|
|
||||||
* Use the SWO interface to log messages
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
#ifndef __SWO_LOG_H
|
|
||||||
#define __SWO_LOG_H
|
|
||||||
#include "stm32h7xx_hal.h"
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#define MAX_MESSAGE_LENGTH 256
|
|
||||||
#define USE_MULTIPLE_CHANNELS false // if true, each log level has its own channel (FATAL : 0, ERROR : 1, etc.)
|
|
||||||
#define USE_ANSI_ESCAPE_CODES true // if true, log messages will be colored according to their log level, and the console can be cleared
|
|
||||||
#define PRINT_TIMESTAMP false // if true, timestamp (from HAL_GetTick) is printed before each log message
|
|
||||||
|
|
||||||
#if !USE_MULTIPLE_CHANNELS
|
|
||||||
#ifndef DEBUG_CHANNEL
|
|
||||||
#define DEBUG_CHANNEL 0 // channel to output messages on
|
|
||||||
#endif
|
|
||||||
#define USE_CHANNEL_MASK_VARIABLE true
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if USE_CHANNEL_MASK_VARIABLE
|
|
||||||
#define MASK_VARIABLE logging_mask // variable to store the channel mask, must be globally defined somewhere
|
|
||||||
extern volatile uint32_t MASK_VARIABLE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum log_level_t {
|
|
||||||
LOG_LEVEL_FATAL,
|
|
||||||
LOG_LEVEL_ERROR,
|
|
||||||
LOG_LEVEL_WARNING,
|
|
||||||
LOG_LEVEL_INFO,
|
|
||||||
LOG_LEVEL_DEBUG,
|
|
||||||
LOG_LEVEL_NOISY
|
|
||||||
};
|
|
||||||
|
|
||||||
#if USE_ANSI_ESCAPE_CODES
|
|
||||||
[[maybe_unused]] static const char *const log_level_names[] = {
|
|
||||||
"\033[31m[FATAL]\033[0m ", "\033[31m[ERROR]\033[0m ",
|
|
||||||
"\033[93m[WARN] \033[0m ", "\033[97m[INFO] \033[0m ",
|
|
||||||
"\033[37m[DEBUG]\033[0m ", "\033[37m[NOISY]\033[0m "};
|
|
||||||
#else
|
|
||||||
[[maybe_unused]] static const char *const log_level_names[] = {
|
|
||||||
"[FATAL] ", "[ERROR] ", "[WARN] ", "[INFO] ", "[DEBUG] ", "[NOISY] "};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline bool __ITM_channel_enabled(uint32_t channel) {
|
|
||||||
#if !USE_MULTIPLE_CHANNELS
|
|
||||||
#if USE_CHANNEL_MASK_VARIABLE
|
|
||||||
return ((ITM->TER & (1UL << DEBUG_CHANNEL)) != 0UL) &&
|
|
||||||
((MASK_VARIABLE & (1UL << channel)) != 0UL);
|
|
||||||
#else
|
|
||||||
channel = DEBUG_CHANNEL;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
return ((ITM->TER & (1UL << channel)) != 0UL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// adapted from ITM_SendChar() in the CMSIS-Core
|
|
||||||
//
|
|
||||||
// channel should be between 0 and 31
|
|
||||||
static inline uint32_t __swo_putc(uint32_t c, unsigned int channel) {
|
|
||||||
#if !USE_MULTIPLE_CHANNELS
|
|
||||||
channel = DEBUG_CHANNEL;
|
|
||||||
#endif
|
|
||||||
if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */
|
|
||||||
((ITM->TER & (1UL << channel)) != 0UL)) /* ITM Port enabled */
|
|
||||||
{
|
|
||||||
while (ITM->PORT[channel].u32 == 0UL) {
|
|
||||||
__NOP();
|
|
||||||
}
|
|
||||||
ITM->PORT[channel].u8 = (uint8_t)c;
|
|
||||||
}
|
|
||||||
return (c);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DEBUG_CHANNEL_ENABLED(channel) \
|
|
||||||
({ \
|
|
||||||
unsigned int ch = (channel); \
|
|
||||||
(ch < 32) ? __ITM_channel_enabled(ch) : false; \
|
|
||||||
})
|
|
||||||
|
|
||||||
[[gnu::nonnull(2), gnu::null_terminated_string_arg(2)]]
|
|
||||||
static inline void __swo_print(unsigned int channel, const char *str) {
|
|
||||||
if (!__ITM_channel_enabled(channel)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
while (*str) {
|
|
||||||
__swo_putc(*str++, channel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void debug_clear_console() {
|
|
||||||
for (int i = 0; i < LOG_LEVEL_NOISY; i++) {
|
|
||||||
#if USE_ANSI_ESCAPE_CODES
|
|
||||||
__swo_print(i, "\033[2J\033[;H"); // clear screen
|
|
||||||
#else
|
|
||||||
__swo_print(i, "\n\n\n\n\n-------------------\n\n\n\n\n"); // clear screen
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[gnu::format(printf, 2, 3)]]
|
|
||||||
static inline void debug_log(enum log_level_t level, const char *msg, ...) {
|
|
||||||
if (!DEBUG_CHANNEL_ENABLED(level)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char __swo_buffer[MAX_MESSAGE_LENGTH];
|
|
||||||
va_list args;
|
|
||||||
va_start(args, msg);
|
|
||||||
size_t len = vsnprintf(__swo_buffer, sizeof(__swo_buffer), msg, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
__swo_putc('\n', level);
|
|
||||||
|
|
||||||
/* Print timestamp if enabled */
|
|
||||||
if (PRINT_TIMESTAMP) {
|
|
||||||
char __time_buffer[16];
|
|
||||||
if (USE_ANSI_ESCAPE_CODES) {
|
|
||||||
snprintf(__time_buffer, sizeof(__time_buffer),
|
|
||||||
"\033[90m[%lu]\033[0m ", HAL_GetTick());
|
|
||||||
} else {
|
|
||||||
snprintf(__time_buffer, sizeof(__time_buffer), "[%lu] ",
|
|
||||||
HAL_GetTick());
|
|
||||||
}
|
|
||||||
__swo_print(level, __time_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SWO_LOG_PREFIX
|
|
||||||
__swo_print(level, SWO_LOG_PREFIX);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
__swo_print(level, log_level_names[level]);
|
|
||||||
__swo_print(level, __swo_buffer);
|
|
||||||
|
|
||||||
if (len >= sizeof(__swo_buffer)) {
|
|
||||||
__swo_print(level, " [message length exceeded] ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[gnu::format(printf, 2, 3)]]
|
|
||||||
static inline void debug_log_cont(enum log_level_t level, const char *msg, ...) {
|
|
||||||
if (!DEBUG_CHANNEL_ENABLED(level)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char __swo_buffer[MAX_MESSAGE_LENGTH];
|
|
||||||
va_list args;
|
|
||||||
va_start(args, msg);
|
|
||||||
size_t len = vsnprintf(__swo_buffer, sizeof(__swo_buffer), msg, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
__swo_print(level, __swo_buffer);
|
|
||||||
|
|
||||||
if (len >= sizeof(__swo_buffer)) {
|
|
||||||
__swo_print(level, " [message length exceeded] ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __SWO_LOG_H */
|
|
116
AMS_Master_Code/Core/Lib/logger/log.c
Normal file
116
AMS_Master_Code/Core/Lib/logger/log.c
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* log.c
|
||||||
|
*
|
||||||
|
* Created on: 21.04.2025
|
||||||
|
* Author: Kilian
|
||||||
|
*
|
||||||
|
* Implementation of the core logging system
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "stm32h7xx_hal.h"
|
||||||
|
|
||||||
|
/* Backend management */
|
||||||
|
static const log_backend_t* registered_backends[MAX_LOG_BACKENDS] = {0};
|
||||||
|
static uint8_t backend_count = 0;
|
||||||
|
|
||||||
|
/* Register a new logging backend */
|
||||||
|
bool log_register_backend(const log_backend_t* backend) {
|
||||||
|
if (backend_count >= MAX_LOG_BACKENDS || backend == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
registered_backends[backend_count++] = backend;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize all registered backends */
|
||||||
|
void log_init_all_backends(void) {
|
||||||
|
/* Initialize all registered backends */
|
||||||
|
for (uint8_t i = 0; i < backend_count; i++) {
|
||||||
|
if (registered_backends[i]->init != NULL) {
|
||||||
|
registered_backends[i]->init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if a log level is enabled */
|
||||||
|
bool log_is_level_enabled(log_level_t level) {
|
||||||
|
for (uint8_t i = 0; i < backend_count; i++) {
|
||||||
|
if (registered_backends[i]->is_enabled(level)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Frontend implementation */
|
||||||
|
|
||||||
|
/* Main logging function */
|
||||||
|
void log_message(log_level_t level, const char *msg, ...) {
|
||||||
|
log_message_t log_msg;
|
||||||
|
log_msg.level = level;
|
||||||
|
log_msg.timestamp = HAL_GetTick();
|
||||||
|
|
||||||
|
/* Format the message prefix (timestamp, log level) */
|
||||||
|
size_t prefix_len = 0;
|
||||||
|
|
||||||
|
/* Add timestamp if configured */
|
||||||
|
if (PRINT_TIMESTAMP) {
|
||||||
|
prefix_len += snprintf(log_msg.message, MAX_MESSAGE_LENGTH, "[%lu] ", log_msg.timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add log level name */
|
||||||
|
if (level <= LOG_LEVEL_NOISY) {
|
||||||
|
prefix_len += snprintf(log_msg.message + prefix_len, MAX_MESSAGE_LENGTH - prefix_len,
|
||||||
|
"%s", log_level_names[level]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Format the log message with variable arguments */
|
||||||
|
va_list args;
|
||||||
|
va_start(args, msg);
|
||||||
|
log_msg.message_length = prefix_len + vsnprintf(log_msg.message + prefix_len,
|
||||||
|
MAX_MESSAGE_LENGTH - prefix_len,
|
||||||
|
msg, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
/* Send to all enabled backends */
|
||||||
|
for (uint8_t i = 0; i < backend_count; i++) {
|
||||||
|
if (registered_backends[i]->is_enabled(level)) {
|
||||||
|
registered_backends[i]->write(&log_msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Continuation logging without timestamp or log level */
|
||||||
|
void log_message_cont(log_level_t level, const char *msg, ...) {
|
||||||
|
log_message_t log_msg;
|
||||||
|
log_msg.level = level;
|
||||||
|
log_msg.timestamp = HAL_GetTick();
|
||||||
|
|
||||||
|
/* Format the log message with variable arguments */
|
||||||
|
va_list args;
|
||||||
|
va_start(args, msg);
|
||||||
|
log_msg.message_length = vsnprintf(log_msg.message, MAX_MESSAGE_LENGTH, msg, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
/* Send to all enabled backends */
|
||||||
|
for (uint8_t i = 0; i < backend_count; i++) {
|
||||||
|
if (registered_backends[i]->is_enabled(level)) {
|
||||||
|
registered_backends[i]->write(&log_msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the console on all backends that support it */
|
||||||
|
void log_clear_console(void) {
|
||||||
|
for (uint8_t i = 0; i < backend_count; i++) {
|
||||||
|
if (registered_backends[i]->clear != NULL) {
|
||||||
|
registered_backends[i]->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
88
AMS_Master_Code/Core/Lib/logger/log.h
Normal file
88
AMS_Master_Code/Core/Lib/logger/log.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* log.h
|
||||||
|
*
|
||||||
|
* Created on: 21.04.2025
|
||||||
|
* Author: Kilian
|
||||||
|
*
|
||||||
|
* Core logging system with support for multiple backends
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#ifndef __LOG_H
|
||||||
|
#define __LOG_H
|
||||||
|
|
||||||
|
#include "stm32h7xx_hal.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/* Configuration */
|
||||||
|
#define MAX_MESSAGE_LENGTH 256
|
||||||
|
#define USE_ANSI_ESCAPE_CODES true // if true, log messages will be colored according to their log level
|
||||||
|
#define PRINT_TIMESTAMP false // if true, timestamp (from HAL_GetTick) is printed before each log message
|
||||||
|
|
||||||
|
/* Maximum number of backends that can be registered */
|
||||||
|
#define MAX_LOG_BACKENDS 4
|
||||||
|
|
||||||
|
/* Log level definitions */
|
||||||
|
typedef enum {
|
||||||
|
LOG_LEVEL_FATAL,
|
||||||
|
LOG_LEVEL_ERROR,
|
||||||
|
LOG_LEVEL_WARNING,
|
||||||
|
LOG_LEVEL_INFO,
|
||||||
|
LOG_LEVEL_DEBUG,
|
||||||
|
LOG_LEVEL_NOISY
|
||||||
|
} log_level_t;
|
||||||
|
|
||||||
|
/* Log message structure */
|
||||||
|
typedef struct {
|
||||||
|
log_level_t level;
|
||||||
|
uint32_t timestamp;
|
||||||
|
char message[MAX_MESSAGE_LENGTH];
|
||||||
|
size_t message_length;
|
||||||
|
} log_message_t;
|
||||||
|
|
||||||
|
/* Log backend interface */
|
||||||
|
typedef struct {
|
||||||
|
const char* name;
|
||||||
|
void (*init)(void);
|
||||||
|
bool (*is_enabled)(log_level_t level);
|
||||||
|
void (*write)(const log_message_t* message);
|
||||||
|
void (*flush)(void);
|
||||||
|
void (*clear)(void);
|
||||||
|
} log_backend_t;
|
||||||
|
|
||||||
|
/* Log level names with formatting for display */
|
||||||
|
#if USE_ANSI_ESCAPE_CODES
|
||||||
|
[[maybe_unused]] static const char *const log_level_names[] = {
|
||||||
|
"\033[31m[FATAL]\033[0m ", "\033[31m[ERROR]\033[0m ",
|
||||||
|
"\033[93m[WARN] \033[0m ", "\033[97m[INFO] \033[0m ",
|
||||||
|
"\033[37m[DEBUG]\033[0m ", "\033[37m[NOISY]\033[0m "};
|
||||||
|
#else
|
||||||
|
[[maybe_unused]] static const char *const log_level_names[] = {
|
||||||
|
"[FATAL] ", "[ERROR] ", "[WARN] ", "[INFO] ", "[DEBUG] ", "[NOISY] "};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Backend management functions */
|
||||||
|
bool log_register_backend(const log_backend_t* backend);
|
||||||
|
void log_init_all_backends(void);
|
||||||
|
|
||||||
|
/* Frontend logging functions */
|
||||||
|
[[gnu::format(printf, 2, 3)]]
|
||||||
|
void log_message(log_level_t level, const char *msg, ...);
|
||||||
|
|
||||||
|
[[gnu::format(printf, 2, 3)]]
|
||||||
|
void log_message_cont(log_level_t level, const char *msg, ...);
|
||||||
|
|
||||||
|
void log_clear_console(void);
|
||||||
|
|
||||||
|
bool log_is_level_enabled(log_level_t level);
|
||||||
|
|
||||||
|
/* Convenience macros for different log levels */
|
||||||
|
#define log_fatal(fmt, ...) log_message(LOG_LEVEL_FATAL, fmt, ##__VA_ARGS__)
|
||||||
|
#define log_error(fmt, ...) log_message(LOG_LEVEL_ERROR, fmt, ##__VA_ARGS__)
|
||||||
|
#define log_warning(fmt, ...) log_message(LOG_LEVEL_WARNING, fmt, ##__VA_ARGS__)
|
||||||
|
#define log_info(fmt, ...) log_message(LOG_LEVEL_INFO, fmt, ##__VA_ARGS__)
|
||||||
|
#define log_debug(fmt, ...) log_message(LOG_LEVEL_DEBUG, fmt, ##__VA_ARGS__)
|
||||||
|
#define log_noisy(fmt, ...) log_message(LOG_LEVEL_NOISY, fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#endif /* __LOG_H */
|
26
AMS_Master_Code/Core/Lib/logger/swo_log.h
Normal file
26
AMS_Master_Code/Core/Lib/logger/swo_log.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* swo_log.h
|
||||||
|
*
|
||||||
|
* Created on: 20.01.2025
|
||||||
|
* Author: Kilian
|
||||||
|
*
|
||||||
|
* Compatibility header for the new logging system
|
||||||
|
* This allows existing code to continue using swo_log.h without modifications
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#ifndef __SWO_LOG_H
|
||||||
|
#define __SWO_LOG_H
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "swo_log_backend.h"
|
||||||
|
|
||||||
|
/* For backward compatibility with existing code */
|
||||||
|
#define debug_log log_message
|
||||||
|
#define debug_log_cont log_message_cont
|
||||||
|
#define debug_clear_console log_clear_console
|
||||||
|
|
||||||
|
#define DEBUG_CHANNEL_ENABLED(level) log_is_level_enabled(level)
|
||||||
|
|
||||||
|
/* All actual functionality is now in log.h and swo_log_backend.h */
|
||||||
|
|
||||||
|
#endif /* __SWO_LOG_H */
|
136
AMS_Master_Code/Core/Lib/logger/swo_log_backend.c
Normal file
136
AMS_Master_Code/Core/Lib/logger/swo_log_backend.c
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* swo_log_backend.c
|
||||||
|
*
|
||||||
|
* Created on: 21.04.2025
|
||||||
|
* Author: Kilian
|
||||||
|
*
|
||||||
|
* SWO backend implementation for the logging system
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "swo_log_backend.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
/* Global variables */
|
||||||
|
#if USE_CHANNEL_MASK_VARIABLE
|
||||||
|
volatile uint32_t MASK_VARIABLE = 0b11111; // LOG_NOISY off by default
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool swo_backend_registered = false;
|
||||||
|
|
||||||
|
/* SWO utility functions */
|
||||||
|
static inline bool __ITM_channel_enabled(uint32_t channel) {
|
||||||
|
#if !USE_MULTIPLE_CHANNELS
|
||||||
|
#if USE_CHANNEL_MASK_VARIABLE
|
||||||
|
return ((ITM->TER & (1UL << DEBUG_CHANNEL)) != 0UL) &&
|
||||||
|
((MASK_VARIABLE & (1UL << channel)) != 0UL);
|
||||||
|
#else
|
||||||
|
channel = DEBUG_CHANNEL;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return ((ITM->TER & (1UL << channel)) != 0UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// adapted from ITM_SendChar() in the CMSIS-Core
|
||||||
|
// channel should be between 0 and 31
|
||||||
|
static inline uint32_t __swo_putc(uint32_t c, unsigned int channel) {
|
||||||
|
#if !USE_MULTIPLE_CHANNELS
|
||||||
|
channel = DEBUG_CHANNEL;
|
||||||
|
#endif
|
||||||
|
if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */
|
||||||
|
((ITM->TER & (1UL << channel)) != 0UL)) /* ITM Port enabled */
|
||||||
|
{
|
||||||
|
while (ITM->PORT[channel].u32 == 0UL) {
|
||||||
|
__NOP();
|
||||||
|
}
|
||||||
|
ITM->PORT[channel].u8 = (uint8_t)c;
|
||||||
|
}
|
||||||
|
return (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEBUG_CHANNEL_ENABLED(channel) \
|
||||||
|
({ \
|
||||||
|
unsigned int ch = (channel); \
|
||||||
|
(ch < 32) ? __ITM_channel_enabled(ch) : false; \
|
||||||
|
})
|
||||||
|
|
||||||
|
[[gnu::nonnull(2), gnu::null_terminated_string_arg(2)]]
|
||||||
|
static inline void __swo_print(unsigned int channel, const char *str) {
|
||||||
|
if (!__ITM_channel_enabled(channel)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (*str) {
|
||||||
|
__swo_putc(*str++, channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SWO backend functions */
|
||||||
|
static void swo_backend_init(void);
|
||||||
|
static bool swo_backend_is_enabled(log_level_t level);
|
||||||
|
static void swo_backend_write(const log_message_t* message);
|
||||||
|
static void swo_backend_flush(void);
|
||||||
|
static void swo_backend_clear(void);
|
||||||
|
|
||||||
|
/* SWO backend definition */
|
||||||
|
static const log_backend_t swo_backend = {
|
||||||
|
.name = "SWO",
|
||||||
|
.init = swo_backend_init,
|
||||||
|
.is_enabled = swo_backend_is_enabled,
|
||||||
|
.write = swo_backend_write,
|
||||||
|
.flush = swo_backend_flush,
|
||||||
|
.clear = swo_backend_clear
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Return the SWO backend definition */
|
||||||
|
const log_backend_t* swo_log_get_backend(void) {
|
||||||
|
return &swo_backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the SWO backend is registered */
|
||||||
|
bool swo_log_is_backend_registered(void) {
|
||||||
|
return swo_backend_registered;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the SWO backend and register it */
|
||||||
|
void swo_log_backend_init(void) {
|
||||||
|
/* Register the backend */
|
||||||
|
swo_backend_registered = log_register_backend(&swo_backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SWO backend initialization */
|
||||||
|
static void swo_backend_init(void) {
|
||||||
|
/* SWO is initialized by the debugger, nothing to do here */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the SWO backend is enabled for the given log level */
|
||||||
|
static bool swo_backend_is_enabled(log_level_t level) {
|
||||||
|
#if USE_MULTIPLE_CHANNELS
|
||||||
|
return DEBUG_CHANNEL_ENABLED(level);
|
||||||
|
#else
|
||||||
|
return (level <= LOG_LEVEL_NOISY) && DEBUG_CHANNEL_ENABLED(level);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write a message to the SWO backend */
|
||||||
|
static void swo_backend_write(const log_message_t* message) {
|
||||||
|
if (message == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_MULTIPLE_CHANNELS
|
||||||
|
__swo_print(message->level, message->message);
|
||||||
|
#else
|
||||||
|
__swo_print(DEBUG_CHANNEL, message->message);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush the SWO backend - not needed for SWO */
|
||||||
|
static void swo_backend_flush(void) {
|
||||||
|
/* SWO is a real-time interface, no buffering, nothing to flush */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the console for SWO */
|
||||||
|
static void swo_backend_clear(void) {
|
||||||
|
#if USE_ANSI_ESCAPE_CODES
|
||||||
|
__swo_print(DEBUG_CHANNEL, "\033[2J\033[H"); // ANSI escape code to clear screen and move cursor to top-left
|
||||||
|
#endif
|
||||||
|
}
|
35
AMS_Master_Code/Core/Lib/logger/swo_log_backend.h
Normal file
35
AMS_Master_Code/Core/Lib/logger/swo_log_backend.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* swo_log_backend.h
|
||||||
|
*
|
||||||
|
* Created on: 21.04.2025
|
||||||
|
* Author: Kilian
|
||||||
|
*
|
||||||
|
* SWO backend for the logging system
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#ifndef __SWO_LOG_BACKEND_H
|
||||||
|
#define __SWO_LOG_BACKEND_H
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "stm32h7xx_hal.h"
|
||||||
|
|
||||||
|
/* SWO Backend Configuration */
|
||||||
|
#define USE_MULTIPLE_CHANNELS false // if true, each log level has its own channel (FATAL : 0, ERROR : 1, etc.)
|
||||||
|
#if !USE_MULTIPLE_CHANNELS
|
||||||
|
#ifndef DEBUG_CHANNEL
|
||||||
|
#define DEBUG_CHANNEL 0 // channel to output messages on
|
||||||
|
#endif
|
||||||
|
#define USE_CHANNEL_MASK_VARIABLE true
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_CHANNEL_MASK_VARIABLE
|
||||||
|
#define MASK_VARIABLE logging_mask // variable to store the channel mask, must be globally defined somewhere
|
||||||
|
extern volatile uint32_t MASK_VARIABLE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* SWO backend API */
|
||||||
|
void swo_log_backend_init(void);
|
||||||
|
bool swo_log_is_backend_registered(void);
|
||||||
|
const log_backend_t* swo_log_get_backend(void);
|
||||||
|
|
||||||
|
#endif /* __SWO_LOG_BACKEND_H */
|
@ -86,12 +86,11 @@ static void MX_SPI2_Init(void);
|
|||||||
static void MX_ADC1_Init(void);
|
static void MX_ADC1_Init(void);
|
||||||
static void MX_ADC2_Init(void);
|
static void MX_ADC2_Init(void);
|
||||||
/* USER CODE BEGIN PFP */
|
/* USER CODE BEGIN PFP */
|
||||||
|
void init_logging(void);
|
||||||
/* USER CODE END PFP */
|
/* USER CODE END PFP */
|
||||||
|
|
||||||
/* Private user code ---------------------------------------------------------*/
|
/* Private user code ---------------------------------------------------------*/
|
||||||
/* USER CODE BEGIN 0 */
|
/* USER CODE BEGIN 0 */
|
||||||
uint32_t volatile logging_mask = 0b11111; // no LOG_LEVEL_NOISY
|
|
||||||
|
|
||||||
#define MAIN_LOOP_PERIOD 50
|
#define MAIN_LOOP_PERIOD 50
|
||||||
|
|
||||||
@ -128,6 +127,18 @@ static void update_tsal_signals() {
|
|||||||
PRE_and_AIR__open_Pin) == GPIO_PIN_SET;
|
PRE_and_AIR__open_Pin) == GPIO_PIN_SET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Initialize logging system */
|
||||||
|
void init_logging(void) {
|
||||||
|
/* Register and initialize SWO backend */
|
||||||
|
swo_log_backend_init();
|
||||||
|
|
||||||
|
/* Initialize all registered backends */
|
||||||
|
log_init_all_backends();
|
||||||
|
|
||||||
|
/* Log a test message */
|
||||||
|
log_info("Logging system initialized");
|
||||||
|
}
|
||||||
|
|
||||||
/* USER CODE END 0 */
|
/* USER CODE END 0 */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -169,6 +180,7 @@ int main(void)
|
|||||||
MX_ADC1_Init();
|
MX_ADC1_Init();
|
||||||
MX_ADC2_Init();
|
MX_ADC2_Init();
|
||||||
/* USER CODE BEGIN 2 */
|
/* USER CODE BEGIN 2 */
|
||||||
|
init_logging();
|
||||||
debug_clear_console();
|
debug_clear_console();
|
||||||
debug_log(LOG_LEVEL_INFO, "AMS_Master on %s (%s), compiled at %s", COMMIT_BRANCH, COMMIT_HASH, COMPILE_DATE);
|
debug_log(LOG_LEVEL_INFO, "AMS_Master on %s (%s), compiled at %s", COMMIT_BRANCH, COMMIT_HASH, COMPILE_DATE);
|
||||||
debug_log(LOG_LEVEL_INFO, "Starting BMS...");
|
debug_log(LOG_LEVEL_INFO, "Starting BMS...");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user