Browse Source

2022-07-26/Jerry Wang
[OCPP 2.0.1]

Action:
1. Add and Improve ISO15118 to OCPP PnC related logic.
2. Add logic to check content format in SetNetworkProfile message.
2. Adjust array length and flags, and add missed structures.

File:
1. EVSE/Modularization/ocpp20/MessageHandler.c
--> Action 1,2
2. EVSE/Projects/define.h
--> Action 3

Jerry Wang 2 năm trước cách đây
mục cha
commit
6ea3db687a
2 tập tin đã thay đổi với 139 bổ sung26 xóa
  1. 110 4
      EVSE/Modularization/ocpp20/MessageHandler.c
  2. 29 22
      EVSE/Projects/define.h

+ 110 - 4
EVSE/Modularization/ocpp20/MessageHandler.c

@@ -7879,6 +7879,16 @@ void CheckSystemValue(void)
 		if(isWebsocketSendable && (server_sign == TRUE) && (ShmOCPP20Data->CSUMsg.bits[gun_index].NotifyEVChargingNeedsReq == ON))
 		{
 			sendNotifyEVChargingNeedsRequest(gun_index);
+			ShmOCPP20Data->CSUMsg.bits[gun_index].NotifyEVChargingNeedsReq = OFF;
+		}
+
+		//==========================================
+		// csu notify EV charging schedule request
+		//==========================================
+		if(isWebsocketSendable && (server_sign == TRUE) && (ShmOCPP20Data->CSUMsg.bits[gun_index].NotifyEVChargingScheduleReq == ON))
+		{
+			sendNotifyEVChargingScheduleRequest(gun_index);
+			ShmOCPP20Data->CSUMsg.bits[gun_index].NotifyEVChargingScheduleReq = OFF;
 		}
 
 		//==========================================
@@ -7955,6 +7965,7 @@ int sendAuthorizeRequest(int gun_index)
 	char tempdata[128]={0};
 	json_object *Authorize = json_object_new_object();
 	json_object *idToken = json_object_new_object();
+	json_object *iso15118CertificateHashData = json_object_new_array();
 
 	DEBUG_INFO("sendAuthorizeRequest...\n");
 	memset(&(ShmOCPP20Data->Authorize.Response_idTokenInfo),0,sizeof(struct IdTokenInfoType));
@@ -8034,6 +8045,27 @@ int sendAuthorizeRequest(int gun_index)
 
 	json_object_object_add(idToken, "idToken", json_object_new_string((char*)ShmOCPP20Data->Authorize.idToken.idToken));
 	json_object_object_add(idToken, "type", json_object_new_string((char*)ShmOCPP20Data->Authorize.idToken.type));
+
+	if(strcmp((char*)ShmOCPP20Data->Authorize.idToken.type, IdTokenEnumTypeStr[IdTokenType_eMAID]) == 0)
+	{
+		json_object *OCSPRequestDataType = json_object_new_object();
+		json_object_object_add(Authorize, "certificate", json_object_new_string((char*)ShmOCPP20Data->Authorize.certificate));
+		for(int idx=0; idx < 4; idx++)
+		{
+			if(strlen((char*)ShmOCPP20Data->Authorize.iso15118CertificateHashData[idx].responderURL) >= 7)
+			{
+				json_object_object_add(OCSPRequestDataType, "hashAlgorithm", json_object_new_string((char*)ShmOCPP20Data->Authorize.iso15118CertificateHashData[idx].hashAlgorithm));
+				json_object_object_add(OCSPRequestDataType, "issuerNameHash", json_object_new_string((char*)ShmOCPP20Data->Authorize.iso15118CertificateHashData[idx].issuerNameHash));
+				json_object_object_add(OCSPRequestDataType, "issuerKeyHash", json_object_new_string((char*)ShmOCPP20Data->Authorize.iso15118CertificateHashData[idx].issuerKeyHash));
+				json_object_object_add(OCSPRequestDataType, "serialNumber", json_object_new_string((char*)ShmOCPP20Data->Authorize.iso15118CertificateHashData[idx].serialNumber));
+				json_object_object_add(OCSPRequestDataType, "responderURL", json_object_new_string((char*)ShmOCPP20Data->Authorize.iso15118CertificateHashData[idx].responderURL));
+
+				json_object_array_add(iso15118CertificateHashData, OCSPRequestDataType);
+			}
+		}
+		json_object_object_add(Authorize, "iso15118CertificateHashData", iso15118CertificateHashData);
+	}
+
 	json_object_object_add(Authorize, "idToken", idToken);
 
 	random_uuid(guid);
