Bladeren bron

[Added][AW-CCS][main.c][main.h][Module_InternalComm.c][Module_InternalComm.h]
2022-08-26 / EASON YANG
Action:
1. Added: Logic for PTB meter.
2. Added: Struct for PTB meter.
3. Added: Commands for PTB meter.

Files:
1. main.c & main.h
Action 1
Action 2

2. Module_InternalComm.c & Module_InternalComm.h
Action 3

FIRMWARE VERSION: B0.62.XX.XXXX.PX

8009 2 jaren geleden
bovenliggende
commit
f0dd4c4271

+ 440 - 73
EVSE/Projects/AW-CCS/Apps/Module_InternalComm.c

@@ -79,7 +79,7 @@ int StoreLogMsg(const char *fmt, ...)
 	tm=localtime(&CurrentTime);
 	gettimeofday(&tv, NULL); // get microseconds, 10^-6
 
-	sprintf(Buf,"echo -n \"[%04d.%02d.%02d %02d:%02d:%02d.%06ld]%s\" >> /Storage/SystemLog/[%04d.%02d]Module_InterCommLog",
+	sprintf(Buf,"echo -n \'[%04d.%02d.%02d %02d:%02d:%02d.%06ld]%s\' >> /Storage/SystemLog/[%04d.%02d]Module_InterCommLog",
 				tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,tv.tv_usec,
 				buffer,
 				tm->tm_year+1900,tm->tm_mon+1);
@@ -295,6 +295,9 @@ void ack_delay(unsigned char cmd)
 		case CMD_UPDATE_END:
 			usleep(300000);
 			break;
+		case CMD_QUERY_PTB_METER_MESSAGE:
+			usleep(500000);
+			break;
 		default:
 			usleep(100000);
 			break;
@@ -309,7 +312,7 @@ int tranceive(int fd, unsigned char* cmd, unsigned char cmd_len, unsigned char*
 	if(write(fd, cmd, cmd_len) >= cmd_len)
 	{
 		ack_delay(cmd[3]);
-		len = read(fd, rx, 512);
+		len = read(fd, rx, 2048);
 	}
 	else
 	{
@@ -1095,6 +1098,149 @@ unsigned char Query_MeterIc_CorrectionPara(unsigned char fd, unsigned char targe
 	return result;
 }
 
+unsigned char Query_AC_GUN_PLUGIN_TIMES(unsigned char fd, unsigned char targetAddr, Gun_Plugin_Times *Ret_Buf)
+{
+	unsigned char result = FAIL;
+	unsigned char tx[7] = {0xaa, 0x00, targetAddr, CMD_QUERY_GUN_PLUGIN_TIMES, 0x00, 0x00, 0x00};
+	unsigned char rx[512];
+	unsigned char chksum = 0x00;
+	unsigned char len = tranceive(fd, tx, sizeof(tx), rx);
+
+	if(len > 6)
+	{
+		if(len < 6+(rx[4] | rx[5]<<8))
+			return result;
+
+		for(int idx=0;idx<(rx[4] | rx[5]<<8);idx++)
+		{
+			chksum ^= rx[6+idx];
+		}
+
+		if((chksum == rx[6+(rx[4] | rx[5]<<8)]) &&
+		   (rx[2] == tx[1]) &&
+		   (rx[1] == tx[2]) &&
+		   (rx[3] == tx[3]))
+		{
+			Ret_Buf-> GunPluginTimes = ((uint32_t)rx[6] | (((uint32_t)rx[7])<<8) | (((uint32_t)rx[8])<<16) | (((uint32_t)rx[9])<<24));
+			result = PASS;
+		}
+	}
+
+	return result;
+}
+
+unsigned char Query_PTB_METER_MESSAGE(unsigned char fd, unsigned char targetAddr, Ptb_Meter *Ret_Buf, uint8_t CMD)
+{
+	unsigned char result = FAIL;
+	unsigned char tx[8] = {0};
+	unsigned char rx[2048] = {0};
+	unsigned char chksum = 0x00;
+
+	tx[0] = 0xaa;
+	tx[1] = 0x00;
+	tx[2] = targetAddr;
+	tx[3] = CMD_QUERY_PTB_METER_MESSAGE;
+	tx[4] = 0x01;
+	tx[5] = 0x00;
+	tx[6] = CMD;
+
+	for(int idx=0;idx<(tx[4] | tx[5]<<8);idx++)
+		chksum ^= tx[6+idx];
+
+	tx[7] = chksum;
+
+	int len = tranceive(fd, tx, sizeof(tx), rx);
+
+	if(len > 6)
+	{
+		if(len < 6+(rx[4] | rx[5]<<8))
+			return result;
+
+		chksum = 0x00;
+		for(int idx=0;idx<(rx[4] | rx[5]<<8);idx++)
+		{
+			chksum ^= rx[6+idx];
+		}
+
+		if((chksum == rx[6+(rx[4] | rx[5]<<8)]) &&
+		   (rx[2] == tx[1]) &&
+		   (rx[1] == tx[2]) &&
+		   (rx[3] == tx[3]))
+		{
+			if(CMD == CMD_READ_OUTPUT_MESSAGE_FORMAT_ID)
+			{
+				memset(Ret_Buf->ReadOutputMessageFormatId, 0x00, ARRAY_SIZE(Ret_Buf->ReadOutputMessageFormatId));
+				if(rx[6] == CMD_READ_OUTPUT_MESSAGE_FORMAT_ID)
+				{
+					memcpy(&Ret_Buf->ReadOutputMessageFormatId[0], &rx[8], ((rx[4] | (rx[5]<<8))-2));
+				}
+			}
+			else if(CMD == CMD_READ_OUTPUT_MESSAGE_LENGTH)
+			{
+				Ret_Buf->ReadOutputMessageLength = 0;
+				if(rx[6] == CMD_READ_OUTPUT_MESSAGE_LENGTH)
+					Ret_Buf->ReadOutputMessageLength = (rx[7] | (rx[8]<<8));
+			}
+			else if(CMD == CMD_READ_OUTPUT_MESSAGE)
+			{
+				memset(Ret_Buf->ReadOutputMessage, 0x00, ARRAY_SIZE(Ret_Buf->ReadOutputMessage));
+				if((Ret_Buf->ReadOutputMessageLength == ((rx[4] | (rx[5]<<8))-1)) && (rx[6] == CMD_READ_OUTPUT_MESSAGE))
+				{
+					memcpy(&Ret_Buf->ReadOutputMessage[0], &rx[7], ((rx[4] | (rx[5]<<8))-1));
+				}
+			}
+			else if(CMD == CMD_READ_OUTPUT_SIGNATURE_LENGTH)
+			{
+				Ret_Buf->ReadOuputSignatureLength = 0;
+				if(rx[6] == CMD_READ_OUTPUT_SIGNATURE_LENGTH)
+					Ret_Buf->ReadOuputSignatureLength = (rx[7] | (rx[8]<<8));
+			}
+			else if(CMD == CMD_READ_OUTPUT_SIGNATURE)
+			{
+				memset(Ret_Buf->ReadOutputSignature, 0x00, ARRAY_SIZE(Ret_Buf->ReadOutputSignature));
+				if((Ret_Buf->ReadOuputSignatureLength == ((rx[4] | (rx[5]<<8))-1)) && (rx[6] == CMD_READ_OUTPUT_SIGNATURE))
+				{
+					memcpy(&Ret_Buf->ReadOutputSignature[0], &rx[7], ((rx[4] | (rx[5]<<8))-1));
+				}
+			}
+			else if(CMD == CMD_READ_PUBLIC_KEY_HEADER_LENGTH)
+			{
+				Ret_Buf->ReadPublicKeyHeaderLength  = 0;
+				if(rx[6] == CMD_READ_PUBLIC_KEY_HEADER_LENGTH)
+					Ret_Buf->ReadPublicKeyHeaderLength = (rx[7] | (rx[8]<<8));
+			}
+			else if(CMD == CMD_READ_PUBLIC_KEY_HEADER)
+			{
+				memset(Ret_Buf->ReadPublicKeyHeader, 0x00, ARRAY_SIZE(Ret_Buf->ReadPublicKeyHeader));
+				if((Ret_Buf->ReadPublicKeyHeaderLength == ((rx[4] | (rx[5]<<8))-1)) && (rx[6] == CMD_READ_PUBLIC_KEY_HEADER))
+				{
+					memcpy(&Ret_Buf->ReadPublicKeyHeader[0], &rx[7], ((rx[4] | (rx[5]<<8))-1));
+				}
+			}
+			else if(CMD == CMD_READ_PUBLIC_KEY_LENGTH)
+			{
+				Ret_Buf->ReadPublicKeyLength = 0;
+				if(rx[6] == CMD_READ_PUBLIC_KEY_LENGTH)
+					Ret_Buf->ReadPublicKeyLength = (rx[7] | (rx[8]<<8));
+			}
+			else if(CMD == CMD_READ_PUBLIC_KEY)
+			{
+				memset(Ret_Buf->ReadPublicKey, 0x00, ARRAY_SIZE(Ret_Buf->ReadPublicKey));
+				if((Ret_Buf->ReadPublicKeyLength == ((rx[4] | (rx[5]<<8))-1)) && (rx[6] == CMD_READ_PUBLIC_KEY))
+				{
+					memcpy(&Ret_Buf->ReadPublicKey[0], &rx[7], ((rx[4] | (rx[5]<<8))-1));
+				}
+			}
+			else
+			{}
+
+			result = PASS;
+		}
+	}
+
+	return result;
+}
+
 unsigned char Config_Fan_Speed(unsigned char fd, unsigned char targetAddr, FanSpeed *Set_Buf)
 {
 	unsigned char result = FAIL;
@@ -1513,37 +1659,6 @@ unsigned char Config_AC_MCU_RESET_REQUEST(unsigned char fd, unsigned char target
 	return result;
 }
 
-unsigned char Query_AC_GUN_PLUGIN_TIMES(unsigned char fd, unsigned char targetAddr, Gun_Plugin_Times *Ret_Buf)
-{
-	unsigned char result = FAIL;
-	unsigned char tx[7] = {0xaa, 0x00, targetAddr, CMD_QUERY_GUN_PLUGIN_TIMES, 0x00, 0x00, 0x00};
-	unsigned char rx[512];
-	unsigned char chksum = 0x00;
-	unsigned char len = tranceive(fd, tx, sizeof(tx), rx);
-
-	if(len > 6)
-	{
-		if(len < 6+(rx[4] | rx[5]<<8))
-			return result;
-
-		for(int idx=0;idx<(rx[4] | rx[5]<<8);idx++)
-		{
-			chksum ^= rx[6+idx];
-		}
-
-		if((chksum == rx[6+(rx[4] | rx[5]<<8)]) &&
-		   (rx[2] == tx[1]) &&
-		   (rx[1] == tx[2]) &&
-		   (rx[3] == tx[3]))
-		{
-			Ret_Buf-> GunPluginTimes = ((uint32_t)rx[6] | (((uint32_t)rx[7])<<8) | (((uint32_t)rx[8])<<16) | (((uint32_t)rx[9])<<24));
-			result = PASS;
-		}
-	}
-
-	return result;
-}
-
 unsigned char Config_AC_MaxCurrent_And_CpPwmDuty(unsigned char fd, unsigned char targetAddr, Ac_Primary_Mcu_Cp_Pwm_Duty *Set_Buf)
 {
 	unsigned char result = FAIL;
@@ -1760,6 +1875,51 @@ unsigned char Config_Aux_Power_Switch(unsigned char fd, unsigned char targetAddr
 	return result;
 }
 
+unsigned char Config_Ptb_Meter_Permission_Status(unsigned char fd, unsigned char targetAddr, Ptb_Meter *Set_Buf)
+{
+	unsigned char result = FAIL;
+	unsigned char tx[8] = {0};
+	unsigned char rx[512];
+	unsigned char chksum = 0x00;
+
+	tx[0] = 0xaa;
+	tx[1] = 0x00;
+	tx[2] = targetAddr;
+	tx[3] = CMD_CONFIG_PTB_METER_PERMISSION;
+	tx[4] = 0x01;
+	tx[5] = 0x00;
+	tx[6] = Set_Buf->PtbMeterPermissionStatus;
+
+	for(int idx=0;idx<(tx[4] | tx[5]<<8);idx++)
+			chksum ^= tx[6+idx];
+	tx[7] = chksum;
+
+	unsigned char len = tranceive(fd, tx, sizeof(tx), rx);
+
+	if(len > 6)
+	{
+		if(len < 6+(rx[4] | rx[5]<<8))
+			return result;
+
+		chksum = 0x00;
+		for(int idx=0;idx<(rx[4] | rx[5]<<8);idx++)
+		{
+			chksum ^= rx[6+idx];
+		}
+
+		if((chksum == rx[6+(rx[4] | rx[5]<<8)]) &&
+			(rx[2] == tx[1]) &&
+			(rx[1] == tx[2]) &&
+			(rx[3] == tx[3]) &&
+			((rx[6] == 0x00) || (rx[6] == 0x01)))
+		{
+			result = PASS;
+		}
+	}
+
+	return result;
+}
+
 unsigned char Update_Start(unsigned char fd, unsigned char targetAddr, unsigned int crc32)
 {
 	unsigned char result = FAIL;
@@ -1958,7 +2118,7 @@ int main(void)
 				// High priority polling log print out
 				//==========================================================
 				//==================================================
-				// Case 1: Config primary MCU LED
+				// Case 1: Configuration primary MCU LED
 				//==================================================
 				if((previousCharger.gun_info[gun_index].primaryMcuLed.mode != ShmCharger->gun_info[gun_index].primaryMcuLed.mode) ||
 				   (previousCharger.gun_info[gun_index].primaryMcuLed.alarm_code != ShmCharger->gun_info[gun_index].primaryMcuLed.alarm_code))
@@ -1974,7 +2134,7 @@ int main(void)
 				}
 
 				//==================================================
-				// Case 2: Config primary Legacy request
+				// Case 2: Configuration primary Legacy request
 				//==================================================
 				if(previousCharger.gun_info[gun_index].legacyRequest.isLegacyRequest != ShmCharger->gun_info[gun_index].legacyRequest.isLegacyRequest)
 				{
@@ -1987,7 +2147,7 @@ int main(void)
 				}
 
 				//==================================================
-				// Case 2: Config primary Relay
+				// Case 2: Configuration primary Relay
 				//==================================================
 				if((previousCharger.gun_info[gun_index].primaryMcuState.relayState.relay_status[0][0] != ShmCharger->gun_info[gun_index].primaryMcuState.relayState.relay_status[0][0]) ||
 				   (previousCharger.gun_info[gun_index].primaryMcuState.relayState.relay_status[0][1] != ShmCharger->gun_info[gun_index].primaryMcuState.relayState.relay_status[0][1]) ||
@@ -2206,6 +2366,119 @@ int main(void)
 					previousCharger.gun_info[gun_index].outputCurrent.L3N_L31[0] = ShmCharger->gun_info[gun_index].outputCurrent.L3N_L31[0];
 				}
 
+				//==================================================
+				// Case 12: Configuration PTB permission status
+				//==================================================
+				if(ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P')
+				{
+					if(previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.PtbMeterPermissionStatus != ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.PtbMeterPermissionStatus)
+					{
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("***** High priority polling : Case 12 *****\n");
+						DEBUG_INFO("*******************************************\n");
+
+						if(ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.PtbMeterPermissionStatus == PERMISSION_START_CHARGING)
+						{
+							DEBUG_INFO("MCU-%d set permission to PTB meter: %d [Start Charging] \n", gun_index, ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.PtbMeterPermissionStatus);
+						}
+						else if(ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.PtbMeterPermissionStatus == PERMISSION_END_CHARGING)
+						{
+							DEBUG_INFO("MCU-%d set permission to PTB meter: %d [End Charging] \n", gun_index, ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.PtbMeterPermissionStatus);
+						}
+						else
+						{}
+
+						previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.PtbMeterPermissionStatus = ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.PtbMeterPermissionStatus;
+					}
+				}
+
+				//==================================================
+				// Case 13: Case 13; Query PTB meter messages
+				//==================================================
+				if(ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P')
+				{
+					if((strcmp((char*)previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessageFormatId, (char*)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessageFormatId) != 0))
+					{
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("** High priority polling : Case 13-0x10 ***\n");
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("MCU-%d get PTB meter output message format id: %s \n", gun_index, &ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessageFormatId);
+						memcpy((char*)previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessageFormatId,(char*)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessageFormatId,ARRAY_SIZE(ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessageFormatId));
+					}
+
+					if(previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessageLength != ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessageLength)
+					{
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("** High priority polling : Case 13-0x11 ***\n");
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("MCU-%d get PTB meter output message length: %d \n", gun_index, ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessageLength);
+						previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessageLength = ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessageLength;
+					}
+
+					if((strcmp((char*)previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessage, (char*)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessage) != 0))
+					{
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("** High priority polling : Case 13-0x12 ***\n");
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("MCU-%d get PTB meter output message: %s \n", gun_index, &ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessage);
+						memcpy((char*)previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessage,(char*)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessage,ARRAY_SIZE(ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessage));
+					}
+
+					if(previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadOuputSignatureLength != ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOuputSignatureLength)
+					{
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("** High priority polling : Case 13-0x13 ***\n");
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("MCU-%d get PTB meter output signature length: %d \n", gun_index, ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOuputSignatureLength);
+						previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadOuputSignatureLength = ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOuputSignatureLength;
+					}
+
+					if((strcmp((char*)previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputSignature, (char*)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputSignature) != 0))
+					{
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("** High priority polling : Case 13-0x14 ***\n");
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("MCU-%d get PTB meter output signature: %s \n", gun_index, &ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputSignature);
+						memcpy((char*)previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputSignature,(char*)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputSignature,ARRAY_SIZE(ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputSignature));
+					}
+
+					if(previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyHeaderLength != ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyHeaderLength)
+					{
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("** High priority polling : Case 13-0x15 ***\n");
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("MCU-%d get PTB meter public key header length: %d \n", gun_index, ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyHeaderLength);
+						previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyHeaderLength = ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyHeaderLength;
+					}
+
+					if((strcmp((char*)previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyHeader, (char*)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyHeader) != 0))
+					{
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("** High priority polling : Case 13-0x16 ***\n");
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("MCU-%d get PTB meter public key header: %s \n", gun_index, &ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyHeader);
+						memcpy((char*)previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyHeader,(char*)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyHeader,ARRAY_SIZE(ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyHeader));
+					}
+
+					if(previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyLength != ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyLength)
+					{
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("** High priority polling : Case 13-0x17 ***\n");
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("MCU-%d get PTB meter public key length: %d \n", gun_index, ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyLength);
+						previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyLength = ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyLength;
+					}
+
+					if((strcmp((char*)previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKey, (char*)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKey) != 0))
+					{
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("** High priority polling : Case 13-0x18 ***\n");
+						DEBUG_INFO("*******************************************\n");
+						DEBUG_INFO("MCU-%d get PTB meter public key: %s \n", gun_index, &ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKey);
+						memcpy((char*)previousCharger.gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKey,(char*)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKey,ARRAY_SIZE(ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKey));
+					}
+				}
+
 				//==========================================================
 				// Low priority polling log print out
 				//==========================================================
@@ -2262,7 +2535,7 @@ int main(void)
 				}
 
 				//==================================================
-				// Case 11: Config primary RTC time
+				// Case 11: Configuration primary RTC time
 				//==================================================
 				if(previousCharger.gun_info[gun_index].rtc.min != ShmCharger->gun_info[gun_index].rtc.min)
 				{
@@ -2289,12 +2562,12 @@ int main(void)
 																									ShmCharger->gun_info[gun_index].rtc.min,
 																									ShmCharger->gun_info[gun_index].rtc.sec);
 					}
-					
+
 					previousCharger.gun_info[gun_index].rtc.min = ShmCharger->gun_info[gun_index].rtc.min;
 				}
 
 				//==================================================
-				// Case 15: Config led breathe timing
+				// Case 15: Configuration led breathe timing
 				//==================================================
 				if((previousCharger.gun_info[gun_index].setBreatheLedTiming.set_Led_Action_Authed_Fade_In != ShmCharger->gun_info[gun_index].setBreatheLedTiming.set_Led_Action_Authed_Fade_In) ||
 				   (previousCharger.gun_info[gun_index].setBreatheLedTiming.set_Led_Action_Authed_Fade_Out != ShmCharger->gun_info[gun_index].setBreatheLedTiming.set_Led_Action_Authed_Fade_Out) ||
@@ -2325,7 +2598,7 @@ int main(void)
 				}
 
 				//==================================================
-				// Case 17: Config led brightness
+				// Case 17: Configuration led brightness
 				//==================================================
 				if((previousCharger.gun_info[gun_index].setLedBrightness.sector_1 != ShmCharger->gun_info[gun_index].setLedBrightness.sector_1) ||
 				   (previousCharger.gun_info[gun_index].setLedBrightness.sector_2 != ShmCharger->gun_info[gun_index].setLedBrightness.sector_2) ||
@@ -2392,9 +2665,9 @@ int main(void)
 				 * High priority communication
 				 */
 
-				//===============================
-				// Case 1 : Config primary MCU LED
-				//===============================
+				//========================================
+				// Case 1 : Configuration primary MCU LED
+				//========================================
 				ShmCharger->gun_info[gun_index].primaryMcuLed.alarm_code = ShmCharger->gun_info[gun_index].systemAlarmCode.SystemAlarmCode;
 				if(Config_AC_MCU_LED(Uart1Fd, (gun_index>0?ADDR_AC_PRIMARY_2:ADDR_AC_PRIMARY_1), &ShmCharger->gun_info[gun_index].primaryMcuLed))
 				{
@@ -2409,9 +2682,9 @@ int main(void)
 						failCount[gun_index] = FAIL_SPEC_COMM;
 				}
 
-				//===============================
-				// Case 2 : Config primary Legacy request
-				//===============================
+				//========================================
+				// Case 2 : Configuration primary Legacy request
+				//========================================
 				if(Config_AC_MCU_LEGACY_REQUEST(Uart1Fd, (gun_index>0?ADDR_AC_PRIMARY_2:ADDR_AC_PRIMARY_1),&ShmCharger->gun_info[gun_index].legacyRequest))
 				{
 					failCount[gun_index] = 0;
@@ -2425,9 +2698,9 @@ int main(void)
 						failCount[gun_index] = FAIL_SPEC_COMM;
 				}
 				
-				//===============================
-				// Case 2-X : Config primary Relay
-				//===============================
+				//========================================
+				// Case 2-X : Configuration primary Relay
+				//========================================
 				if(Config_Relay_Output(Uart1Fd, (gun_index>0?ADDR_AC_PRIMARY_2:ADDR_AC_PRIMARY_1),&ShmCharger->gun_info[gun_index].primaryMcuState.relayState))
 				{
 					failCount[gun_index] = 0;
@@ -2441,9 +2714,9 @@ int main(void)
 						failCount[gun_index] = FAIL_SPEC_COMM;
 				}				
 
-				//===============================
+				//========================================
 				// Case 3 : Query primary MCU status
-				//===============================
+				//========================================
 				if(Query_AC_MCU_Status(Uart1Fd, (gun_index>0?ADDR_AC_PRIMARY_2:ADDR_AC_PRIMARY_1), &ShmCharger->gun_info[gun_index].primaryMcuState))
 				{
 					ShmSysConfigAndInfo->SysInfo.AcChargingData[gun_index].PilotState = ShmCharger->gun_info[gun_index].primaryMcuState.cp_state;
@@ -2521,9 +2794,9 @@ int main(void)
 						failCount[gun_index] = FAIL_SPEC_COMM;
 				}
 
-				//===============================
+				//========================================
 				// Case 4 : Query primary MCU Alarm code
-				//===============================
+				//========================================
 				if(Query_AC_MCU_Alarm(Uart1Fd, (gun_index>0?ADDR_AC_PRIMARY_2:ADDR_AC_PRIMARY_1), &ShmCharger->gun_info[gun_index].primaryMcuAlarm))
 				{
 					//DEBUG_INFO("MCU-%d get alarm code success.\n",gun_index);
@@ -2541,9 +2814,9 @@ int main(void)
 				}
 
 				/*
-				//===============================
+				//========================================
 				// Case 5 : Query primary MCU BLE config
-				//===============================
+				//========================================
 				if(Query_Ble_Config(Uart1Fd, (gun_index>0?ADDR_AC_PRIMARY_2:ADDR_AC_PRIMARY_1), &ShmCharger->gun_info[gun_index].bleConfigData))
 				{
 					ShmSysConfigAndInfo->SysConfig.Bluetooth.isLogin = ShmCharger->gun_info[gun_index].bleConfigData.isLogin;
@@ -2561,9 +2834,9 @@ int main(void)
 						failCount[gun_index] = FAIL_SPEC_COMM;
 				}
 
-				//===============================
+				//========================================
 				// Case 6 : Query primary MCU ble login id
-				//===============================
+				//========================================
 				if(Query_Ble_Central_ID(Uart1Fd, (gun_index>0?ADDR_AC_PRIMARY_2:ADDR_AC_PRIMARY_1), &ShmCharger->gun_info[gun_index].bleLoginCentralId))
 				{
 					memcpy(ShmSysConfigAndInfo->SysConfig.Bluetooth.LoginCentralID, ShmCharger->gun_info[gun_index].bleLoginCentralId.id, sizeof ShmSysConfigAndInfo->SysConfig.Bluetooth.LoginCentralID);
@@ -2579,9 +2852,9 @@ int main(void)
 						failCount[gun_index] = FAIL_SPEC_COMM;
 				}*/
 
-				//===============================
-				// Case 7 : Config primary MCU reset request
-				//===============================
+				//========================================
+				// Case 7 : Configuration primary MCU reset request
+				//========================================
 				if((access("/sys/class/gpio/gpio116/value", F_OK)) != -1)
 				{
 					if(ShmCharger->gun_info[gun_index].mcuResetRequest.isMcuResetRequest == ON)
@@ -2608,9 +2881,9 @@ int main(void)
 					}
 				}
 
-				//===============================
-				// Case 8 : Config primary set CP PWN duty
-				//===============================
+				//========================================
+				// Case 8 : Configuration primary set CP PWN duty
+				//========================================
 				if(ShmCharger->gun_info[gun_index].mcuFlag.isSetCpPwmDuty == ON)
 				{
 					//DEBUG_WARN("Case 8 : Config primary set CP PWN duty...%d\n", ShmCharger->gun_info[gun_index].primaryMcuCp_Pwn_Duty);
@@ -2629,9 +2902,9 @@ int main(void)
 					}
 				}
 
-				//===============================
+				//========================================
 				// Case 9 : Query GPIO
-				//===============================
+				//========================================
 				if(Query_Gpio_Input(Uart1Fd, (gun_index>0?ADDR_AC_PRIMARY_2:ADDR_AC_PRIMARY_1), &ShmCharger->gun_info[gun_index].GPIO_Input))
 				{
 					failCount[gun_index] = 0;
@@ -2645,9 +2918,9 @@ int main(void)
 						failCount[gun_index] = FAIL_SPEC_COMM;
 				}
 
-				//===============================
+				//========================================
 				// Case 10 : Query primary MCU power consumption
-				//===============================
+				//========================================
 				if(Query_Power_Consumption(Uart1Fd, (gun_index>0?ADDR_AC_PRIMARY_2:ADDR_AC_PRIMARY_1), &ShmCharger->gun_info[gun_index].powerConsumptionTotal, &ShmCharger->gun_info[gun_index].powerConsumption[0], &ShmCharger->gun_info[gun_index].powerConsumption[1], &ShmCharger->gun_info[gun_index].powerConsumption[2]))
 				{
 					failCount[gun_index] = 0;
@@ -2660,21 +2933,21 @@ int main(void)
 					else
 						failCount[gun_index] = FAIL_SPEC_COMM;
 				}
-				
-				//===============================
+
+				//========================================
 				// Case 11 : Query present output current
-				//===============================
+				//========================================
 				if(Query_Present_OutputCurrent(Uart1Fd, (gun_index>0?ADDR_AC_PRIMARY_2:ADDR_AC_PRIMARY_1), &ShmCharger->gun_info[gun_index].outputCurrent) == PASS)
 				{
 #ifndef SIMULATION
 					ShmSysConfigAndInfo->SysInfo.AcChargingData[gun_index].PresentChargingCurrent = (float)ShmCharger->gun_info[gun_index].outputCurrent.L1N_L12[0];
 					ShmSysConfigAndInfo->SysInfo.AcChargingData[gun_index].PresentChargingCurrentL2 = (float)ShmCharger->gun_info[gun_index].outputCurrent.L2N_L23[0];
 					ShmSysConfigAndInfo->SysInfo.AcChargingData[gun_index].PresentChargingCurrentL3 = (float)ShmCharger->gun_info[gun_index].outputCurrent.L3N_L31[0];
-					
-					
+
+
 					ShmCharger->gun_info[gun_index].acCcsInfo.EVSEPresentCurrent[0] = (float)ShmCharger->gun_info[gun_index].outputCurrent.L1N_L12[0];
 					ShmCharger->gun_info[gun_index].acCcsInfo.EVSEPresentCurrent[1] = (float)ShmCharger->gun_info[gun_index].outputCurrent.L1N_L12[0];
-					ShmCharger->gun_info[gun_index].acCcsInfo.EVSEPresentCurrent[2] = (float)ShmCharger->gun_info[gun_index].outputCurrent.L1N_L12[0];							
+					ShmCharger->gun_info[gun_index].acCcsInfo.EVSEPresentCurrent[2] = (float)ShmCharger->gun_info[gun_index].outputCurrent.L1N_L12[0];
 #else	//SIMULATION
 				ShmSysConfigAndInfo->SysInfo.AcChargingData[gun_index].PresentChargingCurrent = (float)(ShmSysConfigAndInfo->SysInfo.AcChargingData[gun_index].SystemStatus==SYS_MODE_CHARGING?(((rand()%10)+((ShmCharger->gun_info[gun_index].targetCurrent*10)-5))/10.0):0);
 				if(ShmSysConfigAndInfo->SysConfig.AcPhaseCount == 3)
@@ -2693,6 +2966,100 @@ int main(void)
 					else
 						failCount[gun_index] = FAIL_SPEC_COMM;
 				}
+
+				//========================================
+				// Case 12: Configuration PTB permission status
+				//========================================
+				if(ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P')
+				{
+					if(ShmCharger->gun_info[gun_index].isSetPtbMeterPermisson == ON)
+					{
+						if(Config_Ptb_Meter_Permission_Status(Uart1Fd, (gun_index>0?ADDR_AC_PRIMARY_2:ADDR_AC_PRIMARY_1), &ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters) == PASS)
+						{
+							failCount[gun_index] = 0;
+							ShmCharger->gun_info[gun_index].isSetPtbMeterPermisson = OFF;
+						}
+						else
+						{
+							DEBUG_WARN("MCU-%d set permission to PTB meter fail...%d\n", gun_index, failCount[gun_index]);
+							if(failCount[gun_index]<USHRT_MAX)
+								failCount[gun_index]++;
+							else
+								failCount[gun_index] = FAIL_SPEC_COMM;
+						}
+					}
+				}
+
+				//========================================
+				// Case 13; Query PTB meter messages
+				//========================================
+				if(ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P')
+				{
+					if((ShmCharger->gun_info[gun_index].isGetPtbMeterMessage == ON))
+					{
+						for(uint8_t idx = CMD_READ_OUTPUT_MESSAGE_FORMAT_ID; idx <= (CMD_READ_PUBLIC_KEY+1); idx++)
+						{
+							if(Query_PTB_METER_MESSAGE(Uart1Fd, (gun_index>0?ADDR_AC_PRIMARY_2:ADDR_AC_PRIMARY_1), &ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters, idx) == PASS)
+							{
+								failCount[gun_index] = 0;
+							}
+							else
+							{
+								if(idx == CMD_READ_OUTPUT_MESSAGE_FORMAT_ID)
+								{
+									DEBUG_WARN("MCU-%d get PTB meter output message format id fail...%d\n", gun_index, failCount[gun_index]);
+								}
+								else if(idx == CMD_READ_OUTPUT_MESSAGE_LENGTH)
+								{
+									DEBUG_WARN("MCU-%d get PTB meter output message length fail...%d\n", gun_index, failCount[gun_index]);
+								}
+								else if(idx == CMD_READ_OUTPUT_MESSAGE)
+								{
+									DEBUG_WARN("MCU-%d get PTB meter output message fail...%d\n", gun_index, failCount[gun_index]);
+								}
+								else if(idx == CMD_READ_OUTPUT_SIGNATURE_LENGTH)
+								{
+									DEBUG_WARN("MCU-%d get PTB meter output signature length fail...%d\n", gun_index, failCount[gun_index]);
+								}
+								else if(idx == CMD_READ_OUTPUT_SIGNATURE)
+								{
+									DEBUG_WARN("MCU-%d get PTB meter output signature fail...%d\n", gun_index, failCount[gun_index]);
+								}
+								else if(idx == CMD_READ_PUBLIC_KEY_HEADER_LENGTH)
+								{
+									DEBUG_WARN("MCU-%d get PTB meter public key header length fail...%d\n", gun_index, failCount[gun_index]);
+								}
+								else if(idx == CMD_READ_PUBLIC_KEY_HEADER)
+								{
+									DEBUG_WARN("MCU-%d get PTB meter public key header fail...%d\n", gun_index, failCount[gun_index]);
+								}
+								else if(idx == CMD_READ_PUBLIC_KEY_LENGTH)
+								{
+									DEBUG_WARN("MCU-%d get PTB meter public key length fail...%d\n", gun_index, failCount[gun_index]);
+								}
+								else if(idx == CMD_READ_PUBLIC_KEY)
+								{
+									DEBUG_WARN("MCU-%d get PTB meter public key fail...%d\n", gun_index, failCount[gun_index]);
+								}
+								else
+								{}
+
+								if(failCount[gun_index]<USHRT_MAX)
+									failCount[gun_index]++;
+								else
+									failCount[gun_index] = FAIL_SPEC_COMM;
+							}
+
+							if(idx == (CMD_READ_PUBLIC_KEY+1))
+							{
+								ShmCharger->gun_info[gun_index].isGetPtbMeterMessage = OFF;
+								DEBUG_INFO("========================================\n");
+								DEBUG_INFO("Stop query PTB meter messages.\n");
+								DEBUG_INFO("========================================\n");
+							}
+						}
+					}
+				}
 			}
 			else
 			{

+ 2 - 0
EVSE/Projects/AW-CCS/Apps/Module_InternalComm.h

@@ -34,6 +34,7 @@ enum MESSAGE_COMMAND
 	CMD_QUERY_POWER_CONSUMPTION = 0x2C,
 	CMD_QUERY_GUN_PLUGIN_TIMES = 0x2D,
 	CMD_QUERY_METER_IC_CORRECTION_PARA = 0x36,
+	CMD_QUERY_PTB_METER_MESSAGE = 0x39,
 
 	CMD_CONFIG_FAN_SPEED = 0x81,
 	CMD_CONFIG_SERIAL_NUMBER = 0x82,
@@ -48,6 +49,7 @@ enum MESSAGE_COMMAND
 	CMD_CONFIG_MCU_SET_BREATHE_LED_TIMING = 0x8D,
 	CMD_CONFIG_MCU_SET_LED_BRIGHTNESS = 0x8E,
 	CMD_CONFIG_AUX_POWER_SWITCH = 0x95,
+	CMD_CONFIG_PTB_METER_PERMISSION = 0x97,
 
 	CMD_UPDATE_START = 0xe0,
 	CMD_UPDATE_ABOARD = 0xe1,

+ 398 - 34
EVSE/Projects/AW-CCS/Apps/main.c

@@ -1283,6 +1283,44 @@ uint8_t ocpp_get_freevend_idtag(uint8_t * userId)
 	return result;
 }
 
+uint8_t ocpp_set_ocmf_date_transfer(uint8_t gun_index)
+{
+	uint8_t result = NO;
+
+	memset(ShmOCPP16Data->OcmfData[gun_index].DataString, 0x00, ARRAY_SIZE(ShmOCPP16Data->OcmfData[gun_index].DataString));
+	memset(ShmOCPP16Data->OcmfData[gun_index].PublicKey, 0x00, ARRAY_SIZE(ShmOCPP16Data->OcmfData[gun_index].PublicKey));
+
+	if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16)
+	{
+		if((strcmp((char*)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessageFormatId, "") != 0) &&
+		   (strcmp((char*)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessage, "") != 0) &&
+		   (strcmp((char*)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputSignature, "") != 0) &&
+		   (strcmp((char*)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyHeader, "") != 0) &&
+		   (strcmp((char*)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKey, "") != 0))
+		{
+			strcat((char *)ShmOCPP16Data->OcmfData[gun_index].DataString, (char *)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessageFormatId);
+			strcat((char *)ShmOCPP16Data->OcmfData[gun_index].DataString,"|");
+			strcat((char *)ShmOCPP16Data->OcmfData[gun_index].DataString, (char *)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessage);
+			strcat((char *)ShmOCPP16Data->OcmfData[gun_index].DataString, "|{\"SD\":\"");
+			strcat((char *)ShmOCPP16Data->OcmfData[gun_index].DataString, (char *)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputSignature);
+			strcat((char *)ShmOCPP16Data->OcmfData[gun_index].DataString, "\"}");
+
+			sprintf((char *)ShmOCPP16Data->OcmfData[gun_index].PublicKey, "%s%s", ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyHeader,
+																				  ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKey);
+
+			DEBUG_INFO("Set ptb meter message into data transfer success. \n");
+
+			result = YES;
+		}
+	}
+	else if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20)
+	{
+		// TO DO OCPP 2.0
+	}
+
+	return result;
+}
+
 //======================================================
 // Check interface status
 //======================================================
@@ -1667,18 +1705,18 @@ int DB_Open(sqlite3 *db)
 						  ");";
 
 	char* createRecordBufSql="CREATE TABLE IF NOT EXISTS charging_record_buffer("
-						  "reservationId text, "
-						  "transactionId text, "
-						  "startMethod text, "
-						  "userId text, "
-						  "dateTimeStart text, "
-						  "dateTimeStop text,"
-						  "socStart text, "
-						  "socStop text, "
-						  "chargeEnergy text, "
-						  "stopReason text, "
-						  "finalCost text"
-						  ");";
+							 "reservationId text, "
+							 "transactionId text, "
+							 "startMethod text, "
+							 "userId text, "
+							 "dateTimeStart text, "
+							 "dateTimeStop text,"
+							 "socStart text, "
+							 "socStop text, "
+							 "chargeEnergy text, "
+							 "stopReason text, "
+							 "finalCost text"
+							 ");";
 
 	char* createCfgSql="CREATE TABLE IF NOT EXISTS `config` ( "
 					   "`idx` INTEGER PRIMARY KEY AUTOINCREMENT, "
@@ -1686,6 +1724,20 @@ int DB_Open(sqlite3 *db)
 				       "`connector` INTEGER NOT NULL, "
 					   "`val` TEXT NOT NULL, unique(item,connector) on conflict replace);";
 
+	char* createMeterPermissionRecordSql="CREATE TABLE IF NOT EXISTS `meter_permission_record` ( "
+					   	   	   	   	   	 "`idx` INTEGER PRIMARY KEY AUTOINCREMENT, "
+					   	   	   	   	   	 "`item` TEXT NOT NULL, "
+					   	   	   	   	   	 "`connector` INTEGER NOT NULL, "
+					   	   	   	   	   	 "`val` TEXT NOT NULL, unique(item,connector) on conflict replace);";
+
+	char* createMeterRecordSql="CREATE TABLE IF NOT EXISTS meter_record("
+							   "idx integer primary key AUTOINCREMENT, "
+							   "transactionId text, "
+							   "ocmfString text, "
+							   "publicKey text, "
+							   "isUpload text"
+								");";
+
 	//sqlite3_config(SQLITE_CONFIG_URI, 1);
 	if(sqlite3_open(DB_FILE, &db))
 	{
@@ -1727,6 +1779,28 @@ int DB_Open(sqlite3 *db)
 			DEBUG_INFO( "Opened local config table successfully\n");
 		}
 
+		// PTB meter permission status record
+		if (sqlite3_exec(db, createMeterPermissionRecordSql, 0, 0, &errMsg) != SQLITE_OK)
+		{
+			result = FAIL;
+			DEBUG_ERROR( "Create local meter permission status table error message: %s\n", errMsg);
+		}
+		else
+		{
+			DEBUG_INFO( "Opened local meter permission status table successfully\n");
+		}
+
+		// PTB meter data record
+		if (sqlite3_exec(db, createMeterRecordSql, 0, 0, &errMsg) != SQLITE_OK)
+		{
+			result = FAIL;
+			DEBUG_ERROR( "Create local Meter Data table error message: %s\n", errMsg);
+		}
+		else
+		{
+			DEBUG_INFO( "Opened local Meter Data table successfully\n");
+		}
+
 		sqlite3_close(db);
 	}
 
@@ -1914,6 +1988,8 @@ int DB_Insert_Record(sqlite3 *db, int gun_index)
 	char* errMsg = NULL;
 	char sqlStr[4096];
 	char receiptInfo[2048];
+	char TmpReadOutputOcmfMessage[2048];
+	char TmpReadPublicKeyWithHeader[256];
 
 	getReceiptInfo(gun_index, receiptInfo);
 
@@ -1966,6 +2042,31 @@ int DB_Insert_Record(sqlite3 *db, int gun_index)
 	}
 	//DEBUG_INFO("sqlStr= %s\n", sqlStr);
 
