Compare commits

..

2 Commits

Author SHA1 Message Date
Arin(asus)
fdfab0c666 Add -out option for file output and fix stdin detection logic
- Add -out/-o option to save decode/encode output to files
- Encoded files are saved as binary, console still shows hex strings
- Decoded XML files are saved as text
- Fix stdin detection logic to prioritize command line arguments
- Add missing System.Collections.Generic import for List<string> usage
- File extension auto-processing now supports -out option
- Clean up data folder with renamed files (data0-3.dump/xml)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-07 15:45:04 +09:00
Arin(asus)
f9b17dd7e7 Add support for pipe input and file extension handling
- Added stdin pipe support for both encode and decode operations
- Implemented file extension-based processing:
  * .dump files: hex dump format with arrow separators
  * .hex files: pure hex string data
  * .xml files: XML content for encoding
- Added 'filename --encode' and 'filename --decode' syntax support
- Enhanced command line parsing for flexible usage
- Updated help text with pipe usage examples

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-07 15:07:31 +09:00
17 changed files with 1505 additions and 67 deletions

View File

@@ -0,0 +1,17 @@
{
"permissions": {
"allow": [
"Bash(dotnet build)",
"Bash(dotnet run:*)",
"Bash(git add:*)",
"Bash(git commit:*)",
"Bash(git push:*)",
"Read(//c/Program Files/Wireshark/plugins/**)",
"WebSearch",
"WebFetch(domain:github.com)",
"Bash(dir data)"
],
"deny": [],
"ask": []
}
}

View File

@@ -0,0 +1,5 @@
0000 33 33 00 00 00 01 10 22 33 44 55 66 86 dd 60 00 33....."3DUf..`.
0010 00 00 00 12 11 ff fe 80 00 00 00 00 00 00 12 22 ..............."
0020 33 ff fe 44 55 66 ff 02 00 00 00 00 00 00 00 00 3..DUf..........
0030 00 00 00 00 00 01 c3 51 3b 0e 00 12 c8 18 01 fe .......Q;.......
0040 90 00 00 00 00 02 10 00 ........

View File

