Files
V2GDecoderC/Port/dotnet/Program.cs
chiDT d5263abab0 feat: Perfect C# structure alignment with VC2022 for exact debugging
Major architectural refactoring to achieve 1:1 structural compatibility:

🏗️ **VC2022 Structure Replication**
- Iso1EXIDocument: 1:1 replica of VC2022 iso1EXIDocument struct
- DinEXIDocument: 1:1 replica of VC2022 dinEXIDocument struct
- Iso2EXIDocument: 1:1 replica of VC2022 iso2EXIDocument struct
- All _isUsed flags and Initialize() methods exactly matching VC2022

🔄 **VC2022 Function Porting**
- ParseXmlToIso1(): Exact port of VC2022 parse_xml_to_iso1()
- EncodeIso1ExiDocument(): Exact port of VC2022 encode_iso1ExiDocument()
- Choice 76 (V2G_Message) encoding with identical logic
- BulkChargingComplete ignore behavior preserved

 **Call Sequence Alignment**
- Old: EncodeV2GMessage() → direct EXI encoding
- New: EncodeV2GMessage() → Iso1EXIDocument → EncodeIso1ExiDocument()
- Exact VC2022 call chain: init → parse → encode → finish

🔍 **1:1 Debug Comparison Ready**
- C# exiDoc.V2G_Message_isUsed ↔ VC2022 exiDoc->V2G_Message_isUsed
- Identical structure enables line-by-line debugging comparison
- Ready for precise 1-byte difference investigation (41 vs 42 bytes)

📁 **Project Reorganization**
- Moved from csharp/ to Port/ for cleaner structure
- Port/dotnet/ and Port/vc2022/ for parallel development
- Complete build system and documentation updates

🎯 **Achievement**: 97.6% binary compatibility (41/42 bytes)
Next: 1:1 debug session to identify exact byte difference location

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-10 22:01:08 +09:00

259 lines
9.8 KiB
C#