+	memset(TmpReadOutputOcmfMessage, 0x00, ARRAY_SIZE(TmpReadOutputOcmfMessage));
+	memset(TmpReadPublicKeyWithHeader, 0x00, ARRAY_SIZE(TmpReadPublicKeyWithHeader));
+
+	if(ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P')
+	{
+		strcat((char *)TmpReadOutputOcmfMessage, (char *)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessageFormatId);
+		strcat((char *)TmpReadOutputOcmfMessage,"|");
+		strcat((char *)TmpReadOutputOcmfMessage, (char *)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputMessage);
+		strcat((char *)TmpReadOutputOcmfMessage, "|{\"SD\":\"");
+		strcat((char *)TmpReadOutputOcmfMessage, (char *)ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadOutputSignature);
+		strcat((char *)TmpReadOutputOcmfMessage, "\"}");
+
+		sprintf((char *)TmpReadPublicKeyWithHeader, "%s%s", ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKeyHeader,
+															ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.ReadPublicKey);
+
+		sprintf(sqlStr, "insert into meter_record(transactionId, ocmfString, publicKey, isUpload) "
+											"values('%d', '%s', '%s', '%d');",
+											ShmOCPP16Data->StartTransaction[gun_index].ResponseTransactionId,
+											TmpReadOutputOcmfMessage,
+											TmpReadPublicKeyWithHeader,
+											ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.isUpLoad);
+
+		DEBUG_INFO("PTB meter message is upload to the backend system: %s \n", ((ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.isUpLoad == YES)?"YES":"NO"));
+	}
+
 	if(sqlite3_open(DB_FILE, &db))
 	{
 		result = FAIL;
@@ -2007,6 +2108,29 @@ int DB_Insert_Record(sqlite3 *db, int gun_index)
 			DEBUG_INFO( "delete local charging record successfully\n");
 		}
 
+		// Insert meter data record
+		if (sqlite3_exec(db, sqlStr, 0, 0, &errMsg) != SQLITE_OK)
+		{
+			result = FAIL;
+			DEBUG_INFO( "Insert local meter data error message: %s\n", errMsg);
+		}
+		else
+		{
+			DEBUG_INFO( "Insert local meter data successfully\n");
+		}
+
+		// Delet meter data record
+		sprintf(sqlStr, "delete from meter_record where (idx < (select idx from meter_record order by idx desc limit 1)-2000)");
+		if (sqlite3_exec(db, sqlStr, 0, 0, &errMsg) != SQLITE_OK)
+		{
+			result = FAIL;
+			DEBUG_INFO( "delete local meter data error message: %s\n", errMsg);
+		}
+		else
+		{
+			DEBUG_INFO( "delete local meter data record successfully\n");
+		}
+
 		sqlite3_close(db);
 	}
 
