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,2 @@
|
||||
add_subdirectory(app_hand)
|
||||
add_subdirectory(iso20)
|
||||
@@ -0,0 +1,10 @@
|
||||
add_executable(test_app_hand app_hand.cpp)
|
||||
|
||||
target_link_libraries(test_app_hand
|
||||
PRIVATE
|
||||
iso15118
|
||||
Catch2::Catch2WithMain
|
||||
)
|
||||
|
||||
include(Catch)
|
||||
catch_discover_tests(test_app_hand)
|
||||
@@ -0,0 +1,43 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iso15118/message/supported_app_protocol.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
SCENARIO("App Protocol Ser/Des") {
|
||||
GIVEN("A binary representation of an AppProtocolReq document") {
|
||||
|
||||
uint8_t doc_raw[] = "\x80"
|
||||
"\x00\xf3\xab\x93\x71\xd3\x4b\x9b\x79\xd3\x9b\xa3\x21\xd3\x4b\x9b\x79"
|
||||
"\xd1\x89\xa9\x89\x89\xc1\xd1\x69\x91\x81\xd2\x0a\x18\x01\x00\x00\x04"
|
||||
"\x00\x40";
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::SAP, stream_view);
|
||||
|
||||
THEN("It should be decoded succussfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::SupportedAppProtocolReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::SupportedAppProtocolRequest>();
|
||||
|
||||
REQUIRE(msg.app_protocol.size() == 1);
|
||||
|
||||
const auto& ap = msg.app_protocol[0];
|
||||
|
||||
REQUIRE(ap.version_number_major == 1);
|
||||
REQUIRE(ap.version_number_minor == 0);
|
||||
REQUIRE(ap.schema_id == 1);
|
||||
REQUIRE(ap.priority == 1);
|
||||
|
||||
REQUIRE(ap.protocol_namespace == "urn:iso:std:iso:15118:-20:AC");
|
||||
}
|
||||
}
|
||||
|
||||
// Todo(sl): Missing Decode message
|
||||
// 80400040
|
||||
// {"supportedAppProtocolRes": {"ResponseCode": "OK_SuccessfulNegotiation", "SchemaID": 1}}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
include(Catch)
|
||||
|
||||
function(create_exi_test_target NAME)
|
||||
add_executable(test_exi_${NAME} ${NAME}.cpp)
|
||||
target_link_libraries(test_exi_${NAME}
|
||||
PRIVATE
|
||||
iso15118
|
||||
Catch2::Catch2WithMain
|
||||
)
|
||||
catch_discover_tests(test_exi_${NAME})
|
||||
endfunction()
|
||||
|
||||
create_exi_test_target(session_setup)
|
||||
create_exi_test_target(authorization_setup)
|
||||
create_exi_test_target(authorization)
|
||||
create_exi_test_target(service_discovery)
|
||||
create_exi_test_target(service_detail)
|
||||
create_exi_test_target(service_selection)
|
||||
create_exi_test_target(dc_charge_parameter_discovery)
|
||||
create_exi_test_target(schedule_exchange)
|
||||
create_exi_test_target(dc_cable_check)
|
||||
create_exi_test_target(dc_pre_charge)
|
||||
create_exi_test_target(power_delivery)
|
||||
create_exi_test_target(dc_charge_loop)
|
||||
create_exi_test_target(dc_welding_detection)
|
||||
create_exi_test_target(session_stop)
|
||||
create_exi_test_target(ac_charge_parameter_discovery)
|
||||
create_exi_test_target(ac_charge_loop)
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iso15118/message/ac_charge_loop.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
namespace dt = iso15118::message_20::datatypes;
|
||||
|
||||
SCENARIO("Se/Deserialize ac charge loop messages") {
|
||||
|
||||
GIVEN("Deserialize ac_charge_loop_req_scheduled mode") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x08, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0xdb, 0xfe, 0x1b,
|
||||
0x60, 0x62, 0x88, 0x04, 0x00, 0x5c, 0xb0, 0x00, 0x40, 0x07, 0x02, 0xe8, 0x04, 0x00, 0x00,
|
||||
0x80, 0x7e, 0x08, 0x01, 0x90, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3f, 0x06, 0x80,
|
||||
0x78, 0x10, 0x00, 0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0x38, 0x17, 0x40, 0x40, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20AC, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::AC_ChargeLoopReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::AC_ChargeLoopRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456333);
|
||||
REQUIRE(msg.meter_info_requested == false);
|
||||
|
||||
using ScheduledMode = message_20::datatypes::Scheduled_AC_CLReqControlMode;
|
||||
|
||||
REQUIRE(std::holds_alternative<ScheduledMode>(msg.control_mode));
|
||||
const auto& control_mode = std::get<ScheduledMode>(msg.control_mode);
|
||||
REQUIRE(control_mode.target_energy_request.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.target_energy_request) == 12345.0f);
|
||||
REQUIRE(control_mode.max_energy_request.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.max_energy_request) == 12000.0f);
|
||||
REQUIRE(control_mode.min_energy_request.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.min_energy_request) == 1.0f);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.present_active_power) == 12000.0f);
|
||||
REQUIRE(control_mode.present_active_power_L2.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.present_active_power_L2) == 0.0f);
|
||||
REQUIRE(control_mode.present_active_power_L3.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.present_active_power_L3) == 0.0f);
|
||||
REQUIRE(control_mode.present_reactive_power.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.present_reactive_power) == 0.0f);
|
||||
REQUIRE(control_mode.present_reactive_power_L2.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.present_reactive_power_L2) == 0.0f);
|
||||
REQUIRE(control_mode.present_reactive_power_L3.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.present_reactive_power_L3) == 0.0f);
|
||||
REQUIRE(control_mode.max_charge_power.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*control_mode.max_charge_power) == 32);
|
||||
REQUIRE(control_mode.max_charge_power_L2.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*control_mode.max_charge_power_L2) == 0.0f);
|
||||
REQUIRE(control_mode.max_charge_power_L3.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*control_mode.max_charge_power_L3) == 0.0f);
|
||||
REQUIRE(control_mode.min_charge_power.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*control_mode.min_charge_power) == 20);
|
||||
REQUIRE(control_mode.min_charge_power_L2.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*control_mode.min_charge_power_L2) == 0.0f);
|
||||
REQUIRE(control_mode.min_charge_power_L3.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*control_mode.min_charge_power_L3) == 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize ac_charge_loop request_scheduled mode") {
|
||||
|
||||
message_20::AC_ChargeLoopRequest req;
|
||||
|
||||
req.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456333};
|
||||
req.meter_info_requested = false;
|
||||
auto& control_mode = req.control_mode.emplace<message_20::datatypes::Scheduled_AC_CLReqControlMode>();
|
||||
|
||||
control_mode.target_energy_request = {12345, 0};
|
||||
control_mode.max_energy_request = {12000, 0};
|
||||
control_mode.min_energy_request = {1, 0};
|
||||
control_mode.max_charge_power = {3200, -2};
|
||||
control_mode.max_charge_power_L2 = {0, 0};
|
||||
control_mode.max_charge_power_L3 = {0, 0};
|
||||
control_mode.min_charge_power = {2000, -2};
|
||||
control_mode.min_charge_power_L2 = {0, 0};
|
||||
control_mode.min_charge_power_L3 = {0, 0};
|
||||
control_mode.present_active_power = {12000, 0};
|
||||
control_mode.present_active_power_L2 = {0, 0};
|
||||
control_mode.present_active_power_L3 = {0, 0};
|
||||
control_mode.present_reactive_power = {0, 0};
|
||||
control_mode.present_reactive_power_L2 = {0, 0};
|
||||
control_mode.present_reactive_power_L3 = {0, 0};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x08, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0xdb,
|
||||
0xfe, 0x1b, 0x60, 0x62, 0x88, 0x04, 0x00, 0x5c, 0xb0, 0x00, 0x40, 0x07, 0x02,
|
||||
0xe8, 0x04, 0x00, 0x00, 0x80, 0x7e, 0x08, 0x01, 0x90, 0x10, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x3f, 0x06, 0x80, 0x78, 0x10, 0x00, 0x00, 0x04, 0x00, 0x00,
|
||||
0x02, 0x00, 0x38, 0x17, 0x40, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x40, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize ac_charge_loop_req dynamic mode") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x08, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0xdb, 0xfe,
|
||||
0x1b, 0x60, 0x62, 0x00, 0x51, 0x84, 0x0c, 0x78, 0x67, 0xed, 0x5b, 0x83, 0x04, 0x08,
|
||||
0x78, 0x17, 0x02, 0x04, 0x3c, 0x0b, 0x81, 0x00, 0x00, 0x20, 0x82, 0x0d, 0xc0, 0xb0,
|
||||
0x20, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40,
|
||||
0x00, 0x00, 0x20, 0x03, 0x81, 0x74, 0x08, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x40, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20AC, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::AC_ChargeLoopReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::AC_ChargeLoopRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456333);
|
||||
REQUIRE(msg.meter_info_requested == false);
|
||||
|
||||
REQUIRE(msg.display_parameters.has_value() == true);
|
||||
const auto& display_parameters = msg.display_parameters.value();
|
||||
|
||||
REQUIRE(display_parameters.present_soc.value_or(0) == 10);
|
||||
REQUIRE(display_parameters.charging_complete.value_or(true) == false);
|
||||
|
||||
using DynamicMode = message_20::datatypes::Dynamic_AC_CLReqControlMode;
|
||||
|
||||
REQUIRE(std::holds_alternative<DynamicMode>(msg.control_mode));
|
||||
const auto& control_mode = std::get<DynamicMode>(msg.control_mode);
|
||||
|
||||
REQUIRE(control_mode.departure_time.has_value() == true);
|
||||
REQUIRE(control_mode.departure_time.value() == 1727440880);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.target_energy_request) == 60000.0f);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.max_energy_request) == 60000.0f);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.min_energy_request) == 1.0f);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.max_charge_power) == 150000.0f);
|
||||
REQUIRE(control_mode.max_charge_power_L2.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*control_mode.max_charge_power_L2) == 0.0f);
|
||||
REQUIRE(control_mode.max_charge_power_L3.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*control_mode.max_charge_power_L3) == 0.0f);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.min_charge_power) == 0.0f);
|
||||
REQUIRE(control_mode.min_charge_power_L2.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*control_mode.min_charge_power_L2) == 0.0f);
|
||||
REQUIRE(control_mode.min_charge_power_L3.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*control_mode.min_charge_power_L3) == 0.0f);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.present_active_power) == 12000.0f);
|
||||
REQUIRE(control_mode.present_active_power_L2.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.present_active_power_L2) == 0.0f);
|
||||
REQUIRE(control_mode.present_active_power_L3.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.present_active_power_L3) == 0.0f);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.present_reactive_power) == 0.0f);
|
||||
REQUIRE(control_mode.present_reactive_power_L2.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.present_reactive_power_L2) == 0.0f);
|
||||
REQUIRE(control_mode.present_reactive_power_L3.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.present_reactive_power_L3) == 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize ac_charge_loop request_dynamic mode") {
|
||||
|
||||
message_20::AC_ChargeLoopRequest req;
|
||||
|
||||
req.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456333};
|
||||
req.meter_info_requested = false;
|
||||
auto& disparam = req.display_parameters.emplace();
|
||||
disparam.present_soc = 10;
|
||||
disparam.charging_complete = false;
|
||||
auto& control_mode = req.control_mode.emplace<message_20::datatypes::Dynamic_AC_CLReqControlMode>();
|
||||
control_mode.departure_time = 1727440880;
|
||||
control_mode.target_energy_request = {6000, 1};
|
||||
control_mode.max_energy_request = {6000, 1};
|
||||
control_mode.min_energy_request = {1, 0};
|
||||
control_mode.max_charge_power = {1500, 2};
|
||||
control_mode.max_charge_power_L2 = {0, 0};
|
||||
control_mode.max_charge_power_L3 = {0, 0};
|
||||
control_mode.min_charge_power = {0, 0};
|
||||
control_mode.min_charge_power_L2 = {0, 0};
|
||||
control_mode.min_charge_power_L3 = {0, 0};
|
||||
control_mode.present_active_power = {12000, 0};
|
||||
control_mode.present_active_power_L2 = {0, 0};
|
||||
control_mode.present_active_power_L3 = {0, 0};
|
||||
control_mode.present_reactive_power = {0, 0};
|
||||
control_mode.present_reactive_power_L2 = {0, 0};
|
||||
control_mode.present_reactive_power_L3 = {0, 0};
|
||||
|
||||
std::vector<uint8_t> expected = {
|
||||
0x80, 0x08, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0xdb, 0xfe, 0x1b, 0x60,
|
||||
0x62, 0x00, 0x51, 0x84, 0x0c, 0x78, 0x67, 0xed, 0x5b, 0x83, 0x04, 0x08, 0x78, 0x17, 0x02, 0x04,
|
||||
0x3c, 0x0b, 0x81, 0x00, 0x00, 0x20, 0x82, 0x0d, 0xc0, 0xb0, 0x20, 0x00, 0x00, 0x08, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x03, 0x81, 0x74, 0x08, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize ac_charge_loop_res scheduled mode") {
|
||||
uint8_t doc_raw[] = {0x80, 0x0c, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0xeb,
|
||||
0xfe, 0x1b, 0x60, 0x62, 0x00, 0x10, 0x0c, 0xc4, 0x69, 0x04, 0xb1, 0x20, 0x00,
|
||||
0xc8, 0x80, 0x40, 0x07, 0x02, 0xe8, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x04, 0x00, 0x70,
|
||||
0x2e, 0x81, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20AC, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::AC_ChargeLoopRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::AC_ChargeLoopResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456334);
|
||||
|
||||
REQUIRE(msg.meter_info.has_value() == true);
|
||||
const auto& meter_info = msg.meter_info.value();
|
||||
|
||||
REQUIRE(meter_info.meter_id == "1");
|
||||
REQUIRE(meter_info.charged_energy_reading_wh == 1234);
|
||||
|
||||
using ScheduledMode = message_20::datatypes::Scheduled_AC_CLResControlMode;
|
||||
|
||||
REQUIRE(std::holds_alternative<ScheduledMode>(msg.control_mode));
|
||||
const auto& control_mode = std::get<ScheduledMode>(msg.control_mode);
|
||||
|
||||
REQUIRE(control_mode.target_active_power.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.target_active_power) == 12000.0f);
|
||||
REQUIRE(control_mode.target_active_power_L2.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.target_active_power_L2) == 0.0f);
|
||||
REQUIRE(control_mode.target_active_power_L3.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.target_active_power_L3) == 0.0f);
|
||||
REQUIRE(control_mode.target_reactive_power.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.target_reactive_power) == 0.0f);
|
||||
REQUIRE(control_mode.target_reactive_power_L2.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.target_reactive_power_L2) == 0.0f);
|
||||
REQUIRE(control_mode.target_reactive_power_L3.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.target_reactive_power_L3) == 0.0f);
|
||||
REQUIRE(control_mode.present_active_power.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.present_active_power) == 12000.0f);
|
||||
REQUIRE(control_mode.present_active_power_L2.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.present_active_power_L2) == 0.0f);
|
||||
REQUIRE(control_mode.present_active_power_L3.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.present_active_power_L3) == 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize ac_charge_loop response scheduled") {
|
||||
|
||||
message_20::AC_ChargeLoopResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456334};
|
||||
res.response_code = message_20::datatypes::ResponseCode::OK;
|
||||
res.target_frequency = {50, 0};
|
||||
auto& met_info = res.meter_info.emplace();
|
||||
met_info.meter_id = "1";
|
||||
met_info.charged_energy_reading_wh = 1234;
|
||||
|
||||
auto& res_ctrl_mode = res.control_mode.emplace<message_20::datatypes::Scheduled_AC_CLResControlMode>();
|
||||
res_ctrl_mode.target_active_power = {12000, 0};
|
||||
res_ctrl_mode.target_active_power_L2 = {0, 0};
|
||||
res_ctrl_mode.target_active_power_L3 = {0, 0};
|
||||
res_ctrl_mode.target_reactive_power = {0, 0};
|
||||
res_ctrl_mode.target_reactive_power_L2 = {0, 0};
|
||||
res_ctrl_mode.target_reactive_power_L3 = {0, 0};
|
||||
res_ctrl_mode.present_active_power = {12000, 0};
|
||||
res_ctrl_mode.present_active_power_L2 = {0, 0};
|
||||
res_ctrl_mode.present_active_power_L3 = {0, 0};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x0c, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0xeb,
|
||||
0xfe, 0x1b, 0x60, 0x62, 0x00, 0x10, 0x0c, 0xc4, 0x69, 0x04, 0xb1, 0x20, 0x00,
|
||||
0xc8, 0x80, 0x40, 0x07, 0x02, 0xe8, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x04, 0x00, 0x70,
|
||||
0x2e, 0x81, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iso15118/message/ac_charge_parameter_discovery.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
SCENARIO("Se/Deserialize ac charge parameter discovery messages") {
|
||||
|
||||
GIVEN("Deserialize ac_charge_parameter_discovery_req") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x10, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0x3b,
|
||||
0xfe, 0x1b, 0x60, 0x62, 0x07, 0xE0, 0x80, 0x19, 0x02, 0x00, 0x00, 0x00, 0x80,
|
||||
0x00, 0x00, 0x3F, 0x06, 0x80, 0x78, 0x10, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20AC, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::AC_ChargeParameterDiscoveryReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::AC_ChargeParameterDiscoveryRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456323);
|
||||
|
||||
using AC_ModeReq = message_20::datatypes::AC_CPDReqEnergyTransferMode;
|
||||
|
||||
REQUIRE(std::holds_alternative<AC_ModeReq>(msg.transfer_mode));
|
||||
const auto& transfer_mode = std::get<AC_ModeReq>(msg.transfer_mode);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(transfer_mode.max_charge_power) == 32);
|
||||
REQUIRE(transfer_mode.max_charge_power_L2.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*transfer_mode.max_charge_power_L2) == 0.0f);
|
||||
REQUIRE(transfer_mode.max_charge_power_L3.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*transfer_mode.max_charge_power_L3) == 0.0f);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(transfer_mode.min_charge_power) == 20);
|
||||
REQUIRE(transfer_mode.min_charge_power_L2.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*transfer_mode.min_charge_power_L2) == 0.0f);
|
||||
REQUIRE(transfer_mode.min_charge_power_L3.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*transfer_mode.min_charge_power_L3) == 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize ac_charge_parameter_discovery_req") {
|
||||
|
||||
using AC_ModeReq = message_20::datatypes::AC_CPDReqEnergyTransferMode;
|
||||
|
||||
message_20::AC_ChargeParameterDiscoveryRequest req;
|
||||
|
||||
req.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456323};
|
||||
auto& mode = req.transfer_mode.emplace<AC_ModeReq>();
|
||||
mode.max_charge_power = {3200, -2};
|
||||
mode.max_charge_power_L2 = {0, 0};
|
||||
mode.max_charge_power_L3 = {0, 0};
|
||||
mode.min_charge_power = {2000, -2};
|
||||
mode.min_charge_power_L2 = {0, 0};
|
||||
mode.min_charge_power_L3 = {0, 0};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x10, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0x3b,
|
||||
0xfe, 0x1b, 0x60, 0x62, 0x07, 0xE0, 0x80, 0x19, 0x02, 0x00, 0x00, 0x00, 0x80,
|
||||
0x00, 0x00, 0x3F, 0x06, 0x80, 0x78, 0x10, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(sl): Adding BPT_AC_CPDReqEnergyTransferMode tests
|
||||
// TODO(rb): Adding BPT_AC_CPDResEnergyTransferMode tests
|
||||
|
||||
GIVEN("Deserialize ac_charge_parameter_discovery_res") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x14, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0x4b, 0xfe, 0x1b,
|
||||
0x60, 0x62, 0x00, 0x04, 0x08, 0x50, 0x08, 0x81, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20,
|
||||
0x43, 0x40, 0x3c, 0x08, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20AC, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::AC_ChargeParameterDiscoveryRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::AC_ChargeParameterDiscoveryResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456324);
|
||||
REQUIRE(msg.response_code == message_20::datatypes::ResponseCode::OK);
|
||||
|
||||
using AC_ModeRes = message_20::datatypes::AC_CPDResEnergyTransferMode;
|
||||
|
||||
REQUIRE(std::holds_alternative<AC_ModeRes>(msg.transfer_mode));
|
||||
const auto& transfer_mode = std::get<AC_ModeRes>(msg.transfer_mode);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(transfer_mode.max_charge_power) == 22080);
|
||||
REQUIRE(transfer_mode.max_charge_power_L2.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*transfer_mode.max_charge_power_L2) == 0.0f);
|
||||
REQUIRE(transfer_mode.max_charge_power_L3.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*transfer_mode.max_charge_power_L3) == 0.0f);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(transfer_mode.min_charge_power) == 20000);
|
||||
REQUIRE(transfer_mode.min_charge_power_L2.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*transfer_mode.min_charge_power_L2) == 0.0f);
|
||||
REQUIRE(transfer_mode.min_charge_power_L3.has_value() == true);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(*transfer_mode.min_charge_power_L3) == 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize ac_charge_parameter_discovery_res") {
|
||||
|
||||
using AC_ModeRes = message_20::datatypes::AC_CPDResEnergyTransferMode;
|
||||
|
||||
message_20::AC_ChargeParameterDiscoveryResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456324};
|
||||
res.response_code = message_20::datatypes::ResponseCode::OK;
|
||||
auto& mode = res.transfer_mode.emplace<AC_ModeRes>();
|
||||
mode.max_charge_power = {2208, 1};
|
||||
mode.max_charge_power_L2 = {0, 0};
|
||||
mode.max_charge_power_L3 = {0, 0};
|
||||
mode.min_charge_power = {2000, 1};
|
||||
mode.min_charge_power_L2 = {0, 0};
|
||||
mode.min_charge_power_L3 = {0, 0};
|
||||
std::vector<uint8_t> expected = {0x80, 0x14, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d,
|
||||
0x8c, 0x4b, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x04, 0x08, 0x50, 0x08,
|
||||
0x81, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x43, 0x40, 0x3c,
|
||||
0x08, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(sl): Adding BPT_AC_CPDResEnergyTransferMode tests
|
||||
// TODO(rb): Adding BPT_AC_CPDReqEnergyTransferMode tests
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iso15118/message/authorization.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
SCENARIO("Se/Deserialize authorization messages") {
|
||||
|
||||
GIVEN("Deserialize authorization_req eim") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x00, 0x04, 0x79, 0x0c, 0x8a, 0xdc, 0xee, 0xee,
|
||||
0x09, 0x68, 0x8d, 0x6c, 0xac, 0x3a, 0x60, 0x62, 0x00};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::AuthorizationReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::AuthorizationRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0xF2, 0x19, 0x15, 0xB9, 0xDD, 0xDC, 0x12, 0xD1});
|
||||
REQUIRE(header.timestamp == 1691411798);
|
||||
|
||||
REQUIRE(msg.selected_authorization_service == message_20::datatypes::Authorization::EIM);
|
||||
REQUIRE(std::holds_alternative<message_20::datatypes::EIM_ASReqAuthorizationMode>(msg.authorization_mode));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(sl): Adding authorization_req pnc tests
|
||||
|
||||
GIVEN("Serialize authorization_res") {
|
||||
|
||||
message_20::AuthorizationResponse res;
|
||||
|
||||
res.header = message_20::Header{{0xF2, 0x19, 0x15, 0xB9, 0xDD, 0xDC, 0x12, 0xD1}, 1691411798};
|
||||
res.response_code = message_20::datatypes::ResponseCode::OK;
|
||||
res.evse_processing = message_20::datatypes::Processing::Finished;
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x04, 0x04, 0x79, 0x0c, 0x8a, 0xdc, 0xee, 0xee, 0x09,
|
||||
0x68, 0x8d, 0x6c, 0xac, 0x3a, 0x60, 0x62, 0x00, 0x00};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize authorization_res eim") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x04, 0x04, 0x79, 0x0c, 0x8a, 0xdc, 0xee, 0xee, 0x09,
|
||||
0x68, 0x8d, 0x6c, 0xac, 0x3a, 0x60, 0x62, 0x00, 0x00};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::AuthorizationRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::AuthorizationResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0xF2, 0x19, 0x15, 0xB9, 0xDD, 0xDC, 0x12, 0xD1});
|
||||
REQUIRE(header.timestamp == 1691411798);
|
||||
|
||||
REQUIRE(msg.evse_processing == message_20::datatypes::Processing::Finished);
|
||||
REQUIRE(msg.response_code == message_20::datatypes::ResponseCode::OK);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize authorization_req eim") {
|
||||
|
||||
message_20::AuthorizationRequest req;
|
||||
|
||||
req.header = message_20::Header{{0xF2, 0x19, 0x15, 0xB9, 0xDD, 0xDC, 0x12, 0xD1}, 1691411798};
|
||||
req.selected_authorization_service = message_20::datatypes::Authorization::EIM;
|
||||
req.authorization_mode = message_20::datatypes::EIM_ASReqAuthorizationMode{};
|
||||
// Todo(sl): Adding certificate
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x00, 0x04, 0x79, 0x0c, 0x8a, 0xdc, 0xee, 0xee,
|
||||
0x09, 0x68, 0x8d, 0x6c, 0xac, 0x3a, 0x60, 0x62, 0x00};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <iso15118/message/authorization_setup.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
SCENARIO("Se/Deserialize authorization setup messages") {
|
||||
|
||||
GIVEN("Deserialize authorization_setup_req") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x08, 0x04, 0x79, 0x0c, 0x8a, 0xdc, 0xee, 0xee,
|
||||
0x09, 0x68, 0x8d, 0x6c, 0xac, 0x3a, 0x60, 0x62};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::AuthorizationSetupReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::AuthorizationSetupRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0xF2, 0x19, 0x15, 0xB9, 0xDD, 0xDC, 0x12, 0xD1});
|
||||
REQUIRE(header.timestamp == 1691411798);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize authorization_setup_req") {
|
||||
|
||||
const auto header = message_20::Header{{0xF2, 0x19, 0x15, 0xB9, 0xDD, 0xDC, 0x12, 0xD1}, 1691411798};
|
||||
|
||||
const auto res = message_20::AuthorizationSetupRequest{header};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x08, 0x04, 0x79, 0x0c, 0x8a, 0xdc, 0xee, 0xee,
|
||||
0x09, 0x68, 0x8d, 0x6c, 0xac, 0x3a, 0x60, 0x62};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize authorization_setup_res") {
|
||||
|
||||
message_20::AuthorizationSetupResponse res;
|
||||
|
||||
res.header = message_20::Header{{0xF2, 0x19, 0x15, 0xB9, 0xDD, 0xDC, 0x12, 0xD1}, 1691411798};
|
||||
res.response_code = message_20::datatypes::ResponseCode::OK;
|
||||
res.authorization_services = {message_20::datatypes::Authorization::EIM};
|
||||
res.certificate_installation_service = true;
|
||||
res.authorization_mode = message_20::datatypes::EIM_ASResAuthorizationMode();
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x0c, 0x04, 0x79, 0x0c, 0x8a, 0xdc, 0xee, 0xee, 0x09,
|
||||
0x68, 0x8d, 0x6c, 0xac, 0x3a, 0x60, 0x62, 0x00, 0x05, 0x00};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize authorization_setup_res pnc") {
|
||||
|
||||
message_20::AuthorizationSetupResponse res;
|
||||
|
||||
res.header = message_20::Header{{0xF2, 0x19, 0x15, 0xB9, 0xDD, 0xDC, 0x12, 0xD1}, 1691411798};
|
||||
res.response_code = message_20::datatypes::ResponseCode::OK;
|
||||
res.authorization_services = {message_20::datatypes::Authorization::EIM,
|
||||
message_20::datatypes::Authorization::PnC};
|
||||
res.certificate_installation_service = true;
|
||||
|
||||
auto& mode = res.authorization_mode.emplace<message_20::datatypes::PnC_ASResAuthorizationMode>();
|
||||
|
||||
mode.gen_challenge = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
|
||||
// FIXME(SL): supported_providers missing
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x0c, 0x04, 0x79, 0x0c, 0x8a, 0xdc, 0xee, 0xee, 0x09, 0x68, 0x8d, 0x6c,
|
||||
0xac, 0x3a, 0x60, 0x62, 0x00, 0x01, 0x12, 0x08, 0x00, 0x81, 0x01, 0x82, 0x02,
|
||||
0x83, 0x03, 0x84, 0x04, 0x85, 0x05, 0x86, 0x06, 0x87, 0x07, 0x88, 0x10};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
GIVEN("Deserialize authorization_setup_res") {
|
||||
uint8_t doc_raw[] = {0x80, 0x0c, 0x04, 0x79, 0x0c, 0x8a, 0xdc, 0xee, 0xee, 0x09,
|
||||
0x68, 0x8d, 0x6c, 0xac, 0x3a, 0x60, 0x62, 0x00, 0x05, 0x00};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::AuthorizationSetupRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::AuthorizationSetupResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0xF2, 0x19, 0x15, 0xB9, 0xDD, 0xDC, 0x12, 0xD1});
|
||||
REQUIRE(header.timestamp == 1691411798);
|
||||
REQUIRE(msg.response_code == message_20::datatypes::ResponseCode::OK);
|
||||
REQUIRE(msg.authorization_services.size() == 1);
|
||||
REQUIRE(msg.authorization_services[0] == message_20::datatypes::Authorization::EIM);
|
||||
REQUIRE(msg.certificate_installation_service == true);
|
||||
REQUIRE(std::holds_alternative<message_20::datatypes::EIM_ASResAuthorizationMode>(msg.authorization_mode));
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize authorization_setup_res_pnc") {
|
||||
uint8_t doc_raw[] = {0x80, 0x0c, 0x04, 0x79, 0x0c, 0x8a, 0xdc, 0xee, 0xee, 0x09, 0x68, 0x8d, 0x6c,
|
||||
0xac, 0x3a, 0x60, 0x62, 0x00, 0x01, 0x12, 0x08, 0x00, 0x81, 0x01, 0x82, 0x02,
|
||||
0x83, 0x03, 0x84, 0x04, 0x85, 0x05, 0x86, 0x06, 0x87, 0x07, 0x88, 0x10};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::AuthorizationSetupRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::AuthorizationSetupResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0xF2, 0x19, 0x15, 0xB9, 0xDD, 0xDC, 0x12, 0xD1});
|
||||
REQUIRE(header.timestamp == 1691411798);
|
||||
REQUIRE(msg.response_code == message_20::datatypes::ResponseCode::OK);
|
||||
REQUIRE(msg.authorization_services.size() == 2);
|
||||
REQUIRE(msg.authorization_services[0] == message_20::datatypes::Authorization::EIM);
|
||||
REQUIRE(msg.authorization_services[1] == message_20::datatypes::Authorization::PnC);
|
||||
REQUIRE(msg.certificate_installation_service == true);
|
||||
const message_20::datatypes::GenChallenge exp_gen_challenge = {1, 2, 3, 4, 5, 6, 7, 8,
|
||||
9, 10, 11, 12, 13, 14, 15, 16};
|
||||
const auto& pnc_auth_mode =
|
||||
std::get<message_20::datatypes::PnC_ASResAuthorizationMode>(msg.authorization_mode);
|
||||
REQUIRE(pnc_auth_mode.gen_challenge == exp_gen_challenge);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iso15118/message/dc_cable_check.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
SCENARIO("Se/Deserialize dc cable check messages") {
|
||||
|
||||
GIVEN("Deserialize dc_cable_check_req") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x2c, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7,
|
||||
0x6c, 0x4d, 0x8c, 0x7b, 0xfe, 0x1b, 0x60, 0x62};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20DC, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::DC_CableCheckReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::DC_CableCheckRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456327);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize dc_cable_check_req") {
|
||||
|
||||
message_20::DC_CableCheckRequest req;
|
||||
|
||||
req.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456327};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x2c, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7,
|
||||
0x6c, 0x4d, 0x8c, 0x7b, 0xfe, 0x1b, 0x60, 0x62};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize dc_cable_check_res ongoing") {
|
||||
|
||||
message_20::DC_CableCheckResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456328};
|
||||
res.response_code = message_20::datatypes::ResponseCode::OK;
|
||||
res.processing = message_20::datatypes::Processing::Ongoing;
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x30, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c,
|
||||
0x4d, 0x8c, 0x8b, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x10};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize dc_cable_check_res_ongoing") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x30, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c,
|
||||
0x4d, 0x8c, 0x8b, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x10};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20DC, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::DC_CableCheckRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::DC_CableCheckResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456328);
|
||||
REQUIRE(msg.response_code == message_20::datatypes::ResponseCode::OK);
|
||||
REQUIRE(msg.processing == message_20::datatypes::Processing::Ongoing);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize dc_cable_check_res finished") {
|
||||
|
||||
message_20::DC_CableCheckResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456331};
|
||||
res.response_code = message_20::datatypes::ResponseCode::OK;
|
||||
res.processing = message_20::datatypes::Processing::Finished;
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x30, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c,
|
||||
0x4d, 0x8c, 0xbb, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x00};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize dc_cable_check_res_finished") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x30, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c,
|
||||
0x4d, 0x8c, 0xbb, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x00};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20DC, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::DC_CableCheckRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::DC_CableCheckResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456331);
|
||||
REQUIRE(msg.response_code == message_20::datatypes::ResponseCode::OK);
|
||||
REQUIRE(msg.processing == message_20::datatypes::Processing::Finished);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iso15118/message/dc_charge_loop.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
namespace dt = iso15118::message_20::datatypes;
|
||||
|
||||
SCENARIO("Se/Deserialize dc charge loop messages") {
|
||||
|
||||
GIVEN("Deserialize dc_charge_loop_req") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x34, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0xdb, 0xfe, 0x1b,
|
||||
0x60, 0x62, 0x81, 0x00, 0x12, 0x00, 0x64, 0x64, 0x00, 0x0a, 0x02, 0x00, 0x24, 0x00, 0xca};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20DC, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::DC_ChargeLoopReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::DC_ChargeLoopRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456333);
|
||||
REQUIRE(msg.meter_info_requested == false);
|
||||
REQUIRE(dt::from_RationalNumber(msg.present_voltage) == 400);
|
||||
|
||||
using ScheduledMode = message_20::datatypes::Scheduled_DC_CLReqControlMode;
|
||||
|
||||
REQUIRE(std::holds_alternative<ScheduledMode>(msg.control_mode));
|
||||
const auto& control_mode = std::get<ScheduledMode>(msg.control_mode);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.target_current) == 20);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.target_voltage) == 400);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize dc_charge_loop request") {
|
||||
|
||||
message_20::DC_ChargeLoopRequest req;
|
||||
|
||||
req.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456333};
|
||||
req.meter_info_requested = false;
|
||||
auto& control_mode = req.control_mode.emplace<message_20::datatypes::Scheduled_DC_CLReqControlMode>();
|
||||
control_mode.target_current = {20, 0};
|
||||
control_mode.target_voltage = {400, 0};
|
||||
|
||||
req.present_voltage = {400, 0};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x34, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c,
|
||||
0x4d, 0x8c, 0xdb, 0xfe, 0x1b, 0x60, 0x62, 0x81, 0x00, 0x12,
|
||||
0x00, 0x64, 0x64, 0x00, 0x0a, 0x02, 0x00, 0x24, 0x00, 0xca};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize dc_charge_loop_req dynamic mode") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x34, 0x04, 0x32, 0x75, 0x76, 0x9e, 0xc7, 0x10, 0x64, 0xac, 0x8f, 0x0c, 0xfd,
|
||||
0xab, 0x70, 0x62, 0x00, 0x51, 0x84, 0x02, 0x00, 0x24, 0x00, 0xc6, 0x90, 0x21, 0xe0,
|
||||
0x5c, 0x08, 0x30, 0x3c, 0x04, 0x00, 0x00, 0x82, 0x04, 0x26, 0x1d, 0x41, 0x00, 0x00,
|
||||
0x00, 0x80, 0x0a, 0xc0, 0x20, 0x40, 0x04, 0x20, 0x38, 0x20, 0x02, 0x58, 0x04, 0x00};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20DC, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::DC_ChargeLoopReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::DC_ChargeLoopRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x64, 0xEA, 0xED, 0x3D, 0x8E, 0x20, 0xC9, 0x59});
|
||||
REQUIRE(header.timestamp == 1727440880);
|
||||
REQUIRE(msg.meter_info_requested == false);
|
||||
REQUIRE(dt::from_RationalNumber(msg.present_voltage) == 400.0f);
|
||||
|
||||
REQUIRE(msg.display_parameters.has_value() == true);
|
||||
const auto& display_parameters = msg.display_parameters.value();
|
||||
|
||||
REQUIRE(display_parameters.present_soc.value_or(0) == 10);
|
||||
REQUIRE(display_parameters.charging_complete.value_or(true) == false);
|
||||
|
||||
using DynamicMode = message_20::datatypes::Dynamic_DC_CLReqControlMode;
|
||||
|
||||
REQUIRE(std::holds_alternative<DynamicMode>(msg.control_mode));
|
||||
const auto& control_mode = std::get<DynamicMode>(msg.control_mode);
|
||||
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.target_energy_request) == 60000.0f);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.max_energy_request) == 60000.0f);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.min_energy_request) == 1.0f);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.max_charge_power) == 150000.0f);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.min_charge_power) == 0.0f);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.max_charge_current) == 300.0f);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.max_voltage) == 900.0f);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.min_voltage) == 150.0f);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize dc_charge_loop request dynamic mode") {
|
||||
|
||||
message_20::DC_ChargeLoopRequest req;
|
||||
|
||||
req.header = message_20::Header{{0x64, 0xEA, 0xED, 0x3D, 0x8E, 0x20, 0xC9, 0x59}, 1727440880};
|
||||
req.meter_info_requested = false;
|
||||
auto& control_mode = req.control_mode.emplace<message_20::datatypes::Dynamic_DC_CLReqControlMode>();
|
||||
|
||||
req.present_voltage = {400, 0};
|
||||
control_mode.target_energy_request = {6000, 1};
|
||||
control_mode.max_energy_request = {60, 3};
|
||||
control_mode.min_energy_request = {1, 0};
|
||||
control_mode.max_charge_power = {15000, 1};
|
||||
control_mode.min_charge_power = {0, 0};
|
||||
control_mode.max_charge_current = {300, 0};
|
||||
control_mode.max_voltage = {900, 0};
|
||||
control_mode.min_voltage = {150, 0};
|
||||
req.display_parameters.emplace();
|
||||
req.display_parameters->present_soc = 10;
|
||||
req.display_parameters->charging_complete = false;
|
||||
std::vector<uint8_t> expected = {0x80, 0x34, 0x04, 0x32, 0x75, 0x76, 0x9e, 0xc7, 0x10, 0x64, 0xac, 0x8f,
|
||||
0x0c, 0xfd, 0xab, 0x70, 0x62, 0x00, 0x51, 0x84, 0x02, 0x00, 0x24, 0x00,
|
||||
0xc6, 0x90, 0x21, 0xe0, 0x5c, 0x08, 0x30, 0x3c, 0x04, 0x00, 0x00, 0x82,
|
||||
0x04, 0x26, 0x1d, 0x41, 0x00, 0x00, 0x00, 0x80, 0x0a, 0xc0, 0x20, 0x40,
|
||||
0x04, 0x20, 0x38, 0x20, 0x02, 0x58, 0x04, 0x00};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize dc_charge_loop_res ongoing") {
|
||||
|
||||
message_20::DC_ChargeLoopResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456334};
|
||||
res.response_code = message_20::datatypes::ResponseCode::OK;
|
||||
res.control_mode.emplace<message_20::datatypes::Scheduled_DC_CLResControlMode>();
|
||||
res.current_limit_achieved = true;
|
||||
res.power_limit_achieved = true;
|
||||
res.voltage_limit_achieved = true;
|
||||
res.present_current = {1000, -3};
|
||||
res.present_voltage = {4000, -1};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x38, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c,
|
||||
0x4d, 0x8c, 0xeb, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x63, 0xe8,
|
||||
0x74, 0x03, 0x81, 0xfc, 0x28, 0x07, 0xc2, 0x22, 0x90};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize dc_charge_loop_res dynamic dc_bpt") {
|
||||
|
||||
message_20::DC_ChargeLoopResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456334};
|
||||
res.response_code = message_20::datatypes::ResponseCode::OK;
|
||||
auto& mode = res.control_mode.emplace<message_20::datatypes::Dynamic_DC_CLResControlMode>();
|
||||
|
||||
mode.max_charge_power = {150, 3};
|
||||
mode.min_charge_power = {100, 0};
|
||||
mode.max_charge_current = {60, 1};
|
||||
mode.max_voltage = {9, 2};
|
||||
|
||||
res.current_limit_achieved = true;
|
||||
res.power_limit_achieved = true;
|
||||
res.voltage_limit_achieved = true;
|
||||
res.present_current = {1000, -3};
|
||||
res.present_voltage = {4000, -1};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x38, 0x04, 0x1E, 0xA6, 0x5F, 0xC9, 0x9B, 0xA7, 0x6C, 0x4D,
|
||||
0x8C, 0xEB, 0xFE, 0x1B, 0x60, 0x62, 0x00, 0x63, 0xE8, 0x74, 0x03,
|
||||
0x81, 0xFC, 0x28, 0x07, 0xC2, 0x22, 0x70, 0x83, 0x09, 0x60, 0x10,
|
||||
0x40, 0x03, 0x20, 0x20, 0x40, 0xF0, 0x10, 0x40, 0x12, 0x00};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize dc_charge_loop res ongoing") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x38, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0xeb, 0xfe, 0x1b,
|
||||
0x60, 0x62, 0x00, 0x63, 0xe8, 0x74, 0x03, 0x81, 0xfc, 0x28, 0x07, 0xc2, 0x22, 0x90};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20DC, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::DC_ChargeLoopRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::DC_ChargeLoopResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456334);
|
||||
REQUIRE(msg.response_code == message_20::datatypes::ResponseCode::OK);
|
||||
REQUIRE(msg.current_limit_achieved == true);
|
||||
REQUIRE(msg.power_limit_achieved == true);
|
||||
REQUIRE(msg.voltage_limit_achieved == true);
|
||||
REQUIRE(dt::from_RationalNumber(msg.present_current) == 1);
|
||||
REQUIRE(dt::from_RationalNumber(msg.present_voltage) == 400);
|
||||
REQUIRE(std::holds_alternative<message_20::datatypes::Scheduled_DC_CLResControlMode>(msg.control_mode));
|
||||
const auto& control_mode = std::get<message_20::datatypes::Scheduled_DC_CLResControlMode>(msg.control_mode);
|
||||
REQUIRE(control_mode.max_charge_current.has_value() == false);
|
||||
REQUIRE(control_mode.max_charge_power.has_value() == false);
|
||||
REQUIRE(control_mode.max_voltage.has_value() == false);
|
||||
REQUIRE(control_mode.min_charge_power.has_value() == false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iso15118/message/dc_charge_parameter_discovery.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
SCENARIO("Se/Deserialize dc charge parameter discovery messages") {
|
||||
|
||||
GIVEN("Deserialize dc_charge_parameter_discovery_req") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x3c, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0x3b, 0xfe,
|
||||
0x1b, 0x60, 0x62, 0x88, 0x10, 0x98, 0x75, 0x04, 0x00, 0x32, 0x02, 0x00, 0x2b, 0x00,
|
||||
0x81, 0x00, 0x01, 0x40, 0x80, 0x08, 0x40, 0x70, 0x40, 0x00, 0x50, 0x80};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20DC, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::DC_ChargeParameterDiscoveryReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::DC_ChargeParameterDiscoveryRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456323);
|
||||
|
||||
using DC_ModeReq = message_20::datatypes::DC_CPDReqEnergyTransferMode;
|
||||
|
||||
REQUIRE(std::holds_alternative<DC_ModeReq>(msg.transfer_mode));
|
||||
const auto& transfer_mode = std::get<DC_ModeReq>(msg.transfer_mode);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(transfer_mode.max_charge_current) == 300);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(transfer_mode.max_charge_power) == 150000);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(transfer_mode.max_voltage) == 900);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(transfer_mode.min_charge_current) == 10);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(transfer_mode.min_charge_power) == 100);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(transfer_mode.min_voltage) == 10);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize dc_charge_parameter_discovery_req") {
|
||||
|
||||
using DC_ModeReq = message_20::datatypes::DC_CPDReqEnergyTransferMode;
|
||||
|
||||
message_20::DC_ChargeParameterDiscoveryRequest req;
|
||||
|
||||
req.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456323};
|
||||
auto& mode = req.transfer_mode.emplace<DC_ModeReq>();
|
||||
mode.max_charge_current = {300, 0};
|
||||
mode.max_charge_power = {15000, 1};
|
||||
mode.max_voltage = {900, 0};
|
||||
mode.min_charge_current = {10, 0};
|
||||
mode.min_charge_power = {100, 0};
|
||||
mode.min_voltage = {10, 0};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x3c, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c,
|
||||
0x4d, 0x8c, 0x3b, 0xfe, 0x1b, 0x60, 0x62, 0x88, 0x10, 0x98,
|
||||
0x75, 0x04, 0x00, 0x32, 0x02, 0x00, 0x2b, 0x00, 0x81, 0x00,
|
||||
0x01, 0x40, 0x80, 0x08, 0x40, 0x70, 0x40, 0x00, 0x50, 0x80};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(sl): Adding BPT_DC_CPDReqEnergyTransferMode tests
|
||||
// TODO(rb): Adding BPT_DC_CPDResEnergyTransferMode tests
|
||||
|
||||
GIVEN("Deserialize dc_charge_parameter_discovery_res") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x40, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0x4b, 0xfe, 0x1b,
|
||||
0x60, 0x62, 0x00, 0x44, 0x08, 0x50, 0x08, 0x81, 0xfc, 0x34, 0x03, 0xc0, 0xfe, 0x1a, 0x01,
|
||||
0xe0, 0x7d, 0x0e, 0x80, 0x70, 0x3f, 0x85, 0x42, 0x30, 0x1f, 0xc3, 0x40, 0x3c, 0x40};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20DC, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::DC_ChargeParameterDiscoveryRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::DC_ChargeParameterDiscoveryResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456324);
|
||||
REQUIRE(msg.response_code == message_20::datatypes::ResponseCode::OK);
|
||||
|
||||
using DC_ModeRes = message_20::datatypes::DC_CPDResEnergyTransferMode;
|
||||
|
||||
REQUIRE(std::holds_alternative<DC_ModeRes>(msg.transfer_mode));
|
||||
const auto& transfer_mode = std::get<DC_ModeRes>(msg.transfer_mode);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(transfer_mode.max_charge_current) == 200);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(transfer_mode.max_charge_power) == 22080);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(transfer_mode.max_voltage) == 900);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(transfer_mode.min_charge_current) == 1);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(transfer_mode.min_charge_power) == 200);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(transfer_mode.min_voltage) == 200);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize dc_charge_parameter_discovery_res") {
|
||||
|
||||
using DC_ModeRes = message_20::datatypes::DC_CPDResEnergyTransferMode;
|
||||
|
||||
message_20::DC_ChargeParameterDiscoveryResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456324};
|
||||
res.response_code = message_20::datatypes::ResponseCode::OK;
|
||||
auto& mode = res.transfer_mode.emplace<DC_ModeRes>();
|
||||
mode.max_charge_current = {2000, -1};
|
||||
mode.max_charge_power = {2208, 1};
|
||||
mode.max_voltage = {9000, -1};
|
||||
mode.min_charge_current = {1000, -3};
|
||||
mode.min_charge_power = {2000, -1};
|
||||
mode.min_voltage = {2000, -1};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x40, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d,
|
||||
0x8c, 0x4b, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x44, 0x08, 0x50, 0x08,
|
||||
0x81, 0xfc, 0x34, 0x03, 0xc0, 0xfe, 0x1a, 0x01, 0xe0, 0x7d, 0x0e,
|
||||
0x80, 0x70, 0x3f, 0x85, 0x42, 0x30, 0x1f, 0xc3, 0x40, 0x3c, 0x40};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(sl): Adding BPT_DC_CPDResEnergyTransferMode tests
|
||||
// TODO(rb): Adding BPT_DC_CPDReqEnergyTransferMode tests
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iso15118/message/dc_pre_charge.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
SCENARIO("Se/Deserialize dc pre charge messages") {
|
||||
|
||||
GIVEN("Deserialize dc_pre_charge_req") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x44, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0xbb,
|
||||
0xfe, 0x1b, 0x60, 0x62, 0x21, 0x00, 0x12, 0x00, 0x60, 0x80, 0x09, 0x00, 0x30};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20DC, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::DC_PreChargeReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::DC_PreChargeRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456331);
|
||||
REQUIRE(msg.processing == message_20::datatypes::Processing::Ongoing);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(msg.present_voltage) == 400);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(msg.target_voltage) == 400);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize dc_pre_charge_req") {
|
||||
|
||||
message_20::DC_PreChargeRequest req;
|
||||
|
||||
req.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456331};
|
||||
req.processing = message_20::datatypes::Processing::Ongoing;
|
||||
req.target_voltage = {400, 0};
|
||||
req.present_voltage = {400, 0};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x44, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0xbb,
|
||||
0xfe, 0x1b, 0x60, 0x62, 0x21, 0x00, 0x12, 0x00, 0x60, 0x80, 0x09, 0x00, 0x30};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize dc_pre_charge_res") {
|
||||
|
||||
message_20::DC_PreChargeResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456332};
|
||||
res.response_code = message_20::datatypes::ResponseCode::OK;
|
||||
res.present_voltage = {4000, -1};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x48, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c,
|
||||
0xcb, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x0f, 0xe1, 0x40, 0x3e, 0x00};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize dc_pre_charge_res") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x48, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c,
|
||||
0xcb, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x0f, 0xe1, 0x40, 0x3e, 0x00};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20DC, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::DC_PreChargeRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::DC_PreChargeResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456332);
|
||||
REQUIRE(msg.response_code == message_20::datatypes::ResponseCode::OK);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(msg.present_voltage) == 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iso15118/message/dc_welding_detection.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
SCENARIO("Se/Deserialize dc welding detection messages") {
|
||||
|
||||
GIVEN("Deserialize dc welding detection req") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x4c, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7,
|
||||
0x6c, 0x4d, 0x8d, 0x5b, 0xfe, 0x1b, 0x60, 0x62, 0x20};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20DC, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::DC_WeldingDetectionReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::DC_WeldingDetectionRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456341);
|
||||
|
||||
REQUIRE(msg.processing == message_20::datatypes::Processing::Ongoing);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize dc welding detection req") {
|
||||
|
||||
message_20::DC_WeldingDetectionRequest req;
|
||||
|
||||
req.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456341};
|
||||
req.processing = message_20::datatypes::Processing::Ongoing;
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x4c, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7,
|
||||
0x6c, 0x4d, 0x8d, 0x5b, 0xfe, 0x1b, 0x60, 0x62, 0x20};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize dc_welding_detection res") {
|
||||
|
||||
message_20::DC_WeldingDetectionResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456341};
|
||||
res.response_code = message_20::datatypes::ResponseCode::OK;
|
||||
res.present_voltage = {0, 0};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x50, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d,
|
||||
0x8d, 0x5b, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x10, 0x00, 0x00, 0x00};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize dc welding detection res") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x50, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d,
|
||||
0x8d, 0x5b, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x10, 0x00, 0x00, 0x00};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20DC, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::DC_WeldingDetectionRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::DC_WeldingDetectionResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456341);
|
||||
|
||||
REQUIRE(msg.response_code == message_20::datatypes::ResponseCode::OK);
|
||||
REQUIRE(msg.present_voltage.value == 0);
|
||||
REQUIRE(msg.present_voltage.exponent == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include <iso15118/io/stream_view.hpp>
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
template <typename Message> std::vector<uint8_t> serialize_helper(const Message& message) {
|
||||
uint8_t serialization_buffer[1024];
|
||||
io::StreamOutputView out({serialization_buffer, sizeof(serialization_buffer)});
|
||||
|
||||
const auto size = message_20::serialize(message, out);
|
||||
|
||||
return std::vector<uint8_t>(serialization_buffer, serialization_buffer + size);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iso15118/message/power_delivery.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
SCENARIO("Se/Deserialize power delivery messages") {
|
||||
|
||||
GIVEN("Deserialize power_delivery_req") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x54, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0xdb, 0xfe,
|
||||
0x1b, 0x60, 0x62, 0x00, 0x00, 0x01, 0x00, 0x42, 0x00, 0xb8, 0x41, 0x00, 0x51, 0x24};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::PowerDeliveryReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::PowerDeliveryRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456333);
|
||||
REQUIRE(msg.processing == message_20::datatypes::Processing::Finished);
|
||||
REQUIRE(msg.charge_progress == message_20::datatypes::Progress::Start);
|
||||
|
||||
REQUIRE(msg.power_profile.has_value() == true);
|
||||
auto& power_profile = msg.power_profile.value();
|
||||
REQUIRE(power_profile.time_anchor == 0);
|
||||
REQUIRE(power_profile.entries[0].duration == 23);
|
||||
REQUIRE(message_20::datatypes::from_RationalNumber(power_profile.entries[0].power) == 1000);
|
||||
|
||||
REQUIRE(
|
||||
std::holds_alternative<message_20::datatypes::Scheduled_EVPPTControlMode>(power_profile.control_mode));
|
||||
const auto& mode = std::get<message_20::datatypes::Scheduled_EVPPTControlMode>(power_profile.control_mode);
|
||||
REQUIRE(mode.power_tolerance_acceptance == message_20::datatypes::PowerToleranceAcceptance::Confirmed);
|
||||
REQUIRE(mode.selected_schedule == 1);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize power_delivery_req") {
|
||||
|
||||
message_20::PowerDeliveryRequest req;
|
||||
|
||||
req.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456333};
|
||||
req.processing = message_20::datatypes::Processing::Finished;
|
||||
req.charge_progress = message_20::datatypes::Progress::Start;
|
||||
req.power_profile = message_20::datatypes::PowerProfile{};
|
||||
req.power_profile->time_anchor = 0;
|
||||
req.power_profile->entries.emplace_back();
|
||||
req.power_profile->entries[0].duration = 23;
|
||||
req.power_profile->entries[0].power = message_20::datatypes::RationalNumber{10, 2};
|
||||
req.power_profile->control_mode.emplace<message_20::datatypes::Scheduled_EVPPTControlMode>();
|
||||
auto& mode = std::get<message_20::datatypes::Scheduled_EVPPTControlMode>(req.power_profile->control_mode);
|
||||
mode.power_tolerance_acceptance = message_20::datatypes::PowerToleranceAcceptance::Confirmed;
|
||||
mode.selected_schedule = 1;
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x54, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c,
|
||||
0x4d, 0x8c, 0xdb, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x00, 0x01,
|
||||
0x00, 0x42, 0x00, 0xb8, 0x41, 0x00, 0x51, 0x24};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize power_delivery_res") {
|
||||
|
||||
message_20::PowerDeliveryResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456333};
|
||||
res.response_code = message_20::datatypes::ResponseCode::OK;
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x58, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c,
|
||||
0x4d, 0x8c, 0xdb, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x40};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize power_delivery_res") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x58, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c,
|
||||
0x4d, 0x8c, 0xdb, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x40};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::PowerDeliveryRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::PowerDeliveryResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456333);
|
||||
REQUIRE(msg.response_code == message_20::datatypes::ResponseCode::OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iso15118/message/schedule_exchange.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
namespace dt = iso15118::message_20::datatypes;
|
||||
|
||||
SCENARIO("Se/Deserialize schedule_exchange messages") {
|
||||
|
||||
GIVEN("Deserialize schedule_exchange_req - scheduled mode") {
|
||||
uint8_t doc_raw[] = {0x80, 0x6c, 0x04, 0x23, 0xfe, 0x9d, 0xa7, 0x89, 0x92, 0xab, 0xe5, 0x0c, 0xee, 0x2c, 0x4b,
|
||||
0x70, 0x62, 0x7e, 0x84, 0x28, 0x0e, 0x00, 0x83, 0x00, 0xa0, 0x10, 0x60, 0x28, 0x03, 0xf0,
|
||||
0x02, 0x80, 0x00, 0x04, 0x80, 0xe0, 0x41, 0x80, 0x50, 0x40, 0x00, 0x02, 0xa2, 0xaa, 0xa9,
|
||||
0x03, 0x27, 0x57, 0x26, 0xe3, 0xa6, 0x97, 0x36, 0xf3, 0xa7, 0x37, 0x46, 0x43, 0xa6, 0x97,
|
||||
0x36, 0xf3, 0xa3, 0x13, 0x53, 0x13, 0x13, 0x83, 0xa2, 0xd3, 0x23, 0x03, 0xa5, 0x07, 0x26,
|
||||
0x96, 0x36, 0x54, 0x16, 0xc6, 0x76, 0xf7, 0x26, 0x97, 0x46, 0x86, 0xd3, 0xa3, 0x12, 0xd5,
|
||||
0x06, 0xf7, 0x76, 0x57, 0x20, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x40};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be decoded successfully") {
|
||||
|
||||
REQUIRE(variant.get_type() == message_20::Type::ScheduleExchangeReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::ScheduleExchangeRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x47, 0xFD, 0x3B, 0x4F, 0x13, 0x25, 0x57, 0xCA});
|
||||
REQUIRE(header.timestamp == 1727082830);
|
||||
REQUIRE(msg.max_supporting_points == 1024);
|
||||
REQUIRE(std::holds_alternative<dt::Scheduled_SEReqControlMode>(msg.control_mode));
|
||||
auto& control_mode = std::get<dt::Scheduled_SEReqControlMode>(msg.control_mode);
|
||||
REQUIRE(control_mode.departure_time.has_value() == true);
|
||||
REQUIRE(control_mode.departure_time == 7200);
|
||||
REQUIRE(control_mode.target_energy.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.target_energy) == 10000.0f);
|
||||
REQUIRE(control_mode.max_energy.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.max_energy) == 20000.0f);
|
||||
REQUIRE(control_mode.min_energy.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.min_energy) == 0.05f);
|
||||
REQUIRE(control_mode.energy_offer.has_value() == true);
|
||||
auto& ev_energy_offer = control_mode.energy_offer.value();
|
||||
REQUIRE(ev_energy_offer.power_schedule.time_anchor == 0);
|
||||
REQUIRE(ev_energy_offer.power_schedule.entries.size() == 1);
|
||||
REQUIRE(ev_energy_offer.power_schedule.entries.at(0).duration == 3600);
|
||||
REQUIRE(dt::from_RationalNumber(ev_energy_offer.power_schedule.entries.at(0).power) == 10000.0f);
|
||||
REQUIRE(ev_energy_offer.absolute_price_schedule.time_anchor == 0);
|
||||
REQUIRE(ev_energy_offer.absolute_price_schedule.currency == "EUR");
|
||||
REQUIRE(ev_energy_offer.absolute_price_schedule.price_algorithm ==
|
||||
"urn:iso:std:iso:15118:-20:PriceAlgorithm:1-Power");
|
||||
REQUIRE(ev_energy_offer.absolute_price_schedule.price_rule_stacks.size() == 1);
|
||||
REQUIRE(ev_energy_offer.absolute_price_schedule.price_rule_stacks.at(0).duration == 0);
|
||||
REQUIRE(ev_energy_offer.absolute_price_schedule.price_rule_stacks.at(0).price_rules.size() == 1);
|
||||
REQUIRE(dt::from_RationalNumber(
|
||||
ev_energy_offer.absolute_price_schedule.price_rule_stacks.at(0).price_rules.at(0).energy_fee) ==
|
||||
0);
|
||||
REQUIRE(dt::from_RationalNumber(ev_energy_offer.absolute_price_schedule.price_rule_stacks.at(0)
|
||||
.price_rules.at(0)
|
||||
.power_range_start) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize schedule_exchange_req - scheduled mode") {
|
||||
message_20::ScheduleExchangeRequest req;
|
||||
req.header = message_20::Header{{0x47, 0xFD, 0x3B, 0x4F, 0x13, 0x25, 0x57, 0xCA}, 1727082830};
|
||||
req.max_supporting_points = 1024;
|
||||
auto& control_mode = req.control_mode.emplace<dt::Scheduled_SEReqControlMode>();
|
||||
control_mode.departure_time = 7200;
|
||||
control_mode.target_energy = dt::RationalNumber{10, 3};
|
||||
control_mode.max_energy = dt::RationalNumber{20, 3};
|
||||
control_mode.min_energy = dt::RationalNumber{5, -2};
|
||||
control_mode.energy_offer.emplace();
|
||||
control_mode.energy_offer->power_schedule.time_anchor = 0;
|
||||
control_mode.energy_offer->power_schedule.entries.push_back({3600, {10, 3}});
|
||||
control_mode.energy_offer->absolute_price_schedule.time_anchor = 0;
|
||||
control_mode.energy_offer->absolute_price_schedule.currency = "EUR";
|
||||
control_mode.energy_offer->absolute_price_schedule.price_algorithm =
|
||||
"urn:iso:std:iso:15118:-20:PriceAlgorithm:1-Power";
|
||||
dt::EVPriceRuleStack stack;
|
||||
stack.duration = 0;
|
||||
dt::EVPriceRule rule;
|
||||
rule.energy_fee = {0, 0};
|
||||
rule.power_range_start = {0, 0};
|
||||
stack.price_rules.push_back(rule);
|
||||
control_mode.energy_offer->absolute_price_schedule.price_rule_stacks.push_back(stack);
|
||||
|
||||
std::vector<uint8_t> expected = {
|
||||
0x80, 0x6c, 0x04, 0x23, 0xfe, 0x9d, 0xa7, 0x89, 0x92, 0xab, 0xe5, 0x0c, 0xee, 0x2c, 0x4b, 0x70, 0x62, 0x7e,
|
||||
0x84, 0x28, 0x0e, 0x00, 0x83, 0x00, 0xa0, 0x10, 0x60, 0x28, 0x03, 0xf0, 0x02, 0x80, 0x00, 0x04, 0x80, 0xe0,
|
||||
0x41, 0x80, 0x50, 0x40, 0x00, 0x02, 0xa2, 0xaa, 0xa9, 0x03, 0x27, 0x57, 0x26, 0xe3, 0xa6, 0x97, 0x36, 0xf3,
|
||||
0xa7, 0x37, 0x46, 0x43, 0xa6, 0x97, 0x36, 0xf3, 0xa3, 0x13, 0x53, 0x13, 0x13, 0x83, 0xa2, 0xd3, 0x23, 0x03,
|
||||
0xa5, 0x07, 0x26, 0x96, 0x36, 0x54, 0x16, 0xc6, 0x76, 0xf7, 0x26, 0x97, 0x46, 0x86, 0xd3, 0xa3, 0x12, 0xd5,
|
||||
0x06, 0xf7, 0x76, 0x57, 0x20, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x40};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("DeSerialize schedule_exchange_req - dynamic mode") {
|
||||
uint8_t doc_raw[] = {0x80, 0x6c, 0x04, 0x1c, 0x90, 0x58, 0x02, 0x37, 0x25, 0x7c, 0x84, 0x8d, 0x6b, 0x0c,
|
||||
0x4b, 0x70, 0x62, 0x7e, 0x80, 0xa0, 0x38, 0x03, 0xc1, 0x40, 0x20, 0xc0, 0xa0, 0x10,
|
||||
0x60, 0x78, 0x08, 0x31, 0x13, 0x02, 0x0c, 0x01, 0x40, 0x80, 0x00, 0x00};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be decoded successfully") {
|
||||
|
||||
REQUIRE(variant.get_type() == message_20::Type::ScheduleExchangeReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::ScheduleExchangeRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x39, 0x20, 0xB0, 0x04, 0x6E, 0x4A, 0xF9, 0x09});
|
||||
REQUIRE(header.timestamp == 1727076438);
|
||||
|
||||
REQUIRE(msg.max_supporting_points == 1024);
|
||||
|
||||
REQUIRE(std::holds_alternative<dt::Dynamic_SEReqControlMode>(msg.control_mode));
|
||||
auto& control_mode = std::get<dt::Dynamic_SEReqControlMode>(msg.control_mode);
|
||||
|
||||
REQUIRE(control_mode.departure_time == 7200);
|
||||
REQUIRE(control_mode.minimum_soc == 30);
|
||||
REQUIRE(control_mode.target_soc == 80);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.target_energy) == 40000.0f);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.max_energy) == 60000.0f);
|
||||
REQUIRE(dt::from_RationalNumber(control_mode.min_energy) == -20000.0f);
|
||||
REQUIRE(control_mode.max_v2x_energy.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.max_v2x_energy) == 5000.0f);
|
||||
REQUIRE(control_mode.min_v2x_energy.has_value() == true);
|
||||
REQUIRE(dt::from_RationalNumber(*control_mode.min_v2x_energy) == 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize schedule_exchange_req - dynamic mode") {
|
||||
|
||||
message_20::ScheduleExchangeRequest req;
|
||||
|
||||
req.header = message_20::Header{{0x39, 0x20, 0xB0, 0x04, 0x6E, 0x4A, 0xF9, 0x09}, 1727076438};
|
||||
req.max_supporting_points = 1024;
|
||||
auto& control_mode = req.control_mode.emplace<dt::Dynamic_SEReqControlMode>();
|
||||
control_mode.departure_time = 7200;
|
||||
control_mode.minimum_soc = 30;
|
||||
control_mode.target_soc = 80;
|
||||
control_mode.target_energy = dt::RationalNumber{40, 3};
|
||||
control_mode.max_energy = dt::RationalNumber{60, 3};
|
||||
control_mode.min_energy = dt::RationalNumber{-20, 3};
|
||||
control_mode.max_v2x_energy = dt::RationalNumber{5, 3};
|
||||
control_mode.min_v2x_energy = dt::RationalNumber{0, 0};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x6c, 0x04, 0x1c, 0x90, 0x58, 0x02, 0x37, 0x25, 0x7c,
|
||||
0x84, 0x8d, 0x6b, 0x0c, 0x4b, 0x70, 0x62, 0x7e, 0x80, 0xa0,
|
||||
0x38, 0x03, 0xc1, 0x40, 0x20, 0xc0, 0xa0, 0x10, 0x60, 0x78,
|
||||
0x08, 0x31, 0x13, 0x02, 0x0c, 0x01, 0x40, 0x80, 0x00, 0x00};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize schedule_exchange_res - scheduled mode - no price") {
|
||||
|
||||
message_20::ScheduleExchangeResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x47, 0xFD, 0x3B, 0x4F, 0x13, 0x25, 0x57, 0xCA}, 1727082831};
|
||||
res.response_code = dt::ResponseCode::OK;
|
||||
res.processing = dt::Processing::Finished;
|
||||
auto& control_mode = res.control_mode.emplace<dt::Scheduled_SEResControlMode>();
|
||||
dt::ScheduleTuple tuple;
|
||||
|
||||
tuple.schedule_tuple_id = 1;
|
||||
tuple.charging_schedule.power_schedule.time_anchor = 1727082831;
|
||||
tuple.charging_schedule.power_schedule.entries.push_back({86400, {2208, 1}, std::nullopt, std::nullopt});
|
||||
|
||||
control_mode.schedule_tuple.push_back(tuple);
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x70, 0x04, 0x23, 0xfe, 0x9d, 0xa7, 0x89, 0x92, 0xab, 0xe5, 0x0c,
|
||||
0xfe, 0x2c, 0x4b, 0x70, 0x62, 0x00, 0x04, 0x00, 0x41, 0x9f, 0xc5, 0x89,
|
||||
0x6e, 0x0c, 0x84, 0x05, 0x18, 0x28, 0x40, 0x85, 0x00, 0x89, 0x29, 0x40};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize schedule_exchange_res - scheduled mode - no price") {
|
||||
uint8_t doc_raw[] = {0x80, 0x70, 0x04, 0x23, 0xfe, 0x9d, 0xa7, 0x89, 0x92, 0xab, 0xe5, 0x0c,
|
||||
0xfe, 0x2c, 0x4b, 0x70, 0x62, 0x00, 0x04, 0x00, 0x41, 0x9f, 0xc5, 0x89,
|
||||
0x6e, 0x0c, 0x84, 0x05, 0x18, 0x28, 0x40, 0x85, 0x00, 0x89, 0x29, 0x40};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be decoded successfully") {
|
||||
|
||||
REQUIRE(variant.get_type() == message_20::Type::ScheduleExchangeRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::ScheduleExchangeResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x47, 0xFD, 0x3B, 0x4F, 0x13, 0x25, 0x57, 0xCA});
|
||||
REQUIRE(header.timestamp == 1727082831);
|
||||
|
||||
REQUIRE(msg.response_code == dt::ResponseCode::OK);
|
||||
REQUIRE(msg.processing == dt::Processing::Finished);
|
||||
REQUIRE(msg.control_mode.index() == 1);
|
||||
REQUIRE(std::holds_alternative<dt::Scheduled_SEResControlMode>(msg.control_mode));
|
||||
auto& control_mode = std::get<dt::Scheduled_SEResControlMode>(msg.control_mode);
|
||||
REQUIRE(control_mode.schedule_tuple.size() == 1);
|
||||
REQUIRE(control_mode.schedule_tuple.at(0).schedule_tuple_id == 1);
|
||||
REQUIRE(control_mode.schedule_tuple.at(0).charging_schedule.power_schedule.time_anchor == 1727082831);
|
||||
REQUIRE(control_mode.schedule_tuple.at(0).charging_schedule.power_schedule.entries.size() == 1);
|
||||
REQUIRE(control_mode.schedule_tuple.at(0).charging_schedule.power_schedule.entries.at(0).duration == 86400);
|
||||
REQUIRE(dt::from_RationalNumber(
|
||||
control_mode.schedule_tuple.at(0).charging_schedule.power_schedule.entries.at(0).power) ==
|
||||
22080.0f);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize schedule_exchange_res - scheduled mode - price level") {
|
||||
message_20::ScheduleExchangeResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x47, 0xFD, 0x3B, 0x4F, 0x13, 0x25, 0x57, 0xCA}, 1727082831};
|
||||
res.response_code = dt::ResponseCode::OK;
|
||||
res.processing = dt::Processing::Finished;
|
||||
auto& control_mode = res.control_mode.emplace<dt::Scheduled_SEResControlMode>();
|
||||
dt::ScheduleTuple tuple;
|
||||
|
||||
tuple.schedule_tuple_id = 1;
|
||||
tuple.charging_schedule.power_schedule.time_anchor = 1727082831;
|
||||
tuple.charging_schedule.power_schedule.entries.push_back({86400, {2208, 1}, std::nullopt, std::nullopt});
|
||||
|
||||
auto& price_level = tuple.charging_schedule.price_schedule.emplace<dt::PriceLevelSchedule>();
|
||||
price_level.time_anchor = 1727082831;
|
||||
price_level.price_schedule_id = 1;
|
||||
price_level.number_of_price_levels = 0;
|
||||
price_level.price_level_schedule_entries.push_back({23, 8});
|
||||
|
||||
control_mode.schedule_tuple.push_back(tuple);
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x70, 0x04, 0x23, 0xfe, 0x9d, 0xa7, 0x89, 0x92, 0xab, 0xe5, 0x0c,
|
||||
0xfe, 0x2c, 0x4b, 0x70, 0x62, 0x00, 0x04, 0x00, 0x41, 0x9f, 0xc5, 0x89,
|
||||
0x6e, 0x0c, 0x84, 0x05, 0x18, 0x28, 0x40, 0x85, 0x00, 0x89, 0x25, 0x67,
|
||||
0xf1, 0x62, 0x5b, 0x83, 0x00, 0x12, 0x00, 0x00, 0xb8, 0x08, 0x11, 0x40};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("DeSerialize schedule_exchange_res - scheduled mode - price level") {
|
||||
uint8_t doc_raw[] = {0x80, 0x70, 0x04, 0x23, 0xfe, 0x9d, 0xa7, 0x89, 0x92, 0xab, 0xe5, 0x0c,
|
||||
0xfe, 0x2c, 0x4b, 0x70, 0x62, 0x00, 0x04, 0x00, 0x41, 0x9f, 0xc5, 0x89,
|
||||
0x6e, 0x0c, 0x84, 0x05, 0x18, 0x28, 0x40, 0x85, 0x00, 0x89, 0x25, 0x67,
|
||||
0xf1, 0x62, 0x5b, 0x83, 0x00, 0x12, 0x00, 0x00, 0xb8, 0x08, 0x11, 0x40};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be decoded successfully") {
|
||||
|
||||
REQUIRE(variant.get_type() == message_20::Type::ScheduleExchangeRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::ScheduleExchangeResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x47, 0xFD, 0x3B, 0x4F, 0x13, 0x25, 0x57, 0xCA});
|
||||
REQUIRE(header.timestamp == 1727082831);
|
||||
|
||||
REQUIRE(msg.response_code == dt::ResponseCode::OK);
|
||||
REQUIRE(msg.processing == dt::Processing::Finished);
|
||||
REQUIRE(msg.control_mode.index() == 1);
|
||||
REQUIRE(std::holds_alternative<dt::Scheduled_SEResControlMode>(msg.control_mode));
|
||||
auto& control_mode = std::get<dt::Scheduled_SEResControlMode>(msg.control_mode);
|
||||
REQUIRE(control_mode.schedule_tuple.size() == 1);
|
||||
REQUIRE(control_mode.schedule_tuple.at(0).schedule_tuple_id == 1);
|
||||
REQUIRE(control_mode.schedule_tuple.at(0).charging_schedule.power_schedule.time_anchor == 1727082831);
|
||||
REQUIRE(control_mode.schedule_tuple.at(0).charging_schedule.power_schedule.entries.size() == 1);
|
||||
REQUIRE(control_mode.schedule_tuple.at(0).charging_schedule.power_schedule.entries.at(0).duration == 86400);
|
||||
REQUIRE(dt::from_RationalNumber(
|
||||
control_mode.schedule_tuple.at(0).charging_schedule.power_schedule.entries.at(0).power) ==
|
||||
22080.0f);
|
||||
REQUIRE(control_mode.schedule_tuple.at(0).charging_schedule.price_schedule.index() == 2);
|
||||
auto& price_level =
|
||||
std::get<dt::PriceLevelSchedule>(control_mode.schedule_tuple.at(0).charging_schedule.price_schedule);
|
||||
REQUIRE(price_level.time_anchor == 1727082831);
|
||||
REQUIRE(price_level.price_schedule_id == 1);
|
||||
REQUIRE(price_level.number_of_price_levels == 0);
|
||||
REQUIRE(price_level.price_level_schedule_entries.size() == 1);
|
||||
REQUIRE(price_level.price_level_schedule_entries.at(0).duration == 23);
|
||||
REQUIRE(price_level.price_level_schedule_entries.at(0).price_level == 8);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize schedule_exchange_res - scheduled mode - absolute price") {
|
||||
// TODO(sl): Add test + generate exi stream
|
||||
}
|
||||
|
||||
GIVEN("DeSerialize schedule_exchange_res - scheduled mode - absolute price") {
|
||||
// TODO(rb): Add test + generate exi stream
|
||||
}
|
||||
|
||||
GIVEN("Serialize schedule_exchange_res - dynamic mode") {
|
||||
message_20::ScheduleExchangeResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x39, 0x20, 0xB0, 0x04, 0x6E, 0x4A, 0xF9, 0x09}, 1727076439};
|
||||
res.response_code = dt::ResponseCode::OK;
|
||||
res.processing = dt::Processing::Finished;
|
||||
auto& control_mode = res.control_mode.emplace<dt::Dynamic_SEResControlMode>();
|
||||
control_mode.departure_time = 2000;
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x70, 0x04, 0x1c, 0x90, 0x58, 0x02, 0x37, 0x25, 0x7c, 0x84,
|
||||
0x8d, 0x7b, 0x0c, 0x4b, 0x70, 0x62, 0x00, 0x02, 0x1a, 0x01, 0xe8};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("DeSerialize schedule_exchange_res - dynamic mode") {
|
||||
uint8_t doc_raw[] = {0x80, 0x70, 0x04, 0x1c, 0x90, 0x58, 0x02, 0x37, 0x25, 0x7c, 0x84,
|
||||
0x8d, 0x7b, 0x0c, 0x4b, 0x70, 0x62, 0x00, 0x02, 0x1a, 0x01, 0xe8};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be decoded successfully") {
|
||||
|
||||
REQUIRE(variant.get_type() == message_20::Type::ScheduleExchangeRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::ScheduleExchangeResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x39, 0x20, 0xB0, 0x04, 0x6E, 0x4A, 0xF9, 0x09});
|
||||
REQUIRE(header.timestamp == 1727076439);
|
||||
|
||||
REQUIRE(msg.response_code == dt::ResponseCode::OK);
|
||||
REQUIRE(msg.processing == dt::Processing::Finished);
|
||||
REQUIRE(msg.control_mode.index() == 0);
|
||||
REQUIRE(std::holds_alternative<dt::Dynamic_SEResControlMode>(msg.control_mode));
|
||||
auto& control_mode = std::get<dt::Dynamic_SEResControlMode>(msg.control_mode);
|
||||
REQUIRE(control_mode.departure_time == 2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iso15118/message/service_detail.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
SCENARIO("Se/Deserialize service_detail messages") {
|
||||
|
||||
GIVEN("Deserialize service_detail_req") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x74, 0x04, 0x02, 0x75, 0xff, 0x96, 0x4a, 0x2c, 0xed,
|
||||
0xa1, 0x0e, 0x38, 0x7e, 0x8a, 0x60, 0x62, 0x02, 0x80};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be decoded successfully") {
|
||||
|
||||
REQUIRE(variant.get_type() == message_20::Type::ServiceDetailReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::ServiceDetailRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x04, 0xEB, 0xFF, 0x2C, 0x94, 0x59, 0xDB, 0x42});
|
||||
REQUIRE(header.timestamp == 1692009443);
|
||||
|
||||
REQUIRE(msg.service == message_20::to_underlying_value(message_20::datatypes::ServiceCategory::AC_BPT));
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize service_detail_req") {
|
||||
|
||||
message_20::ServiceDetailRequest req;
|
||||
|
||||
req.header = message_20::Header{{0x04, 0xEB, 0xFF, 0x2C, 0x94, 0x59, 0xDB, 0x42}, 1692009443};
|
||||
req.service = message_20::to_underlying_value(message_20::datatypes::ServiceCategory::AC_BPT);
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x74, 0x04, 0x02, 0x75, 0xff, 0x96, 0x4a, 0x2c, 0xed,
|
||||
0xa1, 0x0e, 0x38, 0x7e, 0x8a, 0x60, 0x62, 0x02, 0x80};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize service_detail_res") {
|
||||
|
||||
message_20::ServiceDetailResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456323};
|
||||
res.response_code = message_20::datatypes::ResponseCode::OK;
|
||||
res.service = message_20::to_underlying_value(message_20::datatypes::ServiceCategory::DC);
|
||||
|
||||
const auto list = message_20::datatypes::DcParameterList{
|
||||
message_20::datatypes::DcConnector::Extended, message_20::datatypes::ControlMode::Scheduled,
|
||||
message_20::datatypes::MobilityNeedsMode::ProvidedByEvcc, message_20::datatypes::Pricing::NoPricing};
|
||||
res.service_parameter_list = {message_20::datatypes::ParameterSet(0, list)};
|
||||
|
||||
std::vector<uint8_t> expected = {
|
||||
0x80, 0x78, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0x3b, 0xfe, 0x1b, 0x60,
|
||||
0x62, 0x00, 0x00, 0x80, 0x00, 0x02, 0xd0, 0xdb, 0xdb, 0x9b, 0x99, 0x58, 0xdd, 0x1b, 0xdc, 0x98,
|
||||
0x04, 0x00, 0xd4, 0x36, 0xf6, 0xe7, 0x47, 0x26, 0xf6, 0xc4, 0xd6, 0xf6, 0x46, 0x56, 0x00, 0x80,
|
||||
0x4d, 0x35, 0xbd, 0x89, 0xa5, 0xb1, 0xa5, 0xd1, 0xe5, 0x39, 0x95, 0x95, 0x91, 0xcd, 0x35, 0xbd,
|
||||
0x91, 0x95, 0x80, 0x20, 0x09, 0x50, 0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x60, 0x00, 0xa0};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize service_detail_res") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x78, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0x3b, 0xfe,
|
||||
0x1b, 0x60, 0x62, 0x00, 0x00, 0x80, 0x00, 0x02, 0xd0, 0xdb, 0xdb, 0x9b, 0x99, 0x58,
|
||||
0xdd, 0x1b, 0xdc, 0x98, 0x04, 0x00, 0xd4, 0x36, 0xf6, 0xe7, 0x47, 0x26, 0xf6, 0xc4,
|
||||
0xd6, 0xf6, 0x46, 0x56, 0x00, 0x80, 0x4d, 0x35, 0xbd, 0x89, 0xa5, 0xb1, 0xa5, 0xd1,
|
||||
0xe5, 0x39, 0x95, 0x95, 0x91, 0xcd, 0x35, 0xbd, 0x91, 0x95, 0x80, 0x20, 0x09, 0x50,
|
||||
0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x60, 0x00, 0xa0};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be decoded successfully") {
|
||||
|
||||
REQUIRE(variant.get_type() == message_20::Type::ServiceDetailRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::ServiceDetailResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456323);
|
||||
|
||||
REQUIRE(msg.service == message_20::to_underlying_value(message_20::datatypes::ServiceCategory::DC));
|
||||
REQUIRE(msg.response_code == message_20::datatypes::ResponseCode::OK);
|
||||
REQUIRE(msg.service_parameter_list.size() == 1);
|
||||
REQUIRE(msg.service_parameter_list[0].id == 0);
|
||||
REQUIRE(msg.service_parameter_list[0].parameter.size() == 4);
|
||||
REQUIRE(msg.service_parameter_list[0].parameter[0].name == "Connector");
|
||||
REQUIRE(std::holds_alternative<int32_t>(msg.service_parameter_list[0].parameter[0].value));
|
||||
REQUIRE(std::get<int32_t>(msg.service_parameter_list[0].parameter[0].value) ==
|
||||
static_cast<int32_t>(message_20::datatypes::DcConnector::Extended));
|
||||
REQUIRE(msg.service_parameter_list[0].parameter[1].name == "ControlMode");
|
||||
REQUIRE(std::holds_alternative<int32_t>(msg.service_parameter_list[0].parameter[1].value));
|
||||
REQUIRE(std::get<int32_t>(msg.service_parameter_list[0].parameter[1].value) ==
|
||||
static_cast<int32_t>(message_20::datatypes::ControlMode::Scheduled));
|
||||
REQUIRE(msg.service_parameter_list[0].parameter[2].name == "MobilityNeedsMode");
|
||||
REQUIRE(std::holds_alternative<int32_t>(msg.service_parameter_list[0].parameter[2].value));
|
||||
REQUIRE(std::get<int32_t>(msg.service_parameter_list[0].parameter[2].value) ==
|
||||
static_cast<int32_t>(message_20::datatypes::MobilityNeedsMode::ProvidedByEvcc));
|
||||
REQUIRE(msg.service_parameter_list[0].parameter[3].name == "Pricing");
|
||||
REQUIRE(std::holds_alternative<int32_t>(msg.service_parameter_list[0].parameter[3].value));
|
||||
REQUIRE(std::get<int32_t>(msg.service_parameter_list[0].parameter[3].value) ==
|
||||
static_cast<int32_t>(message_20::datatypes::Pricing::NoPricing));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iso15118/message/service_discovery.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
SCENARIO("Se/Deserialize service_discovery messages") {
|
||||
|
||||
GIVEN("Deserialize service_discovery_req") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x7c, 0x04, 0x02, 0x75, 0xff, 0x96, 0x4a, 0x2c,
|
||||
0xed, 0xa1, 0x0e, 0x38, 0x7e, 0x8a, 0x60, 0x62, 0x80};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be decoded successfully") {
|
||||
|
||||
REQUIRE(variant.get_type() == message_20::Type::ServiceDiscoveryReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::ServiceDiscoveryRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x04, 0xEB, 0xFF, 0x2C, 0x94, 0x59, 0xDB, 0x42});
|
||||
REQUIRE(header.timestamp == 1692009443);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize service_discovery_req_with_supported_service_ids") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x7c, 0x04, 0x02, 0x75, 0xff, 0x96, 0x4a, 0x2c, 0xed,
|
||||
0xa1, 0x0e, 0x38, 0x7e, 0x8a, 0x60, 0x62, 0x00, 0x44};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be decoded successfully") {
|
||||
|
||||
REQUIRE(variant.get_type() == message_20::Type::ServiceDiscoveryReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::ServiceDiscoveryRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x04, 0xEB, 0xFF, 0x2C, 0x94, 0x59, 0xDB, 0x42});
|
||||
REQUIRE(header.timestamp == 1692009443);
|
||||
REQUIRE(msg.supported_service_ids.has_value() == true);
|
||||
REQUIRE(msg.supported_service_ids.value().size() == 1);
|
||||
REQUIRE(msg.supported_service_ids.value()[0] == 2);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize service_discovery_req") {
|
||||
|
||||
message_20::ServiceDiscoveryRequest req;
|
||||
|
||||
req.header = message_20::Header{{0x04, 0xEB, 0xFF, 0x2C, 0x94, 0x59, 0xDB, 0x42}, 1692009443};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x7c, 0x04, 0x02, 0x75, 0xff, 0x96, 0x4a, 0x2c,
|
||||
0xed, 0xa1, 0x0e, 0x38, 0x7e, 0x8a, 0x60, 0x62, 0x80};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize service_discovery_req_with_supported_service_ids") {
|
||||
|
||||
message_20::ServiceDiscoveryRequest req;
|
||||
|
||||
req.header = message_20::Header{{0x04, 0xEB, 0xFF, 0x2C, 0x94, 0x59, 0xDB, 0x42}, 1692009443};
|
||||
req.supported_service_ids = {2};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x7c, 0x04, 0x02, 0x75, 0xff, 0x96, 0x4a, 0x2c, 0xed,
|
||||
0xa1, 0x0e, 0x38, 0x7e, 0x8a, 0x60, 0x62, 0x00, 0x44};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize service_discovery_res") {
|
||||
|
||||
message_20::ServiceDiscoveryResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456322};
|
||||
res.response_code = message_20::datatypes::ResponseCode::OK;
|
||||
res.service_renegotiation_supported = false;
|
||||
res.energy_transfer_service_list = {{message_20::datatypes::ServiceCategory::DC, false},
|
||||
{message_20::datatypes::ServiceCategory::DC_BPT, false}};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x80, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c,
|
||||
0x2b, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x00, 0x02, 0x00, 0x01, 0x80, 0x50};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize service_discovery_res_with_vas_list") {
|
||||
|
||||
message_20::ServiceDiscoveryResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456322};
|
||||
res.response_code = message_20::datatypes::ResponseCode::OK;
|
||||
res.service_renegotiation_supported = false;
|
||||
res.energy_transfer_service_list = {{message_20::datatypes::ServiceCategory::DC, false},
|
||||
{message_20::datatypes::ServiceCategory::DC_BPT, false}};
|
||||
res.vas_list = {{message_20::to_underlying_value(message_20::datatypes::ServiceCategory::Internet), true}};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x80, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0x2b,
|
||||
0xfe, 0x1b, 0x60, 0x62, 0x00, 0x00, 0x02, 0x00, 0x01, 0x80, 0x40, 0x82, 0x22};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize service_discovery_res") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x80, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c,
|
||||
0x2b, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x00, 0x02, 0x00, 0x01, 0x80, 0x50};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be decoded successfully") {
|
||||
|
||||
REQUIRE(variant.get_type() == message_20::Type::ServiceDiscoveryRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::ServiceDiscoveryResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456322);
|
||||
REQUIRE(msg.response_code == message_20::datatypes::ResponseCode::OK);
|
||||
REQUIRE(msg.service_renegotiation_supported == false);
|
||||
REQUIRE(msg.energy_transfer_service_list.size() == 2);
|
||||
REQUIRE(msg.energy_transfer_service_list[0].service_id == message_20::datatypes::ServiceCategory::DC);
|
||||
REQUIRE(msg.energy_transfer_service_list[0].free_service == false);
|
||||
REQUIRE(msg.energy_transfer_service_list[1].service_id == message_20::datatypes::ServiceCategory::DC_BPT);
|
||||
REQUIRE(msg.energy_transfer_service_list[1].free_service == false);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize service_discovery_res_with_vas_list") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x80, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c, 0x4d, 0x8c, 0x2b,
|
||||
0xfe, 0x1b, 0x60, 0x62, 0x00, 0x00, 0x02, 0x00, 0x01, 0x80, 0x40, 0x82, 0x22};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be decoded successfully") {
|
||||
|
||||
REQUIRE(variant.get_type() == message_20::Type::ServiceDiscoveryRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::ServiceDiscoveryResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456322);
|
||||
REQUIRE(msg.response_code == message_20::datatypes::ResponseCode::OK);
|
||||
REQUIRE(msg.service_renegotiation_supported == false);
|
||||
REQUIRE(msg.energy_transfer_service_list.size() == 2);
|
||||
REQUIRE(msg.energy_transfer_service_list[0].service_id == message_20::datatypes::ServiceCategory::DC);
|
||||
REQUIRE(msg.energy_transfer_service_list[0].free_service == false);
|
||||
REQUIRE(msg.energy_transfer_service_list[1].service_id == message_20::datatypes::ServiceCategory::DC_BPT);
|
||||
REQUIRE(msg.energy_transfer_service_list[1].free_service == false);
|
||||
REQUIRE(msg.vas_list.value().size() == 1);
|
||||
REQUIRE(msg.vas_list.value()[0].service_id ==
|
||||
message_20::to_underlying_value(message_20::datatypes::ServiceCategory::Internet));
|
||||
REQUIRE(msg.vas_list.value()[0].free_service == true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iso15118/message/service_selection.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
namespace dt = message_20::datatypes;
|
||||
|
||||
SCENARIO("Se/Deserialize service_selection messages") {
|
||||
|
||||
GIVEN("Deserialize service_selection_req") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x84, 0x04, 0x02, 0x75, 0xff, 0x96, 0x4a, 0x2c, 0xed, 0xa1,
|
||||
0x0e, 0x38, 0x7e, 0x8a, 0x60, 0x62, 0x01, 0x40, 0x08, 0x80};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be decoded successfully") {
|
||||
|
||||
REQUIRE(variant.get_type() == message_20::Type::ServiceSelectionReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::ServiceSelectionRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x04, 0xEB, 0xFF, 0x2C, 0x94, 0x59, 0xDB, 0x42});
|
||||
REQUIRE(header.timestamp == 1692009443);
|
||||
|
||||
REQUIRE(msg.selected_energy_transfer_service.service_id == dt::ServiceCategory::AC_BPT);
|
||||
REQUIRE(msg.selected_energy_transfer_service.parameter_set_id == 1);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize service_selection_req vas") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x84, 0x04, 0x02, 0x75, 0xFF, 0x96, 0x4A, 0x2C, 0xED, 0xA1, 0x0E,
|
||||
0x38, 0x7E, 0x8A, 0x60, 0x62, 0x01, 0x40, 0x08, 0x04, 0x10, 0x04, 0x20};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be decoded successfully") {
|
||||
|
||||
REQUIRE(variant.get_type() == message_20::Type::ServiceSelectionReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::ServiceSelectionRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x04, 0xEB, 0xFF, 0x2C, 0x94, 0x59, 0xDB, 0x42});
|
||||
REQUIRE(header.timestamp == 1692009443);
|
||||
|
||||
REQUIRE(msg.selected_energy_transfer_service.service_id == dt::ServiceCategory::AC_BPT);
|
||||
REQUIRE(msg.selected_energy_transfer_service.parameter_set_id == 1);
|
||||
|
||||
REQUIRE(msg.selected_vas_list.has_value() == true);
|
||||
const auto& selected_vas_list = msg.selected_vas_list.value();
|
||||
REQUIRE(selected_vas_list.size() == 1);
|
||||
REQUIRE(selected_vas_list.at(0).service_id ==
|
||||
message_20::to_underlying_value(dt::ServiceCategory::Internet));
|
||||
REQUIRE(selected_vas_list.at(0).parameter_set_id == 2);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize service_selection_req") {
|
||||
|
||||
message_20::ServiceSelectionRequest req;
|
||||
|
||||
req.header = message_20::Header{{0x04, 0xEB, 0xFF, 0x2C, 0x94, 0x59, 0xDB, 0x42}, 1692009443};
|
||||
req.selected_energy_transfer_service.service_id = dt::ServiceCategory::AC_BPT;
|
||||
req.selected_energy_transfer_service.parameter_set_id = 1;
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x84, 0x04, 0x02, 0x75, 0xff, 0x96, 0x4a, 0x2c, 0xed, 0xa1,
|
||||
0x0e, 0x38, 0x7e, 0x8a, 0x60, 0x62, 0x01, 0x40, 0x08, 0x80};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize service_selection_req vas") {
|
||||
|
||||
message_20::ServiceSelectionRequest req;
|
||||
|
||||
req.header = message_20::Header{{0x04, 0xEB, 0xFF, 0x2C, 0x94, 0x59, 0xDB, 0x42}, 1692009443};
|
||||
req.selected_energy_transfer_service.service_id = dt::ServiceCategory::AC_BPT;
|
||||
req.selected_energy_transfer_service.parameter_set_id = 1;
|
||||
|
||||
const auto vas = dt::VasSelectedService{message_20::to_underlying_value(dt::ServiceCategory::Internet), 2};
|
||||
|
||||
req.selected_vas_list.emplace({vas});
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x84, 0x04, 0x02, 0x75, 0xFF, 0x96, 0x4A, 0x2C, 0xED, 0xA1, 0x0E,
|
||||
0x38, 0x7E, 0x8A, 0x60, 0x62, 0x01, 0x40, 0x08, 0x04, 0x10, 0x04, 0x20};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize service_selection_res") {
|
||||
|
||||
message_20::ServiceSelectionResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456323};
|
||||
res.response_code = dt::ResponseCode::OK;
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x88, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c,
|
||||
0x4d, 0x8c, 0x3b, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x00};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize service_selection_res") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x88, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c,
|
||||
0x4d, 0x8c, 0x3b, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x00};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be decoded successfully") {
|
||||
|
||||
REQUIRE(variant.get_type() == message_20::Type::ServiceSelectionRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::ServiceSelectionResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456323);
|
||||
|
||||
REQUIRE(msg.response_code == dt::ResponseCode::OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iso15118/message/session_setup.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
SCENARIO("Se/Deserialize session setup messages") {
|
||||
|
||||
GIVEN("Deserialize session_setup_req") {
|
||||
uint8_t doc_raw[] = {0x80, 0x8c, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x9f,
|
||||
0x9c, 0x2b, 0xd0, 0x62, 0xb, 0x2b, 0xa6, 0xa4, 0xab, 0x18, 0x99, 0x19, 0x9a,
|
||||
0x1a, 0x9b, 0x1b, 0x9c, 0x1c, 0x98, 0x20, 0xa1, 0x21, 0xa2, 0x22, 0xac, 0x0};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::SessionSetupReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::SessionSetupRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0});
|
||||
REQUIRE(header.timestamp == 1739635913);
|
||||
|
||||
REQUIRE(msg.evccid == "WMIV1234567890ABCDEX");
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize session_setup_res") {
|
||||
|
||||
const auto header = message_20::Header{{0x2E, 0xFA, 0x18, 0x94, 0xDC, 0x7B, 0x90, 0x11}, 1739635913};
|
||||
|
||||
const auto res = message_20::SessionSetupResponse{
|
||||
header, message_20::datatypes::ResponseCode::OK_NewSessionEstablished, "DE*PNX*E12345*1"};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x90, 0x4, 0x17, 0x7d, 0xc, 0x4a, 0x6e, 0x3d, 0xc8, 0x8, 0x8c,
|
||||
0x9f, 0x9c, 0x2b, 0xd0, 0x62, 0x4, 0x4, 0x51, 0x11, 0x4a, 0x94, 0x13,
|
||||
0x96, 0xa, 0x91, 0x4c, 0x4c, 0x8c, 0xcd, 0xd, 0x4a, 0x8c, 0x40};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Deserialize session_setup_res") {
|
||||
uint8_t doc_raw[] = {0x80, 0x90, 0x4, 0x17, 0x7d, 0xc, 0x4a, 0x6e, 0x3d, 0xc8, 0x8, 0x8c,
|
||||
0x9f, 0x9c, 0x2b, 0xd0, 0x62, 0x4, 0x4, 0x51, 0x11, 0x4a, 0x94, 0x13,
|
||||
0x96, 0xa, 0x91, 0x4c, 0x4c, 0x8c, 0xcd, 0xd, 0x4a, 0x8c, 0x40};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::SessionSetupRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::SessionSetupResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x2E, 0xFA, 0x18, 0x94, 0xDC, 0x7B, 0x90, 0x11});
|
||||
REQUIRE(header.timestamp == 1739635913);
|
||||
|
||||
REQUIRE(msg.evseid == "DE*PNX*E12345*1");
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize session_setup_req") {
|
||||
|
||||
const auto header = message_20::Header{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 1739635913};
|
||||
|
||||
const auto res = message_20::SessionSetupRequest{header, "WMIV1234567890ABCDEX"};
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x8c, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x9f,
|
||||
0x9c, 0x2b, 0xd0, 0x62, 0xb, 0x2b, 0xa6, 0xa4, 0xab, 0x18, 0x99, 0x19, 0x9a,
|
||||
0x1a, 0x9b, 0x1b, 0x9c, 0x1c, 0x98, 0x20, 0xa1, 0x21, 0xa2, 0x22, 0xac, 0x0};
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iso15118/message/session_stop.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
using namespace iso15118;
|
||||
|
||||
SCENARIO("Se/Deserialize session stop messages") {
|
||||
|
||||
GIVEN("Deserialize session_stop_req") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x94, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7,
|
||||
0x6c, 0x4d, 0x8d, 0x7b, 0xfe, 0x1b, 0x60, 0x62, 0x28};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::SessionStopReq);
|
||||
|
||||
const auto& msg = variant.get<message_20::SessionStopRequest>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456343);
|
||||
|
||||
REQUIRE(msg.charging_session == message_20::datatypes::ChargingSession::Terminate);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize session_stop_req") {
|
||||
|
||||
message_20::SessionStopRequest req;
|
||||
|
||||
req.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456343};
|
||||
req.charging_session = message_20::datatypes::ChargingSession::Terminate;
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x94, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7,
|
||||
0x6c, 0x4d, 0x8d, 0x7b, 0xfe, 0x1b, 0x60, 0x62, 0x28};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(req) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Serialize session_stop_res") {
|
||||
|
||||
message_20::SessionStopResponse res;
|
||||
|
||||
res.header = message_20::Header{{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B}, 1725456343};
|
||||
res.response_code = message_20::datatypes::ResponseCode::OK;
|
||||
|
||||
std::vector<uint8_t> expected = {0x80, 0x98, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c,
|
||||
0x4d, 0x8d, 0x7b, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x00};
|
||||
|
||||
THEN("It should be serialized successfully") {
|
||||
REQUIRE(serialize_helper(res) == expected);
|
||||
}
|
||||
}
|
||||
GIVEN("Deserialize session_stop_res") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x98, 0x04, 0x1e, 0xa6, 0x5f, 0xc9, 0x9b, 0xa7, 0x6c,
|
||||
0x4d, 0x8d, 0x7b, 0xfe, 0x1b, 0x60, 0x62, 0x00, 0x00};
|
||||
|
||||
const io::StreamInputView stream_view{doc_raw, sizeof(doc_raw)};
|
||||
|
||||
message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);
|
||||
|
||||
THEN("It should be deserialized successfully") {
|
||||
REQUIRE(variant.get_type() == message_20::Type::SessionStopRes);
|
||||
|
||||
const auto& msg = variant.get<message_20::SessionStopResponse>();
|
||||
const auto& header = msg.header;
|
||||
|
||||
REQUIRE(header.session_id == std::array<uint8_t, 8>{0x3D, 0x4C, 0xBF, 0x93, 0x37, 0x4E, 0xD8, 0x9B});
|
||||
REQUIRE(header.timestamp == 1725456343);
|
||||
|
||||
REQUIRE(msg.response_code == message_20::datatypes::ResponseCode::OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user