Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions can_bus/hexray/BMS/BMS_tx.json
Original file line number Diff line number Diff line change
Expand Up @@ -8287,6 +8287,66 @@
}
}
},
"SegmentSerialIds": {
"msg_id": 483,
"cycle_time": null,
"allowed_modes": [
"DEBUG"
],
"description": "Per-segment 48-bit ADBMS serial number (read from RDSID), split into three 16-bit words (word0 = bits 0-15, word1 = bits 16-31, word2 = bits 32-47)",
"signals": {
"Seg0_SerialIdWord0": { "bits": 16 },
"Seg0_SerialIdWord1": { "bits": 16 },
"Seg0_SerialIdWord2": { "bits": 16 },
"Seg1_SerialIdWord0": { "bits": 16 },
"Seg1_SerialIdWord1": { "bits": 16 },
"Seg1_SerialIdWord2": { "bits": 16 },
"Seg2_SerialIdWord0": { "bits": 16 },
"Seg2_SerialIdWord1": { "bits": 16 },
"Seg2_SerialIdWord2": { "bits": 16 },
"Seg3_SerialIdWord0": { "bits": 16 },
"Seg3_SerialIdWord1": { "bits": 16 },
"Seg3_SerialIdWord2": { "bits": 16 },
"Seg4_SerialIdWord0": { "bits": 16 },
"Seg4_SerialIdWord1": { "bits": 16 },
"Seg4_SerialIdWord2": { "bits": 16 },
"Seg5_SerialIdWord0": { "bits": 16 },
"Seg5_SerialIdWord1": { "bits": 16 },
"Seg5_SerialIdWord2": { "bits": 16 },
"Seg6_SerialIdWord0": { "bits": 16 },
"Seg6_SerialIdWord1": { "bits": 16 },
"Seg6_SerialIdWord2": { "bits": 16 },
"Seg7_SerialIdWord0": { "bits": 16 },
"Seg7_SerialIdWord1": { "bits": 16 },
"Seg7_SerialIdWord2": { "bits": 16 },
"Seg8_SerialIdWord0": { "bits": 16 },
"Seg8_SerialIdWord1": { "bits": 16 },
"Seg8_SerialIdWord2": { "bits": 16 },
"Seg9_SerialIdWord0": { "bits": 16 },
"Seg9_SerialIdWord1": { "bits": 16 },
"Seg9_SerialIdWord2": { "bits": 16 }
}
},
"SegmentSerialIdErrors": {
"msg_id": 484,
"cycle_time": null,
"allowed_modes": [
"DEBUG"
],
"description": "Per-segment error codes for segment serial number reads (NO_ERROR = no error)",
"signals": {
"Seg0_SerialIdError": { "enum": "ErrorCode" },
"Seg1_SerialIdError": { "enum": "ErrorCode" },
"Seg2_SerialIdError": { "enum": "ErrorCode" },
"Seg3_SerialIdError": { "enum": "ErrorCode" },
"Seg4_SerialIdError": { "enum": "ErrorCode" },
"Seg5_SerialIdError": { "enum": "ErrorCode" },
"Seg6_SerialIdError": { "enum": "ErrorCode" },
"Seg7_SerialIdError": { "enum": "ErrorCode" },
"Seg8_SerialIdError": { "enum": "ErrorCode" },
"Seg9_SerialIdError": { "enum": "ErrorCode" }
}
},
"EvseCPStatus": {
"msg_id": 482,
"allowed_modes":[
Expand Down
5 changes: 3 additions & 2 deletions can_bus/hexray/shared_enum.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
"INVALID_READING": 8,
"ERROR_INDETERMINATE": 9,
"POLL_INVALID": 10,
"NO_SEGMENT_DEFINED" : 11,
"NO_ERROR" : 12
"THERM_OUT_OF_RANGE": 11,
"NO_SEGMENT_DEFINED" : 12,
"NO_ERROR" : 13
},
"SwitchState": {
"OFF": 0,
Expand Down
16 changes: 8 additions & 8 deletions firmware/cmake/embedded.cmake

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert this

Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,14 @@ function(embedded_binary
else ()
target_compile_options(${ELF_NAME} PRIVATE -Os)
endif ()
IF (${CMAKE_BUILD_TYPE} STREQUAL "Debug" AND ${USE_UBSAN})
target_compile_options(${ELF_NAME} PRIVATE -fsanitize=undefined)
set_property(SOURCE "${SHARED_LIB_INCLUDE_DIR_CPP}/lib_ubsan.cpp" APPEND PROPERTY COMPILE_OPTIONS
-fno-sanitize=undefined
-Wno-error=suggest-attribute=noreturn
-Wno-suggest-attribute=noreturn
)
target_sources(${ELF_NAME} PRIVATE "${SHARED_LIB_INCLUDE_DIR_CPP}/lib_ubsan.cpp")
IF (${CMAKE_BUILD_TYPE} STREQUAL "Debug")
# target_compile_options(${ELF_NAME} PRIVATE -fsanitize=undefined)
# set_property(SOURCE "${SHARED_LIB_INCLUDE_DIR_CPP}/lib_ubsan.cpp" APPEND PROPERTY COMPILE_OPTIONS
# -fno-sanitize=undefined
# -Wno-error=suggest-attribute=noreturn
# -Wno-suggest-attribute=noreturn
# )
# target_sources(${ELF_NAME} PRIVATE "${SHARED_LIB_INCLUDE_DIR_CPP}/lib_ubsan.cpp")
ENDIF ()

target_link_options(${ELF_NAME} PRIVATE
Expand Down
1 change: 1 addition & 0 deletions firmware/hexray/BMS/src/app/app_segments.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ namespace broadcast
} // namespace debug

void segmentHealthError(const health::Snapshot &health);
void serialNumbers(const io::adbms::Segments<result<uint64_t>> &serial_nums);
void cellVoltageStats(const CellParam<float> &min, const CellParam<float> &max);
void cellTempStats(const CellParam<float> &min, const CellParam<float> &max);
void segmentVoltageStats(const SegmentParam<float> &min, const SegmentParam<float> &max);
Expand Down
27 changes: 27 additions & 0 deletions firmware/hexray/BMS/src/app/segments/app_segments_broadcast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@ BroadcastBuffer<CanErr, MAX_NUM_SEGMENTS, io::can_tx::BMS_SegmentStatCErrors_sen
segment_stat_c_error_buffer(app::can_tx::BMS_SegmentStatCErrors_getData());
BroadcastBuffer<CanErr, MAX_NUM_SEGMENTS, io::can_tx::BMS_SegmentStatDErrors_sendAperiodic>
segment_stat_d_error_buffer(app::can_tx::BMS_SegmentStatDErrors_getData());
// Three consecutive 16-bit words per segment hold the 48-bit serial: [seg*3 + w] = bits [16*w, 16*w + 16).
BroadcastBuffer<uint16_t, 3 * MAX_NUM_SEGMENTS, io::can_tx::BMS_SegmentSerialIds_sendAperiodic>
segment_serial_id_buffer(app::can_tx::BMS_SegmentSerialIds_getData());
BroadcastBuffer<CanErr, MAX_NUM_SEGMENTS, io::can_tx::BMS_SegmentSerialIdErrors_sendAperiodic>
segment_serial_id_error_buffer(app::can_tx::BMS_SegmentSerialIdErrors_getData());

} // namespace

Expand Down Expand Up @@ -439,6 +444,28 @@ namespace debug
}
} // namespace debug

