Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EvseManager Charger timed mutexes, cleanup #526

Merged
merged 6 commits into from
Feb 9, 2024
Merged
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
11 changes: 11 additions & 0 deletions modules/EvseManager/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ target_sources(${MODULE_NAME}
CarManufacturer.cpp
IECStateMachine.cpp
ErrorHandling.cpp
backtrace.cpp
)

target_link_libraries(${MODULE_NAME}
Expand All @@ -32,6 +33,16 @@ target_link_libraries(${MODULE_NAME}
)
endif()

target_compile_options(${MODULE_NAME}
PRIVATE
"-rdynamic"
)

target_link_options(${MODULE_NAME}
PRIVATE
"-rdynamic"
)

# needed for std::filesystem
target_compile_features(${MODULE_NAME} PUBLIC cxx_std_17)
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
Expand Down
777 changes: 401 additions & 376 deletions modules/EvseManager/Charger.cpp

Large diffs are not rendered by default.

234 changes: 114 additions & 120 deletions modules/EvseManager/Charger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

#include "ErrorHandling.hpp"
#include "IECStateMachine.hpp"
#include "scoped_lock_timeout.hpp"

namespace module {

Expand Down Expand Up @@ -97,7 +98,6 @@ class Charger {

void set_faulted();
void set_hlc_error();
void set_rcd_error();

// Public interface during charging
//
Expand All @@ -107,8 +107,6 @@ class Charger {
// call when in state WaitingForAuthentication
void authorize(bool a, const types::authorization::ProvidedIdToken& token);
bool deauthorize();
types::authorization::ProvidedIdToken get_id_token();
std::optional<types::authorization::ProvidedIdToken> get_stop_transaction_id_token();

bool get_authorized_pnc();
bool get_authorized_eim();
Expand All @@ -127,8 +125,6 @@ class Charger {

bool cancel_transaction(const types::evse_manager::StopTransactionRequest&
request); // cancel transaction ahead of time when car is still plugged
types::evse_manager::StopTransactionReason get_transaction_finished_reason(); // get reason for last finished event
types::evse_manager::StartSessionReason get_session_started_reason(); // get reason for last session start event

// execute a virtual replug sequence. Does NOT generate a Car plugged in event etc,
// since the session is not restarted. It can be used to e.g. restart the ISO session
Expand All @@ -138,7 +134,11 @@ class Charger {
void set_current_drawn_by_vehicle(float l1, float l2, float l3);

// Signal for EvseEvents
sigslot::signal<types::evse_manager::SessionEventEnum> signal_event;
sigslot::signal<types::evse_manager::SessionEventEnum> signal_simple_event;
sigslot::signal<types::evse_manager::StartSessionReason> signal_session_started_event;
sigslot::signal<types::authorization::ProvidedIdToken> signal_transaction_started_event;
sigslot::signal<types::evse_manager::StopTransactionReason, std::optional<types::authorization::ProvidedIdToken>>
signal_transaction_finished_event;

sigslot::signal<> signal_ac_with_soc_timeout;

Expand All @@ -155,7 +155,6 @@ class Charger {
void request_error_sequence();

void set_matching_started(bool m);
bool get_matching_started();

void notify_currentdemand_started();

Expand Down Expand Up @@ -187,18 +186,25 @@ class Charger {
void bcb_toggle_detect_stop_pulse();
bool bcb_toggle_detected();

// main Charger thread
Everest::Thread main_thread_handle;
void clear_errors_on_unplug();

const std::unique_ptr<IECStateMachine>& bsp;
const std::unique_ptr<ErrorHandling>& error_handling;
const types::evse_board_support::Connector_type& connector_type;
void update_pwm_now(float dc);
void update_pwm_now_if_changed(float dc);
void update_pwm_max_every_5seconds(float dc);
void pwm_off();
void pwm_F();

void process_cp_events_independent(CPEvent cp_event);
void process_cp_events_state(CPEvent cp_event);
void run_state_machine();

void main_thread();

float max_current;
std::chrono::time_point<date::utc_clock> max_current_valid_until;
float max_current_cable{0.};
void graceful_stop_charging();

float ampere_to_duty_cycle(float ampere);

void check_soft_over_current();

bool power_available();

Expand All @@ -208,124 +214,112 @@ class Charger {
void start_transaction();
void stop_transaction();

bool transaction_active;
bool session_active;
types::evse_manager::StopTransactionReason last_stop_transaction_reason;
types::evse_manager::StartSessionReason last_start_session_reason;

// This mutex locks all variables related to the state machine
std::recursive_mutex state_machine_mutex;

EvseState current_state;
EvseState last_state;
EvseState last_state_detect_state_change;

std::chrono::system_clock::time_point current_state_started;

bool connector_enabled;

bool error_prevent_charging_flag{false};
bool last_error_prevent_charging_flag{false};
void graceful_stop_charging();

float ampere_to_duty_cycle(float ampere);

void check_soft_over_current();
float current_drawn_by_vehicle[3];
bool over_current;
std::chrono::time_point<date::utc_clock> last_over_current_event;
const int soft_over_current_timeout = 7000;

// 4 seconds according to table 3 of ISO15118-3
const int t_step_EF = 4000;
EvseState t_step_EF_return_state;
float t_step_EF_return_pwm;

// 3 seconds according to IEC61851-1
const int t_step_X1 = 3000;
EvseState t_step_X1_return_state;
float t_step_X1_return_pwm;

static constexpr float PWM_5_PERCENT = 0.05;
static constexpr int T_REPLUG_MS = 4000;

bool matching_started;

void process_cp_events_independent(CPEvent cp_event);
void process_cp_events_state(CPEvent cp_event);
void run_state_machine();

bool authorized;
// set to true if auth is from PnC, otherwise to false (EIM)
bool authorized_pnc;

types::authorization::ProvidedIdToken id_token;
std::optional<types::authorization::ProvidedIdToken>
stop_transaction_id_token; // only set in case transaction was stopped locally

// AC or DC
ChargeMode charge_mode{0};
// Config option
bool ac_hlc_enabled;
// HLC enabled in current AC session. This can change during the session if e.g. HLC fails.
bool ac_hlc_enabled_current_session;
// Config option
bool ac_hlc_use_5percent;
Everest::timed_mutex_traceable state_machine_mutex;

// used by different threads, complete main loop must be locked for write access
struct SharedContext {
// As per IEC61851-1 A.5.3
bool legacy_wakeup_done{false};
bool hlc_allow_close_contactor{false};
bool iec_allow_close_contactor{false};
bool hlc_charging_active{false};
HlcTerminatePause hlc_charging_terminate_pause;
types::iso15118_charger::DC_EVSEMaximumLimits current_evse_max_limits;
bool pwm_running{false};
std::optional<types::authorization::ProvidedIdToken>
stop_transaction_id_token; // only set in case transaction was stopped locally
types::authorization::ProvidedIdToken id_token;
bool authorized;
// set to true if auth is from PnC, otherwise to false (EIM)
bool authorized_pnc;
bool matching_started;
float max_current;
std::chrono::time_point<date::utc_clock> max_current_valid_until;
float max_current_cable{0.};
bool transaction_active;
bool session_active;
bool connector_enabled;
EvseState current_state;
types::evse_manager::StopTransactionReason last_stop_transaction_reason;
types::evse_manager::StartSessionReason last_start_session_reason;
float current_drawn_by_vehicle[3];
bool error_prevent_charging_flag{false};
int ac_with_soc_timer;
// non standard compliant option: time out after a while and switch back to DC to get SoC update
bool ac_with_soc_timeout;
} shared_context;

struct ConfigContext {
// non standard compliant option to enforce HLC in AC mode
bool ac_enforce_hlc;
// Config option to use 5 percent PWM in HLC AC mode
bool ac_hlc_use_5percent;
// Config option to enable HLC in AC mode
bool ac_hlc_enabled;
// AC or DC
ChargeMode charge_mode{0};
} config_context;

// Used by different threads, but requires no complete state machine locking
std::atomic_bool contactors_closed{false};
std::atomic<float> soft_over_current_tolerance_percent{10.};
std::atomic<float> soft_over_current_measurement_noise_A{0.5};
// HLC uses 5 percent signalling. Used both for AC and DC modes.
bool hlc_use_5percent_current_session;
// non standard compliant option to enforce HLC in AC mode
bool ac_enforce_hlc;
// non standard compliant option: time out after a while and switch back to DC to get SoC update
bool ac_with_soc_timeout;
int ac_with_soc_timer;

std::chrono::time_point<date::utc_clock> last_pwm_update;

float update_pwm_last_dc;
void update_pwm_now(float dc);
void update_pwm_now_if_changed(float dc);
void update_pwm_max_every_5seconds(float dc);
void pwm_off();
void pwm_F();
bool pwm_running{false};

types::iso15118_charger::DC_EVSEMaximumLimits current_evse_max_limits;

static constexpr auto SLEEP_BEFORE_ENABLING_PWM_HLC_MODE = std::chrono::seconds(1);
static constexpr auto MAINLOOP_UPDATE_RATE = std::chrono::milliseconds(100);
std::atomic_bool hlc_use_5percent_current_session;
// HLC enabled in current AC session. This can change during the session if e.g. HLC fails.
std::atomic_bool ac_hlc_enabled_current_session;

// This struct is only used from main loop thread
struct InternalContext {
bool hlc_bcb_sequence_started{false};
int hlc_ev_pause_bcb_count{0};
std::chrono::time_point<std::chrono::steady_clock> hlc_ev_pause_start_of_bcb;
std::chrono::time_point<std::chrono::steady_clock> hlc_ev_pause_start_of_bcb_sequence;
float update_pwm_last_dc;
std::chrono::time_point<std::chrono::steady_clock> last_pwm_update;

EvseState t_step_EF_return_state;
float t_step_EF_return_pwm;

EvseState t_step_X1_return_state;
float t_step_X1_return_pwm;
std::chrono::time_point<std::chrono::steady_clock> last_over_current_event;
bool over_current{false};

bool last_error_prevent_charging_flag{false};
std::chrono::system_clock::time_point current_state_started;
EvseState last_state_detect_state_change;
EvseState last_state;
} internal_context;

float soft_over_current_tolerance_percent{10.};
float soft_over_current_measurement_noise_A{0.5};
// main Charger thread
Everest::Thread main_thread_handle;

HlcTerminatePause hlc_charging_terminate_pause;
bool hlc_charging_active{false};
bool hlc_allow_close_contactor{false};
bool iec_allow_close_contactor{false};
const std::unique_ptr<IECStateMachine>& bsp;
const std::unique_ptr<ErrorHandling>& error_handling;
const types::evse_board_support::Connector_type& connector_type;

// constants
static constexpr float CHARGER_ABSOLUTE_MAX_CURRENT{80.};
constexpr static int LEGACY_WAKEUP_TIMEOUT{30000};
// valid Length of BCB toggles
static constexpr auto TP_EV_VALD_STATE_DURATION_MIN =
std::chrono::milliseconds(200 - 50); // We give 50 msecs tolerance to the norm values (table 3 ISO15118-3)
static constexpr auto TP_EV_VALD_STATE_DURATION_MAX =
std::chrono::milliseconds(400 + 50); // We give 50 msecs tolerance to the norm values (table 3 ISO15118-3)

// Maximum duration of a BCB toggle sequence of 1-3 BCB toggles
static constexpr auto TT_EVSE_VALD_TOGGLE =
std::chrono::milliseconds(3500 + 200); // We give 200 msecs tolerance to the norm values (table 3 ISO15118-3)

std::chrono::time_point<std::chrono::steady_clock> hlc_ev_pause_start_of_bcb;
std::chrono::time_point<std::chrono::steady_clock> hlc_ev_pause_start_of_bcb_sequence;
int hlc_ev_pause_bcb_count{0};
bool hlc_bcb_sequence_started{false};

bool contactors_closed{false};

// As per IEC61851-1 A.5.3
bool legacy_wakeup_done{false};
constexpr static int legacy_wakeup_timeout{30000};

void clear_errors_on_unplug();

static constexpr float CHARGER_ABSOLUTE_MAX_CURRENT{80.};
static constexpr auto SLEEP_BEFORE_ENABLING_PWM_HLC_MODE = std::chrono::seconds(1);
static constexpr auto MAINLOOP_UPDATE_RATE = std::chrono::milliseconds(100);
static constexpr float PWM_5_PERCENT = 0.05;
static constexpr int T_REPLUG_MS = 4000;
// 3 seconds according to IEC61851-1
static constexpr int T_STEP_X1 = 3000;
// 4 seconds according to table 3 of ISO15118-3
static constexpr int T_STEP_EF = 4000;
static constexpr int SOFT_OVER_CURRENT_TIMEOUT = 7000;
};

} // namespace module
Expand Down
Loading
Loading