@@ -17246,6 +17278,78 @@ int handleSetChargingProfileRequest(char *uuid, char *payload)
 								isPeriodOverMax = TRUE;
 							}
 						}
+
+						if(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff") != NULL)
+						{
+							if(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "id") != NULL)
+							{
+								SetProfileReq.chargingProfile.chargingSchedule[idxSchedule].salesTariff.id = json_object_get_int(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "id"));
+							}
+
+							if(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffDescription") != NULL)
+							{
+								strcpy((char*)SetProfileReq.chargingProfile.chargingSchedule[idxSchedule].salesTariff.salesTariffDescription, json_object_get_string(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffDescription")));
+							}
+
+							if(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "numEPriceLevels") != NULL)
+							{
+								SetProfileReq.chargingProfile.chargingSchedule[idxSchedule].salesTariff.numEPriceLevels = json_object_get_int(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "numEPriceLevels"));
+							}
+
+							if(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry") != NULL)
+							{
+								int cntEntry = json_object_array_length(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"));
+
+								if(cntEntry<=1024)
+								{
+									for(int idxEntry=0; idxEntry<cntEntry; idxEntry++)
+									{
+										if(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "ePriceLevel") != NULL)
+										{
+											SetProfileReq.chargingProfile.chargingSchedule[idxSchedule].salesTariff.salesTariffEntry[idxEntry].ePriceLevel = json_object_get_int(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "ePriceLevel"));
+										}
+
+										if(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "relativeTimeInterval") != NULL)
+										{
+											if(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "relativeTimeInterval"), "start") != NULL)
+												SetProfileReq.chargingProfile.chargingSchedule[idxSchedule].salesTariff.salesTariffEntry[idxEntry].relativeTimeInterval.start = json_object_get_int(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "relativeTimeInterval"), "start"));
+											if(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "relativeTimeInterval"), "duration") != NULL)
+												SetProfileReq.chargingProfile.chargingSchedule[idxSchedule].salesTariff.salesTariffEntry[idxEntry].relativeTimeInterval.duration = json_object_get_int(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "relativeTimeInterval"), "duration"));
+										}
+
+										if(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "consumptionCost") != NULL)
+										{
+											uint8_t cntConCost = json_object_array_length(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "consumptionCost"));
+											if(cntConCost<=3)
+											{
+												for(uint8_t idxConCost=0; idxConCost<cntConCost; idxConCost++)
+												{
+													if(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "consumptionCost"),idxConCost), "startValue") != NULL)
+														SetProfileReq.chargingProfile.chargingSchedule[idxSchedule].salesTariff.salesTariffEntry[idxEntry].consumptionCost[idxConCost].startValue = json_object_get_double(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "consumptionCost"),idxConCost), "cost"));
+													if(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "consumptionCost"),idxConCost), "cost") != NULL)
+													{
+														uint8_t cntCost = json_object_array_length(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "consumptionCost"),idxConCost), "cost"));
+														if(cntConCost<=3)
+														{
+															for(uint8_t idxCost=0; idxCost<cntCost; idxCost++)
+															{
+																if(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "consumptionCost"),idxConCost), "cost"), idxCost), "costKind") != NULL)
+																	strcpy((char*)SetProfileReq.chargingProfile.chargingSchedule[idxSchedule].salesTariff.salesTariffEntry[idxEntry].consumptionCost[idxConCost].cost[idxCost].costKind, json_object_get_string(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "consumptionCost"),idxConCost), "cost"), idxCost), "costKind")));
+																if(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "consumptionCost"),idxConCost), "cost"), idxCost), "amount") != NULL)
+																	SetProfileReq.chargingProfile.chargingSchedule[idxSchedule].salesTariff.salesTariffEntry[idxEntry].consumptionCost[idxConCost].cost[idxCost].amount = json_object_get_int(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "consumptionCost"),idxConCost), "cost"), idxCost), "amount"));
+																if(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "consumptionCost"),idxConCost), "cost"), idxCost), "amountMultiplier") != NULL)
+																	SetProfileReq.chargingProfile.chargingSchedule[idxSchedule].salesTariff.salesTariffEntry[idxEntry].consumptionCost[idxConCost].cost[idxCost].amountMultiplier = json_object_get_int(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "consumptionCost"),idxConCost), "cost"), idxCost), "amountMultiplier"));
+															}
+														}
+													}
+												}
+											}
+											SetProfileReq.chargingProfile.chargingSchedule[idxSchedule].salesTariff.salesTariffEntry[idxEntry].ePriceLevel = json_object_get_int(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(json_object_array_get_idx(json_object_object_get(json_object_object_get(SetChargingProfile, "chargingProfile"), "chargingSchedule"), idxSchedule), "salesTariff"), "salesTariffEntry"),idxEntry), "ePriceLevel"));
+										}
+									}
+								}
+							}
+						}
 					}
 				}
 				else