@@ -0,0 +1,6 @@
0000 10 22 33 44 55 66 80 34 28 2e 23 dd 86 dd 60 00 ."3DUf.4(.#...`.
0010 00 00 00 24 11 ff fe 80 00 00 00 00 00 00 82 34 ...$...........4
0020 28 ff fe 2e 23 dd fe 80 00 00 00 00 00 00 12 22 (...#.........."
0030 33 ff fe 44 55 66 3b 0e c3 51 00 24 5e 42 01 fe 3..DUf;..Q.$^B..
0040 90 01 00 00 00 14 fe 80 00 00 00 00 00 00 82 34 ...............4
0050 28 ff fe 2e 23 dd d1 21 10 00 (...#..!..

View File

@@ -0,0 +1,8 @@
0000 80 34 28 2e 23 dd 10 22 33 44 55 66 86 dd 60 00 .4(.#.."3DUf..`.
0010 00 00 00 40 06 ff fe 80 00 00 00 00 00 00 12 22 ...@..........."
0020 33 ff fe 44 55 66 fe 80 00 00 00 00 00 00 82 34 3..DUf.........4
0030 28 ff fe 2e 23 dd c3 65 d1 21 00 63 9b 07 2c c5 (...#..e.!.c..,.
0040 4a 30 50 18 11 1c d4 f8 00 00 01 fe 80 01 00 00 J0P.............
0050 00 24 80 00 eb ab 93 71 d3 4b 9b 79 d1 89 a9 89 .$.....q.K.y....
0060 89 c1 d1 91 d1 91 81 89 99 d2 6b 9b 3a 23 2b 30 ..........k.:#+0
0070 02 00 00 0c 38 40 ....8@

View File

@@ -0,0 +1,6 @@
0000 10 22 33 44 55 66 80 34 28 2e 23 dd 86 dd 60 00 ."3DUf.4(.#...`.
0010 00 00 00 20 06 ff fe 80 00 00 00 00 00 00 82 34 ... ...........4
0020 28 ff fe 2e 23 dd fe 80 00 00 00 00 00 00 12 22 (...#.........."
0030 33 ff fe 44 55 66 d1 21 c3 65 2c c5 4a 30 00 63 3..DUf.!.e,.J0.c
0040 9b 33 50 18 0b 3c 96 5f 00 00 01 fe 80 01 00 00 .3P..<._........
0050 00 04 80 40 00 c0 ...@..

15
Data/data0.xml Normal file
View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<ns1:V2G_Message xmlns:ns1="urn:iso:15118:2:2013:MsgDef" xmlns:ns2="urn:iso:15118:2:2013:MsgHeader" xmlns:ns3="urn:iso:15118:2:2013:MsgBody" xmlns:ns4="urn:iso:15118:2:2013:MsgDataTypes">
<ns1:Header>
<ns2:SessionID>4142423030303831</ns2:SessionID>
</ns1:Header>
<ns1:Body>
<ns3:WeldingDetectionReq>
<ns3:DC_EVStatus>
<ns4:EVReady>true</ns4:EVReady>
<ns4:EVErrorCode>NO_ERROR</ns4:EVErrorCode>
<ns4:EVRESSSOC>100</ns4:EVRESSSOC>
</ns3:DC_EVStatus>
</ns3:WeldingDetectionReq>
</ns1:Body>
</ns1:V2G_Message>

7
Data/data1.dump Normal file
View File

@@ -0,0 +1,7 @@
0000 10 22 33 44 55 66 80 34 28 2e 23 dd 86 dd 60 00 ."3DUf.4(.#...`.
0010 00 00 00 33 06 ff fe 80 00 00 00 00 00 00 82 34 ...3...........4
0020 28 ff fe 2e 23 dd fe 80 00 00 00 00 00 00 12 22 (...#.........."
0030 33 ff fe 44 55 66 d1 21 c3 65 2c c5 4a 3c 00 63 3..DUf.!.e,.J<.c
0040 9b 49 50 18 0b 26 2f bd 00 00 01 fe 80 01 00 00 .IP..&/.........
0050 00 17 80 98 02 10 50 90 8c 0c 0c 0e 0c 51 e0 20 ......P......Q.
0060 25 69 68 c0 c0 c0 c0 c0 80 %ih......

22
Data/data1.xml Normal file
View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<ns1:V2G_Message xmlns:ns1="urn:iso:15118:2:2013:MsgDef" xmlns:ns2="urn:iso:15118:2:2013:MsgHeader" xmlns:ns3="urn:iso:15118:2:2013:MsgBody" xmlns:ns4="urn:iso:15118:2:2013:MsgDataTypes">
<ns1:Header>
<ns2:SessionID>4142423030303831</ns2:SessionID>
</ns1:Header>
<ns1:Body>
<ns3:WeldingDetectionRes>
<ns3:ResponseCode>OK</ns3:ResponseCode>
<ns3:DC_EVSEStatus>
<ns4:NotificationMaxDelay>0</ns4:NotificationMaxDelay>
<ns4:EVSENotification>StopCharging</ns4:EVSENotification>
<ns4:EVSEIsolationStatus>Invalid</ns4:EVSEIsolationStatus>
<ns4:EVSEStatusCode>EVSE_Shutdown</ns4:EVSEStatusCode>
</ns3:DC_EVSEStatus>
<ns3:EVSEPresentVoltage>
<ns4:Multiplier>0</ns4:Multiplier>
<ns4:Unit>V</ns4:Unit>
<ns4:Value>449</ns4:Value>
</ns3:EVSEPresentVoltage>
</ns3:WeldingDetectionRes>
</ns1:Body>
</ns1:V2G_Message>

7
Data/data2.dump Normal file
View File

@@ -0,0 +1,7 @@
0000 80 34 28 2e 23 dd 10 22 33 44 55 66 86 dd 60 00 .4(.#.."3DUf..`.
0010 00 00 00 2c 06 ff fe 80 00 00 00 00 00 00 12 22 ...,..........."
0020 33 ff fe 44 55 66 fe 80 00 00 00 00 00 00 82 34 3..DUf.........4
0030 28 ff fe 2e 23 dd c3 65 d1 21 00 7d 20 74 2c e1 (...#..e.!.} t,.
0040 d2 0a 50 18 11 1c 49 71 00 00 01 fe 80 01 00 00 ..P...Iq........
0050 00 10 80 98 02 10 50 90 8c 0c 0c 0e 0c 52 11 00 ......P......R..
0060 32 00 2.

22
Data/data2.xml Normal file
View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<ns1:V2G_Message xmlns:ns1="urn:iso:15118:2:2013:MsgDef" xmlns:ns2="urn:iso:15118:2:2013:MsgHeader" xmlns:ns3="urn:iso:15118:2:2013:MsgBody" xmlns:ns4="urn:iso:15118:2:2013:MsgDataTypes">
<ns1:Header>
<ns2:SessionID>41424230303038313</ns2:SessionID>
</ns1:Header>
<ns1:Body>
<ns3:PreChargeRes>
<ns3:ResponseCode>OK</ns3:ResponseCode>
<ns3:DC_EVSEStatus>
<ns4:NotificationMaxDelay>0</ns4:NotificationMaxDelay>
<ns4:EVSENotification>None</ns4:EVSENotification>
<ns4:EVSEIsolationStatus>Valid</ns4:EVSEIsolationStatus>
<ns4:EVSEStatusCode>EVSE_Ready</ns4:EVSEStatusCode>
</ns3:DC_EVSEStatus>
<ns3:EVSEPresentVoltage>
<ns4:Multiplier>0</ns4:Multiplier>
<ns4:Unit>V</ns4:Unit>
<ns4:Value>394</ns4:Value>
</ns3:EVSEPresentVoltage>
</ns3:PreChargeRes>
</ns1:Body>
</ns1:V2G_Message>

16
Data/test_decode.xml Normal file
View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<ns1:V2G_Message xmlns:ns1="urn:iso:15118:2:2013:MsgDef" xmlns:ns2="urn:iso:15118:2:2013:MsgHeader" xmlns:ns3="urn:iso:15118:2:2013:MsgBody" xmlns:ns4="urn:iso:15118:2:2013:MsgDataTypes">
<ns1:Header>
<ns2:SessionID>4142423030303831</ns2:SessionID>
</ns1:Header>
<ns1:Body>
<ns3:WeldingDetectionReq>
<ns3:DC_EVStatus>
<ns4:EVReady>True</ns4:EVReady>
<ns4:EVErrorCode>NO_ERROR</ns4:EVErrorCode>
<ns4:EVRESSSOC>100</ns4:EVRESSSOC>
</ns3:DC_EVStatus>
</ns3:WeldingDetectionReq>
</ns1:Body>
</ns1:V2G_Message>

BIN
Data/test_output.hex Normal file

Binary file not shown.

View File

@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace V2GProtocol
{
@@ -7,59 +9,438 @@ namespace V2GProtocol
{
static void Main(string[] args)
{
Console.WriteLine("=== V2G Transfer Protocol Decoder/Encoder ===");
Console.WriteLine("ISO 15118-2 / DIN SPEC 70121 / SAP Protocol");
Console.WriteLine();
// Only show header for help or analysis mode (not for encode/decode operations)
bool showHeader = false;
if (args.Length == 0)
{
showHeader = true;
}
else if (args.Length > 0)
{
string firstArg = args[0].ToLower();
// Check if it's help command
if (firstArg == "--help" || firstArg == "-h")
{
showHeader = true;
}
// Check if it's a file for analysis mode (only .dump/.txt without options)
else if (File.Exists(args[0]) && args.Length == 1)
{
string extension = Path.GetExtension(args[0]).ToLower();
// Only show header for analysis mode (.dump/.txt)
// NOT for auto-conversion (.hex, .xml)
if (extension == ".dump" || extension == ".txt")
{
showHeader = true;
}
// .hex and .xml are auto-conversion, no header
}
}
if (showHeader)
{
Console.WriteLine("=== V2G Transfer Protocol Decoder/Encoder ===");
Console.WriteLine("ISO 15118-2 / DIN SPEC 70121 / SAP Protocol");
Console.WriteLine();
}
try
{
// 기본 데이터 파일 경로
string dataFilePath = @"data\632 raw data.txt";
if (args.Length > 0)
if (args.Length == 0)
{
dataFilePath = args[0];
}
if (!File.Exists(dataFilePath))
{
Console.WriteLine($"Error: Data file not found: {dataFilePath}");
Console.WriteLine("Usage: V2GDecoder.exe [data_file_path]");
ShowUsage();
return;
}
Console.WriteLine($"Loading data from: {dataFilePath}");
var command = args[0].ToLower();
// 헥스 파일에서 바이너리 데이터 파싱
byte[] rawData = V2GDecoder.ParseHexFile(dataFilePath);
Console.WriteLine($"Parsed {rawData.Length} bytes from hex file");
Console.WriteLine();
// 전체 데이터 헥스 덤프
Console.WriteLine("=== Raw Data Hex Dump ===");
Console.WriteLine(V2GDecoder.BytesToHex(rawData));
Console.WriteLine();
// V2G 메시지 디코딩 시도
Console.WriteLine("=== V2G Message Analysis ===");
// 전체 데이터에서 V2G 메시지 찾기
AnalyzeV2GMessages(rawData);
// 네트워크 패킷 분석 (이더넷/IPv6/TCP 헤더 포함인 경우)
AnalyzeNetworkPacket(rawData);
Console.WriteLine("\nPress any key to exit...");
Console.ReadKey();
// 첫 번째 인자가 옵션인 경우 (--decode, --encode, --help)
if (command.StartsWith("--") || command.StartsWith("-"))
{
switch (command)
{
case "--decode" or "-d":
HandleDecodeCommand(args);
break;
case "--encode" or "-e":
HandleEncodeCommand(args);
break;
case "--help" or "-h":
ShowUsage();
break;
default:
Console.WriteLine($"Error: Unknown option: {args[0]}");
ShowUsage();
break;
}
}
// 두 번째 인자가 옵션인 경우 (filename --decode, filename --encode)
else if (args.Length >= 2 && (args[1].ToLower() == "--decode" || args[1].ToLower() == "-d"))
{
// filename --decode 형태 - 나머지 인자들도 전달
var newArgs = new List<string> { args[1], args[0] };
for (int i = 2; i < args.Length; i++)
newArgs.Add(args[i]);
HandleDecodeCommand(newArgs.ToArray());
}
else if (args.Length >= 2 && (args[1].ToLower() == "--encode" || args[1].ToLower() == "-e"))
{
// filename --encode 형태 - 나머지 인자들도 전달
var newArgs = new List<string> { args[1], args[0] };
for (int i = 2; i < args.Length; i++)
newArgs.Add(args[i]);
HandleEncodeCommand(newArgs.ToArray());
}
// 파일명만 전달된 경우 (분석 모드)
else if (File.Exists(args[0]))
{
// Check file extension to determine default action
string extension = Path.GetExtension(args[0]).ToLower();
if (extension == ".dump" || extension == ".txt")
{
// Hex dump files - use full analysis mode
AnalyzeFile(args[0]);
}
else if (extension == ".hex")
{
// .hex files - automatically decode to XML
var autoArgs = new List<string> { "--decode", args[0] };
// Add remaining args (like -out)
for (int i = 1; i < args.Length; i++)
autoArgs.Add(args[i]);
HandleDecodeCommand(autoArgs.ToArray());
}
else if (extension == ".xml")
{
// .xml files - automatically encode to EXI
var autoArgs = new List<string> { "--encode", args[0] };
// Add remaining args (like -out)
for (int i = 1; i < args.Length; i++)
autoArgs.Add(args[i]);
HandleEncodeCommand(autoArgs.ToArray());
}
else
{
// Unknown extension - require explicit option
Console.WriteLine($"Error: Unknown file extension '{extension}'. Please specify operation:");
Console.WriteLine($" {Path.GetFileName(args[0])} --decode # To decode as EXI to XML");
Console.WriteLine($" {Path.GetFileName(args[0])} --encode # To encode as XML to EXI");
Console.WriteLine($" OR use: --decode {args[0]} / --encode {args[0]}");
return;
}
}
else
{
Console.WriteLine($"Error: Unknown option or file not found: {args[0]}");
ShowUsage();
}
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
Console.WriteLine(ex.StackTrace);
}
}
static void ShowUsage()
{
Console.WriteLine("Usage:");
Console.WriteLine(" V2GDecoder.exe [file.dump/.txt] # Analyze hex dump file");
Console.WriteLine(" V2GDecoder.exe [file.hex] # Auto-decode hex to XML");
Console.WriteLine(" V2GDecoder.exe [file.xml] # Auto-encode XML to EXI");
Console.WriteLine(" V2GDecoder.exe --decode <exi_hex_or_file> # Decode EXI to XML");
Console.WriteLine(" V2GDecoder.exe --encode <xml_file_or_string> # Encode XML to EXI");
Console.WriteLine(" V2GDecoder.exe <file> --decode [-out file] # Force decode operation");
Console.WriteLine(" V2GDecoder.exe <file> --encode [-out file] # Force encode operation");
Console.WriteLine(" V2GDecoder.exe --help # Show this help");
Console.WriteLine();
Console.WriteLine("File Extension Auto-Processing:");
Console.WriteLine(" .dump, .txt → Full analysis mode (network + V2G message)");
Console.WriteLine(" .hex → Auto-decode to XML");
Console.WriteLine(" .xml → Auto-encode to EXI hex");
Console.WriteLine(" Other → Requires --decode or --encode option");
Console.WriteLine();
Console.WriteLine("Pipe Usage:");
Console.WriteLine(" type file.xml | V2GDecoder.exe --encode # Pipe XML file to encode");
Console.WriteLine(" echo \"hex_string\" | V2GDecoder.exe --decode # Pipe hex string to decode");
Console.WriteLine();
Console.WriteLine("Examples:");
Console.WriteLine(" V2GDecoder.exe data/dump2.dump # Full analysis of hex dump");
Console.WriteLine(" V2GDecoder.exe data/test.hex # Auto-decode hex to XML");
Console.WriteLine(" V2GDecoder.exe data/encode0.xml # Auto-encode XML to EXI");
Console.WriteLine(" V2GDecoder.exe -d \"8098021050908C0C0C0E0C5211003200\" # Decode hex string");
Console.WriteLine(" V2GDecoder.exe data/test.dat --decode # Decode unknown file type");
Console.WriteLine(" V2GDecoder.exe data/data0.xml -out data0.hex # Encode to binary file");
Console.WriteLine(" V2GDecoder.exe --decode data.hex -out out.xml # Decode to XML file");
Console.WriteLine(" type data\\encode0.xml | V2GDecoder.exe -e # Pipe XML to encode");
}
static string? GetOutputFilename(string[] args)
{
for (int i = 0; i < args.Length - 1; i++)
{
if (args[i].ToLower() == "-out" || args[i].ToLower() == "-o")
{
return args[i + 1];
}
}
return null;
}
static void HandleDecodeCommand(string[] args)
{
string input;
byte[] exiBytes;
string? outputFile = GetOutputFilename(args);
// Check if we have sufficient arguments for file/string input
if (args.Length >= 2)
{
// We have command line arguments, use them
input = args[1];
}
else if (Console.IsInputRedirected)
{
// No sufficient arguments, check if input is coming from stdin (pipe)
input = Console.In.ReadToEnd().Trim();
if (string.IsNullOrEmpty(input))
{
Console.WriteLine("Error: No input data received from stdin");
return;
}
outputFile = null; // Force console output for stdin
}
else
{
Console.WriteLine("Error: EXI hex string or file required for decode operation");
Console.WriteLine("Usage: V2GDecoder.exe --decode <exi_hex_string_or_file> [-out output_file]");
return;
}
// Check if input is a file
if (File.Exists(input))
{
// Handle different file extensions
string extension = Path.GetExtension(input).ToLower();
if (extension == ".dump")
{
// Hex dump file format with arrows (→)
byte[] rawData = V2GDecoder.ParseHexFile(input);
// Find V2G message in the hex dump
var v2gMessage = ExtractV2GMessageFromHexDump(rawData);
if (v2gMessage != null)
{
exiBytes = v2gMessage;
}
else
{
// Try to decode the raw data directly (might be pure EXI without V2G header)
exiBytes = rawData;
}
}
else if (extension == ".hex")
{
// Plain hex file (pure hex string)
string fileContent = File.ReadAllText(input).Trim();
fileContent = fileContent.Replace(" ", "").Replace("-", "").Replace("0x", "").Replace("\n", "").Replace("\r", "");
exiBytes = Convert.FromHexString(fileContent);
}
else if (extension == ".txt")
{
// Legacy support for .txt files - check content format
string fileContent = File.ReadAllText(input).Trim();
if (fileContent.Contains("→"))
{
// Hex dump format
byte[] rawData = V2GDecoder.ParseHexFile(input);
var v2gMessage = ExtractV2GMessageFromHexDump(rawData);
if (v2gMessage != null)
{
exiBytes = v2gMessage;
}
else
{
exiBytes = rawData;
}
}
else
{
// Plain hex
fileContent = fileContent.Replace(" ", "").Replace("-", "").Replace("0x", "").Replace("\n", "").Replace("\r", "");
exiBytes = Convert.FromHexString(fileContent);
}
}
else
{
// Unknown extension, try as plain hex
string fileContent = File.ReadAllText(input).Trim();
fileContent = fileContent.Replace(" ", "").Replace("-", "").Replace("0x", "").Replace("\n", "").Replace("\r", "");
exiBytes = Convert.FromHexString(fileContent);
}
}
else
{
// Direct hex string input
string exiHexString = input.Replace(" ", "").Replace("-", "").Replace("0x", "");
if (exiHexString.Length % 2 != 0)
{
Console.WriteLine("Error: Invalid hex string (odd number of characters)");
return;
}
exiBytes = Convert.FromHexString(exiHexString);
}
try
{
// Decode EXI to XML - output only the XML
var decodedXml = V2GDecoder.DecodeEXIToXML(exiBytes);
if (outputFile != null)
{
// Save to file
File.WriteAllText(outputFile, decodedXml);
Console.WriteLine($"Decoded XML saved to: {outputFile}");
}
else
{
// Output to console
Console.WriteLine(decodedXml);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error decoding EXI: {ex.Message}");
}
}
static byte[]? ExtractV2GMessageFromHexDump(byte[] data)
{
// Find V2G Transfer Protocol signature (0x01FE)
for (int i = 0; i < data.Length - 8; i++)
{
if (data[i] == 0x01 && data[i + 1] == 0xFE)
{
// Get payload length
uint payloadLength = (uint)((data[i + 4] << 24) | (data[i + 5] << 16) | (data[i + 6] << 8) | data[i + 7]);
// Extract EXI payload
if (i + 8 + payloadLength <= data.Length)
{
byte[] exiPayload = new byte[payloadLength];
Array.Copy(data, i + 8, exiPayload, 0, (int)payloadLength);
return exiPayload;
}
}
}
return null;
}
static void HandleEncodeCommand(string[] args)
{
string xmlInput;
string xmlContent;
string? outputFile = GetOutputFilename(args);
// Check if we have sufficient arguments for file/string input
if (args.Length >= 2)
{
// We have command line arguments, use them
xmlInput = args[1];
// Check if input is a file
if (File.Exists(xmlInput))
{
xmlContent = File.ReadAllText(xmlInput);
}
else
{
xmlContent = xmlInput;
}
}
else if (Console.IsInputRedirected)
{
// No sufficient arguments, check if input is coming from stdin (pipe)
xmlContent = Console.In.ReadToEnd().Trim();
if (string.IsNullOrEmpty(xmlContent))
{
Console.WriteLine("Error: No input data received from stdin");
return;
}
outputFile = null; // Force console output for stdin
}
else
{
Console.WriteLine("Error: XML string or file required for encode operation");
Console.WriteLine("Usage: V2GDecoder.exe --encode <xml_file_or_string> [-out output_file]");
return;
}
try
{
// Encode XML to EXI
var exiBytes = V2GDecoder.EncodeXMLToEXI(xmlContent);
if (outputFile != null)
{
// Save as binary file
File.WriteAllBytes(outputFile, exiBytes);
Console.WriteLine($"Encoded binary saved to: {outputFile} ({exiBytes.Length} bytes)");
// Also show hex string on console for reference
var exiHexString = Convert.ToHexString(exiBytes);
Console.WriteLine($"Hex: {exiHexString}");
}
else
{
// Output hex string to console
var exiHexString = Convert.ToHexString(exiBytes);
Console.WriteLine(exiHexString);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error encoding XML: {ex.Message}");
}
}
static void AnalyzeFile(string dataFilePath)
{
if (!File.Exists(dataFilePath))
{
Console.WriteLine($"Error: Data file not found: {dataFilePath}");
return;
}
Console.WriteLine($"Analyzing file: {dataFilePath}");
// 헥스 파일에서 바이너리 데이터 파싱
byte[] rawData = V2GDecoder.ParseHexFile(dataFilePath);
Console.WriteLine($"Parsed {rawData.Length} bytes from hex file");
Console.WriteLine();
// 전체 데이터 헥스 덤프
Console.WriteLine("=== Raw Data Hex Dump ===");
Console.WriteLine(V2GDecoder.BytesToHex(rawData));
Console.WriteLine();
// V2G 메시지 디코딩 시도
Console.WriteLine("=== V2G Message Analysis ===");
// 전체 데이터에서 V2G 메시지 찾기
AnalyzeV2GMessages(rawData);
// 네트워크 패킷 분석 (이더넷/IPv6/TCP 헤더 포함인 경우)
AnalyzeNetworkPacket(rawData);
}
static void AnalyzeV2GMessages(byte[] data)
{
// V2G Transfer Protocol 시그니처 찾기

File diff suppressed because it is too large Load Diff

View File

@@ -8,4 +8,31 @@
<AssemblyName>V2GDecoder</AssemblyName>
</PropertyGroup>
<ItemGroup>
<None Update="Data\2025-05-01_15-23-10_L460_AVM_AA8_3_DC_Charging_LGIT_32KW_T2_20to100_SOC.pcapng">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\dump0.dump">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\dump2.dump">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\dump1.dump">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\encode0.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\encode1.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\encode2.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\Xml.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>