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:
64
tools/EVerest-main/lib/everest/cbv2g/tests/BUILD.bazel
Normal file
64
tools/EVerest-main/lib/everest/cbv2g/tests/BUILD.bazel
Normal file
@@ -0,0 +1,64 @@
|
||||
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
|
||||
load("//third-party/bazel/toolchains:defs.bzl", "CROSS_TEST_INCOMPATIBLE")
|
||||
|
||||
cc_library(
|
||||
name = "test_utilities",
|
||||
srcs = ["test_utils/codec.cpp"],
|
||||
hdrs = ["test_utils/include/test_utils/codec.hpp"],
|
||||
includes = ["test_utils/include"],
|
||||
deps = [
|
||||
"//lib/everest/cbv2g:din",
|
||||
"//lib/everest/cbv2g:iso2",
|
||||
"//lib/everest/cbv2g:iso20",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "test_app_handshake",
|
||||
srcs = ["app_handshake/app_handshake.cpp"],
|
||||
target_compatible_with = CROSS_TEST_INCOMPATIBLE,
|
||||
deps = [
|
||||
":test_utilities",
|
||||
"@catch2//:catch2_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "test_session_setup",
|
||||
srcs = ["din/session_setup.cpp"],
|
||||
target_compatible_with = CROSS_TEST_INCOMPATIBLE,
|
||||
deps = [
|
||||
":test_utilities",
|
||||
"@catch2//:catch2_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "test_service_discovery",
|
||||
srcs = ["din/service_discovery.cpp"],
|
||||
target_compatible_with = CROSS_TEST_INCOMPATIBLE,
|
||||
deps = [
|
||||
":test_utilities",
|
||||
"@catch2//:catch2_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "test_ac_charge_loop",
|
||||
srcs = ["iso20/ac_charge_loop.cpp"],
|
||||
target_compatible_with = CROSS_TEST_INCOMPATIBLE,
|
||||
deps = [
|
||||
":test_utilities",
|
||||
"@catch2//:catch2_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "test_dc_charge_loop",
|
||||
srcs = ["iso20/dc_charge_loop.cpp"],
|
||||
target_compatible_with = CROSS_TEST_INCOMPATIBLE,
|
||||
deps = [
|
||||
":test_utilities",
|
||||
"@catch2//:catch2_main",
|
||||
],
|
||||
)
|
||||
19
tools/EVerest-main/lib/everest/cbv2g/tests/CMakeLists.txt
Normal file
19
tools/EVerest-main/lib/everest/cbv2g/tests/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
Catch2
|
||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||
GIT_TAG v3.4.0 # or a later release
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(Catch2)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
|
||||
include(Catch)
|
||||
|
||||
# source helper functions and library
|
||||
add_subdirectory(test_utils)
|
||||
|
||||
add_subdirectory(app_handshake)
|
||||
add_subdirectory(din)
|
||||
add_subdirectory(iso20)
|
||||
@@ -0,0 +1 @@
|
||||
add_codec_test(app_handshake)
|
||||
@@ -0,0 +1,60 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <cbv2g/app_handshake/appHand_Datatypes.h>
|
||||
#include <cbv2g/app_handshake/appHand_Decoder.h>
|
||||
|
||||
#include "test_utils/codec.hpp"
|
||||
|
||||
SCENARIO("Encode and decode app protocol request messages") {
|
||||
|
||||
GIVEN("Decode an AppProtocolReq document") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x00, 0xf3, 0xab, 0x93, 0x71, 0xd3, 0x4b, 0x9b, 0x79, 0xd3, 0x9b, 0xa3,
|
||||
0x21, 0xd3, 0x4b, 0x9b, 0x79, 0xd1, 0x89, 0xa9, 0x89, 0x89, 0xc1, 0xd1, 0x69,
|
||||
0x91, 0x81, 0xd2, 0x0a, 0x18, 0x01, 0x00, 0x00, 0x04, 0x00, 0x40};
|
||||
|
||||
THEN("It should be decoded succussfully") {
|
||||
const auto result = test_utils::decode<appHand_exiDocument>(doc_raw, sizeof(doc_raw));
|
||||
REQUIRE(result.decoding_successful);
|
||||
|
||||
const auto& request = result.value;
|
||||
|
||||
REQUIRE(request.supportedAppProtocolReq_isUsed == 1);
|
||||
|
||||
REQUIRE(request.supportedAppProtocolReq.AppProtocol.arrayLen == 1);
|
||||
|
||||
const auto& ap = request.supportedAppProtocolReq.AppProtocol.array[0];
|
||||
|
||||
REQUIRE(ap.VersionNumberMajor == 1);
|
||||
REQUIRE(ap.VersionNumberMinor == 0);
|
||||
REQUIRE(ap.SchemaID == 1);
|
||||
REQUIRE(ap.Priority == 1);
|
||||
|
||||
const auto protocol_namespace = std::string(ap.ProtocolNamespace.characters);
|
||||
REQUIRE(protocol_namespace == "urn:iso:std:iso:15118:-20:AC");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("Encode and decode app protocol response messages") {
|
||||
|
||||
GIVEN("Decode an AppProtocolRes document") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x40, 0x00, 0x40};
|
||||
|
||||
THEN("It should be decoded succussfully") {
|
||||
const auto result = test_utils::decode<appHand_exiDocument>(doc_raw, sizeof(doc_raw));
|
||||
REQUIRE(result.decoding_successful);
|
||||
|
||||
const auto& response = result.value;
|
||||
|
||||
REQUIRE(response.supportedAppProtocolRes_isUsed == 1);
|
||||
|
||||
REQUIRE(response.supportedAppProtocolRes.ResponseCode == appHand_responseCodeType_OK_SuccessfulNegotiation);
|
||||
REQUIRE(response.supportedAppProtocolRes.SchemaID_isUsed == true);
|
||||
REQUIRE(response.supportedAppProtocolRes.SchemaID == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
add_codec_test(session_setup)
|
||||
add_codec_test(service_discovery)
|
||||
@@ -0,0 +1,214 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cbv2g/din/din_msgDefDecoder.h>
|
||||
#include <cbv2g/din/din_msgDefEncoder.h>
|
||||
|
||||
#include "test_utils/codec.hpp"
|
||||
|
||||
SCENARIO("Encode and decode a DIN70121 service discovery message") {
|
||||
|
||||
// Exi Stream: 809a0211d63f74d2297ac9119400
|
||||
// XML:
|
||||
// <ns7:V2G_Message>
|
||||
// <ns7:Header>
|
||||
// <ns8:SessionID>4758FDD348A5EB24</ns8:SessionID>
|
||||
// </ns7:Header>
|
||||
// <ns7:Body>
|
||||
// <ns5:ServiceDiscoveryReq>
|
||||
// <ns5:ServiceCategory>EVCharging</ns5:ServiceCategory>
|
||||
// </ns5:ServiceDiscoveryReq>
|
||||
// </ns7:Body>
|
||||
// </ns7:V2G_Message>
|
||||
|
||||
GIVEN("Good case - Encode a ServiceDiscoveryReq document") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x9a, 0x02, 0x11, 0xd6, 0x3f, 0x74, 0xd2, 0x29, 0x7a, 0xc9, 0x11, 0x94, 0x00};
|
||||
|
||||
din_exiDocument request;
|
||||
init_din_exiDocument(&request);
|
||||
|
||||
init_din_MessageHeaderType(&request.V2G_Message.Header);
|
||||
|
||||
auto& header = request.V2G_Message.Header;
|
||||
header.SessionID.bytesLen = din_sessionIDType_BYTES_SIZE;
|
||||
|
||||
// copy the session id into the header
|
||||
const auto session_id = std::array<uint8_t, 8>{0x47, 0x58, 0xFD, 0xD3, 0x48, 0xA5, 0xEB, 0x24};
|
||||
std::copy(session_id.begin(), session_id.end(), header.SessionID.bytes);
|
||||
|
||||
init_din_BodyType(&request.V2G_Message.Body);
|
||||
auto& body = request.V2G_Message.Body;
|
||||
|
||||
// set the ServiceDiscoveryReqType
|
||||
init_din_ServiceDiscoveryReqType(&body.ServiceDiscoveryReq);
|
||||
body.ServiceDiscoveryReq_isUsed = true;
|
||||
|
||||
// set the service category
|
||||
body.ServiceDiscoveryReq.ServiceScope_isUsed = false;
|
||||
body.ServiceDiscoveryReq.ServiceCategory_isUsed = true;
|
||||
body.ServiceDiscoveryReq.ServiceCategory = din_serviceCategoryType_EVCharging;
|
||||
|
||||
THEN("It should be encoded succussfully") {
|
||||
const auto result = test_utils::encode_and_compare(request, doc_raw, sizeof(doc_raw));
|
||||
|
||||
REQUIRE(result.encoding_successful);
|
||||
REQUIRE(result.bitstream_match);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Good case - Decode a ServiceDiscoveryReq document") {
|
||||
|
||||
auto expected_session_id = std::vector<uint8_t>{0x47, 0x58, 0xFD, 0xD3, 0x48, 0xA5, 0xEB, 0x24};
|
||||
uint8_t doc_raw[] = {0x80, 0x9a, 0x02, 0x11, 0xd6, 0x3f, 0x74, 0xd2, 0x29, 0x7a, 0xc9, 0x11, 0x94, 0x00};
|
||||
|
||||
THEN("It should be decoded succussfully") {
|
||||
const auto result = test_utils::decode<din_exiDocument>(doc_raw, sizeof(doc_raw));
|
||||
REQUIRE(result.decoding_successful);
|
||||
|
||||
const auto& request = result.value;
|
||||
|
||||
// Check Header
|
||||
const auto& header = request.V2G_Message.Header;
|
||||
const auto session_id =
|
||||
std::vector<uint8_t>(std::begin(header.SessionID.bytes), std::end(header.SessionID.bytes));
|
||||
REQUIRE(session_id == expected_session_id);
|
||||
REQUIRE(header.Notification_isUsed == false);
|
||||
REQUIRE(header.Signature_isUsed == false);
|
||||
|
||||
// Check Body
|
||||
const auto& body = request.V2G_Message.Body;
|
||||
REQUIRE(body.ServiceDiscoveryReq_isUsed == true);
|
||||
|
||||
const auto& serviceDiscoveryReq = body.ServiceDiscoveryReq;
|
||||
REQUIRE(serviceDiscoveryReq.ServiceScope_isUsed == false);
|
||||
REQUIRE(serviceDiscoveryReq.ServiceCategory_isUsed == true);
|
||||
}
|
||||
}
|
||||
|
||||
// EXI stream: 809a0211d63f74d2297ac911a00120024100c4
|
||||
// XML:
|
||||
// <ns7:V2G_Message>
|
||||
// <ns7:Header>
|
||||
// <ns8:SessionID>4758FDD348A5EB24</ns8:SessionID>
|
||||
// </ns7:Header>
|
||||
// <ns7:Body>
|
||||
// <ns5:ServiceDiscoveryRes>
|
||||
// <ns5:ResponseCode>OK</ns5:ResponseCode>
|
||||
// <ns5:PaymentOptions>
|
||||
// <ns6:PaymentOption>ExternalPayment</ns6:PaymentOption>
|
||||
// </ns5:PaymentOptions>
|
||||
// <ns5:ChargeService>
|
||||
// <ns6:ServiceTag>
|
||||
// <ns6:ServiceID>1</ns6:ServiceID>
|
||||
// <ns6:ServiceCategory>EVCharging</ns6:ServiceCategory>
|
||||
// </ns6:ServiceTag>
|
||||
// <ns6:FreeService>false</ns6:FreeService>
|
||||
// <ns6:EnergyTransferType>DC_extended</ns6:EnergyTransferType>
|
||||
// </ns5:ChargeService>
|
||||
// </ns5:ServiceDiscoveryRes>
|
||||
// </ns7:Body>
|
||||
// </ns7:V2G_Message>
|
||||
|
||||
GIVEN("Good case - Encode an ServiceDiscoveryRes document") {
|
||||
uint8_t doc_raw[] = {0x80, 0x9a, 0x02, 0x11, 0xd6, 0x3f, 0x74, 0xd2, 0x29, 0x7a,
|
||||
0xc9, 0x11, 0xa0, 0x01, 0x20, 0x02, 0x41, 0x00, 0xc4};
|
||||
|
||||
din_exiDocument request;
|
||||
init_din_exiDocument(&request);
|
||||
|
||||
init_din_MessageHeaderType(&request.V2G_Message.Header);
|
||||
|
||||
auto& header = request.V2G_Message.Header;
|
||||
header.SessionID.bytesLen = din_sessionIDType_BYTES_SIZE;
|
||||
|
||||
// copy the session id into the header
|
||||
const auto session_id = std::array<uint8_t, 8>{0x47, 0x58, 0xFD, 0xD3, 0x48, 0xA5, 0xEB, 0x24};
|
||||
std::copy(session_id.begin(), session_id.end(), header.SessionID.bytes);
|
||||
|
||||
init_din_BodyType(&request.V2G_Message.Body);
|
||||
auto& body = request.V2G_Message.Body;
|
||||
|
||||
// set the ServiceDiscoveryResType
|
||||
init_din_ServiceDiscoveryResType(&body.ServiceDiscoveryRes);
|
||||
body.ServiceDiscoveryRes_isUsed = true;
|
||||
|
||||
// set the response code
|
||||
body.ServiceDiscoveryRes.ResponseCode = din_responseCodeType_OK;
|
||||
|
||||
// set the payment options
|
||||
auto& paymentOptions = body.ServiceDiscoveryRes.PaymentOptions;
|
||||
paymentOptions.PaymentOption.arrayLen = 1;
|
||||
const auto givenPaymentOptions = std::array<din_paymentOptionType, 1>{din_paymentOptionType_ExternalPayment};
|
||||
std::copy(givenPaymentOptions.begin(), givenPaymentOptions.end(), paymentOptions.PaymentOption.array);
|
||||
|
||||
// set the charge service
|
||||
auto& chargeService = body.ServiceDiscoveryRes.ChargeService;
|
||||
chargeService.ServiceTag.ServiceID = 1;
|
||||
chargeService.ServiceTag.ServiceName_isUsed = false;
|
||||
chargeService.ServiceTag.ServiceScope_isUsed = false;
|
||||
chargeService.ServiceTag.ServiceCategory = din_serviceCategoryType_EVCharging;
|
||||
chargeService.FreeService = false;
|
||||
chargeService.EnergyTransferType = din_EVSESupportedEnergyTransferType_DC_extended;
|
||||
|
||||
THEN("It should be encoded succussfully") {
|
||||
const auto result = test_utils::encode_and_compare(request, doc_raw, sizeof(doc_raw));
|
||||
|
||||
REQUIRE(result.encoding_successful);
|
||||
REQUIRE(result.bitstream_match);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Good case - Decode an ServiceDiscoveryRes document") {
|
||||
auto expected_session_id = std::vector<uint8_t>{0x47, 0x58, 0xFD, 0xD3, 0x48, 0xA5, 0xEB, 0x24};
|
||||
uint8_t doc_raw[] = {0x80, 0x9a, 0x02, 0x11, 0xd6, 0x3f, 0x74, 0xd2, 0x29, 0x7a,
|
||||
0xc9, 0x11, 0xa0, 0x01, 0x20, 0x02, 0x41, 0x00, 0xc4};
|
||||
|
||||
THEN("It should be decoded succussfully") {
|
||||
const auto result = test_utils::decode<din_exiDocument>(doc_raw, sizeof(doc_raw));
|
||||
REQUIRE(result.decoding_successful);
|
||||
|
||||
const auto& request = result.value;
|
||||
|
||||
// Check Header
|
||||
const auto& header = request.V2G_Message.Header;
|
||||
const auto session_id =
|
||||
std::vector<uint8_t>(std::begin(header.SessionID.bytes), std::end(header.SessionID.bytes));
|
||||
REQUIRE(session_id == expected_session_id);
|
||||
REQUIRE(header.Notification_isUsed == false);
|
||||
REQUIRE(header.Signature_isUsed == false);
|
||||
|
||||
// Check Body
|
||||
const auto& body = request.V2G_Message.Body;
|
||||
REQUIRE(body.ServiceDiscoveryRes_isUsed == true);
|
||||
|
||||
const auto& serviceDiscoveryRes = body.ServiceDiscoveryRes;
|
||||
|
||||
// check the response code
|
||||
REQUIRE(serviceDiscoveryRes.ResponseCode == din_responseCodeType_OK);
|
||||
|
||||
// check the payment options
|
||||
const auto expectedPaymentOptions =
|
||||
std::vector<din_paymentOptionType>{din_paymentOptionType_ExternalPayment};
|
||||
REQUIRE(serviceDiscoveryRes.PaymentOptions.PaymentOption.arrayLen == 1);
|
||||
const auto& paymentOptionsArray = serviceDiscoveryRes.PaymentOptions.PaymentOption.array;
|
||||
REQUIRE(paymentOptionsArray[0] == expectedPaymentOptions.at(0));
|
||||
|
||||
// check the charge service
|
||||
const auto& chargeService = body.ServiceDiscoveryRes.ChargeService;
|
||||
|
||||
// service tag
|
||||
REQUIRE(chargeService.ServiceTag.ServiceID == 1);
|
||||
REQUIRE(chargeService.ServiceTag.ServiceName_isUsed == false);
|
||||
REQUIRE(chargeService.ServiceTag.ServiceScope_isUsed == false);
|
||||
REQUIRE(chargeService.ServiceTag.ServiceCategory == din_serviceCategoryType_EVCharging);
|
||||
REQUIRE(chargeService.FreeService == false);
|
||||
REQUIRE(chargeService.EnergyTransferType == din_EVSESupportedEnergyTransferType_DC_extended);
|
||||
}
|
||||
}
|
||||
}
|
||||
186
tools/EVerest-main/lib/everest/cbv2g/tests/din/session_setup.cpp
Normal file
186
tools/EVerest-main/lib/everest/cbv2g/tests/din/session_setup.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cbv2g/din/din_msgDefDecoder.h>
|
||||
#include <cbv2g/din/din_msgDefEncoder.h>
|
||||
|
||||
#include "test_utils/codec.hpp"
|
||||
|
||||
SCENARIO("Encode and decode DIN70121 session setup message") {
|
||||
|
||||
// Exi Stream: 809a02000000000000000011d01a121dc983cd6000
|
||||
// XML:
|
||||
// <ns7:V2G_Message>
|
||||
// <ns7:Header>
|
||||
// <ns8:SessionID>0000000000000000</ns8:SessionID>
|
||||
// </ns7:Header>
|
||||
// <ns7:Body>
|
||||
// <ns5:SessionSetupReq>
|
||||
// <ns5:EVCCID>84877260F358</ns5:EVCCID>
|
||||
// </ns5:SessionSetupReq>
|
||||
// </ns7:Body>
|
||||
// </ns7:V2G_Message>
|
||||
|
||||
GIVEN("Good case - Encode an SessionSetupReq document") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x9a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x11, 0xd0, 0x1a, 0x12, 0x1d, 0xc9, 0x83, 0xcd, 0x60, 0x00};
|
||||
|
||||
din_exiDocument request;
|
||||
init_din_exiDocument(&request);
|
||||
|
||||
init_din_MessageHeaderType(&request.V2G_Message.Header);
|
||||
|
||||
auto& header = request.V2G_Message.Header;
|
||||
header.SessionID.bytesLen = din_sessionIDType_BYTES_SIZE;
|
||||
const auto session_id = std::vector<uint8_t>(8, 0);
|
||||
std::copy(session_id.begin(), session_id.end(), header.SessionID.bytes);
|
||||
|
||||
init_din_BodyType(&request.V2G_Message.Body);
|
||||
auto& body = request.V2G_Message.Body;
|
||||
init_din_SessionSetupReqType(&body.SessionSetupReq);
|
||||
body.SessionSetupReq_isUsed = true;
|
||||
const auto evccid = std::array<uint8_t, 8>{0x84, 0x87, 0x72, 0x60, 0xF3, 0x58, 0x00, 0x00};
|
||||
std::copy(evccid.begin(), evccid.end(), body.SessionSetupReq.EVCCID.bytes);
|
||||
body.SessionSetupReq.EVCCID.bytesLen = 6;
|
||||
|
||||
THEN("It should be encoded succussfully") {
|
||||
const auto result = test_utils::encode_and_compare(request, doc_raw, sizeof(doc_raw));
|
||||
|
||||
REQUIRE(result.encoding_successful);
|
||||
REQUIRE(result.bitstream_match);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Good case - Decode an SessionSetupReq document") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x9a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x11, 0xd0, 0x1a, 0x12, 0x1d, 0xc9, 0x83, 0xcd, 0x60, 0x00};
|
||||
|
||||
THEN("It should be decoded succussfully") {
|
||||
const auto result = test_utils::decode<din_exiDocument>(doc_raw, sizeof(doc_raw));
|
||||
REQUIRE(result.decoding_successful);
|
||||
|
||||
const auto& request = result.value;
|
||||
|
||||
// Check Header
|
||||
auto& header = request.V2G_Message.Header;
|
||||
const auto session_id =
|
||||
std::vector<uint8_t>(std::begin(header.SessionID.bytes), std::end(header.SessionID.bytes));
|
||||
REQUIRE(session_id == std::vector<uint8_t>({0, 0, 0, 0, 0, 0, 0, 0}));
|
||||
REQUIRE(header.Notification_isUsed == false);
|
||||
REQUIRE(header.Signature_isUsed == false);
|
||||
|
||||
// Check Body
|
||||
REQUIRE(request.V2G_Message.Body.SessionSetupReq_isUsed == true);
|
||||
|
||||
auto& session_setup_req = request.V2G_Message.Body.SessionSetupReq;
|
||||
|
||||
const auto evccid = std::vector<uint8_t>(std::begin(session_setup_req.EVCCID.bytes),
|
||||
std::end(session_setup_req.EVCCID.bytes));
|
||||
REQUIRE(evccid == std::vector<uint8_t>({0x84, 0x87, 0x72, 0x60, 0xF3, 0x58, 0x00, 0x00}));
|
||||
|
||||
REQUIRE(session_setup_req.EVCCID.bytesLen == 6);
|
||||
}
|
||||
}
|
||||
|
||||
// EXI stream: 809a0211d63f74d2297ac911e0201526a2698d8017da353360c0
|
||||
// XML:
|
||||
// <ns7:V2G_Message>
|
||||
// <ns7:Header>
|
||||
// <ns8:SessionID>4758FDD348A5EB24</ns8:SessionID>
|
||||
// </ns7:Header>
|
||||
// <ns7:Body>
|
||||
// <ns5:SessionSetupRes>
|
||||
// <ns5:ResponseCode>OK_NewSessionEstablished</ns5:ResponseCode>
|
||||
// <ns5:EVSEID>49A89A6360</ns5:EVSEID>
|
||||
// <ns5:DateTimeNow>1667918014</ns5:EVSETimeStamp>
|
||||
// </ns5:SessionSetupRes>
|
||||
// </ns7:Body>
|
||||
// </ns7:V2G_Message>
|
||||
|
||||
GIVEN("Good case - Encode an SessionSetupRes document") {
|
||||
uint8_t doc_raw[] = {0x80, 0x9a, 0x02, 0x11, 0xd6, 0x3f, 0x74, 0xd2, 0x29, 0x7a, 0xc9, 0x11, 0xe0,
|
||||
0x20, 0x15, 0x26, 0xa2, 0x69, 0x8d, 0x80, 0x17, 0xda, 0x35, 0x33, 0x60, 0xc0};
|
||||
|
||||
din_exiDocument request;
|
||||
init_din_exiDocument(&request);
|
||||
|
||||
init_din_MessageHeaderType(&request.V2G_Message.Header);
|
||||
|
||||
auto& header = request.V2G_Message.Header;
|
||||
header.SessionID.bytesLen = din_sessionIDType_BYTES_SIZE;
|
||||
const auto session_id = std::array<uint8_t, 8>{0x47, 0x58, 0xFD, 0xD3, 0x48, 0xA5, 0xEB, 0x24};
|
||||
std::copy(session_id.begin(), session_id.end(), header.SessionID.bytes);
|
||||
|
||||
init_din_BodyType(&request.V2G_Message.Body);
|
||||
auto& body = request.V2G_Message.Body;
|
||||
init_din_SessionSetupResType(&body.SessionSetupRes);
|
||||
body.SessionSetupRes_isUsed = true;
|
||||
|
||||
// set the response code
|
||||
body.SessionSetupRes.ResponseCode = din_responseCodeType_OK_NewSessionEstablished;
|
||||
|
||||
// set the EVSE ID
|
||||
const auto evse_id = std::array<uint8_t, 5>{0x49, 0xA8, 0x9A, 0x63, 0x60};
|
||||
std::copy(evse_id.begin(), evse_id.end(), body.SessionSetupRes.EVSEID.bytes);
|
||||
body.SessionSetupRes.EVSEID.bytesLen = evse_id.size();
|
||||
|
||||
// set the EVSE timestamp
|
||||
body.SessionSetupRes.DateTimeNow_isUsed = true;
|
||||
body.SessionSetupRes.DateTimeNow = 1667918014;
|
||||
|
||||
THEN("It should be encoded succussfully") {
|
||||
const auto result = test_utils::encode_and_compare(request, doc_raw, sizeof(doc_raw));
|
||||
|
||||
REQUIRE(result.encoding_successful);
|
||||
REQUIRE(result.bitstream_match);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Good case - Decode an SessionSetupRes document") {
|
||||
|
||||
const auto expected_session_id = std::vector<uint8_t>{0x47, 0x58, 0xFD, 0xD3, 0x48, 0xA5, 0xEB, 0x24};
|
||||
uint8_t doc_raw[] = {0x80, 0x9a, 0x02, 0x11, 0xd6, 0x3f, 0x74, 0xd2, 0x29, 0x7a, 0xc9, 0x11, 0xe0,
|
||||
0x20, 0x15, 0x26, 0xa2, 0x69, 0x8d, 0x80, 0x17, 0xda, 0x35, 0x33, 0x60, 0xc0};
|
||||
|
||||
THEN("It should be decoded succussfully") {
|
||||
const auto result = test_utils::decode<din_exiDocument>(doc_raw, sizeof(doc_raw));
|
||||
REQUIRE(result.decoding_successful);
|
||||
|
||||
const auto& request = result.value;
|
||||
|
||||
// Check Header
|
||||
auto& header = request.V2G_Message.Header;
|
||||
|
||||
const auto session_id =
|
||||
std::vector<uint8_t>(std::begin(header.SessionID.bytes), std::end(header.SessionID.bytes));
|
||||
REQUIRE(session_id == expected_session_id);
|
||||
REQUIRE(header.Notification_isUsed == false);
|
||||
REQUIRE(header.Signature_isUsed == false);
|
||||
|
||||
// Check Body
|
||||
REQUIRE(request.V2G_Message.Body.SessionSetupRes_isUsed == true);
|
||||
const auto& session_setup_res = request.V2G_Message.Body.SessionSetupRes;
|
||||
|
||||
// check the response code
|
||||
REQUIRE(session_setup_res.ResponseCode == din_responseCodeType_OK_NewSessionEstablished);
|
||||
|
||||
// check the EVSE ID
|
||||
REQUIRE(session_setup_res.EVSEID.bytesLen == 5);
|
||||
const auto evse_id =
|
||||
std::vector<uint8_t>(std::begin(session_setup_res.EVSEID.bytes),
|
||||
std::begin(session_setup_res.EVSEID.bytes) + session_setup_res.EVSEID.bytesLen);
|
||||
REQUIRE(evse_id == std::vector<uint8_t>({0x49, 0xA8, 0x9A, 0x63, 0x60}));
|
||||
|
||||
// check the EVSE timestamp
|
||||
REQUIRE(session_setup_res.DateTimeNow_isUsed == true);
|
||||
REQUIRE(session_setup_res.DateTimeNow == 1667918014);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
add_codec_test(ac_charge_loop)
|
||||
add_codec_test(dc_charge_loop)
|
||||
@@ -0,0 +1,167 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include <cbv2g/iso_20/iso20_AC_Decoder.h>
|
||||
#include <cbv2g/iso_20/iso20_AC_Encoder.h>
|
||||
|
||||
#include "test_utils/codec.hpp"
|
||||
|
||||
// Exi Stream: 8008041e9869d6a61dc1ef895b9b4a8062832418640096
|
||||
// XML:
|
||||
// <AC_ChargeLoopReq>
|
||||
// <Header>
|
||||
// <SessionID>3D30D3AD4C3B83DF</SessionID>
|
||||
// <TimeStamp>1695358101</TimeStamp>
|
||||
// </Header>
|
||||
// <MeterInfoRequested>false</MeterInfoRequested>
|
||||
// <BPT_Scheduled_AC_CLReqControlMode>
|
||||
// <EVPresentActivePower>
|
||||
// <Exponent>3</Exponent>
|
||||
// <Value>200</Value>
|
||||
// </EVPresentActivePower>
|
||||
// </BPT_Scheduled_AC_CLReqControlMode>
|
||||
// </AC_ChargeLoopReq>
|
||||
|
||||
// Exi Stream: 800c041e9869d6a61dc1ef895b9b4a8062005900
|
||||
// XML:
|
||||
// <AC_ChargeLoopRes>
|
||||
// <Header>
|
||||
// <SessionID>3D30D3AD4C3B83DF</SessionID>
|
||||
// <TimeStamp>1695358101</TimeStamp>
|
||||
// </Header>
|
||||
// <ResponseCode>OK</ResponseCode>
|
||||
// <BPT_Scheduled_AC_CLResControlMode/>
|
||||
// </AC_ChargeLoopRes>
|
||||
|
||||
static void setup_header(struct iso20_ac_MessageHeaderType* header,
|
||||
const std::array<uint8_t, iso20_ac_sessionIDType_BYTES_SIZE>& session_id, uint64_t timestamp) {
|
||||
init_iso20_ac_MessageHeaderType(header);
|
||||
header->SessionID.bytesLen = iso20_ac_sessionIDType_BYTES_SIZE;
|
||||
std::copy(session_id.begin(), session_id.end(), header->SessionID.bytes);
|
||||
header->TimeStamp = timestamp;
|
||||
}
|
||||
|
||||
SCENARIO("Encode and decode ISO15118-20 AC charge loop message") {
|
||||
|
||||
GIVEN("Good case - Encode correct bpt control (AcChargeLoopReq)") {
|
||||
uint8_t doc_raw[] = {0x80, 0x08, 0x04, 0x1e, 0x98, 0x69, 0xd6, 0xa6, 0x1d, 0xc1, 0xef, 0x89,
|
||||
0x5b, 0x9b, 0x4a, 0x80, 0x62, 0x83, 0x24, 0x18, 0x64, 0x00, 0x96};
|
||||
|
||||
iso20_ac_exiDocument request;
|
||||
init_iso20_ac_exiDocument(&request);
|
||||
|
||||
request.AC_ChargeLoopReq_isUsed = true;
|
||||
init_iso20_ac_AC_ChargeLoopReqType(&request.AC_ChargeLoopReq);
|
||||
|
||||
const auto session_id =
|
||||
std::array<uint8_t, iso20_ac_sessionIDType_BYTES_SIZE>{0x3D, 0x30, 0xD3, 0xAD, 0x4C, 0x3B, 0x83, 0xDF};
|
||||
const uint64_t timestamp = 1695358101;
|
||||
setup_header(&request.AC_ChargeLoopReq.Header, session_id, timestamp);
|
||||
|
||||
auto& charge_loop = request.AC_ChargeLoopReq;
|
||||
|
||||
charge_loop.MeterInfoRequested = false;
|
||||
|
||||
charge_loop.BPT_Scheduled_AC_CLReqControlMode_isUsed = true;
|
||||
init_iso20_ac_BPT_Scheduled_AC_CLReqControlModeType(&charge_loop.BPT_Scheduled_AC_CLReqControlMode);
|
||||
charge_loop.BPT_Scheduled_AC_CLReqControlMode.EVPresentActivePower = {3, 200};
|
||||
|
||||
THEN("It should be encoded succussfully") {
|
||||
const auto result = test_utils::encode_and_compare(request, doc_raw, sizeof(doc_raw));
|
||||
|
||||
REQUIRE(result.encoding_successful);
|
||||
REQUIRE(result.bitstream_match);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Good case - Encode correct bpt control (AcChargeLoopRes)") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x0c, 0x04, 0x1e, 0x98, 0x69, 0xd6, 0xa6, 0x1d, 0xc1,
|
||||
0xef, 0x89, 0x5b, 0x9b, 0x4a, 0x80, 0x62, 0x00, 0x59, 0x00};
|
||||
|
||||
iso20_ac_exiDocument response;
|
||||
init_iso20_ac_exiDocument(&response);
|
||||
|
||||
response.AC_ChargeLoopRes_isUsed = true;
|
||||
init_iso20_ac_AC_ChargeLoopResType(&response.AC_ChargeLoopRes);
|
||||
|
||||
const auto session_id =
|
||||
std::array<uint8_t, iso20_ac_sessionIDType_BYTES_SIZE>{0x3D, 0x30, 0xD3, 0xAD, 0x4C, 0x3B, 0x83, 0xDF};
|
||||
const uint64_t timestamp = 1695358101;
|
||||
setup_header(&response.AC_ChargeLoopRes.Header, session_id, timestamp);
|
||||
|
||||
auto& charge_loop = response.AC_ChargeLoopRes;
|
||||
charge_loop.ResponseCode = iso20_ac_responseCodeType_OK;
|
||||
charge_loop.BPT_Scheduled_AC_CLResControlMode_isUsed = true;
|
||||
charge_loop.BPT_Scheduled_AC_CLResControlMode = {};
|
||||
|
||||
THEN("It should be encoded succussfully") {
|
||||
const auto result = test_utils::encode_and_compare(response, doc_raw, sizeof(doc_raw));
|
||||
|
||||
REQUIRE(result.encoding_successful);
|
||||
REQUIRE(result.bitstream_match);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Good case - Decode correct bpt control (AcChargeLoopReq)") {
|
||||
const auto expected_session_id = std::vector<uint8_t>{0x3D, 0x30, 0xD3, 0xAD, 0x4C, 0x3B, 0x83, 0xDF};
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x08, 0x04, 0x1e, 0x98, 0x69, 0xd6, 0xa6, 0x1d, 0xc1, 0xef, 0x89,
|
||||
0x5b, 0x9b, 0x4a, 0x80, 0x62, 0x83, 0x24, 0x18, 0x64, 0x00, 0x96};
|
||||
|
||||
THEN("It should be decoded succussfully") {
|
||||
const auto result = test_utils::decode<iso20_ac_exiDocument>(doc_raw, sizeof(doc_raw));
|
||||
REQUIRE(result.decoding_successful);
|
||||
|
||||
const auto& request = result.value;
|
||||
|
||||
REQUIRE(request.AC_ChargeLoopReq_isUsed == true);
|
||||
// Check Header
|
||||
const auto& header = request.AC_ChargeLoopReq.Header;
|
||||
const auto session_id =
|
||||
std::vector<uint8_t>(std::begin(header.SessionID.bytes), std::end(header.SessionID.bytes));
|
||||
REQUIRE(session_id == expected_session_id);
|
||||
|
||||
REQUIRE(header.TimeStamp == 1695358101);
|
||||
|
||||
// Check Body
|
||||
const auto& charge_loop = request.AC_ChargeLoopReq;
|
||||
REQUIRE(charge_loop.MeterInfoRequested == false);
|
||||
|
||||
REQUIRE(charge_loop.BPT_Scheduled_AC_CLReqControlMode_isUsed == true);
|
||||
REQUIRE(charge_loop.BPT_Scheduled_AC_CLReqControlMode.EVPresentActivePower.Exponent == 3);
|
||||
REQUIRE(charge_loop.BPT_Scheduled_AC_CLReqControlMode.EVPresentActivePower.Value == 200);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Good case - Decode correct bpt control (AcChargeLoopRes)") {
|
||||
|
||||
const auto expected_session_id = std::vector<uint8_t>{0x3D, 0x30, 0xD3, 0xAD, 0x4C, 0x3B, 0x83, 0xDF};
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x0c, 0x04, 0x1e, 0x98, 0x69, 0xd6, 0xa6, 0x1d, 0xc1,
|
||||
0xef, 0x89, 0x5b, 0x9b, 0x4a, 0x80, 0x62, 0x00, 0x59, 0x00};
|
||||
|
||||
THEN("It should be decoded succussfully") {
|
||||
const auto result = test_utils::decode<iso20_ac_exiDocument>(doc_raw, sizeof(doc_raw));
|
||||
REQUIRE(result.decoding_successful);
|
||||
|
||||
const auto& request = result.value;
|
||||
|
||||
REQUIRE(request.AC_ChargeLoopRes_isUsed == true);
|
||||
// Check Header
|
||||
const auto& header = request.AC_ChargeLoopRes.Header;
|
||||
const auto session_id =
|
||||
std::vector<uint8_t>(std::begin(header.SessionID.bytes), std::end(header.SessionID.bytes));
|
||||
REQUIRE(session_id == expected_session_id);
|
||||
|
||||
REQUIRE(header.TimeStamp == 1695358101);
|
||||
|
||||
// Check Body
|
||||
const auto& charge_loop = request.AC_ChargeLoopRes;
|
||||
REQUIRE(charge_loop.ResponseCode == iso20_ac_responseCodeType_OK);
|
||||
REQUIRE(charge_loop.BPT_Scheduled_AC_CLResControlMode_isUsed == true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include <cbv2g/iso_20/iso20_DC_Decoder.h>
|
||||
#include <cbv2g/iso_20/iso20_DC_Encoder.h>
|
||||
|
||||
#include "test_utils/codec.hpp"
|
||||
|
||||
// Exi Stream: 8034042d166f29fb80ea560aebdbfb3062810012006164000a02002400c800
|
||||
// XML:
|
||||
// <DC_ChargeLoopReq>
|
||||
// <Header>
|
||||
// <SessionID>5A2CDE53F701D4AC</SessionID>
|
||||
// <TimeStamp>1718607534</TimeStamp>
|
||||
// </Header>
|
||||
// <MeterInfoRequested>false</MeterInfoRequested>
|
||||
// <EVPresentVoltage>
|
||||
// <Exponent>0</Exponent>
|
||||
// <Value>400</Value>
|
||||
// </EVPresentVoltage>
|
||||
// <BPT_Scheduled_DC_CLReqControlMode>
|
||||
// <EVTargetCurrent>
|
||||
// <Exponent>0</Exponent>
|
||||
// <Value>20</Value>
|
||||
// </EVTargetCurrent>
|
||||
// <EVTargetVoltage>
|
||||
// <Exponent>0</Exponent>
|
||||
// <Value>400</Value>
|
||||
// </EVTargetVoltage>
|
||||
// </BPT_Scheduled_DC_CLReqControlMode>
|
||||
// </DC_ChargeLoopReq>
|
||||
|
||||
// Exi Stream: 8038042d166f29fb80ea560b7bdbfb30620063f0680781fc2807c22230
|
||||
// XML:
|
||||
// <DC_ChargeLoopRes>
|
||||
// <Header>
|
||||
// <SessionID>5A2CDE53F701D4AC</SessionID>
|
||||
// <TimeStamp>1718607543</TimeStamp>
|
||||
// </Header>
|
||||
// <ResponseCode>OK</ ResponseCode>
|
||||
// <EVSEPresentCurrent>
|
||||
// <Exponent>-2</Exponent>
|
||||
// <Value>2000</Value>
|
||||
// </EVSEPresentCurrent>
|
||||
// <EVSEPresentVoltage>
|
||||
// <Exponent>-1</Exponent >
|
||||
// <Value>4000</Value >
|
||||
// </EVSEPresentVoltage>
|
||||
// <EVSEPowerLimitAchieved>true</EVSEPowerLimitAchieved>
|
||||
// <EVSECurrentLimitAchieved>true</EVSECurrentLimitAchieved>
|
||||
// <EVSEVoltageLimitAchieved>true</EVSEVoltageLimitAchieved>
|
||||
// <BPT_Scheduled_DC_CLResControlMode/>
|
||||
// </ DC_ChargeLoopRes>
|
||||
|
||||
static void setup_header(struct iso20_dc_MessageHeaderType* header,
|
||||
const std::array<uint8_t, iso20_dc_sessionIDType_BYTES_SIZE>& session_id, uint64_t timestamp) {
|
||||
init_iso20_dc_MessageHeaderType(header);
|
||||
header->SessionID.bytesLen = iso20_dc_sessionIDType_BYTES_SIZE;
|
||||
std::copy(session_id.begin(), session_id.end(), header->SessionID.bytes);
|
||||
header->TimeStamp = timestamp;
|
||||
}
|
||||
|
||||
SCENARIO("Encode and decode ISO15118-20 DC charge loop message") {
|
||||
|
||||
GIVEN("Good case - Encode correct bpt control (DcChargeLoopReq)") {
|
||||
uint8_t doc_raw[] = {0x80, 0x34, 0x04, 0x2d, 0x16, 0x6f, 0x29, 0xfb, 0x80, 0xea, 0x56,
|
||||
0x0a, 0xeb, 0xdb, 0xfb, 0x30, 0x62, 0x81, 0x00, 0x12, 0x00, 0x61,
|
||||
0x64, 0x00, 0x0a, 0x02, 0x00, 0x24, 0x00, 0xc8, 0x00};
|
||||
|
||||
iso20_dc_exiDocument request;
|
||||
init_iso20_dc_exiDocument(&request);
|
||||
|
||||
request.DC_ChargeLoopReq_isUsed = true;
|
||||
init_iso20_dc_DC_ChargeLoopReqType(&request.DC_ChargeLoopReq);
|
||||
|
||||
const auto session_id =
|
||||
std::array<uint8_t, iso20_dc_sessionIDType_BYTES_SIZE>{0x5A, 0x2C, 0xDE, 0x53, 0xF7, 0x01, 0xD4, 0xAC};
|
||||
uint64_t timestamp = 1718607534;
|
||||
setup_header(&request.DC_ChargeLoopReq.Header, session_id, timestamp);
|
||||
|
||||
auto& charge_loop = request.DC_ChargeLoopReq;
|
||||
|
||||
charge_loop.MeterInfoRequested = false;
|
||||
charge_loop.EVPresentVoltage = {0, 400};
|
||||
|
||||
charge_loop.BPT_Scheduled_DC_CLReqControlMode_isUsed = true;
|
||||
init_iso20_dc_BPT_Scheduled_DC_CLReqControlModeType(&charge_loop.BPT_Scheduled_DC_CLReqControlMode);
|
||||
charge_loop.BPT_Scheduled_DC_CLReqControlMode.EVTargetCurrent = {0, 20};
|
||||
charge_loop.BPT_Scheduled_DC_CLReqControlMode.EVTargetVoltage = {0, 400};
|
||||
|
||||
THEN("It should be encoded succussfully") {
|
||||
const auto result = test_utils::encode_and_compare(request, doc_raw, sizeof(doc_raw));
|
||||
|
||||
REQUIRE(result.encoding_successful);
|
||||
REQUIRE(result.bitstream_match);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Good case - Encode correct bpt control (DcChargeLoopRes)") {
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x38, 0x04, 0x2d, 0x16, 0x6f, 0x29, 0xfb, 0x80, 0xea, 0x56, 0x0b, 0x7b, 0xdb, 0xfb,
|
||||
0x30, 0x62, 0x00, 0x63, 0xf0, 0x68, 0x07, 0x81, 0xfc, 0x28, 0x07, 0xc2, 0x22, 0x30};
|
||||
|
||||
iso20_dc_exiDocument response;
|
||||
init_iso20_dc_exiDocument(&response);
|
||||
|
||||
response.DC_ChargeLoopRes_isUsed = true;
|
||||
init_iso20_dc_DC_ChargeLoopResType(&response.DC_ChargeLoopRes);
|
||||
|
||||
const auto session_id =
|
||||
std::array<uint8_t, iso20_dc_sessionIDType_BYTES_SIZE>{0x5A, 0x2C, 0xDE, 0x53, 0xF7, 0x01, 0xD4, 0xAC};
|
||||
uint64_t timestamp = 1718607543;
|
||||
setup_header(&response.DC_ChargeLoopReq.Header, session_id, timestamp);
|
||||
|
||||
auto& charge_loop = response.DC_ChargeLoopRes;
|
||||
|
||||
charge_loop.ResponseCode = iso20_dc_responseCodeType_OK;
|
||||
charge_loop.EVSEPresentCurrent = {-2, 2000};
|
||||
charge_loop.EVSEPresentVoltage = {-1, 4000};
|
||||
charge_loop.EVSEPowerLimitAchieved = true;
|
||||
charge_loop.EVSECurrentLimitAchieved = true;
|
||||
charge_loop.EVSEVoltageLimitAchieved = true;
|
||||
|
||||
charge_loop.BPT_Scheduled_DC_CLResControlMode_isUsed = true;
|
||||
charge_loop.BPT_Scheduled_DC_CLResControlMode = {};
|
||||
|
||||
THEN("It should be encoded succussfully") {
|
||||
const auto result = test_utils::encode_and_compare(response, doc_raw, sizeof(doc_raw));
|
||||
|
||||
REQUIRE(result.encoding_successful);
|
||||
REQUIRE(result.bitstream_match);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Good case - Decode correct bpt control (DcChargeLoopReq)") {
|
||||
const auto expected_session_id = std::vector<uint8_t>{0x5A, 0x2C, 0xDE, 0x53, 0xF7, 0x01, 0xD4, 0xAC};
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x34, 0x04, 0x2d, 0x16, 0x6f, 0x29, 0xfb, 0x80, 0xea, 0x56,
|
||||
0x0a, 0xeb, 0xdb, 0xfb, 0x30, 0x62, 0x81, 0x00, 0x12, 0x00, 0x61,
|
||||
0x64, 0x00, 0x0a, 0x02, 0x00, 0x24, 0x00, 0xc8, 0x00};
|
||||
|
||||
THEN("It should be decoded succussfully") {
|
||||
const auto result = test_utils::decode<iso20_dc_exiDocument>(doc_raw, sizeof(doc_raw));
|
||||
REQUIRE(result.decoding_successful);
|
||||
|
||||
const auto& request = result.value;
|
||||
|
||||
REQUIRE(request.DC_ChargeLoopReq_isUsed == true);
|
||||
// Check Header
|
||||
const auto& header = request.DC_ChargeLoopReq.Header;
|
||||
const auto session_id =
|
||||
std::vector<uint8_t>(std::begin(header.SessionID.bytes), std::end(header.SessionID.bytes));
|
||||
REQUIRE(session_id == expected_session_id);
|
||||
|
||||
REQUIRE(header.TimeStamp == 1718607534);
|
||||
|
||||
// Check Body
|
||||
const auto& charge_loop = request.DC_ChargeLoopReq;
|
||||
REQUIRE(charge_loop.MeterInfoRequested == false);
|
||||
REQUIRE(charge_loop.EVPresentVoltage.Exponent == 0);
|
||||
REQUIRE(charge_loop.EVPresentVoltage.Value == 400);
|
||||
|
||||
REQUIRE(charge_loop.BPT_Scheduled_DC_CLReqControlMode_isUsed == true);
|
||||
REQUIRE(charge_loop.BPT_Scheduled_DC_CLReqControlMode.EVTargetCurrent.Exponent == 0);
|
||||
REQUIRE(charge_loop.BPT_Scheduled_DC_CLReqControlMode.EVTargetCurrent.Value == 20);
|
||||
REQUIRE(charge_loop.BPT_Scheduled_DC_CLReqControlMode.EVTargetVoltage.Exponent == 0);
|
||||
REQUIRE(charge_loop.BPT_Scheduled_DC_CLReqControlMode.EVTargetVoltage.Value == 400);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Good case - Decode correct bpt control (DcChargeLoopRes)") {
|
||||
|
||||
const auto expected_session_id = std::vector<uint8_t>{0x5A, 0x2C, 0xDE, 0x53, 0xF7, 0x01, 0xD4, 0xAC};
|
||||
|
||||
uint8_t doc_raw[] = {0x80, 0x38, 0x04, 0x2d, 0x16, 0x6f, 0x29, 0xfb, 0x80, 0xea, 0x56, 0x0b, 0x7b, 0xdb, 0xfb,
|
||||
0x30, 0x62, 0x00, 0x63, 0xf0, 0x68, 0x07, 0x81, 0xfc, 0x28, 0x07, 0xc2, 0x22, 0x30};
|
||||
|
||||
THEN("It should be decoded succussfully") {
|
||||
const auto result = test_utils::decode<iso20_dc_exiDocument>(doc_raw, sizeof(doc_raw));
|
||||
REQUIRE(result.decoding_successful);
|
||||
|
||||
const auto& request = result.value;
|
||||
|
||||
REQUIRE(request.DC_ChargeLoopRes_isUsed == true);
|
||||
// Check Header
|
||||
const auto& header = request.DC_ChargeLoopRes.Header;
|
||||
const auto session_id =
|
||||
std::vector<uint8_t>(std::begin(header.SessionID.bytes), std::end(header.SessionID.bytes));
|
||||
REQUIRE(session_id == expected_session_id);
|
||||
|
||||
REQUIRE(header.TimeStamp == 1718607543);
|
||||
|
||||
// Check Body
|
||||
const auto& charge_loop = request.DC_ChargeLoopRes;
|
||||
REQUIRE(charge_loop.ResponseCode == iso20_dc_responseCodeType_OK);
|
||||
REQUIRE(charge_loop.EVSEPresentCurrent.Exponent == -2);
|
||||
REQUIRE(charge_loop.EVSEPresentCurrent.Value == 2000);
|
||||
REQUIRE(charge_loop.EVSEPresentVoltage.Exponent == -1);
|
||||
REQUIRE(charge_loop.EVSEPresentVoltage.Value == 4000);
|
||||
REQUIRE(charge_loop.EVSEPowerLimitAchieved == true);
|
||||
REQUIRE(charge_loop.EVSECurrentLimitAchieved == true);
|
||||
REQUIRE(charge_loop.EVSEVoltageLimitAchieved == true);
|
||||
REQUIRE(charge_loop.BPT_Scheduled_DC_CLResControlMode_isUsed == true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
add_library(test_utilities OBJECT codec.cpp)
|
||||
target_link_libraries(test_utilities
|
||||
PUBLIC
|
||||
cbv2g::din
|
||||
cbv2g::iso2
|
||||
cbv2g::iso20
|
||||
)
|
||||
|
||||
target_include_directories(test_utilities
|
||||
PUBLIC
|
||||
include
|
||||
)
|
||||
|
||||
function(add_codec_test CPP_FILE)
|
||||
set(TEST_TARGET_NAME test_${CPP_FILE})
|
||||
add_executable(${TEST_TARGET_NAME} ${CPP_FILE}.cpp)
|
||||
|
||||
target_link_libraries(${TEST_TARGET_NAME}
|
||||
PRIVATE
|
||||
test_utilities
|
||||
Catch2::Catch2WithMain
|
||||
)
|
||||
|
||||
catch_discover_tests(${TEST_TARGET_NAME})
|
||||
endfunction()
|
||||
102
tools/EVerest-main/lib/everest/cbv2g/tests/test_utils/codec.cpp
Normal file
102
tools/EVerest-main/lib/everest/cbv2g/tests/test_utils/codec.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#include "test_utils/codec.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <cbv2g/app_handshake/appHand_Decoder.h>
|
||||
#include <cbv2g/app_handshake/appHand_Encoder.h>
|
||||
|
||||
#include <cbv2g/din/din_msgDefDecoder.h>
|
||||
#include <cbv2g/din/din_msgDefEncoder.h>
|
||||
|
||||
#include <cbv2g/iso_20/iso20_AC_Decoder.h>
|
||||
#include <cbv2g/iso_20/iso20_AC_Encoder.h>
|
||||
#include <cbv2g/iso_20/iso20_DC_Decoder.h>
|
||||
#include <cbv2g/iso_20/iso20_DC_Encoder.h>
|
||||
|
||||
namespace test_utils {
|
||||
|
||||
template <typename DocType>
|
||||
static EncodingResult encode(int (*encode_func)(exi_bitstream_t*, DocType*), const DocType& request,
|
||||
const uint8_t* compare_data, std::size_t length) {
|
||||
// FIXME (aw): what general size to take here?
|
||||
uint8_t stream[256] = {};
|
||||
exi_bitstream_t exi_stream_in;
|
||||
size_t pos1 = 0;
|
||||
|
||||
exi_bitstream_init(&exi_stream_in, stream, sizeof(stream), pos1, nullptr);
|
||||
|
||||
if (0 != encode_func(&exi_stream_in, const_cast<DocType*>(&request))) {
|
||||
return {false, false};
|
||||
}
|
||||
|
||||
const auto encoded_stream = std::vector<uint8_t>(stream, stream + exi_bitstream_get_length(&exi_stream_in));
|
||||
|
||||
const auto expected_exi_stream = std::vector<uint8_t>(compare_data, compare_data + length);
|
||||
|
||||
return {true, encoded_stream == expected_exi_stream};
|
||||
}
|
||||
|
||||
template <typename DocType>
|
||||
DecodingResult<DocType> decode(int (*decode_func)(exi_bitstream_t*, DocType*), const uint8_t* raw_data,
|
||||
std::size_t length) {
|
||||
exi_bitstream_t exi_stream_in;
|
||||
size_t pos1 = 0;
|
||||
|
||||
exi_bitstream_init(&exi_stream_in, const_cast<uint8_t*>(raw_data), length, pos1, nullptr);
|
||||
|
||||
DecodingResult<DocType> result;
|
||||
result.decoding_successful = (decode_func(&exi_stream_in, &result.value) == 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// app handshake
|
||||
//
|
||||
template <>
|
||||
EncodingResult encode_and_compare(const appHand_exiDocument& request, const uint8_t* compare_data, std::size_t length) {
|
||||
return encode(&encode_appHand_exiDocument, request, compare_data, length);
|
||||
}
|
||||
|
||||
template <> DecodingResult<appHand_exiDocument> decode(const uint8_t* raw_data, std::size_t length) {
|
||||
return decode(&decode_appHand_exiDocument, raw_data, length);
|
||||
}
|
||||
|
||||
//
|
||||
// din
|
||||
//
|
||||
template <>
|
||||
EncodingResult encode_and_compare(const din_exiDocument& request, const uint8_t* compare_data, std::size_t length) {
|
||||
return encode(&encode_din_exiDocument, request, compare_data, length);
|
||||
}
|
||||
|
||||
template <> DecodingResult<din_exiDocument> decode(const uint8_t* raw_data, std::size_t length) {
|
||||
return decode(&decode_din_exiDocument, raw_data, length);
|
||||
}
|
||||
|
||||
//
|
||||
// iso20 ac
|
||||
//
|
||||
template <>
|
||||
EncodingResult encode_and_compare(const iso20_ac_exiDocument& request, const uint8_t* compare_data,
|
||||
std::size_t length) {
|
||||
return encode(&encode_iso20_ac_exiDocument, request, compare_data, length);
|
||||
}
|
||||
|
||||
template <> DecodingResult<iso20_ac_exiDocument> decode(const uint8_t* raw_data, std::size_t length) {
|
||||
return decode(&decode_iso20_ac_exiDocument, raw_data, length);
|
||||
}
|
||||
|
||||
//
|
||||
// iso20 dc
|
||||
//
|
||||
template <>
|
||||
EncodingResult encode_and_compare(const iso20_dc_exiDocument& request, const uint8_t* compare_data,
|
||||
std::size_t length) {
|
||||
return encode(&encode_iso20_dc_exiDocument, request, compare_data, length);
|
||||
}
|
||||
|
||||
template <> DecodingResult<iso20_dc_exiDocument> decode(const uint8_t* raw_data, std::size_t length) {
|
||||
return decode(&decode_iso20_dc_exiDocument, raw_data, length);
|
||||
}
|
||||
|
||||
} // namespace test_utils
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace test_utils {
|
||||
|
||||
struct EncodingResult {
|
||||
bool encoding_successful;
|
||||
bool bitstream_match;
|
||||
};
|
||||
|
||||
template <typename DocType>
|
||||
EncodingResult encode_and_compare(const DocType&, const uint8_t* compare_data, std::size_t length);
|
||||
|
||||
template <typename DocType> struct DecodingResult {
|
||||
bool decoding_successful;
|
||||
DocType value;
|
||||
};
|
||||
|
||||
template <typename DocType> DecodingResult<DocType> decode(const uint8_t* raw_data, std::size_t length);
|
||||
|
||||
} // namespace test_utils
|
||||
Reference in New Issue
Block a user