Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions include/iso15118/session/feedback.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ struct Callbacks {
std::function<void(const dt::VasSelectedServiceList&)> selected_vas_services;
std::function<void(const AcLimits&)> ac_limits;
std::function<void(const std::string&, const std::string&)> ev_termination;
std::function<void(const iso15118::message_20::datatypes::ResponseCode&)> response_code;
};

} // namespace feedback
Expand Down Expand Up @@ -114,6 +115,7 @@ class Feedback {
void selected_vas_services(const dt::VasSelectedServiceList&) const;
void ac_limits(const feedback::AcLimits&) const;
void ev_termination(const std::string&, const std::string&) const;
void response_code(const iso15118::message_20::datatypes::ResponseCode&) const;

private:
feedback::Callbacks callbacks;
Expand Down
3 changes: 3 additions & 0 deletions src/iso15118/d20/state/ac_charge_loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ Result AC_ChargeLoop::feed(Event ev) {
const auto res = handle_request(*req, m_ctx.session, false);

m_ctx.respond(res);
m_ctx.feedback.response_code(res.response_code);

if (res.response_code >= dt::ResponseCode::FAILED) {
m_ctx.session_stopped = true;
Expand All @@ -227,6 +228,7 @@ Result AC_ChargeLoop::feed(Event ev) {
present_powers, dynamic_parameters);

m_ctx.respond(res);
m_ctx.feedback.response_code(res.response_code);

if (res.response_code >= dt::ResponseCode::FAILED) {
m_ctx.session_stopped = true;
Expand All @@ -247,6 +249,7 @@ Result AC_ChargeLoop::feed(Event ev) {
const message_20::Type req_type = variant->get_type();
send_sequence_error(req_type, m_ctx);

m_ctx.feedback.response_code(dt::ResponseCode::FAILED_SequenceError);
m_ctx.session_stopped = true;
return {};
}
Expand Down
3 changes: 3 additions & 0 deletions src/iso15118/d20/state/ac_charge_parameter_discovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ Result AC_ChargeParameterDiscovery::feed(Event ev) {
const auto res = handle_request(*req, m_ctx.session, m_ctx.session_config.ac_limits, present_powers);

m_ctx.respond(res);
m_ctx.feedback.response_code(res.response_code);

if (res.response_code >= message_20::datatypes::ResponseCode::FAILED) {
m_ctx.session_stopped = true;
Expand All @@ -147,6 +148,7 @@ Result AC_ChargeParameterDiscovery::feed(Event ev) {

m_ctx.respond(res);
m_ctx.session_stopped = true;
m_ctx.feedback.response_code(res.response_code);

return {};
} else {
Expand All @@ -156,6 +158,7 @@ Result AC_ChargeParameterDiscovery::feed(Event ev) {
// Sequence Error
const message_20::Type req_type = variant->get_type();
send_sequence_error(req_type, m_ctx);
m_ctx.feedback.response_code(dt::ResponseCode::FAILED_SequenceError);

return {};
}
Expand Down
4 changes: 4 additions & 0 deletions src/iso15118/d20/state/authorization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ Result Authorization::feed(Event ev) {
const auto res = handle_request(*req, m_ctx.session, authorization_status, timeout_ongoing_reached);

m_ctx.respond(res);
m_ctx.feedback.response_code(res.response_code);

if (res.response_code >= dt::ResponseCode::FAILED) {
m_ctx.session_stopped = true;
Expand All @@ -141,6 +142,8 @@ Result Authorization::feed(Event ev) {
m_ctx.respond(res);

m_ctx.session_stopped = true;
m_ctx.feedback.response_code(res.response_code);

return {};
} else {
m_ctx.log("expected AuthorizationReq! But code type id: %d", variant->get_type());
Expand All @@ -149,6 +152,7 @@ Result Authorization::feed(Event ev) {
const message_20::Type req_type = variant->get_type();
send_sequence_error(req_type, m_ctx);

m_ctx.feedback.response_code(dt::ResponseCode::FAILED_SequenceError);
m_ctx.session_stopped = true;
return {};
}
Expand Down
3 changes: 3 additions & 0 deletions src/iso15118/d20/state/authorization_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ Result AuthorizationSetup::feed(Event ev) {
logf_info("Timestamp: %d", req->header.timestamp);

m_ctx.respond(res);
m_ctx.feedback.response_code(res.response_code);

if (res.response_code >= dt::ResponseCode::FAILED) {
m_ctx.session_stopped = true;
Expand All @@ -87,6 +88,7 @@ Result AuthorizationSetup::feed(Event ev) {

m_ctx.respond(res);
m_ctx.session_stopped = true;
m_ctx.feedback.response_code(res.response_code);

return {};
} else {
Expand All @@ -96,6 +98,7 @@ Result AuthorizationSetup::feed(Event ev) {
const message_20::Type req_type = variant->get_type();
send_sequence_error(req_type, m_ctx);

m_ctx.feedback.response_code(dt::ResponseCode::FAILED_SequenceError);
m_ctx.session_stopped = true;
return {};
}
Expand Down
3 changes: 3 additions & 0 deletions src/iso15118/d20/state/dc_cable_check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ Result DC_CableCheck::feed(Event ev) {
const auto res = handle_request(*req, m_ctx.session, cable_check_done);

m_ctx.respond(res);
m_ctx.feedback.response_code(res.response_code);

if (res.response_code >= dt::ResponseCode::FAILED) {
m_ctx.session_stopped = true;
Expand All @@ -79,6 +80,7 @@ Result DC_CableCheck::feed(Event ev) {

m_ctx.respond(res);
m_ctx.session_stopped = true;
m_ctx.feedback.response_code(res.response_code);

return {};
} else {
Expand All @@ -88,6 +90,7 @@ Result DC_CableCheck::feed(Event ev) {
const message_20::Type req_type = variant->get_type();
send_sequence_error(req_type, m_ctx);

m_ctx.feedback.response_code(dt::ResponseCode::FAILED_SequenceError);
m_ctx.session_stopped = true;
return {};
}
Expand Down
3 changes: 3 additions & 0 deletions src/iso15118/d20/state/dc_charge_loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ Result DC_ChargeLoop::feed(Event ev) {
const auto res = handle_request(*req, m_ctx.session, false);

m_ctx.respond(res);
m_ctx.feedback.response_code(res.response_code);

if (res.response_code >= dt::ResponseCode::FAILED) {
m_ctx.session_stopped = true;
Expand Down Expand Up @@ -250,6 +251,7 @@ Result DC_ChargeLoop::feed(Event ev) {
m_ctx.session_config.dc_limits, dynamic_parameters);

m_ctx.respond(res);
m_ctx.feedback.response_code(res.response_code);

if (res.response_code >= dt::ResponseCode::FAILED) {
m_ctx.session_stopped = true;
Expand All @@ -271,6 +273,7 @@ Result DC_ChargeLoop::feed(Event ev) {
const message_20::Type req_type = variant->get_type();
send_sequence_error(req_type, m_ctx);

m_ctx.feedback.response_code(dt::ResponseCode::FAILED_SequenceError);
m_ctx.session_stopped = true;
return {};
}
Expand Down
93 changes: 93 additions & 0 deletions src/iso15118/d20/state/dc_charge_parameter_discovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,91 @@ template <> void convert(BPT_DC_ModeRes& out, const d20::DcTransferLimits& in) {
}
}

template <typename DCMode>
bool handle_compatibility_check(const d20::DcTransferLimits& evse_dc_limits, const DCMode& ev_limits) {
// In IEC 61851-23-3 a compatibility check is required

constexpr auto MAX_VOLTAGE_OFFSET = 50.f;
constexpr auto MAX_VOLTAGE_THREASHOLD = 500.f;
constexpr auto MAX_VOLTAGE_FACTOR = 1.1f;
constexpr auto MAX_POWER_LIMIT = 200000.f;
bool compatiblity_flag = true;
float ev_max_power;
float ev_max_current;
float ev_max_voltage;

if (const auto* mode = std::get_if<DC_ModeReq>(&ev_limits)) {
ev_max_power = dt::from_RationalNumber(mode->max_charge_power);
ev_max_current = dt::from_RationalNumber(mode->max_charge_current);
ev_max_voltage = dt::from_RationalNumber(mode->max_voltage);
} else if (const auto* mode = std::get_if<BPT_DC_ModeReq>(&ev_limits)) {
ev_max_power = dt::from_RationalNumber(mode->max_charge_power);
ev_max_current = dt::from_RationalNumber(mode->max_charge_current);
ev_max_voltage = dt::from_RationalNumber(mode->max_voltage);
} else {
return false;
}

const float evse_max_voltage = dt::from_RationalNumber(evse_dc_limits.voltage.max);
const float evse_min_voltage = dt::from_RationalNumber(evse_dc_limits.voltage.min);
const float evse_max_current = dt::from_RationalNumber(evse_dc_limits.charge_limits.current.max);
const float evse_min_current = dt::from_RationalNumber(evse_dc_limits.charge_limits.current.min);
const float evse_max_power = dt::from_RationalNumber(evse_dc_limits.charge_limits.power.max);
const float evse_min_power = dt::from_RationalNumber(evse_dc_limits.charge_limits.power.min);

// CC.5.6 2.a
if (ev_max_voltage <= MAX_VOLTAGE_THREASHOLD) {
if (evse_max_voltage >
std::min({ev_max_voltage + MAX_VOLTAGE_OFFSET, evse_max_voltage, MAX_VOLTAGE_THREASHOLD})) {
if (evse_max_voltage > MAX_VOLTAGE_THREASHOLD) {
logf_error("EVSE max voltage %.1f V > EV max voltage 500V", evse_max_voltage);
} else {
logf_error("EVSE max voltage %.1f V > EV max voltage + 50V: %.1f V", evse_max_voltage,
ev_max_voltage + MAX_VOLTAGE_OFFSET);
}
compatiblity_flag = false;
}
}
if (ev_max_voltage > MAX_VOLTAGE_THREASHOLD) {
if (evse_max_voltage > std::min(ev_max_voltage * MAX_VOLTAGE_FACTOR, evse_max_voltage)) {
logf_error("EVSE max voltage %.1f V > EV max voltage (> 500 V) multiplied by 1,1: %.1f V", evse_max_voltage,
ev_max_voltage * MAX_VOLTAGE_FACTOR);
compatiblity_flag = false;
}
}

// CC.5.6 2.b
if (evse_max_current > std::min(ev_max_current, evse_max_current)) {
logf_error("EVSE max current %.1f A > EV max current %.1f A", evse_max_current, ev_max_current);
compatiblity_flag = false;
}

// CC.5.6 2.c
float ev_power_max = ev_max_power;
if (ev_power_max == 0) {
ev_power_max = std::max(ev_max_voltage * ev_max_current, MAX_POWER_LIMIT);
}
if (evse_max_power > std::min(ev_power_max, evse_max_power)) {
logf_error("EVSE max power %.1f W > EV max power %.1f W", evse_max_power, ev_power_max);
compatiblity_flag = false;
}
// CC.5.6 2.d-f here not implemented because we make no difference between CPD and RATED
// CC.5.6 2.g
if (evse_min_power >= ev_power_max) {
logf_error("EVSE min power %.1f W >= EV max power %.1f W!", evse_min_power, ev_max_power);
compatiblity_flag = false;
}
if (evse_min_voltage >= ev_max_voltage) {
logf_error("EVSE min voltage %.1f V >= EV max voltage %.1f V!", evse_min_voltage, ev_max_voltage);
compatiblity_flag = false;
}
if (evse_min_current >= ev_max_current) {
logf_error("EVSE min current %.1f A >= EV max current %.1f A!", evse_min_current, ev_max_current);
compatiblity_flag = false;
}
return compatiblity_flag;
}

message_20::DC_ChargeParameterDiscoveryResponse
handle_request(const message_20::DC_ChargeParameterDiscoveryRequest& req, const d20::Session& session,
const d20::DcTransferLimits& dc_limits) {
Expand Down Expand Up @@ -82,6 +167,10 @@ handle_request(const message_20::DC_ChargeParameterDiscoveryRequest& req, const
return response_with_code(res, dt::ResponseCode::FAILED_WrongChargeParameter);
}

// Do compatibility check IEC61851-23-3 CC.5.6
if (not handle_compatibility_check(dc_limits, req.transfer_mode))
return response_with_code(res, dt::ResponseCode::FAILED_WrongChargeParameter);

return response_with_code(res, dt::ResponseCode::OK);
}

Expand Down Expand Up @@ -127,6 +216,7 @@ Result DC_ChargeParameterDiscovery::feed(Event ev) {
m_ctx.respond(res);

m_ctx.feedback.dc_max_limits(dc_max_limits);
m_ctx.feedback.response_code(res.response_code);

if (res.response_code >= dt::ResponseCode::FAILED) {
m_ctx.session_stopped = true;
Expand All @@ -139,6 +229,7 @@ Result DC_ChargeParameterDiscovery::feed(Event ev) {

m_ctx.respond(res);
m_ctx.session_stopped = true;
m_ctx.feedback.response_code(res.response_code);

return {};
} else {
Expand All @@ -149,6 +240,8 @@ Result DC_ChargeParameterDiscovery::feed(Event ev) {
const message_20::Type req_type = variant->get_type();
send_sequence_error(req_type, m_ctx);

m_ctx.feedback.response_code(dt::ResponseCode::FAILED_SequenceError);

return {};
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/iso15118/d20/state/dc_pre_charge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Result DC_PreCharge::feed(Event ev) {
m_ctx.feedback.dc_pre_charge_target_voltage(message_20::datatypes::from_RationalNumber(req->target_voltage));

m_ctx.respond(res);
m_ctx.feedback.response_code(res.response_code);

if (res.response_code >= dt::ResponseCode::FAILED) {
m_ctx.session_stopped = true;
Expand All @@ -73,6 +74,7 @@ Result DC_PreCharge::feed(Event ev) {

m_ctx.respond(res);
m_ctx.session_stopped = true;
m_ctx.feedback.response_code(res.response_code);

return {};
} else {
Expand All @@ -82,6 +84,7 @@ Result DC_PreCharge::feed(Event ev) {
const message_20::Type req_type = variant->get_type();
send_sequence_error(req_type, m_ctx);

m_ctx.feedback.response_code(dt::ResponseCode::FAILED_SequenceError);
m_ctx.session_stopped = true;
return {};
}
Expand Down
3 changes: 3 additions & 0 deletions src/iso15118/d20/state/dc_welding_detection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Result DC_WeldingDetection::feed(Event ev) {
const auto res = handle_request(*req, m_ctx.session, present_voltage);

m_ctx.respond(res);
m_ctx.feedback.response_code(res.response_code);

if (res.response_code >= dt::ResponseCode::FAILED) {
m_ctx.session_stopped = true;
Expand All @@ -76,6 +77,7 @@ Result DC_WeldingDetection::feed(Event ev) {
}

m_ctx.respond(res);
m_ctx.feedback.response_code(res.response_code);

// Todo(sl): Tell the reason why the charger is stopping. Shutdown, Error, etc.
if (req->charging_session == message_20::datatypes::ChargingSession::Pause) {
Expand All @@ -98,6 +100,7 @@ Result DC_WeldingDetection::feed(Event ev) {
const message_20::Type req_type = variant->get_type();
send_sequence_error(req_type, m_ctx);

m_ctx.feedback.response_code(dt::ResponseCode::FAILED_SequenceError);
m_ctx.session_stopped = true;
return {};
}
Expand Down
5 changes: 5 additions & 0 deletions src/iso15118/d20/state/power_delivery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Result PowerDelivery::feed(Event ev) {

const auto& res = handle_request(previous_req.value(), m_ctx.session, false);
m_ctx.respond(res);
m_ctx.feedback.response_code(res.response_code);

if (res.response_code >= dt::ResponseCode::FAILED) {
m_ctx.session_stopped = true;
Expand All @@ -87,6 +88,7 @@ Result PowerDelivery::feed(Event ev) {
handle_request(previous_req.value_or(message_20::PowerDeliveryRequest{}), m_ctx.session, true);
m_ctx.respond(res);
m_ctx.session_stopped = true;
m_ctx.feedback.response_code(res.response_code);
}
return {};
}
Expand All @@ -103,6 +105,7 @@ Result PowerDelivery::feed(Event ev) {
m_ctx.feedback.dc_pre_charge_target_voltage(dt::from_RationalNumber(req->target_voltage));

m_ctx.respond(res);
m_ctx.feedback.response_code(res.response_code);

if (res.response_code >= dt::ResponseCode::FAILED) {
m_ctx.session_stopped = true;
Expand All @@ -129,6 +132,7 @@ Result PowerDelivery::feed(Event ev) {
const auto& res = handle_request(*req, m_ctx.session, false);

m_ctx.respond(res);
m_ctx.feedback.response_code(res.response_code);

if (res.response_code >= dt::ResponseCode::FAILED) {
m_ctx.session_stopped = true;
Expand All @@ -154,6 +158,7 @@ Result PowerDelivery::feed(Event ev) {
const message_20::Type req_type = variant->get_type();
send_sequence_error(req_type, m_ctx);

m_ctx.feedback.response_code(dt::ResponseCode::FAILED_SequenceError);
m_ctx.session_stopped = true;
return {};
}
Expand Down
Loading