@@ -2097,6 +2221,83 @@ int DB_Get_Operactive(sqlite3 *db, uint8_t gun_index)
 	return result;
 }
 
+int DB_Update_Meter_Permission(sqlite3 *db, uint8_t gun_index, uint8_t permission_status)
+{
+	uint8_t result = false;
+	char* errMsg = NULL;
+	char sqlStr[1024];
+	srand(time(NULL));
+
+	if(sqlite3_open(DB_FILE, &db))
+	{
+		result = FAIL;
+		DEBUG_INFO( "Can't open database: %s\n", sqlite3_errmsg(db));
+		sqlite3_close(db);
+	}
+	else
+	{
+		sprintf(sqlStr, "insert or replace into meter_permission_record (item, connector, val) values('Permission', %d, %d);", gun_index, permission_status);
+		//DEBUG_INFO("sqlStr= %s\n", sqlStr);
+		if (sqlite3_exec(db, sqlStr, 0, 0, &errMsg) != SQLITE_OK)
+		{
+			result = FAIL;
+			DEBUG_INFO( "update meter permission status error message: %s\n", errMsg);
+		}
+		else
+		{
+			DEBUG_INFO("update connector-%d meter permission status item Permission to %d\n", gun_index, permission_status);
+		}
+
+		sqlite3_close(db);
+	}
+
+	return result;
+}
+
+int DB_Get_Meter_Permission(sqlite3 *db, uint8_t gun_index)
+{
+	uint8_t result = PERMISSION_END_CHARGING;
+	char* errMsg = NULL;
+	char sqlStr[1024];
+	char **rs;
+	int	 rows, cols;
+
+	sprintf(sqlStr, "select * from meter_permission_record where item='Permission' and connector=%d;", gun_index);
+	//DEBUG_INFO("sqlStr= %s\n", sqlStr);
+
+	if(sqlite3_open(DB_FILE, &db))
+	{
+		result = FAIL;
+		DEBUG_INFO( "Can't open database: %s\n", sqlite3_errmsg(db));
+		sqlite3_close(db);
+	}
+	else
+	{
+		sqlite3_get_table(db, sqlStr, &rs, &rows, &cols, &errMsg);
+
+		if(rows>0)
+		{
+			for(int idxRow=1;idxRow<=rows;idxRow++)
+			{
+				if(strcmp(rs[(idxRow*cols)+3], "1") == 0)
+				{
+					result = PERMISSION_START_CHARGING;
+				}
+				DEBUG_INFO("Query connector-%d meter permission status : %s\n", gun_index, rs[(idxRow*cols)+3]);
+			}
+		}
+		else
+		{
+			DEBUG_INFO("Query connector-%d fail, default value.\n", gun_index);
+		}
+
+		sqlite3_free_table(rs);
+		sqlite3_close(db);
+	}
+
+	return result;
+}
+
 //======================================================
 // Peripheral initial
 //======================================================
