diff --git a/csharp/dotnet/EXI/EXIEncoderExact.cs b/csharp/dotnet/EXI/EXIEncoderExact.cs
index 24260d3..b5b077c 100644
--- a/csharp/dotnet/EXI/EXIEncoderExact.cs
+++ b/csharp/dotnet/EXI/EXIEncoderExact.cs
@@ -16,11 +16,16 @@ namespace V2GDecoderNet.EXI
{
var stream = new BitOutputStreamExact();
- // Write EXI header (0x80 0x98)
- stream.WriteNBitUnsignedInteger(16, 0x8098);
+ // Write EXI header - exactly like C writeEXIHeader()
+ stream.WriteNBitUnsignedInteger(8, 0x80);
+ stream.WriteNBitUnsignedInteger(8, 0x98);
- // Write V2G message structure
- EncodeV2GMessageStructure(stream, message);
+ // Encode document content - exactly like C encode_iso1ExiDocument
+ // V2G_Message choice = 76 (7-bit)
+ stream.WriteNBitUnsignedInteger(7, 76);
+
+ // Encode V2G_Message content - matches C encode_iso1AnonType_V2G_Message
+ EncodeV2GMessageContent(stream, message);
return stream.ToArray();
}
@@ -31,60 +36,69 @@ namespace V2GDecoderNet.EXI
}
}
- private static void EncodeV2GMessageStructure(BitOutputStreamExact stream, V2GMessageExact message)
+ ///
+ /// Encode V2G_Message content - exact port of C encode_iso1AnonType_V2G_Message
+ ///
+ private static void EncodeV2GMessageContent(BitOutputStreamExact stream, V2GMessageExact message)
{
- // Grammar state 0: Start with V2G_Message
- stream.WriteNBitUnsignedInteger(1, 0); // START_ELEMENT({urn:iso:15118:2:2013:MsgDef}V2G_Message)
-
- // Grammar state 1: Header
- stream.WriteNBitUnsignedInteger(1, 0); // START_ELEMENT({urn:iso:15118:2:2013:MsgHeader}Header)
+ // Grammar state for V2G_Message: Header is mandatory
+ stream.WriteNBitUnsignedInteger(1, 0); // START_ELEMENT(Header)
EncodeMessageHeader(stream, message.SessionID);
- // Grammar state 2: Body
- stream.WriteNBitUnsignedInteger(1, 0); // START_ELEMENT({urn:iso:15118:2:2013:MsgDef}Body)
- EncodeBody(stream, message.Body);
+ // Grammar state: Body is mandatory
+ stream.WriteNBitUnsignedInteger(1, 0); // START_ELEMENT(Body)
+ EncodeBodyType(stream, message.Body);
- // End V2G_Message
- stream.WriteNBitUnsignedInteger(1, 0); // END_ELEMENT
+ // END_ELEMENT for V2G_Message
+ stream.WriteNBitUnsignedInteger(1, 0);
}
+ ///
+ /// Encode MessageHeader - exact port of C encode_iso1MessageHeaderType
+ ///
private static void EncodeMessageHeader(BitOutputStreamExact stream, string sessionId)
{
- // Grammar state for MessageHeaderType
- // START_ELEMENT({urn:iso:15118:2:2013:MsgHeader}SessionID)
- stream.WriteNBitUnsignedInteger(1, 0);
+ // Grammar state for MessageHeaderType: SessionID is mandatory
+ stream.WriteNBitUnsignedInteger(1, 0); // START_ELEMENT(SessionID)
- // SessionID as hex binary
- stream.WriteNBitUnsignedInteger(1, 0); // CHARACTERS[BINARY_HEX]
-
- // Convert hex string to bytes
+ // SessionID encoding - binary hex format exactly like C
+ // Convert hex string to bytes first
byte[] sessionBytes = ConvertHexStringToBytes(sessionId);
- stream.WriteUnsignedInteger(sessionBytes.Length);
+
+ // Encode as binary string (characters[BINARY_HEX])
+ stream.WriteNBitUnsignedInteger(1, 0); // CHARACTERS choice
+ stream.WriteUnsignedInteger((uint)sessionBytes.Length); // Length encoding
+
+ // Write actual bytes
WriteBytes(stream, sessionBytes);
// End SessionID element
- stream.WriteNBitUnsignedInteger(1, 0); // EE
+ stream.WriteNBitUnsignedInteger(1, 0); // END_ELEMENT
- // End Header (no Notification or Signature)
- stream.WriteNBitUnsignedInteger(1, 0); // EE
+ // Grammar allows optional Notification and Signature, but we don't use them
+ // End Header with 2-bit choice for end
+ stream.WriteNBitUnsignedInteger(2, 2); // END_ELEMENT choice (skipping optional elements)
}
- private static void EncodeBody(BitOutputStreamExact stream, BodyType body)
+ ///
+ /// Encode Body content - exact port of C encode_iso1BodyType
+ ///
+ private static void EncodeBodyType(BitOutputStreamExact stream, BodyType body)
{
- // Body type choice - CurrentDemandReq = 13 (6-bit)
+ // Grammar state for Body: 6-bit choice for message type
if (body.CurrentDemandReq_isUsed)
{
- stream.WriteNBitUnsignedInteger(6, 13); // CurrentDemandReq choice
+ // Choice 13 for CurrentDemandReq - exactly like C version
+ stream.WriteNBitUnsignedInteger(6, 13);
EncodeCurrentDemandReqType(stream, body.CurrentDemandReq);
}
- // Add other message types as needed
else
{
throw new Exception("Unsupported message type for encoding");
}
- // End Body
- stream.WriteNBitUnsignedInteger(1, 0); // EE
+ // End Body element - grammar state 3
+ stream.WriteNBitUnsignedInteger(1, 0); // END_ELEMENT
}
private static void EncodeCurrentDemandReqType(BitOutputStreamExact stream, CurrentDemandReqType req)
@@ -127,7 +141,7 @@ namespace V2GDecoderNet.EXI
{
stream.WriteNBitUnsignedInteger(3, 3); // BulkChargingComplete choice
stream.WriteNBitUnsignedInteger(1, 0); // boolean start
- stream.WriteNBitUnsignedInteger(1, req.BulkChargingComplete ? 1u : 0u); // boolean value
+ stream.WriteNBitUnsignedInteger(1, req.BulkChargingComplete ? 1 : 0); // boolean value
stream.WriteNBitUnsignedInteger(1, 0); // EE
EncodeOptionalElements279(stream, req); // Continue to state 279
}
@@ -136,7 +150,7 @@ namespace V2GDecoderNet.EXI
// ChargingComplete (mandatory)
stream.WriteNBitUnsignedInteger(3, 4); // ChargingComplete choice
stream.WriteNBitUnsignedInteger(1, 0); // boolean start
- stream.WriteNBitUnsignedInteger(1, req.ChargingComplete ? 1u : 0u); // boolean value
+ stream.WriteNBitUnsignedInteger(1, req.ChargingComplete ? 1 : 0); // boolean value
stream.WriteNBitUnsignedInteger(1, 0); // EE
EncodeOptionalElements280(stream, req); // Continue to state 280
}
@@ -161,7 +175,7 @@ namespace V2GDecoderNet.EXI
{
stream.WriteNBitUnsignedInteger(3, 2); // BulkChargingComplete
stream.WriteNBitUnsignedInteger(1, 0); // boolean start
- stream.WriteNBitUnsignedInteger(1, req.BulkChargingComplete ? 1u : 0u);
+ stream.WriteNBitUnsignedInteger(1, req.BulkChargingComplete ? 1 : 0);
stream.WriteNBitUnsignedInteger(1, 0); // EE
EncodeOptionalElements279(stream, req);
}
@@ -169,7 +183,7 @@ namespace V2GDecoderNet.EXI
{
stream.WriteNBitUnsignedInteger(3, 3); // ChargingComplete
stream.WriteNBitUnsignedInteger(1, 0); // boolean start
- stream.WriteNBitUnsignedInteger(1, req.ChargingComplete ? 1u : 0u);
+ stream.WriteNBitUnsignedInteger(1, req.ChargingComplete ? 1 : 0);
stream.WriteNBitUnsignedInteger(1, 0); // EE
EncodeOptionalElements280(stream, req);
}
@@ -188,7 +202,7 @@ namespace V2GDecoderNet.EXI
{
stream.WriteNBitUnsignedInteger(2, 1); // BulkChargingComplete
stream.WriteNBitUnsignedInteger(1, 0); // boolean start
- stream.WriteNBitUnsignedInteger(1, req.BulkChargingComplete ? 1u : 0u);
+ stream.WriteNBitUnsignedInteger(1, req.BulkChargingComplete ? 1 : 0);
stream.WriteNBitUnsignedInteger(1, 0); // EE
EncodeOptionalElements279(stream, req);
}
@@ -196,7 +210,7 @@ namespace V2GDecoderNet.EXI
{
stream.WriteNBitUnsignedInteger(2, 2); // ChargingComplete
stream.WriteNBitUnsignedInteger(1, 0); // boolean start
- stream.WriteNBitUnsignedInteger(1, req.ChargingComplete ? 1u : 0u);
+ stream.WriteNBitUnsignedInteger(1, req.ChargingComplete ? 1 : 0);
stream.WriteNBitUnsignedInteger(1, 0); // EE
EncodeOptionalElements280(stream, req);
}
@@ -209,7 +223,7 @@ namespace V2GDecoderNet.EXI
{
stream.WriteNBitUnsignedInteger(1, 0); // BulkChargingComplete
stream.WriteNBitUnsignedInteger(1, 0); // boolean start
- stream.WriteNBitUnsignedInteger(1, req.BulkChargingComplete ? 1u : 0u);
+ stream.WriteNBitUnsignedInteger(1, req.BulkChargingComplete ? 1 : 0);
stream.WriteNBitUnsignedInteger(1, 0); // EE
EncodeOptionalElements279(stream, req);
}
@@ -217,7 +231,7 @@ namespace V2GDecoderNet.EXI
{
stream.WriteNBitUnsignedInteger(1, 1); // ChargingComplete
stream.WriteNBitUnsignedInteger(1, 0); // boolean start
- stream.WriteNBitUnsignedInteger(1, req.ChargingComplete ? 1u : 0u);
+ stream.WriteNBitUnsignedInteger(1, req.ChargingComplete ? 1 : 0);
stream.WriteNBitUnsignedInteger(1, 0); // EE
EncodeOptionalElements280(stream, req);
}
@@ -228,7 +242,7 @@ namespace V2GDecoderNet.EXI
// After BulkChargingComplete - must have ChargingComplete
stream.WriteNBitUnsignedInteger(1, 0); // ChargingComplete
stream.WriteNBitUnsignedInteger(1, 0); // boolean start
- stream.WriteNBitUnsignedInteger(1, req.ChargingComplete ? 1u : 0u);
+ stream.WriteNBitUnsignedInteger(1, req.ChargingComplete ? 1 : 0);
stream.WriteNBitUnsignedInteger(1, 0); // EE
EncodeOptionalElements280(stream, req);
}
@@ -291,19 +305,19 @@ namespace V2GDecoderNet.EXI
// EVReady (mandatory)
stream.WriteNBitUnsignedInteger(1, 0); // START_ELEMENT(EVReady)
stream.WriteNBitUnsignedInteger(1, 0); // boolean start
- stream.WriteNBitUnsignedInteger(1, status.EVReady ? 1u : 0u); // boolean value
+ stream.WriteNBitUnsignedInteger(1, status.EVReady ? 1 : 0); // boolean value
stream.WriteNBitUnsignedInteger(1, 0); // EE
// EVErrorCode (mandatory)
stream.WriteNBitUnsignedInteger(1, 0); // START_ELEMENT(EVErrorCode)
stream.WriteNBitUnsignedInteger(1, 0); // enum start
- stream.WriteNBitUnsignedInteger(4, (uint)status.EVErrorCode); // 4-bit enum value
+ stream.WriteNBitUnsignedInteger(4, (int)status.EVErrorCode); // 4-bit enum value
stream.WriteNBitUnsignedInteger(1, 0); // EE
// EVRESSSOC (mandatory)
stream.WriteNBitUnsignedInteger(1, 0); // START_ELEMENT(EVRESSSOC)
stream.WriteNBitUnsignedInteger(1, 0); // integer start
- stream.WriteNBitUnsignedInteger(7, (uint)status.EVRESSSOC); // 7-bit value (0-100)
+ stream.WriteNBitUnsignedInteger(7, status.EVRESSSOC); // 7-bit value (0-100)
stream.WriteNBitUnsignedInteger(1, 0); // EE
// End DC_EVStatus
@@ -323,7 +337,7 @@ namespace V2GDecoderNet.EXI
// Unit (mandatory)
stream.WriteNBitUnsignedInteger(1, 0); // START_ELEMENT(Unit)
stream.WriteNBitUnsignedInteger(1, 0); // enum start
- stream.WriteNBitUnsignedInteger(3, (uint)value.Unit); // 3-bit enum
+ stream.WriteNBitUnsignedInteger(3, (int)value.Unit); // 3-bit enum
stream.WriteNBitUnsignedInteger(1, 0); // EE
// Value (mandatory)
@@ -397,7 +411,7 @@ namespace V2GDecoderNet.EXI
// Simple CurrentDemandRes encoding for testing
// This is a placeholder - real implementation would need full grammar
- return stream.GetBytes();
+ return stream.ToArray();
}
catch (Exception ex)
{
diff --git a/csharp/dotnet/V2G/EXICodecExact.cs b/csharp/dotnet/V2G/EXICodecExact.cs
index 4e14053..8dbea2e 100644
--- a/csharp/dotnet/V2G/EXICodecExact.cs
+++ b/csharp/dotnet/V2G/EXICodecExact.cs
@@ -44,246 +44,6 @@ namespace V2GDecoderNet.V2G
public static readonly Dictionary RawStringBytes = new Dictionary();
}
- ///
- /// Exact EXI Encoder implementation matching OpenV2G C code
- ///
- public class EXIEncoderExact
- {
- ///
- /// Encode CurrentDemandRes message to EXI - exact implementation
- ///
- public static byte[] EncodeCurrentDemandRes(CurrentDemandResType message)
- {
- if (message == null) throw new ArgumentNullException(nameof(message));
-
- var stream = new BitOutputStreamExact();
-
- try
- {
- // Write EXI header (always 0x80)
- var header = new EXIHeaderExact();
- int result = EXIHeaderEncoderExact.EncodeHeader(stream, header);
- if (result != EXIErrorCodesExact.EXI_OK)
- throw new EXIExceptionExact(result, "Failed to encode EXI header");
-
- // Encode CurrentDemandRes body
- EncodeCurrentDemandResBody(stream, message);
-
- // Flush any remaining bits
- stream.Flush();
-
- return stream.ToArray();
- }
- catch (Exception ex) when (!(ex is EXIExceptionExact))
- {
- throw new EXIExceptionExact(EXIErrorCodesExact.EXI_ERROR_NOT_IMPLEMENTED_YET,
- "Encoding failed", ex);
- }
- }
-
- ///
- /// Encode CurrentDemandRes body - exact grammar state machine implementation
- ///
- private static void EncodeCurrentDemandResBody(BitOutputStreamExact stream, CurrentDemandResType message)
- {
- // Grammar state 317: ResponseCode (5-bit enumeration)
- stream.WriteNBitUnsignedInteger(5, (int)message.ResponseCode);
-
- // Grammar state 318: DC_EVSEStatus (complex type)
- EncodeDC_EVSEStatus(stream, message.DC_EVSEStatus);
-
- // Grammar state 319: EVSEPresentVoltage (PhysicalValue)
- EncodePhysicalValue(stream, message.EVSEPresentVoltage);
-
- // Grammar state 320: EVSEPresentCurrent (PhysicalValue)
- EncodePhysicalValue(stream, message.EVSEPresentCurrent);
-
- // Grammar state 321: EVSECurrentLimitAchieved (boolean)
- stream.WriteBit(message.EVSECurrentLimitAchieved ? 1 : 0);
-
- // Grammar state 322: EVSEVoltageLimitAchieved (boolean)
- stream.WriteBit(message.EVSEVoltageLimitAchieved ? 1 : 0);
-
- // Grammar state 323: EVSEPowerLimitAchieved (boolean)
- stream.WriteBit(message.EVSEPowerLimitAchieved ? 1 : 0);
-
- // Grammar state 324: Optional elements choice (3-bit)
- // Determine which optional elements are present
- bool hasOptionalLimits = message.EVSEMaximumVoltageLimit_isUsed ||
- message.EVSEMaximumCurrentLimit_isUsed ||
- message.EVSEMaximumPowerLimit_isUsed;
-
- if (hasOptionalLimits)
- {
- // Encode optional limits first
- if (message.EVSEMaximumVoltageLimit_isUsed)
- {
- stream.WriteNBitUnsignedInteger(3, 0); // Choice 0: EVSEMaximumVoltageLimit
- EncodePhysicalValue(stream, message.EVSEMaximumVoltageLimit);
- }
- if (message.EVSEMaximumCurrentLimit_isUsed)
- {
- stream.WriteNBitUnsignedInteger(3, 1); // Choice 1: EVSEMaximumCurrentLimit
- EncodePhysicalValue(stream, message.EVSEMaximumCurrentLimit);
- }
- if (message.EVSEMaximumPowerLimit_isUsed)
- {
- stream.WriteNBitUnsignedInteger(3, 2); // Choice 2: EVSEMaximumPowerLimit
- EncodePhysicalValue(stream, message.EVSEMaximumPowerLimit);
- }
- }
-
- // EVSEID is always present (choice 3)
- stream.WriteNBitUnsignedInteger(3, 3); // Choice 3: EVSEID
- EncodeString(stream, message.EVSEID);
-
- // Grammar state 328: SAScheduleTupleID (8-bit, value-1)
- stream.WriteNBitUnsignedInteger(8, message.SAScheduleTupleID - 1);
-
- // Grammar state 329: Final optional elements (2-bit choice)
- if (message.MeterInfo_isUsed)
- {
- stream.WriteNBitUnsignedInteger(2, 0); // Choice 0: MeterInfo
- EncodeMeterInfo(stream, message.MeterInfo);
- }
- if (message.ReceiptRequired_isUsed)
- {
- stream.WriteNBitUnsignedInteger(2, 1); // Choice 1: ReceiptRequired
- stream.WriteBit(message.ReceiptRequired ? 1 : 0);
- }
-
- // Write any additional final data that was preserved during decoding
- if (EXISharedData.RawStringBytes.ContainsKey("ADDITIONAL_FINAL_DATA"))
- {
- stream.WriteNBitUnsignedInteger(2, 3); // Choice 3: Additional data
- byte[] additionalData = EXISharedData.RawStringBytes["ADDITIONAL_FINAL_DATA"];
- Console.WriteLine($"Writing additional final data: {BitConverter.ToString(additionalData)}");
- foreach (byte b in additionalData)
- {
- stream.WriteNBitUnsignedInteger(8, b);
- }
- }
- else
- {
- // End element (choice 2 or implicit)
- stream.WriteNBitUnsignedInteger(2, 2); // Choice 2: END_ELEMENT
- }
- }
-
- ///
- /// Encode DC_EVSEStatus - exact implementation
- ///
- private static void EncodeDC_EVSEStatus(BitOutputStreamExact stream, DC_EVSEStatusType status)
- {
- // NotificationMaxDelay (16-bit unsigned)
- stream.WriteNBitUnsignedInteger(16, status.NotificationMaxDelay);
-
- // EVSENotification (2-bit enumeration)
- stream.WriteNBitUnsignedInteger(2, (int)status.EVSENotification);
-
- // Optional EVSEIsolationStatus
- if (status.EVSEIsolationStatus_isUsed)
- {
- stream.WriteBit(1); // Presence bit
- stream.WriteNBitUnsignedInteger(3, (int)status.EVSEIsolationStatus);
- }
- else
- {
- stream.WriteBit(0); // Not present
- }
-
- // EVSEStatusCode (4-bit enumeration)
- stream.WriteNBitUnsignedInteger(4, (int)status.EVSEStatusCode);
- }
-
- ///
- /// Encode PhysicalValue - exact implementation
- ///
- private static void EncodePhysicalValue(BitOutputStreamExact stream, PhysicalValueType value)
- {
- // Multiplier (3-bit, value + 3)
- stream.WriteNBitUnsignedInteger(3, value.Multiplier + 3);
-
- // Unit (3-bit enumeration)
- stream.WriteNBitUnsignedInteger(3, (int)value.Unit);
-
- // Value (16-bit signed integer)
- // Convert to unsigned for encoding
- ushort unsignedValue = (ushort)value.Value;
- stream.WriteNBitUnsignedInteger(16, unsignedValue);
- }
-
- ///
- /// Encode string - exact implementation matching C string encoding
- ///
- private static void EncodeString(BitOutputStreamExact stream, string value)
- {
- Console.WriteLine($" String encode start - value: '{value}'");
-
- if (string.IsNullOrEmpty(value))
- {
- // Empty string: length = 2 (encoding for length 0)
- stream.WriteUnsignedInteger(2);
- Console.WriteLine($" Encoded empty string");
- }
- else
- {
- byte[] bytesToWrite;
-
- // Check if we have preserved raw bytes for this string
- if (EXISharedData.RawStringBytes.ContainsKey(value))
- {
- bytesToWrite = EXISharedData.RawStringBytes[value];
- Console.WriteLine($" Using preserved raw bytes: {BitConverter.ToString(bytesToWrite)}");
- }
- else
- {
- bytesToWrite = Encoding.UTF8.GetBytes(value);
- Console.WriteLine($" Using UTF-8 encoded bytes: {BitConverter.ToString(bytesToWrite)}");
- }
-
- // String length encoding: actual_length + 2
- stream.WriteUnsignedInteger((uint)(bytesToWrite.Length + 2));
- Console.WriteLine($" Encoded length: {bytesToWrite.Length + 2}");
-
- // String characters
- foreach (byte b in bytesToWrite)
- {
- stream.WriteNBitUnsignedInteger(8, b);
- }
- Console.WriteLine($" String encode complete");
- }
- }
-
- ///
- /// Encode MeterInfo - simplified implementation
- ///
- private static void EncodeMeterInfo(BitOutputStreamExact stream, MeterInfoType meterInfo)
- {
- Console.WriteLine($" Encoding MeterInfo - MeterID: '{meterInfo.MeterID}', MeterReading: {meterInfo.MeterReading}");
-
- // Simplified encoding for MeterInfo
- EncodeString(stream, meterInfo.MeterID);
- stream.WriteUnsignedInteger((long)meterInfo.MeterReading);
-
- // Write the exact remaining bytes from original decoding
- if (EXISharedData.RawStringBytes.ContainsKey("METER_EXACT_REMAINING"))
- {
- byte[] exactBytes = EXISharedData.RawStringBytes["METER_EXACT_REMAINING"];
- Console.WriteLine($" Writing exact MeterInfo remaining bytes: {BitConverter.ToString(exactBytes)}");
- foreach (byte b in exactBytes)
- {
- stream.WriteNBitUnsignedInteger(8, b);
- }
- }
- else
- {
- Console.WriteLine($" No exact MeterInfo remaining bytes found");
- }
-
- // Don't encode MeterStatus separately - it's already included in the additional data
- }
- }
///
/// Exact EXI Decoder implementation matching OpenV2G C code
diff --git a/csharp/dotnet/V2G/V2GMessageProcessor.cs b/csharp/dotnet/V2G/V2GMessageProcessor.cs
index 4a5ed0f..d45e5af 100644
--- a/csharp/dotnet/V2G/V2GMessageProcessor.cs
+++ b/csharp/dotnet/V2G/V2GMessageProcessor.cs
@@ -474,7 +474,7 @@ namespace V2GDecoderNet
var evErrorCode = dcEvStatus.Element(ns4 + "EVErrorCode");
if (evErrorCode != null)
- req.DC_EVStatus.EVErrorCode = (DC_EVErrorCodeType)int.Parse(evErrorCode.Value);
+ req.DC_EVStatus.EVErrorCode = int.Parse(evErrorCode.Value);
var evRessSoc = dcEvStatus.Element(ns4 + "EVRESSSOC");
if (evRessSoc != null)