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
19 changes: 19 additions & 0 deletions lib/everest/iso15118/include/iso15118/detail/cb_exi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,22 @@ size_t serialize_helper(const MessageType& in, const io::StreamOutputView& strea
}

} // namespace iso15118::message_20

namespace iso15118::d2::msg {

template <typename MessageType> int serialize_to_exi(const MessageType& in, exi_bitstream_t& out);

template <typename MessageType>
size_t serialize_helper(const MessageType& in, const io::StreamOutputView& stream_view) {
auto out = get_exi_output_stream(stream_view);

const auto error = serialize_to_exi(in, out);

if (error != 0) {
throw std::runtime_error("Could not encode exi: " + std::to_string(error));
}

return exi_bitstream_get_length(&out);
}

} // namespace iso15118::d2::msg
34 changes: 34 additions & 0 deletions lib/everest/iso15118/include/iso15118/detail/variant_access.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <cassert>

#include <iso15118/message/d2/variant.hpp>
#include <iso15118/message/variant.hpp>

#include "cb_exi.hpp"
Expand Down Expand Up @@ -34,3 +35,36 @@ struct VariantAccess {
template <typename CbExiMessageType> void insert_type(VariantAccess& va, const CbExiMessageType&);

} // namespace iso15118::message_20

#include <cbv2g/iso_2/iso2_msgDefDatatypes.h>

namespace iso15118::d2::msg {

struct VariantAccess {
// input
exi_bitstream_t input_stream;

// output
void*& data;
iso15118::d2::msg::Type& type;
iso15118::d2::msg::Variant::CustomDeleter& custom_deleter;
std::string& error;

template <typename MessageType, typename CbExiMessageType>
void insert_type(const CbExiMessageType& in, const iso2_MessageHeaderType& header) {
assert(data == nullptr);

data = new MessageType;
type = iso15118::d2::msg::TypeTrait<MessageType>::type;
custom_deleter = [](void* ptr) { delete static_cast<MessageType*>(ptr); };

auto msg = static_cast<MessageType*>(data);
convert(header, msg->header);
convert(in, *msg);
};
};

template <typename CbExiMessageType>
void insert_type(VariantAccess& va, const CbExiMessageType&, const iso2_MessageHeaderType& header);

} // namespace iso15118::d2::msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Pionix GmbH and Contributors to EVerest
#pragma once

#include <iso15118/message/d2/msg_data_types.hpp>

#include <optional>
#include <string>

namespace iso15118::d2::msg {

struct AuthorizationRequest {
Header header;
std::string id;
std::optional<data_types::GenChallenge> gen_challenge;
};

struct AuthorizationResponse {
Header header;
data_types::ResponseCode response_code;
data_types::EvseProcessing evse_processing;
};

} // namespace iso15118::d2::msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Pionix GmbH and Contributors to EVerest
#pragma once

#include <iso15118/message/d2/msg_data_types.hpp>

namespace iso15118::d2::msg {

struct DC_CableCheckRequest {
Header header;
data_types::DcEvStatus ev_status;
};

struct DC_CableCheckResponse {
Header header;
data_types::ResponseCode response_code;
data_types::DcEvseStatus evse_status;
data_types::EvseProcessing evse_processing;
};

} // namespace iso15118::d2::msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Pionix GmbH and Contributors to EVerest
#pragma once

#include <iso15118/message/d2/msg_data_types.hpp>
#include <optional>

namespace iso15118::d2::msg {

struct DC_CurrentDemandRequest {
Header header;
data_types::DcEvStatus ev_status;
data_types::PhysicalValue ev_target_current;
data_types::PhysicalValue ev_target_voltage;
std::optional<data_types::PhysicalValue> ev_maximum_voltage_limit{std::nullopt};
std::optional<data_types::PhysicalValue> ev_maximum_current_limit{std::nullopt};
std::optional<data_types::PhysicalValue> ev_maximum_power_limit{std::nullopt};
std::optional<bool> bulk_charging_complete{std::nullopt};
std::optional<bool> charging_complete{std::nullopt};
std::optional<data_types::PhysicalValue> remaining_time_to_full_soc{std::nullopt};
std::optional<data_types::PhysicalValue> remaining_time_to_bulk_soc{std::nullopt};
};

struct DC_CurrentDemandResponse {
Header header;
data_types::ResponseCode response_code;
data_types::DcEvseStatus evse_status;
data_types::PhysicalValue evse_present_voltage;
data_types::PhysicalValue evse_present_current;
bool evse_current_limit_achieved;
bool evse_voltage_limit_achieved;
bool evse_power_limit_achieved;
data_types::EVSEID evse_id;
data_types::SAScheduleTupleID sa_schedule_tuple_id;
std::optional<data_types::PhysicalValue> evse_maximum_voltage_limit{std::nullopt};
std::optional<data_types::PhysicalValue> evse_maximum_current_limit{std::nullopt};
std::optional<data_types::PhysicalValue> evse_maximum_power_limit{std::nullopt};
std::optional<data_types::MeterInfo> meter_info{std::nullopt};
std::optional<bool> receipt_required{std::nullopt};
};

} // namespace iso15118::d2::msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Pionix GmbH and Contributors to EVerest
#pragma once

#include <iso15118/message/d2/msg_data_types.hpp>

namespace iso15118::d2::msg {

struct DC_PreChargeRequest {
Header header;
data_types::DcEvStatus ev_status;
data_types::PhysicalValue ev_target_voltage;
data_types::PhysicalValue ev_target_current;
};

struct DC_PreChargeResponse {
Header header;
data_types::ResponseCode response_code;
data_types::DcEvseStatus evse_status;
data_types::PhysicalValue evse_present_voltage;
};

} // namespace iso15118::d2::msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Pionix GmbH and Contributors to EVerest
#pragma once

