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>
This commit is contained in:
Arin(asus)
2025-09-07 15:45:04 +09:00
parent f9b17dd7e7
commit fdfab0c666
18 changed files with 237 additions and 121 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 ...@..

View File

@@ -1,7 +0,0 @@
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 61 f8 00 63 3..DUf.!.e,.a..c
0040 ae c9 50 18 08 a8 72 51 00 00 01 fe 80 01 00 00 ..P...rQ........
0050 00 17 80 98 02 10 50 90 8c 0c 0c 0e 0c 51 80 00 ......P......Q..
0060 00 00 20 40 c4 08 a0 30 00 .. @...0.

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>

View File

@@ -1 +0,0 @@
8098021050908C0C0C0E0C5211003200

BIN
Data/test_output.hex Normal file

Binary file not shown.

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -7,10 +8,44 @@ namespace V2GProtocol
class Program class Program
{ {
static void Main(string[] args) static void Main(string[] args)
{
// 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("=== V2G Transfer Protocol Decoder/Encoder ===");
Console.WriteLine("ISO 15118-2 / DIN SPEC 70121 / SAP Protocol"); Console.WriteLine("ISO 15118-2 / DIN SPEC 70121 / SAP Protocol");
Console.WriteLine(); Console.WriteLine();
}
try try
{ {
@@ -45,21 +80,59 @@ namespace V2GProtocol
// 두 번째 인자가 옵션인 경우 (filename --decode, filename --encode) // 두 번째 인자가 옵션인 경우 (filename --decode, filename --encode)
else if (args.Length >= 2 && (args[1].ToLower() == "--decode" || args[1].ToLower() == "-d")) else if (args.Length >= 2 && (args[1].ToLower() == "--decode" || args[1].ToLower() == "-d"))
{ {
// filename --decode 형태 // filename --decode 형태 - 나머지 인자들도 전달
string[] newArgs = { args[1], args[0] }; // 순서를 바꿔서 --decode filename 형태로 만듦 var newArgs = new List<string> { args[1], args[0] };
HandleDecodeCommand(newArgs); 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")) else if (args.Length >= 2 && (args[1].ToLower() == "--encode" || args[1].ToLower() == "-e"))
{ {
// filename --encode 형태 // filename --encode 형태 - 나머지 인자들도 전달
string[] newArgs = { args[1], args[0] }; // 순서를 바꿔서 --encode filename 형태로 만듦 var newArgs = new List<string> { args[1], args[0] };
HandleEncodeCommand(newArgs); for (int i = 2; i < args.Length; i++)
newArgs.Add(args[i]);
HandleEncodeCommand(newArgs.ToArray());
} }
// 파일명만 전달된 경우 (분석 모드) // 파일명만 전달된 경우 (분석 모드)
else if (File.Exists(args[0])) 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]); 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 else
{ {
Console.WriteLine($"Error: Unknown option or file not found: {args[0]}"); Console.WriteLine($"Error: Unknown option or file not found: {args[0]}");
@@ -75,71 +148,87 @@ namespace V2GProtocol
static void ShowUsage() static void ShowUsage()
{ {
Console.WriteLine("Usage:"); Console.WriteLine("Usage:");
Console.WriteLine(" V2GDecoder.exe [file.txt] # Analyze hex dump file"); 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 --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 --encode <xml_file_or_string> # Encode XML to EXI");
Console.WriteLine(" V2GDecoder.exe <file> --decode # Decode file content to XML"); Console.WriteLine(" V2GDecoder.exe <file> --decode [-out file] # Force decode operation");
Console.WriteLine(" V2GDecoder.exe <file> --encode # Encode file content to EXI"); Console.WriteLine(" V2GDecoder.exe <file> --encode [-out file] # Force encode operation");
Console.WriteLine(" V2GDecoder.exe --help # Show this help"); Console.WriteLine(" V2GDecoder.exe --help # Show this help");
Console.WriteLine(); 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("Pipe Usage:");
Console.WriteLine(" type file.xml | V2GDecoder.exe --encode # Pipe XML file to encode"); 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(" echo \"hex_string\" | V2GDecoder.exe --decode # Pipe hex string to decode");
Console.WriteLine(); Console.WriteLine();
Console.WriteLine("Examples:"); Console.WriteLine("Examples:");
Console.WriteLine(" V2GDecoder.exe data/dump2.txt # Full analysis"); 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 -d \"8098021050908C0C0C0E0C5211003200\" # Decode hex string");
Console.WriteLine(" V2GDecoder.exe -d data/dump2.txt # Extract & decode from file"); Console.WriteLine(" V2GDecoder.exe data/test.dat --decode # Decode unknown file type");
Console.WriteLine(" V2GDecoder.exe -e \"<V2G_Message>...</V2G_Message>\" # Encode XML string"); Console.WriteLine(" V2GDecoder.exe data/data0.xml -out data0.hex # Encode to binary file");
Console.WriteLine(" V2GDecoder.exe -e message.xml # Encode XML file"); Console.WriteLine(" V2GDecoder.exe --decode data.hex -out out.xml # Decode to XML file");
Console.WriteLine(" V2GDecoder.exe data/encode0.xml --encode # Encode XML file to EXI"); Console.WriteLine(" type data\\encode0.xml | V2GDecoder.exe -e # Pipe XML to encode");
Console.WriteLine(" V2GDecoder.exe data/dump2.txt --decode # Decode file to XML only"); }
Console.WriteLine(" type data\\encode0.xml | V2GDecoder.exe --encode # Pipe file content to encode");
Console.WriteLine(" echo \"8098021050908C0C0C0E0C5211003200\" | V2GDecoder.exe -d # Pipe hex to decode"); 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) static void HandleDecodeCommand(string[] args)
{ {
string input; string input;
byte[] exiBytes; byte[] exiBytes;
string? outputFile = GetOutputFilename(args);
// Check if input is coming from stdin (pipe) // Check if we have sufficient arguments for file/string input
if (args.Length < 2) if (args.Length >= 2)
{ {
if (!Console.IsInputRedirected) // We have command line arguments, use them
{ input = args[1];
Console.WriteLine("Error: EXI hex string or file required for decode operation");
Console.WriteLine("Usage: V2GDecoder.exe --decode <exi_hex_string_or_file>");
Console.WriteLine(" or: echo \"hex_string\" | V2GDecoder.exe --decode");
return;
} }
else if (Console.IsInputRedirected)
// Read from stdin {
Console.WriteLine("Reading EXI data from stdin (pipe input)..."); // No sufficient arguments, check if input is coming from stdin (pipe)
input = Console.In.ReadToEnd().Trim(); input = Console.In.ReadToEnd().Trim();
if (string.IsNullOrEmpty(input)) if (string.IsNullOrEmpty(input))
{ {
Console.WriteLine("Error: No input data received from stdin"); Console.WriteLine("Error: No input data received from stdin");
return; return;
} }
outputFile = null; // Force console output for stdin
} }
else else
{ {
input = args[1]; 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 // Check if input is a file
if (File.Exists(input)) if (File.Exists(input))
{ {
Console.WriteLine($"Reading EXI data from file: {input}");
// Handle different file extensions // Handle different file extensions
string extension = Path.GetExtension(input).ToLower(); string extension = Path.GetExtension(input).ToLower();
if (extension == ".dump") if (extension == ".dump")
{ {
// Hex dump file format with arrows (→) // Hex dump file format with arrows (→)
Console.WriteLine("Processing hex dump format file...");
byte[] rawData = V2GDecoder.ParseHexFile(input); byte[] rawData = V2GDecoder.ParseHexFile(input);
// Find V2G message in the hex dump // Find V2G message in the hex dump
@@ -147,11 +236,9 @@ namespace V2GProtocol
if (v2gMessage != null) if (v2gMessage != null)
{ {
exiBytes = v2gMessage; exiBytes = v2gMessage;
Console.WriteLine($"Extracted V2G EXI message from hex dump ({exiBytes.Length} bytes).");
} }
else else
{ {
Console.WriteLine("Warning: No V2G message header (01 FE) found in hex dump. Attempting to decode raw data.");
// Try to decode the raw data directly (might be pure EXI without V2G header) // Try to decode the raw data directly (might be pure EXI without V2G header)
exiBytes = rawData; exiBytes = rawData;
} }
@@ -159,11 +246,9 @@ namespace V2GProtocol
else if (extension == ".hex") else if (extension == ".hex")
{ {
// Plain hex file (pure hex string) // Plain hex file (pure hex string)
Console.WriteLine("Processing hex string file...");
string fileContent = File.ReadAllText(input).Trim(); string fileContent = File.ReadAllText(input).Trim();
fileContent = fileContent.Replace(" ", "").Replace("-", "").Replace("0x", "").Replace("\n", "").Replace("\r", ""); fileContent = fileContent.Replace(" ", "").Replace("-", "").Replace("0x", "").Replace("\n", "").Replace("\r", "");
exiBytes = Convert.FromHexString(fileContent); exiBytes = Convert.FromHexString(fileContent);
Console.WriteLine($"Parsed hex string from file ({exiBytes.Length} bytes).");
} }
else if (extension == ".txt") else if (extension == ".txt")
{ {
@@ -172,13 +257,11 @@ namespace V2GProtocol
if (fileContent.Contains("→")) if (fileContent.Contains("→"))
{ {
// Hex dump format // Hex dump format
Console.WriteLine("Processing legacy hex dump format file...");
byte[] rawData = V2GDecoder.ParseHexFile(input); byte[] rawData = V2GDecoder.ParseHexFile(input);
var v2gMessage = ExtractV2GMessageFromHexDump(rawData); var v2gMessage = ExtractV2GMessageFromHexDump(rawData);
if (v2gMessage != null) if (v2gMessage != null)
{ {
exiBytes = v2gMessage; exiBytes = v2gMessage;
Console.WriteLine($"Extracted V2G EXI message from hex dump ({exiBytes.Length} bytes).");
} }
else else
{ {
@@ -190,13 +273,11 @@ namespace V2GProtocol
// Plain hex // Plain hex
fileContent = fileContent.Replace(" ", "").Replace("-", "").Replace("0x", "").Replace("\n", "").Replace("\r", ""); fileContent = fileContent.Replace(" ", "").Replace("-", "").Replace("0x", "").Replace("\n", "").Replace("\r", "");
exiBytes = Convert.FromHexString(fileContent); exiBytes = Convert.FromHexString(fileContent);
Console.WriteLine($"Parsed hex string from file ({exiBytes.Length} bytes).");
} }
} }
else else
{ {
// Unknown extension, try as plain hex // Unknown extension, try as plain hex
Console.WriteLine($"Unknown file extension '{extension}', attempting to parse as hex string...");
string fileContent = File.ReadAllText(input).Trim(); string fileContent = File.ReadAllText(input).Trim();
fileContent = fileContent.Replace(" ", "").Replace("-", "").Replace("0x", "").Replace("\n", "").Replace("\r", ""); fileContent = fileContent.Replace(" ", "").Replace("-", "").Replace("0x", "").Replace("\n", "").Replace("\r", "");
exiBytes = Convert.FromHexString(fileContent); exiBytes = Convert.FromHexString(fileContent);
@@ -214,19 +295,25 @@ namespace V2GProtocol
} }
exiBytes = Convert.FromHexString(exiHexString); exiBytes = Convert.FromHexString(exiHexString);
Console.WriteLine("Processing direct hex string input.");
} }
try try
{ {
Console.WriteLine($"Decoding EXI data ({exiBytes.Length} bytes):"); // Decode EXI to XML - output only the XML
Console.WriteLine($"Input: {Convert.ToHexString(exiBytes)}");
Console.WriteLine();
// Decode EXI to XML
var decodedXml = V2GDecoder.DecodeEXIToXML(exiBytes); 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); Console.WriteLine(decodedXml);
} }
}
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"Error decoding EXI: {ex.Message}"); Console.WriteLine($"Error decoding EXI: {ex.Message}");
@@ -259,72 +346,63 @@ namespace V2GProtocol
{ {
string xmlInput; string xmlInput;
string xmlContent; string xmlContent;
string? outputFile = GetOutputFilename(args);
// Check if input is coming from stdin (pipe) // Check if we have sufficient arguments for file/string input
if (args.Length < 2) if (args.Length >= 2)
{ {
if (!Console.IsInputRedirected) // We have command line arguments, use them
xmlInput = args[1];
// Check if input is a file
if (File.Exists(xmlInput))
{ {
Console.WriteLine("Error: XML string or file required for encode operation"); xmlContent = File.ReadAllText(xmlInput);
Console.WriteLine("Usage: V2GDecoder.exe --encode <xml_file_or_string>");
Console.WriteLine(" or: type file.xml | V2GDecoder.exe --encode");
return;
} }
else
// Read from stdin {
Console.WriteLine("Reading XML data from stdin (pipe input)..."); xmlContent = xmlInput;
}
}
else if (Console.IsInputRedirected)
{
// No sufficient arguments, check if input is coming from stdin (pipe)
xmlContent = Console.In.ReadToEnd().Trim(); xmlContent = Console.In.ReadToEnd().Trim();
if (string.IsNullOrEmpty(xmlContent)) if (string.IsNullOrEmpty(xmlContent))
{ {
Console.WriteLine("Error: No input data received from stdin"); Console.WriteLine("Error: No input data received from stdin");
return; return;
} }
outputFile = null; // Force console output for stdin
} }
else else
{ {
xmlInput = args[1]; Console.WriteLine("Error: XML string or file required for encode operation");
Console.WriteLine("Usage: V2GDecoder.exe --encode <xml_file_or_string> [-out output_file]");
// Check if input is a file return;
if (File.Exists(xmlInput))
{
string extension = Path.GetExtension(xmlInput).ToLower();
if (extension == ".xml")
{
Console.WriteLine($"Reading XML from file: {xmlInput}");
xmlContent = File.ReadAllText(xmlInput);
}
else
{
// For non-XML extensions, still try to read as text file
Console.WriteLine($"Reading content from file: {xmlInput} (extension: {extension})");
xmlContent = File.ReadAllText(xmlInput);
}
}
else
{
Console.WriteLine("Processing XML string:");
xmlContent = xmlInput;
}
} }
try try
{ {
Console.WriteLine("Input XML:");
Console.WriteLine(xmlContent);
Console.WriteLine();
// Encode XML to EXI // Encode XML to EXI
var exiBytes = V2GDecoder.EncodeXMLToEXI(xmlContent); 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); var exiHexString = Convert.ToHexString(exiBytes);
Console.WriteLine($"Encoded EXI data ({exiBytes.Length} bytes):");
Console.WriteLine(exiHexString); Console.WriteLine(exiHexString);
}
// Also show formatted hex
Console.WriteLine();
Console.WriteLine("Formatted hex:");
Console.WriteLine(V2GDecoder.BytesToHex(exiBytes));
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -619,13 +619,7 @@ namespace V2GProtocol
{ {
// 메시지 타입 식별 // 메시지 타입 식별
var messageType = IdentifyV2GMessageType(exiPayload); var messageType = IdentifyV2GMessageType(exiPayload);
sb.AppendLine($"Identified Message Type: {messageType.Type}");
sb.AppendLine($"Message Category: {messageType.Category}");
sb.AppendLine($"Message Description: {messageType.Description}");
sb.AppendLine();
sb.AppendLine("Reconstructed XML from EXI binary:");
sb.AppendLine();
sb.AppendLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); sb.AppendLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
sb.AppendLine("<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\">"); sb.AppendLine("<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\">");
@@ -653,17 +647,11 @@ namespace V2GProtocol
sb.AppendLine(" </ns1:Body>"); sb.AppendLine(" </ns1:Body>");
sb.AppendLine("</ns1:V2G_Message>"); sb.AppendLine("</ns1:V2G_Message>");
sb.AppendLine();
sb.AppendLine("=== Message Analysis ===");
sb.AppendLine($"Message Type: {messageType.Type}");
sb.AppendLine($"Session ID: {sessionID}");
sb.AppendLine($"Category: {messageType.Category}");
sb.AppendLine($"Purpose: {messageType.Description}");
} }
catch (Exception ex) catch (Exception ex)
{ {
sb.AppendLine($"Error decoding EXI: {ex.Message}"); // In case of error, return error message
return $"Error decoding EXI: {ex.Message}";
} }
return sb.ToString(); return sb.ToString();