Explorar o código

2021-11-09 / Wendell

Actions
1. [add] Cabinet parallel function
2. [add] Misc: AuthModeConfig & EVCCIDConfig
3. [add] Limit output power via model name
4. [mod] Misc: operative logic
5. [mod] led indication logic
6. [mod] self test logic
7. [mod] psu temperature info
8. [mod] add latency between FAULT to IDLE
9. [fix] system status won't stop charging at AUTHORIZING state when disconnect with dispenser occur
10.[fix] read cabinet status issue

Files
1. As follow commit history

Image version : V1.05.XX.XXXX.XX
Wendell %!s(int64=3) %!d(string=hai) anos
pai
achega
23f6a5067f

+ 11 - 0
EVSE/Projects/DO360/Apps/Common.c

@@ -117,3 +117,14 @@ unsigned long GetSecTimeoutValue(struct timespec _start_time)
     return ret;
 }
 
+int StatusCodeCompose(char *oriCode, char *newCode)
+{
+    if(strlen(oriCode) > 0)
+    {
+        strcat(oriCode, ",");
+    }
+    strcat(oriCode, newCode);
+
+    return strlen(oriCode);
+}
+

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

@@ -34,5 +34,6 @@ int StorePsuLogMsg(const char *fmt, ...);
 void GetClockTime(struct timespec *_now_time);
 unsigned long GetTimeoutValue(struct timespec _start_time);
 unsigned long GetSecTimeoutValue(struct timespec _start_time);
+int StatusCodeCompose(char *oriCode, char *newCode);
 
 #endif /* COMMON_H_ */

+ 159 - 15
EVSE/Projects/DO360/Apps/Config.h

@@ -55,6 +55,12 @@ typedef unsigned char               byte;
 
 #define SAFETY_TEST_ENABLE          0
 
+#define MAX_SLAVE_CABINET_QUANTITY  4
+#define MASTER_ETH1_IP              "192.168.100.1"
+#define MASTER_ETH1_SUBMASK         "255.255.255.0"
+#define SLAVE_ETH1_IP               "192.168.0.10"
+#define SLAVE_ETH1_SUBMASK          "255.255.255.0"
+
 // **********  Audi ********** //
 // Model Name: DOYC182000D2AD
 // Model Name: DDYC182V0UE2AD
@@ -165,10 +171,13 @@ enum _AuthorizedType
 enum _SELF_TEST_SEQ
 {
 	_STEST_VERSION          = 0x00,
-	_STEST_AC_CONTACTOR     = 0x01,
-	_STEST_PSU_DETECT       = 0x02,
-	_STEST_PSU_CAP          = 0x03,
-	_STEST_FAIL             = 0x04,
+	_STEST_CabinetSwitch    = 0x01,
+	_STEST_AC_CONTACTOR     = 0x02,
+	_STEST_PSU_DETECT       = 0x03,
+	_STEST_PSU_CAP          = 0x04,
+    _STEST_PSU_RETRY        = 0x05,
+    _STEST_EMG_BTN          = 0x06,
+	_STEST_FAIL             = 0x07,
 	_STEST_COMPLETE         = 0xEE,
 };
 
@@ -262,6 +271,10 @@ enum _ETHERNET_USAGE
 	_ETHERNET_USAGE_3G_4g
 };
 
+#define STR_CONN_DISABLE            "Disable"
+#define STR_CONN_CONNECTED          "Connected"
+#define STR_CONN_DISCONNECTED       "Disconnected"
+
 enum _CONN_STATUS
 {
     _Connnection_Disable = 0,
@@ -303,24 +316,36 @@ enum _QR_MODE
     _QR_MODE_ChargeBoxId        = 2,                // for audi
 };
 
+#define STR_CABINET_ROLE_NONE       "Single"
+#define STR_CABINET_ROLE_MASTER     "Master"
+#define STR_CABINET_ROLE_SLAVE      "Slave"
+
+enum _CABINET_ROLE
+{
+    _CROLE_SINGLE               = 0,                // single power cabinet mode
+    _CROLE_MASTER               = 1,                // power cabinet master mode
+    _CROLE_SLAVE                = 2,                // power cabinet slave mode
+};
+
 typedef union
 {
     unsigned int CtrlValue;
     struct
     {
+        unsigned int SelfTestOK:1;                  // 0: self test not completed,  1: self test ok
+        unsigned int NeedSelfTest:1;                // 0: no effect,                1: need execute self test
         unsigned int NeedSoftReset:1;               // 0: no effect,                1: system need soft reset
         unsigned int NeedHardReset:1;               // 0: no effect,                1: system need hard reset
-        unsigned int SelfTestOK:1;                  // 0: self test not completed,  1: self test ok
         unsigned int PrimaryDisable:1;              // 0: primary enable,           1: primary disable
         unsigned int RelayBoardDisable:1;           // 0: relay board enable,       1: relay board disable
         unsigned int FanBoardDisable:1;             // 0: fan board enable,         1: fan board disable
         unsigned int LedBoardDisable:1;             // 0: led board enable,         1: led board disable
         unsigned int SecondRelayBoardEnable:1;      // 0: second relay disable,     1: second relay enable
-        unsigned int StandardLedIndication:1;       // 0: no led indication,        1: enable standard led indication
-        unsigned int E4YOULedIndication:1;          // 0: no led indication,        1: enable e4you led indication
+        unsigned int DOLedIndication:1;             // 0: no led indication,        1: enable DO Model led indication
+        unsigned int DKLedIndication:1;             // 0: no led indication,        1: enable DK Model led indication
         unsigned int BackendEnable:1;               // 0: backend disable,          1: backend enable
         unsigned int Wifi4gResetEnable:1;           // 0: wifi/4g reset io disable, 1: wifi/4g reset io enable
-        unsigned int res:20;
+        unsigned int res:19;
     }bits;
 }SystemControl;
 
@@ -394,11 +419,14 @@ typedef union
     struct
     {
         unsigned int SelfTestOK:1;                  // 0: self test not completed,  1: self test ok
+        unsigned int NeedSelfTest:1;                // 0: no effect,                1: need execute self test
+        unsigned int Paused:1;                      // 0: no effect,                1: primary paused
         unsigned int DisableDoorSensor:1;           // 0: door sensor enable,       1: door sensor disable
         unsigned int DisableEmergencyButton:1;      // 0: emergency button enable,  1: emergency button disable
         unsigned int DoorSensorReverse:1;           // 0: the same as ds's,         1: status is different from ds's
         unsigned int AcContactorReverse:1;          // 0: the same as ds's,         1: status is different from ds's
-        unsigned int res:27;
+        unsigned int CabinetSwitchDetect:1;         // 0: no effect,                1: need detect cabinet switch
+        unsigned int res:24;
     }bits;
 }PrimaryControl;
 
@@ -408,13 +436,15 @@ typedef union
     struct
     {
         unsigned int SelfTestOK:1;                  // 0: self test not completed,  1: self test ok
+        unsigned int NeedSelfTest:1;                // 0: no effect,                1: need execute self test
+        unsigned int Paused:1;                      // 0: no effect,                1: relay paused
         unsigned int AcContactor:1;                 // 0: ac contactor off,         1: ac contactor on
         unsigned int AcContactorOffByPsu:1;         // 0: no effect,                1: ac contactor off
         unsigned int AcContactorOffByEmergency:1;   // 0: no effect,                1: ac contactor off
         unsigned int StandbyCountdown:1;            // 0: charger is using,         1: start countdown
         unsigned int AcInputDisable:1;              // 0: ac input enable,          1: ac input disable
         unsigned int DcInputEnable:1;               // 0: dc input disable,         1: dc input enable
-        unsigned int res:25;
+        unsigned int res:23;
     }bits;
 }RelayControl;
 
@@ -424,7 +454,9 @@ typedef union
     struct
     {
         unsigned int SelfTestOK:1;                  // 0: self test not completed,  1: self test ok
-        unsigned int res:31;
+        unsigned int NeedSelfTest:1;                // 0: no effect,                1: need execute self test
+        unsigned int Paused:1;                      // 0: no effect,                1: fan paused
+        unsigned int res:29;
     }bits;
 }FanControl;
 
@@ -434,7 +466,9 @@ typedef union
     struct
     {
         unsigned int SelfTestOK:1;                  // 0: self test not completed,  1: self test ok
-        unsigned int res:31;
+        unsigned int NeedSelfTest:1;                // 0: no effect,                1: need execute self test
+        unsigned int Paused:1;                      // 0: no effect,                1: led paused
+        unsigned int res:29;
     }bits;
 }LedFanControl;
 
@@ -444,8 +478,10 @@ typedef union
     struct
     {
         unsigned int SelfTestOK:1;                  // 0: self test not completed,  1: self test ok
+        unsigned int NeedSelfTest:1;                // 0: no effect,                1: need execute self test
+        unsigned int Paused:1;                      // 0: no effect,                1: psu paused
         unsigned int FailureResume:1;               // 0: no error,                 1: psu failure, need resume
-        unsigned int res:30;
+        unsigned int res:28;
     }bits;
 }PsuControl;
 
@@ -454,7 +490,10 @@ typedef struct
     unsigned char   MaxDispenser;
     unsigned char   MaxConnector;
     unsigned char   CabinetSwitch;
-    unsigned char   reserved;
+    unsigned char   CabinetRole;
+    unsigned char   SelfTestStep;
+    unsigned char   res;
+    unsigned short  ChargerRatingPower;             // unit: 0.1kw, charger rating power, parsing from model name
     SystemControl   SysCtrl;
     TestControl     TestCtrl;
     DebugControl    DebugCtrl;
@@ -464,6 +503,7 @@ typedef struct
     LedFanControl   LedCtrl;
     PsuControl      PsuCtrl;
     ForceCharging   FCharging[MAX_GROUP_QUANTITY];
+    unsigned char   GunAvailable[MAX_GROUP_QUANTITY];
 }SysControl;
 // ************************************************************************************************* //
 typedef struct
@@ -477,6 +517,7 @@ typedef struct
 typedef struct
 {
     unsigned char GroupPsuQuantity;
+    unsigned char res;
     unsigned char PsuSN[MAX_MODULE_PER_GROUP];
 }GroupInfoData;
 
@@ -638,7 +679,8 @@ typedef union
         unsigned short Location_1_2:1;                          // 0: set parallel off,         1: set parallel on
         unsigned short Location_2_3:1;                          // 0: set parallel off,         1: set parallel on
         unsigned short Location_3_4:1;                          // 0: set parallel off,         1: set parallel on
-        unsigned short res:13;
+        unsigned short Location_4_5:1;                          // 0: set parallel off,         1: set parallel on
+        unsigned short res:12;
     }bits;
 }PsuGroupParallelRelay;
 
@@ -655,12 +697,114 @@ typedef struct
 }PsuGroupingInfoData;
 // ************************************************************************************************* //
 
+typedef enum
+{
+    _SCONN_FREE                 = 0,
+    _SCONN_WAIT                 = 1,
+    _SCONN_MATCHED              = 2,
+}_SOCKET_CONN_STATUS;
+
+typedef enum
+{
+    _DeviceStatus_DisConnect        = 0x00,         // _DS_None                 , slave cabinet in re-connection
+    _DeviceStatus_Identification    = 0x01,         // _DS_Identification       , slave cabinet in identification
+    _DeviceStatus_Idle              = 0x02,         // _DS_Idle                 , slave cabinet in idle
+    _DeviceStatus_Alarm             = 0x03,         // _DS_Alarm                , slave cabinet in alarm
+    _DeviceStatus_Charging          = 0x04,         // _DS_Charging             , no use in slave cabinet
+    _DeviceStatus_Timeout           = 0x05,         // _DS_Timeout              , no use in slave cabinet
+    _DeviceStatus_RetryWait         = 0x06,
+}_DEVICE_STATUS;
+
+typedef enum
+{
+    _Parallel_None              = 0,
+    _Parallel_Wait              = 1,                // ac contactor off, 3s
+    _Parallel_Working           = 2,                // ac contactor on and start re-initial psu
+    _Parallel_Done              = 3,                // re-initial psu done
+}_PARALLEL_STATUS;
+
+typedef struct
+{
+    unsigned char Status;                                       // 0: free, 1: WaitModelName, 2: DispenserMatched
+    unsigned char DeviceIndex;                                  // record device index
+    unsigned int  IpAddress;                                    // record device ip address
+    unsigned char DuplicateIp;                                  // 0: unique ip,    1: duplicate ip
+    unsigned char res;
+}SocketConnInfoData;
+
+typedef struct
+{
+    unsigned char   LocalStatus;                // 0: None, 1: Identification, 2: Idle, 3: Alarm, 4: Charging, 5: _DS_Timeout
+    unsigned char   SlaveID;
+    unsigned char   ModelName[64];              //charger model name
+    unsigned char   SerialNumber[64];           //charger system serial number
+    unsigned char   SystemId[128];              //charger system ID
+
+    unsigned char   CsuBootLoadFwRev[32];       //CSU board bootloader firmware version
+    unsigned char   CsuKernelFwRev[32];         //CSU board OS kernel firmware version
+    unsigned char   CsuRootFsFwRev[32];         //CSU board root file system firmware version
+    unsigned char   CsuPrimFwRev[32];           //CSU board root file system firmware version
+    unsigned char   LcmFwRev[32];               //LCM module firmware version
+    unsigned char   PsuPrimFwRev[32];           //PSU primary firmware version
+    unsigned char   PsuSecFwRev[32];            //PSU secondary firmware version
+    unsigned char   FanModuleFwRev[32];         //Fan  module firmware version
+    unsigned char   RelayModuleFwRev[32];       //Relay control  module firmware version
+    unsigned char   TelcomModemFwRev[32];       //the 3G/4G modem firmware version
+    unsigned char   LedModuleFwRev[32];         //LED control module firmware version
+    unsigned char   Connector1FwRev[32];        //Connector1 module firmware version
+    unsigned char   Connector2FwRev[32];        //Connector2 module firmware version
+
+    unsigned char   AcContactorSetting;                         // 0: OFF, 1: ON        Master -> Slave
+    unsigned char   AcContactorState;                           // 0: OFF, 1: ON        Slave  -> Master
+    unsigned char   OutputRelaySetting[MAX_GROUP_QUANTITY];     // 0: OFF, 1: ON        Master -> Slave
+    unsigned char   GunOutputRelayState[MAX_GROUP_QUANTITY];    // 0: OFF, 1: ON        Slave  -> Master
+    unsigned char   ParallelRelaySetting[MAX_GROUP_QUANTITY];   // 0: OFF, 1: ON        Master -> Slave
+    unsigned char   ParallelRelayState[MAX_GROUP_QUANTITY];     // 0: OFF, 1: ON        Slave  -> Master
+    unsigned char   UpdateRequest;                              // 0: no effect,        1: need to update
+    unsigned char   res;
+    char            FwFileName[128];
+    unsigned char   SocketChannel;                              // record socket index
+    unsigned char   IpDuplicatedFlag;                           // 0: no effect,        1: ip is duplicated
+    unsigned char   ParallelRequest;                            // 0: no effect,        1: parallel request
+    unsigned char   ParallelConfirm;                            // 0: no effect,        1: parallel confirm
+    unsigned short  ParallelPower;                              // parallel power, unit: 0.1kw
+}SlaveCabinetInfoData;
+
+typedef struct
+{
+    unsigned char           ParallelStatus;                     // 0: parallel none, 1: wait, 2: in paralleling, 3: parallel done
+    unsigned char           ParallelCabinetQuantity;            // record max dispenser quantity
+    unsigned char           PresentParallelCabinetQuantity;     // present slave cabinet quantity
+    unsigned char           res;
+    SlaveCabinetInfoData    PCabinet[MAX_SLAVE_CABINET_QUANTITY];
+    unsigned char           PCUpdateState[MAX_SLAVE_CABINET_QUANTITY];  // 0: Not in Update,    1: Updating,    2: Updated
+    unsigned short          TotalParallelPower;                 // max total parallel power, unit: 0.1kw
+}ParallelCabinetInfoData;
+
+typedef struct
+{
+    unsigned char               SCabinetStatus;
+    unsigned char               SCabinetID;
+    unsigned char               SOutputRelay[MAX_GROUP_QUANTITY];       // parallel cabinet output relay state
+    unsigned char               SParallelRelay[MAX_GROUP_QUANTITY];     // parallel cabinet parallel relay state
+    unsigned char               SAcContactor;                       // slave cabinet ac contactor state
+    unsigned char               NeedUpgrade;                            // 1: Need Upgrade, 2: No Update
+    unsigned char               UpgradeState;                           // 0: Not in Update,    1: Updating,    2: Updated
+    unsigned char               res;
+    char                        FwFileName[128];
+}SlaveCabinetControl;
+
+// ************************************************************************************************* //
+
 typedef struct
 {
     SystemAuthInfoData AuthInfo;
     SysControl Control;
     PsuPositionInfoData PsuPosition;
     PsuGroupingInfoData PsuGrouping;
+    SocketConnInfoData CabinetConnInfo[MAX_SLAVE_CABINET_QUANTITY];
+    ParallelCabinetInfoData ParallelCabinet;
+    SlaveCabinetControl SCabinetControl;
 }ChargerInfoData;
 
 #endif /* CONFIG_H_ */

+ 22 - 1
EVSE/Projects/DO360/Apps/Makefile

@@ -13,7 +13,7 @@ Lib_SQLite3 = "-L../../../Modularization/ocppfiles" -lsqlite3
 all: CopyFile apps Clean
 #apps: Module_CSU Module_EvComm Module_EventLogging Module_InternalComm Module_LcmControl Module_PrimaryComm Module_PsuComm 
 # ReadCmdline kill.sh
-apps: Common MainTask EvCommTask EventLoggingTask InternalCommTask LcmControlTask PrimaryCommTask InfyGroup_PsuCommObj PsuCommTask ReadCmdlineTask UnsafetyOutputTool FactoryConfigApp OtherTools
+apps: Common MainTask CabinetParallel SelfTestTask LedIndication EvCommTask EventLoggingTask InternalCommTask LcmControlTask PrimaryCommTask InfyGroup_PsuCommObj PsuCommTask ReadCmdlineTask UnsafetyOutputTool FactoryConfigApp OtherTools
 
 Common:
 	rm -f Common.o
@@ -26,6 +26,24 @@ MainTask:
 	$(CC) -o main main.o timeout.o Common.o ${Lib_Module_RFID} ${Lib_Module_Upgrade} ${Lib_SQLite3}	-lrt
 	cp -f main ../Images/root
 
+CabinetParallel:
+	rm -f Module_CabinetParallel;
+	$(CC) -D $(Project) -includeConfig.h -O0 -g3 -Wall -c -fmessage-length=0 -o Module_CabinetParallel.o Module_CabinetParallel.c
+	$(CC) -o Module_CabinetParallel Module_CabinetParallel.o Common.o -lrt
+	cp -f Module_CabinetParallel ../Images/root	
+
+SelfTestTask:
+	rm -f Module_ChargerSelfTest;
+	$(CC) -D $(Project) -includeConfig.h -O0 -g3 -Wall -c -fmessage-length=0 -o Module_ChargerSelfTest.o Module_ChargerSelfTest.c
+	$(CC) -o Module_ChargerSelfTest Module_ChargerSelfTest.o Common.o -lrt
+	cp -f Module_ChargerSelfTest ../Images/root	
+
+LedIndication:
+	rm -f Module_LedIndication;
+	$(CC) -D $(Project) -includeConfig.h -O0 -g3 -Wall -c -fmessage-length=0 -o Module_LedIndication.o Module_LedIndication.c
+	$(CC) -o Module_LedIndication Module_LedIndication.o Common.o -lrt
+	cp -f Module_LedIndication ../Images/root	
+
 EvCommTask:
 	rm -f Module_EvComm;
 	$(CC) -D $(Project) -includeConfig.h -O0 -g3 -Wall -c -fmessage-length=0 -o Ev_Comm.o Ev_Comm.c
@@ -112,6 +130,9 @@ CleanObj:
 CleanExecute:
 	rm -f main
 	rm -f Module_EvComm
+	rm -f Module_CabinetParallel
+	rm -f Module_ChargerSelfTest
+	rm -f Module_LedIndication
 	rm -f Module_EventLogging
 	rm -f Module_InternalComm
 	rm -f Module_LcmControl

+ 1846 - 0
EVSE/Projects/DO360/Apps/Module_CabinetParallel.c

