Add C# dotnet exact EXI codec implementation
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
1184
csharp/dotnet/V2G/EXICodecExact.cs
Normal file
1184
csharp/dotnet/V2G/EXICodecExact.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using V2GDecoderNet.EXI;
|
||||
|
||||
namespace V2GDecoderNet.V2G
|
||||
@@ -57,21 +58,26 @@ namespace V2GDecoderNet.V2G
|
||||
return inputData ?? Array.Empty<byte>();
|
||||
}
|
||||
|
||||
// Check for V2G Transfer Protocol header
|
||||
if (inputData[0] == V2G_PROTOCOL_VERSION && inputData[1] == V2G_INV_PROTOCOL_VERSION)
|
||||
// First, look for V2G Transfer Protocol header anywhere in the data
|
||||
// Pattern: 0x01 0xFE 0x80 0x01 (V2GTP header for ISO/DIN/SAP)
|
||||
for (int i = 0; i <= inputData.Length - 8; i++)
|
||||
{
|
||||
ushort payloadType = (ushort)((inputData[2] << 8) | inputData[3]);
|
||||
|
||||
if (payloadType == V2G_PAYLOAD_ISO_DIN_SAP || payloadType == V2G_PAYLOAD_ISO2)
|
||||
if (inputData[i] == V2G_PROTOCOL_VERSION && inputData[i + 1] == V2G_INV_PROTOCOL_VERSION)
|
||||
{
|
||||
// Valid V2GTP header detected: skip 8-byte header
|
||||
var exiBody = new byte[inputData.Length - 8];
|
||||
Array.Copy(inputData, 8, exiBody, 0, exiBody.Length);
|
||||
return exiBody;
|
||||
ushort payloadType = (ushort)((inputData[i + 2] << 8) | inputData[i + 3]);
|
||||
|
||||
if (payloadType == V2G_PAYLOAD_ISO_DIN_SAP || payloadType == V2G_PAYLOAD_ISO2)
|
||||
{
|
||||
// Valid V2GTP header found: skip 8-byte header to get EXI body
|
||||
int exiStart = i + 8;
|
||||
var exiBody = new byte[inputData.Length - exiStart];
|
||||
Array.Copy(inputData, exiStart, exiBody, 0, exiBody.Length);
|
||||
return exiBody;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Look for EXI start pattern anywhere in the data
|
||||
// If no V2GTP header found, look for EXI start pattern anywhere in the data
|
||||
for (int i = 0; i <= inputData.Length - 2; i++)
|
||||
{
|
||||
ushort pattern = (ushort)((inputData[i] << 8) | inputData[i + 1]);
|
||||
|
||||
437
csharp/dotnet/V2G/V2GTypesExact.cs
Normal file
437
csharp/dotnet/V2G/V2GTypesExact.cs
Normal file
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2024 C# Port
|
||||
* Original Copyright (C) 2007-2018 Siemens AG
|
||||
*
|
||||
* Exact V2G types and enumerations - byte-compatible with OpenV2G ISO1 implementation
|
||||
* Based on iso1EXIDatatypes.h
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace V2GDecoderNet.V2G
|
||||
{
|
||||
/// <summary>
|
||||
/// Response code enumeration - exact match to iso1responseCodeType
|
||||
/// 5-bit encoding (0-31)
|
||||
/// </summary>
|
||||
public enum ResponseCodeType
|
||||
{
|
||||
OK = 0,
|
||||
OK_NewSessionEstablished = 1,
|
||||
OK_OldSessionJoined = 2,
|
||||
OK_CertificateExpiresSoon = 3,
|
||||
FAILED = 4,
|
||||
FAILED_SequenceError = 5,
|
||||
FAILED_ServiceIDInvalid = 6,
|
||||
FAILED_UnknownSession = 7,
|
||||
FAILED_ServiceSelectionInvalid = 8,
|
||||
FAILED_PaymentSelectionInvalid = 9,
|
||||
FAILED_CertificateExpired = 10,
|
||||
FAILED_SignatureError = 11,
|
||||
FAILED_NoCertificateAvailable = 12,
|
||||
FAILED_CertChainError = 13,
|
||||
FAILED_ChallengeInvalid = 14,
|
||||
FAILED_ContractCanceled = 15,
|
||||
FAILED_WrongChargeParameter = 16,
|
||||
FAILED_PowerDeliveryNotApplied = 17,
|
||||
FAILED_TariffSelectionInvalid = 18,
|
||||
FAILED_ChargingProfileInvalid = 19,
|
||||
FAILED_MeteringSignatureNotValid = 20,
|
||||
FAILED_NoChargeServiceSelected = 21,
|
||||
FAILED_WrongEnergyTransferMode = 22,
|
||||
FAILED_ContactorError = 23,
|
||||
FAILED_CertificateNotAllowedAtThisEVSE = 24,
|
||||
FAILED_CertificateRevoked = 25
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unit symbol enumeration - exact match to iso1unitSymbolType
|
||||
/// 3-bit encoding (0-7)
|
||||
/// </summary>
|
||||
public enum UnitSymbolType
|
||||
{
|
||||
h = 0, // hours
|
||||
m = 1, // meters
|
||||
s = 2, // seconds
|
||||
A = 3, // amperes
|
||||
V = 4, // volts
|
||||
W = 5, // watts
|
||||
Wh = 6 // watt-hours
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EVSE isolation status enumeration - exact match to iso1isolationLevelType
|
||||
/// 3-bit encoding (0-7)
|
||||
/// </summary>
|
||||
public enum IsolationLevelType
|
||||
{
|
||||
Invalid = 0,
|
||||
Valid = 1,
|
||||
Warning = 2,
|
||||
Fault = 3,
|
||||
No_IMD = 4
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EVSE status code enumeration - exact match to iso1DC_EVSEStatusCodeType
|
||||
/// 4-bit encoding (0-15)
|
||||
/// </summary>
|
||||
public enum DC_EVSEStatusCodeType
|
||||
{
|
||||
EVSE_NotReady = 0,
|
||||
EVSE_Ready = 1,
|
||||
EVSE_Shutdown = 2,
|
||||
EVSE_UtilityInterruptEvent = 3,
|
||||
EVSE_IsolationMonitoringActive = 4,
|
||||
EVSE_EmergencyShutdown = 5,
|
||||
EVSE_Malfunction = 6,
|
||||
Reserved_8 = 7,
|
||||
Reserved_9 = 8,
|
||||
Reserved_A = 9,
|
||||
Reserved_B = 10,
|
||||
Reserved_C = 11
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EVSE notification enumeration - exact match to iso1EVSENotificationType
|
||||
/// 2-bit encoding (0-3)
|
||||
/// </summary>
|
||||
public enum EVSENotificationType
|
||||
{
|
||||
None = 0,
|
||||
StopCharging = 1,
|
||||
ReNegotiation = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Physical value structure - exact match to iso1PhysicalValueType
|
||||
/// </summary>
|
||||
public class PhysicalValueType
|
||||
{
|
||||
/// <summary>
|
||||
/// Power-of-10 multiplier (-3 to +3) - encoded as 3-bit (value + 3)
|
||||
/// </summary>
|
||||
public sbyte Multiplier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unit symbol - encoded as 3-bit enumeration
|
||||
/// </summary>
|
||||
public UnitSymbolType Unit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Actual value - encoded as 16-bit signed integer
|
||||
/// </summary>
|
||||
public short Value { get; set; }
|
||||
|
||||
public PhysicalValueType()
|
||||
{
|
||||
Multiplier = 0;
|
||||
Unit = UnitSymbolType.V;
|
||||
Value = 0;
|
||||
}
|
||||
|
||||
public PhysicalValueType(sbyte multiplier, UnitSymbolType unit, short value)
|
||||
{
|
||||
Multiplier = multiplier;
|
||||
Unit = unit;
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DC EVSE status structure - exact match to iso1DC_EVSEStatusType
|
||||
/// </summary>
|
||||
public class DC_EVSEStatusType
|
||||
{
|
||||
/// <summary>
|
||||
/// Notification max delay - 16-bit unsigned integer
|
||||
/// </summary>
|
||||
public ushort NotificationMaxDelay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// EVSE notification - 2-bit enumeration
|
||||
/// </summary>
|
||||
public EVSENotificationType EVSENotification { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// EVSE isolation status - 3-bit enumeration (optional)
|
||||
/// </summary>
|
||||
public IsolationLevelType EVSEIsolationStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional flag for EVSEIsolationStatus
|
||||
/// </summary>
|
||||
public bool EVSEIsolationStatus_isUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// EVSE status code - 4-bit enumeration
|
||||
/// </summary>
|
||||
public DC_EVSEStatusCodeType EVSEStatusCode { get; set; }
|
||||
|
||||
public DC_EVSEStatusType()
|
||||
{
|
||||
NotificationMaxDelay = 0;
|
||||
EVSENotification = EVSENotificationType.None;
|
||||
EVSEIsolationStatus = IsolationLevelType.Invalid;
|
||||
EVSEIsolationStatus_isUsed = false;
|
||||
EVSEStatusCode = DC_EVSEStatusCodeType.EVSE_NotReady;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Meter info structure - exact match to iso1MeterInfoType
|
||||
/// </summary>
|
||||
public class MeterInfoType
|
||||
{
|
||||
public string MeterID { get; set; } = "";
|
||||
public ulong MeterReading { get; set; }
|
||||
public sbyte SigMeterReading { get; set; }
|
||||
public string MeterStatus { get; set; } = "";
|
||||
public long TMeter { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Current demand response structure - exact match to iso1CurrentDemandResType
|
||||
/// Grammar states 317-330
|
||||
/// </summary>
|
||||
public class CurrentDemandResType
|
||||
{
|
||||
/// <summary>
|
||||
/// Response code - 5-bit enumeration (Grammar state 317)
|
||||
/// </summary>
|
||||
public ResponseCodeType ResponseCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DC EVSE status - complex type (Grammar state 318)
|
||||
/// </summary>
|
||||
public DC_EVSEStatusType DC_EVSEStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// EVSE present voltage - PhysicalValue (Grammar state 319)
|
||||
/// </summary>
|
||||
public PhysicalValueType EVSEPresentVoltage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// EVSE present current - PhysicalValue (Grammar state 320)
|
||||
/// </summary>
|
||||
public PhysicalValueType EVSEPresentCurrent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current limit achieved flag (Grammar state 321)
|
||||
/// </summary>
|
||||
public bool EVSECurrentLimitAchieved { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Voltage limit achieved flag (Grammar state 322)
|
||||
/// </summary>
|
||||
public bool EVSEVoltageLimitAchieved { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Power limit achieved flag (Grammar state 323)
|
||||
/// </summary>
|
||||
public bool EVSEPowerLimitAchieved { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum voltage limit (Optional - Grammar state 324 choice 0 → 325)
|
||||
/// </summary>
|
||||
public PhysicalValueType EVSEMaximumVoltageLimit { get; set; }
|
||||
public bool EVSEMaximumVoltageLimit_isUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum current limit (Optional - Grammar state 324 choice 1 → 326)
|
||||
/// </summary>
|
||||
public PhysicalValueType EVSEMaximumCurrentLimit { get; set; }
|
||||
public bool EVSEMaximumCurrentLimit_isUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum power limit (Optional - Grammar state 324 choice 2 → 327)
|
||||
/// </summary>
|
||||
public PhysicalValueType EVSEMaximumPowerLimit { get; set; }
|
||||
public bool EVSEMaximumPowerLimit_isUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// EVSE ID string (37 characters max - Grammar state 324 choice 3 → 328)
|
||||
/// </summary>
|
||||
public string EVSEID { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// SA schedule tuple ID - 8-bit (value-1) (Grammar state 328)
|
||||
/// </summary>
|
||||
public byte SAScheduleTupleID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Meter info (Optional - Grammar state 329 choice 0 → 330)
|
||||
/// </summary>
|
||||
public MeterInfoType MeterInfo { get; set; }
|
||||
public bool MeterInfo_isUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Receipt required flag (Optional - Grammar state 329 choice 1 → END)
|
||||
/// </summary>
|
||||
public bool ReceiptRequired { get; set; }
|
||||
public bool ReceiptRequired_isUsed { get; set; }
|
||||
|
||||
public CurrentDemandResType()
|
||||
{
|
||||
ResponseCode = ResponseCodeType.OK;
|
||||
DC_EVSEStatus = new DC_EVSEStatusType();
|
||||
EVSEPresentVoltage = new PhysicalValueType();
|
||||
EVSEPresentCurrent = new PhysicalValueType();
|
||||
EVSECurrentLimitAchieved = false;
|
||||
EVSEVoltageLimitAchieved = false;
|
||||
EVSEPowerLimitAchieved = false;
|
||||
|
||||
EVSEMaximumVoltageLimit = new PhysicalValueType();
|
||||
EVSEMaximumVoltageLimit_isUsed = false;
|
||||
EVSEMaximumCurrentLimit = new PhysicalValueType();
|
||||
EVSEMaximumCurrentLimit_isUsed = false;
|
||||
EVSEMaximumPowerLimit = new PhysicalValueType();
|
||||
EVSEMaximumPowerLimit_isUsed = false;
|
||||
|
||||
EVSEID = "";
|
||||
SAScheduleTupleID = 1;
|
||||
|
||||
MeterInfo = new MeterInfoType();
|
||||
MeterInfo_isUsed = false;
|
||||
ReceiptRequired = false;
|
||||
ReceiptRequired_isUsed = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Current demand request structure - exact match to iso1CurrentDemandReqType
|
||||
/// Grammar states 273-280
|
||||
/// </summary>
|
||||
public class CurrentDemandReqType
|
||||
{
|
||||
/// <summary>
|
||||
/// DC EV status information (Mandatory - Grammar state 273)
|
||||
/// </summary>
|
||||
public DC_EVStatusType DC_EVStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// EV target current (Mandatory - Grammar state 274)
|
||||
/// </summary>
|
||||
public PhysicalValueType EVTargetCurrent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// EV maximum voltage limit (Optional - Grammar state 275 choice 0)
|
||||
/// </summary>
|
||||
public PhysicalValueType EVMaximumVoltageLimit { get; set; }
|
||||
public bool EVMaximumVoltageLimit_isUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// EV maximum current limit (Optional - Grammar state 275 choice 1)
|
||||
/// </summary>
|
||||
public PhysicalValueType EVMaximumCurrentLimit { get; set; }
|
||||
public bool EVMaximumCurrentLimit_isUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// EV maximum power limit (Optional - Grammar state 275 choice 2)
|
||||
/// </summary>
|
||||
public PhysicalValueType EVMaximumPowerLimit { get; set; }
|
||||
public bool EVMaximumPowerLimit_isUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Bulk charging complete flag (Optional - Grammar state 275 choice 3)
|
||||
/// </summary>
|
||||
public bool BulkChargingComplete { get; set; }
|
||||
public bool BulkChargingComplete_isUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Charging complete flag (Optional - Grammar state 275 choice 4)
|
||||
/// </summary>
|
||||
public bool ChargingComplete { get; set; }
|
||||
public bool ChargingComplete_isUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Remaining time to full SoC (Optional)
|
||||
/// </summary>
|
||||
public PhysicalValueType RemainingTimeToFullSoC { get; set; }
|
||||
public bool RemainingTimeToFullSoC_isUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Remaining time to bulk SoC (Optional)
|
||||
/// </summary>
|
||||
public PhysicalValueType RemainingTimeToBulkSoC { get; set; }
|
||||
public bool RemainingTimeToBulkSoC_isUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// EV target voltage (Mandatory)
|
||||
/// </summary>
|
||||
public PhysicalValueType EVTargetVoltage { get; set; }
|
||||
|
||||
public CurrentDemandReqType()
|
||||
{
|
||||
DC_EVStatus = new DC_EVStatusType();
|
||||
EVTargetCurrent = new PhysicalValueType();
|
||||
EVMaximumVoltageLimit = new PhysicalValueType();
|
||||
EVMaximumVoltageLimit_isUsed = false;
|
||||
EVMaximumCurrentLimit = new PhysicalValueType();
|
||||
EVMaximumCurrentLimit_isUsed = false;
|
||||
EVMaximumPowerLimit = new PhysicalValueType();
|
||||
EVMaximumPowerLimit_isUsed = false;
|
||||
BulkChargingComplete = false;
|
||||
BulkChargingComplete_isUsed = false;
|
||||
ChargingComplete = false;
|
||||
ChargingComplete_isUsed = false;
|
||||
RemainingTimeToFullSoC = new PhysicalValueType();
|
||||
RemainingTimeToFullSoC_isUsed = false;
|
||||
RemainingTimeToBulkSoC = new PhysicalValueType();
|
||||
RemainingTimeToBulkSoC_isUsed = false;
|
||||
EVTargetVoltage = new PhysicalValueType();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DC EV status structure - exact match to iso1DC_EVStatusType
|
||||
/// </summary>
|
||||
public class DC_EVStatusType
|
||||
{
|
||||
public bool EVReady { get; set; }
|
||||
public int EVErrorCode { get; set; } // 4-bit enumeration
|
||||
public int EVRESSSOC { get; set; } // 7-bit (0-100)
|
||||
|
||||
public DC_EVStatusType()
|
||||
{
|
||||
EVReady = false;
|
||||
EVErrorCode = 0;
|
||||
EVRESSSOC = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Universal message body type - matches iso1BodyType
|
||||
/// </summary>
|
||||
public class BodyType
|
||||
{
|
||||
// All possible message types (only one will be used per message)
|
||||
public CurrentDemandReqType CurrentDemandReq { get; set; }
|
||||
public bool CurrentDemandReq_isUsed { get; set; }
|
||||
|
||||
public CurrentDemandResType CurrentDemandRes { get; set; }
|
||||
public bool CurrentDemandRes_isUsed { get; set; }
|
||||
|
||||
public BodyType()
|
||||
{
|
||||
CurrentDemandReq = new CurrentDemandReqType();
|
||||
CurrentDemandReq_isUsed = false;
|
||||
CurrentDemandRes = new CurrentDemandResType();
|
||||
CurrentDemandRes_isUsed = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// V2G Message envelope structure
|
||||
/// </summary>
|
||||
public class V2GMessageExact
|
||||
{
|
||||
public string SessionID { get; set; } = "";
|
||||
public BodyType Body { get; set; }
|
||||
|
||||
public V2GMessageExact()
|
||||
{
|
||||
Body = new BodyType();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user