Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter

- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
This commit is contained in:
Eric F
2026-06-08 00:38:27 -04:00
parent 468cfeaa50
commit d398a6ced2
7326 changed files with 1177561 additions and 7 deletions

View File

@@ -0,0 +1,31 @@
#
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
# template version 3
#
# module setup:
# - ${MODULE_NAME}: module name
ev_setup_cpp_module()
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
target_sources(${MODULE_NAME}
PRIVATE
charger/session_logger.cpp
charger/utils.cpp
)
target_link_libraries(${MODULE_NAME}
PRIVATE
iso15118::iso15118
)
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
target_sources(${MODULE_NAME}
PRIVATE
"charger/ISO15118_chargerImpl.cpp"
"extensions/iso15118_extensionsImpl.cpp"
)
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
# insert other things like install cmds etc here
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1

View File

@@ -0,0 +1,17 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "Evse15118D20.hpp"
namespace module {
void Evse15118D20::init() {
invoke_init(*p_charger);
invoke_init(*p_extensions);
}
void Evse15118D20::ready() {
invoke_ready(*p_charger);
invoke_ready(*p_extensions);
}
} // namespace module

View File

@@ -0,0 +1,88 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef EVSE15118D20_HPP
#define EVSE15118D20_HPP
//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 2
//
#include "ld-ev.hpp"
// headers for provided interface implementations
#include <generated/interfaces/ISO15118_charger/Implementation.hpp>
#include <generated/interfaces/iso15118_extensions/Implementation.hpp>
// headers for required interface implementations
#include <generated/interfaces/ISO15118_vas/Interface.hpp>
#include <generated/interfaces/evse_security/Interface.hpp>
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
// insert your custom include headers here
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
namespace module {
struct Conf {
std::string device;
std::string logging_path;
std::string tls_negotiation_strategy;
bool enforce_tls_1_3;
bool enable_ssl_logging;
bool enable_tls_key_logging;
std::string tls_key_logging_path;
bool enable_sdp_server;
bool supported_dynamic_mode;
bool supported_mobility_needs_mode_provided_by_secc;
bool supported_scheduled_mode;
std::string custom_protocol_namespace;
bool negative_bidirectional_limits;
};
class Evse15118D20 : public Everest::ModuleBase {
public:
Evse15118D20() = delete;
Evse15118D20(const ModuleInfo& info, std::unique_ptr<ISO15118_chargerImplBase> p_charger,
std::unique_ptr<iso15118_extensionsImplBase> p_extensions,
std::unique_ptr<evse_securityIntf> r_security,
std::vector<std::unique_ptr<ISO15118_vasIntf>> r_iso15118_vas, Conf& config) :
ModuleBase(info),
p_charger(std::move(p_charger)),
p_extensions(std::move(p_extensions)),
r_security(std::move(r_security)),
r_iso15118_vas(std::move(r_iso15118_vas)),
config(config){};
const std::unique_ptr<ISO15118_chargerImplBase> p_charger;
const std::unique_ptr<iso15118_extensionsImplBase> p_extensions;
const std::unique_ptr<evse_securityIntf> r_security;
const std::vector<std::unique_ptr<ISO15118_vasIntf>> r_iso15118_vas;
const Conf& config;
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
// insert your public definitions here
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
protected:
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
// insert your protected definitions here
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
private:
friend class LdEverest;
void init();
void ready();
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
// insert your private definitions here
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
};
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
// insert other definitions here
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
} // namespace module
#endif // EVSE15118D20_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,113 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef CHARGER_ISO15118_CHARGER_IMPL_HPP
#define CHARGER_ISO15118_CHARGER_IMPL_HPP
//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 3
//
#include <generated/interfaces/ISO15118_charger/Implementation.hpp>
#include "../Evse15118D20.hpp"
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
#include <bitset>
#include <mutex>
#include "utils.hpp"
#include <iso15118/d20/config.hpp>
#include <iso15118/session/feedback.hpp>
#include <iso15118/tbd_controller.hpp>
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
namespace module {
namespace charger {
struct Conf {};
class ISO15118_chargerImpl : public ISO15118_chargerImplBase {
public:
ISO15118_chargerImpl() = delete;
ISO15118_chargerImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<Evse15118D20>& mod, Conf& config) :
ISO15118_chargerImplBase(ev, "charger"), mod(mod), config(config){};
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
// insert your public definitions here
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
protected:
// command handler functions (virtual)
virtual void handle_setup(types::iso15118::EVSEID& evse_id, types::iso15118::SaeJ2847BidiMode& sae_j2847_mode,
bool& debug_mode) override;
virtual void handle_set_charging_parameters(types::iso15118::SetupPhysicalValues& physical_values) override;
virtual void handle_session_setup(std::vector<types::iso15118::PaymentOption>& payment_options,
bool& supported_certificate_service,
bool& central_contract_validation_allowed) override;
virtual void handle_bpt_setup(types::iso15118::BptSetup& bpt_config) override;
virtual void handle_set_powersupply_capabilities(types::power_supply_DC::Capabilities& capabilities) override;
virtual void handle_authorization_response(types::authorization::AuthorizationStatus& authorization_status,
types::authorization::CertificateStatus& certificate_status) override;
virtual void handle_ac_contactor_closed(bool& status) override;
virtual void handle_dlink_ready(bool& value) override;
virtual void handle_cable_check_finished(bool& status) override;
virtual void handle_receipt_is_required(bool& receipt_required) override;
virtual void handle_stop_charging(bool& stop) override;
virtual void handle_pause_charging(bool& pause) override;
virtual void handle_no_energy_pause_charging(types::iso15118::NoEnergyPauseMode& mode) override;
virtual bool
handle_update_supported_app_protocols(types::iso15118::SupportedAppProtocols& supported_app_protocols) override;
virtual void handle_update_energy_transfer_modes(
std::vector<types::iso15118::EnergyTransferMode>& supported_energy_transfer_modes) override;
virtual void handle_update_ac_max_current(double& max_current) override;
virtual void handle_update_ac_parameters(types::iso15118::AcParameters& ac_parameters) override;
virtual void handle_update_ac_maximum_limits(types::iso15118::AcEvseMaximumPower& maximum_limits) override;
virtual void handle_update_ac_minimum_limits(types::iso15118::AcEvseMinimumPower& minimum_limits) override;
virtual void handle_update_ac_target_values(types::iso15118::AcTargetValues& target_values) override;
virtual void handle_update_ac_present_power(types::units::Power& present_power) override;
virtual void handle_update_dc_maximum_limits(types::iso15118::DcEvseMaximumLimits& maximum_limits) override;
virtual void handle_update_dc_minimum_limits(types::iso15118::DcEvseMinimumLimits& minimum_limits) override;
virtual void handle_update_isolation_status(types::iso15118::IsolationStatus& isolation_status) override;
virtual void
handle_update_dc_present_values(types::iso15118::DcEvsePresentVoltageCurrent& present_voltage_current) override;
virtual void handle_update_meter_info(types::powermeter::Powermeter& powermeter) override;
virtual void handle_send_error(types::iso15118::EvseError& error) override;
virtual void handle_reset_error() override;
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
// insert your protected definitions here
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
private:
const Everest::PtrContainer<Evse15118D20>& mod;
const Conf& config;
virtual void init() override;
virtual void ready() override;
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
iso15118::session::feedback::Callbacks create_callbacks();
std::unique_ptr<iso15118::TbdController> controller;
iso15118::d20::EvseSetupConfig setup_config;
std::bitset<NUMBER_OF_SETUP_STEPS> setup_steps_done{0};
std::vector<iso15118::d20::SupportedVASs> supported_vas_services_per_provider;
std::mutex vas_mutex;
void update_supported_vas_services();
std::optional<size_t> get_vas_provider_index(uint16_t service_id);
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
};
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
// insert other definitions here
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
} // namespace charger
} // namespace module
#endif // CHARGER_ISO15118_CHARGER_IMPL_HPP