@@ -0,0 +1,1846 @@
+/*
+ * Module_CabinetParallel.c
+ *
+ *  Created on: 2021年9月28日
+ *      Author: 7978
+ */
+
+#include    <sys/time.h>
+#include    <sys/timeb.h>
+#include    <sys/types.h>
+#include    <sys/stat.h>
+#include    <sys/types.h>
+#include    <sys/ioctl.h>
+#include    <sys/socket.h>
+#include    <sys/ipc.h>
+#include    <sys/shm.h>
+#include    <sys/shm.h>
+#include    <sys/mman.h>
+#include    <linux/can.h>
+#include    <linux/can/raw.h>
+#include    <linux/wireless.h>
+#include    <arpa/inet.h>
+#include    <netinet/in.h>
+
+#include    <unistd.h>
+#include    <stdarg.h>
+#include    <stdio.h>      /*標準輸入輸出定義*/
+#include    <stdlib.h>     /*標準函數庫定義*/
+#include    <unistd.h>     /*Unix 標準函數定義*/
+#include    <fcntl.h>      /*檔控制定義*/
+#include    <termios.h>    /*PPSIX 終端控制定義*/
+#include    <errno.h>      /*錯誤號定義*/
+#include    <errno.h>
+#include    <string.h>
+#include    <time.h>
+#include    <ctype.h>
+#include    <ifaddrs.h>
+#include    <signal.h>
+#include    <net/if_arp.h>
+#include    "../../define.h"
+#include    "Module_EvComm.h"
+#include    "Module_CabinetParallel.h"
+#include    "Config.h"
+#include    "Common.h"
+
+//==========================================
+// Share Memory
+//==========================================
+struct SysConfigAndInfo             *ShmSysConfigAndInfo;
+ChargerInfoData                     *ShmChargerInfo;
+struct ChargingInfoData             *chargingInfo[CONNECTOR_QUANTITY];
+PsuGroupCollectionData              *ShmGroupCollection;
+struct PsuData                      *ShmPsuData;
+
+//==========================================
+// Local Variable
+//==========================================
+struct WARNING_CODE_INFO SlaveWarningInfo[MAX_SLAVE_CABINET_QUANTITY];
+unsigned char _SCabinetUpdateState = 0;
+unsigned char PCabinetUpdateRequest[MAX_SLAVE_CABINET_QUANTITY];
+
+int _regReqLen[PARALLEL_CABINET_REG_QUANTITY] =
+{
+    REG_REQ_LEN_NONE,                   // reg: 0x00
+    REG_REQ_LEN_MODELNAME,              // reg: 0x01
+    REG_REQ_LEN_ID,                     // reg: 0x02
+    REG_REQ_LEN_REG03,                  // reg: 0x03
+    REG_REQ_LEN_STATUS,                 // reg: 0x04
+    REG_REQ_LEN_OUTPUT_RELAY,           // reg: 0x05
+    REG_REQ_LEN_AC_CONTACTOR,           // reg: 0x06
+    REG_REQ_LEN_UPDATE,                 // reg: 0x07
+    REG_REQ_LEN_PARALLEL_RELAY,         // reg: 0x08
+};
+
+int _regResLen[PARALLEL_CABINET_REG_QUANTITY] =
+{
+    REG_RES_LEN_NONE,                   // reg: 0x00
+    REG_RES_LEN_MODELNAME,              // reg: 0x01
+    REG_RES_LEN_ID,                     // reg: 0x02
+    REG_RES_LEN_REG03,                  // reg: 0x03
+    REG_RES_LEN_STATUS,                 // reg: 0x04
+    REG_RES_LEN_OUTPUT_RELAY,           // reg: 0x05
+    REG_RES_LEN_AC_CONTACTOR,           // reg: 0x06
+    REG_RES_LEN_UPDATE,                 // reg: 0x07
+    REG_RES_LEN_PARALLEL_RELAY,         // reg: 0x08
+};
+
+void ShowSocketData(struct PACKET_STRUCTURE *packet)
+{
+    printf("se: %02X, id: %02X, op: %d, len: %3d, reg: %02X",
+        packet->Header.se, packet->Header.id, packet->Header.op, packet->Header.len, packet->Payload.reg);
+
+    if(packet->Header.len > 1)
+    {
+        printf(", Data:");
+        for(int i = 0; i < packet->Header.len - 1; i++)
+        {
+            printf(" %02X", packet->Payload.data[i]);
+        }
+    }
+    printf("\n");
+}
+
+//==========================================
+// Init all share memory
+//==========================================
+int InitShareMemory(void)
+{
+    int result = PASS;
+    int MeterSMId;
+
+    //creat ShmSysConfigAndInfo
+    if ((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo), 0777)) < 0)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmget ShmSysConfigAndInfo NG");
+        #endif
+        result = FAIL;
+    }
+    else if ((ShmSysConfigAndInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmat ShmSysConfigAndInfo NG");
+        #endif
+        result = FAIL;
+     }
+    else
+    {
+
+    }
+
+    if ((MeterSMId = shmget(SM_ChargerInfoKey, sizeof(ChargerInfoData), 0777)) < 0)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmat ChargerInfoData NG");
+        #endif
+        result = FAIL;
+    }
+    else if ((ShmChargerInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmat ChargerInfoData NG");
+        #endif
+        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;
+}
+
+void InitialConnector(void)
+{
+    for(int i = 0; i < CONNECTOR_QUANTITY; i++)
+    {
+        chargingInfo[i] = &ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].GeneralChargingData;
+    }
+}
+
+void SlaveCabinetCheckInUpdate(void)
+{
+    unsigned char slaveCnt = 0;
+
+    for(int i = 0; i < MAX_SLAVE_CABINET_QUANTITY; i++)
+    {
+        if(ShmChargerInfo->ParallelCabinet.PCabinet[i].LocalStatus != _DS_None &&
+            ShmChargerInfo->ParallelCabinet.PCabinet[i].LocalStatus != _DS_Timeout)
+        {
+            slaveCnt++;
+        }
+    }
+    ShmChargerInfo->ParallelCabinet.PresentParallelCabinetQuantity = slaveCnt;
+    if(slaveCnt > ShmChargerInfo->ParallelCabinet.ParallelCabinetQuantity)
+    {
+        ShmChargerInfo->ParallelCabinet.ParallelCabinetQuantity = slaveCnt;
+    }
+}
+
+void SetSlaveCabinetStatus(unsigned char DeviceIndex, unsigned char status)
+{
+    if(DeviceIndex < MAX_SLAVE_CABINET_QUANTITY)
+    {
+        switch(status)
+        {
+            case _DS_Identification:
+            case _DS_Alarm:
+            case _DS_Charging:
+                ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].LocalStatus = status;
+                break;
+
+            case _DS_Idle:
+                if(ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].LocalStatus != status)
+                {
+                    ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].ParallelRequest = YES;
+                }
+                ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].LocalStatus = status;
+                break;
+
+            case _DS_Timeout:
+                memset(&ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex], 0x00, sizeof(SlaveCabinetInfoData));
+                ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].LocalStatus = status;
+                break;
+
+            case _DS_None:
+            default:
+                memset(&ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex], 0x00, sizeof(SlaveCabinetInfoData));
+                break;
+        }
+    }
+}
+
+void SlaveCabinetIpConflictedCheck(void)
+{
+    unsigned char DuplicatedConfirm[MAX_SLAVE_CABINET_QUANTITY];
+    struct timespec _Conflicted_Time[MAX_SLAVE_CABINET_QUANTITY];
+
+    memset(DuplicatedConfirm, 0x00, MAX_SLAVE_CABINET_QUANTITY);
+
+    while(1)
+    {
+        for(int i = 0; i < MAX_SLAVE_CABINET_QUANTITY; i++)
+        {
+            if(ShmChargerInfo->ParallelCabinet.PCabinet[i].IpDuplicatedFlag == true)
+            {
+                if(DuplicatedConfirm[i] == false)
+                {
+                    DuplicatedConfirm[i] = true;
+                    GetClockTime(&_Conflicted_Time[i]);
+                    LOG_INFO("Slave Cabinet %d IP Conflicted Confirm", i + 1);
+                }
+                else
+                {
+                    if((GetTimeoutValue(_Conflicted_Time[i]) / mSEC_VAL) >= IP_CONFLICTED_TIME)
+                    {
+                        // reach here only when MCabinetCommProcess is stopped
+                        if(ShmChargerInfo->ParallelCabinet.PCabinet[i].LocalStatus != _DS_None &&
+                            ShmChargerInfo->ParallelCabinet.PCabinet[i].LocalStatus != _DS_Timeout)
+                        {
+                            unsigned char channel = ShmChargerInfo->ParallelCabinet.PCabinet[i].SocketChannel;
+
+                            if(ShmChargerInfo->CabinetConnInfo[channel].Status != _SCONN_FREE)
+                            {
+                                SetSlaveCabinetStatus(i, _DS_Timeout);
+                                SlaveCabinetCheckInUpdate();
+                                memset(&ShmChargerInfo->CabinetConnInfo[channel], 0x00, sizeof(SocketConnInfoData));
+                                LOG_INFO("Cabinet ConnInfo Channel %d Clean", channel);
+                            }
+                        }
+                        ShmChargerInfo->ParallelCabinet.PCabinet[i].IpDuplicatedFlag = false;
+                        DuplicatedConfirm[i] = false;
+                        LOG_INFO("Slave Cabinet %d IP Conflicted Stop", i + 1);
+                    }
+                }
+            }
+        }
+        usleep(500000);
+    }
+}
+
+int ConflictedCabinetCheck(void)
+{
+    pid_t forkId;
+
+    forkId = fork();
+    if(forkId == 0)
+    {
+        SlaveCabinetIpConflictedCheck();
+        return forkId;
+    }
+    else if(forkId == -1)
+    {
+        LOG_INFO("fork fail");
+    }
+
+    return forkId;
+}
+
+int GetFreeSocketChannel(SocketConnInfoData *SocketConn, int Len)
+{
+    for(int i = 0; i < Len; i++)
+    {
+        if(SocketConn[i].Status == _SCONN_FREE)
+        {
+            return i;
+        }
+    }
+
+    return FAIL;
+}
+
+bool IsConflictCabinetIp(uint32_t ipAddress)
+{
+    for(int i = 0; i < ARRAY_SIZE(ShmChargerInfo->CabinetConnInfo); i++)
+    {
+        if(ShmChargerInfo->CabinetConnInfo[i].IpAddress == ipAddress)
+        {
+            int slaveCabinet = ShmChargerInfo->CabinetConnInfo[i].DeviceIndex;
+            if(slaveCabinet < MAX_SLAVE_CABINET_QUANTITY)
+            {
+                if(ShmChargerInfo->ParallelCabinet.PCabinet[slaveCabinet].IpDuplicatedFlag == false)
+                {
+                    ShmChargerInfo->ParallelCabinet.PCabinet[slaveCabinet].IpDuplicatedFlag = true;
+                }
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+bool FindSlaveCabinet(unsigned char DeviceIndex, unsigned char ID)
+{
+    bool find = false;
+
+    if(ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].SlaveID == ID)
+    {
+        find = true;
+    }
+
+    return find;
+}
+
+void SendPacket(int socket, struct PACKET_STRUCTURE *packet)
+{
+    //ShowSocketData(packet);
+    //send(socket, packet, packet->Header.len + 4, 0);
+    send(socket, packet, packet->Header.len + 4, MSG_NOSIGNAL);
+}
+
+// Reg: 0x01, Slave Cabinet Model Name Handler
+// allow slave cabinet switch value: 2 ~ 5
+// allow slave cabinet ip address: 31 ~ 34
+// return legal id: 1 ~ 4
+unsigned char MCabinetModelNameHandler(unsigned char connIndex, struct PACKET_STRUCTURE *packet)
+{
+    unsigned char modelName[64];
+    unsigned char cabinetId = 0;
+
+    memset(modelName, 0x00, 64);
+    memcpy(modelName, packet->Payload.data, packet->Header.len - 1);
+
+    cabinetId = (ShmChargerInfo->CabinetConnInfo[connIndex].IpAddress >> 24) & 0xFF;
+    if(cabinetId <= 30 || cabinetId > (30 + MAX_SLAVE_CABINET_QUANTITY))
+    {
+        LOG_INFO("Slave Cabinet DeviceID Out Of Range(%d), Model Name: %s", cabinetId, modelName);
+        cabinetId = 0;
+    }
+    else
+    {
+        cabinetId -= 30;
+        LOG_INFO("Slave Cabinet Check In, Device ID: %d, Model Name: %s", cabinetId, modelName);
+        memcpy(ShmChargerInfo->ParallelCabinet.PCabinet[cabinetId - 1].ModelName, modelName, packet->Header.len - 1);
+        ShmChargerInfo->ParallelCabinet.PCabinet[cabinetId - 1].SocketChannel = connIndex;
+    }
+
+    return cabinetId;
+}
+
+// Reg: 0x01, Slave Cabinet Model Name Response
+void MCabinetModelNameResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result)
+{
+    struct PACKET_STRUCTURE sendBuffer;
+
+    memset(&sendBuffer, 0x00, sizeof(sendBuffer));
+    sendBuffer.Header.se = packet->Header.se;
+    sendBuffer.Header.id = 0xFF;
+    sendBuffer.Header.op = _Header_Response;
+    sendBuffer.Header.len = 2;
+    sendBuffer.Payload.reg = _Reg_Dispenser_Model_Name;
+    sendBuffer.Payload.data[0] = result;
+
+    SendPacket(socket, &sendBuffer);
+}
+
+// Reg: 0x02, Slave Cabinet ID Response
+void MCabinetIDResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result, unsigned char DeviceIndex)
+{
+    struct PACKET_STRUCTURE sendBuffer;
+
+    memset(&sendBuffer, 0x00, sizeof(sendBuffer));
+    sendBuffer.Header.se = packet->Header.se;
+    sendBuffer.Header.id = 0xFF;
+    sendBuffer.Header.op = _Header_Response;
+    sendBuffer.Header.len = 3;
+    sendBuffer.Payload.reg = _Reg_SCabinet_ID;
+    sendBuffer.Payload.data[0] = result;
+    sendBuffer.Payload.data[1] = ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].SlaveID;
+
+    SendPacket(socket, &sendBuffer);
+}
+
+// Reg: 0x04, Slave Cabinet Status Handler
+bool MCabinetStatusHandler(struct PACKET_STRUCTURE *packet, unsigned char DeviceIndex)
+{
+    bool find = FindSlaveCabinet(DeviceIndex, packet->Header.id);
+    bool chagne = false;
+    struct WARNING_CODE_INFO warning;
+
+    if(find)
+    {
+        memset(&warning, 0x00, sizeof(struct WARNING_CODE_INFO));
+
+        warning.WarningCount = (packet->Header.len - 1) / 6;
+
+        if(warning.WarningCount > 10)
+        {
+            warning.WarningCount = 10;
+        }
+
+        for(int i = 0; i < warning.WarningCount; i++)
+        {
+            memcpy(&warning.WarningCode[i][0], &packet->Payload.data[i * 6], 6);
+        }
+
+        if(SlaveWarningInfo[DeviceIndex].WarningCount != warning.WarningCount)
+        {
+            chagne = true;
+        }
+        else
+        {
+            if(warning.WarningCount != 0)
+            {
+                for(int i = 0; i < warning.WarningCount; i++)
+                {
+                    if(strcmp((char *)&SlaveWarningInfo[DeviceIndex].WarningCode[i][0], (char *)&warning.WarningCode[i][0]) != EQUAL)
+                    {
+                        chagne = true;
+                        break;
+                    }
+                }
+            }
+        }
+
+        if(chagne)
+        {
+            memcpy(&SlaveWarningInfo[DeviceIndex], &warning, sizeof(struct WARNING_CODE_INFO));
+
+            char strSlaveDeviceStatus[128];
+            sprintf(strSlaveDeviceStatus, "PCabinet %d, Status Code Len: %d",
+                ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].SlaveID, SlaveWarningInfo[DeviceIndex].WarningCount);
+
+            if(SlaveWarningInfo[DeviceIndex].WarningCount > 0)
+            {
+                for(int i = 0; i < SlaveWarningInfo[DeviceIndex].WarningCount; i++)
+                {
+                    char strTemp[16];
+                    sprintf(strTemp, ", %s", SlaveWarningInfo[DeviceIndex].WarningCode[i]);
+                    strcat(strSlaveDeviceStatus, strTemp);
+                }
+            }
+            LOG_INFO("%s", strSlaveDeviceStatus);
+        }
+    }
+    else
+    {
+        // do nothing
+    }
+
+    return find;
+}
+
+// Reg: 0x04, Slave Cabinet Status Response
+void MCabinetStatusResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result, unsigned char DeviceIndex)
+{
+    struct PACKET_STRUCTURE sendBuffer;
+
+    memset(&sendBuffer, 0x00, sizeof(sendBuffer));
+    sendBuffer.Header.se = packet->Header.se;
+    sendBuffer.Header.id = packet->Header.id;
+    sendBuffer.Header.op = _Header_Response;
+    sendBuffer.Header.len = 2;
+    sendBuffer.Payload.reg = _Reg_SCabinet_Status;
+    sendBuffer.Payload.data[0] = result;
+
+    SendPacket(socket, &sendBuffer);
+}
+
+// Reg: 0x05, Output Relay Status Handler
+bool MCabinetOutputRelayHandler(struct PACKET_STRUCTURE *packet, unsigned char DeviceIndex)
+{
+    bool find = FindSlaveCabinet(DeviceIndex, packet->Header.id);
+    bool chagne = false;
+    unsigned char relayState[MAX_GROUP_QUANTITY];
+    unsigned char *slaveRelayState;
+
+    if(find)
+    {
+        if((packet->Header.len - 1) >= MAX_GROUP_QUANTITY)
+        {
+            slaveRelayState = &ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].GunOutputRelayState[0];
+            memcpy(relayState, &packet->Payload.data, MAX_GROUP_QUANTITY);
+
+            for(int i = 0; i < MAX_GROUP_QUANTITY; i++)
+            {
+                if(slaveRelayState[i] != relayState[i])
+                {
+                    chagne = true;
+                    break;
+                }
+            }
+
+            if(chagne)
+            {
+                memcpy(slaveRelayState, relayState, MAX_GROUP_QUANTITY);
+
+                char strRelayStatus[128];
+                sprintf(strRelayStatus, "PCabinet %d Output Relay", DeviceIndex + 1);
+                for(int i = 0; i < MAX_GROUP_QUANTITY; i++)
+                {
+                    char strTemp[16];
+                    sprintf(strTemp, " Gun %d %3s", i + 1, slaveRelayState[i] > 0 ? "ON" : "OFF");
+                    strcat(strRelayStatus, strTemp);
+                }
+                LOG_INFO("%s", strRelayStatus);
+            }
+        }
+    }
+    else
+    {
+        // do nothing
+    }
+
+    return find;
+}
+
+// Reg: 0x05, Output Relay Status Response
+void MCabinetOutputRelayResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result, unsigned char DeviceIndex)
+{
+    struct PACKET_STRUCTURE sendBuffer;
+    unsigned char *slaveRelayState;
+    slaveRelayState = &ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].OutputRelaySetting[0];
+
+    memset(&sendBuffer, 0x00, sizeof(sendBuffer));
+    sendBuffer.Header.se = packet->Header.se;
+    sendBuffer.Header.id = packet->Header.id;
+    sendBuffer.Header.op = _Header_Response;
+    sendBuffer.Header.len = 6;
+    sendBuffer.Payload.reg = _Reg_OutputRelay_Status;
+    sendBuffer.Payload.data[0] = result;
+    sendBuffer.Payload.data[1] = result == _R_OK ? slaveRelayState[0] : Relay_OFF;
+    sendBuffer.Payload.data[2] = result == _R_OK ? slaveRelayState[1] : Relay_OFF;
+    sendBuffer.Payload.data[3] = result == _R_OK ? slaveRelayState[2] : Relay_OFF;
+    sendBuffer.Payload.data[4] = result == _R_OK ? slaveRelayState[3] : Relay_OFF;
+
+    SendPacket(socket, &sendBuffer);
+}
+
+// Reg: 0x06, Ac Contactor Status Handler
+bool MCabinetAcContactorHandler(struct PACKET_STRUCTURE *packet, unsigned char DeviceIndex)
+{
+    bool find = FindSlaveCabinet(DeviceIndex, packet->Header.id);
+    bool chagne = false;
+    unsigned char contactorState;
+    unsigned char *slaveContactorState;
+
+    if(find)
+    {
+        if((packet->Header.len - 1) >= 1)
+        {
+            slaveContactorState = &ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].AcContactorState;
+            contactorState = packet->Payload.data[0];
+
+            if(*slaveContactorState != contactorState)
+            {
+                chagne = true;
+            }
+
+            if(chagne)
+            {
+                *slaveContactorState = contactorState;
+                LOG_INFO("PCabinet %d AC Contactor State: %s", DeviceIndex + 1, *slaveContactorState > 0 ? "ON" : "OFF");
+            }
+        }
+    }
+    else
+    {
+        // do nothing
+    }
+
+    return find;
+}
+
+// Reg: 0x06, Ac Contactor Status Response
+void MCabinetAcContactorResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result, unsigned char DeviceIndex)
+{
+    struct PACKET_STRUCTURE sendBuffer;
+    unsigned char slaveContactorState = ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].AcContactorSetting;
+
+    memset(&sendBuffer, 0x00, sizeof(sendBuffer));
+    sendBuffer.Header.se = packet->Header.se;
+    sendBuffer.Header.id = packet->Header.id;
+    sendBuffer.Header.op = _Header_Response;
+    sendBuffer.Header.len = 3;
+    sendBuffer.Payload.reg = _Reg_AcContactor_Status;
+    sendBuffer.Payload.data[0] = result;
+    sendBuffer.Payload.data[1] = result == _R_OK ? slaveContactorState : Relay_OFF;
+
+    SendPacket(socket, &sendBuffer);
+}
+
+// Reg: 0x07, Slave Cabinet Firmware Upgrade Handler
+bool MCabinetFwUpgradeHandler(struct PACKET_STRUCTURE *packet, unsigned char DeviceIndex)
+{
+    bool find = FindSlaveCabinet(DeviceIndex, packet->Header.id);
+    bool chagne = false;
+    unsigned char updateState;
+    unsigned char *slaveUpdateState;
+    char *strUpdate[] = {"Not Update", "Updating", "Updated"};
+
+    if(find)
+    {
+        if((packet->Header.len - 1) >= 1)
+        {
+            slaveUpdateState = &ShmChargerInfo->ParallelCabinet.PCUpdateState[DeviceIndex];
+
+            updateState = packet->Payload.data[0];
+
+            if(*slaveUpdateState != updateState)
+            {
+                chagne = true;
+            }
+
+            if(chagne)
+            {
+                switch(updateState)
+                {
+                    case Updated:
+                        ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].UpdateRequest = NO;
+                        break;
+                }
+                *slaveUpdateState = updateState;
+                LOG_INFO("PCabinet %d Update State: %s", DeviceIndex + 1, *slaveUpdateState <= Updated ? strUpdate[*slaveUpdateState] : "Unknown");
+            }
+        }
+    }
+    else
+    {
+
+    }
+
+    return find;
+}
+
+// Reg: 0x07, Slave Cabinet Firmware Upgrade Response
+void MCabinetUpgradeResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result, unsigned char DeviceIndex)
+{
+    struct PACKET_STRUCTURE sendBuffer;
+    unsigned char slaveUpdateRequest = ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].UpdateRequest;
+
+    memset(&sendBuffer, 0x00, sizeof(sendBuffer));
+    sendBuffer.Header.se = packet->Header.se;
+    sendBuffer.Header.id = packet->Header.id;
+    sendBuffer.Header.op = _Header_Response;
+    sendBuffer.Header.len = 3;
+    sendBuffer.Payload.reg = _Reg_SCabinet_FwUpdate;
+    sendBuffer.Payload.data[0] = result;
+    if(result == _R_OK)
+    {
+        sendBuffer.Payload.data[1] = slaveUpdateRequest > 0 ? _R_NeedUpgrade : _R_NoUpgrade;
+        if(slaveUpdateRequest > 0)
+        {
+            int length = strlen(ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].FwFileName);
+            memcpy(&sendBuffer.Payload.data[2], ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].FwFileName, length);
+            sendBuffer.Header.len += length;
+            if(PCabinetUpdateRequest[DeviceIndex] != slaveUpdateRequest)
+            {
+                LOG_INFO("MCabinet >> PCabinet %d Start Upgrade: %s", DeviceIndex + 1, ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].FwFileName);
+            }
+        }
+        PCabinetUpdateRequest[DeviceIndex] = slaveUpdateRequest;
+    }
+
+    SendPacket(socket, &sendBuffer);
+}
+
+// Reg: 0x08, Parallel Relay Status Handler
+bool MCabinetParallelRelayHandler(struct PACKET_STRUCTURE *packet, unsigned char DeviceIndex)
+{
+    bool find = FindSlaveCabinet(DeviceIndex, packet->Header.id);
+    bool chagne = false;
+    unsigned char relayState[MAX_GROUP_QUANTITY];
+    unsigned char *slaveRelayState;
+
+    if(find)
+    {
+        if((packet->Header.len - 1) >= MAX_GROUP_QUANTITY)
+        {
+            slaveRelayState = &ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].ParallelRelayState[0];
+            memcpy(relayState, &packet->Payload.data, MAX_GROUP_QUANTITY);
+
+            for(int i = 0; i < MAX_GROUP_QUANTITY; i++)
+            {
+                if(slaveRelayState[i] != relayState[i])
+                {
+                    chagne = true;
+                    break;
+                }
+            }
+
+            if(chagne)
+            {
+                memcpy(slaveRelayState, relayState, MAX_GROUP_QUANTITY);
+
+                char strRelayStatus[128];
+                sprintf(strRelayStatus, "PCabinet %d Parallel Relay", DeviceIndex + 1);
+                for(int i = 0; i < MAX_GROUP_QUANTITY; i++)
+                {
+                    char strTemp[16];
+                    sprintf(strTemp, " Location %d %3s", i + 1, slaveRelayState[i] > 0 ? "ON" : "OFF");
+                    strcat(strRelayStatus, strTemp);
+                }
+                LOG_INFO("%s", strRelayStatus);
+            }
+        }
+    }
+    else
+    {
+        // do nothing
+    }
+
+    return find;
+}
+
+// Reg: 0x08, Parallel Relay Status Response
+void MCabinetParallelRelayResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result, unsigned char DeviceIndex)
+{
+    struct PACKET_STRUCTURE sendBuffer;
+    unsigned char *slaveRelayState;
+    slaveRelayState = &ShmChargerInfo->ParallelCabinet.PCabinet[DeviceIndex].ParallelRelaySetting[0];
+
+    memset(&sendBuffer, 0x00, sizeof(sendBuffer));
+    sendBuffer.Header.se = packet->Header.se;
+    sendBuffer.Header.id = packet->Header.id;
+    sendBuffer.Header.op = _Header_Response;
+    sendBuffer.Header.len = 6;
+    sendBuffer.Payload.reg = _Reg_ParallelRelay_Status;
+    sendBuffer.Payload.data[0] = result;
+    sendBuffer.Payload.data[1] = result == _R_OK ? slaveRelayState[0] : Relay_OFF;
+    sendBuffer.Payload.data[2] = result == _R_OK ? slaveRelayState[1] : Relay_OFF;
+    sendBuffer.Payload.data[3] = result == _R_OK ? slaveRelayState[2] : Relay_OFF;
+    sendBuffer.Payload.data[4] = result == _R_OK ? slaveRelayState[3] : Relay_OFF;
+
+    SendPacket(socket, &sendBuffer);
+}
+
+int BufferRePacket(int dataLength, unsigned char *buffer, struct PACKET_STRUCTURE *packet)
+{
+    int totalLength = 0, packetCnt = 0, singleLength = 0;
+    struct PACKET_STRUCTURE *tempPacket;
+
+    while(dataLength > 0)
+    {
+        tempPacket = (struct PACKET_STRUCTURE *)&buffer[totalLength];
+        singleLength = tempPacket->Header.len + PACKET_HEADER_LENGTH;
+        if(dataLength >= singleLength)
+        {
+            totalLength += singleLength;
+            dataLength -= singleLength;
+            memset(&packet[packetCnt], 0x00, sizeof(struct PACKET_STRUCTURE));
+            memcpy(&packet[packetCnt], tempPacket, singleLength);
+            packetCnt++;
+        }
+        else
+        {
+            LOG_INFO("Packet[%d] is incomplete(%d/%d)", packetCnt, dataLength, singleLength);
+            dataLength = 0;
+        }
+    }
+
+    return packetCnt;
+}
+
+void MCabinetPacketHandler(int socketFd, unsigned char socketIndex, struct PACKET_STRUCTURE *packet)
+{
+    unsigned char ackResult = _R_NG;
+    unsigned char deviceIndex = 0;
+
+    if(ShmChargerInfo->CabinetConnInfo[socketIndex].Status == _SCONN_WAIT)
+    {
+        // Reg: 0x01, Dispenser model name
+        if(packet->Header.op == _Header_Write && packet->Payload.reg == _Reg_SCabinet_Model_Name)
+        {
+            unsigned char deviceID = MCabinetModelNameHandler(socketIndex, packet);
+
+            if(deviceID > 0)
+            {
+                ackResult = _R_OK;
+                deviceIndex = deviceID - 1;
+            }
+
+            MCabinetModelNameResponse(socketFd, packet, ackResult);
+            ShmChargerInfo->CabinetConnInfo[socketIndex].Status = ackResult == _R_OK ? _SCONN_MATCHED : _SCONN_WAIT;
+            ShmChargerInfo->CabinetConnInfo[socketIndex].DeviceIndex = deviceIndex;
+            if(ackResult == _R_OK)
+            {
+                ShmChargerInfo->ParallelCabinet.PCabinet[deviceIndex].SlaveID = deviceID;
+                SetSlaveCabinetStatus(deviceIndex, _DS_Identification);
+                SlaveCabinetCheckInUpdate();
+            }
+        }
+        else
+        {
+            // do nothing
+        }
+
+        // do not clear timeout value, then close socket when timeout value exceed SOCKET_RECEIVE_INTERVAL
+    }
+    else if(ShmChargerInfo->CabinetConnInfo[socketIndex].Status == _SCONN_MATCHED)
+    {
+        deviceIndex = ShmChargerInfo->CabinetConnInfo[socketIndex].DeviceIndex;
+
+        // Reg: 0x01, Dispenser model name
+        if(packet->Header.op == _Header_Write && packet->Payload.reg == _Reg_SCabinet_Model_Name)
+        {
+            ackResult = _R_OK;
+            MCabinetModelNameResponse(socketFd, packet, ackResult);
+        }
+
+        // Reg: 0x02, Slave Cabinet ID
+        if(packet->Header.op == _Header_Read && packet->Payload.reg == _Reg_SCabinet_ID)
+        {
+            ackResult = _R_OK;
+            SetSlaveCabinetStatus(deviceIndex, _DS_Idle);
+            MCabinetIDResponse(socketFd, packet, ackResult, deviceIndex);
+        }
+
+        // Reg: 0x04, Slave Cabinet Status
+        if(packet->Header.op == _Header_Write && packet->Payload.reg == _Reg_SCabinet_Status)
+        {
+            if(MCabinetStatusHandler(packet, deviceIndex))
+            {
+                ackResult = _R_OK;
+            }
+            MCabinetStatusResponse(socketFd, packet, ackResult, deviceIndex);
+        }
+
+        // Reg: 0x05, Sync Output Relay Status
+        if(packet->Header.op == _Header_Read && packet->Payload.reg == _Reg_OutputRelay_Status)
+        {
+            if(MCabinetOutputRelayHandler(packet, deviceIndex))
+            {
+                ackResult = _R_OK;
+            }
+            MCabinetOutputRelayResponse(socketFd, packet, ackResult, deviceIndex);
+        }
+
+        // Reg: 0x06, Sync Ac Contactor Status
+        if(packet->Header.op == _Header_Read && packet->Payload.reg == _Reg_AcContactor_Status)
+        {
+            if(MCabinetAcContactorHandler(packet, deviceIndex))
+            {
+                ackResult = _R_OK;
+            }
+            MCabinetAcContactorResponse(socketFd, packet, ackResult, deviceIndex);
+        }
+
+        // Reg: 0x07, Fw Update
+        if(packet->Header.op == _Header_Read && packet->Payload.reg == _Reg_SCabinet_FwUpdate)
+        {
+            if(MCabinetFwUpgradeHandler(packet, deviceIndex))
+            {
+                ackResult = _R_OK;
+            }
+            MCabinetUpgradeResponse(socketFd, packet, ackResult, deviceIndex);
+        }
+
+        // Reg: 0x08, Sync Parallel Relay Status
+        if(packet->Header.op == _Header_Read && packet->Payload.reg == _Reg_ParallelRelay_Status)
+        {
+            if(MCabinetParallelRelayHandler(packet, deviceIndex))
+            {
+                ackResult = _R_OK;
+            }
+            MCabinetParallelRelayResponse(socketFd, packet, ackResult, deviceIndex);
+        }
+    }
+}
+
+void MCabinetCommProcess(int socketFd, struct sockaddr_in clientInfo, unsigned char socketIndex)
+{
+    int rxLen = 0, packetCnt = 0;
+    unsigned char dataBuffer[MAX_DATA_BUFFER_LEN];
+    struct PACKET_STRUCTURE packetBuffer[MAX_PACKET_BUFFER_LEN];
+    struct timespec _MCabinet_timeout;
+
+    LOG_INFO("Start Slave Cabinet Communication Process, IP %s connection(%d), PID = %d", (inet_ntoa(clientInfo.sin_addr)), socketIndex, getpid());
+
+    GetClockTime(&_MCabinet_timeout);
+    while(1)
+    {
+        if((rxLen = recv(socketFd, &dataBuffer[0], MAX_DATA_BUFFER_LEN, MSG_DONTWAIT )) > 0)
+        {
+            packetCnt = BufferRePacket(rxLen, &dataBuffer[0], &packetBuffer[0]);
+
+            if(packetCnt > 0)
+            {
+                //LOG_INFO("Socket[%d] %d packet received", socketIndex, packetCnt);
+                for(int i = 0; i < packetCnt; i++)
+                {
+                    //ShowSocketData(&packetBuffer[i]);
+                    MCabinetPacketHandler(socketFd, socketIndex, &packetBuffer[i]);
+                }
+
+                if(ShmChargerInfo->CabinetConnInfo[socketIndex].Status == _SCONN_MATCHED)
+                {
+                    // clear timeout value
+                    GetClockTime(&_MCabinet_timeout);
+                }
+            }
+        }
+        else
+        {
+            usleep((SOCKET_RECEIVE_INTERVAL * 1000));
+        }
+
+        if(GetTimeoutValue(_MCabinet_timeout) / uSEC_VAL >= MASTER_SLAVE_CABINET_TIMEOUT)
+        {
+            //timeout
+            LOG_INFO("Slave Cabinet IP: %s, Socket %d Communication Timeout", (inet_ntoa(clientInfo.sin_addr)), socketIndex);
+            if(ShmChargerInfo->CabinetConnInfo[socketIndex].Status == _SCONN_MATCHED)
+            {
+                SetSlaveCabinetStatus(ShmChargerInfo->CabinetConnInfo[socketIndex].DeviceIndex, _DS_Timeout);
+                SlaveCabinetCheckInUpdate();
+            }
+            break;
+        }
+
+        if(ShmChargerInfo->CabinetConnInfo[socketIndex].Status == _SCONN_MATCHED)
+        {
+            if(ShmChargerInfo->ParallelCabinet.PCabinet[ShmChargerInfo->CabinetConnInfo[socketIndex].DeviceIndex].IpDuplicatedFlag == true)
+            {
+                LOG_INFO("Slave Cabinet %d has been kick", ShmChargerInfo->CabinetConnInfo[socketIndex].DeviceIndex + 1);
+                SetSlaveCabinetStatus(ShmChargerInfo->CabinetConnInfo[socketIndex].DeviceIndex, _DS_Timeout);
+                SlaveCabinetCheckInUpdate();
+                break;
+            }
+        }
+    }
+}
+
+void InitMasterCabinetInfo(void)
+{
+    for(int i = 0; i < MAX_SLAVE_CABINET_QUANTITY; i++)
+    {
+        memset(&SlaveWarningInfo[i], 0x00, sizeof(struct WARNING_CODE_INFO));
+    }
+}
+
+bool IsReadyAcceptSlaveCabinet(void)
+{
+    bool ready = true;
+
+    for(int i = 0; i < ShmChargerInfo->Control.MaxConnector; i++)
+    {
+        if (chargingInfo[i]->SystemStatus != S_IDLE && chargingInfo[i]->SystemStatus != S_MAINTAIN)
+        {
+            ready = false;
+            break;
+        }
+    }
+
+    return ready;
+}
+
+int MasterCabinetProcess(void)
+{
+    int sockFd = 0;
+    int clientSockFd = 0;
+    int connIndex = 0;
+    int bindStatus = 0;
+    int reuseaddr = 1;
+    pid_t forkId;
+    bool isConflict = false, isReady = false, preReady = false;
+
+    struct sockaddr_in  serverInfo, clientInfo;
+    socklen_t           addrlen = sizeof(clientInfo);
+
+    sockFd = socket(AF_INET, SOCK_STREAM, 0);
+    if(sockFd == -1)
+    {
+        LOG_INFO("InitSocketServer NG\n");
+        sleep(5);
+        return FAIL;
+    }
+
+    setsockopt(sockFd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr));
+
+    InitMasterCabinetInfo();
+
+    bzero(&serverInfo,sizeof(serverInfo));
+    serverInfo.sin_family = PF_INET;
+    serverInfo.sin_addr.s_addr = htonl(INADDR_ANY);
+    serverInfo.sin_port = htons(MASTER_TCP_LISTEN_PORT);
+    bindStatus = bind(sockFd, (struct sockaddr *)&serverInfo, sizeof(serverInfo));
+    if(bindStatus < 0)
+    {
+        LOG_INFO("Master Cabinet socket bind fail");
+        return FAIL;
+    }
+    listen(sockFd, CONNECTION_LIMIT);
+
+    LOG_INFO("Master Cabinet Server Start");
+
+    signal(SIGCHLD, SIG_IGN);
+
+    if(ConflictedCabinetCheck() <= 0)
+    {
+        // child process return here
+        return 0;
+    }
+
+    // Main loop
+    while(1)
+    {
+        clientSockFd = accept(sockFd, (struct sockaddr*) &clientInfo, &addrlen);
+
+        isReady = IsReadyAcceptSlaveCabinet();
+        if(isReady)
+        {
+            LOG_INFO("Slave Cabinet ip: %s is accepted at port: %d", inet_ntoa(clientInfo.sin_addr), clientInfo.sin_port);
+        }
+        else
+        {
+            // not ready
+            if(preReady != isReady)
+            {
+                LOG_INFO("MCabinet Is Not Ready To Paralleling");
+            }
+            close(clientSockFd);
+            preReady = isReady;
+            continue;
+        }
+        preReady = isReady;
+
+        connIndex = GetFreeSocketChannel(ShmChargerInfo->CabinetConnInfo, ARRAY_SIZE(ShmChargerInfo->CabinetConnInfo));
+        if(connIndex >= 0)
+        {
+            isConflict = IsConflictCabinetIp(clientInfo.sin_addr.s_addr);
+
+            if(isConflict == false)
+            {
+                ShmChargerInfo->CabinetConnInfo[connIndex].Status = _SCONN_WAIT;
+                ShmChargerInfo->CabinetConnInfo[connIndex].IpAddress = clientInfo.sin_addr.s_addr;
+
+                forkId = fork();
+                if(forkId == 0)
+                {
+                    // child process
+                    MCabinetCommProcess(clientSockFd, clientInfo, connIndex);
+                    close(clientSockFd);
+                    memset(&ShmChargerInfo->CabinetConnInfo[connIndex], 0x00, sizeof(SocketConnInfoData));
+                    return 0;
+                }
+                else if(forkId == -1)
+                {
+                    LOG_INFO("Slave Cabinet Process Fork Fail");
+                }
+            }
+            else
+            {
+                if(isConflict)
+                {
+                    // conflict ip address
+                    LOG_INFO("Conflict Slave Cabinet IP address, Close Socket");
+                }
+                close(clientSockFd);
+                memset(&ShmChargerInfo->CabinetConnInfo[connIndex], 0x00, sizeof(SocketConnInfoData));
+            }
+        }
+        else
+        {
+            // no free channel
+            LOG_INFO("No Free Cabinet Channel, Close Socket");
+            close(clientSockFd);
+        }
+
+        usleep(10000);
+    }
+
+    return 0;
+}
+
+// ****************************** Slave ****************************** //
+unsigned char _modelNameAck = 0;
+unsigned char _idAck = 0;
+unsigned char _header_SE = 0;
+
+struct timespec _regQreuyTime[PARALLEL_CABINET_REG_QUANTITY];
+
+int _regTimeout[PARALLEL_CABINET_REG_QUANTITY] =
+{
+    REG_RSEND_TIME_NONE,                // reg: 0x00
+    REG_RSEND_TIME_MODELNAME,           // reg: 0x01
+    REG_RSEND_TIME_ID,                  // reg: 0x02
+    REG_RSEND_TIME_REG03,               // reg: 0x03
+    REG_RSEND_TIME_STATUS,              // reg: 0x04
+    REG_RSEND_TIME_OUTPUT_RELAY,        // reg: 0x05
+    REG_RSEND_TIME_AC_CONTACTOR,        // reg: 0x06
+    REG_RSEND_TIME_UPDATE,              // reg: 0x07
+    REG_RSEND_TIME_PARALLEL_RELAY,      // reg: 0x08
+};
+
+int ConnectToMasterCabinet(void)
+{
+    int sockFd = 0;
+    struct sockaddr_in serverInfo;
+    struct timeval tv;
+
+    sockFd = socket(AF_INET, SOCK_STREAM, 0);
+    if(sockFd < 0)
+    {
+        LOG_INFO("Create Slave Cabinet Socket Fail");
+        return -1;
+    }
+
+    tv.tv_sec = 3;
+    tv.tv_usec = 0;
+    setsockopt(sockFd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)); //設定等待3s
+    setsockopt(sockFd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval));  //設定傳送3s
+
+    bzero(&serverInfo,sizeof(serverInfo));
+    serverInfo.sin_family = AF_INET;
+    serverInfo.sin_addr.s_addr = inet_addr(MASTER_ETH1_IP);
+    serverInfo.sin_port = htons(MASTER_TCP_LISTEN_PORT);
+
+    if(connect(sockFd, (struct sockaddr *)&serverInfo, sizeof(serverInfo)) < 0)
+    {
+        //LOG_INFO("Connect To Master Cabinet Error[%d]", errno);
+        close(sockFd);
+        return -1;
+    }
+
+    return sockFd;
+}
+
+void SendParallelPacket(int fd, unsigned char opCode, unsigned char length, unsigned char reg, unsigned char *data)
+{
+    struct PACKET_STRUCTURE packet;
+
+    packet.Header.se = _header_SE++;
+    packet.Header.id = ShmChargerInfo->SCabinetControl.SCabinetID;
+    packet.Header.op = opCode;
+    packet.Header.len = length;
+    packet.Payload.reg = reg;
+
+    if(length > 1)
+    {
+        memcpy(packet.Payload.data, data, length - 1);
+    }
+
+    SendPacket(fd, &packet);
+}
+
+// reg: 0x01, Slave Cabinet Write Model Name
+void SCabinetWriteModelName(int fd)
+{
+    if(GetTimeoutValue(_regQreuyTime[_Reg_SCabinet_Model_Name]) / mSEC_VAL >= _regTimeout[_Reg_SCabinet_Model_Name])
+    {
+        SendParallelPacket(
+            fd,
+            _Header_Write,
+            strlen((char *)ShmSysConfigAndInfo->SysConfig.ModelName) + 1,
+            _Reg_SCabinet_Model_Name,
+            ShmSysConfigAndInfo->SysConfig.ModelName);
+
+        GetClockTime(&_regQreuyTime[_Reg_SCabinet_Model_Name]);
+        //LOG_INFO("SCabinet Write Model Nname...");
+    }
+}
+
+// reg: 0x01, Slave Cabinet Model Name Handler
+unsigned char SCabinetModelNameHandler(struct PACKET_STRUCTURE *packet)
+{
+    unsigned char ack = _R_NG;
+
+    if(packet->Header.len >= _regResLen[_Reg_SCabinet_Model_Name])
+    {
+        ack = packet->Payload.data[0] == _R_OK ? _R_OK : _R_NG;
+
+        if(_modelNameAck != ack)
+        {
+            LOG_INFO("SCabinet Write Model Name %s", ack == _R_OK ? "OK" : "NG");
+        }
+        _modelNameAck = ack;
+    }
+
+    return ack;
+}
+
+// reg: 0x02, Slave Cabinet Read ID
+void SCabinetReadID(int fd)
+{
+    if(GetTimeoutValue(_regQreuyTime[_Reg_SCabinet_ID]) / mSEC_VAL >= _regTimeout[_Reg_SCabinet_ID])
+    {
+        SendParallelPacket(
+            fd,
+            _Header_Read,
+            _regReqLen[_Reg_SCabinet_ID],
+            _Reg_SCabinet_ID,
+            0);
+
+        GetClockTime(&_regQreuyTime[_Reg_SCabinet_ID]);
+        //LOG_INFO("SCabinet Read ID...");
+    }
+}
+
+// reg: 0x02, Slave Cabinet ID Handler
+unsigned char SCabinetIDHandler(struct PACKET_STRUCTURE *packet)
+{
+    unsigned char ack = _R_NG;
+    unsigned char id = 0;
+
+    if(packet->Header.len >= _regResLen[_Reg_SCabinet_ID])
+    {
+        ack = packet->Payload.data[0] == _R_OK ? _R_OK : _R_NG;
+
+        if(ack == _R_OK)
+        {
+            id = packet->Payload.data[1];
+
+            if(ShmChargerInfo->SCabinetControl.SCabinetID != id && id != 0)
+            {
+                ShmChargerInfo->SCabinetControl.SCabinetID = id;
+                LOG_INFO("Get SCabinet ID: %d", ShmChargerInfo->SCabinetControl.SCabinetID);
+            }
+        }
+
+        if(_idAck != ack)
+        {
+            LOG_INFO("SCabinet Read ID %s", ack == _R_OK ? "OK" : "NG");
+        }
+    }
+
+    return ack;
+}
+
+// reg: 0x04
+void SCabinetWriteStatus(int fd)
+{
+    bool chagne = false;
+    unsigned char statusCode[256];
+
+    if(ShmSysConfigAndInfo->SysWarningInfo.WarningCount != SlaveWarningInfo[0].WarningCount)
+    {
+        chagne = true;
+    }
+    else
+    {
+        if(ShmSysConfigAndInfo->SysWarningInfo.WarningCount != 0)
+        {
+            for(int i = 0; i < ShmSysConfigAndInfo->SysWarningInfo.WarningCount; i++)
+            {
+                if(strcmp((char *)&SlaveWarningInfo[0].WarningCode[i][0], (char *)&ShmSysConfigAndInfo->SysWarningInfo.WarningCode[i][0]) != EQUAL)
+                {
+                    chagne = true;
+                    break;
+                }
+            }
+        }
+    }
+
+    if(chagne)
+    {
+        memcpy(&SlaveWarningInfo[0], &ShmSysConfigAndInfo->SysWarningInfo, sizeof(struct WARNING_CODE_INFO));
+    }
+
+    if(GetTimeoutValue(_regQreuyTime[_Reg_SCabinet_Status]) / mSEC_VAL >= _regTimeout[_Reg_SCabinet_Status] || chagne)
+    {
+        for(int i = 0; i < ShmSysConfigAndInfo->SysWarningInfo.WarningCount; i++)
+        {
+            memcpy(&statusCode[i * 6], &ShmSysConfigAndInfo->SysWarningInfo.WarningCode[i][0], 6);
+        }
+
+        SendParallelPacket(
+            fd,
+            _Header_Write,
+            (ShmSysConfigAndInfo->SysWarningInfo.WarningCount * 6) + 1,
+            _Reg_SCabinet_Status,
+            &statusCode[0]);
+
+        GetClockTime(&_regQreuyTime[_Reg_SCabinet_Status]);
+        //LOG_INFO("SCabinet Write Status...");
+    }
+}
+
+// reg: 0x04, Slave Cabinet Status Handler
+unsigned char SCabinetStatusHandler(struct PACKET_STRUCTURE *packet)
+{
+    unsigned char ack = _R_NG;
+
+    if(packet->Header.id != ShmChargerInfo->SCabinetControl.SCabinetID)
+    {
+        return ack;
+    }
+    if(packet->Header.len >= _regResLen[_Reg_SCabinet_Status])
+    {
+        ack = packet->Payload.data[0] == _R_OK ? _R_OK : _R_NG;
+    }
+
+    return ack;
+}
+
+// reg: 0x05
+void SCabinetReadOutputRelay(int fd)
+{
+    unsigned char outputRelay[GENERAL_GUN_QUANTITY] = {0};
+
+    if(GetTimeoutValue(_regQreuyTime[_Reg_OutputRelay_Status]) / mSEC_VAL >= _regTimeout[_Reg_OutputRelay_Status])
+    {
+        memcpy(&outputRelay[0], &ShmChargerInfo->SCabinetControl.SOutputRelay[0], GENERAL_GUN_QUANTITY);
+
+        SendParallelPacket(
+            fd,
+            _Header_Read,
+            _regReqLen[_Reg_OutputRelay_Status],
+            _Reg_OutputRelay_Status,
+            &outputRelay[0]);
+
+        GetClockTime(&_regQreuyTime[_Reg_OutputRelay_Status]);
+        //LOG_INFO("SCabinet Read OutputRelay...");
+    }
+}
+
+// reg: 0x05, Slave Cabinet Output Relay Handler
+unsigned char SCabinetOutputRelayHandler(struct PACKET_STRUCTURE *packet)
+{
+    bool chagne = false;
+    unsigned char ack = _R_NG;
+
+    if(packet->Header.id != ShmChargerInfo->SCabinetControl.SCabinetID)
+    {
+        return ack;
+    }
+    if(packet->Header.len >= _regResLen[_Reg_OutputRelay_Status])
+    {
+        ack = packet->Payload.data[0] == _R_OK ? _R_OK : _R_NG;
+
+        if(ack == _R_OK)
+        {
+            for(int i = 0; i < GENERAL_GUN_QUANTITY; i++)
+            {
+                if(packet->Payload.data[i + 1] != ShmChargerInfo->SCabinetControl.SOutputRelay[i])
+                {
+                    chagne = true;
+                }
+            }
+
+            memcpy(&ShmChargerInfo->SCabinetControl.SOutputRelay[0], &packet->Payload.data[1], GENERAL_GUN_QUANTITY);
+
+            if(chagne)
+            {
+                LOG_INFO("SCabinet[%d] Need Set OutputRelay: %3s %3s %3s %3s",
+                    ShmChargerInfo->SCabinetControl.SCabinetID,
+                    ShmChargerInfo->SCabinetControl.SOutputRelay[0] > 0 ? "ON" : "OFF",
+                    ShmChargerInfo->SCabinetControl.SOutputRelay[1] > 0 ? "ON" : "OFF",
+                    ShmChargerInfo->SCabinetControl.SOutputRelay[2] > 0 ? "ON" : "OFF",
+                    ShmChargerInfo->SCabinetControl.SOutputRelay[3] > 0 ? "ON" : "OFF");
+            }
+        }
+    }
+
+    return ack;
+}
+
+// reg: 0x06
+void SCabinetReadAcContactor(int fd)
+{
+    unsigned char acContactor = 0;
+    if(GetTimeoutValue(_regQreuyTime[_Reg_AcContactor_Status]) / mSEC_VAL >= _regTimeout[_Reg_AcContactor_Status])
+    {
+        acContactor = ShmChargerInfo->SCabinetControl.SAcContactor;
+
+        SendParallelPacket(
+            fd,
+            _Header_Read,
+            _regReqLen[_Reg_AcContactor_Status],
+            _Reg_AcContactor_Status,
+            &acContactor);
+
+        GetClockTime(&_regQreuyTime[_Reg_AcContactor_Status]);
+        //LOG_INFO("SCabinet Read AcContactor...");
+    }
+}
+
+// reg: 0x06, Slave Cabinet Ac Contactor Handler
+unsigned char SCabinetAcContactorHandler(struct PACKET_STRUCTURE *packet)
+{
+    bool chagne = false;
+    unsigned char ack = _R_NG;
+
+    if(packet->Header.id != ShmChargerInfo->SCabinetControl.SCabinetID)
+    {
+        return ack;
+    }
+    if(packet->Header.len >= _regResLen[_Reg_AcContactor_Status])
+    {
+        ack = packet->Payload.data[0] == _R_OK ? _R_OK : _R_NG;
+
+        if(ack == _R_OK)
+        {
+            if(packet->Payload.data[1] != ShmChargerInfo->SCabinetControl.SAcContactor)
+            {
+                chagne = true;
+            }
+
+            ShmChargerInfo->SCabinetControl.SAcContactor = packet->Payload.data[1];
+
+            if(chagne)
+            {
+                LOG_INFO("SCabinet[%d] Need Set AC Contactor: %3s",
+                    ShmChargerInfo->SCabinetControl.SCabinetID,
+                    ShmChargerInfo->SCabinetControl.SAcContactor > 0 ? "ON" : "OFF");
+            }
+        }
+    }
+
+    return ack;
+}
+
+// reg: 0x07
+void SCabinetReadFwUpdate(int fd)
+{
+    bool chagne = false;
+
+    if(_SCabinetUpdateState != ShmChargerInfo->SCabinetControl.UpgradeState)
+    {
+        chagne = true;
+    }
+    _SCabinetUpdateState = ShmChargerInfo->SCabinetControl.UpgradeState;
+
+    if(GetTimeoutValue(_regQreuyTime[_Reg_SCabinet_FwUpdate]) / mSEC_VAL >= _regTimeout[_Reg_SCabinet_FwUpdate] || chagne)
+    {
+        SendParallelPacket(
+            fd,
+            _Header_Read,
+            _regReqLen[_Reg_SCabinet_FwUpdate],
+            _Reg_SCabinet_FwUpdate,
+            &_SCabinetUpdateState);
+
+        GetClockTime(&_regQreuyTime[_Reg_SCabinet_FwUpdate]);
+    }
+}
+
+// reg: 0x07, Slave Cabinet FW Update Handler
+unsigned char SCabinetFwUpdateHandler(struct PACKET_STRUCTURE *packet)
+{
+    bool chagne = false;
+    unsigned char update = _R_NoUpgrade;
+    unsigned char ack = _R_NG;
+    unsigned char image[128];
+
+    if(packet->Header.id != ShmChargerInfo->SCabinetControl.SCabinetID)
+    {
+        return ack;
+    }
+    if(packet->Header.len >= _regResLen[_Reg_SCabinet_FwUpdate])
+    {
+        ack = packet->Payload.data[0] == _R_OK ? _R_OK : _R_NG;
+
+        if(ack == _R_OK)
+        {
+            update = packet->Payload.data[1] == _R_NeedUpgrade ? _R_NeedUpgrade : _R_NoUpgrade;
+
+            if(update == _R_NeedUpgrade && ShmChargerInfo->SCabinetControl.UpgradeState == Not_Update)
+            {
+                if(packet->Header.len > _regResLen[_Reg_SCabinet_FwUpdate])
+                {
+                    memset(&image[0], 0x00, sizeof(image));
+                    memcpy(&image[0], &packet->Payload.data[2], packet->Header.len - _regResLen[_Reg_SCabinet_FwUpdate]);
+                }
+                else
+                {
+                    LOG_INFO("SCabinet[%d] %s image length fail: %d", ShmChargerInfo->SCabinetControl.SCabinetID, packet->Header.len);
+                    update = _R_NoUpgrade;
+                }
+            }
+
+            if(update != ShmChargerInfo->SCabinetControl.NeedUpgrade)
+            {
+                chagne = true;
+            }
+            ShmChargerInfo->SCabinetControl.NeedUpgrade = update;
+
+            if(chagne)
+            {
+                LOG_INFO("SCabinet[%d] Update Indicator [%s]", ShmChargerInfo->SCabinetControl.SCabinetID,
+                    ShmChargerInfo->SCabinetControl.NeedUpgrade == _R_NeedUpgrade ? "Need Upgrade" : "No Update");
+
+                if(ShmChargerInfo->SCabinetControl.UpgradeState == Not_Update &&
+                    ShmChargerInfo->SCabinetControl.NeedUpgrade == _R_NeedUpgrade)
+                {
+                    LOG_INFO("SCabinet[%d] Get Image: [%s]", ShmChargerInfo->SCabinetControl.SCabinetID, image);
+                    memcpy(ShmChargerInfo->SCabinetControl.FwFileName, image, sizeof(image));
+                    ShmSysConfigAndInfo->SysInfo.FirmwareUpdate = YES;
+                }
+
+                if(ShmChargerInfo->SCabinetControl.UpgradeState == Updated &&
+                    ShmChargerInfo->SCabinetControl.NeedUpgrade == _R_NoUpgrade)
+                {
+                    LOG_INFO("MCabinet & SCabinet[%d] upgrade completed", ShmChargerInfo->SCabinetControl.SCabinetID);
+                }
+            }
+        }
+    }
+
+    return ack;
+}
+
+// reg: 0x08
+void SCabinetReadParallelRelay(int fd)
+{
+    unsigned char parallelRelay[GENERAL_GUN_QUANTITY] = {0};
+
+    if(GetTimeoutValue(_regQreuyTime[_Reg_ParallelRelay_Status]) / mSEC_VAL >= _regTimeout[_Reg_ParallelRelay_Status])
+    {
+        memcpy(&parallelRelay[0], &ShmChargerInfo->SCabinetControl.SParallelRelay[0], GENERAL_GUN_QUANTITY);
+
+        SendParallelPacket(
+            fd,
+            _Header_Read,
+            _regReqLen[_Reg_ParallelRelay_Status],
+            _Reg_ParallelRelay_Status,
+            &parallelRelay[0]);
+
+        GetClockTime(&_regQreuyTime[_Reg_ParallelRelay_Status]);
+        //LOG_INFO("SCabinet Read ParallelRelay...");
+    }
+}
+
+// reg: 0x08, Slave Cabinet Parallel Relay Handler
+unsigned char SCabinetParallelRelayHandler(struct PACKET_STRUCTURE *packet)
+{
+    bool chagne = false;
+    unsigned char ack = _R_NG;
+
+    if(packet->Header.id != ShmChargerInfo->SCabinetControl.SCabinetID)
+    {
+        return ack;
+    }
+    if(packet->Header.len >= _regResLen[_Reg_ParallelRelay_Status])
+    {
+        ack = packet->Payload.data[0] == _R_OK ? _R_OK : _R_NG;
+
+        if(ack == _R_OK)
+        {
+            for(int i = 0; i < GENERAL_GUN_QUANTITY; i++)
+            {
+                if(packet->Payload.data[i + 1] != ShmChargerInfo->SCabinetControl.SParallelRelay[i])
+                {
+                    chagne = true;
+                }
+            }
+
+            memcpy(&ShmChargerInfo->SCabinetControl.SParallelRelay[0], &packet->Payload.data[1], GENERAL_GUN_QUANTITY);
+
+            if(chagne)
+            {
+                LOG_INFO("SCabinet[%d] Need Set ParallelRelay: %3s %3s %3s %3s",
+                    ShmChargerInfo->SCabinetControl.SCabinetID,
+                    ShmChargerInfo->SCabinetControl.SParallelRelay[0] > 0 ? "ON" : "OFF",
+                    ShmChargerInfo->SCabinetControl.SParallelRelay[1] > 0 ? "ON" : "OFF",
+                    ShmChargerInfo->SCabinetControl.SParallelRelay[2] > 0 ? "ON" : "OFF",
+                    ShmChargerInfo->SCabinetControl.SParallelRelay[3] > 0 ? "ON" : "OFF");
+            }
+        }
+    }
+
+    return ack;
+}
+
+void SCabinetPacketHandler(struct PACKET_STRUCTURE *packet)
+{
+    // Reg: 0x01, Dispenser model name
+    if(packet->Header.op == _Header_Response && packet->Payload.reg == _Reg_SCabinet_Model_Name)
+    {
+        SCabinetModelNameHandler(packet);
+    }
+    // Reg: 0x02, Slave Cabinet ID
+    if(packet->Header.op == _Header_Response && packet->Payload.reg == _Reg_SCabinet_ID)
+    {
+        SCabinetIDHandler(packet);
+    }
+
+    // Reg: 0x04, Slave Cabinet Status
+    if(packet->Header.op == _Header_Response && packet->Payload.reg == _Reg_SCabinet_Status)
+    {
+        SCabinetStatusHandler(packet);
+    }
+
+    // Reg: 0x05, Sync Output Relay Status
+    if(packet->Header.op == _Header_Response && packet->Payload.reg == _Reg_OutputRelay_Status)
+    {
+        SCabinetOutputRelayHandler(packet);
+    }
+
+    // Reg: 0x06, Sync Ac Contactor Status
+    if(packet->Header.op == _Header_Response && packet->Payload.reg == _Reg_AcContactor_Status)
+    {
+        SCabinetAcContactorHandler(packet);
+    }
+
+    // Reg: 0x07, Fw Update
+    if(packet->Header.op == _Header_Response && packet->Payload.reg == _Reg_SCabinet_FwUpdate)
+    {
+        SCabinetFwUpdateHandler(packet);
+    }
+
+    // Reg: 0x08, Sync Parallel Relay Status
+    if(packet->Header.op == _Header_Response && packet->Payload.reg == _Reg_ParallelRelay_Status)
+    {
+        SCabinetParallelRelayHandler(packet);
+    }
+}
+
+int SlaveCabinetProcess(void)
+{
+    int slavefd = 0, rxLen = 0, packetCnt = 0;
+    //struct PACKET_STRUCTURE receiveBuffer;
+    unsigned char dataBuffer[MAX_DATA_BUFFER_LEN];
+    struct PACKET_STRUCTURE packetBuffer[MAX_PACKET_BUFFER_LEN];
+
+    unsigned char Status = 0xFF, preStatus = 0xFF;
+    struct timespec _slaveCabinetStatus_time;
+    struct timespec _SCabinet_timeout;
+
+    ShmChargerInfo->SCabinetControl.SCabinetStatus = _DeviceStatus_DisConnect;
+    ShmChargerInfo->SCabinetControl.SCabinetID = 0xFF;
+    _modelNameAck = 0;
+    _idAck = 0;
+    _header_SE = 0;
+    ShmChargerInfo->SCabinetControl.SCabinetID = 0xFF;
+
+    slavefd = socket(AF_INET, SOCK_STREAM, 0);
+    if (slavefd == -1)
+    {
+        LOG_INFO("Create Slave Cabinet Socket Fail");
+        return -1;
+    }
+    LOG_INFO("Slave Cabinet Client Start, PID = %d", getpid());
+
+    while(1)
+    {
+        // **************************************** transmit ****************************************
+        Status = ShmChargerInfo->SCabinetControl.SCabinetStatus;
+
+        //LOG_INFO("SCabinet Status: %d", Status);
+        switch(Status)
+        {
+            case _DeviceStatus_DisConnect:
+                if(preStatus != Status)
+                {
+                    _modelNameAck = 0;
+                    _idAck = 0;
+                    _header_SE = 0x00;
+                    ShmChargerInfo->SCabinetControl.SCabinetID = 0xFF;
+                    memset(&SlaveWarningInfo[0], 0x00, sizeof(struct WARNING_CODE_INFO));
+
+                    LOG_INFO("Slave Cabinet [Disconnect]");
+                    GetClockTime(&_slaveCabinetStatus_time);
+                }
+                slavefd = ConnectToMasterCabinet();
+                if(slavefd > 0)
+                {
+                    GetClockTime(&_SCabinet_timeout);
+                    ShmChargerInfo->SCabinetControl.SCabinetStatus = _DeviceStatus_Identification;
+                    LOG_INFO("Connecting to MCabinet...");
+                    break;
+                }
+
+                if(GetTimeoutValue(_slaveCabinetStatus_time) / uSEC_VAL >= DISCONNECT_PROMPT)
+                {
+                    LOG_INFO("SCabinet Connecting...");
+                    GetClockTime(&_slaveCabinetStatus_time);
+                }
+                break;
+            case _DeviceStatus_Identification:
+                if(preStatus != Status)
+                {
+                    _modelNameAck = 0;
+                    _idAck = 0;
+                    _header_SE = 0x00;
+                    ShmChargerInfo->SCabinetControl.SCabinetID = 0xFF;
+                    memset(&SlaveWarningInfo[0], 0x00, sizeof(struct WARNING_CODE_INFO));
+                    GetClockTime(&_SCabinet_timeout);
+
+                    LOG_INFO("Slave Cabinet [Identification]");
+                    GetClockTime(&_slaveCabinetStatus_time);
+                }
+
+                if(_modelNameAck != _R_OK)
+                {
+                    SCabinetWriteModelName(slavefd);
+                }
+                if(ShmChargerInfo->SCabinetControl.SCabinetID == 0xFF || ShmChargerInfo->SCabinetControl.SCabinetID == 0)
+                {
+                    SCabinetReadID(slavefd);
+                }
+
+                if(_modelNameAck == _R_OK && ShmChargerInfo->SCabinetControl.SCabinetID != 0xFF && ShmChargerInfo->SCabinetControl.SCabinetID != 0)
+                {
+                    ShmChargerInfo->SCabinetControl.SCabinetStatus = _DeviceStatus_Idle;
+                }
+                break;
+            case _DeviceStatus_Idle:
+                if(preStatus != Status)
+                {
+                    LOG_INFO("Slave Cabinet [Idle]");
+                    GetClockTime(&_slaveCabinetStatus_time);
+                }
+
+                SCabinetWriteStatus(slavefd);
+                SCabinetReadOutputRelay(slavefd);
+                SCabinetReadAcContactor(slavefd);
+                SCabinetReadFwUpdate(slavefd);
+                SCabinetReadParallelRelay(slavefd);
+                break;
+            case _DeviceStatus_Alarm:
+                if(preStatus != Status)
+                {
+                    LOG_INFO("Slave Cabinet [Alarm]");
+                    GetClockTime(&_slaveCabinetStatus_time);
+                }
+                break;
+            case _DeviceStatus_Charging:
+                break;
+            case _DeviceStatus_Timeout:
+                if(preStatus != Status)
+                {
+                    LOG_INFO("Slave Cabinet Retry [Timeout]");
+                    GetClockTime(&_slaveCabinetStatus_time);
+                }
+                ShmChargerInfo->SCabinetControl.SCabinetStatus = _DeviceStatus_RetryWait;
+                break;
+            case _DeviceStatus_RetryWait:
+                if(preStatus != Status)
+                {
+                    LOG_INFO("Slave Cabinet Retry [Wait]");
+                    GetClockTime(&_slaveCabinetStatus_time);
+                }
+
+                if(GetTimeoutValue(_slaveCabinetStatus_time) / uSEC_VAL >= 3)
+                {
+                    ShmChargerInfo->SCabinetControl.SCabinetStatus = _DeviceStatus_DisConnect;
+                }
+                break;
+            default:
+                break;
+        }
+        preStatus = Status;
+
+        // **************************************** receive  ****************************************
+        if(ShmChargerInfo->SCabinetControl.SCabinetStatus != _DeviceStatus_DisConnect &&
+            ShmChargerInfo->SCabinetControl.SCabinetStatus != _DeviceStatus_Timeout &&
+            ShmChargerInfo->SCabinetControl.SCabinetStatus != _DeviceStatus_RetryWait)
+        {
+            if((rxLen = recv(slavefd, &dataBuffer[0], MAX_DATA_BUFFER_LEN, MSG_DONTWAIT )) > 0)
+            {
+                packetCnt = BufferRePacket(rxLen, &dataBuffer[0], &packetBuffer[0]);
+
+                if(packetCnt > 0)
+                {
+                    //LOG_INFO("SCabinet %d packet received", packetCnt);
+                    for(int i = 0; i < packetCnt; i++)
+                    {
+                        //ShowSocketData(&packetBuffer[i]);
+                        SCabinetPacketHandler(&packetBuffer[i]);
+                    }
+
+                    // clear timeout value
+                    GetClockTime(&_SCabinet_timeout);
+                }
+            }
+        }
+
+        // **************************************** timeout  ****************************************
+        if(ShmChargerInfo->SCabinetControl.SCabinetStatus != _DeviceStatus_DisConnect &&
+            ShmChargerInfo->SCabinetControl.SCabinetStatus != _DeviceStatus_Timeout &&
+            ShmChargerInfo->SCabinetControl.SCabinetStatus != _DeviceStatus_RetryWait)
+        {
+            if(GetTimeoutValue(_SCabinet_timeout) / uSEC_VAL >= MASTER_SLAVE_CABINET_TIMEOUT)
+            {
+                if(slavefd > 0)
+                {
+                    close(slavefd);
+                }
+                LOG_INFO("SCabinet timeout, close socket...");
+                ShmChargerInfo->SCabinetControl.SCabinetStatus = _DeviceStatus_Timeout;
+            }
+        }
+        usleep((SOCKET_RECEIVE_INTERVAL * 1000));
+    }
+
+    return 0;
+}
+
+int main(void)
+{
+    if(InitShareMemory() == FAIL)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("InitShareMemory NG");
+        #endif
+
+        sleep(5);
+        return 0;
+    }
+
+    InitialConnector();
+
+    // wait for self test completed
+    while(ShmSysConfigAndInfo->SysInfo.BootingStatus == BOOTTING ||
+        ShmSysConfigAndInfo->SysInfo.SelfTestSeq != _STEST_COMPLETE ||
+        ShmChargerInfo->Control.CabinetRole == _CROLE_SINGLE)
+    {
+        sleep(1);
+    }
+
+    if(ShmChargerInfo->Control.CabinetRole == _CROLE_MASTER)
+    {
+        MasterCabinetProcess();
+    }
+    else if(ShmChargerInfo->Control.CabinetRole == _CROLE_SLAVE)
+    {
+        SlaveCabinetProcess();
+    }
+
+    return 0;
+}

