Эх сурвалжийг харах

2021-09-17 / Wendell

Actions
1. add inrush current solution for safety test
2. add smart charging profile
3. add ocpp StopTransactionOnInvalidId key
4. add db model name
5. fix charging time stop at 2147s
6. fix ocpp bootnotification issue when no dispenser connected
7. enable watch dog
8. fix MaxTotalChargingPower & MaxTotalChargingCurrent issue
9. modify qr code display issue
10.fix status code = no error when emergency alarm occur

Files
1. As follow commit history

Image version : V1.03.XX.XXXX.XX
Wendell 3 жил өмнө
parent
commit
62d6cb22a3

+ 22 - 3
EVSE/Projects/DO360/Apps/Common.c

@@ -70,14 +70,14 @@ void GetClockTime(struct timespec *_now_time)
 }
 
 // return value unit: 1us
-long GetTimeoutValue(struct timespec _start_time)
+unsigned long GetTimeoutValue(struct timespec _start_time)
 {
     struct timespec ts_end;
-    long ret = 0;
+    unsigned long ret = 0;
 
     clock_gettime(CLOCK_MONOTONIC, &ts_end);
 
-    ret = ((ts_end.tv_sec - _start_time.tv_sec) * 1000000) + ((ts_end.tv_nsec - _start_time.tv_nsec) / 1000);
+    ret = ((unsigned long)(ts_end.tv_sec - _start_time.tv_sec) * 1000000) + ((unsigned long)((ts_end.tv_nsec / 1000) - (_start_time.tv_nsec/ 1000)));
     /*
     printf("\r\n TimeInterval: %ld.%09ld - %ld.%09ld = %ld.%06ld ns",
         ts_end.tv_sec, ts_end.tv_nsec,  _start_time.tv_sec, _start_time.tv_nsec,
@@ -98,3 +98,22 @@ long GetTimeoutValue(struct timespec _start_time)
     return ret;
 }
 
+// return value unit: 1s
+unsigned long GetSecTimeoutValue(struct timespec _start_time)
+{
+    struct timespec ts_end;
+    unsigned long ret = 0;
+
+    clock_gettime(CLOCK_MONOTONIC, &ts_end);
+
+    ret = ((unsigned long)(ts_end.tv_sec - _start_time.tv_sec) * 1000) + ((unsigned long)((ts_end.tv_nsec / 1000000) - (_start_time.tv_nsec / 1000000)));
+    /*
+    printf("\r\n TimeInterval: %ld.%09ld - %ld.%09ld = %ld.%03ld ms",
+        ts_end.tv_sec, ts_end.tv_nsec,  _start_time.tv_sec, _start_time.tv_nsec,
+        (ret / 1000), (ret % 1000));
+    */
+    ret /= 1000;
+
+    return ret;
+}
+

+ 2 - 1
EVSE/Projects/DO360/Apps/Common.h

@@ -19,6 +19,7 @@
 int StoreSysLogMsg(const char *fmt, ...);
 int StorePsuLogMsg(const char *fmt, ...);
 void GetClockTime(struct timespec *_now_time);
-long GetTimeoutValue(struct timespec _start_time);
+unsigned long GetTimeoutValue(struct timespec _start_time);
+unsigned long GetSecTimeoutValue(struct timespec _start_time);
 
 #endif /* COMMON_H_ */

+ 12 - 1
EVSE/Projects/DO360/Apps/Config.h

@@ -53,6 +53,8 @@ typedef unsigned char               byte;
 #define MAX_MODULE_PER_GROUP        12
 #define SM_ChargerInfoKey           3000
 
+#define SAFETY_TEST_ENABLE          0
+
 // **********  Audi ********** //
 // Model Name: DOYC182000D2AD
 // Model Name: DDYC182V0UE2AD
@@ -69,6 +71,9 @@ typedef unsigned char               byte;
 // Model Name: DOYE242000D2BD
 // Model Name: DDYE242V0UE2BD
 
+// *********** TCC *********** //
+// Model Name: DBYE182000D1PH
+
 enum _SYSTEM_STATUS
 {
 	S_BOOTING =                         0,
@@ -448,6 +453,8 @@ typedef struct
 {
     unsigned char   MaxDispenser;
     unsigned char   MaxConnector;
+    unsigned char   CabinetSwitch;
+    unsigned char   reserved;
     SystemControl   SysCtrl;
     TestControl     TestCtrl;
     DebugControl    DebugCtrl;
@@ -529,13 +536,15 @@ typedef union
         unsigned int IdleCtrlRes:22;
 
         // MasterCtrlValue
+        unsigned int CableCheckDone:1;                          // 0: no effect,                1: CableCheck done
+        unsigned int InPrechargeMode:1;                         // 0: no effect,                1: system status in PreCharge mode
         unsigned int AlreadyInChargingMode:1;                   // 0: no effect,                1: system status ever enter charging mode
         unsigned int ExtendAvailable:1;                         // 0: no effect,                1: extend capability is available
         unsigned int NeedCurrentBalance:1;                      // 0: no effect,                1: need to current balance
         unsigned int OutputCurrentStable:1;                     // 0: no effect,                1: output current is stable
         unsigned int ReachMaxCurrentDemand:1;                   // 0: no effect,                1: reach ev max current demand
         unsigned int ReachMaxStageCurrent:1;                    // 0: no effect,                1: reach ev max stage current
-        unsigned int MasterCtrlRes:26;
+        unsigned int MasterCtrlRes:24;
 
         // StopChargingCtrlValue
         unsigned int StopChargingRequest:1;                     // 0: no effect,                1: master need to stop
@@ -599,6 +608,8 @@ typedef struct
     unsigned short          ParallelCheck;
     unsigned char           ParallelConfig[MAX_GROUP_QUANTITY]; // group parallel relay setting
     unsigned short          GunLoading;                         // gun output loading, unit: 0.01%
+    unsigned char           GunPsuQuantity;                     // record psu quantity at this gun
+    unsigned char           res;
 }PsuGroupCollectionData;
 
 typedef struct

+ 115 - 94
EVSE/Projects/DO360/Apps/InfyGroup_PsuCommObj.c

@@ -394,6 +394,104 @@ void SendCmdToPsu(int cmd, byte *data, byte dataLen)
     }
 }
 
+void SetPowerOnOff(byte address, byte device, byte value)
+{
+    byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_WCmd_ModulePowerOnOff;
+
+    memset(data, 0x00, ARRAY_SIZE(data));
+    // 1 : 關機
+    // 0 : 開機
+    data[0] = value;
+
+    PwrFrameMsg.InfyBits.DeviceValue = device;
+    PwrFrameMsg.InfyBits.DestinationAddress = address;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+    SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void SetAllModuleOutput(byte address, byte device, int voltage, int current)
+{
+    byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_WCmd_SetOutput;
+
+    int Vol = voltage * 100;
+    int Cur = current * 100;
+
+    memset(data, 0x00, ARRAY_SIZE(data));
+
+    // 輸出電壓
+    data[0] = (Vol >> 24) & 0xFF;
+    data[1] = (Vol >> 16) & 0xFF;
+    data[2] = (Vol >> 8) & 0xFF;
+    data[3] = Vol & 0xFF;
+    // 輸出電流
+    data[4] = (Cur >> 24) & 0xFF;
+    data[5] = (Cur >> 16) & 0xFF;
+    data[6] = (Cur >> 8) & 0xFF;
+    data[7] = Cur & 0xFF;
+
+    PwrFrameMsg.InfyBits.DeviceValue = device;
+    PwrFrameMsg.InfyBits.DestinationAddress = address;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+    SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void SetModuleOutputVol(byte address, byte device, int voltage, int current)
+{
+    byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_WCmd_ModuleSetOutput;
+
+    int Vol = voltage * 100;
+    int Cur = current * 100;
+
+    memset(data, 0x00, ARRAY_SIZE(data));
+
+    // 輸出電壓
+    data[0] = (Vol >> 24) & 0xFF;
+    data[1] = (Vol >> 16) & 0xFF;
+    data[2] = (Vol >> 8) & 0xFF;
+    data[3] = Vol & 0xFF;
+    // 輸出電流
+    data[4] = (Cur >> 24) & 0xFF;
+    data[5] = (Cur >> 16) & 0xFF;
+    data[6] = (Cur >> 8) & 0xFF;
+    data[7] = Cur & 0xFF;
+
+    PwrFrameMsg.InfyBits.DeviceValue = device;
+    PwrFrameMsg.InfyBits.DestinationAddress = address;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+    SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void SetLed(byte address, byte device, byte value)
+{
+    byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_WCmd_ModuleFlashLed;
+
+    memset(data, 0x00, ARRAY_SIZE(data));
+    // 1 : 閃爍
+    // 0 : 正常
+    data[0] = value;
+
+    PwrFrameMsg.InfyBits.DeviceValue = device;
+    PwrFrameMsg.InfyBits.DestinationAddress = address;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+    SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
 bool InitialCommunication()
 {
     CanFd = InitCanBus();
@@ -418,28 +516,19 @@ bool InitialCommunication()
 //================================================
 void SwitchPower(byte group, byte value)
 {
-    byte data[8];
-    PwrFrame PwrFrameMsg;
-    PwrFrameMsg.PwrMessage = 0;
-    PwrFrameMsg.InfyBits.CmdValue = PSU_WCmd_ModulePowerOnOff;
-
-    memset(data, 0x00, ARRAY_SIZE(data));
-    // 1 : 關機
-    // 0 : 開機
-    data[0] = value;
-
     if (group == INFY_ADD_BROADCAST)
     {
-        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+        SetPowerOnOff(group, DEVICE_NO_SINGLE_MODULE, value);
     }
     else
     {
-        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+        SetPowerOnOff(group, DEVICE_NO_GROUP_MODULE, value);
     }
-    PwrFrameMsg.InfyBits.DestinationAddress = group;
-    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+}
 
-    SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+void SinglePsuPower(byte address, byte value)
+{
+    SetPowerOnOff(address, DEVICE_NO_SINGLE_MODULE, value);
 }
 
 void SleepMode(byte group, byte value)
@@ -470,104 +559,36 @@ void SleepMode(byte group, byte value)
 
 void FlashLed(byte group, byte value)
 {
-    byte data[8];
-    PwrFrame PwrFrameMsg;
-    PwrFrameMsg.PwrMessage = 0;
-    PwrFrameMsg.InfyBits.CmdValue = PSU_WCmd_ModuleFlashLed;
-
-    memset(data, 0x00, ARRAY_SIZE(data));
-    // 1 : 閃爍
-    // 0 : 正常
-    data[0] = value;
-
     if (group == INFY_ADD_BROADCAST)
     {
-        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+        SetLed(group, DEVICE_NO_SINGLE_MODULE, value);
     }
     else
     {
-        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+        SetLed(group, DEVICE_NO_GROUP_MODULE, value);
     }
-    PwrFrameMsg.InfyBits.DestinationAddress = group;
-    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+}
 
-    SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+void SingleFlashLed(byte address, byte value)
+{
+    SetLed(address, DEVICE_NO_SINGLE_MODULE, value);
 }
 
 void PresentOutputVol(byte group, int voltage, int current)
 {
-	byte data[8];
-    PwrFrame PwrFrameMsg;
-    PwrFrameMsg.PwrMessage = 0;
-    PwrFrameMsg.InfyBits.CmdValue = PSU_WCmd_SetOutput;
-
-	int Vol = voltage * 100;
-	int Cur = current * 100;
-
-	memset(data, 0x00, ARRAY_SIZE(data));
-
-	// 輸出電壓
-	data[0] = (Vol >> 24) & 0xFF;
-	data[1] = (Vol >> 16) & 0xFF;
-	data[2] = (Vol >> 8) & 0xFF;
-	data[3] = Vol & 0xFF;
-	// 輸出電流
-	data[4] = (Cur >> 24) & 0xFF;
-	data[5] = (Cur >> 16) & 0xFF;
-	data[6] = (Cur >> 8) & 0xFF;
-	data[7] = Cur & 0xFF;
-
-    if (group == INFY_ADD_BROADCAST)
+    if(group == INFY_ADD_BROADCAST)
     {
-        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+        SetAllModuleOutput(group, DEVICE_NO_SINGLE_MODULE, voltage, current);
     }
     else
     {
-        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+        SetAllModuleOutput(group, DEVICE_NO_GROUP_MODULE, voltage, current);
     }
-    PwrFrameMsg.InfyBits.DestinationAddress = group;
-    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
-
-	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
 }
 
-// voltage: unit: 1mV
-// current: unit: 1mA
-void SetModuleOutputVol(byte group, int voltage, int current)
+void SingleOutputVol(byte address, int voltage, int current)
 {
-    byte data[8];
-    PwrFrame PwrFrameMsg;
-    PwrFrameMsg.PwrMessage = 0;
-    PwrFrameMsg.InfyBits.CmdValue = PSU_WCmd_ModuleSetOutput;
-
-    int Vol = voltage;
-    int Cur = current;
-
-    memset(data, 0x00, ARRAY_SIZE(data));
-
-    // 輸出電壓
-    data[0] = (Vol >> 24) & 0xFF;
-    data[1] = (Vol >> 16) & 0xFF;
-    data[2] = (Vol >> 8) & 0xFF;
-    data[3] = Vol & 0xFF;
-    // 輸出電流
-    data[4] = (Cur >> 24) & 0xFF;
-    data[5] = (Cur >> 16) & 0xFF;
-    data[6] = (Cur >> 8) & 0xFF;
-    data[7] = Cur & 0xFF;
-
-    if (group == INFY_ADD_BROADCAST)
-    {
-        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
-    }
-    else
-    {
-        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
-    }
-    PwrFrameMsg.InfyBits.DestinationAddress = group;
-    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
-
-    SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+    SetModuleOutputVol(address, DEVICE_NO_SINGLE_MODULE, voltage, current);
 }
 
 void FanNoiseInfo(byte group, byte value)

+ 3 - 1
EVSE/Projects/DO360/Apps/InfyGroup_PsuCommObj.h

@@ -170,10 +170,12 @@ bool InitialCommunication();
 
 /*Set Cmd*/
 void SwitchPower(byte group, byte value);
+void SinglePsuPower(byte address, byte value);
 void SleepMode(byte group, byte value);
 void FlashLed(byte group, byte value);
+void SingleFlashLed(byte address, byte value);
 void PresentOutputVol(byte group, int voltage, int current);
-void SetModuleOutputVol(byte group, int voltage, int current);
+void SingleOutputVol(byte address, int voltage, int current);
 void FanNoiseInfo(byte group, byte value);
 void SetWalkInConfig(byte group, byte enable, byte sec);
 void SetDipSwitchMode();

+ 119 - 14
EVSE/Projects/DO360/Apps/Module_EvComm.c

@@ -55,6 +55,8 @@
 struct SysConfigAndInfo				*ShmSysConfigAndInfo;
 ChargerInfoData                     *ShmChargerInfo;
 struct ChargingInfoData             *chargingInfo[CONNECTOR_QUANTITY];
+PsuGroupCollectionData              *ShmGroupCollection;
+struct PsuData                      *ShmPsuData;
 
 void ShowSocketData(struct PACKET_STRUCTURE *packet)
 {
@@ -115,6 +117,26 @@ int InitShareMemory()
         result = FAIL;
     }
 
+    if ((MeterSMId = shmget(ShmPsuKey, sizeof(struct PsuData),  0777)) < 0)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmget ShmPsuData NG");
+        #endif
+        result = FAIL;
+    }
+    else if ((ShmPsuData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmat ShmPsuData NG");
+        #endif
+        result = FAIL;
+    }
+
+    if(result == PASS)
+    {
+        ShmGroupCollection = &ShmChargerInfo->PsuGrouping.GroupCollection[0];
+    }
+
 	return result;
 }
 
@@ -959,18 +981,100 @@ void GetPhysicalLimitVoltageAndCurrent(byte index, unsigned short *voltage, unsi
     }
 }
 
-void GetConfigLimitVoltageAndCurrent(byte index, unsigned short *voltage, unsigned short *currrent)
+void GetConfigLimitPowerAndCurrent(byte index, unsigned short *power, unsigned short *currrent)
 {
-    unsigned short limitCurrent = ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX ?
-            (ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].MaxTotalChargingCurrent) :
-            (ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].MaxTotalChargingCurrent / 2);
+    unsigned short limitPower = 0, limitCurrent = 0;
+    unsigned char inUsingCnt = 0;
+
+    for(int i = 0; i < GENERAL_GUN_QUANTITY; i++)
+    {
+        if(ShmChargerInfo->PsuGrouping.GroupCollection[i].Role == _GROLE_MASTER)
+        {
+            inUsingCnt += ShmChargerInfo->PsuGrouping.GroupCollection[index].GunPsuQuantity;
+        }
+    }
+
+    if(ShmChargerInfo->PsuGrouping.GroupCollection[index].GunPsuQuantity != 0 && inUsingCnt != 0 &&
+        ShmSysConfigAndInfo->SysConfig.MaxChargingPower != 0)
+    {
+        limitPower = ShmSysConfigAndInfo->SysConfig.MaxChargingPower * 10;
+        limitPower = (limitPower * ShmGroupCollection[index].GunPsuQuantity) / inUsingCnt;
+    }
+    ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].MaxTotalChargingPower = limitPower;
 
+    if(ShmChargerInfo->PsuGrouping.GroupCollection[index].GunPsuQuantity != 0 && inUsingCnt != 0 &&
+        ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent != 0)
+    {
+        limitCurrent = ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent * 10;
+        limitCurrent = (limitCurrent * ShmGroupCollection[index].GunPsuQuantity) / inUsingCnt;
+    }
+    ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].MaxTotalChargingCurrent = limitCurrent;
+
+    if(limitPower != 0 && limitPower <= *power)
+    {
+        *power = limitPower;
+    }
     if(limitCurrent != 0 && limitCurrent <= *currrent)
     {
         *currrent = limitCurrent;
     }
 }
 