#include <iso15118/message/d2/msg_data_types.hpp>

namespace iso15118::d2::msg {

struct DC_WeldingDetectionRequest {
Header header;
data_types::DcEvStatus ev_status;
};

struct DC_WeldingDetectionResponse {
Header header;
data_types::ResponseCode response_code;
data_types::DcEvseStatus evse_status;
data_types::PhysicalValue evse_present_voltage;
};

} // namespace iso15118::d2::msg
181 changes: 181 additions & 0 deletions lib/everest/iso15118/include/iso15118/message/d2/msg_data_types.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Pionix GmbH and Contributors to EVerest
#pragma once

#include <array>
#include <cstdint>
#include <optional>
#include <string>
#include <vector>

#include <cbv2g/iso_2/iso2_msgDefDatatypes.h>

namespace iso15118::d2::msg {

template <typename InType, typename OutType> void convert(const InType&, OutType&);

namespace data_types {

constexpr auto SESSION_ID_LENGTH = 8;
using SESSION_ID = std::array<uint8_t, SESSION_ID_LENGTH>; // hexBinary, max length 8

constexpr auto GEN_CHALLENGE_LENGTH = 16;
using GenChallenge = std::array<uint8_t, GEN_CHALLENGE_LENGTH>; // base64 binary
using PercentValue = uint8_t; // [0 - 100]
using SAScheduleTupleID = int16_t; // [1-255]
using MeterID = std::string; // MaxLength: 32
using EVSEID = std::string; // Length: 7-37
using MeterReading = uint64_t; // Wh
using SigMeterReading = std::vector<uint8_t>; // MaxLength: 64
using MeterStatus = int16_t;
using TMeter = int64_t; // Unix timestamp format

enum class ResponseCode {
OK,
OK_NewSessionEstablished,
OK_OldSessionJoined,
OK_CertificateExpiresSoon,
FAILED,
FAILED_SequenceError,
FAILED_ServiceIDInvalid,
FAILED_UnknownSession,
FAILED_ServiceSelectionInvalid,
FAILED_PaymentSelectionInvalid,
FAILED_CertificateExpired,
FAILED_SignatureError,
FAILED_NoCertificateAvailable,
FAILED_CertChainError,
FAILED_ChallengeInvalid,
FAILED_ContractCanceled,
FAILED_WrongChargeParameter,
FAILED_PowerDeliveryNotApplied,
FAILED_TariffSelectionInvalid,
FAILED_ChargingProfileInvalid,
FAILED_MeteringSignatureNotValid,
FAILED_NoChargeServiceSelected,
FAILED_WrongEnergyTransferMode,
FAILED_ContactorError,
FAILED_CertificateNotAllowedAtThisEVSE,
FAILED_CertificateRevoked,
};

enum class FaultCode {
ParsingError,
NoTLSRootCertificatAvailable,
UnknownError,
};

enum class EvseProcessing {
Finished,
Ongoing,
Ongoing_WaitingForCustomerInteraction
};

enum class DcEvErrorCode {
NO_ERROR,
FAILED_RESSTemperatureInhibit,
FAILED_EVShiftPosition,
FAILED_ChargerConnectorLockFault,
FAILED_EVRESSMalfunction,
FAILED_ChargingCurrentdifferential,
FAILED_ChargingVoltageOutOfRange,
Reserved_A,
Reserved_B,
Reserved_C,
FAILED_ChargingSystemIncompatibility,
NoData,
};

enum class EvseNotification {
None,
StopCharging,
ReNegotiation,
};

enum class UnitSymbol {
h,
m,
s,
A,
V,
W,
Wh
};

enum class DcEvseStatusCode {
EVSE_NotReady,
EVSE_Ready,
EVSE_Shutdown,
EVSE_UtilityInterruptEvent,
EVSE_IsolationMonitoringActive,
EVSE_EmergencyShutdown,
EVSE_Malfunction,
Reserved_8,
Reserved_9,
Reserved_A,
Reserved_B,
Reserved_C
};

enum class IsolationLevel {
Invalid,
Valid,
Warning,
Fault,
No_IMD
};

struct MeterInfo {
MeterID meter_id;
std::optional<MeterReading> meter_reading{std::nullopt};
std::optional<SigMeterReading> sig_meter_reading{std::nullopt};
std::optional<MeterStatus> meter_status{std::nullopt};
std::optional<TMeter> t_meter{std::nullopt};
};

struct PhysicalValue {
int16_t value{0};
int8_t multiplier{0}; // [-3 - 3]
UnitSymbol unit;
};

struct Notification {
FaultCode fault_code;
std::optional<std::string> fault_msg;
};

struct EvseStatus {
uint16_t notification_max_delay{0};
EvseNotification evse_notification{EvseNotification::None};
};

struct AcEvseStatus : EvseStatus {
bool rcd;
};

struct DcEvseStatus : EvseStatus {
std::optional<IsolationLevel> evse_isolation_status;
DcEvseStatusCode evse_status_code;
};

struct DcEvStatus {
bool ev_ready;
DcEvErrorCode ev_error_code;
PercentValue ev_ress_soc;
};

float from_PhysicalValue(const PhysicalValue& in);
PhysicalValue from_float(const float in, const data_types::UnitSymbol unit);

} // namespace data_types

struct Header {
data_types::SESSION_ID session_id;
std::optional<data_types::Notification> notification;
// TODO: Missing xml signature
};

void convert(const struct iso2_MessageHeaderType& in, Header& out);
void convert(const Header& in, struct iso2_MessageHeaderType& out);

} // namespace iso15118::d2::msg
Loading
Loading