+ 76 - 0
EVSE/Projects/DO360/Apps/Module_CabinetParallel.h

@@ -0,0 +1,76 @@
+/*
+ * Module_CabinetParallel.h
+ *
+ *  Created on: 2021年9月28日
+ *      Author: 7978
+ */
+
+#ifndef MODULE_CABINETPARALLEL_H_
+#define MODULE_CABINETPARALLEL_H_
+
+#define MASTER_SLAVE_CABINET_TIMEOUT    10
+#define SLAVE_RECONNECT_TIME            5           // unit: 1s
+#define MASTER_TCP_LISTEN_PORT          63000
+#define DISCONNECT_PROMPT               300         // unit: 1s
+#define MAX_DATA_BUFFER_LEN             4096
+#define MAX_PACKET_BUFFER_LEN           10
+
+#define PARALLEL_CABINET_REG_QUANTITY   9
+
+#define REG_RSEND_TIME_NONE             0           // unit: 1ms
+#define REG_RSEND_TIME_MODELNAME        3000        // unit: 1ms
+#define REG_RSEND_TIME_ID               3000        // unit: 1ms
+#define REG_RSEND_TIME_REG03            0           // unit: 1ms
+#define REG_RSEND_TIME_STATUS           1000        // unit: 1ms
+#define REG_RSEND_TIME_OUTPUT_RELAY     500         // unit: 1ms
+#define REG_RSEND_TIME_AC_CONTACTOR     500         // unit: 1ms
+#define REG_RSEND_TIME_UPDATE           10000       // unit: 1ms
+#define REG_RSEND_TIME_PARALLEL_RELAY   5000        // unit: 1ms
+
+#define REG_REQ_LEN_NONE                0
+#define REG_REQ_LEN_MODELNAME           0
+#define REG_REQ_LEN_ID                  1
+#define REG_REQ_LEN_REG03               0
+#define REG_REQ_LEN_STATUS              0
+#define REG_REQ_LEN_OUTPUT_RELAY        5
+#define REG_REQ_LEN_AC_CONTACTOR        2
+#define REG_REQ_LEN_UPDATE              2
+#define REG_REQ_LEN_PARALLEL_RELAY      5
+
+#define REG_RES_LEN_NONE                0
+#define REG_RES_LEN_MODELNAME           2
+#define REG_RES_LEN_ID                  3
+#define REG_RES_LEN_REG03               0
+#define REG_RES_LEN_STATUS              2
+#define REG_RES_LEN_OUTPUT_RELAY        6
+#define REG_RES_LEN_AC_CONTACTOR        3
+#define REG_RES_LEN_UPDATE              3
+#define REG_RES_LEN_PARALLEL_RELAY      6
+
+enum PARALLEL_CABINET_PAYLOAD_REGISTER
+{
+    _Reg_SCabinet_None              = 0x00,
+    _Reg_SCabinet_Model_Name        = 0x01,
+    _Reg_SCabinet_ID                = 0x02,
+    _Reg_SCabinet_Reg03             = 0x03,
+    _Reg_SCabinet_Status            = 0x04,
+    _Reg_OutputRelay_Status         = 0x05,
+    _Reg_AcContactor_Status         = 0x06,
+    _Reg_SCabinet_FwUpdate          = 0x07,
+    _Reg_ParallelRelay_Status       = 0x08,
+};
+
+enum RELAY_STATUS
+{
+    Relay_OFF                       = 0x00,
+    Relay_ON                        = 0x01,
+};
+
+enum UPDATE_STATUS
+{
+    Not_Update                      = 0x00,
+    Updating                        = 0x01,
+    Updated                         = 0x02,
+};
+
+#endif /* MODULE_CABINETPARALLEL_H_ */

