Compare commits
No commits in common. "3f8e1290fa9be925ad13953b98fab055151eebc1" and "dd4d17c1336f201163f736b96e0581ff3b317284" have entirely different histories.
3f8e1290fa
...
dd4d17c133
@ -52,7 +52,6 @@ static uint8_t calculateCommandPEC(uint8_t* data, uint8_t datalen) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
static uint8_t checkCommandPEC(const uint8_t* data, uint8_t datalen) {
|
||||
if (datalen <= 3) { return 255; }
|
||||
const uint16_t pec = computeCRC15(data, datalen - 2);
|
||||
|
@ -127,7 +127,7 @@ typedef struct {
|
||||
} isotp_validation_result_t;
|
||||
|
||||
// Internal helper function to validate message parameters and find available slot
|
||||
ACCESS(none, 2, 3)
|
||||
[[gnu::access(none, 2, 3)]]
|
||||
static isotp_validation_result_t isotp_validate_message(isotp_conn_id_t conn_id, const uint8_t *data, size_t datalen) {
|
||||
isotp_validation_result_t result = {.status = ISOTP_ERROR, .index = 0};
|
||||
|
||||
@ -169,7 +169,7 @@ static isotp_validation_result_t isotp_validate_message(isotp_conn_id_t conn_id,
|
||||
}
|
||||
|
||||
isotp_status_t isotp_add_message(isotp_conn_id_t conn_id, const uint8_t * data, size_t datalen) {
|
||||
const isotp_validation_result_t result = isotp_validate_message(conn_id, data, datalen);
|
||||
isotp_validation_result_t result = isotp_validate_message(conn_id, data, datalen);
|
||||
|
||||
if (result.status == ISOTP_OK) {
|
||||
// Add message to the queue at the found index
|
||||
@ -187,7 +187,7 @@ isotp_status_t isotp_add_message(isotp_conn_id_t conn_id, const uint8_t * data,
|
||||
|
||||
isotp_status_t isotp_try_add_message(isotp_conn_id_t conn_id, const uint8_t * data, size_t datalen) {
|
||||
// Just validate without adding to the queue
|
||||
const isotp_validation_result_t result = isotp_validate_message(conn_id, data, datalen);
|
||||
isotp_validation_result_t result = isotp_validate_message(conn_id, data, datalen);
|
||||
return result.status;
|
||||
}
|
||||
|
||||
@ -199,8 +199,8 @@ isotp_status_t isotp_try_add_message(isotp_conn_id_t conn_id, const uint8_t * da
|
||||
}
|
||||
|
||||
isotp_status_t isotp_update() {
|
||||
const uint32_t now = isotp_get_time();
|
||||
const uint32_t delta = now - last_called;
|
||||
uint32_t now = isotp_get_time();
|
||||
uint32_t delta = now - last_called;
|
||||
for (size_t i = 0; i < MAX_ISOTP_MESSAGES_IN_FLIGHT; i++) {
|
||||
|
||||
isotp_message msg = {};
|
||||
@ -228,14 +228,15 @@ isotp_status_t isotp_update() {
|
||||
tx_queue[i].data += MAX_ISOTP_DATA_FIRST;
|
||||
|
||||
// Check if we're in broadcast mode - don't wait for flow control
|
||||
if (check_flag(tx_queue[i].conn_id, ISOTP_FLAGS_BROADCAST)) {
|
||||
isotp_conn_id_t conn_id = tx_queue[i].conn_id;
|
||||
|
||||
// Connection ID was already validated during isotp_add_message
|
||||
if (check_flag(conn_id, ISOTP_FLAGS_BROADCAST)) {
|
||||
// In broadcast mode, assume we can send directly
|
||||
tx_queue[i].flow_control.state = ISOTP_CONTINUE;
|
||||
tx_queue[i].flow_control.block_size = 0; // No block size limit
|
||||
tx_queue[i].flow_control.st_min = 0; // No separation time
|
||||
tx_queue[i].flow_control.st_min_counter = 0;
|
||||
tx_queue[i].state = ISOTP_READY;
|
||||
goto ISOTP_SEND_AGAIN; // Send all frames immediately
|
||||
} else {
|
||||
tx_queue[i].timestamp = now; // Set timestamp when entering WAITING_FLOW_CONTROL state
|
||||
tx_queue[i].state = ISOTP_WAITING_FLOW_CONTROL;
|
||||
@ -373,7 +374,7 @@ static isotp_status_t isotp_handle_first_frame(isotp_conn_id_t conn_id, const ui
|
||||
return ISOTP_INVALID_FRAME;
|
||||
}
|
||||
|
||||
const uint16_t length = ((data[0] & 0x0F) << 8) | data[1];
|
||||
uint16_t length = ((data[0] & 0x0F) << 8) | data[1];
|
||||
if (length > MAX_ISOTP_DATA_SIZE_MESSAGE) {
|
||||
return ISOTP_INVALID_FRAME;
|
||||
}
|
||||
@ -414,7 +415,7 @@ static isotp_status_t isotp_handle_consecutive_frame(isotp_conn_id_t conn_id, co
|
||||
return ISOTP_INVALID_FRAME;
|
||||
}
|
||||
|
||||
const uint8_t seq_n = data[0] & 0x0F;
|
||||
uint8_t seq_n = data[0] & 0x0F;
|
||||
|
||||
for (size_t i = 0; i < MAX_ISOTP_MESSAGES_IN_FLIGHT; i++) {
|
||||
if (rx_queue[i].state == ISOTP_DONE || rx_queue[i].state == ISOTP_FAILED || rx_queue[i].conn_id != conn_id) {
|
||||
@ -431,7 +432,7 @@ static isotp_status_t isotp_handle_consecutive_frame(isotp_conn_id_t conn_id, co
|
||||
rx_queue[i].seq_n++;
|
||||
rx_queue[i].seq_n &= 0x0F; // Wrap around sequence number
|
||||
|
||||
const size_t bytes_to_copy = rx_queue[i].remaining <= MAX_ISOTP_DATA_CONSECUTIVE ? rx_queue[i].remaining : MAX_ISOTP_DATA_CONSECUTIVE;
|
||||
size_t bytes_to_copy = rx_queue[i].remaining <= MAX_ISOTP_DATA_CONSECUTIVE ? rx_queue[i].remaining : MAX_ISOTP_DATA_CONSECUTIVE;
|
||||
memcpy(rx_queue[i].data, data + 1, bytes_to_copy);
|
||||
rx_queue[i].data += bytes_to_copy;
|
||||
rx_queue[i].remaining -= bytes_to_copy;
|
||||
@ -455,7 +456,7 @@ static isotp_status_t isotp_handle_single_frame(isotp_conn_id_t conn_id, const u
|
||||
return ISOTP_INVALID_FRAME;
|
||||
}
|
||||
|
||||
const uint8_t length = data[0] & 0x0F;
|
||||
uint8_t length = data[0] & 0x0F;
|
||||
if (length > MAX_ISOTP_DATA_SINGLE) {
|
||||
return ISOTP_INVALID_FRAME;
|
||||
}
|
||||
@ -479,9 +480,9 @@ static isotp_status_t isotp_handle_flow_control(isotp_conn_id_t conn_id, const u
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint8_t status = data[0] & 0x0F;
|
||||
const uint8_t block_size = data[1];
|
||||
const uint8_t st_min = data[2];
|
||||
uint8_t status = data[0] & 0x0F;
|
||||
uint8_t block_size = data[1];
|
||||
uint8_t st_min = data[2];
|
||||
|
||||
switch (status) {
|
||||
case ISOTP_FC_CTS: // Continue
|
||||
@ -528,7 +529,7 @@ isotp_status_t isotp_handle_incoming(uint16_t id, const uint8_t * data, size_t d
|
||||
return ISOTP_CONNECTION_NOT_FOUND;
|
||||
}
|
||||
|
||||
const uint8_t type = data[0] & 0xF0;
|
||||
uint8_t type = data[0] & 0xF0;
|
||||
|
||||
switch (type) {
|
||||
#if ISOTP_RX
|
||||
|
@ -11,7 +11,7 @@
|
||||
#define ISOTP_RX false // enable RX support
|
||||
#define ISOTP_RX_TIMEOUT 1000 // Timeout for incoming messages (ms)
|
||||
#define ISOTP_RX_MIN_ST 0 // Minimum ST for flow control (ms)
|
||||
//#define ISOTP_PADDING 0xAA // optional padding byte
|
||||
//#define ISOTP_PADDING 0xAA // optional padding byte
|
||||
|
||||
typedef enum isotp_status {
|
||||
ISOTP_OK = 0,
|
||||
@ -50,19 +50,7 @@ static inline const char *isotp_status_to_string(isotp_status_t status) {
|
||||
}
|
||||
}
|
||||
|
||||
#if __has_attribute(flag_enum)
|
||||
#define FLAG_ENUM [[clang::flag_enum]]
|
||||
#else
|
||||
#define FLAG_ENUM
|
||||
#endif
|
||||
|
||||
#if __has_attribute(access)
|
||||
#define ACCESS(access_type, ...) [[gnu::access(access_type, __VA_ARGS__)]]
|
||||
#else
|
||||
#define ACCESS(access_type, ...)
|
||||
#endif
|
||||
|
||||
typedef enum FLAG_ENUM {
|
||||
typedef enum [[clang::flag_enum]] {
|
||||
ISOTP_FLAGS_NONE = 0,
|
||||
ISOTP_FLAGS_LISTEN_ONLY = 1 << 0, // do not send flow control frames
|
||||
ISOTP_FLAGS_BROADCAST = 1 << 1, // linux socketcan broadcast (do not wait for flow control)
|
||||
@ -73,7 +61,7 @@ typedef uint16_t isotp_conn_id_t;
|
||||
|
||||
isotp_status_t isotp_init();
|
||||
isotp_status_t isotp_update();
|
||||
ACCESS(read_only, 2, 3) isotp_status_t isotp_handle_incoming(uint16_t id, const uint8_t *data, size_t datalen);
|
||||
[[gnu::access(read_only, 2, 3)]] isotp_status_t isotp_handle_incoming(uint16_t id, const uint8_t *data, size_t datalen);
|
||||
/**
|
||||
* @brief Add a new connection to the isotp stack.
|
||||
* @param them The CAN ID of the remote device.
|
||||
@ -83,7 +71,7 @@ ACCESS(read_only, 2, 3) isotp_status_t isotp_handle_incoming(uint16_t id, const
|
||||
* On failure: One of the negative isotp_status_t error codes.
|
||||
*/
|
||||
int isotp_add_connection(uint16_t them, uint16_t us, isotp_flags_t flags);
|
||||
ACCESS(read_only, 2, 3) isotp_status_t isotp_add_message(isotp_conn_id_t conn_id, const uint8_t * data, size_t datalen);
|
||||
ACCESS(none, 2, 3) isotp_status_t isotp_try_add_message(isotp_conn_id_t conn_id, const uint8_t * data, size_t datalen);
|
||||
[[gnu::access(read_only, 2, 3)]] isotp_status_t isotp_add_message(isotp_conn_id_t conn_id, const uint8_t * data, size_t datalen);
|
||||
[[gnu::access(none, 2, 3)]] isotp_status_t isotp_try_add_message(isotp_conn_id_t conn_id, const uint8_t * data, size_t datalen);
|
||||
|
||||
#endif // ISOTP_H
|
@ -9,7 +9,6 @@
|
||||
|
||||
#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
|
||||
@ -18,6 +17,52 @@ 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);
|
||||
@ -58,39 +103,23 @@ 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
|
||||
channel_to_check = level;
|
||||
return DEBUG_CHANNEL_ENABLED(level);
|
||||
#else
|
||||
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
|
||||
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) { // Corrected null check
|
||||
if (message == NULL) {
|
||||
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_util_puts(message->message, message->level);
|
||||
__swo_print(message->level, message->message);
|
||||
#else
|
||||
swo_util_puts(message->message, DEBUG_CHANNEL);
|
||||
__swo_print(DEBUG_CHANNEL, message->message);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -102,6 +131,6 @@ static void swo_backend_flush(void) {
|
||||
/* Clear the console for SWO */
|
||||
static void swo_backend_clear(void) {
|
||||
#if USE_ANSI_ESCAPE_CODES
|
||||
swo_util_puts("\033[2J\033[H", DEBUG_CHANNEL); // ANSI escape code to clear screen and move cursor to top-left
|
||||
__swo_print(DEBUG_CHANNEL, "\033[2J\033[H"); // ANSI escape code to clear screen and move cursor to top-left
|
||||
#endif
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
#include "swo_util.h"
|
||||
#include "stm32h7xx.h" // For ITM registers, __NOP() and ITM_TCR_ITMENA_Msk, ITM_TER_TER_Msk
|
||||
#include <stdint.h> // For uint32_t
|
||||
#include <stddef.h> // 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;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
#ifndef SWO_UTIL_H
|
||||
#define SWO_UTIL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
// 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
|
@ -8,86 +8,81 @@
|
||||
#include "ts_state_machine.h"
|
||||
#include "battery.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)
|
||||
#define DEBUG_CHANNEL 1 // channel to output messages on
|
||||
#include "swo_log_backend.h"
|
||||
|
||||
void print_master_status() {
|
||||
if (!swo_util_is_channel_active(PRINT_MASTER_STATUS_SWO_CHANNEL)) {
|
||||
return; // No need to print if the channel is not active
|
||||
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
|
||||
}
|
||||
|
||||
char print_buffer[256];
|
||||
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_MASTER_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_MASTER("------ AMS_Master on %s (%s), compiled at %s ------", COMMIT_BRANCH,
|
||||
swo_write("------ AMS_Master on %s (%s), compiled at %s ------", COMMIT_BRANCH,
|
||||
COMMIT_HASH, COMPILE_DATE);
|
||||
|
||||
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( "\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("\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("\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("\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("\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("\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("\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("\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++) {
|
||||
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++) {
|
||||
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_PRINT_MASTER(" %2zu: %s%5d mV%s | %s%5d mV%s | %s%3d °C%s | %s%3d °C%s", i,
|
||||
swo_write(" %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_PRINT_MASTER(" %2zu: %5d mV | %5d mV | %3d °C | %3d °C", i,
|
||||
swo_write(" %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_PRINT_MASTER("\n------ Updated at %lu ------", HAL_GetTick());
|
||||
swo_write("\n------ Updated at %lu ------", HAL_GetTick());
|
||||
}
|
||||
|
||||
|
@ -3,119 +3,156 @@
|
||||
#include "NTC.h"
|
||||
#include "config_ADBMS6830.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h> // For snprintf
|
||||
|
||||
#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)
|
||||
#define DEBUG_CHANNEL 2 // channel to output messages on
|
||||
#include "swo_log_backend.h"
|
||||
|
||||
void print_battery_info() {
|
||||
if (!swo_util_is_channel_active(PRINT_MODULE_STATUS_SWO_CHANNEL)) {
|
||||
return; // No need to print if the channel is not active
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
log_message_t log_msg = {};
|
||||
|
||||
SWO_PRINT_MODULE("------ AMS_Master on %s (%s), compiled at %s ------\n", COMMIT_BRANCH,
|
||||
COMMIT_HASH, COMPILE_DATE);
|
||||
#define swo_write(...) \
|
||||
snprintf(log_msg.message, sizeof(log_msg.message), __VA_ARGS__); \
|
||||
backend->write(&log_msg); \
|
||||
|
||||
// clear the console
|
||||
backend->clear();
|
||||
|
||||
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));
|
||||
swo_write("------ AMS_Master on %s (%s), compiled at %s ------\n", COMMIT_BRANCH,
|
||||
COMMIT_HASH, COMPILE_DATE);
|
||||
|
||||
// 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]);
|
||||
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 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 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 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 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]);
|
||||
|
||||
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);
|
||||
// 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]);
|
||||
|
||||
// Print error flags if any are set
|
||||
bool hasFlags = false;
|
||||
char flagBuffer[128] = "";
|
||||
char *bufPos = flagBuffer;
|
||||
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);
|
||||
|
||||
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; }
|
||||
// Print error flags if any are set
|
||||
bool hasFlags = false;
|
||||
char flagBuffer[128] = "";
|
||||
char *bufPos = flagBuffer;
|
||||
|
||||
SWO_PRINT_MODULE(" Status flags: %s", hasFlags ? flagBuffer : "[none]");
|
||||
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) {
|
||||
// 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(" 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
swo_util_puts(temp_print_buf, PRINT_MODULE_STATUS_SWO_CHANNEL);
|
||||
}
|
||||
|
||||
SWO_PRINT_MODULE(" Conversion counter: %d",
|
||||
bms_data[i].status.CCTS);
|
||||
}
|
||||
SWO_PRINT_MODULE("\n------ Updated at %lu ------", HAL_GetTick());
|
||||
}
|
||||
swo_write(" Conversion counter: %d",
|
||||
bms_data[i].status.CCTS);
|
||||
}
|
||||
swo_write("\n------ Updated at %lu ------", HAL_GetTick());
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user