Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
58 changes: 56 additions & 2 deletions lib/alerts/alerts.cc
Original file line number Diff line number Diff line change
@@ -1,2 +1,56 @@
// Implement the alerts system here
// It MUST be thread-/task- safe
#include "alerts.hpp"

namespace macfe {

// Convert an alert enum value into a single-bit mask
template <typename T>
uint64_t MakeMask(T error_code) {
return 1ULL << static_cast<uint32_t>(error_code);
}

template <typename T>
requires std::is_enum_v<T> && std::is_integral_v<std::underlying_type_t<T>>
void Alerts<T>::Set(T error_code) {
// Turn this alert on
uint64_t mask = MakeMask(error_code);
bitfield_.fetch_or(mask, std::memory_order_relaxed);
}

template <typename T>
requires std::is_enum_v<T> && std::is_integral_v<std::underlying_type_t<T>>
void Alerts<T>::Clear(T error_code) {
// Turn this alert off
uint64_t mask = MakeMask(error_code);
bitfield_.fetch_and(~mask, std::memory_order_relaxed);
}

template <typename T>
requires std::is_enum_v<T> && std::is_integral_v<std::underlying_type_t<T>>
void Alerts<T>::SetPresent(T error_code, bool present) {
// Set or clear based on the flag
present ? Set(error_code) : Clear(error_code);
}

template <typename T>
requires std::is_enum_v<T> && std::is_integral_v<std::underlying_type_t<T>>
bool Alerts<T>::IsPresent(T error_code) const {
// Check if this alert is currently active
uint64_t mask = MakeMask(error_code);
return (bitfield_.load(std::memory_order_relaxed) & mask) != 0;
}

template <typename T>
requires std::is_enum_v<T> && std::is_integral_v<std::underlying_type_t<T>>
void Alerts<T>::ClearAll() {
// Clear all active alerts
bitfield_.store(0, std::memory_order_relaxed);
}

template <typename T>
requires std::is_enum_v<T> && std::is_integral_v<std::underlying_type_t<T>>
uint64_t Alerts<T>::GetBitfield() const {
// Return the raw alert bitfield
return static_cast<uint64_t>(bitfield_.load(std::memory_order_relaxed));
}

} // namespace macfe
17 changes: 11 additions & 6 deletions lib/alerts/alerts.hpp
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
#pragma once

#include <atomic>
#include <concepts>
#include <cstdint>
#include <cstdlib>

namespace macfe {

template <typename T>
concept underlying_type_t =
std::is_enum_v<T> && std::is_integral_v<std::underlying_type_t<T>>;

template <typename T>
requires std::is_enum_v<T> && std::is_integral_v<std::underlying_type_t<T>>
class Alerts {
public:
void Set(T error_code);
void Clear(T error_code);
void SetPresent(T error_code, bool present);

bool IsPresent(T error_code);

bool IsPresent(T error_code) const;
void ClearAll(void);
uint64_t GetBitfield(void) const;

private:
uint64_t bitfield;
std::atomic<uint32_t> bitfield_{0};
};
} // namespace macfe

} // namespace macfe
2 changes: 1 addition & 1 deletion lib/alerts/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ include_dir = .
[env:native]
platform = native
test_framework = googletest
build_flags =
build_flags =
-std=c++20
56 changes: 56 additions & 0 deletions projects/front_controller/lib/alerts/alerts.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#include "alerts.hpp"

