Просмотр исходного кода

2021-07-27 / Wendell

Actions
1. add grouping function
2. fix factory size, model name & sn issue
3. fix cabinet does not re-start after write model name & sn in some case
4. fix hard reboot issue(dispenser do not reboot)
5. fix misc command issue
6. fix cabinet will charging fail when received stop charging flag at idle mode
7. fix initial function logic
8. add cabinet output voltage & current packet (cabinet to dispenser)
9. add packet of temperature of connector and chiller (dispenser to cabinet)
10.add 4g/wifi reset logic (disconnect internet & backend)
11.add manual stop, start soc, force charging
12.modify charging voltage & current log logic
13.update u-boot.img

Files
1. As follow commit history

Image version : V1.00.XX.XXXX.XX
Wendell 3 лет назад
Родитель
Сommit
db8b46994f

+ 23 - 9
EVSE/Projects/DO360/Apps/Config.h

@@ -11,7 +11,7 @@
 
 typedef unsigned char			    byte;
 
-
+
 #define MODE_BOOT					0
 #define MODE_IDLE					1
 #define MODE_AUTHORIZING			2
@@ -171,8 +171,11 @@ enum _MODULE_PSU_WORK_STEP
 {
 	INITIAL_START 		= 		0,
 	GET_PSU_COUNT 		= 		1,
-	GET_SYS_CAP			=		2,
-	BOOTING_COMPLETE 	= 		3,
+	Get_PSU_LOCATION    =       2,
+	Get_PSU_VERSION     =       3,
+	PSU_COUNT_CONFIRM   =       4,
+	GET_SYS_CAP			=		5,
+	BOOTING_COMPLETE 	= 		6,
 
 	_WORK_CHARGING 		= 		10,
 
@@ -310,7 +313,8 @@ typedef union
         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 res:22;
+        unsigned int BackendEnable:1;               // 0: backend disable,          1: backend enable
+        unsigned int res:21;
     }bits;
 }SystemControl;
 
@@ -331,7 +335,12 @@ typedef union
     unsigned int CtrlValue;
     struct
     {
-        unsigned int res:32;
+        unsigned int MsgMain:1;                     // 0: no effect,                1: enable debug message in main
+        unsigned int MsgPrimaryComm:1;              // 0: no effect,                1: enable debug message in primary comm
+        unsigned int MsgPsu:1;                      // 0: no effect,                1: enable debug message in psu
+        unsigned int MsgEvComm:1;                   // 0: no effect,                1: enable debug message in ev comm
+        unsigned int MsgInternalComm:1;             // 0: no effect,                1: enable debug message in internal comm
+        unsigned int res:27;
     }bits;
 }DebugControl;
 
@@ -519,9 +528,11 @@ typedef union
         // MasterCtrlValue
         unsigned int AlreadyInChargingMode:1;                   // 0: no effect,                1: system status ever enter charging mode
         unsigned int ExtendAvailable:1;                         // 0: no effect,                1: extend capability is available
-        unsigned int NeedCurrentBalanceCheck:1;                 // 0: no effect,                1: need to current balance
+        unsigned int NeedCurrentBalance:1;                      // 0: no effect,                1: need to current balance
         unsigned int OutputCurrentStable:1;                     // 0: no effect,                1: output current is stable
-        unsigned int MasterCtrlRes:28;
+        unsigned int ReachMaxCurrentDemand:1;                   // 0: no effect,                1: reach ev max current demand
+        unsigned int ReachMaxStageCurrent:1;                    // 0: no effect,                1: reach ev max stage current
+        unsigned int MasterCtrlRes:26;
 
         // StopChargingCtrlValue
         unsigned int StopChargingRequest:1;                     // 0: no effect,                1: master need to stop
@@ -555,15 +566,18 @@ typedef union
 
         // SlaveCtrlValue
         unsigned int SlaveChargingRequest:1;                    // 0: no effect,                1: request slave to charging after power off
+        unsigned int CheckSlaveReady:1;                         // 0: no effect,                1: check if slave is ready
+        unsigned int WaitSlaveReady:1;                          // 0: no effect,                1: wait slave is ready
         unsigned int SlavePowerOffRequest:1;                    // 0: no effect,                1: request slave to power off
         unsigned int SlavePowerOffConfirmed:1;                  // 0: no effect,                1: slave power off confirmed
-        unsigned int SlaveCtrlRes:29;
+        unsigned int SlaveCtrlRes:27;
     }bits;
 }PsuGroupControl;
 
 typedef struct
 {
-    unsigned short          Quantity;
+    unsigned char           Quantity;
+    unsigned char           RealQuantity;
     unsigned char           Member[MAX_GROUP_QUANTITY];         // record slave group index
 }PsuGroupPartner;
 

+ 119 - 94
EVSE/Projects/DO360/Apps/FactoryConfig.c

@@ -39,6 +39,7 @@
 #define OUTPUT_FILE			0x02
 
 struct SysConfigData 			SysConfig;
+struct SysConfigAndInfo         *ShmSysConfigAndInfo;
 
 int StoreLogMsg(const char *fmt, ...);
 
@@ -68,14 +69,64 @@ int StoreLogMsg(const char *fmt, ...)
 	return rc;
 }
 
+int runShellCmd(const char *cmd)
+{
+    int result = FAIL;
+    char buf[256];
+    FILE *fp;
+
+    fp = popen(cmd, "r");
+    if(fp != NULL)
+    {
+        while(fgets(buf, sizeof(buf), fp) != NULL)
+        {
+            StoreLogMsg("%s\n", buf);
+        }
+
+        result = PASS;
+    }
+    pclose(fp);
+
+    return result;
+}
+
+//==========================================
+// Init all share memory
+//==========================================
+int InitShareMemory()
+{
+    int result = PASS;
+    int MeterSMId;
+
+    //creat ShmSysConfigAndInfo
+    if((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo),  0777)) < 0)
+    {
+        StoreLogMsg("shmget ShmSysConfigAndInfo NG\n");
+
+        result = FAIL;
+    }
+    else if ((ShmSysConfigAndInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1)
+    {
+        StoreLogMsg("shmat ShmSysConfigAndInfo NG\n");
+
+        result = FAIL;
+     }
+    else
+    {
+
+    }
+
+    return result;
+}
+
 void helpOutput(void)
 {
-	printf("Usage: Module_FactoryConfig [OPTION]...\r\n\r\n");
-	printf("Generate factory default configuration value\r\n\r\n");
-	printf("OPTION:\r\n");
-	printf("	-a Write to file(/mnt) & flash\r\n");
-	printf("	-f Write to file(/mnt)\r\n");
-	printf("	-m Write to flash\r\n");
+    printf("Usage: Module_FactoryConfig [OPTION]...\r\n\r\n");
+    printf("Generate factory default configuration value\r\n\r\n");
+    printf("OPTION:\r\n");
+    printf("    -a Write to file(/mnt) & flash\r\n");
+    printf("    -f Write to file(/mnt)\r\n");
+    printf("    -m Write to flash\r\n");
 }
 
 /**************************************************************************************/