void serialNumbers(const Segments<result<uint64_t>> &serial_nums)
{
for (size_t seg = 0U; seg < NUM_SEGMENTS; seg++)
{
const auto &r = serial_nums[seg];
const uint64_t serial = r.value_or(0U);
segment_serial_id_buffer[seg * 3U] = static_cast<uint16_t>(serial & 0xFFFFU);
segment_serial_id_buffer[seg * 3U + 1U] = static_cast<uint16_t>((serial >> 16U) & 0xFFFFU);
segment_serial_id_buffer[seg * 3U + 2U] = static_cast<uint16_t>((serial >> 32U) & 0xFFFFU);
segment_serial_id_error_buffer[seg] = r ? app::can_utils::ErrorCode::NO_ERROR : toCanErr(r.error());
}
for (size_t seg = NUM_SEGMENTS; seg < MAX_NUM_SEGMENTS; seg++)
{
segment_serial_id_buffer[seg * 3U] = 0U;
segment_serial_id_buffer[seg * 3U + 1U] = 0U;
segment_serial_id_buffer[seg * 3U + 2U] = 0U;
segment_serial_id_error_buffer[seg] = app::can_utils::ErrorCode::NO_SEGMENT_DEFINED;
}
segment_serial_id_buffer.send();
segment_serial_id_error_buffer.send();
}

// void cmdCountMismatch(const Segments<uint8_t> &mismatches)
// {
// for (size_t seg = 0U; seg < NUM_SEGMENTS; seg++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,13 @@ Therms<result<float>>