View File

@@ -0,0 +1,141 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "session_logger.hpp"
#include <chrono>
#include <ctime>
#include <fstream>
#include <iomanip>
#include <stdexcept>
#include <date/date.h>
#include <iso15118/session/logger.hpp>
#include <everest/logging.hpp>
using LogEvent = iso15118::session::logging::Event;
std::string get_filename_for_current_time() {
const auto now = std::chrono::system_clock::now();
const auto now_t = std::chrono::system_clock::to_time_t(now);
std::tm now_tm;
gmtime_r(&now_t, &now_tm);
char buffer[64];
strftime(buffer, sizeof(buffer), "%y%m%d_%H-%M-%S.yaml", &now_tm);
return buffer;
}
// static auto timepoint_to_string(const iso15118::session::logging::TimePoint& timepoint) {
// using namespace date;
// return static_cast<std::string>(timepoint);
// }
std::ostream& operator<<(std::ostream& os, const iso15118::session::logging::ExiMessageDirection& direction) {
using Direction = iso15118::session::logging::ExiMessageDirection;
switch (direction) {
case Direction::FROM_EV:
return os << "FROM_EV";
case Direction::TO_EV:
return os << "TO_EV";
}
return os;
}
class SessionLog {
public:
SessionLog(const std::string& file_name) : file(file_name.c_str(), std::ios::out) {
if (not file.good()) {
throw std::runtime_error("Failed to open file " + file_name + " for writing iso15118 session log");
}
EVLOG_info << "Created logfile at: " << file_name;
}
void operator()(const iso15118::session::logging::SimpleEvent& event) {
file << "- type: INFO\n";
add_timestamp(event.time_point);
file << " info: \"" << event.info << "\"\n";
}
void operator()(const iso15118::session::logging::ExiMessageEvent& event) {
file << "- type: EXI\n";
add_timestamp(event.time_point);
file << " direction: " << event.direction << "\n";
file << " sdp_payload_type: " << event.payload_type << "\n";
add_hex_encoded_data(event.data, event.len);
}
void flush() {
file.flush();
}
private:
std::fstream file;
void add_timestamp(const iso15118::session::logging::TimePoint& timestamp) {
if (not timestamp_initialized) {
last_timestamp = timestamp;
timestamp_initialized = true;
}
const auto offset_ms = std::chrono::duration_cast<std::chrono::milliseconds>(timestamp - last_timestamp);
file << " timestamp_offset: " << offset_ms.count() << "\n";
const auto dp = date::floor<date::days>(timestamp);
const auto time = date::make_time(timestamp - dp);
const auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(time.subseconds());
file << " timestamp: \"";
file << std::setfill('0') << std::setw(2) << time.hours().count() << ":";
file << std::setfill('0') << std::setw(2) << time.minutes().count() << ":";
file << std::setfill('0') << std::setw(2) << time.seconds().count() << ".";
file << std::setfill('0') << std::setw(4) << milliseconds.count();
file << "\"\n";
last_timestamp = timestamp;
}
void add_hex_encoded_data(const uint8_t* data, size_t len) {
file << " data: \"";
const auto flags = file.flags();
file << std::hex;
for (int i = 0; i < len; ++i) {
file << std::setfill('0') << std::setw(2) << static_cast<int>(data[i]);
}
file.flags(flags);
file << "\"\n";
}
iso15118::session::logging::TimePoint last_timestamp;
bool timestamp_initialized{false};
};
SessionLogger::SessionLogger(std::filesystem::path output_dir_) : output_dir(std::filesystem::absolute(output_dir_)) {
// FIXME (aw): this is quite brute force ...
if (not std::filesystem::exists(output_dir)) {
std::filesystem::create_directory(output_dir);
}
iso15118::session::logging::set_session_log_callback([this](std::uintptr_t id, const LogEvent& event) {
auto log_it = logs.find(id);
if (log_it == logs.end()) {
const auto log_file_name = output_dir / get_filename_for_current_time();
const auto emplaced = logs.emplace(id, std::make_unique<SessionLog>(log_file_name.string()));
log_it = emplaced.first;
}
auto& log = *log_it->second;
std::visit(log, event);
log.flush();
});
}
SessionLogger::~SessionLogger() = default;

View File

@@ -0,0 +1,21 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#pragma once
#include <cstdint>
#include <filesystem>
#include <map>
#include <memory>
// forward declare
class SessionLog;
class SessionLogger {
public:
SessionLogger(std::filesystem::path output_dir);
~SessionLogger();
private:
std::filesystem::path output_dir;
std::map<std::uintptr_t, std::unique_ptr<SessionLog>> logs;
};

View File