@@ -85,7 +136,7 @@ void helpOutput(void)
 int main(int argc,char *argv[])
 {
 	unsigned char outType=0;
-	unsigned int i,Chk, MtdBlockSize=0x600000;
+	unsigned int i,Chk, MtdBlockSize=0x300000;
 	unsigned char *ptr;
 	int fd,wrd;
 
@@ -105,23 +156,30 @@ int main(int argc,char *argv[])
 	*/
 	//********** System **********// udhcpc -i eth1 -s ./dhcp_script/eth1.script
 	//
-    if (argc == 4)
-    {
-        strcpy((char *)SysConfig.ModelName, argv[2]);
-        strcpy((char *)SysConfig.SerialNumber, argv[3]);
-    }
-    else
+    time_t t = time(NULL);
+    struct tm tm = *localtime(&t);
+
+    // Initial Share Memory
+    if(InitShareMemory() == FAIL)
     {
+        StoreLogMsg("InitShareMemory NG\n");
+
+        //strcpy((char*)SysConfig.ModelName, "");
+        //strcpy((char*)SysConfig.SerialNumber, "");
         strcpy((char *)SysConfig.ModelName, "DOYC182000D2AD");
         strcpy((char *)SysConfig.SerialNumber, "NeedSetupSN");
+        sleep(5);
     }
+    else
+    {
+        memcpy((char*)SysConfig.ModelName, ShmSysConfigAndInfo->SysConfig.ModelName, ARRAY_SIZE(ShmSysConfigAndInfo->SysConfig.ModelName));
+        memcpy((char*)SysConfig.SerialNumber, ShmSysConfigAndInfo->SysConfig.SerialNumber, ARRAY_SIZE(ShmSysConfigAndInfo->SysConfig.SerialNumber));
 
-	memset(SysConfig.SystemId, 0x00, sizeof(SysConfig.SystemId));
-
-	strcat((char *)SysConfig.SystemId, (char *)SysConfig.ModelName);
-	strcat((char *)SysConfig.SystemId, (char *)SysConfig.SerialNumber);
+        StoreLogMsg("InitShareMemory OK.\n");
+    }
 
-	strcpy((char *)SysConfig.SystemDateTime, "");
+    sprintf((char*)SysConfig.SystemId, "%s%s", SysConfig.ModelName, SysConfig.SerialNumber);
+    sprintf((char*)SysConfig.SystemDateTime, "%d-%d-%d %d:%d:%d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
 	SysConfig.AuthorisationMode = AUTH_MODE_ENABLE;
 	SysConfig.DefaultLanguage = 0;
 	SysConfig.RfidCardNumEndian = 0;
@@ -154,7 +212,7 @@ int main(int argc,char *argv[])
 	SysConfig.Eth1Interface.EthDhcpClient = 0;
 	strcpy((char *) SysConfig.Eth1Interface.EthIpAddress, "192.168.100.1");
 	strcpy((char *) SysConfig.Eth1Interface.EthSubmaskAddress, "255.255.255.0");
-	strcpy((char *) SysConfig.Eth1Interface.EthGatewayAddress, "192.168.0.254");
+	strcpy((char *) SysConfig.Eth1Interface.EthGatewayAddress, "192.168.100.254");
 	SysConfig.AthInterface.WifiMode = 0;
 	SysConfig.TelecomInterface.TelcomEnabled = 0;
 	strcpy((char *) SysConfig.AthInterface.WifiSsid, "");
@@ -198,12 +256,12 @@ int main(int argc,char *argv[])
 	memcpy(ptr,&SysConfig,sizeof(struct SysConfigData));
 
 	//calculate CRC
-	Chk=0;
-	for(i=0;i<(MtdBlockSize-4);i++)
-	{
-		Chk+=*(ptr+i);
-	}
-	memcpy(	ptr+MtdBlockSize-4,&Chk,4);
+    Chk = 0;
+    for(i = ARRAY_SIZE(SysConfig.CsuBootLoadFwRev); i < (MtdBlockSize - 4); i++)
+    {
+        Chk += *(ptr + i);
+    }
+    memcpy(ptr + MtdBlockSize - 4, &Chk, 4);
 
 	/*
 	* Parameter process
@@ -244,82 +302,49 @@ int main(int argc,char *argv[])
 	/*
 	 * Configuration bin file generate
 	*/
-	if((outType&OUTPUT_FILE)>0)
-	{
-		fd = open("/mnt/FactoryDefaultConfig.bin", O_RDWR | O_CREAT);
-		if (fd < 0)
-		{
-			StoreLogMsg("[FactoryConfig]main: open /mnt/FactoryDefaultConfig.bin NG");
-			free(ptr);
-			return 0;
-		}
-		wrd=write(fd, ptr, MtdBlockSize);
-		close(fd);
-		if(wrd<MtdBlockSize)
-		{
-			StoreLogMsg("write /mnt/FactoryDefaultConfig.bin NG\r\n");
-			free(ptr);
-			return 0;
-		}
-		StoreLogMsg("FactoryConfig write to file in /mnt OK.\r\n");
-	}
+    fd = open("/mnt/FactoryDefaultConfig.bin", O_RDWR | O_CREAT | O_TRUNC);
+    if(fd < 0)
+    {
+        StoreLogMsg("[FactoryConfig]main: open /mnt/FactoryDefaultConfig.bin NG");
+        free(ptr);
+        return 0;
+    }
+    wrd = write(fd, ptr, MtdBlockSize);
+    close(fd);
+    if(wrd < MtdBlockSize)
+    {
+        StoreLogMsg("write /mnt/FactoryDefaultConfig.bin NG\r\n");
+        free(ptr);
+        return 0;
+    }
+    StoreLogMsg("FactoryConfig write to file in /mnt OK.\r\n");
 
 	/*
 	* Flash memory write
 	*/
-	if((outType&OUTPUT_FLASH)>0)
+	if((outType & OUTPUT_FLASH) > 0)
 	{
-		// Save factory default setting value to flash factory default setting block
-		fd = open("/dev/mtdblock12", O_RDWR);
-		if (fd < 0)
-		{
-			StoreLogMsg("open /dev/mtdblock12 NG\r\n");
-			free(ptr);
-			return 0;
-		}
-		wrd=write(fd, ptr, MtdBlockSize);
-		close(fd);
-		if(wrd<MtdBlockSize)
-		{
-			StoreLogMsg("write /dev/mtdblock12 NG\r\n");
-			free(ptr);
-			return 0;
-		}
+        // Save factory default setting value to flash setting block
+        StoreLogMsg("Erase /dev/mtd10.\n");
+        runShellCmd("flash_erase /dev/mtd10 0 0");
+        StoreLogMsg("Write /dev/mtd10.\n");
+        runShellCmd("nandwrite -p /dev/mtd10 /mnt/FactoryDefaultConfig.bin");
 
-		// Save factory default setting value to flash backup setting block
-		fd = open("/dev/mtdblock11", O_RDWR);
-		if (fd < 0)
-		{
-			StoreLogMsg("open /dev/mtdblock11 NG\r\n");
-			free(ptr);
-			return 0;
-		}
-		wrd=write(fd, ptr, MtdBlockSize);
-		close(fd);
-		if(wrd<MtdBlockSize)
-		{
-			StoreLogMsg("write /dev/mtdblock11 NG\r\n");
-			free(ptr);
-			return 0;
-		}
+        // Save factory default setting value to flash backup setting block
+        StoreLogMsg("Erase /dev/mtd11.\n");
+        runShellCmd("flash_erase /dev/mtd11 0 0");
+        StoreLogMsg("Write /dev/mtd11.\n");
+        runShellCmd("nandwrite -p /dev/mtd11 /mnt/FactoryDefaultConfig.bin");
 
-		// Save factory default setting value to flash setting block
-		fd = open("/dev/mtdblock10", O_RDWR);
-		if (fd < 0)
-		{
-			StoreLogMsg("open /dev/mtdblock10 NG\r\n");
-			free(ptr);
-			return 0;
-		}
-		wrd=write(fd, ptr, MtdBlockSize);
-		close(fd);
-		if(wrd<MtdBlockSize)
-		{
-			StoreLogMsg("write /dev/mtdblock10 NG\r\n");
-			free(ptr);
-			return 0;
-		}
-		StoreLogMsg("FactoryConfig write to flash OK\r\n");
+        // Save factory default setting value to flash factory default setting block
+        StoreLogMsg("Erase /dev/mtd12.\n");
+        runShellCmd("flash_erase /dev/mtd12 0 0");
+        StoreLogMsg("Write /dev/mtd12.\n");
+        runShellCmd("nandwrite -p /dev/mtd12 /mnt/FactoryDefaultConfig.bin");
+
+        system("rm -f /mnt/FactoryDefaultConfig.bin");
+
+        StoreLogMsg("FactoryConfig write to flash OK\r\n");
 	}
 
 	free(ptr);

+ 956 - 0
EVSE/Projects/DO360/Apps/InfyGroup_PsuCommObj.c

@@ -0,0 +1,956 @@
+/*
+ * Infypwr_PsuCommObj.c
+ *
+ *  Created on: 2019年11月26日
+ *      Author: 7564
+ */
+
+#include "InfyGroup_PsuCommObj.h"
+
+#define ARRAY_SIZE(A)		(sizeof(A) / sizeof(A[0]))
+#define NO		0
+#define YES		1
+
+#define DEBUG_LIB						1
+
+void PRINTF_LIB_FUNC(char *string, ...);
+float IEEE_754_to_float(const byte raw[4]);
+
+//================================================
+// Private function
+//================================================
+void PRINTF_LIB_FUNC(char *string, ...)
+{
+	if (DEBUG_LIB)
+	{
+		va_list args;
+		char buffer[4096];
+
+		va_start(args, string);
+		vsnprintf(buffer, sizeof(buffer), string, args);
+		va_end(args);
+		printf("%s \n", buffer);
+	}
+}
+
+float IEEE_754_to_float(const byte raw[4])
+{
+    float fValue = 0;
+    byte *pbyte = (byte *)&fValue;
+
+    *(pbyte + 0) = raw[3];
+    *(pbyte + 1) = raw[2];
+    *(pbyte + 2) = raw[1];
+    *(pbyte + 3) = raw[0];
+
+    return fValue;
+}
+
+//================================================
+// Callback function
+//================================================
+void RefreshStatus(void *func)
+{
+	return_status = func;
+}
+
+void RefreshModuleCount(void *func)
+{
+	return_module_count = func;
+}
+
+void RefreshAvailableCap(void *func)
+{
+	return_available_cap = func;
+}
+
+void RefreshFwVersion(void *func)
+{
+	return_fw_version = func;
+}
+
+void RefreshInputVol(void *func)
+{
+	return_input_vol = func;
+}
+
+void RefreshGetOutput(void *func)
+{
+	return_get_output = func;
+}
+
+void RefreshGetOutputF(void *func)
+{
+	return_get_output_float = func;
+}
+
+void RefreshMisInfo(void *func)
+{
+	return_mis_info = func;
+}
+
+void RefreshIavailable(void *func)
+{
+	return_iavail_info = func;
+}
+
+void AutoMode_RefreshOutputAndTemp(void *func)
+{
+	return_output_temp = func;
+}
+
+void AutoMode_RefreshModuleStatus(void *func)
+{
+	return_module_status = func;
+}
+
+void AutoMode_RefreshModuleInput(void *func)
+{
+	return_module_input = func;
+}
+
+//================================================
+// CANBUS initialization
+//================================================
+int InitCanBus()
+{
+	int 					s0,nbytes;
+	struct timeval			tv;
+	struct ifreq 			ifr0;
+	struct sockaddr_can		addr0;
+
+	system("/sbin/ip link set can1 down");
+	system("/sbin/ip link set can1 type can bitrate 500000 restart-ms 100");
+	system("/sbin/ip link set can1 up");
+
+	s0 = socket(PF_CAN, SOCK_RAW, CAN_RAW);
+
+	tv.tv_sec = 0;
+	tv.tv_usec = 10000;
+   	if (setsockopt(s0, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct	timeval)) < 0)
+	{
+		#ifdef SystemLogMessage
+   		PRINTF_LIB_FUNC("Set SO_RCVTIMEO NG");
+		#endif
+	}
+	nbytes=40960;
+	if (setsockopt(s0, SOL_SOCKET,  SO_RCVBUF, &nbytes, sizeof(int)) < 0)
+	{
+		#ifdef SystemLogMessage
+		PRINTF_LIB_FUNC("Set SO_RCVBUF NG");
+		#endif
+	}
+	nbytes=40960;
+	if (setsockopt(s0, SOL_SOCKET, SO_SNDBUF, &nbytes, sizeof(int)) < 0)
+	{
+		#ifdef SystemLogMessage
+		PRINTF_LIB_FUNC("Set SO_SNDBUF NG");
+		#endif
+	}
+	nbytes=40960;
+
+   	strcpy(ifr0.ifr_name, "can1" );
+	ioctl(s0, SIOCGIFINDEX, &ifr0); /* ifr.ifr_ifindex gets filled with that device's index */
+	addr0.can_family = AF_CAN;
+	addr0.can_ifindex = ifr0.ifr_ifindex;
+	bind(s0, (struct sockaddr *)&addr0, sizeof(addr0));
+	return s0;
+}
+
+//================================================
+// Receive Cmd from canbus
+//================================================
+void ReceiveDataFromCanBus()
+{
+    int nbytes;
+    struct can_frame frame;
+    PwrFrame *PwrFrameMsg;
+    byte group, address;
+
+    while(1)
+	{
+        memset(&frame, 0, sizeof(struct can_frame));
+        nbytes = read(CanFd, &frame, sizeof(struct can_frame));
+
+        if (nbytes > 0)
+        {
+            PwrFrameMsg = (PwrFrame *)&frame.can_id;
+            address = PwrFrameMsg->InfyBits.SourceAddress;
+
+            if(PwrFrameMsg->InfyBits.DestinationAddress != NEXTON_ADD)
+            {
+                switch (PwrFrameMsg->InfyBits.CmdValue)
+                {
+                    // 0x01
+                    case PSU_RCmd_SysOutputVolCur_F:
+                    {
+                        group = address;
+                        byte vol[4], cur[4];
+                        memcpy(vol, frame.data, 4);
+                        memcpy(cur, frame.data + 4, 4);
+
+                        float _Vol = IEEE_754_to_float(vol);
+                        float _Cur = IEEE_754_to_float(cur);
+
+                        return_get_output_float(group, _Vol, _Cur);
+                    }
+                        break;
+
+                    // 0x02
+                    case PSU_RCmd_SysModuleCount:
+                    {
+                        // 回傳模組數量
+                        byte count = 0;
+                        count = frame.data[2];
+
+                        return_module_count(address, count);
+                    }
+                        break;
+
+                    // 0x04
+                    case PSU_RCmd_ModuleStatus:
+                    {
+                        // 回傳模組組號及狀態
+                        byte SN = address;
+                        group = frame.data[2];
+                        char temp = frame.data[4];
+                        unsigned int status = (frame.data[5] << 16) | (frame.data[6] << 8) | frame.data[7];
+
+                        return_status(group, SN, temp, status);
+                    }
+                        break;
+
+                    // 0x06
+                    case PSU_RCmd_ModuleInputVoltage:
+                    {
+                        // 回傳三向輸入電壓
+                        short abVol = ((frame.data[0] << 8) + frame.data[1]) / 10;
+                        short bcVol = ((frame.data[2] << 8) + frame.data[3]) / 10;
+                        short caVol = ((frame.data[4] << 8) + frame.data[5]) / 10;
+
+                        return_input_vol(address, abVol, bcVol, caVol);
+                    }
+                        break;
+
+                    // 0x07
+                    case PSU_RCmd_ModuleVersion:
+                    {
+                        short dcSwVer = ((frame.data[0] << 8) + frame.data[1]);
+                        short pfcSwVer = ((frame.data[2] << 8) + frame.data[3]);
+                        short hwVer = ((frame.data[4] << 8) + frame.data[5]);
+
+                        return_fw_version(address, dcSwVer, pfcSwVer, hwVer);
+                    }
+                        break;
+
+                    // 0x08
+                    case PSU_RCmd_SysOutputVolCur:
+                    {
+                        // 回傳當前輸出電壓電流
+                        int outputVol = ((frame.data[0] << 24) + (frame.data[1] << 16) + (frame.data[2] << 8) + frame.data[3]) / 100;
+                        int outputCur = ((frame.data[4] << 24) + (frame.data[5] << 16) + (frame.data[6] << 8) + frame.data[7]) / 100;
+
+                        // outputVol unit: 1mV > 0.1V
+                        // outputCur unit: 1mA > 0.1A
+                        return_get_output(address, outputVol, outputCur);
+                    }
+                        break;
+
+                    // 0x0A
+                    case PSU_RCmd_ModuleCapability:
+                    {
+                        // 回傳輸出能力 : 最大電壓、最小電壓、最大電流、額定功率
+                        short maxVol = ((frame.data[0] << 8) + frame.data[1]) * 10;
+                        short minVol = ((frame.data[2] << 8) + frame.data[3]) * 10;
+                        short maxCur = (frame.data[4] << 8) + frame.data[5];
+                        short totalPow = ((frame.data[6] << 8) + frame.data[7]) / 10;
+
+                        // maxVol unit: 1V > 0.1V
+                        // minVol unit: 1V > 0.1V
+                        // maxCur unit: 0.1A
+                        // totalPow unit: 0.01kW > 0.1kW
+                        return_available_cap(address, maxVol, minVol, maxCur, totalPow);
+                    }
+                        break;
+
+                    // 0x0B
+                    case PSU_RCmd_ModuleBarcode:
+                    {
+                        // 回傳BarCode
+                    }
+                        break;
+
+                    // 0x0C
+                    case PSU_RCmd_ModuleIAvailable:
+                    {
+                        // 回傳降載後的電流
+                        unsigned short vextVol = ((frame.data[0] << 8) + frame.data[1]);
+                        unsigned short iAvailCur = ((frame.data[2] << 8) + frame.data[3]);
+
+                        return_iavail_info(address, iAvailCur, vextVol);
+                    }
+                        break;
+
+                    // 0x0E
+                    case PSU_RCmd_ModuleMiscInfo:
+                    {
+                        byte value[4], type = 0;
+                        unsigned short MiscType = (frame.data[0] << 8) | frame.data[1];
+                        float MiscInfoValue = 0;
+                        memcpy(value, frame.data + 4, sizeof(value));
+                        MiscInfoValue = IEEE_754_to_float(value);
+
+                        if(MiscType == FAN_SPEED_CMD)
+                        {
+                            type = 1;
+                        }
+                        if(MiscType == TEMP_DC_CMD)
+                        {
+                            type = 2;
+                        }
+                        if(MiscType == TEMP_PFC_CMD)
+                        {
+                            type = 3;
+                        }
+
+                        return_mis_info(address, MiscInfoValue, type);
+                    }
+                        break;
+
+                    // 0x13
+                    case PSU_WCmd_ModuleWalkIn:
+                    {
+
+                    }
+                        break;
+                }
+            }
+            else
+            {
+                switch(PwrFrameMsg->NextonBits.CmdValue)
+                {
+                    case Nexton_PSU_DcOutputValue:
+                    {
+                        short outputVol = ((frame.data[0] << 8) + frame.data[1]);
+                        short outputCur = ((frame.data[2] << 8) + frame.data[3]);
+                        short outputPow = ((frame.data[4] << 8) + frame.data[5]);
+                        char temp = frame.data[6];
+
+                        return_output_temp(address, outputVol, outputCur, outputPow, temp);
+                    }
+                        break;
+
+                    case Nexton_PSU_StatusEvent:
+                    {
+                        byte isErr =  (frame.data[0] >> 0) & 0x01;
+                        byte status = (frame.data[0] >> 1) & 0x01;
+                        byte err1 = frame.data[2];
+                        byte err2 = frame.data[3];
+                        byte err3 = frame.data[4];
+                        byte err4 = frame.data[5];
+
+                        return_module_status(address, isErr, status, err1, err2, err3, err4);
+                    }
+                        break;
+
+                    case Nexton_PSU_AcInputValue:
+                    {
+                        short vR = ((frame.data[0] << 8) + frame.data[1]);
+                        short vS = ((frame.data[2] << 8) + frame.data[3]);
+                        short vT = ((frame.data[4] << 8) + frame.data[5]);
+
+                        // vR, vS, vT unit: 0.1V
+                        return_module_input(address, vR, vS, vT);
+                    }
+                        break;
+                }
+            }
+		}
+		else
+			usleep(10000);
+	}
+}
+
+//================================================
+// Private Function
+//================================================
+void SendCmdToPsu(int cmd, byte *data, byte dataLen)
+{
+    PwrFrame PwrFrameMsg;
+    struct can_frame frame;
+
+    //設定 CANBSU 2.0B 長封包
+    PwrFrameMsg.PwrMessage = cmd | 0x80000000;
+
+    frame.can_id = PwrFrameMsg.PwrMessage;
+    frame.can_dlc = dataLen;
+    memcpy(frame.data, data, dataLen);
+
+    write(CanFd, &frame, sizeof(struct can_frame));
+    // 群命令才 delay
+    if (PwrFrameMsg.InfyBits.DestinationAddress == INFY_ADD_BROADCAST)
+    {
+        usleep(CMD_DELAY_TIME);
+    }
+}
+
+bool InitialCommunication()
+{
+    CanFd = InitCanBus();
+
+    if(CanFd < 0)
+    {
+        PRINTF_LIB_FUNC("Init can bus fail.\n");
+        return false;
+    }
+
+    recFork = fork();
+    if(recFork == 0)
+    {
+        ReceiveDataFromCanBus();
+    }
+
+    return true;
+}
+
+//================================================
+// API Function
+//================================================
+void SwitchPower(byte group, byte value)
+{
+    byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_WCmd_ModulePowerOnOff;
+
+    memset(data, 0x00, ARRAY_SIZE(data));
+    // 1 : 關機
+    // 0 : 開機
+    data[0] = value;
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+    SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void SleepMode(byte group, byte value)
+{
+	byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_WCmd_ModuleSleepMode;
+
+	memset(data, 0x00, ARRAY_SIZE(data));
+	// 1 : 休眠
+	// 0 : 起床
+	data[0] = value;
+
+	if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void FlashLed(byte group, byte value)
+{
+    byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_WCmd_ModuleFlashLed;
+
+    memset(data, 0x00, ARRAY_SIZE(data));
+    // 1 : 閃爍
+    // 0 : 正常
+    data[0] = value;
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+    SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void PresentOutputVol(byte group, int voltage, int current)
+{
+	byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_WCmd_SetOutput;
+
+	int Vol = voltage * 100;
+	int Cur = current * 100;
+
+	memset(data, 0x00, ARRAY_SIZE(data));
+
+	// 輸出電壓
+	data[0] = (Vol >> 24) & 0xFF;
+	data[1] = (Vol >> 16) & 0xFF;
+	data[2] = (Vol >> 8) & 0xFF;
+	data[3] = Vol & 0xFF;
+	// 輸出電流
+	data[4] = (Cur >> 24) & 0xFF;
+	data[5] = (Cur >> 16) & 0xFF;
+	data[6] = (Cur >> 8) & 0xFF;
+	data[7] = Cur & 0xFF;
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+// voltage: unit: 1mV
+// current: unit: 1mA
+void SetModuleOutputVol(byte group, int voltage, int current)
+{
+    byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_WCmd_ModuleSetOutput;
+
+    int Vol = voltage;
+    int Cur = current;
+
+    memset(data, 0x00, ARRAY_SIZE(data));
+
+    // 輸出電壓
+    data[0] = (Vol >> 24) & 0xFF;
+    data[1] = (Vol >> 16) & 0xFF;
+    data[2] = (Vol >> 8) & 0xFF;
+    data[3] = Vol & 0xFF;
+    // 輸出電流
+    data[4] = (Cur >> 24) & 0xFF;
+    data[5] = (Cur >> 16) & 0xFF;
+    data[6] = (Cur >> 8) & 0xFF;
+    data[7] = Cur & 0xFF;
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+    SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void FanNoiseInfo(byte group, byte value)
+{
+	byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_WCmd_ModuleSetMiscInfo;
+
+	memset(data, 0x00, ARRAY_SIZE(data));
+
+	// 風扇低噪音
+    data[0] = ((SetMiscInfo_FanMode >> 8) & 0xFF);
+    data[1] = (SetMiscInfo_FanMode & 0xFF);
+    data[7] = value;
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void SetWalkInConfig(byte group, byte enable, byte sec)
+{
+	byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_WCmd_ModuleWalkIn;
+
+	memset(data, 0x00, ARRAY_SIZE(data));
+	unsigned short _Sec = sec * 100;
+
+	// Walk-in mode enable
+	data[0] = enable;
+	// Walk-in time (default == 5s)
+	data[6] = (_Sec >> 8) & 0xFF;
+	data[7] = _Sec & 0xFF;
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void SetDirModulePresentOutput(byte group, int voltage, int current, byte _switch, byte _interRelay)
+{
+}
+
+void SetDipSwitchMode()
+{
+    byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_WCmd_DipSwitchMode;
+
+    memset(data, 0x00, ARRAY_SIZE(data));
+    data[0] = 0x01;
+
+    PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    PwrFrameMsg.InfyBits.DestinationAddress = INFY_ADD_BROADCAST;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+    SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+/**********************************************************************************/
+/***                                                                            ***/
+/***                                   Get                                      ***/
+/***                                                                            ***/
+/**********************************************************************************/
+void GetStatus(byte group)
+{
+	byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_RCmd_ModuleStatus;
+
+	memset(data, 0x00, ARRAY_SIZE(data));
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void GetFanSpeed(byte group)
+{
+	byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_RCmd_ModuleMiscInfo;
+
+	memset(data, 0x00, ARRAY_SIZE(data));
+
+	data[0] = (FAN_SPEED_CMD >> 8) & 0xFF;
+	data[1] = FAN_SPEED_CMD & 0xFF;
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void GetDcTemperature(byte group)
+{
+	byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_RCmd_ModuleMiscInfo;
+
+	memset(data, 0x00, ARRAY_SIZE(data));
+
+	data[0] = (TEMP_DC_CMD >> 8) & 0xFF;
+	data[1] = TEMP_DC_CMD & 0xFF;
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void GetPfcTemperature(byte group)
+{
+	byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_RCmd_ModuleMiscInfo;
+
+	memset(data, 0x00, ARRAY_SIZE(data));
+
+	data[0] = (TEMP_PFC_CMD >> 8) & 0xFF;
+	data[1] = TEMP_PFC_CMD & 0xFF;
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void GetModuleCount(byte group)
+{
+	byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_RCmd_SysModuleCount;
+
+	memset(data, 0x00, ARRAY_SIZE(data));
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void GetModuleVer(byte group)
+{
+	// 無系統廣播功能
+	byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_RCmd_ModuleVersion;
+
+	memset(data, 0x00, ARRAY_SIZE(data));
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void GetModuleCap(byte group)
+{
+	byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_RCmd_ModuleCapability;
+
+	memset(data, 0x00, ARRAY_SIZE(data));
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void GetModuleBarCode(byte group)
+{
+	// 無系統廣播功能
+	byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_RCmd_ModuleBarcode;
+
+	memset(data, 0x00, ARRAY_SIZE(data));
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void GetModuleInput(byte group)
+{
+	// 無系統廣播功能
+	byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_RCmd_ModuleInputVoltage;
+
+	memset(data, 0x00, ARRAY_SIZE(data));
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void GetModuleIavailable(byte group)
+{
+	byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_RCmd_ModuleIAvailable;
+
+	memset(data, 0x00, ARRAY_SIZE(data));
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void GetModuleOutput(byte group)
+{
+	byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_RCmd_SysOutputVolCur;
+
+	memset(data, 0x00, ARRAY_SIZE(data));
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+void GetModuleOutputF(byte group)
+{
+	byte data[8];
+    PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+    PwrFrameMsg.InfyBits.CmdValue = PSU_RCmd_SysOutputVolCur_F;
+
+	memset(data, 0x00, ARRAY_SIZE(data));
+
+    if (group == INFY_ADD_BROADCAST)
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_SINGLE_MODULE;
+    }
+    else
+    {
+        PwrFrameMsg.InfyBits.DeviceValue = DEVICE_NO_GROUP_MODULE;
+    }
+    PwrFrameMsg.InfyBits.DestinationAddress = group;
+    PwrFrameMsg.InfyBits.SourceAddress = INFY_ADD_CSU;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+/**********************************************************************************/
+/***                                                                            ***/
+/***                                 Upgrate                                    ***/
+/***                                                                            ***/
+/**********************************************************************************/
+void ChangePsuBaudrate(short baudrate)
+{
+}
+
+
+
+
+

+ 242 - 0
EVSE/Projects/DO360/Apps/InfyGroup_PsuCommObj.h

@@ -0,0 +1,242 @@
+/*
+ * Infypwr_PsuCommObj.h
+ *
+ *  Created on: 2019年11月26日
+ *      Author: 7564
+ */
+
+#ifndef INFYPWR_PSUCOMMOBJ_H_
+#define INFYPWR_PSUCOMMOBJ_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/wireless.h>
+#include <linux/can.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/time.h>
+
+#include 	<stdbool.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 	<math.h>
+
+#define SYSTEM_CMD                  0x3F
+#define DEVICE_NO_SINGLE_MODULE     0x0A
+#define DEVICE_NO_GROUP_MODULE      0x0B
+#define INFY_ADD_BROADCAST          0x3F
+#define INFY_ADD_CSU                0xF0
+#define NEXTON_ADD                  0xFF
+
+#define ARRAY_SIZE(A)		(sizeof(A) / sizeof(A[0]))
+#define CMD_DELAY_TIME 		25000
+#define FAN_SPEED_CMD		0x1201
+#define TEMP_DC_CMD			0x1107
+#define TEMP_PFC_CMD		0x1108
+
+typedef unsigned char       byte;
+typedef unsigned short      word;
+typedef unsigned int        unit;
+
+int 						CanFd;
+pid_t 						recFork;
+
+typedef union
+{
+    unsigned int PwrMessage;
+    struct
+    {
+        unsigned int SourceAddress:8;                   // source address
+        unsigned int DestinationAddress:8;              // destination address
+        unsigned int CmdValue:6;                        // command value
+        unsigned int DeviceValue:4;                     // 0x0A: for module command, 0x0B group command
+        unsigned int Error:3;                           // error code
+        unsigned int res:3;
+    }InfyBits;
+    struct
+    {
+        unsigned int SourceAddress:8;                   // source address
+        unsigned int DestinationAddress:8;              // destination address
+        unsigned int CmdValue:13;                       // command value
+        unsigned int res:3;
+    }NextonBits;
+}PwrFrame;
+
+enum PSU_POWER_CMD
+{
+	PSU_POWER_ON = 		0,
+	PSU_POWER_OFF = 	1,
+};
+
+enum PSU_SLEEP_MODE_CMD
+{
+	PSU_SLEEP_MODE_WAKE_UP = 	0,
+	PSU_SLEEP_MODE_SLEEP = 		1,
+};
+
+enum PSU_FLASH_CMD
+{
+	PSU_FLASH_NORMAL = 		0,
+	PSU_FLASH_ON = 			1,
+};
+
+enum PSU_FAN_NOISE_CMD
+{
+    PSU_FAN_NOISE_BY_POWER =        0xA0,       // power poriority mode
+    PSU_FAN_NOISE_BY_DENOISE =      0xA1,       // denoise mode
+    PSU_FAN_NOISE_BY_QUIET =        0xA2,       // quiet mode
+};
+
+typedef enum
+{
+    Infy_MsgErr_Normal          = 0x00,
+    Infy_MsgErr_Reserved1       = 0x01,
+    Infy_MsgErr_CmdInvalid      = 0x02,
+    Infy_MsgErr_DataInvalid     = 0x03,
+    Infy_MsgErr_InvalidAdd      = 0x04,
+    Infy_MsgErr_Reserved2       = 0x05,
+    Infy_MsgErr_Reserved3       = 0x06,
+    Infy_MsgErr_StartProcess    = 0x07,
+}InfyMessageError;
+
+typedef enum
+{
+    PSU_RCmd_SysOutputVolCur_F      = 0x01,
+    PSU_RCmd_SysModuleCount         = 0x02,
+    PSU_RCmd_ModuleOutputVolCur_F   = 0x03,     // no use
+    PSU_RCmd_ModuleStatus           = 0x04,
+    PSU_RCmd_ModuleInputVoltage     = 0x06,
+    PSU_RCmd_ModuleVersion          = 0x07,
+    PSU_RCmd_SysOutputVolCur        = 0x08,
+    PSU_RCmd_ModuleOutputVolCur     = 0x09,     // no use
+    PSU_RCmd_ModuleCapability       = 0x0A,
+    PSU_RCmd_ModuleBarcode          = 0x0B,
+    PSU_RCmd_ModuleIAvailable       = 0x0C,
+    PSU_RCmd_ModuleMiscInfo         = 0x0E,
+    PSU_WCmd_ModuleSetMiscInfo      = 0x0F,
+    PSU_WCmd_ModuleWalkIn           = 0x13,
+    PSU_WCmd_ModuleFlashLed         = 0x14,
+    PSU_WCmd_ModuleSetGroup         = 0x16,
+    PSU_WCmd_ModuleSleepMode        = 0x19,
+    PSU_WCmd_ModulePowerOnOff       = 0x1A,
+    PSU_WCmd_SetOutput              = 0x1B,
+    PSU_WCmd_ModuleSetOutput        = 0x1C,
+    PSU_WCmd_DipSwitchMode          = 0x1F,
+}InfyPwrCommand;
+
+typedef enum
+{
+    Nexton_PSU_ChargingRequest      = 0x1801,
+    Nexton_PSU_DcOutputValue        = 0x1901,
+    Nexton_PSU_StatusEvent          = 0x1902,
+    Nexton_PSU_AcInputValue         = 0x1903,
+}NextonPwrCommand;
+
+typedef enum
+{
+    GetMiscInfo_DcTemperature       = 0x1107,
+    GetMiscInfo_PfcTemperature      = 0x1108,
+    GetMiscInfo_FanSpeed            = 0x1201,
+}GetMiscInfoCommand;
+
+typedef enum
+{
+    SetMiscInfo_FanMode             = 0x1113,
+    SetMiscInfo_FanSpeed            = 0x1201,
+    SetMiscInfo_CurrentLimit        = 0x1205,
+    SetMiscInfo_SendTemperature     = 0x1301,
+}SetMiscInfoCommand;
+
+/*Initialization*/
+bool InitialCommunication();
+
+/*Set Cmd*/
+void SwitchPower(byte group, byte value);
+void SleepMode(byte group, byte value);
+void FlashLed(byte group, byte value);
+void PresentOutputVol(byte group, int voltage, int current);
+void SetModuleOutputVol(byte group, int voltage, int current);
+void FanNoiseInfo(byte group, byte value);
+void SetWalkInConfig(byte group, byte enable, byte sec);
+void SetDipSwitchMode();
+
+/*Ver : 9.06 used*/
+void SetDirModulePresentOutput(byte group, int voltage, int current, byte _switch, byte _interRelay);
+/*Get Cmd*/
+void GetStatus(byte group);
+void GetFanSpeed(byte group);
+void GetDcTemperature(byte group);
+void GetPfcTemperature(byte group);
+void GetFanSpeed(byte group);
+void GetModuleCount(byte group);
+void GetModuleVer(byte group);
+void GetModuleCap(byte group);
+void GetModuleBarCode(byte group);
+void GetModuleInput(byte group);
+void GetModuleIavailable(byte group);
+void GetModuleOutput(byte group);
+void GetModuleOutputF(byte group);
+
+/*Upgrade*/
+void ChangePsuBaudrate(short baudrate);
+
+/* Callback Function */
+void RefreshStatus(void *func);
+void (*return_status)(byte group, byte address, byte temp, int status);
+
+void RefreshModuleCount(void *func);
+void (*return_module_count)(byte group, byte count);
+
+void RefreshAvailableCap(void *func);
+void (*return_available_cap)(byte address, short maxVol, short minVol, short maxCur, short totalPow);
+
+void RefreshFwVersion(void *func);
+void (*return_fw_version)(byte address, short dcSwVer, short pfcSwVer, short hwVer);
+
+void RefreshInputVol(void *func);
+void (*return_input_vol)(byte address, unsigned short vol1, unsigned short vol2, unsigned short vol3);
+
+void RefreshGetOutput(void *func);
+void (*return_get_output)(byte address, unsigned short outVol, unsigned short outCur);
+
+void RefreshGetOutputF(void *func);
+void (*return_get_output_float)(byte group, float outVol, float outCur);
+
+void RefreshMisInfo(void *func);
+void (*return_mis_info)(byte address, unsigned int fanSpeed, byte type);
+
+void RefreshIavailable(void *func);
+void (*return_iavail_info)(byte address, unsigned short Iavail, unsigned short Vext);
+
+/*Test mode used*/
+void AutoMode_RefreshOutputAndTemp(void *func);
+void (*return_output_temp)(byte address, unsigned short outputVol,
+		unsigned short outputCur, unsigned short outputPower, unsigned char Temperature);
+
+void AutoMode_RefreshModuleStatus(void *func);
+void (*return_module_status)(byte address, unsigned char isErr, unsigned char status,
+		unsigned char err1, unsigned char err2, unsigned char err3, unsigned char err4);
+
+void AutoMode_RefreshModuleInput(void *func);
+void (*return_module_input)(byte address, unsigned short inputR,
+		unsigned short inputS, unsigned short inputT);
+/* Callback Function end */
+#endif /* INFYPWR_PSUCOMMOBJ_H_ */

+ 9 - 3
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: MainTask EvCommTask EventLoggingTask InternalCommTask LcmControlTask PrimaryCommTask PsuCommTask ReadCmdlineTask UnsafetyOutputTool FactoryConfigApp OtherTools
+apps: MainTask EvCommTask EventLoggingTask InternalCommTask LcmControlTask PrimaryCommTask InfyGroup_PsuCommObj PsuCommTask ReadCmdlineTask UnsafetyOutputTool FactoryConfigApp OtherTools
 
 MainTask:
 	rm -f *.o
@@ -56,10 +56,16 @@ PrimaryCommTask:
 	$(CC) -o Module_PrimaryComm Module_PrimaryComm.o PrimaryComm.o
 	cp -f Module_PrimaryComm ../Images/root	
 
+InfyGroup_PsuCommObj:
+	rm -f libInfyGroup_PsuCommObj.a
+	$(CC) -D $(Project) -O0 -g3 -Wall -c -fmessage-length=0 -o InfyGroup_PsuCommObj.o InfyGroup_PsuCommObj.c
+	$(AR) -r libInfyGroup_PsuCommObj.a InfyGroup_PsuCommObj.o
+	rm -f InfyGroup_PsuCommObj.o
+
 PsuCommTask:
 	rm -f Module_PsuComm; 
-	$(CC) -D $(Project) -include../../../Modularization/Infypwr_PsuCommObj.h -includeConfig.h -O0 -g3 -Wall -c -fmessage-length=0 -o Module_PsuComm.o Module_PsuComm.c
-	$(CC) -o Module_PsuComm Module_PsuComm.o ../../../Modularization/libInfypwr_PsuCommObj.a
+	$(CC) -D $(Project) -includeInfyGroup_PsuCommObj.h -includeConfig.h -O0 -g3 -Wall -c -fmessage-length=0 -o Module_PsuComm.o Module_PsuComm.c
+	$(CC) -o Module_PsuComm Module_PsuComm.o libInfyGroup_PsuCommObj.a
 	cp -f Module_PsuComm ../Images/root	
 	
 ReadCmdlineTask:

+ 91 - 86
EVSE/Projects/DO360/Apps/Module_EvComm.c

@@ -53,6 +53,7 @@
 
 struct SysConfigAndInfo				*ShmSysConfigAndInfo;
 ChargerInfoData                     *ShmChargerInfo;
+struct ChargingInfoData             *chargingInfo[CONNECTOR_QUANTITY];
 
 //struct WARNING_CODE_INFO            LastWarningInfo[GENERAL_GUN_QUANTITY];
 
@@ -149,61 +150,9 @@ int InitShareMemory()
 		result = FAIL;
 	 }
 	else
-	{}
-	/*
-	//creat ShmStatusCodeData
-	if ((MeterSMId = shmget(ShmStatusCodeKey, sizeof(struct StatusCodeData),  0777)) < 0)
 	{
-		#ifdef SystemLogMessage
-		DEBUG_ERROR("shmget ShmStatusCodeData NG\n");
-		#endif
-		result = FAIL;
-	}
-	else if ((ShmStatusCodeData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
-	{
-		#ifdef SystemLogMessage
-		DEBUG_ERROR("shmat ShmStatusCodeData NG\n");
-		#endif
-		result = FAIL;
-	}
-	else
-	{}
-
-	//creat ShmOCPP16Data
-	if ((MeterSMId = shmget(ShmOcppModuleKey, sizeof(struct OCPP16Data),  0777)) < 0)
-	{
-		#ifdef SystemLogMessage
-		DEBUG_ERROR("shmget ShmOCPP16Data NG");
-		#endif
-		result = FAIL;
-	}
-	else if ((ShmOCPP16Data = shmat(MeterSMId, NULL, 0)) == (void *) -1)
-	{
-		#ifdef SystemLogMessage
-		DEBUG_ERROR("shmat ShmOCPP16Data NG");
-		#endif
-		result = FAIL;
-	}
-	else
-	{}
 
-	//creat ShmPsuData
-	if ((MeterSMId = shmget(ShmPsuKey, sizeof(struct PsuData),  0777)) < 0)
-	{
-		#ifdef SystemLogMessage
-		DEBUG_ERROR("shmget ShmPsuData NG \n");
-		#endif
-		result = FAIL;
 	}
-	else if ((ShmPsuData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
-	{
-		#ifdef SystemLogMessage
-		DEBUG_ERROR("shmat ShmPsuData NG \n");
-		#endif
-		result = FAIL;
-	 }
-	memset(ShmPsuData,0,sizeof(struct PsuData));
-	*/
 
     if ((MeterSMId = shmget(SM_ChargerInfoKey, sizeof(ChargerInfoData), 0777)) < 0)
     {
@@ -919,6 +868,12 @@ unsigned char ConnectorQuantityTypeParsing(unsigned char *modelName, unsigned ch
 	return quantity;
 }
 
+void SendPacket(int socket, struct PACKET_STRUCTURE *packet)
+{
+    //ShowSocketData(packet);
+    send(socket, packet, packet->Header.len + 4, 0);
+}
+
 void ModelNameResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result)
 {
 	struct PACKET_STRUCTURE sendBuffer;
@@ -931,7 +886,7 @@ void ModelNameResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned cha
 	sendBuffer.Payload.reg = _Reg_Dispenser_Model_Name;
 	sendBuffer.Payload.data[0] = result;
 
-	send(socket, &sendBuffer, sendBuffer.Header.len + 4, 0);
+	SendPacket(socket, &sendBuffer);
 }
 
 void ConnectorIDResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result, unsigned char dispenserIndex)
@@ -948,7 +903,7 @@ void ConnectorIDResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
 	sendBuffer.Payload.data[1] = ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].ConnectorID[0];
 	sendBuffer.Payload.data[2] = ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].ConnectorID[1];
 
-	send(socket, &sendBuffer, sendBuffer.Header.len + 4, 0);
+	SendPacket(socket, &sendBuffer);
 }
 
 // more message for debug
@@ -1022,7 +977,7 @@ void PowerCabinetStatusResponse(int socket, struct PACKET_STRUCTURE *packet, uns
         PRINTF_FUNC("%s", str);
     }
 
-	send(socket, &sendBuffer, sendBuffer.Header.len + 4, 0);
+	SendPacket(socket, &sendBuffer);
 }
 
 void DispenserStatusResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result)
@@ -1037,7 +992,7 @@ void DispenserStatusResponse(int socket, struct PACKET_STRUCTURE *packet, unsign
 	sendBuffer.Payload.reg = _Reg_Dispenser_Status;
 	sendBuffer.Payload.data[0] = result;
 
-	send(socket, &sendBuffer, sendBuffer.Header.len + 4, 0);
+	SendPacket(socket, &sendBuffer);
 }
 
 struct ChargingCapabilityResponse ConnectorCapability[GENERAL_GUN_QUANTITY];
@@ -1093,7 +1048,8 @@ void ChargingCapabilityResponse(int socket, struct PACKET_STRUCTURE *packet)
         (ConnectorCapability[packet->Header.id - 1].MaxOuputCurrent / 10) != (current / 10) ||
         (ConnectorCapability[packet->Header.id - 1].MaxOuputPower / 10) != (power / 10))
 	{
-	    PRINTF_FUNC("Connector %d Capability Voltage: %d, Current: %d, Power: %d", packet->Header.id, (int)(voltage), (int)(current), (int)(power));
+        PRINTF_FUNC("Connector %d Capability Voltage: %4d.%d V, Current: %3d.%d A, Power: %d kW", packet->Header.id,
+            (voltage / 10), (voltage % 10), (current / 10), (current % 10), (power / 10));
 	}
 
 	if(ConnectorCapability[packet->Header.id - 1].Currency != currency ||
@@ -1138,7 +1094,7 @@ void ChargingCapabilityResponse(int socket, struct PACKET_STRUCTURE *packet)
     sendBuffer.Payload.data[18] = ((account >> 8) & 0xFF);
     sendBuffer.Payload.data[19] = (account & 0xFF);
 
-	send(socket, &sendBuffer, sendBuffer.Header.len + 4, 0);
+	SendPacket(socket, &sendBuffer);
 }
 
 void ChargingTargetResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result)
@@ -1153,7 +1109,7 @@ void ChargingTargetResponse(int socket, struct PACKET_STRUCTURE *packet, unsigne
 	sendBuffer.Payload.reg = _Reg_Charging_Target;
 	sendBuffer.Payload.data[0] = result;
 
-	send(socket, &sendBuffer, sendBuffer.Header.len + 4, 0);
+	SendPacket(socket, &sendBuffer);
 }
 
 void FirmwareUpgradeResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char dispenserIndex, unsigned char result)
@@ -1176,7 +1132,7 @@ void FirmwareUpgradeResponse(int socket, struct PACKET_STRUCTURE *packet, unsign
         sendBuffer.Header.len += length;
     }
 
-    send(socket, &sendBuffer, sendBuffer.Header.len + 4, 0);
+    SendPacket(socket, &sendBuffer);
 }
 
 void PlugInStatusResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result)
@@ -1191,7 +1147,7 @@ void PlugInStatusResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned
 	sendBuffer.Payload.reg = _Reg_Plug_In_Status;
 	sendBuffer.Payload.data[0] = result;
 
-	send(socket, &sendBuffer, sendBuffer.Header.len + 4, 0);
+	SendPacket(socket, &sendBuffer);
 }
 
 void ConnectorStateResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result)
@@ -1206,7 +1162,7 @@ void ConnectorStateResponse(int socket, struct PACKET_STRUCTURE *packet, unsigne
 	sendBuffer.Payload.reg = _Reg_Connector_State;
 	sendBuffer.Payload.data[0] = result;
 
-	send(socket, &sendBuffer, sendBuffer.Header.len + 4, 0);
+	SendPacket(socket, &sendBuffer);
 }
 
 void UserIDResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result)
@@ -1222,7 +1178,7 @@ void UserIDResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char r
 	sendBuffer.Payload.data[0] = result == _DAS_Wait ? _R_NG : _R_OK;
 	sendBuffer.Payload.data[1] = result == _DAS_Allowed ? _PS_Permitted : _PS_NotPermitted;
 
-	send(socket, &sendBuffer, sendBuffer.Header.len + 4, 0);
+	SendPacket(socket, &sendBuffer);
 }
 
 void ChargingPermissionResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result)
@@ -1238,7 +1194,7 @@ void ChargingPermissionResponse(int socket, struct PACKET_STRUCTURE *packet, uns
 	sendBuffer.Payload.data[0] = result == _DAS_Wait ? _R_NG : _R_OK;
 	sendBuffer.Payload.data[1] = result == _DAS_Allowed ? _PS_Permitted : _PS_NotPermitted;
 
-	send(socket, &sendBuffer, sendBuffer.Header.len + 4, 0);
+	SendPacket(socket, &sendBuffer);
 }
 
 void AddMiscCommand(struct PACKET_STRUCTURE *packet, struct MISC_COMMAND *misc)
@@ -1438,7 +1394,7 @@ void MiscControlResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned c
         }
     }
 
-    send(socket, &sendBuffer, sendBuffer.Header.len + 4, 0);
+    SendPacket(socket, &sendBuffer);
 }
 
 void WriteCsuVersionResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result)