namespace macfe {

// Convert an alert enum value into a single bit mask
template <typename T>
uint64_t MakeMask(T error_code) {
return 1ULL << static_cast<uint32_t>(error_code);
}

template <typename T>
requires std::is_enum_v<T> && std::is_integral_v<std::underlying_type_t<T>>
void Alerts<T>::Set(T error_code) {
// Turn this alert on
uint64_t mask = MakeMask(error_code);
bitfield_.fetch_or(mask, std::memory_order_relaxed);
}

template <typename T>
requires std::is_enum_v<T> && std::is_integral_v<std::underlying_type_t<T>>
void Alerts<T>::Clear(T error_code) {
// Turn this alert off
uint64_t mask = MakeMask(error_code);
bitfield_.fetch_and(~mask, std::memory_order_relaxed);
}

template <typename T>
requires std::is_enum_v<T> && std::is_integral_v<std::underlying_type_t<T>>
void Alerts<T>::SetPresent(T error_code, bool present) {
// Set or clear based on the flag
present ? Set(error_code) : Clear(error_code);
}

template <typename T>
requires std::is_enum_v<T> && std::is_integral_v<std::underlying_type_t<T>>
bool Alerts<T>::IsPresent(T error_code) const {
// Check if this alert is currently active
uint64_t mask = MakeMask(error_code);
return (bitfield_.load(std::memory_order_relaxed) & mask) != 0;
}

template <typename T>
requires std::is_enum_v<T> && std::is_integral_v<std::underlying_type_t<T>>
void Alerts<T>::ClearAll() {
// Clear all active alerts
bitfield_.store(0, std::memory_order_relaxed);
}

template <typename T>
requires std::is_enum_v<T> && std::is_integral_v<std::underlying_type_t<T>>
uint64_t Alerts<T>::GetBitfield() const {
// Return the raw alert bitfield
return static_cast<uint64_t>(bitfield_.load(std::memory_order_relaxed));
}

} // namespace macfe
28 changes: 28 additions & 0 deletions projects/front_controller/lib/alerts/alerts.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include <atomic>
#include <concepts>
#include <cstdint>

namespace macfe {

template <typename T>
concept underlying_type_t =
std::is_enum_v<T> && std::is_integral_v<std::underlying_type_t<T>>;

template <typename T>
requires std::is_enum_v<T> && std::is_integral_v<std::underlying_type_t<T>>
class Alerts {
public:
void Set(T error_code);
void Clear(T error_code);
void SetPresent(T error_code, bool present);
bool IsPresent(T error_code) const;
void ClearAll(void);
uint64_t GetBitfield(void) const;

private:
std::atomic<uint32_t> bitfield_{0};
};

} // namespace macfe
6 changes: 6 additions & 0 deletions projects/front_controller/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,11 @@ build_src_filter =
build_flags =
${common.flags}
-Isrc/platforms/stm32-ev6/Inc


lib_ignore =
mcal