+ 657 - 0
EVSE/Projects/DO360/Apps/Module_ChargerSelfTest.c

@@ -0,0 +1,657 @@
+/*
+ * Module_ChargerSelfTest.c
+ *
+ *  Created on: 2021年9月24日
+ *      Author: 7978
+ */
+
+#include    <sys/time.h>
+#include    <sys/timeb.h>
+#include    <sys/types.h>
+#include    <sys/stat.h>
+#include    <sys/types.h>
+#include    <sys/ioctl.h>
+#include    <sys/socket.h>
+#include    <sys/ipc.h>
+#include    <sys/shm.h>
+#include    <sys/shm.h>
+#include    <sys/mman.h>
+#include    <linux/can.h>
+#include    <linux/can/raw.h>
+#include    <linux/wireless.h>
+#include    <arpa/inet.h>
+#include    <netinet/in.h>
+
+#include    <unistd.h>
+#include    <stdarg.h>
+#include    <stdio.h>      /*標準輸入輸出定義*/
+#include    <stdlib.h>     /*標準函數庫定義*/
+#include    <unistd.h>     /*Unix 標準函數定義*/
+#include    <fcntl.h>      /*檔控制定義*/
+#include    <termios.h>    /*PPSIX 終端控制定義*/
+#include    <errno.h>      /*錯誤號定義*/
+#include    <errno.h>
+#include    <string.h>
+#include    <time.h>
+#include    <ctype.h>
+#include    <ifaddrs.h>
+#include    <signal.h>
+#include    <net/if_arp.h>
+#include    "../../define.h"
+#include    "Module_ChargerSelfTest.h"
+#include    "Config.h"
+#include    "Common.h"
+
+#define     SELFTEST_TIMEOUT        60                  // unit: 1s
+#define     VERSION_RETRY_TIMEOUT   180                 // unit: 1s
+#define     CABINET_ROLE_TIMEOUT    3                   // unit: 1s
+#define     PSU_SELF_TIMEOUT        60                  // unit: 1s
+#define     PSU_RETRY_TIMEOUT       60                  // unit: 1s
+#define     MAX_PSU_RETRY_CNT       3
+
+struct SysConfigAndInfo         *ShmSysConfigAndInfo;
+struct StatusCodeData           *ShmStatusCodeData;
+struct PsuData                  *ShmPsuData;
+struct PrimaryMcuData           *ShmPrimaryMcuData;
+struct FanModuleData            *ShmFanModuleData;
+struct RelayModuleData          *ShmRelayModuleData[2];
+struct LedModuleData            *ShmLedModuleData;
+ChargerInfoData                 *ShmChargerInfo;
+PsuGroupCollectionData          *ShmGroupCollection;
+struct OCPP16Data               *ShmOCPP16Data;
+struct OCPP20Data               *ShmOCPP20Data;
+
+int InitShareMemory(void)
+{
+    int result = PASS;
+    int MeterSMId;
+
+    //creat ShmSysConfigAndInfo
+    if ((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo), 0777)) < 0)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmget ShmSysConfigAndInfo NG");
+        #endif
+        result = FAIL;
+    }
+    else if ((ShmSysConfigAndInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmat ShmSysConfigAndInfo NG");
+        #endif
+        result = FAIL;
+     }
+    else
+    {
+
+    }
+
+    // initial status code share memory
+    if ((MeterSMId = shmget(ShmStatusCodeKey, sizeof(struct StatusCodeData), 0777)) < 0)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("[main]CreatShareMemory:shmget ShmStatusCodeData NG");
+        #endif
+        return 0;
+    }
+    else if ((ShmStatusCodeData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("[main]CreatShareMemory:shmat ShmStatusCodeData NG");
+        #endif
+        return 0;
+    }
+
+    // initial psu share memory
+    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;
+    }
+
+    // initial DO360 RC1 share memory
+    if ((MeterSMId = shmget(ShmRelayBdKey, sizeof(struct RelayModuleData), 0777)) < 0)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmget ShmRelayModuleData NG");
+        #endif
+        result = FAIL;
+    }
+    else if ((ShmRelayModuleData[0] = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmat ShmRelayModuleData NG");
+        #endif
+        result = FAIL;
+    }
+
+    // initial DO360 RC2 share memory
+    if ((MeterSMId = shmget(ShmRelay2BdKey, sizeof(struct RelayModuleData), 0777)) < 0)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmget ShmRelay2ModuleData NG");
+        #endif
+        result = FAIL;
+    }
+    else if ((ShmRelayModuleData[1] = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmat ShmRelay2ModuleData NG");
+        #endif
+        result = FAIL;
+    }
+
+    // initial fan board share memory
+    if ((MeterSMId = shmget(ShmFanBdKey, sizeof(struct FanModuleData), 0777)) < 0)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmget ShmFanModuleData NG");
+        #endif
+        result = FAIL;
+    }
+    else if ((ShmFanModuleData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmat ShmFanModuleData NG");
+        #endif
+        result = FAIL;
+    }
+
+    // initial led board share memory
+    if ((MeterSMId = shmget(ShmLedBdKey, sizeof(struct LedModuleData), 0777)) < 0)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmget ShmLedModuleData NG");
+        #endif
+        result = FAIL;
+    }
+    else if ((ShmLedModuleData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmat ShmLedModuleData NG");
+        #endif
+        result = FAIL;
+    }
+
+    // initial primary share memory
+    if ((MeterSMId = shmget(ShmPrimaryMcuKey, sizeof(struct PrimaryMcuData), 0777)) < 0)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmget ShmPrimaryMcuData NG");
+        #endif
+        result = FAIL;
+    }
+    else if ((ShmPrimaryMcuData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmat ShmPrimaryMcuData NG");
+        #endif
+        result = FAIL;
+    }
+
+    if ((MeterSMId = shmget(SM_ChargerInfoKey, sizeof(ChargerInfoData), 0777)) < 0)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmat ChargerInfoData NG");
+        #endif
+        result = FAIL;
+    }
+    else if ((ShmChargerInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmat ChargerInfoData NG");
+        #endif
+        result = FAIL;
+    }
+
+    if ((MeterSMId = shmget(ShmOcppModuleKey, sizeof(struct OCPP16Data), 0777)) < 0)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmat ShmOCPP16Data NG");
+        #endif
+        result = FAIL;
+    }
+    else if ((ShmOCPP16Data = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        LOG_ERROR("shmat ShmOCPP16Data NG");
+        result = FAIL;
+    }
+
+    if ((MeterSMId = shmget(ShmOcpp20ModuleKey, sizeof(struct OCPP20Data), 0777)) < 0)
+    {
+        LOG_ERROR("[main]CreatShareMemory:shmget OCPP20Data NG\n");
+        result = FAIL;
+    }
+    else if ((ShmOCPP20Data = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        LOG_ERROR("[main]CreatShareMemory:shmat OCPP20Data NG\n");
+        result = FAIL;
+    }
+
+    if(result == PASS)
+    {
+        ShmGroupCollection = &ShmChargerInfo->PsuGrouping.GroupCollection[0];
+    }
+
+    return result;
+}
+
+void SetSelfTestSate(unsigned char selfTest)
+{
+    if(ShmSysConfigAndInfo->SysInfo.BootingStatus != BOOT_COMPLETE || selfTest == _STEST_FAIL)
+    {
+        ShmSysConfigAndInfo->SysInfo.SelfTestSeq = selfTest;
+    }
+    ShmChargerInfo->Control.SelfTestStep = selfTest;
+}
+
+int main(void)
+{
+    if(InitShareMemory() == FAIL)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("InitShareMemory NG");
+        #endif
+
+        sleep(5);
+        return 0;
+    }
+
+    bool _selfTestTimeout = false, _versionCheck = false, _switchCheck = false, _emgBtn = false;
+    char _selfTest = 0, _preTest = -1, psuRetryCnt = 0;
+    struct timespec _SelfTest_time, _TestStep_time;
+
+    LOG_INFO("Charger Start Self Test...");
+    ShmChargerInfo->Control.SysCtrl.bits.NeedSelfTest = YES;
+    GetClockTime(&_SelfTest_time);
+    ShmChargerInfo->Control.SelfTestStep = ShmSysConfigAndInfo->SysInfo.SelfTestSeq != _STEST_FAIL ?
+        ShmSysConfigAndInfo->SysInfo.SelfTestSeq : _STEST_VERSION;
+
+    while(1)
+    {
+        if(!ShmChargerInfo->Control.SysCtrl.bits.NeedSelfTest)
+        {
+            sleep(1);
+            continue;
+        }
+
+        if(!_selfTestTimeout)
+        {
+            if(ShmSysConfigAndInfo->SysInfo.FirmwareUpdate == YES || ShmOCPP16Data->MsMsg.bits.UpdateFirmwareReq == YES)
+            {
+                _selfTestTimeout = true;
+                LOG_INFO("Charger need firmware upgrade, stop self test!");
+            }
+            else if(ShmPrimaryMcuData->InputDet.bits.EmergencyButton == ABNORMAL)
+            {
+                _selfTestTimeout = true;
+                _emgBtn = true;
+                LOG_INFO("Emergency button is pressed, stop self test!");
+            }
+        }
+
+        _selfTest = ShmChargerInfo->Control.SelfTestStep;
+
+        switch(_selfTest)
+        {
+            case _STEST_VERSION:
+                if(_preTest != _selfTest)
+                {
+                    GetClockTime(&_TestStep_time);
+                    LOG_INFO("SelfTest Process [VersionTest]");
+                }
+
+                if ((ShmChargerInfo->Control.SysCtrl.bits.FanBoardDisable || ShmFanModuleData->SelfTest_Comp) &&
+                    (ShmChargerInfo->Control.SysCtrl.bits.RelayBoardDisable || ShmRelayModuleData[0]->SelfTest_Comp) &&
+                    (ShmChargerInfo->Control.SysCtrl.bits.RelayBoardDisable ||
+                    ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable == false ||
+                    ShmRelayModuleData[1]->SelfTest_Comp) &&
+                    ShmPrimaryMcuData->SelfTest_Comp)
+                {
+                    _versionCheck = true;
+
+                    if(!_switchCheck)
+                    {
+                        SetSelfTestSate(_STEST_CabinetSwitch);
+                        LOG_INFO("Self test version check ok");
+                    }
+                    else
+                    {
+                        // bypass cabinet switch detection
+                        SetSelfTestSate(_STEST_FAIL);
+                        LOG_INFO("VersionTest OK, Soft Reset And Retry!");
+                    }
+                }
+                else
+                {
+                    if(_selfTestTimeout)
+                    {
+                        if(_switchCheck)
+                        {
+                            // self test timeout, set status code for timeout reason
+                            if(!ShmChargerInfo->Control.SysCtrl.bits.FanBoardDisable && !ShmFanModuleData->SelfTest_Comp)
+                            {
+                                if(ShmStatusCodeData->AlarmCode.AlarmEvents.bits.FanboardStestFail == NO)
+                                {
+                                    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.FanboardStestFail = YES;
+                                    LOG_INFO("FanBoard Self Test Fail!");
+                                }
+                            }
+
+                            if((!ShmChargerInfo->Control.SysCtrl.bits.RelayBoardDisable && !ShmRelayModuleData[0]->SelfTest_Comp) ||
+                            (!ShmChargerInfo->Control.SysCtrl.bits.RelayBoardDisable && ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable && !ShmRelayModuleData[1]->SelfTest_Comp))
+                            {
+                                if(ShmStatusCodeData->AlarmCode.AlarmEvents.bits.RelayboardStestFail == NO)
+                                {
+                                    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.RelayboardStestFail = YES;
+                                    LOG_INFO("RelayBoard Self Test Fail!");
+                                }
+                            }
+
+                            if(!ShmPrimaryMcuData->SelfTest_Comp)
+                            {
+                                if(ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PrimaryStestFail == NO)
+                                {
+                                    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PrimaryStestFail = YES;
+                                    LOG_INFO("Primary Self Test Fail!");
+                                }
+                            }
+
+                            if(ShmSysConfigAndInfo->SysInfo.BootingStatus != BOOT_COMPLETE)
+                            {
+                                LOG_INFO("Booting Completed, Version Self Test Fail!");
+                            }
+                            ShmSysConfigAndInfo->SysInfo.SelfTestSeq = _STEST_FAIL;
+                            ShmSysConfigAndInfo->SysInfo.BootingStatus = BOOT_COMPLETE;
+
+                            if(GetTimeoutValue(_TestStep_time) / uSEC_VAL >= VERSION_RETRY_TIMEOUT)
+                            {
+                                // bypass cabinet switch detection
+                                SetSelfTestSate(_STEST_FAIL);
+                                LOG_INFO("Version check still timeout, try soft reset and retry!");
+                            }
+                        }
+                        else
+                        {
+                            SetSelfTestSate(_STEST_CabinetSwitch);
+                            LOG_INFO("Version Self Test Timeout, Need Check Cabinet Switch Value");
+                        }
+                    }
+                }
+                break;
+
+            case _STEST_CabinetSwitch:
+                if(_preTest != _selfTest)
+                {
+                    ShmChargerInfo->Control.PrimaryCtrl.bits.CabinetSwitchDetect = YES;
+                    GetClockTime(&_TestStep_time);
+                    LOG_INFO("SelfTest Process [SwitchDetect]");
+                }
+
+                if(GetTimeoutValue(_TestStep_time) / uSEC_VAL >= CABINET_ROLE_TIMEOUT)
+                {
+                    _switchCheck = true;
+
+                    char *str_cabinet_role[] = {STR_CABINET_ROLE_NONE, STR_CABINET_ROLE_MASTER, STR_CABINET_ROLE_SLAVE};
+
+                    ShmChargerInfo->Control.CabinetRole = ShmChargerInfo->Control.CabinetSwitch <= _CROLE_SLAVE ?
+                        ShmChargerInfo->Control.CabinetSwitch : _CROLE_SINGLE;
+
+                    //ShmChargerInfo->Control.CabinetRole = _CROLE_MASTER;
+                    //ShmChargerInfo->Control.CabinetRole = _CROLE_SLAVE;
+
+                    ShmChargerInfo->Control.PrimaryCtrl.bits.CabinetSwitchDetect = NO;
+                    LOG_INFO("Cabinet Role: [%s], Switch Value: %d",
+                        ShmChargerInfo->Control.CabinetRole <= _CROLE_SLAVE ? str_cabinet_role[ShmChargerInfo->Control.CabinetRole] : "Unknown",
+                        ShmChargerInfo->Control.CabinetSwitch);
+
+                    if(_versionCheck)
+                    {
+                        if(!_emgBtn)
+                        {
+                            if(ShmChargerInfo->Control.CabinetRole == _CROLE_SLAVE)
+                            {
+                                SetSelfTestSate(_STEST_COMPLETE);
+                            }
+                            else
+                            {
+                                SetSelfTestSate(_STEST_PSU_DETECT);
+                            }
+                        }
+                        else
+                        {
+                            SetSelfTestSate(_STEST_EMG_BTN);
+                        }
+                    }
+                    else
+                    {
+                        if(!_emgBtn)
+                        {
+                            SetSelfTestSate(_STEST_VERSION);
+                        }
+                        else
+                        {
+                            SetSelfTestSate(_STEST_EMG_BTN);
+                        }
+                    }
+                }
+                break;
+
+            case _STEST_AC_CONTACTOR:
+                if(_preTest != _selfTest)
+                {
+                    ShmChargerInfo->Control.RelayCtrl.bits.AcContactor = ON;
+
+                    GetClockTime(&_TestStep_time);
+                    LOG_INFO("SelfTest Process [AcContactor]");
+                }
+
+                SetSelfTestSate(_STEST_PSU_DETECT);
+                break;
+
+            case _STEST_PSU_DETECT:
+                if(_preTest != _selfTest)
+                {
+                    ShmChargerInfo->Control.PsuCtrl.bits.SelfTestOK = NO;
+                    ShmChargerInfo->Control.PsuCtrl.bits.NeedSelfTest = YES;
+                    ShmChargerInfo->Control.PsuCtrl.bits.Paused = NO;
+                    ShmChargerInfo->Control.RelayCtrl.bits.AcContactor = ON;
+
+                    GetClockTime(&_TestStep_time);
+                    LOG_INFO("SelfTest Process [PsuDetect]");
+                }
+
+                if(ShmPsuData->Work_Step >= GET_SYS_CAP)
+                {
+                    SetSelfTestSate(_STEST_PSU_CAP);
+                }
+                else
+                {
+                    if(_emgBtn)
+                    {
+                        SetSelfTestSate(_STEST_EMG_BTN);
+                        break;
+                    }
+
+                    if(_selfTestTimeout)
+                    {
+                        // self test timeout, set status code for timeout reason
+                        if(ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuModuleStestFail == NO)
+                        {
+                            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuModuleStestFail = YES;
+                            if(!ShmSysConfigAndInfo->SysInfo.AcContactorStatus)
+                            {
+                                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.AcContactStestFail = YES;
+                                LOG_INFO("Ac Contactor Self Test Fail!");
+                            }
+                            LOG_INFO("PSU Self Test Fail!");
+                        }
+
+                        if(ShmSysConfigAndInfo->SysInfo.BootingStatus != BOOT_COMPLETE)
+                        {
+                            LOG_INFO("Booting Completed, PSU Self Test Fail!");
+                        }
+                        ShmSysConfigAndInfo->SysInfo.SelfTestSeq = _STEST_FAIL;
+                        ShmSysConfigAndInfo->SysInfo.BootingStatus = BOOT_COMPLETE;
+
+                        if(GetTimeoutValue(_TestStep_time) / uSEC_VAL >= PSU_SELF_TIMEOUT)
+                        {
+                            SetSelfTestSate(_STEST_PSU_RETRY);
+                        }
+                    }
+                }
+                break;
+
+            case _STEST_PSU_CAP:
+                if(_preTest != _selfTest)
+                {
+                    GetClockTime(&_TestStep_time);
+                    LOG_INFO("SelfTest Process [PsuCapability]");
+                }
+
+                if(ShmChargerInfo->Control.PsuCtrl.bits.SelfTestOK == YES)
+                {
+                    SetSelfTestSate(_STEST_COMPLETE);
+                }
+                else
+                {
+                    if(_emgBtn)
+                    {
+                        SetSelfTestSate(_STEST_EMG_BTN);
+                        break;
+                    }
+
+                    if(_selfTestTimeout)
+                    {
+                        // self test timeout, set status code for timeout reason
+                        if(ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuModuleStestFail == NO)
+                        {
+                            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuModuleStestFail = YES;
+                            LOG_INFO("PSU Self Test Fail!");
+                        }
+
+                        if(ShmSysConfigAndInfo->SysInfo.BootingStatus != BOOT_COMPLETE)
+                        {
+                            LOG_INFO("Booting Completed, PSU Self Test Fail!");
+                        }
+                        ShmSysConfigAndInfo->SysInfo.SelfTestSeq = _STEST_FAIL;
+                        ShmSysConfigAndInfo->SysInfo.BootingStatus = BOOT_COMPLETE;
+                    }
+
+                    if(GetTimeoutValue(_TestStep_time) / uSEC_VAL >= PSU_SELF_TIMEOUT)
+                    {
+                        SetSelfTestSate(_STEST_PSU_RETRY);
+                    }
+                }
+                break;
+
+            case _STEST_PSU_RETRY:
+                if(_preTest != _selfTest)
+                {
+                    psuRetryCnt++;
+                    ShmChargerInfo->Control.RelayCtrl.bits.AcContactor = OFF;
+
+                    GetClockTime(&_TestStep_time);
+                    LOG_INFO("SelfTest Process [PsuRetry]");
+                }
+
+                if(_emgBtn)
+                {
+                    SetSelfTestSate(_STEST_EMG_BTN);
+                    break;
+                }
+
+                if(psuRetryCnt > MAX_PSU_RETRY_CNT)
+                {
+                    SetSelfTestSate(_STEST_FAIL);
+                }
+
+                if(GetTimeoutValue(_TestStep_time) / uSEC_VAL >= (PSU_RETRY_TIMEOUT))
+                {
+                    SetSelfTestSate(_STEST_PSU_DETECT);
+                }
+                break;
+
+            case _STEST_EMG_BTN:
+                if(_preTest != _selfTest)
+                {
+                    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.EmergencyStopTrip = true;
+
+                    GetClockTime(&_TestStep_time);
+                    LOG_INFO("SelfTest Process [EmgBtn Fail]");
+                }
+                ShmSysConfigAndInfo->SysInfo.SelfTestSeq = _STEST_FAIL;
+                ShmSysConfigAndInfo->SysInfo.BootingStatus = BOOT_COMPLETE;
+
+                if(ShmPrimaryMcuData->InputDet.bits.EmergencyButton == NORMAL)
+                {
+                    // bypass cabinet switch detection
+                    SetSelfTestSate(_STEST_FAIL);
+                    LOG_INFO("Emergency button recover, Soft Reset!");
+                }
+                break;
+
+            case _STEST_FAIL:
+                if(_preTest != _selfTest)
+                {
+                    GetClockTime(&_TestStep_time);
+                    LOG_INFO("SelfTest Process [SelfTestFail]");
+                }
+
+                // stop here
+                // self test fail, need soft reset
+                ShmChargerInfo->Control.SysCtrl.bits.NeedSoftReset = true;
+                break;
+
+            case _STEST_COMPLETE:
+                if(_preTest != _selfTest)
+                {
+                    LOG_INFO("SelfTest Process [SelfTestDone]");
+                }
+
+                if(ShmSysConfigAndInfo->SysInfo.BootingStatus != BOOT_COMPLETE)
+                {
+                    ShmSysConfigAndInfo->SysInfo.BootingStatus = BOOT_COMPLETE;
+                }
+
+                if(_selfTestTimeout)
+                {
+                    // stop here
+                    // self test completed but timeout, need soft reset
+                    ShmChargerInfo->Control.SysCtrl.bits.NeedSoftReset = true;
+                }
+                break;
+
+            default:
+                if(_preTest != _selfTest)
+                {
+                    LOG_INFO("SelfTest Process [Unknown]");
+                }
+                SetSelfTestSate(_STEST_VERSION);
+                break;
+        }
+
+        if(ShmSysConfigAndInfo->SysInfo.BootingStatus != BOOT_COMPLETE)
+        {
+            if(GetTimeoutValue(_SelfTest_time) / uSEC_VAL >= SELFTEST_TIMEOUT)
+            {
+                _selfTestTimeout = true;
+            }
+        }
+
+        _preTest = _selfTest;
+        usleep(10000);
+    }
+
+    return 0;
+}
+

