// SPDX-License-Identifier: Apache-2.0 // Copyright (C) 2022-2023 chargebyte GmbH // Copyright (C) 2022-2023 Contributors to EVerest #include "ISO15118_chargerImpl.hpp" #include "log.hpp" #include "v2g_ctx.hpp" #include const std::string CERTS_SUB_DIR = "certs"; // relativ path of the certs using namespace std::chrono_literals; using BidiMode = types::iso15118::SaeJ2847BidiMode; namespace module { namespace charger { void ISO15118_chargerImpl::init() { if (!v2g_ctx) { dlog(DLOG_LEVEL_ERROR, "v2g_ctx not created"); return; } /* Configure if_name and auth_mode */ v2g_ctx->if_name = mod->config.device.data(); dlog(DLOG_LEVEL_DEBUG, "if_name %s", v2g_ctx->if_name); v2g_ctx->proxy_if_name = mod->config.proxy_device.empty() ? nullptr : mod->config.proxy_device.data(); /* Configure tls_security */ if (mod->config.tls_security == "force") { v2g_ctx->tls_security = TLS_SECURITY_FORCE; dlog(DLOG_LEVEL_DEBUG, "tls_security force"); } else if (mod->config.tls_security == "allow") { v2g_ctx->tls_security = TLS_SECURITY_ALLOW; dlog(DLOG_LEVEL_DEBUG, "tls_security allow"); } else { v2g_ctx->tls_security = TLS_SECURITY_PROHIBIT; dlog(DLOG_LEVEL_DEBUG, "tls_security prohibit"); } v2g_ctx->network_read_timeout_tls = mod->config.tls_timeout; v2g_ctx->certs_path = mod->info.paths.etc / CERTS_SUB_DIR; // Subscribe all vars mod->r_iso2->subscribe_supported_app_protocols_secc([this](const auto value) { if (auto merged = merge_supported_app_protocols(value, ProtocolSource::Iso2)) { publish_supported_app_protocols_secc(*merged); } }); mod->r_iso2->subscribe_require_auth_eim([this]() { if (not mod->selected_iso20()) { publish_require_auth_eim(nullptr); } }); mod->r_iso20->subscribe_require_auth_eim([this]() { if (mod->selected_iso20()) { publish_require_auth_eim(nullptr); } }); mod->r_iso2->subscribe_require_auth_pnc([this](const auto value) { if (not mod->selected_iso20()) { publish_require_auth_pnc(value); } }); mod->r_iso20->subscribe_require_auth_pnc([this](const auto value) { if (mod->selected_iso20()) { publish_require_auth_pnc(value); } }); mod->r_iso2->subscribe_ac_close_contactor([this]() { if (not mod->selected_iso20()) { publish_ac_close_contactor(nullptr); } }); mod->r_iso20->subscribe_ac_close_contactor([this]() { if (mod->selected_iso20()) { publish_ac_close_contactor(nullptr); } }); mod->r_iso2->subscribe_ac_open_contactor([this]() { if (not mod->selected_iso20()) { publish_ac_open_contactor(nullptr); } }); mod->r_iso20->subscribe_supported_app_protocols_secc([this](const auto value) { if (auto merged = merge_supported_app_protocols(value, ProtocolSource::Iso20)) { publish_supported_app_protocols_secc(*merged); } }); mod->r_iso20->subscribe_ac_open_contactor([this]() { if (mod->selected_iso20()) { publish_ac_open_contactor(nullptr); } }); mod->r_iso2->subscribe_start_cable_check([this]() { if (not mod->selected_iso20()) { publish_start_cable_check(nullptr); } }); mod->r_iso20->subscribe_start_cable_check([this]() { if (mod->selected_iso20()) { publish_start_cable_check(nullptr); } }); mod->r_iso2->subscribe_start_pre_charge([this]() { if (not mod->selected_iso20()) { publish_start_pre_charge(nullptr); } }); mod->r_iso20->subscribe_start_pre_charge([this]() { if (mod->selected_iso20()) { publish_start_pre_charge(nullptr); } }); mod->r_iso2->subscribe_dc_open_contactor([this]() { if (not mod->selected_iso20()) { publish_dc_open_contactor(nullptr); } }); mod->r_iso20->subscribe_dc_open_contactor([this]() { if (mod->selected_iso20()) { publish_dc_open_contactor(nullptr); } }); mod->r_iso2->subscribe_v2g_setup_finished([this]() { if (not mod->selected_iso20()) { publish_v2g_setup_finished(nullptr); } }); mod->r_iso20->subscribe_v2g_setup_finished([this]() { if (mod->selected_iso20()) { publish_v2g_setup_finished(nullptr); } }); mod->r_iso2->subscribe_current_demand_started([this]() { if (not mod->selected_iso20()) { publish_current_demand_started(nullptr); } }); mod->r_iso20->subscribe_current_demand_started([this]() { if (mod->selected_iso20()) { publish_current_demand_started(nullptr); } }); mod->r_iso2->subscribe_current_demand_finished([this]() { if (not mod->selected_iso20()) { publish_current_demand_finished(nullptr); } }); mod->r_iso20->subscribe_current_demand_finished([this]() { if (mod->selected_iso20()) { publish_current_demand_finished(nullptr); } }); mod->r_iso2->subscribe_sae_bidi_mode_active([this]() { if (not mod->selected_iso20()) { publish_sae_bidi_mode_active(nullptr); } }); mod->r_iso20->subscribe_sae_bidi_mode_active([this]() { if (mod->selected_iso20()) { publish_sae_bidi_mode_active(nullptr); } }); mod->r_iso2->subscribe_evcc_id([this](const auto id) { if (not mod->selected_iso20()) { publish_evcc_id(id); } }); mod->r_iso20->subscribe_evcc_id([this](const auto id) { if (mod->selected_iso20()) { publish_evcc_id(id); } }); mod->r_iso2->subscribe_selected_payment_option([this](const auto o) { if (not mod->selected_iso20()) { publish_selected_payment_option(o); } }); mod->r_iso20->subscribe_selected_payment_option([this](const auto o) { if (mod->selected_iso20()) { publish_selected_payment_option(o); } }); mod->r_iso2->subscribe_requested_energy_transfer_mode([this](const auto o) { if (not mod->selected_iso20()) { publish_requested_energy_transfer_mode(o); } }); mod->r_iso20->subscribe_requested_energy_transfer_mode([this](const auto o) { if (mod->selected_iso20()) { publish_requested_energy_transfer_mode(o); } }); mod->r_iso2->subscribe_departure_time([this](const auto o) { if (not mod->selected_iso20()) { publish_departure_time(o); } }); mod->r_iso20->subscribe_departure_time([this](const auto o) { if (mod->selected_iso20()) { publish_departure_time(o); } }); mod->r_iso2->subscribe_ac_eamount([this](const auto o) { if (not mod->selected_iso20()) { publish_ac_eamount(o); } }); mod->r_iso20->subscribe_ac_eamount([this](const auto o) { if (mod->selected_iso20()) { publish_ac_eamount(o); } }); mod->r_iso2->subscribe_ac_ev_max_voltage([this](const auto o) { if (not mod->selected_iso20()) { publish_ac_ev_max_voltage(o); } }); mod->r_iso20->subscribe_ac_ev_max_voltage([this](const auto o) { if (mod->selected_iso20()) { publish_ac_ev_max_voltage(o); } }); mod->r_iso2->subscribe_ac_ev_max_current([this](const auto o) { if (not mod->selected_iso20()) { publish_ac_ev_max_current(o); } }); mod->r_iso20->subscribe_ac_ev_max_current([this](const auto o) { if (mod->selected_iso20()) { publish_ac_ev_max_current(o); } }); mod->r_iso2->subscribe_ac_ev_min_current([this](const auto o) { if (not mod->selected_iso20()) { publish_ac_ev_min_current(o); } }); mod->r_iso20->subscribe_ac_ev_min_current([this](const auto o) { if (mod->selected_iso20()) { publish_ac_ev_min_current(o); } }); mod->r_iso20->subscribe_ac_ev_power_limits([this](const auto o) { if (mod->selected_iso20()) { publish_ac_ev_power_limits(o); } }); mod->r_iso20->subscribe_ac_ev_present_powers([this](const auto o) { if (mod->selected_iso20()) { publish_ac_ev_present_powers(o); } }); mod->r_iso20->subscribe_ac_ev_dynamic_control_mode([this](const auto o) { if (mod->selected_iso20()) { publish_ac_ev_dynamic_control_mode(o); } }); mod->r_iso2->subscribe_dc_ev_energy_capacity([this](const auto o) { if (not mod->selected_iso20()) { publish_dc_ev_energy_capacity(o); } }); mod->r_iso20->subscribe_dc_ev_energy_capacity([this](const auto o) { if (mod->selected_iso20()) { publish_dc_ev_energy_capacity(o); } }); mod->r_iso2->subscribe_dc_ev_energy_request([this](const auto o) { if (not mod->selected_iso20()) { publish_dc_ev_energy_request(o); } }); mod->r_iso20->subscribe_dc_ev_energy_request([this](const auto o) { if (mod->selected_iso20()) { publish_dc_ev_energy_request(o); } }); mod->r_iso2->subscribe_dc_full_soc([this](const auto o) { if (not mod->selected_iso20()) { publish_dc_full_soc(o); } }); mod->r_iso20->subscribe_dc_full_soc([this](const auto o) { if (mod->selected_iso20()) { publish_dc_full_soc(o); } }); mod->r_iso2->subscribe_dc_bulk_soc([this](const auto o) { if (not mod->selected_iso20()) { publish_dc_bulk_soc(o); } }); mod->r_iso20->subscribe_dc_bulk_soc([this](const auto o) { if (mod->selected_iso20()) { publish_dc_bulk_soc(o); } }); mod->r_iso2->subscribe_dc_ev_status([this](const auto o) { if (not mod->selected_iso20()) { publish_dc_ev_status(o); } }); mod->r_iso20->subscribe_dc_ev_status([this](const auto o) { if (mod->selected_iso20()) { publish_dc_ev_status(o); } }); mod->r_iso2->subscribe_dc_bulk_charging_complete([this](const auto o) { if (not mod->selected_iso20()) { publish_dc_bulk_charging_complete(o); } }); mod->r_iso20->subscribe_dc_bulk_charging_complete([this](const auto o) { if (mod->selected_iso20()) { publish_dc_bulk_charging_complete(o); } }); mod->r_iso2->subscribe_dc_charging_complete([this](const auto o) { if (not mod->selected_iso20()) { publish_dc_charging_complete(o); } }); mod->r_iso20->subscribe_dc_charging_complete([this](const auto o) { if (mod->selected_iso20()) { publish_dc_charging_complete(o); } }); mod->r_iso2->subscribe_dc_ev_target_voltage_current([this](const auto o) { if (not mod->selected_iso20()) { publish_dc_ev_target_voltage_current(o); } }); mod->r_iso20->subscribe_dc_ev_target_voltage_current([this](const auto o) { if (mod->selected_iso20()) { publish_dc_ev_target_voltage_current(o); } }); mod->r_iso2->subscribe_dc_ev_maximum_limits([this](const auto o) { if (not mod->selected_iso20()) { publish_dc_ev_maximum_limits(o); } }); mod->r_iso20->subscribe_dc_ev_maximum_limits([this](const auto o) { if (mod->selected_iso20()) { publish_dc_ev_maximum_limits(o); } }); mod->r_iso2->subscribe_dc_ev_remaining_time([this](const auto o) { if (not mod->selected_iso20()) { publish_dc_ev_remaining_time(o); } }); mod->r_iso20->subscribe_dc_ev_remaining_time([this](const auto o) { if (mod->selected_iso20()) { publish_dc_ev_remaining_time(o); } }); mod->r_iso2->subscribe_hlc_session_failed([this](const auto reason) { if (not mod->selected_iso20()) { publish_hlc_session_failed(reason); } }); mod->r_iso20->subscribe_hlc_session_failed([this](const auto reason) { if (mod->selected_iso20()) { publish_hlc_session_failed(reason); } }); mod->r_iso2->subscribe_dlink_terminate([this]() { if (not mod->selected_iso20()) { publish_dlink_terminate(nullptr); } }); mod->r_iso20->subscribe_dlink_terminate([this]() { if (mod->selected_iso20()) { publish_dlink_terminate(nullptr); } }); mod->r_iso2->subscribe_dlink_error([this]() { if (not mod->selected_iso20()) { publish_dlink_error(nullptr); } }); mod->r_iso20->subscribe_dlink_error([this]() { if (mod->selected_iso20()) { publish_dlink_error(nullptr); } }); mod->r_iso2->subscribe_dlink_pause([this]() { if (not mod->selected_iso20()) { publish_dlink_pause(nullptr); } }); mod->r_iso20->subscribe_dlink_pause([this]() { if (mod->selected_iso20()) { publish_dlink_pause(nullptr); } }); mod->r_iso2->subscribe_ev_app_protocol([this](const auto o) { if (not mod->selected_iso20()) { publish_ev_app_protocol(o); } }); mod->r_iso20->subscribe_ev_app_protocol([this](const auto o) { if (mod->selected_iso20()) { publish_ev_app_protocol(o); } }); mod->r_iso2->subscribe_v2g_messages([this](const auto o) { if (not mod->selected_iso20()) { publish_v2g_messages(o); } }); mod->r_iso20->subscribe_v2g_messages([this](const auto o) { if (mod->selected_iso20()) { publish_v2g_messages(o); } }); mod->r_iso2->subscribe_selected_protocol([this](const auto o) { if (not mod->selected_iso20()) { publish_selected_protocol(o); } }); mod->r_iso20->subscribe_selected_protocol([this](const auto o) { if (mod->selected_iso20()) { publish_selected_protocol(o); } }); mod->r_iso2->subscribe_selected_service_parameters([this](const auto& param) { if (not mod->selected_iso20()) { publish_selected_service_parameters(param); } }); mod->r_iso20->subscribe_selected_service_parameters([this](const auto& param) { if (mod->selected_iso20()) { publish_selected_service_parameters(param); } }); mod->r_iso2->subscribe_display_parameters([this](const auto o) { if (not mod->selected_iso20()) { publish_display_parameters(o); } }); mod->r_iso20->subscribe_display_parameters([this](const auto o) { if (mod->selected_iso20()) { publish_display_parameters(o); } }); mod->r_iso20->subscribe_d20_dc_dynamic_charge_mode([this](const auto o) { if (mod->selected_iso20()) { publish_d20_dc_dynamic_charge_mode(o); } }); mod->r_iso2->subscribe_dc_ev_present_voltage([this](const auto o) { if (not mod->selected_iso20()) { publish_dc_ev_present_voltage(o); } }); mod->r_iso20->subscribe_dc_ev_present_voltage([this](const auto o) { if (mod->selected_iso20()) { publish_dc_ev_present_voltage(o); } }); mod->r_iso2->subscribe_meter_info_requested([this]() { if (not mod->selected_iso20()) { publish_meter_info_requested(nullptr); } }); mod->r_iso20->subscribe_meter_info_requested([this]() { if (mod->selected_iso20()) { publish_meter_info_requested(nullptr); } }); } void ISO15118_chargerImpl::ready() { } std::optional ISO15118_chargerImpl::merge_supported_app_protocols(const types::iso15118::SupportedAppProtocols& value, ProtocolSource source) { std::lock_guard lock(supported_app_protocols_mutex); bool changed = false; for (const auto protocol : value.app_protocols) { if (std::find(supported_app_protocols.app_protocols.begin(), supported_app_protocols.app_protocols.end(), protocol) == supported_app_protocols.app_protocols.end()) { supported_app_protocols.app_protocols.push_back(protocol); changed = true; } protocol_sources[protocol] = source; } return changed ? std::make_optional(supported_app_protocols) : std::nullopt; } void ISO15118_chargerImpl::handle_setup(types::iso15118::EVSEID& evse_id, types::iso15118::SaeJ2847BidiMode& sae_j2847_mode, bool& debug_mode) { mod->r_iso20->call_setup(evse_id, sae_j2847_mode, debug_mode); mod->r_iso2->call_setup(evse_id, sae_j2847_mode, debug_mode); } void ISO15118_chargerImpl::handle_set_charging_parameters(types::iso15118::SetupPhysicalValues& physical_values) { mod->r_iso20->call_set_charging_parameters(physical_values); mod->r_iso2->call_set_charging_parameters(physical_values); } void ISO15118_chargerImpl::handle_session_setup(std::vector& payment_options, bool& supported_certificate_service, bool& central_contract_validation_allowed) { mod->r_iso20->call_session_setup(payment_options, supported_certificate_service, central_contract_validation_allowed); mod->r_iso2->call_session_setup(payment_options, supported_certificate_service, central_contract_validation_allowed); } void ISO15118_chargerImpl::handle_bpt_setup(types::iso15118::BptSetup& bpt_config) { if (mod->selected_iso20()) { mod->r_iso20->call_bpt_setup(bpt_config); } } void ISO15118_chargerImpl::handle_set_powersupply_capabilities(types::power_supply_DC::Capabilities& capabilities) { mod->r_iso20->call_set_powersupply_capabilities(capabilities); mod->r_iso2->call_set_powersupply_capabilities(capabilities); } void ISO15118_chargerImpl::handle_authorization_response( types::authorization::AuthorizationStatus& authorization_status, types::authorization::CertificateStatus& certificate_status) { if (mod->selected_iso20()) { mod->r_iso20->call_authorization_response(authorization_status, certificate_status); } else { mod->r_iso2->call_authorization_response(authorization_status, certificate_status); } } void ISO15118_chargerImpl::handle_ac_contactor_closed(bool& status) { if (mod->selected_iso20()) { mod->r_iso20->call_ac_contactor_closed(status); } else { mod->r_iso2->call_ac_contactor_closed(status); } } void ISO15118_chargerImpl::handle_dlink_ready(bool& value) { if (mod->selected_iso20()) { mod->r_iso20->call_dlink_ready(value); } else { mod->r_iso2->call_dlink_ready(value); } } void ISO15118_chargerImpl::handle_cable_check_finished(bool& status) { if (mod->selected_iso20()) { mod->r_iso20->call_cable_check_finished(status); } else { mod->r_iso2->call_cable_check_finished(status); } } void ISO15118_chargerImpl::handle_receipt_is_required(bool& receipt_required) { mod->r_iso20->call_receipt_is_required(receipt_required); mod->r_iso2->call_receipt_is_required(receipt_required); } void ISO15118_chargerImpl::handle_stop_charging(bool& stop) { if (mod->selected_iso20()) { mod->r_iso20->call_stop_charging(stop); } else { mod->r_iso2->call_stop_charging(stop); } } void ISO15118_chargerImpl::handle_pause_charging(bool& pause) { if (mod->selected_iso20()) { mod->r_iso20->call_pause_charging(pause); } else { mod->r_iso2->call_pause_charging(pause); } } void ISO15118_chargerImpl::handle_no_energy_pause_charging(types::iso15118::NoEnergyPauseMode& mode) { if (mod->selected_iso20()) { mod->r_iso20->call_no_energy_pause_charging(mode); } else { mod->r_iso2->call_no_energy_pause_charging(mode); } } bool ISO15118_chargerImpl::handle_update_supported_app_protocols( types::iso15118::SupportedAppProtocols& updated_supported_app_protocols) { bool iso20_configured = false; if (updated_supported_app_protocols.app_protocols.empty()) { v2g_ctx->iso20_proxy_enabled = false; EVLOG_info << "No protocols configured, disabling ISO-20 proxy routing"; // Forward empty updates to both implementations // TODO(FH): Currently only forwarded to the ISO-2 module, because ISO-20 module is not able to // disable supported protocols. Currently, this implementation gap has been resolved by deactivating // the ISO-20 proxy if the ISO-20 protocol has not been enabled. In that case, the ISO-2 // proxy takes over the responsibility for responding to the SupportedAppReq. const bool ok_iso2 = mod->r_iso2->call_update_supported_app_protocols(updated_supported_app_protocols); mod->r_iso20->call_update_supported_app_protocols(updated_supported_app_protocols); return ok_iso2; } types::iso15118::SupportedAppProtocols iso2_payload; types::iso15118::SupportedAppProtocols iso20_payload; { /* Iterate though the list of supported_app_protocols and check whether the received protocol is intended for the r_iso2 or the r_iso20 instance */ std::lock_guard lock(supported_app_protocols_mutex); for (const auto protocol : updated_supported_app_protocols.app_protocols) { const auto source_it = protocol_sources.find(protocol); const bool known_protocol = std::find(this->supported_app_protocols.app_protocols.begin(), this->supported_app_protocols.app_protocols.end(), protocol) != this->supported_app_protocols.app_protocols.end(); if (source_it == protocol_sources.end() || !known_protocol) { EVLOG_warning << "Received update for unsupported app protocol: " << types::iso15118::supported_app_protocol_to_string(protocol); return false; } if (source_it->second == ProtocolSource::Iso20) { iso20_configured = true; iso20_payload.app_protocols.push_back(protocol); } else { iso2_payload.app_protocols.push_back(protocol); } } } /* update supported protocols */ bool ok = true; if (!iso2_payload.app_protocols.empty()) { ok = mod->r_iso2->call_update_supported_app_protocols(iso2_payload) && ok; } if (!iso20_payload.app_protocols.empty()) { ok = mod->r_iso20->call_update_supported_app_protocols(iso20_payload) && ok; } /* route to ISO-20 proxy only when ISO15118-20 is explicitly configured. */ v2g_ctx->iso20_proxy_enabled = iso20_configured; if (!iso20_configured) { EVLOG_debug << "Disabling ISO-20 proxy routing since no ISO15118-20 protocol is configured"; } return ok; } void ISO15118_chargerImpl::handle_update_energy_transfer_modes( std::vector& supported_energy_transfer_modes) { mod->r_iso20->call_update_energy_transfer_modes(supported_energy_transfer_modes); mod->r_iso2->call_update_energy_transfer_modes(supported_energy_transfer_modes); } void ISO15118_chargerImpl::handle_update_ac_max_current(double& max_current) { mod->r_iso20->call_update_ac_max_current(max_current); mod->r_iso2->call_update_ac_max_current(max_current); } void ISO15118_chargerImpl::handle_update_ac_parameters(types::iso15118::AcParameters& ac_parameters) { if (mod->selected_iso20()) { mod->r_iso20->call_update_ac_parameters(ac_parameters); } } void ISO15118_chargerImpl::handle_update_ac_maximum_limits(types::iso15118::AcEvseMaximumPower& maximum_limits) { if (mod->selected_iso20()) { mod->r_iso20->call_update_ac_maximum_limits(maximum_limits); } } void ISO15118_chargerImpl::handle_update_ac_minimum_limits(types::iso15118::AcEvseMinimumPower& minimum_limits) { if (mod->selected_iso20()) { mod->r_iso20->call_update_ac_minimum_limits(minimum_limits); } } void ISO15118_chargerImpl::handle_update_ac_target_values(types::iso15118::AcTargetValues& target_values) { if (mod->selected_iso20()) { mod->r_iso20->call_update_ac_target_values(target_values); } } void ISO15118_chargerImpl::handle_update_ac_present_power(types::units::Power& present_power) { if (mod->selected_iso20()) { mod->r_iso20->call_update_ac_present_power(present_power); } } void ISO15118_chargerImpl::handle_update_dc_maximum_limits(types::iso15118::DcEvseMaximumLimits& maximum_limits) { mod->r_iso20->call_update_dc_maximum_limits(maximum_limits); mod->r_iso2->call_update_dc_maximum_limits(maximum_limits); } void ISO15118_chargerImpl::handle_update_dc_minimum_limits(types::iso15118::DcEvseMinimumLimits& minimum_limits) { mod->r_iso20->call_update_dc_minimum_limits(minimum_limits); mod->r_iso2->call_update_dc_minimum_limits(minimum_limits); } void ISO15118_chargerImpl::handle_update_isolation_status(types::iso15118::IsolationStatus& isolation_status) { if (mod->selected_iso20()) { mod->r_iso20->call_update_isolation_status(isolation_status); } else { mod->r_iso2->call_update_isolation_status(isolation_status); } } void ISO15118_chargerImpl::handle_update_dc_present_values( types::iso15118::DcEvsePresentVoltageCurrent& present_voltage_current) { mod->r_iso20->call_update_dc_present_values(present_voltage_current); mod->r_iso2->call_update_dc_present_values(present_voltage_current); } void ISO15118_chargerImpl::handle_update_meter_info(types::powermeter::Powermeter& powermeter) { mod->r_iso20->call_update_meter_info(powermeter); mod->r_iso2->call_update_meter_info(powermeter); } void ISO15118_chargerImpl::handle_send_error(types::iso15118::EvseError& error) { if (mod->selected_iso20()) { mod->r_iso20->call_send_error(error); } else { mod->r_iso2->call_send_error(error); } } void ISO15118_chargerImpl::handle_reset_error() { if (mod->selected_iso20()) { mod->r_iso20->call_reset_error(); } else { mod->r_iso2->call_reset_error(); } } } // namespace charger } // namespace module