From 162f58abe2f05f6cad0331bce628457a5e12af40 Mon Sep 17 00:00:00 2001 From: Kilian Bracher Date: Sat, 3 May 2025 14:47:06 +0200 Subject: [PATCH] update to new isotp stack, send voltages every ~50 ms --- AMS_Master_Code/Core/Inc/battery.h | 2 +- AMS_Master_Code/Core/Inc/can.h | 9 +- .../ADBMS6830B_Driver/Core/Inc/ADBMS_Driver.h | 15 +- AMS_Master_Code/Core/Lib/isotp/isotp.c | 319 ++++++++++++++++-- AMS_Master_Code/Core/Lib/isotp/isotp.h | 25 +- .../Core/Lib/isotp/isotp_user_defs.h | 15 + .../Core/Lib/logger/isotp_log_backend.c | 11 +- .../Core/Lib/logger/isotp_log_backend.h | 7 +- AMS_Master_Code/Core/Src/battery.c | 2 +- AMS_Master_Code/Core/Src/can.c | 91 ++++- AMS_Master_Code/Core/Src/main.c | 3 + 11 files changed, 438 insertions(+), 61 deletions(-) create mode 100644 AMS_Master_Code/Core/Lib/isotp/isotp_user_defs.h diff --git a/AMS_Master_Code/Core/Inc/battery.h b/AMS_Master_Code/Core/Inc/battery.h index afdd6e5..7d43ea3 100644 --- a/AMS_Master_Code/Core/Inc/battery.h +++ b/AMS_Master_Code/Core/Inc/battery.h @@ -14,7 +14,7 @@ extern int16_t min_temp; extern struct {int16_t min; int16_t max;} module_temps[N_BMS]; extern float module_std_deviation[N_BMS]; -extern int16_t cellTemps[N_BMS][N_CELLS]; +extern int16_t cellTemps[N_BMS][10]; HAL_StatusTypeDef battery_init(SPI_HandleTypeDef* hspi); HAL_StatusTypeDef battery_update(); diff --git a/AMS_Master_Code/Core/Inc/can.h b/AMS_Master_Code/Core/Inc/can.h index e9da84f..a71fd5e 100644 --- a/AMS_Master_Code/Core/Inc/can.h +++ b/AMS_Master_Code/Core/Inc/can.h @@ -11,6 +11,11 @@ #define CAN_ID_AMS_ERROR 0x00C #define CAN_ID_SLAVE_STATUS_BASE 0x080 #define CAN_ID_AMS_SIGNALS 0x090 + +//TEMPORARY!! +#define CAN_ID_AMS_DETAILS 0x091 +#define CAN_ID_AMS_DETAILS_FC 0x092 + #define CAN_ID_SLAVE_LOG 0x4F4 #define CAN_ID_SHUNT_BASE 0x520 #define CAN_ID_SHUNT_CURRENT 0x521 @@ -22,12 +27,10 @@ #define CAN_ID_SHUNT_CURRENT_COUNTER 0x527 #define CAN_ID_SHUNT_ENERGY_COUNTER 0x528 -//TEMP until final IDs are defined -#define CAN_ID_LOG_FC 0x132 - void can_init(FDCAN_HandleTypeDef *handle); HAL_StatusTypeDef can_send_status(); HAL_StatusTypeDef can_send_error(TSErrorKind kind, uint8_t arg); +HAL_StatusTypeDef can_send_details(); void ftcan_msg_received_cb(uint16_t id, size_t datalen, const uint8_t *data); diff --git a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_Driver.h b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_Driver.h index c527efc..475ebb1 100644 --- a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_Driver.h +++ b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_Driver.h @@ -74,20 +74,19 @@ struct ADBMS6830_Internal_Status { #define MAXIMUM_GPIO 10 typedef struct { - int16_t cellVoltages[MAXIMUM_CELL_VOLTAGES]; - int16_t auxVoltages[MAXIMUM_AUX_VOLTAGES]; uint64_t bmsID; - struct ADBMS6830_Internal_Status status; - int16_t internalDieTemp; - uint16_t analogSupplyVoltage; - uint16_t digitalSupplyVoltage; - uint16_t sumOfCellMeasurements; - uint16_t refVoltage; uint32_t overVoltage; // Bitfield of overvoltage flags uint32_t underVoltage; // " undervoltage " + int16_t internalDieTemp; + uint16_t refVoltage; + uint16_t analogSupplyVoltage; + uint16_t digitalSupplyVoltage; + + int16_t cellVoltages[MAXIMUM_CELL_VOLTAGES]; + int16_t auxVoltages[MAXIMUM_AUX_VOLTAGES]; } Cell_Module; extern uint32_t error_sources; // Bitfield of error sources diff --git a/AMS_Master_Code/Core/Lib/isotp/isotp.c b/AMS_Master_Code/Core/Lib/isotp/isotp.c index f80c558..ec651f7 100644 --- a/AMS_Master_Code/Core/Lib/isotp/isotp.c +++ b/AMS_Master_Code/Core/Lib/isotp/isotp.c @@ -1,7 +1,8 @@ /* * Author: Kilian * Date: 2025-04-20 - * Description: This file contains a TX-only implementation of the ISO-TP protocol. + * Description: This file contains an implementation of the ISO-TP protocol + * with both transmission and reception capabilities. * * References: * https://munich.dissec.to/kb/chapters/isotp/isotp.html#protocol-basics-iso-15765-2 @@ -10,6 +11,7 @@ * https://ramn.readthedocs.io/en/latest/userguide/isotp_tutorial.html */ #include "isotp.h" +#include "isotp_user_defs.h" #include #include @@ -21,6 +23,9 @@ #define MAX_ISOTP_DATA_FIRST 6 #define MAX_ISOTP_DATA_CONSECUTIVE 7 +// check endianness +static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__, "Endianness is not little endian, this code is not portable!"); + typedef union [[gnu::packed]] { struct { uint8_t header; @@ -45,10 +50,17 @@ enum { }; struct isotp_message_state { +#if ISOTP_RX + uint8_t * data; +#else const uint8_t * data; - size_t remaining; +#endif + uint32_t timestamp; + uint16_t remaining; +#if ISOTP_RX + uint16_t data_len; +#endif uint16_t id; - uint32_t timestamp; // Timestamp for timeout handling enum : uint8_t { ISOTP_NEW_MESSAGE = 0, ISOTP_WAITING_FLOW_CONTROL = 1, @@ -66,56 +78,123 @@ struct isotp_message_state { uint8_t st_min; // in ms, we round up to 1 ms if sub 1 ms uint8_t st_min_counter; } flow_control; - uint8_t index; + uint8_t seq_n; }; static struct isotp_message_state tx_queue[MAX_ISOTP_MESSAGES_IN_FLIGHT] = {[0 ... MAX_ISOTP_MESSAGES_IN_FLIGHT - 1] = {.state=ISOTP_DONE }}; -[[gnu::weak]] bool isotp_can_transmit(uint16_t, const uint8_t *, size_t) { return false; } -[[gnu::weak]] uint32_t isotp_can_get_time() { return 0; } +#if ISOTP_RX +static struct isotp_message_state rx_queue[MAX_ISOTP_MESSAGES_IN_FLIGHT] = {[0 ... MAX_ISOTP_MESSAGES_IN_FLIGHT - 1] = {.state=ISOTP_DONE }}; +#endif + +#define INVALID_CAN_ID 0xFFFF + +static struct {uint16_t src_id; uint16_t dst_id;} connections[MAX_ISOTP_CONNECTIONS] = { + [0 ... MAX_ISOTP_CONNECTIONS - 1] = {.src_id=INVALID_CAN_ID, .dst_id=INVALID_CAN_ID} +}; uint32_t last_called; isotp_status_t isotp_init() { // platform-specific initialization - last_called = isotp_can_get_time() - 100; - return (isotp_status_t) {ISOTP_OK}; + last_called = isotp_get_time() - 100; + return ISOTP_OK; } -isotp_status_t isotp_add_message(uint16_t id, const uint8_t * data, size_t datalen) { +#if ISOTP_RX +#define DATA_TYPE uint8_t * +#else +#define DATA_TYPE const uint8_t * +#endif + +// Internal helper structure to return both status and index +typedef struct { + isotp_status_t status; + size_t index; // Index of available slot if status is ISOTP_OK +} isotp_validation_result_t; + +// Internal helper function to validate message parameters and find available slot +[[gnu::access(none, 2, 3)]] +static isotp_validation_result_t isotp_validate_message(uint16_t id, const uint8_t *data, size_t datalen) { + isotp_validation_result_t result = {.status = ISOTP_ERROR, .index = 0}; + if (datalen > MAX_ISOTP_DATA_SIZE_MESSAGE) { - return ISOTP_DATA_TOO_LONG; + result.status = ISOTP_DATA_TOO_LONG; + return result; } if (data == NULL || datalen == 0) { - return ISOTP_INVALID_PARAMETER; + result.status = ISOTP_INVALID_PARAMETER; + return result; } + // Check if connection exists + bool connection_found = false; + for (size_t i = 0; i < MAX_ISOTP_CONNECTIONS; i++) { + if (connections[i].dst_id == id) { + connection_found = true; + break; + } + } + + if (!connection_found) { + result.status = ISOTP_CONNECTION_NOT_FOUND; + return result; + } + + // Check if message with same ID is already in flight for (size_t i = 0; i < MAX_ISOTP_MESSAGES_IN_FLIGHT; i++) { if (!(tx_queue[i].state == ISOTP_DONE || tx_queue[i].state == ISOTP_FAILED) && tx_queue[i].id == id) { - return ISOTP_MESSAGE_ALREADY_IN_FLIGHT; + result.status = ISOTP_MESSAGE_ALREADY_IN_FLIGHT; + return result; } } + // Find available slot for (size_t i = 0; i < MAX_ISOTP_MESSAGES_IN_FLIGHT; i++) { if (tx_queue[i].state == ISOTP_DONE || tx_queue[i].state == ISOTP_FAILED) { - tx_queue[i] = (struct isotp_message_state) {data, datalen, id, 0, ISOTP_NEW_MESSAGE, {}, 1}; - return ISOTP_OK; + result.status = ISOTP_OK; + result.index = i; + return result; } } - return ISOTP_TOO_MANY_MESSAGES; + result.status = ISOTP_TOO_MANY_MESSAGES; + return result; +} + +isotp_status_t isotp_add_message(uint16_t id, const uint8_t * data, size_t datalen) { + isotp_validation_result_t result = isotp_validate_message(id, data, datalen); + + if (result.status == ISOTP_OK) { + // Add message to the queue at the found index + tx_queue[result.index] = (struct isotp_message_state) { + .data = (DATA_TYPE) data, + .id = id, + .state = ISOTP_NEW_MESSAGE, + .seq_n = 1, + .remaining = datalen + }; + } + + return result.status; +} + +isotp_status_t isotp_try_add_message(uint16_t id, const uint8_t * data, size_t datalen) { + // Just validate without adding to the queue + isotp_validation_result_t result = isotp_validate_message(id, data, datalen); + return result.status; } /* Macro to check CAN transmission result and handle errors */ #define TRY_CAN_TRANSMIT(id, data, size) \ - if (!isotp_can_transmit(id, data, size)) { \ + if (!isotp_transmit(id, data, size)) { \ tx_queue[i].state = ISOTP_FAILED; \ return ISOTP_CAN_TRANSMIT_ERROR; \ } isotp_status_t isotp_update() { - uint32_t now = isotp_can_get_time(); + uint32_t now = isotp_get_time(); uint32_t delta = now - last_called; for (size_t i = 0; i < MAX_ISOTP_MESSAGES_IN_FLIGHT; i++) { @@ -160,7 +239,7 @@ isotp_status_t isotp_update() { tx_queue[i].flow_control.block_size--; } - msg.consecutive.header = ISOTP_CONSECUTIVE_FRAME | (tx_queue[i].index & 0x0F); + msg.consecutive.header = ISOTP_CONSECUTIVE_FRAME | (tx_queue[i].seq_n & 0x0F); size_t bytes_to_send = tx_queue[i].remaining <= MAX_ISOTP_DATA_CONSECUTIVE ? tx_queue[i].remaining : MAX_ISOTP_DATA_CONSECUTIVE; memcpy(msg.consecutive.data, tx_queue[i].data, bytes_to_send); @@ -177,7 +256,7 @@ isotp_status_t isotp_update() { tx_queue[i].data += bytes_to_send; tx_queue[i].remaining -= bytes_to_send; - tx_queue[i].index++; + tx_queue[i].seq_n++; if (tx_queue[i].remaining == 0) { tx_queue[i].state = ISOTP_DONE; @@ -199,17 +278,161 @@ isotp_status_t isotp_update() { break; } } + + #if ISOTP_RX + for (size_t i = 0; i < MAX_ISOTP_MESSAGES_IN_FLIGHT; i++) { + if (rx_queue[i].state == ISOTP_READY) { + if (now - rx_queue[i].timestamp > ISOTP_RX_TIMEOUT) { + rx_queue[i].state = ISOTP_FAILED; + } + } + } + #endif last_called = now; return ISOTP_OK; } -isotp_status_t isotp_handle_flow_control(uint16_t id, const uint8_t * data, size_t datalen) { +isotp_status_t isotp_add_connection(uint16_t src_id, uint16_t dst_id) { + for (size_t i = 0; i < MAX_ISOTP_CONNECTIONS; i++) { + if (connections[i].src_id == INVALID_CAN_ID) { + connections[i].src_id = src_id; + connections[i].dst_id = dst_id; + return ISOTP_OK; + } + } + return ISOTP_TOO_MANY_CONNECTIONS; +} + +enum FC_status : uint8_t { + ISOTP_FC_CTS = 0, + ISOTP_FC_WAIT = 1, + ISOTP_FC_ABORT = 2 +}; + +#if ISOTP_RX +static isotp_status_t isotp_send_fc(uint16_t id, enum FC_status status, uint8_t block_size, uint8_t st_min) { + isotp_message msg = {}; + msg.single.header = ISOTP_FLOW_CONTROL | (status & 0x0F); + msg.single.data[0] = block_size; + msg.single.data[1] = st_min; + + #if ISOTP_PADDING + memset(msg.single.data + 2, ISOTP_PADDING, MAX_ISOTP_DATA_SINGLE - 2); + if (!isotp_transmit(id, (const uint8_t *)&msg, MAX_CAN_DATA_SIZE)) { + return ISOTP_CAN_TRANSMIT_ERROR; + } + #else + if (!isotp_transmit(id, (const uint8_t *)&msg, 3)) { + return ISOTP_CAN_TRANSMIT_ERROR; + } + #endif + + return ISOTP_OK; +} + +isotp_status_t isotp_handle_first_frame(uint16_t id, uint16_t dst_id, const uint8_t * data, size_t datalen) { if (datalen < 3) { - return ISOTP_NOT_FLOW_CONTROL; + return ISOTP_INVALID_FRAME; } - if (data == NULL) { - return ISOTP_INVALID_PARAMETER; + uint16_t length = ((data[0] & 0x0F) << 8) | data[1]; + if (length > MAX_ISOTP_DATA_SIZE_MESSAGE) { + return ISOTP_INVALID_FRAME; + } + + 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) { + uint8_t* rx_buffer = isotp_get_rx_buffer(length); + if (rx_buffer == NULL) { + isotp_send_fc(dst_id, ISOTP_FC_ABORT, 0, 0); // Abort + return ISOTP_BUFFER_CREATION_ERROR; + } + + rx_queue[i] = (struct isotp_message_state) { + .data = rx_buffer, + .id = id, + .remaining = length, + .data_len = length, + .state = ISOTP_NEW_MESSAGE, + .seq_n = 1 // Initialize sequence number + }; + memcpy(rx_queue[i].data, data + 2, MAX_ISOTP_DATA_FIRST); + rx_queue[i].remaining -= MAX_ISOTP_DATA_FIRST; + rx_queue[i].data += MAX_ISOTP_DATA_FIRST; + rx_queue[i].timestamp = isotp_get_time(); + rx_queue[i].state = ISOTP_READY; + isotp_send_fc(dst_id, ISOTP_FC_CTS, 0, ISOTP_RX_MIN_ST); // Send flow control frame + return ISOTP_OK; + } + } + isotp_send_fc(dst_id, ISOTP_FC_ABORT, 0, 0); // Abort + return ISOTP_TOO_MANY_MESSAGES; +} + +isotp_status_t isotp_handle_consecutive_frame(uint16_t id, uint16_t dst_id, const uint8_t * data, size_t datalen) { + if (datalen < 2) { + return ISOTP_INVALID_FRAME; + } + + 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].id != id) { + continue; + } + + if (rx_queue[i].seq_n != seq_n) { + isotp_send_fc(dst_id, ISOTP_FC_ABORT, 0, 0); // Abort + rx_queue[i].state = ISOTP_FAILED; + isotp_free_rx_buffer(rx_queue[i].data - rx_queue[i].data_len + rx_queue[i].remaining); // Free the buffer + return ISOTP_INVALID_SEQUENCE; // Sequence number mismatch + } + + rx_queue[i].seq_n++; + rx_queue[i].seq_n &= 0x0F; // Wrap around sequence number + + + 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; + rx_queue[i].timestamp = isotp_get_time(); // Update timestamp for timeout handling + + if (rx_queue[i].remaining == 0) { + rx_queue[i].state = ISOTP_DONE; + isotp_on_message_received(dst_id, rx_queue[i].data - rx_queue[i].data_len, rx_queue[i].data_len); + isotp_free_rx_buffer(rx_queue[i].data - rx_queue[i].data_len); // Free the buffer after message is received + } + + return ISOTP_OK; + } + + isotp_send_fc(dst_id, ISOTP_FC_ABORT, 0, 0); // Abort + return ISOTP_INVALID_PARAMETER; +} + +isotp_status_t isotp_handle_single_frame(uint16_t id, const uint8_t * data, size_t datalen) { + if (datalen < 2) { + return ISOTP_INVALID_FRAME; + } + + uint8_t length = data[0] & 0x0F; + if (length > MAX_ISOTP_DATA_SINGLE) { + return ISOTP_INVALID_FRAME; + } + + if (datalen < (unsigned) (length + 1)) { + return ISOTP_INVALID_FRAME; + } + + isotp_on_message_received(id, data + 1, length); // Send the correct length of data + return ISOTP_OK; +} +#endif // ISOTP_RX + +static isotp_status_t isotp_handle_flow_control(uint16_t id, const uint8_t * data, size_t datalen) { + if (datalen < 3) { + return ISOTP_INVALID_FRAME; } for (size_t i = 0; i < MAX_ISOTP_MESSAGES_IN_FLIGHT; i++) { @@ -217,30 +440,25 @@ isotp_status_t isotp_handle_flow_control(uint16_t id, const uint8_t * data, size continue; } - uint8_t type = data[0] & 0xF0; uint8_t status = data[0] & 0x0F; uint8_t block_size = data[1]; uint8_t st_min = data[2]; - if (type != ISOTP_FLOW_CONTROL) { - return ISOTP_NOT_FLOW_CONTROL; - } - switch (status) { - case 0: // Continue + case ISOTP_FC_CTS: // Continue tx_queue[i].flow_control.state = ISOTP_CONTINUE; break; - case 1: // Wait + case ISOTP_FC_WAIT: // Wait tx_queue[i].flow_control.state = ISOTP_WAIT; tx_queue[i].state = ISOTP_WAITING_FLOW_CONTROL; - tx_queue[i].timestamp = isotp_can_get_time(); // Update timestamp for timeout handling + tx_queue[i].timestamp = isotp_get_time(); // Update timestamp for timeout handling return ISOTP_OK; - case 2: // Abort + case ISOTP_FC_ABORT: // Abort tx_queue[i].flow_control.state = ISOTP_ABORT; tx_queue[i].state = ISOTP_FAILED; return ISOTP_OK; default: - return ISOTP_NOT_FLOW_CONTROL; + return ISOTP_INVALID_FRAME; } tx_queue[i].flow_control.block_size = block_size; @@ -253,3 +471,38 @@ isotp_status_t isotp_handle_flow_control(uint16_t id, const uint8_t * data, size return ISOTP_INVALID_PARAMETER; } +isotp_status_t isotp_handle_incoming(uint16_t id, const uint8_t * data, size_t datalen) { + if (data == NULL) { + return ISOTP_INVALID_PARAMETER; + } + + uint16_t dst_id = INVALID_CAN_ID; + for (size_t i = 0; i < MAX_ISOTP_CONNECTIONS; i++) { + if (connections[i].src_id == id) { + dst_id = connections[i].dst_id; + break; + } + } + + if (dst_id == INVALID_CAN_ID) { + return ISOTP_CONNECTION_NOT_FOUND; + } + + uint8_t type = data[0] & 0xF0; + + switch (type) { +#if ISOTP_RX + case ISOTP_SINGLE_FRAME: + return isotp_handle_single_frame(id, data, datalen); + case ISOTP_FIRST_FRAME: + return isotp_handle_first_frame(id, dst_id, data, datalen); + case ISOTP_CONSECUTIVE_FRAME: + return isotp_handle_consecutive_frame(id, dst_id, data, datalen); +#endif + case ISOTP_FLOW_CONTROL: + return isotp_handle_flow_control(dst_id, data, datalen); + default: + return ISOTP_INVALID_FRAME; + } +} + diff --git a/AMS_Master_Code/Core/Lib/isotp/isotp.h b/AMS_Master_Code/Core/Lib/isotp/isotp.h index dd068a6..718b4c2 100644 --- a/AMS_Master_Code/Core/Lib/isotp/isotp.h +++ b/AMS_Master_Code/Core/Lib/isotp/isotp.h @@ -5,18 +5,27 @@ #include #define MAX_ISOTP_MESSAGES_IN_FLIGHT 10 +#define MAX_ISOTP_CONNECTIONS 10 #define ISOTP_FC_WAIT_TIMEOUT 1000 // Timeout for flow control frames (ms) + +#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 -typedef enum : int16_t { +typedef enum isotp_status { ISOTP_OK = 0, ISOTP_ERROR = -1, ISOTP_DATA_TOO_LONG = -2, ISOTP_INVALID_PARAMETER = -3, ISOTP_TOO_MANY_MESSAGES = -4, ISOTP_MESSAGE_ALREADY_IN_FLIGHT = -5, - ISOTP_NOT_FLOW_CONTROL = -6, + ISOTP_INVALID_FRAME = -6, ISOTP_CAN_TRANSMIT_ERROR = -7, + ISOTP_TOO_MANY_CONNECTIONS = -8, + ISOTP_CONNECTION_NOT_FOUND = -9, + ISOTP_BUFFER_CREATION_ERROR = -10, + ISOTP_INVALID_SEQUENCE = -11, } isotp_status_t; static inline const char *isotp_status_to_string(isotp_status_t status) { @@ -27,15 +36,21 @@ static inline const char *isotp_status_to_string(isotp_status_t status) { case ISOTP_INVALID_PARAMETER: return "ISOTP_INVALID_PARAMETER"; case ISOTP_TOO_MANY_MESSAGES: return "ISOTP_TOO_MANY_MESSAGES"; case ISOTP_MESSAGE_ALREADY_IN_FLIGHT: return "ISOTP_MESSAGE_ALREADY_IN_FLIGHT"; - case ISOTP_NOT_FLOW_CONTROL: return "ISOTP_NOT_FLOW_CONTROL"; + case ISOTP_INVALID_FRAME: return "ISOTP_INVALID_FRAME"; case ISOTP_CAN_TRANSMIT_ERROR: return "ISOTP_CAN_TRANSMIT_ERROR"; + case ISOTP_TOO_MANY_CONNECTIONS: return "ISOTP_TOO_MANY_CONNECTIONS"; + case ISOTP_CONNECTION_NOT_FOUND: return "ISOTP_CONNECTION_NOT_FOUND"; + case ISOTP_BUFFER_CREATION_ERROR: return "ISOTP_BUFFER_CREATION_ERROR"; + case ISOTP_INVALID_SEQUENCE: return "ISOTP_INVALID_SEQUENCE"; default: return "UNKNOWN_STATUS"; } } isotp_status_t isotp_init(); -[[gnu::access(read_only, 2, 3)]] isotp_status_t isotp_add_message(uint16_t id, const uint8_t *data, size_t datalen); isotp_status_t isotp_update(); -[[gnu::access(read_only, 2, 3)]] isotp_status_t isotp_handle_flow_control(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); +isotp_status_t isotp_add_connection(uint16_t src_id, uint16_t dst_id); +[[gnu::access(read_only, 2, 3)]] isotp_status_t isotp_add_message(uint16_t id, const uint8_t * data, size_t datalen); +[[gnu::access(none, 2, 3)]] isotp_status_t isotp_try_add_message(uint16_t id, const uint8_t * data, size_t datalen); #endif // ISOTP_H \ No newline at end of file diff --git a/AMS_Master_Code/Core/Lib/isotp/isotp_user_defs.h b/AMS_Master_Code/Core/Lib/isotp/isotp_user_defs.h new file mode 100644 index 0000000..243f9d0 --- /dev/null +++ b/AMS_Master_Code/Core/Lib/isotp/isotp_user_defs.h @@ -0,0 +1,15 @@ +#pragma once +#ifndef ISOTP_USER_DEFS_H +#define ISOTP_USER_DEFS_H +#include "isotp.h" + +bool isotp_transmit(uint16_t id, const uint8_t * data, size_t len); +uint32_t isotp_get_time(); + +#if ISOTP_RX +void isotp_on_message_received(uint16_t id, const uint8_t * data, size_t len); +void isotp_free_rx_buffer(void * buffer); +[[gnu::malloc]] uint8_t * isotp_get_rx_buffer(uint16_t len); +#endif + +#endif // ISOTP_USER_DEFS_H \ No newline at end of file diff --git a/AMS_Master_Code/Core/Lib/logger/isotp_log_backend.c b/AMS_Master_Code/Core/Lib/logger/isotp_log_backend.c index fcfd46f..b62dbf1 100644 --- a/AMS_Master_Code/Core/Lib/logger/isotp_log_backend.c +++ b/AMS_Master_Code/Core/Lib/logger/isotp_log_backend.c @@ -99,11 +99,14 @@ bool isotp_log_is_backend_registered(void) { void isotp_log_backend_init(void) { /* Register the backend */ isotp_backend_registered = log_register_backend(&isotp_backend); - - /* Initialize the ISO-TP stack if registration was successful */ - if (isotp_backend_registered) { - isotp_init(); + + /* Set up ISO-TP connection */ + isotp_status_t status = isotp_add_connection(ISOTP_LOG_FC_CAN_ID, ISOTP_LOG_CAN_ID); + if (status != ISOTP_OK) { + log_error("Failed to add ISO-TP connection: %s", isotp_status_to_string(status)); + return; } + log_info("ISO-TP backend initialized"); } /* ISO-TP backend initialization */ diff --git a/AMS_Master_Code/Core/Lib/logger/isotp_log_backend.h b/AMS_Master_Code/Core/Lib/logger/isotp_log_backend.h index 3f15e9c..43e62ec 100644 --- a/AMS_Master_Code/Core/Lib/logger/isotp_log_backend.h +++ b/AMS_Master_Code/Core/Lib/logger/isotp_log_backend.h @@ -9,8 +9,11 @@ /* ISO-TP CAN ID configuration */ -#ifndef ISOTP_LOG_CAN_ID -#define ISOTP_LOG_CAN_ID 0x123 // CAN ID to use for ISO-TP log messages +#ifndef ISOTP_LOG_CAN_ID //TEMPORARY!!!!! +#define ISOTP_LOG_CAN_ID 0x123 // CAN ID to use for ISO-TP log messages +#endif +#ifndef ISOTP_LOG_FC_CAN_ID +#define ISOTP_LOG_FC_CAN_ID 0x132 // CAN ID for flow control messages #endif /* ISO-TP backend API */ diff --git a/AMS_Master_Code/Core/Src/battery.c b/AMS_Master_Code/Core/Src/battery.c index c6a50fe..c3301f4 100644 --- a/AMS_Master_Code/Core/Src/battery.c +++ b/AMS_Master_Code/Core/Src/battery.c @@ -23,7 +23,7 @@ int16_t max_temp = INT16_MIN; typeof(module_temps) module_temps = {[0 ... N_BMS - 1] = {INT16_MAX, INT16_MIN}}; float module_std_deviation[N_BMS] = {}; -int16_t cellTemps[N_BMS][N_CELLS]; +int16_t cellTemps[N_BMS][10] = {}; static bool error_window[MAX_ERRORS_WINDOW_SIZE] = {}; static size_t error_window_index = 0; diff --git a/AMS_Master_Code/Core/Src/can.c b/AMS_Master_Code/Core/Src/can.c index 1a24eca..edb88e2 100644 --- a/AMS_Master_Code/Core/Src/can.c +++ b/AMS_Master_Code/Core/Src/can.c @@ -1,7 +1,9 @@ #include "can.h" +#include "ADBMS_Driver.h" #include "imd_monitoring.h" #include "isotp.h" +#include "isotp_user_defs.h" #include "isotp_log_backend.h" #include "log.h" #include "main.h" @@ -14,12 +16,13 @@ #include #include +#include -bool isotp_can_transmit(uint16_t id, const uint8_t *data, size_t datalen) { +bool isotp_transmit(uint16_t id, const uint8_t *data, size_t datalen) { return ftcan_transmit(id, data, datalen) == HAL_OK; } -uint32_t isotp_can_get_time() { +uint32_t isotp_get_time() { return HAL_GetTick(); } @@ -54,6 +57,86 @@ HAL_StatusTypeDef can_send_status() { return ftcan_transmit(CAN_ID_AMS_SIGNALS, data, 1); } +HAL_StatusTypeDef can_send_details() { + static uint8_t module_index = 0; + static uint8_t data[103] = {}; //sizeof(Cell_Module) + 10 + 1 + auto module = &modules[module_index]; + auto data_ptr = &data[1]; + + isotp_status_t status = isotp_try_add_message(CAN_ID_AMS_DETAILS_FC, data, sizeof(data)); + switch (status) { + case ISOTP_OK: + break; + case ISOTP_MESSAGE_ALREADY_IN_FLIGHT: + return HAL_BUSY; + default: + log_warning("isotp_try_add_message failed: %s", isotp_status_to_string(status)); + return HAL_ERROR; + } + + data[0] = module_index; + data_ptr = ftcan_marshal_unsigned(data_ptr, module->bmsID, 8); + data_ptr = ftcan_marshal_unsigned(data_ptr, module->status.CS_FLT, 2); + data_ptr = ftcan_marshal_unsigned(data_ptr, module->status.CCTS, 2); + + // Marshal status bits into a single byte + uint8_t status_bits = 0; + status_bits |= module->status.SMED << 0; + status_bits |= module->status.SED << 1; + status_bits |= module->status.CMED << 2; + status_bits |= module->status.CED << 3; + status_bits |= module->status.VD_UV << 4; + status_bits |= module->status.VD_OV << 5; + status_bits |= module->status.VA_UV << 6; + status_bits |= module->status.VA_OV << 7; + *(data_ptr++) = status_bits; + + // Marshal the rest of the status bits + status_bits = 0; + status_bits |= module->status.OSCCHK << 0; + status_bits |= module->status.TMODCHK << 1; + status_bits |= module->status.THSD << 2; + status_bits |= module->status.SLEEP << 3; + status_bits |= module->status.SPIFLT << 4; + status_bits |= module->status.COMPARE << 5; + status_bits |= module->status.VDE << 6; + status_bits |= module->status.VDEL << 7; + *(data_ptr++) = status_bits; + + // Marshal voltage flags + data_ptr = ftcan_marshal_unsigned(data_ptr, module->overVoltage, 4); + data_ptr = ftcan_marshal_unsigned(data_ptr, module->underVoltage, 4); + + // Marshal temperature and voltages + data_ptr = ftcan_marshal_signed(data_ptr, module->internalDieTemp, 2); + data_ptr = ftcan_marshal_unsigned(data_ptr, module->analogSupplyVoltage, 2); + data_ptr = ftcan_marshal_unsigned(data_ptr, module->digitalSupplyVoltage, 2); + data_ptr = ftcan_marshal_unsigned(data_ptr, module->refVoltage, 2); + + // Marshal cell voltages + for (int i = 0; i < 16; i++) { + data_ptr = ftcan_marshal_signed(data_ptr, module->cellVoltages[i], 2); + } + + // Marshal auxiliary voltages + for (int i = 0; i < 10; i++) { + data_ptr = ftcan_marshal_signed(data_ptr, module->auxVoltages[i], 2); + } + + // Marshal temperature data + for (int i = 0; i < 10; i++) { + data_ptr = ftcan_marshal_signed(data_ptr, cellTemps[module_index][i], 2); + } + + if ((status = isotp_add_message(CAN_ID_AMS_DETAILS, data, sizeof(data))) != ISOTP_OK) { + log_warning("isotp_add_message failed unexpectedly: %s", isotp_status_to_string(status)); + return HAL_ERROR; + } + + module_index = (module_index + 1) % N_BMS; + return HAL_OK; +} + HAL_StatusTypeDef can_send_error(TSErrorKind kind, uint8_t arg) { uint8_t data[2]; data[0] = kind; @@ -68,8 +151,8 @@ void ftcan_msg_received_cb(uint16_t id, size_t len, const uint8_t *data) { } switch (id) { - case CAN_ID_LOG_FC: - auto status = isotp_handle_flow_control(ISOTP_LOG_CAN_ID, data, len); + case ISOTP_LOG_FC_CAN_ID: + auto status = isotp_handle_incoming(id, data, len); if (status != ISOTP_OK) { log_debug("Error when handling flow control: %s", isotp_status_to_string(status)); } diff --git a/AMS_Master_Code/Core/Src/main.c b/AMS_Master_Code/Core/Src/main.c index 31afa43..5105d02 100644 --- a/AMS_Master_Code/Core/Src/main.c +++ b/AMS_Master_Code/Core/Src/main.c @@ -198,6 +198,8 @@ int main(void) // init for master functions can_init(&hfdcan1); + isotp_init(); + isotp_add_connection(CAN_ID_AMS_DETAILS_FC, CAN_ID_AMS_DETAILS); // for testing. in the final code can log streaming will be enabled by can message isotp_log_enable_streaming(LOG_LEVEL_INFO); @@ -246,6 +248,7 @@ int main(void) soc_update(); imd_update(); can_send_status(); + can_send_details(); isotp_update(); loop_delay();