From 18f6d62c7b7c192bb1ed35a1df6c6eda8eb35f0a Mon Sep 17 00:00:00 2001 From: Kilian Bracher Date: Tue, 20 May 2025 16:00:40 +0200 Subject: [PATCH] refactor swo output --- .../Core/Lib/logger/swo_log_backend.c | 77 ++---- AMS_Master_Code/Core/Lib/logger/swo_util.c | 45 ++++ AMS_Master_Code/Core/Lib/logger/swo_util.h | 15 ++ .../Core/Src/print_master_status.c | 109 ++++---- .../Core/Src/print_module_status.c | 233 ++++++++---------- 5 files changed, 239 insertions(+), 240 deletions(-) create mode 100644 AMS_Master_Code/Core/Lib/logger/swo_util.c create mode 100644 AMS_Master_Code/Core/Lib/logger/swo_util.h diff --git a/AMS_Master_Code/Core/Lib/logger/swo_log_backend.c b/AMS_Master_Code/Core/Lib/logger/swo_log_backend.c index 88ac8bd..92cf487 100644 --- a/AMS_Master_Code/Core/Lib/logger/swo_log_backend.c +++ b/AMS_Master_Code/Core/Lib/logger/swo_log_backend.c @@ -9,6 +9,7 @@ #include "swo_log_backend.h" #include "log.h" +#include "swo_util.h" // Added include for the new utility functions /* Global variables */ #if USE_CHANNEL_MASK_VARIABLE @@ -17,52 +18,6 @@ volatile uint32_t MASK_VARIABLE = 0b11111; // LOG_NOISY off by default 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); @@ -103,23 +58,39 @@ static void swo_backend_init(void) { /* Check if the SWO backend is enabled for the given log level */ static bool swo_backend_is_enabled(log_level_t level) { + unsigned int channel_to_check; #if USE_MULTIPLE_CHANNELS - return DEBUG_CHANNEL_ENABLED(level); + channel_to_check = level; #else - return (level <= LOG_LEVEL_NOISY) && DEBUG_CHANNEL_ENABLED(level); + channel_to_check = DEBUG_CHANNEL; +#endif + + // swo_util_is_channel_active already checks if channel_to_check < 32 + bool channel_active = swo_util_is_channel_active(channel_to_check); + +#if USE_CHANNEL_MASK_VARIABLE + return channel_active && ((MASK_VARIABLE & (1UL << level)) != 0UL); +#else + #if !USE_MULTIPLE_CHANNELS && !USE_CHANNEL_MASK_VARIABLE + return (level <= LOG_LEVEL_NOISY) && channel_active; + #else + return channel_active; + #endif #endif } /* Write a message to the SWO backend */ static void swo_backend_write(const log_message_t* message) { - if (message == NULL) { + if (message == NULL) { // Corrected null check return; } - + // Assuming message->message is ensured to be non-NULL by the logger core if message itself is not NULL. + // Or, if message->message can be NULL, the caller of swo_util_puts should handle it or swo_util_puts should be robust to it. + #if USE_MULTIPLE_CHANNELS - __swo_print(message->level, message->message); + swo_util_puts(message->message, message->level); #else - __swo_print(DEBUG_CHANNEL, message->message); + swo_util_puts(message->message, DEBUG_CHANNEL); #endif } @@ -131,6 +102,6 @@ static void swo_backend_flush(void) { /* 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 + swo_util_puts("\033[2J\033[H", DEBUG_CHANNEL); // ANSI escape code to clear screen and move cursor to top-left #endif } \ No newline at end of file diff --git a/AMS_Master_Code/Core/Lib/logger/swo_util.c b/AMS_Master_Code/Core/Lib/logger/swo_util.c new file mode 100644 index 0000000..85fb363 --- /dev/null +++ b/AMS_Master_Code/Core/Lib/logger/swo_util.c @@ -0,0 +1,45 @@ +#include "swo_util.h" +#include "stm32h7xx.h" // For ITM registers, __NOP() and ITM_TCR_ITMENA_Msk, ITM_TER_TER_Msk +#include // For uint32_t +#include // For NULL + +// Core function to send a character to a specific SWO ITM port +// Adapted from ITM_SendChar() in the CMSIS-Core +void swo_util_putc(char c, unsigned int channel) { + if (channel >= 32) return; // Invalid channel + + // Check if ITM is enabled and the specific channel is enabled + 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(); // Wait until STIM Port is ready for new data + } + ITM->PORT[channel].u8 = (uint8_t)c; + } +} + +// Core function to send a null-terminated string to a specific SWO ITM port +void swo_util_puts(const char *s, unsigned int channel) { + if (channel >= 32 || s == NULL) return; // Invalid channel or null string + + // Check if ITM is enabled and the specific channel is enabled + if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ + ((ITM->TER & (1UL << channel)) != 0UL)) /* ITM Port enabled */ + { + while (*s) { + while (ITM->PORT[channel].u32 == 0UL) { + __NOP(); // Wait until STIM Port is ready for new data + } + ITM->PORT[channel].u8 = (uint8_t)(*s++); + } + } +} + +// Checks if a specific ITM channel is active and ready for output +bool swo_util_is_channel_active(unsigned int channel) { + if (channel >= 32) return false; + bool itm_enabled = ((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL); + bool channel_enabled_raw = ((ITM->TER & (1UL << channel)) != 0UL); + return itm_enabled && channel_enabled_raw; +} diff --git a/AMS_Master_Code/Core/Lib/logger/swo_util.h b/AMS_Master_Code/Core/Lib/logger/swo_util.h new file mode 100644 index 0000000..af31099 --- /dev/null +++ b/AMS_Master_Code/Core/Lib/logger/swo_util.h @@ -0,0 +1,15 @@ +#ifndef SWO_UTIL_H +#define SWO_UTIL_H + +#include + +// Core function to send a character to a specific SWO ITM port +void swo_util_putc(char c, unsigned int channel); + +// Core function to send a null-terminated string to a specific SWO ITM port +void swo_util_puts(const char *s, unsigned int channel); + +// Checks if a specific ITM channel is active and ready for output (ITM enabled and channel enabled) +bool swo_util_is_channel_active(unsigned int channel); + +#endif // SWO_UTIL_H diff --git a/AMS_Master_Code/Core/Src/print_master_status.c b/AMS_Master_Code/Core/Src/print_master_status.c index fea5fcb..25fcb08 100644 --- a/AMS_Master_Code/Core/Src/print_master_status.c +++ b/AMS_Master_Code/Core/Src/print_master_status.c @@ -8,81 +8,86 @@ #include "ts_state_machine.h" #include "battery.h" -#define DEBUG_CHANNEL 1 // channel to output messages on -#include "swo_log_backend.h" +#include "swo_util.h" // Use the new SWO utility functions + +#define PRINT_MASTER_STATUS_SWO_CHANNEL 1 // Define the channel for this specific file + +// Macro to simplify snprintf and swo_util_puts call pattern +// The print_buffer is now local to the macro +#define SWO_PRINT_MASTER(fmt, ...) \ + do { \ + snprintf(print_buffer, sizeof(print_buffer), "\n" fmt, ##__VA_ARGS__); \ + swo_util_puts(print_buffer, PRINT_MASTER_STATUS_SWO_CHANNEL); \ + } while (0) void print_master_status() { - auto const backend = swo_log_get_backend(); - - if (!backend->is_enabled(LOG_LEVEL_INFO)) { - return; // No need to print if the backend is not enabled for this log level + if (!swo_util_is_channel_active(PRINT_MASTER_STATUS_SWO_CHANNEL)) { + return; // No need to print if the channel is not active } - log_message_t log_msg = {}; + char print_buffer[256]; - #define swo_write(...) \ - snprintf(log_msg.message, sizeof(log_msg.message), __VA_ARGS__); \ - backend->write(&log_msg); \ - - // clear the console - backend->clear(); + // Clear the console - using the specific channel +#if USE_ANSI_ESCAPE_CODES // This preprocessor directive should be defined in a config or Makefile + swo_util_puts("\033[2J\033[H", PRINT_MASTER_STATUS_SWO_CHANNEL); +#endif - swo_write("------ AMS_Master on %s (%s), compiled at %s ------", COMMIT_BRANCH, + SWO_PRINT_MASTER("------ AMS_Master on %s (%s), compiled at %s ------", COMMIT_BRANCH, COMMIT_HASH, COMPILE_DATE); - swo_write( "\nGeneral:"); - swo_write( " State: %s", TSStateToString(ts_state.current_state)); - swo_write( " Target: %s", TSStateToString(ts_state.target_state)); - swo_write( " Err Source: %s", ts_state.error_source == 0 ? "NONE" : (ts_state.error_source == 0b11 ? "SHUNT, SLAVE" : (ts_state.error_source == 0b01 ? "SHUNT" : "SLAVE"))); - swo_write(" Err type: %s", ts_state.error_type == 0 ? "NONE" : (ts_state.error_type == 0x01 ? "SLAVE_TIMEOUT" : (ts_state.error_type == 0x02 ? "SLAVE_PANIC" : (ts_state.error_type == 0x03 ? "SHUNT_TIMEOUT" : (ts_state.error_type == 0x04 ? "SHUNT_OVERCURRENT" : (ts_state.error_type == 0x05 ? "SHUNT_OVERTEMP" : "UNKNOWN")))))); - swo_write(" HV active: %s", hv_active ? "YES" : "NO"); + SWO_PRINT_MASTER("\nGeneral:"); + SWO_PRINT_MASTER(" State: %s", TSStateToString(ts_state.current_state)); + SWO_PRINT_MASTER(" Target: %s", TSStateToString(ts_state.target_state)); + SWO_PRINT_MASTER(" Err Source: %s", ts_state.error_source == 0 ? "NONE" : (ts_state.error_source == 0b11 ? "SHUNT, SLAVE" : (ts_state.error_source == 0b01 ? "SHUNT" : "SLAVE"))); + SWO_PRINT_MASTER(" Err type: %s", ts_state.error_type == 0 ? "NONE" : (ts_state.error_type == 0x01 ? "SLAVE_TIMEOUT" : (ts_state.error_type == 0x02 ? "SLAVE_PANIC" : (ts_state.error_type == 0x03 ? "SHUNT_TIMEOUT" : (ts_state.error_type == 0x04 ? "SHUNT_OVERCURRENT" : (ts_state.error_type == 0x05 ? "SHUNT_OVERTEMP" : "UNKNOWN")))))); + SWO_PRINT_MASTER(" HV active: %s", hv_active ? "YES" : "NO"); - swo_write("\nRelay positions:"); - swo_write(" SDC: %s", sdc_closed ? "CLOSED" : "OPEN"); - swo_write(" Air-: %s", neg_air_closed ? "CLOSED" : "OPEN"); - swo_write(" Air+: %s", pos_air_closed ? "CLOSED" : "OPEN"); - swo_write(" Precharge: %s", precharge_closed ? "CLOSED" : "OPEN"); - swo_write(" Precharge/Air+ sense: %s", pre_and_air_open ? "HIGH" : "LOW"); + SWO_PRINT_MASTER("\nRelay positions:"); + SWO_PRINT_MASTER(" SDC: %s", sdc_closed ? "CLOSED" : "OPEN"); + SWO_PRINT_MASTER(" Air-: %s", neg_air_closed ? "CLOSED" : "OPEN"); + SWO_PRINT_MASTER(" Air+: %s", pos_air_closed ? "CLOSED" : "OPEN"); + SWO_PRINT_MASTER(" Precharge: %s", precharge_closed ? "CLOSED" : "OPEN"); + SWO_PRINT_MASTER(" Precharge/Air+ sense: %s", pre_and_air_open ? "HIGH" : "LOW"); - swo_write("\nIMD data:"); - swo_write(" State: %s", IMDStateToString(imd_data.state)); - swo_write(" R_iso: %lu kOhm", imd_data.r_iso); - swo_write(" Frequency: %lu Hz", imd_data.freq); - swo_write(" Duty cycle: %lu %%", imd_data.duty_cycle); - swo_write(" Last high: %lu ms", imd_data.last_high); - swo_write(" OK: %s", imd_data.ok ? "YES" : "NO"); + SWO_PRINT_MASTER("\nIMD data:"); + SWO_PRINT_MASTER(" State: %s", IMDStateToString(imd_data.state)); + SWO_PRINT_MASTER(" R_iso: %lu kOhm", imd_data.r_iso); + SWO_PRINT_MASTER(" Frequency: %lu Hz", imd_data.freq); + SWO_PRINT_MASTER(" Duty cycle: %lu %%", imd_data.duty_cycle); + SWO_PRINT_MASTER(" Last high: %lu ms", imd_data.last_high); + SWO_PRINT_MASTER(" OK: %s", imd_data.ok ? "YES" : "NO"); - swo_write("\nShunt data:"); - swo_write(" Voltage: %ld mV", shunt_data.voltage_bat); - swo_write(" Current: %ld mA", shunt_data.current); - swo_write(" Power: %ld W", shunt_data.power); - swo_write(" Energy: %ld Ws", shunt_data.energy); - swo_write(" Temp: %ld °C", shunt_data.busbartemp / 10); - swo_write(" Time delta: %lu ms", HAL_GetTick() - shunt_data.last_message); + SWO_PRINT_MASTER("\nShunt data:"); + SWO_PRINT_MASTER(" Voltage: %ld mV", shunt_data.voltage_bat); + SWO_PRINT_MASTER(" Current: %ld mA", shunt_data.current); + SWO_PRINT_MASTER(" Power: %ld W", shunt_data.power); + SWO_PRINT_MASTER(" Energy: %ld Ws", shunt_data.energy); + SWO_PRINT_MASTER(" Temp: %ld °C", shunt_data.busbartemp / 10); + SWO_PRINT_MASTER(" Time delta: %lu ms", HAL_GetTick() - shunt_data.last_message); - swo_write("\nBattery data:"); - swo_write(" Min/Max voltage: %d mV / %d mV", battery.pack.min_voltage, battery.pack.max_voltage); - swo_write(" Min/Max temp: %d °C / %d °C", battery.pack.min_temp, battery.pack.max_temp); - swo_write(" SoC: %.2f %%", battery.pack.soc); - swo_write(" Module data: Min V | Max V | Min T | Max T"); - for (size_t i = 0; i < N_BMS; i++) { + SWO_PRINT_MASTER("\nBattery data:"); + SWO_PRINT_MASTER(" Min/Max voltage: %d mV / %d mV", battery.pack.min_voltage, battery.pack.max_voltage); + SWO_PRINT_MASTER(" Min/Max temp: %d °C / %d °C", battery.pack.min_temp, battery.pack.max_temp); + SWO_PRINT_MASTER(" SoC: %.2f %%", battery.pack.soc); + SWO_PRINT_MASTER(" Module data: Min V | Max V | Min T | Max T"); + /* for (size_t i = 0; i < N_BMS; i++) { auto module_data = getModuleMinMax(i); - /* #if USE_ANSI_ESCAPE_CODES + #if USE_ANSI_ESCAPE_CODES #define COLOR_MIN "\033[38;5;75m" //blue for min #define COLOR_MAX "\033[38;5;203m" //red for max #define COLOR_RESET "\033[0m" - swo_write(" %2zu: %s%5d mV%s | %s%5d mV%s | %s%3d °C%s | %s%3d °C%s", i, + SWO_PRINT_MASTER(" %2zu: %s%5d mV%s | %s%5d mV%s | %s%3d °C%s | %s%3d °C%s", i, (module_data.min_v == battery.pack.min_voltage) ? COLOR_MIN : "", (module_data.min_v), COLOR_RESET, (module_data.max_v == battery.pack.max_voltage) ? COLOR_MAX : "", (module_data.max_v), COLOR_RESET, (module_data.min_t == battery.pack.min_temp) ? COLOR_MIN : "", (module_data.min_t), COLOR_RESET, (module_data.max_t == battery.pack.max_temp) ? COLOR_MAX : "", (module_data.max_t), COLOR_RESET); #else - swo_write(" %2zu: %5d mV | %5d mV | %3d °C | %3d °C", i, + SWO_PRINT_MASTER(" %2zu: %5d mV | %5d mV | %3d °C | %3d °C", i, module_data.min_v, module_data.max_v, module_data.min_t, module_data.max_t); - #endif */ - } + #endif + } */ - swo_write("\n------ Updated at %lu ------", HAL_GetTick()); + SWO_PRINT_MASTER("\n------ Updated at %lu ------", HAL_GetTick()); } diff --git a/AMS_Master_Code/Core/Src/print_module_status.c b/AMS_Master_Code/Core/Src/print_module_status.c index 092b634..f605ef8 100644 --- a/AMS_Master_Code/Core/Src/print_module_status.c +++ b/AMS_Master_Code/Core/Src/print_module_status.c @@ -3,156 +3,119 @@ #include "NTC.h" #include "config_ADBMS6830.h" #include +#include // For snprintf -#define DEBUG_CHANNEL 2 // channel to output messages on -#include "swo_log_backend.h" +#include "swo_util.h" // Use the new SWO utility functions + +#define PRINT_MODULE_STATUS_SWO_CHANNEL 2 // Define the channel for this specific file + +// Macro to simplify snprintf and swo_util_puts call pattern +#define SWO_PRINT_MODULE(fmt, ...) \ + do { \ + char print_buffer[256]; \ + snprintf(print_buffer, sizeof(print_buffer), "\n" fmt, ##__VA_ARGS__); \ + swo_util_puts(print_buffer, PRINT_MODULE_STATUS_SWO_CHANNEL); \ + } while (0) void print_battery_info() { - auto const backend = swo_log_get_backend(); - - if (!backend->is_enabled(LOG_LEVEL_INFO)) { - return; // No need to print if the backend is not enabled for this log level + if (!swo_util_is_channel_active(PRINT_MODULE_STATUS_SWO_CHANNEL)) { + return; // No need to print if the channel is not active } - log_message_t log_msg = {}; + // Clear the console - using the specific channel +#if USE_ANSI_ESCAPE_CODES // This preprocessor directive should be defined in a config or Makefile + swo_util_puts("\033[2J\033[H", PRINT_MODULE_STATUS_SWO_CHANNEL); +#endif - #define swo_write(...) \ - snprintf(log_msg.message, sizeof(log_msg.message), __VA_ARGS__); \ - backend->write(&log_msg); \ - - // clear the console - backend->clear(); + SWO_PRINT_MODULE("------ AMS_Master on %s (%s), compiled at %s ------\n", COMMIT_BRANCH, + COMMIT_HASH, COMPILE_DATE); - swo_write("------ AMS_Master on %s (%s), compiled at %s ------\n", COMMIT_BRANCH, - COMMIT_HASH, COMPILE_DATE); + for (size_t i = 0; i < N_BMS; i++) { + SWO_PRINT_MODULE("Module %zu status:", i); + SWO_PRINT_MODULE(" BMS ID: 0x%08lx%08lx", (uint32_t)(bms_data[i].bmsID >> 32), (uint32_t)(bms_data[i].bmsID & 0xFFFFFFFF)); - for (size_t i = 0; i < N_BMS; i++) { - swo_write("Module %d status:", i); - swo_write(" BMS ID: 0x%08lx%08lx", (uint32_t)(bms_data[i].bmsID >> 32), (uint32_t)(bms_data[i].bmsID & 0xFFFFFFFF)); + // Print cell voltages in 4x4 format + SWO_PRINT_MODULE(" Cell voltages (mV):"); + SWO_PRINT_MODULE(" C0: %4d C1: %4d C2: %4d C3: %4d", + bms_data[i].cellVoltages[0], bms_data[i].cellVoltages[1], + bms_data[i].cellVoltages[2], bms_data[i].cellVoltages[3]); + SWO_PRINT_MODULE(" C4: %4d C5: %4d C6: %4d C7: %4d", + bms_data[i].cellVoltages[4], bms_data[i].cellVoltages[5], + bms_data[i].cellVoltages[6], bms_data[i].cellVoltages[7]); + SWO_PRINT_MODULE(" C8: %4d C9: %4d C10: %4d C11: %4d", + bms_data[i].cellVoltages[8], bms_data[i].cellVoltages[9], + bms_data[i].cellVoltages[10], bms_data[i].cellVoltages[11]); + SWO_PRINT_MODULE(" C12: %4d C13: %4d C14: %4d C15: %4d", + bms_data[i].cellVoltages[12], bms_data[i].cellVoltages[13], + bms_data[i].cellVoltages[14], bms_data[i].cellVoltages[15]); - // Print cell voltages in 4x4 format - swo_write(" Cell voltages (mV):"); - swo_write(" C0: %4d C1: %4d C2: %4d C3: %4d", - bms_data[i].cellVoltages[0], bms_data[i].cellVoltages[1], - bms_data[i].cellVoltages[2], bms_data[i].cellVoltages[3]); - swo_write(" C4: %4d C5: %4d C6: %4d C7: %4d", - bms_data[i].cellVoltages[4], bms_data[i].cellVoltages[5], - bms_data[i].cellVoltages[6], bms_data[i].cellVoltages[7]); - swo_write(" C8: %4d C9: %4d C10: %4d C11: %4d", - bms_data[i].cellVoltages[8], bms_data[i].cellVoltages[9], - bms_data[i].cellVoltages[10], bms_data[i].cellVoltages[11]); - swo_write(" C12: %4d C13: %4d C14: %4d C15: %4d", - bms_data[i].cellVoltages[12], bms_data[i].cellVoltages[13], - bms_data[i].cellVoltages[14], bms_data[i].cellVoltages[15]); + // Print GPIO values + SWO_PRINT_MODULE(" GPIO voltages (mV):"); + SWO_PRINT_MODULE( + " G0: %4d G1: %4d G2: %4d G3: %4d G4: %4d", + bms_data[i].auxVoltages[0], bms_data[i].auxVoltages[1], + bms_data[i].auxVoltages[2], bms_data[i].auxVoltages[3], + bms_data[i].auxVoltages[4]); + SWO_PRINT_MODULE( + " G5: %4d G6: %4d G7: %4d G8: %4d G9: %4d", + bms_data[i].auxVoltages[5], bms_data[i].auxVoltages[6], + bms_data[i].auxVoltages[7], bms_data[i].auxVoltages[8], + bms_data[i].auxVoltages[9]); - // Print GPIO values - swo_write(" GPIO voltages (mV):"); - swo_write( - " G0: %4d G1: %4d G2: %4d G3: %4d G4: %4d", - bms_data[i].auxVoltages[0], bms_data[i].auxVoltages[1], - bms_data[i].auxVoltages[2], bms_data[i].auxVoltages[3], - bms_data[i].auxVoltages[4]); - swo_write( - " G5: %4d G6: %4d G7: %4d G8: %4d G9: %4d", - bms_data[i].auxVoltages[5], bms_data[i].auxVoltages[6], - bms_data[i].auxVoltages[7], bms_data[i].auxVoltages[8], - bms_data[i].auxVoltages[9]); + // Print temperatures + SWO_PRINT_MODULE(" GPIO as temperatures (°C):"); + SWO_PRINT_MODULE( + " G0: %4d G1: %4d G2: %4d G3: %4d G4: %4d", + battery.module[i].cellTemps[0], battery.module[i].cellTemps[1], battery.module[i].cellTemps[2], + battery.module[i].cellTemps[3], battery.module[i].cellTemps[4]); + SWO_PRINT_MODULE( + " G5: %4d G6: %4d G7: %4d G8: %4d G9: %4d", + battery.module[i].cellTemps[5], battery.module[i].cellTemps[6], battery.module[i].cellTemps[7], + battery.module[i].cellTemps[8], battery.module[i].cellTemps[9]); - // Print temperatures - swo_write(" GPIO as temperatures (°C):"); - swo_write( - " G0: %4d G1: %4d G2: %4d G3: %4d G4: %4d", - battery.module[i].cellTemps[0], battery.module[i].cellTemps[1], battery.module[i].cellTemps[2], - battery.module[i].cellTemps[3], battery.module[i].cellTemps[4]); - swo_write( - " G5: %4d G6: %4d G7: %4d G8: %4d G9: %4d", - battery.module[i].cellTemps[5], battery.module[i].cellTemps[6], battery.module[i].cellTemps[7], - battery.module[i].cellTemps[8], battery.module[i].cellTemps[9]); + SWO_PRINT_MODULE( + " Internal temp: %d, VAnalog: %d, VDigital: %d, VRef: %d", + bms_data[i].internalDieTemp, bms_data[i].analogSupplyVoltage, + bms_data[i].digitalSupplyVoltage, bms_data[i].refVoltage); - swo_write( - " Internal temp: %d, VAnalog: %d, VDigital: %d, VRef: %d", - bms_data[i].internalDieTemp, bms_data[i].analogSupplyVoltage, - bms_data[i].digitalSupplyVoltage, bms_data[i].refVoltage); + // Print error flags if any are set + bool hasFlags = false; + char flagBuffer[128] = ""; + char *bufPos = flagBuffer; - // Print error flags if any are set - bool hasFlags = false; - char flagBuffer[128] = ""; - char *bufPos = flagBuffer; + if (bms_data[i].status.CS_FLT) { bufPos = stpcpy(bufPos, "CS_FLT "); hasFlags = true; } + if (bms_data[i].status.SMED) { bufPos = stpcpy(bufPos, "SMED "); hasFlags = true; } + if (bms_data[i].status.SED) { bufPos = stpcpy(bufPos, "SED "); hasFlags = true; } + if (bms_data[i].status.CMED) { bufPos = stpcpy(bufPos, "CMED "); hasFlags = true; } + if (bms_data[i].status.CED) { bufPos = stpcpy(bufPos, "CED "); hasFlags = true; } + if (bms_data[i].status.VD_UV) { bufPos = stpcpy(bufPos, "VD_UV "); hasFlags = true; } + if (bms_data[i].status.VD_OV) { bufPos = stpcpy(bufPos, "VD_OV "); hasFlags = true; } + if (bms_data[i].status.VA_UV) { bufPos = stpcpy(bufPos, "VA_UV "); hasFlags = true; } + if (bms_data[i].status.VA_OV) { bufPos = stpcpy(bufPos, "VA_OV "); hasFlags = true; } + if (bms_data[i].status.THSD) { bufPos = stpcpy(bufPos, "THSD "); hasFlags = true; } + if (bms_data[i].status.SLEEP) { bufPos = stpcpy(bufPos, "SLEEP "); hasFlags = true; } + if (bms_data[i].status.SPIFLT) { bufPos = stpcpy(bufPos, "SPIFLT "); hasFlags = true; } + if (bms_data[i].status.COMPARE) { bufPos = stpcpy(bufPos, "COMPARE "); hasFlags = true; } + if (bms_data[i].status.VDE) { bufPos = stpcpy(bufPos, "VDE "); hasFlags = true; } + if (bms_data[i].status.VDEL) { bufPos = stpcpy(bufPos, "VDEL "); hasFlags = true; } - if (bms_data[i].status.CS_FLT) { - bufPos = stpcpy(bufPos, "CS_FLT "); - hasFlags = true; - } - if (bms_data[i].status.SMED) { - bufPos = stpcpy(bufPos, "SMED "); - hasFlags = true; - } - if (bms_data[i].status.SED) { - bufPos = stpcpy(bufPos, "SED "); - hasFlags = true; - } - if (bms_data[i].status.CMED) { - bufPos = stpcpy(bufPos, "CMED "); - hasFlags = true; - } - if (bms_data[i].status.CED) { - bufPos = stpcpy(bufPos, "CED "); - hasFlags = true; - } - if (bms_data[i].status.VD_UV) { - bufPos = stpcpy(bufPos, "VD_UV "); - hasFlags = true; - } - if (bms_data[i].status.VD_OV) { - bufPos = stpcpy(bufPos, "VD_OV "); - hasFlags = true; - } - if (bms_data[i].status.VA_UV) { - bufPos = stpcpy(bufPos, "VA_UV "); - hasFlags = true; - } - if (bms_data[i].status.VA_OV) { - bufPos = stpcpy(bufPos, "VA_OV "); - hasFlags = true; - } - if (bms_data[i].status.THSD) { - bufPos = stpcpy(bufPos, "THSD "); - hasFlags = true; - } - if (bms_data[i].status.SLEEP) { - bufPos = stpcpy(bufPos, "SLEEP "); - hasFlags = true; - } - if (bms_data[i].status.SPIFLT) { - bufPos = stpcpy(bufPos, "SPIFLT "); - hasFlags = true; - } - if (bms_data[i].status.COMPARE) { - bufPos = stpcpy(bufPos, "COMPARE "); - hasFlags = true; - } - if (bms_data[i].status.VDE) { - bufPos = stpcpy(bufPos, "VDE "); - hasFlags = true; - } - if (bms_data[i].status.VDEL) { - bufPos = stpcpy(bufPos, "VDEL "); - hasFlags = true; - } + SWO_PRINT_MODULE(" Status flags: %s", hasFlags ? flagBuffer : "[none]"); - swo_write(" Status flags: %s", hasFlags ? flagBuffer : "[none]"); - - if (bms_data[i].status.CS_FLT) { // Print out which ADCs are faulting - swo_write("Comparison fault on ADC/Cell(s): "); - for (ssize_t j = 0; j < 16; j++) { - if (bms_data[i].status.CS_FLT & (1u << j)) { - swo_write("%d ", j); - } + if (bms_data[i].status.CS_FLT) { + // For this specific case, building the string piece by piece is clearer than a complex SWO_PRINT_MODULE + char temp_print_buf[128]; + int offset = snprintf(temp_print_buf, sizeof(temp_print_buf), "Comparison fault on ADC/Cell(s): "); + for (int j = 0; j < 16; j++) { + if (bms_data[i].status.CS_FLT & (1u << j)) { + offset += snprintf(temp_print_buf + offset, sizeof(temp_print_buf) - (size_t)offset, "%d ", j); + if (offset >= (int)sizeof(temp_print_buf) - 4) break; } } - - swo_write(" Conversion counter: %d", - bms_data[i].status.CCTS); + swo_util_puts(temp_print_buf, PRINT_MODULE_STATUS_SWO_CHANNEL); } - swo_write("\n------ Updated at %lu ------", HAL_GetTick()); - } \ No newline at end of file + + SWO_PRINT_MODULE(" Conversion counter: %d", + bms_data[i].status.CCTS); + } + SWO_PRINT_MODULE("\n------ Updated at %lu ------", HAL_GetTick()); +} \ No newline at end of file