From 27c5824b577d0e82bbcb60f760f2ff58dfcf8140 Mon Sep 17 00:00:00 2001 From: docker-debian Date: Fri, 12 Sep 2025 07:24:52 +0900 Subject: [PATCH] feat: Complete Phase 2 Session & Service Management messages in C MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implemented comprehensive support for ISO 15118-2 Phase 2 messages: - SessionSetupReq/Res with EVCCID and EVSEID parsing - ServiceDiscoveryReq/Res with payment options and charge services - AuthorizationReq/Res with ID and challenge handling - ChargeParameterDiscoveryReq/Res with DC parameters and schedules Added 8 detailed helper functions with emoji indicators for improved readability and comprehensive parameter parsing including physical values, status codes, and complex nested structures. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- V2GDecoder.c | 254 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) diff --git a/V2GDecoder.c b/V2GDecoder.c index a5f61cd..32a2195 100644 --- a/V2GDecoder.c +++ b/V2GDecoder.c @@ -31,6 +31,16 @@ #define V2G_PAYLOAD_ISO2 0x8002 // ISO 15118-20 payload type #define EXI_START_PATTERN 0x8098 // EXI document start pattern +// Function declarations for Phase 2 Session & Service Management helper functions +void print_session_setup_req_details(struct iso1SessionSetupReqType *sessionSetupReq); +void print_session_setup_res_details(struct iso1SessionSetupResType *sessionSetupRes); +void print_service_discovery_req_details(struct iso1ServiceDiscoveryReqType *serviceDiscoveryReq); +void print_service_discovery_res_details(struct iso1ServiceDiscoveryResType *serviceDiscoveryRes); +void print_authorization_req_details(struct iso1AuthorizationReqType *authorizationReq); +void print_authorization_res_details(struct iso1AuthorizationResType *authorizationRes); +void print_charge_param_discovery_req_details(struct iso1ChargeParameterDiscoveryReqType *chargeParamReq); +void print_charge_param_discovery_res_details(struct iso1ChargeParameterDiscoveryResType *chargeParamRes); + // 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) { @@ -1017,6 +1027,38 @@ void print_iso1_message(struct iso1EXIDocument* doc) { doc->V2G_Message.Body.CurrentDemandRes.EVSEID.characters); printf("SAScheduleTupleID: %d\n", doc->V2G_Message.Body.CurrentDemandRes.SAScheduleTupleID); } + else if (doc->V2G_Message.Body.SessionSetupReq_isUsed) { + printf("🔐 SessionSetupReq: Charging session initialization\n"); + print_session_setup_req_details(&doc->V2G_Message.Body.SessionSetupReq); + } + else if (doc->V2G_Message.Body.SessionSetupRes_isUsed) { + printf("✅ SessionSetupRes: Session setup response\n"); + print_session_setup_res_details(&doc->V2G_Message.Body.SessionSetupRes); + } + else if (doc->V2G_Message.Body.ServiceDiscoveryReq_isUsed) { + printf("🔍 ServiceDiscoveryReq: Available charging services discovery\n"); + print_service_discovery_req_details(&doc->V2G_Message.Body.ServiceDiscoveryReq); + } + else if (doc->V2G_Message.Body.ServiceDiscoveryRes_isUsed) { + printf("✅ ServiceDiscoveryRes: Service discovery response\n"); + print_service_discovery_res_details(&doc->V2G_Message.Body.ServiceDiscoveryRes); + } + else if (doc->V2G_Message.Body.AuthorizationReq_isUsed) { + printf("🔑 AuthorizationReq: Charging authorization verification\n"); + print_authorization_req_details(&doc->V2G_Message.Body.AuthorizationReq); + } + else if (doc->V2G_Message.Body.AuthorizationRes_isUsed) { + printf("✅ AuthorizationRes: Authorization response\n"); + print_authorization_res_details(&doc->V2G_Message.Body.AuthorizationRes); + } + else if (doc->V2G_Message.Body.ChargeParameterDiscoveryReq_isUsed) { + printf("⚙️ ChargeParameterDiscoveryReq: Charging parameter exchange\n"); + print_charge_param_discovery_req_details(&doc->V2G_Message.Body.ChargeParameterDiscoveryReq); + } + else if (doc->V2G_Message.Body.ChargeParameterDiscoveryRes_isUsed) { + printf("✅ ChargeParameterDiscoveryRes: Charge parameter response\n"); + print_charge_param_discovery_res_details(&doc->V2G_Message.Body.ChargeParameterDiscoveryRes); + } else if (doc->V2G_Message.Body.CurrentDemandReq_isUsed) { printf("Message Type: CurrentDemandReq\n"); @@ -1083,6 +1125,218 @@ void print_iso1_message(struct iso1EXIDocument* doc) { printf("\n"); } +// Helper function to parse and print session setup request details +void print_session_setup_req_details(struct iso1SessionSetupReqType *sessionSetupReq) { + printf(" 🆔 EVCCID: "); + for(int i = 0; i < sessionSetupReq->EVCCID.bytesLen; i++) { + printf("%02X", sessionSetupReq->EVCCID.bytes[i]); + } + printf("\n"); +} + +// Helper function to parse and print session setup response details +void print_session_setup_res_details(struct iso1SessionSetupResType *sessionSetupRes) { + printf(" 📋 Response Code: %d\n", sessionSetupRes->ResponseCode); + printf(" 🆔 EVSEID: %.*s\n", + sessionSetupRes->EVSEID.charactersLen, + sessionSetupRes->EVSEID.characters); + + if(sessionSetupRes->EVSETimeStamp_isUsed) { + printf(" ⏰ EVSETimeStamp: %ld\n", sessionSetupRes->EVSETimeStamp); + } +} + +// Helper function to parse and print service discovery request details +void print_service_discovery_req_details(struct iso1ServiceDiscoveryReqType *serviceDiscoveryReq) { + if(serviceDiscoveryReq->ServiceScope_isUsed) { + printf(" 🔍 ServiceScope: %.*s\n", + serviceDiscoveryReq->ServiceScope.charactersLen, + serviceDiscoveryReq->ServiceScope.characters); + } + + if(serviceDiscoveryReq->ServiceCategory_isUsed) { + printf(" 📂 ServiceCategory: %d\n", serviceDiscoveryReq->ServiceCategory); + } +} + +// Helper function to parse and print service discovery response details +void print_service_discovery_res_details(struct iso1ServiceDiscoveryResType *serviceDiscoveryRes) { + printf(" 📋 Response Code: %d\n", serviceDiscoveryRes->ResponseCode); + printf(" ⚡ PaymentOptionList:\n"); + for(int i = 0; i < serviceDiscoveryRes->PaymentOptionList.PaymentOption.arrayLen; i++) { + printf(" Payment Option %d: %d\n", i+1, serviceDiscoveryRes->PaymentOptionList.PaymentOption.array[i]); + } + + printf(" 🔧 ChargeService:\n"); + printf(" ServiceID: %d\n", serviceDiscoveryRes->ChargeService.ServiceID); + printf(" ServiceName: %.*s\n", + serviceDiscoveryRes->ChargeService.ServiceName_isUsed ? serviceDiscoveryRes->ChargeService.ServiceName.charactersLen : 0, + serviceDiscoveryRes->ChargeService.ServiceName_isUsed ? serviceDiscoveryRes->ChargeService.ServiceName.characters : ""); + printf(" ServiceCategory: %d\n", serviceDiscoveryRes->ChargeService.ServiceCategory); + printf(" FreeService: %s\n", serviceDiscoveryRes->ChargeService.FreeService ? "true" : "false"); + + if(serviceDiscoveryRes->ServiceList_isUsed && serviceDiscoveryRes->ServiceList.Service.arrayLen > 0) { + printf(" 📋 ServiceList:\n"); + for(int i = 0; i < serviceDiscoveryRes->ServiceList.Service.arrayLen; i++) { + printf(" Service %d - ID: %d, Category: %d\n", + i+1, + serviceDiscoveryRes->ServiceList.Service.array[i].ServiceID, + serviceDiscoveryRes->ServiceList.Service.array[i].ServiceCategory); + } + } +} + +// Helper function to parse and print authorization request details +void print_authorization_req_details(struct iso1AuthorizationReqType *authorizationReq) { + if(authorizationReq->Id_isUsed) { + printf(" 🆔 ID: %.*s\n", + authorizationReq->Id.charactersLen, + authorizationReq->Id.characters); + } + + if(authorizationReq->GenChallenge_isUsed) { + printf(" 🎲 GenChallenge: "); + for(int i = 0; i < authorizationReq->GenChallenge.bytesLen; i++) { + printf("%02X", authorizationReq->GenChallenge.bytes[i]); + } + printf("\n"); + } +} + +// Helper function to parse and print authorization response details +void print_authorization_res_details(struct iso1AuthorizationResType *authorizationRes) { + printf(" 📋 Response Code: %d\n", authorizationRes->ResponseCode); + printf(" ⚡ EVSEProcessing: %d\n", authorizationRes->EVSEProcessing); +} + +// Helper function to parse and print charge parameter discovery request details +void print_charge_param_discovery_req_details(struct iso1ChargeParameterDiscoveryReqType *chargeParamReq) { + if(chargeParamReq->MaxEntriesSAScheduleTuple_isUsed) { + printf(" 📊 MaxEntriesSAScheduleTuple: %d\n", chargeParamReq->MaxEntriesSAScheduleTuple); + } + + printf(" 🔌 RequestedEnergyTransferMode: %d\n", chargeParamReq->RequestedEnergyTransferMode); + + if(chargeParamReq->DC_EVChargeParameter_isUsed) { + printf(" ⚡ DC_EVChargeParameter:\n"); + printf(" 📋 DC_EVStatus:\n"); + printf(" 🔋 EVReady: %s\n", chargeParamReq->DC_EVChargeParameter.DC_EVStatus.EVReady ? "true" : "false"); + printf(" ⚡ EVErrorCode: %d\n", chargeParamReq->DC_EVChargeParameter.DC_EVStatus.EVErrorCode); + printf(" 🔌 EVRESSSOC: %d%%\n", chargeParamReq->DC_EVChargeParameter.DC_EVStatus.EVRESSSOC); + + printf(" 🔋 EVMaximumCurrentLimit:\n"); + printf(" 📊 Multiplier: %d\n", chargeParamReq->DC_EVChargeParameter.EVMaximumCurrentLimit.Multiplier); + printf(" 🔢 Unit: %d\n", chargeParamReq->DC_EVChargeParameter.EVMaximumCurrentLimit.Unit); + printf(" 💯 Value: %d\n", chargeParamReq->DC_EVChargeParameter.EVMaximumCurrentLimit.Value); + + printf(" ⚡ EVMaximumVoltageLimit:\n"); + printf(" 📊 Multiplier: %d\n", chargeParamReq->DC_EVChargeParameter.EVMaximumVoltageLimit.Multiplier); + printf(" 🔢 Unit: %d\n", chargeParamReq->DC_EVChargeParameter.EVMaximumVoltageLimit.Unit); + printf(" 💯 Value: %d\n", chargeParamReq->DC_EVChargeParameter.EVMaximumVoltageLimit.Value); + + if(chargeParamReq->DC_EVChargeParameter.EVMaximumPowerLimit_isUsed) { + printf(" 🔌 EVMaximumPowerLimit:\n"); + printf(" 📊 Multiplier: %d\n", chargeParamReq->DC_EVChargeParameter.EVMaximumPowerLimit.Multiplier); + printf(" 🔢 Unit: %d\n", chargeParamReq->DC_EVChargeParameter.EVMaximumPowerLimit.Unit); + printf(" 💯 Value: %d\n", chargeParamReq->DC_EVChargeParameter.EVMaximumPowerLimit.Value); + } + + if(chargeParamReq->DC_EVChargeParameter.EVEnergyCapacity_isUsed) { + printf(" 🔋 EVEnergyCapacity:\n"); + printf(" 📊 Multiplier: %d\n", chargeParamReq->DC_EVChargeParameter.EVEnergyCapacity.Multiplier); + printf(" 🔢 Unit: %d\n", chargeParamReq->DC_EVChargeParameter.EVEnergyCapacity.Unit); + printf(" 💯 Value: %d\n", chargeParamReq->DC_EVChargeParameter.EVEnergyCapacity.Value); + } + + if(chargeParamReq->DC_EVChargeParameter.EVEnergyRequest_isUsed) { + printf(" ⚡ EVEnergyRequest:\n"); + printf(" 📊 Multiplier: %d\n", chargeParamReq->DC_EVChargeParameter.EVEnergyRequest.Multiplier); + printf(" 🔢 Unit: %d\n", chargeParamReq->DC_EVChargeParameter.EVEnergyRequest.Unit); + printf(" 💯 Value: %d\n", chargeParamReq->DC_EVChargeParameter.EVEnergyRequest.Value); + } + + if(chargeParamReq->DC_EVChargeParameter.FullSOC_isUsed) { + printf(" 🔋 FullSOC: %d%%\n", chargeParamReq->DC_EVChargeParameter.FullSOC); + } + + if(chargeParamReq->DC_EVChargeParameter.BulkSOC_isUsed) { + printf(" 📊 BulkSOC: %d%%\n", chargeParamReq->DC_EVChargeParameter.BulkSOC); + } + } +} + +// Helper function to parse and print charge parameter discovery response details +void print_charge_param_discovery_res_details(struct iso1ChargeParameterDiscoveryResType *chargeParamRes) { + printf(" 📋 Response Code: %d\n", chargeParamRes->ResponseCode); + printf(" ⚡ EVSEProcessing: %d\n", chargeParamRes->EVSEProcessing); + + if(chargeParamRes->SAScheduleList_isUsed) { + printf(" 📅 SASchedules:\n"); + printf(" Schedule Entries: %d\n", chargeParamRes->SAScheduleList.SAScheduleTuple.arrayLen); + + for(int i = 0; i < chargeParamRes->SAScheduleList.SAScheduleTuple.arrayLen; i++) { + printf(" Schedule %d:\n", i+1); + printf(" SAScheduleTupleID: %d\n", chargeParamRes->SAScheduleList.SAScheduleTuple.array[i].SAScheduleTupleID); + + if(chargeParamRes->SAScheduleList.SAScheduleTuple.array[i].PMaxSchedule.PMaxScheduleEntry.arrayLen > 0) { + printf(" PMaxScheduleEntries: %d\n", + chargeParamRes->SAScheduleList.SAScheduleTuple.array[i].PMaxSchedule.PMaxScheduleEntry.arrayLen); + } + } + } + + if(chargeParamRes->DC_EVSEChargeParameter_isUsed) { + printf(" 🔌 DC_EVSEChargeParameter:\n"); + printf(" 📊 DC_EVSEStatus:\n"); + printf(" 🔌 EVSEIsolationStatus: %d\n", chargeParamRes->DC_EVSEChargeParameter.DC_EVSEStatus.EVSEIsolationStatus); + printf(" ⚡ EVSEStatusCode: %d\n", chargeParamRes->DC_EVSEChargeParameter.DC_EVSEStatus.EVSEStatusCode); + + printf(" ⚡ EVSEMaximumCurrentLimit:\n"); + printf(" 📊 Multiplier: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEMaximumCurrentLimit.Multiplier); + printf(" 🔢 Unit: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEMaximumCurrentLimit.Unit); + printf(" 💯 Value: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEMaximumCurrentLimit.Value); + + printf(" 🔋 EVSEMaximumVoltageLimit:\n"); + printf(" 📊 Multiplier: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEMaximumVoltageLimit.Multiplier); + printf(" 🔢 Unit: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEMaximumVoltageLimit.Unit); + printf(" 💯 Value: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEMaximumVoltageLimit.Value); + + printf(" 🔌 EVSEMaximumPowerLimit:\n"); + printf(" 📊 Multiplier: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEMaximumPowerLimit.Multiplier); + printf(" 🔢 Unit: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEMaximumPowerLimit.Unit); + printf(" 💯 Value: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEMaximumPowerLimit.Value); + + printf(" ⚡ EVSEMinimumCurrentLimit:\n"); + printf(" 📊 Multiplier: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEMinimumCurrentLimit.Multiplier); + printf(" 🔢 Unit: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEMinimumCurrentLimit.Unit); + printf(" 💯 Value: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEMinimumCurrentLimit.Value); + + printf(" 🔋 EVSEMinimumVoltageLimit:\n"); + printf(" 📊 Multiplier: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEMinimumVoltageLimit.Multiplier); + printf(" 🔢 Unit: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEMinimumVoltageLimit.Unit); + printf(" 💯 Value: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEMinimumVoltageLimit.Value); + + if(chargeParamRes->DC_EVSEChargeParameter.EVSECurrentRegulationTolerance_isUsed) { + printf(" 📊 EVSECurrentRegulationTolerance:\n"); + printf(" 📊 Multiplier: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSECurrentRegulationTolerance.Multiplier); + printf(" 🔢 Unit: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSECurrentRegulationTolerance.Unit); + printf(" 💯 Value: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSECurrentRegulationTolerance.Value); + } + + printf(" ⚡ EVSEPeakCurrentRipple:\n"); + printf(" 📊 Multiplier: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEPeakCurrentRipple.Multiplier); + printf(" 🔢 Unit: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEPeakCurrentRipple.Unit); + printf(" 💯 Value: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEPeakCurrentRipple.Value); + + if(chargeParamRes->DC_EVSEChargeParameter.EVSEEnergyToBeDelivered_isUsed) { + printf(" 🔋 EVSEEnergyToBeDelivered:\n"); + printf(" 📊 Multiplier: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEEnergyToBeDelivered.Multiplier); + printf(" 🔢 Unit: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEEnergyToBeDelivered.Unit); + printf(" 💯 Value: %d\n", chargeParamRes->DC_EVSEChargeParameter.EVSEEnergyToBeDelivered.Value); + } + } +} + int main(int argc, char *argv[]) { int xml_mode = 0; int encode_mode = 0;