+ 13 - 0
EVSE/Projects/DO360/Apps/Module_ChargerSelfTest.h

@@ -0,0 +1,13 @@
+/*
+ * Module_ChargerSelfTest.h
+ *
+ *  Created on: 2021年9月24日
+ *      Author: 7978
+ */
+
+#ifndef MODULE_CHARGERSELFTEST_H_
+#define MODULE_CHARGERSELFTEST_H_
+
+
+
+#endif /* MODULE_CHARGERSELFTEST_H_ */

+ 175 - 31
EVSE/Projects/DO360/Apps/Module_EvComm.c

@@ -72,7 +72,7 @@ int InitShareMemory()
 	int MeterSMId;
 
 	//creat ShmSysConfigAndInfo
-	if ((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo), IPC_CREAT | 0777)) < 0)
+	if ((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo), 0777)) < 0)
 	{
 		#ifdef SystemLogMessage
 		LOG_ERROR("shmget ShmSysConfigAndInfo NG");
@@ -897,10 +897,10 @@ void PowerCabinetStatusResponse(int socket, struct PACKET_STRUCTURE *packet, uns
     }
 
     bool need_copy = false;
-    if(sendBuffer.Header.len != CabinetStatusToDispenser[sendBuffer.Header.id].Header.len ||
-        sendBuffer.Header.op != CabinetStatusToDispenser[sendBuffer.Header.id].Header.op ||
-        sendBuffer.Payload.reg != CabinetStatusToDispenser[sendBuffer.Header.id].Payload.reg ||
-        sendBuffer.Payload.data[0] != CabinetStatusToDispenser[sendBuffer.Header.id].Payload.data[0])
+    if(sendBuffer.Header.len != CabinetStatusToDispenser[dispenserIndex].Header.len ||
+        sendBuffer.Header.op != CabinetStatusToDispenser[dispenserIndex].Header.op ||
+        sendBuffer.Payload.reg != CabinetStatusToDispenser[dispenserIndex].Payload.reg ||
+        sendBuffer.Payload.data[0] != CabinetStatusToDispenser[dispenserIndex].Payload.data[0])
     {
         need_copy = true;
     }
@@ -908,7 +908,7 @@ void PowerCabinetStatusResponse(int socket, struct PACKET_STRUCTURE *packet, uns
     {
         for(int i = 0; i < sendBuffer.Header.len - 2; i++)
         {
-            if(sendBuffer.Payload.data[1 + i] != CabinetStatusToDispenser[sendBuffer.Header.id].Payload.data[1 + i])
+            if(sendBuffer.Payload.data[1 + i] != CabinetStatusToDispenser[dispenserIndex].Payload.data[1 + i])
             {
                 need_copy = true;
             }
@@ -917,14 +917,14 @@ void PowerCabinetStatusResponse(int socket, struct PACKET_STRUCTURE *packet, uns
     if(need_copy)
     {
         char str[256];
-        memcpy(&CabinetStatusToDispenser[sendBuffer.Header.id], &sendBuffer, sizeof(struct PACKET_STRUCTURE));
+        memcpy(&CabinetStatusToDispenser[dispenserIndex], &sendBuffer, sizeof(struct PACKET_STRUCTURE));
 
-        sprintf(str, "Status Code Update To %d:", sendBuffer.Header.id);
+        sprintf(str, "Cabinet >> Dispenser %d Status Code:", dispenserIndex + 1);
 
-        for(int i = 0; i < CabinetStatusToDispenser[sendBuffer.Header.id].Header.len - 2; i++)
+        for(int i = 0; i < CabinetStatusToDispenser[dispenserIndex].Header.len - 2; i++)
         {
             char temp[8];
-            sprintf(temp, " %02X", CabinetStatusToDispenser[sendBuffer.Header.id].Payload.data[1 + i]);
+            sprintf(temp, " %02X", CabinetStatusToDispenser[dispenserIndex].Payload.data[1 + i]);
             strcat(str, temp);
         }
         LOG_INFO("%s", str);
@@ -965,6 +965,36 @@ void GetPhysicalLimitVoltageAndCurrent(byte index, unsigned short *voltage, unsi
     }
 }
 
+void GetModelNameLimitPower(byte index, unsigned short *power)
+{
+    unsigned short limitPower = 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[i].GunPsuQuantity;
+        }
+    }
+
+    if(ShmChargerInfo->PsuGrouping.GroupCollection[index].GunPsuQuantity != 0 && inUsingCnt != 0 &&
+            ShmChargerInfo->Control.ChargerRatingPower != 0)
+    {
+        limitPower = ShmChargerInfo->Control.ChargerRatingPower;
+        if(ShmChargerInfo->Control.CabinetRole == _CROLE_MASTER)
+        {
+            limitPower += ShmChargerInfo->ParallelCabinet.TotalParallelPower;
+        }
+        limitPower = (limitPower * ShmChargerInfo->PsuGrouping.GroupCollection[index].GunPsuQuantity) / inUsingCnt;
+    }
+
+    if(limitPower != 0 && limitPower <= *power)
+    {
+        *power = limitPower;
+    }
+}
+
 void GetConfigLimitPowerAndCurrent(byte index, unsigned short *power, unsigned short *currrent)
 {
     unsigned short limitPower = 0, limitCurrent = 0;
@@ -1072,6 +1102,7 @@ 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);
+	GetModelNameLimitPower(packet->Header.id - 1, &power);
 	GetConfigLimitPowerAndCurrent(packet->Header.id - 1, &power, &current);
 	GetChargingProfileLimit(packet->Header.id - 1, &power, &current);
 	GetMaxChargingProfileLimit(packet->Header.id - 1, &power, &current);
@@ -1245,8 +1276,33 @@ void AddMiscCommand(struct PACKET_STRUCTURE *packet, struct MISC_COMMAND *misc)
     packet->Header.len += 6;
 }
 
-void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char dispenserIndex, unsigned char result)
-{
+// LOG_INFO("Cabinet >> Connector %d Availability [SelfTestFail]", packet->Header.id);
+// LOG_INFO("Cabinet >> Connector %d Availability [Disable]", packet->Header.id);
+// LOG_INFO("Cabinet >> Connector %d Availability [Inoperative]", packet->Header.id);
+// LOG_INFO("Cabinet >> Connector %d Availability [Enable]", packet->Header.id);
+// LOG_INFO("Cabinet >> Connector %d RemoteStart  [%d]", packet->Header.id, misc.Value);
+// LOG_INFO("Cabinet >> Connector %d Balance      [%d]", packet->Header.id, (misc.Value));
+// LOG_INFO("Cabinet >> Dispenser %d PlugTimeout  [%d]", dispenserIndex + 1, misc.Value);
+// LOG_INFO("Cabinet >> Dispenser %d DefaultPrice [%d]", dispenserIndex + 1, misc.Value);
+// LOG_INFO("Cabinet >> Dispenser %d Currency     [%d]", dispenserIndex + 1, misc.Value);
+// LOG_INFO("Cabinet >> Dispenser %d BackendConn  [%s]", dispenserIndex + 1, strConnection[misc.Value]);
+// LOG_INFO("Cabinet >> Dispenser %d BackendConn  [%d]", dispenserIndex + 1, (misc.Value));
+// LOG_INFO("Cabinet >> Dispenser %d EthernetConn [%s]", dispenserIndex + 1, strConnection[misc.Value]);
+// LOG_INFO("Cabinet >> Dispenser %d EthernetConn [%d]", dispenserIndex + 1, (misc.Value));
+// LOG_INFO("Cabinet >> Dispenser %d WiFiConn     [%s]", dispenserIndex + 1, strConnection[misc.Value]);
+// LOG_INFO("Cabinet >> Dispenser %d WiFiConn     [%d]", dispenserIndex + 1, (misc.Value));
+// LOG_INFO("Cabinet >> Dispenser %d TelModemConn [%s]", dispenserIndex + 1, strConnection[misc.Value]);
+// LOG_INFO("Cabinet >> Dispenser %d TelModemConn [%d]", dispenserIndex + 1, (misc.Value));
+// LOG_INFO("Cabinet >> Dispenser %d BillingInfo  [%s]", dispenserIndex + 1, misc.Value ? "Enable" : "Disable");
+// LOG_INFO("Cabinet >> Dispenser %d StopButton   [%s]", dispenserIndex + 1, misc.Value ? "Enable" : "Disable");
+// LOG_INFO("Cabinet >> Dispenser %d HardReboot   [%d]", dispenserIndex + 1, misc.Value);
+// LOG_INFO("Cabinet >> Dispenser %d SoftReset    [%d]", dispenserIndex + 1, misc.Value);
+// LOG_INFO("Cabinet >> Dispenser %d AuthMode     [%s]", dispenserIndex + 1, misc.Value ? "Disable" : "Enable");
+// LOG_INFO("Cabinet >> Dispenser %d EVCCID       [%s]", dispenserIndex + 1, misc.Value ? "Enable" : "Disable");
+
+void MiscCmdRes(int socket, struct PACKET_STRUCTURE *packet, unsigned char dispenserIndex, unsigned char result)
+{
+    char *strConnection[] = {STR_CONN_DISABLE, STR_CONN_CONNECTED, STR_CONN_DISCONNECTED};
     struct PACKET_STRUCTURE sendBuffer;
 
     memset(&sendBuffer, 0x00, sizeof(sendBuffer));
@@ -1265,9 +1321,29 @@ void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
         {
             ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].Parameter.bits.AvailabilityRequest = false;
             misc.Command = _MiscCmd_ChangeOperative;
-            misc.Value = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].GeneralChargingData.IsAvailable;
 
-            LOG_INFO("Announce Connector %d Availability: %d", packet->Header.id, misc.Value);
+            unsigned char IsAvailable = true;
+
+            if(ShmSysConfigAndInfo->SysInfo.SelfTestSeq != _STEST_COMPLETE)
+            {
+                IsAvailable = false;
+                LOG_INFO("Cabinet >> Connector %d Availability [SelfTestFail]", packet->Header.id);
+            }
+            else if(!ShmChargerInfo->Control.GunAvailable[packet->Header.id - 1])
+            {
+                IsAvailable = false;
+                LOG_INFO("Cabinet >> Connector %d Availability [Disable]", packet->Header.id);
+            }
+            else if(!ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].GeneralChargingData.IsAvailable)
+            {
+                IsAvailable = false;
+                LOG_INFO("Cabinet >> Connector %d Availability [Inoperative]", packet->Header.id);
+            }
+            else
+            {
+                LOG_INFO("Cabinet >> Connector %d Availability [Enable]", packet->Header.id);
+            }
+            misc.Value = IsAvailable;
             AddMiscCommand(&sendBuffer, &misc);
         }
 