@@ -1453,7 +1409,7 @@ void WriteCsuVersionResponse(int socket, struct PACKET_STRUCTURE *packet, unsign
     sendBuffer.Payload.reg = _Reg_Report_Csu_Version;
     sendBuffer.Payload.data[0] = result;
 
-    send(socket, &sendBuffer, sendBuffer.Header.len + 4, 0);
+    SendPacket(socket, &sendBuffer);
 }
 
 void WriteOtherVersionResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result)
@@ -1468,22 +1424,36 @@ void WriteOtherVersionResponse(int socket, struct PACKET_STRUCTURE *packet, unsi
     sendBuffer.Payload.reg = _Reg_Report_Other_Version;
     sendBuffer.Payload.data[0] = result;
 
-    send(socket, &sendBuffer, sendBuffer.Header.len + 4, 0);
+    SendPacket(socket, &sendBuffer);
 }
 
 void WriteChargingInfoResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result)
 {
     struct PACKET_STRUCTURE sendBuffer;
 
+    unsigned short voltage = 0, current = 0;
+
+#if 0
+    // for safety test
+    unsigned char gun = packet->Header.id - 1;
+    voltage = (unsigned short)(chargingInfo[gun]->PresentChargingVoltage * 10);
+    current = (unsigned short)(chargingInfo[gun]->PresentChargingCurrent * 10);
+    voltage -= ((current * 8 * 10) / 10000);
+#endif
+
     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.Header.len = 6;
     sendBuffer.Payload.reg = _Reg_Charging_Info;
     sendBuffer.Payload.data[0] = result;
+    sendBuffer.Payload.data[1] = (voltage >> 8) & 0xFF;
+    sendBuffer.Payload.data[2] = (voltage >> 0) & 0xFF;
+    sendBuffer.Payload.data[3] = (current >> 8) & 0xFF;
+    sendBuffer.Payload.data[4] = (current >> 0) & 0xFF;
 
-    send(socket, &sendBuffer, sendBuffer.Header.len + 4, 0);
+    SendPacket(socket, &sendBuffer);
 }
 
 int GetChargerSystemId(char *id)
@@ -1548,7 +1518,7 @@ void ChargerSystemIdResponse(int socket, struct PACKET_STRUCTURE *packet, unsign
         //PRINTF_FUNC("Dispenser %d Read System Id: %s", dispenserIndex + 1, ShmSysConfigAndInfo->SysConfig.ChargeBoxId);
     }
 
-    send(socket, &sendBuffer, sendBuffer.Header.len + 4, 0);
+    SendPacket(socket, &sendBuffer);
 }
 
 void WriteWaitPlugInResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result)
@@ -1563,7 +1533,7 @@ void WriteWaitPlugInResponse(int socket, struct PACKET_STRUCTURE *packet, unsign
     sendBuffer.Payload.reg = _Reg_WaitPlugIn;
     sendBuffer.Payload.data[0] = result;
 
-    send(socket, &sendBuffer, sendBuffer.Header.len + 4, 0);
+    SendPacket(socket, &sendBuffer);
 }
 
 BOOL FindConnectorID(unsigned char dispenserIndex, unsigned char id)
@@ -1713,6 +1683,7 @@ void SetConnectorID(unsigned char dispenserIndex, unsigned char quantity)
 		currentQuantity++;
 		ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].ConnectorID[i] = currentQuantity;
 		ShmSysConfigAndInfo->SysInfo.ConnectorInfo[currentQuantity - 1].Enable = true;
