#include #include #include /* EXI codec headers */ #include "iso1EXIDatatypes.h" #include "iso1EXIDatatypesDecoder.h" #include "iso2EXIDatatypes.h" #include "iso2EXIDatatypesDecoder.h" #include "dinEXIDatatypes.h" #include "dinEXIDatatypesDecoder.h" #include "ByteStream.h" #define BUFFER_SIZE 4096 void print_session_id(uint8_t *bytes, size_t len) { printf("SessionID: "); for(size_t i = 0; i < len; i++) { printf("%02X", bytes[i]); } printf(" ("); for(size_t i = 0; i < len; i++) { if (bytes[i] >= 32 && bytes[i] <= 126) { printf("%c", bytes[i]); } else { printf("."); } } printf(")\n"); } void print_xml_header() { printf("\n"); printf("\n"); } void print_xml_footer() { printf("\n"); } void print_session_id_xml(uint8_t *bytes, size_t len) { printf(" "); for(size_t i = 0; i < len; i++) { printf("%02X", bytes[i]); } printf("\n"); } void print_iso1_xml(struct iso1EXIDocument *doc) { if (!doc->V2G_Message_isUsed) return; print_xml_header(); // Header printf("
\n"); print_session_id_xml(doc->V2G_Message.Header.SessionID.bytes, doc->V2G_Message.Header.SessionID.bytesLen); if (doc->V2G_Message.Header.Notification_isUsed) { printf(" \n"); printf(" %d\n", doc->V2G_Message.Header.Notification.FaultCode); printf(" %s\n", doc->V2G_Message.Header.Notification.FaultMsg.characters); printf(" \n"); } printf("
\n"); // Body printf(" \n"); if (doc->V2G_Message.Body.CurrentDemandRes_isUsed) { printf(" \n"); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.ResponseCode); printf(" \n"); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.DC_EVSEStatus.EVSENotification); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.DC_EVSEStatus.NotificationMaxDelay); if (doc->V2G_Message.Body.CurrentDemandRes.DC_EVSEStatus.EVSEIsolationStatus_isUsed) { printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.DC_EVSEStatus.EVSEIsolationStatus); } printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.DC_EVSEStatus.EVSEStatusCode); printf(" \n"); printf(" \n"); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage.Multiplier); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage.Unit); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage.Value); printf(" \n"); printf(" \n"); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent.Multiplier); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent.Unit); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent.Value); printf(" \n"); printf(" %s\n", doc->V2G_Message.Body.CurrentDemandRes.EVSECurrentLimitAchieved ? "true" : "false"); printf(" %s\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEVoltageLimitAchieved ? "true" : "false"); printf(" %s\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEPowerLimitAchieved ? "true" : "false"); if (doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumVoltageLimit_isUsed) { printf(" \n"); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumVoltageLimit.Multiplier); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumVoltageLimit.Unit); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumVoltageLimit.Value); printf(" \n"); } if (doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumCurrentLimit_isUsed) { printf(" \n"); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumCurrentLimit.Multiplier); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumCurrentLimit.Unit); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumCurrentLimit.Value); printf(" \n"); } if (doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumPowerLimit_isUsed) { printf(" \n"); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumPowerLimit.Multiplier); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumPowerLimit.Unit); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumPowerLimit.Value); printf(" \n"); } printf(" %.*s\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEID.charactersLen, doc->V2G_Message.Body.CurrentDemandRes.EVSEID.characters); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.SAScheduleTupleID); if (doc->V2G_Message.Body.CurrentDemandRes.MeterInfo_isUsed) { printf(" \n"); printf(" %.*s\n", doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.MeterID.charactersLen, doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.MeterID.characters); if (doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.MeterReading_isUsed) { printf(" %llu\n", doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.MeterReading); } if (doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.SigMeterReading_isUsed) { printf(" "); for(int i = 0; i < doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.SigMeterReading.bytesLen; i++) { printf("%02X", doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.SigMeterReading.bytes[i]); } printf("\n"); } if (doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.MeterStatus_isUsed) { printf(" %d\n", doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.MeterStatus); } if (doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.TMeter_isUsed) { printf(" %lld\n", doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.TMeter); } printf(" \n"); } if (doc->V2G_Message.Body.CurrentDemandRes.ReceiptRequired_isUsed) { printf(" %s\n", doc->V2G_Message.Body.CurrentDemandRes.ReceiptRequired ? "true" : "false"); } printf(" \n"); } else if (doc->V2G_Message.Body.CurrentDemandReq_isUsed) { printf(" \n"); printf(" \n"); printf(" %s\n", doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVReady ? "true" : "false"); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVErrorCode); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVRESSSOC); printf(" \n"); printf(" \n"); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent.Multiplier); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent.Unit); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent.Value); printf(" \n"); printf(" \n"); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage.Multiplier); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage.Unit); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage.Value); printf(" \n"); if (doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit_isUsed) { printf(" \n"); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit.Multiplier); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit.Unit); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit.Value); printf(" \n"); } if (doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit_isUsed) { printf(" \n"); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit.Multiplier); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit.Unit); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit.Value); printf(" \n"); } if (doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit_isUsed) { printf(" \n"); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit.Multiplier); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit.Unit); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit.Value); printf(" \n"); } if (doc->V2G_Message.Body.CurrentDemandReq.BulkChargingComplete_isUsed) { printf(" %s\n", doc->V2G_Message.Body.CurrentDemandReq.BulkChargingComplete ? "true" : "false"); } printf(" %s\n", doc->V2G_Message.Body.CurrentDemandReq.ChargingComplete ? "true" : "false"); if (doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC_isUsed) { printf(" \n"); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC.Multiplier); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC.Unit); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC.Value); printf(" \n"); } if (doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC_isUsed) { printf(" \n"); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC.Multiplier); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC.Unit); printf(" %d\n", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC.Value); printf(" \n"); } printf(" \n"); } else { printf(" \n"); } printf(" \n"); print_xml_footer(); } void print_iso1_message(struct iso1EXIDocument *doc) { printf("=== ISO1 V2G Message ===\n"); if (doc->V2G_Message_isUsed) { // Print Header printf("Header:\n"); print_session_id(doc->V2G_Message.Header.SessionID.bytes, doc->V2G_Message.Header.SessionID.bytesLen); if (doc->V2G_Message.Header.Notification_isUsed) { printf(" Notification: FaultCode=%d, FaultMsg=%s\n", doc->V2G_Message.Header.Notification.FaultCode, doc->V2G_Message.Header.Notification.FaultMsg.characters); } printf("\nBody:\n"); // Check all possible message types if (doc->V2G_Message.Body.SessionSetupReq_isUsed) { printf(" Message Type: SessionSetupReq\n"); printf(" EVCCID: "); for(size_t i = 0; i < doc->V2G_Message.Body.SessionSetupReq.EVCCID.bytesLen; i++) { printf("%02X", doc->V2G_Message.Body.SessionSetupReq.EVCCID.bytes[i]); } printf(" ("); for(size_t i = 0; i < doc->V2G_Message.Body.SessionSetupReq.EVCCID.bytesLen; i++) { if (doc->V2G_Message.Body.SessionSetupReq.EVCCID.bytes[i] >= 32 && doc->V2G_Message.Body.SessionSetupReq.EVCCID.bytes[i] <= 126) { printf("%c", doc->V2G_Message.Body.SessionSetupReq.EVCCID.bytes[i]); } else { printf("."); } } printf(")\n"); } else if (doc->V2G_Message.Body.SessionSetupRes_isUsed) { printf(" Message Type: SessionSetupRes\n"); printf(" ResponseCode: %d\n", doc->V2G_Message.Body.SessionSetupRes.ResponseCode); printf(" EVSEID: %s\n", doc->V2G_Message.Body.SessionSetupRes.EVSEID.characters); if (doc->V2G_Message.Body.SessionSetupRes.EVSETimeStamp_isUsed) { printf(" EVSETimeStamp: %ld\n", doc->V2G_Message.Body.SessionSetupRes.EVSETimeStamp); } } else if (doc->V2G_Message.Body.ServiceDiscoveryReq_isUsed) { printf(" Message Type: ServiceDiscoveryReq\n"); } else if (doc->V2G_Message.Body.ServiceDiscoveryRes_isUsed) { printf(" Message Type: ServiceDiscoveryRes\n"); printf(" ResponseCode: %d\n", doc->V2G_Message.Body.ServiceDiscoveryRes.ResponseCode); } else if (doc->V2G_Message.Body.ServiceDetailReq_isUsed) { printf(" Message Type: ServiceDetailReq\n"); printf(" ServiceID: %d\n", doc->V2G_Message.Body.ServiceDetailReq.ServiceID); } else if (doc->V2G_Message.Body.ServiceDetailRes_isUsed) { printf(" Message Type: ServiceDetailRes\n"); printf(" ResponseCode: %d\n", doc->V2G_Message.Body.ServiceDetailRes.ResponseCode); } else if (doc->V2G_Message.Body.PaymentServiceSelectionReq_isUsed) { printf(" Message Type: PaymentServiceSelectionReq\n"); printf(" SelectedPaymentOption: %d\n", doc->V2G_Message.Body.PaymentServiceSelectionReq.SelectedPaymentOption); } else if (doc->V2G_Message.Body.PaymentServiceSelectionRes_isUsed) { printf(" Message Type: PaymentServiceSelectionRes\n"); printf(" ResponseCode: %d\n", doc->V2G_Message.Body.PaymentServiceSelectionRes.ResponseCode); } else if (doc->V2G_Message.Body.AuthorizationReq_isUsed) { printf(" Message Type: AuthorizationReq\n"); if (doc->V2G_Message.Body.AuthorizationReq.Id_isUsed) { printf(" ID: %s\n", doc->V2G_Message.Body.AuthorizationReq.Id.characters); } if (doc->V2G_Message.Body.AuthorizationReq.GenChallenge_isUsed) { printf(" GenChallenge: "); for(size_t i = 0; i < doc->V2G_Message.Body.AuthorizationReq.GenChallenge.bytesLen; i++) { printf("%02X", doc->V2G_Message.Body.AuthorizationReq.GenChallenge.bytes[i]); } printf("\n"); } } else if (doc->V2G_Message.Body.AuthorizationRes_isUsed) { printf(" Message Type: AuthorizationRes\n"); printf(" ResponseCode: %d\n", doc->V2G_Message.Body.AuthorizationRes.ResponseCode); printf(" EVSEProcessing: %d\n", doc->V2G_Message.Body.AuthorizationRes.EVSEProcessing); } else if (doc->V2G_Message.Body.ChargeParameterDiscoveryReq_isUsed) { printf(" Message Type: ChargeParameterDiscoveryReq\n"); } else if (doc->V2G_Message.Body.ChargeParameterDiscoveryRes_isUsed) { printf(" Message Type: ChargeParameterDiscoveryRes\n"); printf(" ResponseCode: %d\n", doc->V2G_Message.Body.ChargeParameterDiscoveryRes.ResponseCode); } else if (doc->V2G_Message.Body.CableCheckReq_isUsed) { printf(" Message Type: CableCheckReq\n"); } else if (doc->V2G_Message.Body.CableCheckRes_isUsed) { printf(" Message Type: CableCheckRes\n"); printf(" ResponseCode: %d\n", doc->V2G_Message.Body.CableCheckRes.ResponseCode); } else if (doc->V2G_Message.Body.PreChargeReq_isUsed) { printf(" Message Type: PreChargeReq\n"); printf(" EVTargetVoltage: %d\n", doc->V2G_Message.Body.PreChargeReq.EVTargetVoltage.Value); printf(" EVTargetCurrent: %d\n", doc->V2G_Message.Body.PreChargeReq.EVTargetCurrent.Value); } else if (doc->V2G_Message.Body.PreChargeRes_isUsed) { printf(" Message Type: PreChargeRes\n"); printf(" ResponseCode: %d\n", doc->V2G_Message.Body.PreChargeRes.ResponseCode); } else if (doc->V2G_Message.Body.PowerDeliveryReq_isUsed) { printf(" Message Type: PowerDeliveryReq\n"); printf(" ChargeProgress: %d\n", doc->V2G_Message.Body.PowerDeliveryReq.ChargeProgress); printf(" SAScheduleTupleID: %d\n", doc->V2G_Message.Body.PowerDeliveryReq.SAScheduleTupleID); } else if (doc->V2G_Message.Body.PowerDeliveryRes_isUsed) { printf(" Message Type: PowerDeliveryRes\n"); printf(" ResponseCode: %d\n", doc->V2G_Message.Body.PowerDeliveryRes.ResponseCode); } else if (doc->V2G_Message.Body.ChargingStatusReq_isUsed) { printf(" Message Type: ChargingStatusReq\n"); } else if (doc->V2G_Message.Body.ChargingStatusRes_isUsed) { printf(" Message Type: ChargingStatusRes\n"); printf(" ResponseCode: %d\n", doc->V2G_Message.Body.ChargingStatusRes.ResponseCode); } else if (doc->V2G_Message.Body.MeteringReceiptReq_isUsed) { printf(" Message Type: MeteringReceiptReq\n"); } else if (doc->V2G_Message.Body.MeteringReceiptRes_isUsed) { printf(" Message Type: MeteringReceiptRes\n"); printf(" ResponseCode: %d\n", doc->V2G_Message.Body.MeteringReceiptRes.ResponseCode); } else if (doc->V2G_Message.Body.SessionStopReq_isUsed) { printf(" Message Type: SessionStopReq\n"); printf(" ChargingSession: %d\n", doc->V2G_Message.Body.SessionStopReq.ChargingSession); } else if (doc->V2G_Message.Body.SessionStopRes_isUsed) { printf(" Message Type: SessionStopRes\n"); printf(" ResponseCode: %d\n", doc->V2G_Message.Body.SessionStopRes.ResponseCode); } else if (doc->V2G_Message.Body.CurrentDemandReq_isUsed) { printf(" Message Type: CurrentDemandReq\n"); printf(" DC_EVStatus:\n"); printf(" EVReady: %s\n", doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVReady ? "true" : "false"); printf(" EVErrorCode: %d\n", doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVErrorCode); printf(" EVRESSSOC: %d%%\n", doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVRESSSOC); printf(" EVTargetCurrent: %d A (Multiplier: %d, Unit: %d)\n", doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent.Value, doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent.Multiplier, doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent.Unit); printf(" EVTargetVoltage: %d V (Multiplier: %d, Unit: %d)\n", doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage.Value, doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage.Multiplier, doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage.Unit); if (doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit_isUsed) { printf(" EVMaximumVoltageLimit: %d V (Multiplier: %d, Unit: %d)\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit.Value, doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit.Multiplier, doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit.Unit); } if (doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit_isUsed) { printf(" EVMaximumCurrentLimit: %d A (Multiplier: %d, Unit: %d)\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit.Value, doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit.Multiplier, doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit.Unit); } if (doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit_isUsed) { printf(" EVMaximumPowerLimit: %d W (Multiplier: %d, Unit: %d)\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit.Value, doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit.Multiplier, doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit.Unit); } if (doc->V2G_Message.Body.CurrentDemandReq.BulkChargingComplete_isUsed) { printf(" BulkChargingComplete: %s\n", doc->V2G_Message.Body.CurrentDemandReq.BulkChargingComplete ? "true" : "false"); } printf(" ChargingComplete: %s\n", doc->V2G_Message.Body.CurrentDemandReq.ChargingComplete ? "true" : "false"); if (doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC_isUsed) { printf(" RemainingTimeToFullSoC: %d s (Multiplier: %d, Unit: %d)\n", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC.Value, doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC.Multiplier, doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC.Unit); } if (doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC_isUsed) { printf(" RemainingTimeToBulkSoC: %d s (Multiplier: %d, Unit: %d)\n", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC.Value, doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC.Multiplier, doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC.Unit); } } else if (doc->V2G_Message.Body.CurrentDemandRes_isUsed) { printf(" Message Type: CurrentDemandRes\n"); printf(" ResponseCode: %d\n", doc->V2G_Message.Body.CurrentDemandRes.ResponseCode); printf(" DC_EVSEStatus:\n"); printf(" EVSENotification: %d\n", doc->V2G_Message.Body.CurrentDemandRes.DC_EVSEStatus.EVSENotification); printf(" NotificationMaxDelay: %d\n", doc->V2G_Message.Body.CurrentDemandRes.DC_EVSEStatus.NotificationMaxDelay); if (doc->V2G_Message.Body.CurrentDemandRes.DC_EVSEStatus.EVSEIsolationStatus_isUsed) { printf(" EVSEIsolationStatus: %d\n", doc->V2G_Message.Body.CurrentDemandRes.DC_EVSEStatus.EVSEIsolationStatus); } printf(" EVSEStatusCode: %d\n", doc->V2G_Message.Body.CurrentDemandRes.DC_EVSEStatus.EVSEStatusCode); printf(" EVSEPresentVoltage: %d V (Multiplier: %d, Unit: %d)\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage.Value, doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage.Multiplier, doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage.Unit); printf(" EVSEPresentCurrent: %d A (Multiplier: %d, Unit: %d)\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent.Value, doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent.Multiplier, doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent.Unit); printf(" EVSECurrentLimitAchieved: %s\n", doc->V2G_Message.Body.CurrentDemandRes.EVSECurrentLimitAchieved ? "true" : "false"); printf(" EVSEVoltageLimitAchieved: %s\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEVoltageLimitAchieved ? "true" : "false"); printf(" EVSEPowerLimitAchieved: %s\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEPowerLimitAchieved ? "true" : "false"); if (doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumVoltageLimit_isUsed) { printf(" EVSEMaximumVoltageLimit: %d V (Multiplier: %d, Unit: %d)\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumVoltageLimit.Value, doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumVoltageLimit.Multiplier, doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumVoltageLimit.Unit); } if (doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumCurrentLimit_isUsed) { printf(" EVSEMaximumCurrentLimit: %d A (Multiplier: %d, Unit: %d)\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumCurrentLimit.Value, doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumCurrentLimit.Multiplier, doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumCurrentLimit.Unit); } if (doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumPowerLimit_isUsed) { printf(" EVSEMaximumPowerLimit: %d W (Multiplier: %d, Unit: %d)\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumPowerLimit.Value, doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumPowerLimit.Multiplier, doc->V2G_Message.Body.CurrentDemandRes.EVSEMaximumPowerLimit.Unit); } printf(" EVSEID: %.*s\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEID.charactersLen, doc->V2G_Message.Body.CurrentDemandRes.EVSEID.characters); printf(" SAScheduleTupleID: %d\n", doc->V2G_Message.Body.CurrentDemandRes.SAScheduleTupleID); if (doc->V2G_Message.Body.CurrentDemandRes.MeterInfo_isUsed) { printf(" MeterInfo:\n"); printf(" MeterID: %.*s\n", doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.MeterID.charactersLen, doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.MeterID.characters); if (doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.MeterReading_isUsed) { printf(" MeterReading: %llu Wh\n", doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.MeterReading); } if (doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.SigMeterReading_isUsed) { printf(" SigMeterReading: "); for(int i = 0; i < doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.SigMeterReading.bytesLen; i++) { printf("%02X", doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.SigMeterReading.bytes[i]); } printf("\n"); } if (doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.MeterStatus_isUsed) { printf(" MeterStatus: %d\n", doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.MeterStatus); } if (doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.TMeter_isUsed) { printf(" TMeter: %lld\n", doc->V2G_Message.Body.CurrentDemandRes.MeterInfo.TMeter); } } if (doc->V2G_Message.Body.CurrentDemandRes.ReceiptRequired_isUsed) { printf(" ReceiptRequired: %s\n", doc->V2G_Message.Body.CurrentDemandRes.ReceiptRequired ? "true" : "false"); } } else if (doc->V2G_Message.Body.WeldingDetectionReq_isUsed) { printf(" Message Type: WeldingDetectionReq\n"); } else if (doc->V2G_Message.Body.WeldingDetectionRes_isUsed) { printf(" Message Type: WeldingDetectionRes\n"); printf(" ResponseCode: %d\n", doc->V2G_Message.Body.WeldingDetectionRes.ResponseCode); } else { printf(" Message Type: Unknown or unhandled message type\n"); printf(" Debug: Checking which flags are set...\n"); // Debug output to see which flags might be set } } printf("\n"); } void print_iso2_message(struct iso2EXIDocument *doc) { printf("=== ISO2 V2G Message ===\n"); if (doc->V2G_Message_isUsed) { printf("Header:\n"); print_session_id(doc->V2G_Message.Header.SessionID.bytes, doc->V2G_Message.Header.SessionID.bytesLen); printf("\nBody:\n"); if (doc->V2G_Message.Body.SessionSetupReq_isUsed) { printf(" Message Type: SessionSetupReq\n"); printf(" EVCCID: "); for(size_t i = 0; i < doc->V2G_Message.Body.SessionSetupReq.EVCCID.bytesLen; i++) { printf("%02X", doc->V2G_Message.Body.SessionSetupReq.EVCCID.bytes[i]); } printf(" ("); for(size_t i = 0; i < doc->V2G_Message.Body.SessionSetupReq.EVCCID.bytesLen; i++) { if (doc->V2G_Message.Body.SessionSetupReq.EVCCID.bytes[i] >= 32 && doc->V2G_Message.Body.SessionSetupReq.EVCCID.bytes[i] <= 126) { printf("%c", doc->V2G_Message.Body.SessionSetupReq.EVCCID.bytes[i]); } else { printf("."); } } printf(")\n"); } // Add more ISO2 message types as needed else { printf(" Message Type: Other ISO2 message (not fully implemented)\n"); } } printf("\n"); } int main(int argc, char *argv[]) { int xml_mode = 0; char *filename = NULL; if (argc == 2) { filename = argv[1]; } else if (argc == 3 && strcmp(argv[1], "-decode") == 0) { xml_mode = 1; filename = argv[2]; } else { printf("Usage: %s [-decode] input.exi\n", argv[0]); printf("Enhanced EXI viewer with detailed message parsing\n"); printf(" -decode Output in XML format\n"); printf(" (default) Output detailed analysis\n"); return -1; } uint8_t buffer[BUFFER_SIZE]; bitstream_t stream; size_t pos = 0; int errn = 0; struct iso1EXIDocument iso1Doc; struct iso2EXIDocument iso2Doc; struct dinEXIDocument dinDoc; // Initialize documents init_iso1EXIDocument(&iso1Doc); init_iso2EXIDocument(&iso2Doc); init_dinEXIDocument(&dinDoc); // Read file errn = readBytesFromFile(filename, buffer, BUFFER_SIZE, &pos); if (errn != 0) { printf("Error reading file: %s\n", filename); return -1; } if (!xml_mode) { printf("File: %s (%zu bytes)\n", filename, pos); printf("Raw hex data: "); for(size_t i = 0; i < (pos > 32 ? 32 : pos); i++) { printf("%02X ", buffer[i]); } if (pos > 32) printf("..."); printf("\n\n"); } // Setup stream pos = 0; // reset position for decoding stream.size = BUFFER_SIZE; stream.data = buffer; stream.pos = &pos; stream.buffer = 0; stream.capacity = 0; // Try ISO1 first pos = 0; if (!xml_mode) printf("Trying ISO1 decoder...\n"); errn = decode_iso1ExiDocument(&stream, &iso1Doc); if (errn == 0) { if (!xml_mode) printf("✓ Successfully decoded as ISO1\n\n"); if (xml_mode) { print_iso1_xml(&iso1Doc); } else { print_iso1_message(&iso1Doc); } return 0; } else { if (!xml_mode) printf("✗ ISO1 decode failed (error: %d)\n", errn); } // Try ISO2 pos = 0; if (!xml_mode) printf("Trying ISO2 decoder...\n"); errn = decode_iso2ExiDocument(&stream, &iso2Doc); if (errn == 0) { if (!xml_mode) printf("✓ Successfully decoded as ISO2\n\n"); print_iso2_message(&iso2Doc); return 0; } else { if (!xml_mode) printf("✗ ISO2 decode failed (error: %d)\n", errn); } // Try DIN pos = 0; if (!xml_mode) printf("Trying DIN decoder...\n"); errn = decode_dinExiDocument(&stream, &dinDoc); if (errn == 0) { if (!xml_mode) { printf("✓ Successfully decoded as DIN\n\n"); printf("=== DIN V2G Message ===\n"); // Add DIN message printing as needed } return 0; } else { if (!xml_mode) printf("✗ DIN decode failed (error: %d)\n", errn); } if (!xml_mode) { printf("\n❌ Could not decode EXI file with any supported codec\n"); printf("Supported formats: ISO1, ISO2, DIN\n"); } return -1; }