@@ -0,0 +1,508 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "utils.hpp"
#include <everest/logging.hpp>
#include <iso15118/d20/limits.hpp>
#include <iso15118/message/common_types.hpp>
#include <iso15118/message/dc_charge_parameter_discovery.hpp>
#include <iso15118/message/schedule_exchange.hpp>
#include <iso15118/message/service_detail.hpp>
namespace module::charger {
namespace dt = iso15118::message_20::datatypes;
namespace {
dt::Parameter convert_parameter(const types::iso15118_vas::Parameter& parameter) {
dt::Parameter out;
out.name = parameter.name;
if (parameter.value.bool_value.has_value()) {
out.value = parameter.value.bool_value.value();
} else if (parameter.value.int_value.has_value()) {
out.value = static_cast<int32_t>(parameter.value.int_value.value());
} else if (parameter.value.short_value.has_value()) {
out.value = static_cast<int16_t>(parameter.value.short_value.value());
} else if (parameter.value.byte_value.has_value()) {
out.value = static_cast<int8_t>(parameter.value.byte_value.value());
} else if (parameter.value.rational_number.has_value()) {
out.value = dt::from_float(parameter.value.rational_number.value());
} else if (parameter.value.finite_string.has_value()) {
out.value = parameter.value.finite_string.value();
} else {
throw std::invalid_argument("Invalid ParameterValue in convert_parameter: " + parameter.name +
" has no value set");
}
return out;
}
dt::ParameterSet convert_parameter_set(const types::iso15118_vas::ParameterSet& parameter_set) {
dt::ParameterSet out;
out.id = parameter_set.set_id;
for (const auto& parameter : parameter_set.parameters) {
const auto* ptr = out.parameter.try_emplace_back(convert_parameter(parameter));
if (ptr == nullptr) {
EVLOG_warning << "VAS parameter set is bigger then 32";
break;
}
}
return out;
}
} // namespace
std::optional<float> convert_from_optional(const std::optional<dt::RationalNumber>& in) {
return (in.has_value()) ? std::make_optional(dt::from_RationalNumber(*in)) : std::nullopt;
}
std::optional<dt::RationalNumber> convert_from_optional(const std::optional<float>& in) {
return (in.has_value()) ? std::make_optional(dt::from_float(*in)) : std::nullopt;
}
std::optional<float> convert_from_optional(const std::optional<uint32_t>& in) {
return (in.has_value()) ? std::make_optional(static_cast<float>(*in)) : std::nullopt;
}
types::iso15118::AppProtocol convert_app_protocol(const iso15118::message_20::SupportedAppProtocol& app_protocol) {
types::iso15118::AppProtocol result;
result.protocol_namespace = app_protocol.protocol_namespace;
result.priority = app_protocol.priority;
result.schema_id = app_protocol.schema_id;
result.version_number_major = static_cast<int32_t>(app_protocol.version_number_major);
result.version_number_minor = static_cast<int32_t>(app_protocol.version_number_minor);
return result;
}
types::iso15118::EvInformation convert_ev_info(const iso15118::d20::EVInformation& ev_info) {
types::iso15118::EvInformation result;
result.evcc_id = ev_info.evcc_id;
result.selected_protocol = convert_app_protocol(ev_info.selected_app_protocol);
result.supported_protocols.Protocols.reserve(ev_info.ev_supported_app_protocols.size());
for (const auto& supported_app : ev_info.ev_supported_app_protocols) {
result.supported_protocols.Protocols.push_back(convert_app_protocol(supported_app));
}
result.tls_leaf_certificate = ev_info.ev_tls_leaf_cert;
result.tls_sub_ca_1_certificate = ev_info.ev_tls_sub_ca_1_cert;
result.tls_sub_ca_2_certificate = ev_info.ev_tls_sub_ca_2_cert;
result.tls_root_certificate = ev_info.ev_tls_root_cert;
return result;
}
types::iso15118::DcChargeDynamicModeValues convert_dynamic_values(const dt::Dynamic_DC_CLReqControlMode& in) {
return {dt::from_RationalNumber(in.target_energy_request),
dt::from_RationalNumber(in.max_energy_request),
dt::from_RationalNumber(in.min_energy_request),
dt::from_RationalNumber(in.max_charge_power),
dt::from_RationalNumber(in.min_charge_power),
dt::from_RationalNumber(in.max_charge_current),
dt::from_RationalNumber(in.max_voltage),
dt::from_RationalNumber(in.min_voltage),
convert_from_optional(in.departure_time),
std::nullopt,
std::nullopt,
std::nullopt,
std::nullopt,
std::nullopt};
}
types::iso15118::DcChargeDynamicModeValues convert_dynamic_values(const dt::BPT_Dynamic_DC_CLReqControlMode& in) {
return {dt::from_RationalNumber(in.target_energy_request), dt::from_RationalNumber(in.max_energy_request),
dt::from_RationalNumber(in.min_energy_request), dt::from_RationalNumber(in.max_charge_power),
dt::from_RationalNumber(in.min_charge_power), dt::from_RationalNumber(in.max_charge_current),
dt::from_RationalNumber(in.max_voltage), dt::from_RationalNumber(in.min_voltage),
convert_from_optional(in.departure_time), dt::from_RationalNumber(in.max_discharge_power),
dt::from_RationalNumber(in.min_discharge_power), dt::from_RationalNumber(in.max_discharge_current),
convert_from_optional(in.max_v2x_energy_request), convert_from_optional(in.min_v2x_energy_request)};
}
template <>
void fill_v2x_charging_parameters(types::iso15118::V2XChargingParameters& out_params,
const iso15118::d20::DcTransferLimits& evse_limits,
const dt::DC_CPDReqEnergyTransferMode& ev_limits) {
// As per the OCPP 2.1 spec (2.109) we should use the MIN/MAX function between EV and EVSE
out_params.min_charge_power = std::max(dt::from_RationalNumber(evse_limits.charge_limits.power.min),
dt::from_RationalNumber(ev_limits.min_charge_power));
out_params.max_charge_power = std::min(dt::from_RationalNumber(evse_limits.charge_limits.power.max),
dt::from_RationalNumber(ev_limits.max_charge_power));
out_params.min_charge_current = std::max(dt::from_RationalNumber(evse_limits.charge_limits.current.min),
dt::from_RationalNumber(ev_limits.min_charge_current));
out_params.max_charge_current = std::min(dt::from_RationalNumber(evse_limits.charge_limits.current.max),
dt::from_RationalNumber(ev_limits.max_charge_current));
out_params.min_voltage =
std::max(dt::from_RationalNumber(evse_limits.voltage.min), dt::from_RationalNumber(ev_limits.min_voltage));
out_params.max_voltage =
std::min(dt::from_RationalNumber(evse_limits.voltage.max), dt::from_RationalNumber(ev_limits.max_voltage));
out_params.target_soc = ev_limits.target_soc;
}
template <>
void fill_v2x_charging_parameters(types::iso15118::V2XChargingParameters& out_params,
const iso15118::d20::DcTransferLimits& evse_limits,
const dt::BPT_DC_CPDReqEnergyTransferMode& ev_limits) {
// Fill in the common data
fill_v2x_charging_parameters<iso15118::d20::DcTransferLimits, dt::DC_CPDReqEnergyTransferMode>(
out_params, evse_limits, static_cast<const dt::DC_CPDReqEnergyTransferMode&>(ev_limits));
// Fill in the bidi data
if (evse_limits.discharge_limits.has_value()) {
const auto& evse_discharge_limits = evse_limits.discharge_limits.value();
out_params.min_discharge_power = std::max(dt::from_RationalNumber(evse_discharge_limits.power.min),
dt::from_RationalNumber(ev_limits.min_discharge_power));
out_params.max_discharge_power = std::min(dt::from_RationalNumber(evse_discharge_limits.power.max),
dt::from_RationalNumber(ev_limits.max_discharge_power));
out_params.min_discharge_current = std::max(dt::from_RationalNumber(evse_discharge_limits.current.min),
dt::from_RationalNumber(ev_limits.min_discharge_current));
out_params.max_discharge_current = std::min(dt::from_RationalNumber(evse_discharge_limits.current.max),
dt::from_RationalNumber(ev_limits.max_discharge_current));
}
}
template <>
void fill_v2x_charging_parameters(types::iso15118::V2XChargingParameters& out_params,
const iso15118::d20::AcTransferLimits& evse_limits,
const dt::AC_CPDReqEnergyTransferMode& ev_limits) {
// As per the OCPP 2.1 spec (2.109) we should use the MIN/MAX function between EV and EVSE
out_params.min_charge_power = std::max(dt::from_RationalNumber(evse_limits.charge_power.min),
dt::from_RationalNumber(ev_limits.min_charge_power));
out_params.max_charge_power = std::min(dt::from_RationalNumber(evse_limits.charge_power.max),
dt::from_RationalNumber(ev_limits.max_charge_power));
if (evse_limits.charge_power_L2.has_value() and ev_limits.max_charge_power_L2.has_value() and
ev_limits.min_charge_power_L2.has_value()) {
out_params.min_charge_power_l2 = std::max(dt::from_RationalNumber(evse_limits.charge_power_L2.value().min),
dt::from_RationalNumber(ev_limits.min_charge_power_L2.value()));
out_params.max_charge_power_l2 = std::min(dt::from_RationalNumber(evse_limits.charge_power_L2.value().max),
dt::from_RationalNumber(ev_limits.max_charge_power_L2.value()));
}
if (evse_limits.charge_power_L3.has_value() and ev_limits.max_charge_power_L3.has_value() and
ev_limits.min_charge_power_L3.has_value()) {
out_params.min_charge_power_l3 = std::max(dt::from_RationalNumber(evse_limits.charge_power_L3.value().min),
dt::from_RationalNumber(ev_limits.min_charge_power_L3.value()));
out_params.max_charge_power_l3 = std::min(dt::from_RationalNumber(evse_limits.charge_power_L3.value().max),
dt::from_RationalNumber(ev_limits.max_charge_power_L3.value()));
}
}
template <>
void fill_v2x_charging_parameters(types::iso15118::V2XChargingParameters& out_params,
const iso15118::d20::AcTransferLimits& evse_limits,
const dt::BPT_AC_CPDReqEnergyTransferMode& ev_limits) {
// Fill in the common data
fill_v2x_charging_parameters<iso15118::d20::AcTransferLimits, dt::AC_CPDReqEnergyTransferMode>(
out_params, evse_limits, static_cast<const dt::AC_CPDReqEnergyTransferMode&>(ev_limits));
if (evse_limits.discharge_power.has_value()) {
const auto& evse_discharge_limits = evse_limits.discharge_power.value();
out_params.min_discharge_power = std::max(dt::from_RationalNumber(evse_discharge_limits.min),
dt::from_RationalNumber(ev_limits.min_discharge_power));
out_params.max_discharge_power = std::min(dt::from_RationalNumber(evse_discharge_limits.max),
dt::from_RationalNumber(ev_limits.max_discharge_power));
}
if (evse_limits.discharge_power_L2.has_value() && ev_limits.min_discharge_power_L2.has_value() &&
ev_limits.max_discharge_power_L2.has_value()) {
const auto& evse_discharge_limits = evse_limits.discharge_power_L2.value();
out_params.min_discharge_power_l2 = std::max(dt::from_RationalNumber(evse_discharge_limits.min),
dt::from_RationalNumber(ev_limits.min_discharge_power_L2.value()));
out_params.max_discharge_power_l2 = std::min(dt::from_RationalNumber(evse_discharge_limits.max),
dt::from_RationalNumber(ev_limits.max_discharge_power_L2.value()));
}
if (evse_limits.discharge_power_L3.has_value() && ev_limits.min_discharge_power_L3.has_value() &&
ev_limits.max_discharge_power_L3.has_value()) {
const auto& evse_discharge_limits = evse_limits.discharge_power_L3.value();
out_params.min_discharge_power_l3 = std::max(dt::from_RationalNumber(evse_discharge_limits.min),
dt::from_RationalNumber(ev_limits.min_discharge_power_L3.value()));
out_params.max_discharge_power_l3 = std::min(dt::from_RationalNumber(evse_discharge_limits.max),
dt::from_RationalNumber(ev_limits.max_discharge_power_L3.value()));
}
}
template <>
void fill_v2x_charging_parameters(types::iso15118::V2XChargingParameters& out_params,
const dt::Scheduled_SEReqControlMode& ev_control_mode) {
out_params.ev_target_energy_request = convert_from_optional(ev_control_mode.target_energy);
out_params.ev_min_energy_request = convert_from_optional(ev_control_mode.min_energy);
out_params.ev_max_energy_request = convert_from_optional(ev_control_mode.max_energy);
}
template <>
void fill_v2x_charging_parameters(types::iso15118::V2XChargingParameters& out_params,
const dt::Dynamic_SEReqControlMode& ev_control_mode) {
out_params.ev_target_energy_request = dt::from_RationalNumber(ev_control_mode.target_energy);
out_params.ev_min_energy_request = dt::from_RationalNumber(ev_control_mode.min_energy);
out_params.ev_max_energy_request = dt::from_RationalNumber(ev_control_mode.max_energy);
out_params.ev_min_v2xenergy_request = convert_from_optional(ev_control_mode.min_v2x_energy);
out_params.ev_max_v2xenergy_request = convert_from_optional(ev_control_mode.max_v2x_energy);
}
everest::lib::util::fixed_vector<dt::ParameterSet, 32>
convert_parameter_set_list(const std::vector<types::iso15118_vas::ParameterSet>& parameter_set_list) {
everest::lib::util::fixed_vector<dt::ParameterSet, 32> out;
for (const auto& parameter_set : parameter_set_list) {
const auto* ptr = out.try_emplace_back(convert_parameter_set(parameter_set));
if (ptr == nullptr) {
EVLOG_warning << "VAS parameter set list is bigger then 32";
break;
}
}
return out;
}
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::AC_CPDReqEnergyTransferMode& mode) {
const auto max_charge_L1 = dt::from_RationalNumber(mode.max_charge_power);
const auto max_charge_L2 = convert_from_optional(mode.max_charge_power_L2);
const auto max_charge_L3 = convert_from_optional(mode.max_charge_power_L3);
const auto max_charge_total = max_charge_L1 + max_charge_L2.value_or(0.0) + max_charge_L3.value_or(0.0);
const auto min_charge_L1 = dt::from_RationalNumber(mode.min_charge_power);
const auto min_charge_L2 = convert_from_optional(mode.min_charge_power_L2);
const auto min_charge_L3 = convert_from_optional(mode.min_charge_power_L3);
const auto min_charge_total = min_charge_L1 + min_charge_L2.value_or(0.0) + min_charge_L3.value_or(0.0);
types::iso15118::AcEvPowerLimits ac_ev_power_limits;
ac_ev_power_limits.max_charge_power = {max_charge_total, std::make_optional<float>(max_charge_L1), max_charge_L2,
max_charge_L3};
ac_ev_power_limits.min_charge_power = {min_charge_total, std::make_optional<float>(min_charge_L1), min_charge_L2,
min_charge_L3};
return ac_ev_power_limits;
}
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::BPT_AC_CPDReqEnergyTransferMode& mode) {
const auto max_charge_L1 = dt::from_RationalNumber(mode.max_charge_power);
const auto max_charge_L2 = convert_from_optional(mode.max_charge_power_L2);
const auto max_charge_L3 = convert_from_optional(mode.max_charge_power_L3);
const auto max_charge_total = max_charge_L1 + max_charge_L2.value_or(0.0) + max_charge_L3.value_or(0.0);
const auto min_charge_L1 = dt::from_RationalNumber(mode.min_charge_power);
const auto min_charge_L2 = convert_from_optional(mode.min_charge_power_L2);
const auto min_charge_L3 = convert_from_optional(mode.min_charge_power_L3);
const auto min_charge_total = min_charge_L1 + min_charge_L2.value_or(0.0) + min_charge_L3.value_or(0.0);
const auto max_discharge_L1 = dt::from_RationalNumber(mode.max_discharge_power);
const auto max_discharge_L2 = convert_from_optional(mode.max_discharge_power_L2);
const auto max_discharge_L3 = convert_from_optional(mode.max_discharge_power_L3);
const auto max_discharge_total = max_discharge_L1 + max_discharge_L2.value_or(0.0) + max_discharge_L3.value_or(0.0);
const auto min_discharge_L1 = dt::from_RationalNumber(mode.min_discharge_power);
const auto min_discharge_L2 = convert_from_optional(mode.min_discharge_power_L2);
const auto min_discharge_L3 = convert_from_optional(mode.min_discharge_power_L3);
const auto min_discharge_total = min_discharge_L1 + min_discharge_L2.value_or(0.0) + min_discharge_L3.value_or(0.0);
types::iso15118::AcEvPowerLimits ac_ev_power_limits;
ac_ev_power_limits.max_charge_power = {max_charge_total, std::make_optional<float>(max_charge_L1), max_charge_L2,
max_charge_L3};
ac_ev_power_limits.min_charge_power = {min_charge_total, std::make_optional<float>(min_charge_L1), min_charge_L2,
min_charge_L3};
ac_ev_power_limits.max_discharge_power = {max_discharge_total, std::make_optional<float>(max_discharge_L1),
max_discharge_L2, max_discharge_L3};
ac_ev_power_limits.min_discharge_power = {min_discharge_total, std::make_optional<float>(min_discharge_L1),
min_discharge_L2, min_discharge_L3};
return ac_ev_power_limits;
}
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::Dynamic_AC_CLReqControlMode& mode) {
const auto max_charge_L1 = dt::from_RationalNumber(mode.max_charge_power);
const auto max_charge_L2 = convert_from_optional(mode.max_charge_power_L2);
const auto max_charge_L3 = convert_from_optional(mode.max_charge_power_L3);
const auto max_charge_total = max_charge_L1 + max_charge_L2.value_or(0.0) + max_charge_L3.value_or(0.0);
const auto min_charge_L1 = dt::from_RationalNumber(mode.min_charge_power);
const auto min_charge_L2 = convert_from_optional(mode.min_charge_power_L2);
const auto min_charge_L3 = convert_from_optional(mode.min_charge_power_L3);
const auto min_charge_total = min_charge_L1 + min_charge_L2.value_or(0.0) + min_charge_L3.value_or(0.0);
types::iso15118::AcEvPowerLimits ac_ev_power_limits;
ac_ev_power_limits.max_charge_power = {max_charge_total, std::make_optional<float>(max_charge_L1), max_charge_L2,
max_charge_L3};
ac_ev_power_limits.min_charge_power = {min_charge_total, std::make_optional<float>(min_charge_L1), min_charge_L2,
min_charge_L3};
return ac_ev_power_limits;
}
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::BPT_Dynamic_AC_CLReqControlMode& mode) {
const auto max_charge_L1 = dt::from_RationalNumber(mode.max_charge_power);
const auto max_charge_L2 = convert_from_optional(mode.max_charge_power_L2);
const auto max_charge_L3 = convert_from_optional(mode.max_charge_power_L3);
const auto max_charge_total = max_charge_L1 + max_charge_L2.value_or(0.0) + max_charge_L3.value_or(0.0);
const auto min_charge_L1 = dt::from_RationalNumber(mode.min_charge_power);
const auto min_charge_L2 = convert_from_optional(mode.min_charge_power_L2);
const auto min_charge_L3 = convert_from_optional(mode.min_charge_power_L3);
const auto min_charge_total = min_charge_L1 + min_charge_L2.value_or(0.0) + min_charge_L3.value_or(0.0);
const auto max_discharge_L1 = dt::from_RationalNumber(mode.max_discharge_power);
const auto max_discharge_L2 = convert_from_optional(mode.max_discharge_power_L2);
const auto max_discharge_L3 = convert_from_optional(mode.max_discharge_power_L3);
const auto max_discharge_total = max_discharge_L1 + max_discharge_L2.value_or(0.0) + max_discharge_L3.value_or(0.0);
const auto min_discharge_L1 = dt::from_RationalNumber(mode.min_discharge_power);
const auto min_discharge_L2 = convert_from_optional(mode.min_discharge_power_L2);
const auto min_discharge_L3 = convert_from_optional(mode.min_discharge_power_L3);
const auto min_discharge_total = min_discharge_L1 + min_discharge_L2.value_or(0.0) + min_discharge_L3.value_or(0.0);
types::iso15118::AcEvPowerLimits ac_ev_power_limits;
ac_ev_power_limits.max_charge_power = {max_charge_total, std::make_optional<float>(max_charge_L1), max_charge_L2,
max_charge_L3};
ac_ev_power_limits.min_charge_power = {min_charge_total, std::make_optional<float>(min_charge_L1), min_charge_L2,
min_charge_L3};
ac_ev_power_limits.max_discharge_power = {max_discharge_total, std::make_optional<float>(max_discharge_L1),
max_discharge_L2, max_discharge_L3};
ac_ev_power_limits.min_discharge_power = {min_discharge_total, std::make_optional<float>(min_discharge_L1),
min_discharge_L2, min_discharge_L3};
return ac_ev_power_limits;
}
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::Scheduled_AC_CLReqControlMode& mode) {
const auto max_charge_L1 = convert_from_optional(mode.max_charge_power);
const auto max_charge_L2 = convert_from_optional(mode.max_charge_power_L2);
const auto max_charge_L3 = convert_from_optional(mode.max_charge_power_L3);
const auto max_charge_total =
max_charge_L1.value_or(0.0) + max_charge_L2.value_or(0.0) + max_charge_L3.value_or(0.0);
const auto min_charge_L1 = convert_from_optional(mode.min_charge_power);
const auto min_charge_L2 = convert_from_optional(mode.min_charge_power_L2);
const auto min_charge_L3 = convert_from_optional(mode.min_charge_power_L3);
const auto min_charge_total =
min_charge_L1.value_or(0.0) + min_charge_L2.value_or(0.0) + min_charge_L3.value_or(0.0);
types::iso15118::AcEvPowerLimits ac_ev_power_limits;
ac_ev_power_limits.max_charge_power =
(max_charge_L1.has_value() or max_charge_L2.has_value() or max_charge_L3.has_value())
? std::make_optional<types::units::Power>({max_charge_total, max_charge_L1, max_charge_L2, max_charge_L3})
: std::nullopt;
ac_ev_power_limits.min_charge_power =
(max_charge_L1.has_value() or max_charge_L2.has_value() or max_charge_L3.has_value())
? std::make_optional<types::units::Power>({min_charge_total, min_charge_L1, min_charge_L2, min_charge_L3})
: std::nullopt;
return ac_ev_power_limits;
}
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::BPT_Scheduled_AC_CLReqControlMode& mode) {
const auto max_charge_L1 = convert_from_optional(mode.max_charge_power);
const auto max_charge_L2 = convert_from_optional(mode.max_charge_power_L2);
const auto max_charge_L3 = convert_from_optional(mode.max_charge_power_L3);
const auto max_charge_total =
max_charge_L1.value_or(0.0) + max_charge_L2.value_or(0.0) + max_charge_L3.value_or(0.0);
const auto min_charge_L1 = convert_from_optional(mode.min_charge_power);
const auto min_charge_L2 = convert_from_optional(mode.min_charge_power_L2);
const auto min_charge_L3 = convert_from_optional(mode.min_charge_power_L3);
const auto min_charge_total =
min_charge_L1.value_or(0.0) + min_charge_L2.value_or(0.0) + min_charge_L3.value_or(0.0);
const auto max_discharge_L1 = convert_from_optional(mode.max_discharge_power);
const auto max_discharge_L2 = convert_from_optional(mode.max_discharge_power_L2);
const auto max_discharge_L3 = convert_from_optional(mode.max_discharge_power_L3);
const auto max_discharge_total =
max_discharge_L1.value_or(0.0) + max_discharge_L2.value_or(0.0) + max_discharge_L3.value_or(0.0);
const auto min_discharge_L1 = convert_from_optional(mode.min_discharge_power);
const auto min_discharge_L2 = convert_from_optional(mode.min_discharge_power_L2);
const auto min_discharge_L3 = convert_from_optional(mode.min_discharge_power_L3);
const auto min_discharge_total =
min_discharge_L1.value_or(0.0) + min_discharge_L2.value_or(0.0) + min_discharge_L3.value_or(0.0);
types::iso15118::AcEvPowerLimits ac_ev_power_limits;
ac_ev_power_limits.max_charge_power =
(max_charge_L1.has_value() or max_charge_L2.has_value() or max_charge_L3.has_value())
? std::make_optional<types::units::Power>({max_charge_total, max_charge_L1, max_charge_L2, max_charge_L3})
: std::nullopt;
ac_ev_power_limits.min_charge_power =
(min_charge_L1.has_value() or min_charge_L2.has_value() or min_charge_L3.has_value())
? std::make_optional<types::units::Power>({min_charge_total, min_charge_L1, min_charge_L2, min_charge_L3})
: std::nullopt;
ac_ev_power_limits.max_discharge_power =
(max_discharge_L1.has_value() or max_discharge_L2.has_value() or max_discharge_L3.has_value())
? std::make_optional<types::units::Power>(
{max_discharge_total, max_discharge_L1, max_discharge_L2, max_discharge_L3})
: std::nullopt;
ac_ev_power_limits.min_discharge_power =
(min_discharge_L1.has_value() or min_discharge_L2.has_value() or min_discharge_L3.has_value())
? std::make_optional<types::units::Power>(
{min_discharge_total, min_discharge_L1, min_discharge_L2, min_discharge_L3})
: std::nullopt;
return ac_ev_power_limits;
}
types::iso15118::AcEvPresentPowerValues fill_ac_ev_present_power_values(const dt::Dynamic_AC_CLReqControlMode& mode) {
types::iso15118::AcEvPresentPowerValues present_values{};
const auto present_active_power_L1 = dt::from_RationalNumber(mode.present_active_power);
const auto present_active_power_L2 = convert_from_optional(mode.present_active_power_L2);
const auto present_active_power_L3 = convert_from_optional(mode.present_active_power_L3);
const auto present_active_power_total =
present_active_power_L1 + present_active_power_L2.value_or(0.0) + present_active_power_L3.value_or(0.0);
const auto present_reactive_power_L1 = dt::from_RationalNumber(mode.present_reactive_power);
const auto present_reactive_power_L2 = convert_from_optional(mode.present_reactive_power_L2);
const auto present_reactive_power_L3 = convert_from_optional(mode.present_reactive_power_L3);
const auto present_reactive_power_total =
present_reactive_power_L1 + present_reactive_power_L2.value_or(0.0) + present_reactive_power_L3.value_or(0.0);
present_values.present_active_power = {present_active_power_total, present_active_power_L1, present_active_power_L2,
present_active_power_L3};
present_values.present_reactive_power = {present_reactive_power_total, present_reactive_power_L1,
present_reactive_power_L2, present_reactive_power_L3};
return present_values;
}
types::iso15118::AcEvPresentPowerValues fill_ac_ev_present_power_values(const dt::Scheduled_AC_CLReqControlMode& mode) {
types::iso15118::AcEvPresentPowerValues present_values{};
const auto present_active_power_L1 = dt::from_RationalNumber(mode.present_active_power);
const auto present_active_power_L2 = convert_from_optional(mode.present_active_power_L2);
const auto present_active_power_L3 = convert_from_optional(mode.present_active_power_L3);
const auto present_active_power_total =
present_active_power_L1 + present_active_power_L2.value_or(0.0) + present_active_power_L3.value_or(0.0);
const auto present_reactive_power_L1 = convert_from_optional(mode.present_reactive_power);
const auto present_reactive_power_L2 = convert_from_optional(mode.present_reactive_power_L2);
const auto present_reactive_power_L3 = convert_from_optional(mode.present_reactive_power_L3);
const auto present_reactive_power_total = present_reactive_power_L1.value_or(0.0) +
present_reactive_power_L2.value_or(0.0) +
present_reactive_power_L3.value_or(0.0);
present_values.present_active_power = {present_active_power_total, present_active_power_L1, present_active_power_L2,
present_active_power_L3};
present_values.present_reactive_power =
(present_reactive_power_L1.has_value() or present_reactive_power_L2.has_value() or
present_reactive_power_L3.has_value())
? std::make_optional<types::units::Power>({present_reactive_power_total, present_reactive_power_L1,
present_reactive_power_L2, present_reactive_power_L3})
: std::nullopt;
return present_values;
}
} // namespace module::charger

