diff --git a/include/iso15118/ev/d20/context.hpp b/include/iso15118/ev/d20/context.hpp index dab9edd3..7a146732 100644 --- a/include/iso15118/ev/d20/context.hpp +++ b/include/iso15118/ev/d20/context.hpp @@ -9,6 +9,7 @@ #include #include +#include namespace iso15118::ev::d20 { @@ -76,6 +77,26 @@ class Context { session_stopped = stop; } + bool is_session_stopped() { + return session_stopped; + } + + void set_charger_cert_hash(std::optional hash) { + charger_cert_hash = hash; + } + + auto get_charger_cert_hash() const { + return charger_cert_hash; + } + + void set_charger_cert_session_hash(std::optional hash) { + charger_cert_session_hash = hash; + } + + auto get_charger_cert_session_hash() const { + return charger_cert_session_hash; + } + message_20::datatypes::Identifier get_evcc_id() { return evcc_id; } @@ -93,6 +114,10 @@ class Context { Session session{std::array{}}; bool session_stopped{false}; + + std::optional charger_cert_hash{std::nullopt}; + + std::optional charger_cert_session_hash{std::nullopt}; }; } // namespace iso15118::ev::d20 diff --git a/include/iso15118/ev/d20/session.hpp b/include/iso15118/ev/d20/session.hpp index f52ecd41..c5c283df 100644 --- a/include/iso15118/ev/d20/session.hpp +++ b/include/iso15118/ev/d20/session.hpp @@ -11,13 +11,18 @@ class Session { public: static constexpr auto ID_LENGTH = 8; - Session(std::array id_) : id(id_) {}; + Session(std::array id_) : id(id_){}; ~Session() = default; std::array get_id() const { return id; } + // Sets the session ID, mostly for testing purposes + void set_id(const std::array& new_id) { + id = new_id; + } + private: std::array id{}; }; diff --git a/include/iso15118/ev/d20/state/authorization_setup.hpp b/include/iso15118/ev/d20/state/authorization_setup.hpp index 8b20c2f8..f63125ee 100644 --- a/include/iso15118/ev/d20/state/authorization_setup.hpp +++ b/include/iso15118/ev/d20/state/authorization_setup.hpp @@ -6,9 +6,10 @@ namespace iso15118::ev::d20::state { -struct AuthorizationSetup : public StateBase{ +struct AuthorizationSetup : public StateBase { public: - AuthorizationSetup(Context& ctx) : StateBase(ctx, StateID::AuthorizationSetup) {} + AuthorizationSetup(Context& ctx) : StateBase(ctx, StateID::AuthorizationSetup) { + } void enter() final; diff --git a/include/iso15118/ev/d20/state/dc_charge_parameter_discovery.hpp b/include/iso15118/ev/d20/state/dc_charge_parameter_discovery.hpp new file mode 100644 index 00000000..359b7e98 --- /dev/null +++ b/include/iso15118/ev/d20/state/dc_charge_parameter_discovery.hpp @@ -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 DC_ChargeParameterDiscovery : public StateBase { +public: + DC_ChargeParameterDiscovery(Context& ctx) : StateBase(ctx, StateID::DC_ChargeParameterDiscovery) { + } + + void enter() final; + + Result feed(Event) final; +}; + +} // namespace iso15118::ev::d20::state diff --git a/include/iso15118/ev/d20/state/session_setup.hpp b/include/iso15118/ev/d20/state/session_setup.hpp index d31cf1c9..840cfe31 100644 --- a/include/iso15118/ev/d20/state/session_setup.hpp +++ b/include/iso15118/ev/d20/state/session_setup.hpp @@ -6,9 +6,10 @@ namespace iso15118::ev::d20::state { -struct SessionSetup : public StateBase{ +struct SessionSetup : public StateBase { public: - SessionSetup(Context& ctx) : StateBase(ctx, StateID::SessionSetup) {} + SessionSetup(Context& ctx) : StateBase(ctx, StateID::SessionSetup) { + } void enter() final; diff --git a/include/iso15118/ev/d20/states.hpp b/include/iso15118/ev/d20/states.hpp index 214cbc20..99c949ef 100644 --- a/include/iso15118/ev/d20/states.hpp +++ b/include/iso15118/ev/d20/states.hpp @@ -52,7 +52,7 @@ struct StateBase { using ContainerType = BasePointerType; using EventType = Event; - StateBase(Context& ctx, StateID id) : m_ctx(ctx), m_id(id) {}; + StateBase(Context& ctx, StateID id) : m_ctx(ctx), m_id(id){}; virtual ~StateBase() = default; @@ -60,9 +60,9 @@ struct StateBase { return m_id; } - virtual void enter() {}; + virtual void enter(){}; virtual Result feed(Event) = 0; - virtual void leave() {}; + virtual void leave(){}; protected: Context& m_ctx; diff --git a/src/iso15118/CMakeLists.txt b/src/iso15118/CMakeLists.txt index 2f648287..7454bc2f 100644 --- a/src/iso15118/CMakeLists.txt +++ b/src/iso15118/CMakeLists.txt @@ -16,6 +16,7 @@ target_sources(iso15118 ev/d20/context_helper.cpp ev/d20/state/session_setup.cpp ev/d20/state/authorization_setup.cpp + ev/d20/state/dc_charge_parameter_discovery.cpp io/connection_plain.cpp io/logging.cpp diff --git a/src/iso15118/ev/d20/state/dc_charge_parameter_discovery.cpp b/src/iso15118/ev/d20/state/dc_charge_parameter_discovery.cpp new file mode 100644 index 00000000..f195df51 --- /dev/null +++ b/src/iso15118/ev/d20/state/dc_charge_parameter_discovery.cpp @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 Pionix GmbH and Contributors to EVerest +#include +#include +#include +#include + +namespace iso15118::ev::d20::state { + +void DC_ChargeParameterDiscovery::enter() { + // TODO(SL): Adding logging +} + +Result DC_ChargeParameterDiscovery::feed(Event ev) { + if (ev != Event::V2GTP_MESSAGE) { + return {}; + } else { + return {}; + } +} + +} // namespace iso15118::ev::d20::state diff --git a/src/iso15118/ev/d20/state/session_setup.cpp b/src/iso15118/ev/d20/state/session_setup.cpp index 6da4def1..3da2b1a5 100644 --- a/src/iso15118/ev/d20/state/session_setup.cpp +++ b/src/iso15118/ev/d20/state/session_setup.cpp @@ -1,36 +1,62 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright 2025 Pionix GmbH and Contributors to EVerest -#include - -#include - -#include -#include -#include - +// Copyright 2025 Pionix GmbH, Roger Bedell, and Contributors to EVerest +#include +#include #include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include namespace iso15118::ev::d20::state { namespace { -using ResponseCode = message_20::SupportedAppProtocolResponse::ResponseCode; +using ResponseCode = message_20::datatypes::ResponseCode; bool check_response_code(ResponseCode response_code) { switch (response_code) { - case ResponseCode::OK_SuccessfulNegotiation: + case ResponseCode::OK_NewSessionEstablished: + return true; + case ResponseCode::OK_OldSessionJoined: return true; - case ResponseCode::OK_SuccessfulNegotiationWithMinorDeviation: - logf_error("Evse has sent SupportedAppProtocolResponse with a ResponseCode: " - "OK_SuccessfulNegotiationWithMinorDeviation. In 15118-20 this is not allowed!"); - return false; - case ResponseCode::Failed_NoNegotiation: - logf_error("Evse has sent SupportedAppProtocolResponse with a ResponseCode: " - "Failed_NoNegotiation"); [[fallthrough]]; default: return false; } } + +bool session_is_zero(const message_20::datatypes::SessionId& session_id) { + return std::all_of(session_id.begin(), session_id.end(), [](int i) { return i == 0; }); +} + +io::sha512_hash_t calculate_new_cert_session_id_hash(const io::sha512_hash_t& charger_cert_hash, + const message_20::datatypes::SessionId& session_id) { + io::sha512_hash_t session_id_charger_hash{}; + std::array concatenated_session_id_charger{}; + + std::copy(session_id.begin(), session_id.end(), concatenated_session_id_charger.begin()); + std::copy(charger_cert_hash.begin(), charger_cert_hash.end(), + concatenated_session_id_charger.begin() + session_id.size()); + + unsigned int digestlen{0}; + + const auto result = EVP_Digest(concatenated_session_id_charger.data(), concatenated_session_id_charger.size(), + session_id_charger_hash.data(), &digestlen, EVP_sha512(), nullptr); + if (not result) { + logf_error("X509_digest failed"); + return std::array{}; + } + + return session_id_charger_hash; +} + } // namespace void SessionSetup::enter() { @@ -43,34 +69,94 @@ Result SessionSetup::feed(Event ev) { } const auto variant = m_ctx.pull_response(); + bool session_resumed = false; - if (const auto res = variant->get_if()) { + if (const auto res = variant->get_if()) { if (not check_response_code(res->response_code)) { m_ctx.stop_session(true); // Tell stack to close the tcp/tls connection return {}; } - if (not res->schema_id.has_value()) { - logf_error( - "SupportedAppProtocolRes should have a SchemaId. This is here not the case! Abort the session."); + if (res->evseid.size() <= 0) { + logf_error("EVSEID is empty. Abort the session."); m_ctx.stop_session(true); // Tell stack to close the tcp/tls connection return {}; + } else { + // m_ctx.evse_info.evse_id = res->evseid; } - // TODO(SL): Check schema id and select the correct schema - - // 2. Create SessionSetupReq - message_20::SessionSetupRequest req; - - setup_header(req.header, m_ctx.get_session()); - req.evccid = m_ctx.get_evcc_id(); - - m_ctx.respond(req); + // TODO(RB): Check if the returned sessionid is ok by checking against the sent one. + // If the sent one was 0, the new one should be non zero. + const auto charger_cert_hash = m_ctx.get_charger_cert_hash(); + + // Handle new session establishment or session resumption by checking the response_code from the EVSE + if (res->response_code == message_20::datatypes::ResponseCode::OK_NewSessionEstablished) { + logf_info("New session established by EVSE."); + + if (session_is_zero(res->header.session_id)) { + logf_error("Returned SessionID is zero although a new session was requested. Abort the session."); + m_ctx.stop_session(true); // Tell stack to close the tcp/tls connection + return {}; + } else { + // New session established successfully + m_ctx.get_session().set_id(res->header.session_id); + + // Save the charger cert hash and the calculated hash of charger cert and session id for later use + if (charger_cert_hash.has_value()) { + m_ctx.set_charger_cert_hash(charger_cert_hash.value()); + const auto new_charger_cert_session_hash = + calculate_new_cert_session_id_hash(charger_cert_hash.value(), res->header.session_id); + m_ctx.set_charger_cert_session_hash(new_charger_cert_session_hash); + } else { + logf_warning("No charger certificate hash available although a new session was established."); + } + } + } else if (res->response_code == message_20::datatypes::ResponseCode::OK_OldSessionJoined) { + // If the sent SessionID was non 0, the returned one should be the same. In order to + // proceed it needs to be verified that the pairing of charger and ev is the same as before by checking a + // hash of the charger cert and the session id that was saved when the session was paused with the new hash + // calculated from the returned session id and the charger cert hash. If they are not the same, this is an + // error, and the session should be shut down. + // Make sure we have a charger cert hash to check against + if (not charger_cert_hash.has_value()) { + logf_error( + "No charger certificate hash available although an old session was resumed. Abort the session."); + m_ctx.stop_session(true); // Tell stack to close the tcp/tls connection + return {}; + } + const auto new_charger_cert_session_hash = + calculate_new_cert_session_id_hash(charger_cert_hash.value(), res->header.session_id); + if (m_ctx.get_charger_cert_session_hash() != new_charger_cert_session_hash) { + logf_error("Charger certificate/session hash does not match the saved one although an old session was " + "resumed. Abort the session."); + m_ctx.stop_session(true); // Tell stack to close the tcp/tls connection + return {}; + } + // If we reach this point, the session has been successfully resumed + logf_info("Session resumed successfully."); + + session_resumed = true; + } - return {m_ctx.create_state()}; + // if the session is resumed, then no authorization setup or authorization needs to be done, we continue with + // what was already in progress in the context. + if (session_resumed) { + logf_info("Session is resumed, continuing with the existing context."); + // TODO(RB) Go directly to either AC or DC ChargeParameterDiscovery + message_20::DC_ChargeParameterDiscoveryRequest req; + setup_header(req.header, m_ctx.get_session()); + m_ctx.respond(req); + // The DC_ChargeParameterDiscovery state handles the DC_ChargeParameterDiscoveryResponse + return {m_ctx.create_state()}; + } else { + message_20::AuthorizationSetupRequest req; + setup_header(req.header, m_ctx.get_session()); + m_ctx.respond(req); + return {m_ctx.create_state()}; + } } else { - logf_error("expected SupportedAppProtocol! But code type id: %d", variant->get_type()); + logf_error("expected SessionSetupResponse! But code type id: %d", variant->get_type()); m_ctx.stop_session(true); // Tell stack to close the tcp/tls connection return {}; } diff --git a/test/iso15118/ev/fsm/helper.hpp b/test/iso15118/ev/fsm/helper.hpp index 383978dd..77407c01 100644 --- a/test/iso15118/ev/fsm/helper.hpp +++ b/test/iso15118/ev/fsm/helper.hpp @@ -13,7 +13,7 @@ using namespace iso15118; class FsmStateHelper { public: - FsmStateHelper() : ctx(msg_exch) {}; + FsmStateHelper() : ctx(msg_exch){}; ev::d20::Context& get_context(); diff --git a/test/iso15118/ev/fsm/session_setup.cpp b/test/iso15118/ev/fsm/session_setup.cpp index d16ad800..0333278e 100644 --- a/test/iso15118/ev/fsm/session_setup.cpp +++ b/test/iso15118/ev/fsm/session_setup.cpp @@ -5,8 +5,9 @@ #include "helper.hpp" #include +#include +#include #include -#include #include using namespace iso15118; @@ -19,39 +20,138 @@ SCENARIO("ISO15118-20 EV session setup state transitions") { GIVEN("Good case - new session") { fsm::v2::FSM fsm{ctx.create_state()}; - const auto res = message_20::SupportedAppProtocolResponse{ - message_20::SupportedAppProtocolResponse::ResponseCode::OK_SuccessfulNegotiation, 0}; + const auto header = message_20::Header{ + .session_id = std::array{0x10, 0x34, 0xAB, 0x7A, 0x01, 0xF3, 0x95, 0x02}, + .timestamp = 1691411798, + }; + const auto res = message_20::SessionSetupResponse{ + header, message_20::datatypes::ResponseCode::OK_NewSessionEstablished, "everest se"}; state_helper.handle_response(res); const auto result = fsm.feed(ev::d20::Event::V2GTP_MESSAGE); - THEN("Check if session setup is sent") { + THEN("Check if passes to authorization setup state and sends AuthorizationSetupRequest") { REQUIRE(result.transitioned() == true); REQUIRE(fsm.get_current_state_id() == ev::d20::StateID::AuthorizationSetup); - const auto response_message = ctx.get_request(); - REQUIRE(response_message.has_value()); + const auto request_message = ctx.get_request(); + REQUIRE(request_message.has_value()); - const auto& session_setup_req = response_message.value(); - REQUIRE(session_setup_req.header.session_id == std::array{0, 0, 0, 0, 0, 0, 0, 0}); - // TODO(SL): Missing check for evcc_id + const auto& authorization_setup_req = request_message.value(); + REQUIRE(authorization_setup_req.header.session_id == ctx.get_session().get_id()); } } + GIVEN("Good case - resume old session") { + fsm::v2::FSM fsm{ctx.create_state()}; + + // Set the session ID to match the one in the SessionSetupResponse + ctx.get_session().set_id(std::array{0x10, 0x34, 0xAB, 0x7A, 0x01, 0xF3, 0x95, 0x02}); + + // Set a the same charger cert hash as the one that was used to create the session + ctx.set_charger_cert_hash(io::sha512_hash_t{ + 0x3F, 0x66, 0xE4, 0x5F, 0x3A, 0x30, 0x3B, 0x8F, 0x47, 0xCD, 0xD6, 0x86, 0xAD, 0x75, 0x13, 0x6F, + 0xCE, 0x44, 0xE6, 0xAD, 0xDC, 0x52, 0x8A, 0x6A, 0x3D, 0xAC, 0x5F, 0x8D, 0xCB, 0x5A, 0x67, 0xF3, + 0xE5, 0xA5, 0xF2, 0x56, 0x74, 0x5A, 0xFA, 0xF2, 0x28, 0x31, 0xCE, 0xAB, 0xE8, 0x3C, 0xD7, 0x3C, + 0xF2, 0x83, 0x81, 0xAA, 0x5D, 0x87, 0x13, 0xA5, 0x78, 0xA8, 0xB4, 0xAB, 0x0D, 0x62, 0x1F, 0x84}); + + ctx.set_charger_cert_session_hash(io::sha512_hash_t{ + 0x77, 0xb7, 0x7a, 0xd3, 0x3, 0xd0, 0xb1, 0xed, 0x28, 0xe8, 0x23, 0xed, 0xe4, 0xe9, 0xc3, 0xe5, + 0x85, 0xce, 0x47, 0x4d, 0xa5, 0x91, 0xa8, 0x40, 0x18, 0xdb, 0xac, 0x2c, 0xf0, 0x22, 0x30, 0x3c, + 0x51, 0x13, 0xbb, 0x5, 0x95, 0x30, 0x66, 0x11, 0x46, 0xb8, 0x94, 0x3e, 0x59, 0x6d, 0x35, 0xae, + 0x9, 0x76, 0xfa, 0x2a, 0x3b, 0xb0, 0x63, 0x6e, 0x12, 0x7f, 0x10, 0xdb, 0x60, 0xd6, 0xb7, 0x4d}); + + const auto header = message_20::Header{ + .session_id = std::array{0x10, 0x34, 0xAB, 0x7A, 0x01, 0xF3, 0x95, 0x02}, + .timestamp = 1691411798, + }; + const auto res = message_20::SessionSetupResponse{ + header, message_20::datatypes::ResponseCode::OK_OldSessionJoined, "everest se"}; + + state_helper.handle_response(res); + const auto result = fsm.feed(ev::d20::Event::V2GTP_MESSAGE); + + THEN("Check if passes to DC_ChargeParameterDiscovery state and that DC_ChargeParameterDiscoveryReq is sent") { + REQUIRE(result.transitioned() == true); + REQUIRE(fsm.get_current_state_id() == ev::d20::StateID::DC_ChargeParameterDiscovery); + + const auto request_message = ctx.get_request(); + REQUIRE(request_message.has_value()); + + const auto& dc_charge_param_discovery_req = request_message.value(); + REQUIRE(dc_charge_param_discovery_req.header.session_id == ctx.get_session().get_id()); + } + } + + GIVEN("Bad case - resume old session with wrong session id") { + fsm::v2::FSM fsm{ctx.create_state()}; + + // Set the session ID to not match the one in the SessionSetupResponse + ctx.get_session().set_id(std::array{0x10, 0x34, 0xAB, 0x7A, 0x01, 0xF3, 0x95, 0x02}); + + // Set a the same charger cert hash as the one that was used to create the session + ctx.set_charger_cert_hash(io::sha512_hash_t{ + 0x3F, 0x66, 0xE4, 0x5F, 0x3A, 0x30, 0x3B, 0x8F, 0x47, 0xCD, 0xD6, 0x86, 0xAD, 0x75, 0x13, 0x6F, + 0xCE, 0x44, 0xE6, 0xAD, 0xDC, 0x52, 0x8A, 0x6A, 0x3D, 0xAC, 0x5F, 0x8D, 0xCB, 0x5A, 0x67, 0xF3, + 0xE5, 0xA5, 0xF2, 0x56, 0x74, 0x5A, 0xFA, 0xF2, 0x28, 0x31, 0xCE, 0xAB, 0xE8, 0x3C, 0xD7, 0x3C, + 0xF2, 0x83, 0x81, 0xAA, 0x5D, 0x87, 0x13, 0xA5, 0x78, 0xA8, 0xB4, 0xAB, 0x0D, 0x62, 0x1F, 0x84}); + + ctx.set_charger_cert_session_hash(io::sha512_hash_t{ + 0x77, 0xb7, 0x7a, 0xd3, 0x3, 0xd0, 0xb1, 0xed, 0x28, 0xe8, 0x23, 0xed, 0xe4, 0xe9, 0xc3, 0xe5, + 0x85, 0xce, 0x47, 0x4d, 0xa5, 0x91, 0xa8, 0x40, 0x18, 0xdb, 0xac, 0x2c, 0xf0, 0x22, 0x30, 0x3c, + 0x51, 0x13, 0xbb, 0x5, 0x95, 0x30, 0x66, 0x11, 0x46, 0xb8, 0x94, 0x3e, 0x59, 0x6d, 0x35, 0xae, + 0x9, 0x76, 0xfa, 0x2a, 0x3b, 0xb0, 0x63, 0x6e, 0x12, 0x7f, 0x10, 0xdb, 0x60, 0xd6, 0xb7, 0x4d}); - // GIVEN("Good case - new session: DC Schema is selected") { - // THEN("Check if dc state machine is selected") { - // } - // } - // GIVEN("Good case - new session: AC Schema is selected") { - // THEN("Check if ac state machine is selected") { - // } - // } - // GIVEN("Bad case - Other message then SupportedAppProtocolRes") { - // } - // GIVEN("Bad case - ResponseCode Failed") { - // } - // GIVEN("Bad case - ResponseCode Ok but no SchemaID") { - // } - // GIVEN("Good case - Resume old session") { - // } + const auto header = message_20::Header{ + .session_id = std::array{0x10, 0x34, 0xAB, 0x7A, 0x01, 0xF3, 0x95, 0x03}, + .timestamp = 1691411798, + }; + const auto res = message_20::SessionSetupResponse{ + header, message_20::datatypes::ResponseCode::OK_OldSessionJoined, "everest se"}; + + state_helper.handle_response(res); + const auto result = fsm.feed(ev::d20::Event::V2GTP_MESSAGE); + + THEN("Check if session is stopped.") { + REQUIRE(result.transitioned() == false); + REQUIRE(result.FeedResult::operator bool() == false); + REQUIRE(ctx.is_session_stopped() == true); + } + } + + GIVEN("Bad case - resume old session with wrong charger cert hash") { + fsm::v2::FSM fsm{ctx.create_state()}; + + // Set the session ID to match the one in the SessionSetupResponse + ctx.get_session().set_id(std::array{0x10, 0x34, 0xAB, 0x7A, 0x01, 0xF3, 0x95, 0x02}); + + const auto header = message_20::Header{ + .session_id = std::array{0x10, 0x34, 0xAB, 0x7A, 0x01, 0xF3, 0x95, 0x02}, + .timestamp = 1691411798, + }; + + // Set a different charger cert hash than the one that was used to create the session + ctx.set_charger_cert_hash(io::sha512_hash_t{ + 0x3F, 0x66, 0xE4, 0x5F, 0x3A, 0x30, 0x3B, 0x8F, 0x47, 0xCD, 0xD6, 0x86, 0xAD, 0x75, 0x13, 0x6F, + 0xCE, 0x44, 0xE6, 0xAD, 0xDC, 0x52, 0x8A, 0x6A, 0x3D, 0xAC, 0x5F, 0x8D, 0xCB, 0x5A, 0x67, 0xF3, + 0xE5, 0xA5, 0xF2, 0x56, 0x74, 0x5A, 0xFA, 0xF2, 0x28, 0x31, 0xCE, 0xAB, 0xE8, 0x3C, 0xD7, 0x3C, + 0xF2, 0x83, 0x81, 0xAA, 0x5D, 0x87, 0x13, 0xA5, 0x78, 0xA8, 0xB4, 0xAB, 0x0D, 0x62, 0x1F, 0x85}); + + ctx.set_charger_cert_session_hash(io::sha512_hash_t{ + 0x77, 0xb7, 0x7a, 0xd3, 0x3, 0xd0, 0xb1, 0xed, 0x28, 0xe8, 0x23, 0xed, 0xe4, 0xe9, 0xc3, 0xe5, + 0x85, 0xce, 0x47, 0x4d, 0xa5, 0x91, 0xa8, 0x40, 0x18, 0xdb, 0xac, 0x2c, 0xf0, 0x22, 0x30, 0x3c, + 0x51, 0x13, 0xbb, 0x5, 0x95, 0x30, 0x66, 0x11, 0x46, 0xb8, 0x94, 0x3e, 0x59, 0x6d, 0x35, 0xae, + 0x9, 0x76, 0xfa, 0x2a, 0x3b, 0xb0, 0x63, 0x6e, 0x12, 0x7f, 0x10, 0xdb, 0x60, 0xd6, 0xb7, 0x4d}); + + const auto res = message_20::SessionSetupResponse{ + header, message_20::datatypes::ResponseCode::OK_OldSessionJoined, "everest se"}; + + state_helper.handle_response(res); + const auto result = fsm.feed(ev::d20::Event::V2GTP_MESSAGE); + + THEN("Check if session is stopped.") { + REQUIRE(result.transitioned() == false); + REQUIRE(result.FeedResult::operator bool() == false); + REQUIRE(ctx.is_session_stopped() == true); + } + } } diff --git a/test/iso15118/session/feedback.cpp b/test/iso15118/session/feedback.cpp index 9143246b..febde0a0 100644 --- a/test/iso15118/session/feedback.cpp +++ b/test/iso15118/session/feedback.cpp @@ -254,22 +254,22 @@ SCENARIO("Feedback Tests") { }; // TODO(SL): Missing tests for notify_ev_charging_needs, selected_service_parameters GIVEN("Test ev_information") { - iso15118::d20::EVInformation expected{ - std::vector{{"urn:iso:std:iso:15118:-20:DC", 1, 1, 1, 1}}, - {"urn:iso:std:iso:15118:-20:DC", 1, 1, 1, 1}, - "54EA7E40B356", - std::nullopt, - std::nullopt, - std::nullopt, - std::nullopt}; - feedback.ev_information( - {std::vector{{"urn:iso:std:iso:15118:-20:DC", 1, 1, 1, 1}}, - {"urn:iso:std:iso:15118:-20:DC", 1, 1, 1, 1}, - "54EA7E40B356", - std::nullopt, - std::nullopt, - std::nullopt, - std::nullopt}); + iso15118::d20::EVInformation expected{std::vector{ + {"urn:iso:std:iso:15118:-20:DC", 1, 1, 1, 1}}, + {"urn:iso:std:iso:15118:-20:DC", 1, 1, 1, 1}, + "54EA7E40B356", + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt}; + feedback.ev_information({std::vector{ + {"urn:iso:std:iso:15118:-20:DC", 1, 1, 1, 1}}, + {"urn:iso:std:iso:15118:-20:DC", 1, 1, 1, 1}, + "54EA7E40B356", + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt}); THEN("ev_information should be like expected") { REQUIRE(feedback_results.ev_information.ev_supported_app_protocols == expected.ev_supported_app_protocols);