@@ -19596,8 +19700,10 @@ void handleNotifyEVChargingNeedsResponse(char *payload, int gun_index)
 	}
 	json_object_put(NotifyEVChargingNeeds);
 
-	ShmOCPP20Data->SpMsg.bits.NotifyChargingLimitReq = OFF;
-	ShmOCPP20Data->SpMsg.bits.NotifyChargingLimitConf = ON;
+	//ShmOCPP20Data->SpMsg.bits.NotifyChargingLimitReq = OFF;
+	//ShmOCPP20Data->SpMsg.bits.NotifyChargingLimitConf = ON;
+	ShmOCPP20Data->CSUMsg.bits[gun_index].NotifyEVChargingNeedsReq = OFF;
+	ShmOCPP20Data->CSUMsg.bits[gun_index].NotifyEVChargingNeedsConf = ON;
 }
 
 void handleNotifyEVChargingScheduleResponse(char *payload, int gun_index)
@@ -19615,8 +19721,8 @@ void handleNotifyEVChargingScheduleResponse(char *payload, int gun_index)
 	}
 	json_object_put(NotifyEVChargingSchedule);
 
-	ShmOCPP20Data->SpMsg.bits.NotifyEVChargingScheduleReq = OFF;
-	ShmOCPP20Data->SpMsg.bits.NotifyEVChargingScheduleConf = ON;
+	ShmOCPP20Data->CSUMsg.bits[gun_index].NotifyEVChargingScheduleReq = OFF;
+	ShmOCPP20Data->CSUMsg.bits[gun_index].NotifyEVChargingScheduleConf = ON;
 }
 
 void handleNotifyEventResponse(char *payload, int gun_index)

+ 29 - 22
EVSE/Projects/define.h

@@ -5140,7 +5140,7 @@ struct DCChargingParametersType
 struct AdditionalInfoType
 {
 	unsigned char	additionalIdToken[37];						// Required. This field specifies the additional IdToken.
-	unsigned char	type[50];									// Required. This defines the type of the additionalIdToken. This is a custom type, so the implementation needs to be agreed upon by all involved parties.
+	unsigned char	type[51];									// Required. This defines the type of the additionalIdToken. This is a custom type, so the implementation needs to be agreed upon by all involved parties.
 };
 
 struct APNType
@@ -5168,13 +5168,14 @@ struct GroupIdTokenType
 {
 	unsigned char idToken[37];									// Required. IdToken is case insensitive. Might hold the hidden id of an RFID tag, but can for example also contain a UUID.
 	unsigned char type[16];										// Required. Enumeration of possible idToken types.
+	//struct AdditionalInfoType additionalInfo[10];               // Optional. AdditionalInfo can be used to send extra information which can be validated by the CSMS in addition to the regular authorization with IdToken.
 };
 
 struct MessageContentType
 {
 	unsigned char format[8];									// Required. Format of the message.
-	unsigned char	language[8];								// Optional. Message language identifier. Contains a language code as defined in [RFC5646].
-	unsigned char content[512];									// Required. Message contents.
+	unsigned char	language[9];								// Optional. Message language identifier. Contains a language code as defined in [RFC5646].
+	unsigned char content[513];									// Required. Message contents.
 };
 
 struct IdTokenInfoType
