#include <sys/time.h> #include <sys/timeb.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/shm.h> #include <sys/mman.h> #include <linux/wireless.h> #include <arpa/inet.h> #include <netinet/in.h> #include <unistd.h> #include <stdarg.h> #include <stdio.h> /*標準輸入輸出定義*/ #include <stdlib.h> /*標準函數庫定義*/ #include <unistd.h> /*Unix 標準函數定義*/ #include <fcntl.h> /*檔控制定義*/ #include <termios.h> /*PPSIX 終端控制定義*/ #include <errno.h> /*錯誤號定義*/ #include <errno.h> #include <string.h> #include <time.h> #include <ctype.h> #include <ifaddrs.h> #include <math.h> #include "../../define.h" #include "internalComm.h" #include <stdbool.h> #include "Config.h" #include "Common.h" #define TEN_MINUTES 600 #define ENV_TEMP_MIN 45 #define ENV_TEMP_MAX 50 #define DEFAULT_AC_INDEX 2 #define COLOR_MAX_LV 100 #define COLOR_MIN_LV 0 #define AC_DEFAULT_VOL 220 #define NO_DEFINE 255 #define NDEFAULT_AC_INDEX 2 #define OVP_UVP_CHK_COUNT 5 struct SysConfigAndInfo *ShmSysConfigAndInfo; struct StatusCodeData *ShmStatusCodeData; struct FanModuleData *ShmFanModuleData; struct RelayModuleData *ShmRelayModuleData[2]; 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; OutputRelayControl *LocationOutputRelayCtrl[MAX_GROUP_QUANTITY]; OutputRelayControl *LocationOutputRelayResponse[MAX_GROUP_QUANTITY]; unsigned char LocationParallelRelayCtrl[PARALLEL_RELAY_COUNT]; unsigned char LocationParallelRelayResponse[PARALLEL_RELAY_COUNT]; Connector_GFD *LocaltionGfd[MAX_GROUP_QUANTITY]; #define VIN_MAX_VOLTAGE_IEC 285 // 大於該值 : OVP #define VIN_MAX_REV_VOLTAGE_IEC 275 // 小於賦歸 OVP #define VIN_MIN_VOLTAGE_IEC 160 // 小於該值 : UVP #define VIN_MIN_REV_VOLTAGE_IEC 170 // 大於賦歸 UVP #define VIN_MAX_VOLTAGE_UL 315 // 大於該值 : OVP // 美規 (W) #define VIN_MAX_REV_VOLTAGE_UL 305 // 小於賦歸 OVP #define VIN_MIN_VOLTAGE_UL 210 // 小於該值 : UVP #define VIN_MIN_REV_VOLTAGE_UL 220 // 大於賦歸 UVP #define DCIN_OVP_THRESHOLD_VOL 825 // dc input ovp threshold voltage #define DCIN_OVP_RECOVERY_VOL 815 // dc input ovp recovery voltage #define DCIN_UVP_THRESHOLD_VOL 400 // dc input uvp threshold voltage #define DCIN_UVP_RECOVERY_VOL 410 // dc input uvp recovery voltage #define VIN_DROP_VOLTAGE 150 // 小於該值 : ac drop #define VOUT_MAX_VOLTAGE 995 #define VOUT_MIN_VOLTAGE 150 #define IOUT_MAX_CURRENT 50 #define MAX_FAN_SPEED 14000 #define MIN_FAN_SPEED 3000 #define NORMAL_FAN_SPEED 7000 // GFD Status #define GFD_IDLE 0 #define GFD_CABLECHK 1 #define GFD_PRECHARGE 2 #define GFD_CHARGING 3 // LED Intensity (rate) #define LED_INTENSITY_DARKEST 0.2 #define LED_INTENSITY_MEDIUM 0.6 #define LED_INTENSITY_BRIGHTEST 1 // EE Spec #define LED_BRIGHTNESS_LV_HIGH 1 #define LED_BRIGHTNESS_LV_MID 0.5 #define LED_BRIGHTNESS_LV_LOW 0.2 // 最小切換 Relay 電壓 #define SELF_TO_CHANGE_RELAY_STATUS 600 // 透過電壓確認 Relay 是否搭上的依據電壓 #define CHECK_RELAY_STATUS 300 #define CHECK_RELAY_STATUS_GAP 100 // 安全在停止充電程序中斷開 Relay 的電流 #define SEFETY_SWITCH_RELAY_CUR 50 // 確認 Relay Welding 電壓 #define RELAY_WELDING_DET 300 #if SAFETY_TEST_ENABLE #define RELAY_OPEN_AT_PRECHARGE 1 #else #define RELAY_OPEN_AT_PRECHARGE 0 #endif #define RELAY_DEBUG_MSG 0 byte gunCount; byte acgunCount; // 槍資訊 struct ChargingInfoData *_chargingData[CONNECTOR_QUANTITY]; struct ChargingInfoData *ac_chargingInfo[AC_QUANTITY]; bool _isOutputNoneMatch[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY]; struct timespec _checkOutputNoneMatchTimer[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY]; bool _isRelayWelding[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY]; struct timespec _checkRelayWeldingTimer[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY]; byte _dcOvpCnt = 0; byte _dcUvpCnt = 0; byte _threePhaseOvp[3] = {0, 0, 0}; byte _threePhaseUvp[3] = {0, 0, 0}; bool FindChargingInfoData(byte target, struct ChargingInfoData **chargingData); int Uart5Fd; char *relayRs485PortName = "/dev/ttyS5"; unsigned short fanSpeedSmoothValue = 500; struct timespec _priority_time; struct timespec _led_priority_time; unsigned short _setFanSpeed = 0; float _beforeChargingTotalEnergy = 0.0; byte _checkLedChanged = 3; byte _RelaySelfTestOK; bool _isGfdEnable = false; Ver ver; PresentInputVoltage inputVoltage; DCInputVoltage dcInputVoltage; PresentOutputVoltage outputVoltage; FanSpeed fanSpeed; Temperature temperature; AuxPower auxPower; Gfd gfd_adc[2]; Gfd_config gfd_config; Gpio_in gpio_in; Gpio_out gpio_out; Relay outputRelay[2]; Relay regRelay[2]; Relay TempRegRelay[2]; Rtc rtc; Led_Color cur_led_color; Led_Color led_color; #define AC_OVP 1 #define AC_UVP 2 #define AC_OCP 4 #define AC_OTP 8 #define AC_GMI_FAULT 16 #define AC_CP_ERROR 32 #define AC_AC_LEAKAGE 64 #define AC_DC_LEAKAGE 128 #define AC_SYSTEM_SELFTEST_FAULT 256 #define AC_HANDSHAKE_TIMEOUT 512 #define AC_EMC_STOP 1024 #define AC_RELAY_WELDING 2048 #define AC_GF_MODULE_FAULT 4096 #define AC_SHUTTER_FAULT 8192 #define AC_LOCKER_FAULT 16384 #define AC_POWER_DROP 32768 #define AC_CIRCUIT_SHORT 65536 #define AC_ROTARY_SWITCH_FAULT 131072 #define AC_RELAY_DRIVE_FAULT 262144 int _alarm_code[] = {AC_OVP, AC_UVP, AC_OCP, AC_OTP, AC_GMI_FAULT, AC_CP_ERROR, AC_AC_LEAKAGE , AC_DC_LEAKAGE, AC_SYSTEM_SELFTEST_FAULT, AC_HANDSHAKE_TIMEOUT, AC_EMC_STOP, AC_RELAY_WELDING , AC_GF_MODULE_FAULT, AC_SHUTTER_FAULT, AC_LOCKER_FAULT, AC_POWER_DROP, AC_CIRCUIT_SHORT , AC_ROTARY_SWITCH_FAULT, AC_RELAY_DRIVE_FAULT}; int DiffTimeb(struct timeb ST, struct timeb ET) { //return milli-second unsigned int StartTime, StopTime; StartTime = (unsigned int) ST.time; StopTime = (unsigned int) ET.time; //return (StopTime-StartTime)*1000+ET.millitm-ST.millitm; return (StopTime - StartTime); } unsigned short MaxValue(unsigned short value1, unsigned short value2) { return value1 >= value2 ? value1 : value2; } //========================================== // Communication Function //========================================== void GetFwAndHwVersion_Fan() { if(Query_FW_Ver(Uart5Fd, Addr.Fan, &ver) == PASS) { // FanModuleData strcpy((char *) ShmFanModuleData->version, ver.Version_FW); // SystemInfo strcpy((char *) ShmSysConfigAndInfo->SysInfo.FanModuleFwRev, ver.Version_FW); LOG_INFO("GetFwAndHwVersion_Fan s1 = %s", ver.Version_FW); } if (Query_HW_Ver(Uart5Fd, Addr.Fan, &ver) == PASS) { // SystemInfo strcpy((char *) ShmSysConfigAndInfo->SysInfo.FanModuleHwRev, ver.Version_FW); LOG_INFO("GetFwAndHwVersion_Fan s2 = %s", ver.Version_HW); } } void GetFwAndHwVersion_Relay() { if (Query_FW_Ver(Uart5Fd, Addr.DO360_RC1, &ver) == PASS) { // RelayModuleData strcpy((char *) ShmRelayModuleData[0]->version, ver.Version_FW); // SystemInfo strcpy((char *) ShmSysConfigAndInfo->SysInfo.RelayModuleFwRev, ver.Version_FW); LOG_INFO("GetFwAndHwVersion_RC1 s1 = %s", ver.Version_FW); } if (Query_HW_Ver(Uart5Fd, Addr.DO360_RC1, &ver) == PASS) { // SystemInfo strcpy((char *) ShmSysConfigAndInfo->SysInfo.RelayModuleHwRev, ver.Version_FW); LOG_INFO("GetFwAndHwVersion_RC1 s2 = %s", ver.Version_HW); } } void GetFwAndHwVersion_Relay2() { // DO360 RC2 if (Query_FW_Ver(Uart5Fd, Addr.DO360_RC2, &ver) == PASS) { // RelayModuleData strcpy((char *) ShmRelayModuleData[1]->version, ver.Version_FW); // SystemInfo strcpy((char *) ShmSysConfigAndInfo->SysInfo.Relay2ModuleFwRev, ver.Version_FW); LOG_INFO("GetFwAndHwVersion_RC2 s1 = %s", ver.Version_FW); } if (Query_HW_Ver(Uart5Fd, Addr.DO360_RC2, &ver) == PASS) { // SystemInfo strcpy((char *) ShmSysConfigAndInfo->SysInfo.Relay2ModuleHwRev, ver.Version_FW); LOG_INFO("GetFwAndHwVersion_RC2 s2 = %s", ver.Version_HW); } } void GetFwAndHwVersion_Led() { if (Query_FW_Ver(Uart5Fd, Addr.Led, &ver) == PASS) { // LedModuleData strcpy((char *) ShmLedModuleData->version, ver.Version_FW); // SystemInfo strcpy((char *) ShmSysConfigAndInfo->SysInfo.LedModuleFwRev, ver.Version_FW); LOG_INFO("GetFwAndHwVersion_Led s1 = %s", ver.Version_FW); ShmLedModuleData->SelfTest_Comp = YES; } else { //LOG_INFO("GetFwAndHwVersion_Led fail"); } // if (Query_HW_Ver(Uart5Fd, Addr.Led, &ver) == PASS) // { // // SystemInfo // strcpy((char *) ShmSysConfigAndInfo->SysInfo.RelayModuleHwRev, ver.Version_FW); // //LOG_INFO("GetFwAndHwVersion_Relay s2 = %s", ver.Version_HW); // } } void GetFwVersion_AC() { if (Query_FW_Ver(Uart5Fd, Addr.AcPlug, &ver) == PASS) { ac_chargingInfo[0]->SelfTest_Comp = YES; strcpy((char *) ac_chargingInfo[0]->version, ver.Version_FW); } } void GetAcModelName() { memset(ShmSysConfigAndInfo->SysConfig.AcModelName, 0x00, sizeof(ShmSysConfigAndInfo->SysConfig.AcModelName)); if (Query_Model_Name(Uart5Fd, Addr.AcPlug, ShmSysConfigAndInfo->SysConfig.AcModelName) == PASS) { LOG_INFO("ac model name = %s", ShmSysConfigAndInfo->SysConfig.AcModelName); } } void SetRtcData_Relay(unsigned char index) { struct timeb csuTime; struct tm *tmCSU; ftime(&csuTime); tmCSU = localtime(&csuTime.time); // LOG_INFO("Time : %04d-%02d-%02d %02d:%02d:%02d", tmCSU->tm_year + 1900, // tmCSU->tm_mon + 1, tmCSU->tm_mday, tmCSU->tm_hour, tmCSU->tm_min, // tmCSU->tm_sec); rtc.RtcData[0] = '0' + (tmCSU->tm_year + 1900) / 1000 % 10; rtc.RtcData[1] = '0' + (tmCSU->tm_year + 1900) / 100 % 10; rtc.RtcData[2] = '0' + (tmCSU->tm_year + 1900) / 10 % 10; rtc.RtcData[3] = '0' + (tmCSU->tm_year + 1900) / 1 % 10; rtc.RtcData[4] = '0' + (tmCSU->tm_mon + 1) / 10 % 10; rtc.RtcData[5] = '0' + (tmCSU->tm_mon + 1) / 1 % 10; rtc.RtcData[6] = '0' + (tmCSU->tm_mday) / 10 % 10; rtc.RtcData[7] = '0' + (tmCSU->tm_mday) / 1 % 10; rtc.RtcData[8] = '0' + (tmCSU->tm_hour) / 10 % 10; rtc.RtcData[9] = '0' + (tmCSU->tm_hour) / 1 % 10; rtc.RtcData[10] = '0' + (tmCSU->tm_min) / 10 % 10; rtc.RtcData[11] = '0' + (tmCSU->tm_min) / 1 % 10; rtc.RtcData[12] = '0' + (tmCSU->tm_sec) / 10 % 10; rtc.RtcData[13] = '0' + (tmCSU->tm_sec) / 1 % 10; if(index == 0) { if (Config_Rtc_Data(Uart5Fd, Addr.DO360_RC1, &rtc) == PASS) { //LOG_INFO("SetRtc (RB) sucessfully."); } } else { if (Config_Rtc_Data(Uart5Fd, Addr.DO360_RC2, &rtc) == PASS) { //LOG_INFO("SetRtc (RB) sucessfully."); } } } void SetRtcData_Fan() { struct timeb csuTime; struct tm *tmCSU; ftime(&csuTime); tmCSU = localtime(&csuTime.time); // LOG_INFO("Time : %04d-%02d-%02d %02d:%02d:%02d", tmCSU->tm_year + 1900, // tmCSU->tm_mon + 1, tmCSU->tm_mday, tmCSU->tm_hour, tmCSU->tm_min, // tmCSU->tm_sec); rtc.RtcData[0] = '0' + (tmCSU->tm_year + 1900) / 1000 % 10; rtc.RtcData[1] = '0' + (tmCSU->tm_year + 1900) / 100 % 10; rtc.RtcData[2] = '0' + (tmCSU->tm_year + 1900) / 10 % 10; rtc.RtcData[3] = '0' + (tmCSU->tm_year + 1900) / 1 % 10; rtc.RtcData[4] = '0' + (tmCSU->tm_mon + 1) / 10 % 10; rtc.RtcData[5] = '0' + (tmCSU->tm_mon + 1) / 1 % 10; rtc.RtcData[6] = '0' + (tmCSU->tm_mday) / 10 % 10; rtc.RtcData[7] = '0' + (tmCSU->tm_mday) / 1 % 10; rtc.RtcData[8] = '0' + (tmCSU->tm_hour) / 10 % 10; rtc.RtcData[9] = '0' + (tmCSU->tm_hour) / 1 % 10; rtc.RtcData[10] = '0' + (tmCSU->tm_min) / 10 % 10; rtc.RtcData[11] = '0' + (tmCSU->tm_min) / 1 % 10; rtc.RtcData[12] = '0' + (tmCSU->tm_sec) / 10 % 10; rtc.RtcData[13] = '0' + (tmCSU->tm_sec) / 1 % 10; if (Config_Rtc_Data(Uart5Fd, Addr.Fan, &rtc) == PASS) { //LOG_INFO("SetRtc (FB) sucessfully."); } } void SetModelName_Fan() { if (Config_Model_Name(Uart5Fd, Addr.Fan, ShmSysConfigAndInfo->SysConfig.ModelName) == PASS) { LOG_INFO("Set Model name PASS = %s", ShmSysConfigAndInfo->SysConfig.ModelName); } } // AC 三相輸入電壓 void GetPresentInputVol() { if(ShmChargerInfo->Control.RelayCtrl.bits.AcInputDisable == YES) { if(Query_DC_InputVoltage(Uart5Fd, Addr.DO360_RC1, &dcInputVoltage) == PASS) { ShmSysConfigAndInfo->SysInfo.InputVoltageDc = dcInputVoltage.DC_Input_1; // DC Input OVP if(ShmStatusCodeData->AlarmCode.AlarmEvents.bits.DcInputOVP == NO) { if(dcInputVoltage.DC_Input_1 > DCIN_OVP_THRESHOLD_VOL) { _dcOvpCnt++; if(_dcOvpCnt >= OVP_UVP_CHK_COUNT) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.DcInputOVP = YES; LOG_INFO("Dc Input OVP: %.1f V", dcInputVoltage.DC_Input_1); } } else { _dcOvpCnt = 0; } } else { if(dcInputVoltage.DC_Input_1 <= DCIN_OVP_RECOVERY_VOL) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.DcInputOVP = NO; LOG_INFO("Dc Input OVP Recovery: %.1f V", dcInputVoltage.DC_Input_1); } _dcOvpCnt = 0; } // DC Input UVP if(ShmStatusCodeData->AlarmCode.AlarmEvents.bits.DcInputUVP == NO) { if(dcInputVoltage.DC_Input_1 < DCIN_UVP_THRESHOLD_VOL) { _dcUvpCnt++; if(_dcUvpCnt >= OVP_UVP_CHK_COUNT) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.DcInputUVP = YES; LOG_INFO("Dc Input UVP: %.1f V", dcInputVoltage.DC_Input_1); } } else { _dcUvpCnt = 0; } } else { if(dcInputVoltage.DC_Input_1 >= DCIN_UVP_RECOVERY_VOL) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.DcInputUVP = NO; LOG_INFO("Dc Input UVP Recovery: %.1f V", dcInputVoltage.DC_Input_1); } _dcUvpCnt = 0; } } } else { if (Query_Present_InputVoltage(Uart5Fd, Addr.DO360_RC1, &inputVoltage) == PASS) { // resolution : 0.1 ShmSysConfigAndInfo->SysInfo.InputVoltageR = ShmRelayModuleData[0]->InputL1Volt = inputVoltage.L1N_L12; ShmSysConfigAndInfo->SysInfo.InputVoltageS = ShmRelayModuleData[0]->InputL2Volt = inputVoltage.L2N_L23; ShmSysConfigAndInfo->SysInfo.InputVoltageT = ShmRelayModuleData[0]->InputL3Volt = inputVoltage.L3N_L31; //********************************************************************************************************// // Vin (UVP) if (ShmSysConfigAndInfo->SysInfo.ChargerType == _CHARGER_TYPE_IEC) { if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP == NO) { if (inputVoltage.L1N_L12 < VIN_MIN_VOLTAGE_IEC) { LOG_INFO("In Uvp L1N_L12 = %f", inputVoltage.L1N_L12); if (_threePhaseUvp[0] >= OVP_UVP_CHK_COUNT) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP = YES; else _threePhaseUvp[0] += 1; } } else { if (inputVoltage.L1N_L12 > VIN_MIN_REV_VOLTAGE_IEC) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP = NO; _threePhaseUvp[0] = 0; } } if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP == NO) { if (inputVoltage.L2N_L23 < VIN_MIN_VOLTAGE_IEC) { LOG_INFO("In Uvp L2N_L23 = %f", inputVoltage.L2N_L23); if (_threePhaseUvp[1] >= OVP_UVP_CHK_COUNT) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP = YES; else _threePhaseUvp[1] += 1; } } else { if (inputVoltage.L2N_L23 > VIN_MIN_REV_VOLTAGE_IEC) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP = NO; _threePhaseUvp[1] = 0; } } if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP == NO) { if (inputVoltage.L3N_L31 < VIN_MIN_VOLTAGE_IEC) { LOG_INFO("In Uvp L3N_L31 = %f", inputVoltage.L3N_L31); if (_threePhaseUvp[2] >= OVP_UVP_CHK_COUNT) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP = YES; else _threePhaseUvp[2] += 1; } } else { if (inputVoltage.L3N_L31 > VIN_MIN_REV_VOLTAGE_IEC) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP = NO; _threePhaseUvp[2] = 0; } } } else if (ShmSysConfigAndInfo->SysInfo.ChargerType == _CHARGER_TYPE_UL) { if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP == NO) { if (inputVoltage.L1N_L12 < VIN_MIN_VOLTAGE_UL) { LOG_INFO("In Uvp L1N_L12 = %f", inputVoltage.L1N_L12); if (_threePhaseUvp[0] >= OVP_UVP_CHK_COUNT) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP = YES; else _threePhaseUvp[0] += 1; } } else { if (inputVoltage.L1N_L12 > VIN_MIN_REV_VOLTAGE_UL) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP = NO; _threePhaseUvp[0] = 0; } } if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP == NO) { if (inputVoltage.L2N_L23 < VIN_MIN_VOLTAGE_UL) { LOG_INFO("In Uvp L2N_L23 = %f", inputVoltage.L2N_L23); if (_threePhaseUvp[1] >= OVP_UVP_CHK_COUNT) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP = YES; else _threePhaseUvp[1] += 1; } } else { if (inputVoltage.L2N_L23 > VIN_MIN_REV_VOLTAGE_UL) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP = NO; _threePhaseUvp[1] = 0; } } if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP == NO) { if (inputVoltage.L3N_L31 < VIN_MIN_VOLTAGE_UL) { LOG_INFO("In Uvp L3N_L31 = %f", inputVoltage.L3N_L31); if (_threePhaseUvp[2] >= OVP_UVP_CHK_COUNT) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP = YES; else _threePhaseUvp[2] += 1; } } else { if (inputVoltage.L3N_L31 > VIN_MIN_REV_VOLTAGE_UL) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP = NO; _threePhaseUvp[2] = 0; } } } //********************************************************************************************************// // Vin (OVP) if (ShmSysConfigAndInfo->SysInfo.ChargerType == _CHARGER_TYPE_IEC) { if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP == NO) { if (inputVoltage.L1N_L12 > VIN_MAX_VOLTAGE_IEC) { LOG_INFO("In Ovp L1N_L12 = %f", inputVoltage.L1N_L12); if (_threePhaseOvp[0] >= OVP_UVP_CHK_COUNT) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP = YES; else _threePhaseOvp[0] += 1; } } else { if (inputVoltage.L1N_L12 < VIN_MAX_REV_VOLTAGE_IEC) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP = NO; _threePhaseOvp[0] = 0; } } if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP == NO) { if (inputVoltage.L2N_L23 > VIN_MAX_VOLTAGE_IEC) { LOG_INFO("In Ovp L2N_L23 = %f", inputVoltage.L2N_L23); if (_threePhaseOvp[1] >= OVP_UVP_CHK_COUNT) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP = YES; else _threePhaseOvp[1] += 1; } } else { if (inputVoltage.L2N_L23 < VIN_MAX_REV_VOLTAGE_IEC) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP = NO; _threePhaseOvp[1] = 0; } } if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP == NO) { if (inputVoltage.L3N_L31 > VIN_MAX_VOLTAGE_IEC) { LOG_INFO("In Ovp L3N_L31 = %f", inputVoltage.L3N_L31); if (_threePhaseOvp[2] >= OVP_UVP_CHK_COUNT) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP = YES; else _threePhaseOvp[2] += 1; } } else { if (inputVoltage.L3N_L31 < VIN_MAX_REV_VOLTAGE_IEC) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP = NO; _threePhaseOvp[2] = 0; } } } else if (ShmSysConfigAndInfo->SysInfo.ChargerType == _CHARGER_TYPE_UL) { if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP == NO) { if (inputVoltage.L1N_L12 > VIN_MAX_VOLTAGE_UL) { LOG_INFO("In Ovp L1N_L12 = %f", inputVoltage.L1N_L12); if (_threePhaseOvp[0] >= OVP_UVP_CHK_COUNT) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP = YES; else _threePhaseOvp[0] += 0; } } else { if (inputVoltage.L1N_L12 < VIN_MAX_REV_VOLTAGE_UL) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP = NO; _threePhaseOvp[0] = 0; } } if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP == NO) { if (inputVoltage.L2N_L23 > VIN_MAX_VOLTAGE_UL) { LOG_INFO("In Ovp L2N_L23 = %f", inputVoltage.L2N_L23); if (_threePhaseOvp[1] >= OVP_UVP_CHK_COUNT) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP = YES; else _threePhaseOvp[1] += 0; } } else { if (inputVoltage.L2N_L23 < VIN_MAX_REV_VOLTAGE_UL) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP = NO; _threePhaseOvp[1] = 0; } } if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP == NO) { if (inputVoltage.L3N_L31 > VIN_MAX_VOLTAGE_UL) { LOG_INFO("In Ovp L3N_L31 = %f", inputVoltage.L3N_L31); if (_threePhaseOvp[2] >= OVP_UVP_CHK_COUNT) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP = YES; else _threePhaseOvp[2] += 1; } } else { if (inputVoltage.L3N_L31 < VIN_MAX_REV_VOLTAGE_UL) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP = NO; _threePhaseOvp[2] = 0; } } } } } } // 左右槍的 Relay 前後的輸出電壓 void GetPersentOutputVol() { if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable) { // two relay board if (Query_Present_OutputVoltage(Uart5Fd, Addr.DO360_RC1, &outputVoltage) == PASS) { ShmRelayModuleData[0]->Gun1FuseOutputVolt = outputVoltage.behindFuse_Voltage_C1; ShmRelayModuleData[0]->Gun1RelayOutputVolt = outputVoltage.behindRelay_Voltage_C1; ShmRelayModuleData[0]->Gun2FuseOutputVolt = outputVoltage.behindFuse_Voltage_C2; ShmRelayModuleData[0]->Gun2RelayOutputVolt = outputVoltage.behindRelay_Voltage_C2; _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 if (Query_Present_OutputVoltage(Uart5Fd, Addr.DO360_RC2, &outputVoltage) == PASS) { ShmRelayModuleData[1]->Gun1FuseOutputVolt = outputVoltage.behindFuse_Voltage_C1; ShmRelayModuleData[1]->Gun1RelayOutputVolt = outputVoltage.behindRelay_Voltage_C1; ShmRelayModuleData[1]->Gun2FuseOutputVolt = outputVoltage.behindFuse_Voltage_C2; ShmRelayModuleData[1]->Gun2RelayOutputVolt = outputVoltage.behindRelay_Voltage_C2; _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 { // only one relay board if (Query_Present_OutputVoltage(Uart5Fd, Addr.DO360_RC1, &outputVoltage) == PASS) { ShmRelayModuleData[0]->Gun1FuseOutputVolt = outputVoltage.behindFuse_Voltage_C1; ShmRelayModuleData[0]->Gun1RelayOutputVolt = outputVoltage.behindRelay_Voltage_C1; ShmRelayModuleData[0]->Gun2FuseOutputVolt = outputVoltage.behindFuse_Voltage_C2; ShmRelayModuleData[0]->Gun2RelayOutputVolt = outputVoltage.behindRelay_Voltage_C2; _chargingData[0]->FuseChargingVoltage = ShmRelayModuleData[0]->Gun1FuseOutputVolt; _chargingData[0]->FireChargingVoltage = ShmRelayModuleData[0]->Gun1RelayOutputVolt; _chargingData[1]->FuseChargingVoltage = ShmRelayModuleData[0]->Gun2FuseOutputVolt; _chargingData[1]->FireChargingVoltage = ShmRelayModuleData[0]->Gun2RelayOutputVolt; } } } // 風扇速度 void GetFanSpeed() { //LOG_INFO("Get fan board speed"); if (Query_Fan_Speed(Uart5Fd, Addr.Fan, &fanSpeed) == PASS) { ShmFanModuleData->PresentFan1Speed = fanSpeed.speed[0]; ShmFanModuleData->PresentFan2Speed = fanSpeed.speed[1]; ShmFanModuleData->PresentFan3Speed = fanSpeed.speed[2]; ShmFanModuleData->PresentFan4Speed = fanSpeed.speed[3]; // LOG_INFO("SystemFanRotaSpeed_1 = %d", fanSpeed.speed[0]); // LOG_INFO("SystemFanRotaSpeed_2 = %d", fanSpeed.speed[1]); // LOG_INFO("SystemFanRotaSpeed_3 = %d", fanSpeed.speed[2]); // LOG_INFO("SystemFanRotaSpeed_4 = %d", fanSpeed.speed[3]); // Config_Fan_Speed(Uart5Fd, Addr.Fan, &fanSpeed[0]); //SysInfoData (SystemFanRotaSpeed) } } // 讀取 Relay 狀態 void GetRelayOutputStatus(void) { unsigned char location = 0; if(Query_Relay_Output(Uart5Fd, Addr.DO360_RC1, ®Relay[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, ®Relay[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 != LocationOutputRelayResponse[location]->bits.Gun_N) { LOG_INFO("Gun %d Get K1K2 N %s at Location %d", i + 1, LocationOutputRelayResponse[location]->bits.Gun_N ? "On" : "Off", location + 1); } ShmOutputRelayConfirmed[i]->bits.Output_N = LocationOutputRelayResponse[location]->bits.Gun_N; if(ShmOutputRelayConfirmed[i]->bits.Output_P != LocationOutputRelayResponse[location]->bits.Gun_P) { LOG_INFO("Gun %d Get K1K2 P %s at Location %d", i + 1, LocationOutputRelayResponse[location]->bits.Gun_P ? "On" : "Off", location + 1); } ShmOutputRelayConfirmed[i]->bits.Output_P = LocationOutputRelayResponse[location]->bits.Gun_P; } // update parallel relay feedback status int parallelCnt = ShmChargerInfo->Control.MaxConnector == GENERAL_GUN_QUANTITY ? PARALLEL_RELAY_COUNT : 1; for(int i = 0; i < parallelCnt; i++) { bool relayOnOff = 0; if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable) { switch(i) { case 0: LocationParallelRelayResponse[i] = regRelay[0].relay_event.bits.Gun1_Parallel_N; break; case 1: LocationParallelRelayResponse[i] = regRelay[0].relay_event.bits.Gun2_Parallel_N; break; case 2: LocationParallelRelayResponse[i] = regRelay[1].relay_event.bits.Gun1_Parallel_N; break; case 3: LocationParallelRelayResponse[i] = regRelay[1].relay_event.bits.Gun2_Parallel_N; break; case 4: LocationParallelRelayResponse[i] = regRelay[0].relay_event.bits.CCS_Precharge; break; case 5: LocationParallelRelayResponse[i] = regRelay[1].relay_event.bits.CCS_Precharge; break; } relayOnOff = LocationParallelRelayResponse[i]; } else { bool original = ShmParallelRelayConfig->CtrlValue & (1 << i) ? false : true; relayOnOff = regRelay[0].relay_event.bits.Gun1_Parallel_N == regRelay[0].relay_event.bits.Gun2_Parallel_N ? regRelay[0].relay_event.bits.Gun1_Parallel_N : original; #if RELAY_DEBUG_MSG if(regRelay[0].relay_event.bits.Gun1_Parallel_N != regRelay[0].relay_event.bits.Gun2_Parallel_N) { LOG_INFO("Parallel Relay N & P at Location %d is Not Match: %d, %d", i + 1, regRelay[0].relay_event.bits.Gun1_Parallel_N, regRelay[0].relay_event.bits.Gun2_Parallel_N); } #endif } if((ShmParallelRelayConfirmed->CtrlValue & (1 << i)) != (relayOnOff << i)) { LOG_INFO("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(LocationOutputRelayCtrl[location]->bits.Gun_N == LocationOutputRelayCtrl[location]->bits.Gun_P) { _chargingData[index]->RelayK1K2Status = LocationOutputRelayCtrl[location]->bits.Gun_N ? YES : NO; } else { _chargingData[index]->RelayK1K2Status = NO; } } } void GetGfdAdc(void) { unsigned char location = 0, result = 0; char *str_gfd[] = {"Idle", "Pass", "Fail", "Warning"}; if(!_isGfdEnable) { for(int i = 0; i < ShmChargerInfo->Control.MaxConnector; i++) { if(_chargingData[i]->PantographFlag == YES) { _isGfdEnable = true; LOG_INFO("Enable Power Cabinet GFD Function"); } } } if(_isGfdEnable) { // define : 每 0.2 ~ 1 秒一次 // occur : <= 75k 歐姆 @ 150 - 750 Vdc // warning : >= 100 歐姆 && <= 500 歐姆 @ 150-750 Vdc if(Query_Gfd_Adc(Uart5Fd, Addr.DO360_RC1, &gfd_adc[0]) == PASS) { // if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[0].Parameter.bits.GfdDetection || // ShmSysConfigAndInfo->SysInfo.ConnectorInfo[1].Parameter.bits.GfdDetection) // { // LOG_INFO("Query Relay1 GFD ADC1 Status = %d, ADC2 Status = %d", gfd_adc[0].result_conn1, gfd_adc[0].result_conn2); // } } // else // { // if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[0].Parameter.bits.GfdDetection || // ShmSysConfigAndInfo->SysInfo.ConnectorInfo[1].Parameter.bits.GfdDetection) // { // LOG_INFO("Query Relay1 GFD ADC Fail"); // } // } if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable) { if(Query_Gfd_Adc(Uart5Fd, Addr.DO360_RC2, &gfd_adc[1]) == PASS) { } } // update output relay feedback status for(int i = 0; i < ShmChargerInfo->Control.MaxConnector; i++) { location = ShmPsuGrouping->GroupCollection[i].Location; result = LocaltionGfd[location]->bits.GFD_Result; if(_chargingData[i]->GroundFaultStatus != result) { if(result <= GFD_WARNING) { LOG_INFO("Gun %d GFD Result %s at Location %d", i + 1, str_gfd[result], location + 1); if(result == GFD_FAIL || result == GFD_WARNING) { LOG_INFO("Gun %d GFD Step = %d, R = %d, Vol = %d", i + 1, LocaltionGfd[location]->bits.rb_step, LocaltionGfd[location]->bits.Resister, LocaltionGfd[location]->bits.Voltage); } } else { LOG_INFO("Gun %d Unknown GFD Result %d at Location %d", i + 1, result, location + 1); } } _chargingData[i]->GroundFaultStatus = result; } } } void SetFanModuleSpeed() { { FanSpeed _fanSpeed; _setFanSpeed += fanSpeedSmoothValue; if (_setFanSpeed >= ShmFanModuleData->SetFan1Speed) _setFanSpeed = ShmFanModuleData->SetFan1Speed; //printf("_setFanSpeed = %d \n", _setFanSpeed); _fanSpeed.speed[0] = _setFanSpeed; _fanSpeed.speed[1] = _setFanSpeed; _fanSpeed.speed[2] = _setFanSpeed; _fanSpeed.speed[3] = _setFanSpeed; if (Config_Fan_Speed(Uart5Fd, Addr.Fan, &_fanSpeed) == PASS) { //LOG_INFO("successfully Fan"); } } } void SetPCabinetOutputRelayOff(byte index) { if(ShmChargerInfo->Control.CabinetRole == _CROLE_MASTER) { if(ShmChargerInfo->ParallelCabinet.PCabinet[index].OutputRelaySetting[index] != NO) { LOG_INFO("Set Parallel Cabinet Gun %d Output Relay OFF", index + 1); } ShmChargerInfo->ParallelCabinet.PCabinet[index].OutputRelaySetting[index] = NO; } } void SetMCabinetOutputRelay(byte index) { if(ShmChargerInfo->Control.RelayCtrl.bits.AbnormalRelay) { return; } if ((_chargingData[index]->SystemStatus >= S_PREPARING_FOR_EVSE && _chargingData[index]->SystemStatus <= S_CHARGING)) { if(_chargingData[index]->GroundFaultStatus == GFD_FAIL) { if(ShmOutputRelayConfig[index]->bits.Output_N || ShmOutputRelayConfig[index]->bits.Output_P) { LOG_INFO("Gun %d Set K1K2 Open By GFD Fail", index + 1); } ShmOutputRelayConfig[index]->bits.Output_N = false; ShmOutputRelayConfig[index]->bits.Output_P = false; SetPCabinetOutputRelayOff(index); } else { #if RELAY_OPEN_AT_PRECHARGE if(_chargingData[index]->SystemStatus == S_PREPARING_FOR_EVSE) { if(ShmPsuGrouping->GroupCollection[index].GroupCtrl.bits.CableCheckDone == false && ShmPsuGrouping->GroupCollection[index].GroupCtrl.bits.InPrechargeMode == false) { if(!ShmOutputRelayConfig[index]->bits.Output_N || !ShmOutputRelayConfig[index]->bits.Output_P) { LOG_INFO("Gun %d Set K1K2 Close And Prepare To Cable Check", index + 1); } ShmOutputRelayConfig[index]->bits.Output_N = true; ShmOutputRelayConfig[index]->bits.Output_P = true; } else if(ShmPsuGrouping->GroupCollection[index].GroupCtrl.bits.CableCheckDone == true && ShmPsuGrouping->GroupCollection[index].GroupCtrl.bits.InPrechargeMode == false) { if(_chargingData[index]->FireChargingVoltage <= SELF_TO_CHANGE_RELAY_STATUS) { if(ShmOutputRelayConfig[index]->bits.Output_N || ShmOutputRelayConfig[index]->bits.Output_P) { LOG_INFO("Gun %d Set K1K2 Open By Cable Check Done", index + 1); } ShmOutputRelayConfig[index]->bits.Output_N = false; ShmOutputRelayConfig[index]->bits.Output_P = false; } } else if(ShmPsuGrouping->GroupCollection[index].GroupCtrl.bits.CableCheckDone == true && ShmPsuGrouping->GroupCollection[index].GroupCtrl.bits.InPrechargeMode == true) { unsigned short voltage = 0, diffVol = 0; voltage = (int)(_chargingData[index]->PresentChargingVoltage * 10); diffVol = voltage >= ShmPsuGrouping->GroupOutput[index].GTargetVoltage ? voltage - ShmPsuGrouping->GroupOutput[index].GTargetVoltage : ShmPsuGrouping->GroupOutput[index].GTargetVoltage - voltage; if(diffVol <= 30) { if(!ShmOutputRelayConfig[index]->bits.Output_N || !ShmOutputRelayConfig[index]->bits.Output_P) { LOG_INFO("Gun %d Set K1K2 Close And Voltage Is Balance", index + 1); } ShmOutputRelayConfig[index]->bits.Output_N = true; ShmOutputRelayConfig[index]->bits.Output_P = true; } } } else { if(!ShmOutputRelayConfig[index]->bits.Output_N || !ShmOutputRelayConfig[index]->bits.Output_P) { LOG_INFO("Gun %d Set K1K2 Close In Charging Status", index + 1); } ShmOutputRelayConfig[index]->bits.Output_N = true; ShmOutputRelayConfig[index]->bits.Output_P = true; } #else if(!ShmOutputRelayConfig[index]->bits.Output_N || !ShmOutputRelayConfig[index]->bits.Output_P) { LOG_INFO("Gun %d Set K1K2 Close And Prepare To Charging", index + 1); } ShmOutputRelayConfig[index]->bits.Output_N = true; ShmOutputRelayConfig[index]->bits.Output_P = true; #endif } } else if ((_chargingData[index]->SystemStatus >= S_TERMINATING && _chargingData[index]->SystemStatus <= S_COMPLETE) || _chargingData[index]->SystemStatus == S_ALARM) { if ((_chargingData[index]->PresentChargingCurrent * 10) <= SEFETY_SWITCH_RELAY_CUR || _chargingData[index]->GroundFaultStatus == GFD_FAIL) { if(ShmOutputRelayConfig[index]->bits.Output_N || ShmOutputRelayConfig[index]->bits.Output_P) { LOG_INFO("Gun %d Set K1K2 Open And Charging Stop", index + 1); } ShmOutputRelayConfig[index]->bits.Output_N = false; ShmOutputRelayConfig[index]->bits.Output_P = false; SetPCabinetOutputRelayOff(index); } } else { if(ShmOutputRelayConfig[index]->bits.Output_N || ShmOutputRelayConfig[index]->bits.Output_P) { LOG_INFO("Gun %d Set K1K2 Open At Idle Mode", index + 1); } ShmOutputRelayConfig[index]->bits.Output_N = false; ShmOutputRelayConfig[index]->bits.Output_P = false; if(_chargingData[index]->SystemStatus == S_IDLE || _chargingData[index]->SystemStatus == S_MAINTAIN || _chargingData[index]->SystemStatus == S_FAULT) { SetPCabinetOutputRelayOff(index); } } } void SetSCabinetOutputRelay(byte index) { if(ShmChargerInfo->Control.RelayCtrl.bits.AbnormalRelay) { return; } ShmOutputRelayConfig[index]->bits.Output_N = ShmChargerInfo->SCabinetControl.SOutputRelay[index] > 0 ? true : false; ShmOutputRelayConfig[index]->bits.Output_P = ShmChargerInfo->SCabinetControl.SOutputRelay[index] > 0 ? true : false; } //========================================== // Common Function //========================================== void SetK1K2RelayStatus(byte index) { unsigned char location = 0; if(index < MAX_GROUP_QUANTITY && index < ShmChargerInfo->Control.MaxConnector) { if(ShmChargerInfo->Control.CabinetRole != _CROLE_SLAVE) { SetMCabinetOutputRelay(index); } else { SetSCabinetOutputRelay(index); } location = ShmPsuGrouping->GroupCollection[index].Location; if(ShmOutputRelayConfig[index]->bits.Output_N != LocationOutputRelayCtrl[location]->bits.Gun_N) { #if RELAY_DEBUG_MSG LOG_INFO("Connector %d Set K1K2 N %s at Location %d", index + 1, ShmOutputRelayConfig[index]->bits.Output_N ? "On" : "Off", location + 1); #endif } LocationOutputRelayCtrl[location]->bits.Gun_N = ShmOutputRelayConfig[index]->bits.Output_N; if(ShmOutputRelayConfig[index]->bits.Output_P != LocationOutputRelayCtrl[location]->bits.Gun_P) { #if RELAY_DEBUG_MSG LOG_INFO("Connector %d Set K1K2 P %s at Location %d", index + 1, ShmOutputRelayConfig[index]->bits.Output_P ? "On" : "Off", location + 1); #endif } LocationOutputRelayCtrl[location]->bits.Gun_P = ShmOutputRelayConfig[index]->bits.Output_P; } } void SetParalleRelayStatus() { int parallelCnt = ShmChargerInfo->Control.MaxConnector == GENERAL_GUN_QUANTITY ? PARALLEL_RELAY_COUNT : 1; for(int i = 0; i < parallelCnt; i++) { if((ShmParallelRelayConfig->CtrlValue & (1 << i)) != (LocationParallelRelayCtrl[i] << i)) { #if RELAY_DEBUG_MSG LOG_INFO("Set Parallel Relay N & P %s at Location %d", (ShmParallelRelayConfig->CtrlValue & (1 << i)) ? "On" : "Off", i + 1); #endif } LocationParallelRelayCtrl[i] = (ShmParallelRelayConfig->CtrlValue & (1 << i)) ? YES : NO; switch(i) { case 0: outputRelay[0].relay_event.bits.Gun1_Parallel_N = LocationParallelRelayCtrl[i]; if(!ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable) { outputRelay[0].relay_event.bits.Gun2_Parallel_N = LocationParallelRelayCtrl[i]; } break; case 1: outputRelay[0].relay_event.bits.Gun2_Parallel_N = LocationParallelRelayCtrl[i]; break; case 2: outputRelay[1].relay_event.bits.Gun1_Parallel_N = LocationParallelRelayCtrl[i]; break; case 3: outputRelay[1].relay_event.bits.Gun2_Parallel_N = LocationParallelRelayCtrl[i]; break; case 4: outputRelay[0].relay_event.bits.CCS_Precharge = LocationParallelRelayCtrl[i]; break; case 5: outputRelay[1].relay_event.bits.CCS_Precharge = LocationParallelRelayCtrl[i]; break; } } } void SetAcContactorStatus(void) { if(ShmChargerInfo->Control.RelayCtrl.bits.AcContactor == YES && ShmChargerInfo->Control.RelayCtrl.bits.AcContactorOffByPsu == NO && ShmChargerInfo->Control.RelayCtrl.bits.AcContactorOffByEmergency == NO) { outputRelay[0].relay_event.bits.AC_Contactor = YES; } else { outputRelay[0].relay_event.bits.AC_Contactor = NO; } if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable) { if(ShmChargerInfo->Control.RelayCtrl.bits.AcContactor == YES && ShmChargerInfo->Control.RelayCtrl.bits.AcContactorOffByPsu == NO && ShmChargerInfo->Control.RelayCtrl.bits.AcContactorOffByEmergency == NO) { outputRelay[1].relay_event.bits.AC_Contactor = YES; } else { outputRelay[1].relay_event.bits.AC_Contactor = NO; } } } bool IsNoneMatchLedColor() { bool result = false; if (cur_led_color.Connect_1_Red != led_color.Connect_1_Red || cur_led_color.Connect_1_Green != led_color.Connect_1_Green || cur_led_color.Connect_1_Blue != led_color.Connect_1_Blue || cur_led_color.Connect_2_Red != led_color.Connect_2_Red || cur_led_color.Connect_2_Green != led_color.Connect_2_Green || cur_led_color.Connect_2_Blue != led_color.Connect_2_Blue) { result = true; } return result; } void SetLedColor(struct ChargingInfoData *chargingData_1, struct ChargingInfoData *chargingData_2) { byte _colorBuf = COLOR_MAX_LV * LED_INTENSITY_BRIGHTEST; if (ShmSysConfigAndInfo->SysConfig.LedInfo.Intensity == _LED_INTENSITY_DARKEST) _colorBuf = COLOR_MAX_LV * LED_INTENSITY_DARKEST; else if (ShmSysConfigAndInfo->SysConfig.LedInfo.Intensity == _LED_INTENSITY_MEDIUM) _colorBuf = COLOR_MAX_LV * LED_INTENSITY_MEDIUM; if (ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf) { if ((chargingData_1->SystemStatus == S_BOOTING || chargingData_1->SystemStatus == S_IDLE || chargingData_1->SystemStatus == S_RESERVATION) && (chargingData_2->SystemStatus == S_BOOTING || chargingData_2->SystemStatus == S_IDLE || chargingData_2->SystemStatus == S_RESERVATION)) { led_color.Connect_1_Green = _colorBuf; led_color.Connect_1_Blue = COLOR_MIN_LV; led_color.Connect_1_Red = COLOR_MIN_LV; led_color.Connect_2_Green = _colorBuf; led_color.Connect_2_Blue = COLOR_MIN_LV; led_color.Connect_2_Red = COLOR_MIN_LV; } else if ((chargingData_1->SystemStatus >= S_AUTHORIZING && chargingData_1->SystemStatus <= S_COMPLETE) || (chargingData_1->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingData_1->SystemStatus <= S_CCS_PRECHARGE_ST1) || (chargingData_2->SystemStatus >= S_AUTHORIZING && chargingData_2->SystemStatus <= S_COMPLETE) || (chargingData_2->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingData_2->SystemStatus <= S_CCS_PRECHARGE_ST1)) { led_color.Connect_1_Green = COLOR_MIN_LV; led_color.Connect_1_Blue = _colorBuf; led_color.Connect_1_Red = COLOR_MIN_LV; led_color.Connect_2_Green = COLOR_MIN_LV; led_color.Connect_2_Blue = _colorBuf; led_color.Connect_2_Red = COLOR_MIN_LV; } } else { if (chargingData_1->SystemStatus == S_BOOTING || chargingData_1->SystemStatus == S_IDLE || chargingData_1->SystemStatus == S_RESERVATION) { led_color.Connect_1_Green = _colorBuf; led_color.Connect_1_Blue = COLOR_MIN_LV; led_color.Connect_1_Red = COLOR_MIN_LV; } else if ((chargingData_1->SystemStatus >= S_AUTHORIZING && chargingData_1->SystemStatus <= S_COMPLETE) || (chargingData_1->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingData_1->SystemStatus <= S_CCS_PRECHARGE_ST1)) { led_color.Connect_1_Green = COLOR_MIN_LV; led_color.Connect_1_Blue = _colorBuf; led_color.Connect_1_Red = COLOR_MIN_LV; } // -------------------------------------------------------------------------- if (chargingData_2->SystemStatus == S_BOOTING || chargingData_2->SystemStatus == S_IDLE || chargingData_2->SystemStatus == S_RESERVATION) { led_color.Connect_2_Green = _colorBuf; led_color.Connect_2_Blue = COLOR_MIN_LV; led_color.Connect_2_Red = COLOR_MIN_LV; } else if ((chargingData_2->SystemStatus >= S_AUTHORIZING && chargingData_2->SystemStatus <= S_COMPLETE) || (chargingData_2->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingData_2->SystemStatus <= S_CCS_PRECHARGE_ST1)) { led_color.Connect_2_Green = COLOR_MIN_LV; led_color.Connect_2_Blue = _colorBuf; led_color.Connect_2_Red = COLOR_MIN_LV; } } if (ShmSysConfigAndInfo->SysWarningInfo.Level == 2) { led_color.Connect_1_Green = COLOR_MIN_LV; led_color.Connect_1_Blue = COLOR_MIN_LV; led_color.Connect_1_Red = _colorBuf; led_color.Connect_2_Green = COLOR_MIN_LV; led_color.Connect_2_Blue = COLOR_MIN_LV; led_color.Connect_2_Red = _colorBuf; } if (_checkLedChanged > 0) { if (Config_Led_Color(Uart5Fd, Addr.Led, &led_color) == PASS) { _checkLedChanged--; cur_led_color.Connect_1_Red = led_color.Connect_1_Red; cur_led_color.Connect_1_Green = led_color.Connect_1_Green; cur_led_color.Connect_1_Blue = led_color.Connect_1_Blue; cur_led_color.Connect_2_Red = led_color.Connect_2_Red; cur_led_color.Connect_2_Green = led_color.Connect_2_Green; cur_led_color.Connect_2_Blue = led_color.Connect_2_Blue; } } else if (IsNoneMatchLedColor()) _checkLedChanged = 3; } //========================================== // Init all share memory //========================================== int InitShareMemory() { int result = PASS; int MeterSMId; if ((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo), 0777)) < 0) { #ifdef SystemLogMessage LOG_ERROR("shmget ShmSysConfigAndInfo NG"); #endif result = FAIL; } else if ((ShmSysConfigAndInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1) { #ifdef SystemLogMessage LOG_ERROR("[shmat ShmSysConfigAndInfo NG"); #endif result = FAIL; } if ((MeterSMId = shmget(ShmStatusCodeKey, sizeof(struct StatusCodeData), 0777)) < 0) { #ifdef SystemLogMessage LOG_ERROR("shmget ShmStatusCodeData NG"); #endif result = FAIL; } else if ((ShmStatusCodeData = shmat(MeterSMId, NULL, 0)) == (void *) -1) { #ifdef SystemLogMessage LOG_ERROR("shmat ShmStatusCodeData NG"); #endif result = FAIL; } if ((MeterSMId = shmget(ShmFanBdKey, sizeof(struct FanModuleData), 0777)) < 0) { #ifdef SystemLogMessage LOG_ERROR("shmget ShmFanModuleData NG"); #endif result = FAIL; } else if ((ShmFanModuleData = shmat(MeterSMId, NULL, 0)) == (void *) -1) { #ifdef SystemLogMessage LOG_ERROR("shmat ShmFanModuleData NG"); #endif result = FAIL; } if ((MeterSMId = shmget(ShmRelayBdKey, sizeof(struct RelayModuleData), 0777)) < 0) { #ifdef SystemLogMessage LOG_ERROR("shmget ShmRelayModuleData NG"); #endif result = FAIL; } else if ((ShmRelayModuleData[0] = shmat(MeterSMId, NULL, 0)) == (void *) -1) { #ifdef SystemLogMessage LOG_ERROR("shmat ShmRelayModuleData NG"); #endif result = FAIL; } // DO360 RC2 if ((MeterSMId = shmget(ShmRelay2BdKey, sizeof(struct RelayModuleData), 0777)) < 0) { #ifdef SystemLogMessage LOG_ERROR("shmget ShmRelay2ModuleData NG"); #endif result = FAIL; } else if ((ShmRelayModuleData[1] = shmat(MeterSMId, NULL, 0)) == (void *) -1) { #ifdef SystemLogMessage LOG_ERROR("shmat ShmRelay2ModuleData NG"); #endif result = FAIL; } if ((MeterSMId = shmget(ShmLedBdKey, sizeof(struct LedModuleData), 0777)) < 0) { #ifdef SystemLogMessage LOG_ERROR("shmget ShmLedModuleData NG"); #endif result = FAIL; } else if ((ShmLedModuleData = shmat(MeterSMId, NULL, 0)) == (void *) -1) { #ifdef SystemLogMessage LOG_ERROR("shmat ShmLedModuleData NG"); #endif result = FAIL; } if ((MeterSMId = shmget(ShmPsuKey, sizeof(struct PsuData), 0777)) < 0) { #ifdef SystemLogMessage LOG_ERROR("shmget ShmPsuData NG"); #endif result = FAIL; } else if ((ShmPsuData = shmat(MeterSMId, NULL, 0)) == (void *) -1) { #ifdef SystemLogMessage LOG_ERROR("shmat ShmPsuData NG"); #endif result = FAIL; } if ((MeterSMId = shmget(ShmOcppModuleKey, sizeof(struct OCPP16Data), 0777)) < 0) { #ifdef SystemLogMessage LOG_ERROR("shmat ShmOCPP16Data NG"); #endif result = FAIL; } else if ((ShmOCPP16Data = shmat(MeterSMId, NULL, 0)) == (void *) -1) { #ifdef SystemLogMessage LOG_ERROR("shmat ShmOCPP16Data NG"); #endif result = FAIL; } if ((MeterSMId = shmget(SM_ChargerInfoKey, sizeof(ChargerInfoData), 0777)) < 0) { #ifdef SystemLogMessage LOG_ERROR("shmat ChargerInfoData NG"); #endif result = FAIL; } else if ((ShmChargerInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1) { #ifdef SystemLogMessage LOG_ERROR("shmat ChargerInfoData NG"); #endif result = FAIL; } if(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) { LocationOutputRelayCtrl[0] = (OutputRelayControl *)&outputRelay[0].relay_event.relay_status[1]; LocationOutputRelayCtrl[1] = (OutputRelayControl *)&outputRelay[0].relay_event.relay_status[2]; LocationOutputRelayResponse[0] = (OutputRelayControl *)®Relay[0].relay_event.relay_status[1]; LocationOutputRelayResponse[1] = (OutputRelayControl *)®Relay[0].relay_event.relay_status[2]; memset(LocationParallelRelayCtrl, 0x00, sizeof(LocationParallelRelayCtrl)); memset(LocationParallelRelayResponse, 0x00, sizeof(LocationParallelRelayResponse)); LocaltionGfd[0] = (Connector_GFD *)&gfd_adc[0].Resister_conn1; LocaltionGfd[1] = (Connector_GFD *)&gfd_adc[0].Resister_conn2; if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable) { LocationOutputRelayCtrl[2] = (OutputRelayControl *)&outputRelay[1].relay_event.relay_status[1]; LocationOutputRelayCtrl[3] = (OutputRelayControl *)&outputRelay[1].relay_event.relay_status[2]; LocationOutputRelayResponse[2] = (OutputRelayControl *)®Relay[1].relay_event.relay_status[1]; LocationOutputRelayResponse[3] = (OutputRelayControl *)®Relay[1].relay_event.relay_status[2]; LocaltionGfd[2] = (Connector_GFD *)&gfd_adc[1].Resister_conn1; LocaltionGfd[3] = (Connector_GFD *)&gfd_adc[1].Resister_conn2; } } } return result; } int InitComPort() { int fd; struct termios tios; fd = open(relayRs485PortName, O_RDWR); if(fd <= 0) { #ifdef SystemLogMessage LOG_ERROR("Module_InternalComm. InitComPort NG"); #endif if(ShmStatusCodeData!=NULL) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.CsuInitFailed=1; } sleep(5); return -1; } ioctl (fd, TCGETS, &tios); tios.c_cflag = B115200 | CS8 | CLOCAL | CREAD; tios.c_lflag = 0; tios.c_iflag = 0; tios.c_oflag = 0; tios.c_cc[VMIN]=0; tios.c_cc[VTIME]=(byte)0; // timeout 0.5 second tios.c_lflag=0; tcflush(fd, TCIFLUSH); ioctl (fd, TCSETS, &tios); return fd; } //================================================ // Main process //================================================ bool FindChargingInfoData(byte target, struct ChargingInfoData **chargingData) { for (byte index = 0; index < CHAdeMO_QUANTITY; index++) { if (ShmSysConfigAndInfo->SysInfo.ChademoChargingData[index].Index == target) { chargingData[target] = &ShmSysConfigAndInfo->SysInfo.ChademoChargingData[index]; return true; } } for (byte index = 0; index < CCS_QUANTITY; index++) { if (ShmSysConfigAndInfo->SysInfo.CcsChargingData[index].Index == target) { chargingData[target] = &ShmSysConfigAndInfo->SysInfo.CcsChargingData[index]; return true; } } for (byte index = 0; index < GB_QUANTITY; index++) { if (ShmSysConfigAndInfo->SysInfo.GbChargingData[index].Index == target) { chargingData[target] = &ShmSysConfigAndInfo->SysInfo.GbChargingData[index]; return true; } } //DO360 if(GENERAL_GUN_QUANTITY > 0 && target < GENERAL_GUN_QUANTITY) { //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[target].GeneralChargingData.Index = target; chargingData[target] = &ShmSysConfigAndInfo->SysInfo.ConnectorInfo[target].GeneralChargingData; return true; } return false; } bool FindAcChargingInfoData(byte target, struct ChargingInfoData **acChargingData) { if (target < AC_QUANTITY) { acChargingData[target] = &ShmSysConfigAndInfo->SysInfo.AcChargingData[target]; return true; } return false; } void Initialization() { bool isPass = false; for (byte index = 0; index < ARRAY_SIZE(outputRelay[0].relay_event.relay_status); index++) { outputRelay[0].relay_event.relay_status[index] = 0x00; outputRelay[1].relay_event.relay_status[index] = 0x00; } while(!isPass) { isPass = true; for (byte _index = 0; _index < CONNECTOR_QUANTITY; _index++) { if (!FindChargingInfoData(_index, &_chargingData[0])) { LOG_ERROR("InternalComm : FindChargingInfoData false"); isPass = false; break; } } sleep(1); } isPass = false; if (acgunCount > 0) { while(!isPass) { isPass = true; for (byte _index = 0; _index < acgunCount; _index++) { if (!FindAcChargingInfoData(_index, &ac_chargingInfo[0])) { LOG_ERROR("EvComm : FindAcChargingInfoData false"); isPass = false; break; } } sleep(1); } } } bool IsNoneMatchRelayStatus(byte index) { bool result = false; 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) { LOG_INFO("[%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 RELAY_DEBUG_MSG LOG_INFO("[%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 RELAY_DEBUG_MSG LOG_INFO("[%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 RELAY_DEBUG_MSG LOG_INFO("[%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 RELAY_DEBUG_MSG LOG_INFO("[%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 RELAY_DEBUG_MSG LOG_INFO("[%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 RELAY_DEBUG_MSG LOG_INFO("[%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 RELAY_DEBUG_MSG LOG_INFO("[%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 RELAY_DEBUG_MSG LOG_INFO("[%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 RELAY_DEBUG_MSG LOG_INFO("[%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; } return result; } void CheckRelayStatusByADC() { if (ShmRelayModuleData[0]->Gun1FuseOutputVolt > 0 && ShmRelayModuleData[0]->Gun1RelayOutputVolt > 0 && (ShmRelayModuleData[0]->Gun1FuseOutputVolt == ShmRelayModuleData[0]->Gun1RelayOutputVolt)) { // Relay 前後電壓一致 _chargingData[0]->RelayK1K2Status = 0x01; } else _chargingData[0]->RelayK1K2Status = 0x00; if (ShmRelayModuleData[1]->Gun2FuseOutputVolt > 0 && ShmRelayModuleData[1]->Gun2RelayOutputVolt > 0 && (ShmRelayModuleData[1]->Gun2FuseOutputVolt == ShmRelayModuleData[1]->Gun2RelayOutputVolt)) { // Relay 前後電壓一致 _chargingData[1]->RelayK1K2Status = 0x01; } else _chargingData[1]->RelayK1K2Status = 0x00; } void SetGfdConfig(byte index, byte resister) { unsigned char add = 0; gfd_config.index = (index % 2); gfd_config.state = resister; add = index < 2 ? Addr.DO360_RC1 : Addr.DO360_RC2; //LOG_INFO("************************GFD Vol = %d, GFD Res = %d", gfd_config.reqVol, gfd_config.resister); if (Config_Gfd_Value(Uart5Fd, add, &gfd_config) == PASS) { // LOG_INFO("Set reqVol = %f, resister = %d", // gfd_config.reqVol, // gfd_config.resister); // if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[0].Parameter.bits.GfdDetection || // ShmSysConfigAndInfo->SysInfo.ConnectorInfo[1].Parameter.bits.GfdDetection) // { // LOG_INFO("Set Relay %02X GFD Config index = %d, state = %d OK", add, gfd_config.index, gfd_config.state); // } } // else // { // if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[0].Parameter.bits.GfdDetection || // ShmSysConfigAndInfo->SysInfo.ConnectorInfo[1].Parameter.bits.GfdDetection) // { // LOG_INFO("Set Relay %02X GFD Config index = %d, state = %d NG", add, gfd_config.index, gfd_config.state); // } // } } char GfdConfig[4]; void CableCheckDetected(byte index) { unsigned char location = 0; char *strGfdConfig[] = {"Idle", "CableCheck", "PreCharge", "Charging"}; // Cable Check // 當火線上的電壓 = 車端要求的電壓電流 // _chargingData[targetGun]->EvBatterytargetVoltage // 才可以開始偵測 1s // Warning : Rgfd <= 150 歐/V 假設電壓為 500V 則~ Rgfd <= 75000 歐 // Pre-Warning : 150 歐/V < Rgfd <= 500 歐/V 假設電壓為 500V 則 75000 歐 < Rgfd <= 250000 // SO Normal : Rgfd > 500 歐/V 假設電壓為 500 V 則 Rgfd > 250000 歐 if(_chargingData[index]->PantographFlag == YES) { location = ShmPsuGrouping->GroupCollection[index].Location; if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].Parameter.bits.GfdDetection && _chargingData[index]->SystemStatus >= S_PREPARING_FOR_EVSE && _chargingData[index]->SystemStatus < S_TERMINATING) { if(_chargingData[index]->SystemStatus == S_PREPARING_FOR_EVSE && _chargingData[index]->RelayWeldingCheck == YES) { SetGfdConfig(location, GFD_CABLECHK); if(GfdConfig[index] != GFD_CABLECHK) { LOG_INFO("Gun %d Set GFD = %s", index + 1, strGfdConfig[GFD_CABLECHK]); } GfdConfig[index] = GFD_CABLECHK; } else { SetGfdConfig(location, GFD_CHARGING); if(GfdConfig[index] != GFD_CHARGING) { LOG_INFO("Gun %d Set GFD = %s", index + 1, strGfdConfig[GFD_CHARGING]); } GfdConfig[index] = GFD_CHARGING; } } else { SetGfdConfig(location, GFD_IDLE); if(GfdConfig[index] != GFD_IDLE) { LOG_INFO("Gun %d Set GFD = %s", index + 1, strGfdConfig[GFD_IDLE]); } GfdConfig[index] = GFD_IDLE; ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].Parameter.bits.GfdDetection = 0; } } } void CheckOutputPowerOverCarReq(byte index) { float fireV = _chargingData[index]->FireChargingVoltage; float carV = _chargingData[index]->EvBatterytargetVoltage * 10; if ((_chargingData[index]->EvBatterytargetVoltage * 10) > 1500 && (_chargingData[index]->Type == _Type_Chademo || _chargingData[index]->Type == _Type_CCS_2 || _chargingData[index]->Type == _Type_GB)) { if (fireV >= (carV + (carV * 0.1))) { LOG_INFO("[Module_InternalComm]CheckOutputPowerOverCarReq NG : fire = %f, battery = %f", _chargingData[index]->FireChargingVoltage, (_chargingData[index]->EvBatterytargetVoltage * 10)); LOG_INFO("[Module_InternalComm]CheckOutputPowerOverCarReq NG : fire = %f, battery = %f", _chargingData[index]->FireChargingVoltage, (_chargingData[index]->EvBatterytargetVoltage * 10)); _chargingData[index]->StopChargeFlag = YES; } } } void CheckOutputVolNoneMatchFire(byte index) { if ((_chargingData[index]->EvBatterytargetVoltage * 10) > 1500 && (_chargingData[index]->Type == _Type_Chademo || _chargingData[index]->Type == _Type_CCS_2 || _chargingData[index]->Type == _Type_GB)) { if (((_chargingData[index]->PresentChargingVoltage * 10) < _chargingData[index]->FireChargingVoltage - 300) || ((_chargingData[index]->PresentChargingVoltage * 10) > _chargingData[index]->FireChargingVoltage + 300)) { if (!_isOutputNoneMatch[index]) { _isOutputNoneMatch[index] = YES; GetClockTime(&_checkOutputNoneMatchTimer[index]); } else { if ((GetTimeoutValue(_checkOutputNoneMatchTimer[index]) / 1000) >= 5000) { LOG_INFO("[Module_InternalComm]CheckOutputVolNoneMatchFire NG (%d) : pre = %f, fire = %f", index, (_chargingData[index]->PresentChargingVoltage * 10), _chargingData[index]->FireChargingVoltage); LOG_INFO("[Module_InternalComm]CheckOutputVolNoneMatchFire NG (%d): pre = %f, fire = %f", index, (_chargingData[index]->PresentChargingVoltage * 10), _chargingData[index]->FireChargingVoltage); _chargingData[index]->StopChargeFlag = YES; } } } else _isOutputNoneMatch[index] = NO; } } void CheckRelayWeldingStatus(byte index) { if (!_isRelayWelding[index]) { if ((_chargingData[index]->PresentChargingVoltage * 10) >= VOUT_MIN_VOLTAGE * 10) { GetClockTime(&_checkRelayWeldingTimer[index]); _isRelayWelding[index] = YES; } } else { if ((GetTimeoutValue(_checkRelayWeldingTimer[index]) / 1000) >= 1000) { _chargingData[index]->RelayWeldingCheck = YES; return; } if (_chargingData[index]->FireChargingVoltage >= VOUT_MIN_VOLTAGE) { if (_chargingData[index]->Type == _Type_Chademo) ShmStatusCodeData->FaultCode.FaultEvents.bits.ChademoOutputRelayWelding = YES; else if (_chargingData[index]->Type == _Type_GB) ShmStatusCodeData->FaultCode.FaultEvents.bits.GbOutputRelayWelding = YES; else if (_chargingData[index]->Type == _Type_CCS_2) ShmStatusCodeData->FaultCode.FaultEvents.bits.CcsOutputRelayWelding = YES; LOG_INFO("CheckRelayWeldingStatus : fail"); _chargingData[index]->StopChargeFlag = YES; } } } void GetFanSpeedByFunction() { if (ShmSysConfigAndInfo->SysConfig.SwitchDebugFlag == YES) return; // 風控修改 : // ******************************************************* // // // 當前PSU輸出總 KW PSU Temp // 50 x -------------------- x ---------- + 0.5 x (PSU Temp - 70) // 當前樁最大功率 KW 50 // // ******************************************************* // // 當前樁最大功率 KW : ShmPsuData->SystemAvailablePower unsigned int _maxPower = ShmPsuData->SystemAvailablePower; // 當前PSU輸出總 KW & PSU Temp : int temp = 0; float power = 0; for (byte index = 0; index < ShmPsuData->GroupCount; index++) { for (byte count = 0; count < ShmPsuData->PsuGroup[index].GroupPresentPsuQuantity; count++) { int ExletTemp = (int)ShmPsuData->PsuGroup[index].PsuModule[count].ExletTemp - 60; if (temp < ExletTemp) { temp = ExletTemp; } } power += (_chargingData[index]->PresentChargingPower * 10); } double _pw_rate = 0; if (_maxPower > 0) _pw_rate = power / (double)_maxPower; double _temp_rate = 0; if (temp > 0) _temp_rate = (double)temp / 50; unsigned char _temp_diff = 0; if (temp > 70) _temp_diff = temp - 70; ShmFanModuleData->TestFanSpeed = (((50 * _pw_rate * _temp_rate) + (0.5 * _temp_diff)) / 100) * MAX_FAN_SPEED; if (ShmFanModuleData->TestFanSpeed > MAX_FAN_SPEED) ShmFanModuleData->TestFanSpeed = MAX_FAN_SPEED; if (ShmFanModuleData->TestFanSpeed < 0) ShmFanModuleData->TestFanSpeed = 0; // ----------------------------------------------------------------------- // printf("power = %f \n", power); // printf("_maxPower = %d \n", _maxPower); // printf("temp = %d \n", temp); // // printf("_pw_rate = %f \n", _pw_rate); // printf("_temp_rate = %f \n", _temp_rate); // printf("_temp_diff = %d \n", _temp_diff); // printf("fan rate = %f \n", (30 * _pw_rate * _temp_rate + 14 * _temp_diff)); // printf("ShmFanModuleData->TestFanSpeed = %d \n", ShmFanModuleData->TestFanSpeed); } int main(void) { if(InitShareMemory() == FAIL) { #ifdef SystemLogMessage LOG_ERROR("InitShareMemory NG"); #endif if(ShmStatusCodeData!=NULL) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.FailToCreateShareMemory=1; } sleep(5); return 0; } gunCount = ShmChargerInfo->Control.MaxConnector; acgunCount = ShmSysConfigAndInfo->SysConfig.AcConnectorCount; // Open Uart5 for RB Uart5Fd = InitComPort(); Initialization(); sleep(1); if(Uart5Fd < 0) { LOG_ERROR("(Internal) open port error."); return 0; } _RelaySelfTestOK = NO; memset(&outputRelay[0], 0x00, sizeof(Relay)); memset(&outputRelay[1], 0x00, sizeof(Relay)); if(ShmChargerInfo->Control.SysCtrl.bits.RelayBoardDisable == false) { if(ShmRelayModuleData[0]->SelfTest_Comp == NO) { if(Config_Relay_Output(Uart5Fd, Addr.DO360_RC1, &outputRelay[0]) != PASS) LOG_INFO("Config_Relay1_Output fail"); } else { if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable == false) { _RelaySelfTestOK = YES; } } if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable) { if(ShmRelayModuleData[1]->SelfTest_Comp == NO) { if(Config_Relay_Output(Uart5Fd, Addr.DO360_RC2, &outputRelay[1]) != PASS) LOG_INFO("Config_Relay2_Output fail"); } else { _RelaySelfTestOK = YES; } } } cur_led_color.Connect_1_Red = COLOR_MIN_LV; cur_led_color.Connect_1_Green = COLOR_MIN_LV; cur_led_color.Connect_1_Blue = COLOR_MIN_LV; cur_led_color.Connect_2_Red = COLOR_MIN_LV; cur_led_color.Connect_2_Green = COLOR_MIN_LV; cur_led_color.Connect_2_Blue = COLOR_MIN_LV; //bool printRelayStatus = true; for(;;) { if(!ShmChargerInfo->Control.RelayCtrl.bits.Paused) { // 程序開始之前~ 必須先確定 FW 版本與硬體版本,確認後!!~ 該模組才算是真正的 Initial Comp. if(ShmChargerInfo->Control.SysCtrl.bits.RelayBoardDisable == false) { if (ShmRelayModuleData[0]->SelfTest_Comp == NO && !ShmChargerInfo->Control.TestCtrl.bits.ChargingSimulation) { // clena fw version memset(ShmSysConfigAndInfo->SysInfo.RelayModuleFwRev, 0x00, 32); GetFwAndHwVersion_Relay(); SetRtcData_Relay(0); sleep(1); if(strlen((char *)ShmSysConfigAndInfo->SysInfo.RelayModuleFwRev)) { ShmRelayModuleData[0]->SelfTest_Comp = YES; if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable == false) { _RelaySelfTestOK = YES; } } } // DO360 RC2 if (ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable == true && ShmRelayModuleData[1]->SelfTest_Comp == NO && !ShmChargerInfo->Control.TestCtrl.bits.ChargingSimulation) { // clena fw version memset(ShmSysConfigAndInfo->SysInfo.Relay2ModuleFwRev, 0x00, 32); GetFwAndHwVersion_Relay2(); SetRtcData_Relay(1); sleep(1); if (strlen((char *)ShmSysConfigAndInfo->SysInfo.Relay2ModuleFwRev) != 0) { ShmRelayModuleData[1]->SelfTest_Comp = YES; if(ShmRelayModuleData[0]->SelfTest_Comp == YES) { _RelaySelfTestOK = YES; } } } } if(ShmChargerInfo->Control.SysCtrl.bits.FanBoardDisable == false) { if (ShmFanModuleData->SelfTest_Comp == NO && !ShmChargerInfo->Control.TestCtrl.bits.ChargingSimulation) { // clena fw version memset(ShmSysConfigAndInfo->SysInfo.FanModuleFwRev, 0x00, 32); GetFwAndHwVersion_Fan(); SetModelName_Fan(); SetRtcData_Fan(); sleep(1); GetClockTime(&_priority_time); if(strlen((char *)ShmSysConfigAndInfo->SysInfo.FanModuleFwRev) != 0) { ShmFanModuleData->SelfTest_Comp = YES; } } } if(_RelaySelfTestOK == YES || ShmChargerInfo->Control.TestCtrl.bits.ChargingSimulation) { // ==============優先權最高 10 ms ============== // 輸出電壓 GetPersentOutputVol(); // 三相輸入電壓 GetPresentInputVol(); GetRelayOutputStatus(); GetGfdAdc(); for(int i = 0; i < ShmChargerInfo->Control.MaxConnector; i++) { // Cable check (Set) CableCheckDetected(i); // check k1 k2 relay 狀態 CheckK1K2RelayOutput(i); // 依據當前各槍的狀態選擇 搭上/放開 Relay SetK1K2RelayStatus(i); if (_chargingData[i]->SystemStatus == S_IDLE) { _chargingData[i]->RelayWeldingCheck = NO; _isRelayWelding[i] = NO; } if (_chargingData[i]->SystemStatus == S_BOOTING || (_chargingData[i]->SystemStatus >= S_REASSIGN_CHECK && _chargingData[i]->SystemStatus <= S_COMPLETE) || (_chargingData[i]->SystemStatus >= S_CCS_PRECHARGE_ST0 && _chargingData[i]->SystemStatus <= S_CCS_PRECHARGE_ST1) || ShmSysConfigAndInfo->SysInfo.WaitForPlugit == YES || (ShmSysConfigAndInfo->SysInfo.PageIndex >= _LCM_AUTHORIZING && ShmSysConfigAndInfo->SysInfo.PageIndex <= _LCM_WAIT_FOR_PLUG)) { _chargingData[i]->IsReadyToCharging = YES; // 限定只有在槍類別為 GBT 的時候才做 relay welding 的判斷 // if (_chargingData[i]->Type == _Type_GB) // { // if (_chargingData[i]->SystemStatus >= S_PREPARING_FOR_EVSE && // _chargingData[i]->RelayWeldingCheck == NO) // CheckRelayWeldingStatus(i); // } // else _chargingData[i]->RelayWeldingCheck = YES; if (_chargingData[i]->SystemStatus == S_CHARGING) { // DO360 do not check under voltage output & any voltage difference //CheckOutputPowerOverCarReq(i); //CheckOutputVolNoneMatchFire(i); } else _isOutputNoneMatch[i] = NO; } else _chargingData[i]->IsReadyToCharging = NO; } // 橋接 relay SetParalleRelayStatus(); SetAcContactorStatus(); // 搭上/鬆開 Relay if(IsNoneMatchRelayStatus(0)) { if (Config_Relay_Output(Uart5Fd, Addr.DO360_RC1, &outputRelay[0])) { //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]; } } if(ShmChargerInfo->Control.SysCtrl.bits.SecondRelayBoardEnable) { // 搭上/鬆開 Relay if(IsNoneMatchRelayStatus(1)) { if (Config_Relay_Output(Uart5Fd, Addr.DO360_RC2, &outputRelay[1])) { //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(!ShmChargerInfo->Control.FanCtrl.bits.Paused) { if (ShmFanModuleData->SelfTest_Comp == YES || strlen((char *)ShmSysConfigAndInfo->SysInfo.FanModuleFwRev) != 0 || ShmSysConfigAndInfo->SysInfo.FanModuleFwRev[0] != '\0') { if (GetTimeoutValue(_priority_time) / 1000 >= 1000) { GetFanSpeedByFunction(); GetFanSpeed(); ShmSysConfigAndInfo->SysInfo.SystemFanRotaSpeed = _setFanSpeed; GetClockTime(&_priority_time); unsigned short TargetSpeed = ShmFanModuleData->TestFanSpeed; if(TargetSpeed != 0 && TargetSpeed < MIN_FAN_SPEED) { TargetSpeed = MIN_FAN_SPEED; } ShmFanModuleData->SetFan1Speed = TargetSpeed; ShmFanModuleData->SetFan2Speed = TargetSpeed; ShmFanModuleData->SetFan3Speed = TargetSpeed; ShmFanModuleData->SetFan4Speed = TargetSpeed; //LOG_INFO("set fan = %d", ShmFanModuleData->SetFan1Speed); SetFanModuleSpeed(); } } } usleep(10000); } return FAIL; }