View File

@@ -0,0 +1,152 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#pragma once
#include <cstdint>
#include <optional>
#include <vector>
#include <generated/types/iso15118.hpp>
#include <generated/types/iso15118_vas.hpp>
#include <iso15118/d20/ev_information.hpp>
#include <iso15118/message/ac_charge_loop.hpp>
#include <iso15118/message/ac_charge_parameter_discovery.hpp>
#include <iso15118/message/dc_charge_loop.hpp>
#include <iso15118/message/service_detail.hpp>
#include <iso15118/message/type.hpp>
#include <everest/util/vector/fixed_vector.hpp>
static constexpr auto NUMBER_OF_SETUP_STEPS = 5;
namespace module::charger {
namespace dt = iso15118::message_20::datatypes;
enum class SetupStep : std::uint8_t {
SETUP,
ENERGY_SERVICE,
AUTH_SETUP,
MAX_LIMITS,
MIN_LIMITS,
};
template <typename T> constexpr auto to_underlying_value(T t) {
return static_cast<std::underlying_type_t<T>>(t);
}
static_assert(NUMBER_OF_SETUP_STEPS == to_underlying_value(SetupStep::MIN_LIMITS) + 1,
"NUMBER_OF_SETUP_STEPS should be in sync with the SetupStep enum definition");
constexpr types::iso15118::V2gMessageId convert_v2g_message_type(iso15118::message_20::Type type) {
using Type = iso15118::message_20::Type;
using Id = types::iso15118::V2gMessageId;
switch (type) {
case Type::None:
return Id::UnknownMessage;
case Type::SupportedAppProtocolReq:
return Id::SupportedAppProtocolReq;
case Type::SupportedAppProtocolRes:
return Id::SupportedAppProtocolRes;
case Type::SessionSetupReq:
return Id::SessionSetupReq;
case Type::SessionSetupRes:
return Id::SessionSetupRes;
case Type::AuthorizationSetupReq:
return Id::AuthorizationSetupReq;
case Type::AuthorizationSetupRes:
return Id::AuthorizationSetupRes;
case Type::AuthorizationReq:
return Id::AuthorizationReq;
case Type::AuthorizationRes:
return Id::AuthorizationRes;
case Type::ServiceDiscoveryReq:
return Id::ServiceDiscoveryReq;
case Type::ServiceDiscoveryRes:
return Id::ServiceDiscoveryRes;
case Type::ServiceDetailReq:
return Id::ServiceDetailReq;
case Type::ServiceDetailRes:
return Id::ServiceDetailRes;
case Type::ServiceSelectionReq:
return Id::ServiceSelectionReq;
case Type::ServiceSelectionRes:
return Id::ServiceSelectionRes;
case Type::DC_ChargeParameterDiscoveryReq:
return Id::DcChargeParameterDiscoveryReq;
case Type::DC_ChargeParameterDiscoveryRes:
return Id::DcChargeParameterDiscoveryRes;
case Type::ScheduleExchangeReq:
return Id::ScheduleExchangeReq;
case Type::ScheduleExchangeRes:
return Id::ScheduleExchangeRes;
case Type::DC_CableCheckReq:
return Id::DcCableCheckReq;
case Type::DC_CableCheckRes:
return Id::DcCableCheckRes;
case Type::DC_PreChargeReq:
return Id::DcPreChargeReq;
case Type::DC_PreChargeRes:
return Id::DcPreChargeRes;
case Type::PowerDeliveryReq:
return Id::PowerDeliveryReq;
case Type::PowerDeliveryRes:
return Id::PowerDeliveryRes;
case Type::DC_ChargeLoopReq:
return Id::DcChargeLoopReq;
case Type::DC_ChargeLoopRes:
return Id::DcChargeLoopRes;
case Type::DC_WeldingDetectionReq:
return Id::DcWeldingDetectionReq;
case Type::DC_WeldingDetectionRes:
return Id::DcWeldingDetectionRes;
case Type::SessionStopReq:
return Id::SessionStopReq;
case Type::SessionStopRes:
return Id::SessionStopRes;
case Type::AC_ChargeParameterDiscoveryReq:
return Id::AcChargeParameterDiscoveryReq;
case Type::AC_ChargeParameterDiscoveryRes:
return Id::AcChargeParameterDiscoveryRes;
case Type::AC_ChargeLoopReq:
return Id::AcChargeLoopReq;
case Type::AC_ChargeLoopRes:
return Id::AcChargeLoopRes;
}
return Id::UnknownMessage;
}
std::optional<float> convert_from_optional(const std::optional<dt::RationalNumber>& in);
std::optional<dt::RationalNumber> convert_from_optional(const std::optional<float>& in);
std::optional<float> convert_from_optional(const std::optional<uint32_t>& in);
types::iso15118::AppProtocol convert_app_protocol(const iso15118::message_20::SupportedAppProtocol& app_protocol);
types::iso15118::EvInformation convert_ev_info(const iso15118::d20::EVInformation& ev_info);
types::iso15118::DcChargeDynamicModeValues convert_dynamic_values(const dt::Dynamic_DC_CLReqControlMode& in);
types::iso15118::DcChargeDynamicModeValues convert_dynamic_values(const dt::BPT_Dynamic_DC_CLReqControlMode& in);
template <typename EVSE, typename EV>
void fill_v2x_charging_parameters(types::iso15118::V2XChargingParameters& out_params, const EVSE& evse_limits,
const EV& ev_limits);
template <typename In>
void fill_v2x_charging_parameters(types::iso15118::V2XChargingParameters& out_params, const In& data);
everest::lib::util::fixed_vector<dt::ParameterSet, 32>
convert_parameter_set_list(const std::vector<types::iso15118_vas::ParameterSet>& parameter_set_list);
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::AC_CPDReqEnergyTransferMode& mode);
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::BPT_AC_CPDReqEnergyTransferMode& mode);
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::Dynamic_AC_CLReqControlMode& mode);
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::BPT_Dynamic_AC_CLReqControlMode& mode);
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::Scheduled_AC_CLReqControlMode& mode);
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::BPT_Scheduled_AC_CLReqControlMode& mode);
types::iso15118::AcEvPresentPowerValues fill_ac_ev_present_power_values(const dt::Dynamic_AC_CLReqControlMode& mode);
types::iso15118::AcEvPresentPowerValues fill_ac_ev_present_power_values(const dt::Scheduled_AC_CLReqControlMode& mode);
} // namespace module::charger

