diff --git a/documentation/CAN_Message_Packing.md b/documentation/CAN_Message_Packing.md index efa6e42..e26a504 100644 --- a/documentation/CAN_Message_Packing.md +++ b/documentation/CAN_Message_Packing.md @@ -111,6 +111,54 @@ CRC byte. | 7 bit4 | Positive contactor can open | bool | `0=no`, `1=yes` | | 7 bit7:5 | reserved | | transmit `0` | + +## Extra section: shunt + HV monitor telemetry (`0x602`-`0x605`, 10 Hz) + +These frames mirror all currently available shunt and HV monitor runtime telemetry +(`param::*`) in the same style as contactor telemetry: fixed CAN IDs and raw +telemetry payload bytes without CRC/counter fields. All numeric values are packed +as `uint16` with defined scale/offset. +Values that exceed the representable range are saturated to `0..65535`. + +### `BMS_SHUNT_HV_META` (0x602) + +| Byte | Signal | Type | Encoding | +|-----|--------|------|----------| +| 0 | Shunt state | enum (`uint8`) | `ShuntState` (`0=INIT,1=OPERATING,2=FAULT`) | +| 1 | Shunt DTC LSB | `uint8` | `param::dtc` bits 7:0 | +| 2 | Shunt DTC MSB | `uint8` | `param::dtc` bits 15:8 | +| 3 | HV monitor state | enum (`uint8`) | `HVMonitorState` (`0=INIT,1=OPERATING,2=FAULT`) | +| 4 | HV monitor DTC | bitfield (`uint8`) | `HVMonitorDTC` | +| 5 | Voltage matched | bool (`uint8`) | `0=false`, `1=true` | +| 6-7 | HV monitor delta voltage | `uint16` | `V x 100` | + +### `BMS_MSG_SHUNT_HV_I_CURRENT_COUNTERS` (0x603) + +| Byte | Signal | Type | Scaling/Offset | +|-----|--------|------|----------------| +| 0-1 | Current | `uint16` | `(A x 10) + 5000` | +| 2-3 | Current average | `uint16` | `(A x 10) + 5000` | +| 4-5 | Charge counter (`As`) | `uint16` | `As + 32768` | +| 6-7 | Energy counter (`Wh`) | `uint16` | `Wh + 32768` | + +### `BMS_MSG_SHUNT_HV_DI_TEMP_POWER` (0x604) + +| Byte | Signal | Type | Scaling/Offset | +|-----|--------|------|----------------| +| 0-1 | Current derivative | `uint16` | `(A/s x 1) + 32768` | +| 2-3 | Temperature | `uint16` | `(degC x 10) + 400` | +| 4-5 | Power | `uint16` | `(W x 0.1) + 32768` | +| 6-7 | reserved | `uint16` | `0` | + +### `BMS_MSG_SHUNT_HV_U12_U3` (0x605) + +| Byte | Signal | Type | Scaling/Offset | +|-----|--------|------|----------------| +| 0-1 | Input HV box voltage (`U1`) | `uint16` | `V x 100` | +| 2-3 | Output HV box voltage (`U2`) | `uint16` | `V x 100` | +| 4-5 | `U3` voltage | `uint16` | `V x 100` | +| 6-7 | reserved | `uint16` | `0` | + ## VCU to BMS (`BMS_VCU`, 0x437) All signals below are unsigned unless otherwise noted. diff --git a/documentation/Shunt_HV_Monitor_Telemetry.md b/documentation/Shunt_HV_Monitor_Telemetry.md index 9324217..7eea77d 100644 --- a/documentation/Shunt_HV_Monitor_Telemetry.md +++ b/documentation/Shunt_HV_Monitor_Telemetry.md @@ -74,3 +74,13 @@ In the HV Monitor section, prints: ### Current visibility gap - `param::hv_monitor_dtc` exists internally but is not currently printed by the serial monitor. + +### CAN telemetry availability + +All values listed in this document are now exported on BMS CAN via dedicated telemetry +messages (`0x602`-`0x605`) alongside contactor telemetry (`0x601`). + +- `0x602` publishes shunt/HV monitor states and DTC bitfields. +- `0x603`..`0x605` publish scaled/offset `uint16` telemetry values. + +See `documentation/CAN_Message_Packing.md` for exact byte-level layout. diff --git a/src/bms/battery_manager.cpp b/src/bms/battery_manager.cpp index a9c02e0..990fa69 100644 --- a/src/bms/battery_manager.cpp +++ b/src/bms/battery_manager.cpp @@ -4,6 +4,7 @@ #include "bms/battery_manager.h" #include "bms/current.h" #include "bms/contactor_manager.h" +#include "bms/hv_monitor.h" #include "utils/can_packer.h" #include "utils/can_crc.h" #include "utils/current_limit_lookup.h" @@ -15,6 +16,29 @@ // #define DEBUG + +namespace { + +uint16_t encodeUnsigned(float value, float scale, float offset) +{ + const float encoded = (value * scale) + offset; + const float clamped = std::clamp(encoded, 0.0f, 65535.0f); + return static_cast(clamped); +} + +uint16_t encodeSignedOffset(float value, float scale) +{ + return encodeUnsigned(value, scale, 32768.0f); +} + +void writeUint16ToCanBytes(CANMessage &msg, uint8_t start_index, uint16_t value) +{ + msg.data[start_index + 0] = static_cast(value & 0xFF); + msg.data[start_index + 1] = static_cast(value >> 8); +} + +} + BMS::BMS(BatteryPack &_batteryPack, Shunt_IVTS &_shunt, Contactormanager &_contactorManager) : batteryPack(_batteryPack), shunt(_shunt), @@ -135,6 +159,7 @@ void BMS::Task1000Ms() void BMS::Monitor100Ms() { send_contactor_telemetry_message(); + send_shunt_hv_monitor_telemetry_messages(); } // ############################################################################################################################################################################### @@ -652,6 +677,46 @@ void BMS::send_contactor_telemetry_message() send_message(&msg); } + +void BMS::send_shunt_hv_monitor_telemetry_messages() +{ + CANMessage msg; + msg.len = 8; + + msg.id = BMS_MSG_SHUNT_HV_META; + msg.data[0] = static_cast(param::state); + msg.data[1] = static_cast(param::dtc & 0xFF); + msg.data[2] = static_cast((param::dtc >> 8) & 0xFF); + msg.data[3] = static_cast(param::hv_monitor_state); + msg.data[4] = static_cast(param::hv_monitor_dtc); + msg.data[5] = param::voltage_matched ? 1U : 0U; + writeUint16ToCanBytes(msg, 6, encodeUnsigned(param::hv_monitor_delta_voltage, 100.0f, 0.0f)); + send_message(&msg); + + msg.id = BMS_MSG_SHUNT_HV_I_CURRENT_COUNTERS; + writeUint16ToCanBytes(msg, 0, encodeUnsigned(param::current, 10.0f, 5000.0f)); + writeUint16ToCanBytes(msg, 2, encodeUnsigned(param::current_avg, 10.0f, 5000.0f)); + writeUint16ToCanBytes(msg, 4, encodeSignedOffset(param::as, 1.0f)); + writeUint16ToCanBytes(msg, 6, encodeSignedOffset(param::wh, 1.0f)); + send_message(&msg); + + msg.id = BMS_MSG_SHUNT_HV_DI_TEMP_POWER; + writeUint16ToCanBytes(msg, 0, encodeSignedOffset(param::current_dA_per_s, 1.0f)); + writeUint16ToCanBytes(msg, 2, encodeUnsigned(param::temp, 10.0f, 400.0f)); + writeUint16ToCanBytes(msg, 4, encodeSignedOffset(param::power, 0.1f)); + msg.data[6] = 0U; + msg.data[7] = 0U; + send_message(&msg); + + msg.id = BMS_MSG_SHUNT_HV_U12_U3; + writeUint16ToCanBytes(msg, 0, encodeUnsigned(param::u_input_hvbox, 100.0f, 0.0f)); + writeUint16ToCanBytes(msg, 2, encodeUnsigned(param::u_output_hvbox, 100.0f, 0.0f)); + writeUint16ToCanBytes(msg, 4, encodeUnsigned(param::u3, 100.0f, 0.0f)); + msg.data[6] = 0U; + msg.data[7] = 0U; + send_message(&msg); +} + void BMS::send_message(CANMessage *frame) { if (ACAN_T4::BMS_CAN.tryToSend(*frame)) diff --git a/src/bms/battery_manager.h b/src/bms/battery_manager.h index 96dcb1a..7fe02a7 100644 --- a/src/bms/battery_manager.h +++ b/src/bms/battery_manager.h @@ -166,6 +166,7 @@ class BMS void send_battery_status_message(); void send_contactor_telemetry_message(); + void send_shunt_hv_monitor_telemetry_messages(); // --- Core Functions --- void update_soc_coulomb_counting(); diff --git a/src/settings.h b/src/settings.h index 7c4dd5c..7a11718 100644 --- a/src/settings.h +++ b/src/settings.h @@ -77,6 +77,10 @@ #define BMS_MSG_SOC 0x41D #define BMS_MSG_HMI 0x41E #define BMS_MSG_CONTACTOR_TELEMETRY 0x601 +#define BMS_MSG_SHUNT_HV_META 0x602 +#define BMS_MSG_SHUNT_HV_I_CURRENT_COUNTERS 0x603 +#define BMS_MSG_SHUNT_HV_DI_TEMP_POWER 0x604 +#define BMS_MSG_SHUNT_HV_U12_U3 0x605 #define BMS_VCU_TIMEOUT 300 #define BMS_ENERGY_AVG_WINDOW_SEC 60.0f