+		ShmSysConfigAndInfo->SysInfo.ConnectorInfo[currentQuantity - 1].GeneralChargingData.Index = currentQuantity - 1;
 	}
 }
 
@@ -1923,8 +1894,8 @@ BOOL ConnectorChargingTargetHandler(struct PACKET_STRUCTURE *packet, unsigned ch
 			if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].GeneralChargingData.EvBatterytargetVoltage != targetVol ||
 				ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].GeneralChargingData.EvBatterytargetCurrent != targetCur)
 			{
-				PRINTF_FUNC("Connector %d Target Voltage: %d, Current: %d",
-                    packet->Header.id, (int)(targetVol * 10), (int)(targetCur * 10));
+                PRINTF_FUNC("Connector %d Target Voltage: %d V, Current: %d A",
+                    packet->Header.id, (int)(targetVol), (int)(targetCur));
 			}
 
 			ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].GeneralChargingData.EvBatterytargetVoltage = targetVol;
@@ -2017,11 +1988,21 @@ BOOL ConnectorStateHandler(struct PACKET_STRUCTURE *packet, unsigned char dispen
 	BOOL find = FindConnectorID(dispenserIndex, packet->Header.id);
 	unsigned char ConnectionState;
 	unsigned char *AlarmCode;
+	unsigned char GunTemp = 0;
+	unsigned char ChillerTemp = 0;
+	unsigned char noAlarm[6];
 
-	if(find && packet->Header.len <= 8)
+	memset(noAlarm, 0x00, 6);
+
+	if(find)
 	{
 	    ConnectionState = packet->Payload.data[0];
-	    AlarmCode = &packet->Payload.data[1];
+	    AlarmCode = packet->Header.len >= 8 ? &packet->Payload.data[1] : &noAlarm[0];
+	    GunTemp = packet->Header.len >= 10 ? packet->Payload.data[7] : GunTemp;
+	    ChillerTemp = packet->Header.len >= 10 ? packet->Payload.data[8] : ChillerTemp;
+
+	    chargingInfo[packet->Header.id - 1]->ConnectorTemp = GunTemp;
+	    chargingInfo[packet->Header.id - 1]->ChillerTemp = ChillerTemp;
 
 		if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteStatus != ConnectionState)
 		{
@@ -2034,8 +2015,11 @@ BOOL ConnectorStateHandler(struct PACKET_STRUCTURE *packet, unsigned char dispen
                     if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteStatus == _CRS_Preparing ||
                         ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteStatus == _CRS_Charging)
                     {
-                        PRINTF_FUNC("*********** Connector id %d Set Normal Stop Flag ***********\n", packet->Header.id);
-                        ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].Parameter.bits.NormalStopRequest = true;
+                        if(chargingInfo[packet->Header.id - 1]->SystemStatus != S_IDLE)
+                        {
+                            PRINTF_FUNC("*********** Connector id %d Set Normal Stop Flag ***********\n", packet->Header.id);
+                            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].Parameter.bits.NormalStopRequest = true;
+                        }
                     }
                     break;
 
@@ -2375,26 +2359,37 @@ unsigned char DispenserWriteOtherVersionInfoHandler(struct PACKET_STRUCTURE *pac
 unsigned char DispenserWriteChargingInfoHandler(struct PACKET_STRUCTURE *packet, unsigned char dispenserIndex)
 {
     BOOL find = FindConnectorID(dispenserIndex, packet->Header.id);
+    unsigned char gun = 0;
 
     if(find)
     {
+        gun = packet->Header.id - 1;
+        unsigned short diffVoltage = 0, diffCurrent = 0;
         unsigned short voltage = (packet->Payload.data[0] << 8) + (packet->Payload.data[1]);
         unsigned short current = (packet->Payload.data[2] << 8) + (packet->Payload.data[3]);
         //unsigned int time = (packet->Payload.data[4] << 24) + (packet->Payload.data[5] << 16) + (packet->Payload.data[6] << 8) + (packet->Payload.data[7]);
         unsigned char soc = (packet->Payload.data[8]);
 
-        if((ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteChargingVoltage / 10) != (voltage / 10) ||
-            (ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteChargingCurrent / 10) != (current / 10) ||
-            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteSoc != soc)
+        diffVoltage = voltage >= ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].RemoteChargingVoltage ?
+            voltage - ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].RemoteChargingVoltage :
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].RemoteChargingVoltage - voltage;
+
+        diffCurrent = current >= ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].RemoteChargingCurrent ?
+            current - ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].RemoteChargingCurrent :
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].RemoteChargingCurrent - current;
+
+        if(diffVoltage > 10 || diffCurrent > 10 || ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].RemoteSoc != soc)
         {
-            PRINTF_FUNC("Connector %d Charging Info: Voltage %4dV Current %4dA Soc %d\% ", packet->Header.id, voltage, current, soc);
+            PRINTF_FUNC("Connector %d Charging Info: Voltage: %4d.%d V, Current: %3d.%d A, Soc: %3d, Temp: %3d, Chiller: %3d",
+                packet->Header.id, (voltage / 10), (voltage % 10), (current / 10), (current % 10), soc,
+                chargingInfo[gun]->ConnectorTemp - 60, chargingInfo[gun]->ChillerTemp - 60);
         }
 
-        ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteChargingVoltage = voltage;
-        ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteChargingCurrent = current;
-        //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteRemainChargingDuration = time;
-        ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteSoc = soc;
-        ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].GeneralChargingData.EvBatterySoc = soc;
+        ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].RemoteChargingVoltage = voltage;
+        ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].RemoteChargingCurrent = current;
+        //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].RemoteRemainChargingDuration = time;
+        ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].RemoteSoc = soc;
+        ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].GeneralChargingData.EvBatterySoc = soc;
     }
     else
     {
@@ -3037,6 +3032,14 @@ int tcpSocketServerStart(void)
 	return 0;
 }
 
+void InitialConnector(void)
+{
+    for(int i = 0; i < CONNECTOR_QUANTITY; i++)
+    {
+        chargingInfo[i] = &ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].GeneralChargingData;
+    }
+}
+
 int main(void)
 {
 	if(InitShareMemory() == FAIL)
@@ -3049,6 +3052,8 @@ int main(void)
 		return 0;
 	}
 
+	InitialConnector();
+
 	// wait for self test completed
     while(ShmSysConfigAndInfo->SysInfo.BootingStatus == BOOTTING)
     {

+ 290 - 476
EVSE/Projects/DO360/Apps/Module_InternalComm.c

@@ -60,6 +60,13 @@ struct LedModuleData			*ShmLedModuleData;
 struct PsuData 					*ShmPsuData;
 struct OCPP16Data				*ShmOCPP16Data;
 ChargerInfoData                 *ShmChargerInfo;
+PsuGroupingInfoData             *ShmPsuGrouping;
+PsuGroupOutputRelay             *ShmOutputRelayConfig[MAX_GROUP_QUANTITY];
+PsuGroupOutputRelay             *ShmOutputRelayConfirmed[MAX_GROUP_QUANTITY];
+PsuGroupParallelRelay           *ShmParallelRelayConfig;
+PsuGroupParallelRelay           *ShmParallelRelayConfirmed;
+RBRelayControl                  *LocationRelayCtrl[MAX_GROUP_QUANTITY];
+RBRelayControl                  *LocationRelayResponse[MAX_GROUP_QUANTITY];
 
 #define VIN_MAX_VOLTAGE_IEC         285	// 大於該值 : OVP
 #define VIN_MAX_REV_VOLTAGE_IEC     275 // 小於賦歸 OVP
@@ -110,7 +117,7 @@ ChargerInfoData                 *ShmChargerInfo;
 byte gunCount;
 byte acgunCount;
 // 槍資訊
-struct ChargingInfoData *_chargingData[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY + GENERAL_GUN_QUANTITY];
+struct ChargingInfoData *_chargingData[CONNECTOR_QUANTITY];
 struct ChargingInfoData *ac_chargingInfo[AC_QUANTITY];
 
 bool _isOutputNoneMatch[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY];
@@ -745,6 +752,8 @@ void GetPersentOutputVol()
 
             _chargingData[0]->FuseChargingVoltage = ShmRelayModuleData[0]->Gun1FuseOutputVolt;
             _chargingData[0]->FireChargingVoltage = ShmRelayModuleData[0]->Gun1RelayOutputVolt;
+            _chargingData[3]->FuseChargingVoltage = ShmRelayModuleData[0]->Gun2FuseOutputVolt;
+            _chargingData[3]->FireChargingVoltage = ShmRelayModuleData[0]->Gun2RelayOutputVolt;
         }
 
         // DO360 RC2
@@ -757,6 +766,8 @@ void GetPersentOutputVol()
 
             _chargingData[1]->FuseChargingVoltage = ShmRelayModuleData[1]->Gun2FuseOutputVolt;
             _chargingData[1]->FireChargingVoltage = ShmRelayModuleData[1]->Gun2RelayOutputVolt;
+            _chargingData[2]->FuseChargingVoltage = ShmRelayModuleData[1]->Gun1FuseOutputVolt;
+            _chargingData[2]->FireChargingVoltage = ShmRelayModuleData[1]->Gun1RelayOutputVolt;
         }
     }
     else
@@ -799,15 +810,94 @@ void GetFanSpeed()
 // 讀取 Relay 狀態
 void GetRelayOutputStatus()
 {
-//	if (Query_Relay_Output(Uart5Fd, Addr.Relay, &regRelay) == PASS)
-//	{
-//		regRelay.relay_event.bits.AC_Contactor = ShmSysConfigAndInfo->SysInfo.AcContactorStatus;
-//	}
+    unsigned char location = 0;
+
+    if(Query_Relay_Output(Uart5Fd, Addr.DO360_RC1, &regRelay[0]) == PASS)
+    {
+        regRelay[0].relay_event.bits.AC_Contactor = outputRelay[0].relay_event.bits.AC_Contactor;
+    }
+    if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable)
+    {
+        if(Query_Relay_Output(Uart5Fd, Addr.DO360_RC2, &regRelay[1]) == PASS)
+        {
+            regRelay[1].relay_event.bits.AC_Contactor = outputRelay[1].relay_event.bits.AC_Contactor;
+        }
+    }
+
+    // update output relay feedback status
+    for(int i = 0; i < ShmChargerInfo->Control.MaxConnector; i++)
+    {
+        location = ShmPsuGrouping->GroupCollection[i].Location;
+
+        if(ShmOutputRelayConfirmed[i]->bits.Output_N != LocationRelayResponse[location]->bits.Gun_N)
+        {
+            PRINTF_FUNC("Gun %d Get K1K2 N %s at Location %d",
+                i + 1, LocationRelayResponse[location]->bits.Gun_N ? "On" : "Off", location + 1);
+        }
+        ShmOutputRelayConfirmed[i]->bits.Output_N = LocationRelayResponse[location]->bits.Gun_N;
+
+        if(ShmOutputRelayConfirmed[i]->bits.Output_P != LocationRelayResponse[location]->bits.Gun_P)
+        {
+            PRINTF_FUNC("Gun %d Get K1K2 P %s at Location %d",
+                i + 1, LocationRelayResponse[location]->bits.Gun_P ? "On" : "Off", location + 1);
+        }
+        ShmOutputRelayConfirmed[i]->bits.Output_P = LocationRelayResponse[location]->bits.Gun_P;
+    }
+
+    // update parallel relay feedback status
+    for(int i = 0; i < ShmChargerInfo->Control.MaxConnector - 1; i++)
+    {
+        bool relayOnOff = 0;
+
+        if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable)
+        {
+            relayOnOff = LocationRelayResponse[i]->bits.Gun_Parallel_N_P;
+        }
+        else
+        {
+            bool original = ShmParallelRelayConfig->CtrlValue & (1 << i) ? false : true;
+
+            relayOnOff = LocationRelayResponse[i]->bits.Gun_Parallel_N_P == LocationRelayResponse[i + 1]->bits.Gun_Parallel_N_P ?
+                LocationRelayResponse[i]->bits.Gun_Parallel_N_P : original;
+#if 0
+            if(LocationRelayResponse[i]->bits.Gun_Parallel_N_P != LocationRelayResponse[i + 1]->bits.Gun_Parallel_N_P)
+            {
+                PRINTF_FUNC("Parallel Relay N & P at Location %d is Not Match: %d, %d",
+                    i + 1, LocationRelayResponse[i]->bits.Gun_Parallel_N_P, LocationRelayResponse[i + 1]->bits.Gun_Parallel_N_P);
+            }
+#endif
+        }
+
+        if((ShmParallelRelayConfirmed->CtrlValue & (1 << i)) != (relayOnOff << i))
+        {
+            PRINTF_FUNC("Get Parallel Relay N & P %s at Location %d", relayOnOff ? "On" : "Off", i + 1);
+        }
+
+        if(relayOnOff)
+        {
+            ShmParallelRelayConfirmed->CtrlValue |= 1 << i;
+        }
+        else
+        {
+            ShmParallelRelayConfirmed->CtrlValue &= ~(1 << i);
+        }
+    }
 }
 
 // 確認 K1 K2 relay 的狀態
 void CheckK1K2RelayOutput(byte index)
 {
+    unsigned char location = 0;
+    if(index < MAX_GROUP_QUANTITY && index < ShmChargerInfo->Control.MaxConnector)
+    {
+        location = ShmPsuGrouping->GroupCollection[index].Location;
+
+        if(LocationRelayCtrl[location]->bits.Gun_N == LocationRelayCtrl[location]->bits.Gun_P)
+        {
+            _chargingData[index]->RelayK1K2Status = LocationRelayCtrl[location]->bits.Gun_N ? YES : NO;
+        }
+    }
+#if 0
     if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable)
     {
         // two relay board
@@ -858,6 +948,7 @@ void CheckK1K2RelayOutput(byte index)
     }
 //	PRINTF_FUNC("Check Relay Output. index = %d, RelayKPK2Status = %d, BridgeRelayStatus = %d \n",
 //			index, _chargingData[index]->RelayKPK2Status, ShmSysConfigAndInfo->SysInfo.BridgeRelayStatus);
+#endif
 }
 
 void GetGfdAdc()
@@ -1046,356 +1137,91 @@ void SetFanModuleSpeed()
 //==========================================
 void SetK1K2RelayStatus(byte index)
 {
-	if (_chargingData[index]->SystemStatus < S_PREPARING_FOR_EVSE)
-	{
-        if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable)
+    unsigned char location = 0;
+
+    if(index < MAX_GROUP_QUANTITY && index < ShmChargerInfo->Control.MaxConnector)
+    {
+        if ((_chargingData[index]->SystemStatus >= S_PREPARING_FOR_EVSE &&
+                _chargingData[index]->SystemStatus <= S_CHARGING))
         {
-            // two relay board
-            if(index == 0)
-            {
-                if(regRelay[0].relay_event.bits.Gun1_P == YES)
-                    outputRelay[0].relay_event.bits.Gun1_P = NO;
-                if (regRelay[0].relay_event.bits.Gun1_N == YES)
-                    outputRelay[0].relay_event.bits.Gun1_N = NO;
-            }
-            if(index == 1)
+            if(!ShmOutputRelayConfig[index]->bits.Output_N || !ShmOutputRelayConfig[index]->bits.Output_P)
             {
-                if(regRelay[1].relay_event.bits.Gun2_P == YES)
-                    outputRelay[1].relay_event.bits.Gun2_P = NO;
-                if (regRelay[1].relay_event.bits.Gun2_N == YES)
-                    outputRelay[1].relay_event.bits.Gun2_N = NO;
+                PRINTF_FUNC("Gun %d Set K1K2 Close And Prepare To Charging", index + 1);
             }
+            ShmOutputRelayConfig[index]->bits.Output_N = true;
+            ShmOutputRelayConfig[index]->bits.Output_P = true;
         }
-        else
+        else if ((_chargingData[index]->SystemStatus >= S_TERMINATING &&
+                _chargingData[index]->SystemStatus <= S_COMPLETE) ||
+                _chargingData[index]->SystemStatus == S_ALARM)
         {
-            // only one relay board
-            if(index == 0)
-            {
-                if(regRelay[0].relay_event.bits.Gun1_P == YES)
-                    outputRelay[0].relay_event.bits.Gun1_P = NO;
-                if (regRelay[0].relay_event.bits.Gun1_N == YES)
-                    outputRelay[0].relay_event.bits.Gun1_N = NO;
-            }
-            if(index == 1)
-            {
-                if(regRelay[0].relay_event.bits.Gun2_P == YES)
-                    outputRelay[0].relay_event.bits.Gun2_P = NO;
-                if (regRelay[0].relay_event.bits.Gun2_N == YES)
-                    outputRelay[0].relay_event.bits.Gun2_N = NO;
-            }
-        }
-	}
-	else if ((_chargingData[index]->SystemStatus >= S_PREPARING_FOR_EVSE &&
-			_chargingData[index]->SystemStatus <= S_CHARGING))
-	{
-		if (_chargingData[index]->RelayWeldingCheck == YES)
-		{
-            if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable)
-            {
-                // two relay board
-                if(index == 0)
-                {
-                    if(regRelay[0].relay_event.bits.Gun1_N == NO)
-                        outputRelay[0].relay_event.bits.Gun1_N = YES;
-                    if (regRelay[0].relay_event.bits.Gun1_P == NO)
-                        outputRelay[0].relay_event.bits.Gun1_P = YES;
-                }
-                if(index == 1)
-                {
-                    if(regRelay[1].relay_event.bits.Gun2_N == NO)
-                        outputRelay[1].relay_event.bits.Gun2_N = YES;
-                    if (regRelay[1].relay_event.bits.Gun2_P == NO)
-                        outputRelay[1].relay_event.bits.Gun2_P = YES;
-                }
-            }
-            else
+            if ((_chargingData[index]->PresentChargingCurrent * 10) <= SEFETY_SWITCH_RELAY_CUR)
             {
-                // only one relay board
-                if(index == 0)
-                {
-                    if(regRelay[0].relay_event.bits.Gun1_N == NO)
-                        outputRelay[0].relay_event.bits.Gun1_N = YES;
-                    if (regRelay[0].relay_event.bits.Gun1_P == NO)
-                        outputRelay[0].relay_event.bits.Gun1_P = YES;
-                }
-                if(index == 1)
-                {
-                    if(regRelay[0].relay_event.bits.Gun2_N == NO)
-                        outputRelay[0].relay_event.bits.Gun2_N = YES;
-                    if (regRelay[0].relay_event.bits.Gun2_P == NO)
-                        outputRelay[0].relay_event.bits.Gun2_P = YES;
-                }
-            }
-		}
-	}
-	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)
-		{
-            if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable)
-            {
-                // two relay board
-                if(index == 0)
-                {
-                    if(regRelay[0].relay_event.bits.Gun1_P == YES)
-                        outputRelay[0].relay_event.bits.Gun1_P = NO;
-                    if (regRelay[0].relay_event.bits.Gun1_N == YES)
-                        outputRelay[0].relay_event.bits.Gun1_N = NO;
-                }
-                if(index == 1)
+                if(ShmOutputRelayConfig[index]->bits.Output_N || ShmOutputRelayConfig[index]->bits.Output_P)
                 {
-                    if(regRelay[1].relay_event.bits.Gun2_P == YES)
-                        outputRelay[1].relay_event.bits.Gun2_P = NO;
-                    if (regRelay[1].relay_event.bits.Gun2_N == YES)
-                        outputRelay[1].relay_event.bits.Gun2_N = NO;
+                    PRINTF_FUNC("Gun %d Set K1K2 Open And Charging Stop", index + 1);
                 }
+                ShmOutputRelayConfig[index]->bits.Output_N = false;
+                ShmOutputRelayConfig[index]->bits.Output_P = false;
             }