const float voltage = reading.value();
const float resistance = R_SERIES * (voltage / (V_REF2 - voltage));
out[seg][therm] = app::therm::adbms_ntc10k_lut.resistanceToTemp(resistance);
const auto temp = app::therm::adbms_ntc10k_lut.resistanceToTemp(resistance);
if (!temp)
{
out[seg][therm] = std::unexpected(temp.error());
continue;
}
out[seg][therm] = temp.value();
}
}
return out;
Expand Down
2 changes: 1 addition & 1 deletion firmware/hexray/BMS/src/app/states/app_balancingState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ namespace balancingState
(io::irs::negativeState() == app::can_utils::ContactorState::CONTACTOR_STATE_OPEN);
const bool balancing_enabled = app::can_rx::Debug_CellBalancing_Request_get();

if (balancing_enabled && !ir_negative_open)
if (balancing_enabled && ir_negative_open)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think ir negative has to be closed for balancing by rules

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we gotta be hv up, but yeah ir negative closed is closer to rules

{
app::segments::balancing::tick();
}
Expand Down
4 changes: 4 additions & 0 deletions firmware/hexray/BMS/src/io/adbms/io_adbms_aux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ namespace io::adbms
result<void> clear::flags()
{
Segments<RegBuffer> clr_regs{};
for (size_t seg = 0U; seg < NUM_SEGMENTS; seg++)
{
clr_regs[seg].fill(0xFF);
}
RETURN_IF_ERR(writeRegGroup(CLRFLAG, clr_regs));
RETURN_IF_ERR(writeRegGroup(CLOVUV, clr_regs));
return {};
Expand Down
24 changes: 24 additions & 0 deletions firmware/hexray/BMS/src/io/adbms/io_adbms_configs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,28 @@ Segments<result<PWMConfig>> read::pwmReg()
}
return pwm_configs;
}

Segments<result<uint64_t>> read::serialNum()
{
Segments<result<uint64_t>> serial_nums{};

const Segments<result<RegBuffer>> raw_serial = readRegGroup(RDSID);
for (size_t seg = 0U; seg < NUM_SEGMENTS; ++seg)
{
if (!raw_serial[seg])
{
serial_nums[seg] = unexpected(raw_serial[seg].error());
continue;
}

const RegBuffer &bytes = raw_serial[seg].value();
uint64_t serial = 0U;
for (size_t i = 0U; i < REG_GROUP_SIZE; ++i)
{
serial |= static_cast<uint64_t>(bytes[i]) << (8U * i);
}
serial_nums[seg] = serial;
}
return serial_nums;
}
} // namespace io::adbms
3 changes: 3 additions & 0 deletions firmware/hexray/BMS/src/io/adbms/io_adbms_internal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ namespace io::adbms
inline constexpr uint8_t CMD_BYTES = 2;
inline constexpr uint8_t PEC_BYTES = 2;

// Serial Number
inline constexpr uint16_t RDSID = 0x002CU;

// Config
inline constexpr uint16_t WRCFGA = 0x0001U;
inline constexpr uint16_t WRCFGB = 0x0024U;
Expand Down
4 changes: 2 additions & 2 deletions firmware/hexray/BMS/src/io/io_adbms.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include <expected>

// Physical daisy-chain dimensions for this ECU.
inline constexpr uint8_t NUM_SEGMENTS = 10;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert

inline constexpr uint8_t NUM_SEGMENTS = 1;
inline constexpr uint8_t CELLS_PER_SEGMENT = 14;
inline constexpr uint8_t THERMISTORS_PER_SEGMENT = 14;
inline constexpr uint8_t THERM_GPIOS_PER_SEGMENT = 8;
Expand Down Expand Up @@ -238,6 +238,7 @@ namespace read
[[nodiscard]] Segments<result<int16_t>> segVoltage();
[[nodiscard]] ThermGpios<result<int16_t>> thermGpioVoltage();
[[nodiscard]] Segments<StatusGroupsRes> status();
[[nodiscard]] Segments<result<uint64_t>> serialNum();
} // namespace read

namespace command
Expand Down Expand Up @@ -267,7 +268,6 @@ namespace command
[[nodiscard]] result<void> pollAuxAdc();
[[nodiscard]] result<void> startBalance();
[[nodiscard]] result<void> stopBalance();

[[nodiscard]] result<void> owcCells(OpenWireSwitch owcSwitch);
} // namespace command

Expand Down
9 changes: 8 additions & 1 deletion firmware/hexray/BMS/src/io/io_thermistors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ float readSelectedTemp()
const float raw_voltage = aux_tsns.getVoltage();
const float thermistor_resistance = (raw_voltage * BIAS_RESISTOR_OHM) / (REFERENCE_VOLTAGE - raw_voltage);

return b57861s_lut.resistanceToTemp(thermistor_resistance);
const auto result = b57861s_lut.resistanceToTemp(thermistor_resistance);
if (!result)
{
LOG_ERROR("Thermistor LUT error: {}", static_cast<int>(result.error()));
return std::numeric_limits<float>::lowest();
}