@@ -1278,7 +1354,7 @@ void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
             misc.Command = _MiscCmd_RemoteStart;
             misc.Value = true;
 
-            LOG_INFO("Announce Connector %d Remote Start: %d", packet->Header.id, misc.Value);
+            LOG_INFO("Cabinet >> Connector %d RemoteStart  [%d]", packet->Header.id, misc.Value);
             AddMiscCommand(&sendBuffer, &misc);
         }
 
@@ -1289,7 +1365,7 @@ void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
 //            misc.Command = _MiscCmd_RemoteStop;
 //            misc.Value = true;
 
-//            LOG_INFO("Announce Connector %d Remote Stop: %d", packet->Header.id, misc.Value);
+//            LOG_INFO("Cabinet >> Connector %d Remote Stop: %d", packet->Header.id, misc.Value);
 //            AddMiscCommand(&sendBuffer, &misc);
 //        }
 
@@ -1300,7 +1376,7 @@ void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
 //            misc.Command = _MiscCmd_UnlockStop;
 //            misc.Value = true;
 
-//            LOG_INFO("Announce Connector %d Unlock Stop: %d", packet->Header.id, misc.Value);
+//            LOG_INFO("Cabinet >> Connector %d Unlock Stop: %d", packet->Header.id, misc.Value);
 //            AddMiscCommand(&sendBuffer, &misc);
 //        }
 
@@ -1310,7 +1386,7 @@ void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
             misc.Command = _MiscCmd_AccountBalance;
             misc.Value = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].AccountBalance;
 
-            LOG_INFO("Announce Connector %d Account Balance: %d", packet->Header.id, (misc.Value));
+            LOG_INFO("Cabinet >> Connector %d Balance      [%d]", packet->Header.id, (misc.Value));
             AddMiscCommand(&sendBuffer, &misc);
         }
 
@@ -1323,7 +1399,7 @@ void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
                 misc.Command = _MiscCmd_ConnectorTimeout;
                 misc.Value = ShmSysConfigAndInfo->SysInfo.DispenserInfo.ConnectorTimeout;
 
-                LOG_INFO("Announce Dispenser %d Connection Timeout: %d", dispenserIndex + 1, misc.Value);
+                LOG_INFO("Cabinet >> Dispenser %d PlugTimeout  [%d]", dispenserIndex + 1, misc.Value);
                 AddMiscCommand(&sendBuffer, &misc);
             }
 
@@ -1333,7 +1409,7 @@ void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
                 misc.Command = _MiscCmd_DefaultPrice;
                 misc.Value = ShmSysConfigAndInfo->SysInfo.DispenserInfo.DefaultPrice;
 
-                LOG_INFO("Announce Dispenser %d Default Price: %d", dispenserIndex + 1, misc.Value);
+                LOG_INFO("Cabinet >> Dispenser %d DefaultPrice [%d]", dispenserIndex + 1, misc.Value);
                 AddMiscCommand(&sendBuffer, &misc);
             }
 
@@ -1343,7 +1419,7 @@ void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
                 misc.Command = _MiscCmd_Currency;
                 misc.Value = ShmSysConfigAndInfo->SysInfo.DispenserInfo.Currency;
 
-                LOG_INFO("Announce Dispenser %d Currency Index: %d", dispenserIndex + 1, misc.Value);
+                LOG_INFO("Cabinet >> Dispenser %d Currency     [%d]", dispenserIndex + 1, misc.Value);
                 AddMiscCommand(&sendBuffer, &misc);
             }
 
@@ -1353,7 +1429,14 @@ void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
                 misc.Command = _MiscCmd_BackendStatus;
                 misc.Value = ShmSysConfigAndInfo->SysInfo.CabinetMicsStatus.BackendStatus;
 
-                LOG_INFO("Announce Dispenser %d BackendStatus: %d", dispenserIndex + 1, (misc.Value));
+                if(misc.Value <= _Connnection_Disconnected)
+                {
+                    LOG_INFO("Cabinet >> Dispenser %d BackendConn  [%s]", dispenserIndex + 1, strConnection[misc.Value]);
+                }
+                else
+                {
+                    LOG_INFO("Cabinet >> Dispenser %d BackendConn  [%d]", dispenserIndex + 1, (misc.Value));
+                }
                 AddMiscCommand(&sendBuffer, &misc);
             }
 
@@ -1363,7 +1446,14 @@ void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
                 misc.Command = _MiscCmd_EthernetStatus;
                 misc.Value = ShmSysConfigAndInfo->SysInfo.CabinetMicsStatus.EthernetStatus;
 
-                LOG_INFO("Announce Dispenser %d EthernetStatus: %d", dispenserIndex + 1, (misc.Value));
+                if(misc.Value <= _Connnection_Disconnected)
+                {
+                    LOG_INFO("Cabinet >> Dispenser %d EthernetConn [%s]", dispenserIndex + 1, strConnection[misc.Value]);
+                }
+                else
+                {
+                    LOG_INFO("Cabinet >> Dispenser %d EthernetConn [%d]", dispenserIndex + 1, (misc.Value));
+                }
                 AddMiscCommand(&sendBuffer, &misc);
             }
 
@@ -1373,7 +1463,14 @@ void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
                 misc.Command = _MiscCmd_WiFiStatus;
                 misc.Value = ShmSysConfigAndInfo->SysInfo.CabinetMicsStatus.WiFiStatus;
 
-                LOG_INFO("Announce Dispenser %d WiFiStatus: %d", dispenserIndex + 1, (misc.Value));
+                if(misc.Value <= _Connnection_Disconnected)
+                {
+                    LOG_INFO("Cabinet >> Dispenser %d WiFiConn     [%s]", dispenserIndex + 1, strConnection[misc.Value]);
+                }
+                else
+                {
+                    LOG_INFO("Cabinet >> Dispenser %d WiFiConn     [%d]", dispenserIndex + 1, (misc.Value));
+                }
                 AddMiscCommand(&sendBuffer, &misc);
             }
 
@@ -1383,7 +1480,14 @@ void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
                 misc.Command = _MiscCmd_4GStatus;
                 misc.Value = ShmSysConfigAndInfo->SysInfo.CabinetMicsStatus.TelcomModemStatus;
 
-                LOG_INFO("Announce Dispenser %d TelcomModemStatus: %d", dispenserIndex + 1, (misc.Value));
+                if(misc.Value <= _Connnection_Disconnected)
+                {
+                    LOG_INFO("Cabinet >> Dispenser %d TelModemConn [%s]", dispenserIndex + 1, strConnection[misc.Value]);
+                }
+                else
+                {
+                    LOG_INFO("Cabinet >> Dispenser %d TelModemConn [%d]", dispenserIndex + 1, (misc.Value));
+                }
                 AddMiscCommand(&sendBuffer, &misc);
             }
 
@@ -1393,7 +1497,7 @@ void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
                 misc.Command = _MiscCmd_Billing;
                 misc.Value = ShmSysConfigAndInfo->SysInfo.CabinetMicsStatus.BillingStatus;
 
-                LOG_INFO("Announce Dispenser %d %s Billing Information", dispenserIndex + 1, misc.Value ? "Enable" : "Disable");
+                LOG_INFO("Cabinet >> Dispenser %d BillingInfo  [%s]", dispenserIndex + 1, misc.Value ? "Enable" : "Disable");
                 AddMiscCommand(&sendBuffer, &misc);
             }
 
@@ -1403,7 +1507,7 @@ void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
                 misc.Command = _MiscCmd_StopButton;
                 misc.Value = ShmSysConfigAndInfo->SysInfo.CabinetMicsStatus.StopChargingButton;
 
-                LOG_INFO("Announce Dispenser %d %s Stop Charging Button", dispenserIndex + 1, misc.Value ? "Enable" : "Disable");
+                LOG_INFO("Cabinet >> Dispenser %d StopButton   [%s]", dispenserIndex + 1, misc.Value ? "Enable" : "Disable");
                 AddMiscCommand(&sendBuffer, &misc);
             }
 
@@ -1414,7 +1518,7 @@ void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
                 misc.Command = _MiscCmd_HardwareReboot;
                 misc.Value = true;
 
-                LOG_INFO("Announce Dispenser %d Hardware Reboot: %d", dispenserIndex + 1, misc.Value);
+                LOG_INFO("Cabinet >> Dispenser %d HardReboot   [%d]", dispenserIndex + 1, misc.Value);
                 AddMiscCommand(&sendBuffer, &misc);
             }
 
@@ -1425,7 +1529,36 @@ void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
                 misc.Command = _MiscCmd_SoftwareRestart;
                 misc.Value = true;
 
-                LOG_INFO("Announce Dispenser %d Software Reset: %d", dispenserIndex + 1, misc.Value);
+                LOG_INFO("Cabinet >> Dispenser %d SoftReset    [%d]", dispenserIndex + 1, misc.Value);
+                AddMiscCommand(&sendBuffer, &misc);
+            }
+
+            if(ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].Setting.bits.AuthModeConfigRequest)
+            {
+                ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].Setting.bits.AuthModeConfigRequest = false;
+                misc.Command = _MiscCmd_AuthDisable;
+                misc.Value = ShmSysConfigAndInfo->SysInfo.CabinetMicsStatus.AuthModeConfig;
+
+                LOG_INFO("Cabinet >> Dispenser %d AuthMode     [%s]", dispenserIndex + 1, misc.Value ? "Disable" : "Enable");
+                AddMiscCommand(&sendBuffer, &misc);
+            }
+
+            if(ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].Setting.bits.EVCCIDConfigRequest)
+            {
+                ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].Setting.bits.EVCCIDConfigRequest = false;
+                misc.Command = _MiscCmd_EVCCIDEnable;
+
+                if(ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].ModelName[0] == 'D' &&
+                    ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].ModelName[0] == 'X')
+                {
+                    misc.Value = ShmSysConfigAndInfo->SysInfo.CabinetMicsStatus.AuthModeConfig > 0 ? 0 : 1;
+                }
+                else
+                {
+                    misc.Value = ShmSysConfigAndInfo->SysInfo.CabinetMicsStatus.EVCCIDConfig;
+                }
+
+                LOG_INFO("Cabinet >> Dispenser %d EVCCID       [%s]", dispenserIndex + 1, misc.Value ? "Enable" : "Disable");
                 AddMiscCommand(&sendBuffer, &misc);
             }
         }
@@ -1930,6 +2063,7 @@ BOOL ConnectorChargingTargetHandler(struct PACKET_STRUCTURE *packet, unsigned ch
 		}
 
 		GetPhysicalLimitVoltageAndCurrent(packet->Header.id - 1, &voltage, &current);
+		GetModelNameLimitPower(packet->Header.id - 1, &power);
 		GetConfigLimitPowerAndCurrent(packet->Header.id - 1, &power, &current);
 
 		if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteTargetVoltage != voltage ||
@@ -2671,6 +2805,15 @@ void DispenserSocketProcess(int socketFd, struct sockaddr_in clientInfo, unsigne
                                 ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].Setting.bits.TelcomModemStatusRequest = true;
                                 ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].Setting.bits.BillingStatusRequest = true;
                                 ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].Setting.bits.StopButtonStatusRequest = true;
+                                ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].Setting.bits.AuthModeConfigRequest = true;
+                                ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].Setting.bits.EVCCIDConfigRequest = true;
+
+                                for(int i = 0; i < ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].ConnectorQuantity; i++)
+                                {
+                                    unsigned char gun = ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].ConnectorID[i] - 1;
+
+                                    ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].Parameter.bits.AvailabilityRequest = true;
+                                }
                             }
 						}
 					}
@@ -2765,7 +2908,7 @@ void DispenserSocketProcess(int socketFd, struct sockaddr_in clientInfo, unsigne
 					    {
 					        ackResult = _R_OK;
 					    }
-					    MiscControlResponse(socketFd, &receiveBuffer, dispenserIndex, ackResult);
+					    MiscCmdRes(socketFd, &receiveBuffer, dispenserIndex, ackResult);
 					}
 
 					// Reg: 0x0D, Report csu version
@@ -3180,7 +3323,8 @@ int main(void)
 	InitialConnector();
 
 	// wait for self test completed
-    while(ShmSysConfigAndInfo->SysInfo.BootingStatus == BOOTTING)
+    while(ShmSysConfigAndInfo->SysInfo.BootingStatus == BOOTTING ||
+        ShmChargerInfo->Control.CabinetRole == _CROLE_SLAVE)
     {
         sleep(1);
     }

+ 2 - 0
EVSE/Projects/DO360/Apps/Module_EvComm.h

@@ -178,6 +178,8 @@ enum MiscCommand
     _MiscCmd_4GStatus           = 0x0009,
     _MiscCmd_Billing            = 0x000A,
     _MiscCmd_StopButton         = 0x000B,
+    _MiscCmd_AuthDisable        = 0x000C,
+    _MiscCmd_EVCCIDEnable       = 0x000D,
     _MiscCmd_HardwareReboot     = 0x0101,
     _MiscCmd_SoftwareRestart    = 0x0102,
     _MiscCmd_RemoteStart        = 0x0103,

+ 120 - 80
EVSE/Projects/DO360/Apps/Module_InternalComm.c

@@ -1097,118 +1097,157 @@ void SetFanModuleSpeed()
 	}
 }
 