-            else
+        }
+        else
+        {
+            if(ShmOutputRelayConfig[index]->bits.Output_N || ShmOutputRelayConfig[index]->bits.Output_P)
             {
-                // only one relay board
-                if(index == 0)
-                {
-                    if(regRelay[0].relay_event.bits.Gun1_P == YES)
-                        outputRelay[0].relay_event.bits.Gun1_P = NO;
-                    if (regRelay[0].relay_event.bits.Gun1_N == YES)
-                        outputRelay[0].relay_event.bits.Gun1_N = NO;
-                }
-                if(index == 1)
-                {
-                    if(regRelay[0].relay_event.bits.Gun2_P == YES)
-                        outputRelay[0].relay_event.bits.Gun2_P = NO;
-                    if (regRelay[0].relay_event.bits.Gun2_N == YES)
-                        outputRelay[0].relay_event.bits.Gun2_N = NO;
-                }
+                PRINTF_FUNC("Gun %d Set K1K2 Open At Idle Mode", index + 1);
             }
-		}
-	}
-	else if (_chargingData[index]->SystemStatus == S_CCS_PRECHARGE_ST0)
-	{
+            ShmOutputRelayConfig[index]->bits.Output_N = false;
+            ShmOutputRelayConfig[index]->bits.Output_P = false;
+        }
 
-	}
-	else if (_chargingData[index]->SystemStatus == S_CCS_PRECHARGE_ST1)
-	{
+        location = ShmPsuGrouping->GroupCollection[index].Location;
 
-	}
+        if(ShmOutputRelayConfig[index]->bits.Output_N != LocationRelayCtrl[location]->bits.Gun_N)
+        {
+#if 0
+            PRINTF_FUNC("Connector %d Set K1K2 N %s at Location %d",
+                index + 1, ShmOutputRelayConfig[index]->bits.Output_N ? "On" : "Off", location + 1);
+#endif
+        }
+        LocationRelayCtrl[location]->bits.Gun_N = ShmOutputRelayConfig[index]->bits.Output_N;
+
+        if(ShmOutputRelayConfig[index]->bits.Output_P != LocationRelayCtrl[location]->bits.Gun_P)
+        {
+#if 0
+            PRINTF_FUNC("Connector %d Set K1K2 P %s at Location %d",
+                index + 1, ShmOutputRelayConfig[index]->bits.Output_P ? "On" : "Off", location + 1);
+#endif
+        }
+        LocationRelayCtrl[location]->bits.Gun_P = ShmOutputRelayConfig[index]->bits.Output_P;
+    }
 }
 
 void SetParalleRelayStatus()
 {
-	// 之後雙槍單模機種,橋接都會上
-	if (gunCount >= 2)
-	{
-		if (_chargingData[0]->SystemStatus == S_BOOTING || _chargingData[1]->SystemStatus == S_BOOTING ||
-				((_chargingData[0]->SystemStatus == S_IDLE || _chargingData[0]->SystemStatus == S_MAINTAIN || _chargingData[0]->SystemStatus == S_FAULT) &&
-				(_chargingData[1]->SystemStatus == S_IDLE || _chargingData[1]->SystemStatus == S_MAINTAIN || _chargingData[1]->SystemStatus == S_FAULT)))
-		{
-            if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable)
-            {
-                // two relay board
-                // 初始化~ 不搭橋接
+    for(int i = 0; i < ShmChargerInfo->Control.MaxConnector - 1; i++)
+    {
+        if((ShmParallelRelayConfig->CtrlValue & (1 << i)) != (LocationRelayCtrl[i]->bits.Gun_Parallel_N_P << i))
+        {
 #if 0
-                if (regRelay[0].relay_event.bits.Gun1_Parallel_P == YES)
-                    outputRelay[0].relay_event.bits.Gun1_Parallel_P = NO;
-                if (regRelay[0].relay_event.bits.Gun1_Parallel_N == YES)
-                    outputRelay[0].relay_event.bits.Gun1_Parallel_N = NO;
-                if (regRelay[0].relay_event.bits.Gun2_Parallel_P == YES)
-                    outputRelay[0].relay_event.bits.Gun2_Parallel_P = NO;
-                if (regRelay[0].relay_event.bits.Gun2_Parallel_N == YES)
-                    outputRelay[0].relay_event.bits.Gun2_Parallel_N = NO;
-                if (regRelay[1].relay_event.bits.Gun1_Parallel_P == YES)
-                    outputRelay[1].relay_event.bits.Gun1_Parallel_P = NO;
-                if (regRelay[1].relay_event.bits.Gun1_Parallel_N == YES)
-                    outputRelay[1].relay_event.bits.Gun1_Parallel_N = NO;
+            PRINTF_FUNC("Set Parallel Relay N & P %s at Location %d",
+                (ShmParallelRelayConfig->CtrlValue & (1 << i)) ? "On" : "Off", i + 1);
 #endif
-                // gun 1 & gun 3 parallel relay enable
-                if (regRelay[0].relay_event.bits.Gun1_Parallel_P == NO)
-                    outputRelay[0].relay_event.bits.Gun1_Parallel_P = YES;
-                if (regRelay[0].relay_event.bits.Gun1_Parallel_N == NO)
-                    outputRelay[0].relay_event.bits.Gun1_Parallel_N = YES;
-
-                // gun 3 & gun 4 parallel relay disable
-                if (regRelay[0].relay_event.bits.Gun2_Parallel_P == YES)
-                    outputRelay[0].relay_event.bits.Gun2_Parallel_P = NO;
-                if (regRelay[0].relay_event.bits.Gun2_Parallel_N == YES)
-                    outputRelay[0].relay_event.bits.Gun2_Parallel_N = NO;
-
-                // gun 4 & gun 2 parallel relay enable
-                if (regRelay[1].relay_event.bits.Gun1_Parallel_P == NO)
-                    outputRelay[1].relay_event.bits.Gun1_Parallel_P = YES;
-                if (regRelay[1].relay_event.bits.Gun1_Parallel_N == NO)
-                    outputRelay[1].relay_event.bits.Gun1_Parallel_N = YES;
-            }
-            else
+        }
+        LocationRelayCtrl[i]->bits.Gun_Parallel_N_P = (ShmParallelRelayConfig->CtrlValue & (1 << i)) ? YES : NO;
+
+        if(!ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable)
+        {
+            if((ShmParallelRelayConfig->CtrlValue & (1 << i)) != (LocationRelayCtrl[i]->bits.Gun_Parallel_P << i))
             {
-                // only one relay board
-                // 初始化~ 不搭橋接
-                if (regRelay[0].relay_event.bits.Gun1_Parallel_N == YES)
-                    outputRelay[0].relay_event.bits.Gun1_Parallel_N = NO;
-                if (regRelay[0].relay_event.bits.Gun2_Parallel_N == YES)
-                    outputRelay[0].relay_event.bits.Gun2_Parallel_N = NO;
-            }
-		}
-		else
-		{
-			if (_chargingData[0]->IsReadyToCharging == YES ||
-					_chargingData[1]->IsReadyToCharging == YES)
-			{
-				// ************需考慮在切換中 - 切開 relay 與搭回 relay 的時機點************
-				if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX)
-				{
-					if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag < _REASSIGNED_RELAY_M_TO_A)
-					{
-                        if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable)
-                        {
-                            // two relay board
-                            // 最大充 - 搭上橋接
-#if 0
-                            if (regRelay[0].relay_event.bits.Gun1_Parallel_N == NO)
-                                outputRelay[0].relay_event.bits.Gun1_Parallel_N = YES;
-                            if (regRelay[0].relay_event.bits.Gun1_Parallel_P == NO)
-                                outputRelay[0].relay_event.bits.Gun1_Parallel_P = YES;
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_N == NO)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_N = YES;
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_P == NO)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_P = YES;
-                            if (regRelay[1].relay_event.bits.Gun1_Parallel_N == NO)
-                                outputRelay[1].relay_event.bits.Gun1_Parallel_N = YES;
-                            if (regRelay[1].relay_event.bits.Gun1_Parallel_P == NO)
-                                outputRelay[1].relay_event.bits.Gun1_Parallel_P = YES;
-#endif
-                            // gun 3 & gun 4 parallel relay enable
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_N == NO)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_N = YES;
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_P == NO)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_P = YES;
-                        }
-                        else
-                        {
-                            // only one relay board
-                            // 最大充 - 搭上橋接
-                            if (regRelay[0].relay_event.bits.Gun1_Parallel_N == NO)
-                                outputRelay[0].relay_event.bits.Gun1_Parallel_N = YES;
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_N == NO)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_N = YES;
-                        }
-					}
-					else
-					{
-                        if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable)
-                        {
-                            // two relay board
-                            // 平均充 - 不搭
-#if 0
-                            if (regRelay[0].relay_event.bits.Gun1_Parallel_P == YES)
-                                outputRelay[0].relay_event.bits.Gun1_Parallel_P = NO;
-                            if (regRelay[0].relay_event.bits.Gun1_Parallel_N == YES)
-                                outputRelay[0].relay_event.bits.Gun1_Parallel_N = NO;
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_P == YES)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_P = NO;
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_N == YES)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_N = NO;
-                            if (regRelay[1].relay_event.bits.Gun1_Parallel_P == YES)
-                                outputRelay[1].relay_event.bits.Gun1_Parallel_P = NO;
-                            if (regRelay[1].relay_event.bits.Gun1_Parallel_N == YES)
-                                outputRelay[1].relay_event.bits.Gun1_Parallel_N = NO;
-#endif
-                            // gun 3 & gun 4 parallel relay disable
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_P == YES)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_P = NO;
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_N == YES)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_N = NO;
-                        }
-                        else
-                        {
-                            // only one relay board
-                            // 平均充 - 不搭
-                            if (regRelay[0].relay_event.bits.Gun1_Parallel_N == YES)
-                                outputRelay[0].relay_event.bits.Gun1_Parallel_N = NO;
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_N == YES)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_N = NO;
-                        }
-					}
-				}
-				else if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER)
-				{
-					if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag < _REASSIGNED_RELAY_A_TO_M)
-					{
-                        if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable)
-                        {
-                            // two relay board
-                            // 平均充 - 不搭
-#if 0
-                            if (regRelay[0].relay_event.bits.Gun1_Parallel_P == YES)
-                                outputRelay[0].relay_event.bits.Gun1_Parallel_P = NO;
-                            if (regRelay[0].relay_event.bits.Gun1_Parallel_N == YES)
-                                outputRelay[0].relay_event.bits.Gun1_Parallel_N = NO;
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_P == YES)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_P = NO;
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_N == YES)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_N = NO;
-                            if (regRelay[1].relay_event.bits.Gun1_Parallel_P == YES)
-                                outputRelay[1].relay_event.bits.Gun1_Parallel_P = NO;
-                            if (regRelay[1].relay_event.bits.Gun1_Parallel_N == YES)
-                                outputRelay[1].relay_event.bits.Gun1_Parallel_N = NO;
-#endif
-                            // gun 3 & gun 4 parallel relay disable
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_P == YES)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_P = NO;
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_N == YES)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_N = NO;
-                        }
-                        else
-                        {
-                            // only one relay board
-                            // 平均充 - 不搭
-                            if (regRelay[0].relay_event.bits.Gun1_Parallel_N == YES)
-                                outputRelay[0].relay_event.bits.Gun1_Parallel_N = NO;
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_N == YES)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_N = NO;
-                        }
-					}
-					else
-					{
-                        if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable)
-                        {
-                            // two relay board
-                            // 最大充 - 搭上橋接
 #if 0
-                            if (regRelay[0].relay_event.bits.Gun1_Parallel_N == NO)
-                                outputRelay[0].relay_event.bits.Gun1_Parallel_N = YES;
-                            if (regRelay[0].relay_event.bits.Gun1_Parallel_P == NO)
-                                outputRelay[0].relay_event.bits.Gun1_Parallel_P = YES;
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_N == NO)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_N = YES;
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_P == NO)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_P = YES;
-                            if (regRelay[1].relay_event.bits.Gun1_Parallel_N == NO)
-                                outputRelay[1].relay_event.bits.Gun1_Parallel_N = YES;
-                            if (regRelay[1].relay_event.bits.Gun1_Parallel_P == NO)
-                                outputRelay[1].relay_event.bits.Gun1_Parallel_P = YES;
+                PRINTF_FUNC("Set Parallel Relay P %s at Location %d",
+                    (ShmParallelRelayConfig->CtrlValue & (1 << i)) ? "On" : "Off", i + 1);
 #endif
-                            // gun 3 & gun 4 parallel relay enable
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_N == NO)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_N = YES;
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_P == NO)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_P = YES;
-                        }
-                        else
-                        {
-                            // only one relay board
-                            // 最大充 - 搭上橋接
-                            if (regRelay[0].relay_event.bits.Gun1_Parallel_N == NO)
-                                outputRelay[0].relay_event.bits.Gun1_Parallel_N = YES;
-                            if (regRelay[0].relay_event.bits.Gun2_Parallel_N == NO)
-                                outputRelay[0].relay_event.bits.Gun2_Parallel_N = YES;
-                        }
-					}
-				}
-			}
-		}
-	}
+            }
+            LocationRelayCtrl[i + 1]->bits.Gun_Parallel_N_P = (ShmParallelRelayConfig->CtrlValue & (1 << i)) ? YES : NO;
+        }
+    }
 }
 
 void SetAcContactorStatus(void)
@@ -1745,6 +1571,33 @@ int InitShareMemory()
         #endif
         result = FAIL;
     }
+    if(result == PASS)
+    {
+        ShmPsuGrouping = &ShmChargerInfo->PsuGrouping;
+        for(int i = 0; i < MAX_GROUP_QUANTITY; i++)
+        {
+            ShmOutputRelayConfig[i] = &ShmChargerInfo->PsuGrouping.OutputRelayConfig[i];
+            ShmOutputRelayConfirmed[i] = &ShmChargerInfo->PsuGrouping.OutputRelayConfirmed[i];
+        }
+        ShmParallelRelayConfig = &ShmChargerInfo->PsuGrouping.ParallelRelayConfig;
+        ShmParallelRelayConfirmed = &ShmChargerInfo->PsuGrouping.ParallelRelayConfirmed;
+
+        if(ShmChargerInfo->Control.SysCtrl.bits.RelayBoardDisable == false)
+        {
+            LocationRelayCtrl[0] = (RBRelayControl *)&outputRelay[0].relay_event.relay_status[1];
+            LocationRelayCtrl[1] = (RBRelayControl *)&outputRelay[0].relay_event.relay_status[2];
+            LocationRelayResponse[0] = (RBRelayControl *)&regRelay[0].relay_event.relay_status[1];
+            LocationRelayResponse[1] = (RBRelayControl *)&regRelay[0].relay_event.relay_status[2];
+
+            if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable)
+            {
+                LocationRelayCtrl[2] = (RBRelayControl *)&outputRelay[1].relay_event.relay_status[1];
+                LocationRelayCtrl[3] = (RBRelayControl *)&outputRelay[1].relay_event.relay_status[2];
+                LocationRelayResponse[2] = (RBRelayControl *)&regRelay[1].relay_event.relay_status[1];
+                LocationRelayResponse[3] = (RBRelayControl *)&regRelay[1].relay_event.relay_status[2];
+            }
+        }
+    }
 
 	return result;
 }