return result.value();
}
} // namespace io::therm
4 changes: 4 additions & 0 deletions firmware/hexray/BMS/src/jobs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ void jobs_run100Hz_tick()
app::latches::broadcast();
app::can_tx::BMS_BSPDBrakePressureThresholdExceeded_set(io::bspdtest::isBrakePressureThresholdExceeded());
app::can_tx::BMS_BSPDAccelBrakeOk_set(io::bspdtest::isAccelBrakeOk());
io::bspdtest::enable(app::can_rx::Debug_EnableTestCurrent_get());

if (app::can_alerts::AnyBoardHasFault())
{
Expand Down Expand Up @@ -188,12 +189,15 @@ void jobs_runAdbmsConfigs_tick()
}
}

const Segments<result<uint64_t>> serial_numbers = io::adbms::read::serialNum();

std::array<std::bitset<app::segments::health::NUM_HEALTH_BITS>, MAX_NUM_SEGMENTS> health;
{
const io::unique_semaphore h{ health_lock };
health = app::segments::health::getAll();
}

app::segments::broadcast::serialNumbers(serial_numbers);
app::segments::broadcast::segmentHealthError(health);

if (all_segments_ok)
Expand Down
39 changes: 26 additions & 13 deletions firmware/shared/srcpp/app/app_thermistor.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once
#include "app_math.hpp"
#include "util_errorCodes.hpp"

#include <cstddef>
#include <cstdint>
Expand Down Expand Up @@ -48,27 +49,39 @@ namespace therm
* Calculate temperature based on thermistor temperature and LUT
* @param thermistor_resistance resistance of the thermistor
* @param temp_resistance_lut reverse lookup table
* @return Thermistor temperature in degrees C or -1 if out of bounds or invalid LUT
* @return Thermistor temperature in degrees C or lowest float if out of bounds or invalid LUT.
* Special case for temperature too high, will return highest float instead of lowest.
*/
float resistanceToTemp(float thermistor_resistance) const noexcept
std::expected<float, ErrorCode> resistanceToTemp(float thermistor_resistance) const noexcept
{
if (!valid_ || resistances_ == nullptr || size_ == 0U)
return -1.0f;
return std::unexpected(ErrorCode::LUT_INVALID);

// Guard against NaN/inf inputs
if (!std::isfinite(thermistor_resistance))
return -1.0f;

// Handle trivial single-entry LUT safely
if (size_ == 1U)
// Ensure resistance is within bounds: resistances[0] is highest, resistances[size-1] is lowest
if (!std::isfinite(thermistor_resistance) || thermistor_resistance >= resistances_[0])
{
return APPROX_EQUAL_FLOAT(thermistor_resistance, resistances_[0], 0.0001f) ? starting_temp_ : -1.0f;
return std::unexpected(ErrorCode::LUT_UNDERSHOOT);
}
else if (thermistor_resistance <= resistances_[size_ - 1U])
{
return std::unexpected(ErrorCode::LUT_OVERSHOOT);
}

// Ensure resistance is within bounds: resistances[0] is highest, resistances[size-1] is lowest
if (!(thermistor_resistance <= resistances_[0] && thermistor_resistance >= resistances_[size_ - 1U]))
// Handle trivial single-entry LUT safely
if (size_ == 1U)
{
return -1.0f;
if (!APPROX_EQUAL_FLOAT(thermistor_resistance, resistances_[0], 0.0001f))
{
if (thermistor_resistance > resistances_[0])
{
return std::unexpected(ErrorCode::LUT_UNDERSHOOT);
}
else
{
return std::unexpected(ErrorCode::LUT_OVERSHOOT);
}
}
return starting_temp_;
}

// Binary search for insertion point
Expand Down
6 changes: 6 additions & 0 deletions firmware/shared/srcpp/util/util_errorCodes.hpp

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is breaking, make sure to merge asap

Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ enum class ErrorCode
INVALID_READING,
ERROR_INDETERMINATE,
POLL_INVALID,
THERM_OUT_OF_RANGE,
NUM_EXIT_CODES,
LUT_INVALID,
LUT_OVERSHOOT,
LUT_UNDERSHOOT

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also surely num at the end

};

template <typename T> using result = std::expected<T, ErrorCode>;
Expand Down Expand Up @@ -47,6 +51,8 @@ constexpr const char *error_code_to_string(const ErrorCode code)
return "Indeterminate error";
case ErrorCode::POLL_INVALID:
return "Poll invalid";
case ErrorCode::THERM_OUT_OF_RANGE:
return "Therm out of range";
case ErrorCode::NUM_EXIT_CODES:
default:
return "Unknown error code";
Expand Down
Loading