board_build.ldscript = src/platforms/stm32-ev6/STM32F767ZITX_FLASH.ld
24 changes: 16 additions & 8 deletions projects/front_controller/src/accumulator/accumulator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ static void UpdateStateMachine(ContactorFeedbacks fb) {
cmd = {.precharge = OPEN, .positive = OPEN, .negative = CLOSE};

if (fb.precharge == IS_CLOSED || fb.positive == IS_CLOSED) {
alerts::Get().accumulator_contactor_wrong_state = true;
alerts::GetAlertsManager().Set(
alerts::FcAlert::AccumulatorContactorWrongState);
new_state = ERROR;

} else if (FeedbackMatchesCommand(cmd, fb)) {
Expand All @@ -164,7 +165,8 @@ static void UpdateStateMachine(ContactorFeedbacks fb) {
cmd = {.precharge = OPEN, .positive = OPEN, .negative = CLOSE};

if (!FeedbackMatchesCommand(cmd, fb)) {
alerts::Get().accumulator_contactor_wrong_state = true;
alerts::GetAlertsManager().Set(
alerts::FcAlert::AccumulatorContactorWrongState);
new_state = ERROR;

} else if (elapsed >= 100) {
Expand All @@ -177,7 +179,8 @@ static void UpdateStateMachine(ContactorFeedbacks fb) {
cmd = {.precharge = CLOSE, .positive = OPEN, .negative = CLOSE};

if (fb.positive == IS_CLOSED || fb.negative == IS_OPEN) {
alerts::Get().accumulator_contactor_wrong_state = true;
alerts::GetAlertsManager().Set(
alerts::FcAlert::AccumulatorContactorWrongState);
new_state = ERROR;

} else if (FeedbackMatchesCommand(cmd, fb)) {
Expand All @@ -189,7 +192,8 @@ static void UpdateStateMachine(ContactorFeedbacks fb) {
cmd = {.precharge = CLOSE, .positive = OPEN, .negative = CLOSE};

if (!FeedbackMatchesCommand(cmd, fb)) {
alerts::Get().accumulator_contactor_wrong_state = true;
alerts::GetAlertsManager().Set(
alerts::FcAlert::AccumulatorContactorWrongState);
new_state = ERROR;

} else if (IsPrechargeComplete() &&
Expand All @@ -203,7 +207,8 @@ static void UpdateStateMachine(ContactorFeedbacks fb) {
cmd = {.precharge = CLOSE, .positive = CLOSE, .negative = CLOSE};

if (fb.precharge == IS_OPEN || fb.negative == IS_OPEN) {
alerts::Get().accumulator_contactor_wrong_state = true;
alerts::GetAlertsManager().Set(
alerts::FcAlert::AccumulatorContactorWrongState);
new_state = ERROR;

} else if (FeedbackMatchesCommand(cmd, fb)) {
Expand All @@ -216,7 +221,8 @@ static void UpdateStateMachine(ContactorFeedbacks fb) {
cmd = {.precharge = CLOSE, .positive = CLOSE, .negative = CLOSE};

if (!FeedbackMatchesCommand(cmd, fb)) {
alerts::Get().accumulator_contactor_wrong_state = true;
alerts::GetAlertsManager().Set(
alerts::FcAlert::AccumulatorContactorWrongState);
new_state = ERROR;

} else if (elapsed >= 100) {
Expand All @@ -229,7 +235,8 @@ static void UpdateStateMachine(ContactorFeedbacks fb) {
cmd = {.precharge = OPEN, .positive = CLOSE, .negative = CLOSE};

if (fb.positive == IS_OPEN || fb.negative == IS_OPEN) {
alerts::Get().accumulator_contactor_wrong_state = true;
alerts::GetAlertsManager().Set(
alerts::FcAlert::AccumulatorContactorWrongState);
new_state = ERROR;

} else if (FeedbackMatchesCommand(cmd, fb)) {
Expand All @@ -242,7 +249,8 @@ static void UpdateStateMachine(ContactorFeedbacks fb) {
cmd = {.precharge = OPEN, .positive = CLOSE, .negative = CLOSE};

if (!FeedbackMatchesCommand(cmd, fb)) {
alerts::Get().accumulator_contactor_wrong_state = true;
alerts::GetAlertsManager().Set(
alerts::FcAlert::AccumulatorContactorWrongState);
new_state = ERROR;
}
break;
Expand Down
24 changes: 10 additions & 14 deletions projects/front_controller/src/alerts/alerts.cc
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
#include "alerts.hpp"

#include "generated/can/veh_messages.hpp"
// Include the template implementation
#include <alerts.cc>

namespace alerts {

using namespace generated::can;

static TxFcAlerts msg;

TxFcAlerts& Get(void) {
return msg;
}

void Reset(void) {
msg = TxFcAlerts{};
macfe::Alerts<FcAlert>& GetAlertsManager(void) {
static macfe::Alerts<FcAlert> instance;
return instance;
}

} // namespace alerts

// from macfe/perip/can
// forces compilation of all methods
template class macfe::Alerts<alerts::FcAlert>;

void CanErrorHandler(void) {
alerts::Get().can_tx_error = true;
}
alerts::GetAlertsManager().Set(alerts::FcAlert::CanTxError);
}
11 changes: 6 additions & 5 deletions projects/front_controller/src/alerts/alerts.hpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@

#pragma once

#include "generated/can/veh_messages.hpp"
#include <alerts.hpp>

namespace alerts {
#include "fc_alert_types.hpp"

generated::can::TxFcAlerts& Get(void);
namespace alerts {

void Reset(void);
macfe::Alerts<FcAlert>& GetAlertsManager(void);

} // namespace alerts
}
24 changes: 24 additions & 0 deletions projects/front_controller/src/alerts/fc_alert_types.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

#pragma once

#include <cstdint>

namespace alerts {

enum class FcAlert : uint32_t {
AppsImplausible,
AccumulatorLowSoc,
AccumulatorContactorWrongState,
MotorRetriesExceeded,
LeftMotorStartingError,
RightMotorStartingError,
LeftMotorRunningError,
RightMotorRunningError,
DashboardBootTimeout,
CanTxError,
EV47Active,
NoInv1Can,
NoInv2Can,
};

} // namespace alerts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ void Update_100Hz(void) {
}
}

alerts::Get().apps_implausible = apps_implausible;
alerts::Get().ev47_active = pedal_needs_reset;
alerts::GetAlertsManager().SetPresent(alerts::FcAlert::AppsImplausible,
apps_implausible);
alerts::GetAlertsManager().SetPresent(alerts::FcAlert::EV47Active,
pedal_needs_reset);

if (apps_implausible) {
torque_request = 0.f;
Expand Down
Loading