#include "Module_PsuComm.h" #define ARRAY_SIZE(A) (sizeof(A) / sizeof(A[0])) #define PASS 1 #define FAIL -1 #define YES 1 #define NO 0 #define DERATING 30 #define ELEMENT_NOT_FIND 255 #define CHK_VOL_RANGE 50 #define CHK_CUR_RANGE 10 #define DERATING_RANGE 100 #define ZERO_CURRENT 10 // 該值須保持最小為 1A #define ZERO_VOLTAGE 50 #define STOP_CURRENT 30 #define PSU_MIN_CUR 1000 #define PRE_CHARG_STEP_CUR 30 #define PRE_CHARG_RANGE 5 #define EQUAL 0 struct SysConfigAndInfo *ShmSysConfigAndInfo; struct StatusCodeData *ShmStatusCodeData; struct PsuData *ShmPsuData; bool libInitialize = false; byte getAvailableCapOffset = 5; byte deratingKeepCount = 0; float carReqVol = 0; float carReqCur = 0; float evseOutVol = 0; float evseOutCur = 0; void PRINTF_FUNC(char *string, ...); int StoreLogMsg(const char *fmt, ...); #define DEBUG_INFO(format, args...) StoreLogMsg("[%s:%d][%s][Info] "format, __FILE__, __LINE__, __FUNCTION__, ##args) #define DEBUG_WARN(format, args...) StoreLogMsg("[%s:%d][%s][Warn] "format, __FILE__, __LINE__, __FUNCTION__, ##args) #define DEBUG_ERROR(format, args...) StoreLogMsg("[%s:%d][%s][Error] "format, __FILE__, __LINE__, __FUNCTION__, ##args) unsigned long GetTimeoutValue(struct timeval _sour_time); unsigned long GetTimeoutValue(struct timeval _sour_time) { struct timeval _end_time; gettimeofday(&_end_time, NULL); return 1000000 * (_end_time.tv_sec - _sour_time.tv_sec) + _end_time.tv_usec - _sour_time.tv_usec; } int StoreLogMsg(const char *fmt, ...) { char Buf[4096+256]; char buffer[4096]; va_list args; struct timeb SeqEndTime; struct tm *tm; va_start(args, fmt); int rc = vsnprintf(buffer, sizeof(buffer), fmt, args); va_end(args); memset(Buf,0,sizeof(Buf)); ftime(&SeqEndTime); SeqEndTime.time = time(NULL); tm=localtime(&SeqEndTime.time); sprintf(Buf,"echo \"%04d-%02d-%02d %02d:%02d:%02d.%03d - %s\" >> /Storage/SystemLog/[%04d.%02d]SystemLog", tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,SeqEndTime.millitm, buffer, tm->tm_year+1900,tm->tm_mon+1); system(Buf); return rc; } void PRINTF_FUNC(char *string, ...) { va_list args; char buffer[4096]; va_start(args, string); vsnprintf(buffer, sizeof(buffer), string, args); va_end(args); if (ShmSysConfigAndInfo->SysConfig.SwitchDebugFlag == YES) printf("%s \n", buffer); else DEBUG_INFO("%s \n", buffer); } //================================= // Common routine //================================= size_t FindIndex(const int a[], size_t size, int value, byte group) { size_t index = 0; while ( index < size && a[index] != value ) ++index; return (index == size ? ELEMENT_NOT_FIND : group); } byte FindTargetGroup(byte address) { byte _group = ELEMENT_NOT_FIND; if (ShmPsuData->GroupCount == 1) _group = 0; else { _group = FindIndex(connector_1, ShmPsuData->PsuGroup[0].GroupPresentPsuQuantity, address, 0); if (_group == ELEMENT_NOT_FIND) _group = FindIndex(connector_2, ShmPsuData->PsuGroup[1].GroupPresentPsuQuantity, address, 1); } return _group; } bool IsOverModuleCount(byte count) { bool result = false; if (count >= ShmPsuData->SystemPresentPsuQuantity) result = true; return result; } //================================= // Save data to share memory Function //================================= 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; } } return false; } //================================= // Alarm code mapping to share memory Function //================================= // 檢查 Byte 中某個 Bit 的值 // _byte : 欲改變的 byte // _bit : 該 byte 的第幾個 bit unsigned char mask_table[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; unsigned char DetectBitValue(unsigned char _byte, unsigned char _bit) { return ( _byte & mask_table[_bit] ) != 0x00; } void AbnormalStopAnalysis(byte gun_index, int errCode) { for (char i = 0; i < 3; i++) { unsigned char byteIndex = (errCode >> (8 * i)) & 0xff; for (char bitIndex = 0; bitIndex < 8; bitIndex++) { if(DetectBitValue(byteIndex , bitIndex) == 1) { switch(byteIndex) { case 0: { if (bitIndex == 0) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuOutputShortCircuit = YES; else if (bitIndex == 5) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = YES; } break; case 1: { if (bitIndex == 1) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFailureAlarm = YES; else if (bitIndex == 2) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuProtectionAlarm = YES; else if (bitIndex == 3) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFanFailureAlarm = YES; else if (bitIndex == 4) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuCriticalPointOTP = YES; else if (bitIndex == 5) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = YES; } break; case 2: { if (bitIndex == 0) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuPowerLimitedState = YES; else if (bitIndex == 1) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDuplicateID = YES; else if (bitIndex == 2) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseOnputImbalance = YES; else if (bitIndex == 3) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseInputInadequate = YES; else if (bitIndex == 4) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseInputInadequate = YES; else if (bitIndex == 5) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputUVP = YES; else if (bitIndex == 6) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputOVP = YES; } break; } } // else // { // switch (byteIndex) { // case 0: { // if (bitIndex == 0) // ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuOutputShortCircuit = NO; // else if (bitIndex == 5) // ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = NO; // } // break; // case 1: { // if (bitIndex == 1) // ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFailureAlarm = NO; // else if (bitIndex == 2) // ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuProtectionAlarm = NO; // else if (bitIndex == 3) // ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFanFailureAlarm = NO; // else if (bitIndex == 4) // ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuCriticalPointOTP = NO; // else if (bitIndex == 5) // ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = NO; // } // break; // case 2: { // if (bitIndex == 1) // ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDuplicateID = NO; // if (bitIndex == 2) // ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseOnputImbalance = NO; // else if (bitIndex == 3) // ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseInputInadequate = NO; // else if (bitIndex == 4) // ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseInputInadequate = NO; // else if (bitIndex == 5) // ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputUVP = NO; // else if (bitIndex == 6) // ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputOVP = NO; // } // break; // } // } } } } //================================= // Callback Function //================================= void GetStatusCallback(byte group, byte address, byte temp, int alarm) { if (IsOverModuleCount(address)) return; byte group1 = FindTargetGroup(address); if (group1 == 1) address -= ShmPsuData->PsuGroup[group1 - 1].GroupPresentPsuQuantity; ShmPsuData->PsuGroup[group1].PsuModule[address].CriticalTemp1 = temp; ShmPsuData->PsuGroup[group1].PsuModule[address].CriticalTemp2 = temp; ShmPsuData->PsuGroup[group1].PsuModule[address].CriticalTemp3 = temp; ShmPsuData->PsuGroup[group1].PsuModule[address].ExletTemp = temp; ShmPsuData->PsuGroup[group1].PsuModule[address].AlarmCode = alarm; AbnormalStopAnalysis(group1, alarm); //printf("alarm = %d \n", alarm); } void GetModuleCountCallback(byte group, byte count) { if (group == SYSTEM_CMD) ShmPsuData->SystemPresentPsuQuantity = count; else { ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity = count; } } void GetMaxPowerAndCur(unsigned char mode, int ratingCur, int *pow, int *cur) { unsigned short maxCurrent = ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent * 10; unsigned short maxPower = ShmSysConfigAndInfo->SysConfig.MaxChargingPower * 10; if (mode == _MAIN_CHARGING_MODE_AVER) { maxCurrent /= 2; maxPower /= 2; } if (maxPower != 0 && maxPower <= *pow) *pow = maxPower; if (maxCurrent != 0 && maxCurrent <= *cur) *cur = maxCurrent; if (ratingCur != 0 && ratingCur <= *cur) *cur = ratingCur; } void GetAvailableCapCallback(byte address, short maxVol, short minVol, short maxCur, short totalPow) { int _groupPower = 0, _groupCurrent = 0; byte group = FindTargetGroup(address); if (group == 1) address -= ShmPsuData->PsuGroup[group - 1].GroupPresentPsuQuantity; if (chargingInfo[group]->DeratingChargingCurrent == 0) ShmPsuData->PsuGroup[group].PsuModule[address].AvailableCurrent = PSU_MIN_CUR; else ShmPsuData->PsuGroup[group].PsuModule[address].AvailableCurrent = maxCur; ShmPsuData->PsuGroup[group].PsuModule[address].AvailablePower = totalPow; // 總和該 Group 的可輸出電流 for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { _groupCurrent += ShmPsuData->PsuGroup[group].PsuModule[index].AvailableCurrent; _groupPower += ShmPsuData->PsuGroup[group].PsuModule[index].AvailablePower; } // 各群得到最大輸出能力 (電流、Power) ShmPsuData->PsuGroup[group].GroupAvailableCurrent = _groupCurrent; ShmPsuData->PsuGroup[group].GroupAvailablePower = _groupPower; chargingInfo[group]->MaximumChargingVoltage = maxVol; int _power = 0, _current = 0, _ratingcurrent = 0; bool isGetAllDeratingCurrent = true; for (byte index = 0; index < ShmPsuData->GroupCount; index++) { _power += ShmPsuData->PsuGroup[index].GroupAvailablePower; _current += ShmPsuData->PsuGroup[index].GroupAvailableCurrent; _ratingcurrent += chargingInfo[index]->DeratingChargingCurrent; if (chargingInfo[index]->DeratingChargingCurrent == 0) isGetAllDeratingCurrent = false; } // 如果不是所有群都得到 Derating current,則先不採樣該次的 ratingCurrent if (!isGetAllDeratingCurrent) _ratingcurrent = 0; ShmPsuData->SystemAvailableCurrent = _current; ShmPsuData->SystemAvailablePower = _power; if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER || (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_GET_NEW_CAP && ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A)) { int halfPow = ShmPsuData->PsuGroup[group].GroupAvailablePower; int halfCur = ShmPsuData->PsuGroup[group].GroupAvailableCurrent; int ratingCur = chargingInfo[group]->DeratingChargingCurrent; GetMaxPowerAndCur(_MAIN_CHARGING_MODE_AVER, ratingCur, &halfPow, &halfCur); // if ((ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_GET_NEW_CAP && // ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A)) // { // chargingInfo[group]->AvailableChargingCurrent = DERATING_RANGE; // chargingInfo[group]->AvailableChargingPower = ShmPsuData->PsuGroup[group].GroupAvailablePower; // } // else { // 以下狀況 -> 槍資訊中的最大輸出能力,為該群的輸出能力 // 1. 如不是最大充 // 2. 智能切換成均充過程 chargingInfo[group]->AvailableChargingCurrent = halfCur; chargingInfo[group]->AvailableChargingPower = halfPow; } } else if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX) { GetMaxPowerAndCur(_MAIN_CHARGING_MODE_MAX, _ratingcurrent, &_power, &_current); if (ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf == YES) { for (byte count = 0; count < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; count++) { chargingInfo[count]->MaximumChargingVoltage = maxVol; chargingInfo[count]->AvailableChargingCurrent = _current; chargingInfo[count]->AvailableChargingPower = _power; } } else { // 如果是最大充,該槍資訊中的輸出能力為各群輸出能力的和 chargingInfo[group]->AvailableChargingCurrent = _current; chargingInfo[group]->AvailableChargingPower = _power; } } } void GetFwCallback(byte address, short dcSwVer, short pfcSwVer, short hwVer) { if (IsOverModuleCount(address)) return; byte group = FindTargetGroup(address); sprintf((char *)ShmPsuData->PsuVersion[address].FwPrimaryVersion, "DC %d.%02d", (dcSwVer & 0xFF00) >> 8, dcSwVer & 0xFF); sprintf((char *)ShmPsuData->PsuVersion[address].FwSecondVersion, "PFC %d.%02d", (pfcSwVer & 0xFF00) >> 8, pfcSwVer & 0xFF); if (group == 1) address -= ShmPsuData->PsuGroup[group - 1].GroupPresentPsuQuantity; sprintf((char *)ShmPsuData->PsuGroup[group].PsuModule[address].FwVersion, "DC %d.%02d", (dcSwVer & 0xFF00) >> 8, dcSwVer & 0xFF); //DEBUG_INFO("fw Ver. = %s \n", ShmPsuData->PsuGroup[group].PsuModule[address].FwVersion); } void GetInputVoltageCallback(byte address, unsigned short vol1, unsigned short vol2, unsigned short vol3) { if (IsOverModuleCount(address)) return; byte group = FindTargetGroup(address); if (group == 1) address -= ShmPsuData->PsuGroup[group - 1].GroupPresentPsuQuantity; ShmPsuData->PsuGroup[group].PsuModule[address].InputVoltageL1 = vol1; ShmPsuData->PsuGroup[group].PsuModule[address].InputVoltageL2 = vol2; ShmPsuData->PsuGroup[group].PsuModule[address].InputVoltageL3 = vol3; } void GetPresentOutputCallback(byte group, unsigned short outVol, unsigned short outCur) { unsigned short outputVol = outVol; unsigned short outputCur = outCur; // PSU Group - 電壓 ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage = outputVol; // PSU Group - 電流 ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent = outputCur; if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX || (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER && (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_WAITING && ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_COMP)) ) { outputVol = 0; outputCur = 0; for (byte index = 0; index < ShmPsuData->GroupCount; index++) { if (ShmPsuData->PsuGroup[index].GroupPresentOutputVoltage > outputVol) outputVol = ShmPsuData->PsuGroup[index].GroupPresentOutputVoltage; outputCur += ShmPsuData->PsuGroup[index].GroupPresentOutputCurrent; } // 黑白機 if (ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf == YES) { for (byte count = 0; count < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; count++) { float _vol_buf = outputVol; float _cur_buf = outputCur; // EVSE - 電壓 _vol_buf /= 10; chargingInfo[count]->PresentChargingVoltage = _vol_buf; // EVSE - 電流 _cur_buf /= 10; chargingInfo[count]->PresentChargingCurrent = _cur_buf; } } if ((chargingInfo[group]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[group]->SystemStatus <= S_COMPLETE) || (chargingInfo[group]->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingInfo[group]->SystemStatus <= S_CCS_PRECHARGE_ST1)) { float _vol_buf = outputVol; float _cur_buf = outputCur; // EVSE - 電壓 _vol_buf /= 10; chargingInfo[group]->PresentChargingVoltage = _vol_buf; // EVSE - 電流 _cur_buf /= 10; chargingInfo[group]->PresentChargingCurrent = _cur_buf; } } else { float _vol_buf = ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage; float _cur_buf = ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent; // EVSE - 電壓 _vol_buf /= 10; chargingInfo[group]->PresentChargingVoltage = _vol_buf; // EVSE - 電流 _cur_buf /= 10; chargingInfo[group]->PresentChargingCurrent = _cur_buf; } // PRINTF_FUNC("Gun_%d, PresentChargingCurrent = %f \n", group, // chargingInfo[group]->PresentChargingCurrent); } void GetFanSpeedCallback(byte address, unsigned int fanSpeed) { if (IsOverModuleCount(address)) return; byte group = FindTargetGroup(address); if (group == 1) address -= ShmPsuData->PsuGroup[group - 1].GroupPresentPsuQuantity; ShmPsuData->PsuGroup[group].PsuModule[address].FanSpeed_1 = fanSpeed; ShmPsuData->PsuGroup[group].PsuModule[address].FanSpeed_2 = fanSpeed; ShmPsuData->PsuGroup[group].PsuModule[address].FanSpeed_3 = fanSpeed; ShmPsuData->PsuGroup[group].PsuModule[address].FanSpeed_4 = fanSpeed; } void GetIavailableCallback(byte address, unsigned short Iavail, unsigned short Vext) { if (IsOverModuleCount(address)) return; //PRINTF_FUNC("address = %d, Iavail = %d \n", address, Iavail); byte group = FindTargetGroup(address); if (group == 1) address -= ShmPsuData->PsuGroup[group - 1].GroupPresentPsuQuantity; //PRINTF_FUNC("group = %d, address_%d, Iavail = %d \n", group, address, Iavail); ShmPsuData->PsuGroup[group].PsuModule[address].IAvailableCurrent = Iavail; bool isPass = true; int totalCur = 0; if (Iavail == 0) { for (byte count = 0; count < 2; count++) { chargingInfo[group]->SampleChargingCur[count] = Iavail; } } else { // 該群的可輸出電流 for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { totalCur += ShmPsuData->PsuGroup[group].PsuModule[index].IAvailableCurrent; } for (byte count = 0; count < 2; count++) { if (chargingInfo[group]->SampleChargingCur[count] == 0) { chargingInfo[group]->SampleChargingCur[count] = totalCur; return; } else { if (chargingInfo[group]->SampleChargingCur[count] != totalCur) { chargingInfo[group]->SampleChargingCur[count] = totalCur; isPass = false; break; } } } } if (isPass) { //PRINTF_FUNC("rating pass value = %d \n", totalCur); chargingInfo[group]->DeratingChargingCurrent = totalCur; } } //========================================== // Init all share memory //========================================== int InitShareMemory() { int result = PASS; int MeterSMId; //creat ShmSysConfigAndInfo if ((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo), 0777)) < 0) { #ifdef SystemLogMessage DEBUG_ERROR("shmget ShmSysConfigAndInfo NG %d \n"); #endif result = FAIL; } else if ((ShmSysConfigAndInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1) { #ifdef SystemLogMessage DEBUG_ERROR("shmat ShmSysConfigAndInfo NG \n"); #endif 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 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)); return result; } //================================================ // Main process //================================================ void InitialPsuData() { ShmPsuData->SystemPresentPsuQuantity = 0; for (byte _groupCount = 0; _groupCount < ARRAY_SIZE(ShmPsuData->PsuGroup); _groupCount++) { ShmPsuData->PsuGroup[_groupCount].GroupPresentPsuQuantity = 0; ShmPsuData->PsuGroup[_groupCount].GroupAvailablePower = 0; ShmPsuData->PsuGroup[_groupCount].GroupAvailableCurrent = 0; } ShmPsuData->Work_Step = _INIT_PSU_STATUS; } void Initialization() { bool isPass = false; while(!isPass) { isPass = true; for (byte _index = 0; _index < _gunCount; _index++) { if (!FindChargingInfoData(_index, &chargingInfo[0])) { DEBUG_ERROR("Module_PsuComm : FindChargingInfoData false \n"); isPass = false; break; } } } if (ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf == YES) ShmPsuData->GroupCount = 1; else ShmPsuData->GroupCount = _gunCount; char EvsePower[2]; EvsePower[2] = '\0'; char count = 0; byte psuTarIndex = 0; // 解析 ModelName 取得各槍各有幾個 PSU 及編號 if (strlen((char *) ShmSysConfigAndInfo->SysConfig.ModelName) >= 6) { strncpy(EvsePower, (char *)(ShmSysConfigAndInfo->SysConfig.ModelName + 4), 2); if (strcmp(EvsePower, "15") == EQUAL) count = 5; else if (strcmp(EvsePower, "30") == EQUAL) count = 1; else if (strcmp(EvsePower, "60") == EQUAL) count = 2; else if (strcmp(EvsePower, "18") == EQUAL) count = 6; else if (strcmp(EvsePower, "36") == EQUAL) count = 12; if (count > 0) { if (ShmPsuData->GroupCount == 1) conn_1_count = count; else if (ShmPsuData->GroupCount == 2) { if(count % 2 > 0) conn_1_count = (count / 2) + 1; else conn_1_count = (count / 2); conn_2_count = count - conn_1_count; } for(byte psuIndex = 0; psuIndex < conn_1_count; psuIndex++) { connector_1[psuIndex] = psuTarIndex; psuTarIndex++; } for(byte psuIndex = 0; psuIndex < conn_2_count; psuIndex++) { connector_2[psuIndex] = psuTarIndex; psuTarIndex++; } for(byte psuIndex = 0; psuIndex < conn_1_count; psuIndex++) PRINTF_FUNC("Connector 1 - Number = %d \n", connector_1[psuIndex]); for(byte psuIndex = 0; psuIndex < conn_2_count; psuIndex++) PRINTF_FUNC("Connector 2 - Number = %d \n", connector_2[psuIndex]); } else DEBUG_ERROR("Module_PsuComm : Can't parsing model name. \n"); } } void CheckSmartChargingStep(bool isWaitingAver, bool isCharging) { if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_PREPARE_M_TO_A) { if (isWaitingAver) { if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX) { PRINTF_FUNC("=============Smart Charging : _REASSIGNED_GET_NEW_CAP============= Step 2 \n"); ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_GET_NEW_CAP; } else { PRINTF_FUNC("=============Smart Charging : _REASSIGNED_NONE============= Step 0 \n"); ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_NONE; } } } else if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_PREPARE_A_TO_M) { if (isCharging) { if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER) { PRINTF_FUNC("=============Smart Charging : _REASSIGNED_ADJUST_A_TO_M============= Step 12 \n"); ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_ADJUST_A_TO_M; } else { PRINTF_FUNC("=============Smart Charging_1 : _REASSIGNED_COMP============= Step 15 \n"); ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_COMP; } } else { PRINTF_FUNC("=============Smart Charging_2 : _REASSIGNED_COMP============= Step 15 \n"); ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_COMP; } } } int main(void) { if(InitShareMemory() == FAIL) { #ifdef SystemLogMessage DEBUG_ERROR("InitShareMemory NG\n"); #endif if(ShmStatusCodeData != NULL) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.FailToCreateShareMemory = 1; } sleep(5); return 0; } PRINTF_FUNC("InitShareMemory OK\n"); // register callback function RefreshStatus(&GetStatusCallback); RefreshModuleCount(&GetModuleCountCallback); RefreshAvailableCap(&GetAvailableCapCallback); RefreshFwVersion(&GetFwCallback); RefreshInputVol(&GetInputVoltageCallback); RefreshGetOutput(&GetPresentOutputCallback); RefreshFanInfo(&GetFanSpeedCallback); RefreshIavailable(&GetIavailableCallback); sleep(2); _gunCount = ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; // initial object InitialPsuData(); Initialization(); libInitialize = InitialCommunication(); byte isInitialComp = NO; PRINTF_FUNC("ALTERNATIVE_CONG = %d \n", ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf); //main loop while (libInitialize) { // 斷電狀態 if (ShmSysConfigAndInfo->SysInfo.AcContactorStatus == NO) { //一但 AC Off PSU 斷電全部的 PSU Group ID 會全部清 0 if (!isInitialComp) { InitialPsuData(); ShmPsuData->Work_Step = INITIAL_START; isInitialComp = YES; } sleep(1); continue; } else isInitialComp = NO; // 自檢失敗 if (ShmPsuData->Work_Step == _NO_WORKING) { PRINTF_FUNC("== PSU == self test fail. \n"); sleep(5); } switch(ShmPsuData->Work_Step) { case INITIAL_START: { PRINTF_FUNC("== PSU == INITIAL_START \n"); gettimeofday(&_cmdSubPriority_time, NULL); sleep(5); SwitchPower(SYSTEM_CMD, PSU_POWER_OFF); ShmPsuData->Work_Step = GET_PSU_COUNT; } break; case GET_PSU_COUNT: { int time = GetTimeoutValue(_cmdSubPriority_time) / 1000; byte moduleCount = 0; if (time > 2000) { PRINTF_FUNC("== PSU == indexCount = %d, moduleCount = %d, sysCount = %d\n", ShmPsuData->GroupCount, moduleCount, ShmPsuData->SystemPresentPsuQuantity); // if (ShmPsuData->GroupCount == 0) // ShmPsuData->GroupCount = ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; // 分別取各群模組數量 for (byte index = 0; index < ShmPsuData->GroupCount; index++) { // 總和各群模組數量 moduleCount += ShmPsuData->PsuGroup[index].GroupPresentPsuQuantity; // 取各群模組數量 GetModuleCount(index); // 取版號 GetModuleVer(index); } // 發送取得目前全部模組數量 GetModuleCount(SYSTEM_CMD); // 判斷系統數量與各群數量一致 if(moduleCount == ShmPsuData->SystemPresentPsuQuantity && moduleCount > 0) { PRINTF_FUNC("Psu Count = %d \n", moduleCount); if (ShmSysConfigAndInfo->SysInfo.BootingStatus == BOOTTING) { // 電樁在 Booting 的狀態 - 自檢 PRINTF_FUNC("== PSU == GET_SYS_CAP \n"); ShmPsuData->Work_Step = GET_SYS_CAP; } else { PRINTF_FUNC("== PSU == _WORK_CHARGING \n"); ShmPsuData->Work_Step = _WORK_CHARGING; //sdlu test gettimeofday(&_test_time, NULL); } } _getCapDelayCount = 3; gettimeofday(&_cmdSubPriority_time, NULL); } } break; case GET_SYS_CAP: { int time = GetTimeoutValue(_cmdSubPriority_time) / 1000; if (time > 1000) { for (byte index = 0; index < ShmPsuData->GroupCount; index++) { // Pooling Status GetStatus(index); // 取系統總輸出能力 GetModuleCap(index); } _getCapDelayCount--; gettimeofday(&_cmdSubPriority_time, NULL); } // 判斷系統輸出額定功率與電流 if (ShmPsuData->SystemAvailablePower > 0 && ShmPsuData->SystemAvailableCurrent > 0 && _getCapDelayCount <= 0) { PRINTF_FUNC("SystemAvailableCurrent = %d, SystemAvailablePower = %d \n", ShmPsuData->SystemAvailableCurrent, ShmPsuData->SystemAvailablePower); PRINTF_FUNC("== PSU == BOOTING_COMPLETE \n"); ShmPsuData->Work_Step = BOOTING_COMPLETE; } } break; case BOOTING_COMPLETE: { bool isSelfTestPass = true; for (byte groupIndex = 0; groupIndex < _gunCount; groupIndex++) { if (chargingInfo[groupIndex]->SystemStatus == S_BOOTING) { isSelfTestPass = false; } } if (isSelfTestPass) ShmPsuData->Work_Step = _WORK_CHARGING; sleep(1); } break; case _WORK_CHARGING: { int time = GetTimeoutValue(_cmdSubPriority_time) / 1000; // 低 Priority 的指令 if (time > 1500) { isCharging = false; isWaitingAver = false; isReadToCharging = false; for (byte index = 0; index < ShmPsuData->GroupCount; index++) { // Pooling Status GetStatus(index); // 取系統總輸出能力 GetModuleCap(index); // 取得模塊輸入電壓 GetModuleInput(index); // 取得模塊輸出額定電流能力 GetModuleIavailable(index); if (chargingInfo[index]->SystemStatus == S_CHARGING) { isCharging = true; if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_PREPARE_M_TO_A) { if (toAverVolPoint > 0 && toAverVolPoint == chargingInfo[index]->EvBatterytargetCurrent) { // 欲最大充 -> 均充需要等待充電中的輸出電流拉高到目標電流 if ((chargingInfo[index]->PresentChargingCurrent * 10) >= chargingInfo[index]->EvBatterytargetCurrent - CHK_CUR_RANGE) { if (toAverVolCount == 0) isWaitingAver = true; else toAverVolCount--; } } else { toAverVolPoint = chargingInfo[index]->EvBatterytargetCurrent; toAverVolCount = 3; } } else { toAverVolPoint = 0; toAverVolCount = 3; } } if ((chargingInfo[index]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[index]->SystemStatus <= S_CHARGING) || (chargingInfo[index]->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingInfo[index]->SystemStatus <= S_CCS_PRECHARGE_ST1)) { isReadToCharging = true; } } gettimeofday(&_cmdSubPriority_time, NULL); CheckSmartChargingStep(isWaitingAver, isCharging); } for (byte groupIndex = 0; groupIndex < _gunCount; groupIndex++) { GetModuleOutput(groupIndex); // 針對各槍當前狀態,傳送需要回傳的資料指令 if (((chargingInfo[groupIndex]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[groupIndex]->SystemStatus <= S_CHARGING) && chargingInfo[groupIndex]->RelayK1K2Status) || (chargingInfo[groupIndex]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[groupIndex]->SystemStatus <= S_CHARGING && chargingInfo[groupIndex]->Type == _Type_GB) || (chargingInfo[groupIndex]->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingInfo[groupIndex]->SystemStatus <= S_CCS_PRECHARGE_ST1)) { if (chargingInfo[groupIndex]->EvBatterytargetVoltage > 0 && carReqVol != chargingInfo[groupIndex]->EvBatterytargetVoltage) { carReqVol = chargingInfo[groupIndex]->EvBatterytargetVoltage; DEBUG_INFO("ev need vol = %f \n", chargingInfo[groupIndex]->EvBatterytargetVoltage); } if (chargingInfo[groupIndex]->EvBatterytargetCurrent > 0 && carReqCur != chargingInfo[groupIndex]->EvBatterytargetCurrent) { carReqCur = chargingInfo[groupIndex]->EvBatterytargetCurrent; DEBUG_INFO("ev need cur = %f \n", chargingInfo[groupIndex]->EvBatterytargetCurrent); } if (time > 1500) { if (chargingInfo[groupIndex]->FireChargingVoltage > 0 && evseOutVol != (chargingInfo[groupIndex]->FireChargingVoltage / 10)) { evseOutVol = (chargingInfo[groupIndex]->FireChargingVoltage / 10); PRINTF_FUNC("groupIndex = %d, evse output vol = %f \n", groupIndex, chargingInfo[groupIndex]->FireChargingVoltage); } if ((chargingInfo[groupIndex]->PresentChargingCurrent * 10) > 0 && evseOutCur != (chargingInfo[groupIndex]->PresentChargingCurrent * 10)) { evseOutCur = (chargingInfo[groupIndex]->PresentChargingCurrent * 10); PRINTF_FUNC("groupIndex = %d, evse output cur = %f \n", groupIndex, (chargingInfo[groupIndex]->PresentChargingCurrent * 10)); } } if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX) { // PRINTF_FUNC("index = %d, SystemStatus = %d, Ev = %f, curCur = %f \n", groupIndex, // chargingInfo[groupIndex]->SystemStatus, chargingInfo[groupIndex]->EvBatterytargetCurrent, // (chargingInfo[groupIndex]->PresentChargingCurrent * 10)); // 智能判斷 Start ----------------------------------------------------------- if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_GET_NEW_CAP) { if (ShmPsuData->SystemAvailableCurrent != chargingInfo[groupIndex]->AvailableChargingCurrent) { // 車端要求電流為該充電槍的額定輸出電流的範圍內 if (chargingInfo[groupIndex]->EvBatterytargetCurrent <= chargingInfo[groupIndex]->AvailableChargingCurrent || deratingKeepCount >= DERATING) { // 車端降載完成 PRINTF_FUNC("=============Smart Charging : _REASSIGNED_ADJUST_M_TO_A============= Step 3 \n"); ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_ADJUST_M_TO_A; gettimeofday(&_derating_time, NULL); deratingKeepCount = 0; } else { deratingKeepCount++; } } } else if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_ADJUST_M_TO_A) { bool isChanged = false; // 需求電流不降低的情況下 -> 依然要切 if (chargingInfo[groupIndex]->AvailableChargingCurrent < chargingInfo[groupIndex]->EvBatterytargetCurrent) { PRINTF_FUNC("** _REASSIGNED_ADJUST_M_TO_A ** Gun_%d, AvailableChargingCurrent = %f, EvBatterytargetCurrent = %f \n", groupIndex, (chargingInfo[groupIndex]->PresentChargingCurrent * 10), chargingInfo[groupIndex]->AvailableChargingCurrent); for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++) { if (chargingInfo[subIndex]->SystemStatus == S_REASSIGN) { if ((ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent) <= CHK_CUR_RANGE) isChanged = true; break; } } // 這狀況下輸出端的電流載滿載衝的狀況下,並不會降電流 // 所以只能拉載到該槍端的最大輸出能力 // if ((chargingInfo[groupIndex]->PresentChargingCurrent * 10) >= chargingInfo[groupIndex]->AvailableChargingCurrent - CHK_CUR_RANGE || // (chargingInfo[groupIndex]->PresentChargingCurrent * 10) <= CHK_CUR_RANGE) // { // isChanged = true; // } } else if (((chargingInfo[groupIndex]->PresentChargingCurrent * 10) >= ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent - CHK_CUR_RANGE) && ((chargingInfo[groupIndex]->PresentChargingCurrent * 10) <= ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent + CHK_CUR_RANGE)) { for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++) { if (chargingInfo[subIndex]->SystemStatus == S_REASSIGN) { if ((ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent) <= CHK_CUR_RANGE) isChanged = true; break; } } } if (isChanged) { PRINTF_FUNC("** _REASSIGNED_ADJUST_M_TO_A ** Gun_%d, PresentChargingCurrent = %f, GroupPresentOutputCurrent = %d \n", groupIndex, (chargingInfo[groupIndex]->PresentChargingCurrent * 10), ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent); // 輸出端與車端要求電流接近 PRINTF_FUNC("=============Smart Charging : _REASSIGNED_RELAY_M_TO_A============= Step 4 \n"); ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_RELAY_M_TO_A; } } if (ShmPsuData->SystemAvailablePower > 0) { // 調整輸出電流 : 漸進調整方式 if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_ADJUST_M_TO_A) { // 當前充電中的目標電壓 float targetVol = chargingInfo[groupIndex]->EvBatterytargetVoltage; // 當前充電中的目標電流 //float targetCur = 0; // 準備切出去的模塊電流 float deratingCur = 0; byte reassignIndex = ELEMENT_NOT_FIND; // 找到等待分配的槍 for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++) { if (chargingInfo[subIndex]->SystemStatus == S_REASSIGN) { reassignIndex = subIndex; } } if (reassignIndex != ELEMENT_NOT_FIND) { //int derating = GetTimeoutValue(_derating_time) / 1000; //if (derating > 1000) { if (ShmPsuData->PsuGroup[reassignIndex].GroupPresentOutputCurrent > 0) { deratingCur = ShmPsuData->PsuGroup[reassignIndex].GroupPresentOutputCurrent - DERATING_RANGE; if (deratingCur <= CHK_CUR_RANGE) deratingCur = CHK_CUR_RANGE; PresentOutputVol(reassignIndex, targetVol, deratingCur); gettimeofday(&_derating_time, NULL); } } // ***********直接降低要移除的模塊電流即可************* // 因為爬的速度沒有降的速度快,所以採兩倍速度爬升 // targetCur = ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent + (DERATING_RANGE * 2); // if (targetCur >= chargingInfo[groupIndex]->EvBatterytargetCurrent) // targetCur = chargingInfo[groupIndex]->EvBatterytargetCurrent; if (targetVol == 0) { SwitchPower(SYSTEM_CMD, PSU_POWER_OFF); FlashLed(SYSTEM_CMD, PSU_FLASH_NORMAL); } else { SwitchPower(SYSTEM_CMD, PSU_POWER_ON); FlashLed(SYSTEM_CMD, PSU_FLASH_ON); } } } else { // 該充電槍的目標電壓與目標電流 PresentOutputVol(SYSTEM_CMD, chargingInfo[groupIndex]->EvBatterytargetVoltage, chargingInfo[groupIndex]->EvBatterytargetCurrent); if (chargingInfo[groupIndex]->EvBatterytargetVoltage == 0) { SwitchPower(SYSTEM_CMD, PSU_POWER_OFF); FlashLed(SYSTEM_CMD, PSU_FLASH_NORMAL); } else { SwitchPower(SYSTEM_CMD, PSU_POWER_ON); FlashLed(SYSTEM_CMD, PSU_FLASH_ON); } } } } else if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER) { // 智能判斷 Start ----------------------------------------------------------- if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_ADJUST_A_TO_M) { bool balanceVol = true; for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++) { if (chargingInfo[subIndex]->SystemStatus == S_IDLE || chargingInfo[subIndex]->SystemStatus == S_RESERVATION) { // 各群電壓接近平衡 if (((chargingInfo[subIndex]->PresentChargingVoltage * 10) < (chargingInfo[groupIndex]->PresentChargingVoltage * 10) - ZERO_VOLTAGE) || ((chargingInfo[subIndex]->PresentChargingVoltage * 10) < chargingInfo[groupIndex]->EvBatterytargetVoltage - CHK_VOL_RANGE)) { PRINTF_FUNC("** _REASSIGNED_ADJUST_A_TO_M ** Gun_%d, PresentChargingVoltage = %f, PresentChargingVoltage_V = %f, EvBatterytargetVoltage = %f \n", subIndex, (chargingInfo[subIndex]->PresentChargingVoltage * 10), ((chargingInfo[groupIndex]->PresentChargingVoltage * 10) - ZERO_VOLTAGE), (chargingInfo[groupIndex]->EvBatterytargetVoltage - CHK_VOL_RANGE)); balanceVol = false; } break; } } if (balanceVol) { // 閒置端與車端要求電壓接近 PRINTF_FUNC("=============Smart Charging : _REASSIGNED_RELAY_A_TO_M============= Step 13 \n"); preChargingCur = preChargingTarget = 0; ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_RELAY_A_TO_M; } } else if(ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_WAITING) { int idleCurrent = 0; int chargingCurrent = 0; for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++) { if (chargingInfo[subIndex]->SystemStatus == S_IDLE || chargingInfo[subIndex]->SystemStatus == S_RESERVATION || chargingInfo[subIndex]->SystemStatus == S_REASSIGN_CHECK) idleCurrent = ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent; else chargingCurrent = ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent; } if (idleCurrent >= chargingCurrent - PRE_CHARG_RANGE) { PRINTF_FUNC("=============Smart Charging_0 : _REASSIGNED_COMP============= Step 15 \n"); ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_COMP; } } if (chargingInfo[groupIndex]->AvailableChargingCurrent > 0) { if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_ADJUST_A_TO_M) { for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++) { if (chargingInfo[subIndex]->SystemStatus == S_IDLE || chargingInfo[subIndex]->SystemStatus == S_RESERVATION || chargingInfo[subIndex]->SystemStatus == S_REASSIGN_CHECK) { // 閒置模塊升壓,另對剛分配近來的模塊,預上升電流值 (preChargingCur) PresentOutputVol(subIndex, chargingInfo[groupIndex]->EvBatterytargetVoltage, ZERO_CURRENT + preChargingTarget); preChargingCur = ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent; } else { PRINTF_FUNC("CurOutputCurrent = %d \n", ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent + preChargingCur); // 充電中的模塊維持輸出 PresentOutputVol(subIndex, chargingInfo[subIndex]->EvBatterytargetVoltage, chargingInfo[subIndex]->EvBatterytargetCurrent - preChargingCur); if ((ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_WAITING) && (preChargingCur >= preChargingTarget - ZERO_CURRENT)) preChargingTarget += PRE_CHARG_STEP_CUR; if (preChargingTarget >= chargingInfo[subIndex]->EvBatterytargetCurrent / 2) preChargingTarget = chargingInfo[subIndex]->EvBatterytargetCurrent / 2; } if (chargingInfo[groupIndex]->EvBatterytargetVoltage == 0) { SwitchPower(subIndex, PSU_POWER_OFF); FlashLed(subIndex, PSU_FLASH_NORMAL); } else { SwitchPower(subIndex, PSU_POWER_ON); FlashLed(subIndex, PSU_FLASH_ON); } } } else { PresentOutputVol(groupIndex, chargingInfo[groupIndex]->EvBatterytargetVoltage, chargingInfo[groupIndex]->EvBatterytargetCurrent); if (chargingInfo[groupIndex]->EvBatterytargetVoltage == 0) { SwitchPower(groupIndex, PSU_POWER_OFF); FlashLed(groupIndex, PSU_FLASH_NORMAL); } else { SwitchPower(groupIndex, PSU_POWER_ON); FlashLed(groupIndex, PSU_FLASH_ON); } } } } } else if (chargingInfo[groupIndex]->SystemStatus >= S_TERMINATING && chargingInfo[groupIndex]->SystemStatus <= S_COMPLETE) { if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX) { if (!isCharging) { SwitchPower(SYSTEM_CMD, PSU_POWER_OFF); FlashLed(SYSTEM_CMD, PSU_FLASH_NORMAL); if (chargingInfo[groupIndex]->SystemStatus == S_COMPLETE) { if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_PREPARE_M_TO_A && ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A) { // 代表在切換的過程中,停止充電了 if ((chargingInfo[groupIndex]->PresentChargingCurrent * 10) <= STOP_CURRENT) ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_RELAY_M_TO_A; } } } else if (chargingInfo[groupIndex]->SystemStatus == S_COMPLETE) { // 代表充電的槍依舊在充電,欲進入充電的槍取消充電了 if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_PREPARE_M_TO_A && ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A) { ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_NONE; } } } else if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER) { if (!isReadToCharging) { SwitchPower(SYSTEM_CMD, PSU_POWER_OFF); FlashLed(SYSTEM_CMD, PSU_FLASH_NORMAL); } else { SwitchPower(groupIndex, PSU_POWER_OFF); FlashLed(groupIndex, PSU_FLASH_NORMAL); } if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_WAITING) ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_COMP; else ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_NONE; } } } break; } } usleep(20000); } return FAIL; }