+void GetChargingProfileLimit(byte index, unsigned short *power, unsigned short *currrent)
+{
+    if((chargingInfo[index]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[index]->SystemStatus <= S_CHARGING) ||
+        (chargingInfo[index]->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingInfo[index]->SystemStatus <= S_CCS_PRECHARGE_ST1))
+    {
+        if(chargingInfo[index]->ChargingProfilePower >= 0 && *power > ((int)chargingInfo[index]->ChargingProfilePower / 100))
+        {
+            *power = (int)chargingInfo[index]->ChargingProfilePower / 100;
+        }
+
+        if(chargingInfo[index]->ChargingProfileCurrent >= 0 && *currrent > (int)chargingInfo[index]->ChargingProfileCurrent)
+        {
+            *currrent = (int)chargingInfo[index]->ChargingProfileCurrent;
+        }
+    }
+}
+
+void GetMaxChargingProfileLimit(byte index, unsigned short *power, unsigned short *currrent)
+{
+    unsigned short limitPower = 0, limitCurrent = 0;
+    unsigned char inUsingCnt = 0;
+
+    for(int i = 0; i < GENERAL_GUN_QUANTITY; i++)
+    {
+        if(ShmChargerInfo->PsuGrouping.GroupCollection[i].Role == _GROLE_MASTER)
+        {
+            inUsingCnt += ShmChargerInfo->PsuGrouping.GroupCollection[index].GunPsuQuantity;
+        }
+    }
+
+    // max charging profile
+    if(ShmChargerInfo->PsuGrouping.GroupCollection[index].GunPsuQuantity != 0 && inUsingCnt != 0 &&
+        ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower >= 0)
+    {
+        limitPower = (int)ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower / 100;
+        limitPower = (limitPower * ShmGroupCollection[index].GunPsuQuantity) / inUsingCnt;
+
+        if(*power > limitPower)
+        {
+            *power = limitPower;
+        }
+
+        if (chargingInfo[index]->EvBatterytargetVoltage > 0 &&
+            (int)chargingInfo[index]->PresentChargingVoltage > 0)
+        {
+            limitCurrent = (limitPower * 100 / chargingInfo[index]->PresentChargingVoltage) * 10;
+
+            if(*currrent > limitCurrent)
+            {
+                *currrent = limitCurrent;
+            }
+        }
+    }
+}
+
 void ChargingCapabilityResponse(int socket, struct PACKET_STRUCTURE *packet)
 {
 	struct PACKET_STRUCTURE sendBuffer;
@@ -984,7 +1088,9 @@ void ChargingCapabilityResponse(int socket, struct PACKET_STRUCTURE *packet)
 	power = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].GeneralChargingData.AvailableChargingPower;
 
 	GetPhysicalLimitVoltageAndCurrent(packet->Header.id - 1, &voltage, &current);
-	GetConfigLimitVoltageAndCurrent(packet->Header.id - 1, &voltage, &current);
+	GetConfigLimitPowerAndCurrent(packet->Header.id - 1, &power, &current);
+	GetChargingProfileLimit(packet->Header.id - 1, &power, &current);
+	GetMaxChargingProfileLimit(packet->Header.id - 1, &power, &current);
 
 	currency = ShmSysConfigAndInfo->SysInfo.DispenserInfo.Currency;
 	price = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].UserPrice;
@@ -1388,7 +1494,7 @@ void WriteChargingInfoResponse(int socket, struct PACKET_STRUCTURE *packet, unsi
     voltage -= ((current * 8 * 10) / 10000);
 #endif
 
-    if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].Parameter.bits.PantographEnable)
+    if(chargingInfo[gun]->PantographFlag == YES)
     {
         voltage = (unsigned short)(chargingInfo[gun]->PresentChargingVoltage * 10);
         current = (unsigned short)(chargingInfo[gun]->PresentChargingCurrent * 10);
@@ -1427,8 +1533,7 @@ int GetChargerSystemId(char *id)
 
         case _QR_MODE_Default:
         default:
-            strcat((char *)id, (char *)ShmSysConfigAndInfo->SysConfig.ModelName);
-            strcat((char *)id, (char *)ShmSysConfigAndInfo->SysConfig.SerialNumber);
+            strcat((char *)id, (char *)ShmSysConfigAndInfo->SysConfig.SystemId);
             break;
     }
 
@@ -1572,10 +1677,10 @@ void ConnectorPantographBindingHandler(unsigned char connectorIndex, unsigned ch
     switch(physical)
     {
         case 'P':
-            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].Parameter.bits.PantographEnable = 1;
+            chargingInfo[connectorIndex]->PantographFlag = YES;
             break;
         default:
-            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].Parameter.bits.PantographEnable = 0;
+            chargingInfo[connectorIndex]->PantographFlag = NO;
             break;
     }
 }
@@ -1597,7 +1702,7 @@ void ConnectorTypeBindingHandler(unsigned char dispenserIndex, unsigned char *ty
             dispenserIndex + 1, gunIndex + 1, str_gun_type[type[i]],
             ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gunIndex].RemoteMaxPhysicalVoltage,
             ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gunIndex].RemoteMaxPhysicalCurrent,
-            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gunIndex].Parameter.bits.PantographEnable ? "Normal" : "Pantograph");
+            chargingInfo[gunIndex]->PantographFlag == YES ? "Pantograph" : "Normal");
 	}
 }
 