@@ -5182,9 +5183,9 @@ struct IdTokenInfoType
 	unsigned char status[32];									// Required. Current status of the ID Token.
 	unsigned char cacheExpiryDateTime[28];						// Optional. Date and Time after which the token must be considered invalid.
 	short int	chargingPriority;								// Optional. Priority from a business point of view. Default priority is 0, The range is from -9 to 9. Higher values indicate a higher priority.
-	unsigned char language1[8];									// Optional. Preferred user interface language of identifier user. Contains a language code as defined in [RFC5646].
+	unsigned char language1[9];									// Optional. Preferred user interface language of identifier user. Contains a language code as defined in [RFC5646].
 	unsigned int evseId[100];									// Optional. Only used when the IdToken is only valid for one or more specific EVSEs, not for the entire Charging Station.
-	unsigned char language2[8];									// Optional. Second preferred user interface language of identifier user. Don’t use when language1 is omitted, has to be different from language1.
+	unsigned char language2[9];									// Optional. Second preferred user interface language of identifier user. Don’t use when language1 is omitted, has to be different from language1.
 	struct GroupIdTokenType groupIdToken;						// Optional. This contains the group identifier.
 	struct MessageContentType personalMessage;					// Optional. Personal message that can be shown to the EV Driver and can be used for tariff information, user greetings etc.
 };
@@ -5242,6 +5243,7 @@ struct CostTypeOCPP
 {
 	unsigned char costKind[36];									// Required. The kind of cost referred to in the message element amount
 	int amount;													// Required. The estimated or actual cost per kWh
+	int amountMultiplier;                                       // Optional. Values: -3..3, The amountMultiplier defines the exponent to base 10 (dec). The final value is determined by: amount * 10 ^ amountMultiplier
 };
 
 struct ConsumptionCostTypeOCPP
@@ -5481,10 +5483,10 @@ struct NetworkConnectionProfileType
 struct OCSPRequestDataType
 {
 	unsigned char hashAlgorithm[8];									// Required. Used algorithms for the hashes provided.
-	unsigned char issuerNameHash[128];								// Required. hashed value of the IssuerName.
-	unsigned char issuerKeyHash[128];								// Required. Hashed value of the issuers public key
-	unsigned char serialNumber[40];									// Required. The serial number of the certificate.
-	unsigned char responderURL[512];								// Required. This contains the responder URL (Case insensitive).
+	unsigned char issuerNameHash[129];								// Required. hashed value of the IssuerName.
+	unsigned char issuerKeyHash[129];								// Required. Hashed value of the issuers public key
+	unsigned char serialNumber[41];									// Required. The serial number of the certificate.
+	unsigned char responderURL[513];								// Required. This contains the responder URL (Case insensitive).
 };
 
 struct ReportDataType
@@ -5551,6 +5553,7 @@ struct StatusInfoType
  */
 struct Authorize_20
 {
+	unsigned char certificate[5601];                                // Optional. The X.509 certificated presented by EV for authorization.
 	struct IdTokenType idToken;										// Required. This contains the identifier that needs to be authorized.
 	struct OCSPRequestDataType iso15118CertificateHashData[4];		// Optional. Contains the information needed to verify the EV Contract Certificate via OCSP.
 	unsigned char Response_certificateStatus[32];					// Optional. Certificate status information. - if all certificates are valid: return 'Accepted'. - if one of the certificates was revoked, return 'CertificateRevoked'.
@@ -5668,11 +5671,11 @@ struct FirmwareStatusNotification_20
 
 struct Get15118EVCertificate_20
 {
-	unsigned char iso15118SchemaVersion[50];						// Required. Schema version currently used for the 15118 session between EV and Charging Station. Needed for parsing of the EXI stream by the CSMS.
+	unsigned char iso15118SchemaVersion[51];						// Required. Schema version currently used for the 15118 session between EV and Charging Station. Needed for parsing of the EXI stream by the CSMS.
 	unsigned char action[16];										// Required. Defines whether certificate needs to be installed or updated.
-	unsigned char exiRequest[5600];									// Required. Raw CertificateInstallationReq request from EV, Base64 encoded.
+	unsigned char exiRequest[5601];									// Required. Raw CertificateInstallationReq request from EV, Base64 encoded.
 	unsigned char Response_status[16];								// Required. Indicates whether the message was processed properly.
-	unsigned char Response_exiResponse[5600];						// Required. Raw CertificateInstallationRes response for the EV, Base64 encoded.
+	unsigned char Response_exiResponse[5601];						// Required. Raw CertificateInstallationRes response for the EV, Base64 encoded.
 };
 
 struct GetBaseReport_20
@@ -5833,6 +5836,7 @@ struct NotifyEVChargingNeeds_20
 	unsigned int evseId;											// Required. Defines the EVSE and connector to which the EV is connected. EvseId may not be 0.
 	struct ChargingNeedsType chargingNeeds;							// Required. The characteristics of the energy delivery required.
 	unsigned char Response_status[16];								// Required. Returns whether the CSMS has been able to process the message successfully. It does not imply that the evChargingNeeds can be met with the current charging profile.
+	struct StatusInfoType Response_statusInfo;                      // Optional. Detailed status information.
 };
 
 struct NotifyEVChargingSchedule_20