@@ -1885,109 +1738,84 @@ void Initialization()
 
 bool IsNoneMatchRelayStatus(byte index)
 {
-	bool result = false;
+    bool result = false;
 
-	if ((regRelay[index].relay_event.bits.AC_Contactor != outputRelay[index].relay_event.bits.AC_Contactor) ||
-		(regRelay[index].relay_event.bits.CCS_Precharge != outputRelay[index].relay_event.bits.CCS_Precharge) ||
-		(regRelay[index].relay_event.bits.Gun1_P != outputRelay[index].relay_event.bits.Gun1_P) ||
-		(regRelay[index].relay_event.bits.Gun1_N != outputRelay[index].relay_event.bits.Gun1_N) ||
-		(regRelay[index].relay_event.bits.Gun2_P != outputRelay[index].relay_event.bits.Gun2_P) ||
-		(regRelay[index].relay_event.bits.Gun2_N != outputRelay[index].relay_event.bits.Gun2_N) ||
-		(regRelay[index].relay_event.bits.Gun1_Parallel_P != outputRelay[index].relay_event.bits.Gun1_Parallel_P) ||
-		(regRelay[index].relay_event.bits.Gun1_Parallel_N != outputRelay[index].relay_event.bits.Gun1_Parallel_N) ||
-		(regRelay[index].relay_event.bits.Gun2_Parallel_P != outputRelay[index].relay_event.bits.Gun2_Parallel_P) ||
-		(regRelay[index].relay_event.bits.Gun2_Parallel_N != outputRelay[index].relay_event.bits.Gun2_Parallel_N))
-	{
-		if (regRelay[index].relay_event.bits.AC_Contactor != outputRelay[index].relay_event.bits.AC_Contactor)
-		{
-		    if(TempRegRelay[index].relay_event.bits.AC_Contactor != outputRelay[index].relay_event.bits.AC_Contactor)
-		    {
-		        PRINTF_FUNC("[%d]AC Contact Relay none match, need to %s", index,
-                    outputRelay[index].relay_event.bits.AC_Contactor == YES ? "On" : "Off");
-		        TempRegRelay[index].relay_event.bits.AC_Contactor = outputRelay[index].relay_event.bits.AC_Contactor;
-		    }
-		}
-		if (regRelay[index].relay_event.bits.CCS_Precharge != outputRelay[index].relay_event.bits.CCS_Precharge)
-		{
-		    if(TempRegRelay[index].relay_event.bits.CCS_Precharge != outputRelay[index].relay_event.bits.CCS_Precharge)
-		    {
-		        PRINTF_FUNC("[%d]CCS Precharge Relay none match, need to %s", index,
-                    outputRelay[index].relay_event.bits.CCS_Precharge == YES ? "On" : "Off");
-		        TempRegRelay[index].relay_event.bits.CCS_Precharge = outputRelay[index].relay_event.bits.CCS_Precharge;
-		    }
-		}
-		if (regRelay[index].relay_event.bits.Gun1_P != outputRelay[index].relay_event.bits.Gun1_P)
-		{
-		    if(TempRegRelay[index].relay_event.bits.Gun1_P != outputRelay[index].relay_event.bits.Gun1_P)
-		    {
-		        PRINTF_FUNC("[%d]SMR1:D+ Relay none match, need to %s", index,
-                    outputRelay[index].relay_event.bits.Gun1_P == YES ? "On" : "Off");
-		        TempRegRelay[index].relay_event.bits.Gun1_P = outputRelay[index].relay_event.bits.Gun1_P;
-		    }
-		}
-		if (regRelay[index].relay_event.bits.Gun1_N != outputRelay[index].relay_event.bits.Gun1_N)
-		{
-		    if(TempRegRelay[index].relay_event.bits.Gun1_N != outputRelay[index].relay_event.bits.Gun1_N)
-		    {
-		        PRINTF_FUNC("[%d]SMR1:D- Relay none match, need to %s", index,
-                    outputRelay[index].relay_event.bits.Gun1_N == YES ? "On" : "Off");
-		        TempRegRelay[index].relay_event.bits.Gun1_N = outputRelay[index].relay_event.bits.Gun1_N;
-		    }
-		}
-		if (regRelay[index].relay_event.bits.Gun2_P != outputRelay[index].relay_event.bits.Gun2_P)
-		{
-		    if(TempRegRelay[index].relay_event.bits.Gun2_P != outputRelay[index].relay_event.bits.Gun2_P)
-		    {
-		        PRINTF_FUNC("[%d]SMR2:D+ Relay none match, need to %s", index,
-                    outputRelay[index].relay_event.bits.Gun2_P == YES ? "On" : "Off");
-		        TempRegRelay[index].relay_event.bits.Gun2_P = outputRelay[index].relay_event.bits.Gun2_P;
-		    }
-		}
-		if (regRelay[index].relay_event.bits.Gun2_N != outputRelay[index].relay_event.bits.Gun2_N)
-		{
-		    if(TempRegRelay[index].relay_event.bits.Gun2_N != outputRelay[index].relay_event.bits.Gun2_N)
-		    {
-		        PRINTF_FUNC("[%d]SMR2:D- Relay none match, need to %s", index,
-                    outputRelay[index].relay_event.bits.Gun2_N == YES ? "On" : "Off");
-		        TempRegRelay[index].relay_event.bits.Gun2_N = outputRelay[index].relay_event.bits.Gun2_N;
-		    }
-		}
-		if (regRelay[index].relay_event.bits.Gun1_Parallel_P != outputRelay[index].relay_event.bits.Gun1_Parallel_P)
-		{
-		    if(TempRegRelay[index].relay_event.bits.Gun1_Parallel_P != outputRelay[index].relay_event.bits.Gun1_Parallel_P)
-		    {
-		        PRINTF_FUNC("[%d]Parallel:D+ Relay none match, need to %s", index,
-                    outputRelay[index].relay_event.bits.Gun1_Parallel_P == YES ? "On" : "Off");
-		        TempRegRelay[index].relay_event.bits.Gun1_Parallel_P = outputRelay[index].relay_event.bits.Gun1_Parallel_P;
-		    }
-		}
-		if (regRelay[index].relay_event.bits.Gun1_Parallel_N != outputRelay[index].relay_event.bits.Gun1_Parallel_N)
-		{
-		    if(TempRegRelay[index].relay_event.bits.Gun1_Parallel_N != outputRelay[index].relay_event.bits.Gun1_Parallel_N)
-		    {
-		        PRINTF_FUNC("[%d]Parallel:D- Relay none match, need to %s", index,
-                    outputRelay[index].relay_event.bits.Gun1_Parallel_N == YES ? "On" : "Off");
-		        TempRegRelay[index].relay_event.bits.Gun1_Parallel_N = outputRelay[index].relay_event.bits.Gun1_Parallel_N;
-		    }
-		}
-		if (regRelay[index].relay_event.bits.Gun2_Parallel_P != outputRelay[index].relay_event.bits.Gun2_Parallel_P)
-		{
-		    if(TempRegRelay[index].relay_event.bits.Gun2_Parallel_P != outputRelay[index].relay_event.bits.Gun2_Parallel_P)
-		    {
-		        PRINTF_FUNC("[%d]Parallel2:D+ Relay none match, need to %s", index,
-                    outputRelay[index].relay_event.bits.Gun2_Parallel_P == YES ? "On" : "Off");
-		        TempRegRelay[index].relay_event.bits.Gun2_Parallel_P = outputRelay[index].relay_event.bits.Gun2_Parallel_P;
-		    }
-		}
-		if (regRelay[index].relay_event.bits.Gun2_Parallel_N != outputRelay[index].relay_event.bits.Gun2_Parallel_N)
-		{
-		    if(TempRegRelay[index].relay_event.bits.Gun2_Parallel_N != outputRelay[index].relay_event.bits.Gun2_Parallel_N)
-		    {
-		        PRINTF_FUNC("[%d]Parallel2:D- Relay none match, need to %s", index,
-                    outputRelay[index].relay_event.bits.Gun2_Parallel_N == YES ? "On" : "Off");
-		        TempRegRelay[index].relay_event.bits.Gun2_Parallel_N = outputRelay[index].relay_event.bits.Gun2_Parallel_N;
-		    }
-		}
+    if(regRelay[index].relay_event.relay_status[0] != outputRelay[index].relay_event.relay_status[0] ||
+        regRelay[index].relay_event.relay_status[1] != outputRelay[index].relay_event.relay_status[1] ||
+        regRelay[index].relay_event.relay_status[2] != outputRelay[index].relay_event.relay_status[2])
+	{
+        if(TempRegRelay[index].relay_event.bits.AC_Contactor != outputRelay[index].relay_event.bits.AC_Contactor)
+        {
+            PRINTF_FUNC("[%d]AC Contact Relay none match, need to %s", index,
+                outputRelay[index].relay_event.bits.AC_Contactor == YES ? "On" : "Off");
+        }
+        if(TempRegRelay[index].relay_event.bits.CCS_Precharge != outputRelay[index].relay_event.bits.CCS_Precharge)
+        {
+#if 0
+            PRINTF_FUNC("[%d]CCS Precharge Relay none match, need to %s", index,
+                outputRelay[index].relay_event.bits.CCS_Precharge == YES ? "On" : "Off");
+#endif
+        }
+        if(TempRegRelay[index].relay_event.bits.Gun1_P != outputRelay[index].relay_event.bits.Gun1_P)
+        {
+#if 0
+            PRINTF_FUNC("[%d]SMR1:D+ Relay none match, need to %s", index,
+                outputRelay[index].relay_event.bits.Gun1_P == YES ? "On" : "Off");
+#endif
+        }
+        if(TempRegRelay[index].relay_event.bits.Gun1_N != outputRelay[index].relay_event.bits.Gun1_N)
+        {
+#if 0
+            PRINTF_FUNC("[%d]SMR1:D- Relay none match, need to %s", index,
+                outputRelay[index].relay_event.bits.Gun1_N == YES ? "On" : "Off");
+#endif
+        }
+        if(TempRegRelay[index].relay_event.bits.Gun2_P != outputRelay[index].relay_event.bits.Gun2_P)
+        {
+#if 0
+            PRINTF_FUNC("[%d]SMR2:D+ Relay none match, need to %s", index,
+                outputRelay[index].relay_event.bits.Gun2_P == YES ? "On" : "Off");
+#endif
+        }
+        if(TempRegRelay[index].relay_event.bits.Gun2_N != outputRelay[index].relay_event.bits.Gun2_N)
+        {
+#if 0
+            PRINTF_FUNC("[%d]SMR2:D- Relay none match, need to %s", index,
+                outputRelay[index].relay_event.bits.Gun2_N == YES ? "On" : "Off");
+#endif
+        }
+        if(TempRegRelay[index].relay_event.bits.Gun1_Parallel_P != outputRelay[index].relay_event.bits.Gun1_Parallel_P)
+        {
+#if 0
+            PRINTF_FUNC("[%d]Parallel:D+ Relay none match, need to %s", index,
+                outputRelay[index].relay_event.bits.Gun1_Parallel_P == YES ? "On" : "Off");
+#endif
+        }
+        if(TempRegRelay[index].relay_event.bits.Gun1_Parallel_N != outputRelay[index].relay_event.bits.Gun1_Parallel_N)
+        {
+#if 0
+            PRINTF_FUNC("[%d]Parallel:D- Relay none match, need to %s", index,
+                outputRelay[index].relay_event.bits.Gun1_Parallel_N == YES ? "On" : "Off");
+#endif
+        }
+        if(TempRegRelay[index].relay_event.bits.Gun2_Parallel_P != outputRelay[index].relay_event.bits.Gun2_Parallel_P)
+        {
+#if 0
+            PRINTF_FUNC("[%d]Parallel2:D+ Relay none match, need to %s", index,
+                outputRelay[index].relay_event.bits.Gun2_Parallel_P == YES ? "On" : "Off");
+#endif
+        }
+        if(TempRegRelay[index].relay_event.bits.Gun2_Parallel_N != outputRelay[index].relay_event.bits.Gun2_Parallel_N)
+        {
+#if 0
+            PRINTF_FUNC("[%d]Parallel2:D- Relay none match, need to %s", index,
+                outputRelay[index].relay_event.bits.Gun2_Parallel_N == YES ? "On" : "Off");
+#endif
+        }
+
+        TempRegRelay[index].relay_event.relay_status[0] = outputRelay[index].relay_event.relay_status[0];
+        TempRegRelay[index].relay_event.relay_status[1] = outputRelay[index].relay_event.relay_status[1];
+        TempRegRelay[index].relay_event.relay_status[2] = outputRelay[index].relay_event.relay_status[2];
 
 		result = true;
 	}
@@ -1995,20 +1823,6 @@ bool IsNoneMatchRelayStatus(byte index)
 	return result;
 }
 
-void MatchRelayStatus()
-{
-	// 因為 AC Contactor 沒有 Feedback,所以暫時先這樣處理
-	//regRelay.relay_event.bits.AC_Contactor = outputRelay.relay_event.bits.AC_Contactor;
-//	ShmSysConfigAndInfo->SysInfo.AcContactorStatus  = regRelay.relay_event.bits.AC_Contactor = outputRelay.relay_event.bits.AC_Contactor;
-//	regRelay.relay_event.bits.CCS_Precharge = outputRelay.relay_event.bits.CCS_Precharge;
-//	regRelay.relay_event.bits.Gun1_P = outputRelay.relay_event.bits.Gun1_P;
-//	regRelay.relay_event.bits.Gun1_N = outputRelay.relay_event.bits.Gun1_N;
-//	regRelay.relay_event.bits.Gun2_P = outputRelay.relay_event.bits.Gun2_P;
-//	regRelay.relay_event.bits.Gun2_N = outputRelay.relay_event.bits.Gun2_N;
-//	regRelay.relay_event.bits.Gun1_Parallel_P = outputRelay.relay_event.bits.Gun1_Parallel_P;
-//	regRelay.relay_event.bits.Gun1_Parallel_N = outputRelay.relay_event.bits.Gun1_Parallel_N;
-}
-
 void CheckRelayStatusByADC()
 {
 	if (ShmRelayModuleData[0]->Gun1FuseOutputVolt > 0 && ShmRelayModuleData[0]->Gun1RelayOutputVolt > 0 &&
@@ -2624,7 +2438,7 @@ int main(void)
 		return 0;
 	}
 
-	gunCount = ShmSysConfigAndInfo->SysConfig.TotalConnectorCount;
+	gunCount = ShmChargerInfo->Control.MaxConnector;
 	acgunCount = ShmSysConfigAndInfo->SysConfig.AcConnectorCount;
 	// Open Uart5 for RB
 	Uart5Fd = InitComPort();
@@ -2668,7 +2482,7 @@ int main(void)
             // 程序開始之前~ 必須先確定 FW 版本與硬體版本,確認後!!~ 該模組才算是真正的 Initial Comp.
             if(ShmChargerInfo->Control.SysCtrl.bits.RelayBoardDisable == false)
             {
-                if (ShmRelayModuleData[0]->SelfTest_Comp == NO)
+                if (ShmRelayModuleData[0]->SelfTest_Comp == NO && !ShmChargerInfo->Control.TestCtrl.bits.ChargingSimulation)
                 {
                     // clena fw version
                     memset(ShmSysConfigAndInfo->SysInfo.RelayModuleFwRev, 0x00, 32);
@@ -2690,7 +2504,7 @@ int main(void)
 
                 // DO360 RC2
                 if (ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable == true &&
-                        ShmRelayModuleData[1]->SelfTest_Comp == NO)
+                    ShmRelayModuleData[1]->SelfTest_Comp == NO && !ShmChargerInfo->Control.TestCtrl.bits.ChargingSimulation)
                 {
                     // clena fw version
                     memset(ShmSysConfigAndInfo->SysInfo.Relay2ModuleFwRev, 0x00, 32);
@@ -2713,7 +2527,7 @@ int main(void)
 
             if(ShmChargerInfo->Control.SysCtrl.bits.FanBoardDisable == false)
             {
-                if (ShmFanModuleData->SelfTest_Comp == NO)
+                if (ShmFanModuleData->SelfTest_Comp == NO && !ShmChargerInfo->Control.TestCtrl.bits.ChargingSimulation)
                 {
                     // clena fw version
                     memset(ShmSysConfigAndInfo->SysInfo.FanModuleFwRev, 0x00, 32);
@@ -2731,7 +2545,8 @@ int main(void)
                 }
             }
 
-            if(_RelaySelfTestOK == YES)
+
+            if(_RelaySelfTestOK == YES || ShmChargerInfo->Control.TestCtrl.bits.ChargingSimulation)
             {
                 // ==============優先權最高 10 ms ==============
                 // 輸出電壓
@@ -2740,9 +2555,9 @@ int main(void)
                 // 三相輸入電壓
                 GetPresentInputVol();
 
-                //GetRelayOutputStatus();
+                GetRelayOutputStatus();
 
-                for (int i = 0; i < gunCount; i++)
+                for(int i = 0; i < ShmChargerInfo->Control.MaxConnector; i++)
                 {
                     // check k1 k2 relay 狀態
                     CheckK1K2RelayOutput(i);
@@ -2797,16 +2612,15 @@ int main(void)
                 {
                     if (Config_Relay_Output(Uart5Fd, Addr.DO360_RC1, &outputRelay[0]))
                     {
-                        regRelay[0].relay_event.bits.AC_Contactor = outputRelay[0].relay_event.bits.AC_Contactor;
-                        regRelay[0].relay_event.bits.CCS_Precharge = outputRelay[0].relay_event.bits.CCS_Precharge;
-                        regRelay[0].relay_event.bits.Gun1_P = outputRelay[0].relay_event.bits.Gun1_P;
-                        regRelay[0].relay_event.bits.Gun1_N = outputRelay[0].relay_event.bits.Gun1_N;
-                        regRelay[0].relay_event.bits.Gun2_P = outputRelay[0].relay_event.bits.Gun2_P;
-                        regRelay[0].relay_event.bits.Gun2_N = outputRelay[0].relay_event.bits.Gun2_N;
-                        regRelay[0].relay_event.bits.Gun1_Parallel_P = outputRelay[0].relay_event.bits.Gun1_Parallel_P;
-                        regRelay[0].relay_event.bits.Gun1_Parallel_N = outputRelay[0].relay_event.bits.Gun1_Parallel_N;
-                        regRelay[0].relay_event.bits.Gun2_Parallel_P = outputRelay[0].relay_event.bits.Gun2_Parallel_P;
-                        regRelay[0].relay_event.bits.Gun2_Parallel_N = outputRelay[0].relay_event.bits.Gun2_Parallel_N;
+                        //regRelay[0].relay_event.relay_status[0] = outputRelay[0].relay_event.relay_status[0];
+                        //regRelay[0].relay_event.relay_status[1] = outputRelay[0].relay_event.relay_status[1];
+                        //regRelay[0].relay_event.relay_status[2] = outputRelay[0].relay_event.relay_status[2];
+                    }
+                    if(ShmChargerInfo->Control.TestCtrl.bits.ChargingSimulation)
+                    {
+                        regRelay[0].relay_event.relay_status[0] = outputRelay[0].relay_event.relay_status[0];
+                        regRelay[0].relay_event.relay_status[1] = outputRelay[0].relay_event.relay_status[1];
+                        regRelay[0].relay_event.relay_status[2] = outputRelay[0].relay_event.relay_status[2];
                     }
                 }
 
@@ -2817,21 +2631,21 @@ int main(void)
                     {
                         if (Config_Relay_Output(Uart5Fd, Addr.DO360_RC2, &outputRelay[1]))
                         {
-                            regRelay[1].relay_event.bits.AC_Contactor = outputRelay[1].relay_event.bits.AC_Contactor;
-                            regRelay[1].relay_event.bits.CCS_Precharge = outputRelay[1].relay_event.bits.CCS_Precharge;
-                            regRelay[1].relay_event.bits.Gun1_P = outputRelay[1].relay_event.bits.Gun1_P;
-                            regRelay[1].relay_event.bits.Gun1_N = outputRelay[1].relay_event.bits.Gun1_N;
-                            regRelay[1].relay_event.bits.Gun2_P = outputRelay[1].relay_event.bits.Gun2_P;
-                            regRelay[1].relay_event.bits.Gun2_N = outputRelay[1].relay_event.bits.Gun2_N;
-                            regRelay[1].relay_event.bits.Gun1_Parallel_P = outputRelay[1].relay_event.bits.Gun1_Parallel_P;
-                            regRelay[1].relay_event.bits.Gun1_Parallel_N = outputRelay[1].relay_event.bits.Gun1_Parallel_N;
-                            regRelay[1].relay_event.bits.Gun2_Parallel_P = outputRelay[1].relay_event.bits.Gun2_Parallel_P;
-                            regRelay[1].relay_event.bits.Gun2_Parallel_N = outputRelay[1].relay_event.bits.Gun2_Parallel_N;
+                            //regRelay[1].relay_event.relay_status[0] = outputRelay[1].relay_event.relay_status[0];
+                            //regRelay[1].relay_event.relay_status[1] = outputRelay[1].relay_event.relay_status[1];
+                            //regRelay[1].relay_event.relay_status[2] = outputRelay[1].relay_event.relay_status[2];
                         }
                     }
+                    if(ShmChargerInfo->Control.TestCtrl.bits.ChargingSimulation)
+                    {
+                        regRelay[1].relay_event.relay_status[0] = outputRelay[1].relay_event.relay_status[0];
+                        regRelay[1].relay_event.relay_status[1] = outputRelay[1].relay_event.relay_status[1];
+                        regRelay[1].relay_event.relay_status[2] = outputRelay[1].relay_event.relay_status[2];
+                    }
                 }
             }
 
+
             if (ShmFanModuleData->SelfTest_Comp == YES ||
                     strlen((char *)ShmSysConfigAndInfo->SysInfo.FanModuleFwRev) != 0 ||
                     ShmSysConfigAndInfo->SysInfo.FanModuleFwRev[0] != '\0')

Разница между файлами не показана из-за своего большого размера
+ 552 - 762
EVSE/Projects/DO360/Apps/Module_PsuComm.c


+ 12 - 4
EVSE/Projects/DO360/Apps/Module_PsuComm.h

@@ -33,12 +33,11 @@
 #include 	<stdbool.h>
 
 typedef unsigned char 		byte;
-typedef unsigned short 	word;
+typedef unsigned short 	    word;
 typedef unsigned int 		unit;
 
-unsigned char _gunCount;
-struct ChargingInfoData *chargingInfo[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY + GENERAL_GUN_QUANTITY];
-bool isStartOutputSwitch[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY + GENERAL_GUN_QUANTITY];
+struct ChargingInfoData *chargingInfo[CONNECTOR_QUANTITY];
+bool isStartOutputSwitch[CONNECTOR_QUANTITY];
 
 struct timeval _cmdSubPriority_time;
 struct timeval _derating_time;
@@ -71,3 +70,12 @@ enum _PSU_CMD_SEQ
 	_PSU_CMD_IVAILIABLE	= 12,
 	_PSU_CMD_TEMP		= 13
 };
+
+enum _CURRENT_CONFIG_MODE
+{
+    _CURRENT_MODE_NONE      = 0,
+    _CURRENT_MODE_BALANCE   = 1,
+    _CURRENT_MODE_INCREASE  = 2,
+    _CURRENT_MODE_DECREASE  = 3,
+    _CURRENT_MODE_DERATING  = 4,
+};

+ 778 - 28
EVSE/Projects/DO360/Apps/ReadCmdline.c

@@ -75,7 +75,10 @@ char *msg = "state : get gun state (index) \n"
 		"lock : get gun locked state (index) \n"
 		"self : self test state (x) \n"
 		"ver : ver of board (407 or index or rb or fan) \n"
-		"ac : get ac relay state (x) \n";
+		"ac : get ac relay state (x) \n"
+        "gunchg: set gun start charging \n"
+        "gunstp: set gun stop charging \n"
+        "gunext: extend gun capability \n";
 
 bool FindChargingInfoData(byte target, struct ChargingInfoData **chargingData)
 {
@@ -289,8 +292,6 @@ void RunStatusProc(char *v1, char *v2)
             printf("ConnectorAlarmCode = %s \n", _chargingData[_index]->ConnectorAlarmCode);
             printf("EvConnAlarmCode = %s \n", _chargingData[_index]->EvConnAlarmCode);
             printf("RemotenAlarmCode = %s \n", ShmSysConfigAndInfo->SysInfo.ConnectorInfo[_index].RemotenAlarmCode);
-			//printf("ConnectorAlarmCode = %s \n", ShmOCPP16Data->StatusNotification[index].ErrorCode);
-			//printf("ConnectorAlarmCode = %s \n", ShmOCPP16Data->StatusNotification[index].VendorErrorCode);
 		}
 		else
 		{
@@ -646,15 +647,48 @@ void SetGFDMode(char *v1)
 	ShmSysConfigAndInfo->SysConfig.AlwaysGfdFlag = mode;
 }
 
-void GetPsuTemp()
+// Gun  Temp  Chiller  PSU 0  PSU 1  PSU 2  ...
+//  1    XXX    XXX     XXX    XXX    XXX    XXX
+void GetTemperature(char *v1)
 {
-	for (byte index = 0; index < ShmPsuData->GroupCount; index++)
-	{
-		for (byte count = 0; count < ShmPsuData->PsuGroup[index].GroupPresentPsuQuantity; count++)
-		{
-			printf("PSU Temp = %d \n", ShmPsuData->PsuGroup[index].PsuModule[count].ExletTemp);
-		}
-	}
+    bool show = false;
+    char strGunTemp[16], strChillerTemp[16];
+
+    if(strcmp(v1, "c") == 0)
+    {
+        printf("\r\n Get c Parameter");
+        show = true;
+    }
+    do
+    {
+        printf("\r\n Gun  Temp  Chiller  PSU 0  PSU 1  PSU 2  ...");
+        for(int i = 0; i < CONNECTOR_QUANTITY; i++)
+        {
+            sprintf(strGunTemp, "N/A");
+            sprintf(strChillerTemp, "N/A");
+
+            if(_chargingData[i]->ConnectorTemp != 0 && _chargingData[i]->ConnectorTemp != 0xFF)
+            {
+                sprintf(strGunTemp, "%3d", _chargingData[i]->ConnectorTemp - 60);
+            }
+            if(_chargingData[i]->ChillerTemp != 0 && _chargingData[i]->ChillerTemp != 0xFF)
+            {
+                sprintf(strChillerTemp, "%3d", _chargingData[i]->ChillerTemp - 60);
+            }
+            printf("\r\n  %d    %s    %s  ", i + 1, strGunTemp, strChillerTemp);
+
+            for(int j = 0; j < ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity; j++)
+            {
+                printf("   %3d ", ShmPsuData->PsuGroup[i].PsuModule[j].ExletTemp);
+            }
+        }
+        printf("\r\n");
+
+        if(show)
+        {
+            sleep(1);
+        }
+    }while(show);
 }
 
 void GetAcInputVol()
@@ -1520,36 +1554,37 @@ void RemoveGroupCollection(byte group, byte target)
     }
 }
 
-// Gun  Role  Quantity  Master   Member    OutputVoltage  OutputCurrent  AvailablePower  AvailableCurrent  StableCurrent  OutputRelay  ParallelRelay
-//  1    00       3       00    00 00 00       0000 V         0000 A         000 kW           0000 A          0000 A           00            XX
+// Gun(Status)(Ro)(Q)  Master      Member      OutputVol  OutputCur  AvaiPower  AvaiCur  StabCur  K1K2  ParaRelay
+//  1   (00)   00  3     00    [00] [00] [00]    0000 V     0000 A    0000 kW    0000 A   0000 A   00      XX
 void ShowGroupingInfo(void)
 {
     byte target = 0;
 
-    printf("\r\n Gun  Role  Quantity  Master   Member    OutputVoltage  OutputCurrent  AvailablePower  AvailableCurrent  StableCurrent  OutputRelay  ParallelRelay");
+    printf("\r\n Gun(Status)(Ro)(Q)  Master      Member      OutputVol  OutputCur  AvaiPower  AvaiCur  StabCur  K1K2  ParaRelay");
 
     for(int i = 0; i < 4; i++)
     {
         target = ShmPsuGrouping->Layout[i];
-        printf("\r\n  %d    %2d       %d       %02X    ",
-            target + 1, ShmGroupCollection[target].Role, ShmGroupCollection[target].Partner.Quantity, ShmGroupCollection[target].TargetGroup);
+        printf("\r\n  %d   (%2d)   %2d  %d     %02X    ",
+            target + 1, _chargingData[target]->SystemStatus, ShmGroupCollection[target].Role,
+            ShmGroupCollection[target].Partner.Quantity, ShmGroupCollection[target].TargetGroup);
 
         for(int j = 0; j < 3; j++)
         {
             if(ShmGroupCollection[target].Role == 1 && j < ShmGroupCollection[target].Partner.Quantity)
             {
-                printf("%02X ", ShmGroupCollection[target].Partner.Member[j]);
+                printf("[%02X] ", ShmGroupCollection[target].Partner.Member[j]);
             }
             else
             {
-                printf("   ");
+                printf("     ");
             }
         }
-        printf("      %4d V         %4d A         %3d kW           %4d A          %4d A    ",
+        printf("   %4d V     %4d A    %4d kW    %4d A   %4d A   ",
             (int)_chargingData[target]->PresentChargingVoltage, (int)_chargingData[target]->PresentChargingCurrent,
             (int)(_chargingData[target]->AvailableChargingPower / 10), (int)(_chargingData[target]->AvailableChargingCurrent / 10),
             (int)(_chargingData[target]->DeratingChargingCurrent / 10));
-        printf("       %02X            %02X",ShmPsuGrouping->OutputRelayConfig[target].CtrlValue, ShmPsuGrouping->ParallelRelayConfig.CtrlValue);
+        printf("%02X      %02X",ShmPsuGrouping->OutputRelayConfig[target].CtrlValue, ShmPsuGrouping->ParallelRelayConfig.CtrlValue);
     }
     printf("\r\n\r\nSystem Capability Current = %4d.%01d A, Power = %3d.%01d kW",
         (ShmPsuData->SystemAvailableCurrent / 10), (ShmPsuData->SystemAvailableCurrent % 10),
@@ -1832,6 +1867,10 @@ void SimplePsuGroupStartCharging(byte group)
     {
         AddGroupCollection(partner.Member[i], group);
     }
+
+    ShmPsuGrouping->OutputRelayConfig[group].bits.Output_N = true;
+    ShmPsuGrouping->OutputRelayConfig[group].bits.Output_P = true;
+
 #if 0
     // search from left
     location = ShmGroupCollection[group].Location - 1;
@@ -1901,6 +1940,9 @@ void PsuGroupStopCharging(byte group)
         }
     }
     SetGroupToIdle(group);
+
+    ShmPsuGrouping->OutputRelayConfig[group].bits.Output_N = false;
+    ShmPsuGrouping->OutputRelayConfig[group].bits.Output_P = false;
 }
 
 void RunSimplePsuGrouping(char *v1, char *v2)
@@ -1944,8 +1986,8 @@ void ShowCabinetInfo(void)
 {
     int ipAddress = 0;
 
-    printf("\r\nPower Cabinet Charging Mode = %d, ReAssignedFlag = %d",
-        ShmSysConfigAndInfo->SysInfo.MainChargingMode, ShmSysConfigAndInfo->SysInfo.ReAssignedFlag);
+    printf("\r\nPower Cabinet Charging Mode = %d, ReAssignedFlag = %d, Psu Work Step = %d",
+        ShmSysConfigAndInfo->SysInfo.MainChargingMode, ShmSysConfigAndInfo->SysInfo.ReAssignedFlag, ShmPsuData->Work_Step);
 
     printf("\r\n Dispenser: %d / %d, Connector: %d / %d",
         ShmSysConfigAndInfo->SysInfo.DispenserInfo.PresentDispenserQuantity,
@@ -1953,6 +1995,12 @@ void ShowCabinetInfo(void)
         ShmSysConfigAndInfo->SysInfo.DispenserInfo.PresentConnectorQuantity,
         ShmSysConfigAndInfo->SysInfo.DispenserInfo.TotalConnectorQuantity);
 
+    for(int i = 0; i < GENERAL_GUN_QUANTITY; i++)
+    {
+        printf("\r\n Connector[%d] Index: %d, Status = %2d , %s", i, _chargingData[i]->Index, _chargingData[i]->SystemStatus,
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].Enable ? "Enable" : "Disable");
+    }
+
     for(int i = 0; i < ShmSysConfigAndInfo->SysInfo.DispenserInfo.DispenserQuantity; i++)
     {
         printf("\r\n  Dispenser[%d] Status: %d", i, ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].LocalStatus);
@@ -1986,10 +2034,10 @@ void ShowCabinetInfo(void)
 void SetTestControl(char *v1, char *v2)
 {
     int testItem = 0;
-    int testItemLen = 2;
+    int testItemLen = 3;
     int enable = 0;
-    char strTest[32][32] = {"tbl", "tfsb"};
-    char strItem[32][32] = {"Balance", "Fast Standby Time"};
+    char strTest[32][32] = {"tbl", "tfsb", "chgsm"};
+    char strItem[32][32] = {"Balance", "Fast Standby Time", "Charging Simulation"};
 
     enable = atoi(v2);
 
@@ -2032,6 +2080,642 @@ void SetTestControl(char *v1, char *v2)
     printf("\r\n");
 }
 
+// Gun  Role  Master  K1K2  GTVoltage  GTCurrent  StableCurrent  OutputLoading  GunLoading
+//  1    00     00      0     0000 V    000.0 A       0000 A         XXX.XX       XXX.XX
+void ShowGroupingDemand(void)
+{
+    byte target = 0;
+    unsigned char k1k2 = 0;
+
+    printf("\r\n Gun  Role  Master  K1K2  GTVoltage  GTCurrent  StableCurrent  OutputLoading  GunLoading");
+
+    for(int i = 0; i < 4; i++)
+    {
+        target = ShmPsuGrouping->Layout[i];
+        if(ShmGroupCollection[target].TargetGroup != 0)
+        {
+            k1k2 = _chargingData[ShmGroupCollection[target].TargetGroup - 1]->RelayK1K2Status;
+        }
+        else
+        {
+            k1k2 = _chargingData[target]->RelayK1K2Status;
+        }
+
+        printf("\r\n  %d    %2d     %02X      %d     %4d V    %3d.%d A       %4d A         %3d.%02d",
+            target + 1, ShmGroupCollection[target].Role, ShmGroupCollection[target].TargetGroup, k1k2,
+            (ShmPsuGrouping->GroupOutput[target].GTargetVoltage / 10),
+            (ShmPsuGrouping->GroupOutput[target].GTargetCurrent / 10),
+            (ShmPsuGrouping->GroupOutput[target].GTargetCurrent % 10),
+            (int)(_chargingData[target]->AvailableChargingCurrent / 10),
+            (ShmPsuGrouping->GroupOutput[target].OutputLoading / 100),
+            (ShmPsuGrouping->GroupOutput[target].OutputLoading % 100));
+        if(ShmGroupCollection[target].TargetGroup == target + 1)
+        {
+            printf("       %3d.%02d", (ShmGroupCollection[target].GunLoading / 100), (ShmGroupCollection[target].GunLoading % 100));
+        }
+    }
+
+    printf("\r\n\r\n");
+}
+
+// v1: gun
+// v2: voltage
+// v3: current
+void SetGunStartCharging(char *v1, char *v2, char *v3)
+{
+    int gun = 0;
+    float _voltage = 0, _current = 0;
+
+    gun = atoi(v1);
+    _voltage = atof(v2);
+    _current = atof(v3);
+
+    if(gun <= 0 || gun > GENERAL_GUN_QUANTITY || _voltage < 0 || _voltage > 1000 || _current < 0 || _current > 1200)
+    {
+        printf("\r\nGun Start Charging Input parameter %s, %s, %s over range", v1, v2, v3);
+        printf("\r\n\r\n");
+        return;
+    }
+/*
+    if(_chargingData[gun - 1]->SystemStatus == S_IDLE)
+    {
+        printf("\r\nSet Gun %d Start Charging > Voltage: %4d, Current: %d", gun, (int)_voltage, (int)_current);
+
+        ShmChargerInfo->Control.FCharging[gun - 1].FCtrl.bits.EnableForceCharging = true;
+        ShmChargerInfo->Control.FCharging[gun - 1].FCtrl.bits.StartForceCharging = true;
+        ShmChargerInfo->Control.FCharging[gun - 1].FTargetVoltage = _voltage * 10;
+        ShmChargerInfo->Control.FCharging[gun - 1].FTargetCurrent = _current * 10;
+    }
+    else if(ShmGroupCollection[gun - 1].Role == _GROLE_MASTER)
+    {
+        if(ShmChargerInfo->Control.FCharging[gun - 1].FCtrl.bits.EnableForceCharging)
+        {
+            printf("\r\nSet Gun %d > Voltage: %4d, Current: %d", gun, (int)_voltage, (int)_current);
+            ShmChargerInfo->Control.FCharging[gun - 1].FTargetVoltage = _voltage * 10;
+            ShmChargerInfo->Control.FCharging[gun - 1].FTargetCurrent = _current * 10;
+        }
+        else
+        {
+            printf("\r\nGun %d Force Charging Is Disable", gun);
+        }
+    }
+    else
+    {
+        printf("\r\nGun %d SystemStatus(%d) Is Not Available", gun, _chargingData[gun - 1]->SystemStatus);
+    }
+
+    printf("\r\n\r\n");
+*/
+    bool wait = true;
+    int time = 0;
+    struct timeval _Wait_time;
+    unsigned char PreviousSystemStatus = 0xFF;
+    unsigned short _targetVoltage = 0, _targetCurrent = 0;
+
+    while(wait)
+    {
+        switch(_chargingData[gun - 1]->SystemStatus)
+        {
+            case S_IDLE:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_IDLE", gun);
+                    printf("\r\nSet Gun %d Start Charging > Voltage: %4d, Current: %d", gun, (int)_voltage, (int)_current);
+
+                    ShmChargerInfo->Control.FCharging[gun - 1].FCtrl.bits.EnableForceCharging = true;
+                    ShmChargerInfo->Control.FCharging[gun - 1].FCtrl.bits.StartForceCharging = true;
+                    ShmChargerInfo->Control.FCharging[gun - 1].FTargetVoltage = _voltage * 10;
+                    ShmChargerInfo->Control.FCharging[gun - 1].FTargetCurrent = _current * 10;
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+                }
+                break;
+
+            case S_REASSIGN_CHECK:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_REASSIGN_CHECK, Wait For Request Charging", gun);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+                }
+                break;
+
+            case S_REASSIGN:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_REASSIGN, Wait For Grouping", gun);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+                }
+                break;
+
+            case S_PREPARNING:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_PREPARNING", gun);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+                }
+                break;
+
+            case S_PREPARING_FOR_EV:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_PREPARING_FOR_EV", gun);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+                }
+                break;
+
+            case S_PREPARING_FOR_EVSE:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_PREPARING_FOR_EVSE, Wait For EVSE", gun);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+                }
+
+                if(_targetVoltage != (int)_chargingData[gun - 1]->EvBatterytargetVoltage ||
+                    _targetCurrent != (int)_chargingData[gun - 1]->EvBatterytargetCurrent)
+                {
+                    _targetVoltage = (int)_chargingData[gun - 1]->EvBatterytargetVoltage;
+                    _targetCurrent = (int)_chargingData[gun - 1]->EvBatterytargetCurrent;
+                    printf("\r\nGun %d Set Voltage: %4d, Current: %d", gun, _targetVoltage, _targetCurrent);
+                }
+                break;
+
+            case S_CHARGING:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_CHARGING", gun);
+                    if(PreviousSystemStatus == 0xFF)
+                    {
+                        _targetVoltage = (int)_chargingData[gun - 1]->EvBatterytargetVoltage;
+                        _targetCurrent = (int)_chargingData[gun - 1]->EvBatterytargetCurrent;
+                        printf("\r\nGun %d Voltage: %4d, Current: %d", gun, _targetVoltage, _targetCurrent);
+
+                        if(ShmChargerInfo->Control.FCharging[gun - 1].FCtrl.bits.EnableForceCharging)
+                        {
+                            printf("\r\nSet Gun %d Force Charging > Voltage: %4d, Current: %d", gun, (int)_voltage, (int)_current);
+                            ShmChargerInfo->Control.FCharging[gun - 1].FTargetVoltage = _voltage * 10;
+                            ShmChargerInfo->Control.FCharging[gun - 1].FTargetCurrent = _current * 10;
+                        }
+                    }
+
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+                    gettimeofday(&_Wait_time, NULL);
+                }
+                if(_targetVoltage != (int)_chargingData[gun - 1]->EvBatterytargetVoltage ||
+                    _targetCurrent != (int)_chargingData[gun - 1]->EvBatterytargetCurrent)
+                {
+                    _targetVoltage = (int)_chargingData[gun - 1]->EvBatterytargetVoltage;
+                    _targetCurrent = (int)_chargingData[gun - 1]->EvBatterytargetCurrent;
+                    printf("\r\nGun %d Set Voltage: %4d, Current: %d", gun, _targetVoltage, _targetCurrent);
+                }
+
+                time = GetTimeoutValue(_Wait_time) / uSEC_VAL;
+                if(time >= 3)
+                {
+                    wait = false;
+                    printf("\r\nDone");
+                }
+                break;
+
+            case S_TERMINATING:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_TERMINATING", gun);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+                }
+                wait = false;
+                break;
+
+            case S_COMPLETE:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_COMPLETE", gun);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+                }
+                wait = false;
+                break;
+
+            case S_ALARM:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_ALARM", gun);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+                }
+                wait = false;
+                break;
+
+            default:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun SystemStatus %d Unknown(%d)", gun, _chargingData[gun - 1]->SystemStatus);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+                }
+                printf("\r\nGun %d SystemStatus(%d) Is Not Available", gun, _chargingData[gun - 1]->SystemStatus);
+                wait = false;
+                break;
+        }
+
+        char word[128];
+        char newString[7][10];
+        int i,j,ctr;
+
+        memset(word, 0x00, sizeof(word));
+        get_char(word);
+
+        if (strlen(word) == 0)
+        {
+            continue;
+        }
+
+        j=0; ctr=0;
+        strcpy(newString[1], "-1");
+        strcpy(newString[2], "-1");
+        for (i = 0; i <= (strlen(word)); i++)
+        {
+            if (word[i] == ' ' || word[i] == '\0' || word[i] == 10)
+            {
+                newString[ctr][j] = '\0';
+                ctr++;
+                j = 0;
+            }
+            else
+            {
+                newString[ctr][j] = word[i];
+                j++;
+            }
+        }
+
+        if(strcmp(newString[0], "c") == 0)
+        {
+            printf("\r\nStop");
+            wait = false;
+        }
+
+        usleep(100000);
+    }
+
+    printf("\r\n\r\n");
+}
+
+// v1: gun
+void SetGunStopCharging(char *v1)
+{
+    int gun = 0;
+
+    gun = atoi(v1);
+
+    if(gun <= 0 || gun > GENERAL_GUN_QUANTITY)
+    {
+        printf("\r\nGun Stop Charging Input parameter %s over range", v1);
+        printf("\r\n\r\n");
+        return;
+    }
+/*
+    if(_chargingData[gun - 1]->SystemStatus >= S_REASSIGN_CHECK && _chargingData[gun - 1]->SystemStatus <= S_CHARGING)
+    {
+        printf("\r\nSet Gun %d Stop Charging(ManualStop)", gun);
+        _chargingData[gun - 1]->ChargingStopFlag.bits.ManualStop = true;
+    }
+    else if(ShmGroupCollection[gun - 1].Role == _GROLE_SLAVE)
+    {
+        printf("\r\nSet Group [%02X] Stop", gun - 1);
+        ShmGroupCollection[gun - 1].GroupCtrl.bits.SlavePowerOffRequest = true;
+    }
+    else
+    {
+        printf("\r\nGun %d SystemStatus(%d) Is Not Available", gun, _chargingData[gun - 1]->SystemStatus);
+    }
+
+    printf("\r\n\r\n");
+*/
+
+    bool wait = true;
+    int time = 0;
+    struct timeval _Wait_time;
+    unsigned char PreviousSystemStatus = 0xFF;
+
+    while(wait)
+    {
+        switch(_chargingData[gun - 1]->SystemStatus)
+        {
+            case S_IDLE:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_IDLE", gun);
+
+                    if(PreviousSystemStatus == 0xFF)
+                    {
+                        if(ShmGroupCollection[gun - 1].Role == _GROLE_SLAVE)
+                        {
+                            printf("\r\nSet Group [%02X] Stop", gun - 1);
+                            ShmGroupCollection[gun - 1].GroupCtrl.bits.SlavePowerOffRequest = true;
+                        }
+                    }
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+
+                    gettimeofday(&_Wait_time, NULL);
+                }
+
+                time = GetTimeoutValue(_Wait_time) / uSEC_VAL;
+                if(time >= 3)
+                {
+                    wait = false;
+                    printf("\r\nDone");
+                }
+                break;
+
+            case S_REASSIGN_CHECK:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_REASSIGN_CHECK, Wait For Request Charging", gun);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+
+                    if(!_chargingData[gun - 1]->ChargingStopFlag.bits.ManualStop)
+                    {
+                        _chargingData[gun - 1]->ChargingStopFlag.bits.ManualStop = true;
+                        printf("\r\nSet Gun %d Stop Charging(ManualStop)", gun);
+                    }
+                }
+                break;
+
+            case S_REASSIGN:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_REASSIGN, Wait For Grouping", gun);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+
+                    if(!_chargingData[gun - 1]->ChargingStopFlag.bits.ManualStop)
+                    {
+                        _chargingData[gun - 1]->ChargingStopFlag.bits.ManualStop = true;
+                        printf("\r\nSet Gun %d Stop Charging(ManualStop)", gun);
+                    }
+                }
+                break;
+
+            case S_PREPARNING:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_PREPARNING", gun);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+
+                    if(!_chargingData[gun - 1]->ChargingStopFlag.bits.ManualStop)
+                    {
+                        _chargingData[gun - 1]->ChargingStopFlag.bits.ManualStop = true;
+                        printf("\r\nSet Gun %d Stop Charging(ManualStop)", gun);
+                    }
+                }
+                break;
+
+            case S_PREPARING_FOR_EV:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_PREPARING_FOR_EV", gun);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+
+                    if(!_chargingData[gun - 1]->ChargingStopFlag.bits.ManualStop)
+                    {
+                        _chargingData[gun - 1]->ChargingStopFlag.bits.ManualStop = true;
+                        printf("\r\nSet Gun %d Stop Charging(ManualStop)", gun);
+                    }
+                }
+                break;
+
+            case S_PREPARING_FOR_EVSE:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_PREPARING_FOR_EVSE, Wait For EVSE", gun);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+
+                    if(!_chargingData[gun - 1]->ChargingStopFlag.bits.ManualStop)
+                    {
+                        _chargingData[gun - 1]->ChargingStopFlag.bits.ManualStop = true;
+                        printf("\r\nSet Gun %d Stop Charging(ManualStop)", gun);
+                    }
+                }
+                break;
+
+            case S_CHARGING:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_CHARGING", gun);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+
+                    if(!_chargingData[gun - 1]->ChargingStopFlag.bits.ManualStop)
+                    {
+                        _chargingData[gun - 1]->ChargingStopFlag.bits.ManualStop = true;
+                        printf("\r\nSet Gun %d Stop Charging(ManualStop)", gun);
+                    }
+                }
+                break;
+
+            case S_TERMINATING:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_TERMINATING", gun);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+                }
+                break;
+
+            case S_COMPLETE:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_COMPLETE", gun);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+                }
+                break;
+
+            case S_ALARM:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun %d S_ALARM", gun);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+                }
+                break;
+
+            default:
+                if(PreviousSystemStatus != _chargingData[gun - 1]->SystemStatus)
+                {
+                    printf("\r\nGun SystemStatus %d Unknown(%d)", gun, _chargingData[gun - 1]->SystemStatus);
+                    PreviousSystemStatus = _chargingData[gun - 1]->SystemStatus;
+                }
+                printf("\r\nGun %d SystemStatus(%d) Is Not Available", gun, _chargingData[gun - 1]->SystemStatus);
+                wait = false;
+                break;
+        }
+
+        char word[128];
+        char newString[7][10];
+        int i,j,ctr;
+
+        memset(word, 0x00, sizeof(word));
+        get_char(word);
+
+        if (strlen(word) == 0)
+        {
+            continue;
+        }
+
+        j=0; ctr=0;
+        strcpy(newString[1], "-1");
+        strcpy(newString[2], "-1");
+        for (i = 0; i <= (strlen(word)); i++)
+        {
+            if (word[i] == ' ' || word[i] == '\0' || word[i] == 10)
+            {
+                newString[ctr][j] = '\0';
+                ctr++;
+                j = 0;
+            }
+            else
+            {
+                newString[ctr][j] = word[i];
+                j++;
+            }
+        }
+
+        if(strcmp(newString[0], "c") == 0)
+        {
+            printf("\r\nStop");
+            wait = false;
+        }
+
+        usleep(100000);
+    }
+
+    printf("\r\n\r\n");
+}
+
+void SetGunExtend(char *v1)
+{
+    int gun = 0;
+
+    gun = atoi(v1);
+
+    if(_chargingData[gun - 1]->SystemStatus == S_CHARGING && ShmGroupCollection[gun - 1].Role == _GROLE_MASTER)
+    {
+        printf("\r\nSet Group [%02X] Extend Capability", gun - 1);
+        ShmGroupCollection[gun - 1].GroupCtrl.bits.MorePowerRequest = true;
+    }
+    else
+    {
+        printf("\r\nGun %d Extend Capability Is Not Available, SystemStatus(%d)", gun, _chargingData[gun - 1]->SystemStatus);
+    }
+
+    printf("\r\n\r\n");
+}
+
+// Gun  TargetV  TargetC  GTargetV  GTargetC   OutputV  OutputC   G_Psu_V  G_Psu_C   Psu 0_V  Psu 0_C   Psu 1_V  Psu 1_C   Psu 2_V  Psu 2_C  ...
+//  X  XXXX.X V  XXX.X A  XXXX.X V   XXX.X A  XXXX.X V  XXX.X A  XXXX.X V  XXX.X A  XXXX.X V  XXX.X A  XXXX.X V  XXX.X A  XXXX.X V  XXX.X A
+void ShowGunOutput(void)
+{
+    byte target = 0;
+    unsigned short voltage = 0, current = 0;
+
+    printf("\r\n Gun  TargetV  TargetC  GTargetV  GTargetC   OutputV  OutputC   G_Psu_V  G_Psu_C   Psu 0_V  Psu 0_C   Psu 1_V  Psu 1_C   Psu 2_V  Psu 2_C  ...");
+
+    for(int i = 0; i < CONNECTOR_QUANTITY; i++)
+    {
+        target = ShmPsuGrouping->Layout[i];
+
+        // "\r\n  %d  %4d.%d V  %3d.%d A  %4d.%d V   %3d.%d A  %4d.%d V  %3d.%d A  %4d.%d V  %3d.%d A  %4d.%d V  %3d.%d A  %4d.%d V  %3d.%d A"
+        voltage = (unsigned short)(_chargingData[target]->EvBatterytargetVoltage * 10);
+        current = (unsigned short)(_chargingData[target]->EvBatterytargetCurrent * 10);
+        printf("\r\n  %d  %4d.%d V  %3d.%d A", target + 1, (voltage / 10), (voltage % 10), (current / 10), (current % 10));
+
+        voltage = ShmPsuGrouping->GroupOutput[target].GTargetVoltage;
+        current = ShmPsuGrouping->GroupOutput[target].GTargetCurrent;
+        printf("  %4d.%d V   %3d.%d A", (voltage / 10), (voltage % 10), (current / 10), (current % 10));
+
+        voltage = (unsigned short)(_chargingData[target]->PresentChargingVoltage * 10);
+        current = (unsigned short)(_chargingData[target]->PresentChargingCurrent * 10);
+        printf("  %4d.%d V  %3d.%d A", (voltage / 10), (voltage % 10), (current / 10), (current % 10));
+
+        voltage = ShmPsuData->PsuGroup[target].GroupPresentOutputVoltage;
+        current = ShmPsuData->PsuGroup[target].GroupPresentOutputCurrent;
+        printf("  %4d.%d V  %3d.%d A", (voltage / 10), (voltage % 10), (current / 10), (current % 10));
+
+        /*
+        for(int j = 0; j < ShmPsuData->PsuGroup[target].GroupPresentPsuQuantity; j++)
+        {
+            printf("  %4d.%d V  %3d.%d A", (voltage / 10), (voltage % 10), (current / 10), (current % 10));
+        }
+        */
+    }
+    printf("\r\n\r\n");
+}
+
+
+void SetGpio(char *v1, char *v2)
+{
+    int testItem = 0;
+    int testItemLen = 1;
+    int ioOutput = 0;
+    char strTest[32][32] = {"4g"};
+    char strItem[32][32] = {"4G Reset"};
+
+    ioOutput = atoi(v2);
+
+    if(ioOutput < 0)
+    {
+        return;
+    }
+    for(int i = 0; i < testItemLen; i++)
+    {
+        if(strcmp((char *)&strTest[i][0], v1) == 0)
+        {
+            testItem = i + 1;
+            break;
+        }
+    }
+
+    if(testItem != 0)
+    {
+        if(ioOutput)
+        {
+            system("echo 1 > /sys/class/gpio/gpio104/value");
+        }
+        else
+        {
+            system("echo 0 > /sys/class/gpio/gpio104/value");
+        }
+        printf("Set %s %s\n",
+            strItem[testItem - 1], ioOutput > 0 ? "High" : "Low");
+    }
+    else
+    {
+        printf("Gpio Item %s Not Found\n", v1);
+    }
+
+    printf("\r\n");
+}
+
+void ShowStatus(void)
+{
+    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\nAlarmCode");
+        printf("\r\n Connector = %6s, EvConn = %6s, Remote = %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");
+    }
+    printf("\r\n");
+
+    printf("\r\nStatus Code Len = %d", ShmSysConfigAndInfo->SysWarningInfo.WarningCount);
+    if(ShmSysConfigAndInfo->SysWarningInfo.WarningCount > 0)
+    {
+        printf("\r\n WarningCode:");
+        for(int i = 0; i < ShmSysConfigAndInfo->SysWarningInfo.WarningCount; i++)
+        {
+            printf(" %s", (char *)&ShmSysConfigAndInfo->SysWarningInfo.WarningCode[i][0]);
+        }
+    }
+
+    printf("\r\n\r\n");
+}
+
 int main(void)
 {
 	if(InitShareMemory() == FAIL)
@@ -2200,8 +2884,8 @@ int main(void)
 		}
 		else if(strcmp(newString[0], "temp") == 0)
 		{
-		    // 取得 PSU 溫度
-			GetPsuTemp();
+		    // 取得溫度
+		    GetTemperature(newString[1]);
 		}
 		else if(strcmp(newString[0], "acin") == 0)
 		{
@@ -2236,6 +2920,7 @@ int main(void)
 		{
 			GetOrClearId(newString[1]);
 		}
+#if 0
 		else if(strcmp(newString[0], "strchg") == 0)
 		{
 		    //如果連一個參數都沒有 (此命令不理會) 加上判斷第二參數
@@ -2264,12 +2949,12 @@ int main(void)
             // 槍狀態
             RunUnconditionalCharge(newString[1], newString[2], newString[3], newString[4]);
         }
+#endif
         else if(strcmp(newString[0], "wiring") == 0)
         {
             if(strcmp(newString[1], "-1") != 0 && strcmp(newString[1], "") != 0 &&
                 strcmp(newString[2], "-1") != 0 && strcmp(newString[2], "") != 0)
             {
-                // wiring dispenser_id quantity
                 SetWiringInfo(newString[1], newString[2]);
             }
 
@@ -2306,9 +2991,74 @@ int main(void)
             if(strcmp(newString[1], "-1") == 0 || strcmp(newString[1], "") == 0 ||
                 strcmp(newString[2], "-1") == 0 || strcmp(newString[2], "") == 0)
             {
+                printf("Test Control Value = %08X\n",ShmChargerInfo->Control.TestCtrl.CtrlValue);
+                printf ("Input cmd fail ------  tctl [tcmd] [value]\n\n");
+
                 continue;
             }
             SetTestControl(newString[1], newString[2]);
+        }
+        else if(strcmp(newString[0], "group") == 0)
+        {
+            if(strcmp(newString[1], "-1") == 0 || strcmp(newString[1], "") == 0)
+            {
+                ShowGroupingInfo();
+                continue;
+            }
+        }
+        else if(strcmp(newString[0], "gdmd") == 0)
+        {
+            ShowGroupingDemand();
+        }
+        else if(strcmp(newString[0], "gunchg") == 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 ------  gunchg [gun 1-4] [voltage 0-1000] [current 0-100]\n\n");
+                continue;
+            }
+
+            SetGunStartCharging(newString[1], newString[2], newString[3]);
+        }
+        else if(strcmp(newString[0], "gunstp") == 0)
+        {
+            if(strcmp(newString[1], "-1") == 0 || strcmp(newString[1], "") == 0)
+            {
+                printf ("Input cmd fail ------  gunstp [gun 1-4]\n\n");
+                continue;
+            }
+
+            SetGunStopCharging(newString[1]);
+        }
+        else if(strcmp(newString[0], "gunext") == 0)
+        {
+            if(strcmp(newString[1], "-1") == 0 || strcmp(newString[1], "") == 0)
+            {
+                printf ("Input cmd fail ------  gunext [gun 1-4]\n\n");
+                continue;
+            }
+
+            SetGunExtend(newString[1]);
+        }
+        else if(strcmp(newString[0], "output") == 0)
+        {
+            ShowGunOutput();
+        }
+        else if(strcmp(newString[0], "gio") == 0)
+        {
+            if(strcmp(newString[1], "-1") == 0 || strcmp(newString[1], "") == 0 ||
+                strcmp(newString[2], "-1") == 0 || strcmp(newString[2], "") == 0)
+            {
+                printf ("Input cmd fail ------  gio [io] [on-off 0-1]\n\n");
+                continue;
+            }
+            SetGpio(newString[1], newString[2]);
+        }
+        else if(strcmp(newString[0], "status") == 0)
+        {
+            ShowStatus();
         }
 		else
 			printf ("%s\n", msg);