using System;
using System.IO;
using System.Text;
namespace V2GDecoderNet
{
class Program
{
private const int BUFFER_SIZE = 4096;
// Network protocol patterns and definitions
private const ushort ETH_TYPE_IPV6 = 0x86DD; // Ethernet Type: IPv6
private const byte IPV6_NEXT_HEADER_TCP = 0x06; // IPv6 Next Header: TCP
private const ushort TCP_V2G_PORT = 15118; // V2G communication port
// V2G Transfer Protocol patterns and definitions
private const byte V2G_PROTOCOL_VERSION = 0x01; // Protocol Version
private const byte V2G_INV_PROTOCOL_VERSION = 0xFE; // Inverse Protocol Version
private const ushort V2G_PAYLOAD_ISO_DIN_SAP = 0x8001; // ISO 15118-2/DIN/SAP payload type
private const ushort V2G_PAYLOAD_ISO2 = 0x8002; // ISO 15118-20 payload type
private const ushort EXI_START_PATTERN = 0x8098; // EXI document start pattern
static int Main(string[] args)
{
bool xmlMode = false;
bool encodeMode = false;
string filename = null;
if (args.Length == 1)
{
filename = args[0];
}
else if (args.Length == 2 && args[0] == "-decode")
{
xmlMode = true;
filename = args[1];
}
else if (args.Length == 2 && args[0] == "-encode")
{
encodeMode = true;
filename = args[1];
}
else
{
Console.Error.WriteLine($"Usage: {Environment.GetCommandLineArgs()[0]} [-decode|-encode] input_file");
Console.Error.WriteLine("Enhanced EXI viewer with XML conversion capabilities");
Console.Error.WriteLine(" -decode Convert EXI to Wireshark-style XML format");
Console.Error.WriteLine(" -encode Convert XML to EXI format");
Console.Error.WriteLine(" (default) Analyze EXI with detailed output");
return -1;
}
if (!File.Exists(filename))
{
Console.Error.WriteLine($"Error reading file: {filename}");
return -1;
}
try
{
if (encodeMode)
{
return HandleEncodeMode(filename);
}
else
{
return HandleDecodeOrAnalyzeMode(filename, xmlMode);
}
}
catch (Exception ex)
{
Console.Error.WriteLine($"Error processing file: {ex.Message}");
return -1;
}
}
private static int HandleEncodeMode(string filename)
{
try
{
// Read XML file
string xmlContent = File.ReadAllText(filename, Encoding.UTF8);
// Parse and encode XML to EXI
var exiData = V2GMessageProcessor.EncodeXmlToExi(xmlContent);
if (exiData == null || exiData.Length == 0)
{
Console.Error.WriteLine("Error encoding XML to EXI");
return -1;
}
// Check if output is redirected
bool isRedirected = Console.IsOutputRedirected;
if (isRedirected)
{
// Redirected output: write binary data
var stdout = Console.OpenStandardOutput();
stdout.Write(exiData, 0, exiData.Length);
stdout.Flush();
}
else
{
// Terminal output: show hex string only
foreach (byte b in exiData)
{
Console.Write($"{b:X2}");
}
Console.WriteLine();
}
return 0;
}
catch (Exception ex)
{
Console.Error.WriteLine($"Error encoding to EXI: {ex.Message}");
return -1;
}
}
private static int HandleDecodeOrAnalyzeMode(string filename, bool xmlMode)
{
try
{
// Read EXI file
byte[] buffer = File.ReadAllBytes(filename);
if (!xmlMode)
{
// Analysis mode - show detailed information like C version
Console.WriteLine($"File: {filename} ({buffer.Length} bytes)");
Console.Write("Raw hex data: ");
int displayLength = Math.Min(buffer.Length, 32);
for (int i = 0; i < displayLength; i++)
{
Console.Write($"{buffer[i]:X2} ");
}
if (buffer.Length > 32) Console.Write("...");
Console.WriteLine("\n");
// Analyze data structure
AnalyzeDataStructure(buffer);
}
// Extract EXI body from V2G Transfer Protocol data
byte[] exiBuffer = ExtractExiBody(buffer);
if (exiBuffer.Length != buffer.Length && !xmlMode)
{
Console.WriteLine($"\n=== V2G Transfer Protocol Analysis ===");
Console.WriteLine($"Original size: {buffer.Length} bytes");
Console.WriteLine($"EXI body size: {exiBuffer.Length} bytes");
Console.WriteLine($"Stripped V2GTP header: {buffer.Length - exiBuffer.Length} bytes");
}
// Decode EXI message
var result = V2GMessageProcessor.DecodeExiMessage(exiBuffer);
if (result.Success)
{
if (xmlMode)
{
// XML decode mode - output Wireshark-style XML
Console.WriteLine(result.XmlOutput);
}
else
{
// Analysis mode - show detailed analysis
Console.WriteLine(result.AnalysisOutput);
Console.WriteLine(result.XmlOutput); // Also show XML in analysis mode
}
return 0;
}
else
{
Console.Error.WriteLine($"Error decoding EXI: {result.ErrorMessage}");
return -1;
}
}
catch (Exception ex)
{
Console.Error.WriteLine($"Error processing file: {ex.Message}");
return -1;
}
}
private static void AnalyzeDataStructure(byte[] buffer)
{
Console.WriteLine("=== Data Structure Analysis ===");
Console.WriteLine($"Total size: {buffer.Length} bytes");
if (buffer.Length >= 4)
{
uint firstFourBytes = (uint)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]);
Console.WriteLine($"First 4 bytes: 0x{firstFourBytes:X8}");
}
// Check for EXI start pattern
for (int i = 0; i <= buffer.Length - 2; i++)
{
ushort pattern = (ushort)((buffer[i] << 8) | buffer[i + 1]);
if (pattern == EXI_START_PATTERN)
{
Console.WriteLine($"EXI start pattern (0x{EXI_START_PATTERN:X4}) found at offset: {i}");
Console.WriteLine($"EXI payload size: {buffer.Length - i} bytes");
break;
}
}
// Determine protocol type
if (buffer.Length >= 8 && buffer[0] == V2G_PROTOCOL_VERSION && buffer[1] == V2G_INV_PROTOCOL_VERSION)
{
Console.WriteLine("Protocol: V2G Transfer Protocol detected");
}
else if (buffer.Length >= 2 && ((buffer[0] << 8) | buffer[1]) == EXI_START_PATTERN)
{
Console.WriteLine("Protocol: Direct EXI format");
}
else
{
Console.WriteLine("Protocol: Unknown or Direct EXI");
}
Console.WriteLine();
}
private static byte[] ExtractExiBody(byte[] inputData)
{
if (inputData.Length < 8)
{
// Too small for V2G TP header, assume it's pure EXI
return inputData;
}
// Check for V2GTP header: Version(1) + Inv.Version(1) + PayloadType(2) + PayloadLength(4)
if (inputData[0] == V2G_PROTOCOL_VERSION && inputData[1] == V2G_INV_PROTOCOL_VERSION)
{
// Extract payload type and length
ushort payloadType = (ushort)((inputData[2] << 8) | inputData[3]);
uint payloadLength = (uint)((inputData[4] << 24) | (inputData[5] << 16) | (inputData[6] << 8) | inputData[7]);
if (payloadType == V2G_PAYLOAD_ISO_DIN_SAP || payloadType == V2G_PAYLOAD_ISO2)
{
if (8 + payloadLength <= inputData.Length)
{
byte[] result = new byte[payloadLength];
Array.Copy(inputData, 8, result, 0, (int)payloadLength);
return result;
}
}
}
// Not V2GTP format, return as-is
return inputData;
}
}
}