@@ -1822,7 +1927,7 @@ BOOL ConnectorChargingTargetHandler(struct PACKET_STRUCTURE *packet, unsigned ch
 {
 	BOOL find = FindConnectorID(dispenserIndex, packet->Header.id);
 	BOOL done = false;
-	unsigned short voltage = 0, current = 0;
+	unsigned short voltage = 0, current = 0, power = 0;
 
 	if(find)
 	{
@@ -1841,7 +1946,7 @@ BOOL ConnectorChargingTargetHandler(struct PACKET_STRUCTURE *packet, unsigned ch
 		}
 
 		GetPhysicalLimitVoltageAndCurrent(packet->Header.id - 1, &voltage, &current);
-		GetConfigLimitVoltageAndCurrent(packet->Header.id - 1, &voltage, &current);
+		GetConfigLimitPowerAndCurrent(packet->Header.id - 1, &power, &current);
 
 		if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteTargetVoltage != voltage ||
             ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteTargetCurrent != current)
@@ -2438,7 +2543,7 @@ unsigned char GroundFaultDetectionHandler(struct PACKET_STRUCTURE *packet, unsig
         gun = packet->Header.id - 1;
         unsigned char enable = packet->Payload.data[0];
 
-        if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].Parameter.bits.PantographEnable)
+        if(chargingInfo[gun]->PantographFlag == YES)
         {
             if(enable == _GFD_Enable &&
                 (chargingInfo[gun]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[gun]->SystemStatus <= S_CHARGING))

+ 150 - 12
EVSE/Projects/DO360/Apps/Module_InternalComm.c

@@ -69,6 +69,7 @@ PsuGroupParallelRelay           *ShmParallelRelayConfirmed;
 RBRelayControl                  *LocationRelayCtrl[MAX_GROUP_QUANTITY];
 RBRelayControl                  *LocationRelayResponse[MAX_GROUP_QUANTITY];
 Connector_GFD                   *LocaltionGfd[MAX_GROUP_QUANTITY];
+PsuGroupCollectionData          *ShmGroupCollection;
 
 #define VIN_MAX_VOLTAGE_IEC         285	// 大於該值 : OVP
 #define VIN_MAX_REV_VOLTAGE_IEC     275 // 小於賦歸 OVP
@@ -116,6 +117,12 @@ Connector_GFD                   *LocaltionGfd[MAX_GROUP_QUANTITY];
 // 確認 Relay Welding 電壓
 #define RELAY_WELDING_DET					300
 
+#if SAFETY_TEST_ENABLE
+#define RELAY_OPEN_AT_PRECHARGE             1
+#else
+#define RELAY_OPEN_AT_PRECHARGE             0
+#endif
+
 byte gunCount;
 byte acgunCount;
 // 槍資訊
@@ -415,6 +422,16 @@ void SetModelName_Fan()
 // AC 三相輸入電壓
 void GetPresentInputVol()
 {
+    if(ShmChargerInfo->Control.RelayCtrl.bits.AcInputDisable == YES)
+    {
+        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP = NO;
+        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP = NO;
+        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP = NO;
+        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP = NO;
+        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP = NO;
+        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP = NO;
+        return;
+    }
 	if (Query_Present_InputVoltage(Uart5Fd, Addr.DO360_RC1, &inputVoltage) == PASS)
 	{
 		// resolution : 0.1
@@ -900,7 +917,7 @@ void GetGfdAdc(void)
     {
         for(int i = 0; i < ShmChargerInfo->Control.MaxConnector; i++)
         {
-            if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].Parameter.bits.PantographEnable)
+            if(_chargingData[i]->PantographFlag == YES)
             {
                 _isGfdEnable = true;
                 LOG_INFO("Enable Power Cabinet GFD Function");
@@ -915,8 +932,20 @@ void GetGfdAdc(void)
         // warning : >= 100 歐姆 && <= 500 歐姆 @ 150-750 Vdc
         if(Query_Gfd_Adc(Uart5Fd, Addr.DO360_RC1, &gfd_adc[0]) == PASS)
         {
-
+//            if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[0].Parameter.bits.GfdDetection ||
+//                ShmSysConfigAndInfo->SysInfo.ConnectorInfo[1].Parameter.bits.GfdDetection)
+//            {
+//                LOG_INFO("Query Relay1 GFD ADC1 Status = %d, ADC2 Status = %d", gfd_adc[0].result_conn1, gfd_adc[0].result_conn2);
+//            }
         }
+//        else
+//        {
+//            if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[0].Parameter.bits.GfdDetection ||
+//                ShmSysConfigAndInfo->SysInfo.ConnectorInfo[1].Parameter.bits.GfdDetection)
+//            {
+//                LOG_INFO("Query Relay1 GFD ADC Fail");
+//            }
+//        }
         if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable)
         {
             if(Query_Gfd_Adc(Uart5Fd, Addr.DO360_RC2, &gfd_adc[1]) == PASS)
@@ -1098,12 +1127,70 @@ void SetK1K2RelayStatus(byte index)
             }
             else
             {
+#if RELAY_OPEN_AT_PRECHARGE
+
+                if(_chargingData[index]->SystemStatus == S_PREPARING_FOR_EVSE)
+                {
+                    if(ShmGroupCollection[index].GroupCtrl.bits.CableCheckDone == false &&
+                        ShmGroupCollection[index].GroupCtrl.bits.InPrechargeMode == false)
+                    {
+                        if(!ShmOutputRelayConfig[index]->bits.Output_N || !ShmOutputRelayConfig[index]->bits.Output_P)
+                        {
+                            LOG_INFO("Gun %d Set K1K2 Close And Prepare To Cable Check", index + 1);
+                        }
+                        ShmOutputRelayConfig[index]->bits.Output_N = true;
+                        ShmOutputRelayConfig[index]->bits.Output_P = true;
+                    }
+                    else if(ShmGroupCollection[index].GroupCtrl.bits.CableCheckDone == true &&
+                        ShmGroupCollection[index].GroupCtrl.bits.InPrechargeMode == false)
+                    {
+                        if(_chargingData[index]->FireChargingVoltage <= SELF_TO_CHANGE_RELAY_STATUS)
+                        {
+                            if(ShmOutputRelayConfig[index]->bits.Output_N || ShmOutputRelayConfig[index]->bits.Output_P)
+                            {
+                                LOG_INFO("Gun %d Set K1K2 Open By Cable Check Done", index + 1);
+                            }
+                            ShmOutputRelayConfig[index]->bits.Output_N = false;
+                            ShmOutputRelayConfig[index]->bits.Output_P = false;
+                        }
+                    }
+                    else if(ShmGroupCollection[index].GroupCtrl.bits.CableCheckDone == true &&
+                        ShmGroupCollection[index].GroupCtrl.bits.InPrechargeMode == true)
+                    {
+                        unsigned short voltage = 0, diffVol = 0;
+                        voltage = (int)(_chargingData[index]->PresentChargingVoltage * 10);
+                        diffVol = voltage >= ShmPsuGrouping->GroupOutput[index].GTargetVoltage ?
+                            voltage - ShmPsuGrouping->GroupOutput[index].GTargetVoltage :
+                            ShmPsuGrouping->GroupOutput[index].GTargetVoltage - voltage;
+
+                        if(diffVol <= 30)
+                        {
+                            if(!ShmOutputRelayConfig[index]->bits.Output_N || !ShmOutputRelayConfig[index]->bits.Output_P)
+                            {
+                                LOG_INFO("Gun %d Set K1K2 Close And Voltage Is Balance", index + 1);
+                            }
+                            ShmOutputRelayConfig[index]->bits.Output_N = true;
+                            ShmOutputRelayConfig[index]->bits.Output_P = true;
+                        }
+                    }
+                }
+                else
+                {
+                    if(!ShmOutputRelayConfig[index]->bits.Output_N || !ShmOutputRelayConfig[index]->bits.Output_P)
+                    {
+                        LOG_INFO("Gun %d Set K1K2 Close In Charging Status", index + 1);
+                    }
+                    ShmOutputRelayConfig[index]->bits.Output_N = true;
+                    ShmOutputRelayConfig[index]->bits.Output_P = true;
+                }
+#else
                 if(!ShmOutputRelayConfig[index]->bits.Output_N || !ShmOutputRelayConfig[index]->bits.Output_P)
                 {
                     LOG_INFO("Gun %d Set K1K2 Close And Prepare To Charging", index + 1);
                 }
                 ShmOutputRelayConfig[index]->bits.Output_N = true;
                 ShmOutputRelayConfig[index]->bits.Output_P = true;
+#endif
             }
         }
         else if ((_chargingData[index]->SystemStatus >= S_TERMINATING &&
@@ -1431,7 +1518,7 @@ int InitShareMemory()
 		#endif
 		result = FAIL;
 	}
-	memset(ShmFanModuleData,0,sizeof(struct FanModuleData));
+	//memset(ShmFanModuleData,0,sizeof(struct FanModuleData));
 
 	if ((MeterSMId = shmget(ShmRelayBdKey, sizeof(struct RelayModuleData), 0777)) < 0)
 	{
@@ -1447,7 +1534,7 @@ int InitShareMemory()
 		#endif
 		result = FAIL;
 	}
-	memset(ShmRelayModuleData[0],0,sizeof(struct RelayModuleData));
+	//memset(ShmRelayModuleData[0],0,sizeof(struct RelayModuleData));
 
 	// DO360 RC2
 	if ((MeterSMId = shmget(ShmRelay2BdKey, sizeof(struct RelayModuleData), 0777)) < 0)
@@ -1464,7 +1551,7 @@ int InitShareMemory()
 		#endif
 		result = FAIL;
 	}
-	memset(ShmRelayModuleData[1],0,sizeof(struct RelayModuleData));
+	//memset(ShmRelayModuleData[1],0,sizeof(struct RelayModuleData));
 
 
 	if ((MeterSMId = shmget(ShmLedBdKey, sizeof(struct LedModuleData), 0777)) < 0)
@@ -1481,7 +1568,7 @@ int InitShareMemory()
 		#endif
 		result = FAIL;
 	}
-	memset(ShmLedModuleData,0,sizeof(struct LedModuleData));
+	//memset(ShmLedModuleData,0,sizeof(struct LedModuleData));
 
 	if ((MeterSMId = shmget(ShmPsuKey, sizeof(struct PsuData), 0777)) < 0)
 	{
@@ -1557,6 +1644,8 @@ int InitShareMemory()
                 LocaltionGfd[3] = (Connector_GFD *)&gfd_adc[1].Resister_conn2;
             }
         }
+
+        ShmGroupCollection = &ShmPsuGrouping->GroupCollection[0];
     }
 
 	return result;
@@ -1818,12 +1907,28 @@ void SetGfdConfig(byte index, byte resister)
 //		LOG_INFO("Set reqVol = %f, resister = %d",
 //				gfd_config.reqVol,
 //				gfd_config.resister);
+//        if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[0].Parameter.bits.GfdDetection ||
+//            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[1].Parameter.bits.GfdDetection)
+//        {
+//            LOG_INFO("Set Relay %02X GFD Config index = %d, state = %d OK", add, gfd_config.index, gfd_config.state);
+//        }
 	}
+//	else
+//	{
+//        if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[0].Parameter.bits.GfdDetection ||
+//            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[1].Parameter.bits.GfdDetection)
+//        {
+//            LOG_INFO("Set Relay %02X GFD Config index = %d, state = %d NG", add, gfd_config.index, gfd_config.state);
+//        }
+//	}
 }
 
+char GfdConfig[4];
+
 void CableCheckDetected(byte index)
 {
     unsigned char location = 0;
+    char *strGfdConfig[] = {"Idle", "CableCheck", "PreCharge", "Charging"};
 
 	// Cable Check
 	// 當火線上的電壓 = 車端要求的電壓電流
@@ -1833,7 +1938,7 @@ void CableCheckDetected(byte index)
 	// Pre-Warning : 150 歐/V < Rgfd <= 500 歐/V 假設電壓為 500V 則 75000 歐 < Rgfd <= 250000
 	// SO Normal : Rgfd > 500 歐/V 假設電壓為 500 V 則 Rgfd > 250000 歐
 
-    if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].Parameter.bits.PantographEnable)
+    if(_chargingData[index]->PantographFlag == YES)
     {
         location = ShmPsuGrouping->GroupCollection[index].Location;
 
@@ -1843,15 +1948,31 @@ void CableCheckDetected(byte index)
             if(_chargingData[index]->SystemStatus == S_PREPARING_FOR_EVSE && _chargingData[index]->RelayWeldingCheck == YES)
             {
                 SetGfdConfig(location, GFD_CABLECHK);
+                if(GfdConfig[index] != GFD_CABLECHK)
+                {
+                    LOG_INFO("Gun %d Set GFD = %s", index + 1, strGfdConfig[GFD_CABLECHK]);
+                }
+                GfdConfig[index] = GFD_CABLECHK;
             }
             else
             {
                 SetGfdConfig(location, GFD_CHARGING);
+                if(GfdConfig[index] != GFD_CHARGING)
+                {
+                    LOG_INFO("Gun %d Set GFD = %s", index + 1, strGfdConfig[GFD_CHARGING]);
+                }
+                GfdConfig[index] = GFD_CHARGING;
             }
         }
         else
         {
             SetGfdConfig(location, GFD_IDLE);
+            if(GfdConfig[index] != GFD_IDLE)
+            {
+                LOG_INFO("Gun %d Set GFD = %s", index + 1, strGfdConfig[GFD_IDLE]);
+            }
+            GfdConfig[index] = GFD_IDLE;
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].Parameter.bits.GfdDetection = 0;
         }
     }
 }
@@ -2408,22 +2529,39 @@ int main(void)
 		return 0;
 	}
 