View File

@@ -0,0 +1,21 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "iso15118_extensionsImpl.hpp"
namespace module {
namespace extensions {
void iso15118_extensionsImpl::init() {
}
void iso15118_extensionsImpl::ready() {
}
void iso15118_extensionsImpl::handle_set_get_certificate_response(
types::iso15118::ResponseExiStreamStatus& certificate_response) {
// your code for cmd set_get_certificate_response goes here
}
} // namespace extensions
} // namespace module

View File

@@ -0,0 +1,62 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef EXTENSIONS_ISO15118_EXTENSIONS_IMPL_HPP
#define EXTENSIONS_ISO15118_EXTENSIONS_IMPL_HPP
//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 3
//
#include <generated/interfaces/iso15118_extensions/Implementation.hpp>
#include "../Evse15118D20.hpp"
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
// insert your custom include headers here
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
namespace module {
namespace extensions {
struct Conf {};
class iso15118_extensionsImpl : public iso15118_extensionsImplBase {
public:
iso15118_extensionsImpl() = delete;
iso15118_extensionsImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<Evse15118D20>& mod, Conf& config) :
iso15118_extensionsImplBase(ev, "extensions"), mod(mod), config(config){};
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
// insert your public definitions here
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
protected:
// command handler functions (virtual)
virtual void
handle_set_get_certificate_response(types::iso15118::ResponseExiStreamStatus& certificate_response) override;
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
// insert your protected definitions here
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
private:
const Everest::PtrContainer<Evse15118D20>& mod;
const Conf& config;
virtual void init() override;
virtual void ready() override;
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
// insert your private definitions here
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
};
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
// insert other definitions here
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
} // namespace extensions
} // namespace module
#endif // EXTENSIONS_ISO15118_EXTENSIONS_IMPL_HPP

