Skip to content
This repository was archived by the owner on Feb 26, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion include/iso15118/ev/d20/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <iso15118/message/variant.hpp>

#include <iso15118/ev/d20/session.hpp>
#include <iso15118/ev/session/feedback.hpp>
#include <iso15118/io/sha_hash.hpp>

namespace iso15118::ev::d20 {
Expand Down Expand Up @@ -56,7 +57,7 @@ class Session;

class Context {
public:
Context(MessageExchange&);
Context(session::feedback::Callbacks, MessageExchange&);

template <typename StateType, typename... Args> BasePointerType create_state(Args&&... args) {
return std::make_unique<StateType>(*this, std::forward<Args>(args)...);
Expand Down Expand Up @@ -105,6 +106,11 @@ class Context {
return session;
}

// Contains the EVSE received data
EVSESessionInfo evse_session_info;

const iso15118::ev::d20::session::Feedback feedback;

private:
MessageExchange& message_exchange;

Expand Down
17 changes: 17 additions & 0 deletions include/iso15118/ev/d20/evse_session_info.hpp
Original file line number Diff line number Diff line change
@@ -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>

namespace iso15118::ev::d20 {

// Holds information reported by the EVSE that could be different between sessions
struct EVSESessionInfo {
std::vector<message_20::datatypes::Authorization> auth_services{};
bool certificate_installation_service{false};
std::optional<std::vector<message_20::datatypes::Name>> supported_providers{std::nullopt};
message_20::datatypes::GenChallenge gen_challenge{std::array<uint8_t, 16>{}}; // 16 bytes
};

} // namespace iso15118::ev::d20
Comment thread
cienporcien marked this conversation as resolved.
Outdated
1 change: 1 addition & 0 deletions include/iso15118/ev/d20/session.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <array>
#include <cstdint>
#include <iso15118/io/sha_hash.hpp>
Comment thread
cienporcien marked this conversation as resolved.
Outdated

namespace iso15118::ev::d20 {

Expand Down
19 changes: 19 additions & 0 deletions include/iso15118/ev/d20/state/authorization.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Pionix GmbH and Contributors to EVerest
#pragma once

#include "../states.hpp"

namespace iso15118::ev::d20::state {

struct Authorization : public StateBase {
public:
Authorization(Context& ctx) : StateBase(ctx, StateID::Authorization) {
}

void enter() final;

Result feed(Event) final;
};

} // namespace iso15118::ev::d20::state
Comment thread
cienporcien marked this conversation as resolved.
4 changes: 2 additions & 2 deletions include/iso15118/ev/detail/d20/context_helper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// Copyright 2025 Pionix GmbH and Contributors to EVerest
#pragma once

// #include <iso15118/d20/context.hpp>
// #include <iso15118/d20/session.hpp>
#include <iso15118/ev/d20/context.hpp>
#include <iso15118/ev/d20/session.hpp>
#include <iso15118/message/common_types.hpp>

// Forward declaration
Expand Down
42 changes: 42 additions & 0 deletions include/iso15118/ev/session/feedback.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// 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/ev/d20/evse_session_info.hpp>
#include <iso15118/ev/d20/session.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>
Comment thread
cienporcien marked this conversation as resolved.

namespace iso15118::ev::d20::session {

namespace dt = message_20::datatypes;

namespace feedback {

struct Callbacks {
std::function<void(const EVSESessionInfo&)> evse_session_info;
};

} // namespace feedback

class Feedback {
public:
Feedback(feedback::Callbacks);

void evse_session_info(const EVSESessionInfo&) const;

private:
feedback::Callbacks callbacks;
};

} // namespace iso15118::ev::d20::session
2 changes: 2 additions & 0 deletions src/iso15118/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ target_sources(iso15118
ev/d20/context_helper.cpp
ev/d20/state/session_setup.cpp
ev/d20/state/authorization_setup.cpp
ev/d20/state/authorization.cpp
ev/d20/state/dc_charge_parameter_discovery.cpp
ev/session/feedback.cpp

io/connection_plain.cpp
io/logging.cpp
Expand Down
9 changes: 5 additions & 4 deletions src/iso15118/ev/d20/context.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Pionix GmbH and Contributors to EVerest
#include <iso15118/ev/d20/context.hpp>

#include <iso15118/detail/helper.hpp>
#include <iso15118/ev/d20/context.hpp>
#include <iso15118/ev/detail/d20/context_helper.hpp>

namespace iso15118::ev::d20 {

Expand All @@ -28,13 +28,14 @@ std::unique_ptr<message_20::Variant> MessageExchange::pull_response() {

message_20::Type MessageExchange::peek_response_type() const {
if (not response) {
logf_warning("Tried to access V2G message, but there is none");
iso15118::logf_warning("Tried to access V2G message, but there is none");
Comment thread
cienporcien marked this conversation as resolved.
Outdated
return message_20::Type::None;
}
return response->get_type();
}

Context::Context(MessageExchange& message_exchange_) : message_exchange(message_exchange_) {
Context::Context(session::feedback::Callbacks feedback_callbacks, MessageExchange& message_exchange_) :
feedback(std::move(feedback_callbacks)), message_exchange(message_exchange_) {
}

std::unique_ptr<message_20::Variant> Context::pull_response() {
Expand Down
27 changes: 27 additions & 0 deletions src/iso15118/ev/d20/state/authorization.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Pionix GmbH and Contributors to EVerest
#include <iso15118/detail/helper.hpp>
#include <iso15118/ev/d20/state/authorization.hpp>
#include <iso15118/ev/detail/d20/context_helper.hpp>
#include <iso15118/message/authorization.hpp>

namespace iso15118::ev::d20::state {

message_20::AuthorizationRequest handle_request() {
// TODO(SL): Implement
return message_20::AuthorizationRequest();
}

void Authorization::enter() {
// TODO(SL): Adding logging
}

Result Authorization::feed(Event ev) {
if (ev != Event::V2GTP_MESSAGE) {
return {};
} else {
return {};
}
}

} // namespace iso15118::ev::d20::state
Comment thread
cienporcien marked this conversation as resolved.
Outdated
95 changes: 92 additions & 3 deletions src/iso15118/ev/d20/state/authorization_setup.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,103 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Pionix GmbH and Contributors to EVerest
// Copyright 2025 Pionix GmbH, Roger Bedell and Contributors to EVerest
#include <iso15118/detail/helper.hpp>
#include <iso15118/ev/d20/context.hpp>
#include <iso15118/ev/d20/state/authorization.hpp>
#include <iso15118/ev/d20/state/authorization_setup.hpp>
#include <iso15118/ev/detail/d20/context_helper.hpp>
#include <iso15118/ev/session/feedback.hpp>
#include <iso15118/message/authorization.hpp>
#include <iso15118/message/authorization_setup.hpp>

namespace iso15118::ev::d20::state {

namespace {
using ResponseCode = message_20::datatypes::ResponseCode;
bool check_response_code(ResponseCode response_code) {
switch (response_code) {
case ResponseCode::OK:
return true;
[[fallthrough]];
default:
return false;
}
Comment thread
cienporcien marked this conversation as resolved.
}
} // namespace

void AuthorizationSetup::enter() {
// TODO(SL): Adding logging
}

Result AuthorizationSetup::feed([[maybe_unused]] Event ev) {
return {};
}
if (ev != Event::V2GTP_MESSAGE) {
return {};
}

const auto variant = m_ctx.pull_response();

if (const auto res = variant->get_if<message_20::AuthorizationSetupResponse>()) {

if (not check_response_code(res->response_code)) {
m_ctx.stop_session(true); // Tell stack to close the tcp/tls connection
return {};
}

if (res->certificate_installation_service) {
// TODO(RB): Implement certificate installation service
logf_warning("EVSE supports certificate installation service, but this is not implemented in the EV yet.");
// Remember it in the context for later use
m_ctx.evse_session_info.certificate_installation_service = true;
}

// Save the offered authorization services in the session context so we can use it later and also report it to
// the EV.
m_ctx.evse_session_info.auth_services = res->authorization_services;

if (res->authorization_mode.index() == 1) { // PnC
Comment thread
cienporcien marked this conversation as resolved.
Outdated
const auto& pnc_auth_mode =
std::get<message_20::datatypes::PnC_ASResAuthorizationMode>(res->authorization_mode);
if (pnc_auth_mode.supported_providers.has_value()) {
m_ctx.evse_session_info.supported_providers = pnc_auth_mode.supported_providers.value();
}
Comment thread
cienporcien marked this conversation as resolved.
Outdated
m_ctx.evse_session_info.gen_challenge = pnc_auth_mode.gen_challenge;
} else {
// EIM selected, nothing to do here for now since authorization_mode is empty for EIM
}
// Inform the ev about the evse session information
m_ctx.feedback.evse_session_info(m_ctx.evse_session_info);

// Send request and transition to next state
message_20::AuthorizationRequest req;
setup_header(req.header, m_ctx.get_session());
// TODO(RB): Choose the authorization service based on user preference and what the evse supports
// For now, we just pick the first one offered by the evse
if (m_ctx.evse_session_info.auth_services.empty()) {
logf_error("No authorization services offered by the EVSE. Abort the session.");
m_ctx.stop_session(true); // Tell stack to close the tcp/tls connection
return {};
}
req.selected_authorization_service = m_ctx.evse_session_info.auth_services.front();
if (req.selected_authorization_service == message_20::datatypes::Authorization::EIM) {
req.authorization_mode = message_20::datatypes::EIM_ASReqAuthorizationMode{};
} else if (req.selected_authorization_service == message_20::datatypes::Authorization::PnC) {
// TODO(RB): Fill in the PnC authorization mode data
// For now, we just fill in dummy data
message_20::datatypes::PnC_ASReqAuthorizationMode pnc_mode;
pnc_mode.id = "dummy_id"; // TODO(RB): Replace with actual ID
pnc_mode.gen_challenge = m_ctx.evse_session_info.gen_challenge; // Use the challenge from the evse
// TODO(RB): Fill in the contract certificate chain
req.authorization_mode = pnc_mode;
Comment thread
SebaLukas marked this conversation as resolved.
Outdated
} else {
logf_error("Unknown authorization service selected. Abort the session.");
m_ctx.stop_session(true); // Tell stack to close the tcp/tls connection
return {};
}
m_ctx.respond(req);
return m_ctx.create_state<Authorization>();
} else {
logf_error("expected AuthorizationSetupResponse! But code type id: %d", variant->get_type());
m_ctx.stop_session(true); // Tell stack to close the tcp/tls connection
return {};
}
}
} // namespace iso15118::ev::d20::state
16 changes: 16 additions & 0 deletions src/iso15118/ev/session/feedback.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2023 Pionix GmbH and Contributors to EVerest
#include <iso15118/ev/session/feedback.hpp>

#include <iso15118/detail/helper.hpp>
#include <iso15118/ev/d20/evse_session_info.hpp>
namespace iso15118::ev::d20::session {

Feedback::Feedback(feedback::Callbacks callbacks_) : callbacks(std::move(callbacks_)) {
}

void Feedback::evse_session_info(const d20::EVSESessionInfo& info) const {
call_if_available(callbacks.evse_session_info, info);
}

} // namespace iso15118::ev::d20::session
3 changes: 2 additions & 1 deletion test/iso15118/ev/fsm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ function(create_ev_fsm_test_target NAME)
catch_discover_tests(test_ev_fsm_${NAME})
endfunction()

create_ev_fsm_test_target(session_setup)
create_ev_fsm_test_target(session_setup)
create_ev_fsm_test_target(authorization_setup)
Comment thread
cienporcien marked this conversation as resolved.
Outdated
Loading