+	_RelaySelfTestOK = NO;
 	memset(&outputRelay[0], 0x00, sizeof(Relay));
 	memset(&outputRelay[1], 0x00, sizeof(Relay));
 
     if(ShmChargerInfo->Control.SysCtrl.bits.RelayBoardDisable == false)
     {
-        if(Config_Relay_Output(Uart5Fd, Addr.DO360_RC1, &outputRelay[0]) != PASS)
-            LOG_INFO("Config_Relay1_Output fail");
+        if(ShmRelayModuleData[0]->SelfTest_Comp == NO)
+        {
+            if(Config_Relay_Output(Uart5Fd, Addr.DO360_RC1, &outputRelay[0]) != PASS)
+                LOG_INFO("Config_Relay1_Output fail");
+        }
+        else
+        {
+            if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable == false)
+            {
+                _RelaySelfTestOK = YES;
+            }
+        }
 
         if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable)
         {
-            if(Config_Relay_Output(Uart5Fd, Addr.DO360_RC2, &outputRelay[1]) != PASS)
-                LOG_INFO("Config_Relay2_Output fail");
+            if(ShmRelayModuleData[1]->SelfTest_Comp == NO)
+            {
+                if(Config_Relay_Output(Uart5Fd, Addr.DO360_RC2, &outputRelay[1]) != PASS)
+                    LOG_INFO("Config_Relay2_Output fail");
+            }
+            else
+            {
+                _RelaySelfTestOK = YES;
+            }
         }
     }
 
-    _RelaySelfTestOK = NO;
 	cur_led_color.Connect_1_Red = COLOR_MIN_LV;
 	cur_led_color.Connect_1_Green = COLOR_MIN_LV;
 	cur_led_color.Connect_1_Blue = COLOR_MIN_LV;

+ 97 - 1
EVSE/Projects/DO360/Apps/Module_PrimaryComm.c

@@ -39,7 +39,8 @@
 #define YES					1
 #define NO					0
 
-#define COMM_FAIL_COUNT     10
+#define COMM_FAIL_COUNT         10
+#define STATE_CHANGE_COUNT      3
 
 typedef unsigned char 		byte;
 
@@ -64,6 +65,15 @@ byte _OutputDrv = 0;
 byte _acStatus = 0;
 byte _acChkCount = 0;
 int _CommFailCount = 0;
+char _CabinetSwitch = -1;
+char _TempSwitch = -1;
+char _TempSPD = -1;
+char _TempDoor = -1;
+char _TempEmg = -1;
+byte _SwitchCnt = 0;
+byte _SPDCnt = 0;
+byte _DoorCnt = 0;
+byte _EmgBtnCnt = 0;
 
 int DiffTimeb(struct timeb ST, struct timeb ET)
 {
@@ -269,6 +279,21 @@ void GetInputGpioStatus()
 			_acChkCount = 0;
 
 		ShmPrimaryMcuData->InputDet.bits.AcMainBreakerDetec = gpio_in.AC_MainBreaker;
+		/*
+		if(_TempSPD != gpio_in.SPD)
+		{
+		    _SPDCnt++;
+		    if(_SPDCnt >= STATE_CHANGE_COUNT || _TempSPD == -1)
+		    {
+		        _TempSPD = gpio_in.SPD;
+		        _SPDCnt = 0;
+		    }
+		}
+		if(_TempSPD != -1)
+		{
+		    ShmPrimaryMcuData->InputDet.bits.SpdDetec = _TempSPD;
+		}
+		*/
 		ShmPrimaryMcuData->InputDet.bits.SpdDetec = gpio_in.SPD;
 
 		// DO360 Door Status is the inverse of DS's
@@ -281,11 +306,48 @@ void GetInputGpioStatus()
             ShmPrimaryMcuData->InputDet.bits.DoorOpen = gpio_in.Door_Open ? 1 : 0;
         }
 
+		/*
+        if(_TempDoor != gpio_in.Door_Open)
+        {
+            _DoorCnt++;
+            if(_DoorCnt >= STATE_CHANGE_COUNT || _TempDoor == -1)
+            {
+                _TempDoor = gpio_in.Door_Open;
+                _DoorCnt = 0;
+            }
+        }
+        if(_TempDoor != -1)
+        {
+            if(ShmChargerInfo->Control.PrimaryCtrl.bits.DoorSensorReverse)
+            {
+                ShmPrimaryMcuData->InputDet.bits.DoorOpen = _DoorCnt ? 0 : 1;
+            }
+            else
+            {
+                ShmPrimaryMcuData->InputDet.bits.DoorOpen = _DoorCnt ? 1 : 0;
+            }
+        }
+        */
 		// Bypass door open
 		//ShmPrimaryMcuData->InputDet.bits.DoorOpen = 0;
 
 		ShmPrimaryMcuData->InputDet.bits.Button1 = gpio_in.Button[0];
 		ShmPrimaryMcuData->InputDet.bits.Button2 = gpio_in.Button[1];
+		/*
+		if(_TempEmg != gpio_in.Emergency_Btn)
+		{
+		    _EmgBtnCnt++;
+		    if(_EmgBtnCnt >= STATE_CHANGE_COUNT || _TempEmg == -1)
+		    {
+		        _TempEmg = gpio_in.Emergency_Btn;
+		        _EmgBtnCnt = 0;
+		    }
+		}
+		if(_TempEmg != -1)
+		{
+		    ShmPrimaryMcuData->InputDet.bits.EmergencyButton = _TempEmg ? 1 : 0;
+		}
+		*/
 		ShmPrimaryMcuData->InputDet.bits.EmergencyButton = gpio_in.Emergency_Btn;
 
 		//LOG_INFO("left = %d", ShmPrimaryMcuData->InputDet.bits.Button1);
@@ -293,6 +355,40 @@ void GetInputGpioStatus()
 		//LOG_INFO("ShmSysConfigAndInfo->SysInfo.AcContactorStatus = %d", ShmSysConfigAndInfo->SysInfo.AcContactorStatus);
 		//if (ShmPrimaryMcuData->InputDet.bits.AcMainBreakerDetec == YES)
 		//	LOG_INFO("AC Mainbreaker occur.");
+
+		ShmPrimaryMcuData->InputDet.bits.Key0 = gpio_in.Key[0] ? 0 : 1;
+		ShmPrimaryMcuData->InputDet.bits.Key1 = gpio_in.Key[1] ? 0 : 1;
+		ShmPrimaryMcuData->InputDet.bits.Key2 = gpio_in.Key[2] ? 0 : 1;
+		ShmPrimaryMcuData->InputDet.bits.Key3 = gpio_in.Key[3] ? 0 : 1;
+
+		char _SwValue = (ShmPrimaryMcuData->InputDet.bits.Key0 << 0) |
+		                (ShmPrimaryMcuData->InputDet.bits.Key1 << 1) |
+                        (ShmPrimaryMcuData->InputDet.bits.Key2 << 2) |
+                        (ShmPrimaryMcuData->InputDet.bits.Key3 << 3);
+		if(_TempSwitch != _SwValue)
+		{
+		    _SwitchCnt++;
+		    if(_SwitchCnt >= STATE_CHANGE_COUNT)
+		    {
+		        _TempSwitch = _SwValue;
+		        _SwitchCnt = 0;
+		    }
+		}
+
+		if(_CabinetSwitch != _TempSwitch)
+		{
+		    LOG_INFO("Cabinet Switch: %d, Key3: %d, Key2: %d, Key1: %d, Key0: %d",
+                _TempSwitch,
+                ShmPrimaryMcuData->InputDet.bits.Key3,
+                ShmPrimaryMcuData->InputDet.bits.Key2,
+                ShmPrimaryMcuData->InputDet.bits.Key1,
+                ShmPrimaryMcuData->InputDet.bits.Key0);
+		}
+        _CabinetSwitch = _TempSwitch;
+        if(_CabinetSwitch != -1)
+        {
+            ShmChargerInfo->Control.CabinetSwitch = _CabinetSwitch;
+        }
 	}
 }
 

+ 165 - 15
EVSE/Projects/DO360/Apps/Module_PsuComm.c

@@ -64,7 +64,22 @@
 #define WAIT_SLAVE_READY_TIME           15          // unit: second
 #define WAIT_SLAVE_DELAY                1           // unit: second
 #define SHOW_OUTPUT_DELAY               1
-#define CURRENT_BALANCE_CRITERIA        300         // unit: 0.1A, 30A
+#define CURRENT_BALANCE_CRITERIA        400         // unit: 0.1A, 40A
+#define SAFETY_PRECHARGE_OFFSET         200         // unit: 0.1V, 20V
+#define CHARGING_DELAY_INTERVAL         200         // unit: 1ms, 400ms
+#define MAX_CHARGING_DELAY_COUNT        15
+#define VOLTAGE_RESUME_STEP             10          // unit: 0.1V, 1V
+#define POWER_ONOFF_RESEND_INTERVAL     1           // unit: 1s, 1s
+
+#if SAFETY_TEST_ENABLE
+#define PRECHARGE_OFFSET                1           // 0: normal output, 1: precharge voltage offset enable
+#define ONE_MODULE_OUTPUT               1           // 0: normal output, 1: only one module output enable
+#define MASTER_OUTPUT_FIRST             0           // 0: normal output, 1: master output first enable
+#else
+#define PRECHARGE_OFFSET                0           // 0: normal output, 1: precharge voltage offset enable
+#define ONE_MODULE_OUTPUT               0           // 0: normal output, 1: only one module output enable
+#define MASTER_OUTPUT_FIRST             0           // 0: normal output, 1: master output first enable
+#endif
 
 struct SysConfigAndInfo			*ShmSysConfigAndInfo;
 struct StatusCodeData 			*ShmStatusCodeData;
@@ -100,6 +115,8 @@ struct timespec _BalanceCurrent_time[CONNECTOR_QUANTITY];
 struct timespec _MaxCurrent_time[CONNECTOR_QUANTITY];
 struct timespec _StageCurrent_time[CONNECTOR_QUANTITY];
 struct timespec _CheckSlaveReady_time[CONNECTOR_QUANTITY];
+struct timespec _ChargingDelay_time[CONNECTOR_QUANTITY];
+struct timespec _PoweOnOff_time[CONNECTOR_QUANTITY];
 
 unsigned short  GCTargetVoltage[CONNECTOR_QUANTITY];
 unsigned short  GCTargetCurrent[CONNECTOR_QUANTITY];
@@ -111,6 +128,9 @@ GroupOutputConfigInfo PreGroupOutput[MAX_GROUP_QUANTITY];
 unsigned char OutputConfigStep[MAX_GROUP_QUANTITY];
 unsigned char _preOutputConfigStep[MAX_GROUP_QUANTITY];
 
+unsigned char _GfdStep[MAX_GROUP_QUANTITY];
+unsigned char _VoltageResumeCnt[MAX_GROUP_QUANTITY];
+
 //=================================
 // Common routine
 //=================================
@@ -458,6 +478,7 @@ void GetModuleCountCallback(byte group, byte count)
 	    if(group < _maxGroupCount)
 	    {
 	        ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity = count;
+	        ShmGroupCollection[group].GunPsuQuantity = count;
 	    }
 	}
 }
@@ -534,7 +555,7 @@ void UpdateSystemAvailable(void)
 
 // maxVol, minVol unit: 0.1V
 // maxCur unit: 0.1A
-// totalPow unit: 0.1kW
+// totalPow unit: 0.01kW
 // 0x0A: PSU_RCmd_ModuleCapability
 void GetAvailableCapCallback(byte address, short maxVol, short minVol, short maxCur, short totalPow)
 {
@@ -1534,6 +1555,7 @@ void AddMember(byte group, byte master)
         if(ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity > 0)
         {
             ShmGroupCollection[master].Partner.RealQuantity++;
+            ShmGroupCollection[master].GunPsuQuantity += ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity;
         }
         //printf("\r\n Add Group %02X To Gun %d (Quantity %d), Set Parallel Relay %d On", group, target + 1, ShmGroupCollection[target].Partner.Quantity, ParallelConfig);
     }
@@ -1593,6 +1615,7 @@ void RemoveMember(unsigned char master, unsigned char slave)
         if(ShmPsuData->PsuGroup[slave].GroupPresentPsuQuantity > 0)
         {
             ShmGroupCollection[master].Partner.RealQuantity--;
+            ShmGroupCollection[master].GunPsuQuantity -= ShmPsuData->PsuGroup[slave].GroupPresentPsuQuantity;
         }
     }
 }
@@ -1649,7 +1672,19 @@ void SetPsuGroupPowerOnOff(unsigned char group, unsigned char power_on_off)
 
         if(ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity > 0)
         {
+#if ONE_MODULE_OUTPUT
+            // for safety test (inrush current)
+            if(ShmGroupCollection[group].GroupCtrl.bits.InPrechargeMode)
+            {
+                SinglePsuPower(ShmPsuPosition->GroupLocationInfo[group].PsuSN[0], power_cmd);
+            }
+            else
+            {
+                SwitchPower(group, power_cmd);
+            }
+#else
             SwitchPower(group, power_cmd);
+#endif
             Await();
             FlashLed(group, led_cmd);
             Await();
@@ -2334,6 +2369,57 @@ void PsuGroupOutputConfigCheck(unsigned char master)
     }
 }
 
