/* * Copyright (C) 2007-2010 Siemens AG * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ /******************************************************************* * * @author Sebastian.Kaebisch.EXT@siemens.com * @version 0.3 * @contact Joerg.Heuer@siemens.com * ********************************************************************/ #include "v2g_service.h" #include "v2g_serviceDispatcher.h" #include "v2g_serviceDataTypes.h" #include "v2g_serviceMethods.h" #include "v2g_serviceDataSerializiation.h" #include "EXITypes.h" #include "EXIDecoder.h" #include "EXIEncoder.h" /** * Deserialize an element value of the EXI stream and assign it to the * service data structure */ static int deserializeElementCharacter(struct v2gService* service) { switch(service->eqn.namespaceURI) { case 4: switch(service->eqn.localPart) { case 26: /*PEVID*/ if(service->val.type == STRING) { /* string copy and string length assignment */ memcpy(service->v2gMsg.Body.SessionSetupReq.PEVID.data, service->val.string.codepoints,service->val.string.len); service->v2gMsg.Body.SessionSetupReq.PEVID.arraylen.data = service->val.string.len; } else { return -1; /* wrong data type */ } /* is used */ service->v2gMsg.Body.SessionSetupReq.isused.PEVID=1; break; case 58: /*ServiceType*/ if(service->val.type == ENUMERATION) { service->v2gMsg.Body.ServiceDiscoveryReq.ServiceType=service->val.enumeration; } else { return -1; /* wrong data type */ } /* is used */ service->v2gMsg.Body.ServiceDiscoveryReq.isused.ServiceType=1; break; case 57: /*ServiceScope*/ if(service->val.type == STRING) { /* string copy and string length assignment */ memcpy(service->v2gMsg.Body.ServiceDiscoveryReq.ServiceScope.data, service->val.string.codepoints,service->val.string.len); service->v2gMsg.Body.ServiceDiscoveryReq.ServiceScope.arraylen.data = service->val.string.len; } else { return -1; /* wrong data type */ } /* is used */ service->v2gMsg.Body.ServiceDiscoveryReq.isused.ServiceScope=1; break; case 31: /*PEVPubKey*/ if(service->val.type == BINARY_HEX) { /* array copy and array length assignment */ memcpy(service->v2gMsg.Body.ServicePaymentSelectionReq.PEVPubKey.data, service->val.binary.data,service->val.binary.len); service->v2gMsg.Body.ServicePaymentSelectionReq.PEVPubKey.arraylen.data = service->val.binary.len; } else { return -1; /* wrong data type */ } break; case 1: /*ContractID*/ if(service->val.type == STRING) { /* string copy and string length assignment */ memcpy(service->v2gMsg.Body.PaymentDetailsReq.ContractID.data, service->val.string.codepoints,service->val.string.len); service->v2gMsg.Body.PaymentDetailsReq.ContractID.arraylen.data = service->val.string.len; } else { return -1; /* wrong data type */ } break; case 10: /*EoC*/ if(service->val.type == INTEGER_32) { service->v2gMsg.Body.PowerDiscoveryReq.EoC=service->val.int32; } else { return -1; /* wrong data type */ } break; case 27: /*PEVMaxPhases*/ if(service->val.type == INTEGER_16) { service->v2gMsg.Body.PowerDiscoveryReq.PEVMaxPhases=service->val.int32; } else { return -1; /* wrong data type */ } break; case 45: /*ReqLockStatus*/ if(service->val.type == BOOLEAN) { service->v2gMsg.Body.LineLockReq.ReqLockStatus=service->val.boolean; } else { return -1; /* wrong data type */ } break; case 46: /*ReqSwitchStatus*/ if(service->val.type == BOOLEAN) { service->v2gMsg.Body.PowerDeliveryReq.ReqSwitchStatus=service->val.boolean; } else { return -1; /* wrong data type */ } break; case 64: /*Tariff*/ if(service->val.type == ENUMERATION) { service->v2gMsg.Body.PowerDeliveryReq.Tariff=service->val.enumeration; } else { return -1; /* wrong data type */ } /* is used */ service->v2gMsg.Body.PowerDeliveryReq.isused.Tariff=1; break; case 63: /*TCurrent*/ if(service->val.type == INTEGER_32) { service->v2gMsg.Body.MeteringReceiptReq.TCurrent=service->val.int32; } else { return -1; /* wrong data type */ } /* is used */ service->v2gMsg.Body.MeteringReceiptReq.isused.TCurrent=1; break; } /* close switch(service->eqn.localPart) */ break; case 5: switch(service->eqn.localPart) { case 34: /*SessionID*/ if(service->val.type == BINARY_HEX) { /* array copy and array length assignment */ memcpy(service->v2gMsg.Header.SessionInformation.SessionID.data, service->val.binary.data,service->val.binary.len); service->v2gMsg.Header.SessionInformation.SessionID.arraylen.data = service->val.binary.len; } else { return -1; /* wrong data type */ } break; case 32: /*ServiceSessionID*/ if(service->val.type == BINARY_HEX) { /* array copy and array length assignment */ memcpy(service->v2gMsg.Header.SessionInformation.ServiceSessionID.data, service->val.binary.data,service->val.binary.len); service->v2gMsg.Header.SessionInformation.ServiceSessionID.arraylen.data = service->val.binary.len; } else { return -1; /* wrong data type */ } /* is used */ service->v2gMsg.Header.SessionInformation.isused.ServiceSessionID=1; break; case 24: /*ProtocolVersion*/ if(service->val.type == STRING) { /* string copy and string length assignment */ memcpy(service->v2gMsg.Header.SessionInformation.ProtocolVersion.data, service->val.string.codepoints,service->val.string.len); service->v2gMsg.Header.SessionInformation.ProtocolVersion.arraylen.data = service->val.string.len; } else { return -1; /* wrong data type */ } /* is used */ service->v2gMsg.Header.SessionInformation.isused.ProtocolVersion=1; break; case 9: /*Event*/ if(service->val.type == ENUMERATION) { service->v2gMsg.Header.Notification.EventList.Event=service->val.enumeration; } else { return -1; /* wrong data type */ } break; case 13: /*FaultCode*/ if(service->val.type == ENUMERATION) { service->v2gMsg.Header.Notification.FaultCode=service->val.enumeration; } else { return -1; /* wrong data type */ } /* is used */ service->v2gMsg.Header.Notification.isused.FaultCode=1; break; case 14: /*FaultMsg*/ if(service->val.type == STRING) { /* string copy and string length assignment */ memcpy(service->v2gMsg.Header.Notification.FaultMsg.data, service->val.string.codepoints,service->val.string.len); service->v2gMsg.Header.Notification.FaultMsg.arraylen.data = service->val.string.len; } else { return -1; /* wrong data type */ } /* is used */ service->v2gMsg.Header.Notification.isused.FaultMsg=1; break; case 4: /*ConnectorLocked*/ if(service->val.type == BOOLEAN) { if(service->idPath.id[2] == 59) { service->v2gMsg.Body.SessionSetupReq.PEVStatus.ConnectorLocked=service->val.boolean; } else if(service->idPath.id[2] == 41) { service->v2gMsg.Body.PowerDiscoveryReq.PEVStatus.ConnectorLocked=service->val.boolean; } else if(service->idPath.id[2] == 11) { service->v2gMsg.Body.LineLockReq.PEVStatus.ConnectorLocked=service->val.boolean; } else if(service->idPath.id[2] == 37) { service->v2gMsg.Body.PowerDeliveryReq.PEVStatus.ConnectorLocked=service->val.boolean; } else if(service->idPath.id[2] == 17) { service->v2gMsg.Body.MeteringReceiptReq.PEVStatus.ConnectorLocked=service->val.boolean; } } else { return -1; /* wrong data type */ } break; case 0: /*ChargerStandby*/ if(service->val.type == BOOLEAN) { if(service->idPath.id[2] == 59) { service->v2gMsg.Body.SessionSetupReq.PEVStatus.ChargerStandby=service->val.boolean; } else if(service->idPath.id[2] == 41) { service->v2gMsg.Body.PowerDiscoveryReq.PEVStatus.ChargerStandby=service->val.boolean; } else if(service->idPath.id[2] == 11) { service->v2gMsg.Body.LineLockReq.PEVStatus.ChargerStandby=service->val.boolean; } else if(service->idPath.id[2] == 37) { service->v2gMsg.Body.PowerDeliveryReq.PEVStatus.ChargerStandby=service->val.boolean; } else if(service->idPath.id[2] == 17) { service->v2gMsg.Body.MeteringReceiptReq.PEVStatus.ChargerStandby=service->val.boolean; } } else { return -1; /* wrong data type */ } break; case 20: /*Multiplier*/ if(service->val.type == ENUMERATION) { if(service->idPath.id[3] == 2) { service->v2gMsg.Body.PowerDiscoveryReq.EAmount.Multiplier=service->val.enumeration; } else if(service->idPath.id[3] == 28) { service->v2gMsg.Body.PowerDiscoveryReq.PEVMaxPower.Multiplier=service->val.enumeration; } else if(service->idPath.id[3] == 29) { service->v2gMsg.Body.PowerDiscoveryReq.PEVMaxVoltage.Multiplier=service->val.enumeration; } else if(service->idPath.id[3] == 30) { service->v2gMsg.Body.PowerDiscoveryReq.PEVMinVoltage.Multiplier=service->val.enumeration; } else if(service->idPath.id[3] == 8) { service->v2gMsg.Body.PowerDiscoveryRes.EVSEVoltage.Multiplier=service->val.enumeration; } else if(service->idPath.id[3] == 4) { service->v2gMsg.Body.PowerDiscoveryRes.EVSEIMax.Multiplier=service->val.enumeration; } else if(service->idPath.id[3] == 6) { service->v2gMsg.Body.MeteringStatusRes.EVSEMaxPower.Multiplier=service->val.enumeration; } else if(service->idPath.id[3] == 25) { service->v2gMsg.Body.MeteringStatusRes.PCurrent.Multiplier=service->val.enumeration; } else if(service->idPath.id[2] == 37) { service->v2gMsg.Body.PowerDeliveryReq.ChargingProfile.ChargingProfileEntryMaxPower.Multiplier=service->val.enumeration; } else if(service->idPath.id[2] == 23) { service->v2gMsg.Body.MeteringStatusRes.MeterInfo.MeterReading.Multiplier=service->val.enumeration; } else if(service->idPath.id[7] == 46) { service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.Tariff[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.arraylen.Tariff].TariffEntries.TariffEntry[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.Tariff[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.arraylen.Tariff].TariffEntries.arraylen.TariffEntry].TariffPMax.Multiplier=service->val.enumeration; } else if(service->idPath.id[7] == 6) { service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.Tariff[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.arraylen.Tariff].TariffEntries.TariffEntry[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.Tariff[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.arraylen.Tariff].TariffEntries.arraylen.TariffEntry].EPrice.Multiplier=service->val.enumeration; } } else { return -1; /* wrong data type */ } break; case 49: /*Unit*/ if(service->val.type == ENUMERATION) { if(service->idPath.id[3] == 2) { service->v2gMsg.Body.PowerDiscoveryReq.EAmount.Unit=service->val.enumeration; } else if(service->idPath.id[3] == 28) { service->v2gMsg.Body.PowerDiscoveryReq.PEVMaxPower.Unit=service->val.enumeration; } else if(service->idPath.id[3] == 29) { service->v2gMsg.Body.PowerDiscoveryReq.PEVMaxVoltage.Unit=service->val.enumeration; } else if(service->idPath.id[3] == 30) { service->v2gMsg.Body.PowerDiscoveryReq.PEVMinVoltage.Unit=service->val.enumeration; } else if(service->idPath.id[3] == 8) { service->v2gMsg.Body.PowerDiscoveryRes.EVSEVoltage.Unit=service->val.enumeration; } else if(service->idPath.id[3] == 4) { service->v2gMsg.Body.PowerDiscoveryRes.EVSEIMax.Unit=service->val.enumeration; } else if(service->idPath.id[3] == 6) { service->v2gMsg.Body.MeteringStatusRes.EVSEMaxPower.Unit=service->val.enumeration; } else if(service->idPath.id[3] == 25) { service->v2gMsg.Body.MeteringStatusRes.PCurrent.Unit=service->val.enumeration; } else if(service->idPath.id[2] == 37) { service->v2gMsg.Body.PowerDeliveryReq.ChargingProfile.ChargingProfileEntryMaxPower.Unit=service->val.enumeration; } else if(service->idPath.id[2] == 23) { service->v2gMsg.Body.MeteringStatusRes.MeterInfo.MeterReading.Unit=service->val.enumeration; } else if(service->idPath.id[7] == 46) { service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.Tariff[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.arraylen.Tariff].TariffEntries.TariffEntry[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.Tariff[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.arraylen.Tariff].TariffEntries.arraylen.TariffEntry].TariffPMax.Unit=service->val.enumeration; } else if(service->idPath.id[7] == 6) { service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.Tariff[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.arraylen.Tariff].TariffEntries.TariffEntry[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.Tariff[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.arraylen.Tariff].TariffEntries.arraylen.TariffEntry].EPrice.Unit=service->val.enumeration; } } else { return -1; /* wrong data type */ } break; case 50: /*Value*/ if(service->val.type == INTEGER_32) { if(service->idPath.id[3] == 2) { service->v2gMsg.Body.PowerDiscoveryReq.EAmount.Value=service->val.int32; } else if(service->idPath.id[3] == 28) { service->v2gMsg.Body.PowerDiscoveryReq.PEVMaxPower.Value=service->val.int32; } else if(service->idPath.id[3] == 29) { service->v2gMsg.Body.PowerDiscoveryReq.PEVMaxVoltage.Value=service->val.int32; } else if(service->idPath.id[3] == 30) { service->v2gMsg.Body.PowerDiscoveryReq.PEVMinVoltage.Value=service->val.int32; } else if(service->idPath.id[3] == 8) { service->v2gMsg.Body.PowerDiscoveryRes.EVSEVoltage.Value=service->val.int32; } else if(service->idPath.id[3] == 4) { service->v2gMsg.Body.PowerDiscoveryRes.EVSEIMax.Value=service->val.int32; } else if(service->idPath.id[3] == 6) { service->v2gMsg.Body.MeteringStatusRes.EVSEMaxPower.Value=service->val.int32; } else if(service->idPath.id[3] == 25) { service->v2gMsg.Body.MeteringStatusRes.PCurrent.Value=service->val.int32; } else if(service->idPath.id[2] == 37) { service->v2gMsg.Body.PowerDeliveryReq.ChargingProfile.ChargingProfileEntryMaxPower.Value=service->val.int32; } else if(service->idPath.id[2] == 23) { service->v2gMsg.Body.MeteringStatusRes.MeterInfo.MeterReading.Value=service->val.int32; } else if(service->idPath.id[7] == 46) { service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.Tariff[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.arraylen.Tariff].TariffEntries.TariffEntry[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.Tariff[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.arraylen.Tariff].TariffEntries.arraylen.TariffEntry].TariffPMax.Value=service->val.int32; } else if(service->idPath.id[7] == 6) { service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.Tariff[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.arraylen.Tariff].TariffEntries.TariffEntry[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.Tariff[service->v2gMsg.Body.PowerDiscoveryRes.TariffTable.arraylen.Tariff].TariffEntries.arraylen.TariffEntry].EPrice.Value=service->val.int32; } } else { return -1; /* wrong data type */ } break; case 2: /*ChargingProfileEntryStart*/ if(service->val.type == INTEGER_32) { service->v2gMsg.Body.PowerDeliveryReq.ChargingProfile.ChargingProfileEntryStart=service->val.int32; } else { return -1; /* wrong data type */ } break; case 16: /*MeterID*/ if(service->val.type == STRING) { /* string copy and string length assignment */ memcpy(service->v2gMsg.Body.MeteringStatusRes.MeterInfo.MeterID.data, service->val.string.codepoints,service->val.string.len); service->v2gMsg.Body.MeteringStatusRes.MeterInfo.MeterID.arraylen.data = service->val.string.len; } else { return -1; /* wrong data type */ } /* is used */ service->v2gMsg.Body.MeteringStatusRes.MeterInfo.isused.MeterID=1; break; case 19: /*MeterStatus*/ if(service->val.type == INTEGER_16) { if(service->idPath.id[2] == 23) { service->v2gMsg.Body.MeteringStatusRes.MeterInfo.MeterStatus=service->val.int32; } else if(service->idPath.id[2] == 17) { service->v2gMsg.Body.MeteringReceiptReq.MeterInfo.MeterStatus=service->val.int32; } } else { return -1; /* wrong data type */ } /* is used */ service->v2gMsg.Body.MeteringStatusRes.MeterInfo.isused.MeterStatus=1; break; case 37: /*TMeter*/ if(service->val.type == INTEGER_32) { if(service->idPath.id[2] == 23) { service->v2gMsg.Body.MeteringStatusRes.MeterInfo.TMeter=service->val.int32; } else if(service->idPath.id[2] == 17) { service->v2gMsg.Body.MeteringReceiptReq.MeterInfo.TMeter=service->val.int32; } } else { return -1; /* wrong data type */ } /* is used */ service->v2gMsg.Body.MeteringStatusRes.MeterInfo.isused.TMeter=1; break; } /* close switch(service->eqn.localPart) */ break; } /* close switch(service->eqn.namespaceURI) */ return 0; } /** * Depending on the current EXI event a message element is deserialized or a * defined service method is called in here */ static int deserializeElementOrServiceCall(struct v2gService* service) { switch(service->eqn.namespaceURI) { case 4: switch(service->eqn.localPart) { case 26:/* PEVID */ service->v2gMsg.Body.SessionSetupReq.isused.PEVID=1; service->v2gMsg.Body.MeteringReceiptReq.isused.PEVID=1; break; case 58:/* ServiceType */ /* is used */ service->v2gMsg.Body.ServiceDiscoveryReq.isused.ServiceType=1; break; case 57:/* ServiceScope */ /* is used */ service->v2gMsg.Body.ServiceDiscoveryReq.isused.ServiceScope=1; break; case 64:/* Tariff */ /* is used */ service->v2gMsg.Body.PowerDeliveryReq.isused.Tariff=1; break; case 0:/* ChargingProfile */ /* is used */ service->v2gMsg.Body.PowerDeliveryReq.isused.ChargingProfile=1; break; case 63:/* TCurrent */ /* is used */ service->v2gMsg.Body.MeteringReceiptReq.isused.TCurrent=1; break; case 59:/* SessionSetupReq */ /* test, if data length is unequal to the expected payload */ if((service->inStream.size)!= *(service->inStream.pos)) { service->errorCode = V2G_NON_VALID_MESSAGE; return -1; } /* service call */ sessionSetup(&(service->v2gMsg.Body.SessionSetupReq), &(service->v2gMsg.Body.SessionSetupRes)); /* signalize the response message */ service->v2gMsg.Body.isused.SessionSetupRes=1; /* serialize the response data */ if(serialize_message(service)) { /* serializiation error*/ service->errorCode= V2G_SERIALIZATION_FAILED; } break; case 48:/* ServiceDiscoveryReq */ /* test, if data length is unequal to the expected payload */ if((service->inStream.size)!= *(service->inStream.pos)) { service->errorCode = V2G_NON_VALID_MESSAGE; return -1; } /* service call */ serviceDiscovery(&(service->v2gMsg.Body.ServiceDiscoveryReq), &(service->v2gMsg.Body.ServiceDiscoveryRes)); /* signalize the response message */ service->v2gMsg.Body.isused.ServiceDiscoveryRes=1; /* serialize the response data */ if(serialize_message(service)) { /* serializiation error*/ service->errorCode= V2G_SERIALIZATION_FAILED; } break; case 53:/* ServicePaymentSelectionReq */ /* test, if data length is unequal to the expected payload */ if((service->inStream.size)!= *(service->inStream.pos)) { service->errorCode = V2G_NON_VALID_MESSAGE; return -1; } /* service call */ selectedServicePayment(&(service->v2gMsg.Body.ServicePaymentSelectionReq), &(service->v2gMsg.Body.ServicePaymentSelectionRes)); /* signalize the response message */ service->v2gMsg.Body.isused.ServicePaymentSelectionRes=1; /* serialize the response data */ if(serialize_message(service)) { /* serializiation error*/ service->errorCode= V2G_SERIALIZATION_FAILED; } break; case 33:/* PaymentDetailsReq */ /* test, if data length is unequal to the expected payload */ if((service->inStream.size)!= *(service->inStream.pos)) { service->errorCode = V2G_NON_VALID_MESSAGE; return -1; } /* service call */ paymentDetails(&(service->v2gMsg.Body.PaymentDetailsReq), &(service->v2gMsg.Body.PaymentDetailsRes)); /* signalize the response message */ service->v2gMsg.Body.isused.PaymentDetailsRes=1; /* serialize the response data */ if(serialize_message(service)) { /* serializiation error*/ service->errorCode= V2G_SERIALIZATION_FAILED; } break; case 41:/* PowerDiscoveryReq */ /* test, if data length is unequal to the expected payload */ if((service->inStream.size)!= *(service->inStream.pos)) { service->errorCode = V2G_NON_VALID_MESSAGE; return -1; } /* service call */ powerDiscovery(&(service->v2gMsg.Body.PowerDiscoveryReq), &(service->v2gMsg.Body.PowerDiscoveryRes)); /* signalize the response message */ service->v2gMsg.Body.isused.PowerDiscoveryRes=1; /* serialize the response data */ if(serialize_message(service)) { /* serializiation error*/ service->errorCode= V2G_SERIALIZATION_FAILED; } break; case 11:/* LineLockReq */ /* test, if data length is unequal to the expected payload */ if((service->inStream.size)!= *(service->inStream.pos)) { service->errorCode = V2G_NON_VALID_MESSAGE; return -1; } /* service call */ lineLock(&(service->v2gMsg.Body.LineLockReq), &(service->v2gMsg.Body.LineLockRes)); /* signalize the response message */ service->v2gMsg.Body.isused.LineLockRes=1; /* serialize the response data */ if(serialize_message(service)) { /* serializiation error*/ service->errorCode= V2G_SERIALIZATION_FAILED; } break; case 37:/* PowerDeliveryReq */ /* test, if data length is unequal to the expected payload */ if((service->inStream.size)!= *(service->inStream.pos)) { service->errorCode = V2G_NON_VALID_MESSAGE; return -1; } /* service call */ powerDelivery(&(service->v2gMsg.Body.PowerDeliveryReq), &(service->v2gMsg.Body.PowerDeliveryRes)); /* signalize the response message */ service->v2gMsg.Body.isused.PowerDeliveryRes=1; /* serialize the response data */ if(serialize_message(service)) { /* serializiation error*/ service->errorCode= V2G_SERIALIZATION_FAILED; } break; case 21:/* MeteringStatusReq */ /* test, if data length is unequal to the expected payload */ if((service->inStream.size)!= *(service->inStream.pos)) { service->errorCode = V2G_NON_VALID_MESSAGE; return -1; } /* service call */ meteringStatus(&(service->v2gMsg.Body.MeteringStatusReq), &(service->v2gMsg.Body.MeteringStatusRes)); /* signalize the response message */ service->v2gMsg.Body.isused.MeteringStatusRes=1; /* serialize the response data */ if(serialize_message(service)) { /* serializiation error*/ service->errorCode= V2G_SERIALIZATION_FAILED; } break; case 17:/* MeteringReceiptReq */ /* test, if data length is unequal to the expected payload */ if((service->inStream.size)!= *(service->inStream.pos)) { service->errorCode = V2G_NON_VALID_MESSAGE; return -1; } /* service call */ meteringReceipt(&(service->v2gMsg.Body.MeteringReceiptReq), &(service->v2gMsg.Body.MeteringReceiptRes)); /* signalize the response message */ service->v2gMsg.Body.isused.MeteringReceiptRes=1; /* serialize the response data */ if(serialize_message(service)) { /* serializiation error*/ service->errorCode= V2G_SERIALIZATION_FAILED; } break; } break; case 5: switch(service->eqn.localPart) { case 32:/* ServiceSessionID */ /* is used */ service->v2gMsg.Header.SessionInformation.isused.ServiceSessionID=1; break; case 24:/* ProtocolVersion */ /* is used */ service->v2gMsg.Header.SessionInformation.isused.ProtocolVersion=1; break; case 13:/* FaultCode */ /* is used */ service->v2gMsg.Header.Notification.isused.FaultCode=1; break; case 14:/* FaultMsg */ /* is used */ service->v2gMsg.Header.Notification.isused.FaultMsg=1; break; case 10:/* EventList */ /* is used */ service->v2gMsg.Header.Notification.isused.EventList=1; break; case 16:/* MeterID */ /* is used */ service->v2gMsg.Body.MeteringStatusRes.MeterInfo.isused.MeterID=1; break; case 18:/* MeterReading */ /* is used */ service->v2gMsg.Body.MeteringStatusRes.MeterInfo.isused.MeterReading=1; break; case 19:/* MeterStatus */ /* is used */ service->v2gMsg.Body.MeteringStatusRes.MeterInfo.isused.MeterStatus=1; break; case 37:/* TMeter */ /* is used */ service->v2gMsg.Body.MeteringStatusRes.MeterInfo.isused.TMeter=1; break; } break; case 6: switch(service->eqn.localPart) { case 6:/* Notification */ /* is used */ service->v2gMsg.Header.isused.Notification=1; break; } break; } return 0; } /** * Deserialize the EXI stream * @return 0 = 0K; -1 = ERROR */ static int deserializeMessage(struct v2gService* service) { int noEndOfDocument = 1; /* true */ int returnCode=0; do { exiDecodeNextEvent(&(service->inStream), &(service->stateDecode), &(service->event)); if (returnCode) { if(service->errorCode==0) { service->errorCode= V2G_NON_VALID_MESSAGE; } return returnCode; } switch (service->event) { case START_DOCUMENT: returnCode = exiDecodeStartDocument(&(service->inStream), &(service->stateDecode)); break; case END_DOCUMENT: returnCode = exiDecodeEndDocument(&(service->inStream), &(service->stateDecode)); noEndOfDocument = 0; /* false */ break; case START_ELEMENT: returnCode = exiDecodeStartElement(&(service->inStream), &(service->stateDecode), &(service->eqn)); service->idPath.id[service->idPath.pos++]=service->eqn.localPart; break; case END_ELEMENT: returnCode = exiDecodeEndElement(&(service->inStream), &(service->stateDecode), &(service->eqn)); returnCode = deserializeElementOrServiceCall(service); service->idPath.pos--; break; case CHARACTERS: /* decode */ returnCode = exiDecodeCharacters(&(service->inStream), &(service->stateDecode), &(service->val)); /* assign data to the v2g message structure */ returnCode = deserializeElementCharacter(service); break; case ATTRIBUTE: /* decode */ /* returnCode = exiDecodeAttribute(&isStream, &stateDecode, &eqn, &val); */ break; default: /* ERROR */ return -1; } } while (noEndOfDocument); return 0; } /** * Takes the EXI stream, invokes the called service method, and provides the response EXI stream * @return 0 = 0K; -1 = ERROR */ int messageDispatcher(struct v2gService* service, uint8_t* inStream, size_t sizeInStream, uint8_t* outStream, size_t sizeOutStream, size_t* outStreamLength) { size_t inPos, outPos; /* assign inStream data to service v2g structure */ inPos = service->transportHeaderOffset; service->inStream.data = inStream; service->inStream.size = sizeInStream+inPos; service->inStream.pos = &inPos; service->inStream.buffer=0; service->inStream.capacity=0; /* assign outStream data to service v2g structure */ outPos=service->transportHeaderOffset; service->outStream.data = outStream; service->outStream.size = sizeOutStream; service->outStream.pos = &outPos; service->outStream.buffer=0; service->outStream.capacity=8; /* clear error code */ service->errorCode = 0; /* init EXI decoder (read header, set initial state) */ exiInitDecoder(&(service->inStream), &(service->stateDecode)); /* init EXI encoder (write header, set initial state) */ exiInitEncoder(&(service->outStream), &(service->stateEncode)); /* init uniqueID stack */ service->idPath.pos=0; /* init v2g message */ init_AnonType_V2G_Message(&(service->v2gMsg)); /* deserialize the input stream and call the corresponding service */ if(deserializeMessage(service)) { return -1; /* something went wrong */ } /* determine payload size (without transport offset) */ outPos -= service->transportHeaderOffset; *outStreamLength = outPos; return 0; } /** * Init the service * @return 0 = 0K; -1 = ERROR */ int init_v2gservice(struct v2gService* service, bytes_t bytes, string_ucs_t string, uint16_t transportHeaderOffset) { /* init byte array */ service->val.binary = bytes; /* init string array */ service->val.string = string; /* init offset for transport protocoll */ service->transportHeaderOffset=transportHeaderOffset; return 0; }