diff --git a/modules/YetiSimulator/YetiSimulator.cpp b/modules/YetiSimulator/YetiSimulator.cpp index e54b784dd..6085ab1b9 100644 --- a/modules/YetiSimulator/YetiSimulator.cpp +++ b/modules/YetiSimulator/YetiSimulator.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Pionix GmbH and Contributors to EVerest -#include "YetiSimulator.hpp" #include "board_support/evse_board_supportImpl.hpp" +#include "util/state.hpp" #include "util/util.hpp" namespace module { @@ -13,7 +13,7 @@ void YetiSimulator::init() { invoke_init(*p_rcd); invoke_init(*p_connector_lock); - clear_data(); + reset_module_state(); mqtt_handler = std::make_unique(p_board_support.get(), p_rcd.get(), p_connector_lock.get()); mqtt.subscribe("everest_external/nodered/" + std::to_string(config.connector_id) + "/carsim/error", @@ -29,48 +29,48 @@ void YetiSimulator::ready() { module_state->pubCnt = 0; - Simulator(250, this); + start_simulation(250); if (info.telemetry_enabled) { std::thread(&YetiSimulator::run_telemetry_slow, this).detach(); std::thread(&YetiSimulator::run_telemetry_fast, this).detach(); } } -state::ModuleState& YetiSimulator::get_module_state() { +state::ModuleState& YetiSimulator::get_module_state() const { return *module_state; } -evse_board_supportImplBase& YetiSimulator::get_board_support() { +evse_board_supportImplBase& YetiSimulator::get_board_support() const { return *p_board_support; -}; +} -ev_board_supportImplBase& YetiSimulator::get_ev_board_support() { +ev_board_supportImplBase& YetiSimulator::get_ev_board_support() const { return *p_ev_board_support; } -ac_rcdImplBase& YetiSimulator::get_ac_rcd() { +ac_rcdImplBase& YetiSimulator::get_ac_rcd() const { return *p_rcd; } -connector_lockImplBase& YetiSimulator::get_connector_lock() { +connector_lockImplBase& YetiSimulator::get_connector_lock() const { return *p_connector_lock; } -Everest::MqttProvider& YetiSimulator::get_mqtt() { +Everest::MqttProvider& YetiSimulator::get_mqtt() const { return mqtt; } const ModuleInfo& YetiSimulator::get_info() const { return info; } -powermeterImplBase& YetiSimulator::get_powermeter() { +powermeterImplBase& YetiSimulator::get_powermeter() const { return *p_powermeter; } -void YetiSimulator::clear_data() { +void YetiSimulator::reset_module_state() { module_state = std::make_unique(); } -void YetiSimulator::run_telemetry_slow() { +void YetiSimulator::run_telemetry_slow() const { const auto current_iso_time_string = util::get_current_iso_time_string(); auto& p_p_c_v = module_state->telemetry_data.power_path_controller_version; @@ -88,7 +88,7 @@ void YetiSimulator::run_telemetry_slow() { {"error", p_p_c_v.error}}); } -void YetiSimulator::run_telemetry_fast() { +void YetiSimulator::run_telemetry_fast() const { const auto current_iso_time_string = util::get_current_iso_time_string(); auto& p_p_c = module_state->telemetry_data.power_path_controller; p_p_c.timestamp = current_iso_time_string; @@ -150,4 +150,586 @@ void YetiSimulator::run_telemetry_fast() { {"error", rcd.error}}); } +void YetiSimulator::start_simulation(const int sleep_time_ms) { + std::thread(&YetiSimulator::run_simulation, this, sleep_time_ms).detach(); +} + +[[noreturn]] void YetiSimulator::run_simulation(const int sleep_time_ms) const { + while (true) { + if (module_state->simulation_enabled) { + simulation_step(); + } + + module_state->pubCnt++; + switch (module_state->pubCnt) { + case 1: + publish_powermeter(); + publish_telemetry(); + break; + case 3: + publish_keepalive(); + break; + default: + module_state->pubCnt = 0; + break; + } + + std::this_thread::sleep_for(std::chrono::milliseconds{sleep_time_ms}); + } +} + +void YetiSimulator::simulation_step() const { + check_error_rcd(); + read_from_car(); + simulation_statemachine(); + add_noise(); + simulate_powermeter(); + publish_ev_board_support(); +} + +void YetiSimulator::check_error_rcd() const { + using Everest::error::Severity; + auto& board_support = get_board_support(); + auto& rcd = get_ac_rcd(); + + if (module_state->simulation_data.rcd_current > 5.0) { + if (not module_state->rcd_error_reported) { + const auto error = + board_support.error_factory->create_error("ac_rcd/DC", "", "Simulated fault event", Severity::High); + board_support.raise_error(error); + module_state->rcd_error_reported = true; + } + } else { + if (module_state->rcd_error_reported) { + board_support.clear_error("ac_rcd/DC"); + } + module_state->rcd_error_reported = false; + } + rcd.publish_rcd_current_mA(module_state->simulation_data.rcd_current); +} + +void YetiSimulator::read_from_car() const { + auto error_handler = ErrorHandler{&get_board_support(), &get_ac_rcd(), &get_connector_lock()}; + + auto amps1 = double{}; + auto amps2 = double{}; + auto amps3 = double{}; + + auto hlc_active = false; + if (module_state->pwm_duty_cycle >= 0.03 and module_state->pwm_duty_cycle <= 0.07) + hlc_active = true; + + auto amps = duty_cycle_to_amps(module_state->pwm_duty_cycle); + if (amps > module_state->ev_max_current or hlc_active == true) + amps = module_state->ev_max_current; + + if (module_state->relais_on == true and module_state->ev_three_phases > 0) + amps1 = amps; + else + amps1 = 0; + if (module_state->relais_on == true and module_state->ev_three_phases > 1 and + module_state->use_three_phases_confirmed) + amps2 = amps; + else + amps2 = 0; + if (module_state->relais_on == true and module_state->ev_three_phases > 2 and + module_state->use_three_phases_confirmed) + amps3 = amps; + else + amps3 = 0; + + if (module_state->pwm_running) { + module_state->pwm_voltage_hi = module_state->simulation_data.cp_voltage; + module_state->pwm_voltage_lo = -12.0; + } else { + module_state->pwm_voltage_hi = module_state->simulation_data.cp_voltage; + module_state->pwm_voltage_lo = module_state->pwm_voltage_hi; + } + + if (module_state->pwm_error_f) { + module_state->pwm_voltage_hi = -12.0; + module_state->pwm_voltage_lo = -12.0; + } + if (module_state->simulation_data.error_e) { + module_state->pwm_voltage_hi = 0.0; + module_state->pwm_voltage_lo = 0.0; + } + if (module_state->simulation_data.diode_fail) { + module_state->pwm_voltage_lo = -module_state->pwm_voltage_hi; + } + + const auto cpLo = module_state->pwm_voltage_lo; + const auto cpHi = module_state->pwm_voltage_hi; + + // sth is wrong with negative signal + if (module_state->pwm_running and not is_voltage_in_range(cpLo, -12.0)) { + // CP-PE short or signal somehow gone + if (is_voltage_in_range(cpLo, 0.0) and is_voltage_in_range(cpHi, 0.0)) { + module_state->current_state = state::State::STATE_E; + drawPower(0, 0, 0, 0); + } else if (is_voltage_in_range(cpHi + cpLo, 0.0)) { // Diode fault + // error_handler.error_DiodeFault(true); TODO + drawPower(0, 0, 0, 0); + } + } else if (is_voltage_in_range(cpHi, 12.0)) { + // +12V State A IDLE (open circuit) + // clear all errors that clear on disconnection + clear_disconnect_errors(error_handler, get_board_support()); + module_state->current_state = state::State::STATE_A; + drawPower(0, 0, 0, 0); + } else if (is_voltage_in_range(cpHi, 9.0)) { + module_state->current_state = state::State::STATE_B; + drawPower(0, 0, 0, 0); + } else if (is_voltage_in_range(cpHi, 6.0)) { + module_state->current_state = state::State::STATE_C; + drawPower(amps1, amps2, amps3, 0.2); + } else if (is_voltage_in_range(cpHi, 3.0)) { + module_state->current_state = state::State::STATE_D; + drawPower(amps1, amps2, amps3, 0.2); + } else if (is_voltage_in_range(cpHi, -12.0)) { + module_state->current_state = state::State::STATE_F; + drawPower(0, 0, 0, 0); + } +} + +void YetiSimulator::simulation_statemachine() const { + auto& board_support = get_board_support(); + + if (module_state->last_state not_eq module_state->current_state) { + publish_event(board_support, module_state->current_state); + } + + switch (module_state->current_state) { + case state::State::STATE_DISABLED: + powerOff(board_support); + module_state->power_on_allowed = false; + break; + + case state::State::STATE_A: { + module_state->use_three_phases_confirmed = module_state->use_three_phases; + const auto* _board_support = dynamic_cast(&board_support); + _board_support->pwm_off(); + reset_powermeter(); + module_state->simplified_mode = false; + + if (module_state->last_state not_eq state::State::STATE_A and + module_state->last_state not_eq state::State::STATE_DISABLED and + module_state->last_state not_eq state::State::STATE_F) { + powerOff(board_support); + + // If car was unplugged, reset RCD flag. + module_state->simdata_setting.rcd_current = 0.1; + module_state->rcd_error = false; + } + break; + } + case state::State::STATE_B: + // Table A.6: Sequence 7 EV stops charging + // Table A.6: Sequence 8.2 EV supply equipment + // responds to EV opens S2 (w/o PWM) + + if (module_state->last_state not_eq state::State::STATE_A and + module_state->last_state not_eq state::State::STATE_B) { + // Need to switch off according to Table A.6 Sequence 8.1 within + powerOff(board_support); + } + + // Table A.6: Sequence 1.1 Plug-in + if (module_state->last_state == state::State::STATE_A) { + module_state->simplified_mode = false; + } + + break; + case state::State::STATE_C: + // Table A.6: Sequence 1.2 Plug-in + if (module_state->last_state == state::State::STATE_A) { + module_state->simplified_mode = true; + } + + if (not module_state->pwm_running) { // C1 + // Table A.6 Sequence 10.2: EV does not stop drawing power even + // if PWM stops. Stop within 6 seconds (E.g. Kona1!) + // This is implemented in EvseManager + if (not module_state->power_on_allowed) + powerOff(board_support); + } else if (module_state->power_on_allowed) { // C2 + // Table A.6: Sequence 4 EV ready to charge. + // Must enable power within 3 seconds. + powerOn(board_support); + } + break; + case state::State::STATE_D: + // Table A.6: Sequence 1.2 Plug-in (w/ventilation) + if (module_state->last_state == state::State::STATE_A) { + module_state->simplified_mode = true; + } + + if (not module_state->pwm_running) { + // Table A.6 Sequence 10.2: EV does not stop drawing power + // even if PWM stops. Stop within 6 seconds (E.g. Kona1!) + /* if (mod.last_pwm_running) // FIMXE implement 6 second timer + startTimer(6000); + if (timerElapsed()) { */ + // force power off under load + powerOff(board_support); + // } + } else if (module_state->power_on_allowed and not module_state->relais_on and module_state->has_ventilation) { + // Table A.6: Sequence 4 EV ready to charge. + // Must enable power within 3 seconds. + powerOn(board_support); + } + break; + case state::State::STATE_E: { + powerOff(board_support); + const auto* _board_support = dynamic_cast(&board_support); + _board_support->pwm_off(); + break; + } + case state::State::STATE_F: + powerOff(board_support); + break; + default: + break; + } + module_state->last_state = module_state->current_state; + module_state->last_pwm_running = module_state->pwm_running; +} + +void YetiSimulator::add_noise() const { + const auto random_number_between_0_and_1 = [] { + return static_cast(rand()) / static_cast(RAND_MAX); + }; + const auto noise = 1 + (random_number_between_0_and_1() - 0.5) * 0.02; + const auto lonoise = 1 + (random_number_between_0_and_1() - 0.5) * 0.005; + const auto impedance = module_state->simdata_setting.impedance / 1000.0; + + module_state->simulation_data.currents.L1 = module_state->simdata_setting.currents.L1 * noise; + module_state->simulation_data.currents.L2 = module_state->simdata_setting.currents.L2 * noise; + module_state->simulation_data.currents.L3 = module_state->simdata_setting.currents.L3 * noise; + module_state->simulation_data.currents.N = module_state->simdata_setting.currents.N * noise; + + module_state->simulation_data.voltages.L1 = + module_state->simdata_setting.voltages.L1 * noise - impedance * module_state->simulation_data.currents.L1; + module_state->simulation_data.voltages.L2 = + module_state->simdata_setting.voltages.L2 * noise - impedance * module_state->simulation_data.currents.L2; + module_state->simulation_data.voltages.L3 = + module_state->simdata_setting.voltages.L3 * noise - impedance * module_state->simulation_data.currents.L3; + + module_state->simulation_data.frequencies.L1 = module_state->simdata_setting.frequencies.L1 * lonoise; + module_state->simulation_data.frequencies.L2 = module_state->simdata_setting.frequencies.L2 * lonoise; + module_state->simulation_data.frequencies.L3 = module_state->simdata_setting.frequencies.L3 * lonoise; + + module_state->simulation_data.cp_voltage = module_state->simdata_setting.cp_voltage * noise; + module_state->simulation_data.rcd_current = module_state->simdata_setting.rcd_current * noise; + module_state->simulation_data.pp_resistor = module_state->simdata_setting.pp_resistor * noise; + + module_state->simulation_data.diode_fail = module_state->simdata_setting.diode_fail; + module_state->simulation_data.error_e = module_state->simdata_setting.error_e; +} + +void YetiSimulator::simulate_powermeter() const { + using namespace std::chrono; + + const auto time_stamp = time_point_cast(system_clock::now()).time_since_epoch().count(); + if (module_state->powermeter_sim_last_time_stamp == 0) + module_state->powermeter_sim_last_time_stamp = time_stamp; + const auto deltat = time_stamp - module_state->powermeter_sim_last_time_stamp; + module_state->powermeter_sim_last_time_stamp = time_stamp; + + const auto wattL1 = module_state->simulation_data.voltages.L1 * module_state->simulation_data.currents.L1 * + (module_state->relais_on ? 1 : 0); + const auto wattL2 = module_state->simulation_data.voltages.L2 * module_state->simulation_data.currents.L2 * + (module_state->relais_on and module_state->use_three_phases_confirmed ? 1 : 0); + const auto wattL3 = module_state->simulation_data.voltages.L3 * module_state->simulation_data.currents.L3 * + (module_state->relais_on and module_state->use_three_phases_confirmed ? 1 : 0); + + module_state->watt_hr.L1 += wattL1 * deltat / 1000.0 / 3600.0; + module_state->watt_hr.L2 += wattL2 * deltat / 1000.0 / 3600.0; + module_state->watt_hr.L3 += wattL3 * deltat / 1000.0 / 3600.0; + + module_state->powermeter_data.time_stamp = round(time_stamp / 1000); + module_state->powermeter_data.totalWattHr = + round(module_state->watt_hr.L1 + module_state->watt_hr.L2 + module_state->watt_hr.L3); + + module_state->powermeter_data.wattL1 = round(wattL1); + module_state->powermeter_data.vrmsL1 = module_state->simulation_data.voltages.L1; + module_state->powermeter_data.irmsL1 = module_state->simulation_data.currents.L1; + module_state->powermeter_data.wattHrL1 = round(module_state->watt_hr.L1); + module_state->powermeter_data.tempL1 = 25.0 + (wattL1 + wattL2 + wattL3) * 0.003; + module_state->powermeter_data.freqL1 = module_state->simulation_data.frequencies.L1; + + module_state->powermeter_data.wattL2 = round(wattL2); + module_state->powermeter_data.vrmsL2 = module_state->simulation_data.voltages.L2; + module_state->powermeter_data.irmsL2 = module_state->simulation_data.currents.L1; + module_state->powermeter_data.wattHrL2 = round(module_state->watt_hr.L2); + module_state->powermeter_data.tempL2 = 25.0 + (wattL1 + wattL2 + wattL3) * 0.003; + module_state->powermeter_data.freqL2 = module_state->simulation_data.frequencies.L2; + + module_state->powermeter_data.wattL3 = round(wattL3); + module_state->powermeter_data.vrmsL3 = module_state->simulation_data.voltages.L3; + module_state->powermeter_data.irmsL3 = module_state->simulation_data.currents.L3; + module_state->powermeter_data.wattHrL3 = round(module_state->watt_hr.L3); + module_state->powermeter_data.tempL3 = 25.0 + (wattL1 + wattL2 + wattL3) * 0.003; + module_state->powermeter_data.freqL3 = module_state->simulation_data.frequencies.L3; + + module_state->powermeter_data.irmsN = module_state->simulation_data.currents.N; +} + +void YetiSimulator::publish_ev_board_support() const { + auto& ev_board_support = get_ev_board_support(); + + const auto pp = read_pp_ampacity(); + + ev_board_support.publish_bsp_measurement( + {.proximity_pilot = pp, + .cp_pwm_duty_cycle = static_cast(module_state->pwm_duty_cycle * 100), + .rcd_current_mA = module_state->simulation_data.rcd_current}); +} + +void YetiSimulator::publish_powermeter() const { + auto& powermeter = get_powermeter(); + auto& mqtt = get_mqtt(); + auto& info = get_info(); + + powermeter.publish_powermeter(power_meter_external(module_state->powermeter_data)); + + // Deprecated external stuff + mqtt.publish("/external/powermeter/vrmsL1", module_state->powermeter_data.vrmsL1); + mqtt.publish("/external/powermeter/phaseSeqError", false); + mqtt.publish("/external/powermeter/time_stamp", std::to_string(module_state->powermeter_data.time_stamp)); + mqtt.publish("/external/powermeter/tempL1", module_state->powermeter_data.tempL1); + mqtt.publish("/external/powermeter/totalKw", + (module_state->powermeter_data.wattL1 + module_state->powermeter_data.wattL2 + + module_state->powermeter_data.wattL3) / + 1000.0); + mqtt.publish("/external/powermeter/totalKWattHr", + (module_state->powermeter_data.wattHrL1 + module_state->powermeter_data.wattHrL2 + + module_state->powermeter_data.wattHrL3) / + 1000.0); + mqtt.publish("/external/powermeter_json", json{module_state->powermeter_data}.dump()); + + mqtt.publish("/external/" + info.id + "/powermeter/tempL1", module_state->powermeter_data.tempL1); + mqtt.publish("/external/" + info.id + "/powermeter/totalKw", + (module_state->powermeter_data.wattL1 + module_state->powermeter_data.wattL2 + + module_state->powermeter_data.wattL3) / + 1000.0); + mqtt.publish("/external/" + info.id + "/powermeter/totalKWattHr", + (module_state->powermeter_data.wattHrL1 + module_state->powermeter_data.wattHrL2 + + module_state->powermeter_data.wattHrL3) / + 1000.0); +} + +void YetiSimulator::publish_telemetry() const { + auto& board_support = get_board_support(); + + board_support.publish_telemetry({.evse_temperature_C = static_cast(module_state->powermeter_data.tempL1), + .fan_rpm = 1500., + .supply_voltage_12V = 12.01, + .supply_voltage_minus_12V = -11.8, + .relais_on = module_state->relais_on}); +} + +void YetiSimulator::publish_keepalive() const { + using namespace std::chrono; + auto& mqtt = get_mqtt(); + + mqtt.publish( + "/external/keepalive_json", + json{ + {"hw_revision", 0}, + {"hw_type", 0}, + {"protocol_version_major", 0}, + {"protocol_version_minor", 1}, + {"sw_version_string", "simulation"}, + {"time_stamp", {time_point_cast(system_clock::now()).time_since_epoch().count() / 1000}}, + } + .dump()); +} + +types::powermeter::Powermeter power_meter_external(const state::PowermeterData& powermeter_data) { + const auto current_iso_time_string = util::get_current_iso_time_string(); + const auto& [time_stamp, totalWattHr, wattL1, vrmsL1, irmsL1, wattHrL1, tempL1, freqL1, wattL2, vrmsL2, irmsL2, + wattHrL2, tempL2, freqL2, wattL3, vrmsL3, irmsL3, wattHrL3, tempL3, freqL3, irmsN] = powermeter_data; + return { + .timestamp = current_iso_time_string, + .energy_Wh_import = + { + .total = static_cast(totalWattHr), + .L1 = static_cast(wattHrL1), + .L2 = static_cast(wattHrL2), + .L3 = static_cast(wattHrL3), + }, + .meter_id = "YETI_POWERMETER", + .phase_seq_error = false, + .power_W = + types::units::Power{ + .total = static_cast(wattL1 + wattL2 + wattL3), + .L1 = static_cast(wattL1), + .L2 = static_cast(wattL2), + .L3 = static_cast(wattL3), + }, + .voltage_V = + types::units::Voltage{ + .L1 = vrmsL1, + .L2 = vrmsL2, + .L3 = vrmsL3, + }, + .current_A = + types::units::Current{ + .L1 = irmsL1, + .L2 = irmsL2, + .L3 = irmsL3, + .N = irmsN, + }, + .frequency_Hz = + types::units::Frequency{ + .L1 = static_cast(freqL1), + .L2 = static_cast(freqL2), + .L3 = static_cast(freqL3), + }, + + }; +} + +double duty_cycle_to_amps(const double dc) { + if (dc < 8.0 / 100.0) + return 0; + if (dc < 85.0 / 100.0) + return dc * 100.0 * 0.6; + if (dc < 96.0 / 100.0) + return (dc * 100.0 - 64) * 2.5; + if (dc < 97.0 / 100.0) + return 80; + return 0; +} + +bool is_voltage_in_range(const double voltage, const double center) { + constexpr auto interval = 1.1; + return voltage > center - interval and voltage < center + interval; +} + +void YetiSimulator::drawPower(const int l1, const int l2, const int l3, const int n) const { + module_state->simdata_setting.currents.L1 = l1; + module_state->simdata_setting.currents.L2 = l2; + module_state->simdata_setting.currents.L3 = l3; + module_state->simdata_setting.currents.N = n; +} + +void YetiSimulator::clear_disconnect_errors(ErrorHandler& error_handler, + const evse_board_supportImplBase& board_support) { + if (board_support.error_state_monitor->is_error_active("evse_board_support/DiodeFault", "")) { + // error_handler.error_DiodeFault(false); TODO + } +} + +void YetiSimulator::powerOn(evse_board_supportImplBase& board_support) const { + if (not module_state->relais_on) { + publish_event(board_support, state::State::Event_PowerOn); + module_state->relais_on = true; + module_state->telemetry_data.power_switch.switching_count += 1; + } +} + +void YetiSimulator::powerOff(evse_board_supportImplBase& board_support) const { + if (module_state->relais_on) { + publish_event(board_support, state::State::Event_PowerOff); + module_state->telemetry_data.power_switch.switching_count++; + module_state->relais_on = false; + } +} + +// NOLINTNEXTLINE +void publish_event(evse_board_supportImplBase& board_support, state::State event) { + board_support.publish_event(event_to_enum(event)); +} + +// NOLINTNEXTLINE +static types::board_support_common::BspEvent event_to_enum(state::State event) { + using state::State; + using types::board_support_common::Event; + + switch (event) { + case State::STATE_A: + return {.event = Event::A}; + case State::STATE_B: + return {.event = Event::B}; + case State::STATE_C: + return {.event = Event::C}; + case State::STATE_D: + return {.event = Event::D}; + case State::STATE_E: + return {.event = Event::E}; + case State::STATE_F: + return {.event = Event::F}; + case State::STATE_DISABLED: + return {.event = Event::F}; + case State::Event_PowerOn: + return {.event = Event::PowerOn}; + case State::Event_PowerOff: + return {.event = Event::PowerOff}; + default: + EVLOG_error << "Invalid event : " << event_to_string(event); + return {.event = Event::Disconnected}; // TODO: correct default value + } +} + +// NOLINTNEXTLINE +static std::string event_to_string(state::State state) { + using state::State; + + switch (state) { + case State::STATE_A: + return "A"; + case State::STATE_B: + return "B"; + case State::STATE_C: + return "C"; + case State::STATE_D: + return "D"; + case State::STATE_E: + return "E"; + case State::STATE_F: + return "F"; + case State::STATE_DISABLED: + return "F"; + case State::Event_PowerOn: + return "PowerOn"; + case State::Event_PowerOff: + return "PowerOff"; + default: + return "invalid"; + } +} + +void YetiSimulator::reset_powermeter() const { + module_state->watt_hr.L1 = 0; + module_state->watt_hr.L2 = 0; + module_state->watt_hr.L3 = 0; + module_state->powermeter_sim_last_time_stamp = 0; +} + +types::board_support_common::ProximityPilot YetiSimulator::read_pp_ampacity() const { + const auto pp_resistor = module_state->simdata_setting.pp_resistor; + + if (pp_resistor < 80.0 or pp_resistor > 2460) { + EVLOG_error << "PP resistor value " << pp_resistor << " Ohm seems to be outside the allowed range."; + return {.ampacity = types::board_support_common::Ampacity::None}; + } + + // PP resistor value in spec, use a conservative interpretation of the resistance ranges + if (pp_resistor > 936.0 and pp_resistor <= 2460.0) { + return {.ampacity = types::board_support_common::Ampacity::A_13}; + } + if (pp_resistor > 308.0 && pp_resistor <= 936.0) { + return {.ampacity = types::board_support_common::Ampacity::A_20}; + } + if (pp_resistor > 140.0 && pp_resistor <= 308.0) { + return {.ampacity = types::board_support_common::Ampacity::A_32}; + } + if (pp_resistor > 80.0 && pp_resistor <= 140.0) { + return {.ampacity = types::board_support_common::Ampacity::A_63_3ph_70_1ph}; + } + return {.ampacity = types::board_support_common::Ampacity::None}; +} + } // namespace module diff --git a/modules/YetiSimulator/YetiSimulator.hpp b/modules/YetiSimulator/YetiSimulator.hpp index b9e298e64..970624ad8 100644 --- a/modules/YetiSimulator/YetiSimulator.hpp +++ b/modules/YetiSimulator/YetiSimulator.hpp @@ -18,8 +18,8 @@ // ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1 // insert your custom include headers here +#include "util/error_handler.hpp" #include "util/mqtt_handler.hpp" -#include "util/simulator.hpp" #include "util/state.hpp" // ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1 @@ -58,15 +58,15 @@ class YetiSimulator : public Everest::ModuleBase { // ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1 // insert your public definitions here - void clear_data(); - Everest::MqttProvider& get_mqtt(); - state::ModuleState& get_module_state(); + void reset_module_state(); + Everest::MqttProvider& get_mqtt() const; + state::ModuleState& get_module_state() const; const ModuleInfo& get_info() const; - evse_board_supportImplBase& get_board_support(); - ev_board_supportImplBase& get_ev_board_support(); - powermeterImplBase& get_powermeter(); - ac_rcdImplBase& get_ac_rcd(); - connector_lockImplBase& get_connector_lock(); + evse_board_supportImplBase& get_board_support() const; + ev_board_supportImplBase& get_ev_board_support() const; + powermeterImplBase& get_powermeter() const; + ac_rcdImplBase& get_ac_rcd() const; + connector_lockImplBase& get_connector_lock() const; // ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1 protected: @@ -75,14 +75,32 @@ class YetiSimulator : public Everest::ModuleBase { // ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1 private: - friend class LdEverest; + friend struct LdEverest; void init(); void ready(); // ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1 // insert your private definitions here - void run_telemetry_slow(); - void run_telemetry_fast(); + void run_telemetry_slow() const; + void run_telemetry_fast() const; + void start_simulation(int sleep_time_ms); + [[noreturn]] void run_simulation(int sleep_time_ms) const; + void simulation_step() const; + void check_error_rcd() const; + void read_from_car() const; + void simulation_statemachine() const; + void add_noise() const; + void simulate_powermeter() const; + void publish_ev_board_support() const; + void publish_powermeter() const; + void publish_telemetry() const; + void publish_keepalive() const; + void drawPower(int l1, int l2, int l3, int n) const; + static void clear_disconnect_errors(ErrorHandler& error_handler, const evse_board_supportImplBase& board_support); + void powerOn(evse_board_supportImplBase& board_support) const; + void powerOff(evse_board_supportImplBase& board_support) const; + void reset_powermeter() const; + [[nodiscard]] types::board_support_common::ProximityPilot read_pp_ampacity() const; std::unique_ptr module_state; std::unique_ptr mqtt_handler; @@ -92,6 +110,12 @@ class YetiSimulator : public Everest::ModuleBase { // ev@087e516b-124c-48df-94fb-109508c7cda9:v1 // insert other definitions here +types::powermeter::Powermeter power_meter_external(const state::PowermeterData& powermeter_data); +double duty_cycle_to_amps(double dc); +bool is_voltage_in_range(const double voltage, double center); +void publish_event(evse_board_supportImplBase& board_support, state::State event); +static types::board_support_common::BspEvent event_to_enum(state::State event); +static std::string event_to_string(state::State state); // ev@087e516b-124c-48df-94fb-109508c7cda9:v1 } // namespace module diff --git a/modules/YetiSimulator/board_support/evse_board_supportImpl.cpp b/modules/YetiSimulator/board_support/evse_board_supportImpl.cpp index 2d0753097..878732822 100644 --- a/modules/YetiSimulator/board_support/evse_board_supportImpl.cpp +++ b/modules/YetiSimulator/board_support/evse_board_supportImpl.cpp @@ -2,26 +2,16 @@ // Copyright Pionix GmbH and Contributors to EVerest #include "evse_board_supportImpl.hpp" +#include "util/state.hpp" -namespace module { -namespace board_support { +namespace module::board_support { void evse_board_supportImpl::init() { } void evse_board_supportImpl::ready() { - const auto capabilities = types::evse_board_support::HardwareCapabilities{ - .max_current_A_import = 32.0, - .min_current_A_import = 6.0, - .max_phase_count_import = 3, - .min_phase_count_import = 1, - .max_current_A_export = 16.0, - .min_current_A_export = 0.0, - .max_phase_count_export = 3, - .min_phase_count_export = 1, - .supports_changing_phases_during_charging = true, - .connector_type = types::evse_board_support::Connector_type::IEC62196Type2Cable}; - publish_capabilities(capabilities); + const auto default_capabilities = set_default_capabilities(); + publish_capabilities(default_capabilities); } void evse_board_supportImpl::handle_enable(bool& value) { @@ -61,7 +51,7 @@ void evse_board_supportImpl::handle_ac_switch_three_phases_while_charging(bool& module_state.use_three_phases_confirmed = value; } -void evse_board_supportImpl::handle_evse_replug(int& value) { +void evse_board_supportImpl::handle_evse_replug(int& _) { EVLOG_error << "Replugging not supported"; } @@ -69,27 +59,30 @@ types::board_support_common::ProximityPilot evse_board_supportImpl::handle_ac_re using types::board_support_common::Ampacity; const auto pp_resistor = mod->get_module_state().simulation_data.pp_resistor; - if (pp_resistor < 80 || pp_resistor > 2460) { + if (pp_resistor < 80 or pp_resistor > 2460) { EVLOG_error << "PP resistor value " << pp_resistor << " Ohm seems to be outside the allowed range."; return {.ampacity = Ampacity::None}; - } else if (pp_resistor > 936 && pp_resistor <= 2460) { + } + if (pp_resistor > 936 && pp_resistor <= 2460) { return {.ampacity = Ampacity::A_13}; - } else if (pp_resistor > 308 && pp_resistor <= 936) { + } + if (pp_resistor > 308 && pp_resistor <= 936) { return {.ampacity = Ampacity::A_20}; - } else if (pp_resistor > 140 && pp_resistor <= 308) { + } + if (pp_resistor > 140 && pp_resistor <= 308) { return {.ampacity = Ampacity::A_32}; - } else if (pp_resistor > 80 && pp_resistor <= 140) { + } + if (pp_resistor > 80 && pp_resistor <= 140) { return {.ampacity = Ampacity::A_63_3ph_70_1ph}; - } else { - return {.ampacity = Ampacity::None}; } + return {.ampacity = Ampacity::None}; } void evse_board_supportImpl::handle_ac_set_overcurrent_limit_A(double& value) { // TODO: intentional? } -void evse_board_supportImpl::pwm_on(double dutycycle) { +void evse_board_supportImpl::pwm_on(const double dutycycle) const { auto& module_state = mod->get_module_state(); if (dutycycle > 0.0) { @@ -101,7 +94,7 @@ void evse_board_supportImpl::pwm_on(double dutycycle) { } } -void evse_board_supportImpl::pwm_off() { +void evse_board_supportImpl::pwm_off() const { auto& module_state = mod->get_module_state(); module_state.pwm_duty_cycle = 1.0; @@ -109,7 +102,7 @@ void evse_board_supportImpl::pwm_off() { module_state.pwm_error_f = false; } -void evse_board_supportImpl::pwm_f() { +void evse_board_supportImpl::pwm_f() const { auto& module_state = mod->get_module_state(); module_state.pwm_duty_cycle = 1.0; @@ -117,5 +110,16 @@ void evse_board_supportImpl::pwm_f() { module_state.pwm_error_f = true; } -} // namespace board_support -} // namespace module +types::evse_board_support::HardwareCapabilities set_default_capabilities() { + return {.max_current_A_import = 32.0, + .min_current_A_import = 6.0, + .max_phase_count_import = 3, + .min_phase_count_import = 1, + .max_current_A_export = 16.0, + .min_current_A_export = 0.0, + .max_phase_count_export = 3, + .min_phase_count_export = 1, + .supports_changing_phases_during_charging = true, + .connector_type = types::evse_board_support::Connector_type::IEC62196Type2Cable}; +} +} // namespace module::board_support \ No newline at end of file diff --git a/modules/YetiSimulator/board_support/evse_board_supportImpl.hpp b/modules/YetiSimulator/board_support/evse_board_supportImpl.hpp index 4b5b25d47..91f60c04c 100644 --- a/modules/YetiSimulator/board_support/evse_board_supportImpl.hpp +++ b/modules/YetiSimulator/board_support/evse_board_supportImpl.hpp @@ -7,10 +7,9 @@ // template version 3 // +#include #include -#include "../YetiSimulator.hpp" - // ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1 // insert your custom include headers here // ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1 @@ -28,7 +27,7 @@ class evse_board_supportImpl : public evse_board_supportImplBase { // ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1 // insert your public definitions here - void pwm_off(); + void pwm_off() const; // ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1 protected: @@ -56,13 +55,14 @@ class evse_board_supportImpl : public evse_board_supportImplBase { // ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1 // insert your private definitions here - void pwm_on(double dutycycle); - void pwm_f(); + void pwm_on(double dutycycle) const; + void pwm_f() const; // ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1 }; // ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1 // insert other definitions here +types::evse_board_support::HardwareCapabilities set_default_capabilities(); // ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1 } // namespace board_support diff --git a/modules/YetiSimulator/connector_lock/connector_lockImpl.cpp b/modules/YetiSimulator/connector_lock/connector_lockImpl.cpp index 9508128af..1c40fad99 100644 --- a/modules/YetiSimulator/connector_lock/connector_lockImpl.cpp +++ b/modules/YetiSimulator/connector_lock/connector_lockImpl.cpp @@ -2,9 +2,9 @@ // Copyright Pionix GmbH and Contributors to EVerest #include "connector_lockImpl.hpp" +#include -namespace module { -namespace connector_lock { +namespace module::connector_lock { void connector_lockImpl::init() { } @@ -20,5 +20,4 @@ void connector_lockImpl::handle_unlock() { EVLOG_info << "Unlock connector"; } -} // namespace connector_lock -} // namespace module +} // namespace module::connector_lock \ No newline at end of file diff --git a/modules/YetiSimulator/connector_lock/connector_lockImpl.hpp b/modules/YetiSimulator/connector_lock/connector_lockImpl.hpp index d68cdcc68..369b931ed 100644 --- a/modules/YetiSimulator/connector_lock/connector_lockImpl.hpp +++ b/modules/YetiSimulator/connector_lock/connector_lockImpl.hpp @@ -15,8 +15,7 @@ // insert your custom include headers here // ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1 -namespace module { -namespace connector_lock { +namespace module::connector_lock { struct Conf {}; @@ -24,7 +23,7 @@ class connector_lockImpl : public connector_lockImplBase { public: connector_lockImpl() = delete; connector_lockImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer& mod, Conf& config) : - connector_lockImplBase(ev, "connector_lock"), mod(mod), config(config){}; + connector_lockImplBase(ev, "connector_lock"), mod(mod), config(config) {}; // ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1 // insert your public definitions here @@ -32,8 +31,8 @@ class connector_lockImpl : public connector_lockImplBase { protected: // command handler functions (virtual) - virtual void handle_lock() override; - virtual void handle_unlock() override; + void handle_lock() override; + void handle_unlock() override; // ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1 // insert your protected definitions here @@ -43,8 +42,8 @@ class connector_lockImpl : public connector_lockImplBase { const Everest::PtrContainer& mod; const Conf& config; - virtual void init() override; - virtual void ready() override; + void init() override; + void ready() override; // ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1 // insert your private definitions here @@ -55,5 +54,4 @@ class connector_lockImpl : public connector_lockImplBase { // insert other definitions here // ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1 -} // namespace connector_lock -} // namespace module +} // namespace module::connector_lock \ No newline at end of file diff --git a/modules/YetiSimulator/ev_board_support/ev_board_supportImpl.cpp b/modules/YetiSimulator/ev_board_support/ev_board_supportImpl.cpp index d64563b39..5cb4a8415 100644 --- a/modules/YetiSimulator/ev_board_support/ev_board_supportImpl.cpp +++ b/modules/YetiSimulator/ev_board_support/ev_board_supportImpl.cpp @@ -2,9 +2,9 @@ // Copyright Pionix GmbH and Contributors to EVerest #include "ev_board_supportImpl.hpp" +#include -namespace module { -namespace ev_board_support { +namespace module::ev_board_support { void ev_board_supportImpl::init() { } @@ -14,9 +14,9 @@ void ev_board_supportImpl::ready() { void ev_board_supportImpl::handle_enable(bool& value) { auto& module_state = mod->get_module_state(); - if (module_state.simulation_enabled && !value) { + if (module_state.simulation_enabled and not value) { publish_bsp_event({types::board_support_common::Event::A}); - mod->clear_data(); + mod->reset_module_state(); } module_state.simulation_enabled = value; } @@ -27,23 +27,23 @@ void ev_board_supportImpl::handle_set_cp_state(types::ev_board_support::EvCpStat switch (cp_state) { case EvCpState::A: - simdata_setting.cp_voltage = 12.0; + simdata_setting.cp_voltage = cp_voltage_a; break; case EvCpState::B: - simdata_setting.cp_voltage = 9.0; + simdata_setting.cp_voltage = cp_voltage_b; break; case EvCpState::C: - simdata_setting.cp_voltage = 6.0; + simdata_setting.cp_voltage = cp_voltage_c; break; case EvCpState::D: - simdata_setting.cp_voltage = 3.0; + simdata_setting.cp_voltage = cp_voltage_d; break; case EvCpState::E: simdata_setting.error_e = true; break; default: break; - }; + } } void ev_board_supportImpl::handle_allow_power_on(bool& value) { @@ -78,5 +78,4 @@ void ev_board_supportImpl::handle_set_rcd_error(double& rcd_current_mA) { simdata_setting.rcd_current = rcd_current_mA; } -} // namespace ev_board_support -} // namespace module +} // namespace module::ev_board_support \ No newline at end of file diff --git a/modules/YetiSimulator/ev_board_support/ev_board_supportImpl.hpp b/modules/YetiSimulator/ev_board_support/ev_board_supportImpl.hpp index 43f9b5424..1dd382f63 100644 --- a/modules/YetiSimulator/ev_board_support/ev_board_supportImpl.hpp +++ b/modules/YetiSimulator/ev_board_support/ev_board_supportImpl.hpp @@ -15,8 +15,7 @@ // insert your custom include headers here // ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1 -namespace module { -namespace ev_board_support { +namespace module::ev_board_support { struct Conf {}; @@ -24,7 +23,7 @@ class ev_board_supportImpl : public ev_board_supportImplBase { public: ev_board_supportImpl() = delete; ev_board_supportImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer& mod, Conf& config) : - ev_board_supportImplBase(ev, "ev_board_support"), mod(mod), config(config){}; + ev_board_supportImplBase(ev, "ev_board_support"), mod(mod), config(config) {}; // ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1 // insert your public definitions here @@ -58,7 +57,10 @@ class ev_board_supportImpl : public ev_board_supportImplBase { // ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1 // insert other definitions here +constexpr auto inline cp_voltage_a = 12.0; +constexpr auto inline cp_voltage_b = 9.0; +constexpr auto inline cp_voltage_c = 6.0; +constexpr auto inline cp_voltage_d = 3.0; // ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1 -} // namespace ev_board_support -} // namespace module +} // namespace module::ev_board_support \ No newline at end of file diff --git a/modules/YetiSimulator/powermeter/powermeterImpl.cpp b/modules/YetiSimulator/powermeter/powermeterImpl.cpp index 249b00de2..fddc3e4a9 100644 --- a/modules/YetiSimulator/powermeter/powermeterImpl.cpp +++ b/modules/YetiSimulator/powermeter/powermeterImpl.cpp @@ -2,9 +2,9 @@ // Copyright Pionix GmbH and Contributors to EVerest #include "powermeterImpl.hpp" +#include -namespace module { -namespace powermeter { +namespace module::powermeter { void powermeterImpl::init() { } @@ -13,7 +13,7 @@ void powermeterImpl::ready() { } types::powermeter::TransactionStartResponse -powermeterImpl::handle_start_transaction(types::powermeter::TransactionReq& value) { +powermeterImpl::handle_start_transaction(types::powermeter::TransactionReq& _) { return {.status = types::powermeter::TransactionRequestStatus::OK}; } @@ -22,5 +22,4 @@ types::powermeter::TransactionStopResponse powermeterImpl::handle_stop_transacti .error = "YetiDriver does not support stop transaction request."}; } -} // namespace powermeter -} // namespace module +} // namespace module::powermeter \ No newline at end of file diff --git a/modules/YetiSimulator/rcd/ac_rcdImpl.cpp b/modules/YetiSimulator/rcd/ac_rcdImpl.cpp index a1c868f27..1de63af31 100644 --- a/modules/YetiSimulator/rcd/ac_rcdImpl.cpp +++ b/modules/YetiSimulator/rcd/ac_rcdImpl.cpp @@ -3,8 +3,7 @@ #include "ac_rcdImpl.hpp" -namespace module { -namespace rcd { +namespace module::rcd { void ac_rcdImpl::init() { } @@ -21,5 +20,4 @@ bool ac_rcdImpl::handle_reset() { return true; } -} // namespace rcd -} // namespace module +} // namespace module::rcd \ No newline at end of file diff --git a/modules/YetiSimulator/util/error_handler.cpp b/modules/YetiSimulator/util/error_handler.cpp index d63be421c..e0b1358fb 100644 --- a/modules/YetiSimulator/util/error_handler.cpp +++ b/modules/YetiSimulator/util/error_handler.cpp @@ -12,333 +12,16 @@ ErrorHandler::ErrorHandler(evse_board_supportImplBase* p_board_support, ac_rcdIm p_board_support(p_board_support), p_rcd(p_rcd), p_connector_lock(p_connector_lock) { } -void ErrorHandler::error_DiodeFault(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/DiodeFault", "", - "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/DiodeFault"); - } -} - -void ErrorHandler::error_BrownOut(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/BrownOut", "", - "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/BrownOut"); - } -} - -void ErrorHandler::error_EnergyManagement(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/EnergyManagement", "", - "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/EnergyManagement"); - } -} - -void ErrorHandler::error_PermanentFault(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/PermanentFault", "", - "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/PermanentFault"); - } -} - -void ErrorHandler::error_MREC2GroundFailure(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/MREC2GroundFailure", "", - "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/MREC2GroundFailure"); - } -} - -void ErrorHandler::error_MREC3HighTemperature(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/MREC3HighTemperature", "", - "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/MREC3HighTemperature"); - } -} - -void ErrorHandler::error_MREC4OverCurrentFailure(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/MREC4OverCurrentFailure", - "", "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/MREC4OverCurrentFailure"); - } -} - -void ErrorHandler::error_MREC5OverVoltage(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/MREC5OverVoltage", "", - "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/MREC5OverVoltage"); - } -} - -void ErrorHandler::error_MREC6UnderVoltage(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/MREC6UnderVoltage", "", - "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/MREC6UnderVoltage"); - } -} - -void ErrorHandler::error_MREC8EmergencyStop(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/MREC8EmergencyStop", "", - "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/MREC8EmergencyStop"); - } -} - -void ErrorHandler::error_MREC10InvalidVehicleMode(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/MREC10InvalidVehicleMode", - "", "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/MREC10InvalidVehicleMode"); - } -} - -void ErrorHandler::error_MREC14PilotFault(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/MREC14PilotFault", "", - "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/MREC14PilotFault"); - } -} - -void ErrorHandler::error_MREC15PowerLoss(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/MREC15PowerLoss", "", - "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/MREC15PowerLoss"); - } -} - -void ErrorHandler::error_MREC17EVSEContactorFault(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/MREC17EVSEContactorFault", - "", "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/MREC17EVSEContactorFault"); - } -} - -void ErrorHandler::error_MREC18CableOverTempDerate(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/MREC18CableOverTempDerate", - "", "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/MREC18CableOverTempDerate"); - } -} - -void ErrorHandler::error_MREC19CableOverTempStop(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/MREC19CableOverTempStop", - "", "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/MREC19CableOverTempStop"); - } -} - -void ErrorHandler::error_MREC20PartialInsertion(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/MREC20PartialInsertion", "", - "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/MREC20PartialInsertion"); - } -} - -void ErrorHandler::error_MREC23ProximityFault(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/MREC23ProximityFault", "", - "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/MREC23ProximityFault"); - } -} - -void ErrorHandler::error_MREC24ConnectorVoltageHigh(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/MREC24ConnectorVoltageHigh", - "", "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/MREC24ConnectorVoltageHigh"); - } -} - -void ErrorHandler::error_MREC25BrokenLatch(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/MREC25BrokenLatch", "", - "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/MREC25BrokenLatch"); - } -} - -void ErrorHandler::error_MREC26CutCable(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("evse_board_support/MREC26CutCable", "", - "Simulated fault event", Severity::High); - p_board_support->raise_error(error); - } else { - p_board_support->clear_error("evse_board_support/MREC26CutCable"); - } -} - -void ErrorHandler::error_ac_rcd_MREC2GroundFailure(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("ac_rcd/MREC2GroundFailure", "", - "Simulated fault event", Severity::High); - p_rcd->raise_error(error); - } else { - p_rcd->clear_error("ac_rcd/MREC2GroundFailure"); - } -} - -void ErrorHandler::error_ac_rcd_VendorError(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("ac_rcd/VendorError", "", - "Simulated fault event", Severity::High); - p_rcd->raise_error(error); - } else { - p_rcd->clear_error("ac_rcd/VendorError"); - } -} - -void ErrorHandler::error_ac_rcd_Selftest(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("ac_rcd/Selftest", "", "Simulated fault event", - Severity::High); - p_rcd->raise_error(error); - } else { - p_rcd->clear_error("ac_rcd/Selftest"); - } -} - -void ErrorHandler::error_ac_rcd_AC(bool raise) { - if (raise) { - const auto error = - p_board_support->error_factory->create_error("ac_rcd/AC", "", "Simulated fault event", Severity::High); - p_rcd->raise_error(error); - } else { - p_rcd->clear_error("ac_rcd/AC"); - } -} - -void ErrorHandler::error_ac_rcd_DC(bool raise) { - if (raise) { - const auto error = - p_board_support->error_factory->create_error("ac_rcd/DC", "", "Simulated fault event", Severity::High); - p_rcd->raise_error(error); - } else { - p_rcd->clear_error("ac_rcd/DC"); - } -} - -void ErrorHandler::error_lock_ConnectorLockCapNotCharged(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("connector_lock/ConnectorLockCapNotCharged", "", - "Simulated fault event", Severity::High); - p_connector_lock->raise_error(error); - } else { - p_connector_lock->clear_error("connector_lock/ConnectorLockCapNotCharged"); - } -} - -void ErrorHandler::error_lock_ConnectorLockUnexpectedOpen(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("connector_lock/ConnectorLockUnexpectedOpen", - "", "Simulated fault event", Severity::High); - p_connector_lock->raise_error(error); - } else { - p_connector_lock->clear_error("connector_lock/ConnectorLockUnexpectedOpen"); - } -} - -void ErrorHandler::error_lock_ConnectorLockUnexpectedClose(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("connector_lock/ConnectorLockUnexpectedClose", - "", "Simulated fault event", Severity::High); - p_connector_lock->raise_error(error); - } else { - p_connector_lock->clear_error("connector_lock/ConnectorLockUnexpectedClose"); - } -} - -void ErrorHandler::error_lock_ConnectorLockFailedLock(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("connector_lock/ConnectorLockFailedLock", "", - "Simulated fault event", Severity::High); - p_connector_lock->raise_error(error); - } else { - p_connector_lock->clear_error("connector_lock/ConnectorLockFailedLock"); - } -} - -void ErrorHandler::error_lock_ConnectorLockFailedUnlock(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("connector_lock/ConnectorLockFailedUnlock", "", - "Simulated fault event", Severity::High); - p_connector_lock->raise_error(error); - } else { - p_connector_lock->clear_error("connector_lock/ConnectorLockFailedUnlock"); - } -} - -void ErrorHandler::error_lock_MREC1ConnectorLockFailure(bool raise) { - if (raise) { - const auto error = p_board_support->error_factory->create_error("connector_lock/MREC1ConnectorLockFailure", "", - "Simulated fault event", Severity::High); - p_connector_lock->raise_error(error); - } else { - p_connector_lock->clear_error("connector_lock/MREC1ConnectorLockFailure"); - } +Everest::error::Error create_error(const Everest::error::ErrorFactory& error_factory, const ErrorDefinition& def) { + return error_factory.create_error(def.type, def.sub_type, def.message, def.severity); } -void ErrorHandler::error_lock_VendorError(bool raise) { +template +void forward_error(HandleType& handle, const Everest::error::Error& error, const bool raise) { if (raise) { - const auto error = p_board_support->error_factory->create_error("connector_lock/VendorError", "", - "Simulated fault event", Severity::High); - p_connector_lock->raise_error(error); + handle->raise_error(error); } else { - p_connector_lock->clear_error("connector_lock/VendorError"); + handle->clear_error(error.type); } } diff --git a/modules/YetiSimulator/util/error_handler.hpp b/modules/YetiSimulator/util/error_handler.hpp index a4a8de47e..4167bbdb3 100644 --- a/modules/YetiSimulator/util/error_handler.hpp +++ b/modules/YetiSimulator/util/error_handler.hpp @@ -9,49 +9,124 @@ namespace module { +struct ErrorDefinition { + const char* type; + const char* sub_type{""}; + const char* message{""}; + Everest::error::Severity severity{Everest::error::Severity::High}; + enum class ErrorDestination : uint8_t { + board_support, + rcd, + connector_lock, + } error_destination; +}; + +Everest::error::Error create_error(const Everest::error::ErrorFactory& error_factory, const ErrorDefinition& def); + class ErrorHandler { public: ErrorHandler(evse_board_supportImplBase* p_board_support, ac_rcdImplBase* p_rcd, connector_lockImplBase* p_connector_lock); - void error_DiodeFault(bool raise); - void error_BrownOut(bool raise); - void error_EnergyManagement(bool raise); - void error_PermanentFault(bool raise); - void error_MREC2GroundFailure(bool raise); - void error_MREC3HighTemperature(bool raise); - void error_MREC4OverCurrentFailure(bool raise); - void error_MREC5OverVoltage(bool raise); - void error_MREC6UnderVoltage(bool raise); - void error_MREC8EmergencyStop(bool raise); - void error_MREC10InvalidVehicleMode(bool raise); - void error_MREC14PilotFault(bool raise); - void error_MREC15PowerLoss(bool raise); - void error_MREC17EVSEContactorFault(bool raise); - void error_MREC18CableOverTempDerate(bool raise); - void error_MREC19CableOverTempStop(bool raise); - void error_MREC20PartialInsertion(bool raise); - void error_MREC23ProximityFault(bool raise); - void error_MREC24ConnectorVoltageHigh(bool raise); - void error_MREC25BrokenLatch(bool raise); - void error_MREC26CutCable(bool raise); - void error_ac_rcd_MREC2GroundFailure(bool raise); - void error_ac_rcd_VendorError(bool raise); - void error_ac_rcd_Selftest(bool raise); - void error_ac_rcd_AC(bool raise); - void error_ac_rcd_DC(bool raise); - void error_lock_ConnectorLockCapNotCharged(bool raise); - void error_lock_ConnectorLockUnexpectedOpen(bool raise); - void error_lock_ConnectorLockUnexpectedClose(bool raise); - void error_lock_ConnectorLockFailedLock(bool raise); - void error_lock_ConnectorLockFailedUnlock(bool raise); - void error_lock_MREC1ConnectorLockFailure(bool raise); - void error_lock_VendorError(bool raise); - private: evse_board_supportImplBase* p_board_support; ac_rcdImplBase* p_rcd; connector_lockImplBase* p_connector_lock; }; +namespace error_definitions { +inline const auto connector_lock_ConnectorLockUnexpectedClose = + ErrorDefinition{"connector_lock/ConnectorLockUnexpectedClose"}; + +inline const auto evse_board_support_DiodeFault = + ErrorDefinition{"evse_board_support/DiodeFault", "", "Simulated fault event"}; + +inline const auto evse_board_support_BrownOut = + ErrorDefinition{"evse_board_support/BrownOut", "", "Simulated fault event"}; + +inline const auto evse_board_support_EnergyManagement = + ErrorDefinition{"evse_board_support/EnergyManagement", "", "Simulated fault event"}; + +inline const auto evse_board_support_PermanentFault = + ErrorDefinition{"evse_board_support/PermanentFault", "", "Simulated fault event"}; + +inline const auto evse_board_support_MREC2GroundFailure = + ErrorDefinition{"evse_board_support/MREC2GroundFailure", "", "Simulated fault event"}; + +inline const auto evse_board_support_MREC3HighTemperature = + ErrorDefinition{"evse_board_support/MREC3HighTemperature", "", "Simulated fault event"}; + +inline const auto evse_board_support_MREC4OverCurrentFailure = + ErrorDefinition{"evse_board_support/MREC4OverCurrentFailure", "", "Simulated fault event"}; + +inline const auto evse_board_support_MREC5OverVoltage = + ErrorDefinition{"evse_board_support/MREC5OverVoltage", "", "Simulated fault event"}; + +inline const auto evse_board_support_MREC6UnderVoltage = + ErrorDefinition{"evse_board_support/MREC6UnderVoltage", "", "Simulated fault event"}; + +inline const auto evse_board_support_MREC8EmergencyStop = + ErrorDefinition{"evse_board_support/MREC8EmergencyStop", "", "Simulated fault event"}; + +inline const auto evse_board_support_MREC10InvalidVehicleMode = + ErrorDefinition{"evse_board_support/MREC10InvalidVehicleMode", "", "Simulated fault event"}; + +inline const auto evse_board_support_MREC14PilotFault = + ErrorDefinition{"evse_board_support/MREC14PilotFault", "", "Simulated fault event"}; + +inline const auto evse_board_support_MREC15PowerLoss = + ErrorDefinition{"evse_board_support/MREC15PowerLoss", "", "Simulated fault event"}; + +inline const auto evse_board_support_MREC17EVSEContactorFault = + ErrorDefinition{"evse_board_support/MREC17EVSEContactorFault", "", "Simulated fault event"}; + +inline const auto evse_board_support_MREC18CableOverTempDerate = + ErrorDefinition{"evse_board_support/MREC18CableOverTempDerate", "", "Simulated fault event"}; + +inline const auto evse_board_support_MREC19CableOverTempStop = + ErrorDefinition{"evse_board_support/MREC19CableOverTempStop", "", "Simulated fault event"}; + +inline const auto evse_board_support_MREC20PartialInsertion = + ErrorDefinition{"evse_board_support/MREC20PartialInsertion", "", "Simulated fault event"}; + +inline const auto evse_board_support_MREC23ProximityFault = + ErrorDefinition{"evse_board_support/MREC23ProximityFault", "", "Simulated fault event"}; + +inline const auto evse_board_support_MREC24ConnectorVoltageHigh = + ErrorDefinition{"evse_board_support/MREC24ConnectorVoltageHigh", "", "Simulated fault event"}; + +inline const auto evse_board_support_MREC25BrokenLatch = + ErrorDefinition{"evse_board_support/MREC25BrokenLatch", "", "Simulated fault event"}; + +inline const auto evse_board_support_MREC26CutCable = + ErrorDefinition{"evse_board_support/MREC26CutCable", "", "Simulated fault event"}; + +inline const auto ac_rcd_VendorError = ErrorDefinition{"ac_rcd/VendorError", "", "Simulated fault event"}; + +inline const auto ac_rcd_Selftest = ErrorDefinition{"ac_rcd/Selftest", "", "Simulated fault event"}; + +inline const auto ac_rcd_AC = ErrorDefinition{"ac_rcd/AC", "", "Simulated fault event"}; + +inline const auto ac_rcd_DC = ErrorDefinition{"ac_rcd/DC", "", "Simulated fault event"}; + +inline const auto connector_lock_ConnectorLockCapNotCharged = + ErrorDefinition{"connector_lock/ConnectorLockCapNotCharged", "", "Simulated fault event"}; + +inline const auto connector_lock_ConnectorLockUnexpectedOpen = + ErrorDefinition{"connector_lock/ConnectorLockUnexpectedOpen", "", "Simulated fault event"}; + +inline const auto connector_lock_ConnectorLockFailedLock = + ErrorDefinition{"connector_lock/ConnectorLockFailedLock", "", "Simulated fault event"}; + +inline const auto connector_lock_ConnectorLockFailedUnlock = + ErrorDefinition{"connector_lock/ConnectorLockFailedUnlock", "", "Simulated fault event"}; + +inline const auto connector_lock_MREC1ConnectorLockFailure = + ErrorDefinition{"connector_lock/MREC1ConnectorLockFailure", "", "Simulated fault event"}; + +inline const auto connector_lock_VendorError = + ErrorDefinition{"connector_lock/VendorError", "", "Simulated fault event"}; + +} // namespace error_definitions + } // namespace module diff --git a/modules/YetiSimulator/util/mqtt_handler.cpp b/modules/YetiSimulator/util/mqtt_handler.cpp index 4537d7844..42c4908bc 100644 --- a/modules/YetiSimulator/util/mqtt_handler.cpp +++ b/modules/YetiSimulator/util/mqtt_handler.cpp @@ -5,89 +5,135 @@ #include "everest/logging.hpp" #include "nlohmann/json.hpp" +#include +#include + namespace module { MqttHandler::MqttHandler(evse_board_supportImplBase* p_board_support, ac_rcdImplBase* p_rcd, connector_lockImplBase* p_connector_lock) : - errorHandler{p_board_support, p_rcd, p_connector_lock} { + errorHandler{p_board_support, p_rcd, p_connector_lock}, error_factory{p_board_support->error_factory.get()} { } -void MqttHandler::handle_mqtt_payload(const std::string& payload) { - const auto e = nlohmann::json::parse(payload); +static std::tuple parse_error_type(const std::string& payload) { + // parsing, getting raise + const auto e = json::parse(payload); - const auto raise = e["raise"] == "true"; + const auto raise = e.value("raise", false); - const auto error_type = std::string{e["error_type"]}; + const std::string& error_type = e.at("error_type"); - if (error_type == "DiodeFault") { - errorHandler.error_DiodeFault(raise); - } else if (error_type == "BrownOut") { - errorHandler.error_BrownOut(raise); - } else if (error_type == "EnergyManagement") { - errorHandler.error_EnergyManagement(raise); - } else if (error_type == "PermanentFault") { - errorHandler.error_PermanentFault(raise); - } else if (error_type == "MREC2GroundFailure") { - errorHandler.error_MREC2GroundFailure(raise); - } else if (error_type == "MREC3HighTemperature") { - errorHandler.error_MREC3HighTemperature(raise); - } else if (error_type == "MREC4OverCurrentFailure") { - errorHandler.error_MREC4OverCurrentFailure(raise); - } else if (error_type == "MREC5OverVoltage") { - errorHandler.error_MREC5OverVoltage(raise); - } else if (error_type == "MREC6UnderVoltage") { - errorHandler.error_MREC6UnderVoltage(raise); - } else if (error_type == "MREC8EmergencyStop") { - errorHandler.error_MREC8EmergencyStop(raise); - } else if (error_type == "MREC10InvalidVehicleMode") { - errorHandler.error_MREC10InvalidVehicleMode(raise); - } else if (error_type == "MREC14PilotFault") { - errorHandler.error_MREC14PilotFault(raise); - } else if (error_type == "MREC15PowerLoss") { - errorHandler.error_MREC15PowerLoss(raise); - } else if (error_type == "MREC17EVSEContactorFault") { - errorHandler.error_MREC17EVSEContactorFault(raise); - } else if (error_type == "MREC18CableOverTempDerate") { - errorHandler.error_MREC18CableOverTempDerate(raise); - } else if (error_type == "MREC19CableOverTempStop") { - errorHandler.error_MREC19CableOverTempStop(raise); - } else if (error_type == "MREC20PartialInsertion") { - errorHandler.error_MREC20PartialInsertion(raise); - } else if (error_type == "MREC23ProximityFault") { - errorHandler.error_MREC23ProximityFault(raise); - } else if (error_type == "MREC24ConnectorVoltageHigh") { - errorHandler.error_MREC24ConnectorVoltageHigh(raise); - } else if (error_type == "MREC25BrokenLatch") { - errorHandler.error_MREC25BrokenLatch(raise); - } else if (error_type == "MREC26CutCable") { - errorHandler.error_MREC26CutCable(raise); - } else if (error_type == "ac_rcd_MREC2GroundFailure") { - errorHandler.error_ac_rcd_MREC2GroundFailure(raise); - } else if (error_type == "ac_rcd_VendorError") { - errorHandler.error_ac_rcd_VendorError(raise); - } else if (error_type == "ac_rcd_Selftest") { - errorHandler.error_ac_rcd_Selftest(raise); - } else if (error_type == "ac_rcd_AC") { - errorHandler.error_ac_rcd_AC(raise); - } else if (error_type == "ac_rcd_DC") { - errorHandler.error_ac_rcd_DC(raise); - } else if (error_type == "lock_ConnectorLockCapNotCharged") { - errorHandler.error_lock_ConnectorLockCapNotCharged(raise); - } else if (error_type == "lock_ConnectorLockUnexpectedOpen") { - errorHandler.error_lock_ConnectorLockUnexpectedOpen(raise); - } else if (error_type == "lock_ConnectorLockUnexpectedClose") { - errorHandler.error_lock_ConnectorLockUnexpectedClose(raise); - } else if (error_type == "lock_ConnectorLockFailedLock") { - errorHandler.error_lock_ConnectorLockFailedLock(raise); - } else if (error_type == "lock_ConnectorLockFailedUnlock") { - errorHandler.error_lock_ConnectorLockFailedUnlock(raise); - } else if (error_type == "lock_MREC1ConnectorLockFailure") { - errorHandler.error_lock_MREC1ConnectorLockFailure(raise); - } else if (error_type == "lock_VendorError") { - errorHandler.error_lock_VendorError(raise); - } else { - EVLOG_error << "Unknown error raised via MQTT"; + if (error_type == "lock_ConnectorLockUnexpectedClose") { + return {raise, error_definitions::connector_lock_ConnectorLockUnexpectedClose}; + } + if (error_type == "evse_board_support/DiodeFault") { + return {raise, error_definitions::evse_board_support_DiodeFault}; + } + if (error_type == "evse_board_support/BrownOut") { + return {raise, error_definitions::evse_board_support_BrownOut}; + } + if (error_type == "evse_board_support/EnergyManagement") { + return {raise, error_definitions::evse_board_support_EnergyManagement}; + } + if (error_type == "evse_board_support/PermanentFault") { + return {raise, error_definitions::evse_board_support_PermanentFault}; + } + if (error_type == "evse_board_support/MREC2GroundFailure") { + return {raise, error_definitions::evse_board_support_MREC2GroundFailure}; + } + if (error_type == "evse_board_support/MREC3HighTemperature") { + return {raise, error_definitions::evse_board_support_MREC3HighTemperature}; + } + if (error_type == "evse_board_support/MREC4OverCurrentFailure") { + return {raise, error_definitions::evse_board_support_MREC4OverCurrentFailure}; + } + if (error_type == "evse_board_support/MREC5OverVoltage") { + return {raise, error_definitions::evse_board_support_MREC5OverVoltage}; + } + if (error_type == "evse_board_support/MREC6UnderVoltage") { + return {raise, error_definitions::evse_board_support_MREC6UnderVoltage}; + } + if (error_type == "evse_board_support/MREC8EmergencyStop") { + return {raise, error_definitions::evse_board_support_MREC8EmergencyStop}; + } + if (error_type == "evse_board_support/MREC10InvalidVehicleMode") { + return {raise, error_definitions::evse_board_support_MREC10InvalidVehicleMode}; + } + if (error_type == "evse_board_support/MREC14PilotFault") { + return {raise, error_definitions::evse_board_support_MREC14PilotFault}; + } + if (error_type == "evse_board_support/MREC15PowerLoss") { + return {raise, error_definitions::evse_board_support_MREC15PowerLoss}; + } + if (error_type == "evse_board_support/MREC17EVSEContactorFault") { + return {raise, error_definitions::evse_board_support_MREC17EVSEContactorFault}; + } + if (error_type == "evse_board_support/MREC18CableOverTempDerate") { + return {raise, error_definitions::evse_board_support_MREC18CableOverTempDerate}; + } + if (error_type == "evse_board_support/MREC19CableOverTempStop") { + return {raise, error_definitions::evse_board_support_MREC19CableOverTempStop}; } + if (error_type == "evse_board_support/MREC20PartialInsertion") { + return {raise, error_definitions::evse_board_support_MREC20PartialInsertion}; + } + if (error_type == "evse_board_support/MREC23ProximityFault") { + return {raise, error_definitions::evse_board_support_MREC23ProximityFault}; + } + if (error_type == "evse_board_support/MREC24ConnectorVoltageHigh") { + return {raise, error_definitions::evse_board_support_MREC24ConnectorVoltageHigh}; + } + if (error_type == "evse_board_support/MREC25BrokenLatch") { + return {raise, error_definitions::evse_board_support_MREC25BrokenLatch}; + } + if (error_type == "evse_board_support/MREC26CutCable") { + return {raise, error_definitions::evse_board_support_MREC26CutCable}; + } + if (error_type == "ac_rcd/VendorError") { + return {raise, error_definitions::ac_rcd_VendorError}; + } + if (error_type == "ac_rcd/Selftest") { + return {raise, error_definitions::ac_rcd_Selftest}; + } + if (error_type == "ac_rcd/DC") { + return {raise, error_definitions::ac_rcd_DC}; + } + if (error_type == "connector_lock/ConnectorLockCapNotCharged") { + return {raise, error_definitions::connector_lock_ConnectorLockCapNotCharged}; + } + if (error_type == "connector_lock/ConnectorLockUnexpectedOpen") { + return {raise, error_definitions::connector_lock_ConnectorLockUnexpectedOpen}; + } + if (error_type == "connector_lock/ConnectorLockFailedLock") { + return {raise, error_definitions::connector_lock_ConnectorLockFailedLock}; + } + if (error_type == "connector_lock/ConnectorLockFailedUnlock") { + return {raise, error_definitions::connector_lock_ConnectorLockFailedUnlock}; + } + if (error_type == "connector_lock/MREC1ConnectorLockFailure") { + return {raise, error_definitions::connector_lock_MREC1ConnectorLockFailure}; + } + if (error_type == "connector_lock/VendorError") { + return {raise, error_definitions::connector_lock_VendorError}; + } + EVLOG_error << "Unknown error raised via MQTT"; + throw std::runtime_error("Invalid error type"); +} + +void MqttHandler::handle_mqtt_payload(const std::string& payload) const { + const auto [raise, error_definition] = parse_error_type(payload); + const auto error = create_error(*error_factory, error_definition); + + // TODO + // if (error_definition.error_destination == ErrorDefinition::ErrorDestination::board_support) { + // forward_error(handle, error_definition, raise); + // } else if (error_definition.error_destination == ErrorDefinition::ErrorDestination::connector_lock) { + // forward_error(handle, error_definition, raise); + // } else if (error_definition.error_destination == ErrorDefinition::ErrorDestination::rcd) { + // forward_error(handle, error_definition, raise); + // } else { + // EVLOG_error << "Unknown error destination"; + // } } } // namespace module \ No newline at end of file diff --git a/modules/YetiSimulator/util/mqtt_handler.hpp b/modules/YetiSimulator/util/mqtt_handler.hpp index 2d9b5d107..f9a4c6553 100644 --- a/modules/YetiSimulator/util/mqtt_handler.hpp +++ b/modules/YetiSimulator/util/mqtt_handler.hpp @@ -8,18 +8,19 @@ #include "generated/interfaces/connector_lock/Implementation.hpp" #include "generated/interfaces/evse_board_support/Implementation.hpp" #include + namespace module { class MqttHandler { public: MqttHandler(evse_board_supportImplBase* p_board_support, ac_rcdImplBase* p_rcd, connector_lockImplBase* p_connector_lock); - ; - void handle_mqtt_payload(const std::string& payload); + void handle_mqtt_payload(const std::string& payload) const; private: ErrorHandler errorHandler; + Everest::error::ErrorFactory* error_factory; }; } // namespace module diff --git a/modules/YetiSimulator/util/state.cpp b/modules/YetiSimulator/util/state.cpp index c79c3fb3c..e8a775bbe 100644 --- a/modules/YetiSimulator/util/state.cpp +++ b/modules/YetiSimulator/util/state.cpp @@ -3,6 +3,7 @@ #include "state.hpp" #include +#include #include #include @@ -11,17 +12,23 @@ using std::chrono::milliseconds; using std::chrono::system_clock; using std::chrono::time_point_cast; -PowermeterData::PowermeterData() : - time_stamp{time_point_cast(system_clock::now()).time_since_epoch().count() / 1000} { +TimeStamp::TimeStamp() : + time_stamp{time_point_cast(system_clock::now()).time_since_epoch().count() / milliseconds_in_second} { } -ModuleState::ModuleState() : - time_stamp{time_point_cast(system_clock::now()).time_since_epoch().count() / 1000} { + +TimeStamp& TimeStamp::operator=(const double value) { + time_stamp = static_cast(value); + return *this; +} + +TimeStamp::operator int64_t() const { + return time_stamp; } -std::string state_to_string(state::ModuleState& module_state) { +std::string state_to_string(const ModuleState& module_state) { using state::State; - const auto pwm = (module_state.pwm_running ? '2' : '1'); + const auto pwm = module_state.pwm_running ? '2' : '1'; switch (module_state.current_state) { case State::STATE_DISABLED: @@ -44,7 +51,7 @@ std::string state_to_string(state::ModuleState& module_state) { } void to_json(nlohmann::json& json, const PowermeterData& powermeter_data) { - json = nlohmann::json{{"time_stamp", powermeter_data.time_stamp}, + json = nlohmann::json{{"time_stamp", static_cast(powermeter_data.time_stamp)}, {"totalWattHr", powermeter_data.totalWattHr}, {"wattL1", powermeter_data.wattL1}, {"vrmsL1", powermeter_data.vrmsL1}, @@ -70,4 +77,4 @@ void to_json(nlohmann::json& json, const PowermeterData& powermeter_data) { {"irmsN", powermeter_data.irmsN}}; } -} // namespace module::state \ No newline at end of file +} // namespace module::state diff --git a/modules/YetiSimulator/util/state.hpp b/modules/YetiSimulator/util/state.hpp index 41eb8373c..3d7eb1911 100644 --- a/modules/YetiSimulator/util/state.hpp +++ b/modules/YetiSimulator/util/state.hpp @@ -8,10 +8,16 @@ namespace module::state { -struct PowermeterData { - PowermeterData(); - int64_t time_stamp; +struct TimeStamp { + TimeStamp(); + TimeStamp& operator=(const double value); + + operator int64_t() const; + int64_t time_stamp; +}; +struct PowermeterData { + TimeStamp time_stamp; double totalWattHr = 0.0; double wattL1 = 0.0; @@ -186,8 +192,6 @@ enum class State { }; struct ModuleState { - ModuleState(); - PowermeterData powermeter_data; SimulationData simulation_data; SimdataSetting simdata_setting; @@ -200,7 +204,7 @@ struct ModuleState { bool relais_on = false; State current_state = State::STATE_DISABLED; State last_state = State::STATE_DISABLED; - int64_t time_stamp; + TimeStamp time_stamp; bool use_three_phases = true; bool simplified_mode = false; @@ -229,10 +233,12 @@ struct ModuleState { int ev_three_phases = 3; }; -std::string state_to_string(state::ModuleState& module_state); +std::string state_to_string(const state::ModuleState& module_state); void to_json(nlohmann::json& json, const PowermeterData& powermeter_data); +constexpr inline auto milliseconds_in_second = 1000; + } // namespace module::state // NOLINTEND