+void StepRecognition(unsigned char master, unsigned short voltage)
+{
+    if(_GfdStep[master] == PREPARE_STEP_NONE && voltage > 0)
+    {
+        // gfd step
+        _GfdStep[master] = PREPARE_STEP_CABLE_CHECK;
+        LOG_INFO("Gun %d GFD Start Step", master + 1);
+    }
+    else if(_GfdStep[master] == PREPARE_STEP_CABLE_CHECK && voltage == 0)
+    {
+        // gfd done step
+        _GfdStep[master] = PREPARE_STEP_GFD_DONE;
+        LOG_INFO("Gun %d GFD Stop Step", master + 1);
+        ShmGroupCollection[master].GroupCtrl.bits.CableCheckDone = true;
+    }
+    else if(_GfdStep[master] == PREPARE_STEP_GFD_DONE && voltage >= SAFETY_PRECHARGE_OFFSET)
+    {
+        // precharge step
+        _GfdStep[master] = PREPARE_STEP_PRECHARGE;
+        LOG_INFO("Gun %d PreCharge Step", master + 1);
+        ShmGroupCollection[master].GroupCtrl.bits.InPrechargeMode = true;
+    }
+
+    if(ShmGroupCollection[master].GroupCtrl.bits.AlreadyInChargingMode)
+    {
+        // charging step
+        if(_GfdStep[master] != PREPARE_STEP_CHARGING)
+        {
+            LOG_INFO("Gun %d Charging Step", master + 1);
+        }
+        _GfdStep[master] = PREPARE_STEP_CHARGING;
+
+        if(ShmGroupCollection[master].GroupCtrl.bits.InPrechargeMode)
+        {
+            if(_VoltageResumeCnt[master] < MAX_CHARGING_DELAY_COUNT)
+            {
+                int time = GetTimeoutValue(_ChargingDelay_time[master]) / mSEC_VAL;
+                if(time >= CHARGING_DELAY_INTERVAL)
+                {
+                    GetClockTime(&_ChargingDelay_time[master]);
+                    _VoltageResumeCnt[master]++;
+                }
+            }
+            else
+            {
+                ShmGroupCollection[master].GroupCtrl.bits.InPrechargeMode = false;
+            }
+        }
+    }
+}
+
 // master: master group index
 // group: self group index
 void UpdatePsuGroupOutputConfig(unsigned char master)
@@ -2345,17 +2431,52 @@ void UpdatePsuGroupOutputConfig(unsigned char master)
     TargetVoltage = (int)(chargingInfo[master]->EvBatterytargetVoltage * 10);
     TargetCurrent = (int)(chargingInfo[master]->EvBatterytargetCurrent * 10);
 
-    if(chargingInfo[master]->RelayK1K2Status)
+    if(chargingInfo[master]->RelayK1K2Status || ShmGroupCollection[master].GroupCtrl.bits.CableCheckDone)
     {
         // update target voltage
         if(!ShmGroupCollection[master].GroupCtrl.bits.DeratingConfirmed)
         {
+            StepRecognition(master, TargetVoltage);
+
+#if PRECHARGE_OFFSET
+            // for safety test (inrush current)
+            if(!ShmGroupCollection[master].GroupCtrl.bits.AlreadyInChargingMode)
+            {
+                GCTargetVoltage[master] = _GfdStep[master] == PREPARE_STEP_PRECHARGE ?
+                    TargetVoltage - SAFETY_PRECHARGE_OFFSET : TargetVoltage;
+            }
+            else
+            {
+                if(ShmGroupCollection[master].GroupCtrl.bits.InPrechargeMode)
+                {
+                    GCTargetVoltage[master] = TargetVoltage > (GCTargetVoltage[master] + VOLTAGE_RESUME_STEP) ?
+                        (GCTargetVoltage[master] + VOLTAGE_RESUME_STEP) : TargetVoltage;
+                }
+                else
+                {
+                    GCTargetVoltage[master] = TargetVoltage;
+                }
+            }
+#else
             GCTargetVoltage[master] = TargetVoltage;
+#endif
             ShmPsuGrouping->GroupOutput[master].GTargetVoltage = GCTargetVoltage[master];
             for(int i = 0; i < ShmGroupCollection[master].Partner.Quantity; i++)
             {
                 slave = ShmGroupCollection[master].Partner.Member[i];
+#if ONE_MODULE_OUTPUT
+                // for safety test (inrush current)
+                if(ShmGroupCollection[master].GroupCtrl.bits.InPrechargeMode)
+                {
+                    ShmPsuGrouping->GroupOutput[slave].GTargetVoltage = 0;
+                }
+                else
+                {
+                    ShmPsuGrouping->GroupOutput[slave].GTargetVoltage = GCTargetVoltage[master];
+                }
+#else
                 ShmPsuGrouping->GroupOutput[slave].GTargetVoltage = GCTargetVoltage[master];
+#endif
             }
         }
 
@@ -2377,8 +2498,13 @@ void UpdatePsuGroupOutputConfig(unsigned char master)
                 slave = ShmGroupCollection[master].Partner.Member[i];
                 if(ShmGroupCollection[slave].Role == _GROLE_SLAVE || ShmGroupCollection[slave].Role == _GROLE_PREPARE_SWITCH_OFF)
                 {
+#if ONE_MODULE_OUTPUT
+                    // for safety test (inrush current)
+                    ShmPsuGrouping->GroupOutput[slave].GTargetCurrent = 0;
+#else
                     ShmPsuGrouping->GroupOutput[slave].GTargetCurrent =
                         ShmPsuData->PsuGroup[slave].GroupPresentPsuQuantity > 0 ? ZERO_CURRENT : 0;
+#endif
                 }
             }
         }
@@ -2409,7 +2535,7 @@ void UpdatePsuGroupOutputConfig(unsigned char master)
                     PSU_LOG("Gun %d Increase Current: %d.%d A, %d.%d A -> %d.%d A", master + 1,
                         ((GCTargetCurrent[master] - PresentTargetCurrent) / 10), ((GCTargetCurrent[master] - PresentTargetCurrent) % 10),
                         (PresentTargetCurrent / 10), (PresentTargetCurrent % 10), (GCTargetCurrent[master] / 10), (GCTargetCurrent[master] % 10));
-#if 0
+#if MASTER_OUTPUT_FIRST
                     // for safety test
                     if(GCTargetCurrent[master] <= CURRENT_BALANCE_CRITERIA)
                     {
@@ -2431,7 +2557,7 @@ void UpdatePsuGroupOutputConfig(unsigned char master)
                     PSU_LOG("Gun %d Decrease Current: %d.%d A, %d.%d A -> %d.%d A", master + 1,
                         ((PresentTargetCurrent - GCTargetCurrent[master]) / 10), ((PresentTargetCurrent - GCTargetCurrent[master]) % 10),
                         (PresentTargetCurrent / 10), (PresentTargetCurrent % 10), (GCTargetCurrent[master] / 10), (GCTargetCurrent[master] % 10));
-#if 0
+#if MASTER_OUTPUT_FIRST
                     // for safety test
                     if(GCTargetCurrent[master] <= ShmGroupCollection[master].Partner.RealQuantity * CURRENT_BALANCE_CRITERIA)
                     {
@@ -2469,7 +2595,8 @@ void UpdatePsuGroupOutputConfig(unsigned char master)
 
                     if(ShmGroupCollection[master].GroupCtrl.bits.OutputCurrentStable)
                     {
-#if 0
+#if MASTER_OUTPUT_FIRST
+                        // for safety test
                         if(GCTargetCurrent[master] > ShmGroupCollection[master].Partner.RealQuantity * CURRENT_BALANCE_CRITERIA)
                         {
                             CheckCurrentBalance(master);
@@ -2517,17 +2644,23 @@ void UpdatePsuGroupOutputConfig(unsigned char master)
 // group: self group index
 void SetPsuGroupOutput(unsigned char group)
 {
+    int time = 0;
+
     if(ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity > 0)
     {
-        //if(ShmPsuGrouping->GroupOutput[group].GTargetCurrent > 100)
-        //{
+#if ONE_MODULE_OUTPUT
+        // for safety test (inrush current)
+        if(ShmGroupCollection[group].GroupCtrl.bits.InPrechargeMode)
+        {
+            SingleOutputVol(ShmPsuPosition->GroupLocationInfo[group].PsuSN[0], ShmPsuGrouping->GroupOutput[group].GTargetVoltage, ShmPsuGrouping->GroupOutput[group].GTargetCurrent);
+        }
+        else
+        {
             PresentOutputVol(group, ShmPsuGrouping->GroupOutput[group].GTargetVoltage, ShmPsuGrouping->GroupOutput[group].GTargetCurrent);
-        //}
-        //else
-        //{
-        //    int moduleCurrent = (ShmPsuGrouping->GroupOutput[group].GTargetCurrent * 100) / ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity;
-        //    SetModuleOutputVol(group, ShmPsuGrouping->GroupOutput[group].GTargetVoltage * 100, moduleCurrent);
-        //}
+        }
+#else
+        PresentOutputVol(group, ShmPsuGrouping->GroupOutput[group].GTargetVoltage, ShmPsuGrouping->GroupOutput[group].GTargetCurrent);
+#endif
         Await();
     }
 
@@ -2539,6 +2672,13 @@ void SetPsuGroupOutput(unsigned char group)
         if(!isStartOutputSwitch[group])
         {
             SetPsuGroupPowerOnOff(group, PSU_POWER_ON);
+            GetClockTime(&_PoweOnOff_time[group]);
+        }
+        time = GetTimeoutValue(_PoweOnOff_time[group]) / uSEC_VAL;
+        if(time > POWER_ONOFF_RESEND_INTERVAL)
+        {
+            SetPsuGroupPowerOnOff(group, PSU_POWER_ON);
+            GetClockTime(&_PoweOnOff_time[group]);
         }
     }
     else
@@ -2546,6 +2686,13 @@ void SetPsuGroupOutput(unsigned char group)
         if(isStartOutputSwitch[group])
         {
             SetPsuGroupPowerOnOff(group, PSU_POWER_OFF);
+            GetClockTime(&_PoweOnOff_time[group]);
+        }
+        time = GetTimeoutValue(_PoweOnOff_time[group]) / uSEC_VAL;
+        if(time > POWER_ONOFF_RESEND_INTERVAL)
+        {
+            SetPsuGroupPowerOnOff(group, PSU_POWER_OFF);
+            GetClockTime(&_PoweOnOff_time[group]);
         }
     }
 }
@@ -3418,11 +3565,13 @@ void PsuGroupControlProcess(void)
                     _preOutputConfigStep[group] = _CURRENT_MODE_NONE;
                     MaxCurrentDemand[group] = 0;
                     StageMaxCurrent[group] = 0;
+                    _GfdStep[group] = PREPARE_STEP_NONE;
+                    _VoltageResumeCnt[group] = 0;
                 }
 
                 if(!ShmGroupCollection[group].GroupCtrl.bits.AlreadyInChargingMode)
                 {
-                    if(chargingInfo[group]->SystemStatus == S_CHARGING)
+                    if(chargingInfo[group]->SystemStatus == S_CHARGING && chargingInfo[group]->RelayK1K2Status)
                     {
                         LOG_INFO("Gun %d Enter Charging Mode", group + 1);
                         ShmGroupCollection[group].GroupCtrl.bits.AlreadyInChargingMode = true;
@@ -3430,6 +3579,7 @@ void PsuGroupControlProcess(void)
                         ShmGroupCollection[group].GroupCtrl.bits.ReachMaxStageCurrent = false;
                         GetClockTime(&_MaxCurrent_time[group]);
                         GetClockTime(&_StageCurrent_time[group]);
+                        GetClockTime(&_ChargingDelay_time[group]);
                     }
                 }
 

+ 6 - 0
EVSE/Projects/DO360/Apps/Module_PsuComm.h

@@ -36,6 +36,12 @@ typedef unsigned char 		byte;
 typedef unsigned short 	    word;
 typedef unsigned int 		unit;
 
+#define PREPARE_STEP_NONE                   0
+#define PREPARE_STEP_CABLE_CHECK            1
+#define PREPARE_STEP_GFD_DONE               2
+#define PREPARE_STEP_PRECHARGE              3
+#define PREPARE_STEP_CHARGING               4
+
 struct ChargingInfoData *chargingInfo[CONNECTOR_QUANTITY];
 bool isStartOutputSwitch[CONNECTOR_QUANTITY];
 

+ 70 - 1
EVSE/Projects/DO360/Apps/ReadCmdline.c

@@ -608,7 +608,7 @@ void GetSystemInfo()
 	printf ("\r\nSerialNumber = %s", ShmSysConfigAndInfo->SysConfig.SerialNumber);
 	printf ("\r\nInternetConn = %d", ShmSysConfigAndInfo->SysInfo.InternetConn);
 
-	printf ("\r\nMaxChargingPower = %d, MaxChargingCurrent = %d",
+	printf ("\r\nMaxChargingPower = %d kW, MaxChargingCurrent = %d A",
 			ShmSysConfigAndInfo->SysConfig.MaxChargingPower,
 			ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent);
 	printf("\r\n\r\n");
@@ -2815,6 +2815,71 @@ void EraseWhiteCard(char *v1)
     printf("\r\n\r\n");
 }
 
+void ShowChargerLimit(void)
+{
+    int limitPower = -1;
+    char *str_gun_type[] = {STR_GUN_TYPE_CHADEMO, STR_GUN_TYPE_CCS, STR_GUN_TYPE_GBT};
+    unsigned char inUsingCnt = 0;
+
+    printf("\r\nCharger Limit");
+
+    printf("\r\n System Psu Cnt: %2d", ShmPsuData->SystemPresentPsuQuantity);
+    printf("\r\n Charger Max ChargingProfile Power: %d kW", ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower == -1 ?
+        (int)ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower : (int)ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower / 1000);
+    printf("\r\n Max Total Current: %d A, Max Total Power: %d kW, Total Energy: %d kW, Total Duration %d",
+        ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent, ShmSysConfigAndInfo->SysConfig.MaxChargingPower,
+        ShmSysConfigAndInfo->SysConfig.MaxChargingEnergy, ShmSysConfigAndInfo->SysConfig.MaxChargingDuration);
+
+    printf("\r\n\r\n Gun Enable    Type  Psu  Phy_Vol  Phy_Cur  Config_Ocpp_MaxOcpp_Pow  Config_Ocpp_MaxOcpp_Cur");
+    for(int i = 0; i < GENERAL_GUN_QUANTITY; i++)
+    {
+        inUsingCnt = 0;
+        for(int j = 0; j < GENERAL_GUN_QUANTITY; j++)
+        {
+            if(ShmChargerInfo->PsuGrouping.GroupCollection[j].Role == _GROLE_MASTER)
+            {
+                inUsingCnt += ShmChargerInfo->PsuGrouping.GroupCollection[i].GunPsuQuantity;
+            }
+        }
+        // Gun Enable    Type  Psu  Phy_Vol  Phy_Cur  Config_Ocpp_MaxOcpp_Pow  Config_Ocpp_MaxOcpp_Cur
+        //  1    0    CHAdeMO   00   0000 V   0000 A    0000 / 0000 / 0000 kW     0000 / 0000 A
+        // Gun 1  Enable, Type: CCS, Psu Cnt: 00, Max Physical Vol: 0000 V, Cur: 0000 A, Max Config Pow: 0000 kW, Cur: 0000 A
+        printf("\r\n  %d    %d   ", i + 1, ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].Enable);
+        if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].Enable)
+        {
+            printf(" %7s   %2d",
+                _chargingData[i]->Type <= _Type_GB ? str_gun_type[_chargingData[i]->Type] : "???",
+                ShmGroupCollection[i].GunPsuQuantity);
+            printf("   %4d V   %4d A",
+                (ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].RemoteMaxPhysicalVoltage / 10),
+                (ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].RemoteMaxPhysicalCurrent / 10));
+
+            if(ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower != -1)
+            {
+                limitPower = (int)ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower;
+                if(inUsingCnt > 0)
+                {
+                    limitPower = (limitPower * ShmGroupCollection[i].GunPsuQuantity) / inUsingCnt;
+                }
+            }
+            else
+            {
+                limitPower = -1;
+            }
+            printf("    %4d / %4d / %4d kW",
+                (ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].MaxTotalChargingPower / 10),
+                _chargingData[i]->ChargingProfilePower == -1 ? (int)_chargingData[i]->ChargingProfilePower : ((int)_chargingData[i]->ChargingProfilePower / 1000),
+                limitPower == -1 ? limitPower : (limitPower / 1000));
+
+            printf("     %4d / %4d A",
+                ((int)ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].MaxTotalChargingCurrent / 10),
+                _chargingData[i]->ChargingProfileCurrent == -1 ? (int)_chargingData[i]->ChargingProfileCurrent : ((int)_chargingData[i]->ChargingProfileCurrent / 10));
+        }
+    }
+
+    printf("\r\n\r\n");
+}
+
 int main(void)
 {
 	if(InitShareMemory() == FAIL)
@@ -3182,6 +3247,10 @@ int main(void)
                 continue;
             }
             EraseWhiteCard(newString[1]);