@@ -2896,6 +3097,7 @@ int Initialization(uint8_t gun_index)
 	}
 
 	ShmCharger->gun_info[gun_index].isOperactive = DB_Get_Operactive(localDb, gun_index);
+	ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.PtbMeterPermissionStatus = DB_Get_Meter_Permission(localDb, gun_index);
 
 	return result;
 }
@@ -5324,6 +5526,121 @@ void checkRfidAuthrize()
 	}
 }
 
+void setPtbMeterPermission(uint8_t gun_index, uint8_t permission)
+{
+	switch(permission)
+	{
+		case PREMISSION_DEFAULT:
+
+			// Changed permission to [Default]
+			ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.PtbMeterPermissionStatus = PREMISSION_DEFAULT;
+			DEBUG_INFO("Set PTB meter permission to [ PREMISSION_DEFAULT ] \n");
+
+			break;
+		case PERMISSION_START_CHARGING:
+			// Changed permission to [Start Charging]
+			if((ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.PtbMeterPermissionStatus != PERMISSION_START_CHARGING) &&
+			   (ShmCharger->gun_info[gun_index].isSetPtbMeterPermisson != ON))
+			{
+				ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.PtbMeterPermissionStatus = PERMISSION_START_CHARGING;
+				ShmCharger->gun_info[gun_index].isSetPtbMeterPermisson = ON;
+				DEBUG_INFO("Set PTB meter permission to [ PERMISSION_START_CHARGING ] \n");
+				DB_Update_Meter_Permission(localDb, gun_index, PERMISSION_START_CHARGING);
+			}
+			break;
+		case PERMISSION_END_CHARGING:
+			// Changed permission to [End Charging]
+			if((ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.PtbMeterPermissionStatus != PERMISSION_END_CHARGING) &&
+			   (ShmCharger->gun_info[gun_index].isSetPtbMeterPermisson != ON))
+			{
+				ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.PtbMeterPermissionStatus = PERMISSION_END_CHARGING;
+				ShmCharger->gun_info[gun_index].isSetPtbMeterPermisson = ON;
+				DEBUG_INFO("Set PTB meter permission to [ PERMISSION_END_CHARGING ] \n");
+				DB_Update_Meter_Permission(localDb, gun_index, PERMISSION_END_CHARGING);
+			}
+			break;
+	}
+}
+
+void proccessEndOfChargingForPtbMeter(uint8_t gun_index)
+{
+	if(getDiffSecNow(startTime[gun_index][TMR_IDX_PTB_METER_MESSAGE]) >= 12)
+	{
+		if((ocpp_set_ocmf_date_transfer(gun_index) == YES))
+		{
+			checkStopReason(gun_index);
+
+			if(ShmOCPP16Data->OcmfData[gun_index].SendOcmfDataReq != ON)
+				ShmOCPP16Data->OcmfData[gun_index].SendOcmfDataReq = ON;
+
+			ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.isUpLoad = YES;
+			setChargerMode(gun_index, SYS_MODE_COMPLETE);
+		}
+		else
+		{
+			checkStopReason(gun_index);
+			ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.isUpLoad = NO;
+			setChargerMode(gun_index, SYS_MODE_COMPLETE);
+		}
+	}
+	else
+	{
+		setPtbMeterPermission(gun_index, PERMISSION_END_CHARGING);
+
+		if((getDiffSecNow(startTime[gun_index][TMR_IDX_PTB_METER_MESSAGE]) >= 6) && (getDiffSecNow(startTime[gun_index][TMR_IDX_PTB_METER_MESSAGE]) <= 9))
+			ShmCharger->gun_info[gun_index].isGetPtbMeterMessage = ON;
+	}
+}
+
+void checkMissingPtbMeterMessage(uint8_t gun_index)
+{
+	if((ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.PtbMeterPermissionStatus == PERMISSION_START_CHARGING))
+	{
+		// Trigger get PTB meter message
+		if((getDiffSecNow(startTime[gun_index][TMR_IDX_PTB_METER_SEND]) > 0) && (getDiffSecNow(startTime[gun_index][TMR_IDX_PTB_METER_SEND]) <= 5))
+		{
+			ShmCharger->gun_info[gun_index].isGetPtbMeterMessage = ON;
+		}
+
+		// 5 seconds for MCU & PTB communcation + 5 seconds for CSU & MCU get PTB messages.
+		if((getDiffSecNow(startTime[gun_index][TMR_IDX_PTB_METER_SEND]) >= 12))
+		{
+			if((ShmCharger->gun_info[gun_index].isGetPtbMeterMessage != ON))
+			{
+				if((ocpp_set_ocmf_date_transfer(gun_index) == YES))
+				{
+					if(ShmOCPP16Data->OcmfData[gun_index].SendOcmfDataReq != ON)
+						ShmOCPP16Data->OcmfData[gun_index].SendOcmfDataReq = ON;
+
+					ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.isUpLoad = YES;
+					ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.PtbMeterPermissionStatus = PERMISSION_END_CHARGING;
+					DB_Update_Meter_Permission(localDb, gun_index, PERMISSION_END_CHARGING);
+					DB_Insert_Record(localDb, gun_index);
+
+					DEBUG_INFO("Meter data send to the backend system. \n");
+				}
+				else
+				{
+					ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.isUpLoad = NO;
+					ShmCharger->gun_info[gun_index].Ptb_Meter_Parameters.PtbMeterPermissionStatus = PERMISSION_END_CHARGING;
+					DB_Update_Meter_Permission(localDb, gun_index, PERMISSION_END_CHARGING);
+
+					DEBUG_INFO("No data to send. \n");
+				}
+			}
+			else
+			{}
+		}
+		else
+		{}
+
+	}
+	else
+	{
+		refreshStartTimer(&startTime[gun_index][TMR_IDX_PTB_METER_SEND]);
+	}
+}
+
 //======================================================
 // Main process
 //======================================================