View File

@@ -0,0 +1,93 @@
description: >-
This module is a draft implementation of iso15118-20 for the EVSE side
config:
device:
description: >-
Ethernet device used for HLC. Any local interface that has an ipv6
link-local and a MAC addr will work
type: string
default: eth0
logging_path:
description: Path to logging directory (will be created if non existent)
type: string
default: "."
tls_negotiation_strategy:
description: Select strategy on how to negotiate connection encryption
type: string
enum:
- ACCEPT_CLIENT_OFFER
- ENFORCE_TLS
- ENFORCE_NO_TLS
default: ACCEPT_CLIENT_OFFER
enforce_tls_1_3:
description: Enforcing tls version 1.3. Only applies if tls_negotiation_strategy is ENFORCE_TLS.
type: boolean
default: false
enable_ssl_logging:
description: Verbosely log the ssl/tls connection
type: boolean
default: false
enable_tls_key_logging:
description: >-
Enable/Disable the export of TLS session keys (pre-master-secret)
during a TLS handshake. Note that this option is for testing and
simulation purpose only
type: boolean
default: false
tls_key_logging_path:
description: >-
Output directory for the TLS key log file
type: string
default: /tmp
enable_sdp_server:
description: >-
Enable the built-in SDP server
type: boolean
default: true
supported_dynamic_mode:
description: The EVSE should support dynamic mode
type: boolean
default: true
supported_mobility_needs_mode_provided_by_secc:
description: >-
The EVSE should support the mobility needs mode provided by the SECC.
Mobility needs mode provided by the EVCC is always provided.
type: boolean
default: false
supported_scheduled_mode:
description: The EVSE should support scheduled mode
type: boolean
default: false
custom_protocol_namespace:
description: Providing a custom protocol namespace.
type: string
default: ""
negative_bidirectional_limits:
description: >-
Some cars send or expect negative discharge limits. However, it is not clear from the standard
whether the discharge limits should be negative. Until this is clarified, the positive limits
can be converted using this option.
type: boolean
default: false
provides:
charger:
interface: ISO15118_charger
description: >-
This interface provides limited access to iso15118-20
extensions:
interface: iso15118_extensions
description: >-
This interface is used to share data between ISO15118 and OCPP modules
to support the requirements of the OCPP protocol
requires:
security:
interface: evse_security
iso15118_vas:
interface: ISO15118_vas
min_connections: 0
max_connections: 128
metadata:
license: https://opensource.org/licenses/Apache-2.0
authors:
- aw@pionix.de
- Sebastian Lukas