+ 3 - 1
EVSE/Projects/DO360/Apps/internalComm.c

@@ -371,6 +371,8 @@ unsigned char Query_Relay_Output(unsigned char fd, unsigned char targetAddr, Rel
 
 			Ret_Buf->relay_event.bits.Gun2_N = (rx[8] >> 0) & 0x01;
 			Ret_Buf->relay_event.bits.Gun2_P = (rx[8] >> 1) & 0x01;
+            Ret_Buf->relay_event.bits.Gun2_Parallel_N = (rx[8] >> 2) & 0x01;
+            Ret_Buf->relay_event.bits.Gun2_Parallel_P = (rx[8] >> 3) & 0x01;
 			result = PASS;
 		}
 	}
@@ -1217,7 +1219,7 @@ unsigned char Config_Led_Color(unsigned char fd, unsigned char targetAddr, Led_C
 
 	for (int idx = 0; idx < (tx[4] | tx[5] << 8); idx++)
 		chksum ^= tx[6 + idx];
-	tx[13] = chksum;
+	tx[12] = chksum;
 
 //	for(int i = 0; i < 13; i++)
 //			printf ("tx = %x \n", tx[i]);

+ 39 - 26
EVSE/Projects/DO360/Apps/internalComm.h

@@ -101,6 +101,19 @@ typedef struct AUXPOWER
 	unsigned char voltage[8];
 }AuxPower;
 