+        }
+        else if(strcmp(newString[0], "limit") == 0)
+        {
+            ShowChargerLimit();
         }
 		else
 			printf ("%s\n", msg);

+ 3 - 0
EVSE/Projects/DO360/Apps/kill.sh

@@ -11,3 +11,6 @@ pkill OcppBackend
 pkill Module_ProduceUtils
 pkill main
 
+sleep 1
+
+echo V > /dev/watchdog

BIN
EVSE/Projects/DO360/Apps/libInfyGroup_PsuCommObj.a


+ 339 - 86
EVSE/Projects/DO360/Apps/main.c

@@ -118,7 +118,7 @@
 char 	*valid_Internet[2] 	  = {"8.8.8.8", "180.76.76.76"};
 unsigned char mask_table[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
 int whileLoopTime = 10000; // 10 ms
-int	wtdFd = -1;
+int wtdFd = -1;
 byte _authorizeIndex = NO_DEFINE;
 BOOL _UpgradeNeedReboot = FALSE;
 
@@ -195,6 +195,9 @@ bool IsConnectorWholeIdle();
 void SetAcContactor(unsigned char OnOff);
 void UpdateErrorCodeToOcpp(byte index);
 bool CheckConnectorTypeStatus(void);
+void CreateWatchdog(void);
+void TryCloseWatchdog(void);
+void TryFeedWatchdog(void);
 
 struct SysConfigAndInfo			*ShmSysConfigAndInfo;
 struct StatusCodeData 			*ShmStatusCodeData;
@@ -207,6 +210,8 @@ struct FanModuleData			*ShmFanModuleData;
 struct RelayModuleData			*ShmRelayModuleData[2];
 struct LedModuleData			*ShmLedModuleData;
 struct OCPP16Data				*ShmOCPP16Data;
+struct OCPP20Data               *ShmOCPP20Data;
+struct MeterInformation         *ShmCsuMeterData;
 ChargerInfoData                 *ShmChargerInfo;
 PsuPositionInfoData             *ShmPsuPosition;
 PsuGroupingInfoData             *ShmPsuGrouping;
@@ -226,6 +231,12 @@ struct timespec                 _SystemStatus_Time[CONNECTOR_QUANTITY];
 
 unsigned char                   _PsuGroupAvailable[CONNECTOR_QUANTITY];
 
+float                           gunOutputVol[CONNECTOR_QUANTITY];
+unsigned char                   _ocppProfileChkFlag[CONNECTOR_QUANTITY];
+float                           _lastProfilePower[CONNECTOR_QUANTITY];
+float                           _lastProfileCurrent[CONNECTOR_QUANTITY];
+float                           _lastMaxProfilePower;
+
 bool _NeedReset4gWifi;
 struct timespec _4gWifiReset_time;
 
@@ -246,7 +257,7 @@ bool isModelNameMatch = true;
 
 //int rfidFd = -1;
 //char* rfidPortName = "/dev/ttyS2";
-char* fwVersion = "V1.02.00.0000.00";
+char* fwVersion = "V1.03.00.0000.00";
 
 sqlite3 *localDb;
 bool isDb_ready;
@@ -347,6 +358,8 @@ void substr(char *dest, const char* src, unsigned int start, unsigned int cnt)
 int InitWatchDog()
 {
 	int fd;
+	int timeout = 180;
+
 	system("/usr/bin/fuser -k /dev/watchdog");
 	sleep(1);
 	system("echo V > /dev/watchdog");
@@ -357,6 +370,8 @@ int InitWatchDog()
 	{
 	    LOG_ERROR("System watch dog initial fail.\r\n");
 	}
+	ioctl(fd, _IOWR('W', 6, int), &timeout);
+
 	return fd;
 }
 
@@ -693,7 +708,18 @@ int CreateShareMemory()
 	}
 	memset(ShmOCPP16Data,0,sizeof(struct OCPP16Data));
 
-    //creat ShmOCPP16Data
+    if ((MeterSMId = shmget(ShmOcpp20ModuleKey, sizeof(struct OCPP20Data), IPC_CREAT | 0777)) < 0)
+    {
+        LOG_ERROR("[main]CreatShareMemory:shmget OCPP20Data NG\n");
+        return 0;
+    }
+    else if ((ShmOCPP20Data = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        LOG_ERROR("[main]CreatShareMemory:shmat OCPP20Data NG\n");
+        return 0;
+    }
+    memset(ShmOCPP20Data,0,sizeof(struct OCPP20Data));
+
     if ((MeterSMId = shmget(SM_ChargerInfoKey, sizeof(ChargerInfoData), IPC_CREAT | 0777)) < 0)
     {
         #ifdef SystemLogMessage
@@ -1452,6 +1478,7 @@ void InitEthernet()
 	    ShmSysConfigAndInfo->SysInfo.CabinetMicsStatus.EthernetStatus = _Connnection_Disconnected;
 	    ShmSysConfigAndInfo->SysInfo.CabinetMicsStatus.WiFiStatus = _Connnection_Disable;
 	    ShmSysConfigAndInfo->SysInfo.CabinetMicsStatus.TelcomModemStatus = _Connnection_Disable;
+	    LOG_INFO("Internet Fork PID = %d", getpid());
 
 		for(;;)
 		{
@@ -1803,6 +1830,7 @@ void InitialShareMemoryInfo()
 	ShmSysConfigAndInfo->SysInfo.InternetConn = 0;
 	ShmSysConfigAndInfo->SysInfo.OcppConnStatus = 0;
 	ShmSysConfigAndInfo->SysInfo.OrderCharging = NO_DEFINE;
+	ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower = -1;
 
 	strcpy((char *) ShmSysConfigAndInfo->SysConfig.UserId, "");
 
@@ -1924,7 +1952,7 @@ void InitialPsuGroupingAndLocation(void)
 
 void InitialMaxDispenserConnectorQuantity(void)
 {
-    if(ShmSysConfigAndInfo->SysConfig.ModelName[0] == 'D' && ShmSysConfigAndInfo->SysConfig.ModelName[1] == 'K')
+    if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable == false)
     {
         ShmChargerInfo->Control.MaxDispenser = 2;
         ShmChargerInfo->Control.MaxConnector = 2;
@@ -1995,6 +2023,15 @@ bool InitialChargerSetting(void)
 
         ShmChargerInfo->Control.SysCtrl.bits.E4YOULedIndication = true;
     }
+    else if(ShmSysConfigAndInfo->SysConfig.ModelName[0] == 'D' && ShmSysConfigAndInfo->SysConfig.ModelName[1] == 'B')
+    {
+        ShmChargerInfo->Control.SysCtrl.bits.FanBoardDisable = true;
+        ShmChargerInfo->Control.SysCtrl.bits.LedBoardDisable = true;
+
+        ShmChargerInfo->Control.SysCtrl.bits.E4YOULedIndication = true;
+        ShmChargerInfo->Control.RelayCtrl.bits.AcInputDisable = true;
+        ShmChargerInfo->Control.RelayCtrl.bits.DcInputEnable = true;
+    }
     else
     {
         result = false;
@@ -2800,7 +2837,7 @@ void ReleaseEmsOccureByString(byte index, char *code)
 	if (isTrigger)
 	{
 		ReleaseChargingProcessByString(level);
-		InformOcppErrOccur(6);
+		//InformOcppErrOccur(6);
 	}
 }
 
@@ -3899,7 +3936,7 @@ bool CheckConnectorTypeStatus(void)
 		for(int i = 0; i < CONNECTOR_QUANTITY; i++)
 		{
 			chargingInfo[i] = &ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].GeneralChargingData;
-			chargingInfo[i]->Index = 0xFF;
+			chargingInfo[i]->Index = (i < ShmSysConfigAndInfo->SysConfig.WiringInfo.MaxConnectorQuantity || i == 0) ? i : 0xFF;
 			chargingInfo[i]->Evboard_id = 0x00;
 			chargingInfo[i]->ReservationId = -1;
 			chargingInfo[i]->slotsIndex = 0;
@@ -4421,10 +4458,11 @@ void CreateTimeoutFork()
 	pid_t timeoutPid;
 
 	timeoutPid = fork();
-	if (timeoutPid > 0)
+	if (timeoutPid == 0)
 	{
 	    GetClockTime(&_cmdSubPriority_time);
 		CheckConnectionTimeout();
+		LOG_INFO("Timeout Fork PID = %d", getpid());
 
 		while(true)
 		{
@@ -4575,6 +4613,8 @@ void CheckFwUpdateFunction()
 	if (ShmSysConfigAndInfo->SysInfo.FirmwareUpdate == YES)
 	{
 		LOG_INFO("ftp : update start.");
+		TryCloseWatchdog();
+
 		//KillTask();
 	    ChangeLcmByIndex(_LCM_FIX);
 	    system("killall Module_PrimaryComm");
@@ -4609,6 +4649,8 @@ void CheckFwUpdateFunction()
 		if (strcmp((char *)ShmOCPP16Data->FirmwareStatusNotification.Status, "Downloaded") == EQUAL)
 		{
 			LOG_INFO("Backend : update start.");
+			TryCloseWatchdog();
+
 			strcpy((char *)ShmOCPP16Data->FirmwareStatusNotification.Status, "");
 			strcpy((char *)ShmOCPP16Data->FirmwareStatusNotification.Status, "Installing");
 			ShmOCPP16Data->SpMsg.bits.FirmwareStatusNotificationReq = YES;
@@ -4721,6 +4763,7 @@ void CheckSoftHardReset(void)
         sleep(5);
         system("killall OcppBackend &");
         KillAllTask();
+        TryCloseWatchdog();
         system("/usr/bin/run_evse_restart.sh");
 
     }
@@ -5138,6 +5181,7 @@ void CheckOcppStatus()
                     sleep(3);
                     system("killall OcppBackend &");
                     KillAllTask();
+                    TryCloseWatchdog();
                     system("/usr/bin/run_evse_restart.sh");
                 }
 		    }
@@ -5156,6 +5200,7 @@ void OcppStartTransation(byte gunIndex)
 
 	LOG_INFO("Gun index %d, OCPP Start Transation Index %d, IdTag = %s, StartSoc = %d",
         chargingInfo[gunIndex]->Index, _OcppGunIndex, ShmOCPP16Data->StartTransaction[_OcppGunIndex].IdTag, chargingInfo[gunIndex]->EvBatteryStartSoc);
+	ShmOCPP16Data->CpMsg.bits[_OcppGunIndex].StartTransactionConf = NO;
 	ShmOCPP16Data->CpMsg.bits[_OcppGunIndex].StartTransactionReq = YES;
 }
 
@@ -5743,6 +5788,7 @@ void StopProcessingLoop()
                 LOG_INFO("Soft reboot for retry self-tets (Primary).");
                 KillAllTask();
                 sleep(3);
+                TryCloseWatchdog();
                 system("/usr/bin/run_evse_restart.sh");
                 return;
             }
@@ -5766,15 +5812,36 @@ void StopProcessingLoop()
 	}
 }
 
