file 정리
This commit is contained in:
@@ -1,661 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2024 C# Port
|
||||
*
|
||||
* Exact EXI Codec Program - Byte-compatible with OpenV2G C implementation
|
||||
* Produces identical binary output to original C code
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using V2GDecoderNet.EXI;
|
||||
using V2GDecoderNet.V2G;
|
||||
|
||||
namespace V2GDecoderNet
|
||||
{
|
||||
class ProgramExact
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("=== V2GDecoderNet - Exact EXI Codec ===");
|
||||
Console.WriteLine("Byte-compatible C# port of OpenV2G EXI implementation");
|
||||
Console.WriteLine();
|
||||
|
||||
if (args.Length < 1)
|
||||
{
|
||||
ShowUsage();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string command = args[0].ToLower();
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case "decode-exact":
|
||||
if (args.Length < 2)
|
||||
{
|
||||
Console.WriteLine("Error: Input file required for decode-exact command");
|
||||
ShowUsage();
|
||||
return;
|
||||
}
|
||||
DecodeFileExact(args[1], args.Length > 2 ? args[2] : null);
|
||||
break;
|
||||
|
||||
case "encode-exact":
|
||||
if (args.Length < 2)
|
||||
{
|
||||
Console.WriteLine("Error: Input file required for encode-exact command");
|
||||
ShowUsage();
|
||||
return;
|
||||
}
|
||||
EncodeFileExact(args[1], args.Length > 2 ? args[2] : null);
|
||||
break;
|
||||
|
||||
case "test-exact":
|
||||
RunExactRoundtripTest(args.Length > 1 ? args[1] : "../../test1.exi");
|
||||
break;
|
||||
|
||||
case "test-all-exact":
|
||||
TestAllFilesExact();
|
||||
break;
|
||||
|
||||
case "debug-bits":
|
||||
if (args.Length < 2)
|
||||
{
|
||||
Console.WriteLine("Error: debug-bits requires input file");
|
||||
ShowUsage();
|
||||
return;
|
||||
}
|
||||
DebugBitLevel(args[1]);
|
||||
break;
|
||||
|
||||
case "decode-req":
|
||||
if (args.Length < 2)
|
||||
{
|
||||
Console.WriteLine("Error: decode-req requires input file");
|
||||
ShowUsage();
|
||||
return;
|
||||
}
|
||||
DecodeCurrentDemandReqDirect(args[1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
Console.WriteLine($"Error: Unknown command '{command}'");
|
||||
ShowUsage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error: {ex.Message}");
|
||||
if (ex is EXIExceptionExact exiEx)
|
||||
{
|
||||
Console.WriteLine($"EXI Error Code: {exiEx.ErrorCode}");
|
||||
Console.WriteLine($"EXI Error: {EXIExceptionExact.GetErrorMessage(exiEx.ErrorCode)}");
|
||||
}
|
||||
#if DEBUG
|
||||
Console.WriteLine($"Stack Trace: {ex.StackTrace}");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void ShowUsage()
|
||||
{
|
||||
Console.WriteLine("Usage:");
|
||||
Console.WriteLine(" V2GDecoderNet decode-exact <input.exi> [output.xml]");
|
||||
Console.WriteLine(" V2GDecoderNet encode-exact <test-params> [output.exi]");
|
||||
Console.WriteLine(" V2GDecoderNet test-exact [input.exi]");
|
||||
Console.WriteLine(" V2GDecoderNet test-all-exact");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Examples:");
|
||||
Console.WriteLine(" V2GDecoderNet decode-exact test1.exi test1_exact.xml");
|
||||
Console.WriteLine(" V2GDecoderNet test-exact test1.exi");
|
||||
Console.WriteLine(" V2GDecoderNet test-all-exact");
|
||||
}
|
||||
|
||||
static void DecodeFileExact(string inputFile, string? outputFile = null)
|
||||
{
|
||||
Console.WriteLine($"Exact decoding: {inputFile}");
|
||||
|
||||
if (!File.Exists(inputFile))
|
||||
{
|
||||
throw new FileNotFoundException($"Input file not found: {inputFile}");
|
||||
}
|
||||
|
||||
// Read EXI data
|
||||
byte[] exiData = File.ReadAllBytes(inputFile);
|
||||
Console.WriteLine($"Read {exiData.Length} bytes from {inputFile}");
|
||||
|
||||
// Extract EXI body from V2GTP data if present
|
||||
byte[] exiBody = ExtractEXIBody(exiData);
|
||||
|
||||
if (exiBody.Length != exiData.Length)
|
||||
{
|
||||
Console.WriteLine($"Extracted EXI body: {exiBody.Length} bytes (V2GTP header removed)");
|
||||
}
|
||||
|
||||
// Decode using exact EXI decoder
|
||||
var v2gMessage = EXIDecoderExact.DecodeV2GMessage(exiBody);
|
||||
|
||||
// Debug: Print decoded message values
|
||||
Console.WriteLine("\n=== Decoded Message Debug Info ===");
|
||||
if (v2gMessage.Body.CurrentDemandReq_isUsed)
|
||||
{
|
||||
var req = v2gMessage.Body.CurrentDemandReq;
|
||||
Console.WriteLine($"CurrentDemandReq detected:");
|
||||
Console.WriteLine($" EVRESSSOC: {req.DC_EVStatus.EVRESSSOC}");
|
||||
Console.WriteLine($" EVReady: {req.DC_EVStatus.EVReady}");
|
||||
Console.WriteLine($" EVErrorCode: {req.DC_EVStatus.EVErrorCode}");
|
||||
Console.WriteLine($" EVTargetCurrent: Mult={req.EVTargetCurrent.Multiplier}, Unit={req.EVTargetCurrent.Unit}, Value={req.EVTargetCurrent.Value}");
|
||||
Console.WriteLine($" EVMaximumVoltageLimit_isUsed: {req.EVMaximumVoltageLimit_isUsed}");
|
||||
if (req.EVMaximumVoltageLimit_isUsed)
|
||||
Console.WriteLine($" EVMaximumVoltageLimit: Mult={req.EVMaximumVoltageLimit.Multiplier}, Unit={req.EVMaximumVoltageLimit.Unit}, Value={req.EVMaximumVoltageLimit.Value}");
|
||||
Console.WriteLine($" ChargingComplete: {req.ChargingComplete} (isUsed: {req.ChargingComplete_isUsed})");
|
||||
Console.WriteLine($" EVTargetVoltage: Mult={req.EVTargetVoltage.Multiplier}, Unit={req.EVTargetVoltage.Unit}, Value={req.EVTargetVoltage.Value}");
|
||||
}
|
||||
Console.WriteLine("=====================================\n");
|
||||
|
||||
// Convert to XML representation
|
||||
string xmlOutput = MessageToXml(v2gMessage);
|
||||
|
||||
// Determine output file name
|
||||
outputFile ??= Path.ChangeExtension(inputFile, "_exact.xml");
|
||||
|
||||
// Write XML output
|
||||
File.WriteAllText(outputFile, xmlOutput);
|
||||
Console.WriteLine($"XML written to: {outputFile}");
|
||||
Console.WriteLine($"XML size: {xmlOutput.Length} characters");
|
||||
}
|
||||
|
||||
static void EncodeFileExact(string testParams, string? outputFile = null)
|
||||
{
|
||||
Console.WriteLine($"Exact encoding with test parameters: {testParams}");
|
||||
|
||||
// Create test message based on parameters or use default
|
||||
var message = CreateTestMessage();
|
||||
|
||||
// Encode using exact EXI encoder (temporary - needs universal encoder)
|
||||
byte[] exiData = new byte[] { 0x80 }; // TODO: Implement universal encoder
|
||||
|
||||
// Determine output file name
|
||||
outputFile ??= "test_exact_output.exi";
|
||||
|
||||
// Write EXI output
|
||||
File.WriteAllBytes(outputFile, exiData);
|
||||
Console.WriteLine($"EXI written to: {outputFile}");
|
||||
Console.WriteLine($"EXI size: {exiData.Length} bytes");
|
||||
|
||||
// Show hex dump
|
||||
Console.WriteLine("Hex dump:");
|
||||
ShowHexDump(exiData, 0, Math.Min(64, exiData.Length));
|
||||
}
|
||||
|
||||
static void RunExactRoundtripTest(string inputFile)
|
||||
{
|
||||
Console.WriteLine($"Running exact roundtrip test on: {inputFile}");
|
||||
|
||||
if (!File.Exists(inputFile))
|
||||
{
|
||||
throw new FileNotFoundException($"Input file not found: {inputFile}");
|
||||
}
|
||||
|
||||
// Step 1: Read original EXI file
|
||||
byte[] originalExi = File.ReadAllBytes(inputFile);
|
||||
Console.WriteLine($"Original EXI size: {originalExi.Length} bytes");
|
||||
|
||||
// Step 2: Extract EXI body
|
||||
byte[] exiBody = ExtractEXIBody(originalExi);
|
||||
Console.WriteLine($"EXI body size: {exiBody.Length} bytes");
|
||||
|
||||
// Step 3: Decode EXI to message using exact decoder
|
||||
var v2gMessage = EXIDecoderExact.DecodeV2GMessage(exiBody);
|
||||
Console.WriteLine("Decoded EXI to message structure");
|
||||
|
||||
// Step 4: Encode message back to EXI using exact encoder (temporary - needs universal encoder)
|
||||
byte[] newExi = new byte[] { 0x80 }; // TODO: Implement universal encoder
|
||||
Console.WriteLine($"Encoded message to EXI: {newExi.Length} bytes");
|
||||
|
||||
// Step 5: Compare original vs new EXI
|
||||
bool identical = exiBody.SequenceEqual(newExi);
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("=== Exact Roundtrip Test Results ===");
|
||||
Console.WriteLine($"Original EXI body: {exiBody.Length} bytes");
|
||||
Console.WriteLine($"New EXI: {newExi.Length} bytes");
|
||||
Console.WriteLine($"Files identical: {(identical ? "YES ✓" : "NO ✗")}");
|
||||
|
||||
if (!identical)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Differences found:");
|
||||
ShowDifferences(exiBody, newExi);
|
||||
|
||||
// Save files for comparison
|
||||
string originalFile = Path.ChangeExtension(inputFile, "_original_body.exi");
|
||||
string newFile = Path.ChangeExtension(inputFile, "_new_exact.exi");
|
||||
File.WriteAllBytes(originalFile, exiBody);
|
||||
File.WriteAllBytes(newFile, newExi);
|
||||
Console.WriteLine($"Saved original body to: {originalFile}");
|
||||
Console.WriteLine($"Saved new EXI to: {newFile}");
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(identical ? "✓ Exact roundtrip test PASSED" : "✗ Exact roundtrip test FAILED");
|
||||
}
|
||||
|
||||
static void TestAllFilesExact()
|
||||
{
|
||||
Console.WriteLine("Testing all EXI files with exact codec:");
|
||||
|
||||
string[] testFiles = { "test1.exi", "test2.exi", "test3.exi", "test4.exi", "test5.exi" };
|
||||
int passCount = 0;
|
||||
|
||||
foreach (string testFile in testFiles)
|
||||
{
|
||||
string fullPath = Path.Combine("../../", testFile);
|
||||
if (File.Exists(fullPath))
|
||||
{
|
||||
Console.WriteLine($"\n--- Testing {testFile} ---");
|
||||
try
|
||||
{
|
||||
RunExactRoundtripTest(fullPath);
|
||||
passCount++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"FAILED: {ex.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Skipping {testFile} - file not found");
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine($"\n=== Summary: {passCount}/{testFiles.Length} tests passed ===");
|
||||
}
|
||||
|
||||
static CurrentDemandResType CreateTestMessage()
|
||||
{
|
||||
return new CurrentDemandResType
|
||||
{
|
||||
ResponseCode = ResponseCodeType.OK,
|
||||
DC_EVSEStatus = new DC_EVSEStatusType
|
||||
{
|
||||
NotificationMaxDelay = 0,
|
||||
EVSENotification = EVSENotificationType.None,
|
||||
EVSEIsolationStatus = IsolationLevelType.Valid,
|
||||
EVSEIsolationStatus_isUsed = true,
|
||||
EVSEStatusCode = DC_EVSEStatusCodeType.EVSE_Ready
|
||||
},
|
||||
EVSEPresentVoltage = new PhysicalValueType(0, UnitSymbolType.V, 450),
|
||||
EVSEPresentCurrent = new PhysicalValueType(0, UnitSymbolType.A, 5),
|
||||
EVSECurrentLimitAchieved = false,
|
||||
EVSEVoltageLimitAchieved = false,
|
||||
EVSEPowerLimitAchieved = false,
|
||||
EVSEID = "Z",
|
||||
SAScheduleTupleID = 1
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert V2G message to XML format matching C print_iso1_xml_wireshark() exactly
|
||||
/// </summary>
|
||||
static string MessageToXml(V2GMessageExact v2gMessage)
|
||||
{
|
||||
var xml = new System.Text.StringBuilder();
|
||||
|
||||
// XML Header with full namespace declarations (matching C print_xml_header_wireshark)
|
||||
xml.AppendLine(@"<?xml version=""1.0"" encoding=""UTF-8""?>");
|
||||
xml.Append(@"<ns1:V2G_Message xmlns:ns1=""urn:iso:15118:2:2013:MsgDef""");
|
||||
xml.Append(@" xmlns:ns2=""urn:iso:15118:2:2013:MsgHeader""");
|
||||
xml.Append(@" xmlns:ns3=""urn:iso:15118:2:2013:MsgBody""");
|
||||
xml.AppendLine(@" xmlns:ns4=""urn:iso:15118:2:2013:MsgDataTypes"">");
|
||||
|
||||
// Header with SessionID
|
||||
xml.Append("<ns1:Header><ns2:SessionID>");
|
||||
if (!string.IsNullOrEmpty(v2gMessage.SessionID))
|
||||
{
|
||||
xml.Append(v2gMessage.SessionID);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default SessionID like C decoder output
|
||||
xml.Append("4142423030303831");
|
||||
}
|
||||
xml.AppendLine("</ns2:SessionID></ns1:Header>");
|
||||
|
||||
// Body
|
||||
xml.Append("<ns1:Body>");
|
||||
|
||||
if (v2gMessage.Body.CurrentDemandReq_isUsed)
|
||||
{
|
||||
WriteCurrentDemandReqXml(xml, v2gMessage.Body.CurrentDemandReq);
|
||||
}
|
||||
else if (v2gMessage.Body.CurrentDemandRes_isUsed)
|
||||
{
|
||||
WriteCurrentDemandResXml(xml, v2gMessage.Body.CurrentDemandRes);
|
||||
}
|
||||
else
|
||||
{
|
||||
xml.Append("<ns3:Unknown>Message type not recognized</ns3:Unknown>");
|
||||
}
|
||||
|
||||
xml.Append("</ns1:Body>");
|
||||
xml.Append("</ns1:V2G_Message>");
|
||||
|
||||
return xml.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write CurrentDemandReq XML matching C source exactly
|
||||
/// </summary>
|
||||
static void WriteCurrentDemandReqXml(System.Text.StringBuilder xml, CurrentDemandReqType req)
|
||||
{
|
||||
xml.Append("<ns3:CurrentDemandReq>");
|
||||
|
||||
// DC_EVStatus
|
||||
xml.Append("<ns3:DC_EVStatus>");
|
||||
xml.Append($"<ns4:EVReady>{(req.DC_EVStatus.EVReady ? "true" : "false")}</ns4:EVReady>");
|
||||
xml.Append($"<ns4:EVErrorCode>{req.DC_EVStatus.EVErrorCode}</ns4:EVErrorCode>");
|
||||
xml.Append($"<ns4:EVRESSSOC>{req.DC_EVStatus.EVRESSSOC}</ns4:EVRESSSOC>");
|
||||
xml.Append("</ns3:DC_EVStatus>");
|
||||
|
||||
// EVTargetCurrent
|
||||
xml.Append("<ns3:EVTargetCurrent>");
|
||||
xml.Append($"<ns4:Multiplier>{req.EVTargetCurrent.Multiplier}</ns4:Multiplier>");
|
||||
xml.Append($"<ns4:Unit>{(int)req.EVTargetCurrent.Unit}</ns4:Unit>");
|
||||
xml.Append($"<ns4:Value>{req.EVTargetCurrent.Value}</ns4:Value>");
|
||||
xml.Append("</ns3:EVTargetCurrent>");
|
||||
|
||||
// EVMaximumVoltageLimit (optional)
|
||||
if (req.EVMaximumVoltageLimit_isUsed && req.EVMaximumVoltageLimit != null)
|
||||
{
|
||||
xml.Append("<ns3:EVMaximumVoltageLimit>");
|
||||
xml.Append($"<ns4:Multiplier>{req.EVMaximumVoltageLimit.Multiplier}</ns4:Multiplier>");
|
||||
xml.Append($"<ns4:Unit>{(int)req.EVMaximumVoltageLimit.Unit}</ns4:Unit>");
|
||||
xml.Append($"<ns4:Value>{req.EVMaximumVoltageLimit.Value}</ns4:Value>");
|
||||
xml.Append("</ns3:EVMaximumVoltageLimit>");
|
||||
}
|
||||
|
||||
// EVMaximumCurrentLimit (optional)
|
||||
if (req.EVMaximumCurrentLimit_isUsed && req.EVMaximumCurrentLimit != null)
|
||||
{
|
||||
xml.Append("<ns3:EVMaximumCurrentLimit>");
|
||||
xml.Append($"<ns4:Multiplier>{req.EVMaximumCurrentLimit.Multiplier}</ns4:Multiplier>");
|
||||
xml.Append($"<ns4:Unit>{(int)req.EVMaximumCurrentLimit.Unit}</ns4:Unit>");
|
||||
xml.Append($"<ns4:Value>{req.EVMaximumCurrentLimit.Value}</ns4:Value>");
|
||||
xml.Append("</ns3:EVMaximumCurrentLimit>");
|
||||
}
|
||||
|
||||
// EVMaximumPowerLimit (optional)
|
||||
if (req.EVMaximumPowerLimit_isUsed && req.EVMaximumPowerLimit != null)
|
||||
{
|
||||
xml.Append("<ns3:EVMaximumPowerLimit>");
|
||||
xml.Append($"<ns4:Multiplier>{req.EVMaximumPowerLimit.Multiplier}</ns4:Multiplier>");
|
||||
xml.Append($"<ns4:Unit>{(int)req.EVMaximumPowerLimit.Unit}</ns4:Unit>");
|
||||
xml.Append($"<ns4:Value>{req.EVMaximumPowerLimit.Value}</ns4:Value>");
|
||||
xml.Append("</ns3:EVMaximumPowerLimit>");
|
||||
}
|
||||
|
||||
// BulkChargingComplete (optional)
|
||||
if (req.BulkChargingComplete_isUsed)
|
||||
{
|
||||
xml.Append($"<ns3:BulkChargingComplete>{(req.BulkChargingComplete ? "true" : "false")}</ns3:BulkChargingComplete>");
|
||||
}
|
||||
|
||||
// ChargingComplete (always present)
|
||||
xml.Append($"<ns3:ChargingComplete>{(req.ChargingComplete ? "true" : "false")}</ns3:ChargingComplete>");
|
||||
|
||||
// RemainingTimeToFullSoC (optional)
|
||||
if (req.RemainingTimeToFullSoC_isUsed && req.RemainingTimeToFullSoC != null)
|
||||
{
|
||||
xml.Append("<ns3:RemainingTimeToFullSoC>");
|
||||
xml.Append($"<ns4:Multiplier>{req.RemainingTimeToFullSoC.Multiplier}</ns4:Multiplier>");
|
||||
xml.Append($"<ns4:Unit>{(int)req.RemainingTimeToFullSoC.Unit}</ns4:Unit>");
|
||||
xml.Append($"<ns4:Value>{req.RemainingTimeToFullSoC.Value}</ns4:Value>");
|
||||
xml.Append("</ns3:RemainingTimeToFullSoC>");
|
||||
}
|
||||
|
||||
// RemainingTimeToBulkSoC (optional)
|
||||
if (req.RemainingTimeToBulkSoC_isUsed && req.RemainingTimeToBulkSoC != null)
|
||||
{
|
||||
xml.Append("<ns3:RemainingTimeToBulkSoC>");
|
||||
xml.Append($"<ns4:Multiplier>{req.RemainingTimeToBulkSoC.Multiplier}</ns4:Multiplier>");
|
||||
xml.Append($"<ns4:Unit>{(int)req.RemainingTimeToBulkSoC.Unit}</ns4:Unit>");
|
||||
xml.Append($"<ns4:Value>{req.RemainingTimeToBulkSoC.Value}</ns4:Value>");
|
||||
xml.Append("</ns3:RemainingTimeToBulkSoC>");
|
||||
}
|
||||
|
||||
// EVTargetVoltage (must come last according to EXI grammar)
|
||||
if (req.EVTargetVoltage != null)
|
||||
{
|
||||
xml.Append("<ns3:EVTargetVoltage>");
|
||||
xml.Append($"<ns4:Multiplier>{req.EVTargetVoltage.Multiplier}</ns4:Multiplier>");
|
||||
xml.Append($"<ns4:Unit>{(int)req.EVTargetVoltage.Unit}</ns4:Unit>");
|
||||
xml.Append($"<ns4:Value>{req.EVTargetVoltage.Value}</ns4:Value>");
|
||||
xml.Append("</ns3:EVTargetVoltage>");
|
||||
}
|
||||
|
||||
xml.Append("</ns3:CurrentDemandReq>");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write CurrentDemandRes XML matching C source exactly
|
||||
/// </summary>
|
||||
static void WriteCurrentDemandResXml(System.Text.StringBuilder xml, CurrentDemandResType res)
|
||||
{
|
||||
xml.Append("<ns3:CurrentDemandRes>");
|
||||
xml.Append($"<ns3:ResponseCode>{res.ResponseCode}</ns3:ResponseCode>");
|
||||
|
||||
xml.Append("<ns3:DC_EVSEStatus>");
|
||||
xml.Append($"<ns4:EVSEIsolationStatus>{res.DC_EVSEStatus.EVSEIsolationStatus}</ns4:EVSEIsolationStatus>");
|
||||
xml.Append($"<ns4:EVSEStatusCode>{res.DC_EVSEStatus.EVSEStatusCode}</ns4:EVSEStatusCode>");
|
||||
xml.Append("</ns3:DC_EVSEStatus>");
|
||||
|
||||
if (res.EVSEPresentVoltage != null)
|
||||
{
|
||||
xml.Append("<ns3:EVSEPresentVoltage>");
|
||||
xml.Append($"<ns4:Multiplier>{res.EVSEPresentVoltage.Multiplier}</ns4:Multiplier>");
|
||||
xml.Append($"<ns4:Unit>{(int)res.EVSEPresentVoltage.Unit}</ns4:Unit>");
|
||||
xml.Append($"<ns4:Value>{res.EVSEPresentVoltage.Value}</ns4:Value>");
|
||||
xml.Append("</ns3:EVSEPresentVoltage>");
|
||||
}
|
||||
|
||||
if (res.EVSEPresentCurrent != null)
|
||||
{
|
||||
xml.Append("<ns3:EVSEPresentCurrent>");
|
||||
xml.Append($"<ns4:Multiplier>{res.EVSEPresentCurrent.Multiplier}</ns4:Multiplier>");
|
||||
xml.Append($"<ns4:Unit>{(int)res.EVSEPresentCurrent.Unit}</ns4:Unit>");
|
||||
xml.Append($"<ns4:Value>{res.EVSEPresentCurrent.Value}</ns4:Value>");
|
||||
xml.Append("</ns3:EVSEPresentCurrent>");
|
||||
}
|
||||
|
||||
xml.Append($"<ns3:EVSECurrentLimitAchieved>{(res.EVSECurrentLimitAchieved ? "true" : "false")}</ns3:EVSECurrentLimitAchieved>");
|
||||
xml.Append($"<ns3:EVSEVoltageLimitAchieved>{(res.EVSEVoltageLimitAchieved ? "true" : "false")}</ns3:EVSEVoltageLimitAchieved>");
|
||||
xml.Append($"<ns3:EVSEPowerLimitAchieved>{(res.EVSEPowerLimitAchieved ? "true" : "false")}</ns3:EVSEPowerLimitAchieved>");
|
||||
xml.Append($"<ns3:EVSEID>{res.EVSEID}</ns3:EVSEID>");
|
||||
xml.Append($"<ns3:SAScheduleTupleID>{res.SAScheduleTupleID}</ns3:SAScheduleTupleID>");
|
||||
|
||||
xml.Append("</ns3:CurrentDemandRes>");
|
||||
}
|
||||
|
||||
static byte[] ExtractEXIBody(byte[] inputData)
|
||||
{
|
||||
if (inputData == null || inputData.Length < 8)
|
||||
return inputData ?? new byte[0];
|
||||
|
||||
// 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++)
|
||||
{
|
||||
if (inputData[i] == 0x01 && inputData[i + 1] == 0xFE)
|
||||
{
|
||||
ushort payloadType = (ushort)((inputData[i + 2] << 8) | inputData[i + 3]);
|
||||
|
||||
if (payloadType == 0x8001 || payloadType == 0x8002) // V2G_PAYLOAD_ISO_DIN_SAP or 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no V2GTP header found, look for EXI start pattern (0x8098) anywhere in the data
|
||||
for (int i = 0; i <= inputData.Length - 2; i++)
|
||||
{
|
||||
ushort pattern = (ushort)((inputData[i] << 8) | inputData[i + 1]);
|
||||
if (pattern == 0x8098) // EXI_START_PATTERN
|
||||
{
|
||||
// Found EXI start pattern
|
||||
var exiBody = new byte[inputData.Length - i];
|
||||
Array.Copy(inputData, i, exiBody, 0, exiBody.Length);
|
||||
return exiBody;
|
||||
}
|
||||
}
|
||||
|
||||
return inputData;
|
||||
}
|
||||
|
||||
static void ShowDifferences(byte[] original, byte[] newData)
|
||||
{
|
||||
int maxCompare = Math.Min(original.Length, newData.Length);
|
||||
int differences = 0;
|
||||
|
||||
for (int i = 0; i < maxCompare; i++)
|
||||
{
|
||||
if (original[i] != newData[i])
|
||||
{
|
||||
differences++;
|
||||
if (differences <= 10) // Show first 10 differences
|
||||
{
|
||||
Console.WriteLine($" Offset {i:X4}: {original[i]:X2} -> {newData[i]:X2}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (differences > 10)
|
||||
{
|
||||
Console.WriteLine($" ... and {differences - 10} more differences");
|
||||
}
|
||||
|
||||
if (original.Length != newData.Length)
|
||||
{
|
||||
Console.WriteLine($" Size difference: {newData.Length - original.Length} bytes");
|
||||
}
|
||||
}
|
||||
|
||||
static void ShowHexDump(byte[] data, int offset, int length)
|
||||
{
|
||||
for (int i = offset; i < offset + length && i < data.Length; i += 16)
|
||||
{
|
||||
Console.Write($"{i:X4}: ");
|
||||
|
||||
// Show hex bytes
|
||||
for (int j = 0; j < 16 && i + j < data.Length && i + j < offset + length; j++)
|
||||
{
|
||||
Console.Write($"{data[i + j]:X2} ");
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
static void DebugBitLevel(string exiFilePath)
|
||||
{
|
||||
byte[] data = File.ReadAllBytes(exiFilePath);
|
||||
var stream = new BitInputStreamExact(data);
|
||||
|
||||
Console.WriteLine("=== Exact Bit-Level Analysis ===");
|
||||
Console.WriteLine($"Total bytes: {data.Length}");
|
||||
Console.WriteLine($"Hex: {BitConverter.ToString(data)}");
|
||||
|
||||
// Skip EXI header (0x80)
|
||||
int headerByte = stream.ReadNBitUnsignedInteger(8);
|
||||
Console.WriteLine($"EXI Header: 0x{headerByte:X2} at position {stream.Position}, bit {stream.BitPosition}");
|
||||
|
||||
// Start decoding body according to C grammar
|
||||
|
||||
// Grammar state 317: ResponseCode
|
||||
Console.WriteLine($"\n--- Grammar State 317: ResponseCode ---");
|
||||
Console.WriteLine($"Position: {stream.Position}, bit: {stream.BitPosition}");
|
||||
|
||||
// FirstStartTag[START_ELEMENT(ResponseCode)]
|
||||
uint eventCode1 = (uint)stream.ReadNBitUnsignedInteger(1);
|
||||
Console.WriteLine($"Event code 1 (1-bit): {eventCode1} at pos {stream.Position}, bit {stream.BitPosition}");
|
||||
|
||||
if (eventCode1 == 0)
|
||||
{
|
||||
// FirstStartTag[CHARACTERS[ENUMERATION]]
|
||||
uint eventCode2 = (uint)stream.ReadNBitUnsignedInteger(1);
|
||||
Console.WriteLine($"Event code 2 (1-bit): {eventCode2} at pos {stream.Position}, bit {stream.BitPosition}");
|
||||
|
||||
if (eventCode2 == 0)
|
||||
{
|
||||
int responseCode = stream.ReadNBitUnsignedInteger(5);
|
||||
Console.WriteLine($"ResponseCode (5-bit): {responseCode} at pos {stream.Position}, bit {stream.BitPosition}");
|
||||
|
||||
// valid EE for simple element ResponseCode?
|
||||
uint eventCode3 = (uint)stream.ReadNBitUnsignedInteger(1);
|
||||
Console.WriteLine($"Event code 3 (1-bit): {eventCode3} at pos {stream.Position}, bit {stream.BitPosition}");
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine($"\nContinuing to read more data to find alignment...");
|
||||
// Skip ahead to find where we should be
|
||||
for (int i = 0; i < 10 && !stream.IsEndOfStream; i++)
|
||||
{
|
||||
int nextByte = stream.ReadNBitUnsignedInteger(8);
|
||||
Console.WriteLine($"Byte {i}: 0x{nextByte:X2} at pos {stream.Position}, bit {stream.BitPosition}");
|
||||
}
|
||||
}
|
||||
|
||||
static void DecodeCurrentDemandReqDirect(string exiFilePath)
|
||||
{
|
||||
Console.WriteLine("=== Direct CurrentDemandReq Decoding Test ===");
|
||||
|
||||
byte[] data = File.ReadAllBytes(exiFilePath);
|
||||
Console.WriteLine($"Input file: {exiFilePath}, size: {data.Length} bytes");
|
||||
Console.WriteLine($"Hex: {BitConverter.ToString(data)}");
|
||||
|
||||
// Skip EXI header and decode directly as CurrentDemandReq
|
||||
var stream = new BitInputStreamExact(data);
|
||||
|
||||
// Skip EXI header (0x80)
|
||||
int headerByte = stream.ReadNBitUnsignedInteger(8);
|
||||
Console.WriteLine($"EXI Header: 0x{headerByte:X2}");
|
||||
|
||||
try
|
||||
{
|
||||
// Try to decode directly as CurrentDemandReq (grammar state 273)
|
||||
var message = EXIDecoderExact.DecodeCurrentDemandReq(stream);
|
||||
|
||||
Console.WriteLine("\n=== Successfully decoded CurrentDemandReq ===");
|
||||
Console.WriteLine($"DC_EVStatus:");
|
||||
Console.WriteLine($" EVReady: {message.DC_EVStatus.EVReady}");
|
||||
Console.WriteLine($" EVErrorCode: {message.DC_EVStatus.EVErrorCode}");
|
||||
Console.WriteLine($" EVRESSSOC: {message.DC_EVStatus.EVRESSSOC}%");
|
||||
|
||||
Console.WriteLine($"EVTargetCurrent:");
|
||||
Console.WriteLine($" Multiplier: {message.EVTargetCurrent.Multiplier}");
|
||||
Console.WriteLine($" Unit: {message.EVTargetCurrent.Unit}");
|
||||
Console.WriteLine($" Value: {message.EVTargetCurrent.Value}");
|
||||
|
||||
Console.WriteLine($"EVTargetVoltage:");
|
||||
Console.WriteLine($" Multiplier: {message.EVTargetVoltage.Multiplier}");
|
||||
Console.WriteLine($" Unit: {message.EVTargetVoltage.Unit}");
|
||||
Console.WriteLine($" Value: {message.EVTargetVoltage.Value}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"\nDecoding failed: {ex.Message}");
|
||||
Console.WriteLine($"Stack trace: {ex.StackTrace}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v6.0",
|
||||
"signature": ""
|
||||
},
|
||||
"compilationOptions": {},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v6.0": {
|
||||
"V2GDecoderNet/1.0.0": {
|
||||
"runtime": {
|
||||
"V2GDecoderNet.dll": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"V2GDecoderNet/1.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"runtimeOptions": {
|
||||
"tfm": "net6.0",
|
||||
"framework": {
|
||||
"name": "Microsoft.NETCore.App",
|
||||
"version": "6.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -14,7 +14,7 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyCopyrightAttribute("Copyright © 2024")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+fe368f2d23641061368bcd6a69da3991990085d6")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+a6af2aceedb2c7070ea2a26dabfe87180156642a")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("V2GDecoderNet")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("V2GDecoderNet")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
@@ -1 +1 @@
|
||||
f32aa50a95c554c2500fe55755b8877db9aeaf4b42ed47a256d4613dd3873036
|
||||
dc1404d97a6b12c300b7aa3a4da3c2f29b08f0c5428d19fadeb7c8ee3acc2ac4
|
||||
|
||||
@@ -1 +1 @@
|
||||
ad16f80ccd83ad882bbfc2dc135308cc57c1313a1e372ab828e094635a7e4f8f
|
||||
908c1d3d2df67752e93f781d8e0aedd6d0c6f06c41a88a8327628c2394d311a2
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user