+typedef union
+{
+    unsigned char relay_status;
+    struct
+    {
+        unsigned char Gun_N:1;                      // 0: gun_n off,                1: gun_n on
+        unsigned char Gun_P:1;                      // 0: gun_p off,                1: gun_p on
+        unsigned char Gun_Parallel_N_P:1;           // 0: gun_parallel off,         1: gun_parallel on
+        unsigned char Gun_Parallel_P:1;             // 0: gun_parallel off,         1: gun_parallel on
+        unsigned char res:4;
+    }bits;
+}RBRelayControl;
+
 typedef struct RELAY
 {
 	union
@@ -108,32 +121,32 @@ typedef struct RELAY
 		unsigned char relay_status[8];
 		struct
 		{
-			unsigned char AC_Contactor :1;		//bit 0
-			unsigned char CCS_Precharge :1;	//bit 1
-			unsigned char :1;  				//bit 2 reserved
-			unsigned char :1;					//bit 3 reserved
-			unsigned char :1;					//bit 4 reserved
-			unsigned char :1;					//bit 5 reserved
-			unsigned char :1;					//bit 6 reserved
-			unsigned char :1;					//bit 7 reserved
-
-			unsigned char Gun1_N :1;			//bit 0
-			unsigned char Gun1_P :1;			//bit 1
-			unsigned char Gun1_Parallel_N :1;	//bit 2
-			unsigned char Gun1_Parallel_P :1;	//bit 3
-			unsigned char :1;					//bit 4 reserved
-			unsigned char :1;					//bit 5 reserved
-			unsigned char :1;					//bit 6 reserved
-			unsigned char :1;					//bit 7 reserved
-
-			unsigned char Gun2_N :1;			//bit 0
-			unsigned char Gun2_P :1;			//bit 1
-			unsigned char Gun2_Parallel_N :1;	//bit 2
-			unsigned char Gun2_Parallel_P :1;	//bit 3
-			unsigned char :1;					//bit 4 reserved
-			unsigned char :1;					//bit 5 reserved
-			unsigned char :1;					//bit 6 reserved
-			unsigned char :1;					//bit 7 reserved
+            unsigned char AC_Contactor :1;      //bit 0
+            unsigned char CCS_Precharge :1;     //bit 1
+            unsigned char :1;                   //bit 2 reserved
+            unsigned char :1;                   //bit 3 reserved
+            unsigned char :1;                   //bit 4 reserved
+            unsigned char :1;                   //bit 5 reserved
+            unsigned char :1;                   //bit 6 reserved
+            unsigned char :1;                   //bit 7 reserved
+
+            unsigned char Gun1_N :1;            //bit 0
+            unsigned char Gun1_P :1;            //bit 1
+            unsigned char Gun1_Parallel_N :1;   //bit 2
+            unsigned char Gun1_Parallel_P :1;   //bit 3
+            unsigned char :1;                   //bit 4 reserved
+            unsigned char :1;                   //bit 5 reserved
+            unsigned char :1;                   //bit 6 reserved
+            unsigned char :1;                   //bit 7 reserved
+
+            unsigned char Gun2_N :1;            //bit 0
+            unsigned char Gun2_P :1;            //bit 1
+            unsigned char Gun2_Parallel_N :1;   //bit 2
+            unsigned char Gun2_Parallel_P :1;   //bit 3
+            unsigned char :1;                   //bit 4 reserved
+            unsigned char :1;                   //bit 5 reserved
+            unsigned char :1;                   //bit 6 reserved
+            unsigned char :1;                   //bit 7 reserved
 		}bits;
 	}relay_event;
 }Relay;

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


Разница между файлами не показана из-за своего большого размера
+ 293 - 359
EVSE/Projects/DO360/Apps/main.c


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


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


BIN
EVSE/Projects/DO360/Images/u-boot.img


Некоторые файлы не были показаны из-за большого количества измененных файлов