feat: Implement C# EXI encoder based on C iso1EXIDatatypesEncoder
- Complete EXI encoder implementation for CurrentDemandReq messages - Uses exact C grammar states and bit patterns - 7-bit choice (76) for V2G_Message document encoding - 6-bit choice (13) for CurrentDemandReq body encoding - Proper grammar state machine following C version - Fixed bit patterns and integer encoding methods - All compilation errors resolved Progress: Basic encoding functionality working, produces 49 bytes vs target 43 bytes Next: Fine-tune to match exact C version byte output 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -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)
|
||||
/// <summary>
|
||||
/// Encode V2G_Message content - exact port of C encode_iso1AnonType_V2G_Message
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode MessageHeader - exact port of C encode_iso1MessageHeaderType
|
||||
/// </summary>
|
||||
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)
|
||||
/// <summary>
|
||||
/// Encode Body content - exact port of C encode_iso1BodyType
|
||||
/// </summary>
|
||||
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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user