-//==========================================
-// Common Function
-//==========================================
-void SetK1K2RelayStatus(byte index)
+void SetPCabinetOutputRelayOff(byte index)
 {
-    unsigned char location = 0;
+    if(ShmChargerInfo->Control.CabinetRole == _CROLE_MASTER)
+    {
+        if(ShmChargerInfo->ParallelCabinet.PCabinet[index].OutputRelaySetting[index] != NO)
+        {
+            LOG_INFO("Set Parallel Cabinet Gun %d Output Relay OFF", index + 1);
+        }
+        ShmChargerInfo->ParallelCabinet.PCabinet[index].OutputRelaySetting[index] = NO;
+    }
+}
 
-    if(index < MAX_GROUP_QUANTITY && index < ShmChargerInfo->Control.MaxConnector)
+void SetMCabinetOutputRelay(byte index)
+{
+    if ((_chargingData[index]->SystemStatus >= S_PREPARING_FOR_EVSE &&
+            _chargingData[index]->SystemStatus <= S_CHARGING))
     {
-        if ((_chargingData[index]->SystemStatus >= S_PREPARING_FOR_EVSE &&
-                _chargingData[index]->SystemStatus <= S_CHARGING))
+        if(_chargingData[index]->GroundFaultStatus == GFD_FAIL)
         {
-            if(_chargingData[index]->GroundFaultStatus == GFD_FAIL)
+            if(ShmOutputRelayConfig[index]->bits.Output_N || ShmOutputRelayConfig[index]->bits.Output_P)
             {
-                if(ShmOutputRelayConfig[index]->bits.Output_N || ShmOutputRelayConfig[index]->bits.Output_P)
-                {
-                    LOG_INFO("Gun %d Set K1K2 Open By GFD Fail", index + 1);
-                }
-                ShmOutputRelayConfig[index]->bits.Output_N = false;
-                ShmOutputRelayConfig[index]->bits.Output_P = false;
+                LOG_INFO("Gun %d Set K1K2 Open By GFD Fail", index + 1);
             }
-            else
-            {
+            ShmOutputRelayConfig[index]->bits.Output_N = false;
+            ShmOutputRelayConfig[index]->bits.Output_P = false;
+            SetPCabinetOutputRelayOff(index);
+        }
+        else
+        {
 #if RELAY_OPEN_AT_PRECHARGE
 
-                if(_chargingData[index]->SystemStatus == S_PREPARING_FOR_EVSE)
+            if(_chargingData[index]->SystemStatus == S_PREPARING_FOR_EVSE)
+            {
+                if(ShmPsuGrouping->GroupCollection[index].GroupCtrl.bits.CableCheckDone == false &&
+                    ShmPsuGrouping->GroupCollection[index].GroupCtrl.bits.InPrechargeMode == false)
                 {
-                    if(ShmPsuGrouping->GroupCollection[index].GroupCtrl.bits.CableCheckDone == false &&
-                        ShmPsuGrouping->GroupCollection[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(ShmPsuGrouping->GroupCollection[index].GroupCtrl.bits.CableCheckDone == true &&
-                        ShmPsuGrouping->GroupCollection[index].GroupCtrl.bits.InPrechargeMode == false)
+                    if(!ShmOutputRelayConfig[index]->bits.Output_N || !ShmOutputRelayConfig[index]->bits.Output_P)
                     {
-                        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;
-                        }
+                        LOG_INFO("Gun %d Set K1K2 Close And Prepare To Cable Check", index + 1);
                     }
-                    else if(ShmPsuGrouping->GroupCollection[index].GroupCtrl.bits.CableCheckDone == true &&
-                        ShmPsuGrouping->GroupCollection[index].GroupCtrl.bits.InPrechargeMode == true)
+                    ShmOutputRelayConfig[index]->bits.Output_N = true;
+                    ShmOutputRelayConfig[index]->bits.Output_P = true;
+                }
+                else if(ShmPsuGrouping->GroupCollection[index].GroupCtrl.bits.CableCheckDone == true &&
+                    ShmPsuGrouping->GroupCollection[index].GroupCtrl.bits.InPrechargeMode == false)
+                {
+                    if(_chargingData[index]->FireChargingVoltage <= SELF_TO_CHANGE_RELAY_STATUS)
                     {
-                        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)
                         {
-                            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;
+                            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
+                else if(ShmPsuGrouping->GroupCollection[index].GroupCtrl.bits.CableCheckDone == true &&
+                    ShmPsuGrouping->GroupCollection[index].GroupCtrl.bits.InPrechargeMode == true)
                 {
-                    if(!ShmOutputRelayConfig[index]->bits.Output_N || !ShmOutputRelayConfig[index]->bits.Output_P)
+                    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)
                     {
-                        LOG_INFO("Gun %d Set K1K2 Close In Charging Status", index + 1);
+                        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;
                     }
-                    ShmOutputRelayConfig[index]->bits.Output_N = true;
-                    ShmOutputRelayConfig[index]->bits.Output_P = true;
                 }
-#else
+            }
+            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);
+                    LOG_INFO("Gun %d Set K1K2 Close In Charging Status", index + 1);
                 }
                 ShmOutputRelayConfig[index]->bits.Output_N = true;
                 ShmOutputRelayConfig[index]->bits.Output_P = true;
-#endif
             }
-        }
-        else if ((_chargingData[index]->SystemStatus >= S_TERMINATING &&
-                _chargingData[index]->SystemStatus <= S_COMPLETE) ||
-                _chargingData[index]->SystemStatus == S_ALARM)
-        {
-            if ((_chargingData[index]->PresentChargingCurrent * 10) <= SEFETY_SWITCH_RELAY_CUR ||
-                _chargingData[index]->GroundFaultStatus == GFD_FAIL)
+#else
+            if(!ShmOutputRelayConfig[index]->bits.Output_N || !ShmOutputRelayConfig[index]->bits.Output_P)
             {
-                if(ShmOutputRelayConfig[index]->bits.Output_N || ShmOutputRelayConfig[index]->bits.Output_P)
-                {
-                    LOG_INFO("Gun %d Set K1K2 Open And Charging Stop", index + 1);
-                }
-                ShmOutputRelayConfig[index]->bits.Output_N = false;
-                ShmOutputRelayConfig[index]->bits.Output_P = false;
+                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
+    }
+    else if ((_chargingData[index]->SystemStatus >= S_TERMINATING &&
+            _chargingData[index]->SystemStatus <= S_COMPLETE) ||
+            _chargingData[index]->SystemStatus == S_ALARM)
+    {
+        if ((_chargingData[index]->PresentChargingCurrent * 10) <= SEFETY_SWITCH_RELAY_CUR ||
+            _chargingData[index]->GroundFaultStatus == GFD_FAIL)
         {
             if(ShmOutputRelayConfig[index]->bits.Output_N || ShmOutputRelayConfig[index]->bits.Output_P)
             {
-                LOG_INFO("Gun %d Set K1K2 Open At Idle Mode", index + 1);
+                LOG_INFO("Gun %d Set K1K2 Open And Charging Stop", index + 1);
             }
             ShmOutputRelayConfig[index]->bits.Output_N = false;
             ShmOutputRelayConfig[index]->bits.Output_P = false;
+            SetPCabinetOutputRelayOff(index);
+        }
+    }
+    else
+    {
+        if(ShmOutputRelayConfig[index]->bits.Output_N || ShmOutputRelayConfig[index]->bits.Output_P)
+        {
+            LOG_INFO("Gun %d Set K1K2 Open At Idle Mode", index + 1);
+        }
+        ShmOutputRelayConfig[index]->bits.Output_N = false;
+        ShmOutputRelayConfig[index]->bits.Output_P = false;
+
+        if(_chargingData[index]->SystemStatus == S_IDLE ||
+            _chargingData[index]->SystemStatus == S_MAINTAIN ||
+            _chargingData[index]->SystemStatus == S_FAULT)
+        {
+            SetPCabinetOutputRelayOff(index);
+        }
+    }
+}
+
+void SetSCabinetOutputRelay(byte index)
+{
+    ShmOutputRelayConfig[index]->bits.Output_N = ShmChargerInfo->SCabinetControl.SOutputRelay[index] > 0 ? true : false;
+    ShmOutputRelayConfig[index]->bits.Output_P = ShmChargerInfo->SCabinetControl.SOutputRelay[index] > 0 ? true : false;
+}
+
+//==========================================
+// Common Function
+//==========================================
+void SetK1K2RelayStatus(byte index)
+{
+    unsigned char location = 0;
+
+    if(index < MAX_GROUP_QUANTITY && index < ShmChargerInfo->Control.MaxConnector)
+    {
+        if(ShmChargerInfo->Control.CabinetRole != _CROLE_SLAVE)
+        {
+            SetMCabinetOutputRelay(index);
+        }
+        else
+        {
+            SetSCabinetOutputRelay(index);
         }
 
         location = ShmPsuGrouping->GroupCollection[index].Location;
@@ -2563,7 +2602,7 @@ int main(void)
 	//bool printRelayStatus = true;
 	for(;;)
 	{
-	    if(!ShmSysConfigAndInfo->SysInfo.FirmwareUpdate)
+	    if(!ShmChargerInfo->Control.RelayCtrl.bits.Paused)
 	    {
             // 程序開始之前~ 必須先確定 FW 版本與硬體版本,確認後!!~ 該模組才算是真正的 Initial Comp.
             if(ShmChargerInfo->Control.SysCtrl.bits.RelayBoardDisable == false)
@@ -2735,8 +2774,9 @@ int main(void)
                     }
                 }
             }
-
-
+	    }
+	    if(!ShmChargerInfo->Control.FanCtrl.bits.Paused)
+	    {
             if (ShmFanModuleData->SelfTest_Comp == YES ||
                     strlen((char *)ShmSysConfigAndInfo->SysInfo.FanModuleFwRev) != 0 ||
                     ShmSysConfigAndInfo->SysInfo.FanModuleFwRev[0] != '\0')

+ 501 - 0
EVSE/Projects/DO360/Apps/Module_LedIndication.c

@@ -0,0 +1,501 @@
+/*
+ * Module_LedIndication.c
+ *
+ *  Created on: 2021年11月2日
+ *      Author: 7978
+ */
+
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/shm.h>
+#include <sys/mman.h>
+#include <linux/can.h>
+#include <linux/can/raw.h>
+#include <linux/wireless.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdio.h>      /*標準輸入輸出定義*/
+#include <stdlib.h>     /*標準函數庫定義*/
+#include <unistd.h>     /*Unix 標準函數定義*/
+#include <fcntl.h>      /*檔控制定義*/
+#include <termios.h>    /*PPSIX 終端控制定義*/
+#include <errno.h>      /*錯誤號定義*/
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <ifaddrs.h>
+#include <signal.h>
+#include <net/if_arp.h>
+#include "../../define.h"
+#include "Module_LedIndication.h"
+#include "Config.h"
+#include "Common.h"
+
+struct SysConfigAndInfo             *ShmSysConfigAndInfo;
+ChargerInfoData                     *ShmChargerInfo;
+struct ChargingInfoData             *chargingInfo[CONNECTOR_QUANTITY];
+struct PrimaryMcuData               *ShmPrimaryMcuData;
+
+struct timespec _DO_LED_time;
+struct timespec _DKLed_time[2];
+unsigned char _DOLedStatus, _preDOLedStatus;
+unsigned char _DKLedStatus[2], _preDKLedStatus[2];
+
+//==========================================
+// Init all share memory
+//==========================================
+int InitShareMemory(void)
+{
+    int result = PASS;
+    int MeterSMId;
+
+    //creat ShmSysConfigAndInfo
+    if ((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo), 0777)) < 0)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmget ShmSysConfigAndInfo NG");
+        #endif
+        result = FAIL;
+    }
+    else if ((ShmSysConfigAndInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmat ShmSysConfigAndInfo NG");
+        #endif
+        result = FAIL;
+     }
+    else
+    {
+
+    }
+
+    // initial primary share memory
+    if ((MeterSMId = shmget(ShmPrimaryMcuKey, sizeof(struct PrimaryMcuData), 0777)) < 0)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmget ShmPrimaryMcuData NG");
+        #endif
+        result = FAIL;
+    }
+    else if ((ShmPrimaryMcuData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmat ShmPrimaryMcuData NG");
+        #endif
+        result = FAIL;
+    }
+
+    if ((MeterSMId = shmget(SM_ChargerInfoKey, sizeof(ChargerInfoData), 0777)) < 0)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmat ChargerInfoData NG");
+        #endif
+        result = FAIL;
+    }
+    else if ((ShmChargerInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("shmat ChargerInfoData NG");
+        #endif
+        result = FAIL;
+    }
+
+    return result;
+}
+
+void InitialConnector(void)
+{
+    for(int i = 0; i < CONNECTOR_QUANTITY; i++)
+    {
+        chargingInfo[i] = &ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].GeneralChargingData;
+    }
+}
+
+// connector: connector infex, 0 ~ 3
+void SetLedStatus(unsigned char connector, unsigned char indication)
+{
+    int greenOffset = 0, redOffset = 0;
+
+    if(ShmChargerInfo->Control.SysCtrl.bits.DOLedIndication)
+    {
+        greenOffset = 2;
+        redOffset = 3;
+    }
+    if(ShmChargerInfo->Control.SysCtrl.bits.DKLedIndication)
+    {
+        if(connector == 0)
+        {
+            greenOffset = 4;
+            redOffset = 5;
+        }
+        else if(connector == 1)
+        {
+            greenOffset = 2;
+            redOffset = 3;
+        }
+        else
+        {
+            return;
+        }
+    }
+
+    switch(indication)
+    {
+        case _LED_INDICATION_OFF:
+            ShmPrimaryMcuData->OutputDrv.OutputDrvValue[0] &= ~(0x01 << greenOffset);       // green off
+            ShmPrimaryMcuData->OutputDrv.OutputDrvValue[0] &= ~(0x01 << redOffset);         // red off
+            break;
+        case _LED_INDICATION_RUN:
+            ShmPrimaryMcuData->OutputDrv.OutputDrvValue[0] |= (0x01 << greenOffset);        // green on
+            ShmPrimaryMcuData->OutputDrv.OutputDrvValue[0] &= ~(0x01 << redOffset);         // red off
+            break;
+        case _LED_INDICATION_FAULT:
+            ShmPrimaryMcuData->OutputDrv.OutputDrvValue[0] &= ~(0x01 << greenOffset);       // green off
+            ShmPrimaryMcuData->OutputDrv.OutputDrvValue[0] |= (0x01 << redOffset);          // red on
+            break;
+        case _LED_INDICATION_ON:
+            ShmPrimaryMcuData->OutputDrv.OutputDrvValue[0] |= (0x01 << greenOffset);        // green on
+            ShmPrimaryMcuData->OutputDrv.OutputDrvValue[0] |= (0x01 << redOffset);          // red on
+            break;
+        case _LED_INDICATION_GREEN_TOGGLE:
+            if(ShmPrimaryMcuData->OutputDrv.OutputDrvValue[0] & (0x01 << greenOffset))
+            {
+                ShmPrimaryMcuData->OutputDrv.OutputDrvValue[0] &= ~(0x01 << greenOffset);   // green off
+            }
+            else
+            {
+                ShmPrimaryMcuData->OutputDrv.OutputDrvValue[0] |= (0x01 << greenOffset);    // green on
+            }
+            break;
+        case _LED_INDICATION_RED_TOGGLE:
+            if(ShmPrimaryMcuData->OutputDrv.OutputDrvValue[0] & (0x01 << redOffset))
+            {
+                ShmPrimaryMcuData->OutputDrv.OutputDrvValue[0] &= ~(0x01 << redOffset);     // red off
+            }
+            else
+            {
+                ShmPrimaryMcuData->OutputDrv.OutputDrvValue[0] |= (0x01 << redOffset);      // red on
+            }
+            break;
+    }
+}
+
+void MCabinetDOIndication(void)
+{
+    if(ShmSysConfigAndInfo->SysInfo.FirmwareUpdate || ShmSysConfigAndInfo->SysWarningInfo.Level == 2)
+    {
+        _DOLedStatus = _STANDARD_LED_Alarm;
+        if(_preDOLedStatus != _DOLedStatus)
+        {
+            _preDOLedStatus = _DOLedStatus;
+        }
+
+        SetLedStatus(0, _LED_INDICATION_FAULT);
+    }
+    else
+    {
+        if(ShmSysConfigAndInfo->SysInfo.DispenserInfo.PresentDispenserQuantity == 0)
+        {
+            _DOLedStatus = _STANDARD_LED_Disconnection;
+            if(_preDOLedStatus != _DOLedStatus)
+            {
+                _preDOLedStatus = _DOLedStatus;
+
+                // reset led status & indication time
+                GetClockTime(&_DO_LED_time);
+                SetLedStatus(0, _LED_INDICATION_OFF);
+            }
+
+            if((GetTimeoutValue(_DO_LED_time) / mSEC_VAL) >= DO_LED_BLINK_TIME)
+            {
+                SetLedStatus(0, _LED_INDICATION_GREEN_TOGGLE);
+                SetLedStatus(0, _LED_INDICATION_RED_TOGGLE);
+                GetClockTime(&_DO_LED_time);
+            }
+        }
+        else
+        {
+            _DOLedStatus = _STANDARD_LED_Running;
+            if(_preDOLedStatus != _DOLedStatus)
+            {
+                _preDOLedStatus = _DOLedStatus;
+            }
+
+            SetLedStatus(0, _LED_INDICATION_RUN);
+        }
+    }
+}
+
+void MCabinetDKIndication(void)
+{
+    for(int i = 0; i < 2; i++)
+    {
+        if(ShmSysConfigAndInfo->SysInfo.FirmwareUpdate)
+        {
+            _DKLedStatus[i] = _E4YOU_LED_Alarm;
+            if(_preDKLedStatus[i] != _DKLedStatus[i])
+            {
+                _preDKLedStatus[i] = _DKLedStatus[i];
+            }
+
+            SetLedStatus(i, _LED_INDICATION_FAULT);
+        }
+        else if((ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].GeneralChargingData.SystemStatus == S_FAULT ||
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].GeneralChargingData.SystemStatus == S_ALARM) &&
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].Enable)
+        {
+            _DKLedStatus[i] = _E4YOU_LED_Alarm;
+            if(_preDKLedStatus[i] != _DKLedStatus[i])
+            {
+                _preDKLedStatus[i] = _DKLedStatus[i];
+            }
+
+            SetLedStatus(i, _LED_INDICATION_FAULT);
+        }
+        else if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].Enable == false)
+        {
+            _DKLedStatus[i] = _E4YOU_LED_Disconnection;
+            if(_preDKLedStatus[i] != _DKLedStatus[i])
+            {
+                _preDKLedStatus[i] = _DKLedStatus[i];
+
+                // reset led status & indication time
+                GetClockTime(&_DKLed_time[i]);
+                SetLedStatus(i, _LED_INDICATION_OFF);
+            }
+
+            if((GetTimeoutValue(_DKLed_time[i]) / mSEC_VAL) >= DK_LED_BLINK_TIME)
+            {
+                GetClockTime(&_DKLed_time[i]);
+                SetLedStatus(i, _LED_INDICATION_GREEN_TOGGLE);
+                SetLedStatus(i, _LED_INDICATION_RED_TOGGLE);
+            }
+        }
+        else if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].GeneralChargingData.SystemStatus == S_IDLE ||
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].GeneralChargingData.SystemStatus == S_MAINTAIN ||
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].GeneralChargingData.SystemStatus == S_RESERVATION)
+        {
+            _DKLedStatus[i] = _E4YOU_LED_Idle;
+            if(_preDKLedStatus[i] != _DKLedStatus[i])
+            {
+                _preDKLedStatus[i] = _DKLedStatus[i];
+            }
+
+            SetLedStatus(i, _LED_INDICATION_RUN);
+        }
+        else if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].GeneralChargingData.SystemStatus >= S_REASSIGN_CHECK &&
+                ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].GeneralChargingData.SystemStatus <= S_COMPLETE)
+        {
+            _DKLedStatus[i] = _E4YOU_LED_Charging;
+            if(_preDKLedStatus[i] != _DKLedStatus[i])
+            {
+                _preDKLedStatus[i] = _DKLedStatus[i];
+
+                // reset led status & indication time
+                GetClockTime(&_DKLed_time[i]);
+                SetLedStatus(i, _LED_INDICATION_OFF);
+            }
+
+            if((GetTimeoutValue(_DKLed_time[i]) / mSEC_VAL) >= DK_INCHARGING_BLINK_TIME)
+            {
+                GetClockTime(&_DKLed_time[i]);
+                SetLedStatus(i, _LED_INDICATION_GREEN_TOGGLE);
+            }
+        }
+    }
+}
+
+void SCabinetDOIndication(void)
+{
+    if(ShmChargerInfo->SCabinetControl.SCabinetStatus == _DeviceStatus_Idle ||
+        ShmChargerInfo->SCabinetControl.SCabinetStatus == _DeviceStatus_Alarm ||
+        ShmChargerInfo->SCabinetControl.SCabinetStatus == _DeviceStatus_Charging)
+    {
+        if(ShmSysConfigAndInfo->SysInfo.FirmwareUpdate)
+        {
+            _DOLedStatus = _STANDARD_LED_Alarm;
+            if(_preDOLedStatus != _DOLedStatus)
+            {
+                _preDOLedStatus = _DOLedStatus;
+            }
+
+            SetLedStatus(0, _LED_INDICATION_FAULT);
+        }
+        else
+        {
+            _DOLedStatus = _STANDARD_LED_Running;
+            if(_preDOLedStatus != _DOLedStatus)
+            {
+                _preDOLedStatus = _DOLedStatus;
+            }
+
+            SetLedStatus(0, _LED_INDICATION_RUN);
+        }
+    }
+    else
+    {
+        _DOLedStatus = _STANDARD_LED_Disconnection;
+        if(_preDOLedStatus != _DOLedStatus)
+        {
+            _preDOLedStatus = _DOLedStatus;
+
+            // reset led status & indication time
+            GetClockTime(&_DO_LED_time);
+            SetLedStatus(0, _LED_INDICATION_OFF);
+        }
+
+        if((GetTimeoutValue(_DO_LED_time) / mSEC_VAL) >= DO_LED_BLINK_TIME)
+        {
+            SetLedStatus(0, _LED_INDICATION_GREEN_TOGGLE);
+            SetLedStatus(0, _LED_INDICATION_RED_TOGGLE);
+            GetClockTime(&_DO_LED_time);
+        }
+    }
+}
+
+void SCabinetDKIndication(void)
+{
+    if(ShmChargerInfo->SCabinetControl.SCabinetStatus == _DeviceStatus_Idle ||
+        ShmChargerInfo->SCabinetControl.SCabinetStatus == _DeviceStatus_Alarm ||
+        ShmChargerInfo->SCabinetControl.SCabinetStatus == _DeviceStatus_Charging)
+    {
+        for(int i = 0; i < 2; i++)
+        {
+            if(ShmSysConfigAndInfo->SysInfo.FirmwareUpdate)
+            {
+                _DKLedStatus[i] = _E4YOU_LED_Alarm;
+                if(_preDKLedStatus[i] != _DKLedStatus[i])
+                {
+                    _preDKLedStatus[i] = _DKLedStatus[i];
+                }
+
+                SetLedStatus(i, _LED_INDICATION_FAULT);
+            }
+            else
+            {
+                _DKLedStatus[i] = _E4YOU_LED_Idle;
+                if(_preDKLedStatus[i] != _DKLedStatus[i])
+                {
+                    _preDKLedStatus[i] = _DKLedStatus[i];
+                }
+
+                SetLedStatus(i, _LED_INDICATION_RUN);
+            }
+        }
+    }
+    else
+    {
+        for(int i = 0; i < 2; i++)
+        {
+            _DKLedStatus[i] = _E4YOU_LED_Disconnection;
+            if(_preDKLedStatus[i] != _DKLedStatus[i])
+            {
+                _preDKLedStatus[i] = _DKLedStatus[i];
+
+                // reset led status & indication time
+                GetClockTime(&_DKLed_time[i]);
+                SetLedStatus(i, _LED_INDICATION_OFF);
+            }
+
+            if((GetTimeoutValue(_DKLed_time[i]) / mSEC_VAL) >= DK_LED_BLINK_TIME)
+            {
+                GetClockTime(&_DKLed_time[i]);
+                SetLedStatus(i, _LED_INDICATION_GREEN_TOGGLE);
+                SetLedStatus(i, _LED_INDICATION_RED_TOGGLE);
+            }
+        }
+    }
+}
+
+void LedIndicationProcess(void)
+{
+    if(ShmChargerInfo->Control.SysCtrl.bits.DOLedIndication)
+    {
+        if(ShmSysConfigAndInfo->SysInfo.BootingStatus != BOOT_COMPLETE ||
+            ShmSysConfigAndInfo->SysInfo.SelfTestSeq != _STEST_COMPLETE)
+        {
+            SetLedStatus(0, _LED_INDICATION_ON);
+            return;
+        }
+
+        if(ShmChargerInfo->Control.CabinetRole != _CROLE_SLAVE)
+        {
+            MCabinetDOIndication();
+        }
+        else
+        {
+            SCabinetDOIndication();
+        }
+    }
+    if(ShmChargerInfo->Control.SysCtrl.bits.DKLedIndication)
+    {
+        if(ShmSysConfigAndInfo->SysInfo.BootingStatus != BOOT_COMPLETE ||
+            ShmSysConfigAndInfo->SysInfo.SelfTestSeq != _STEST_COMPLETE)
+        {
+            for(int i = 0; i < 2; i++)
+            {
+                SetLedStatus(i, _LED_INDICATION_ON);
+            }
+            return;
+        }
+
+        if(ShmChargerInfo->Control.CabinetRole != _CROLE_SLAVE)
+        {
+            MCabinetDKIndication();
+        }
+        else
+        {
+            SCabinetDKIndication();
+        }
+    }
+}
+
+int main(void)
+{
+    if(InitShareMemory() == FAIL)
+    {
+        #ifdef SystemLogMessage
+        LOG_ERROR("InitShareMemory NG");
+        #endif
+
+        sleep(5);
+        return 0;
+    }
+
+    InitialConnector();
+
+    if(ShmChargerInfo->Control.SysCtrl.bits.DOLedIndication)
+    {
+        _DOLedStatus = _STANDARD_LED_None;
+        _preDOLedStatus = _STANDARD_LED_None;
+        SetLedStatus(0, _LED_INDICATION_ON);
+    }
+    if(ShmChargerInfo->Control.SysCtrl.bits.DKLedIndication)
+    {
+        _DKLedStatus[0] = _E4YOU_LED_None;
+        _DKLedStatus[1] = _E4YOU_LED_None;
+        _preDKLedStatus[0] = _E4YOU_LED_None;
+        _preDKLedStatus[1] = _E4YOU_LED_None;
+        SetLedStatus(0, _LED_INDICATION_ON);
+        SetLedStatus(1, _LED_INDICATION_ON);
+    }
+
+    while(1)
+    {
+        LedIndicationProcess();
+        usleep(100000);
+    }
+
+    return 0;
+}

