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:
@@ -0,0 +1,38 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace iso15118::config {
|
||||
|
||||
enum class TlsNegotiationStrategy {
|
||||
ACCEPT_CLIENT_OFFER,
|
||||
ENFORCE_TLS,
|
||||
ENFORCE_NO_TLS,
|
||||
};
|
||||
|
||||
enum class CertificateBackend {
|
||||
EVEREST_LAYOUT,
|
||||
JOSEPPA_LAYOUT,
|
||||
};
|
||||
|
||||
struct SSLConfig {
|
||||
CertificateBackend backend{CertificateBackend::EVEREST_LAYOUT};
|
||||
// Used by the JOSEPPA_LAYOUT
|
||||
std::string config_string;
|
||||
// Used by the EVEREST_LAYOUT
|
||||
std::string path_certificate_chain;
|
||||
std::string path_certificate_key;
|
||||
std::optional<std::string> private_key_password{};
|
||||
std::string path_certificate_v2g_root;
|
||||
std::string path_certificate_mo_root;
|
||||
bool enable_ssl_logging{false};
|
||||
bool enable_tls_key_logging{false};
|
||||
bool enforce_tls_1_3{false};
|
||||
std::filesystem::path tls_key_logging_path{};
|
||||
};
|
||||
|
||||
} // namespace iso15118::config
|
||||
@@ -0,0 +1,29 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2025 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <iso15118/message/common_types.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
namespace dt = message_20::datatypes;
|
||||
|
||||
struct AcTargetPower {
|
||||
std::optional<dt::RationalNumber> target_active_power;
|
||||
std::optional<dt::RationalNumber> target_active_power_L2;
|
||||
std::optional<dt::RationalNumber> target_active_power_L3;
|
||||
std::optional<dt::RationalNumber> target_reactive_power;
|
||||
std::optional<dt::RationalNumber> target_reactive_power_L2;
|
||||
std::optional<dt::RationalNumber> target_reactive_power_L3;
|
||||
std::optional<dt::RationalNumber> target_frequency;
|
||||
};
|
||||
|
||||
struct AcPresentPower {
|
||||
std::optional<dt::RationalNumber> present_active_power;
|
||||
std::optional<dt::RationalNumber> present_active_power_L2;
|
||||
std::optional<dt::RationalNumber> present_active_power_L3;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,78 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include <iso15118/d20/limits.hpp>
|
||||
#include <iso15118/message/common_types.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
struct ControlMobilityNeedsModes {
|
||||
message_20::datatypes::ControlMode control_mode;
|
||||
message_20::datatypes::MobilityNeedsMode mobility_mode;
|
||||
};
|
||||
|
||||
struct AcSetupConfig {
|
||||
uint32_t voltage;
|
||||
std::vector<message_20::datatypes::AcConnector> connectors;
|
||||
};
|
||||
|
||||
struct BptSetupConfig {
|
||||
message_20::datatypes::BptChannel bpt_channel;
|
||||
message_20::datatypes::GeneratorMode generator_mode;
|
||||
std::optional<message_20::datatypes::GridCodeIslandingDetectionMethod> grid_code_detection_method;
|
||||
};
|
||||
|
||||
struct EvseSetupConfig {
|
||||
std::string evse_id;
|
||||
std::vector<message_20::datatypes::ServiceCategory> supported_energy_services;
|
||||
std::vector<message_20::datatypes::Authorization> authorization_services;
|
||||
std::vector<uint16_t> supported_vas_services;
|
||||
bool enable_certificate_install_service;
|
||||
d20::DcTransferLimits dc_limits;
|
||||
d20::AcTransferLimits ac_limits;
|
||||
std::vector<ControlMobilityNeedsModes> control_mobility_modes;
|
||||
std::optional<std::string> custom_protocol{std::nullopt};
|
||||
std::optional<AcSetupConfig> ac_setup_config{std::nullopt};
|
||||
std::optional<BptSetupConfig> bpt_setup_config{std::nullopt};
|
||||
d20::DcTransferLimits powersupply_limits;
|
||||
};
|
||||
|
||||
// This should only have EVSE information
|
||||
struct SessionConfig {
|
||||
explicit SessionConfig(EvseSetupConfig);
|
||||
|
||||
std::string evse_id;
|
||||
|
||||
bool cert_install_service;
|
||||
std::vector<message_20::datatypes::Authorization> authorization_services;
|
||||
|
||||
std::vector<message_20::datatypes::ServiceCategory> supported_energy_transfer_services;
|
||||
std::vector<std::uint16_t> supported_vas_services;
|
||||
|
||||
std::vector<message_20::datatypes::AcParameterList> ac_parameter_list;
|
||||
std::vector<message_20::datatypes::AcBptParameterList> ac_bpt_parameter_list;
|
||||
std::vector<message_20::datatypes::DcParameterList> dc_parameter_list;
|
||||
std::vector<message_20::datatypes::DcBptParameterList> dc_bpt_parameter_list;
|
||||
|
||||
std::vector<message_20::datatypes::McsParameterList> mcs_parameter_list;
|
||||
std::vector<message_20::datatypes::McsBptParameterList> mcs_bpt_parameter_list;
|
||||
|
||||
std::vector<message_20::datatypes::InternetParameterList> internet_parameter_list;
|
||||
std::vector<message_20::datatypes::ParkingParameterList> parking_parameter_list;
|
||||
|
||||
DcTransferLimits dc_limits;
|
||||
AcTransferLimits ac_limits;
|
||||
|
||||
DcTransferLimits powersupply_limits;
|
||||
|
||||
std::vector<ControlMobilityNeedsModes> supported_control_mobility_modes;
|
||||
|
||||
std::optional<std::string> custom_protocol{std::nullopt};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,175 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <any>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include <iso15118/d20/timeout.hpp>
|
||||
#include <iso15118/message/payload_type.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
#include <iso15118/session/feedback.hpp>
|
||||
#include <iso15118/session/logger.hpp>
|
||||
|
||||
#include "config.hpp"
|
||||
#include "control_event.hpp"
|
||||
#include "ev_information.hpp"
|
||||
#include "ev_session_info.hpp"
|
||||
#include "session.hpp"
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
// forward declare
|
||||
class ControlEventQueue;
|
||||
|
||||
class MessageExchange {
|
||||
public:
|
||||
MessageExchange(io::StreamOutputView);
|
||||
|
||||
void set_request(std::unique_ptr<message_20::Variant> new_request);
|
||||
std::unique_ptr<message_20::Variant> pull_request();
|
||||
message_20::Type peek_request_type() const;
|
||||
|
||||
template <typename MessageType> void set_response(const MessageType& msg) {
|
||||
response_size = message_20::serialize(msg, response);
|
||||
response_available = true;
|
||||
payload_type = message_20::PayloadTypeTrait<MessageType>::type;
|
||||
response_type = message_20::TypeTrait<MessageType>::type;
|
||||
response_message = msg;
|
||||
}
|
||||
|
||||
template <typename Msg> std::optional<Msg> get_response() {
|
||||
static_assert(message_20::TypeTrait<Msg>::type != message_20::Type::None, "Unhandled type!");
|
||||
if (message_20::TypeTrait<Msg>::type != response_type) {
|
||||
return std::nullopt;
|
||||
}
|
||||
try {
|
||||
return std::any_cast<Msg>(response_message);
|
||||
} catch (const std::bad_any_cast& ex) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<bool, size_t, io::v2gtp::PayloadType, message_20::Type> check_and_clear_response();
|
||||
bool has_response() const {
|
||||
return response_available;
|
||||
}
|
||||
|
||||
private:
|
||||
// input
|
||||
std::unique_ptr<message_20::Variant> request{nullptr};
|
||||
|
||||
// output
|
||||
const io::StreamOutputView response;
|
||||
size_t response_size{0};
|
||||
bool response_available{false};
|
||||
io::v2gtp::PayloadType payload_type;
|
||||
message_20::Type response_type;
|
||||
std::any response_message;
|
||||
};
|
||||
|
||||
std::unique_ptr<MessageExchange> create_message_exchange(uint8_t* buf, const size_t len);
|
||||
|
||||
struct StateBase;
|
||||
using BasePointerType = std::unique_ptr<StateBase>;
|
||||
|
||||
class Context {
|
||||
public:
|
||||
// FIXME (aw): bundle arguments
|
||||
Context(session::feedback::Callbacks, session::SessionLogger&, d20::SessionConfig, std::optional<PauseContext>&,
|
||||
const std::optional<ControlEvent>&, MessageExchange&, Timeouts&);
|
||||
|
||||
template <typename StateType, typename... Args> BasePointerType create_state(Args&&... args) {
|
||||
return std::make_unique<StateType>(*this, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
std::unique_ptr<message_20::Variant> pull_request();
|
||||
message_20::Type peek_request_type() const;
|
||||
|
||||
template <typename MessageType> void respond(const MessageType& msg) {
|
||||
message_exchange.set_response(msg);
|
||||
}
|
||||
|
||||
template <typename Msg> std::optional<Msg> get_response() {
|
||||
return message_exchange.get_response<Msg>();
|
||||
}
|
||||
|
||||
const auto& get_control_event() {
|
||||
return current_control_event;
|
||||
}
|
||||
|
||||
template <typename T> T const* get_control_event() {
|
||||
if (not current_control_event.has_value()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (not std::holds_alternative<T>(*current_control_event)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &std::get<T>(*current_control_event);
|
||||
}
|
||||
|
||||
void set_new_vehicle_cert_hash(std::optional<io::sha512_hash_t> hash) {
|
||||
vehicle_cert_hash = hash;
|
||||
}
|
||||
|
||||
auto get_new_vehicle_cert_hash() const {
|
||||
return vehicle_cert_hash;
|
||||
}
|
||||
|
||||
void start_timeout(d20::TimeoutType type, uint32_t time_ms) {
|
||||
timeouts.start_timeout(type, time_ms);
|
||||
}
|
||||
|
||||
void stop_timeout(d20::TimeoutType type) {
|
||||
timeouts.stop_timeout(type);
|
||||
}
|
||||
|
||||
d20::TimeoutType const* get_active_timeout() {
|
||||
if (not current_timeout.has_value()) {
|
||||
return nullptr;
|
||||
}
|
||||
return ¤t_timeout.value();
|
||||
}
|
||||
|
||||
void set_active_timeout(TimeoutType timeout) {
|
||||
current_timeout = timeout;
|
||||
}
|
||||
|
||||
const session::Feedback feedback;
|
||||
|
||||
session::SessionLogger& log;
|
||||
|
||||
Session session;
|
||||
|
||||
SessionConfig session_config;
|
||||
|
||||
// Contains the EV received data
|
||||
EVSessionInfo session_ev_info;
|
||||
EVInformation ev_info;
|
||||
|
||||
std::optional<d20::PauseContext>& pause_ctx;
|
||||
|
||||
bool session_stopped{false};
|
||||
bool session_paused{false};
|
||||
|
||||
std::optional<UpdateDynamicModeParameters> cache_dynamic_mode_parameters;
|
||||
std::optional<AcTargetPower> cache_ac_target_power;
|
||||
std::optional<AcPresentPower> cache_ac_present_power;
|
||||
|
||||
private:
|
||||
const std::optional<ControlEvent>& current_control_event;
|
||||
MessageExchange& message_exchange;
|
||||
|
||||
std::optional<io::sha512_hash_t> vehicle_cert_hash{std::nullopt};
|
||||
|
||||
Timeouts& timeouts;
|
||||
|
||||
std::optional<TimeoutType> current_timeout{std::nullopt};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,94 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include <iso15118/d20/ac_powers.hpp>
|
||||
#include <iso15118/d20/dynamic_mode_parameters.hpp>
|
||||
#include <iso15118/d20/limits.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
class CableCheckFinished {
|
||||
public:
|
||||
explicit CableCheckFinished(bool success_) : success(success_) {
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return success;
|
||||
}
|
||||
|
||||
private:
|
||||
bool success;
|
||||
};
|
||||
|
||||
struct PresentVoltageCurrent {
|
||||
float voltage;
|
||||
float current;
|
||||
};
|
||||
|
||||
class AuthorizationResponse {
|
||||
public:
|
||||
explicit AuthorizationResponse(bool authorized_) : authorized(authorized_) {
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return authorized;
|
||||
}
|
||||
|
||||
private:
|
||||
bool authorized;
|
||||
};
|
||||
|
||||
class StopCharging {
|
||||
public:
|
||||
explicit StopCharging(bool stop_) : stop(stop_) {
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return stop;
|
||||
}
|
||||
|
||||
private:
|
||||
bool stop;
|
||||
};
|
||||
|
||||
class PauseCharging {
|
||||
public:
|
||||
explicit PauseCharging(bool pause_) : pause(pause_) {
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return pause;
|
||||
}
|
||||
|
||||
private:
|
||||
bool pause;
|
||||
};
|
||||
|
||||
using EnergyServices = std::vector<message_20::datatypes::ServiceCategory>;
|
||||
|
||||
class ClosedContactor {
|
||||
public:
|
||||
explicit ClosedContactor(bool closed_) : closed(closed_) {
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return closed;
|
||||
}
|
||||
|
||||
private:
|
||||
bool closed;
|
||||
};
|
||||
|
||||
// TODO(SL): Define this globally for message and states
|
||||
using SupportedVASs = std::vector<uint16_t>;
|
||||
|
||||
using ControlEvent = std::variant<CableCheckFinished, PresentVoltageCurrent, AuthorizationResponse, StopCharging,
|
||||
PauseCharging, DcTransferLimits, AcTransferLimits, UpdateDynamicModeParameters,
|
||||
ClosedContactor, AcTargetPower, AcPresentPower, EnergyServices, SupportedVASs>;
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
|
||||
#include "control_event.hpp"
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
class ControlEventQueue {
|
||||
public:
|
||||
std::optional<ControlEvent> pop();
|
||||
void push(ControlEvent);
|
||||
|
||||
private:
|
||||
std::queue<ControlEvent> queue;
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <optional>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
struct UpdateDynamicModeParameters {
|
||||
std::optional<std::time_t> departure_time;
|
||||
std::optional<std::uint8_t> target_soc;
|
||||
std::optional<std::uint8_t> min_soc;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2025 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/message/supported_app_protocol.hpp>
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
using EVSupportedAppProtocols = everest::lib::util::fixed_vector<message_20::SupportedAppProtocol, 20>;
|
||||
|
||||
// Holds information about the EV
|
||||
struct EVInformation {
|
||||
EVSupportedAppProtocols ev_supported_app_protocols;
|
||||
message_20::SupportedAppProtocol selected_app_protocol;
|
||||
std::string evcc_id;
|
||||
std::optional<std::string> ev_tls_leaf_cert;
|
||||
std::optional<std::string> ev_tls_sub_ca_1_cert;
|
||||
std::optional<std::string> ev_tls_sub_ca_2_cert;
|
||||
std::optional<std::string> ev_tls_root_cert;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2025 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/message/common_types.hpp>
|
||||
#include <iso15118/session/feedback.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
// Holds information reported by the EV
|
||||
struct EVSessionInfo {
|
||||
session::feedback::EvTransferLimits ev_transfer_limits;
|
||||
session::feedback::EvSEControlMode ev_control_mode;
|
||||
std::vector<message_20::datatypes::ServiceCategory> ev_energy_services;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <iso15118/message/common_types.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
namespace dt = message_20::datatypes;
|
||||
|
||||
template <typename T> struct Limit {
|
||||
T max;
|
||||
T min;
|
||||
};
|
||||
|
||||
struct Limits {
|
||||
Limit<message_20::datatypes::RationalNumber> power;
|
||||
Limit<message_20::datatypes::RationalNumber> current;
|
||||
};
|
||||
|
||||
struct DcTransferLimits {
|
||||
Limits charge_limits;
|
||||
std::optional<Limits> discharge_limits;
|
||||
Limit<message_20::datatypes::RationalNumber> voltage;
|
||||
std::optional<message_20::datatypes::RationalNumber> power_ramp_limit;
|
||||
};
|
||||
|
||||
struct AcTransferLimits {
|
||||
Limit<dt::RationalNumber> charge_power;
|
||||
std::optional<Limit<dt::RationalNumber>> charge_power_L2;
|
||||
std::optional<Limit<dt::RationalNumber>> charge_power_L3;
|
||||
|
||||
dt::RationalNumber nominal_frequency;
|
||||
std::optional<dt::RationalNumber> max_power_asymmetry;
|
||||
std::optional<dt::RationalNumber> power_ramp_limitation;
|
||||
|
||||
std::optional<Limit<dt::RationalNumber>> discharge_power;
|
||||
std::optional<Limit<dt::RationalNumber>> discharge_power_L2;
|
||||
std::optional<Limit<dt::RationalNumber>> discharge_power_L3;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,152 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include <iso15118/io/sha_hash.hpp>
|
||||
#include <iso15118/message/common_types.hpp>
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
namespace dt = message_20::datatypes;
|
||||
|
||||
// Key: service IDs, value: vector with the parameter set ids
|
||||
using CustomVasList = std::map<std::uint16_t, std::vector<uint16_t>>;
|
||||
|
||||
struct OfferedServices {
|
||||
|
||||
everest::lib::util::fixed_vector<dt::Authorization, 2> auth_services;
|
||||
std::vector<dt::ServiceCategory> energy_services;
|
||||
std::vector<uint16_t> vas_services;
|
||||
|
||||
std::map<uint8_t, dt::AcParameterList> ac_parameter_list;
|
||||
std::map<uint8_t, dt::AcBptParameterList> ac_bpt_parameter_list;
|
||||
std::map<uint8_t, dt::DcParameterList> dc_parameter_list;
|
||||
std::map<uint8_t, dt::DcBptParameterList> dc_bpt_parameter_list;
|
||||
std::map<uint8_t, dt::McsParameterList> mcs_parameter_list;
|
||||
std::map<uint8_t, dt::McsBptParameterList> mcs_bpt_parameter_list;
|
||||
std::map<uint8_t, dt::InternetParameterList> internet_parameter_list;
|
||||
std::map<uint8_t, dt::ParkingParameterList> parking_parameter_list;
|
||||
CustomVasList custom_vas_list;
|
||||
};
|
||||
|
||||
struct SelectedServiceParameters {
|
||||
|
||||
dt::ServiceCategory selected_energy_service;
|
||||
|
||||
std::variant<dt::AcConnector, dt::DcConnector, dt::McsConnector> selected_connector;
|
||||
dt::ControlMode selected_control_mode;
|
||||
dt::MobilityNeedsMode selected_mobility_needs_mode;
|
||||
dt::Pricing selected_pricing;
|
||||
|
||||
// BPT
|
||||
std::optional<dt::BptChannel> selected_bpt_channel;
|
||||
std::optional<dt::GeneratorMode> selected_generator_mode;
|
||||
|
||||
// AC specific
|
||||
std::optional<float> evse_nominal_voltage;
|
||||
std::optional<dt::GridCodeIslandingDetectionMethod> selected_grid_code_method;
|
||||
|
||||
SelectedServiceParameters() = default;
|
||||
SelectedServiceParameters(dt::ServiceCategory energy_service_, dt::DcConnector dc_connector_,
|
||||
dt::ControlMode control_mode_, dt::MobilityNeedsMode mobility_, dt::Pricing pricing_);
|
||||
SelectedServiceParameters(dt::ServiceCategory energy_service_, dt::DcConnector dc_connector_,
|
||||
dt::ControlMode control_mode_, dt::MobilityNeedsMode mobility_, dt::Pricing pricing_,
|
||||
dt::BptChannel channel_, dt::GeneratorMode generator_);
|
||||
SelectedServiceParameters(dt::ServiceCategory energy_service_, dt::McsConnector mcs_connector_,
|
||||
dt::ControlMode control_mode_, dt::MobilityNeedsMode mobility_, dt::Pricing pricing_);
|
||||
SelectedServiceParameters(dt::ServiceCategory energy_service_, dt::McsConnector mcs_connector_,
|
||||
dt::ControlMode control_mode_, dt::MobilityNeedsMode mobility_, dt::Pricing pricing_,
|
||||
dt::BptChannel channel_, dt::GeneratorMode generator_);
|
||||
SelectedServiceParameters(dt::ServiceCategory energy_service_, dt::AcConnector ac_connector_,
|
||||
dt::ControlMode control_mode_, dt::MobilityNeedsMode mobility_, dt::Pricing pricing_,
|
||||
float nominal_voltage_);
|
||||
SelectedServiceParameters(dt::ServiceCategory energy_service_, dt::AcConnector ac_connector_,
|
||||
dt::ControlMode control_mode_, dt::MobilityNeedsMode mobility_, dt::Pricing pricing_,
|
||||
dt::BptChannel channel_, dt::GeneratorMode generator_, float nominal_voltage_,
|
||||
dt::GridCodeIslandingDetectionMethod grid_code_method_);
|
||||
};
|
||||
|
||||
// Todo(sl): missing services
|
||||
// WPT -> ControlMode, Pricing
|
||||
// DC_ACDP -> ControlMode, MobilityNeedsMode
|
||||
// DC_ACDP_BPT -> ControlMode, MobilityNeedsMode, BPTChannel
|
||||
|
||||
struct SelectedVasParameter {
|
||||
std::vector<dt::ServiceCategory> vas_services;
|
||||
|
||||
dt::Protocol internet_protocol;
|
||||
dt::Port internet_port;
|
||||
|
||||
dt::IntendedService parking_intended_service;
|
||||
dt::ParkingStatus parking_status;
|
||||
};
|
||||
|
||||
// TODO(SL): How to handle d2 pause? Move Struct to a seperate header file?
|
||||
// TODO(SL): Missing handling scheduletuple in schedule mode [V2G20-1058]
|
||||
struct PauseContext {
|
||||
io::sha512_hash_t vehicle_cert_session_id_hash{};
|
||||
std::array<uint8_t, 8> old_session_id{};
|
||||
SelectedServiceParameters selected_service_parameters{};
|
||||
};
|
||||
|
||||
class Session {
|
||||
|
||||
// TODO(sl): move to a common defs file
|
||||
static constexpr auto ID_LENGTH = 8;
|
||||
|
||||
public:
|
||||
Session();
|
||||
Session(const PauseContext& pause_ctx);
|
||||
Session(SelectedServiceParameters);
|
||||
Session(OfferedServices);
|
||||
|
||||
std::array<uint8_t, ID_LENGTH> get_id() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
bool find_energy_parameter_set_id(const dt::ServiceCategory service, int16_t id);
|
||||
bool find_vas_parameter_set_id(const uint16_t vas_service, int16_t id);
|
||||
|
||||
void selected_service_parameters(const dt::ServiceCategory service, const uint16_t id);
|
||||
void selected_service_parameters(const uint16_t vas_service, const uint16_t id);
|
||||
|
||||
auto get_selected_services() const& {
|
||||
return selected_services;
|
||||
}
|
||||
|
||||
bool is_ac_charger() const {
|
||||
return selected_services.selected_energy_service == dt::ServiceCategory::AC or
|
||||
selected_services.selected_energy_service == dt::ServiceCategory::AC_BPT;
|
||||
}
|
||||
|
||||
bool is_dc_charger() const {
|
||||
return selected_services.selected_energy_service == dt::ServiceCategory::DC or
|
||||
selected_services.selected_energy_service == dt::ServiceCategory::DC_BPT or
|
||||
selected_services.selected_energy_service == dt::ServiceCategory::MCS or
|
||||
selected_services.selected_energy_service == dt::ServiceCategory::MCS_BPT;
|
||||
}
|
||||
|
||||
~Session();
|
||||
|
||||
OfferedServices offered_services;
|
||||
|
||||
bool service_renegotiation_supported{false};
|
||||
|
||||
private:
|
||||
// NOTE (aw): could be const
|
||||
std::array<uint8_t, ID_LENGTH> id{};
|
||||
|
||||
SelectedServiceParameters selected_services{};
|
||||
SelectedVasParameter selected_vas_services{};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,31 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2025 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
#include <iso15118/d20/ac_powers.hpp>
|
||||
#include <iso15118/d20/dynamic_mode_parameters.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
struct AC_ChargeLoop : public StateBase {
|
||||
AC_ChargeLoop(Context& ctx) : StateBase(ctx, StateID::AC_ChargeLoop) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
float target_frequency{0};
|
||||
bool stop{false};
|
||||
bool pause{false};
|
||||
|
||||
UpdateDynamicModeParameters dynamic_parameters{};
|
||||
AcTargetPower target_powers{};
|
||||
AcPresentPower present_powers{};
|
||||
|
||||
bool first_entry_in_charge_loop{false};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
#include <iso15118/d20/ac_powers.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
struct AC_ChargeParameterDiscovery : public StateBase {
|
||||
AC_ChargeParameterDiscovery(Context& ctx) : StateBase(ctx, StateID::AC_ChargeParameterDiscovery) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
AcPresentPower present_powers;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
#include <iso15118/message/authorization.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
struct Authorization : public StateBase {
|
||||
public:
|
||||
Authorization(Context& ctx) : StateBase(ctx, StateID::Authorization){};
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
message_20::datatypes::AuthStatus authorization_status{message_20::datatypes::AuthStatus::Pending};
|
||||
bool first_req_msg{true};
|
||||
bool timeout_ongoing_reached{false};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct AuthorizationSetup : public StateBase {
|
||||
AuthorizationSetup(Context& ctx) : StateBase(ctx, StateID::AuthorizationSetup) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct DC_CableCheck : public StateBase {
|
||||
DC_CableCheck(Context& ctx) : StateBase(ctx, StateID::DC_CableCheck) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
bool cable_check_initiated{false};
|
||||
bool cable_check_done{false};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
#include <iso15118/d20/dynamic_mode_parameters.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct DC_ChargeLoop : public StateBase {
|
||||
DC_ChargeLoop(Context& ctx) : StateBase(ctx, StateID::DC_ChargeLoop) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
float present_voltage{0};
|
||||
float present_current{0};
|
||||
bool stop{false};
|
||||
bool pause{false};
|
||||
|
||||
UpdateDynamicModeParameters dynamic_parameters;
|
||||
|
||||
bool first_entry_in_charge_loop{true};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct DC_ChargeParameterDiscovery : public StateBase {
|
||||
DC_ChargeParameterDiscovery(Context& ctx) : StateBase(ctx, StateID::DC_ChargeParameterDiscovery) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct DC_PreCharge : public StateBase {
|
||||
DC_PreCharge(Context& ctx) : StateBase(ctx, StateID::DC_PreCharge) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
bool pre_charge_initiated{false};
|
||||
float present_voltage{0};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct DC_WeldingDetection : public StateBase {
|
||||
DC_WeldingDetection(Context& ctx) : StateBase(ctx, StateID::DC_WeldingDetection) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
float present_voltage{0};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
#include <iso15118/message/power_delivery.hpp>
|
||||
#include <optional>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
struct PowerDelivery : public StateBase {
|
||||
PowerDelivery(Context& ctx) : StateBase(ctx, StateID::PowerDelivery) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
float present_voltage{0};
|
||||
bool ac_connector_closed{false};
|
||||
std::optional<message_20::PowerDeliveryRequest> previous_req;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
#include <iso15118/d20/dynamic_mode_parameters.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
struct ScheduleExchange : public StateBase {
|
||||
ScheduleExchange(Context& ctx) : StateBase(ctx, StateID::ScheduleExchange) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
UpdateDynamicModeParameters dynamic_parameters;
|
||||
bool first_req_msg{true};
|
||||
bool timeout_ongoing_reached{false};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct ServiceDetail : public StateBase {
|
||||
public:
|
||||
ServiceDetail(Context& ctx) : StateBase(ctx, StateID::ServiceDetail) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct ServiceDiscovery : public StateBase {
|
||||
public:
|
||||
ServiceDiscovery(Context& ctx) : StateBase(ctx, StateID::ServiceDiscovery) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct ServiceSelection : public StateBase {
|
||||
ServiceSelection(Context& ctx) : StateBase(ctx, StateID::ServiceSelection) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct SessionSetup : public StateBase {
|
||||
SessionSetup(Context& ctx) : StateBase(ctx, StateID::SessionSetup) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
std::string evse_id;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct SessionStop : public StateBase {
|
||||
SessionStop(Context& ctx) : StateBase(ctx, StateID::SessionStop) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct SupportedAppProtocol : public StateBase {
|
||||
public:
|
||||
SupportedAppProtocol(Context& ctx) : StateBase(ctx, StateID::SupportedAppProtocol) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,73 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
class Context;
|
||||
|
||||
enum class Event {
|
||||
RESET,
|
||||
V2GTP_MESSAGE,
|
||||
CONTROL_MESSAGE,
|
||||
TIMEOUT,
|
||||
|
||||
// internal events
|
||||
FAILED,
|
||||
};
|
||||
|
||||
enum class StateID {
|
||||
SupportedAppProtocol,
|
||||
SessionSetup,
|
||||
AuthorizationSetup,
|
||||
Authorization,
|
||||
ServiceDetail,
|
||||
ServiceDiscovery,
|
||||
ServiceSelection,
|
||||
AC_ChargeParameterDiscovery,
|
||||
AC_ChargeLoop,
|
||||
DC_ChargeParameterDiscovery,
|
||||
DC_PreCharge,
|
||||
DC_ChargeLoop,
|
||||
DC_WeldingDetection,
|
||||
DC_CableCheck,
|
||||
PowerDelivery,
|
||||
ScheduleExchange,
|
||||
SessionStop
|
||||
};
|
||||
|
||||
struct Result {
|
||||
constexpr Result() = default;
|
||||
Result(BasePointerType result_state) : unhandled(false), new_state(std::move(result_state)) {
|
||||
}
|
||||
|
||||
bool unhandled{true};
|
||||
BasePointerType new_state{nullptr};
|
||||
};
|
||||
|
||||
struct StateBase {
|
||||
using ContainerType = BasePointerType;
|
||||
using EventType = Event;
|
||||
|
||||
StateBase(Context& ctx, StateID id) : m_ctx(ctx), m_id(id){};
|
||||
|
||||
virtual ~StateBase() = default;
|
||||
|
||||
StateID get_id() const {
|
||||
return m_id;
|
||||
}
|
||||
|
||||
virtual void enter(){};
|
||||
virtual Result feed(Event) = 0;
|
||||
virtual void leave(){};
|
||||
|
||||
protected:
|
||||
Context& m_ctx;
|
||||
|
||||
private:
|
||||
StateID m_id;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2025 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include <iso15118/io/time.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
template <typename T> constexpr auto to_underlying_value(T t) {
|
||||
return static_cast<std::underlying_type_t<T>>(t);
|
||||
}
|
||||
|
||||
enum class TimeoutType : uint8_t {
|
||||
SEQUENCE = 0,
|
||||
PERFORMANCE,
|
||||
ONGOING,
|
||||
CONTACTOR,
|
||||
};
|
||||
|
||||
constexpr uint8_t TIMEOUT_TYPE_SIZE = 4;
|
||||
|
||||
static_assert(TIMEOUT_TYPE_SIZE == to_underlying_value(TimeoutType::CONTACTOR) + 1,
|
||||
"TIMEOUT_TYPE_SIZE should be in sync with the TimeoutType enum definition");
|
||||
|
||||
constexpr auto TIMEOUT_ONGOING = 1000 * 55;
|
||||
constexpr auto TIMEOUT_SEQUENCE = 1000 * 60;
|
||||
constexpr auto TIMEOUT_EIM_ONGOING = 1000 * 60 * 3;
|
||||
|
||||
class Timeouts {
|
||||
public:
|
||||
explicit Timeouts() = default;
|
||||
~Timeouts() = default;
|
||||
|
||||
void start_timeout(TimeoutType type, uint32_t timeout_ms);
|
||||
void stop_timeout(TimeoutType type);
|
||||
void reset_timeout(TimeoutType type);
|
||||
std::optional<std::vector<TimeoutType>> check();
|
||||
|
||||
private:
|
||||
std::array<std::optional<Timeout>, TIMEOUT_TYPE_SIZE> timeouts;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,99 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cbv2g/common/exi_bitstream.h>
|
||||
|
||||
#include <iso15118/io/stream_view.hpp>
|
||||
|
||||
#define CB2CPP_STRING(property) (std::string(property.characters, property.charactersLen))
|
||||
|
||||
#define CPP2CB_STRING(in, out) \
|
||||
if (in.length() > sizeof(out.characters)) { \
|
||||
throw std::runtime_error("String too long"); \
|
||||
} \
|
||||
in.copy(out.characters, in.length()); \
|
||||
out.charactersLen = in.length()
|
||||
|
||||
#define CPP2CB_BYTES(in, out) \
|
||||
if (in.size() > sizeof(out.bytes)) { \
|
||||
throw std::runtime_error("Byte vector too long"); \
|
||||
} \
|
||||
std::copy(in.begin(), in.end(), out.bytes); \
|
||||
out.bytesLen = in.size()
|
||||
|
||||
#define CB2CPP_BYTES(in, out) \
|
||||
if (in.bytesLen > out.size()) { \
|
||||
throw std::runtime_error("Byte array too long"); \
|
||||
} \
|
||||
std::copy(std::begin(in.bytes), std::end(in.bytes), out.begin());
|
||||
|
||||
#define CB_SET_USED(property) (property##_isUsed = 1)
|
||||
#define CB2CPP_ASSIGN_IF_USED(in, out) \
|
||||
if (in##_isUsed) { \
|
||||
out = in; \
|
||||
}
|
||||
|
||||
#define CPP2CB_ASSIGN_IF_USED(in, out) \
|
||||
if (in) { \
|
||||
out = in.value(); \
|
||||
} \
|
||||
\
|
||||
out##_isUsed = static_cast<bool>(in);
|
||||
|
||||
#define CB2CPP_CONVERT_IF_USED(in, out) \
|
||||
if (in##_isUsed) { \
|
||||
convert(in, out.emplace()); \
|
||||
}
|
||||
|
||||
#define CPP2CB_CONVERT_IF_USED(in, out) \
|
||||
if (in) { \
|
||||
convert(in.value(), out); \
|
||||
} \
|
||||
\
|
||||
out##_isUsed = static_cast<bool>(in);
|
||||
|
||||
#define CPP2CB_STRING_IF_USED(in, out) \
|
||||
if (in) { \
|
||||
CPP2CB_STRING(in.value(), out); \
|
||||
} \
|
||||
\
|
||||
out##_isUsed = static_cast<bool>(in);
|
||||
|
||||
#define CB2CPP_STRING_IF_USED(in, out) \
|
||||
if (in##_isUsed) { \
|
||||
out = CB2CPP_STRING(in); \
|
||||
}
|
||||
|
||||
#define CB2CPP_BYTES_IF_USED(in, out) \
|
||||
if (in##_isUsed) { \
|
||||
CB2CPP_BYTES(in, out.emplace()); \
|
||||
}
|
||||
|
||||
template <typename T1, typename T2> void cb_convert_enum(const T1& in, T2& out) {
|
||||
out = static_cast<T2>(in);
|
||||
}
|
||||
|
||||
exi_bitstream_t get_exi_input_stream(const iso15118::io::StreamInputView&);
|
||||
exi_bitstream_t get_exi_output_stream(const iso15118::io::StreamOutputView&);
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
template <typename MessageType> int serialize_to_exi(const MessageType& in, exi_bitstream_t& out);
|
||||
|
||||
template <typename MessageType>
|
||||
size_t serialize_helper(const MessageType& in, const io::StreamOutputView& stream_view) {
|
||||
auto out = get_exi_output_stream(stream_view);
|
||||
|
||||
const auto error = serialize_to_exi(in, out);
|
||||
|
||||
if (error != 0) {
|
||||
throw std::runtime_error("Could not encode exi: " + std::to_string(error));
|
||||
}
|
||||
|
||||
return exi_bitstream_get_length(&out);
|
||||
}
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/context.hpp>
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/common_types.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
// FIXME (aw): not sure about correct signature here for RVO
|
||||
template <typename Response, typename ResponseCode> Response& response_with_code(Response& res, ResponseCode code) {
|
||||
// FIXME (aw): could add an static_assert here that ResponseCode is an enum?
|
||||
res.response_code = code;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool validate_and_setup_header(message_20::Header&, const Session&, const decltype(message_20::Header::session_id)&);
|
||||
|
||||
void setup_header(message_20::Header&, const Session&);
|
||||
|
||||
void send_sequence_error(const message_20::Type, d20::Context&);
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 205 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/ac_charge_loop.hpp>
|
||||
|
||||
#include <iso15118/d20/ac_powers.hpp>
|
||||
#include <iso15118/d20/dynamic_mode_parameters.hpp>
|
||||
#include <iso15118/d20/limits.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::AC_ChargeLoopResponse handle_request(const message_20::AC_ChargeLoopRequest& req,
|
||||
const d20::Session& session, bool stop, bool pause,
|
||||
float target_frequency, const AcTargetPower& target_powers,
|
||||
const AcPresentPower& present_powers,
|
||||
const UpdateDynamicModeParameters& dynamic_parameters);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/ac_powers.hpp>
|
||||
#include <iso15118/d20/config.hpp>
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/ac_charge_parameter_discovery.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::AC_ChargeParameterDiscoveryResponse
|
||||
handle_request(const message_20::AC_ChargeParameterDiscoveryRequest& req, const d20::Session& session,
|
||||
const d20::AcTransferLimits& limits, const d20::AcPresentPower& powers);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/authorization.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::AuthorizationResponse handle_request(const message_20::AuthorizationRequest& req,
|
||||
const d20::Session& session,
|
||||
const message_20::datatypes::AuthStatus& authorization_status,
|
||||
bool timeout_reached);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/config.hpp>
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/authorization_setup.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::AuthorizationSetupResponse
|
||||
handle_request(const message_20::AuthorizationSetupRequest& req, d20::Session& session, bool cert_install_service,
|
||||
const std::vector<message_20::datatypes::Authorization>& authorization_services);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/dc_cable_check.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::DC_CableCheckResponse handle_request(const message_20::DC_CableCheckRequest& req,
|
||||
const d20::Session& session, bool cable_check_done);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,26 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
#include <variant>
|
||||
|
||||
#include <iso15118/d20/dynamic_mode_parameters.hpp>
|
||||
#include <iso15118/d20/limits.hpp>
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/dc_charge_loop.hpp>
|
||||
|
||||
#include <iso15118/session/feedback.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::DC_ChargeLoopResponse handle_request(const message_20::DC_ChargeLoopRequest& req,
|
||||
const d20::Session& session, const float present_voltage,
|
||||
const float present_current, const bool stop, const bool pause,
|
||||
const DcTransferLimits& dc_limits,
|
||||
const UpdateDynamicModeParameters& dynamic_parameters);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/config.hpp>
|
||||
#include <iso15118/d20/limits.hpp>
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/dc_charge_parameter_discovery.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::DC_ChargeParameterDiscoveryResponse
|
||||
handle_request(const message_20::DC_ChargeParameterDiscoveryRequest& req, const d20::Session& session,
|
||||
const d20::DcTransferLimits& dc_limits);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/dc_pre_charge.hpp>
|
||||
|
||||
#include <iso15118/session/feedback.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::DC_PreChargeResponse handle_request(const message_20::DC_PreChargeRequest& req, const d20::Session& session,
|
||||
const float present_voltage);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/dc_welding_detection.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::DC_WeldingDetectionResponse handle_request(const message_20::DC_WeldingDetectionRequest& req,
|
||||
const d20::Session& session, const float present_voltage);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/power_delivery.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::PowerDeliveryResponse handle_request(const message_20::PowerDeliveryRequest& req,
|
||||
const d20::Session& session, bool contactor_error);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/schedule_exchange.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <optional>
|
||||
|
||||
#include <iso15118/d20/dynamic_mode_parameters.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::ScheduleExchangeResponse handle_request(const message_20::ScheduleExchangeRequest& req,
|
||||
const d20::Session& session,
|
||||
const message_20::datatypes::RationalNumber& max_power,
|
||||
const UpdateDynamicModeParameters& dynamic_parameters,
|
||||
bool timeout_reached);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/config.hpp>
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/service_detail.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::ServiceDetailResponse handle_request(const message_20::ServiceDetailRequest& req, d20::Session& session,
|
||||
const d20::SessionConfig& config,
|
||||
const std::optional<dt::ServiceParameterList>& custom_vas_parameters);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <iso15118/d20/config.hpp>
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/common_types.hpp>
|
||||
#include <iso15118/message/service_discovery.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::ServiceDiscoveryResponse
|
||||
handle_request(const message_20::ServiceDiscoveryRequest& req, d20::Session& session,
|
||||
const std::vector<message_20::datatypes::ServiceCategory>& energy_services,
|
||||
const std::vector<uint16_t>& vas_services,
|
||||
std::vector<message_20::datatypes::ServiceCategory>& ev_energy_services);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/config.hpp>
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/service_selection.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::ServiceSelectionResponse handle_request(const message_20::ServiceSelectionRequest& req,
|
||||
d20::Session& session);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/session_setup.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::SessionSetupResponse handle_request(const message_20::SessionSetupRequest& req, const d20::Session& session,
|
||||
const std::string& evse_id, bool new_session);
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/session_stop.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::SessionStopResponse handle_request(const message_20::SessionStopRequest& req, const d20::Session& session);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/io/log_levels.hpp>
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace iso15118 {
|
||||
|
||||
void logf(const char* fmt, ...);
|
||||
void logf(const LogLevel&, const char* fmt, ...);
|
||||
|
||||
void logf_error(const char* fmt, ...);
|
||||
void logf_warning(const char* fmt, ...);
|
||||
void logf_info(const char* fmt, ...);
|
||||
void logf_debug(const char* fmt, ...);
|
||||
void logf_trace(const char* fmt, ...);
|
||||
|
||||
void vlogf(const char* fmt, va_list ap);
|
||||
void vlogf(const LogLevel&, const char* fmt, va_list ap);
|
||||
|
||||
void log(const LogLevel&, const std::string&);
|
||||
|
||||
void log_and_throw(const char* msg);
|
||||
|
||||
std::string adding_err_msg(const std::string& msg);
|
||||
|
||||
template <typename CallbackType, typename... Args> bool call_if_available(const CallbackType& callback, Args... args) {
|
||||
if (not callback) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::invoke(callback, std::forward<Args>(args)...);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Note(sl): Copied from https://en.cppreference.com/w/cpp/utility/intcmp because libiso15118 uses C++17
|
||||
template <class T, class U> constexpr bool cmp_equal(T t, U u) noexcept {
|
||||
if constexpr (std::is_signed_v<T> == std::is_signed_v<U>)
|
||||
return t == u;
|
||||
else if constexpr (std::is_signed_v<T>)
|
||||
return t >= 0 && std::make_unsigned_t<T>(t) == u;
|
||||
else
|
||||
return u >= 0 && std::make_unsigned_t<U>(u) == t;
|
||||
}
|
||||
|
||||
} // namespace iso15118
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
std::string log_openssl_error(const std::string& error_msg);
|
||||
void log_and_raise_openssl_error(const std::string& error_msg);
|
||||
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
bool check_and_update_interface(std::string& interface_name);
|
||||
|
||||
bool get_first_sockaddr_in6_for_interface(const std::string& interface_name, sockaddr_in6& address);
|
||||
|
||||
std::unique_ptr<char[]> sockaddr_in6_to_name(const sockaddr_in6&);
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,36 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include "cb_exi.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
struct VariantAccess {
|
||||
// input
|
||||
exi_bitstream_t input_stream;
|
||||
|
||||
// output
|
||||
void*& data;
|
||||
iso15118::message_20::Type& type;
|
||||
iso15118::message_20::Variant::CustomDeleter& custom_deleter;
|
||||
std::string& error;
|
||||
|
||||
template <typename MessageType, typename CbExiMessageType> void insert_type(const CbExiMessageType& in) {
|
||||
assert(data == nullptr);
|
||||
|
||||
data = new MessageType;
|
||||
type = iso15118::message_20::TypeTrait<MessageType>::type;
|
||||
custom_deleter = [](void* ptr) { delete static_cast<MessageType*>(ptr); };
|
||||
|
||||
convert(in, *static_cast<MessageType*>(data));
|
||||
};
|
||||
};
|
||||
|
||||
template <typename CbExiMessageType> void insert_type(VariantAccess& va, const CbExiMessageType&);
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,43 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
#include "ipv6_endpoint.hpp"
|
||||
|
||||
#include <iso15118/io/sha_hash.hpp>
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
enum class ConnectionEvent {
|
||||
ACCEPTED,
|
||||
OPEN,
|
||||
NEW_DATA,
|
||||
CLOSED,
|
||||
};
|
||||
|
||||
using ConnectionEventCallback = std::function<void(ConnectionEvent)>;
|
||||
|
||||
struct ReadResult {
|
||||
bool would_block{true};
|
||||
size_t bytes_read{0};
|
||||
};
|
||||
|
||||
struct IConnection {
|
||||
virtual void set_event_callback(const ConnectionEventCallback&) = 0;
|
||||
|
||||
virtual Ipv6EndPoint get_public_endpoint() const = 0;
|
||||
|
||||
virtual void write(const uint8_t* buf, size_t len) = 0;
|
||||
virtual ReadResult read(uint8_t* buf, size_t len) = 0;
|
||||
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual std::optional<sha512_hash_t> get_vehicle_cert_hash() const = 0;
|
||||
|
||||
virtual ~IConnection() = default;
|
||||
};
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "connection_abstract.hpp"
|
||||
|
||||
#include <iso15118/config.hpp>
|
||||
#include <iso15118/io/poll_manager.hpp>
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
class ConnectionPlain : public IConnection {
|
||||
public:
|
||||
ConnectionPlain(PollManager&, const std::string& interface_name);
|
||||
|
||||
void set_event_callback(const ConnectionEventCallback&) final;
|
||||
Ipv6EndPoint get_public_endpoint() const final;
|
||||
|
||||
void write(const uint8_t* buf, size_t len) final;
|
||||
ReadResult read(uint8_t* buf, size_t len) final;
|
||||
|
||||
void close() final;
|
||||
|
||||
std::optional<sha512_hash_t> get_vehicle_cert_hash() const final {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
~ConnectionPlain();
|
||||
|
||||
private:
|
||||
PollManager& poll_manager;
|
||||
|
||||
Ipv6EndPoint end_point;
|
||||
|
||||
int fd{-1};
|
||||
|
||||
bool connection_open{false};
|
||||
|
||||
ConnectionEventCallback event_callback{nullptr};
|
||||
|
||||
void handle_connect();
|
||||
void handle_data();
|
||||
};
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,46 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
#include "connection_abstract.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <iso15118/config.hpp>
|
||||
#include <iso15118/io/poll_manager.hpp>
|
||||
#include <iso15118/io/sha_hash.hpp>
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
// forward declaration
|
||||
struct SSLContext;
|
||||
class ConnectionSSL : public IConnection {
|
||||
public:
|
||||
ConnectionSSL(PollManager&, const std::string& interface_name, const config::SSLConfig&);
|
||||
|
||||
void set_event_callback(const ConnectionEventCallback&) final;
|
||||
Ipv6EndPoint get_public_endpoint() const final;
|
||||
|
||||
void write(const uint8_t* buf, size_t len) final;
|
||||
ReadResult read(uint8_t* buf, size_t len) final;
|
||||
|
||||
void close() final;
|
||||
|
||||
std::optional<sha512_hash_t> get_vehicle_cert_hash() const final;
|
||||
|
||||
~ConnectionSSL();
|
||||
|
||||
private:
|
||||
PollManager& poll_manager;
|
||||
std::unique_ptr<SSLContext> ssl;
|
||||
|
||||
Ipv6EndPoint end_point;
|
||||
|
||||
ConnectionEventCallback event_callback{nullptr};
|
||||
|
||||
bool handshake_complete{false};
|
||||
|
||||
void handle_connect();
|
||||
void handle_data();
|
||||
};
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
struct Ipv6EndPoint {
|
||||
uint16_t port;
|
||||
uint16_t address[8];
|
||||
};
|
||||
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
namespace iso15118 {
|
||||
|
||||
enum class LogLevel {
|
||||
Error,
|
||||
Warning,
|
||||
Info,
|
||||
Debug,
|
||||
Trace,
|
||||
};
|
||||
|
||||
} // namespace iso15118
|
||||
@@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "log_levels.hpp"
|
||||
|
||||
namespace iso15118::io {
|
||||
void set_logging_callback(const std::function<void(LogLevel, std::string)>&);
|
||||
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,36 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <poll.h>
|
||||
namespace iso15118::io {
|
||||
|
||||
using PollCallback = const std::function<void()>;
|
||||
struct PollSet {
|
||||
std::vector<struct pollfd> fds;
|
||||
std::vector<PollCallback*> callbacks;
|
||||
};
|
||||
|
||||
class PollManager {
|
||||
public:
|
||||
PollManager();
|
||||
|
||||
void register_fd(int fd, PollCallback& poll_callback);
|
||||
void unregister_fd(int fd);
|
||||
|
||||
void poll(int timeout_ms);
|
||||
void abort();
|
||||
|
||||
private:
|
||||
std::map<int, PollCallback> registered_fds;
|
||||
|
||||
PollSet poll_set;
|
||||
|
||||
int event_fd{-1};
|
||||
};
|
||||
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace iso15118::io::v2gtp {
|
||||
enum class Security : uint8_t {
|
||||
TLS = 0x00,
|
||||
NO_TRANSPORT_SECURITY = 0x10,
|
||||
};
|
||||
|
||||
enum class TransportProtocol : uint8_t {
|
||||
TCP = 0x00,
|
||||
RESERVED_FOR_UDP = 0x10,
|
||||
};
|
||||
|
||||
static constexpr auto SDP_SERVER_PORT = 15118;
|
||||
|
||||
enum class PayloadType : uint16_t {
|
||||
SAP = 0x8001,
|
||||
Part20Main = 0x8002,
|
||||
Part20AC = 0x8003,
|
||||
Part20DC = 0x8004,
|
||||
};
|
||||
|
||||
} // namespace iso15118::io::v2gtp
|
||||
@@ -0,0 +1,73 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "sdp.hpp"
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
// FIXME (aw): these shouldn't be necessary public - but nice to have
|
||||
static constexpr uint8_t SDP_PROTOCOL_VERSION = 0x01;
|
||||
static constexpr uint8_t SDP_INVERSE_PROTOCOL_VERSION = 0xFE;
|
||||
|
||||
// FIXME (aw): should be called V2GTP or SDP buffer
|
||||
class SdpPacket {
|
||||
public:
|
||||
static constexpr auto V2GTP_HEADER_SIZE = 8;
|
||||
enum class State {
|
||||
BUFFER_EMPTY,
|
||||
HEADER_READ,
|
||||
COMPLETE,
|
||||
|
||||
// failed states
|
||||
INVALID_HEADER,
|
||||
PAYLOAD_TOO_LONG,
|
||||
};
|
||||
|
||||
auto get_state() const {
|
||||
return state;
|
||||
}
|
||||
|
||||
auto is_complete() const {
|
||||
return state == State::COMPLETE;
|
||||
}
|
||||
|
||||
auto get_payload_length() const {
|
||||
return (state == State::COMPLETE) ? (length - V2GTP_HEADER_SIZE) : 0;
|
||||
}
|
||||
|
||||
v2gtp::PayloadType get_payload_type() const;
|
||||
|
||||
uint8_t const* get_payload_buffer() const {
|
||||
return buffer + V2GTP_HEADER_SIZE;
|
||||
}
|
||||
|
||||
uint8_t const* get_buffer() const {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
uint8_t* get_current_buffer_pos() {
|
||||
return buffer + bytes_read;
|
||||
}
|
||||
|
||||
size_t get_remaining_buffer_capacity() const {
|
||||
return sizeof(buffer) - bytes_read;
|
||||
}
|
||||
|
||||
size_t get_remaining_bytes_to_read() const;
|
||||
|
||||
void update_read_bytes(size_t len);
|
||||
|
||||
private:
|
||||
void parse_header();
|
||||
|
||||
State state{State::BUFFER_EMPTY};
|
||||
uint8_t buffer[2048];
|
||||
size_t bytes_read{0};
|
||||
size_t length; // length includes V2GTP_HEADER_SIZE
|
||||
};
|
||||
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,71 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "ipv6_endpoint.hpp"
|
||||
#include "sdp.hpp"
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
struct PeerRequestContext {
|
||||
explicit PeerRequestContext(bool valid_) : valid(valid_){};
|
||||
v2gtp::Security security;
|
||||
v2gtp::TransportProtocol transport_protocol;
|
||||
struct sockaddr_in6 address;
|
||||
|
||||
operator bool() const {
|
||||
return valid;
|
||||
}
|
||||
|
||||
private:
|
||||
const bool valid;
|
||||
};
|
||||
|
||||
class SdpServer {
|
||||
public:
|
||||
explicit SdpServer(const std::string& interface_name);
|
||||
~SdpServer();
|
||||
PeerRequestContext get_peer_request();
|
||||
void send_response(const PeerRequestContext&, const Ipv6EndPoint&);
|
||||
|
||||
auto get_fd() const {
|
||||
return fd;
|
||||
}
|
||||
|
||||
void set_dlink_ready(bool ready);
|
||||
bool is_dlink_ready() const;
|
||||
|
||||
private:
|
||||
int fd{-1};
|
||||
uint8_t udp_buffer[2048];
|
||||
std::atomic<bool> dlink_ready_{false};
|
||||
};
|
||||
|
||||
class TlsKeyLoggingServer {
|
||||
public:
|
||||
TlsKeyLoggingServer(const std::string& interface_name, uint16_t port);
|
||||
~TlsKeyLoggingServer();
|
||||
|
||||
ssize_t send(const char* line);
|
||||
|
||||
auto get_fd() const {
|
||||
return fd;
|
||||
}
|
||||
|
||||
auto get_port() const {
|
||||
return port;
|
||||
}
|
||||
|
||||
private:
|
||||
int fd{-1};
|
||||
uint16_t port{0};
|
||||
sockaddr_in6 destination_address{};
|
||||
};
|
||||
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
constexpr std::size_t sha_512_hash_size = 64;
|
||||
using sha512_hash_t = std::array<uint8_t, sha_512_hash_size>;
|
||||
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
struct StreamInputView {
|
||||
uint8_t const* payload;
|
||||
size_t payload_len;
|
||||
};
|
||||
|
||||
struct StreamOutputView {
|
||||
uint8_t* payload;
|
||||
size_t payload_len;
|
||||
|
||||
operator StreamInputView() const {
|
||||
return {payload, payload_len};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,51 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace iso15118 {
|
||||
|
||||
using TimePoint = std::chrono::steady_clock::time_point;
|
||||
|
||||
inline TimePoint get_current_time_point() {
|
||||
return std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
inline TimePoint offset_time_point_by_ms(const TimePoint& time_point, int32_t offset) {
|
||||
return time_point + std::chrono::milliseconds(offset);
|
||||
}
|
||||
|
||||
inline int32_t get_timeout_ms_until(const TimePoint& until, int32_t max_timeout_ms) {
|
||||
const auto duration =
|
||||
std::chrono::duration_cast<std::chrono::duration<int32_t, std::milli>>(until - get_current_time_point());
|
||||
const auto timeout_ms = duration.count();
|
||||
|
||||
// if the timeout is already reached, return 0 to trigger an immediate timeout event
|
||||
if (timeout_ms <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return timeout_ms < max_timeout_ms ? timeout_ms : max_timeout_ms;
|
||||
}
|
||||
|
||||
class Timeout {
|
||||
public:
|
||||
explicit Timeout(uint32_t timeout_ms) {
|
||||
timeout_point = get_current_time_point() + std::chrono::milliseconds(timeout_ms);
|
||||
};
|
||||
~Timeout() = default;
|
||||
|
||||
bool is_reached() {
|
||||
return get_current_time_point() >= timeout_point;
|
||||
}
|
||||
|
||||
TimePoint get_timeout_point() const {
|
||||
return timeout_point;
|
||||
}
|
||||
|
||||
private:
|
||||
TimePoint timeout_point{};
|
||||
};
|
||||
|
||||
} // namespace iso15118
|
||||
@@ -0,0 +1,122 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
struct Scheduled_AC_CLReqControlMode : Scheduled_CLReqControlMode {
|
||||
std::optional<RationalNumber> max_charge_power;
|
||||
std::optional<RationalNumber> max_charge_power_L2;
|
||||
std::optional<RationalNumber> max_charge_power_L3;
|
||||
std::optional<RationalNumber> min_charge_power;
|
||||
std::optional<RationalNumber> min_charge_power_L2;
|
||||
std::optional<RationalNumber> min_charge_power_L3;
|
||||
RationalNumber present_active_power;
|
||||
std::optional<RationalNumber> present_active_power_L2;
|
||||
std::optional<RationalNumber> present_active_power_L3;
|
||||
std::optional<RationalNumber> present_reactive_power;
|
||||
std::optional<RationalNumber> present_reactive_power_L2;
|
||||
std::optional<RationalNumber> present_reactive_power_L3;
|
||||
};
|
||||
|
||||
struct BPT_Scheduled_AC_CLReqControlMode : Scheduled_AC_CLReqControlMode {
|
||||
std::optional<RationalNumber> max_discharge_power;
|
||||
std::optional<RationalNumber> max_discharge_power_L2;
|
||||
std::optional<RationalNumber> max_discharge_power_L3;
|
||||
std::optional<RationalNumber> min_discharge_power;
|
||||
std::optional<RationalNumber> min_discharge_power_L2;
|
||||
std::optional<RationalNumber> min_discharge_power_L3;
|
||||
};
|
||||
|
||||
struct Dynamic_AC_CLReqControlMode : Dynamic_CLReqControlMode {
|
||||
RationalNumber max_charge_power;
|
||||
std::optional<RationalNumber> max_charge_power_L2;
|
||||
std::optional<RationalNumber> max_charge_power_L3;
|
||||
RationalNumber min_charge_power;
|
||||
std::optional<RationalNumber> min_charge_power_L2;
|
||||
std::optional<RationalNumber> min_charge_power_L3;
|
||||
RationalNumber present_active_power;
|
||||
std::optional<RationalNumber> present_active_power_L2;
|
||||
std::optional<RationalNumber> present_active_power_L3;
|
||||
RationalNumber present_reactive_power;
|
||||
std::optional<RationalNumber> present_reactive_power_L2;
|
||||
std::optional<RationalNumber> present_reactive_power_L3;
|
||||
};
|
||||
|
||||
struct BPT_Dynamic_AC_CLReqControlMode : Dynamic_AC_CLReqControlMode {
|
||||
RationalNumber max_discharge_power;
|
||||
std::optional<RationalNumber> max_discharge_power_L2;
|
||||
std::optional<RationalNumber> max_discharge_power_L3;
|
||||
RationalNumber min_discharge_power;
|
||||
std::optional<RationalNumber> min_discharge_power_L2;
|
||||
std::optional<RationalNumber> min_discharge_power_L3;
|
||||
std::optional<RationalNumber> max_v2x_energy_request;
|
||||
std::optional<RationalNumber> min_v2x_energy_request;
|
||||
};
|
||||
|
||||
struct Scheduled_AC_CLResControlMode : Scheduled_CLResControlMode {
|
||||
std::optional<RationalNumber> target_active_power;
|
||||
std::optional<RationalNumber> target_active_power_L2;
|
||||
std::optional<RationalNumber> target_active_power_L3;
|
||||
std::optional<RationalNumber> target_reactive_power;
|
||||
std::optional<RationalNumber> target_reactive_power_L2;
|
||||
std::optional<RationalNumber> target_reactive_power_L3;
|
||||
std::optional<RationalNumber> present_active_power;
|
||||
std::optional<RationalNumber> present_active_power_L2;
|
||||
std::optional<RationalNumber> present_active_power_L3;
|
||||
};
|
||||
|
||||
struct BPT_Scheduled_AC_CLResControlMode : Scheduled_AC_CLResControlMode {};
|
||||
|
||||
struct Dynamic_AC_CLResControlMode : Dynamic_CLResControlMode {
|
||||
RationalNumber target_active_power;
|
||||
std::optional<RationalNumber> target_active_power_L2;
|
||||
std::optional<RationalNumber> target_active_power_L3;
|
||||
std::optional<RationalNumber> target_reactive_power;
|
||||
std::optional<RationalNumber> target_reactive_power_L2;
|
||||
std::optional<RationalNumber> target_reactive_power_L3;
|
||||
std::optional<RationalNumber> present_active_power;
|
||||
std::optional<RationalNumber> present_active_power_L2;
|
||||
std::optional<RationalNumber> present_active_power_L3;
|
||||
};
|
||||
|
||||
struct BPT_Dynamic_AC_CLResControlMode : Dynamic_AC_CLResControlMode {};
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct AC_ChargeLoopRequest {
|
||||
Header header;
|
||||
|
||||
// the following 2 are inherited from ChargeLoopReq
|
||||
std::optional<datatypes::DisplayParameters> display_parameters;
|
||||
bool meter_info_requested;
|
||||
|
||||
std::variant<datatypes::Scheduled_AC_CLReqControlMode, datatypes::BPT_Scheduled_AC_CLReqControlMode,
|
||||
datatypes::Dynamic_AC_CLReqControlMode, datatypes::BPT_Dynamic_AC_CLReqControlMode>
|
||||
control_mode;
|
||||
};
|
||||
|
||||
struct AC_ChargeLoopResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
// the following 3 are inherited from ChargeLoopRes
|
||||
std::optional<datatypes::EvseStatus> status;
|
||||
std::optional<datatypes::MeterInfo> meter_info;
|
||||
std::optional<datatypes::Receipt> receipt;
|
||||
|
||||
std::optional<datatypes::RationalNumber> target_frequency;
|
||||
|
||||
std::variant<datatypes::Scheduled_AC_CLResControlMode, datatypes::BPT_Scheduled_AC_CLResControlMode,
|
||||
datatypes::Dynamic_AC_CLResControlMode, datatypes::BPT_Dynamic_AC_CLResControlMode>
|
||||
control_mode = datatypes::Scheduled_AC_CLResControlMode();
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,71 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
struct AC_CPDReqEnergyTransferMode {
|
||||
RationalNumber max_charge_power;
|
||||
std::optional<RationalNumber> max_charge_power_L2;
|
||||
std::optional<RationalNumber> max_charge_power_L3;
|
||||
RationalNumber min_charge_power;
|
||||
std::optional<RationalNumber> min_charge_power_L2;
|
||||
std::optional<RationalNumber> min_charge_power_L3;
|
||||
};
|
||||
|
||||
struct BPT_AC_CPDReqEnergyTransferMode : AC_CPDReqEnergyTransferMode {
|
||||
RationalNumber max_discharge_power;
|
||||
std::optional<RationalNumber> max_discharge_power_L2;
|
||||
std::optional<RationalNumber> max_discharge_power_L3;
|
||||
RationalNumber min_discharge_power;
|
||||
std::optional<RationalNumber> min_discharge_power_L2;
|
||||
std::optional<RationalNumber> min_discharge_power_L3;
|
||||
};
|
||||
|
||||
struct AC_CPDResEnergyTransferMode {
|
||||
RationalNumber max_charge_power;
|
||||
std::optional<RationalNumber> max_charge_power_L2;
|
||||
std::optional<RationalNumber> max_charge_power_L3;
|
||||
RationalNumber min_charge_power;
|
||||
std::optional<RationalNumber> min_charge_power_L2;
|
||||
std::optional<RationalNumber> min_charge_power_L3;
|
||||
RationalNumber nominal_frequency;
|
||||
std::optional<RationalNumber> max_power_asymmetry;
|
||||
std::optional<RationalNumber> power_ramp_limitation;
|
||||
std::optional<RationalNumber> present_active_power;
|
||||
std::optional<RationalNumber> present_active_power_L2;
|
||||
std::optional<RationalNumber> present_active_power_L3;
|
||||
};
|
||||
|
||||
struct BPT_AC_CPDResEnergyTransferMode : AC_CPDResEnergyTransferMode {
|
||||
RationalNumber max_discharge_power;
|
||||
std::optional<RationalNumber> max_discharge_power_L2;
|
||||
std::optional<RationalNumber> max_discharge_power_L3;
|
||||
RationalNumber min_discharge_power;
|
||||
std::optional<RationalNumber> min_discharge_power_L2;
|
||||
std::optional<RationalNumber> min_discharge_power_L3;
|
||||
};
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct AC_ChargeParameterDiscoveryRequest {
|
||||
Header header;
|
||||
std::variant<datatypes::AC_CPDReqEnergyTransferMode, datatypes::BPT_AC_CPDReqEnergyTransferMode> transfer_mode;
|
||||
};
|
||||
|
||||
struct AC_ChargeParameterDiscoveryResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
std::variant<datatypes::AC_CPDResEnergyTransferMode, datatypes::BPT_AC_CPDResEnergyTransferMode> transfer_mode =
|
||||
datatypes::AC_CPDResEnergyTransferMode();
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,43 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
enum class AuthStatus {
|
||||
Accepted = 0,
|
||||
Pending = 1,
|
||||
Rejected = 2,
|
||||
};
|
||||
|
||||
struct EIM_ASReqAuthorizationMode {};
|
||||
|
||||
struct PnC_ASReqAuthorizationMode {
|
||||
std::string id;
|
||||
GenChallenge gen_challenge;
|
||||
ContractCertificateChain contract_certificate_chain;
|
||||
};
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct AuthorizationRequest {
|
||||
Header header;
|
||||
datatypes::Authorization selected_authorization_service;
|
||||
std::variant<datatypes::EIM_ASReqAuthorizationMode, datatypes::PnC_ASReqAuthorizationMode> authorization_mode;
|
||||
};
|
||||
|
||||
struct AuthorizationResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
datatypes::Processing evse_processing{datatypes::Processing::Finished};
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,42 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
using SupportedProvidersList = everest::lib::util::fixed_vector<Name, 128>; // [0 - 128]
|
||||
|
||||
struct EIM_ASResAuthorizationMode {};
|
||||
struct PnC_ASResAuthorizationMode {
|
||||
GenChallenge gen_challenge;
|
||||
std::optional<datatypes::SupportedProvidersList> supported_providers;
|
||||
};
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct AuthorizationSetupRequest {
|
||||
Header header;
|
||||
};
|
||||
|
||||
struct AuthorizationSetupResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
everest::lib::util::fixed_vector<datatypes::Authorization, 2> authorization_services{datatypes::Authorization::EIM};
|
||||
bool certificate_installation_service{false};
|
||||
std::variant<datatypes::EIM_ASResAuthorizationMode, datatypes::PnC_ASResAuthorizationMode> authorization_mode =
|
||||
datatypes::EIM_ASResAuthorizationMode();
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,378 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
template <typename InType, typename OutType> void convert(const InType&, OutType&);
|
||||
|
||||
template <typename T> constexpr auto to_underlying_value(T t) {
|
||||
return static_cast<std::underlying_type_t<T>>(t);
|
||||
}
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
using PercentValue = uint8_t; // [0 - 100]
|
||||
using NumericId = uint32_t; // [1 - 4294967295]
|
||||
using Identifier = std::string; // MaxLength: 255
|
||||
using Name = std::string; // MaxLength: 80
|
||||
using Description = std::string; // MaxLength: 160
|
||||
|
||||
static constexpr auto SESSION_ID_LENGTH = 8;
|
||||
using SessionId = std::array<uint8_t, SESSION_ID_LENGTH>;
|
||||
|
||||
using MeterId = std::string; // MaxLength: 32
|
||||
using MeterSignature = std::string; // Base64 encoded, MaxLength: 64
|
||||
|
||||
static constexpr auto GEN_CHALLENGE_LENGTH = 16;
|
||||
using GenChallenge = std::array<uint8_t, GEN_CHALLENGE_LENGTH>; // Base64 encoded, MaxLength: 16
|
||||
|
||||
using Certificate = std::string; // Base64 encoded, MaxLength: 1600
|
||||
using SubCertificate = everest::lib::util::fixed_vector<Certificate, 3>; // Max: 3
|
||||
|
||||
enum class ResponseCode {
|
||||
OK = 0,
|
||||
OK_CertificateExpiresSoon = 1,
|
||||
OK_NewSessionEstablished = 2,
|
||||
OK_OldSessionJoined = 3,
|
||||
OK_PowerToleranceConfirmed = 4,
|
||||
WARNING_AuthorizationSelectionInvalid = 5,
|
||||
WARNING_CertificateExpired = 6,
|
||||
WARNING_CertificateNotYetValid = 7,
|
||||
WARNING_CertificateRevoked = 8,
|
||||
WARNING_CertificateValidationError = 9,
|
||||
WARNING_ChallengeInvalid = 10,
|
||||
WARNING_EIMAuthorizationFailure = 11,
|
||||
WARNING_eMSPUnknown = 12,
|
||||
WARNING_EVPowerProfileViolation = 13,
|
||||
WARNING_GeneralPnCAuthorizationError = 14,
|
||||
WARNING_NoCertificateAvailable = 15,
|
||||
WARNING_NoContractMatchingPCIDFound = 16,
|
||||
WARNING_PowerToleranceNotConfirmed = 17,
|
||||
WARNING_ScheduleRenegotiationFailed = 18,
|
||||
WARNING_StandbyNotAllowed = 19,
|
||||
WARNING_WPT = 20,
|
||||
FAILED = 21,
|
||||
FAILED_AssociationError = 22,
|
||||
FAILED_ContactorError = 23,
|
||||
FAILED_EVPowerProfileInvalid = 24,
|
||||
FAILED_EVPowerProfileViolation = 25,
|
||||
FAILED_MeteringSignatureNotValid = 26,
|
||||
FAILED_NoEnergyTransferServiceSelected = 27,
|
||||
FAILED_NoServiceRenegotiationSupported = 28,
|
||||
FAILED_PauseNotAllowed = 29,
|
||||
FAILED_PowerDeliveryNotApplied = 30,
|
||||
FAILED_PowerToleranceNotConfirmed = 31,
|
||||
FAILED_ScheduleRenegotiation = 32,
|
||||
FAILED_ScheduleSelectionInvalid = 33,
|
||||
FAILED_SequenceError = 34,
|
||||
FAILED_ServiceIDInvalid = 35,
|
||||
FAILED_ServiceSelectionInvalid = 36,
|
||||
FAILED_SignatureError = 37,
|
||||
FAILED_UnknownSession = 38,
|
||||
FAILED_WrongChargeParameter = 39
|
||||
};
|
||||
|
||||
enum class Processing {
|
||||
Finished = 0,
|
||||
Ongoing = 1,
|
||||
Ongoing_WaitingForCustomerInteraction = 2,
|
||||
};
|
||||
|
||||
enum class Authorization {
|
||||
EIM = 0,
|
||||
PnC = 1,
|
||||
};
|
||||
|
||||
enum class ServiceCategory : uint16_t {
|
||||
AC = 1,
|
||||
DC = 2,
|
||||
WPT = 3,
|
||||
DC_ACDP = 4,
|
||||
AC_BPT = 5,
|
||||
DC_BPT = 6,
|
||||
DC_ACDP_BPT = 7,
|
||||
MCS = 8,
|
||||
MCS_BPT = 9,
|
||||
AC_DER = 10,
|
||||
Internet = 65,
|
||||
ParkingStatus = 66,
|
||||
};
|
||||
|
||||
enum class EvseNotification {
|
||||
Pause,
|
||||
ExitStandby,
|
||||
Terminate,
|
||||
ScheduleRenegotiation,
|
||||
ServiceRenegotiation,
|
||||
MeteringConfirmation,
|
||||
};
|
||||
|
||||
enum class ChargingSession {
|
||||
Pause,
|
||||
Terminate,
|
||||
ServiceRenegotiation,
|
||||
};
|
||||
|
||||
enum class AcConnector {
|
||||
SinglePhase = 1,
|
||||
ThreePhase = 3,
|
||||
};
|
||||
enum class DcConnector {
|
||||
Core = 1,
|
||||
Extended = 2,
|
||||
Dual2 = 3,
|
||||
Dual4 = 4,
|
||||
};
|
||||
enum class McsConnector {
|
||||
Mcs = 1,
|
||||
Chaoji = 2,
|
||||
UltraChaoji = 3,
|
||||
rMcs = 4,
|
||||
xMcs = 5,
|
||||
Aviation = 6,
|
||||
Marine = 7,
|
||||
};
|
||||
|
||||
enum class ControlMode {
|
||||
Scheduled = 1,
|
||||
Dynamic = 2,
|
||||
};
|
||||
enum class MobilityNeedsMode {
|
||||
ProvidedByEvcc = 1,
|
||||
ProvidedBySecc = 2,
|
||||
};
|
||||
enum class Pricing {
|
||||
NoPricing = 0,
|
||||
AbsolutePricing = 1,
|
||||
PriceLevels = 2,
|
||||
};
|
||||
|
||||
enum class BptChannel {
|
||||
Unified = 1,
|
||||
Separated = 2,
|
||||
};
|
||||
|
||||
enum class GeneratorMode {
|
||||
GridFollowing = 1,
|
||||
GridForming = 2,
|
||||
};
|
||||
|
||||
enum class GridCodeIslandingDetectionMethod {
|
||||
Active = 1,
|
||||
Passive = 2,
|
||||
};
|
||||
|
||||
enum class Protocol {
|
||||
Ftp,
|
||||
Http,
|
||||
Https,
|
||||
};
|
||||
|
||||
enum class Port {
|
||||
Port20 = 20,
|
||||
Port21 = 21,
|
||||
Port80 = 80,
|
||||
Port443 = 443,
|
||||
};
|
||||
|
||||
enum class IntendedService {
|
||||
VehicleCheckIn = 1,
|
||||
VehicleCheckOut = 2,
|
||||
};
|
||||
|
||||
enum class ParkingStatus {
|
||||
AutoInternal = 1,
|
||||
AutoExternal = 2,
|
||||
ManualInternal = 3,
|
||||
ManualExternal = 4,
|
||||
};
|
||||
|
||||
struct RationalNumber {
|
||||
int16_t value{0};
|
||||
int8_t exponent{0};
|
||||
};
|
||||
|
||||
struct EvseStatus {
|
||||
uint16_t notification_max_delay;
|
||||
EvseNotification notification;
|
||||
};
|
||||
|
||||
struct AcParameterList {
|
||||
AcConnector connector;
|
||||
ControlMode control_mode;
|
||||
MobilityNeedsMode mobility_needs_mode;
|
||||
uint32_t evse_nominal_voltage;
|
||||
Pricing pricing;
|
||||
};
|
||||
|
||||
struct AcBptParameterList : AcParameterList {
|
||||
BptChannel bpt_channel;
|
||||
GeneratorMode generator_mode;
|
||||
GridCodeIslandingDetectionMethod grid_code_detection_method;
|
||||
};
|
||||
|
||||
struct DcParameterList {
|
||||
DcConnector connector;
|
||||
ControlMode control_mode;
|
||||
MobilityNeedsMode mobility_needs_mode;
|
||||
Pricing pricing;
|
||||
};
|
||||
|
||||
struct DcBptParameterList : DcParameterList {
|
||||
BptChannel bpt_channel;
|
||||
GeneratorMode generator_mode;
|
||||
};
|
||||
|
||||
struct McsParameterList {
|
||||
McsConnector connector;
|
||||
ControlMode control_mode;
|
||||
MobilityNeedsMode mobility_needs_mode;
|
||||
Pricing pricing;
|
||||
};
|
||||
|
||||
struct McsBptParameterList : McsParameterList {
|
||||
BptChannel bpt_channel;
|
||||
GeneratorMode generator_mode;
|
||||
};
|
||||
|
||||
struct InternetParameterList {
|
||||
Protocol protocol;
|
||||
Port port;
|
||||
};
|
||||
|
||||
struct ParkingParameterList {
|
||||
IntendedService intended_service;
|
||||
ParkingStatus parking_status;
|
||||
};
|
||||
|
||||
struct Scheduled_CLReqControlMode {
|
||||
std::optional<RationalNumber> target_energy_request;
|
||||
std::optional<RationalNumber> max_energy_request;
|
||||
std::optional<RationalNumber> min_energy_request;
|
||||
};
|
||||
|
||||
struct Dynamic_CLReqControlMode {
|
||||
std::optional<uint32_t> departure_time;
|
||||
RationalNumber target_energy_request;
|
||||
RationalNumber max_energy_request;
|
||||
RationalNumber min_energy_request;
|
||||
};
|
||||
|
||||
struct Scheduled_CLResControlMode {};
|
||||
|
||||
struct Dynamic_CLResControlMode {
|
||||
std::optional<uint32_t> departure_time;
|
||||
std::optional<uint8_t> minimum_soc;
|
||||
std::optional<uint8_t> target_soc;
|
||||
std::optional<uint16_t> ack_max_delay;
|
||||
};
|
||||
|
||||
struct PowerScheduleEntry {
|
||||
uint32_t duration;
|
||||
RationalNumber power;
|
||||
std::optional<RationalNumber> power_l2;
|
||||
std::optional<RationalNumber> power_l3;
|
||||
};
|
||||
|
||||
struct MeterInfo {
|
||||
MeterId meter_id;
|
||||
uint64_t charged_energy_reading_wh;
|
||||
std::optional<uint64_t> bpt_discharged_energy_reading_wh;
|
||||
std::optional<uint64_t> capacitive_energy_reading_varh;
|
||||
std::optional<uint64_t> bpt_inductive_energy_reading_varh;
|
||||
std::optional<MeterSignature> meter_signature;
|
||||
std::optional<int16_t> meter_status;
|
||||
std::optional<uint64_t> meter_timestamp;
|
||||
};
|
||||
|
||||
struct DisplayParameters {
|
||||
std::optional<PercentValue> present_soc;
|
||||
std::optional<PercentValue> min_soc;
|
||||
std::optional<PercentValue> target_soc;
|
||||
std::optional<PercentValue> max_soc;
|
||||
std::optional<uint32_t> remaining_time_to_min_soc;
|
||||
std::optional<uint32_t> remaining_time_to_target_soc;
|
||||
std::optional<uint32_t> remaining_time_to_max_soc;
|
||||
std::optional<bool> charging_complete;
|
||||
std::optional<RationalNumber> battery_energy_capacity;
|
||||
std::optional<bool> inlet_hot;
|
||||
};
|
||||
|
||||
struct DetailedCost {
|
||||
RationalNumber amount;
|
||||
RationalNumber cost_per_unit;
|
||||
};
|
||||
|
||||
struct DetailedTax {
|
||||
NumericId tax_rule_id;
|
||||
RationalNumber amount;
|
||||
};
|
||||
|
||||
struct Receipt {
|
||||
uint64_t time_anchor;
|
||||
std::optional<DetailedCost> energy_costs;
|
||||
std::optional<DetailedCost> occupancy_costs;
|
||||
std::optional<DetailedCost> additional_service_costs;
|
||||
std::optional<DetailedCost> overstay_costs;
|
||||
everest::lib::util::fixed_vector<DetailedTax, 10> tax_costs; // 0 to 10 elements! // FIXME(sl): optional?
|
||||
};
|
||||
|
||||
struct X509IssuerSerial {
|
||||
std::string issuer_name;
|
||||
int64_t serial_number;
|
||||
};
|
||||
|
||||
struct ListOfRootCertificateIDs {
|
||||
everest::lib::util::fixed_vector<X509IssuerSerial, 20> root_certificate_id;
|
||||
};
|
||||
|
||||
// TODO(sl): Adding content to following structs
|
||||
struct SignedInfo {};
|
||||
struct SignatureValue {};
|
||||
struct KeyInfo {};
|
||||
struct Object {};
|
||||
|
||||
struct Signature {
|
||||
SignedInfo signed_info;
|
||||
SignatureValue signature;
|
||||
std::optional<KeyInfo> key_info;
|
||||
std::optional<Object> object;
|
||||
std::optional<std::string> id;
|
||||
};
|
||||
|
||||
struct ContractCertificateChain {
|
||||
Certificate certificate;
|
||||
SubCertificate sub_certificates;
|
||||
};
|
||||
|
||||
float from_RationalNumber(const RationalNumber& in);
|
||||
RationalNumber from_float(float in);
|
||||
|
||||
std::string from_Protocol(const Protocol& in);
|
||||
|
||||
std::string from_control_mode(const ControlMode& in);
|
||||
std::string from_mobility_needs_mode(const MobilityNeedsMode& in);
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct Header {
|
||||
datatypes::SessionId session_id{};
|
||||
uint64_t timestamp;
|
||||
// std::optional<datatypes::Signature> signature;
|
||||
};
|
||||
|
||||
template <typename cb_HeaderType> void convert(const cb_HeaderType& in, Header& out);
|
||||
|
||||
template <typename cb_RationalNumberType> void convert(const cb_RationalNumberType& in, datatypes::RationalNumber& out);
|
||||
template <typename cb_RationalNumberType> void convert(const datatypes::RationalNumber& in, cb_RationalNumberType& out);
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
struct DC_CableCheckRequest {
|
||||
Header header;
|
||||
};
|
||||
|
||||
struct DC_CableCheckResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
datatypes::Processing processing{datatypes::Processing::Ongoing};
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,110 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
struct Scheduled_DC_CLReqControlMode : Scheduled_CLReqControlMode {
|
||||
RationalNumber target_current;
|
||||
RationalNumber target_voltage;
|
||||
std::optional<RationalNumber> max_charge_power;
|
||||
std::optional<RationalNumber> min_charge_power;
|
||||
std::optional<RationalNumber> max_charge_current;
|
||||
std::optional<RationalNumber> max_voltage;
|
||||
std::optional<RationalNumber> min_voltage;
|
||||
};
|
||||
|
||||
struct BPT_Scheduled_DC_CLReqControlMode : Scheduled_DC_CLReqControlMode {
|
||||
std::optional<RationalNumber> max_discharge_power;
|
||||
std::optional<RationalNumber> min_discharge_power;
|
||||
std::optional<RationalNumber> max_discharge_current;
|
||||
};
|
||||
|
||||
struct Dynamic_DC_CLReqControlMode : Dynamic_CLReqControlMode {
|
||||
RationalNumber max_charge_power;
|
||||
RationalNumber min_charge_power;
|
||||
RationalNumber max_charge_current;
|
||||
RationalNumber max_voltage;
|
||||
RationalNumber min_voltage;
|
||||
};
|
||||
|
||||
struct BPT_Dynamic_DC_CLReqControlMode : Dynamic_DC_CLReqControlMode {
|
||||
RationalNumber max_discharge_power;
|
||||
RationalNumber min_discharge_power;
|
||||
RationalNumber max_discharge_current;
|
||||
std::optional<RationalNumber> max_v2x_energy_request;
|
||||
std::optional<RationalNumber> min_v2x_energy_request;
|
||||
};
|
||||
|
||||
struct Scheduled_DC_CLResControlMode : Scheduled_CLResControlMode {
|
||||
std::optional<RationalNumber> max_charge_power;
|
||||
std::optional<RationalNumber> min_charge_power;
|
||||
std::optional<RationalNumber> max_charge_current;
|
||||
std::optional<RationalNumber> max_voltage;
|
||||
};
|
||||
|
||||
struct BPT_Scheduled_DC_CLResControlMode : Scheduled_DC_CLResControlMode {
|
||||
std::optional<RationalNumber> max_discharge_power;
|
||||
std::optional<RationalNumber> min_discharge_power;
|
||||
std::optional<RationalNumber> max_discharge_current;
|
||||
std::optional<RationalNumber> min_voltage;
|
||||
};
|
||||
|
||||
struct Dynamic_DC_CLResControlMode : Dynamic_CLResControlMode {
|
||||
RationalNumber max_charge_power;
|
||||
RationalNumber min_charge_power;
|
||||
RationalNumber max_charge_current;
|
||||
RationalNumber max_voltage;
|
||||
};
|
||||
|
||||
struct BPT_Dynamic_DC_CLResControlMode : Dynamic_DC_CLResControlMode {
|
||||
RationalNumber max_discharge_power;
|
||||
RationalNumber min_discharge_power;
|
||||
RationalNumber max_discharge_current;
|
||||
RationalNumber min_voltage;
|
||||
};
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct DC_ChargeLoopRequest {
|
||||
|
||||
Header header;
|
||||
|
||||
// the following 2 are inherited from ChargeLoopReq
|
||||
std::optional<datatypes::DisplayParameters> display_parameters;
|
||||
bool meter_info_requested;
|
||||
|
||||
datatypes::RationalNumber present_voltage;
|
||||
std::variant<datatypes::Scheduled_DC_CLReqControlMode, datatypes::BPT_Scheduled_DC_CLReqControlMode,
|
||||
datatypes::Dynamic_DC_CLReqControlMode, datatypes::BPT_Dynamic_DC_CLReqControlMode>
|
||||
control_mode;
|
||||
};
|
||||
|
||||
struct DC_ChargeLoopResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
// the following 3 are inherited from ChargeLoopRes
|
||||
std::optional<datatypes::EvseStatus> status;
|
||||
std::optional<datatypes::MeterInfo> meter_info;
|
||||
std::optional<datatypes::Receipt> receipt;
|
||||
|
||||
datatypes::RationalNumber present_current{0, 0};
|
||||
datatypes::RationalNumber present_voltage{0, 0};
|
||||
bool power_limit_achieved{false};
|
||||
bool current_limit_achieved{false};
|
||||
bool voltage_limit_achieved{false};
|
||||
|
||||
std::variant<datatypes::Scheduled_DC_CLResControlMode, datatypes::BPT_Scheduled_DC_CLResControlMode,
|
||||
datatypes::Dynamic_DC_CLResControlMode, datatypes::BPT_Dynamic_DC_CLResControlMode>
|
||||
control_mode = datatypes::Scheduled_DC_CLResControlMode();
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
struct DC_CPDReqEnergyTransferMode {
|
||||
RationalNumber max_charge_power;
|
||||
RationalNumber min_charge_power;
|
||||
RationalNumber max_charge_current;
|
||||
RationalNumber min_charge_current;
|
||||
RationalNumber max_voltage;
|
||||
RationalNumber min_voltage;
|
||||
std::optional<uint8_t> target_soc;
|
||||
};
|
||||
|
||||
struct BPT_DC_CPDReqEnergyTransferMode : DC_CPDReqEnergyTransferMode {
|
||||
RationalNumber max_discharge_power;
|
||||
RationalNumber min_discharge_power;
|
||||
RationalNumber max_discharge_current;
|
||||
RationalNumber min_discharge_current;
|
||||
};
|
||||
|
||||
struct DC_CPDResEnergyTransferMode {
|
||||
RationalNumber max_charge_power;
|
||||
RationalNumber min_charge_power;
|
||||
RationalNumber max_charge_current;
|
||||
RationalNumber min_charge_current;
|
||||
RationalNumber max_voltage;
|
||||
RationalNumber min_voltage;
|
||||
std::optional<RationalNumber> power_ramp_limit;
|
||||
};
|
||||
|
||||
struct BPT_DC_CPDResEnergyTransferMode : DC_CPDResEnergyTransferMode {
|
||||
RationalNumber max_discharge_power;
|
||||
RationalNumber min_discharge_power;
|
||||
RationalNumber max_discharge_current;
|
||||
RationalNumber min_discharge_current;
|
||||
};
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct DC_ChargeParameterDiscoveryRequest {
|
||||
Header header;
|
||||
std::variant<datatypes::DC_CPDReqEnergyTransferMode, datatypes::BPT_DC_CPDReqEnergyTransferMode> transfer_mode;
|
||||
};
|
||||
|
||||
struct DC_ChargeParameterDiscoveryResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
std::variant<datatypes::DC_CPDResEnergyTransferMode, datatypes::BPT_DC_CPDResEnergyTransferMode> transfer_mode =
|
||||
datatypes::DC_CPDResEnergyTransferMode();
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
struct DC_PreChargeRequest {
|
||||
Header header;
|
||||
|
||||
datatypes::Processing processing;
|
||||
datatypes::RationalNumber present_voltage;
|
||||
datatypes::RationalNumber target_voltage;
|
||||
};
|
||||
|
||||
struct DC_PreChargeResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
datatypes::RationalNumber present_voltage;
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
struct DC_WeldingDetectionRequest {
|
||||
Header header;
|
||||
|
||||
datatypes::Processing processing;
|
||||
};
|
||||
|
||||
struct DC_WeldingDetectionResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
datatypes::RationalNumber present_voltage;
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,50 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
// FIXME (aw): how to streamline this with type.hpp?
|
||||
|
||||
#include <iso15118/io/sdp.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
template <typename T> struct PayloadTypeTrait;
|
||||
|
||||
//
|
||||
// definitions of type traits
|
||||
//
|
||||
#ifdef CREATE_TYPE_TRAIT
|
||||
#define CREATE_TYPE_TRAIT_PUSHED CREATE_TYPE_TRAIT
|
||||
#endif
|
||||
|
||||
#define CREATE_TYPE_TRAIT(struct_name, payload_type) \
|
||||
struct struct_name; \
|
||||
template <> struct PayloadTypeTrait<struct_name> { \
|
||||
static const io::v2gtp::PayloadType type = io::v2gtp::PayloadType::payload_type; \
|
||||
}
|
||||
|
||||
CREATE_TYPE_TRAIT(SupportedAppProtocolResponse, SAP);
|
||||
CREATE_TYPE_TRAIT(SessionSetupResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(AuthorizationSetupResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(AuthorizationResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(ServiceDiscoveryResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(ServiceDetailResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(ServiceSelectionResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(DC_ChargeParameterDiscoveryResponse, Part20DC);
|
||||
CREATE_TYPE_TRAIT(ScheduleExchangeResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(DC_CableCheckResponse, Part20DC);
|
||||
CREATE_TYPE_TRAIT(DC_PreChargeResponse, Part20DC);
|
||||
CREATE_TYPE_TRAIT(PowerDeliveryResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(DC_ChargeLoopResponse, Part20DC);
|
||||
CREATE_TYPE_TRAIT(DC_WeldingDetectionResponse, Part20DC);
|
||||
CREATE_TYPE_TRAIT(SessionStopResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(AC_ChargeParameterDiscoveryResponse, Part20AC);
|
||||
CREATE_TYPE_TRAIT(AC_ChargeLoopResponse, Part20AC);
|
||||
|
||||
#ifdef CREATE_TYPE_TRAIT_PUSHED
|
||||
#define CREATE_TYPE_TRAIT CREATE_TYPE_TRAIT_PUSHED
|
||||
#else
|
||||
#undef CREATE_TYPE_TRAIT
|
||||
#endif
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,68 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
enum class Progress {
|
||||
Start,
|
||||
Stop,
|
||||
Standby,
|
||||
ScheduleRenegotiation,
|
||||
};
|
||||
|
||||
struct Dynamic_EVPPTControlMode {
|
||||
// intentionally left blank
|
||||
};
|
||||
|
||||
enum class PowerToleranceAcceptance : uint8_t {
|
||||
NotConfirmed,
|
||||
Confirmed,
|
||||
};
|
||||
|
||||
struct Scheduled_EVPPTControlMode {
|
||||
NumericId selected_schedule;
|
||||
std::optional<PowerToleranceAcceptance> power_tolerance_acceptance;
|
||||
};
|
||||
|
||||
struct PowerProfile {
|
||||
uint64_t time_anchor;
|
||||
std::variant<Dynamic_EVPPTControlMode, Scheduled_EVPPTControlMode> control_mode;
|
||||
everest::lib::util::fixed_vector<PowerScheduleEntry, 2048> entries; // maximum 2048
|
||||
};
|
||||
|
||||
enum class ChannelSelection : uint8_t {
|
||||
Charge,
|
||||
Discharge,
|
||||
};
|
||||
|
||||
}; // namespace datatypes
|
||||
|
||||
struct PowerDeliveryRequest {
|
||||
Header header;
|
||||
|
||||
datatypes::Processing processing;
|
||||
datatypes::Progress charge_progress;
|
||||
|
||||
std::optional<datatypes::PowerProfile> power_profile;
|
||||
std::optional<datatypes::ChannelSelection> channel_selection;
|
||||
};
|
||||
|
||||
struct PowerDeliveryResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
std::optional<datatypes::EvseStatus> status;
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,206 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
static constexpr auto TAX_RULE_LENGTH = 10;
|
||||
static constexpr auto PRICE_RULE_STACK_LENGTH = 1024;
|
||||
static constexpr auto PRICE_RULE_LENGTH = 8;
|
||||
static constexpr auto OVERSTAY_RULE_LENGTH = 5;
|
||||
static constexpr auto ADDITIONAL_SERVICE_LENGTH = 5;
|
||||
static constexpr auto PRICE_LEVEL_SCHEDULE_LENGTH = 1024;
|
||||
static constexpr auto SCHEDULED_POWER_DURATION_S = 86400;
|
||||
|
||||
using MaxSupportingPointsScheduleTuple = uint16_t; // needs to be [12 - 1024]
|
||||
|
||||
using Curreny = std::string; // MaxLength: 3
|
||||
using Language = std::string; // MaxLength: 3
|
||||
|
||||
struct TaxRule {
|
||||
NumericId tax_rule_id;
|
||||
std::optional<Name> tax_rule_name;
|
||||
RationalNumber tax_rate;
|
||||
std::optional<bool> tax_included_in_price;
|
||||
bool applies_to_energy_fee;
|
||||
bool applies_to_parking_fee;
|
||||
bool applies_to_overstay_fee;
|
||||
bool applies_to_minimum_maximum_cost;
|
||||
};
|
||||
|
||||
struct PriceRule {
|
||||
RationalNumber energy_fee;
|
||||
std::optional<RationalNumber> parking_fee;
|
||||
std::optional<uint32_t> parking_fee_period;
|
||||
std::optional<uint16_t> carbon_dioxide_emission;
|
||||
std::optional<uint8_t> renewable_generation_percentage;
|
||||
RationalNumber power_range_start;
|
||||
};
|
||||
|
||||
struct PriceRuleStack {
|
||||
uint32_t duration;
|
||||
std::array<PriceRule, PRICE_RULE_LENGTH> price_rule;
|
||||
};
|
||||
|
||||
struct AdditionalService {
|
||||
Name service_name;
|
||||
RationalNumber service_fee;
|
||||
};
|
||||
|
||||
using TaxRuleList = std::array<TaxRule, TAX_RULE_LENGTH>;
|
||||
using PriceRuleStackList = std::array<PriceRuleStack, PRICE_RULE_STACK_LENGTH>;
|
||||
using AdditionalServiceList = std::array<AdditionalService, ADDITIONAL_SERVICE_LENGTH>;
|
||||
|
||||
struct Dynamic_SEReqControlMode {
|
||||
uint32_t departure_time;
|
||||
std::optional<PercentValue> minimum_soc;
|
||||
std::optional<PercentValue> target_soc;
|
||||
RationalNumber target_energy;
|
||||
RationalNumber max_energy;
|
||||
RationalNumber min_energy;
|
||||
std::optional<RationalNumber> max_v2x_energy;
|
||||
std::optional<RationalNumber> min_v2x_energy;
|
||||
};
|
||||
|
||||
struct EVPowerScheduleEntry {
|
||||
uint32_t duration;
|
||||
RationalNumber power;
|
||||
};
|
||||
|
||||
struct EVPowerSchedule {
|
||||
uint64_t time_anchor;
|
||||
everest::lib::util::fixed_vector<EVPowerScheduleEntry, 1024> entries; // max 1024
|
||||
};
|
||||
|
||||
struct EVPriceRule {
|
||||
RationalNumber energy_fee;
|
||||
RationalNumber power_range_start;
|
||||
};
|
||||
|
||||
struct EVPriceRuleStack {
|
||||
uint32_t duration;
|
||||
everest::lib::util::fixed_vector<EVPriceRule, 8> price_rules; // max 8
|
||||
};
|
||||
|
||||
struct EVAbsolutePriceSchedule {
|
||||
uint64_t time_anchor;
|
||||
Curreny currency;
|
||||
Identifier price_algorithm;
|
||||
everest::lib::util::fixed_vector<EVPriceRuleStack, 1024> price_rule_stacks; // max 1024
|
||||
};
|
||||
|
||||
struct EVEnergyOffer {
|
||||
EVPowerSchedule power_schedule;
|
||||
EVAbsolutePriceSchedule absolute_price_schedule;
|
||||
};
|
||||
|
||||
struct Scheduled_SEReqControlMode {
|
||||
std::optional<uint32_t> departure_time;
|
||||
std::optional<RationalNumber> target_energy;
|
||||
std::optional<RationalNumber> max_energy;
|
||||
std::optional<RationalNumber> min_energy;
|
||||
std::optional<EVEnergyOffer> energy_offer;
|
||||
};
|
||||
|
||||
struct OverstayRule {
|
||||
std::optional<Description> overstay_rule_description;
|
||||
uint32_t start_time;
|
||||
RationalNumber overstay_fee;
|
||||
uint32_t overstay_fee_period;
|
||||
};
|
||||
|
||||
struct OverstayRulesList {
|
||||
std::optional<uint32_t> overstay_time_threshold;
|
||||
std::optional<RationalNumber> overstay_power_threshold;
|
||||
everest::lib::util::fixed_vector<OverstayRule, 5> overstay_rule; // 5
|
||||
};
|
||||
|
||||
struct AbsolutePriceSchedule {
|
||||
std::optional<std::string> id;
|
||||
uint64_t time_anchor;
|
||||
NumericId price_schedule_id;
|
||||
std::optional<Description> price_schedule_description;
|
||||
Curreny currency;
|
||||
Language language;
|
||||
Identifier price_algorithm;
|
||||
std::optional<RationalNumber> minimum_cost;
|
||||
std::optional<RationalNumber> maximum_cost;
|
||||
std::optional<TaxRuleList> tax_rules;
|
||||
PriceRuleStackList price_rule_stacks;
|
||||
std::optional<OverstayRulesList> overstay_rules;
|
||||
std::optional<AdditionalServiceList> additional_selected_services;
|
||||
};
|
||||
|
||||
struct PriceLevelScheduleEntry {
|
||||
uint32_t duration;
|
||||
uint8_t price_level;
|
||||
};
|
||||
|
||||
struct PriceLevelSchedule {
|
||||
std::optional<std::string> id;
|
||||
uint64_t time_anchor;
|
||||
NumericId price_schedule_id;
|
||||
std::optional<Description> price_schedule_description;
|
||||
uint8_t number_of_price_levels;
|
||||
everest::lib::util::fixed_vector<PriceLevelScheduleEntry, 1024> price_level_schedule_entries; // 1024
|
||||
};
|
||||
|
||||
struct Dynamic_SEResControlMode {
|
||||
std::optional<uint32_t> departure_time;
|
||||
std::optional<PercentValue> minimum_soc;
|
||||
std::optional<PercentValue> target_soc;
|
||||
std::variant<std::monostate, AbsolutePriceSchedule, PriceLevelSchedule> price_schedule;
|
||||
};
|
||||
|
||||
struct PowerSchedule {
|
||||
uint64_t time_anchor;
|
||||
std::optional<RationalNumber> available_energy;
|
||||
std::optional<RationalNumber> power_tolerance;
|
||||
everest::lib::util::fixed_vector<PowerScheduleEntry, 1024> entries; // 1024
|
||||
};
|
||||
|
||||
struct ChargingSchedule {
|
||||
PowerSchedule power_schedule;
|
||||
std::variant<std::monostate, AbsolutePriceSchedule, PriceLevelSchedule> price_schedule;
|
||||
};
|
||||
|
||||
struct ScheduleTuple {
|
||||
NumericId schedule_tuple_id; // 1 - 255
|
||||
ChargingSchedule charging_schedule;
|
||||
std::optional<ChargingSchedule> discharging_schedule;
|
||||
};
|
||||
|
||||
struct Scheduled_SEResControlMode {
|
||||
everest::lib::util::fixed_vector<ScheduleTuple, 3> schedule_tuple; // 3
|
||||
};
|
||||
|
||||
}; // namespace datatypes
|
||||
|
||||
struct ScheduleExchangeRequest {
|
||||
Header header;
|
||||
datatypes::MaxSupportingPointsScheduleTuple max_supporting_points;
|
||||
std::variant<datatypes::Dynamic_SEReqControlMode, datatypes::Scheduled_SEReqControlMode> control_mode;
|
||||
};
|
||||
|
||||
struct ScheduleExchangeResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
datatypes::Processing processing{datatypes::Processing::Finished};
|
||||
std::optional<bool> go_to_pause;
|
||||
|
||||
std::variant<datatypes::Dynamic_SEResControlMode, datatypes::Scheduled_SEResControlMode> control_mode =
|
||||
datatypes::Dynamic_SEResControlMode();
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <variant>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
struct Parameter {
|
||||
Name name;
|
||||
std::variant<bool, int8_t, int16_t, int32_t, Name, RationalNumber> value;
|
||||
};
|
||||
|
||||
struct ParameterSet {
|
||||
uint16_t id;
|
||||
everest::lib::util::fixed_vector<Parameter, 32> parameter;
|
||||
|
||||
ParameterSet() = default;
|
||||
ParameterSet(uint16_t _id);
|
||||
ParameterSet(uint16_t _id, const AcParameterList& list);
|
||||
ParameterSet(uint16_t _id, const AcBptParameterList& list);
|
||||
ParameterSet(uint16_t _id, const DcParameterList& list);
|
||||
ParameterSet(uint16_t _id, const DcBptParameterList& list);
|
||||
ParameterSet(uint16_t _id, const McsParameterList& list);
|
||||
ParameterSet(uint16_t _id, const McsBptParameterList& list);
|
||||
ParameterSet(uint16_t _id, const InternetParameterList& list);
|
||||
ParameterSet(uint16_t _id, const ParkingParameterList& list);
|
||||
};
|
||||
|
||||
using ServiceParameterList = everest::lib::util::fixed_vector<ParameterSet, 32>; // Max: 32
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct ServiceDetailRequest {
|
||||
Header header;
|
||||
uint16_t service;
|
||||
};
|
||||
|
||||
struct ServiceDetailResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
uint16_t service{to_underlying_value(datatypes::ServiceCategory::DC)};
|
||||
datatypes::ServiceParameterList service_parameter_list{datatypes::ParameterSet(0)};
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,48 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
using ServiceIdList = everest::lib::util::fixed_vector<std::uint16_t, 16>; // 16
|
||||
|
||||
struct Service {
|
||||
ServiceCategory service_id;
|
||||
bool free_service;
|
||||
};
|
||||
using ServiceList = everest::lib::util::fixed_vector<Service, 8>; // max: 8
|
||||
|
||||
struct VasService {
|
||||
uint16_t service_id;
|
||||
bool free_service;
|
||||
};
|
||||
using VasServiceList = everest::lib::util::fixed_vector<VasService, 8>; // max: 8
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct ServiceDiscoveryRequest {
|
||||
Header header;
|
||||
std::optional<datatypes::ServiceIdList> supported_service_ids;
|
||||
};
|
||||
|
||||
struct ServiceDiscoveryResponse {
|
||||
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
bool service_renegotiation_supported = false;
|
||||
datatypes::ServiceList energy_transfer_service_list = {{
|
||||
datatypes::ServiceCategory::AC, // service_id
|
||||
false // free_service
|
||||
}};
|
||||
std::optional<datatypes::VasServiceList> vas_list;
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,40 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
struct SelectedService {
|
||||
ServiceCategory service_id;
|
||||
uint16_t parameter_set_id;
|
||||
};
|
||||
|
||||
struct VasSelectedService {
|
||||
uint16_t service_id;
|
||||
uint16_t parameter_set_id;
|
||||
};
|
||||
|
||||
using VasSelectedServiceList = everest::lib::util::fixed_vector<VasSelectedService, 16>; // Max: 16
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct ServiceSelectionRequest {
|
||||
Header header;
|
||||
datatypes::SelectedService selected_energy_transfer_service;
|
||||
std::optional<datatypes::VasSelectedServiceList> selected_vas_list;
|
||||
};
|
||||
|
||||
struct ServiceSelectionResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
struct SessionSetupRequest {
|
||||
Header header;
|
||||
datatypes::Identifier evccid;
|
||||
};
|
||||
|
||||
struct SessionSetupResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
datatypes::Identifier evseid;
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
struct SessionStopRequest {
|
||||
Header header;
|
||||
datatypes::ChargingSession charging_session;
|
||||
std::optional<datatypes::Name> ev_termination_code;
|
||||
std::optional<datatypes::Description> ev_termination_explanation;
|
||||
};
|
||||
|
||||
struct SessionStopResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <iso15118/io/stream_view.hpp>
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
struct SupportedAppProtocol {
|
||||
std::string protocol_namespace;
|
||||
uint32_t version_number_major;
|
||||
uint32_t version_number_minor;
|
||||
uint8_t schema_id;
|
||||
uint8_t priority;
|
||||
|
||||
bool operator==(const iso15118::message_20::SupportedAppProtocol& other) const {
|
||||
return this->protocol_namespace == other.protocol_namespace and this->priority == other.priority and
|
||||
this->schema_id == other.schema_id and this->version_number_major == other.version_number_major and
|
||||
this->version_number_minor == other.version_number_minor;
|
||||
}
|
||||
};
|
||||
|
||||
struct SupportedAppProtocolRequest {
|
||||
everest::lib::util::fixed_vector<SupportedAppProtocol, 20> app_protocol;
|
||||
};
|
||||
|
||||
struct SupportedAppProtocolResponse {
|
||||
enum class ResponseCode {
|
||||
OK_SuccessfulNegotiation = 0,
|
||||
OK_SuccessfulNegotiationWithMinorDeviation = 1,
|
||||
Failed_NoNegotiation = 2,
|
||||
};
|
||||
|
||||
ResponseCode response_code;
|
||||
std::optional<uint8_t> schema_id;
|
||||
};
|
||||
|
||||
size_t encode_supported_app_protocol_response(const io::StreamOutputView&, const SupportedAppProtocolResponse&);
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,109 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/io/stream_view.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
enum class Type {
|
||||
None,
|
||||
SupportedAppProtocolReq,
|
||||
SupportedAppProtocolRes,
|
||||
SessionSetupReq,
|
||||
SessionSetupRes,
|
||||
AuthorizationSetupReq,
|
||||
AuthorizationSetupRes,
|
||||
AuthorizationReq,
|
||||
AuthorizationRes,
|
||||
ServiceDiscoveryReq,
|
||||
ServiceDiscoveryRes,
|
||||
ServiceDetailReq,
|
||||
ServiceDetailRes,
|
||||
ServiceSelectionReq,
|
||||
ServiceSelectionRes,
|
||||
DC_ChargeParameterDiscoveryReq,
|
||||
DC_ChargeParameterDiscoveryRes,
|
||||
ScheduleExchangeReq,
|
||||
ScheduleExchangeRes,
|
||||
DC_CableCheckReq,
|
||||
DC_CableCheckRes,
|
||||
DC_PreChargeReq,
|
||||
DC_PreChargeRes,
|
||||
PowerDeliveryReq,
|
||||
PowerDeliveryRes,
|
||||
DC_ChargeLoopReq,
|
||||
DC_ChargeLoopRes,
|
||||
DC_WeldingDetectionReq,
|
||||
DC_WeldingDetectionRes,
|
||||
SessionStopReq,
|
||||
SessionStopRes,
|
||||
AC_ChargeParameterDiscoveryReq,
|
||||
AC_ChargeParameterDiscoveryRes,
|
||||
AC_ChargeLoopReq,
|
||||
AC_ChargeLoopRes,
|
||||
};
|
||||
|
||||
template <typename T> struct TypeTrait {
|
||||
static const Type type = Type::None;
|
||||
};
|
||||
|
||||
template <typename InType, typename OutType> void convert(const InType&, OutType&);
|
||||
|
||||
template <typename MessageType> size_t serialize(const MessageType&, const io::StreamOutputView&);
|
||||
|
||||
//
|
||||
// definitions of type traits
|
||||
//
|
||||
#ifdef CREATE_TYPE_TRAIT
|
||||
#define CREATE_TYPE_TRAIT_PUSHED CREATE_TYPE_TRAIT
|
||||
#endif
|
||||
|
||||
#define CREATE_TYPE_TRAIT(struct_name, enum_name) \
|
||||
struct struct_name; \
|
||||
template <> struct TypeTrait<struct_name> { \
|
||||
static const Type type = Type::enum_name; \
|
||||
}
|
||||
|
||||
CREATE_TYPE_TRAIT(SupportedAppProtocolRequest, SupportedAppProtocolReq);
|
||||
CREATE_TYPE_TRAIT(SupportedAppProtocolResponse, SupportedAppProtocolRes);
|
||||
CREATE_TYPE_TRAIT(SessionSetupRequest, SessionSetupReq);
|
||||
CREATE_TYPE_TRAIT(SessionSetupResponse, SessionSetupRes);
|
||||
CREATE_TYPE_TRAIT(AuthorizationSetupRequest, AuthorizationSetupReq);
|
||||
CREATE_TYPE_TRAIT(AuthorizationSetupResponse, AuthorizationSetupRes);
|
||||
CREATE_TYPE_TRAIT(AuthorizationRequest, AuthorizationReq);
|
||||
CREATE_TYPE_TRAIT(AuthorizationResponse, AuthorizationRes);
|
||||
CREATE_TYPE_TRAIT(ServiceDiscoveryRequest, ServiceDiscoveryReq);
|
||||
CREATE_TYPE_TRAIT(ServiceDiscoveryResponse, ServiceDiscoveryRes);
|
||||
CREATE_TYPE_TRAIT(ServiceDetailRequest, ServiceDetailReq);
|
||||
CREATE_TYPE_TRAIT(ServiceDetailResponse, ServiceDetailRes);
|
||||
CREATE_TYPE_TRAIT(ServiceSelectionRequest, ServiceSelectionReq);
|
||||
CREATE_TYPE_TRAIT(ServiceSelectionResponse, ServiceSelectionRes);
|
||||
CREATE_TYPE_TRAIT(DC_ChargeParameterDiscoveryRequest, DC_ChargeParameterDiscoveryReq);
|
||||
CREATE_TYPE_TRAIT(DC_ChargeParameterDiscoveryResponse, DC_ChargeParameterDiscoveryRes);
|
||||
CREATE_TYPE_TRAIT(ScheduleExchangeRequest, ScheduleExchangeReq);
|
||||
CREATE_TYPE_TRAIT(ScheduleExchangeResponse, ScheduleExchangeRes);
|
||||
CREATE_TYPE_TRAIT(DC_CableCheckRequest, DC_CableCheckReq);
|
||||
CREATE_TYPE_TRAIT(DC_CableCheckResponse, DC_CableCheckRes);
|
||||
CREATE_TYPE_TRAIT(DC_PreChargeRequest, DC_PreChargeReq);
|
||||
CREATE_TYPE_TRAIT(DC_PreChargeResponse, DC_PreChargeRes);
|
||||
CREATE_TYPE_TRAIT(PowerDeliveryRequest, PowerDeliveryReq);
|
||||
CREATE_TYPE_TRAIT(PowerDeliveryResponse, PowerDeliveryRes);
|
||||
CREATE_TYPE_TRAIT(DC_ChargeLoopRequest, DC_ChargeLoopReq);
|
||||
CREATE_TYPE_TRAIT(DC_ChargeLoopResponse, DC_ChargeLoopRes);
|
||||
CREATE_TYPE_TRAIT(DC_WeldingDetectionRequest, DC_WeldingDetectionReq);
|
||||
CREATE_TYPE_TRAIT(DC_WeldingDetectionResponse, DC_WeldingDetectionRes);
|
||||
CREATE_TYPE_TRAIT(SessionStopRequest, SessionStopReq);
|
||||
CREATE_TYPE_TRAIT(SessionStopResponse, SessionStopRes);
|
||||
CREATE_TYPE_TRAIT(AC_ChargeParameterDiscoveryRequest, AC_ChargeParameterDiscoveryReq);
|
||||
CREATE_TYPE_TRAIT(AC_ChargeParameterDiscoveryResponse, AC_ChargeParameterDiscoveryRes);
|
||||
CREATE_TYPE_TRAIT(AC_ChargeLoopRequest, AC_ChargeLoopReq);
|
||||
CREATE_TYPE_TRAIT(AC_ChargeLoopResponse, AC_ChargeLoopRes);
|
||||
|
||||
#ifdef CREATE_TYPE_TRAIT_PUSHED
|
||||
#define CREATE_TYPE_TRAIT CREATE_TYPE_TRAIT_PUSHED
|
||||
#else
|
||||
#undef CREATE_TYPE_TRAIT
|
||||
#endif
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
// FIXME (aw): we only need the payload types from sdp.hpp, this could be shared in a separate header file
|
||||
#include <iso15118/io/sdp.hpp>
|
||||
#include <iso15118/io/stream_view.hpp>
|
||||
|
||||
#include "type.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
class Variant {
|
||||
public:
|
||||
using CustomDeleter = void (*)(void*);
|
||||
Variant(io::v2gtp::PayloadType, const io::StreamInputView&);
|
||||
template <typename MessageType> Variant(const MessageType& in) {
|
||||
static_assert(TypeTrait<MessageType>::type != Type::None, "Unhandled type!");
|
||||
|
||||
data = new MessageType;
|
||||
*static_cast<MessageType*>(data) = in;
|
||||
custom_deleter = [](void* ptr) { delete static_cast<MessageType*>(ptr); };
|
||||
type = message_20::TypeTrait<MessageType>::type;
|
||||
}
|
||||
~Variant();
|
||||
|
||||
Type get_type() const;
|
||||
|
||||
const std::string& get_error() const;
|
||||
|
||||
template <typename T> const T& get() const {
|
||||
static_assert(TypeTrait<T>::type != Type::None, "Unhandled type!");
|
||||
if (TypeTrait<T>::type != type) {
|
||||
throw std::runtime_error("Illegal message type access");
|
||||
}
|
||||
|
||||
return *static_cast<T*>(data);
|
||||
}
|
||||
|
||||
template <typename T> T const* get_if() const {
|
||||
static_assert(TypeTrait<T>::type != Type::None, "Unhandled type!");
|
||||
if (TypeTrait<T>::type != type) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return static_cast<T*>(data);
|
||||
}
|
||||
|
||||
private:
|
||||
CustomDeleter custom_deleter{nullptr};
|
||||
void* data{nullptr};
|
||||
Type type{Type::None};
|
||||
std::string error;
|
||||
};
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,122 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include <iso15118/d20/ev_information.hpp>
|
||||
#include <iso15118/d20/limits.hpp>
|
||||
#include <iso15118/d20/session.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/dc_charge_parameter_discovery.hpp>
|
||||
#include <iso15118/message/schedule_exchange.hpp>
|
||||
#include <iso15118/message/service_detail.hpp>
|
||||
#include <iso15118/message/service_selection.hpp>
|
||||
#include <iso15118/message/type.hpp>
|
||||
|
||||
namespace iso15118::session {
|
||||
|
||||
namespace dt = message_20::datatypes;
|
||||
|
||||
namespace feedback {
|
||||
|
||||
enum class Signal {
|
||||
REQUIRE_AUTH_EIM,
|
||||
START_CABLE_CHECK,
|
||||
SETUP_FINISHED,
|
||||
PRE_CHARGE_STARTED,
|
||||
CHARGE_LOOP_STARTED,
|
||||
CHARGE_LOOP_FINISHED,
|
||||
DC_OPEN_CONTACTOR,
|
||||
AC_CLOSE_CONTACTOR,
|
||||
AC_OPEN_CONTACTOR,
|
||||
DLINK_TERMINATE,
|
||||
DLINK_ERROR,
|
||||
DLINK_PAUSE,
|
||||
};
|
||||
|
||||
struct DcMaximumLimits {
|
||||
float voltage{NAN};
|
||||
float current{NAN};
|
||||
float power{NAN};
|
||||
};
|
||||
|
||||
using PresentVoltage = dt::RationalNumber;
|
||||
using MeterInfoRequested = bool;
|
||||
using DcReqControlMode = std::variant<dt::Scheduled_DC_CLReqControlMode, dt::BPT_Scheduled_DC_CLReqControlMode,
|
||||
dt::Dynamic_DC_CLReqControlMode, dt::BPT_Dynamic_DC_CLReqControlMode>;
|
||||
|
||||
using AcReqControlMode = std::variant<dt::Scheduled_AC_CLReqControlMode, dt::BPT_Scheduled_AC_CLReqControlMode,
|
||||
dt::Dynamic_AC_CLReqControlMode, dt::BPT_Dynamic_AC_CLReqControlMode>;
|
||||
|
||||
using DcChargeLoopReq = std::variant<DcReqControlMode, dt::DisplayParameters, PresentVoltage, MeterInfoRequested>;
|
||||
|
||||
using EvseTransferLimits = std::variant<d20::DcTransferLimits, d20::AcTransferLimits>;
|
||||
|
||||
using EvTransferLimits = std::variant<dt::DC_CPDReqEnergyTransferMode, dt::BPT_DC_CPDReqEnergyTransferMode,
|
||||
dt::AC_CPDReqEnergyTransferMode, dt::BPT_AC_CPDReqEnergyTransferMode>;
|
||||
using EvSEControlMode = std::variant<dt::Dynamic_SEReqControlMode, dt::Scheduled_SEReqControlMode>;
|
||||
|
||||
using AcChargeLoopReq = std::variant<AcReqControlMode, dt::DisplayParameters, MeterInfoRequested>;
|
||||
using AcLimits = std::variant<dt::AC_CPDReqEnergyTransferMode, dt::BPT_AC_CPDReqEnergyTransferMode>;
|
||||
|
||||
struct Callbacks {
|
||||
std::function<void(Signal)> signal;
|
||||
std::function<void(float)> dc_pre_charge_target_voltage;
|
||||
std::function<void(const DcChargeLoopReq&)> dc_charge_loop_req;
|
||||
std::function<void(const DcMaximumLimits&)> dc_max_limits;
|
||||
std::function<void(const AcChargeLoopReq&)> ac_charge_loop_req;
|
||||
std::function<void(const message_20::Type&)> v2g_message;
|
||||
std::function<void(const std::string&)> evccid;
|
||||
std::function<void(const std::string&)> selected_protocol;
|
||||
|
||||
std::function<void(const dt::ServiceCategory&, const std::optional<dt::AcConnector>&, const dt::ControlMode&,
|
||||
const dt::MobilityNeedsMode&, const EvseTransferLimits&, const EvTransferLimits&,
|
||||
const EvSEControlMode&, const std::vector<message_20::datatypes::ServiceCategory>&)>
|
||||
notify_ev_charging_needs;
|
||||
std::function<void(const d20::SelectedServiceParameters&)> selected_service_parameters;
|
||||
std::function<void(const d20::EVInformation&)> ev_information;
|
||||
std::function<std::optional<dt::ServiceParameterList>(uint16_t)> get_vas_parameters;
|
||||
std::function<void(const dt::VasSelectedServiceList&)> selected_vas_services;
|
||||
std::function<void(const AcLimits&)> ac_limits;
|
||||
std::function<void(const std::string&, const std::string&)> ev_termination;
|
||||
};
|
||||
|
||||
} // namespace feedback
|
||||
|
||||
class Feedback {
|
||||
public:
|
||||
Feedback(feedback::Callbacks);
|
||||
|
||||
void signal(feedback::Signal) const;
|
||||
void dc_pre_charge_target_voltage(float) const;
|
||||
void dc_charge_loop_req(const feedback::DcChargeLoopReq&) const;
|
||||
void dc_max_limits(const feedback::DcMaximumLimits&) const;
|
||||
void ac_charge_loop_req(const feedback::AcChargeLoopReq&) const;
|
||||
void v2g_message(const message_20::Type&) const;
|
||||
void evcc_id(const std::string&) const;
|
||||
void selected_protocol(const std::string&) const;
|
||||
|
||||
void notify_ev_charging_needs(const dt::ServiceCategory&, const std::optional<dt::AcConnector>&,
|
||||
const dt::ControlMode&, const dt::MobilityNeedsMode&,
|
||||
const feedback::EvseTransferLimits&, const feedback::EvTransferLimits&,
|
||||
const feedback::EvSEControlMode&,
|
||||
const std::vector<message_20::datatypes::ServiceCategory>&) const;
|
||||
void selected_service_parameters(const d20::SelectedServiceParameters&) const;
|
||||
void ev_information(const d20::EVInformation&) const;
|
||||
std::optional<dt::ServiceParameterList> get_vas_parameters(uint16_t) const;
|
||||
void selected_vas_services(const dt::VasSelectedServiceList&) const;
|
||||
void ac_limits(const feedback::AcLimits&) const;
|
||||
void ev_termination(const std::string&, const std::string&) const;
|
||||
|
||||
private:
|
||||
feedback::Callbacks callbacks;
|
||||
};
|
||||
|
||||
} // namespace iso15118::session
|
||||
@@ -0,0 +1,81 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <iso15118/config.hpp>
|
||||
|
||||
#include <everest/util/fsm/fsm.hpp>
|
||||
#include <iso15118/d20/config.hpp>
|
||||
#include <iso15118/d20/context.hpp>
|
||||
#include <iso15118/d20/control_event_queue.hpp>
|
||||
#include <iso15118/d20/states.hpp>
|
||||
|
||||
#include <iso15118/io/connection_abstract.hpp>
|
||||
#include <iso15118/io/poll_manager.hpp>
|
||||
#include <iso15118/io/sdp_packet.hpp>
|
||||
#include <iso15118/io/time.hpp>
|
||||
|
||||
#include <iso15118/session/feedback.hpp>
|
||||
#include <iso15118/session/logger.hpp>
|
||||
|
||||
#include <iso15118/d20/timeout.hpp>
|
||||
|
||||
namespace iso15118 {
|
||||
|
||||
struct SessionState {
|
||||
bool connected{false};
|
||||
bool new_data{false};
|
||||
bool fsm_needs_call{false};
|
||||
};
|
||||
|
||||
class Session {
|
||||
public:
|
||||
Session(std::unique_ptr<io::IConnection>, d20::SessionConfig, const session::feedback::Callbacks&,
|
||||
std::optional<d20::PauseContext>&);
|
||||
~Session();
|
||||
|
||||
TimePoint const& poll();
|
||||
void push_control_event(const d20::ControlEvent&);
|
||||
|
||||
bool is_finished() const {
|
||||
return (ctx.session_stopped or ctx.session_paused) and not message_exchange.has_response();
|
||||
}
|
||||
|
||||
void close();
|
||||
|
||||
private:
|
||||
std::unique_ptr<io::IConnection> connection;
|
||||
session::SessionLogger log;
|
||||
|
||||
SessionState state;
|
||||
// input buffer
|
||||
io::SdpPacket packet;
|
||||
|
||||
// output buffer
|
||||
uint8_t response_buffer[1028];
|
||||
|
||||
d20::MessageExchange message_exchange{{response_buffer + io::SdpPacket::V2GTP_HEADER_SIZE,
|
||||
sizeof(response_buffer) - io::SdpPacket::V2GTP_HEADER_SIZE}};
|
||||
|
||||
// control event buffer
|
||||
d20::ControlEventQueue control_event_queue;
|
||||
std::optional<d20::ControlEvent> active_control_event{std::nullopt};
|
||||
|
||||
d20::Context ctx;
|
||||
|
||||
fsm::v2::FSM<d20::StateBase> fsm;
|
||||
|
||||
TimePoint next_session_event;
|
||||
|
||||
d20::Timeouts timeouts;
|
||||
|
||||
void handle_connection_event(io::ConnectionEvent event);
|
||||
void send_response();
|
||||
std::optional<TimePoint> last_response_tx_time; // timestamp of the last response message sent
|
||||
std::optional<TimePoint> response_send_after; // time point when the next response message can be sent
|
||||
};
|
||||
|
||||
} // namespace iso15118
|
||||
@@ -0,0 +1,57 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
namespace iso15118::session {
|
||||
|
||||
namespace logging {
|
||||
|
||||
using TimePoint = std::chrono::time_point<std::chrono::system_clock>;
|
||||
|
||||
struct SimpleEvent {
|
||||
TimePoint time_point;
|
||||
std::string info;
|
||||
};
|
||||
|
||||
enum class ExiMessageDirection {
|
||||
FROM_EV,
|
||||
TO_EV,
|
||||
};
|
||||
struct ExiMessageEvent {
|
||||
TimePoint time_point;
|
||||
uint16_t payload_type;
|
||||
uint8_t const* data;
|
||||
size_t len;
|
||||
ExiMessageDirection direction;
|
||||
};
|
||||
|
||||
using Event = std::variant<SimpleEvent, ExiMessageEvent>;
|
||||
|
||||
using Callback = std::function<void(std::size_t id, const Event&)>;
|
||||
|
||||
void set_session_log_callback(const Callback&);
|
||||
|
||||
} // namespace logging
|
||||
|
||||
class SessionLogger {
|
||||
public:
|
||||
SessionLogger(void*);
|
||||
void enter_state(const std::string& new_state);
|
||||
void event(const std::string& info) const;
|
||||
void exi(uint16_t payload_type, uint8_t const* data, size_t len, logging::ExiMessageDirection direction) const;
|
||||
|
||||
void operator()(const std::string&) const;
|
||||
void operator()(const char* format, ...) const;
|
||||
|
||||
private:
|
||||
std::uintptr_t id;
|
||||
std::string last_state_name;
|
||||
};
|
||||
|
||||
} // namespace iso15118::session
|
||||
@@ -0,0 +1,72 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "config.hpp"
|
||||
#include <iso15118/d20/config.hpp>
|
||||
#include <iso15118/d20/control_event.hpp>
|
||||
#include <iso15118/d20/limits.hpp>
|
||||
#include <iso15118/io/poll_manager.hpp>
|
||||
#include <iso15118/io/sdp_server.hpp>
|
||||
#include <iso15118/io/time.hpp>
|
||||
#include <iso15118/message/common_types.hpp>
|
||||
#include <iso15118/session/feedback.hpp>
|
||||
#include <iso15118/session/iso.hpp>
|
||||
|
||||
namespace iso15118 {
|
||||
|
||||
struct TbdConfig {
|
||||
config::SSLConfig ssl{config::CertificateBackend::EVEREST_LAYOUT, {}, {}, {}, {}, {}, {}};
|
||||
std::string interface_name;
|
||||
config::TlsNegotiationStrategy tls_negotiation_strategy{config::TlsNegotiationStrategy::ACCEPT_CLIENT_OFFER};
|
||||
bool enable_sdp_server{true};
|
||||
};
|
||||
|
||||
class TbdController {
|
||||
public:
|
||||
TbdController(TbdConfig, session::feedback::Callbacks, d20::EvseSetupConfig);
|
||||
|
||||
void loop();
|
||||
|
||||
void send_control_event(const d20::ControlEvent&);
|
||||
|
||||
void update_authorization_services(const std::vector<message_20::datatypes::Authorization>& services,
|
||||
bool cert_install_service);
|
||||
void update_dc_limits(const d20::DcTransferLimits&);
|
||||
void update_powersupply_limits(const d20::DcTransferLimits&);
|
||||
void update_energy_modes(const std::vector<message_20::datatypes::ServiceCategory>&);
|
||||
void update_ac_limits(const d20::AcTransferLimits&);
|
||||
|
||||
void update_supported_vas_services(const std::vector<uint16_t>& vas_services);
|
||||
|
||||
void set_dlink_ready(bool ready);
|
||||
|
||||
private:
|
||||
io::PollManager poll_manager;
|
||||
std::unique_ptr<io::SdpServer> sdp_server;
|
||||
|
||||
std::unique_ptr<Session> session;
|
||||
|
||||
// callbacks for sdp server
|
||||
void handle_sdp_server_input();
|
||||
|
||||
const TbdConfig config;
|
||||
const session::feedback::Callbacks callbacks;
|
||||
|
||||
d20::EvseSetupConfig evse_setup;
|
||||
|
||||
std::string interface_name;
|
||||
|
||||
std::optional<d20::PauseContext> pause_ctx{std::nullopt};
|
||||
|
||||
static constexpr uint32_t V2G_COMMUNICATION_SETUP_TIMEOUT_MS{18000};
|
||||
std::optional<Timeout> communication_setup_timeout;
|
||||
};
|
||||
|
||||
} // namespace iso15118
|
||||
Reference in New Issue
Block a user