-void CreateWatchdog()
+void CreateWatchdog(void)
 {
-	if (ShmSysConfigAndInfo->SysConfig.SwitchDebugFlag == NO)
-	{
-		wtdFd = InitWatchDog();
+    wtdFd = InitWatchDog();
 
-		if (wtdFd < 0)
-			ShmStatusCodeData->AlarmCode.AlarmEvents.bits.CsuInitFailed = 1;
-	}
+    if(wtdFd < 0)
+    {
+        LOG_INFO("Watchdog Initial Fail");
+        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.CsuInitFailed = 1;
+    }
+    else
+    {
+        LOG_INFO("Watchdog Initial Success");
+    }
+}
+
+void TryCloseWatchdog(void)
+{
+    if(wtdFd > 0)
+    {
+        write(wtdFd, "V", 1);
+        close(wtdFd);
+    }
+}
+
+void TryFeedWatchdog(void)
+{
+    if(wtdFd > 0)
+    {
+        write(wtdFd, "a", 1);
+    }
 }
 
 bool IsConnectorWholeIdle()
@@ -5870,8 +5937,9 @@ void CheckTask()
 
     if(system("pidof -s Module_InternalComm > /dev/null") != 0)
     {
-        LOG_ERROR("Module_InternalComm not running, System Restart.");
-        ShmChargerInfo->Control.SysCtrl.bits.NeedSoftReset = true;
+        LOG_ERROR("Module_InternalComm not running, restart it.");
+        system ("/root/Module_InternalComm &");
+        //ShmChargerInfo->Control.SysCtrl.bits.NeedSoftReset = true;
     }
 }
 
@@ -5907,6 +5975,34 @@ void StartDispenserDhcpServer(void)
 //==========================================
 // Check Smart Charging Profile
 //==========================================
+void Ocpp_ProfileReq_Cmd(byte gunIndex)
+{
+    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16)
+    {
+        if(ShmOCPP16Data->CSUMsg.bits[gunIndex].ChargingProfileConf == NO)
+        {
+            if(ShmOCPP16Data->CSUMsg.bits[gunIndex].ChargingProfileReq == NO)
+            {
+                ShmOCPP16Data->CSUMsg.bits[gunIndex].ChargingProfileReq = YES;
+            }
+        }
+    }
+}
+
+bool Ocpp_Chk_ProfileConf_Cmd(byte gunIndex)
+{
+    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16)
+    {
+        if (ShmOCPP16Data->CSUMsg.bits[gunIndex].ChargingProfileConf == YES)
+        {
+            ShmOCPP16Data->CSUMsg.bits[gunIndex].ChargingProfileConf = NO;
+            return true;
+        }
+    }
+
+    return false;
+}
+
 int GetStartScheduleTime(unsigned char *time)
 {
 	int result = -1;
@@ -5926,68 +6022,171 @@ int GetStartScheduleTime(unsigned char *time)
 	return result;
 }
 
-void CheckSmartChargeProfile(byte _index)
+void Ocpp_ChargingProfile_Process(byte _index)
 {
-	if (ShmOCPP16Data->CSUMsg.bits[_index].ChargingProfileConf == NO)
-	{
-		if (ShmOCPP16Data->CSUMsg.bits[_index].ChargingProfileReq == NO)
-			ShmOCPP16Data->CSUMsg.bits[_index].ChargingProfileReq = YES;
-	}
-	else
-	{
-		// Get Charging Profile
-		ShmOCPP16Data->CSUMsg.bits[_index].ChargingProfileConf = NO;
-		if (strcmp((char *)ShmOCPP16Data->SmartChargingProfile[_index].ChargingProfileKind, "Absolute") == EQUAL)
-		{
-			int _time = GetStartScheduleTime(ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.StartSchedule);
-			byte _startCount = NO_DEFINE;
-			byte _maxCount = ARRAY_SIZE(ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod);
+    int _time = 0;
+    int _startCount = NO_DEFINE;
+    int _maxCount = 0;
 
-			for (byte _count = 0; _count < _maxCount; _count++)
-			{
-				// 預設最小輸出電流 (MIN_OUTPUT_CUR) A
-				if (_time >= ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_count].StartPeriod &&
-						ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_count].Limit > MIN_OUTPUT_CUR)
-				{
-					_startCount = _count;
-				}
-			}
+    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16)
+    {
+        if (strcmp((char *)ShmOCPP16Data->SmartChargingProfile[_index].ChargingProfileKind, "Absolute") == EQUAL &&
+            ShmOCPP16Data->SmartChargingProfile[_index].ChargingProfileId == YES)
+        {
+            _time = GetStartScheduleTime(ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.StartSchedule);
+            _maxCount = ARRAY_SIZE(ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod);
+            _startCount = NO_DEFINE;
 
-			LOG_INFO("_startCount = %d", _startCount);
-			if (_startCount < _maxCount)
-			{
-				LOG_INFO("*********Limit = %f ", ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_startCount].Limit);
-				chargingInfo[_index]->ChargingProfileCurrent = ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_startCount].Limit * 10;
-				chargingInfo[_index]->ChargingProfilePower = ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_startCount].Limit * chargingInfo[_index]->EvBatterytargetVoltage / 100;
+            for (byte _count = 0; _count < _maxCount; _count++)
+            {
+                // 預設最小輸出電流 (MIN_OUTPUT_CUR) A
+                if (_time >= ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_count].StartPeriod)
+                {
+                    if ((_count == 0 && ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_count].Limit >= MIN_OUTPUT_CUR) ||
+                            ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_count].Limit > MIN_OUTPUT_CUR)
+                    {
+                        _startCount = _count;
+                    }
+                }
+            }
 
-				//chargingInfo[_index]->ChargingProfilePower = ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_startCount].Limit * AC_OUTPUT_VOL;
-//				if ((chargingInfo[_index]->EvBatterytargetVoltage * 10) > 0)
-//				{
-//					chargingInfo[_index]->ChargingProfileCurrent = chargingInfo[_index]->ChargingProfilePower / (chargingInfo[_index]->EvBatterytargetVoltage * 10);
-//				}
-			}
-			else
-			{
-				chargingInfo[_index]->ChargingProfilePower = -1;
-				chargingInfo[_index]->ChargingProfileCurrent = -1;
-			}
+            if (_startCount < _maxCount)
+            {
+                chargingInfo[_index]->ChargingProfilePower = ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_startCount].Limit * AC_OUTPUT_VOL * ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_startCount].NumberPhases;
+                if (chargingInfo[_index]->EvBatterytargetVoltage > 0 &&
+                    (int)chargingInfo[_index]->PresentChargingVoltage > 0)
+                {
+                    chargingInfo[_index]->ChargingProfileCurrent = (chargingInfo[_index]->ChargingProfilePower / chargingInfo[_index]->PresentChargingVoltage) * 10;
+                }
+                else
+                {
+                    chargingInfo[_index]->ChargingProfileCurrent = -1;
+                }
+            }
+            else
+            {
+                chargingInfo[_index]->ChargingProfilePower = -1;
+                chargingInfo[_index]->ChargingProfileCurrent = -1;
+            }
+        }
+        else
+        {
+            chargingInfo[_index]->ChargingProfilePower = -1;
+            chargingInfo[_index]->ChargingProfileCurrent = -1;
+        }
+    }
+    else
+    {
+        chargingInfo[_index]->ChargingProfilePower = -1;
+        chargingInfo[_index]->ChargingProfileCurrent = -1;
+    }
 