@@ -5866,6 +6183,10 @@ int main(void)
 																	   (ShmSysConfigAndInfo->SysConfig.ModelName[2]=='D') ||
 																	   (ShmSysConfigAndInfo->SysConfig.ModelName[2]=='W')
 																	   ?3:1);
+
+						// Refresh PTB resend timer
+						if(ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P')
+							refreshStartTimer(&startTime[gun_index][TMR_IDX_PTB_METER_SEND]);
 					}
 
 					break;
@@ -5910,8 +6231,16 @@ int main(void)
 						previousData[gun_index].primaryMcuCp_Pwn_Duty = 0;
 						previousData[gun_index].targetCurrent = 0;
 						previousData[gun_index].current_limit = 0;
+
+						// Refresh PTB resend timer
+						if(ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P')
+							refreshStartTimer(&startTime[gun_index][TMR_IDX_PTB_METER_SEND]);
 					}
 
+					// Check missing PTB meter messages
+					if(ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P')
+						checkMissingPtbMeterMessage(gun_index);
+
 					// Check handshake timeout
 					checkHandshakeCountdown(gun_index);
 
@@ -6467,6 +6796,10 @@ int main(void)
 									ocpp_set_starttransaction_req(gun_index, ON);
 									refreshStartTimer(&startChargingTime[gun_index]);
 
+									// PTB Permission
+									if(ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P')
+										setPtbMeterPermission(gun_index, PERMISSION_START_CHARGING);
+
 									setChargerMode(gun_index, SYS_MODE_CHARGING);
 								}
 
@@ -6573,6 +6906,11 @@ int main(void)
 									ocpp_copy_userid_to_starttransaction(gun_index);
 									ocpp_set_starttransaction_req(gun_index, ON);
 									ShmCharger->gun_info[gun_index].isCCSStartTransation = OFF;
+
+									// PTB Permission
+									if(ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P')
+										setPtbMeterPermission(gun_index, PERMISSION_START_CHARGING);
+
 									setChargerMode(gun_index, SYS_MODE_CHARGING);
 									DEBUG_INFO("set SYS_MODE_CHARGING\n");
 									refreshStartTimer(&startChargingTime[gun_index]);
@@ -6619,6 +6957,11 @@ int main(void)
 						ocpp_copy_userid_to_starttransaction(gun_index);
 						ocpp_set_starttransaction_req(gun_index, ON);
 						refreshStartTimer(&startChargingTime[gun_index]);
+
+						// PTB Permission
+						if(ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P')
+							setPtbMeterPermission(gun_index, PERMISSION_START_CHARGING);
+
 						setChargerMode(gun_index, SYS_MODE_CHARGING);
 					}
 					else if(ShmCharger->gun_info[gun_index].primaryMcuState.socket_e.isSocketEPinOn == ON)
@@ -6691,6 +7034,10 @@ int main(void)
 						ocpp_set_profile_req(gun_index, ON);
 						ShmCharger->gun_info[gun_index].isChargerStopByCondition = NO;
 						ShmCharger->gun_info[gun_index].resultAuthorization = DEFAULT_RFID;
+
+						// Refresh timer for getting PTB meter message
+						if(ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P')
+							refreshStartTimer(&startTime[gun_index][TMR_IDX_PTB_METER_MESSAGE]);
 					}
 					//if time up, clear CCS MSG count
 					if((ShmCharger->gun_info[gun_index].chargingMode == CHARGING_MODE_HLC) &&
@@ -6945,15 +7292,7 @@ int main(void)
 						// Debug information
 						if((getDiffSecNow(startTime[gun_index][TMR_IDX_REFRESH_CHARGING_INFO]) > TIMEOUT_SPEC_LOGPPRINTOUT) || (getDiffSecNow(startTime[gun_index][TMR_IDX_REFRESH_CHARGING_INFO]) < 0))
 						{
-							/*
-							DEBUG_INFO("==============================================================\n");
-							DEBUG_INFO("ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent: %d \n", ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent);
-							DEBUG_INFO("ShmCharger->gun_info[%d].primaryMcuCp_Pwn_Duty.max_current: %d\n", gun_index, ShmCharger->gun_info[gun_index].primaryMcuCp_Pwn_Duty.max_current);
-							DEBUG_INFO("ShmCharger->gun_info[%d].targetCurrent: %d\n", gun_index, ShmCharger->gun_info[gun_index].targetCurrent);
-							DEBUG_INFO("==============================================================\n");
-							*/
 							refreshStartTimer(&startTime[gun_index][TMR_IDX_REFRESH_CHARGING_INFO]);
-
 							getDateTimeString((char*)ShmSysConfigAndInfo->SysInfo.AcChargingData[gun_index].StopDateTime);
 							DB_Update_Record_Buf(localDb, gun_index);
 						}
@@ -6975,6 +7314,10 @@ int main(void)
 
 						if(ShmCharger->gun_info[gun_index].isGunUnpluggedBefore == YES)
 							setRelay(gun_index, OFF);
+
+						//  Refresh timer for getting PTB meter message
+						if(ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P')
+							refreshStartTimer(&startTime[gun_index][TMR_IDX_PTB_METER_MESSAGE]);
 					}
 
 					refreshStartTimer(&endChargingTime[gun_index]);
@@ -7004,9 +7347,17 @@ int main(void)
 						{
 							ShmCharger->gun_info[gun_index].primaryMcuCp_Pwn_Duty.max_current = CCS_PWM_DUTY_100;
 							ShmCharger->gun_info[gun_index].mcuFlag.isSetCpPwmDuty = ON;
-							sleep(1);
-							checkStopReason(gun_index);
-							setChargerMode(gun_index, SYS_MODE_COMPLETE);
+
+							if(ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P')
+							{
+								proccessEndOfChargingForPtbMeter(gun_index);
+							}
+							else
+							{
+								sleep(1);
+								checkStopReason(gun_index);
+								setChargerMode(gun_index, SYS_MODE_COMPLETE);
+							}
 						}
 						else if(ShmCharger->gun_info[gun_index].chargingMode == CHARGING_MODE_HLC)
 						{
@@ -7019,11 +7370,23 @@ int main(void)
 						}
 						else
 						{
-							setChargerMode(gun_index, SYS_MODE_COMPLETE);
+							if(ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P')
+							{
+								proccessEndOfChargingForPtbMeter(gun_index);
+							}
+							else
+							{
+								checkStopReason(gun_index);
+								setChargerMode(gun_index, SYS_MODE_COMPLETE);
+							}
 						}
 					}
 					else
 					{
+						// Refresh timer for getting PTB meter message
+						if(ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P')
+							refreshStartTimer(&startTime[gun_index][TMR_IDX_PTB_METER_MESSAGE]);
+
 						// If the charger stops charging, the led should be stoped blink
 						if(!ShmCharger->gun_info[gun_index].primaryMcuState.relay_state)
 						{
@@ -7052,13 +7415,6 @@ int main(void)
 						// Debug information
 						if((getDiffSecNow(startTime[gun_index][TMR_IDX_REFRESH_CHARGING_INFO]) > TIMEOUT_SPEC_LOGPPRINTOUT) || (getDiffSecNow(startTime[gun_index][TMR_IDX_REFRESH_CHARGING_INFO]) < 0))
 						{
-							/*
-							DEBUG_INFO("=============================================================\n");
-							DEBUG_INFO("ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent: %d\n", ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent);
-							DEBUG_INFO("ShmCharger->gun_info[%d].primaryMcuCp_Pwn_Duty.max_current: %d\n", gun_index, ShmCharger->gun_info[gun_index].primaryMcuCp_Pwn_Duty.max_current);
-							DEBUG_INFO("ShmCharger->gun_info[%d].targetCurrent: %d\n", gun_index, ShmCharger->gun_info[gun_index].targetCurrent);
-							DEBUG_INFO("=============================================================\n");
-							*/
 							refreshStartTimer(&startTime[gun_index][TMR_IDX_REFRESH_CHARGING_INFO]);
 						}
 
@@ -7094,9 +7450,17 @@ int main(void)
 						ShmCharger->gun_info[gun_index].primaryMcuCp_Pwn_Duty.max_current = CCS_PWM_DUTY_100;
 						ShmCharger->gun_info[gun_index].mcuFlag.isSetCpPwmDuty = ON;
 						ShmCharger->gun_info[gun_index].isCCSWaitChangeDuty = OFF;
-						sleep(1);
-						checkStopReason(gun_index);
-						setChargerMode(gun_index, SYS_MODE_COMPLETE);
+
+						if(ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P')
+						{
+							proccessEndOfChargingForPtbMeter(gun_index);
+						}
+						else
+						{
+							sleep(1);
+							checkStopReason(gun_index);
+							setChargerMode(gun_index, SYS_MODE_COMPLETE);
+						}
 					}
 
 					break;

+ 55 - 3
EVSE/Projects/AW-CCS/Apps/main.h

@@ -63,7 +63,7 @@
 #define ALARM_SHUTTER_FAULT                     0x00002000
 #define ALARM_LOCKER_FAULT                      0x00004000
 #define ALARM_POWER_DROP                        0x00008000
-  
+
 #define ALARM_L1_CIRCUIT_SHORT                  0x00010000
 #define ALARM_ROTATORY_SWITCH_FAULT             0x00020000
 #define ALARM_RELAY_DRIVE_FAULT                 0x00040000
@@ -238,8 +238,8 @@ enum TIMER_IDX
 	TMR_IDX_LCM_POWER_CONSUMPTION,
 	TMR_IDX_RESET_WIFI,
 	TMR_IDX_CLEAN_REMOTE_START_WAIT,
-	TMR_IDX_17,
-	TMR_IDX_18,
+	TMR_IDX_PTB_METER_MESSAGE,
+	TMR_IDX_PTB_METER_SEND,
 	TMR_IDX_19,
 	TMR_IDX_GUN_DETECT,
 	TMR_IDX_CNT
@@ -256,6 +256,37 @@ enum RFID_AUTHORIZATION_STATUS
 	UNKNOW_RFID
 };
 
+//===================================
+// Define PTB meter permission constant
+//===================================
+enum PERMISSION_PTB_METER_STATUS
+{
+	PREMISSION_DEFAULT = 0,
+	PERMISSION_START_CHARGING,
+	PERMISSION_END_CHARGING
+};
+
+//===================================
+// Define PTB meter sub-command constant
+//===================================
+enum PTB_METER_SUB_COMMAND
+{
+	CMD_READ_OUTPUT_OCMF_MESSAGE_LENGTH = 0x01,
+	CMD_READ_OUTPUT_OCMF_MESSAGE = 0x02,
+	CMD_READ_PUBLIC_KEY_WITH_HEADER_LENGTH = 0x03,
+	CMD_READ_PUBLIC_KEY_WITH_HEADER = 0x04,
+
+	CMD_READ_OUTPUT_MESSAGE_FORMAT_ID = 0x10,
+	CMD_READ_OUTPUT_MESSAGE_LENGTH = 0x11,
+	CMD_READ_OUTPUT_MESSAGE = 0x12,
+	CMD_READ_OUTPUT_SIGNATURE_LENGTH = 0x13,
+	CMD_READ_OUTPUT_SIGNATURE = 0x14,
+	CMD_READ_PUBLIC_KEY_HEADER_LENGTH = 0x15,
+	CMD_READ_PUBLIC_KEY_HEADER = 0x16,
+	CMD_READ_PUBLIC_KEY_LENGTH = 0x17,
+	CMD_READ_PUBLIC_KEY	= 0x18
+};
+
 #define DEBUG_INFO(format, args...) StoreLogMsg("[%s:%d][%s][Info] "format, (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__), __LINE__, __FUNCTION__, ##args)
 #define DEBUG_WARN(format, args...) StoreLogMsg("[%s:%d][%s][Warn] "format, (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__), __LINE__, __FUNCTION__, ##args)
 #define DEBUG_ERROR(format, args...) StoreLogMsg("[%s:%d][%s][Error] "format, (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__), __LINE__, __FUNCTION__, ##args)
@@ -709,6 +740,23 @@ typedef struct CCS_INFO
 	uint16_t	TempFlag15:1;
 }Ac_Ccs_Info;
 
+typedef struct PTB_METER
+{
+	uint8_t isUpLoad;
+	uint8_t PtbMeterPermissionStatus;				// 0x01:Start Charging 0x02:End Charging
+
+	uint16_t ReadOutputMessageLength;
+	uint16_t ReadOuputSignatureLength;
+	uint16_t ReadPublicKeyHeaderLength;
+	uint16_t ReadPublicKeyLength;
+
+	unsigned char ReadOutputMessageFormatId[32];
+	unsigned char ReadOutputMessage[1024+1];
+	unsigned char ReadOutputSignature[256+1];
+	unsigned char ReadPublicKeyHeader[54+1];
+	unsigned char ReadPublicKey[128+1];
+}Ptb_Meter;
+
 typedef struct GUN_INFO
 {
 	Ver 											ver;
@@ -736,6 +784,8 @@ typedef struct GUN_INFO
 	Set_Aux_Power_Switch							setAuxPowerSwitch;
 	Gpio_in											GPIO_Input;
 	Ac_Ccs_Info										acCcsInfo;
+	Ptb_Meter										Ptb_Meter_Parameters;
+
 	float											presentChargedEnergyPeriod[24];		// Session present charged energy at each period, resolution: 0.01 KWH
 	uint8_t											ccsHandshakeState;
 	uint8_t											PreviousEVChargeProgress;
@@ -767,6 +817,8 @@ typedef struct GUN_INFO
 	uint32_t										isGetEvCCIDTimeout:1;
 	uint32_t										isRemoteStartWait:1;
 	uint32_t										isEvCCIDAuthorizeFail:1;
+	uint32_t										isSetPtbMeterPermisson:1;
+	uint32_t										isGetPtbMeterMessage:1;
 }Gun_Info;
 
 struct Charger