Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ServiceDetail messages add EVSide Se/Deserialization #94

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 74 additions & 7 deletions src/iso15118/message/service_detail.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,56 @@
out.service = static_cast<datatypes::ServiceCategory>(in.ServiceID);
}

struct ParamterValueVisitor {
ParamterValueVisitor(iso20_ParameterType& parameter_) : parameter(parameter_){};
template <> void convert(const struct iso20_ServiceDetailResType& in, ServiceDetailResponse& out) {

cb_convert_enum(in.ResponseCode, out.response_code);

cb_convert_enum(in.ServiceID, out.service);
out.service_parameter_list.clear();
for (uint8_t i = 0; i < in.ServiceParameterList.ParameterSet.arrayLen; i++) {
const auto& in_parameter_set = in.ServiceParameterList.ParameterSet.array[i];
datatypes::ParameterSet out_parameter_set;
out_parameter_set.id = in_parameter_set.ParameterSetID;

out_parameter_set.parameter.clear();
for (uint8_t t = 0; t < in_parameter_set.Parameter.arrayLen; t++) {
const auto& in_parameter = in_parameter_set.Parameter.array[t];
datatypes::Parameter out_parameter;

out_parameter.name = std::string(in_parameter.Name.characters, in_parameter.Name.charactersLen);
if (in_parameter.boolValue_isUsed) {
out_parameter.value = in_parameter.boolValue;
} else if (in_parameter.byteValue_isUsed) {
out_parameter.value = in_parameter.byteValue;
} else if (in_parameter.shortValue_isUsed) {
out_parameter.value = in_parameter.shortValue;
} else if (in_parameter.intValue_isUsed) {
out_parameter.value = in_parameter.intValue;
} else if (in_parameter.finiteString_isUsed) {
out_parameter.value =
std::string(in_parameter.finiteString.characters, in_parameter.finiteString.charactersLen);
} else if (in_parameter.rationalNumber_isUsed) {
out_parameter.value =
datatypes::RationalNumber{in_parameter.rationalNumber.Value, in_parameter.rationalNumber.Exponent};
}
out_parameter_set.parameter.push_back(out_parameter);
}
out.service_parameter_list.push_back(out_parameter_set);
}

convert(in.Header, out.header);
}

template <> void convert(const ServiceDetailRequest& in, iso20_ServiceDetailReqType& out) {
init_iso20_ServiceDetailReqType(&out);

cb_convert_enum(in.service, out.ServiceID);

convert(in.header, out.Header);
}

struct ParameterValueVisitor {
ParameterValueVisitor(iso20_ParameterType& parameter_) : parameter(parameter_){};

Check notice on line 170 in src/iso15118/message/service_detail.cpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/iso15118/message/service_detail.cpp#L170

Struct 'ParameterValueVisitor' has a constructor with 1 argument that is not explicit.
void operator()(const bool& in) {
CB_SET_USED(parameter.boolValue);
parameter.boolValue = in;
Expand Down Expand Up @@ -161,18 +209,18 @@

uint8_t index = 0;
for (auto const& in_parameter_set : in.service_parameter_list) {
auto& out_paramater_set = out.ServiceParameterList.ParameterSet.array[index++];
out_paramater_set.ParameterSetID = in_parameter_set.id;
auto& out_parameter_set = out.ServiceParameterList.ParameterSet.array[index++];
out_parameter_set.ParameterSetID = in_parameter_set.id;

uint8_t t = 0;
for (auto const& in_parameter : in_parameter_set.parameter) {
auto& out_parameter = out_paramater_set.Parameter.array[t++];
auto& out_parameter = out_parameter_set.Parameter.array[t++];
init_iso20_ParameterType(&out_parameter);

CPP2CB_STRING(in_parameter.name, out_parameter.Name);
std::visit(ParamterValueVisitor(out_parameter), in_parameter.value);
std::visit(ParameterValueVisitor(out_parameter), in_parameter.value);
}
out_paramater_set.Parameter.arrayLen = in_parameter_set.parameter.size();
out_parameter_set.Parameter.arrayLen = in_parameter_set.parameter.size();
}

out.ServiceParameterList.ParameterSet.arrayLen = in.service_parameter_list.size();
Expand All @@ -182,6 +230,10 @@
va.insert_type<ServiceDetailRequest>(in);
}

template <> void insert_type(VariantAccess& va, const struct iso20_ServiceDetailResType& in) {
va.insert_type<ServiceDetailResponse>(in);
};

template <> int serialize_to_exi(const ServiceDetailResponse& in, exi_bitstream_t& out) {
iso20_exiDocument doc;
init_iso20_exiDocument(&doc);
Expand All @@ -193,8 +245,23 @@
return encode_iso20_exiDocument(&out, &doc);
}

template <> int serialize_to_exi(const ServiceDetailRequest& in, exi_bitstream_t& out) {
iso20_exiDocument doc;
init_iso20_exiDocument(&doc);

CB_SET_USED(doc.ServiceDetailReq);

convert(in, doc.ServiceDetailReq);

return encode_iso20_exiDocument(&out, &doc);
}

template <> size_t serialize(const ServiceDetailResponse& in, const io::StreamOutputView& out) {
return serialize_helper(in, out);
}

template <> size_t serialize(const ServiceDetailRequest& in, const io::StreamOutputView& out) {
return serialize_helper(in, out);
}

} // namespace iso15118::message_20
2 changes: 2 additions & 0 deletions src/iso15118/message/variant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ static void handle_main(VariantAccess& va) {
insert_type(va, doc.ServiceDiscoveryRes);
} else if (doc.ServiceDetailReq_isUsed) {
insert_type(va, doc.ServiceDetailReq);
} else if (doc.ServiceDetailRes_isUsed) {
insert_type(va, doc.ServiceDetailRes);
} else if (doc.ServiceSelectionReq_isUsed) {
insert_type(va, doc.ServiceSelectionReq);
} else if (doc.ScheduleExchangeReq_isUsed) {
Expand Down
66 changes: 64 additions & 2 deletions test/exi/cb/iso20/service_detail.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ SCENARIO("Se/Deserialize service_detail messages") {

message_20::Variant variant(io::v2gtp::PayloadType::Part20Main, stream_view);

THEN("It should be decoded succussfully") {
THEN("It should be decoded successfully") {

REQUIRE(variant.get_type() == message_20::Type::ServiceDetailReq);

Expand All @@ -32,6 +32,21 @@ SCENARIO("Se/Deserialize service_detail messages") {
}
}

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::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;
Expand All @@ -52,8 +67,55 @@ SCENARIO("Se/Deserialize service_detail messages") {
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 succussfully") {
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::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));
}
}
}