+ 16 - 0
EVSE/Projects/DO360/Apps/Module_LedIndication.h

@@ -0,0 +1,16 @@
+/*
+ * Module_LedIndication.h
+ *
+ *  Created on: 2021年11月2日
+ *      Author: 7978
+ */
+
+#ifndef MODULE_LEDINDICATION_H_
+#define MODULE_LEDINDICATION_H_
+
+#define DO_LED_BLINK_TIME               1000
+#define DK_LED_BLINK_TIME               1000
+#define DK_INCHARGING_BLINK_TIME        500
+
+
+#endif /* MODULE_LEDINDICATION_H_ */

+ 2 - 2
EVSE/Projects/DO360/Apps/Module_PrimaryComm.c

@@ -379,7 +379,7 @@ void GetInputGpioStatus()
                 ShmPrimaryMcuData->InputDet.bits.Key0);
 		}
         _CabinetSwitch = _TempSwitch;
-        if(_CabinetSwitch >= 0)
+        if(_CabinetSwitch >= 0 && ShmChargerInfo->Control.PrimaryCtrl.bits.CabinetSwitchDetect)
         {
             if(ShmChargerInfo->Control.CabinetSwitch != _CabinetSwitch)
             {
@@ -529,7 +529,7 @@ int main(void)
 
 	for(;;)
 	{
-	    if(!ShmSysConfigAndInfo->SysInfo.FirmwareUpdate)
+	    if(!ShmChargerInfo->Control.PrimaryCtrl.bits.Paused)
 	    {
             // 程序開始之前~ 必須先確定 FW 版本與硬體版本,確認後!!~ 該模組才算是真正的 Initial Comp.
             // 模組更新 FW 後,需重新做

+ 79 - 8
EVSE/Projects/DO360/Apps/Module_PsuComm.c

@@ -456,6 +456,10 @@ void GetStatusCallback(byte group, byte SN, byte temp, int alarm)
                 ShmPsuPosition->ReInitPsuLocation = true;
             }
         }
+        else
+        {
+            ShmPsuData->PsuGroup[group].PsuModule[ShmPsuPosition->PsuAddressInfo[SN].GIndex].CriticalTemp1 = temp;
+        }
     }
 }
 
@@ -696,14 +700,15 @@ void GetMisCallback(byte address, unsigned int value, byte type)
     }
     else if (type == 2)
     {
-        ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp1 = value;
-        ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp2 = value;
-        ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp3 = value;
+        //ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp1 = value;
+        //ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp2 = value;
+        //ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp3 = value;
         ShmPsuData->PsuGroup[group].PsuModule[gIndex].ExletTemp = value;
     }
     else if (type == 3)
     {
         //printf("PFC - group = %d, index = %d, value = %d \n", group, address, value);
+        ShmPsuData->PsuGroup[group].PsuModule[gIndex].InletTemp = value;
     }
 }
 
@@ -879,7 +884,7 @@ void GetOutputAndTempCallback(byte address, unsigned short outputVol_s,
         return;
     }
 
-    ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp1 = Temperature;
+    //ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp1 = Temperature;
     ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp2 = Temperature;
     ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp3 = Temperature;
 }
@@ -1175,6 +1180,7 @@ void ShowGroupAvailableCurrentPower(unsigned char group)
     }
 }
 
+unsigned char _TempType = 0;
 void PsuGroupRoutineQuery(void)
 {
     for(byte group = 0; group < GENERAL_GUN_QUANTITY; group++)
@@ -1199,7 +1205,14 @@ void PsuGroupRoutineQuery(void)
             else if (psuCmdSeq == _PSU_CMD_TEMP)
             {
                 // 取得模塊溫度
-                GetDcTemperature(group);
+                if(_TempType == _PSU_TMP_DCDC)
+                {
+                    GetDcTemperature(group);
+                }
+                else
+                {
+                    GetPfcTemperature(group);
+                }
             }
         }
     }
@@ -1215,6 +1228,8 @@ void PsuGroupRoutineQuery(void)
     else if(psuCmdSeq == _PSU_CMD_IVAILIABLE)
     {
         psuCmdSeq = _PSU_CMD_TEMP;
+
+        _TempType = _TempType == _PSU_TMP_DCDC ? _PSU_TMP_PFC : _PSU_TMP_DCDC;
     }
     else
     {
@@ -2783,6 +2798,48 @@ void SetMemberPowerOffDone(unsigned char master)
     }
 }
 
+unsigned char _ParallelRelay[MAX_GROUP_QUANTITY];
+void SetPCabinetParallelRelay(unsigned short parallelConfig)
+{
+    bool change = false;
+
+    if(ShmChargerInfo->Control.CabinetRole == _CROLE_MASTER)
+    {
+        for(int i = 0; i < MAX_SLAVE_CABINET_QUANTITY; i++)
+        {
+            change = false;
+            if(ShmChargerInfo->ParallelCabinet.PCabinet[i].LocalStatus == _DeviceStatus_Idle ||
+                ShmChargerInfo->ParallelCabinet.PCabinet[i].LocalStatus == _DeviceStatus_Alarm ||
+                ShmChargerInfo->ParallelCabinet.PCabinet[i].LocalStatus == _DeviceStatus_Charging)
+            {
+                for(int j = 0; j < GENERAL_GUN_QUANTITY; j++)
+                {
+                    _ParallelRelay[j] = (parallelConfig & (1 << j)) > 0 ? YES : NO;
+
+                    if(_ParallelRelay[i] != ShmChargerInfo->ParallelCabinet.PCabinet[i].ParallelRelaySetting[i])
+                    {
+                        change = true;
+                    }
+                }
+
+                if(change)
+                {
+                    char strParallel[128];
+                    sprintf(strParallel, "Set PCabinet %d Parallel Relay:", i + 1);
+                    for(int j = 0; j < GENERAL_GUN_QUANTITY; j++)
+                    {
+                        char strState[8];
+                        sprintf(strState, " %3s", _ParallelRelay[j] ? "ON" : "OFF");
+                        strcat(strParallel, strState);
+                    }
+                    LOG_INFO("%s", strParallel);
+                }
+                ShmChargerInfo->ParallelCabinet.PCabinet[i].ParallelRelaySetting[i] = _ParallelRelay[i];
+            }
+        }
+    }
+}
+
 // master: master group index
 // Yes_No: Yes: relay on, No: relay off
 // role_condition: when role_condition = _GROLE_MASTER, parallel relay of all member do the action(on or off)
@@ -2820,6 +2877,8 @@ void SetParallelRelayOnOff(unsigned char master, unsigned char Yes_No, unsigned
         {
             ShmPsuGrouping->ParallelRelayConfig.CtrlValue &= ~ShmPsuGrouping->GroupCollection[master].ParallelCheck;
         }
+
+        SetPCabinetParallelRelay(ShmPsuGrouping->ParallelRelayConfig.CtrlValue);
     }
 }
 
@@ -3980,7 +4039,9 @@ int main(void)
 		// 斷電狀態
         if (ShmChargerInfo->Control.RelayCtrl.bits.AcContactor == NO ||
             ShmChargerInfo->Control.RelayCtrl.bits.AcContactorOffByPsu == YES ||
-            ShmChargerInfo->Control.RelayCtrl.bits.AcContactorOffByEmergency == YES)
+            ShmChargerInfo->Control.RelayCtrl.bits.AcContactorOffByEmergency == YES ||
+            ShmChargerInfo->Control.PsuCtrl.bits.NeedSelfTest == YES ||
+            ShmChargerInfo->Control.PsuCtrl.bits.Paused == YES)
 		{
 			//一但 AC Off PSU 斷電全部的 PSU Group ID 會全部清 0
 			if (!isInitialComp)
@@ -3994,6 +4055,12 @@ int main(void)
 				InitialPsuData();
 				isInitialComp = YES;
 			}
+			if(ShmChargerInfo->Control.PsuCtrl.bits.NeedSelfTest)
+			{
+			    ShmChargerInfo->Control.PsuCtrl.bits.NeedSelfTest = NO;
+			    ShmChargerInfo->Control.PsuCtrl.bits.SelfTestOK = NO;
+			    LOG_INFO("Psu Need Execute Self Test!");
+			}
 			sleep(1);
 			continue;
 		}
@@ -4317,11 +4384,15 @@ int main(void)
                     LOG_INFO("== PSU == BOOTING_COMPLETE");
                 }
 
-				if(ShmChargerInfo->Control.SysCtrl.bits.SelfTestOK)
+				if(ShmChargerInfo->Control.PsuCtrl.bits.SelfTestOK)
 				{
 					ShmPsuData->Work_Step = _WORK_CHARGING;
 				}
-				ShmChargerInfo->Control.SysCtrl.bits.SelfTestOK = true;
+				else
+				{
+				    LOG_INFO("== PSU == Self Test OK!");
+				}
+				ShmChargerInfo->Control.PsuCtrl.bits.SelfTestOK = true;
 				sleep(1);
 			}
 				break;

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

@@ -60,6 +60,12 @@ int connector_2[12];
 byte conn_1_count = 0;
 byte conn_2_count = 0;
 
+enum _PSU_TEMP_TYPE
+{
+    _PSU_TMP_DCDC       = 0,
+    _PSU_TMP_PFC        = 1,
+};
+
 enum _PSU_CMD_SEQ
 {
 	_PSU_CMD_STATUS		= 1,

+ 122 - 16
EVSE/Projects/DO360/Apps/ReadCmdline.c

@@ -62,6 +62,8 @@ struct PsuData 					*ShmPsuData;
 ChargerInfoData                 *ShmChargerInfo;
 PsuPositionInfoData             *ShmPsuPosition;
 PsuGroupingInfoData             *ShmPsuGrouping;
+struct OCPP16Data               *ShmOCPP16Data;
+struct OCPP20Data               *ShmOCPP20Data;
 
 struct ChargingInfoData 		*_chargingData[CONNECTOR_QUANTITY];
 struct ChargingInfoData 		*ac_chargingInfo[AC_QUANTITY];
@@ -239,6 +241,25 @@ int InitShareMemory()
     {
         result = FAIL;
     }
+
+    if ((MeterSMId = shmget(ShmOcppModuleKey, sizeof(struct OCPP16Data), 0777)) < 0)
+    {
+        result = FAIL;
+    }
+    else if ((ShmOCPP16Data = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        result = FAIL;
+    }
+
+    if ((MeterSMId = shmget(ShmOcpp20ModuleKey, sizeof(struct OCPP20Data), 0777)) < 0)
+    {
+        result = FAIL;
+    }
+    else if ((ShmOCPP20Data = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        result = FAIL;
+    }
+
     if(result == PASS)
     {
         ShmPsuPosition = &ShmChargerInfo->PsuPosition;
@@ -425,7 +446,7 @@ void ShowFwVer(void)
             ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].LocalStatus != _DS_Timeout)
         {
             printf(", Model Name: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].ModelName);
-            printf("\r\n Csu Bootload: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].CsuBootLoadFwRev);
+            printf("\r\n  Csu Bootload: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].CsuBootLoadFwRev);
             //printf("\r\n   Csu Kernel: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].CsuKernelFwRev);
             printf("\r\n    Csu Kernel: ");
             for(int j = 0; j < strlen((char *)ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].CsuKernelFwRev); j++)
@@ -436,13 +457,13 @@ void ShowFwVer(void)
                     printf("%c", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].CsuKernelFwRev[j]);
                 }
             }
-            printf("\r\n  Csu Root Fs: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].CsuRootFsFwRev);
-            printf("\r\n  Csu Primary: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].CsuPrimFwRev);
-            printf("\r\n   Fan Module: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].FanModuleFwRev);
-            printf("\r\n Relay Module: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].RelayModuleFwRev);
-            printf("\r\n  Connector 1: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].Connector1FwRev);
-            printf("\r\n  Connector 2: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].Connector2FwRev);
-            printf("\r\n   Led Module: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].LedModuleFwRev);
+            printf("\r\n   Csu Root Fs: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].CsuRootFsFwRev);
+            printf("\r\n   Csu Primary: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].CsuPrimFwRev);
+            printf("\r\n    Fan Module: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].FanModuleFwRev);
+            printf("\r\n  Relay Module: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].RelayModuleFwRev);
+            printf("\r\n   Connector 1: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].Connector1FwRev);
+            printf("\r\n   Connector 2: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].Connector2FwRev);
+            printf("\r\n    Led Module: %s", ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].LedModuleFwRev);
         }
     }
     printf("\r\n\r\n");
@@ -685,8 +706,9 @@ void SetGFDMode(char *v1)
 	ShmSysConfigAndInfo->SysConfig.AlwaysGfdFlag = mode;
 }
 
-// Gun  Temp  Chiller  PSU 0  PSU 1  PSU 2  ...
-//  1    XXX    XXX     XXX    XXX    XXX    XXX
+//                        PSU 0        PSU 1        PSU 2        ...
+// Gun  Temp  Chiller   DD/PFC/Amb   DD/PFC/Amb   DD/PFC/Amb   DD/PFC/Amb
+//  1    XXX    XXX    XXX/XXX/XXX  XXX/XXX/XXX  XXX/XXX/XXX  XXX/XXX/XXX
 void GetTemperature(char *v1)
 {
     bool show = false;
@@ -699,7 +721,8 @@ void GetTemperature(char *v1)
     }
     do
     {
-        printf("\r\n Gun  Temp  Chiller  PSU 0  PSU 1  PSU 2  ...");
+        printf("\r\n                        PSU 0        PSU 1        PSU 2        .....");
+        printf("\r\n Gun  Temp  Chiller   DD/PFC/Amb   DD/PFC/Amb   DD/PFC/Amb   DD/PFC/Amb");
         for(int i = 0; i < CONNECTOR_QUANTITY; i++)
         {
             sprintf(strGunTemp, "N/A");
@@ -717,10 +740,13 @@ void GetTemperature(char *v1)
 
             for(int j = 0; j < ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity; j++)
             {
-                printf("   %3d ", ShmPsuData->PsuGroup[i].PsuModule[j].ExletTemp);
+                printf("  %3d/%3d/%3d",
+                    ShmPsuData->PsuGroup[i].PsuModule[j].ExletTemp,
+                    ShmPsuData->PsuGroup[i].PsuModule[j].InletTemp,
+                    ShmPsuData->PsuGroup[i].PsuModule[j].CriticalTemp1);
             }
         }
-        printf("\r\n");
+        printf("\r\n\r\n");
 
         if(show)
         {
@@ -2738,20 +2764,31 @@ void SetGpio(char *v1, char *v2)
 
 void ShowStatus(void)
 {
+    char *str_cabinet_role[] = {STR_CABINET_ROLE_NONE, STR_CABINET_ROLE_MASTER, STR_CABINET_ROLE_SLAVE};
+
     for(int i = 0; i < ShmChargerInfo->Control.MaxConnector; i++)
     {
-        printf("\r\nGun %d Status = %d, Available = %d", i + 1, _chargingData[i]->SystemStatus, _chargingData[i]->IsAvailable);
+        printf("\r\nGun %d Status = %d, IsAvailable = %d, GunEnable = %d",
+            i + 1,
+            _chargingData[i]->SystemStatus,
+            _chargingData[i]->IsAvailable,
+            ShmChargerInfo->Control.GunAvailable[i]);
         printf("\r\nAlarmCode");
-        printf("\r\n Connector = %6s, EvConn = %6s, Remote = %6s",
+        printf("\r\n Connector = %6s, EvConn = %6s, Remote = %6s, Vendor = %6s",
             strncmp((char *)_chargingData[i]->ConnectorAlarmCode, "", 6) != 0 ?
                     (char *)_chargingData[i]->ConnectorAlarmCode : "No Err",
             strncmp((char *)_chargingData[i]->EvConnAlarmCode, "", 6) != 0 ?
                     (char *)_chargingData[i]->ConnectorAlarmCode : "No Err",
             strncmp((char *)ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].RemotenAlarmCode, "", 6) != 0 ?
-                    (char *)ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].RemotenAlarmCode : "No Err");
+                    (char *)ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].RemotenAlarmCode : "No Err",
+            strncmp((char *)ShmOCPP16Data->StatusNotification[i].VendorErrorCode, "", 6) != 0 ?
+                    (char *)ShmOCPP16Data->StatusNotification[i].VendorErrorCode : "No Err");
     }
     printf("\r\n");
 
+    printf("\r\nPower Cabinet Role: %s, Switch Value: %d",
+        ShmChargerInfo->Control.CabinetSwitch <= _CROLE_SLAVE ? str_cabinet_role[ShmChargerInfo->Control.CabinetSwitch] : "Unknown",
+        ShmChargerInfo->Control.CabinetSwitch);
     printf("\r\nStatus Code Len = %d", ShmSysConfigAndInfo->SysWarningInfo.WarningCount);
     if(ShmSysConfigAndInfo->SysWarningInfo.WarningCount > 0)
     {
@@ -2885,6 +2922,60 @@ void ShowChargerLimit(void)
     printf("\r\n\r\n");
 }
 
+void SetGunCommand(char *v1, char *v2, char *v3)
+{
+    int cmdItem = 0;
+    int cmdItemLen = 2;
+    int gunID = 0;
+    int enable = 0;
+    char strGunCmd[32][32] = {"enable", "operative"};
+    char strDescription[32][32] = {"Available", "Operative"};
+
+    gunID = atoi(v2);
+    enable = atoi(v3);
+
+    if(gunID <= 0 || gunID > CONNECTOR_QUANTITY || enable < 0)
+    {
+        return;
+    }
+    for(int i = 0; i < cmdItemLen; i++)
+    {
+        if(strcmp((char *)&strGunCmd[i][0], v1) == 0)
+        {
+            cmdItem = i + 1;
+            break;
+        }
+    }
+
+    if(cmdItem != 0)
+    {
+        switch(cmdItem)
+        {
+            case 1:
+                ShmChargerInfo->Control.GunAvailable[gunID - 1] = enable > 0 ? YES : NO;
+                ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gunID - 1].Parameter.bits.AvailabilityRequest = true;
+                break;
+            case 2:
+                _chargingData[gunID - 1]->IsAvailable = enable > 0 ? YES : NO;
+                ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gunID - 1].Parameter.bits.AvailabilityRequest = true;
+                break;
+        }
+
+        printf("Gun cmd [%s] [%s]\n", strDescription[cmdItem - 1], enable ? "Enable" : "Disable");
+    }
+    else
+    {
+        printf("Gun cmd %s not found\n", v1);
+
+        for(int i = 0; i < cmdItemLen; i++)
+        {
+            printf(" [%s] -> %s Test\n", strGunCmd[i], strDescription[i]);
+        }
+    }
+
+    printf("\r\n");
+}
+
 int main(void)
 {
 	if(InitShareMemory() == FAIL)
@@ -3256,6 +3347,21 @@ int main(void)
         else if(strcmp(newString[0], "limit") == 0)
         {
             ShowChargerLimit();
+        }
+        else if(strcmp(newString[0], "pcmd") == 0)
+        {
+
+        }
+        else if(strcmp(newString[0], "gcmd") == 0)
+        {
+            if(strcmp(newString[1], "-1") == 0 || strcmp(newString[1], "") == 0 ||
+                strcmp(newString[2], "-1") == 0 || strcmp(newString[2], "") == 0 ||
+                strcmp(newString[3], "-1") == 0 || strcmp(newString[3], "") == 0)
+            {
+                printf ("Input cmd fail ------  gcmd [cmd] [gun] [value]\n\n");
+                continue;
+            }
+            SetGunCommand(newString[1], newString[2], newString[3]);
         }
 		else
 			printf ("%s\n", msg);

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

@@ -9,6 +9,9 @@ pkill Module_4g
 pkill Module_Wifi
 pkill OcppBackend
 pkill Module_ProduceUtils
+pkill Module_ChargerSelfTest
+pkill Module_CabinetParallel
+pkill Module_LedIndication
 pkill main
 
 sleep 1

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 639 - 327
EVSE/Projects/DO360/Apps/main.c


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


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


Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio