Compare commits
7 Commits
5ed9b8cdcc
...
d4af6cfc14
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4af6cfc14 | ||
|
|
3c43fa1318 | ||
|
|
2c82751a1a | ||
|
|
22aab10585 | ||
|
|
760eb49afa | ||
|
|
a93ad2b8e5 | ||
|
|
4d9b03e3c5 |
20
build.bat
Normal file
20
build.bat
Normal file
@@ -0,0 +1,20 @@
|
||||
@echo off
|
||||
echo Building enhanced_exi_viewer...
|
||||
|
||||
gcc -o enhanced_exi_viewer enhanced_exi_viewer.c ^
|
||||
src/iso1/*.c ^
|
||||
src/iso2/*.c ^
|
||||
src/din/*.c ^
|
||||
src/codec/*.c ^
|
||||
-I./src/codec ^
|
||||
-I./src/iso1 ^
|
||||
-I./src/iso2 ^
|
||||
-I./src/din
|
||||
|
||||
if %ERRORLEVEL% EQU 0 (
|
||||
echo Build successful! enhanced_exi_viewer.exe created.
|
||||
) else (
|
||||
echo Build failed with error code %ERRORLEVEL%
|
||||
)
|
||||
|
||||
pause
|
||||
@@ -1,76 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int hex_char_to_int(char c) {
|
||||
if (c >= '0' && c <= '9') return c - '0';
|
||||
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main() {
|
||||
const char* hex_string = "8098021050908C0C0C0E0C50E00000002040C40C203030C01400003103D00C0618370105088270095A5A30303030300008";
|
||||
|
||||
size_t hex_len = strlen(hex_string);
|
||||
if (hex_len % 2 != 0) {
|
||||
printf("Error: Hex string length must be even\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t binary_len = hex_len / 2;
|
||||
unsigned char* binary_data = malloc(binary_len);
|
||||
|
||||
if (!binary_data) {
|
||||
printf("Memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Convert hex string to binary
|
||||
for (size_t i = 0; i < binary_len; i++) {
|
||||
int high = hex_char_to_int(hex_string[i * 2]);
|
||||
int low = hex_char_to_int(hex_string[i * 2 + 1]);
|
||||
|
||||
if (high == -1 || low == -1) {
|
||||
printf("Invalid hex character at position %zu\n", i * 2);
|
||||
free(binary_data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
binary_data[i] = (high << 4) | low;
|
||||
}
|
||||
|
||||
// Write to file
|
||||
FILE* file = fopen("test3.exi", "wb");
|
||||
if (!file) {
|
||||
printf("Cannot create output file\n");
|
||||
free(binary_data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t written = fwrite(binary_data, 1, binary_len, file);
|
||||
fclose(file);
|
||||
free(binary_data);
|
||||
|
||||
if (written != binary_len) {
|
||||
printf("Write error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Successfully created test3.exi with %zu bytes\n", binary_len);
|
||||
|
||||
// Show first few bytes for verification
|
||||
printf("First 16 bytes: ");
|
||||
FILE* verify = fopen("test3.exi", "rb");
|
||||
if (verify) {
|
||||
for (int i = 0; i < 16 && i < binary_len; i++) {
|
||||
int c = fgetc(verify);
|
||||
printf("%02X ", c);
|
||||
}
|
||||
fclose(verify);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
create_test3.exe
BIN
create_test3.exe
Binary file not shown.
@@ -1,24 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main() {
|
||||
const char* hex_string = "8098021050908C0C0C0E0C50D10032018600A01881AE0601860C806140C801030800006100001881980600";
|
||||
FILE* file = fopen("test4.exi", "wb");
|
||||
|
||||
if (!file) {
|
||||
printf("Error creating test4.exi\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t len = strlen(hex_string);
|
||||
for (size_t i = 0; i < len; i += 2) {
|
||||
unsigned int byte;
|
||||
sscanf(&hex_string[i], "%2x", &byte);
|
||||
fputc(byte, file);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
printf("test4.exi created successfully (%zu bytes)\n", len/2);
|
||||
return 0;
|
||||
}
|
||||
BIN
create_test4.exe
BIN
create_test4.exe
Binary file not shown.
@@ -1,66 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* EXI codec headers */
|
||||
#include "iso1EXIDatatypes.h"
|
||||
#include "iso1EXIDatatypesEncoder.h"
|
||||
#include "ByteStream.h"
|
||||
|
||||
#define BUFFER_SIZE 1024
|
||||
|
||||
int main() {
|
||||
struct iso1EXIDocument exiDoc;
|
||||
bitstream_t stream;
|
||||
uint8_t buffer[BUFFER_SIZE];
|
||||
size_t pos = 0;
|
||||
int errn = 0;
|
||||
|
||||
/* Initialize EXI document */
|
||||
init_iso1EXIDocument(&exiDoc);
|
||||
|
||||
/* Create a simple V2G message */
|
||||
exiDoc.V2G_Message_isUsed = 1;
|
||||
init_iso1MessageHeaderType(&exiDoc.V2G_Message.Header);
|
||||
|
||||
/* Set session ID to all zeros */
|
||||
memset(exiDoc.V2G_Message.Header.SessionID.bytes, 0, 8);
|
||||
exiDoc.V2G_Message.Header.SessionID.bytesLen = 8;
|
||||
|
||||
/* Create session setup request */
|
||||
exiDoc.V2G_Message.Body.SessionSetupReq_isUsed = 1;
|
||||
init_iso1SessionSetupReqType(&exiDoc.V2G_Message.Body.SessionSetupReq);
|
||||
|
||||
/* Set EVCC ID */
|
||||
strcpy((char*)exiDoc.V2G_Message.Body.SessionSetupReq.EVCCID.bytes, "01");
|
||||
exiDoc.V2G_Message.Body.SessionSetupReq.EVCCID.bytesLen = 2;
|
||||
|
||||
/* Setup output stream */
|
||||
stream.size = BUFFER_SIZE;
|
||||
stream.data = buffer;
|
||||
stream.pos = &pos;
|
||||
stream.buffer = 0;
|
||||
stream.capacity = 8;
|
||||
|
||||
/* Encode to EXI */
|
||||
printf("Encoding V2G message to EXI...\n");
|
||||
errn = encode_iso1ExiDocument(&stream, &exiDoc);
|
||||
|
||||
if (errn != 0) {
|
||||
printf("Encoding failed with error: %d\n", errn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Write to file */
|
||||
FILE *fp = fopen("test_message.exi", "wb");
|
||||
if (fp == NULL) {
|
||||
printf("Cannot create output file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fwrite(buffer, 1, pos, fp);
|
||||
fclose(fp);
|
||||
|
||||
printf("Created test_message.exi with %zu bytes\n", pos);
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -2,6 +2,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* EXI codec headers */
|
||||
#include "iso1EXIDatatypes.h"
|
||||
@@ -17,6 +19,205 @@
|
||||
|
||||
#define BUFFER_SIZE 4096
|
||||
|
||||
// Network protocol patterns and definitions
|
||||
#define ETH_TYPE_IPV6 0x86DD // Ethernet Type: IPv6
|
||||
#define IPV6_NEXT_HEADER_TCP 0x06 // IPv6 Next Header: TCP
|
||||
#define TCP_V2G_PORT 15118 // V2G communication port
|
||||
|
||||
// V2G Transfer Protocol patterns and definitions
|
||||
#define V2G_PROTOCOL_VERSION 0x01 // Protocol Version
|
||||
#define V2G_INV_PROTOCOL_VERSION 0xFE // Inverse Protocol Version
|
||||
#define V2G_PAYLOAD_ISO_DIN_SAP 0x8001 // ISO 15118-2/DIN/SAP payload type
|
||||
#define V2G_PAYLOAD_ISO2 0x8002 // ISO 15118-20 payload type
|
||||
#define EXI_START_PATTERN 0x8098 // EXI document start pattern
|
||||
|
||||
// Function to detect and extract EXI body from V2G Transfer Protocol data
|
||||
size_t extract_exi_body(uint8_t* input_data, size_t input_size, uint8_t* output_data, size_t output_size) {
|
||||
if (input_size < 8) {
|
||||
// Too small for V2G TP header, assume it's pure EXI
|
||||
if (input_size <= output_size) {
|
||||
memcpy(output_data, input_data, input_size);
|
||||
return input_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check for V2G Transfer Protocol header
|
||||
if (input_data[0] == V2G_PROTOCOL_VERSION && input_data[1] == V2G_INV_PROTOCOL_VERSION) {
|
||||
uint16_t payload_type = (input_data[2] << 8) | input_data[3];
|
||||
|
||||
if (payload_type == V2G_PAYLOAD_ISO_DIN_SAP || payload_type == V2G_PAYLOAD_ISO2) {
|
||||
// Valid V2G TP header detected: skip 8-byte header
|
||||
size_t exi_size = input_size - 8;
|
||||
if (exi_size <= output_size) {
|
||||
memcpy(output_data, input_data + 8, exi_size);
|
||||
return exi_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Look for EXI start pattern anywhere in the data
|
||||
for (size_t i = 0; i <= input_size - 2; i++) {
|
||||
uint16_t pattern = (input_data[i] << 8) | input_data[i + 1];
|
||||
if (pattern == EXI_START_PATTERN) {
|
||||
// Found EXI start pattern
|
||||
size_t exi_size = input_size - i;
|
||||
if (exi_size <= output_size) {
|
||||
memcpy(output_data, input_data + i, exi_size);
|
||||
return exi_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// No pattern found, assume it's pure EXI
|
||||
if (input_size <= output_size) {
|
||||
memcpy(output_data, input_data, input_size);
|
||||
return input_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Function to get payload type name
|
||||
const char* get_payload_type_name(uint16_t payload_type) {
|
||||
switch(payload_type) {
|
||||
case V2G_PAYLOAD_ISO_DIN_SAP: return "ISO 15118-2/DIN/SAP";
|
||||
case V2G_PAYLOAD_ISO2: return "ISO 15118-20";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
// Function to analyze complete packet structure
|
||||
void analyze_data_structure(uint8_t* data, size_t size) {
|
||||
printf("=== Data Structure Analysis ===\n");
|
||||
printf("Total size: %zu bytes\n", size);
|
||||
|
||||
size_t offset = 0;
|
||||
|
||||
// Check for Ethernet header (at least 14 bytes)
|
||||
if (size >= 14) {
|
||||
uint16_t eth_type = (data[12] << 8) | data[13];
|
||||
if (eth_type == ETH_TYPE_IPV6) {
|
||||
printf("Layer 2: Ethernet Frame\n");
|
||||
printf(" Destination MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
data[0], data[1], data[2], data[3], data[4], data[5]);
|
||||
printf(" Source MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
data[6], data[7], data[8], data[9], data[10], data[11]);
|
||||
printf(" EtherType: 0x%04x (IPv6)\n", eth_type);
|
||||
offset = 14;
|
||||
|
||||
// Check for IPv6 header (40 bytes)
|
||||
if (size >= offset + 40) {
|
||||
uint8_t version = (data[offset] >> 4) & 0x0F;
|
||||
uint16_t payload_length = (data[offset + 4] << 8) | data[offset + 5];
|
||||
uint8_t next_header = data[offset + 6];
|
||||
uint8_t hop_limit = data[offset + 7];
|
||||
|
||||
if (version == 6) {
|
||||
printf("Layer 3: IPv6 Header\n");
|
||||
printf(" Version: %d\n", version);
|
||||
printf(" Payload Length: %u\n", payload_length);
|
||||
printf(" Next Header: %u", next_header);
|
||||
if (next_header == IPV6_NEXT_HEADER_TCP) {
|
||||
printf(" (TCP)\n");
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
printf(" Hop Limit: %u\n", hop_limit);
|
||||
|
||||
// Show IPv6 addresses
|
||||
printf(" Source Address: ");
|
||||
for (int i = 0; i < 16; i += 2) {
|
||||
printf("%02x%02x", data[offset + 8 + i], data[offset + 8 + i + 1]);
|
||||
if (i < 14) printf(":");
|
||||
}
|
||||
printf("\n Destination Address: ");
|
||||
for (int i = 0; i < 16; i += 2) {
|
||||
printf("%02x%02x", data[offset + 24 + i], data[offset + 24 + i + 1]);
|
||||
if (i < 14) printf(":");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
offset += 40;
|
||||
|
||||
// Check for TCP header (at least 20 bytes)
|
||||
if (next_header == IPV6_NEXT_HEADER_TCP && size >= offset + 20) {
|
||||
uint16_t src_port = (data[offset] << 8) | data[offset + 1];
|
||||
uint16_t dst_port = (data[offset + 2] << 8) | data[offset + 3];
|
||||
uint32_t seq_num = (data[offset + 4] << 24) | (data[offset + 5] << 16) |
|
||||
(data[offset + 6] << 8) | data[offset + 7];
|
||||
uint8_t tcp_header_len = (data[offset + 12] >> 4) * 4;
|
||||
|
||||
printf("Layer 4: TCP Header\n");
|
||||
printf(" Source Port: %u\n", src_port);
|
||||
printf(" Destination Port: %u", dst_port);
|
||||
if (dst_port == TCP_V2G_PORT || src_port == TCP_V2G_PORT) {
|
||||
printf(" (V2G Communication)\n");
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
printf(" Sequence Number: %u\n", seq_num);
|
||||
printf(" TCP Header Length: %u bytes\n", tcp_header_len);
|
||||
|
||||
offset += tcp_header_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Look for V2G Transfer Protocol starting from current offset
|
||||
if (size >= offset + 8 &&
|
||||
data[offset] == V2G_PROTOCOL_VERSION &&
|
||||
data[offset + 1] == V2G_INV_PROTOCOL_VERSION) {
|
||||
|
||||
printf("Layer 7: V2G Transfer Protocol\n");
|
||||
printf(" Protocol Version: 0x%02x\n", data[offset]);
|
||||
printf(" Inverse Protocol Version: 0x%02x\n", data[offset + 1]);
|
||||
|
||||
uint16_t payload_type = (data[offset + 2] << 8) | data[offset + 3];
|
||||
printf(" Payload Type: 0x%04x (%s)\n", payload_type, get_payload_type_name(payload_type));
|
||||
|
||||
uint32_t payload_length = (data[offset + 4] << 24) | (data[offset + 5] << 16) |
|
||||
(data[offset + 6] << 8) | data[offset + 7];
|
||||
printf(" Payload Length: %u\n", payload_length);
|
||||
printf("EXI body starts at offset: %zu\n", offset + 8);
|
||||
|
||||
// Verify payload length
|
||||
if (size >= offset + 8 && (size - offset - 8) == payload_length) {
|
||||
printf("✓ Payload length matches actual data (%zu bytes)\n", size - offset - 8);
|
||||
} else if (size >= offset + 8) {
|
||||
printf("⚠ Payload length mismatch: expected %u, got %zu bytes\n",
|
||||
payload_length, size - offset - 8);
|
||||
}
|
||||
|
||||
offset += 8;
|
||||
}
|
||||
else if (offset == 0) {
|
||||
// No network headers detected, check if it's direct V2G TP or EXI
|
||||
if (size >= 4) {
|
||||
uint32_t header = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
|
||||
printf("First 4 bytes: 0x%08X\n", header);
|
||||
printf("Protocol: Unknown or Direct EXI\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Look for EXI pattern
|
||||
for (size_t i = 0; i <= size - 2; i++) {
|
||||
uint16_t pattern = (data[i] << 8) | data[i + 1];
|
||||
if (pattern == EXI_START_PATTERN) {
|
||||
printf("EXI start pattern (0x8098) found at offset: %zu\n", i);
|
||||
if (i >= offset) {
|
||||
printf("EXI payload size: %zu bytes\n", size - i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Helper function to convert char* string to exi_string_character_t* array
|
||||
static int writeStringToEXIString(char* string, exi_string_character_t* exiString) {
|
||||
int pos = 0;
|
||||
@@ -37,25 +238,60 @@ char* trim_whitespace(char* str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
// Helper function to find XML tag content within a bounded section
|
||||
// Helper function to find XML tag content within a bounded section (namespace-aware)
|
||||
char* find_tag_in_section(const char* section_start, const char* section_end, const char* tag) {
|
||||
static char result[1024];
|
||||
char start_tag[256], end_tag[256];
|
||||
snprintf(start_tag, sizeof(start_tag), "<%s>", tag);
|
||||
snprintf(end_tag, sizeof(end_tag), "</%s>", tag);
|
||||
char ns_pattern[256];
|
||||
char* content_start = NULL;
|
||||
char* tag_end = NULL;
|
||||
|
||||
// Search for tag within the bounded section
|
||||
char* tag_start = strstr(section_start, start_tag);
|
||||
if (!tag_start || tag_start >= section_end) {
|
||||
// First try namespace pattern (:tag>)
|
||||
snprintf(ns_pattern, sizeof(ns_pattern), ":%s>", tag);
|
||||
char* ns_tag = section_start;
|
||||
while ((ns_tag = strstr(ns_tag, ns_pattern)) != NULL && ns_tag < section_end) {
|
||||
// Find the opening '<'
|
||||
char* tag_begin = ns_tag;
|
||||
while (tag_begin > section_start && *tag_begin != '<') tag_begin--;
|
||||
if (*tag_begin == '<' && tag_begin >= section_start) {
|
||||
content_start = ns_tag + strlen(ns_pattern);
|
||||
break;
|
||||
}
|
||||
ns_tag++;
|
||||
}
|
||||
|
||||
// If namespace version not found, try regular version
|
||||
if (!content_start) {
|
||||
char start_tag[256];
|
||||
snprintf(start_tag, sizeof(start_tag), "<%s>", tag);
|
||||
char* tag_start = strstr(section_start, start_tag);
|
||||
if (tag_start && tag_start < section_end) {
|
||||
content_start = tag_start + strlen(start_tag);
|
||||
}
|
||||
}
|
||||
|
||||
if (!content_start || content_start >= section_end) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* content_start = tag_start + strlen(start_tag);
|
||||
if (content_start >= section_end) {
|
||||
return NULL;
|
||||
// Look for end tag (try both patterns)
|
||||
char end_tag_pattern[256];
|
||||
snprintf(end_tag_pattern, sizeof(end_tag_pattern), "</%s>", tag);
|
||||
tag_end = strstr(content_start, end_tag_pattern);
|
||||
if (!tag_end || tag_end > section_end) {
|
||||
// Try namespace end pattern
|
||||
snprintf(ns_pattern, sizeof(ns_pattern), ":%s>", tag);
|
||||
char* ns_end = content_start;
|
||||
while ((ns_end = strstr(ns_end, ns_pattern)) != NULL && ns_end < section_end) {
|
||||
char* end_begin = ns_end;
|
||||
while (end_begin > content_start && *end_begin != '<') end_begin--;
|
||||
if (end_begin > content_start && *end_begin == '<' && *(end_begin + 1) == '/') {
|
||||
tag_end = end_begin;
|
||||
break;
|
||||
}
|
||||
ns_end++;
|
||||
}
|
||||
}
|
||||
|
||||
char* tag_end = strstr(content_start, end_tag);
|
||||
if (!tag_end || tag_end > section_end) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -66,13 +302,81 @@ char* find_tag_in_section(const char* section_start, const char* section_end, co
|
||||
strncpy(result, content_start, len);
|
||||
result[len] = '\0';
|
||||
|
||||
char* trimmed = trim_whitespace(result);
|
||||
return trimmed;
|
||||
return trim_whitespace(result);
|
||||
}
|
||||
|
||||
// Helper function to find XML tag content (namespace-aware)
|
||||
char* find_tag_content_ns(const char* xml, const char* tag) {
|
||||
static char result[1024];
|
||||
char ns_pattern[256], end_pattern[256];
|
||||
|
||||
// Look for pattern ":tagname>" to handle namespaces
|
||||
snprintf(ns_pattern, sizeof(ns_pattern), ":%s>", tag);
|
||||
snprintf(end_pattern, sizeof(end_pattern), "</%s>", tag);
|
||||
|
||||
// First try to find namespace version (:tag>)
|
||||
char* ns_start = strstr(xml, ns_pattern);
|
||||
char* start = NULL;
|
||||
|
||||
if (ns_start) {
|
||||
// Found namespaced tag, find the opening '<'
|
||||
char* tag_begin = ns_start;
|
||||
while (tag_begin > xml && *tag_begin != '<') tag_begin--;
|
||||
if (*tag_begin == '<') {
|
||||
start = ns_start + strlen(ns_pattern);
|
||||
}
|
||||
}
|
||||
|
||||
// If namespace version not found, try regular version
|
||||
if (!start) {
|
||||
char start_tag[256];
|
||||
snprintf(start_tag, sizeof(start_tag), "<%s>", tag);
|
||||
char* regular_start = strstr(xml, start_tag);
|
||||
if (regular_start) {
|
||||
start = regular_start + strlen(start_tag);
|
||||
}
|
||||
}
|
||||
|
||||
if (!start) return NULL;
|
||||
|
||||
// Look for end tag (try both namespaced and regular)
|
||||
char ns_end_pattern[256];
|
||||
snprintf(ns_end_pattern, sizeof(ns_end_pattern), "</%s>", tag);
|
||||
|
||||
char* end = strstr(start, ns_end_pattern);
|
||||
if (!end) {
|
||||
// Try with different namespace prefix
|
||||
snprintf(ns_end_pattern, sizeof(ns_end_pattern), ":%s>", tag);
|
||||
char* ns_end = strstr(start, ns_end_pattern);
|
||||
if (ns_end) {
|
||||
char* end_tag_begin = ns_end;
|
||||
while (end_tag_begin > start && *end_tag_begin != '<') end_tag_begin--;
|
||||
if (*end_tag_begin == '<' && *(end_tag_begin + 1) == '/') {
|
||||
end = ns_end + strlen(ns_end_pattern);
|
||||
// Backtrack to find the actual end
|
||||
end = end_tag_begin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!end) return NULL;
|
||||
|
||||
size_t len = end - start;
|
||||
if (len >= sizeof(result)) len = sizeof(result) - 1;
|
||||
|
||||
strncpy(result, start, len);
|
||||
result[len] = '\0';
|
||||
return trim_whitespace(result);
|
||||
}
|
||||
|
||||
// Helper function to find XML tag content
|
||||
char* find_tag_content(const char* xml, const char* tag) {
|
||||
static char result[1024];
|
||||
// First try namespace-aware search
|
||||
char* result = find_tag_content_ns(xml, tag);
|
||||
if (result) return result;
|
||||
|
||||
// Fallback to original method
|
||||
static char fallback_result[1024];
|
||||
char start_tag[256], end_tag[256];
|
||||
snprintf(start_tag, sizeof(start_tag), "<%s>", tag);
|
||||
snprintf(end_tag, sizeof(end_tag), "</%s>", tag);
|
||||
@@ -85,11 +389,11 @@ char* find_tag_content(const char* xml, const char* tag) {
|
||||
if (!end) return NULL;
|
||||
|
||||
size_t len = end - start;
|
||||
if (len >= sizeof(result)) len = sizeof(result) - 1;
|
||||
if (len >= sizeof(fallback_result)) len = sizeof(fallback_result) - 1;
|
||||
|
||||
strncpy(result, start, len);
|
||||
result[len] = '\0';
|
||||
return trim_whitespace(result);
|
||||
strncpy(fallback_result, start, len);
|
||||
fallback_result[len] = '\0';
|
||||
return trim_whitespace(fallback_result);
|
||||
}
|
||||
|
||||
int parse_session_id(const char* hex_str, uint8_t* bytes, size_t* len) {
|
||||
@@ -139,6 +443,27 @@ int parse_xml_to_iso1(const char* xml_content, struct iso1EXIDocument* doc) {
|
||||
doc->V2G_Message.Header.SessionID.bytesLen = len;
|
||||
doc->V2G_Message_isUsed = 1;
|
||||
}
|
||||
} else {
|
||||
// Search directly for namespaced SessionID
|
||||
char* ns_start = strstr(xml_content, "<ns2:SessionID>");
|
||||
if (ns_start) {
|
||||
ns_start += strlen("<ns2:SessionID>");
|
||||
char* ns_end = strstr(ns_start, "</ns2:SessionID>");
|
||||
if (ns_end) {
|
||||
size_t len_str = ns_end - ns_start;
|
||||
static char session_id_temp[256];
|
||||
if (len_str < sizeof(session_id_temp)) {
|
||||
strncpy(session_id_temp, ns_start, len_str);
|
||||
session_id_temp[len_str] = '\0';
|
||||
session_id_str = trim_whitespace(session_id_temp);
|
||||
size_t len;
|
||||
if (parse_session_id(session_id_str, doc->V2G_Message.Header.SessionID.bytes, &len) == 0) {
|
||||
doc->V2G_Message.Header.SessionID.bytesLen = len;
|
||||
doc->V2G_Message_isUsed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for CurrentDemandReq
|
||||
@@ -261,6 +586,86 @@ int parse_xml_to_iso1(const char* xml_content, struct iso1EXIDocument* doc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check for CurrentDemandRes
|
||||
if (strstr(xml_content, "<CurrentDemandRes>") || strstr(xml_content, "<ns3:CurrentDemandRes>")) {
|
||||
doc->V2G_Message.Body.CurrentDemandRes_isUsed = 1;
|
||||
init_iso1CurrentDemandResType(&doc->V2G_Message.Body.CurrentDemandRes);
|
||||
|
||||
// Parse ResponseCode
|
||||
char* response_code = find_tag_content(xml_content, "ResponseCode");
|
||||
if (response_code) {
|
||||
doc->V2G_Message.Body.CurrentDemandRes.ResponseCode = atoi(response_code);
|
||||
}
|
||||
|
||||
// Parse DC_EVSEStatus
|
||||
char* evse_isolation = find_tag_content_ns(xml_content, "EVSEIsolationStatus");
|
||||
if (evse_isolation) {
|
||||
doc->V2G_Message.Body.CurrentDemandRes.DC_EVSEStatus.EVSEIsolationStatus = atoi(evse_isolation);
|
||||
doc->V2G_Message.Body.CurrentDemandRes.DC_EVSEStatus.EVSEIsolationStatus_isUsed = 1u;
|
||||
}
|
||||
|
||||
char* evse_status = find_tag_content_ns(xml_content, "EVSEStatusCode");
|
||||
if (evse_status) {
|
||||
doc->V2G_Message.Body.CurrentDemandRes.DC_EVSEStatus.EVSEStatusCode = atoi(evse_status);
|
||||
}
|
||||
|
||||
// Parse EVSEPresentVoltage using bounded section approach
|
||||
char* voltage_section = strstr(xml_content, "<EVSEPresentVoltage>");
|
||||
if (!voltage_section) voltage_section = strstr(xml_content, "<ns3:EVSEPresentVoltage>");
|
||||
if (voltage_section) {
|
||||
char* voltage_end = strstr(voltage_section, "</EVSEPresentVoltage>");
|
||||
if (!voltage_end) voltage_end = strstr(voltage_section, "</ns3:EVSEPresentVoltage>");
|
||||
if (voltage_end) {
|
||||
parse_physical_value_from_section(voltage_section, voltage_end, &doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse EVSEPresentCurrent using bounded section approach
|
||||
char* current_section = strstr(xml_content, "<EVSEPresentCurrent>");
|
||||
if (!current_section) current_section = strstr(xml_content, "<ns3:EVSEPresentCurrent>");
|
||||
if (current_section) {
|
||||
char* current_end = strstr(current_section, "</EVSEPresentCurrent>");
|
||||
if (!current_end) current_end = strstr(current_section, "</ns3:EVSEPresentCurrent>");
|
||||
if (current_end) {
|
||||
parse_physical_value_from_section(current_section, current_end, &doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse limit achieved flags
|
||||
char* current_limit = find_tag_content(xml_content, "EVSECurrentLimitAchieved");
|
||||
if (current_limit) {
|
||||
doc->V2G_Message.Body.CurrentDemandRes.EVSECurrentLimitAchieved = (strcmp(current_limit, "true") == 0);
|
||||
}
|
||||
|
||||
char* voltage_limit = find_tag_content(xml_content, "EVSEVoltageLimitAchieved");
|
||||
if (voltage_limit) {
|
||||
doc->V2G_Message.Body.CurrentDemandRes.EVSEVoltageLimitAchieved = (strcmp(voltage_limit, "true") == 0);
|
||||
}
|
||||
|
||||
char* power_limit = find_tag_content(xml_content, "EVSEPowerLimitAchieved");
|
||||
if (power_limit) {
|
||||
doc->V2G_Message.Body.CurrentDemandRes.EVSEPowerLimitAchieved = (strcmp(power_limit, "true") == 0);
|
||||
}
|
||||
|
||||
// Parse EVSEID
|
||||
char* evseid = find_tag_content(xml_content, "EVSEID");
|
||||
if (evseid) {
|
||||
size_t len = strlen(evseid);
|
||||
if (len < sizeof(doc->V2G_Message.Body.CurrentDemandRes.EVSEID.characters)) {
|
||||
memcpy(doc->V2G_Message.Body.CurrentDemandRes.EVSEID.characters, evseid, len);
|
||||
doc->V2G_Message.Body.CurrentDemandRes.EVSEID.charactersLen = len;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse SAScheduleTupleID
|
||||
char* sa_schedule = find_tag_content(xml_content, "SAScheduleTupleID");
|
||||
if (sa_schedule) {
|
||||
doc->V2G_Message.Body.CurrentDemandRes.SAScheduleTupleID = atoi(sa_schedule);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1; // Unsupported message type
|
||||
}
|
||||
|
||||
@@ -281,23 +686,7 @@ int readEXIFile(char* file, uint8_t* buffer, size_t buffer_size, size_t *bytes_r
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Helper functions for Wireshark XML output
|
||||
const char* get_unit_string(int unit) {
|
||||
switch(unit) {
|
||||
case 2: return "s"; // seconds
|
||||
case 3: return "A"; // amperes
|
||||
case 4: return "V"; // volts
|
||||
case 5: return "W"; // watts
|
||||
default: return ""; // fallback to number
|
||||
}
|
||||
}
|
||||
|
||||
const char* get_error_string(int error) {
|
||||
switch(error) {
|
||||
case 0: return "NO_ERROR";
|
||||
default: return ""; // fallback to number
|
||||
}
|
||||
}
|
||||
// Helper functions for Wireshark XML output removed - using numeric values directly
|
||||
|
||||
void print_xml_header_wireshark() {
|
||||
printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
||||
@@ -332,23 +721,13 @@ void print_iso1_xml_wireshark(struct iso1EXIDocument* doc) {
|
||||
|
||||
printf("<ns3:EVSEPresentVoltage>");
|
||||
printf("<ns4:Multiplier>%d</ns4:Multiplier>", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage.Multiplier);
|
||||
const char* unit_str = get_unit_string(doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage.Unit);
|
||||
if (strlen(unit_str) > 0) {
|
||||
printf("<ns4:Unit>%s</ns4:Unit>", unit_str);
|
||||
} else {
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage.Unit);
|
||||
}
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage.Unit);
|
||||
printf("<ns4:Value>%d</ns4:Value>", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage.Value);
|
||||
printf("</ns3:EVSEPresentVoltage>");
|
||||
|
||||
printf("<ns3:EVSEPresentCurrent>");
|
||||
printf("<ns4:Multiplier>%d</ns4:Multiplier>", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent.Multiplier);
|
||||
unit_str = get_unit_string(doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent.Unit);
|
||||
if (strlen(unit_str) > 0) {
|
||||
printf("<ns4:Unit>%s</ns4:Unit>", unit_str);
|
||||
} else {
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent.Unit);
|
||||
}
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent.Unit);
|
||||
printf("<ns4:Value>%d</ns4:Value>", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent.Value);
|
||||
printf("</ns3:EVSEPresentCurrent>");
|
||||
|
||||
@@ -366,47 +745,27 @@ void print_iso1_xml_wireshark(struct iso1EXIDocument* doc) {
|
||||
printf("<ns3:DC_EVStatus>");
|
||||
printf("<ns4:EVReady>%s</ns4:EVReady>", doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVReady ? "true" : "false");
|
||||
|
||||
const char* error_str = get_error_string(doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVErrorCode);
|
||||
if (strlen(error_str) > 0) {
|
||||
printf("<ns4:EVErrorCode>%s</ns4:EVErrorCode>", error_str);
|
||||
} else {
|
||||
printf("<ns4:EVErrorCode>%d</ns4:EVErrorCode>", doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVErrorCode);
|
||||
}
|
||||
printf("<ns4:EVErrorCode>%d</ns4:EVErrorCode>", doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVErrorCode);
|
||||
|
||||
printf("<ns4:EVRESSSOC>%d</ns4:EVRESSSOC>", doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVRESSSOC);
|
||||
printf("</ns3:DC_EVStatus>");
|
||||
|
||||
printf("<ns3:EVTargetCurrent>");
|
||||
printf("<ns4:Multiplier>%d</ns4:Multiplier>", doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent.Multiplier);
|
||||
const char* unit_str = get_unit_string(doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent.Unit);
|
||||
if (strlen(unit_str) > 0) {
|
||||
printf("<ns4:Unit>%s</ns4:Unit>", unit_str);
|
||||
} else {
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent.Unit);
|
||||
}
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent.Unit);
|
||||
printf("<ns4:Value>%d</ns4:Value>", doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent.Value);
|
||||
printf("</ns3:EVTargetCurrent>");
|
||||
|
||||
printf("<ns3:EVTargetVoltage>");
|
||||
printf("<ns4:Multiplier>%d</ns4:Multiplier>", doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage.Multiplier);
|
||||
unit_str = get_unit_string(doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage.Unit);
|
||||
if (strlen(unit_str) > 0) {
|
||||
printf("<ns4:Unit>%s</ns4:Unit>", unit_str);
|
||||
} else {
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage.Unit);
|
||||
}
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage.Unit);
|
||||
printf("<ns4:Value>%d</ns4:Value>", doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage.Value);
|
||||
printf("</ns3:EVTargetVoltage>");
|
||||
|
||||
if (doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit_isUsed) {
|
||||
printf("<ns3:EVMaximumVoltageLimit>");
|
||||
printf("<ns4:Multiplier>%d</ns4:Multiplier>", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit.Multiplier);
|
||||
unit_str = get_unit_string(doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit.Unit);
|
||||
if (strlen(unit_str) > 0) {
|
||||
printf("<ns4:Unit>%s</ns4:Unit>", unit_str);
|
||||
} else {
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit.Unit);
|
||||
}
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit.Unit);
|
||||
printf("<ns4:Value>%d</ns4:Value>", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit.Value);
|
||||
printf("</ns3:EVMaximumVoltageLimit>");
|
||||
}
|
||||
@@ -414,12 +773,7 @@ void print_iso1_xml_wireshark(struct iso1EXIDocument* doc) {
|
||||
if (doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit_isUsed) {
|
||||
printf("<ns3:EVMaximumCurrentLimit>");
|
||||
printf("<ns4:Multiplier>%d</ns4:Multiplier>", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit.Multiplier);
|
||||
unit_str = get_unit_string(doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit.Unit);
|
||||
if (strlen(unit_str) > 0) {
|
||||
printf("<ns4:Unit>%s</ns4:Unit>", unit_str);
|
||||
} else {
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit.Unit);
|
||||
}
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit.Unit);
|
||||
printf("<ns4:Value>%d</ns4:Value>", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit.Value);
|
||||
printf("</ns3:EVMaximumCurrentLimit>");
|
||||
}
|
||||
@@ -427,12 +781,7 @@ void print_iso1_xml_wireshark(struct iso1EXIDocument* doc) {
|
||||
if (doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit_isUsed) {
|
||||
printf("<ns3:EVMaximumPowerLimit>");
|
||||
printf("<ns4:Multiplier>%d</ns4:Multiplier>", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit.Multiplier);
|
||||
unit_str = get_unit_string(doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit.Unit);
|
||||
if (strlen(unit_str) > 0) {
|
||||
printf("<ns4:Unit>%s</ns4:Unit>", unit_str);
|
||||
} else {
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit.Unit);
|
||||
}
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit.Unit);
|
||||
printf("<ns4:Value>%d</ns4:Value>", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit.Value);
|
||||
printf("</ns3:EVMaximumPowerLimit>");
|
||||
}
|
||||
@@ -446,12 +795,7 @@ void print_iso1_xml_wireshark(struct iso1EXIDocument* doc) {
|
||||
if (doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC_isUsed) {
|
||||
printf("<ns3:RemainingTimeToFullSoC>");
|
||||
printf("<ns4:Multiplier>%d</ns4:Multiplier>", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC.Multiplier);
|
||||
unit_str = get_unit_string(doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC.Unit);
|
||||
if (strlen(unit_str) > 0) {
|
||||
printf("<ns4:Unit>%s</ns4:Unit>", unit_str);
|
||||
} else {
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC.Unit);
|
||||
}
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC.Unit);
|
||||
printf("<ns4:Value>%d</ns4:Value>", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC.Value);
|
||||
printf("</ns3:RemainingTimeToFullSoC>");
|
||||
}
|
||||
@@ -459,12 +803,7 @@ void print_iso1_xml_wireshark(struct iso1EXIDocument* doc) {
|
||||
if (doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC_isUsed) {
|
||||
printf("<ns3:RemainingTimeToBulkSoC>");
|
||||
printf("<ns4:Multiplier>%d</ns4:Multiplier>", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC.Multiplier);
|
||||
unit_str = get_unit_string(doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC.Unit);
|
||||
if (strlen(unit_str) > 0) {
|
||||
printf("<ns4:Unit>%s</ns4:Unit>", unit_str);
|
||||
} else {
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC.Unit);
|
||||
}
|
||||
printf("<ns4:Unit>%d</ns4:Unit>", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC.Unit);
|
||||
printf("<ns4:Value>%d</ns4:Value>", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC.Value);
|
||||
printf("</ns3:RemainingTimeToBulkSoC>");
|
||||
}
|
||||
@@ -656,10 +995,18 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// Parse XML to ISO1 document structure
|
||||
if (parse_xml_to_iso1(xml_content, &iso1Doc) != 0) {
|
||||
printf("Error parsing XML file\\n");
|
||||
printf("Error parsing XML file - no supported message type found\\n");
|
||||
free(xml_content);
|
||||
return -1;
|
||||
}
|
||||
// Show encoding info only when redirecting to file (keeps terminal output clean)
|
||||
struct stat stat_buf_debug;
|
||||
int is_file_redirect = (fstat(fileno(stdout), &stat_buf_debug) == 0 && S_ISREG(stat_buf_debug.st_mode));
|
||||
if (is_file_redirect) {
|
||||
fprintf(stderr, "XML parsing successful\\n");
|
||||
fprintf(stderr, "SessionID length: %d\\n", iso1Doc.V2G_Message.Header.SessionID.bytesLen);
|
||||
fprintf(stderr, "CurrentDemandReq_isUsed: %s\\n", iso1Doc.V2G_Message.Body.CurrentDemandReq_isUsed ? "true" : "false");
|
||||
}
|
||||
|
||||
free(xml_content);
|
||||
|
||||
@@ -677,8 +1024,27 @@ int main(int argc, char *argv[]) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Write EXI data to stdout (binary)
|
||||
fwrite(buffer, 1, pos, stdout);
|
||||
// Check if output is redirected (for Windows/MINGW compatibility)
|
||||
// Use environment variable approach or check for redirection
|
||||
char* term = getenv("TERM");
|
||||
int use_hex_output = (term != NULL) || isatty(fileno(stdout));
|
||||
|
||||
// Also check if user specifically wants binary output by checking for redirection
|
||||
struct stat stat_buf;
|
||||
if (fstat(fileno(stdout), &stat_buf) == 0 && S_ISREG(stat_buf.st_mode)) {
|
||||
use_hex_output = 0; // Regular file, use binary
|
||||
}
|
||||
|
||||
if (use_hex_output) {
|
||||
// Terminal output: show hex string only
|
||||
for(size_t i = 0; i < pos; i++) {
|
||||
printf("%02X", buffer[i]);
|
||||
}
|
||||
printf("\n");
|
||||
} else {
|
||||
// Redirected output: write binary data
|
||||
fwrite(buffer, 1, pos, stdout);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -697,6 +1063,28 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
if (pos > 32) printf("...");
|
||||
printf("\\n\\n");
|
||||
|
||||
// Analyze data structure and extract EXI body
|
||||
analyze_data_structure(buffer, pos);
|
||||
}
|
||||
|
||||
// Extract EXI body from V2G Transfer Protocol data
|
||||
uint8_t exi_buffer[BUFFER_SIZE];
|
||||
size_t exi_size = extract_exi_body(buffer, pos, exi_buffer, BUFFER_SIZE);
|
||||
|
||||
if (exi_size != pos) {
|
||||
if (!xml_mode) {
|
||||
printf("EXI body extracted: %zu bytes (was %zu bytes)\\n", exi_size, pos);
|
||||
printf("EXI hex data: ");
|
||||
for(size_t i = 0; i < (exi_size > 32 ? 32 : exi_size); i++) {
|
||||
printf("%02X ", exi_buffer[i]);
|
||||
}
|
||||
if (exi_size > 32) printf("...");
|
||||
printf("\\n\\n");
|
||||
}
|
||||
// Use extracted EXI data
|
||||
memcpy(buffer, exi_buffer, exi_size);
|
||||
pos = exi_size;
|
||||
}
|
||||
|
||||
// Setup stream
|
||||
|
||||
Binary file not shown.
53
test4.xml
53
test4.xml
@@ -1,53 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<V2G_Message xmlns="urn:iso:15118:2:2013:MsgDef"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Header>
|
||||
<SessionID>4142423030303831</SessionID>
|
||||
</Header>
|
||||
<Body>
|
||||
<CurrentDemandReq>
|
||||
<DC_EVStatus>
|
||||
<EVReady>true</EVReady>
|
||||
<EVErrorCode>0</EVErrorCode>
|
||||
<EVRESSSOC>100</EVRESSSOC>
|
||||
</DC_EVStatus>
|
||||
<EVTargetCurrent>
|
||||
<Multiplier>0</Multiplier>
|
||||
<Unit>3</Unit>
|
||||
<Value>5</Value>
|
||||
</EVTargetCurrent>
|
||||
<EVTargetVoltage>
|
||||
<Multiplier>0</Multiplier>
|
||||
<Unit>4</Unit>
|
||||
<Value>460</Value>
|
||||
</EVTargetVoltage>
|
||||
<EVMaximumVoltageLimit>
|
||||
<Multiplier>0</Multiplier>
|
||||
<Unit>4</Unit>
|
||||
<Value>471</Value>
|
||||
</EVMaximumVoltageLimit>
|
||||
<EVMaximumCurrentLimit>
|
||||
<Multiplier>0</Multiplier>
|
||||
<Unit>3</Unit>
|
||||
<Value>100</Value>
|
||||
</EVMaximumCurrentLimit>
|
||||
<EVMaximumPowerLimit>
|
||||
<Multiplier>3</Multiplier>
|
||||
<Unit>5</Unit>
|
||||
<Value>50</Value>
|
||||
</EVMaximumPowerLimit>
|
||||
<BulkChargingComplete>false</BulkChargingComplete>
|
||||
<ChargingComplete>true</ChargingComplete>
|
||||
<RemainingTimeToFullSoC>
|
||||
<Multiplier>0</Multiplier>
|
||||
<Unit>2</Unit>
|
||||
<Value>0</Value>
|
||||
</RemainingTimeToFullSoC>
|
||||
<RemainingTimeToBulkSoC>
|
||||
<Multiplier>0</Multiplier>
|
||||
<Unit>2</Unit>
|
||||
<Value>0</Value>
|
||||
</RemainingTimeToBulkSoC>
|
||||
</CurrentDemandReq>
|
||||
</Body>
|
||||
</V2G_Message>
|
||||
@@ -1 +0,0 @@
|
||||
Error encoding to EXI (error: -109)
|
||||
53
test5.xml
53
test5.xml
@@ -1,53 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<V2G_Message xmlns="urn:iso:15118:2:2013:MsgDef"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Header>
|
||||
<SessionID>4142423030303831</SessionID>
|
||||
</Header>
|
||||
<Body>
|
||||
<CurrentDemandReq>
|
||||
<DC_EVStatus>
|
||||
<EVReady>true</EVReady>
|
||||
<EVErrorCode>0</EVErrorCode>
|
||||
<EVRESSSOC>100</EVRESSSOC>
|
||||
</DC_EVStatus>
|
||||
<EVTargetCurrent>
|
||||
<Multiplier>0</Multiplier>
|
||||
<Unit>3</Unit>
|
||||
<Value>1</Value>
|
||||
</EVTargetCurrent>
|
||||
<EVTargetVoltage>
|
||||
<Multiplier>0</Multiplier>
|
||||
<Unit>4</Unit>
|
||||
<Value>460</Value>
|
||||
</EVTargetVoltage>
|
||||
<EVMaximumVoltageLimit>
|
||||
<Multiplier>0</Multiplier>
|
||||
<Unit>4</Unit>
|
||||
<Value>471</Value>
|
||||
</EVMaximumVoltageLimit>
|
||||
<EVMaximumCurrentLimit>
|
||||
<Multiplier>0</Multiplier>
|
||||
<Unit>3</Unit>
|
||||
<Value>100</Value>
|
||||
</EVMaximumCurrentLimit>
|
||||
<EVMaximumPowerLimit>
|
||||
<Multiplier>3</Multiplier>
|
||||
<Unit>5</Unit>
|
||||
<Value>50</Value>
|
||||
</EVMaximumPowerLimit>
|
||||
<BulkChargingComplete>false</BulkChargingComplete>
|
||||
<ChargingComplete>true</ChargingComplete>
|
||||
<RemainingTimeToFullSoC>
|
||||
<Multiplier>0</Multiplier>
|
||||
<Unit>2</Unit>
|
||||
<Value>0</Value>
|
||||
</RemainingTimeToFullSoC>
|
||||
<RemainingTimeToBulkSoC>
|
||||
<Multiplier>0</Multiplier>
|
||||
<Unit>2</Unit>
|
||||
<Value>0</Value>
|
||||
</RemainingTimeToBulkSoC>
|
||||
</CurrentDemandReq>
|
||||
</Body>
|
||||
</V2G_Message>
|
||||
@@ -1 +0,0 @@
|
||||
<EFBFBD><EFBFBD>P<><50>P
|
||||
@@ -1,47 +0,0 @@
|
||||
DEBUG: Parsing EVTargetCurrent section
|
||||
DEBUG find_tag_in_section: Looking for 'Multiplier' in section of 137 chars
|
||||
DEBUG: Found 'Multiplier' = '0'
|
||||
DEBUG find_tag_in_section: Looking for 'Unit' in section of 137 chars
|
||||
DEBUG: Found 'Unit' = '3'
|
||||
DEBUG find_tag_in_section: Looking for 'Value' in section of 137 chars
|
||||
DEBUG: Found 'Value' = '1'
|
||||
DEBUG PhysicalValue: mult='0'->0, unit='3'->3, value='1'->1
|
||||
DEBUG: Parsing EVTargetVoltage section
|
||||
DEBUG find_tag_in_section: Looking for 'Multiplier' in section of 139 chars
|
||||
DEBUG: Found 'Multiplier' = '0'
|
||||
DEBUG find_tag_in_section: Looking for 'Unit' in section of 139 chars
|
||||
DEBUG: Found 'Unit' = '4'
|
||||
DEBUG find_tag_in_section: Looking for 'Value' in section of 139 chars
|
||||
DEBUG: Found 'Value' = '460'
|
||||
DEBUG PhysicalValue: mult='0'->0, unit='4'->4, value='460'->460
|
||||
DEBUG find_tag_in_section: Looking for 'Multiplier' in section of 145 chars
|
||||
DEBUG: Found 'Multiplier' = '0'
|
||||
DEBUG find_tag_in_section: Looking for 'Unit' in section of 145 chars
|
||||
DEBUG: Found 'Unit' = '4'
|
||||
DEBUG find_tag_in_section: Looking for 'Value' in section of 145 chars
|
||||
DEBUG: Found 'Value' = '471'
|
||||
DEBUG PhysicalValue: mult='0'->0, unit='4'->4, value='471'->471
|
||||
DEBUG find_tag_in_section: Looking for 'Multiplier' in section of 145 chars
|
||||
DEBUG: Found 'Multiplier' = '0'
|
||||
DEBUG find_tag_in_section: Looking for 'Unit' in section of 145 chars
|
||||
DEBUG: Found 'Unit' = '3'
|
||||
DEBUG find_tag_in_section: Looking for 'Value' in section of 145 chars
|
||||
DEBUG: Found 'Value' = '100'
|
||||
DEBUG PhysicalValue: mult='0'->0, unit='3'->3, value='100'->100
|
||||
DEBUG find_tag_in_section: Looking for 'Multiplier' in section of 142 chars
|
||||
DEBUG: Found 'Multiplier' = '3'
|
||||
DEBUG find_tag_in_section: Looking for 'Unit' in section of 142 chars
|
||||
DEBUG: Found 'Unit' = '5'
|
||||
DEBUG find_tag_in_section: Looking for 'Value' in section of 142 chars
|
||||
DEBUG: Found 'Value' = '50'
|
||||
DEBUG PhysicalValue: mult='3'->3, unit='5'->5, value='50'->50
|
||||
DEBUG: Parsed V2G Message:
|
||||
V2G_Message_isUsed: 1
|
||||
CurrentDemandReq_isUsed: 1
|
||||
EVReady: 1
|
||||
EVErrorCode: 0
|
||||
EVRESSSOC: 100
|
||||
EVTargetCurrent: 1 (Mult: 0, Unit: 3)
|
||||
EVTargetVoltage: 460 (Mult: 0, Unit: 4)
|
||||
ChargingComplete: 1
|
||||
<EFBFBD><EFBFBD>P<><50>P
|
||||
1
test5ws.xml
Normal file
1
test5ws.xml
Normal file
@@ -0,0 +1 @@
|
||||
<?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:CurrentDemandReq><ns3:DC_EVStatus><ns4:EVReady>true</ns4:EVReady><ns4:EVErrorCode>NO_ERROR</ns4:EVErrorCode><ns4:EVRESSSOC>100</ns4:EVRESSSOC></ns3:DC_EVStatus><ns3:EVTargetCurrent><ns4:Multiplier>0</ns4:Multiplier><ns4:Unit>A</ns4:Unit><ns4:Value>1</ns4:Value></ns3:EVTargetCurrent><ns3:EVMaximumVoltageLimit><ns4:Multiplier>0</ns4:Multiplier><ns4:Unit>V</ns4:Unit><ns4:Value>471</ns4:Value></ns3:EVMaximumVoltageLimit><ns3:EVMaximumCurrentLimit><ns4:Multiplier>0</ns4:Multiplier><ns4:Unit>A</ns4:Unit><ns4:Value>100</ns4:Value></ns3:EVMaximumCurrentLimit><ns3:EVMaximumPowerLimit><ns4:Multiplier>3</ns4:Multiplier><ns4:Unit>W</ns4:Unit><ns4:Value>50</ns4:Value></ns3:EVMaximumPowerLimit><ns3:BulkChargingComplete>false</ns3:BulkChargingComplete><ns3:ChargingComplete>true</ns3:ChargingComplete><ns3:RemainingTimeToFullSoC><ns4:Multiplier>0</ns4:Multiplier><ns4:Unit>s</ns4:Unit><ns4:Value>0</ns4:Value></ns3:RemainingTimeToFullSoC><ns3:RemainingTimeToBulkSoC><ns4:Multiplier>0</ns4:Multiplier><ns4:Unit>s</ns4:Unit><ns4:Value>0</ns4:Value></ns3:RemainingTimeToBulkSoC><ns3:EVTargetVoltage><ns4:Multiplier>0</ns4:Multiplier><ns4:Unit>V</ns4:Unit><ns4:Value>460</ns4:Value></ns3:EVTargetVoltage></ns3:CurrentDemandReq></ns1:Body></ns1:V2G_Message>
|
||||
Reference in New Issue
Block a user