@@ -5841,6 +5845,7 @@ struct NotifyEVChargingSchedule_20
 	unsigned int evseId;											// Required. The charging schedule contained in this notification applies to an EVSE. EvseId must be > 0.
 	struct ChargingScheduleType chargingSchedule;					// Required. Planned energy consumption of the EV over time. Always relative to timeBase.
 	unsigned char Response_status[16];								// Required. Returns whether the CSMS has been able to process the message successfully. It does not imply any approval of the charging schedule.
+	struct StatusInfoType Response_statusInfo;                      // Optional. Detailed status information.
 };
 
 struct NotifyEvent_20
@@ -5963,6 +5968,7 @@ struct SetChargingProfile_20
 	struct ChargingProfileType chargingProfile;						// Required. The charging profile to be set at the Charging Station.
 	unsigned char Response_status[16];								// Required. Returns whether the Charging Station has been able to process the message successfully. This does not guarantee the schedule will be followed to the letter. There might be other constraints the Charging Station may need to take into account.
 	unsigned char guid[37];											// Save guid from server request
+	struct StatusInfoType Response_statusInfo;                      // Optional. Detailed status information.
 };
 
 struct SetDisplayMessage_20
@@ -6135,8 +6141,8 @@ struct OCPP20Data
 			unsigned char NotifyDisplayMessagesReq :1;
 			unsigned char NotifyDisplayMessagesConf :1;
 
-			unsigned char NotifyEVChargingScheduleReq :1;
-			unsigned char NotifyEVChargingScheduleConf :1;
+			unsigned char NotifyCustomerInformationReq :1;
+			unsigned char NotifyCustomerInformationConf :1;
 			unsigned char NotifyEventReq :1;
 			unsigned char NotifyEventConf :1;
 			unsigned char NotifyMonitoringReportReq :1;
@@ -6150,8 +6156,8 @@ struct OCPP20Data
 			unsigned char SecurityEventNotificationConf :1;
 			unsigned char SignCertificateReq :1;
 			unsigned char SignCertificateConf :1;
-            unsigned char NotifyCustomerInformationReq :1;  //bit 6
-            unsigned char NotifyCustomerInformationConf :1; //bit 7
+            unsigned char :1; //bit 6
+            unsigned char :1; //bit 7
 
 		} bits;
 	} SpMsg;
@@ -6278,12 +6284,13 @@ struct OCPP20Data
 		{
 			//CSUMsgValue[0]
 			unsigned char ChargingProfileReq:1;	//bit 0,
-			unsigned char ChargingProfileConf:1;	//bit 0,
-            unsigned char ClearedChargingLimitReq :1;
-            unsigned char ClearedChargingLimitConf :1;
-            unsigned char NotifyEVChargingNeedsReq :1;
-            unsigned char NotifyEVChargingNeedsConf :1;
-            unsigned char :2;   //bit 1,2,3,4,5,6,7 , reserved
+			unsigned char ChargingProfileConf:1; //bit 1
+            unsigned char ClearedChargingLimitReq :1; //bit 2
+            unsigned char ClearedChargingLimitConf :1; //bit 3
+            unsigned char NotifyEVChargingNeedsReq :1; //bit 4
+            unsigned char NotifyEVChargingNeedsConf :1; //bit 5
+            unsigned char NotifyEVChargingScheduleReq:1; //bit 6
+            unsigned char NotifyEVChargingScheduleConf:1; //bit 7
 		} bits[CONNECTOR_QUANTITY];
 	}CSUMsg;