-			LOG_INFO("ChargingProfilePower = %f", chargingInfo[_index]->ChargingProfilePower);
-			LOG_INFO("ChargingProfileCurrent = %f", chargingInfo[_index]->ChargingProfileCurrent);
-		}
-//
-//		printf("-------------Schedule------------\n");
-//		printf("index = %d \n", _index);
-//		printf("StartSchedule = %s \n", ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.StartSchedule);
-//		printf("ChargingRateUnit = %s \n", ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingRateUnit);
-//		printf("----------SchedulePeriod---------\n");
-//		for (int v = 0; v < 10; v++)
-//		{
-//			printf("StartPeriod = %d \n", ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[v].StartPeriod);
-//			printf("Limit = %f \n", ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[v].Limit);
-//		}
-//		printf("---------------------------------\n");
-	}
+    if((int)_lastProfilePower[_index] != (int)chargingInfo[_index]->ChargingProfilePower ||
+        (int)_lastProfileCurrent[_index] != (int)chargingInfo[_index]->ChargingProfileCurrent)
+    {
+        LOG_INFO("Gun %d Get Profile - Index = %d, Limit = %f",
+            _index + 1, _startCount,
+            ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_startCount].Limit);
+        LOG_INFO("Max: %d kW, Gun %d ChargingProfile Power = %d, Current = %d",
+            ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower == -1 ? (int)ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower : ((int)ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower / 1000),
+            _index + 1, (int)chargingInfo[_index]->ChargingProfilePower, (int)chargingInfo[_index]->ChargingProfileCurrent);
+    }
+    _lastProfilePower[_index] = chargingInfo[_index]->ChargingProfilePower;
+    _lastProfileCurrent[_index] = chargingInfo[_index]->ChargingProfileCurrent;
+}
+
+void Ocpp_MaxChargingProfile_Process(void)
+{
+    int _time = 0;
+    int _startCount = NO_DEFINE;
+    int _maxCount = 0;
+
+    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16)
+    {
+        if (strcmp((char *)ShmOCPP16Data->MaxChargingProfile.ChargingProfileKind, "Absolute") == EQUAL &&
+            ShmOCPP16Data->MaxChargingProfile.ChargingProfileId == YES)
+        {
+            _time = GetStartScheduleTime(ShmOCPP16Data->MaxChargingProfile.ChargingSchedule.StartSchedule);
+            _maxCount = ARRAY_SIZE(ShmOCPP16Data->MaxChargingProfile.ChargingSchedule.ChargingSchedulePeriod);
+            _startCount = NO_DEFINE;
+
+            for (byte _count = 0; _count < _maxCount; _count++)
+            {
+                // 預設最小輸出電流 (MIN_OUTPUT_CUR) A
+                if (_time >= ShmOCPP16Data->MaxChargingProfile.ChargingSchedule.ChargingSchedulePeriod[_count].StartPeriod)
+                {
+                    if ((_count == 0 && ShmOCPP16Data->MaxChargingProfile.ChargingSchedule.ChargingSchedulePeriod[_count].Limit >= MIN_OUTPUT_CUR) ||
+                        ShmOCPP16Data->MaxChargingProfile.ChargingSchedule.ChargingSchedulePeriod[_count].Limit > MIN_OUTPUT_CUR)
+                    {
+                        _startCount = _count;
+                    }
+                }
+            }
+
+            if(_startCount < _maxCount)
+            {
+                ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower = ShmOCPP16Data->MaxChargingProfile.ChargingSchedule.ChargingSchedulePeriod[_startCount].Limit * AC_OUTPUT_VOL * ShmOCPP16Data->MaxChargingProfile.ChargingSchedule.ChargingSchedulePeriod[_startCount].NumberPhases;
+            }
+            else
+            {
+                ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower = -1;
+            }
+        }
+        else
+        {
+            ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower = -1;
+        }
+    }
+    else
+    {
+        ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower = -1;
+    }
+
+    if((int)_lastMaxProfilePower != (int)ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower)
+    {
+        LOG_INFO("Charger Get Max Profile - Index = %d, Limit = %f",
+            _startCount, ShmOCPP16Data->MaxChargingProfile.ChargingSchedule.ChargingSchedulePeriod[_startCount].Limit);
+        LOG_INFO("Charger Max Profile Power = %d", (int)ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower);
+    }
+    _lastMaxProfilePower = ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower;
+}
+
+void CheckSmartChargeProfile(byte _index)
+{
+    if(Ocpp_Chk_ProfileConf_Cmd(_index))
+    {
+        Ocpp_MaxChargingProfile_Process();
+        Ocpp_ChargingProfile_Process(_index);
+    }
+}
+
+bool Ocpp_CheckInvalidId(byte _index)
+{
+    bool invalid = false;
+
+    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16)
+    {
+        if(strstr((char *) ShmOCPP16Data->ConfigurationTable.CoreProfile[StopTransactionOnInvalidId].ItemData, "TRUE"))
+        {
+            if(strcmp((char *)ShmOCPP16Data->StartTransaction[_index].ResponseIdTagInfo.Status, "Blocked") == EQUAL ||
+                strcmp((char *)ShmOCPP16Data->StartTransaction[_index].ResponseIdTagInfo.Status, "Expired") == EQUAL ||
+                strcmp((char *)ShmOCPP16Data->StartTransaction[_index].ResponseIdTagInfo.Status, "Invalid") == EQUAL)
+            {
+                invalid = true;
+                LOG_INFO("Gun %d Stop Transaction On Invalid Id", _index + 1);
+            }
+        }
+        else
+        {
+            if(strcmp((char *)ShmOCPP16Data->StartTransaction[_index].ResponseIdTagInfo.Status, "Accepted") != EQUAL)
+            {
+                invalid = true;
+                LOG_INFO("Gun %d Start Transaction Not Accepted", _index + 1);
+            }
+        }
+    }
+
+    return invalid;
 }
 
 void TheEndCharging(byte gun_index)
@@ -6078,6 +6277,10 @@ void CheckDispenserVersionUpdateRequirement(void)
 
 }
 
+void ChargerBootingProcess(void)
+{
+
+}
 
 // connector: connector infex, 0 ~ 3
 void SetLedIndicationStatus(unsigned char connector, unsigned char indication)
@@ -6277,6 +6480,7 @@ void CreateLedIndicationFork(void)
     pid = fork();
     if(pid == 0)
     {
+        LOG_INFO("Led Indication Fork PID = %d", getpid());
         while(1)
         {
             LedIndicationProcess();
@@ -6360,7 +6564,7 @@ bool IsConnectorGroupingCompleted(unsigned char connector)
 
 int main(void)
 {
-    int time = 0;
+    unsigned long time = 0;
 
 	if(CreateShareMemory() == 0)
 	{
@@ -6378,6 +6582,7 @@ int main(void)
 	}
 	LOG_INFO("\n");
 	LOG_INFO("===== Boot and Initialization start =====");
+	LOG_INFO("Main Fork PID = %d", getpid());
 
 	if (!InitialSystemDefaultConfig())
 	{
@@ -6490,6 +6695,7 @@ int main(void)
 
 	CreateLedIndicationFork();
 
+	CreateWatchdog();
 	// Main loop
 	LOG_INFO("****************************Main Loop********************************** \n");
 	GetClockTime(&_cmdMainPriority_time);
@@ -6531,8 +6737,25 @@ int main(void)
 			CheckTask();
 			for (byte _index = 0; _index < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; _index++)
 			{
-				if (chargingInfo[_index]->SystemStatus == S_CHARGING)
-					CheckSmartChargeProfile(_index);
+			    if((chargingInfo[_index]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[_index]->SystemStatus <= S_CHARGING) ||
+                    (chargingInfo[_index]->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingInfo[_index]->SystemStatus <= S_CCS_PRECHARGE_ST1))
+			    {
+                    if (chargingInfo[_index]->SystemStatus == S_CHARGING && _ocppProfileChkFlag[_index] == 12)
+                    {
+                        Ocpp_ProfileReq_Cmd(_index);
+                        gunOutputVol[_index] = chargingInfo[_index]->PresentChargingVoltage;
+                        _ocppProfileChkFlag[_index] = 0;
+                    }
+                    else if (chargingInfo[_index]->SystemStatus != S_CHARGING)
+                    {
+                        Ocpp_ProfileReq_Cmd(_index);
+                        _ocppProfileChkFlag[_index] = 0;
+                    }
+                    else
+                    {
+                        _ocppProfileChkFlag[_index]++;
+                    }
+			    }
 			}
 
 			GetClockTime(&_cmdMainPriority_time);
@@ -6549,6 +6772,22 @@ int main(void)
 			CheckErrorOccurStatus(gun_index);
 			ChkOcppStatus(gun_index);
 
+            if((chargingInfo[gun_index]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[gun_index]->SystemStatus <= S_CHARGING) ||
+                (chargingInfo[gun_index]->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingInfo[gun_index]->SystemStatus <= S_CCS_PRECHARGE_ST1))
+            {
+                if(chargingInfo[gun_index]->SystemStatus == S_CHARGING)
+                {
+                    // 進充電後,如果輸出電壓落差大於 10V 則直接繼續看 ChargingProfile
+                    if (chargingInfo[gun_index]->PresentChargingVoltage >= gunOutputVol[gun_index] + 10 ||
+                            chargingInfo[gun_index]->PresentChargingVoltage <= gunOutputVol[gun_index] - 10)
+                    {
+                        _ocppProfileChkFlag[gun_index] = 12;
+                        gunOutputVol[gun_index] = chargingInfo[gun_index]->PresentChargingVoltage;
+                    }
+                }
+            }
+            CheckSmartChargeProfile(gun_index);
+
 			//LOG_INFO("index = %d, ErrorCode = %s \n", gun_index, ShmOCPP16Data->StatusNotification[gun_index].ErrorCode);
 			switch(chargingInfo[gun_index]->SystemStatus)
 			{
@@ -6624,6 +6863,12 @@ int main(void)
                             chargingInfo[gun_index]->PresentChargedEnergy = 0;
                             chargingInfo[gun_index]->PresentChargingPower = 0;
 
+                            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].MaxTotalChargingPower = 0;
+                            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].MaxTotalChargingCurrent = 0;
+
+                            chargingInfo[gun_index]->ChargingProfilePower = -1;
+                            chargingInfo[gun_index]->ChargingProfileCurrent = -1;
+
                             // clean force charging info
                             memset(&ShmChargerInfo->Control.FCharging[gun_index], 0x00, sizeof(ForceCharging));
                         }
@@ -6837,14 +7082,12 @@ int main(void)
 							ShmSysConfigAndInfo->SysInfo.OrderCharging = NO_DEFINE;
 						//StopSystemTimeoutDet();
 						ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].Parameter.bits.PsuReleasable = false;
-						ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].MaxTotalChargingCurrent = ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent * 10;
-						ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].MaxTotalChargingPower = ShmSysConfigAndInfo->SysConfig.MaxChargingPower * 10;
 						ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].MaxOutputEnergy = ShmSysConfigAndInfo->SysConfig.MaxChargingEnergy;
 						ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].MaxOutputDuration = ShmSysConfigAndInfo->SysConfig.MaxChargingDuration;
 
-						LOG_INFO("Max Total Current %d, Max Total Power %d, Total Energy %d, Total Duration %d",
-                            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].MaxTotalChargingCurrent,
-                            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].MaxTotalChargingPower,
+						LOG_INFO("Max Total Current %d A, Max Total Power %d kW, Total Energy %d kWh, Total Duration %d",
+                            ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent,
+                            ShmSysConfigAndInfo->SysConfig.MaxChargingPower,
                             ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].MaxOutputEnergy,
                             ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].MaxOutputDuration);
 						SetAcContactor(ON);
@@ -7097,7 +7340,7 @@ int main(void)
                         chargingInfo[gun_index]->EvBatterytargetCurrent = current;
                     }
 
-                    time = GetTimeoutValue(_SystemStatus_Time[gun_index]) / uSEC_VAL;
+                    time = GetSecTimeoutValue(_SystemStatus_Time[gun_index]);
 
                     // 計算 Power
                     //chargingInfo[gun_index]->PresentChargingPower = ((float)((chargingInfo[gun_index]->PresentChargingVoltage) * (chargingInfo[gun_index]->PresentChargingCurrent)) / 1000);
@@ -7137,18 +7380,28 @@ int main(void)
                         ChargingTerminalProcess(gun_index);
                     }
 					else if(CheckBackendChargingTimeout(gun_index) ||
-                        CheckBackendChargingEnergy(gun_index) ||
-                        (ShmOCPP16Data->CpMsg.bits[gun_index].StartTransactionConf &&
-                        strcmp((char *)ShmOCPP16Data->StartTransaction[gun_index].ResponseIdTagInfo.Status, "Invalid") == EQUAL))
+                        CheckBackendChargingEnergy(gun_index))
 					{
 					    LOG_INFO("********** Gun %d Backend Stop (S_CHARGING) **********", gun_index + 1);
 						// 板端或後臺要求停止
 						ChargingTerminalProcess(gun_index);
 					}
+					else if(ShmOCPP16Data->CpMsg.bits[gun_index].StartTransactionConf)
+					{
+					    if(Ocpp_CheckInvalidId(gun_index))
+					    {
+	                        LOG_INFO("********** Gun %d Backend InvalidId Stop (S_CHARGING) **********", gun_index + 1);
+	                        ChargingTerminalProcess(gun_index);
+					    }
+					}
 
                     if(ShmOCPP16Data->CpMsg.bits[gun_index].StartTransactionConf)
                     {
                         ShmOCPP16Data->CpMsg.bits[gun_index].StartTransactionConf = NO;
+                        if(strcmp((char *)ShmOCPP16Data->StartTransaction[gun_index].ResponseIdTagInfo.Status, "Accepted") == EQUAL)
+                        {
+                            LOG_INFO("Gun %d OCPP Start Transaction Accepted, Id = %d", gun_index + 1, ShmOCPP16Data->StartTransaction[gun_index].ResponseTransactionId);
+                        }
                     }
 				}
 					break;
@@ -7271,7 +7524,7 @@ int main(void)
 				ChangeLcmByIndex(ShmSysConfigAndInfo->SysInfo.ConnectorPage);
 		}
 
-		write(wtdFd, "a", 1);
+		TryFeedWatchdog();
 		usleep(whileLoopTime);
 	}
 

BIN
EVSE/Projects/DO360/Images/FactoryDefaultConfig.bin


BIN
EVSE/Projects/DO360/Images/ramdisk.gz