Compare commits
	
		
			2 Commits
		
	
	
		
			8a718f5d4f
			...
			fdfab0c666
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | fdfab0c666 | ||
|   | f9b17dd7e7 | 
							
								
								
									
										17
									
								
								.claude/settings.local.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								.claude/settings.local.json
									
									
									
									
									
										Normal 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": [] | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										5
									
								
								Data/Dump/01_V2GMSG-SDP_Request.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								Data/Dump/01_V2GMSG-SDP_Request.txt
									
									
									
									
									
										Normal 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                           ........ | ||||||
							
								
								
									
										6
									
								
								Data/Dump/02_V2GMSG-SDP_Response.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Data/Dump/02_V2GMSG-SDP_Response.txt
									
									
									
									
									
										Normal 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                     (...#..!.. | ||||||
							
								
								
									
										8
									
								
								Data/Dump/03-V2GMSG-SAP_SupportedAppProtocolReq.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Data/Dump/03-V2GMSG-SAP_SupportedAppProtocolReq.txt
									
									
									
									
									
										Normal 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@ | ||||||
							
								
								
									
										6
									
								
								Data/Dump/04-V2GMSG-SAP_SupportedAppProtocolRes.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Data/Dump/04-V2GMSG-SAP_SupportedAppProtocolRes.txt
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										15
									
								
								Data/data0.xml
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										7
									
								
								Data/data1.dump
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										22
									
								
								Data/data1.xml
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										7
									
								
								Data/data2.dump
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										22
									
								
								Data/data2.xml
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										16
									
								
								Data/test_decode.xml
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Data/test_output.hex
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										455
									
								
								Program.cs
									
									
									
									
									
								
							
							
						
						
									
										455
									
								
								Program.cs
									
									
									
									
									
								
							| @@ -1,5 +1,7 @@ | |||||||
| using System; | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
| using System.IO; | using System.IO; | ||||||
|  | using System.Linq; | ||||||
|  |  | ||||||
| namespace V2GProtocol | namespace V2GProtocol | ||||||
| { | { | ||||||
| @@ -7,59 +9,438 @@ namespace V2GProtocol | |||||||
|     { |     { | ||||||
|         static void Main(string[] args) |         static void Main(string[] args) | ||||||
|         { |         { | ||||||
|             Console.WriteLine("=== V2G Transfer Protocol Decoder/Encoder ==="); |             // Only show header for help or analysis mode (not for encode/decode operations) | ||||||
|             Console.WriteLine("ISO 15118-2 / DIN SPEC 70121 / SAP Protocol"); |             bool showHeader = false; | ||||||
|             Console.WriteLine(); |              | ||||||
|  |             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 |             try | ||||||
|             { |             { | ||||||
|                 // 기본 데이터 파일 경로 |                 if (args.Length == 0) | ||||||
|                 string dataFilePath = @"data\632 raw data.txt"; |  | ||||||
|                  |  | ||||||
|                 if (args.Length > 0) |  | ||||||
|                 { |                 { | ||||||
|                     dataFilePath = args[0]; |                     ShowUsage(); | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 if (!File.Exists(dataFilePath)) |  | ||||||
|                 { |  | ||||||
|                     Console.WriteLine($"Error: Data file not found: {dataFilePath}"); |  | ||||||
|                     Console.WriteLine("Usage: V2GDecoder.exe [data_file_path]"); |  | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 Console.WriteLine($"Loading data from: {dataFilePath}"); |                 var command = args[0].ToLower(); | ||||||
|                  |                  | ||||||
|                 // 헥스 파일에서 바이너리 데이터 파싱 |                 // 첫 번째 인자가 옵션인 경우 (--decode, --encode, --help) | ||||||
|                 byte[] rawData = V2GDecoder.ParseHexFile(dataFilePath); |                 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(); | ||||||
|                      |                      | ||||||
|                 Console.WriteLine($"Parsed {rawData.Length} bytes from hex file"); |                     if (extension == ".dump" || extension == ".txt") | ||||||
|                 Console.WriteLine(); |                     { | ||||||
|                  |                         // Hex dump files - use full analysis mode | ||||||
|                 // 전체 데이터 헥스 덤프 |                         AnalyzeFile(args[0]); | ||||||
|                 Console.WriteLine("=== Raw Data Hex Dump ==="); |                     } | ||||||
|                 Console.WriteLine(V2GDecoder.BytesToHex(rawData)); |                     else if (extension == ".hex") | ||||||
|                 Console.WriteLine(); |                     { | ||||||
|                  |                         // .hex files - automatically decode to XML | ||||||
|                 // V2G 메시지 디코딩 시도 |                         var autoArgs = new List<string> { "--decode", args[0] }; | ||||||
|                 Console.WriteLine("=== V2G Message Analysis ==="); |                         // Add remaining args (like -out) | ||||||
|                  |                         for (int i = 1; i < args.Length; i++) | ||||||
|                 // 전체 데이터에서 V2G 메시지 찾기 |                             autoArgs.Add(args[i]); | ||||||
|                 AnalyzeV2GMessages(rawData); |                         HandleDecodeCommand(autoArgs.ToArray()); | ||||||
|                  |                     } | ||||||
|                 // 네트워크 패킷 분석 (이더넷/IPv6/TCP 헤더 포함인 경우) |                     else if (extension == ".xml") | ||||||
|                 AnalyzeNetworkPacket(rawData); |                     { | ||||||
|                  |                         // .xml files - automatically encode to EXI | ||||||
|                 Console.WriteLine("\nPress any key to exit..."); |                         var autoArgs = new List<string> { "--encode", args[0] }; | ||||||
|                 Console.ReadKey(); |                         // 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) |             catch (Exception ex) | ||||||
|             { |             { | ||||||
|                 Console.WriteLine($"Error: {ex.Message}"); |                 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) |         static void AnalyzeV2GMessages(byte[] data) | ||||||
|         { |         { | ||||||
|             // V2G Transfer Protocol 시그니처 찾기 |             // V2G Transfer Protocol 시그니처 찾기 | ||||||
|   | |||||||
							
								
								
									
										955
									
								
								V2GDecoder.cs
									
									
									
									
									
								
							
							
						
						
									
										955
									
								
								V2GDecoder.cs
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -8,4 +8,31 @@ | |||||||
|     <AssemblyName>V2GDecoder</AssemblyName> |     <AssemblyName>V2GDecoder</AssemblyName> | ||||||
|   </PropertyGroup> |   </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> | </Project> | ||||||
		Reference in New Issue
	
	Block a user