#include "Module_PsuComm.h" #include "Config.h" #include "Common.h" #define DERATING_COUNT 30 #define DERATING_GAP 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_MAX_CUR 1000 // unit: 0.1A #define PSU_MIN_VOL 1000 // unit: 0.1V #define PRE_CHARG_STEP_CUR 30 #define PRE_CHARG_RANGE 50 #define PSU_TASK_CHECK_TIME 1 #define PSU_COMM_CHECK_TIME 1 #define GET_PSU_COUNT_INTERVAL 1 // unit: second #define GET_PSU_COUNT_TIME 13 // unit: second #define GET_PSU_LOCATION_INTERVAL 200 // unit: millisecond #define PSU_COUNT_CONFIRM_INTERVAL 200 // unit: millisecond #define PSU_COUNT_CONFIRM_TIME 1 // unit: second #define GET_PSU_VERSION_INTERVAL 200 // unit: millisecond #define GET_PSU_CAP_INTERVAL 200 // unit: millisecond #define GET_PSU_CAP_TIME 1 // unit: second #define STABLE_CURRENT_TOLERANCE 10 // unit: 0.1A, 1A #define MAX_STABLE_COUNT 24 #define WAIT_EV_DERATING_TIMEOUT 5 // unit: second #define WAIT_SLAVE_POWER_OFF_TIMEOUT 5 // unit: second #define WAIT_PARALLEL_RELAY_DELAY 1 // unit: second #define WAIT_RELAY_CONFIRMED_TIME 3 // unit: second #define MAX_PREPARE_SWITCH_OFF_TIME 10 // unit: second #define MIN_POWER_OFF_TIME 1 // unit: second #define WAIT_SLAVE_TO_CHARGING 1 // unit: second #define WAIT_SLAVE_TIMEOUT 5 // unit: second #define WAIT_DUMMY_FAULT_TIME 3 // unit: second #define WAIT_GRAB_TIME 15 // unit: second #define MAX_PSU_POWER_OFF_CURRENT 50 // unit: 0.1A, 5A #define MAX_PSU_POWER_OFF_VOLTAGE 100 // unit: 0.1A, 10V #define PRECHARGE_OFFSET_VOLTAGE 20 // unit: 0.1V, 2V #define PRECHARGE_RANGE_VOLTAGE 200 // unit: 0.1V, 10V #define WAIT_PRECHARGE_TIME 10 // unit: second #define EXTEND_CAPABILITY_DELAY 10 // unit: second #define EXTEND_AFTER_DERATING_DELAY 3 // unit: second #define EXTEND_GRAB_INTERVAL 30 // unit: second #define EXTEND_LOADING 8000 // unit: 0.01%, 80% #define RELEASE_LOADING 5000 // unit: 0.01%, 50% #define RELEASE_LOADING_OFFSET 1000 // unit: 0.01%, 10% #define BALANCE_CURRENT_INTERVAL 100 // unit: 1ms, 100ms #define SMOOTH_DERATING_INTERVAL 100 // unit: 1ms, 100ms #define CURRENT_REACH_TARGET_TIME 5 // unit: 1s, 5s #define CURRENT_STABLE_TIME 5 // unit: 1s, 5s #define REACH_CURRENT_TOLERANCE 10 // unit: 0.1A, 1A #define MAX_ADJ_BALANCE_CURRENT 30 // unit: 0.1A, 3A #define START_BALANCE_CRITERIA 100 // unit: 0.01%, 1% #define STOP_BALANCE_CRITERIA 10 // unit: 0.01%, 0.1% #define EV_MAX_CURRENT_DELAY 60 // unit: second #define EV_MAX_STAGE_CURRENT_DELAY 30 // unit: second #define WAIT_SLAVE_READY_TIME 15 // unit: second #define WAIT_SLAVE_DELAY 1 // unit: second #define WAIT_DUMMY_MASTER_OFF 15 // unit: second #define SHOW_OUTPUT_DELAY 1 #define CURRENT_BALANCE_CRITERIA 400 // unit: 0.1A, 40A #define SAFETY_PRECHARGE_OFFSET 200 // unit: 0.1V, 20V #define CHARGING_DELAY_INTERVAL 200 // unit: 1ms, 400ms #define MAX_CHARGING_DELAY_COUNT 15 #define VOLTAGE_RESUME_STEP 10 // unit: 0.1V, 1V #define POWER_ONOFF_RESEND_INTERVAL 1 // unit: 1s, 1s #define COMM_LOST_CRITICAL 0 #define LOST_CNT_CRITICAL 10 #define PSU_CLEAN_ERR_INTERVAL 3 // unit: 1s, 3s #if SAFETY_TEST_ENABLE #define PRECHARGE_OFFSET 1 // 0: normal output, 1: precharge voltage offset enable #define ONE_MODULE_OUTPUT 1 // 0: normal output, 1: only one module output enable #define MASTER_OUTPUT_FIRST 0 // 0: normal output, 1: master output first enable #else #define PRECHARGE_OFFSET 0 // 0: normal output, 1: precharge voltage offset enable #define ONE_MODULE_OUTPUT 0 // 0: normal output, 1: only one module output enable #define MASTER_OUTPUT_FIRST 0 // 0: normal output, 1: master output first enable #endif #define MIN_RELEASE_POWER 30 // unit: 1kw #define MAX_DIFF_POWER_TO_DERATING 5 // unit: 1kw #define MAX_DIFF_POWER_TO_EXTEND 3 // unit: 1kw #define MIN_DIFF_PHYSICAL_POWER 3 // unit: 1kw #define MIN_DIFF_CONFIG_POWER 3 // unit: 1kw #define PSU_DEBUG_MSG 0 #define ENABLE_SMOOTH_DERATING 1 #define PSU_INDICATION_TIME 10 // unit: 1s struct SysConfigAndInfo *ShmSysConfigAndInfo; struct StatusCodeData *ShmStatusCodeData; struct PsuData *ShmPsuData; ChargerInfoData *ShmChargerInfo; PsuPositionInfoData *ShmPsuPosition; PsuGroupingInfoData *ShmPsuGrouping; bool libInitialize = false; byte _gunCount = 0; byte _maxGroupCount = 0; byte getAvailableCapOffset = 5; byte deratingKeepCount = 0; byte psuCmdSeq = _PSU_CMD_CAP; bool psuReceiveRecovery = false; bool isCommStart = false; int lostCnt = 0; bool _isTriggerShutdown = false; bool _isShutdownCompleted = false; pid_t _RxPsuPid = 0; unsigned short evseOutVol[CONNECTOR_QUANTITY] = {0, 0, 0, 0}; unsigned short evseOutCur[CONNECTOR_QUANTITY] = {0, 0, 0, 0}; unsigned short evseOutputDelay[CONNECTOR_QUANTITY] = {0, 0, 0, 0}; struct timespec _PsuReceiveRecoveryCheck_time; struct timespec _PsuWorkStep_time; struct timespec _cmdSubPriority_time; struct timespec _PsuGroupRole_time[CONNECTOR_QUANTITY]; struct timespec _ChargingRequest_time[CONNECTOR_QUANTITY]; struct timespec _DummyMasterRequest_time[CONNECTOR_QUANTITY]; struct timespec _PsuGroupDerating_time[CONNECTOR_QUANTITY]; struct timespec _StopCharging_time[CONNECTOR_QUANTITY]; struct timespec _ExtendCapability_time[CONNECTOR_QUANTITY]; struct timespec _ReachCurrent_time[CONNECTOR_QUANTITY]; struct timespec _BalanceCurrent_time[CONNECTOR_QUANTITY]; struct timespec _MaxCurrent_time[CONNECTOR_QUANTITY]; struct timespec _StageCurrent_time[CONNECTOR_QUANTITY]; struct timespec _CheckSlaveReady_time[CONNECTOR_QUANTITY]; struct timespec _ChargingDelay_time[CONNECTOR_QUANTITY]; struct timespec _PoweOnOff_time[CONNECTOR_QUANTITY]; struct timespec _PsuCommCheck_time; struct timespec _SmoothDerating_time[CONNECTOR_QUANTITY]; struct timespec _CleanPsuAlarm_time[CONNECTOR_QUANTITY]; struct timespec _ExtendGrab_time[CONNECTOR_QUANTITY]; unsigned short GCTargetVoltage[CONNECTOR_QUANTITY]; unsigned short GCTargetCurrent[CONNECTOR_QUANTITY]; unsigned short StableOutputCurrent[CONNECTOR_QUANTITY]; unsigned short MaxCurrentDemand[CONNECTOR_QUANTITY]; unsigned short StageMaxCurrent[CONNECTOR_QUANTITY]; GroupOutputConfigInfo PreGroupOutput[MAX_GROUP_QUANTITY]; unsigned char OutputConfigStep[MAX_GROUP_QUANTITY]; unsigned char _preOutputConfigStep[MAX_GROUP_QUANTITY]; unsigned char _GfdStep[MAX_GROUP_QUANTITY]; unsigned char _VoltageResumeCnt[MAX_GROUP_QUANTITY]; unsigned char _GunIndexOfPrioritySequence[MAX_GROUP_QUANTITY]; PsuStatusInfo _LocalPsuStatus[MAX_PSU_MODULE_QUANTITY]; bool _Psu_Indication_Enable[MAX_PSU_MODULE_QUANTITY]; int _Psu_Indication_Count[MAX_PSU_MODULE_QUANTITY]; int GetPsuModuleQuantity(unsigned char group); //================================= // Common routine //================================= bool Is_OutputK1K2_Ready(int gunIndex) { bool ready = false; if(gunIndex < CONNECTOR_QUANTITY) { if(chargingInfo[gunIndex]->RelayK1K2Status || ShmChargerInfo->Control.TestCtrl.bits.ChargingSimulation) { ready = true; } } return ready; } // default is return enable bool Is_EnableReleaseAndExtendWhenForceCharging(int gunIndex) { if(ShmChargerInfo->Control.FCharging[gunIndex].FCtrl.bits.EnableForceCharging) { return ShmChargerInfo->Control.FCharging[gunIndex].FCtrl.bits.EnableReleaseAndExtend; } return true; } // return psu group number // return -1 when out of TotalPsuQuantity int FindTargetGroup(byte address) { return address < ShmPsuPosition->TotalPsuQuantity ? ShmPsuPosition->PsuAddressInfo[address].GroupNo : -1; } // return psu index in the group // return -1 when out of TotalPsuQuantity int FindGroupIndex(byte address) { return address < ShmPsuPosition->TotalPsuQuantity ? ShmPsuPosition->PsuAddressInfo[address].GIndex : -1; } int FindPsuIndex(byte group, byte gIndex) { int psuIndex = 0; for(int i = 0; i < _maxGroupCount; i++) { if(i < group) { psuIndex += ShmChargerInfo->Control.PsuInitQuantity[i]; } else { break; } } psuIndex += gIndex; return psuIndex; } void PsuGroupOnOff(byte group, byte on_off) { if(on_off == _PSU_ON) { SwitchPower_On(group); } else { SwitchPower_Off(group); } } void PsuSingleOnOff(byte address, byte on_off) { if(on_off == _PSU_ON) { SinglePsuPower_On(address); } else { SinglePsuPower_Off(address); } } void LedGroupOnOff(byte group, byte on_off) { if(on_off == _PSU_ON) { FlashLed_Blinking(group); } else { FlashLed_Static(group); } } void LedSingleOnOff(byte address, byte on_off) { if(on_off == _PSU_ON) { SingleFlashLed_Blinking(address); } else { SingleFlashLed_Static(address); } } //================================= // Save data to share memory Function //================================= bool FindChargingInfoData(byte target, struct ChargingInfoData **chargingData) { if(GENERAL_GUN_QUANTITY > 0 && target < GENERAL_GUN_QUANTITY) { chargingData[target] = &ShmSysConfigAndInfo->SysInfo.ConnectorInfo[target].GeneralChargingData; 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 < 4; i++) { unsigned char byteIndex = (errCode >> (8 * i)) & 0xff; for (char bitIndex = 0; bitIndex < 8; bitIndex++) { if(DetectBitValue(byteIndex , bitIndex) == 1) { switch(i) { case 0: { // err 1 if (bitIndex == 2) { // 012307 // fuse burn-out ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFuseBurnOut = YES; } else if (bitIndex == 3) { // 012308 // Communication fault between PFC and DCDC ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuPfcAndDcdcCommFault = YES; } else if (bitIndex == 6) { // 012309 // Unbalance positive and negative BUS voltage ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuBusVoltageUnbalance = YES; } else if (bitIndex == 7) { // 012310 // BUS over voltage ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuBusOverVoltage = YES; } } break; case 1: { // err 2 if (bitIndex == 0) { // 012311 // BUS voltage abnormal ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuBusVoltageAbnormal = YES; } else if (bitIndex == 1) { // 012270 // Over voltage of any phase ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputOVP = YES; } else if (bitIndex == 2) { // 012263 // ID number repetition ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDuplicateID = YES; } else if (bitIndex == 3) { // 012312 // BUS under voltage ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuBusUnderVoltage = YES; } else if (bitIndex == 4) { // 012313 // Phase loss ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputPhaseLoss = YES; } else if (bitIndex == 6) { // 012271 // Under voltage of any phase ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputUVP = NO; } } break; case 2: { // err3 if (bitIndex == 0) { // 012240 // CAN communication fault ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuCommunicationFail = YES; } else if (bitIndex == 1) { // 012275 // DCDC uneven current sharing ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuSevereUnevenCurrent = YES; } else if (bitIndex == 3) { // 012278 // PFC power off //ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFfcSideShutDown = YES; } else if (bitIndex == 5) { // 012314 // Full speed of fan ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFanFullSpeed = YES; } else if (bitIndex == 6) { // 012266 // DCDC power off //ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = YES; } else if (bitIndex == 7) { // 012273 // Module unders power limiting status ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuPowerLimitedState = YES; } } break; case 3: { // err 4 if (bitIndex == 0) { // 012315 // Temperature power limiting ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuTemperaturePowerLimit = YES; } else if (bitIndex == 1) { // 012316 // AC power limiting ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuAcPowerLimit = YES; } else if (bitIndex == 2) { // 012317 // DCDC eeprom faults ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcdcEepromFault = YES; } else if (bitIndex == 3) { // 012269 // Fan faults ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFanFailureAlarm = YES; } else if (bitIndex == 4) { // 012264 // DCDC short circuit ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuOutputShortCircuit = YES; } else if (bitIndex == 5) { // 012318 // PFC eeprom faults ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuPfcEepromFault = YES; } else if (bitIndex == 6) { // 012226 // DCDC over temperature ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuCriticalPointOTP = YES; } else if (bitIndex == 7) { // 012319 // DCDC output over voltage ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcdcOverVoltage = 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; // } // } } } } // return single psu alarm status: PsuStatusInfo unsigned int InfyPwrStateAnalysis(int psu_index, unsigned char state_0, unsigned char state_1, unsigned char state_2) { bool _changed = false; PsuStatusInfo _alarmStatus; _alarmStatus.StatusVal = 0; if(ShmPsuPosition->SingleInfyPwrState[psu_index].InfyPwrState.StateVal[0] != state_0 || (ShmPsuPosition->SingleInfyPwrState[psu_index].InfyPwrState.StateVal[1] & 0xFE) != (state_1 & 0xFE) || (ShmPsuPosition->SingleInfyPwrState[psu_index].InfyPwrState.StateVal[2] & 0x7F) != (state_2 & 0x7F)) { _changed = true; } InfyPsuStateFlagInfo _infyState; _infyState.StateVal[0] = state_0; _infyState.StateVal[1] = state_1; _infyState.StateVal[2] = state_2; if(_infyState.bits.OutputShort || _infyState.bits.PsuFault || _infyState.bits.FanFault || _infyState.bits.PsuProtect || _infyState.bits.FanFault || _infyState.bits.OverTemperature || _infyState.bits.OutputOverVoltage || _infyState.bits.CanCommInterrupt || _infyState.bits.PsuIdRepetition || _infyState.bits.InputPhaseLost || _infyState.bits.InputUnderVoltage || _infyState.bits.InputOverVoltage) { _alarmStatus.bits.Fault = true; } ShmPsuPosition->SingleInfyPwrState[psu_index].InfyPwrStateFlag.bits.Changed = _changed; ShmPsuPosition->SingleInfyPwrState[psu_index].InfyPwrState.StateVal[0] = state_0; ShmPsuPosition->SingleInfyPwrState[psu_index].InfyPwrState.StateVal[1] = state_1; ShmPsuPosition->SingleInfyPwrState[psu_index].InfyPwrState.StateVal[2] = state_2; return _alarmStatus.StatusVal; } //================================= // Callback Function //================================= // 0x04: PSU_RCmd_ModuleStatus void GetGroupCallback(byte group, byte psu_index, unsigned short full_address) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if(ShmPsuData->Work_Step < Get_PSU_LOCATION) { return; } if(group >= _maxGroupCount || psu_index >= MAX_PSU_MODULE_QUANTITY) { return; } ShmPsuPosition->PsuAddressInfo[psu_index].Full_Address = full_address; ShmPsuPosition->PsuAddressInfo[psu_index].GroupNo = group; if(!ShmPsuPosition->PsuAddressInfo[psu_index].CheckIn) { ShmPsuPosition->PsuAddressInfo[psu_index].CheckIn = true; ShmPsuPosition->TotalPsuQuantity++; //LOG_INFO("SN = %d At Group %02X", SN, group); } if(ShmPsuPosition->TotalPsuQuantity == ShmPsuData->SystemInitialPsuQuantity) { byte groupNo = 0, quantity = 0; if(!ShmPsuPosition->PsuLocationInit) { memset(ShmPsuPosition->GroupLocationInfo, 0x00, sizeof(ShmPsuPosition->GroupLocationInfo)); for(int i = 0; i < MAX_PSU_MODULE_QUANTITY; i++) { if(ShmPsuPosition->PsuAddressInfo[i].CheckIn) { groupNo = ShmPsuPosition->PsuAddressInfo[i].GroupNo; quantity = ShmPsuPosition->GroupLocationInfo[groupNo].GroupPsuQuantity; ShmPsuPosition->PsuAddressInfo[i].GIndex = quantity; ShmPsuPosition->GroupLocationInfo[groupNo].PsuIndex[quantity] = i; ShmPsuPosition->GroupLocationInfo[groupNo].GroupPsuQuantity++; //LOG_INFO("Psu %d Assign To Group %02X At %d", index, group, ShmPsuPosition->PsuAddressInfo[index].GIndex); } } bool match = true; for(int i = 0; i < _maxGroupCount; i++) { if(ShmPsuPosition->GroupLocationInfo[i].GroupPsuQuantity != ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity) { match = false; } } if(match) { ShmPsuPosition->PsuLocationInit = true; } else { // try to re-initial psu location ShmPsuPosition->ReInitPsuLocation = true; } } } } // 0x04: PSU_RCmd_ModuleStatus_alarm_flag void GetAlarmFlagCallback(byte address, unsigned int alarm1, unsigned int alarm2) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if(ShmPsuData->Work_Step < Get_PSU_LOCATION) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } if(ShmPsuPosition->PsuLocationInit) { } } void UpdatePsuGroupAlarmStatus(byte group) { int psu_index = 0; unsigned int status_or = 0, status_and = 0xFFFFFFFF; if(ShmPsuPosition->GroupLocationInfo[group].GroupPsuQuantity > 0) { for(int i = 0; i < ShmPsuPosition->GroupLocationInfo[group].GroupPsuQuantity; i++) { psu_index = ShmPsuPosition->GroupLocationInfo[group].PsuIndex[i]; status_or |= ShmPsuPosition->SinglePsuStatus[psu_index].StatusVal; status_and &= ShmPsuPosition->SinglePsuStatus[psu_index].StatusVal; } ShmChargerInfo->PsuGrouping.GroupPsuStatus_OR[group].StatusVal = status_or; ShmChargerInfo->PsuGrouping.GroupPsuStatus_AND[group].StatusVal = status_and; } else { ShmChargerInfo->PsuGrouping.GroupPsuStatus_OR[group].StatusVal = 0; ShmChargerInfo->PsuGrouping.GroupPsuStatus_AND[group].StatusVal = 0; } } // 0x04: PSU_RCmd_ModuleStatus_alarm_status void GetAlarmStatusCallback(byte address, unsigned int status) { bool _update = false; ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if(ShmPsuData->Work_Step < Get_PSU_LOCATION) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } if(ShmPsuPosition->PsuLocationInit) { if(ShmPsuPosition->SinglePsuStatus[address].StatusVal != status) { _update = true; } ShmPsuPosition->SinglePsuStatus[address].StatusVal = status; if(_update) { UpdatePsuGroupAlarmStatus(group); } } } void GetInfyPwrAlarmFlagCallback(byte address, byte state_2, byte state_1, byte state_0) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if(ShmPsuData->Work_Step < Get_PSU_LOCATION || address >= ShmPsuData->SystemInitialPsuQuantity || !ShmPsuPosition->PsuLocationInit) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } unsigned int _alarmStatus = 0; _alarmStatus = InfyPwrStateAnalysis(address, state_0, state_1, state_2); GetAlarmStatusCallback(address, _alarmStatus); } void GetPhPwrAlarmFlagCallback(byte address, unsigned int status, unsigned int alarm_1, unsigned int alarm_0) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if(ShmPsuData->Work_Step < Get_PSU_LOCATION) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } if(ShmPsuPosition->PsuLocationInit) { GetAlarmStatusCallback(address, status); } } // 0x04: PSU_RCmd_ModuleStatus_ambient void GetAmbientCallback(byte address, byte temp) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if(ShmPsuData->Work_Step < Get_PSU_LOCATION) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } if(ShmPsuPosition->PsuLocationInit) { ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp1 = temp; } } // 0x02: PSU_RCmd_SysModuleCount void GetModuleCountCallback(byte group, byte count, bool summation) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if(group < _maxGroupCount) { ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity = count; } if(summation) { int total = 0; for(int i = 0; i < _maxGroupCount; i++) { total += ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity; } if(ShmPsuData->Work_Step == GET_PSU_COUNT) { ShmPsuData->SystemInitialPsuQuantity = total; } ShmPsuData->SystemPresentPsuQuantity = total; } } // 0x02: PSU_RCmd_SysModuleCount_SystemPresentPsuQuantity void GetSysModuleCountCallback(byte group, byte count) { if(ShmPsuData->Work_Step == GET_PSU_COUNT) { ShmPsuData->SystemInitialPsuQuantity = count; } ShmPsuData->SystemPresentPsuQuantity = count; } void UpdateGunAvailableCapability(unsigned char group) { int _availableCurrent = 0, _availablePower = 0, _realPower = 0; unsigned char master = 0; master = ShmChargerInfo->PsuGrouping.GroupCollection[group].TargetGroup; // calculate output group capability if(master == 0) { chargingInfo[group]->AvailableChargingCurrent = ShmPsuData->PsuGroup[group].GroupAvailableCurrent; chargingInfo[group]->AvailableChargingPower = ShmPsuData->PsuGroup[group].GroupAvailablePower; chargingInfo[group]->RealRatingPower = ShmPsuData->PsuGroup[group].GroupRealOutputPower * 10; } else { if(ShmPsuGrouping->GroupCollection[master - 1].Role == _GROLE_MASTER) { _availableCurrent = ShmPsuData->PsuGroup[master - 1].GroupAvailableCurrent; _availablePower = ShmPsuData->PsuGroup[master - 1].GroupAvailablePower; _realPower = ShmPsuData->PsuGroup[master - 1].GroupRealOutputPower * 10; for(byte i = 0; i < ShmPsuGrouping->GroupCollection[master - 1].Partner.Quantity; i++) { byte slave = ShmPsuGrouping->GroupCollection[master - 1].Partner.Member[i]; if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE || ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_PREPARE_SWITCH_OFF) { _availableCurrent += ShmPsuData->PsuGroup[slave].GroupAvailableCurrent; _availablePower += ShmPsuData->PsuGroup[slave].GroupAvailablePower; _realPower += ShmPsuData->PsuGroup[slave].GroupRealOutputPower * 10; } } if(ShmPsuGrouping->GroupCollection[master - 1].GroupCtrl.bits.DeratingConfirmed) { chargingInfo[master - 1]->AvailableChargingCurrent = ShmPsuGrouping->GroupCollection[master - 1].ReAssignAvailableCurrent; } else { chargingInfo[master - 1]->AvailableChargingCurrent = _availableCurrent; } chargingInfo[master - 1]->AvailableChargingPower = _availablePower; chargingInfo[master - 1]->RealRatingPower = _realPower; // if((master - 1) != group) // { // chargingInfo[group]->AvailableChargingCurrent = 0;; // chargingInfo[group]->AvailableChargingPower = 0; // chargingInfo[group]->RealRatingPower = 0; // } } } } void UpdateSystemAvailable(void) { int _sysCurrent = 0, _sysPower = 0; // summation of system current & power for(byte i = 0; i < _maxGroupCount; i++) { _sysCurrent += ShmPsuData->PsuGroup[i].GroupAvailableCurrent; _sysPower += ShmPsuData->PsuGroup[i].GroupAvailablePower; } ShmPsuData->SystemAvailableCurrent = _sysCurrent; ShmPsuData->SystemAvailablePower = _sysPower; } // maxVol, minVol unit: 0.1V // maxCur unit: 0.1A // totalPow unit: 0.1kW // 0x0A: PSU_RCmd_ModuleCapability void GetAvailableCapCallback(byte address, short maxVol, short minVol, short maxCur, short totalPow) { int _groupCurrent = 0, _groupPower = 0; ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step < GET_SYS_CAP || address >= ShmPsuData->SystemInitialPsuQuantity || !ShmPsuPosition->PsuLocationInit) { return; } byte master = 0; int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } // calculate psu module available power ShmPsuData->PsuGroup[group].PsuModule[gIndex].AvailablePower = totalPow; //if(ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage >= PSU_MIN_VOL) if(ShmPsuGrouping->GroupOutput[group].GTargetVoltage >= PSU_MIN_VOL) { ShmPsuData->PsuGroup[group].PsuModule[gIndex].AvailableCurrent = ((ShmPsuData->PsuGroup[group].PsuModule[gIndex].AvailablePower * 100) * 10) / (ShmPsuGrouping->GroupOutput[group].GTargetVoltage / 10); } else { ShmPsuData->PsuGroup[group].PsuModule[gIndex].AvailableCurrent = maxCur > PSU_MAX_CUR ? PSU_MAX_CUR : maxCur; } // summation of psu group current & power for(byte i = 0; i < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; i++) { _groupCurrent += ShmPsuData->PsuGroup[group].PsuModule[i].AvailableCurrent; _groupPower += ShmPsuData->PsuGroup[group].PsuModule[i].AvailablePower; } if(ShmPsuData->PsuGroup[group].StableIAvailableCurrent != 0) { ShmPsuData->PsuGroup[group].GroupAvailableCurrent = ShmPsuData->PsuGroup[group].StableIAvailableCurrent; } else { if(ShmPsuData->PsuGroup[group].GroupRealOutputPower != 0 && ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage >= PSU_MIN_VOL) { ShmPsuData->PsuGroup[group].GroupAvailableCurrent = ((ShmPsuData->PsuGroup[group].GroupRealOutputPower * 1000) * 10) / (ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage / 10); } else { ShmPsuData->PsuGroup[group].GroupAvailableCurrent = _groupCurrent; } } ShmPsuData->PsuGroup[group].GroupAvailablePower = _groupPower; // update MaximumChargingVoltage master = ShmChargerInfo->PsuGrouping.GroupCollection[group].TargetGroup; if(master == 0) { chargingInfo[group]->MaximumChargingVoltage = maxVol; } else { if(ShmPsuGrouping->GroupCollection[master - 1].Role == _GROLE_MASTER) { chargingInfo[master - 1]->MaximumChargingVoltage = maxVol; // if((master - 1) != group) // { // chargingInfo[group]->MaximumChargingVoltage = 0; // } } } UpdateGunAvailableCapability(group); UpdateSystemAvailable(); //LOG_INFO("address = %d, maxVol = %d, minVol = %d, maxCur = %d, totalPow = %d", address, maxVol, minVol, maxCur, totalPow); } // 0x07: PSU_RCmd_ModuleVersion void GetFwCallback(byte address, short dcSwVer, short pfcSwVer, short hwVer) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step != Get_PSU_VERSION || address >= ShmPsuData->SystemInitialPsuQuantity || !ShmPsuPosition->PsuLocationInit) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } 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); sprintf((char *)ShmPsuData->PsuGroup[group].PsuModule[gIndex].FwVersion, "DC %d.%02d", (dcSwVer & 0xFF00) >> 8, dcSwVer & 0xFF); //LOG_INFO("Psu %d %s %s", address, ShmPsuData->PsuVersion[address].FwPrimaryVersion, ShmPsuData->PsuVersion[address].FwSecondVersion); } // 0x07: PSU_RCmd_ModuleVersion_dc void GetDcFwCallback(byte address, char *dcSwVer) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step != Get_PSU_VERSION || address >= ShmPsuData->SystemInitialPsuQuantity || !ShmPsuPosition->PsuLocationInit) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } strcpy((char *)ShmPsuData->PsuVersion[address].FwPrimaryVersion, dcSwVer); strcpy((char *)ShmPsuData->PsuGroup[group].PsuModule[gIndex].FwVersion, dcSwVer); } // 0x07: PSU_RCmd_ModuleVersion_pfc void GetPfcFwCallback(byte address, char *pfcSwVer) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step != Get_PSU_VERSION || address >= ShmPsuData->SystemInitialPsuQuantity || !ShmPsuPosition->PsuLocationInit) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } strcpy((char *)ShmPsuData->PsuVersion[address].FwSecondVersion, pfcSwVer); } // no using -- GetInputVoltageCallback void GetInputVoltageCallback(byte address, unsigned short vol1, unsigned short vol2, unsigned short vol3) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step < GET_SYS_CAP || address >= ShmPsuData->SystemInitialPsuQuantity || !ShmPsuPosition->PsuLocationInit) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } ShmPsuData->PsuGroup[group].PsuModule[gIndex].InputVoltageL1 = vol1; ShmPsuData->PsuGroup[group].PsuModule[gIndex].InputVoltageL2 = vol2; ShmPsuData->PsuGroup[group].PsuModule[gIndex].InputVoltageL3 = vol3; } // no using -- GetInputVoltageCallback End // no using -- GetPresentOutputCallback void GetPresentOutputCallback(byte group, unsigned short outVol, unsigned short outCur) { } // no using -- GetPresentOutputCallback End // type 1: FAN_SPEED_CMD // type 2: TEMP_DC_CMD // type 3: TEMP_PFC_CMD // 0x0E: PSU_RCmd_ModuleMiscInfo void GetMisCallback(byte address, unsigned int value, byte type) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step < GET_SYS_CAP || address >= ShmPsuData->SystemInitialPsuQuantity || !ShmPsuPosition->PsuLocationInit) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } if (type == 1) { ShmPsuData->PsuGroup[group].PsuModule[gIndex].FanSpeed_1 = value; ShmPsuData->PsuGroup[group].PsuModule[gIndex].FanSpeed_2 = value; ShmPsuData->PsuGroup[group].PsuModule[gIndex].FanSpeed_3 = value; ShmPsuData->PsuGroup[group].PsuModule[gIndex].FanSpeed_4 = value; } else if (type == 2) { //ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp1 = value; //ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp2 = value; //ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp3 = value; ShmPsuData->PsuGroup[group].PsuModule[gIndex].ExletTemp = value; } else if (type == 3) { //printf("PFC - group = %d, index = %d, value = %d \n", group, address, value); ShmPsuData->PsuGroup[group].PsuModule[gIndex].InletTemp = value; } } // 0x0E: PSU_RCmd_ModuleMiscInfo_FanSpeed void GetFanSpeedCallback(byte address, unsigned int speed) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step < GET_SYS_CAP || address >= ShmPsuData->SystemInitialPsuQuantity || !ShmPsuPosition->PsuLocationInit) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } ShmPsuData->PsuGroup[group].PsuModule[gIndex].FanSpeed_1 = speed; ShmPsuData->PsuGroup[group].PsuModule[gIndex].FanSpeed_2 = speed; ShmPsuData->PsuGroup[group].PsuModule[gIndex].FanSpeed_3 = speed; ShmPsuData->PsuGroup[group].PsuModule[gIndex].FanSpeed_4 = speed; } // 0x0E: PSU_RCmd_ModuleMiscInfo_InletTemp void GetInletTempCallback(byte address, char temp) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step < GET_SYS_CAP || address >= ShmPsuData->SystemInitialPsuQuantity || !ShmPsuPosition->PsuLocationInit) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } ShmPsuData->PsuGroup[group].PsuModule[gIndex].InletTemp = temp; } // 0x0E: PSU_RCmd_ModuleMiscInfo_ExletTemp void GetExletTempCallback(byte address, char temp) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step < GET_SYS_CAP || address >= ShmPsuData->SystemInitialPsuQuantity || !ShmPsuPosition->PsuLocationInit) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } ShmPsuData->PsuGroup[group].PsuModule[gIndex].ExletTemp = temp; } // 0x0E: PSU_RCmd_ModuleMiscInfo_OutletTemp void GetOutletTempCallback(byte address, char temp) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step < GET_SYS_CAP || address >= ShmPsuData->SystemInitialPsuQuantity || !ShmPsuPosition->PsuLocationInit) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } ShmPsuData->PsuGroup[group].PsuModule[gIndex].OutletTemp = temp; } // temp1: dd in 1 // temp2: dd in 2 // temp3: dd out 1 // temp4: dd out 2 // 0x0E: PSU_RCmd_ModuleMiscInfo_OtherTemp void GetOtherTempCallback(byte address, char temp1, char temp2, char temp3, char temp4) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step < GET_SYS_CAP || address >= ShmPsuData->SystemInitialPsuQuantity || !ShmPsuPosition->PsuLocationInit) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } ShmPsuData->PsuGroup[group].PsuModule[gIndex].InletTemp_1 = temp1; ShmPsuData->PsuGroup[group].PsuModule[gIndex].InletTemp_2 = temp2; ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp2 = temp3; ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp3 = temp4; } // Iavail unit: 0.1A // Vext unit: 0.1V // 0x0C: PSU_RCmd_ModuleIAvailable // 0x02CCF0XX void GetIavailableCallback(byte address, unsigned short Iavail, unsigned short Vext) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step < GET_SYS_CAP || address >= ShmPsuData->SystemInitialPsuQuantity || !ShmPsuPosition->PsuLocationInit) { return; } byte master = 0; unsigned short diffIAvailable = 0; int totalCurrent = 0; int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } ShmPsuData->PsuGroup[group].PsuModule[gIndex].IAvailableCurrent = Iavail; // summation of psu group i available current for (byte i = 0; i < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; i++) { totalCurrent += ShmPsuData->PsuGroup[group].PsuModule[i].IAvailableCurrent; } ShmPsuData->PsuGroup[group].TotalIAvailableCurrent = totalCurrent; diffIAvailable = totalCurrent >= ShmPsuData->PsuGroup[group].TempIAvailableCurrent ? totalCurrent - ShmPsuData->PsuGroup[group].TempIAvailableCurrent : ShmPsuData->PsuGroup[group].TempIAvailableCurrent - totalCurrent; if(diffIAvailable > STABLE_CURRENT_TOLERANCE) { ShmPsuData->PsuGroup[group].StableCurrentCounter = 0; ShmPsuData->PsuGroup[group].StableIAvailableCurrent = 0; } ShmPsuData->PsuGroup[group].TempIAvailableCurrent = ShmPsuData->PsuGroup[group].TotalIAvailableCurrent; ShmPsuData->PsuGroup[group].StableCurrentCounter++; if(ShmPsuData->PsuGroup[group].StableCurrentCounter >= MAX_STABLE_COUNT) { // get stable StableIAvailableCurrent ShmPsuData->PsuGroup[group].StableIAvailableCurrent = ShmPsuData->PsuGroup[group].TotalIAvailableCurrent; // get stable GroupRealOutputPower ShmPsuData->PsuGroup[group].GroupRealOutputPower = (ShmPsuData->PsuGroup[group].StableIAvailableCurrent * ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage) / 100 / 1000; ShmPsuData->PsuGroup[group].StableCurrentCounter = 0; } master = ShmChargerInfo->PsuGrouping.GroupCollection[group].TargetGroup; if(master == 0) { // unit: 0.1A chargingInfo[group]->DeratingChargingCurrent = ShmPsuData->PsuGroup[group].StableIAvailableCurrent; chargingInfo[group]->DeratingChargingPower = (chargingInfo[group]->DeratingChargingCurrent * chargingInfo[group]->PresentChargingVoltage) / 10 / 100; } else { // calculate DeratingChargingCurrent of master group totalCurrent = ShmPsuData->PsuGroup[master - 1].StableIAvailableCurrent; for(byte i = 0; i < ShmPsuGrouping->GroupCollection[master - 1].Partner.Quantity; i++) { byte slave = ShmPsuGrouping->GroupCollection[master - 1].Partner.Member[i]; if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE) { totalCurrent += ShmPsuData->PsuGroup[slave].StableIAvailableCurrent; } } chargingInfo[master - 1]->DeratingChargingCurrent = totalCurrent; chargingInfo[master - 1]->DeratingChargingPower = (chargingInfo[master - 1]->DeratingChargingCurrent * chargingInfo[master - 1]->PresentChargingVoltage) / 10 / 100; if((master - 1) != group) { chargingInfo[group]->DeratingChargingCurrent = 0; chargingInfo[group]->DeratingChargingPower = 0; } } } // outVol unit: 1V // outCur unit: 1A // 0x01: PSU_RCmd_SysOutputVolCur_F void GetPresentOutputFCallback(byte group, float outVol, float outCur) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step < GET_SYS_CAP || group >= _maxGroupCount || !ShmPsuPosition->PsuLocationInit) { return; } byte master = 0; unsigned short pVoltage = 0, pCurrent = 0; unsigned short gVoltage = 0, gCurrent = 0; pVoltage = isinf(outVol) == 0 ? (unsigned short)(outVol * 10) : 0; pCurrent = isinf(outCur) == 0 ? (unsigned short)(outCur * 10) : 0; ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage = pVoltage; ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent = pCurrent; ShmPsuData->PsuGroup[group].GroupPresentOutputPower = (pVoltage * pCurrent) / 100 / 100; master = ShmChargerInfo->PsuGrouping.GroupCollection[group].TargetGroup; if(master == 0) { // calculate PresentChargingVoltage and PresentChargingCurrent of self group chargingInfo[group]->PresentChargingVoltage = (float)ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage / 10; chargingInfo[group]->PresentChargingCurrent = (float)ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent / 10; } else { // calculate PresentChargingVoltage and PresentChargingCurrent of master group gVoltage = ShmPsuData->PsuGroup[master - 1].GroupPresentOutputVoltage; gCurrent = ShmPsuData->PsuGroup[master - 1].GroupPresentOutputCurrent; for(byte i = 0; i < ShmPsuGrouping->GroupCollection[master - 1].Partner.Quantity; i++) { byte slave = ShmPsuGrouping->GroupCollection[master - 1].Partner.Member[i]; if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE || ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_PREPARE_SWITCH_OFF || ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE_POWER_OFF) { if(ShmPsuData->PsuGroup[slave].GroupPresentOutputVoltage > gVoltage) { gVoltage = ShmPsuData->PsuGroup[slave].GroupPresentOutputVoltage; } gCurrent += ShmPsuData->PsuGroup[slave].GroupPresentOutputCurrent; } } chargingInfo[master - 1]->PresentChargingVoltage = (float)gVoltage / 10; chargingInfo[master - 1]->PresentChargingCurrent = (float)gCurrent / 10; if((master - 1) != group) { chargingInfo[group]->PresentChargingVoltage = 0; chargingInfo[group]->PresentChargingCurrent = 0; } } } // outVol unit: 1V // outCur unit: 1A void GetModuleOutputCallback(byte address, float outVol, float outCur) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step < GET_SYS_CAP || !ShmPsuPosition->PsuLocationInit) { return; } unsigned short voltage = isinf(outVol) == 0 ? (unsigned short)(outVol * 10) : 0; unsigned short current = isinf(outCur) == 0 ? (unsigned short)(outCur * 10) : 0; int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } ShmPsuData->PsuGroup[group].PsuModule[gIndex].PresentOutputVoltage = voltage; ShmPsuData->PsuGroup[group].PsuModule[gIndex].PresentOutputCurrent = current; } // phihong pwr only void GetErrorRecordCallback(byte psu_index, byte count_down, byte *error_record) { ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step < GET_SYS_CAP || !ShmPsuPosition->PsuLocationInit) { return; } int err_cnt = 0; bool _change = false; for(int i = 0; i < 7; i++) { if(error_record[i] != 0) { err_cnt++; if(ShmPsuPosition->SinglePhPsuError[psu_index].PsuError[i] != error_record[i] || _change) { _change = true; } } else { break; } } if(_change) { memset(ShmPsuPosition->SinglePhPsuError[psu_index].PsuError, 0x00, sizeof(ShmPsuPosition->SinglePhPsuError[psu_index].PsuError)); memcpy(ShmPsuPosition->SinglePhPsuError[psu_index].PsuError, error_record, err_cnt); } else { _change = ShmPsuPosition->SinglePhPsuError[psu_index].ErrorCount != err_cnt ? true : false; } ShmPsuPosition->SinglePhPsuError[psu_index].ErrorCount = err_cnt; ShmPsuPosition->SinglePhPsuError[psu_index].PhPwrStateFlag.bits.Changed |= _change; } //========================================== // 特規用指令 //========================================== // 0x1901: Nexton_PSU_DcOutputValue void GetOutputAndTempCallback(byte address, unsigned short outputVol_s, unsigned short outputCur_s, unsigned short outputPower, unsigned char Temperature) { return; ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step < GET_SYS_CAP || address >= ShmPsuData->SystemInitialPsuQuantity || !ShmPsuPosition->PsuLocationInit) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } //ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp1 = Temperature; //ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp2 = Temperature; //ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp3 = Temperature; } // 0x1902: Nexton_PSU_StatusEvent void GetModuleStatusCallback(byte address, unsigned char isErr, unsigned char status, unsigned char err1, unsigned char err2, unsigned char err3, unsigned char err4) { return; ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step < GET_SYS_CAP || address >= ShmPsuData->SystemInitialPsuQuantity || !ShmPsuPosition->PsuLocationInit) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } int alarm = (err4 << 24) | (err3 << 16) | (err2 << 8) | err1; ShmPsuData->PsuGroup[group].PsuModule[gIndex].AlarmCode = alarm; AbnormalStopAnalysis(group, alarm); if(isErr) { // 012267 //ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFailureAlarm = YES; ShmPsuData->PsuGroup[group].GroupErrorFlag.bits.PsuFailure = true; } } // 0x1903: Nexton_PSU_AcInputValue void GetModuleInputCallback(byte address, unsigned short inputR, unsigned short inputS, unsigned short inputT) { return; ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt++; if (ShmPsuData->Work_Step < GET_SYS_CAP || address >= ShmPsuData->SystemInitialPsuQuantity || !ShmPsuPosition->PsuLocationInit) { return; } int group = FindTargetGroup(address); int gIndex = FindGroupIndex(address); if(group < 0 || gIndex < 0) { return; } ShmPsuData->PsuGroup[group].PsuModule[gIndex].InputVoltageL1 = inputR; ShmPsuData->PsuGroup[group].PsuModule[gIndex].InputVoltageL2 = inputS; ShmPsuData->PsuGroup[group].PsuModule[gIndex].InputVoltageL3 = inputT; } //========================================== // Init all share memory //========================================== int InitShareMemory() { int result = PASS; int MeterSMId; //creat ShmSysConfigAndInfo if ((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo), 0777)) < 0) { #ifdef SystemLogMessage LOG_ERROR("shmget ShmSysConfigAndInfo NG %d"); #endif result = FAIL; } else if ((ShmSysConfigAndInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1) { #ifdef SystemLogMessage LOG_ERROR("shmat ShmSysConfigAndInfo NG"); #endif result = FAIL; } else {} //creat ShmStatusCodeData 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; } else {} //creat ShmPsuData 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(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) { ShmPsuPosition = &ShmChargerInfo->PsuPosition; ShmPsuGrouping = &ShmChargerInfo->PsuGrouping; } return result; } //================================================ // Main process //================================================ void InitialPsuData(void) { ShmPsuData->SystemInitialPsuQuantity = 0; ShmPsuData->SystemPresentPsuQuantity = 0; ShmPsuData->SystemAvailablePower = 0; LOG_INFO("************ psu Group = %d", ShmPsuData->GroupCount); for (byte _groupCount = 0; _groupCount < ShmPsuData->GroupCount; _groupCount++) { ShmPsuData->PsuGroup[_groupCount].GroupPresentPsuQuantity = 0; ShmPsuData->PsuGroup[_groupCount].GroupAvailablePower = 0; ShmPsuData->PsuGroup[_groupCount].GroupAvailableCurrent = 0; ShmPsuData->PsuGroup[_groupCount].GroupErrorFlag.PsuGroupErrorValue = 0; } ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFuseBurnOut = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuPfcAndDcdcCommFault = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuBusVoltageUnbalance = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuBusOverVoltage = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuBusVoltageAbnormal = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputOVP = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDuplicateID = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuBusUnderVoltage = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputPhaseLoss = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputUVP = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuCommunicationFail = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuSevereUnevenCurrent = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFfcSideShutDown = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFanFullSpeed = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuPowerLimitedState = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuTemperaturePowerLimit = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuAcPowerLimit = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcdcEepromFault = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFanFailureAlarm = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuOutputShortCircuit = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuPfcEepromFault = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuCriticalPointOTP = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcdcOverVoltage = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFault = NO; ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuProtectionAlarm = NO; memset(_LocalPsuStatus, 0x00, sizeof(_LocalPsuStatus)); memset(_Psu_Indication_Enable, 0x00, sizeof(_Psu_Indication_Enable)); memset(_Psu_Indication_Count, 0x00, sizeof(_Psu_Indication_Count)); memset(&ShmChargerInfo->PsuGrouping.GroupPsuStatus_OR, 0x00, sizeof(ShmChargerInfo->PsuGrouping.GroupPsuStatus_OR)); memset(&ShmChargerInfo->PsuGrouping.GroupPsuStatus_AND, 0x00, sizeof(ShmChargerInfo->PsuGrouping.GroupPsuStatus_AND)); } void Initialization() { bool isPass = false; while(!isPass) { isPass = true; for (byte _index = 0; _index < _maxGroupCount; _index++) { if (!FindChargingInfoData(_index, &chargingInfo[0])) { LOG_ERROR("Module_PsuComm : FindChargingInfoData false"); isPass = false; break; } } sleep(1); } ShmPsuData->GroupCount = _maxGroupCount; } bool Is_PsuRxComm_Alive(void) { if(_RxPsuPid > 0) { if(kill(_RxPsuPid, 0) == 0) { // Process exists. return true; } } return false; } void Run_PsuRxCommProcess(void) { _RxPsuPid = InitialCommunication(); LOG_INFO("Create PsuRx PID = %d", _RxPsuPid); } void PsuReceiveRecoveryCheck(void) { char *ptrSave, *ptrToken; int fd, psuTaskCount = 0; char pathBuffer[64], psuTaskPidString[64]; system("pidof Module_PsuComm > /tmp/Module_PsuTask"); snprintf(pathBuffer, sizeof(pathBuffer), "/tmp/Module_PsuTask"); fd = open(pathBuffer, O_RDWR); if(fd < 0) { close(fd); return; } if(read(fd, psuTaskPidString, 64) < 0) { close(fd); return; } ptrToken = strtok_r(psuTaskPidString, " ", &ptrSave); while(ptrToken != NULL) { int psuPid = atoi(ptrToken); if(psuPid > 0) { psuTaskCount++; } ptrToken = strtok_r(NULL, " ", &ptrSave); } close(fd); if(psuTaskCount == 1) { LOG_INFO("************ PSU Receive Task Need Recovery ************\n"); Run_PsuRxCommProcess(); psuReceiveRecovery = true; } } void ShowGroupMember(unsigned char group) { if(group < MAX_GROUP_QUANTITY) { if(ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity > 0) { for(byte psu = 0; psu < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; psu++) { LOG_INFO("Group %d - Number = %d, SN = %02X", group + 1, psu, ShmPsuPosition->GroupLocationInfo[group].PsuIndex[psu]); } } } } void ShowPsuVersion(unsigned char group) { if(group < MAX_GROUP_QUANTITY) { if(ShmPsuPosition->GroupLocationInfo[group].GroupPsuQuantity > 0) { LOG_INFO("Group %d PSU Version Info", group + 1); for(int i = 0; i < ShmPsuPosition->GroupLocationInfo[group].GroupPsuQuantity; i++) { int psuIndex = ShmPsuPosition->GroupLocationInfo[group].PsuIndex[i]; LOG_INFO("PSU Primary: %s, Second: %s", ShmPsuData->PsuVersion[psuIndex].FwPrimaryVersion, ShmPsuData->PsuVersion[psuIndex].FwSecondVersion); } } } } void ShowGroupAvailableCurrentPower(unsigned char group) { if(group < MAX_GROUP_QUANTITY) { LOG_INFO("Group %d Available Current = %3d.%dA, Power = %3d.%dkW", group + 1, (ShmPsuData->PsuGroup[group].GroupAvailableCurrent / 10), (ShmPsuData->PsuGroup[group].GroupAvailableCurrent % 10), (ShmPsuData->PsuGroup[group].GroupAvailablePower / 10), (ShmPsuData->PsuGroup[group].GroupAvailablePower % 10)); } } unsigned char _TempType = 0; void PsuGroupRoutineQuery(void) { for(byte group = 0; group < GENERAL_GUN_QUANTITY; group++) { if(ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity > 0) { if (psuCmdSeq == _PSU_CMD_CAP) { // 取系統總輸出能力 GetModuleCap(group); } else if (psuCmdSeq == _PSU_CMD_OUTPUT) { // 取各群輸出電壓電流 (float) GetModuleOutputF(group); } else if (psuCmdSeq == _PSU_CMD_IVAILIABLE) { // 取得模塊輸出額定電流能力 unsigned short voltage = 0; if(ShmPsuGrouping->GroupCollection[group].TargetGroup == 0) { voltage = (unsigned short)(chargingInfo[group]->FireChargingVoltage); } else { voltage = (unsigned short)(chargingInfo[ShmPsuGrouping->GroupCollection[group].TargetGroup - 1]->FireChargingVoltage); } GetModuleIavailable(group, voltage); } else if (psuCmdSeq == _PSU_CMD_TEMP) { // 取得模塊溫度 if(_TempType == _PSU_TMP_DCDC) { GetDcTemperature(group); } else { GetPfcTemperature(group); } } } } if(psuCmdSeq == _PSU_CMD_CAP) { psuCmdSeq = _PSU_CMD_OUTPUT; } else if(psuCmdSeq == _PSU_CMD_OUTPUT) { psuCmdSeq = _PSU_CMD_IVAILIABLE; } else if(psuCmdSeq == _PSU_CMD_IVAILIABLE) { psuCmdSeq = _PSU_CMD_TEMP; _TempType = _TempType == _PSU_TMP_DCDC ? _PSU_TMP_PFC : _PSU_TMP_DCDC; } else { psuCmdSeq = _PSU_CMD_CAP; } } void SetPsuGroupRole(byte group, byte role) { if(group < GENERAL_GUN_QUANTITY) { ShmPsuGrouping->GroupCollection[group].Role = role; } } void SetPsuGroupToIdle(byte group) { if(group < GENERAL_GUN_QUANTITY) { SetPsuGroupRole(group, _GROLE_IDLE); memset(&ShmPsuGrouping->GroupCollection[group].Partner, 0x00, sizeof(PsuGroupPartner)); memset(&ShmPsuGrouping->GroupCollection[group].PossibleMember, 0x00, sizeof(PsuGroupPartner)); ShmPsuGrouping->GroupCollection[group].TargetGroup = 0; ShmPsuGrouping->GroupCollection[group].ReservedTarget = 0; //LOG_INFO("Reset Group[%02X] To Idle", group); } } // group: self group index void SetPsuGroupToMaster(byte group) { if(group < GENERAL_GUN_QUANTITY) { SetPsuGroupRole(group, _GROLE_MASTER); ShmPsuGrouping->GroupCollection[group].TargetGroup = group + 1; //LOG_INFO("Set Group[%02X] As Master To Gun %d", group, group + 1); } } // group: self group index // target: target group index + 1 void SetPsuGroupToSlave(byte group, byte target) { if(group < GENERAL_GUN_QUANTITY && target <= GENERAL_GUN_QUANTITY) { SetPsuGroupRole(group, _GROLE_SLAVE); ShmPsuGrouping->GroupCollection[group].TargetGroup = target; ShmPsuGrouping->GroupCollection[group].ReservedTarget = 0; memset(&ShmPsuGrouping->GroupCollection[group].PossibleMember, 0x00, sizeof(PsuGroupPartner)); ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.SlaveCtrlValue = 0; //LOG_INFO("Set Group[%02X] As Slave To Gun %d", group, target); } } // target: target group index + 1 // tPartner: set member to power off void PrepareToPowerOff(byte target, PsuGroupPartner *tPartner) { unsigned char master = 0, slave = 0; char strMember[64]; bool find = false; sprintf(strMember, "Set Member:"); for(int i = 0; i < tPartner->Quantity; i++) { slave = tPartner->Member[i]; master = ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1; SetPsuGroupRole(slave, _GROLE_PREPARE_SWITCH_OFF); ShmPsuGrouping->GroupCollection[slave].ReservedTarget = target; ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.NeedDerating = true; char strSlave[8]; sprintf(strSlave, " [%02X]", slave); strcat(strMember, strSlave); find = true; } if(find) { char strTemp[32]; if(target != 0) { sprintf(strTemp, " Prepare To Change To Gun %d", target); } else { sprintf(strTemp, " Prepare To Power Of"); } strcat(strMember, strTemp); LOG_INFO("%s", strMember); } } // target: target group index + 1 // tPartner: set member to prepare to attach on void PrepareToExtendCapability(byte target, PsuGroupPartner *tPartner) { char strMember[64]; sprintf(strMember, "Set Member:"); for(int i = 0; i < tPartner->Quantity; i++) { SetPsuGroupRole(tPartner->Member[i], _GROLE_PREPARE_ATTACH_ON); ShmPsuGrouping->GroupCollection[tPartner->Member[i]].ReservedTarget = target; char strSlave[8]; sprintf(strSlave, " [%02X]", tPartner->Member[i]); strcat(strMember, strSlave); } if(tPartner->Quantity > 0) { char strTemp[32]; sprintf(strTemp, " Prepare To Attach To Gun %d", target); strcat(strMember, strTemp); LOG_INFO("%s", strMember); } } void FindPsuGroupPartner(byte master, int condition, PsuGroupPartner *tPartner, int type, int quantityLimit) { int slave = 0, location = 0; PsuGroupPartner partner; int extendPower = 0; bool done = false; int parallelRelay = 0; unsigned short parallelFlag = 0; memset(&partner, 0x00, sizeof(PsuGroupPartner)); // search from left location = ShmPsuGrouping->GroupCollection[master].Location - 1; for(int i = location; i >= 0; i--) { switch(type) { case _EXTEND_TYPE_QUANTITY: if(partner.Quantity >= condition) { done = true; } break; case _EXTEND_TYPE_POWER: if(extendPower >= condition) { done = true; } break; default: done = true; break; } if(done || partner.Quantity >= quantityLimit) { break; } slave = ShmPsuGrouping->Layout[i]; if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_IDLE || (ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_WAIT_SLAVE && (ShmPsuGrouping->GroupCollection[slave].ReservedTarget - 1) == master)) { parallelRelay = ShmPsuGrouping->GroupCollection[master].ParallelConfig[slave]; parallelFlag |= parallelRelay != 0 ? (1 << (parallelRelay - 1)) : 0; if(ShmPsuData->PsuGroup[slave].GroupPresentPsuQuantity > 0) { partner.Member[partner.Quantity] = slave; partner.ParallelFlag[partner.Quantity] = parallelFlag; partner.Quantity++; extendPower += (ShmPsuData->PsuGroup[slave].GroupAvailablePower / 10); parallelFlag = 0; } if(ShmChargerInfo->Control.SysCtrl.bits.Enable6ParallelRelay) { parallelFlag = 0; } } else { if(ShmChargerInfo->Control.SysCtrl.bits.Enable6ParallelRelay == 0) { // Enable6ParallelRelay = 0, need to check slave is the same target or not if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE && master == (ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1)) { continue; } break; } } } parallelFlag = 0; // search from right location = ShmPsuGrouping->GroupCollection[master].Location + 1; for(int i = location; i < ShmChargerInfo->Control.MaxConnector; i++) { switch(type) { case _EXTEND_TYPE_QUANTITY: if(partner.Quantity >= condition) { done = true; } break; case _EXTEND_TYPE_POWER: if(extendPower >= condition) { done = true; } break; default: done = true; break; } if(done || partner.Quantity >= quantityLimit) { break; } slave = ShmPsuGrouping->Layout[i]; if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_IDLE || (ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_WAIT_SLAVE && (ShmPsuGrouping->GroupCollection[slave].ReservedTarget - 1) == master)) { parallelRelay = ShmPsuGrouping->GroupCollection[master].ParallelConfig[slave]; parallelFlag |= parallelRelay != 0 ? (1 << (parallelRelay - 1)) : 0; if(ShmPsuData->PsuGroup[slave].GroupPresentPsuQuantity > 0) { partner.Member[partner.Quantity] = slave; partner.ParallelFlag[partner.Quantity] = parallelFlag; partner.Quantity++; extendPower += (ShmPsuData->PsuGroup[slave].GroupAvailablePower / 10); parallelFlag = 0; } if(ShmChargerInfo->Control.SysCtrl.bits.Enable6ParallelRelay) { parallelFlag = 0; } } else { if(ShmChargerInfo->Control.SysCtrl.bits.Enable6ParallelRelay == 0) { // Enable6ParallelRelay = 0, need to check slave is the same target or not if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE && master == (ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1)) { continue; } break; } } } memcpy(tPartner, &partner, sizeof(PsuGroupPartner)); } int GetPsuGroupAvailable(byte group) { PsuGroupPartner partner; FindPsuGroupPartner(group, MAX_GROUP_QUANTITY, &partner, _EXTEND_TYPE_QUANTITY, MAX_GROUP_QUANTITY); return partner.Quantity; } // return quantity which role is _GROLE_MASTER int FindChargingMasterQuantity(void) { int quantity = 0; for(int i = 0; i < ShmChargerInfo->Control.MaxConnector; i++) { if(ShmPsuGrouping->GroupCollection[i].Role == _GROLE_MASTER) { quantity++; } } return quantity; } // return total psu group quantity int FindTotalPsuGroupQuantity(void) { int quantity = 0; for(int i = 0; i < MAX_GROUP_QUANTITY; i++) { if(ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity > 0) { quantity++; } } return quantity; } void ShowGunPrioritySequence(unsigned char *sequence, int quantity) { char strSequence[256]; sprintf(strSequence, "Priority Sequence:"); for(int i = 0; i < quantity; i++) { char strGun[32]; sprintf(strGun, " [Gun %d: %d kW]", sequence[i] + 1, (int)ShmPsuGrouping->GroupCollection[sequence[i]].DiffPower_PhysicalLimit); strcat(strSequence, strGun); } PSU_LOG("%s", strSequence); } void CheckExtendConflictPriority(unsigned char *sequence, int quantity) { bool done = true; int temp = 0; for(int i = 0; i < quantity - 1; i++) { done = true; for(int j = 0; j < quantity - i - 1; j++) { if(ShmPsuGrouping->GroupCollection[sequence[j + 1]].DiffPower_PhysicalLimit > ShmPsuGrouping->GroupCollection[sequence[j]].DiffPower_PhysicalLimit) { temp = sequence[j]; sequence[j] = sequence[j + 1]; sequence[j + 1] = temp; done = false; } } //ShowGunPrioritySequence(sequence, quantity); if(done) { break; } } } // return conflict reason int IsExtendConflict(byte master) { int available = 0, conflictMasterCnt = 0, conflictGroupCnt = 0, average = 0, remainder = 0; available = GetPsuGroupAvailable(master); if(available == 0) { return _CONFLICT_AVAILABLE; } for(int i = 0; i < ShmChargerInfo->Control.MaxConnector; i++) { if(ShmPsuGrouping->GroupCollection[i].GroupCtrl.bits.ExtendAvailable || ShmPsuGrouping->GroupCollection[i].GroupCtrl.RoleCtrl.ExtendCapabilityCtrlValue != 0) { conflictMasterCnt++; conflictGroupCnt += ShmPsuGrouping->GroupCollection[i].Partner.Quantity + 1; } } average = conflictMasterCnt != 0 ? ((conflictGroupCnt + available) / conflictMasterCnt) : 0; remainder = conflictMasterCnt != 0 ? ((conflictGroupCnt + available) % conflictMasterCnt) : 0; if(ShmPsuGrouping->GroupCollection[master].Partner.Quantity + 1 < average) { ShmPsuGrouping->GroupCollection[master].ExtendQuantityLimit = average - ShmPsuGrouping->GroupCollection[master].Partner.Quantity - 1; if(ShmPsuGrouping->GroupCollection[master].ExtendQuantityLimit > 1) { ShmPsuGrouping->GroupCollection[master].ExtendQuantityLimit = 1; } #if PSU_DEBUG_MSG LOG_INFO("Gun %d Extend Average First, Quantity Limit: %d", master + 1, ShmPsuGrouping->GroupCollection[master].ExtendQuantityLimit); #endif return _CONFLICT_NONE; } for(int i = 0; i < ShmChargerInfo->Control.MaxConnector; i++) { if(ShmPsuGrouping->GroupCollection[i].GroupCtrl.bits.ExtendAvailable || ShmPsuGrouping->GroupCollection[i].GroupCtrl.RoleCtrl.ExtendCapabilityCtrlValue != 0) { if(ShmPsuGrouping->GroupCollection[i].Partner.Quantity + 1 < average) { return _CONFLICT_AVERAGE; } } } if(remainder > 0) { int find = 0; CheckExtendConflictPriority(_GunIndexOfPrioritySequence, MAX_GROUP_QUANTITY); ShowGunPrioritySequence(_GunIndexOfPrioritySequence, MAX_GROUP_QUANTITY); for(int i = 0; i < ShmChargerInfo->Control.MaxConnector; i++) { if(find >= remainder) { break; } if(ShmPsuGrouping->GroupCollection[_GunIndexOfPrioritySequence[i]].GroupCtrl.bits.ExtendAvailable) { find++; if(master == _GunIndexOfPrioritySequence[i]) { ShmPsuGrouping->GroupCollection[_GunIndexOfPrioritySequence[i]].ExtendQuantityLimit = 1; #if PSU_DEBUG_MSG LOG_INFO("Gun %d Extend Via Priority First, Quantity Limit: %d", master + 1, ShmPsuGrouping->GroupCollection[master].ExtendQuantityLimit); #endif return _CONFLICT_NONE; } } } } return _CONFLICT_PRIORITY; } void FindGrabPartner(byte group, byte GrabMaster, PsuGroupPartner *tPartner) { bool find = false; int location = 0, master = 0, slave = 0; // find other group in the same direction if(ShmPsuGrouping->Location[group] < ShmPsuGrouping->Location[GrabMaster]) { // find other group far to GrabMaster in the same direction location = ShmPsuGrouping->GroupCollection[group].Location - 1; for(int i = location; i >= 0; i--) { slave = ShmPsuGrouping->Layout[i]; master = ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1; if(master == GrabMaster) { if(ShmPsuGrouping->GroupCollection[master].AlternateMaster != 0) { if((ShmPsuGrouping->GroupCollection[master].AlternateMaster - 1) == slave) { continue; } } tPartner->Member[tPartner->Quantity] = slave; tPartner->Quantity++; find = true; #if PSU_DEBUG_MSG LOG_INFO("Find Priority Partner [%02X] Far To GrabMaster At Right Side", slave); #endif break; } } if(!find) { // find other group near to GrabMaster in the same direction location = ShmPsuGrouping->GroupCollection[group].Location + 1; for(int i = location; i < ShmChargerInfo->Control.MaxConnector; i++) { slave = ShmPsuGrouping->Layout[i]; if(slave == GrabMaster) { break; } master = ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1; if(master == GrabMaster) { if(ShmPsuGrouping->GroupCollection[master].AlternateMaster != 0) { if((ShmPsuGrouping->GroupCollection[master].AlternateMaster - 1) == slave) { continue; } } tPartner->Member[tPartner->Quantity] = slave; tPartner->Quantity++; find = true; #if PSU_DEBUG_MSG LOG_INFO("Find Priority Partner [%02X] Near To GrabMaster At Right Side", slave); #endif break; } } if(!find) { for(int i = ShmChargerInfo->Control.MaxConnector - 1; i >= 0; i--) { slave = ShmPsuGrouping->Layout[i]; if(slave == GrabMaster) { break; } master = ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1; if(master == GrabMaster) { if(ShmPsuGrouping->GroupCollection[master].AlternateMaster != 0) { if((ShmPsuGrouping->GroupCollection[master].AlternateMaster - 1) == slave) { continue; } } tPartner->Member[tPartner->Quantity] = slave; tPartner->Quantity++; find = true; #if PSU_DEBUG_MSG LOG_INFO("Find Priority Partner [%02X] At Right Side At Ring Mode", slave); #endif break; } } } } } if(ShmPsuGrouping->Location[group] > ShmPsuGrouping->Location[GrabMaster]) { // find other group far to GrabMaster in the same direction location = ShmPsuGrouping->GroupCollection[group].Location + 1; for(int i = location; i < ShmChargerInfo->Control.MaxConnector; i++) { slave = ShmPsuGrouping->Layout[i]; master = ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1; if(master == GrabMaster) { tPartner->Member[tPartner->Quantity] = slave; tPartner->Quantity++; find = true; #if PSU_DEBUG_MSG LOG_INFO("Find Priority Partner [%02X] Far To GrabMaster At Left Side", slave); #endif break; } } if(!find) { // find other group near to GrabMaster in the same direction location = ShmPsuGrouping->GroupCollection[group].Location - 1; for(int i = location; i >= 0; i--) { slave = ShmPsuGrouping->Layout[i]; if(slave == GrabMaster) { break; } master = ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1; if(master == GrabMaster) { tPartner->Member[tPartner->Quantity] = slave; tPartner->Quantity++; find = true; #if PSU_DEBUG_MSG LOG_INFO("Find Priority Partner [%02X] Near To GrabMaster At Left Side", slave); #endif break; } } if(!find) { for(int i = 0; i < ShmChargerInfo->Control.MaxConnector; i++) { slave = ShmPsuGrouping->Layout[i]; if(slave == GrabMaster) { break; } master = ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1; if(master == GrabMaster) { tPartner->Member[tPartner->Quantity] = slave; tPartner->Quantity++; find = true; #if PSU_DEBUG_MSG LOG_INFO("Find Priority Partner [%02X] At Left Side At Ring Mode", slave); #endif break; } } } } } } // return keep or stop bool AlternateMasterGrabLogic(unsigned char master, int grabLocation, int *GrabTarget, int *MaxMember) { bool keep = true; unsigned char slave = 0, target = 0; slave = ShmPsuGrouping->Layout[grabLocation]; if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE && ShmPsuGrouping->GroupCollection[slave].TargetGroup != master + 1) { target = ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1; if(ShmPsuGrouping->GroupCollection[target].AlternateMaster == 0) { if(ShmPsuGrouping->GroupCollection[target].Partner.RealQuantity > *MaxMember) { *MaxMember = ShmPsuGrouping->GroupCollection[target].Partner.RealQuantity; *GrabTarget = target + 1; } } else { if(ShmPsuGrouping->GroupCollection[target].Partner.RealQuantity - 1 > *MaxMember) { *MaxMember = ShmPsuGrouping->GroupCollection[target].Partner.RealQuantity - 1; *GrabTarget = target + 1; } } } if(ShmChargerInfo->Control.SysCtrl.bits.Enable6ParallelRelay == 0) { keep = false; } return keep; } // return keep or stop bool AlternateMasterDeratingLogic(unsigned char master, int grabLocation, int *GrabTarget, int *MaxMember) { bool keep = true; unsigned char slave = 0, target = 0; slave = ShmPsuGrouping->Layout[grabLocation]; if((ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_PREPARE_SWITCH_OFF || ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE_POWER_OFF || ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SWITCH_OFF_OK || ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_WAIT_IDLE) && ShmPsuGrouping->GroupCollection[slave].TargetGroup != master + 1) { target = ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1; if(ShmPsuGrouping->GroupCollection[target].AlternateMaster == 0) { if(ShmPsuGrouping->GroupCollection[target].Partner.RealQuantity > *MaxMember) { *MaxMember = ShmPsuGrouping->GroupCollection[target].Partner.RealQuantity; *GrabTarget = target + 1; } } else { if(ShmPsuGrouping->GroupCollection[target].Partner.RealQuantity - 1 > *MaxMember) { *MaxMember = ShmPsuGrouping->GroupCollection[target].Partner.RealQuantity - 1; *GrabTarget = target + 1; } } } if(ShmChargerInfo->Control.SysCtrl.bits.Enable6ParallelRelay == 0) { keep = false; } return keep; } bool CheckAlternateMaster(byte group, PsuGroupPartner *tPartner, bool isSlave) { int location = 0; int GrabTarget = 0, MaxMember = 0; memset(tPartner, 0x00, sizeof(PsuGroupPartner)); // search from left location = ShmPsuGrouping->GroupCollection[group].Location - 1; for(int i = location; i >= 0; i--) { if(isSlave) { if(!AlternateMasterGrabLogic(group, i, &GrabTarget, &MaxMember)) { break; } } else { if(!AlternateMasterDeratingLogic(group, i, &GrabTarget, &MaxMember)) { break; } } } // search from right location = ShmPsuGrouping->GroupCollection[group].Location + 1; for(int i = location; i < ShmChargerInfo->Control.MaxConnector; i++) { if(isSlave) { if(!AlternateMasterGrabLogic(group, i, &GrabTarget, &MaxMember)) { break; } } else { if(!AlternateMasterDeratingLogic(group, i, &GrabTarget, &MaxMember)) { break; } } } if(GrabTarget > 0) { FindGrabPartner(group, GrabTarget - 1, tPartner); } return tPartner->Quantity > 0 ? true : false; } // return grab success or fail // return tPartner with possible member bool PsuGroupGrabCheck(byte group, PsuGroupPartner *tPartner) { int slave = 0, target = 0, location = 0, average = 0, total = 0; if(ShmPsuGrouping->GroupCollection[group].Role != _GROLE_SLAVE && ShmPsuGrouping->GroupCollection[group].Role != _GROLE_REQUEST_TO_CHARGING) { return false; } memset(tPartner, 0x00, sizeof(PsuGroupPartner)); total = GetPsuGroupAvailable(group) + 1; average = FindTotalPsuGroupQuantity() / (1 + FindChargingMasterQuantity()); if(total < average) { // search from left location = ShmPsuGrouping->GroupCollection[group].Location - 1; for(int i = location; i >= 0; i--) { if(total + tPartner->Quantity < average) { slave = ShmPsuGrouping->Layout[i]; if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE && (ShmPsuGrouping->GroupCollection[group].Role == _GROLE_REQUEST_TO_CHARGING || ShmPsuGrouping->GroupCollection[slave].TargetGroup == ShmPsuGrouping->GroupCollection[group].TargetGroup)) { target = ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1; if((ShmPsuGrouping->GroupCollection[target].Partner.Quantity + 1) > average) { if(ShmChargerInfo->Control.SysCtrl.bits.Enable6ParallelRelay == 0) { tPartner->Member[tPartner->Quantity] = slave; tPartner->Quantity++; } else { FindGrabPartner(group, target, tPartner); } } } else { if(ShmChargerInfo->Control.SysCtrl.bits.Enable6ParallelRelay == 0) { break; } } } } // search from right location = ShmPsuGrouping->GroupCollection[group].Location + 1; for(int i = location; i < ShmChargerInfo->Control.MaxConnector; i++) { if(total + tPartner->Quantity < average) { slave = ShmPsuGrouping->Layout[i]; if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE && (ShmPsuGrouping->GroupCollection[group].Role == _GROLE_REQUEST_TO_CHARGING || ShmPsuGrouping->GroupCollection[slave].TargetGroup == ShmPsuGrouping->GroupCollection[group].TargetGroup)) { target = ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1; if((ShmPsuGrouping->GroupCollection[target].Partner.Quantity + 1) > average) { if(ShmChargerInfo->Control.SysCtrl.bits.Enable6ParallelRelay == 0) { tPartner->Member[tPartner->Quantity] = slave; tPartner->Quantity++; } else { FindGrabPartner(group, target, tPartner); } } } else { if(ShmChargerInfo->Control.SysCtrl.bits.Enable6ParallelRelay == 0) { break; } } } } } return tPartner->Quantity > 0 ? true : false; } bool IsAnyGroupDerating(void) { bool isDerating = false; for(int i = 0; i < MAX_GROUP_QUANTITY; i++) { if(ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity > 0) { if(ShmPsuGrouping->GroupCollection[i].Role != _GROLE_MASTER && ShmPsuGrouping->GroupCollection[i].Role != _GROLE_SLAVE) { isDerating = true; } } } return isDerating; } // return keep or stop bool ExtendGrabLogic(unsigned char master, int grabLocation, int *GrabTarget, int *MaxGrabTotal, int average) { bool keep = true; unsigned char slave = 0, target = 0; slave = ShmPsuGrouping->Layout[grabLocation]; if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE && ShmPsuGrouping->GroupCollection[slave].TargetGroup != master + 1) { target = ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1; if(ShmPsuGrouping->GroupCollection[target].AlternateMaster == 0) { if((ShmPsuGrouping->GroupCollection[target].Partner.RealQuantity + 1) > average && (ShmPsuGrouping->GroupCollection[target].Partner.RealQuantity + 1) > *MaxGrabTotal) { *MaxGrabTotal = ShmPsuGrouping->GroupCollection[target].Partner.RealQuantity + 1; *GrabTarget = target + 1; } } else { if((ShmPsuGrouping->GroupCollection[target].Partner.RealQuantity) > average && (ShmPsuGrouping->GroupCollection[target].Partner.RealQuantity) > *MaxGrabTotal) { *MaxGrabTotal = ShmPsuGrouping->GroupCollection[target].Partner.RealQuantity; *GrabTarget = target + 1; } } } if(ShmChargerInfo->Control.SysCtrl.bits.Enable6ParallelRelay == 0) { keep = false; } return keep; } // return grab success or fail // return tPartner with possible member bool ExtendCapabilityGrabCheck(byte group, PsuGroupPartner *tPartner) { int location = 0, average = 0, total = 0; int GrabTarget = 0, MaxTotal = 0; if(ShmPsuGrouping->GroupCollection[group].Role != _GROLE_MASTER) { return false; } if(IsAnyGroupDerating()) { return false; } memset(tPartner, 0x00, sizeof(PsuGroupPartner)); total = ShmPsuGrouping->GroupCollection[group].Partner.RealQuantity; total += ShmPsuGrouping->GroupCollection[group].AlternateMaster > 0 ? 1 : 0; average = FindTotalPsuGroupQuantity() / FindChargingMasterQuantity(); if(total < average) { // search from left location = ShmPsuGrouping->GroupCollection[group].Location - 1; for(int i = location; i >= 0; i--) { if(!ExtendGrabLogic(group, i, &GrabTarget, &MaxTotal, average)) { break; } } // search from right location = ShmPsuGrouping->GroupCollection[group].Location + 1; for(int i = location; i < ShmChargerInfo->Control.MaxConnector; i++) { if(!ExtendGrabLogic(group, i, &GrabTarget, &MaxTotal, average)) { break; } } } if(GrabTarget > 0) { FindGrabPartner(group, GrabTarget - 1, tPartner); } return tPartner->Quantity > 0 ? true : false; } // return tPartner with possible member when group power off void PsuGroupPowerOffCheck(byte group, PsuGroupPartner *tPartner) { int master = 0, quantity = 0, location = 0; memset(tPartner, 0x00, sizeof(PsuGroupPartner)); if(ShmPsuGrouping->GroupCollection[group].Role != _GROLE_SLAVE) { return; } master = ShmPsuGrouping->GroupCollection[group].TargetGroup - 1; quantity = ShmPsuGrouping->GroupCollection[master].Partner.Quantity; for(int i = 0; i < quantity; i++) { if(tPartner->Quantity == 0) { if(group == ShmPsuGrouping->GroupCollection[master].Partner.Member[i]) { location = i; tPartner->Member[tPartner->Quantity] = group; tPartner->Quantity++; } } else { // find other group in the same direction if(ShmPsuGrouping->Location[ShmPsuGrouping->GroupCollection[master].Partner.Member[location]] < ShmPsuGrouping->Location[master]) { if(ShmPsuGrouping->Location[ShmPsuGrouping->GroupCollection[master].Partner.Member[i]] < ShmPsuGrouping->Location[master]) { tPartner->Member[tPartner->Quantity] = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; tPartner->Quantity++; //printf("\r\n Find Other Group %02X In The Same Direction", ShmPsuGrouping->GroupCollection[master].Partner.Member[i]); } } if(ShmPsuGrouping->Location[ShmPsuGrouping->GroupCollection[master].Partner.Member[location]] > ShmPsuGrouping->Location[master]) { if(ShmPsuGrouping->Location[ShmPsuGrouping->GroupCollection[master].Partner.Member[i]] > ShmPsuGrouping->Location[master]) { tPartner->Member[tPartner->Quantity] = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; tPartner->Quantity++; //printf("\r\n Find Other Group %02X In The Same Direction", ShmPsuGrouping->GroupCollection[master].Partner.Member[i]); } } } } } void UpdateGunTotalPsuQuantity(int master) { ShmPsuGrouping->GroupCollection[master].GunPsuQuantity = GetPsuModuleQuantity(master); } // group: group index, target: target index // master: master group index void AddMember(byte group, byte master, unsigned short flag) { if(group < GENERAL_GUN_QUANTITY && master < GENERAL_GUN_QUANTITY) { if(ShmPsuGrouping->GroupCollection[master].Role != _GROLE_MASTER && ShmPsuGrouping->GroupCollection[master].Role != _GROLE_REQUEST_TO_CHARGING && ShmPsuGrouping->GroupCollection[master].Role != _GROLE_DUMMY_MASTER) { return; } if(ShmPsuGrouping->GroupCollection[group].Role != _GROLE_IDLE && ShmPsuGrouping->GroupCollection[group].Role != _GROLE_WAIT_SLAVE && ShmPsuGrouping->GroupCollection[group].Role != _GROLE_PRECHARGE_READY) { return; } SetPsuGroupToSlave(group, master + 1); ShmPsuGrouping->GroupCollection[master].Partner.Member[ShmPsuGrouping->GroupCollection[master].Partner.Quantity] = group; ShmPsuGrouping->GroupCollection[master].Partner.ParallelFlag[ShmPsuGrouping->GroupCollection[master].Partner.Quantity] = flag; ShmPsuGrouping->GroupCollection[master].Partner.Quantity++; if(ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity > 0) { ShmPsuGrouping->GroupCollection[master].Partner.RealQuantity++; //ShmPsuGrouping->GroupCollection[master].GunPsuQuantity += ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; UpdateGunTotalPsuQuantity(master); #if PSU_DEBUG_MSG LOG_INFO("Gun %d Add Group [%02X], Quantity: %d (%d), Flag: %04X", master + 1, group, ShmPsuGrouping->GroupCollection[master].Partner.Quantity, ShmPsuGrouping->GroupCollection[master].Partner.RealQuantity, flag); #endif } //printf("\r\n Add Group %02X To Gun %d (Quantity %d), Set Parallel Relay %d On", group, target + 1, ShmPsuGrouping->GroupCollection[target].Partner.Quantity, ParallelConfig); } } // master: master group index void AddSpecificMember(unsigned char master, PsuGroupPartner *partner) { char strMember[64]; sprintf(strMember, "Gun %d Add Member:", master + 1); for(int i = 0; i < partner->Quantity; i++) { AddMember(partner->Member[i], master, partner->ParallelFlag[i]); char strSlave[8]; sprintf(strSlave, " [%02X]", partner->Member[i]); strcat(strMember, strSlave); } if(partner->Quantity > 0) { LOG_INFO("%s", strMember); } } // master: master group index void AddAvailableMember(unsigned char master) { PsuGroupPartner partner; FindPsuGroupPartner(master, MAX_GROUP_QUANTITY, &partner, _EXTEND_TYPE_QUANTITY, MAX_GROUP_QUANTITY); AddSpecificMember(master, &partner); } // master: master group index void AddDummyMaster(unsigned char master, PsuGroupPartner *partner) { ShmPsuGrouping->GroupCollection[master].AlternateMaster = partner->Member[0] + 1; AddSpecificMember(master, partner); } // master: master group index // slave: slave group index void RemoveMember(unsigned char master, unsigned char slave) { bool find = false; int location = 0; unsigned char other = 0; unsigned short parallelFlag = 0; for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { if(slave == ShmPsuGrouping->GroupCollection[master].Partner.Member[i]) { ShmPsuGrouping->GroupCollection[master].Partner.Member[i] = 0; location = i; find = true; break; } } if(find) { for(int i = location + 1; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { other = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; parallelFlag = ShmPsuGrouping->GroupCollection[master].Partner.ParallelFlag[i]; ShmPsuGrouping->GroupCollection[master].Partner.Member[i] = 0; ShmPsuGrouping->GroupCollection[master].Partner.Member[i - 1] = other; ShmPsuGrouping->GroupCollection[master].Partner.ParallelFlag[i - 1] = parallelFlag; } ShmPsuGrouping->GroupCollection[master].Partner.Quantity--; if(ShmPsuData->PsuGroup[slave].GroupPresentPsuQuantity > 0) { ShmPsuGrouping->GroupCollection[master].Partner.RealQuantity--; //ShmPsuGrouping->GroupCollection[master].GunPsuQuantity -= ShmPsuData->PsuGroup[slave].GroupPresentPsuQuantity; UpdateGunTotalPsuQuantity(master); } #if PSU_DEBUG_MSG LOG_INFO("Gun %d Remove Group [%02X], Quantity: %d (%d)", master + 1, slave, ShmPsuGrouping->GroupCollection[master].Partner.Quantity, ShmPsuGrouping->GroupCollection[master].Partner.RealQuantity); #endif } } // master: master group index void RemoveNonGroupMember(unsigned char master) { unsigned char slave = 0; char strMember[64]; PsuGroupPartner partner; bool find = false; if(ShmPsuGrouping->GroupCollection[master].Role == _GROLE_MASTER) { sprintf(strMember, "Gun %d Remove Member:", master + 1); memcpy(&partner, &ShmPsuGrouping->GroupCollection[master].Partner, sizeof(PsuGroupPartner)); for(int i = 0; i < partner.Quantity; i++) { slave = partner.Member[i]; if(ShmPsuGrouping->GroupCollection[slave].Role != _GROLE_SLAVE) { RemoveMember(master, slave); if(ShmPsuGrouping->GroupCollection[slave].ReservedTarget == 0) { SetPsuGroupToIdle(slave); } else { SetPsuGroupRole(slave, _GROLE_WAIT_SLAVE); } char strSlave[8]; sprintf(strSlave, " [%02X]", slave); strcat(strMember, strSlave); find = true; } } if(find) { LOG_INFO("%s", strMember); } } } void SetPsuGroupPowerOnOff(unsigned char group, unsigned char power_on_off) { if(group < CONNECTOR_QUANTITY) { if(ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity > 0) { #if ONE_MODULE_OUTPUT // for safety test (inrush current) if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.InPrechargeMode) { PsuSingleOnOff(ShmPsuPosition->GroupLocationInfo[group].PsuSN[0], power_on_off); } else { PsuGroupOnOff(group, power_on_off); } #else PsuGroupOnOff(group, power_on_off); #endif LedGroupOnOff(group, power_on_off); } isStartOutputSwitch[group] = power_on_off == _PSU_ON ? true : false; } } // master: master group index unsigned short GetPresentTargetCurrent(unsigned char master, unsigned char role_condition) { unsigned char slave = 0; unsigned short current = 0; current = ShmPsuGrouping->GroupOutput[master].GTargetCurrent; for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; if(role_condition == _GROLE_MASTER || ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE) { current += ShmPsuGrouping->GroupOutput[slave].GTargetCurrent; } } return current; } // group: group index int GetPsuModuleQuantity(unsigned char group) { int quantity = 0; unsigned char slave = 0; quantity = ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; for(int i = 0; i < ShmPsuGrouping->GroupCollection[group].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[group].Partner.Member[i]; quantity += ShmPsuData->PsuGroup[slave].GroupPresentPsuQuantity; } return quantity; } // group: group index bool IsAvailableGroup(unsigned char group) { return ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity > 0 ? true : false; } // master: master group index int GetMasterAvailableGroup(unsigned char master) { int quantity = 0; unsigned char slave = 0; quantity = IsAvailableGroup(master) ? quantity + 1 : quantity; for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; quantity = IsAvailableGroup(slave) ? quantity + 1 : quantity; } return quantity; } // group: group index void UpdateGunLoading(unsigned char group) { if(ShmChargerInfo->PsuGrouping.GroupCollection[group].TargetGroup != 0 && group == ShmChargerInfo->PsuGrouping.GroupCollection[group].TargetGroup - 1) { unsigned short TargetCurrent = (int)(chargingInfo[group]->EvBatterytargetCurrent * 10); ShmPsuGrouping->GroupCollection[group].GunLoading = chargingInfo[group]->AvailableChargingCurrent != 0 ? (TargetCurrent * 10000 / (int)chargingInfo[group]->AvailableChargingCurrent) : 0; if(chargingInfo[group]->PresentChargingVoltage >= (PSU_MIN_VOL / 10)) { // unit: 1kW float _diffPowerByCurrent = 0, _diffPowerByPower = 0, _presentTargerPower = 0; _presentTargerPower = ((((float)ShmPsuGrouping->TotalGroupOutput[group].GTargetCurrent / 10) * chargingInfo[group]->PresentChargingVoltage) / 1000); // DiffPower_Available ShmPsuGrouping->GroupCollection[group].DiffPower_Available = (((float)(chargingInfo[group]->AvailableChargingCurrent - ShmPsuGrouping->TotalGroupOutput[group].GTargetCurrent) / 10) * chargingInfo[group]->PresentChargingVoltage) / 1000; // DiffPower_Capability _diffPowerByCurrent = (((float)(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[group].CapabilityCurrent - ShmPsuGrouping->TotalGroupOutput[group].GTargetCurrent) / 10) * chargingInfo[group]->PresentChargingVoltage) / 1000; _diffPowerByPower = (ShmSysConfigAndInfo->SysInfo.ConnectorInfo[group].CapabilityPower / 10) - _presentTargerPower; ShmPsuGrouping->GroupCollection[group].DiffPower_Capability = _diffPowerByPower < _diffPowerByCurrent ? _diffPowerByPower : _diffPowerByCurrent; // DiffPower_PhysicalLimit ShmPsuGrouping->GroupCollection[group].DiffPower_PhysicalLimit = (((float)(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[group].RemoteMaxPhysicalCurrent - ShmPsuGrouping->TotalGroupOutput[group].GTargetCurrent) / 10) * chargingInfo[group]->PresentChargingVoltage) / 1000; // DiffPower_ConfigLimit _diffPowerByCurrent = (((float)(ShmChargerInfo->OutputLimit.GunLimitCurrent[group] - ShmPsuGrouping->TotalGroupOutput[group].GTargetCurrent) / 10) * chargingInfo[group]->PresentChargingVoltage) / 1000; _diffPowerByPower = (ShmChargerInfo->OutputLimit.GunLimitPower[group] / 10) - _presentTargerPower; ShmPsuGrouping->GroupCollection[group].DiffPower_ConfigLimit = _diffPowerByPower < _diffPowerByCurrent ? _diffPowerByPower : _diffPowerByCurrent; } else { ShmPsuGrouping->GroupCollection[group].DiffPower_Available = 0; ShmPsuGrouping->GroupCollection[group].DiffPower_Capability = 0; ShmPsuGrouping->GroupCollection[group].DiffPower_PhysicalLimit = 0; ShmPsuGrouping->GroupCollection[group].DiffPower_ConfigLimit = 0; } } else { ShmPsuGrouping->GroupCollection[group].GunLoading = 0; } } // group: group index void UpdatePsuGroupLoading(unsigned char group) { ShmPsuGrouping->GroupOutput[group].OutputLoading = ShmPsuData->PsuGroup[group].GroupAvailableCurrent != 0 ? (ShmPsuGrouping->GroupOutput[group].GTargetCurrent * 10000 / ShmPsuData->PsuGroup[group].GroupAvailableCurrent) : 0; } // master: master group index void UpdateMasterPsuGroupLoading(unsigned char master) { unsigned char slave = 0; UpdatePsuGroupLoading(master); for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; UpdatePsuGroupLoading(slave); } } void PsuGroupIncreaseCurrent(unsigned char group, unsigned short needIncrease, unsigned short *realIncreaseCurrent) { unsigned short increase = needIncrease; if((ShmPsuGrouping->GroupOutput[group].GTargetCurrent + increase) <= ShmPsuData->PsuGroup[group].GroupAvailableCurrent) { ShmPsuGrouping->GroupOutput[group].GTargetCurrent += increase; } else { increase = ShmPsuData->PsuGroup[group].GroupAvailableCurrent - ShmPsuGrouping->GroupOutput[group].GTargetCurrent; ShmPsuGrouping->GroupOutput[group].GTargetCurrent = ShmPsuData->PsuGroup[group].GroupAvailableCurrent; } *realIncreaseCurrent += increase; } void PsuGroupDecreaseCurrent(unsigned char group, unsigned short needDecrease, unsigned short *realDecreaseCurrent) { unsigned short decrease = needDecrease; if(ShmPsuGrouping->GroupOutput[group].GTargetCurrent >= (decrease + ZERO_CURRENT)) { ShmPsuGrouping->GroupOutput[group].GTargetCurrent -= decrease; } else { decrease = ShmPsuGrouping->GroupOutput[group].GTargetCurrent - ZERO_CURRENT; ShmPsuGrouping->GroupOutput[group].GTargetCurrent = ZERO_CURRENT; } *realDecreaseCurrent += decrease; } void IncreaseCurrentByGunLoading(unsigned char group, unsigned short loading, unsigned short *realIncrease, unsigned short MaxIncrease) { unsigned short target = 0, need = 0; if(*realIncrease >= MaxIncrease) { return; } target = (loading * ShmPsuData->PsuGroup[group].GroupAvailableCurrent) / 10000; need = target >= ShmPsuGrouping->GroupOutput[group].GTargetCurrent ? (target - ShmPsuGrouping->GroupOutput[group].GTargetCurrent) : 0; need = need > (MaxIncrease - *realIncrease) ? (MaxIncrease - *realIncrease) : need; //LOG_INFO("Group [%02X] Target Current %d.%d A, Increase Current: %d.%d A", // group, (target / 10), (target % 10), (need / 10), (need % 10)); if(need > 0) { PsuGroupIncreaseCurrent(group, need, realIncrease); } } void DecreaseCurrentByGunLoading(unsigned char group, unsigned short loading, unsigned short *realDecrease, unsigned short MaxDecrease) { unsigned short target = 0, need = 0; if(*realDecrease >= MaxDecrease) { return; } target = (loading * ShmPsuData->PsuGroup[group].GroupAvailableCurrent) / 10000; need = ShmPsuGrouping->GroupOutput[group].GTargetCurrent >= target ? (ShmPsuGrouping->GroupOutput[group].GTargetCurrent - target) : 0; need = need > (MaxDecrease - *realDecrease) ? (MaxDecrease - *realDecrease) : need; //LOG_INFO("Group [%02X] Target Current %d.%d A, Decrease Current: %d.%d A", // group, (target / 10), (target % 10), (need / 10), (need % 10)); if(need > 0) { PsuGroupDecreaseCurrent(group, need, realDecrease); } } // master: master group index void AverageIncreaseCurrent(unsigned char master, unsigned short NeedIncreaseCurrent) { unsigned char availableGroup = 0, slave = 0; unsigned short avgGroupCurrent = 0, excessCurrent = 0, realIncrease = 0; unsigned char OutputMaster = 0; #if PSU_DEBUG_MSG PSU_LOG("Gun %d Increase By GunLoading %d.%02d Percent", master + 1, (ShmPsuGrouping->GroupCollection[master].GunLoading / 100), (ShmPsuGrouping->GroupCollection[master].GunLoading % 100)); #endif OutputMaster = ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0 ? master : (ShmPsuGrouping->GroupCollection[master].AlternateMaster - 1); if(ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0) { IncreaseCurrentByGunLoading(master, ShmPsuGrouping->GroupCollection[master].GunLoading, &realIncrease, NeedIncreaseCurrent); } for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; IncreaseCurrentByGunLoading(slave, ShmPsuGrouping->GroupCollection[master].GunLoading, &realIncrease, NeedIncreaseCurrent); } availableGroup = GetMasterAvailableGroup(master); if(NeedIncreaseCurrent > realIncrease && availableGroup > 0) { // increase current by group quantity avgGroupCurrent = (NeedIncreaseCurrent - realIncrease) / availableGroup; #if PSU_DEBUG_MSG PSU_LOG("Gun %d Increase By Group, AvgGroupCurrent %d.%d A", master + 1, (avgGroupCurrent / 10), (avgGroupCurrent % 10)); #endif if(ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0) { PsuGroupIncreaseCurrent(master, avgGroupCurrent, &realIncrease); } for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; PsuGroupIncreaseCurrent(slave, avgGroupCurrent, &realIncrease); } } if(NeedIncreaseCurrent > realIncrease) { // increase excess current to master group excessCurrent = NeedIncreaseCurrent - realIncrease; #if PSU_DEBUG_MSG PSU_LOG("Gun %d Increase, ExcessCurrent %d.%d A", master + 1, (excessCurrent / 10), (excessCurrent % 10)); #endif PsuGroupIncreaseCurrent(OutputMaster, excessCurrent, &realIncrease); } } // master: master group index void AverageDecreaseCurrent(unsigned char master, unsigned short NeedDecreaseCurrent) { unsigned char availableGroup = 0, slave = 0; unsigned short avgGroupCurrent = 0, excessCurrent = 0, realDecrease = 0; unsigned char OutputMaster = 0; #if PSU_DEBUG_MSG PSU_LOG("Gun %d Decrease By GunLoading %d.%02d Percent", master + 1, (ShmPsuGrouping->GroupCollection[master].GunLoading / 100), (ShmPsuGrouping->GroupCollection[master].GunLoading % 100)); #endif OutputMaster = ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0 ? master : (ShmPsuGrouping->GroupCollection[master].AlternateMaster - 1); if(ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0) { DecreaseCurrentByGunLoading(master, ShmPsuGrouping->GroupCollection[master].GunLoading, &realDecrease, NeedDecreaseCurrent); } for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; DecreaseCurrentByGunLoading(slave, ShmPsuGrouping->GroupCollection[master].GunLoading, &realDecrease, NeedDecreaseCurrent); } availableGroup = GetMasterAvailableGroup(master); if(NeedDecreaseCurrent > realDecrease) { // decrease current by group quantity avgGroupCurrent = (NeedDecreaseCurrent - realDecrease) / availableGroup; #if PSU_DEBUG_MSG PSU_LOG("Gun %d Decrease By Group, AvgGroupCurrent %d.%d A", master + 1, (avgGroupCurrent / 10), (avgGroupCurrent % 10)); #endif if(ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0) { PsuGroupDecreaseCurrent(master, avgGroupCurrent, &realDecrease); } for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; PsuGroupDecreaseCurrent(slave, avgGroupCurrent, &realDecrease); } } if(NeedDecreaseCurrent > realDecrease) { // decrease excess current excessCurrent = NeedDecreaseCurrent - realDecrease; #if PSU_DEBUG_MSG PSU_LOG("Gun %d Decrease, ExcessCurrent %d.%d A", master + 1, (excessCurrent / 10), (excessCurrent % 10)); #endif PsuGroupDecreaseCurrent(OutputMaster, excessCurrent, &realDecrease); } } void MasterIncreaseCurrent(unsigned char master, unsigned short NeedIncreaseCurrent) { unsigned short excessCurrent = 0, realIncrease = 0; PsuGroupIncreaseCurrent(master, NeedIncreaseCurrent, &realIncrease); if(NeedIncreaseCurrent > realIncrease) { excessCurrent = NeedIncreaseCurrent - realIncrease; AverageIncreaseCurrent(master, excessCurrent); } } void MasterDecreaseCurrent(unsigned char master, unsigned short NeedDecreaseCurrent) { unsigned char slave = 0; unsigned short avgGroupCurrent = 0, excessCurrent = 0, realDecrease = 0; if(ShmPsuGrouping->GroupCollection[master].Partner.RealQuantity > 0) { // decrease current by group quantity avgGroupCurrent = NeedDecreaseCurrent / ShmPsuGrouping->GroupCollection[master].Partner.RealQuantity; #if PSU_DEBUG_MSG PSU_LOG("Gun %d Decrease By Group, AvgGroupCurrent %d.%d A", master + 1, (avgGroupCurrent / 10), (avgGroupCurrent % 10)); #endif for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; if(ShmPsuData->PsuGroup[slave].GroupPresentPsuQuantity > 0) { PsuGroupDecreaseCurrent(slave, avgGroupCurrent, &realDecrease); } } } if(NeedDecreaseCurrent > realDecrease) { excessCurrent = NeedDecreaseCurrent - realDecrease; PsuGroupDecreaseCurrent(master, excessCurrent, &realDecrease); } } void UpdateMaxCurrent(unsigned char master, unsigned short current) { int time = 0; // update max stage current if(current > StageMaxCurrent[master]) { StageMaxCurrent[master] = current; ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ReachMaxStageCurrent = false; GetClockTime(&_StageCurrent_time[master]); } if(!ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ReachMaxStageCurrent) { time = GetTimeoutValue(_StageCurrent_time[master]) / uSEC_VAL; if(time >= EV_MAX_STAGE_CURRENT_DELAY) { ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ReachMaxStageCurrent = true; LOG_INFO("Gun %d Reach Max Stage Current", master + 1); } } // update max target current and reset max current time if(current > MaxCurrentDemand[master]) { if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ReachMaxCurrentDemand) { LOG_INFO("Gun %d Max Current Demand Timer Reset", master + 1); } MaxCurrentDemand[master] = current; ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ReachMaxCurrentDemand = false; GetClockTime(&_MaxCurrent_time[master]); } if(!ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ReachMaxCurrentDemand) { time = GetTimeoutValue(_MaxCurrent_time[master]) / uSEC_VAL; if(time >= EV_MAX_CURRENT_DELAY) { ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ReachMaxCurrentDemand = true; LOG_INFO("Gun %d Reach Max Current Demand", master + 1); } } } // master: master group index bool IsMasterOutputCurrentStable(unsigned char master) { int time = 0; bool stable = false, reachTarget = false; unsigned short presentOutput = (int)chargingInfo[master]->PresentChargingCurrent * 10; unsigned short TargetCurrent = 0; TargetCurrent = (int)(chargingInfo[master]->EvBatterytargetCurrent * 10); reachTarget = presentOutput > (TargetCurrent - REACH_CURRENT_TOLERANCE) && presentOutput < (TargetCurrent + REACH_CURRENT_TOLERANCE); if((presentOutput >= StableOutputCurrent[master] && presentOutput - StableOutputCurrent[master] > REACH_CURRENT_TOLERANCE) || (presentOutput < StableOutputCurrent[master] && StableOutputCurrent[master] - presentOutput > REACH_CURRENT_TOLERANCE)) { GetClockTime(&_ReachCurrent_time[master]); StableOutputCurrent[master] = presentOutput; } time = GetTimeoutValue(_ReachCurrent_time[master]) / uSEC_VAL; if(reachTarget || time >= CURRENT_STABLE_TIME || (ShmChargerInfo->Control.FCharging[master].FCtrl.bits.EnableForceCharging && time >= CURRENT_REACH_TARGET_TIME)) { stable = true; } return stable; } // master: master group index void MasterBalanceCurrent(unsigned char master) { int time = 0; unsigned char slave = 0; unsigned short realBalance = 0, grabCurrent = 0; time = GetTimeoutValue(_BalanceCurrent_time[master]) / mSEC_VAL; if(time >= BALANCE_CURRENT_INTERVAL) { //LOG_INFO("Gun %d Start Balance Current", master + 1); if(ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0) { DecreaseCurrentByGunLoading(master, ShmPsuGrouping->GroupCollection[master].GunLoading, &grabCurrent, MAX_ADJ_BALANCE_CURRENT); } for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; DecreaseCurrentByGunLoading(slave, ShmPsuGrouping->GroupCollection[master].GunLoading, &grabCurrent, MAX_ADJ_BALANCE_CURRENT); } //LOG_INFO("Gun %d Grab Balance Current %d.%d A", master + 1, (grabCurrent / 10), (grabCurrent % 10)); if(ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0) { IncreaseCurrentByGunLoading(master, ShmPsuGrouping->GroupCollection[master].GunLoading, &realBalance, grabCurrent); } for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; IncreaseCurrentByGunLoading(slave, ShmPsuGrouping->GroupCollection[master].GunLoading, &realBalance, grabCurrent); } //LOG_INFO("Gun %d Increase Balance Current %d.%d A", master + 1, (realBalance / 10), (realBalance % 10)); UpdateMasterPsuGroupLoading(master); GetClockTime(&_BalanceCurrent_time[master]); } } unsigned short GetLoadingDiff(unsigned char master) { unsigned char slave = 0; unsigned short maxLoading = 0, minLoading = 0, diffLoading = 0; unsigned char OutputMaster = 0; OutputMaster = ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0 ? master : (ShmPsuGrouping->GroupCollection[master].AlternateMaster - 1); maxLoading = ShmPsuGrouping->GroupOutput[OutputMaster].OutputLoading; minLoading = ShmPsuGrouping->GroupOutput[OutputMaster].OutputLoading; for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; if(ShmPsuData->PsuGroup[slave].GroupPresentPsuQuantity == 0 || ShmPsuData->PsuGroup[slave].GroupAvailableCurrent == 0) { continue; } maxLoading = ShmPsuGrouping->GroupOutput[slave].OutputLoading > maxLoading ? ShmPsuGrouping->GroupOutput[slave].OutputLoading : maxLoading; minLoading = ShmPsuGrouping->GroupOutput[slave].OutputLoading < minLoading ? ShmPsuGrouping->GroupOutput[slave].OutputLoading : minLoading; } diffLoading = maxLoading - minLoading; return diffLoading; } void CheckCurrentBalance(unsigned char master) { unsigned short diffLoading = 0; diffLoading = GetLoadingDiff(master); if(!ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.NeedCurrentBalance) { if(diffLoading >= START_BALANCE_CRITERIA) { ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.NeedCurrentBalance = true; PSU_LOG("Gun %d Output Current Is Unbalance, diffLoading = %d.%02d", master + 1, (diffLoading / 100), (diffLoading % 100)); GetClockTime(&_BalanceCurrent_time[master]); } } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.NeedCurrentBalance) { MasterBalanceCurrent(master); diffLoading = GetLoadingDiff(master); if(diffLoading <= STOP_BALANCE_CRITERIA) { ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.NeedCurrentBalance = false; PSU_LOG("Gun %d Output Current Is Balance", master + 1); } } } // master: master group index // slave: slave group index bool IsGroupPartner(unsigned char master, unsigned char slave) { bool find = false; for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { if(slave == ShmPsuGrouping->GroupCollection[master].Partner.Member[i]) { find = true; break; } } return find; } void CleanSmoothDerating(unsigned char master) { ShmPsuGrouping->GroupCollection[master].SmoothDeratingTarget = 0; ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.SmoothDerating = false; } void SetSmoothDerating(unsigned char master, unsigned char slave) { ShmPsuGrouping->GroupCollection[master].SmoothDeratingTarget = slave + 1; ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.SmoothDerating = true; GetClockTime(&_SmoothDerating_time[master]); } // master: master group index void CheckSmoothBalance(unsigned char master) { int time = 0; unsigned char slave = 0; unsigned short realBalance = 0, grabCurrent = 0; unsigned char _ReleaseSlave = 0; if(ShmPsuGrouping->GroupCollection[master].SmoothDeratingTarget == 0 || !IsGroupPartner(master, ShmPsuGrouping->GroupCollection[master].SmoothDeratingTarget - 1)) { CleanSmoothDerating(master); LOG_INFO("Gun %d Smooth Derating Target Is Not Available!", master + 1); return; } unsigned short _CapCurrent = 0; // unit: 0.1A unsigned short _ReleaseCurrent = 0; // unit: 0.1A unsigned short _ReleaseLoading = 0; // unit: 0.01% unsigned short TargetCurrent = 0; // unit: 0.1A PsuGroupPartner ReleaseMember; _CapCurrent = (int)ShmSysConfigAndInfo->SysInfo.ConnectorInfo[master].CapabilityCurrent; TargetCurrent = (int)(chargingInfo[master]->EvBatterytargetCurrent * 10); _ReleaseSlave = ShmPsuGrouping->GroupCollection[master].SmoothDeratingTarget - 1; _ReleaseCurrent = (int)chargingInfo[master]->AvailableChargingCurrent > (int)ShmPsuData->PsuGroup[_ReleaseSlave].GroupAvailableCurrent ? (int)chargingInfo[master]->AvailableChargingCurrent - (int)ShmPsuData->PsuGroup[_ReleaseSlave].GroupAvailableCurrent : 0; _ReleaseLoading = _ReleaseCurrent != 0 ? (TargetCurrent * 10000 / _ReleaseCurrent) : 0; if(ShmPsuGrouping->GroupOutput[_ReleaseSlave].GTargetCurrent <= MAX_ADJ_BALANCE_CURRENT) { float originalPower = 0, capabilityPower = 0, releasePower = 0; memset(&ReleaseMember, 0x00, sizeof(PsuGroupPartner)); ReleaseMember.Member[0] = _ReleaseSlave; ReleaseMember.Quantity = 1; PrepareToPowerOff(0, &ReleaseMember); originalPower = ((chargingInfo[master]->AvailableChargingCurrent / 10) * chargingInfo[master]->PresentChargingVoltage) / 1000; capabilityPower = ((ShmSysConfigAndInfo->SysInfo.ConnectorInfo[master].CapabilityCurrent / 10) * chargingInfo[master]->PresentChargingVoltage) / 1000; releasePower = (((float)(_ReleaseCurrent) / 10) * chargingInfo[master]->PresentChargingVoltage) / 1000; LOG_INFO("Gun %d Smooth Release [%02X]", master + 1, ReleaseMember.Member[0]); LOG_INFO("Gun %d Available %d A (%d kW) >> %d A (%d kW)", master + 1, ((int)chargingInfo[master]->AvailableChargingCurrent / 10), (int)originalPower, (_ReleaseCurrent / 10), (int)releasePower); LOG_INFO("Gun %d Capability %d A (%d kW) >> %d A (%d kW)", master + 1, ((int)ShmSysConfigAndInfo->SysInfo.ConnectorInfo[master].CapabilityCurrent / 10), (int)capabilityPower, _ReleaseCurrent >= _CapCurrent ? (_CapCurrent / 10) : (_ReleaseCurrent / 10), (int)releasePower); CleanSmoothDerating(master); return; } time = GetTimeoutValue(_SmoothDerating_time[master]) / mSEC_VAL; if(time >= SMOOTH_DERATING_INTERVAL) { DecreaseCurrentByGunLoading(master, _ReleaseLoading, &grabCurrent, MAX_ADJ_BALANCE_CURRENT); for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; if(slave != _ReleaseSlave) { DecreaseCurrentByGunLoading(slave, _ReleaseLoading, &grabCurrent, MAX_ADJ_BALANCE_CURRENT); } else { DecreaseCurrentByGunLoading(slave, 0, &grabCurrent, MAX_ADJ_BALANCE_CURRENT); } } //LOG_INFO("Gun %d Grab Balance Current %d.%d A", master + 1, (grabCurrent / 10), (grabCurrent % 10)); IncreaseCurrentByGunLoading(master, _ReleaseLoading, &realBalance, grabCurrent); for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; if(slave != _ReleaseSlave) { IncreaseCurrentByGunLoading(slave, _ReleaseLoading, &realBalance, grabCurrent); } } //LOG_INFO("Gun %d Increase Balance Current %d.%d A", master + 1, (realBalance / 10), (realBalance % 10)); UpdateMasterPsuGroupLoading(master); GetClockTime(&_SmoothDerating_time[master]); } } bool IsOtherCharging(unsigned char group) { bool find = false; int other = 0, selfTarget = 0, location = 0; if(ShmPsuGrouping->GroupCollection[group].TargetGroup == 0) { return find; } selfTarget = ShmPsuGrouping->GroupCollection[group].TargetGroup - 1; // search from left location = ShmPsuGrouping->GroupCollection[group].Location - 1; for(int i = location; i >= 0; i--) { other = ShmPsuGrouping->Layout[i]; if(ShmPsuGrouping->GroupCollection[other].Role == _GROLE_MASTER) { find = other != selfTarget ? true : false; break; } } if(!find) { // search from right location = ShmPsuGrouping->GroupCollection[group].Location + 1; for(int i = location; i < ShmChargerInfo->Control.MaxConnector; i++) { other = ShmPsuGrouping->Layout[i]; if(ShmPsuGrouping->GroupCollection[other].Role == _GROLE_MASTER) { find = other != selfTarget ? true : false; break; } } } return find; } // master: master group index void MasterReleasePsuGroup(unsigned char master) { bool findOtherInCharging = false; unsigned char slave = 0, member = 0, releaseTarget = 0; unsigned char otherCharging[MAX_GROUP_QUANTITY] = {0}; unsigned char releaseList[MAX_GROUP_QUANTITY] = {0}; float releasePower[MAX_GROUP_QUANTITY] = {0}; unsigned short releaseCurrent[MAX_GROUP_QUANTITY] = {0}; PsuGroupPartner ReleaseMember; unsigned short target = 0, oriAvailableCurrent = 0, oriCapabilityCurrent = 0, maxReleaseCurrent = 0; float targetPower = 0, oriAvailablePower = 0, capabilityPower = 0, maxReleasePower = 0; if(ShmChargerInfo->PsuGrouping.GroupCollection[master].Role != _GROLE_MASTER || ShmPsuGrouping->GroupCollection[master].Partner.Quantity == 0) { return; } target = (int)(chargingInfo[master]->EvBatterytargetCurrent * 10); targetPower = (((float)(target) / 10) * chargingInfo[master]->PresentChargingVoltage) / 1000; oriAvailableCurrent = (int)chargingInfo[master]->AvailableChargingCurrent; oriAvailablePower = (((float)oriAvailableCurrent / 10) * chargingInfo[master]->PresentChargingVoltage) / 1000; oriCapabilityCurrent = (int)ShmSysConfigAndInfo->SysInfo.ConnectorInfo[master].CapabilityCurrent; capabilityPower = (((float)oriCapabilityCurrent / 10) * chargingInfo[master]->PresentChargingVoltage) / 1000; for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; unsigned short current = 0; PsuGroupPowerOffCheck(slave, &ReleaseMember); otherCharging[i] = IsOtherCharging(slave); findOtherInCharging = otherCharging[i] ? otherCharging[i] : findOtherInCharging; releaseList[i] = slave; for(int j = 0; j < ReleaseMember.Quantity; j++) { member = ReleaseMember.Member[j]; current += ShmPsuData->PsuGroup[member].GroupAvailableCurrent; } releaseCurrent[i] = current; float power = (((float)(oriAvailableCurrent - releaseCurrent[i]) / 10) * chargingInfo[master]->PresentChargingVoltage) / 1000; if(power >= (targetPower + MAX_DIFF_POWER_TO_DERATING) || (oriAvailableCurrent - releaseCurrent[i]) >= oriCapabilityCurrent) { releasePower[i] = power; } else { releasePower[i] = 0; } //LOG_INFO("Gun %d Release [%02X], Total Release %d Group, Gun Loading %d.%02d >> %d.%02d", master + 1, slave, ReleaseMember.Quantity, // (originalLoading / 100), (originalLoading % 100), // (releaseLoading[i] / 100), (releaseLoading[i] % 100)); } for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { if((otherCharging[i] || !findOtherInCharging) && releasePower[i] > maxReleasePower && releasePower[i] != 0) { maxReleasePower = releasePower[i]; maxReleaseCurrent = releaseCurrent[i]; releaseTarget = releaseList[i]; } } if(maxReleasePower > 0) { unsigned short _current = 0; _current = oriAvailableCurrent - maxReleaseCurrent; ShmPsuGrouping->GroupCollection[releaseTarget].GroupCtrl.bits.SlavePowerOffRequest = true; LOG_INFO("Gun %d Set [%02X] Release(%s)", master + 1, releaseTarget, findOtherInCharging ? "Other In Charging" : "Normal"); LOG_INFO("Gun %d Available %d A (%d kW) >> %d A (%d kW)", master + 1, (oriAvailableCurrent / 10), (int)oriAvailablePower, (_current / 10), (int)maxReleasePower); LOG_INFO("Gun %d Capability %d A (%d kW) >> %d A (%d kW)", master + 1, (oriCapabilityCurrent / 10), (int)capabilityPower, _current >= oriCapabilityCurrent ? (oriCapabilityCurrent / 10) : (_current / 10), (int)maxReleasePower); } } // master: master group index void MasterDynamicRelease(unsigned char master) { unsigned char slave = 0; PsuGroupPartner ReleaseMember; unsigned short target = 0, releaseCurrent = 0, originalAvailable = 0, originalCapability = 0; float targetPower = 0, originalPower = 0, capabilityPower = 0, releasePower = 0; if(ShmChargerInfo->PsuGrouping.GroupCollection[master].Role != _GROLE_MASTER || ShmPsuGrouping->GroupCollection[master].Partner.Quantity == 0) { return; } target = (int)(chargingInfo[master]->EvBatterytargetCurrent * 10); targetPower = (((float)(target) / 10) * chargingInfo[master]->PresentChargingVoltage) / 1000; originalAvailable = (int)chargingInfo[master]->AvailableChargingCurrent; originalCapability = (int)ShmSysConfigAndInfo->SysInfo.ConnectorInfo[master].CapabilityCurrent; releaseCurrent = 0; memset(&ReleaseMember, 0x00, sizeof(PsuGroupPartner)); for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; releasePower = (((float)(originalAvailable - releaseCurrent - ShmPsuData->PsuGroup[slave].GroupAvailableCurrent) / 10) * chargingInfo[master]->PresentChargingVoltage) / 1000; if(releasePower >= (targetPower + MAX_DIFF_POWER_TO_DERATING) || (originalAvailable - releaseCurrent - ShmPsuData->PsuGroup[slave].GroupAvailableCurrent) >= originalCapability) { releaseCurrent += ShmPsuData->PsuGroup[slave].GroupAvailableCurrent; ReleaseMember.Member[ReleaseMember.Quantity] = slave; ReleaseMember.Quantity++; } } if(ReleaseMember.Quantity > 0) { char strMember[64]; memset(strMember, 0x00, sizeof(strMember)); for(int i = 0; i < ReleaseMember.Quantity; i++) { char strTemp[16]; sprintf(strTemp, " [%02X]", ReleaseMember.Member[i]); strcat(strMember, strTemp); } PrepareToPowerOff(0, &ReleaseMember); originalPower = (((float)originalAvailable / 10) * chargingInfo[master]->PresentChargingVoltage) / 1000; capabilityPower = (((float)originalCapability / 10) * chargingInfo[master]->PresentChargingVoltage) / 1000; releasePower = (((float)(originalAvailable - releaseCurrent) / 10) * chargingInfo[master]->PresentChargingVoltage) / 1000; LOG_INFO("Gun %d Direct Release%s", master + 1, strMember); LOG_INFO("Gun %d Available %d A (%d kW) >> %d A (%d kW)", master + 1, (originalAvailable / 10), (int)originalPower, ((originalAvailable - releaseCurrent) / 10), (int)releasePower); LOG_INFO("Gun %d Capability %d A (%d kW) >> %d A (%d kW)", master + 1, (originalCapability / 10), (int)capabilityPower, ((originalAvailable - releaseCurrent) / 10), (int)releasePower); } } void FindDeratingPriority(unsigned char master, PsuGroupPartner *tPartner) { unsigned char slave = 0; memset(tPartner, 0x00, sizeof(PsuGroupPartner)); if((ShmChargerInfo->Control.MaxConnector - 1 - ShmPsuGrouping->GroupCollection[master].Location) > ShmPsuGrouping->GroupCollection[master].Location - 0) { for(int i = ShmChargerInfo->Control.MaxConnector - 1; i >= 0; i--) { slave = ShmPsuGrouping->Layout[i]; if(slave != master) { if((ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1) == master && (ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0 || slave != (ShmPsuGrouping->GroupCollection[master].AlternateMaster - 1))) { tPartner->Member[tPartner->Quantity++] = slave; } } else { break; } } for(int i = 0; i < ShmChargerInfo->Control.MaxConnector; i++) { slave = ShmPsuGrouping->Layout[i]; if(slave != master) { if((ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1) == master && (ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0 || slave != (ShmPsuGrouping->GroupCollection[master].AlternateMaster - 1))) { tPartner->Member[tPartner->Quantity++] = slave; } } else { break; } } } else { for(int i = 0; i < ShmChargerInfo->Control.MaxConnector; i++) { slave = ShmPsuGrouping->Layout[i]; if(slave != master) { if((ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1) == master && (ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0 || slave != (ShmPsuGrouping->GroupCollection[master].AlternateMaster - 1))) { tPartner->Member[tPartner->Quantity++] = slave; } } else { break; } } for(int i = ShmChargerInfo->Control.MaxConnector - 1; i >= 0; i--) { slave = ShmPsuGrouping->Layout[i]; if(slave != master) { if((ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1) == master && (ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0 || slave != (ShmPsuGrouping->GroupCollection[master].AlternateMaster - 1))) { tPartner->Member[tPartner->Quantity++] = slave; } } else { break; } } } } // master: master group index void CheckSmoothDerating(unsigned char master) { unsigned char slave = 0; unsigned short target = 0, originalAvailable = 0, originalCapability = 0; float targetPower = 0, releasePower = 0; PsuGroupPartner releasePriority; if(ShmChargerInfo->PsuGrouping.GroupCollection[master].Role != _GROLE_MASTER || ShmPsuGrouping->GroupCollection[master].Partner.Quantity == 0 || ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.SmoothDerating) { return; } target = (int)(chargingInfo[master]->EvBatterytargetCurrent * 10); targetPower = (((float)(target) / 10) * chargingInfo[master]->PresentChargingVoltage) / 1000; originalAvailable = (int)chargingInfo[master]->AvailableChargingCurrent; originalCapability = (int)ShmSysConfigAndInfo->SysInfo.ConnectorInfo[master].CapabilityCurrent; FindDeratingPriority(master, &releasePriority); for(int i = 0; i < releasePriority.Quantity; i++) { slave = releasePriority.Member[i]; releasePower = (((float)(originalAvailable - ShmPsuData->PsuGroup[slave].GroupAvailableCurrent) / 10) * chargingInfo[master]->PresentChargingVoltage) / 1000; if(releasePower >= (targetPower + MAX_DIFF_POWER_TO_DERATING) || (originalAvailable - ShmPsuData->PsuGroup[slave].GroupAvailableCurrent) >= originalCapability) { SetSmoothDerating(master, slave); LOG_INFO("Gun %d Set Smooth Derating Member: [%02X]", master + 1, slave); break; } } /* for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; releasePower = (((float)(originalAvailable - ShmPsuData->PsuGroup[slave].GroupAvailableCurrent) / 10) * chargingInfo[master]->PresentChargingVoltage) / 1000; if(releasePower >= (targetPower + MAX_DIFF_POWER_TO_DERATING) || (originalAvailable - ShmPsuData->PsuGroup[slave].GroupAvailableCurrent) >= originalCapability) { SetSmoothDerating(master, slave); LOG_INFO("Gun %d Set Smooth Derating Member: [%02X]", master + 1, slave); break; } } */ } void CheckReleaseOrExtend(unsigned char master) { int time = 0; PsuGroupPartner partner; if((ShmChargerInfo->Control.TestCtrl.bits.ChargingSimulation || Is_EnableReleaseAndExtendWhenForceCharging(master)) && ShmPsuGrouping->GroupCollection[master].GroupCtrl.RoleCtrl.DeratingCtrlValue == 0 && ShmPsuGrouping->GroupCollection[master].GroupCtrl.RoleCtrl.ExtendCapabilityCtrlValue == 0) { if(ShmPsuGrouping->GroupCollection[master].DiffPower_Available >= MIN_RELEASE_POWER) { if((ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0 && ShmPsuGrouping->GroupCollection[master].Partner.Quantity > 0) || (ShmPsuGrouping->GroupCollection[master].AlternateMaster != 0 && ShmPsuGrouping->GroupCollection[master].Partner.Quantity > 1)) { if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ReachMaxStageCurrent && ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ReachMaxCurrentDemand) { #if ENABLE_SMOOTH_DERATING == 0 if(ShmChargerInfo->Control.SysCtrl.bits.Enable6ParallelRelay == 0) { MasterReleasePsuGroup(master); } else { MasterDynamicRelease(master); } #else CheckSmoothDerating(master); #endif } } } else if(ShmPsuGrouping->GroupCollection[master].DiffPower_Available < MAX_DIFF_POWER_TO_EXTEND && ShmPsuGrouping->GroupCollection[master].DiffPower_Capability < MAX_DIFF_POWER_TO_EXTEND && ShmPsuGrouping->GroupCollection[master].DiffPower_PhysicalLimit >= MIN_DIFF_PHYSICAL_POWER) { time = GetSecTimeoutValue(_ExtendCapability_time[master]); if(time >= EXTEND_AFTER_DERATING_DELAY) { int available = GetPsuGroupAvailable(master); if(available > 0) { if(ShmPsuGrouping->GroupCollection[master].DiffPower_ConfigLimit >= MIN_DIFF_CONFIG_POWER) { if(!ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendAvailable) { LOG_INFO("Gun %d Extend Capability Available, DifPcap: %.1f kW, DiffConfig: %.1f kW, DifPphy: %.1f kW", master + 1, ShmPsuGrouping->GroupCollection[master].DiffPower_Capability, ShmPsuGrouping->GroupCollection[master].DiffPower_ConfigLimit, ShmPsuGrouping->GroupCollection[master].DiffPower_PhysicalLimit); GetClockTime(&_ExtendCapability_time[master]); } ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendAvailable = true; } } else { if(!(ShmPsuGrouping->GroupCollection[master].DiffPower_ConfigLimit < MIN_DIFF_CONFIG_POWER && ShmChargerInfo->OutputLimit.IndividualLimit[master] > 0)) { // check & grab time = GetSecTimeoutValue(_ExtendGrab_time[master]); if(time >= EXTEND_GRAB_INTERVAL) { if(ExtendCapabilityGrabCheck(master, &partner)) { PrepareToPowerOff(0, &partner); } GetClockTime(&_ExtendGrab_time[master]); } } } } } } } bool IsPsuGroupOutputConfigDifferent(unsigned char group) { bool different = false; if(ShmPsuGrouping->GroupOutput[group].GTargetVoltage != PreGroupOutput[group].GTargetVoltage || ShmPsuGrouping->GroupOutput[group].GTargetCurrent != PreGroupOutput[group].GTargetCurrent) { different = true; } PreGroupOutput[group].GTargetVoltage = ShmPsuGrouping->GroupOutput[group].GTargetVoltage; PreGroupOutput[group].GTargetCurrent = ShmPsuGrouping->GroupOutput[group].GTargetCurrent; return different; } // Gun X Demand Change -> Voltage: XXXX.X V, Current: XXXX.X A, Available: XXXX.X A, Loading: XXX.XX // Master [XX] -> Voltage: XXXX.X V, Current: XXXX.X A, Available: XXXX.X A, Loading: XXX.XX // Member [XX] -> Voltage: XXXX.X V, Current: XXXX.X A, Available: XXXX.X A, Loading: XXX.XX void ShowPsuGroupOutputConfig(unsigned char master) { unsigned char slave = 0; PSU_LOG("Gun %d Demand Change -> Voltage: %4d V, Current: %4d.%d A, Available: %4d.%d A, Loading: %3d.%02d", master + 1, (ShmPsuGrouping->GroupOutput[master].GTargetVoltage / 10), ((int)chargingInfo[master]->EvBatterytargetCurrent), (((int)(chargingInfo[master]->EvBatterytargetCurrent * 10)) % 10), ((int)chargingInfo[master]->AvailableChargingCurrent / 10), ((int)chargingInfo[master]->AvailableChargingCurrent % 10), (ShmPsuGrouping->GroupCollection[master].GunLoading / 100), (ShmPsuGrouping->GroupCollection[master].GunLoading % 100)); PSU_LOG(" Master [%02X] -> Voltage: %4d V, Current: %4d.%d A, Available: %4d.%d A, Loading: %3d.%02d", master, (ShmPsuGrouping->GroupOutput[master].GTargetVoltage / 10), (ShmPsuGrouping->GroupOutput[master].GTargetCurrent / 10), (ShmPsuGrouping->GroupOutput[master].GTargetCurrent % 10), (ShmPsuData->PsuGroup[master].GroupAvailableCurrent / 10), (ShmPsuData->PsuGroup[master].GroupAvailableCurrent % 10), (ShmPsuGrouping->GroupOutput[master].OutputLoading / 100), (ShmPsuGrouping->GroupOutput[master].OutputLoading % 100)); for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; PSU_LOG(" Member [%02X] -> Voltage: %4d V, Current: %4d.%d A, Available: %4d.%d A, Loading: %3d.%02d", slave, (ShmPsuGrouping->GroupOutput[slave].GTargetVoltage / 10), (ShmPsuGrouping->GroupOutput[slave].GTargetCurrent / 10), (ShmPsuGrouping->GroupOutput[slave].GTargetCurrent % 10), (ShmPsuData->PsuGroup[slave].GroupAvailableCurrent / 10), (ShmPsuData->PsuGroup[slave].GroupAvailableCurrent % 10), (ShmPsuGrouping->GroupOutput[slave].OutputLoading / 100), (ShmPsuGrouping->GroupOutput[slave].OutputLoading % 100)); } } void PsuGroupOutputConfigCheck(unsigned char master) { unsigned char slave = 0; bool show = false; show = IsPsuGroupOutputConfigDifferent(master); for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; if(IsPsuGroupOutputConfigDifferent(slave)) { show = true; } } if(show) { ShowPsuGroupOutputConfig(master); } } void StepRecognition(unsigned char master, unsigned short voltage) { if(_GfdStep[master] == PREPARE_STEP_NONE && voltage > 0) { // gfd step _GfdStep[master] = PREPARE_STEP_CABLE_CHECK; LOG_INFO("Gun %d GFD Start Step", master + 1); } else if(_GfdStep[master] == PREPARE_STEP_CABLE_CHECK && voltage == 0) { // gfd done step _GfdStep[master] = PREPARE_STEP_GFD_DONE; LOG_INFO("Gun %d GFD Stop Step", master + 1); ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.CableCheckDone = true; } else if(_GfdStep[master] == PREPARE_STEP_GFD_DONE && voltage >= SAFETY_PRECHARGE_OFFSET) { // precharge step _GfdStep[master] = PREPARE_STEP_PRECHARGE; LOG_INFO("Gun %d PreCharge Step", master + 1); ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.InPrechargeMode = true; } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.AlreadyInChargingMode) { // charging step if(_GfdStep[master] != PREPARE_STEP_CHARGING) { LOG_INFO("Gun %d Charging Step", master + 1); } _GfdStep[master] = PREPARE_STEP_CHARGING; if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.InPrechargeMode) { if(_VoltageResumeCnt[master] < MAX_CHARGING_DELAY_COUNT) { int time = GetTimeoutValue(_ChargingDelay_time[master]) / mSEC_VAL; if(time >= CHARGING_DELAY_INTERVAL) { GetClockTime(&_ChargingDelay_time[master]); _VoltageResumeCnt[master]++; } } else { ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.InPrechargeMode = false; } } } } // master: master group index // voltage: target voltage, unit: 0.1V void UpdateOutputGroupVoltage(unsigned char master, unsigned short voltage) { unsigned char slave = 0; ShmPsuGrouping->TotalGroupOutput[master].GTargetVoltage = voltage; // set master group output voltage ShmPsuGrouping->GroupOutput[master].GTargetVoltage = voltage; for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { // set slave group output voltage slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; #if ONE_MODULE_OUTPUT // for safety test (inrush current) if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.InPrechargeMode) { ShmPsuGrouping->GroupOutput[slave].GTargetVoltage = 0; } else { ShmPsuGrouping->GroupOutput[slave].GTargetVoltage = voltage; } #else if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE || ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_PREPARE_SWITCH_OFF) { ShmPsuGrouping->GroupOutput[slave].GTargetVoltage = voltage; } #endif } } // master: master group index // group: self group index void UpdatePsuGroupOutputConfig(unsigned char master) { unsigned char slave = 0; unsigned short TargetVoltage = 0, TargetCurrent = 0, PresentTargetCurrent = 0; unsigned short current = 0; unsigned char OutputMaster = 0; OutputMaster = ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0 ? master : (ShmPsuGrouping->GroupCollection[master].AlternateMaster - 1); TargetVoltage = (int)(chargingInfo[master]->EvBatterytargetVoltage * 10); TargetCurrent = (int)(chargingInfo[master]->EvBatterytargetCurrent * 10); if(Is_OutputK1K2_Ready(master) || ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.CableCheckDone) { // update target voltage StepRecognition(master, TargetVoltage); #if PRECHARGE_OFFSET // for safety test (inrush current) if(!ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.AlreadyInChargingMode) { GCTargetVoltage[master] = _GfdStep[master] == PREPARE_STEP_PRECHARGE ? TargetVoltage - SAFETY_PRECHARGE_OFFSET : TargetVoltage; } else { if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.InPrechargeMode) { GCTargetVoltage[master] = TargetVoltage > (GCTargetVoltage[master] + VOLTAGE_RESUME_STEP) ? (GCTargetVoltage[master] + VOLTAGE_RESUME_STEP) : TargetVoltage; } else { GCTargetVoltage[master] = TargetVoltage; } } #else GCTargetVoltage[master] = TargetVoltage; #endif UpdateOutputGroupVoltage(master, GCTargetVoltage[master]); // update target current if(((ShmPsuGrouping->GroupCollection[master].Partner.RealQuantity + 1) * ZERO_CURRENT) > TargetCurrent || !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.AlreadyInChargingMode) { current = ZERO_CURRENT; #if PSU_DEBUG_MSG if(ShmPsuGrouping->GroupOutput[master].GTargetCurrent != current) { LOG_INFO("Gun %d Need Minimum Target Current = %d", master + 1, current); } #endif ShmPsuGrouping->GroupOutput[master].GTargetCurrent = ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0 ? current : 0; ShmPsuGrouping->TotalGroupOutput[master].GTargetCurrent = ShmPsuGrouping->GroupOutput[master].GTargetCurrent; for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE || ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_PREPARE_SWITCH_OFF) { #if ONE_MODULE_OUTPUT // for safety test (inrush current) ShmPsuGrouping->GroupOutput[slave].GTargetCurrent = 0; #else ShmPsuGrouping->GroupOutput[slave].GTargetCurrent = ShmPsuData->PsuGroup[slave].GroupPresentPsuQuantity > 0 ? ZERO_CURRENT : 0; #endif ShmPsuGrouping->TotalGroupOutput[master].GTargetCurrent += ShmPsuGrouping->GroupOutput[slave].GTargetCurrent; } } if(ShmPsuGrouping->TotalGroupOutput[master].GTargetCurrent < 20) { unsigned short diffCurrent = 0; diffCurrent = 20 - ShmPsuGrouping->TotalGroupOutput[master].GTargetCurrent; ShmPsuGrouping->GroupOutput[OutputMaster].GTargetCurrent += diffCurrent; } } else { if(!ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingConfirmed) { // master in normal output mode PresentTargetCurrent = GetPresentTargetCurrent(master, _GROLE_MASTER); current = TargetCurrent <= (int)chargingInfo[master]->AvailableChargingCurrent ? TargetCurrent : (int)chargingInfo[master]->AvailableChargingCurrent; #if PSU_DEBUG_MSG if(GCTargetCurrent[master] != current) { LOG_INFO("Gun %d Need Normal Target Current = %d.%d A", master + 1, (current / 10), (current % 10)); } #endif ShmPsuGrouping->TotalGroupOutput[master].GTargetCurrent = current; GCTargetCurrent[master] = current; UpdateMaxCurrent(master, GCTargetCurrent[master]); if(GCTargetCurrent[master] > PresentTargetCurrent) { // increase current OutputConfigStep[master] = _CURRENT_MODE_INCREASE; PSU_LOG("Gun %d Increase Current: %d.%d A, %d.%d A -> %d.%d A", master + 1, ((GCTargetCurrent[master] - PresentTargetCurrent) / 10), ((GCTargetCurrent[master] - PresentTargetCurrent) % 10), (PresentTargetCurrent / 10), (PresentTargetCurrent % 10), (GCTargetCurrent[master] / 10), (GCTargetCurrent[master] % 10)); #if MASTER_OUTPUT_FIRST // for safety test if(GCTargetCurrent[master] <= CURRENT_BALANCE_CRITERIA) { MasterIncreaseCurrent(master, GCTargetCurrent[master] - PresentTargetCurrent); } else { AverageIncreaseCurrent(master, GCTargetCurrent[master] - PresentTargetCurrent); } #else AverageIncreaseCurrent(master, GCTargetCurrent[master] - PresentTargetCurrent); #endif } else if(GCTargetCurrent[master] < PresentTargetCurrent) { // decrease current OutputConfigStep[master] = _CURRENT_MODE_DECREASE; PSU_LOG("Gun %d Decrease Current: %d.%d A, %d.%d A -> %d.%d A", master + 1, ((PresentTargetCurrent - GCTargetCurrent[master]) / 10), ((PresentTargetCurrent - GCTargetCurrent[master]) % 10), (PresentTargetCurrent / 10), (PresentTargetCurrent % 10), (GCTargetCurrent[master] / 10), (GCTargetCurrent[master] % 10)); #if MASTER_OUTPUT_FIRST // for safety test if(GCTargetCurrent[master] <= ShmPsuGrouping->GroupCollection[master].Partner.RealQuantity * CURRENT_BALANCE_CRITERIA) { MasterDecreaseCurrent(master, PresentTargetCurrent - GCTargetCurrent[master]); } else { AverageDecreaseCurrent(master, PresentTargetCurrent - GCTargetCurrent[master]); } #else AverageDecreaseCurrent(master, PresentTargetCurrent - GCTargetCurrent[master]); #endif } else { // balance current or do not change OutputConfigStep[master] = _CURRENT_MODE_BALANCE; if(OutputConfigStep[master] != _preOutputConfigStep[master]) { GetClockTime(&_ReachCurrent_time[master]); PSU_LOG("Gun %d In Balance Mode", master + 1); StableOutputCurrent[master] = (int)chargingInfo[master]->PresentChargingCurrent * 10; ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.OutputCurrentStable = false; ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.NeedCurrentBalance = false; } if(!ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.OutputCurrentStable) { if(IsMasterOutputCurrentStable(master)) { ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.OutputCurrentStable = true; LOG_INFO("Gun %d Output Current = %5.1f A Stable", master + 1, chargingInfo[master]->PresentChargingCurrent); } } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.OutputCurrentStable || ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.SmoothDerating) { if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.SmoothDerating) { CheckSmoothBalance(master); } else { #if MASTER_OUTPUT_FIRST // for safety test if(GCTargetCurrent[master] > ShmPsuGrouping->GroupCollection[master].Partner.RealQuantity * CURRENT_BALANCE_CRITERIA) { CheckCurrentBalance(master); } else { ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.NeedCurrentBalance = false; } #else CheckCurrentBalance(master); #endif } if(!ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.NeedCurrentBalance && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.SmoothDerating) { CheckReleaseOrExtend(master); } } } } else { // master in derating mode OutputConfigStep[master] = _CURRENT_MODE_DERATING; if(OutputConfigStep[master] != _preOutputConfigStep[master]) { LOG_INFO("Gun %d In Derating Mode", master + 1); } } _preOutputConfigStep[master] = OutputConfigStep[master]; } } else { ShmPsuGrouping->GroupOutput[master].GTargetVoltage = 0; ShmPsuGrouping->GroupOutput[master].GTargetCurrent = 0; for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; ShmPsuGrouping->GroupOutput[slave].GTargetVoltage = 0; ShmPsuGrouping->GroupOutput[slave].GTargetCurrent = 0; } } } // group: self group index void SetPsuGroupOutput(unsigned char group) { int time = 0; if(ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity > 0) { if(ShmPsuGrouping->GroupOutput[group].GTargetVoltage >= PSU_MIN_VOL) { #if ONE_MODULE_OUTPUT // for safety test (inrush current) if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.InPrechargeMode) { SingleOutputVol(ShmPsuPosition->GroupLocationInfo[group].PsuSN[0], ShmPsuGrouping->GroupOutput[group].GTargetVoltage, ShmPsuGrouping->GroupOutput[group].GTargetCurrent); } else { PresentOutputVol(group, ShmPsuGrouping->GroupOutput[group].GTargetVoltage, ShmPsuGrouping->GroupOutput[group].GTargetCurrent); } #else PresentOutputVol(group, ShmPsuGrouping->GroupOutput[group].GTargetVoltage, ShmPsuGrouping->GroupOutput[group].GTargetCurrent); #endif if(!isStartOutputSwitch[group]) { SetPsuGroupPowerOnOff(group, _PSU_ON); GetClockTime(&_PoweOnOff_time[group]); } } else { if(isStartOutputSwitch[group]) { SetPsuGroupPowerOnOff(group, _PSU_OFF); GetClockTime(&_PoweOnOff_time[group]); } #if ONE_MODULE_OUTPUT // for safety test (inrush current) if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.InPrechargeMode) { SingleOutputVol(ShmPsuPosition->GroupLocationInfo[group].PsuSN[0], ShmPsuGrouping->GroupOutput[group].GTargetVoltage, ShmPsuGrouping->GroupOutput[group].GTargetCurrent); } else { PresentOutputVol(group, ShmPsuGrouping->GroupOutput[group].GTargetVoltage, ShmPsuGrouping->GroupOutput[group].GTargetCurrent); } #else PresentOutputVol(group, ShmPsuGrouping->GroupOutput[group].GTargetVoltage, ShmPsuGrouping->GroupOutput[group].GTargetCurrent); #endif } } time = GetTimeoutValue(_PoweOnOff_time[group]) / uSEC_VAL; if(time > POWER_ONOFF_RESEND_INTERVAL) { SetPsuGroupPowerOnOff(group, isStartOutputSwitch[group] ? _PSU_ON : _PSU_OFF); GetClockTime(&_PoweOnOff_time[group]); } //UpdatePsuGroupLoading(group); UpdateGunLoading(group); } // master: master group index bool CanMasterStartDerating(unsigned char master) { bool start = false; unsigned short TargetCurrent = 0; TargetCurrent = (int)(chargingInfo[master]->EvBatterytargetCurrent * 10); if(TargetCurrent <= ShmPsuGrouping->GroupCollection[master].ReAssignAvailableCurrent) { start = true; } return start; } // master: master group index // role_condition: when role_condition = _GROLE_MASTER, stop all member void SetMemberStartPowerOff(unsigned char master, unsigned char role_condition) { unsigned char slave = 0; char strMember[64]; bool find = false; if(ShmPsuGrouping->GroupCollection[master].Role == _GROLE_MASTER) { sprintf(strMember, "Gun %d Set Member:", master + 1); for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; if(role_condition == _GROLE_MASTER || ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_PREPARE_SWITCH_OFF) { SetPsuGroupRole(slave, _GROLE_SLAVE_POWER_OFF); char strSlave[8]; sprintf(strSlave, " [%02X]", slave); strcat(strMember, strSlave); find = true; } } if(find) { strcat(strMember, " Power Off"); LOG_INFO("%s", strMember); } } } // master: master group index bool IsMemberPowerOffOK(unsigned char master) { bool done = true; unsigned char slave = 0; for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; if(ShmPsuGrouping->GroupCollection[slave].Role != _GROLE_SLAVE && ShmPsuGrouping->GroupCollection[slave].Role != _GROLE_SWITCH_OFF_OK) { done = false; } } return done; } // master: master group index void SetMemberPowerOffDone(unsigned char master) { unsigned char slave = 0; if(ShmPsuGrouping->GroupCollection[master].Role == _GROLE_MASTER) { for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].Partner.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].Partner.Member[i]; if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SWITCH_OFF_OK) { SetPsuGroupRole(slave, _GROLE_WAIT_IDLE); } else if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE_POWER_OFF) { // can not power off normally SetPsuGroupRole(slave, _GROLE_TERMINATE); } } } } unsigned char _ParallelRelay[MAX_GROUP_QUANTITY]; void SetPCabinetParallelRelay(unsigned short parallelConfig) { bool change = false; if(ShmChargerInfo->Control.CabinetRole == _CROLE_MASTER) { for(int i = 0; i < MAX_SLAVE_CABINET_QUANTITY; i++) { change = false; if(ShmChargerInfo->ParallelCabinet.PCabinet[i].LocalStatus == _DeviceStatus_Idle || ShmChargerInfo->ParallelCabinet.PCabinet[i].LocalStatus == _DeviceStatus_Alarm || ShmChargerInfo->ParallelCabinet.PCabinet[i].LocalStatus == _DeviceStatus_Charging) { for(int j = 0; j < GENERAL_GUN_QUANTITY; j++) { _ParallelRelay[j] = (parallelConfig & (1 << j)) > 0 ? YES : NO; if(_ParallelRelay[i] != ShmChargerInfo->ParallelCabinet.PCabinet[i].ParallelRelaySetting[i]) { change = true; } } if(change) { char strParallel[128]; sprintf(strParallel, "Set PCabinet %d Parallel Relay:", i + 1); for(int j = 0; j < GENERAL_GUN_QUANTITY; j++) { char strState[8]; sprintf(strState, " %3s", _ParallelRelay[j] ? "ON" : "OFF"); strcat(strParallel, strState); } LOG_INFO("%s", strParallel); } ShmChargerInfo->ParallelCabinet.PCabinet[i].ParallelRelaySetting[i] = _ParallelRelay[i]; } } } } // master: master group index // Yes_No: Yes: relay on, No: relay off // role_condition: when role_condition = _GROLE_MASTER, parallel relay of all member do the action(on or off) void SetParallelRelayOnOff(unsigned char master, unsigned char Yes_No, unsigned char role_condition) { //int ParallelConfig = 0; unsigned char slave = 0; PsuGroupPartner *partner; if(ShmPsuGrouping->GroupCollection[master].Role == _GROLE_MASTER || ShmPsuGrouping->GroupCollection[master].Role == _GROLE_DUMMY_MASTER || (ShmPsuGrouping->GroupCollection[master].Role == _GROLE_REQUEST_TO_CHARGING && Yes_No)) { ShmPsuGrouping->GroupCollection[master].ParallelCheck = 0; partner = role_condition == _GROLE_PRECHARGE_READY ? &ShmPsuGrouping->GroupCollection[master].PossibleMember : &ShmPsuGrouping->GroupCollection[master].Partner; for(int i = 0; i < partner->Quantity; i++) { slave = partner->Member[i]; if(role_condition == _GROLE_MASTER || ShmPsuGrouping->GroupCollection[slave].Role != _GROLE_SLAVE) { //ParallelConfig = ShmPsuGrouping->GroupCollection[master].ParallelConfig[slave]; //if(ParallelConfig != 0) //{ // ShmPsuGrouping->GroupCollection[master].ParallelCheck |= (1 << (ParallelConfig - 1)); //} ShmPsuGrouping->GroupCollection[master].ParallelCheck |= partner->ParallelFlag[i]; } } if(Yes_No) { ShmPsuGrouping->ParallelRelayConfig.CtrlValue |= ShmPsuGrouping->GroupCollection[master].ParallelCheck; } else { ShmPsuGrouping->ParallelRelayConfig.CtrlValue &= ~ShmPsuGrouping->GroupCollection[master].ParallelCheck; } SetPCabinetParallelRelay(ShmPsuGrouping->ParallelRelayConfig.CtrlValue); } } // master: master group index bool IsParallelRelayConfirmed(unsigned char master) { bool confirmed = true; for(int i = 0; i < CONNECTOR_QUANTITY; i++) { if((1 << i) & ShmPsuGrouping->GroupCollection[master].ParallelCheck) { if((ShmPsuGrouping->ParallelRelayConfig.CtrlValue & (1 << i)) != (ShmPsuGrouping->ParallelRelayConfirmed.CtrlValue & (1 << i))) { confirmed = false; break; } } } return confirmed; } // master: master group index bool IsPossibleMemberReady(unsigned char master) { bool ready = true; unsigned char slave = 0; if(ShmPsuGrouping->GroupCollection[master].PossibleMember.Quantity > 0) { for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].PossibleMember.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].PossibleMember.Member[i]; if(ShmPsuGrouping->GroupCollection[slave].Role != _GROLE_WAIT_SLAVE) { ready = false; } } } return ready; } // master: master group index bool IsExtendPrechargeReady(unsigned char master) { bool ready = true; unsigned char slave = 0; for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].PossibleMember.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].PossibleMember.Member[i]; if(ShmPsuData->PsuGroup[slave].GroupPresentPsuQuantity == 0 || ShmPsuData->PsuGroup[slave].GroupAvailableCurrent == 0) { continue; } unsigned short voltage = 0; voltage = ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0 ? ShmPsuData->PsuGroup[master].GroupPresentOutputVoltage : ShmPsuData->PsuGroup[ShmPsuGrouping->GroupCollection[master].AlternateMaster - 1].GroupPresentOutputVoltage; if(ShmPsuGrouping->GroupCollection[slave].Role != _GROLE_PREPARE_ATTACH_ON || ShmPsuData->PsuGroup[slave].GroupPresentOutputVoltage > (voltage + PRECHARGE_RANGE_VOLTAGE) || ShmPsuData->PsuGroup[slave].GroupPresentOutputVoltage < (voltage - PRECHARGE_OFFSET_VOLTAGE - PRECHARGE_RANGE_VOLTAGE)) { ready = false; } } return ready; } // master: master group index bool CheckExtendPrechargeReady(unsigned char master) { bool ready = false; unsigned char slave = 0; for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].PossibleMember.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].PossibleMember.Member[i]; if(ShmPsuData->PsuGroup[slave].GroupPresentPsuQuantity == 0 || ShmPsuData->PsuGroup[slave].GroupAvailableCurrent == 0) { continue; } unsigned short voltage = 0; voltage = ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0 ? ShmPsuData->PsuGroup[master].GroupPresentOutputVoltage : ShmPsuData->PsuGroup[ShmPsuGrouping->GroupCollection[master].AlternateMaster - 1].GroupPresentOutputVoltage; char message[512]; sprintf(message, "Gun %d PsuGroup[%d] PresentVoltqage: %4d V ", master + 1, slave, (ShmPsuData->PsuGroup[slave].GroupPresentOutputVoltage / 10)); for(int j = 0; j < ShmPsuData->PsuGroup[slave].GroupPresentPsuQuantity; j++) { char strVoltage[32]; sprintf(strVoltage, " Psu[%d][%d] %4d V", slave, j, (ShmPsuData->PsuGroup[slave].PsuModule[j].PresentOutputVoltage / 10)); strcat(message, strVoltage); if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_PREPARE_ATTACH_ON && ShmPsuData->PsuGroup[slave].PsuModule[j].PresentOutputVoltage > (voltage + PRECHARGE_RANGE_VOLTAGE) && ShmPsuData->PsuGroup[slave].PsuModule[j].PresentOutputVoltage < (voltage - PRECHARGE_OFFSET_VOLTAGE - PRECHARGE_RANGE_VOLTAGE)) { ready = true; } } PSU_LOG("%s", message); } return ready; } // master: master group index void SetExtendPrechargeCompleted(unsigned char master) { unsigned char slave = 0; for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].PossibleMember.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].PossibleMember.Member[i]; SetPsuGroupRole(slave, _GROLE_PRECHARGE_READY); } } // master: master group index void SetExtendPrechargeStop(unsigned char master) { unsigned char slave = 0; for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].PossibleMember.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].PossibleMember.Member[i]; SetPsuGroupRole(slave, _GROLE_EXTEND_STOP); } memset(&ShmPsuGrouping->GroupCollection[master].PossibleMember, 0x00, sizeof(PsuGroupPartner)); } // master: master group index void AddExtendMember(unsigned char master) { unsigned char slave = 0; unsigned short parallelFlag = 0; for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].PossibleMember.Quantity; i++) { slave = ShmPsuGrouping->GroupCollection[master].PossibleMember.Member[i]; parallelFlag = ShmPsuGrouping->GroupCollection[master].PossibleMember.ParallelFlag[i]; if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_PRECHARGE_READY) { AddMember(slave, master, parallelFlag); } } } // group: self group index void CheckChargingRequest(unsigned char group) { PsuGroupPartner partner; if(ShmPsuGrouping->GroupCollection[group].Role != _GROLE_IDLE) { return; } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ChargingRequest) { if(ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity > 0) { SetPsuGroupRole(group, _GROLE_REQUEST_TO_CHARGING); } else { if(GetPsuGroupAvailable(group) > 0 || CheckAlternateMaster(group, &partner, YES)) { SetPsuGroupRole(group, _GROLE_DUMMY_MASTER); } else { SetPsuGroupRole(group, _GROLE_NO_RESOURCE); } } } } // group: self group index void ChargingRequestProcess(unsigned char group) { int time = 0; PsuGroupPartner partner; if(ShmPsuGrouping->GroupCollection[group].Role != _GROLE_REQUEST_TO_CHARGING) { return; } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ChargingRequest && !ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ChargingRequestConfirmed) { GetClockTime(&_ChargingRequest_time[group]); ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ChargingRequest = false; ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ChargingRequestConfirmed = true; #if GRAB_AT_START_CHARGING ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.GroupShareCheck = true; #else ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ShareCheckDone = true; #endif } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.GroupShareCheck && !ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ShareConfirmed) { // check is there psu group to grab if(PsuGroupGrabCheck(group, &partner)) { GetClockTime(&_ChargingRequest_time[group]); ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.GrabGroupWait = true; PrepareToPowerOff(group + 1, &partner); memcpy(&ShmPsuGrouping->GroupCollection[group].PossibleMember, &partner, sizeof(PsuGroupPartner)); } else { ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ShareCheckDone = true; LOG_INFO("Gun %d Grab Nothing", group + 1); } ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ShareConfirmed = true; } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.GrabGroupWait && !ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ShareCheckDone) { // wait until grab psu ready or timeout bool ready = IsPossibleMemberReady(group); time = GetTimeoutValue(_ChargingRequest_time[group]) / uSEC_VAL; if(ready || time >= WAIT_GRAB_TIME) { ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ShareCheckDone = true; LOG_INFO("Gun %d Grab %s", group + 1, ready ? "OK" : "Timeout"); } } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ShareCheckDone && !ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.FindGroupPartner) { GetClockTime(&_ChargingRequest_time[group]); AddAvailableMember(group); ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.FindGroupPartner = true; } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.FindGroupPartner && !ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ParallelRelayOn) { // after a little delay, set parallel relay on time = GetTimeoutValue(_ChargingRequest_time[group]) / uSEC_VAL; if(time >= WAIT_PARALLEL_RELAY_DELAY) { unsigned short original = ShmPsuGrouping->ParallelRelayConfig.CtrlValue; GetClockTime(&_ChargingRequest_time[group]); SetParallelRelayOnOff(group, YES, _GROLE_MASTER); ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ParallelRelayOn = true; LOG_INFO("Gun %d Charging Request Set All Member Parallel Relay On 0x%02X -> 0x%02X", group + 1, original, ShmPsuGrouping->ParallelRelayConfig.CtrlValue); } } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ParallelRelayOn && !ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ParallelRelayConfirmed) { // wait until parallel relay on confirmed bool confirmed = IsParallelRelayConfirmed(group); time = GetTimeoutValue(_ChargingRequest_time[group]) / uSEC_VAL; //if(confirmed || time >= WAIT_RELAY_CONFIRMED_TIME) if(time >= WAIT_RELAY_CONFIRMED_TIME) { GetClockTime(&_ChargingRequest_time[group]); ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ParallelRelayConfirmed = true; LOG_INFO("Gun %d Charging Request Parallel Relay Confirmed %s", group + 1, confirmed ? "OK" : "Timeout"); } } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ParallelRelayConfirmed && !ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.GroupingDone) { ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.GroupingDone = true; } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.GroupingDone) { SetPsuGroupToMaster(group); ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.IdleCtrlValue = 0; LOG_INFO("Gun %d Grouping Completed", group + 1); } } // group: self group index void DummuMasterProcess(unsigned char group) { int time = 0; PsuGroupPartner partner; if(ShmPsuGrouping->GroupCollection[group].Role != _GROLE_DUMMY_MASTER) { return; } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterRequest && !ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterReqConfirmed) { LOG_INFO("Gun %d Dummy Master Request Start", group + 1); ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterReqConfirmed = true; } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterReqConfirmed && !ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterPermission) { memset(&partner, 0x00, sizeof(PsuGroupPartner)); ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterPermission = true; FindPsuGroupPartner(group, MAX_GROUP_QUANTITY, &partner, _EXTEND_TYPE_QUANTITY, 1); if(partner.Quantity > 0) { GetClockTime(&_DummyMasterRequest_time[group]); AddDummyMaster(group, &partner); ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterGrabCheck = true; ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterFindPartner = true; } else { LOG_INFO("Gun %d need to make a grab for dummy master", group + 1); } } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterPermission && !ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterGrabCheck) { memset(&partner, 0x00, sizeof(PsuGroupPartner)); // check is there psu group to grab if(CheckAlternateMaster(group, &partner, YES)) { GetClockTime(&_DummyMasterRequest_time[group]); ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterWait = true; PrepareToPowerOff(group + 1, &partner); memcpy(&ShmPsuGrouping->GroupCollection[group].PossibleMember, &partner, sizeof(PsuGroupPartner)); } else { ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterCompleted = true; ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterFault = true; LOG_INFO("Gun %d Dummy Master Grab Nothing", group + 1); } ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterGrabCheck = true; } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterWait && !ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterFindPartner) { // wait until grab psu ready or timeout bool ready = IsPossibleMemberReady(group); time = GetTimeoutValue(_DummyMasterRequest_time[group]) / uSEC_VAL; if(ready || time >= WAIT_GRAB_TIME) { ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterReady = true; LOG_INFO("Gun %d Grab %s", group + 1, ready ? "OK" : "Timeout"); } } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterReady && !ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterFindPartner) { GetClockTime(&_DummyMasterRequest_time[group]); memset(&partner, 0x00, sizeof(PsuGroupPartner)); FindPsuGroupPartner(group, MAX_GROUP_QUANTITY, &partner, _EXTEND_TYPE_QUANTITY, 1); if(partner.Quantity > 0) { AddDummyMaster(group, &partner); ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterFindPartner = true; } else { ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterCompleted = true; ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterFault = true; LOG_INFO("Gun %d Dummy Master Grab Fault", group + 1); } } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterFindPartner && !ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterRelayOn) { // after a little delay, set parallel relay on time = GetTimeoutValue(_DummyMasterRequest_time[group]) / uSEC_VAL; if(time >= WAIT_PARALLEL_RELAY_DELAY) { unsigned short original = ShmPsuGrouping->ParallelRelayConfig.CtrlValue; GetClockTime(&_DummyMasterRequest_time[group]); SetParallelRelayOnOff(group, YES, _GROLE_MASTER); ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterRelayOn = true; LOG_INFO("Gun %d Set Dummy Member Parallel Relay On 0x%02X -> 0x%02X", group + 1, original, ShmPsuGrouping->ParallelRelayConfig.CtrlValue); } } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterRelayOn && !ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterRelayConfirmed) { // wait until parallel relay on confirmed bool confirmed = IsParallelRelayConfirmed(group); time = GetTimeoutValue(_DummyMasterRequest_time[group]) / uSEC_VAL; //if(confirmed || time >= WAIT_RELAY_CONFIRMED_TIME) if(time >= WAIT_RELAY_CONFIRMED_TIME) { GetClockTime(&_DummyMasterRequest_time[group]); ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterRelayConfirmed = true; LOG_INFO("Gun %d Dummy Member Parallel Relay Confirmed %s", group + 1, confirmed ? "OK" : "Timeout"); } } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterRelayConfirmed && !ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterCompleted) { ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterCompleted = true; } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterCompleted) { if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.DummyMasterFault) { SetPsuGroupRole(group, _GROLE_DUMMY_FAULT); ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.DummyMasterCtrlValue = 0; LOG_INFO("Gun %d Dummy Master Grouping Fault", group + 1); } else { SetPsuGroupToMaster(group); ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.IdleCtrlValue = 0; LOG_INFO("Gun %d Dummy Master Grouping Completed", group + 1); } } } // master: master group index void PsuGroupDeratingProcess(unsigned char master) { int time = 0; // slave group set NeedDerating flag to start re-assign if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.NeedDerating) { // reduce output current capability start GetClockTime(&_PsuGroupDerating_time[master]); unsigned short ReAssignCurrent = GetPresentTargetCurrent(master, _GROLE_SLAVE); ShmPsuGrouping->GroupCollection[master].ReAssignAvailableCurrent = ReAssignCurrent; ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.NeedDerating = false; LOG_INFO("Gun %d DeratingConfirmed%s, ReAssignAvailableCurrent = %d.%d A", master + 1, ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingConfirmed ? " Again" : "", (ReAssignCurrent / 10), (ReAssignCurrent % 10)); if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingConfirmed) { ShmPsuGrouping->GroupCollection[master].GroupCtrl.RoleCtrl.DeratingCtrlValue = 0; } ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingConfirmed = true; } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingConfirmed && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingStart) { // wait until derating from ev or timeout bool start = CanMasterStartDerating(master); bool bypass = ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.AlreadyInChargingMode ? false : true; time = GetTimeoutValue(_PsuGroupDerating_time[master]) / uSEC_VAL; if(start || time >= WAIT_EV_DERATING_TIMEOUT || bypass) { GetClockTime(&_PsuGroupDerating_time[master]); ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingStart = true; LOG_INFO("Gun %d %s Start Derating%s", master + 1, start ? "Normal" : "Force", bypass ? " (Bypass)" : ""); SetMemberStartPowerOff(master, _GROLE_PREPARE_SWITCH_OFF); if(!bypass) { // update stage max current and reset max current time StageMaxCurrent[master] = start ? (int)(chargingInfo[master]->EvBatterytargetCurrent * 10) : ShmPsuGrouping->GroupCollection[master].ReAssignAvailableCurrent; ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ReachMaxStageCurrent = false; GetClockTime(&_StageCurrent_time[master]); } } } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingStart && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingPowerOffDone) { // wait until psu member power off ok or timeout bool power_off_ok = IsMemberPowerOffOK(master); time = GetTimeoutValue(_PsuGroupDerating_time[master]) / uSEC_VAL; if(power_off_ok || time >= WAIT_SLAVE_POWER_OFF_TIMEOUT) { GetClockTime(&_PsuGroupDerating_time[master]); SetMemberPowerOffDone(master); ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingPowerOffDone = true; LOG_INFO("Gun %d Set Derating Member Power Off %s", master + 1, power_off_ok ? "OK" : "Timeout"); } } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingPowerOffDone && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingRelayOff) { // after a little delay, set parallel relay off time = GetTimeoutValue(_PsuGroupDerating_time[master]) / uSEC_VAL; if(time >= WAIT_PARALLEL_RELAY_DELAY) { unsigned short original = ShmPsuGrouping->ParallelRelayConfig.CtrlValue; GetClockTime(&_PsuGroupDerating_time[master]); SetParallelRelayOnOff(master, NO, _GROLE_SWITCH_OFF_OK); ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingRelayOff = true; LOG_INFO("Gun %d Set Parallel Relay Off 0x%02X -> 0x%02X", master + 1, original, ShmPsuGrouping->ParallelRelayConfig.CtrlValue); } } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingRelayOff && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingRelayConfirmed) { // wait until parallel relay off confirmed bool confirmed = IsParallelRelayConfirmed(master); time = GetTimeoutValue(_PsuGroupDerating_time[master]) / uSEC_VAL; //if(confirmed || time >= WAIT_RELAY_CONFIRMED_TIME) if(time >= WAIT_RELAY_CONFIRMED_TIME) { GetClockTime(&_PsuGroupDerating_time[master]); ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingRelayConfirmed = true; LOG_INFO("Gun %d Parallel Relay Confirmed %s", master + 1, confirmed ? "OK" : "Timeout"); } } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingRelayConfirmed && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingCompleted) { // remove all non group member RemoveNonGroupMember(master); ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingCompleted = true; } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingCompleted) { ShmPsuGrouping->GroupCollection[master].GroupCtrl.RoleCtrl.DeratingCtrlValue = 0; UpdateGunAvailableCapability(master); GetClockTime(&_ExtendCapability_time[master]); LOG_INFO("Gun %d Derating Completed", master + 1); } } void MasterStopChargingProcess(unsigned char master) { int time = 0; if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.StopChargingRequest && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.StopChargingConfirmed) { // set all member to power off GetClockTime(&_StopCharging_time[master]); SetMemberStartPowerOff(master, _GROLE_MASTER); ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.StopChargingConfirmed = true; } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.StopChargingConfirmed && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.AllPowerOffDone) { // wait until psu member power off ok or timeout bool power_off_ok = IsMemberPowerOffOK(master); time = GetTimeoutValue(_StopCharging_time[master]) / uSEC_VAL; if(power_off_ok || time >= WAIT_SLAVE_POWER_OFF_TIMEOUT) { GetClockTime(&_StopCharging_time[master]); SetMemberPowerOffDone(master); ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.AllPowerOffDone = true; LOG_INFO("Gun %d Set All Member Power Off %s", master + 1, power_off_ok ? "OK" : "Timeout"); } } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.AllPowerOffDone && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.AllParallelRelayOff) { // after a little delay, set all member parallel relay off time = GetTimeoutValue(_StopCharging_time[master]) / uSEC_VAL; if(time >= WAIT_PARALLEL_RELAY_DELAY) { unsigned short original = ShmPsuGrouping->ParallelRelayConfig.CtrlValue; GetClockTime(&_StopCharging_time[master]); SetParallelRelayOnOff(master, NO, _GROLE_MASTER); ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.AllParallelRelayOff = true; LOG_INFO("Gun %d Set All Member Parallel Relay Off 0x%02X -> 0x%02X", master + 1, original, ShmPsuGrouping->ParallelRelayConfig.CtrlValue); } } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.AllParallelRelayOff && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.AllParallelRelayConfirmed) { // wait until parallel relay off confirmed bool confirmed = IsParallelRelayConfirmed(master); time = GetTimeoutValue(_StopCharging_time[master]) / uSEC_VAL; //if(confirmed || time >= WAIT_RELAY_CONFIRMED_TIME) if(time >= WAIT_RELAY_CONFIRMED_TIME) { GetClockTime(&_StopCharging_time[master]); ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.AllParallelRelayConfirmed = true; LOG_INFO("Gun %d All Member Parallel Relay Confirmed %s", master + 1, confirmed ? "OK" : "Timeout"); } } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.AllParallelRelayConfirmed && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.AllMemberStopCompleted) { // remove all non group member RemoveNonGroupMember(master); ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.AllMemberStopCompleted = true; LOG_INFO("Gun %d All Member Stop Completed", master + 1); } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.AllMemberStopCompleted && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.StopChargingCompleted) { // check self group power down or not if(ShmPsuData->PsuGroup[master].GroupPresentOutputCurrent <= MAX_PSU_POWER_OFF_CURRENT) { ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.StopChargingCompleted = true; } } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.StopChargingCompleted) { ShmPsuGrouping->GroupCollection[master].GroupCtrl.RoleCtrl.MasterCtrlValue = 0; ShmPsuGrouping->GroupCollection[master].GroupCtrl.RoleCtrl.StopChargingCtrlValue = 0; SetPsuGroupToIdle(master); LOG_INFO("Gun %d Stop Charging Completed", master + 1); } } void SlaveStopChargingProcess(unsigned char slave) { int time = 0; unsigned char master = 0; PsuGroupPartner PowerOffMember; #if GRAB_AT_START_CHARGING PsuGroupPartner GrabMember; #endif if(ShmPsuGrouping->GroupCollection[slave].Role != _GROLE_SLAVE) { return; } master = ShmPsuGrouping->GroupCollection[slave].TargetGroup - 1; if(ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.SlaveChargingRequest && !ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.CheckSlaveReady) { ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.CheckSlaveReady = true; if(ShmPsuGrouping->GroupCollection[master].Role == _GROLE_REQUEST_TO_CHARGING) { LOG_INFO("Gun %d Need Wait Gun %d Grouping Completed", slave + 1, master + 1); GetClockTime(&_CheckSlaveReady_time[slave]); } else if(ShmPsuGrouping->GroupCollection[master].Role == _GROLE_MASTER && ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingConfirmed) { LOG_INFO("Gun %d Need Wait Gun %d Derating Completed", slave + 1, master + 1); GetClockTime(&_CheckSlaveReady_time[slave]); } else { bool isAlternate = false; if(ShmPsuGrouping->GroupCollection[master].AlternateMaster != 0) { if((ShmPsuGrouping->GroupCollection[master].AlternateMaster - 1) == slave) { isAlternate = true; } } ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.WaitSlaveReady = true; if(isAlternate) { ShmPsuGrouping->GroupCollection[slave].ReservedTarget = slave + 1; ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.WaitDummyMaster = true; ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.AlternateMasterStopRequest = true; LOG_INFO("Gun %d Request DummyMaster To Power Off", slave + 1); GetClockTime(&_CheckSlaveReady_time[slave]); } else { ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.SlavePowerOffRequest = true; LOG_INFO("Gun %d Need Power Off And Request To Charging", slave + 1); } } } // wait until master derating completed if(ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.CheckSlaveReady && !ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.WaitSlaveReady) { time = GetTimeoutValue(_CheckSlaveReady_time[slave]) / uSEC_VAL; if(time >= WAIT_SLAVE_READY_TIME || (ShmPsuGrouping->GroupCollection[master].Role == _GROLE_MASTER && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingConfirmed)) { if(!(ShmPsuGrouping->GroupCollection[master].Role == _GROLE_MASTER && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.DeratingConfirmed)) { ShmPsuGrouping->GroupCollection[slave].GroupCtrl.RoleCtrl.SlaveCtrlValue = 0; LOG_INFO("Gun %d Wait Gun %d Timeout", slave + 1); } else { ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.WaitSlaveReady = true; LOG_INFO("Gun %d Is Ready", slave + 1); GetClockTime(&_CheckSlaveReady_time[slave]); } } } if(ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.WaitSlaveReady && !ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.SlavePowerOffRequest) { time = GetTimeoutValue(_CheckSlaveReady_time[slave]) / uSEC_VAL; if(time >= WAIT_SLAVE_DELAY) { ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.SlavePowerOffRequest = true; } } if(ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.WaitDummyMaster && !ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.SlavePowerOffRequest) { time = GetTimeoutValue(_CheckSlaveReady_time[slave]) / uSEC_VAL; if(time >= WAIT_DUMMY_MASTER_OFF) { ShmPsuGrouping->GroupCollection[slave].GroupCtrl.RoleCtrl.SlaveCtrlValue = 0; LOG_INFO("Gun %d Wait DummyMaster %d Power Off Timeout", slave + 1, master + 1); } } // self group, other slave or master set SlavePowerOffRequest flag to power off if(ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.SlavePowerOffRequest && !ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.SlavePowerOffConfirmed) { if(ShmChargerInfo->Control.SysCtrl.bits.Enable6ParallelRelay == 0) { PsuGroupPowerOffCheck(slave, &PowerOffMember); } else { PowerOffMember.Quantity = 1; PowerOffMember.Member[0] = slave; } #if GRAB_AT_START_CHARGING if(PowerOffMember.Quantity == 1 && ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.SlaveChargingRequest) { // grab here if(PsuGroupGrabCheck(slave, &GrabMember)) { for(int i = 0; i < GrabMember.Quantity; i++) { PowerOffMember.Member[PowerOffMember.Quantity++] = GrabMember.Member[i]; } } } #endif if(PowerOffMember.Quantity > 0) { unsigned char target = ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.SlaveChargingRequest ? (slave + 1) : 0; PrepareToPowerOff(target, &PowerOffMember); if(PowerOffMember.Quantity > 1 && ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.SlaveChargingRequest) { ShmPsuGrouping->GroupCollection[slave].PossibleMember.Quantity = PowerOffMember.Quantity - 1; memcpy(ShmPsuGrouping->GroupCollection[slave].PossibleMember.Member, &PowerOffMember.Member[1], PowerOffMember.Quantity - 1); } ShmPsuGrouping->GroupCollection[slave].GroupCtrl.bits.SlavePowerOffConfirmed = true; } else { ShmPsuGrouping->GroupCollection[slave].GroupCtrl.RoleCtrl.SlaveCtrlValue = 0; } } } void MasterExtendCapabilityProcess(unsigned char master) { int time = 0; // stop extend capability process when derating or stop charging if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.RoleCtrl.DeratingCtrlValue != 0 || ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.StopChargingRequest) { if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.MorePowerConfirmed) { SetExtendPrechargeStop(master); } ShmPsuGrouping->GroupCollection[master].GroupCtrl.RoleCtrl.ExtendCapabilityCtrlValue = 0; ShmPsuGrouping->GroupCollection[master].ExtendQuantityLimit = 0; return; } // start extend capability if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.MorePowerRequest && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.MorePowerConfirmed) { GetClockTime(&_ExtendCapability_time[master]); memset(&ShmPsuGrouping->GroupCollection[master].PossibleMember, 0x00, sizeof(PsuGroupPartner)); FindPsuGroupPartner(master, (int)ShmPsuGrouping->GroupCollection[master].DiffPower_PhysicalLimit, &ShmPsuGrouping->GroupCollection[master].PossibleMember, _EXTEND_TYPE_POWER, ShmPsuGrouping->GroupCollection[master].ExtendQuantityLimit); if(ShmPsuGrouping->GroupCollection[master].PossibleMember.Quantity > 0) { PrepareToExtendCapability(master + 1, &ShmPsuGrouping->GroupCollection[master].PossibleMember); ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.MorePowerConfirmed = true; } else { ShmPsuGrouping->GroupCollection[master].GroupCtrl.RoleCtrl.ExtendCapabilityCtrlValue = 0; ShmPsuGrouping->GroupCollection[master].ExtendQuantityLimit = 0; } } // set extend member precharge voltage if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.MorePowerConfirmed && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendPrechargeDone) { //unsigned short voltage = ShmPsuData->PsuGroup[master].GroupPresentOutputVoltage >= PRECHARGE_OFFSET_VOLTAGE ? // ShmPsuData->PsuGroup[master].GroupPresentOutputVoltage - PRECHARGE_OFFSET_VOLTAGE : 0; unsigned short voltage = 0; voltage = ShmPsuGrouping->GroupCollection[master].AlternateMaster == 0 ? ShmPsuData->PsuGroup[master].GroupPresentOutputVoltage : ShmPsuData->PsuGroup[ShmPsuGrouping->GroupCollection[master].AlternateMaster - 1].GroupPresentOutputVoltage; voltage = voltage >= PRECHARGE_OFFSET_VOLTAGE ? voltage - PRECHARGE_OFFSET_VOLTAGE : 0; for(int i = 0; i < ShmPsuGrouping->GroupCollection[master].PossibleMember.Quantity; i++) { unsigned char slave = ShmPsuGrouping->GroupCollection[master].PossibleMember.Member[i]; if(ShmPsuData->PsuGroup[slave].GroupPresentPsuQuantity > 0 && ShmPsuData->PsuGroup[slave].GroupAvailableCurrent > 0) { ShmPsuGrouping->GroupOutput[slave].GTargetVoltage = voltage; ShmPsuGrouping->GroupOutput[slave].GTargetCurrent = ZERO_CURRENT; } } if(!ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendPrecharge) { GetClockTime(&_ExtendCapability_time[master]); LOG_INFO("Gun %d Set ExtendPrecharge Voltage %d.%d V", master + 1, (voltage / 10), (voltage % 10)); } ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendPrecharge = true; } // wait for extend member precharge ready if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendPrecharge && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendPrechargeDone) { bool ready = IsExtendPrechargeReady(master); time = GetTimeoutValue(_ExtendCapability_time[master]) / uSEC_VAL; if(ready || time >= WAIT_PRECHARGE_TIME) { LOG_INFO("Gun %d ExtendPrecharge %s", master + 1, ready ? "Ready" : "Timeout"); if(!ready) { ready = CheckExtendPrechargeReady(master); LOG_INFO("Gun %d check every psu's voltage and ExtendPrecharge is %s", master + 1, ready ? "Ready" : "Timeout"); } if(ready) { GetClockTime(&_ExtendCapability_time[master]); SetExtendPrechargeCompleted(master); ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendPrechargeDone = true; } else { SetExtendPrechargeStop(master); ShmPsuGrouping->GroupCollection[master].GroupCtrl.RoleCtrl.ExtendCapabilityCtrlValue = 0; ShmPsuGrouping->GroupCollection[master].ExtendQuantityLimit = 0; } } } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendPrechargeDone && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendRelayOn) { // after a little delay, set extend parallel relay on time = GetTimeoutValue(_ExtendCapability_time[master]) / uSEC_VAL; if(time >= WAIT_PARALLEL_RELAY_DELAY) { unsigned short original = ShmPsuGrouping->ParallelRelayConfig.CtrlValue; GetClockTime(&_ExtendCapability_time[master]); SetParallelRelayOnOff(master, YES, _GROLE_PRECHARGE_READY); ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendRelayOn = true; LOG_INFO("Gun %d Set Extend Parallel Relay On 0x%02X -> 0x%02X", master + 1, original, ShmPsuGrouping->ParallelRelayConfig.CtrlValue); } } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendRelayOn && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendRelayConfirmed) { // wait until extend parallel relay on confirmed bool confirmed = IsParallelRelayConfirmed(master); time = GetTimeoutValue(_ExtendCapability_time[master]) / uSEC_VAL; //if(confirmed || time >= WAIT_RELAY_CONFIRMED_TIME) if(time >= WAIT_RELAY_CONFIRMED_TIME) { ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendRelayConfirmed = true; LOG_INFO("Gun %d Extend Parallel Relay Confirmed %s", master + 1, confirmed ? "OK" : "Timeout"); } } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendRelayConfirmed && !ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendCompleted) { AddExtendMember(master); ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendCompleted = true; } if(ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ExtendCompleted) { ShmPsuGrouping->GroupCollection[master].GroupCtrl.RoleCtrl.ExtendCapabilityCtrlValue = 0; ShmPsuGrouping->GroupCollection[master].ExtendQuantityLimit = 0; ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.OutputCurrentStable = false; GetClockTime(&_ReachCurrent_time[master]); UpdateGunAvailableCapability(master); ShmPsuGrouping->GroupCollection[master].GroupCtrl.bits.ReachMaxStageCurrent = false; GetClockTime(&_StageCurrent_time[master]); LOG_INFO("Gun %d Extend Capability Completed", master + 1); } } void ShowGunVoltageCurrent(unsigned char master) { unsigned short voltage = 0, current = 0, fireVoltage = 0; unsigned short diffVoltage = 0, diffCurrent = 0; if(ShmPsuGrouping->GroupCollection[master].Role == _GROLE_MASTER) { voltage = (int)(chargingInfo[master]->PresentChargingVoltage * 10); current = (int)(chargingInfo[master]->PresentChargingCurrent * 10); fireVoltage = chargingInfo[master]->FireChargingVoltage; diffVoltage = voltage >= evseOutVol[master] ? voltage - evseOutVol[master] : evseOutVol[master] - voltage; diffCurrent = current >= evseOutCur[master] ? current - evseOutCur[master] : evseOutCur[master] - current; if(diffVoltage >= 10 || diffCurrent >= 10) { evseOutputDelay[master] = SHOW_OUTPUT_DELAY; evseOutVol[master] = voltage; evseOutCur[master] = current; } if(evseOutputDelay[master] != 0) { LOG_INFO("Gun %d NeedV: %4d V, NeedC: %3d A, OutputV: %4d.%d V, OutputC: %3d.%d A, FireV: %4d V", master + 1, (int)chargingInfo[master]->EvBatterytargetVoltage, (int)chargingInfo[master]->EvBatterytargetCurrent, (voltage / 10), (voltage % 10), (current / 10), (current % 10), fireVoltage / 10); evseOutputDelay[master]--; } } } // group: self group index void TryCleanPsuAlarm(unsigned char group) { for(int i = 0; i < ShmPsuPosition->GroupLocationInfo[group].GroupPsuQuantity; i++) { int psu_index = ShmPsuPosition->GroupLocationInfo[group].PsuIndex[i]; if(ShmPsuPosition->SinglePsuStatus[psu_index].StatusVal == PSU_STATUS_FLAG_LOCK) { UnlockPsuAlarm(ShmPsuPosition->PsuAddressInfo[psu_index].Full_Address); PSU_LOG("Unlock PSU Group[%d] Index[%d] Alarm Status", group, ShmPsuPosition->PsuAddressInfo[psu_index].GIndex); } } } void CheckPsuAlarmStatus(void) { if(_isTriggerShutdown) { return; } for(int i = 0; i < MAX_GROUP_QUANTITY; i++) { for(int j = 0; j < ShmPsuPosition->GroupLocationInfo[i].GroupPsuQuantity; j++) { int psu_index = ShmPsuPosition->GroupLocationInfo[i].PsuIndex[j]; int group = ShmPsuPosition->PsuAddressInfo[psu_index].GroupNo; int gIndex = ShmPsuPosition->PsuAddressInfo[psu_index].GIndex; if(ShmPsuPosition->SinglePsuStatus[psu_index].StatusVal != _LocalPsuStatus[psu_index].StatusVal) { if(((ShmPsuPosition->SinglePsuStatus[psu_index].StatusVal & 0x02) != (_LocalPsuStatus[psu_index].StatusVal & 0x02))) { if((ShmPsuPosition->SinglePsuStatus[psu_index].StatusVal & 0x02) != 0) { LOG_INFO("Group[%d][%d] Psu[%2d] Fault Occur", group, gIndex, psu_index); } else { LOG_INFO("Group[%d][%d] Psu[%2d] Fault Recovery", group, gIndex, psu_index); } } if(((ShmPsuPosition->SinglePsuStatus[psu_index].StatusVal & 0x04) != (_LocalPsuStatus[psu_index].StatusVal & 0x04))) { if((ShmPsuPosition->SinglePsuStatus[psu_index].StatusVal & 0x04) != 0) { LOG_INFO("Group[%d][%d] Psu[%2d] Alarm Occur", group, gIndex, psu_index); } else { LOG_INFO("Group[%d][%d] Psu[%2d] Alarm Recovery", group, gIndex, psu_index); } } if(((ShmPsuPosition->SinglePsuStatus[psu_index].StatusVal & 0x08) != (_LocalPsuStatus[psu_index].StatusVal & 0x08))) { if((ShmPsuPosition->SinglePsuStatus[psu_index].StatusVal & 0x08) != 0) { LOG_INFO("Group[%d][%d] Psu[%2d] Lock Occur", group, gIndex, psu_index); } else { LOG_INFO("Group[%d][%d] Psu[%2d] Lock Recovery", group, gIndex, psu_index); } } } _LocalPsuStatus[psu_index].StatusVal = ShmPsuPosition->SinglePsuStatus[psu_index].StatusVal; } } } void ShowInfyPsuErrState(int psu_index) { LOG_INFO("Group[%d][%d] Psu[%2d] State2: [%02X], State1: [%02X], State0: [%02X]", ShmPsuPosition->PsuAddressInfo[psu_index].GroupNo, ShmPsuPosition->PsuAddressInfo[psu_index].GIndex, psu_index, ShmPsuPosition->SingleInfyPwrState[psu_index].InfyPwrState.StateVal[2], ShmPsuPosition->SingleInfyPwrState[psu_index].InfyPwrState.StateVal[1], ShmPsuPosition->SingleInfyPwrState[psu_index].InfyPwrState.StateVal[0]); } void InfyPwrStateSummary(void) { InfyPsuStateFlagInfo _InfyPwrState; memset(&_InfyPwrState, 0x00, sizeof(_InfyPwrState)); for(int i = 0; i < MAX_PSU_MODULE_QUANTITY; i++) { _InfyPwrState.StateVal[0] |= ShmPsuPosition->SingleInfyPwrState[i].InfyPwrState.StateVal[0]; _InfyPwrState.StateVal[1] |= ShmPsuPosition->SingleInfyPwrState[i].InfyPwrState.StateVal[1]; _InfyPwrState.StateVal[2] |= ShmPsuPosition->SingleInfyPwrState[i].InfyPwrState.StateVal[2]; } // 012264 // DCDC short circuit ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuOutputShortCircuit = _InfyPwrState.bits.OutputShort ? YES : NO; // 012334 // PSU Failure Alarm ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFault = _InfyPwrState.bits.PsuFault ? YES : NO; // 012268 // PSU Protection Alarm ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuProtectionAlarm = _InfyPwrState.bits.PsuProtect ? YES : NO; // 012269 // Fan faults ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFanFailureAlarm = _InfyPwrState.bits.FanFault ? YES : NO; // 012226 // DCDC over temperature ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuCriticalPointOTP = _InfyPwrState.bits.OverTemperature ? YES : NO; // 012319 // DCDC output over voltage ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcdcOverVoltage = _InfyPwrState.bits.OutputOverVoltage ? YES : NO; // 012273 // Module unders power limiting status ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuPowerLimitedState = _InfyPwrState.bits.PowerLimit ? YES : NO; // 012263 // ID number repetition ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDuplicateID = _InfyPwrState.bits.PsuIdRepetition ? YES : NO; // 012313 // Phase loss ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputPhaseLoss = _InfyPwrState.bits.InputPhaseLost ? YES : NO; // 012271 // Under voltage of any phase ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputUVP = _InfyPwrState.bits.InputUnderVoltage ? YES : NO; // 012270 // Over voltage of any phase ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputOVP = _InfyPwrState.bits.InputOverVoltage ? YES : NO; } void ShowPhPsuErrRecord(int psu_index) { if(ShmPsuPosition->SinglePhPsuError[psu_index].ErrorCount == 0) { LOG_INFO("Group[%d][%d] Psu[%2d] Error Record Clear", ShmPsuPosition->PsuAddressInfo[psu_index].GroupNo, ShmPsuPosition->PsuAddressInfo[psu_index].GIndex, psu_index); } else { char strErrRecord[128]; char strError[16]; sprintf(strErrRecord, "Group[%d][%d] Psu[%2d] Err:", ShmPsuPosition->PsuAddressInfo[psu_index].GroupNo, ShmPsuPosition->PsuAddressInfo[psu_index].GIndex, psu_index); for(int i = 0; i < ShmPsuPosition->SinglePhPsuError[psu_index].ErrorCount; i++) { sprintf(strError, " E-%2d", ShmPsuPosition->SinglePhPsuError[psu_index].PsuError[i]); strcat(strErrRecord, strError); } LOG_INFO("%s", strErrRecord); } } void CheckPsuErrRecord(void) { if(_isTriggerShutdown) { return; } for(int i = 0; i < MAX_GROUP_QUANTITY; i++) { for(int j = 0; j < ShmPsuPosition->GroupLocationInfo[i].GroupPsuQuantity; j++) { int psu_index = ShmPsuPosition->GroupLocationInfo[i].PsuIndex[j]; if(ShmChargerInfo->Control.LibCtrl.bits.InfyPwrLib) { if(ShmPsuPosition->SingleInfyPwrState[psu_index].InfyPwrStateFlag.bits.Changed) { ShowInfyPsuErrState(psu_index); InfyPwrStateSummary(); ShmPsuPosition->SingleInfyPwrState[psu_index].InfyPwrStateFlag.bits.Changed = false; } } if(ShmChargerInfo->Control.LibCtrl.bits.PhPwrLib) { if(ShmPsuPosition->SinglePhPsuError[psu_index].PhPwrStateFlag.bits.Changed) { ShowPhPsuErrRecord(psu_index); ShmPsuPosition->SinglePhPsuError[psu_index].PhPwrStateFlag.bits.Changed = false; } } } } } bool IsPsuGroupAnyAlarm(unsigned char group) { if((ShmChargerInfo->PsuGrouping.GroupPsuStatus_OR[group].StatusVal & PSU_STATUS_FLAG_ALARM) > 0) { return true; } return false; } bool IsPsuGroupAnyFault(unsigned char group) { if((ShmChargerInfo->PsuGrouping.GroupPsuStatus_OR[group].StatusVal & PSU_STATUS_FLAG_FAULT) > 0) { return true; } return false; } bool IsPsuGroupAllAlarm(unsigned char group) { if((ShmChargerInfo->PsuGrouping.GroupPsuStatus_AND[group].StatusVal & PSU_STATUS_FLAG_ALARM) > 0) { return true; } return false; } bool IsPsuGroupAllFault(unsigned char group) { if((ShmChargerInfo->PsuGrouping.GroupPsuStatus_AND[group].StatusVal & PSU_STATUS_FLAG_FAULT) > 0) { return true; } return false; } bool IsPsuGroupAnyLock(unsigned char group) { if((ShmChargerInfo->PsuGrouping.GroupPsuStatus_OR[group].StatusVal & PSU_STATUS_FLAG_LOCK)) { return true; } return false; } bool IsAlternateMasterStop(unsigned char group) { if(ShmPsuGrouping->GroupCollection[group].AlternateMaster != 0) { return ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.AlternateMasterStopRequest; } return false; } void PsuGroupControlProcess(void) { int time = 0; unsigned char role = 0; PsuGroupPartner partner; //unsigned short TargetVoltage = 0, TargetCurrent = 0; for(byte group = 0; group < GENERAL_GUN_QUANTITY; group++) { role = ShmPsuGrouping->GroupCollection[group].Role; switch(role) { case _GROLE_IDLE: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.IdleCtrlValue = 0; ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.MasterCtrlValue = 0; ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.StopChargingCtrlValue = 0; ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.DeratingCtrlValue = 0; ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.ExtendCapabilityCtrlValue = 0; ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.SlaveCtrlValue = 0; ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.DummyMasterCtrlValue = 0; ShmPsuGrouping->GroupCollection[group].ExtendQuantityLimit = 0; ShmPsuGrouping->GroupCollection[group].AlternateMaster = 0; PSU_LOG("===== PSU Group[%02X] ===== Idle", group); GetClockTime(&_PsuGroupRole_time[group]); GetClockTime(&_CleanPsuAlarm_time[group]); ShmPsuGrouping->GroupOutput[group].GTargetVoltage = 0; ShmPsuGrouping->GroupOutput[group].GTargetCurrent = 0; PreGroupOutput[group].GTargetVoltage = 0; PreGroupOutput[group].GTargetCurrent = 0; ShmPsuGrouping->TotalGroupOutput[group].GTargetVoltage = 0; ShmPsuGrouping->TotalGroupOutput[group].GTargetCurrent = 0; SetPsuGroupOutput(group); UpdatePsuGroupLoading(group); } if(isStartOutputSwitch[group]) { SetPsuGroupPowerOnOff(group, _PSU_OFF); } if(ShmChargerInfo->Control.LibCtrl.bits.PhPwrLib) { if(IsPsuGroupAnyAlarm(group)) { time = GetTimeoutValue(_CleanPsuAlarm_time[group]) / uSEC_VAL; if(time >= PSU_CLEAN_ERR_INTERVAL) { PSU_LOG("PSU Group[%d] Alarm or Fault Occur, Need Do Something", group); GetClockTime(&_CleanPsuAlarm_time[group]); } // if module exist any alarm or fault, break here break; } else if(IsPsuGroupAnyLock(group)) { time = GetTimeoutValue(_CleanPsuAlarm_time[group]) / uSEC_VAL; if(time >= PSU_CLEAN_ERR_INTERVAL) { TryCleanPsuAlarm(group); GetClockTime(&_CleanPsuAlarm_time[group]); } // if module exist any lock, break here break; } } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.IdleCtrlValue != 0) { CheckChargingRequest(group); } else { if(ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity == 0) { if(GetPsuGroupAvailable(group) == 0) { if(!CheckAlternateMaster(group, &partner, YES) && !CheckAlternateMaster(group, &partner, NO)) { SetPsuGroupRole(group, _GROLE_NO_RESOURCE); } } } } break; case _GROLE_MASTER: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.MasterCtrlValue = 0; ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.StopChargingCtrlValue = 0; //ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.DeratingCtrlValue = 0; ShmPsuGrouping->GroupCollection[group].ExtendQuantityLimit = 0; PSU_LOG("===== PSU Group[%02X] ===== Master", group); GetClockTime(&_PsuGroupRole_time[group]); OutputConfigStep[group] = _CURRENT_MODE_NONE; _preOutputConfigStep[group] = _CURRENT_MODE_NONE; MaxCurrentDemand[group] = 0; StageMaxCurrent[group] = 0; _GfdStep[group] = PREPARE_STEP_NONE; _VoltageResumeCnt[group] = 0; } if(!ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.AlreadyInChargingMode) { if(chargingInfo[group]->SystemStatus == S_CHARGING && Is_OutputK1K2_Ready(group)) { LOG_INFO("Gun %d Enter Charging Mode", group + 1); ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.AlreadyInChargingMode = true; ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ReachMaxCurrentDemand = false; ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ReachMaxStageCurrent = false; GetClockTime(&_MaxCurrent_time[group]); GetClockTime(&_StageCurrent_time[group]); GetClockTime(&_ChargingDelay_time[group]); } } if((chargingInfo[group]->SystemStatus <= S_IDLE) || (chargingInfo[group]->SystemStatus >= S_TERMINATING && chargingInfo[group]->SystemStatus <= S_FAULT)) { if(!ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.StopChargingRequest) { LOG_INFO("Gun %d SystemStatus(%d) Need Stop Charging", group + 1, chargingInfo[group]->SystemStatus); } ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.StopChargingRequest = true; } else if(IsAlternateMasterStop(group)) { if(!ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.StopChargingRequest) { LOG_INFO("Gun %d Alternate Master Stop", group + 1, chargingInfo[group]->SystemStatus); } ShmChargerInfo->GunError[group].ErrFlag.bits.PsuGroupNoResource = true; ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.StopChargingRequest = true; } if((IsPsuGroupAllAlarm(group) || IsPsuGroupAllFault(group)) && !_isTriggerShutdown && !ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.StopChargingRequest) { if(!ShmChargerInfo->GunError[group].ErrFlag.bits.PsuGroupNoResource) { LOG_INFO("Gun %d PsuGroup All Alarm/Fault >> No Resource, Need Stop Charging", group + 1); } ShmChargerInfo->GunError[group].ErrFlag.bits.PsuGroupNoResource = true; } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.ExtendCapabilityCtrlValue == 0) { if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ExtendAvailable) { time = GetTimeoutValue(_ExtendCapability_time[group]) / uSEC_VAL; if(time >= EXTEND_CAPABILITY_DELAY) { #if 0 int available = GetPsuGroupAvailable(group); if(available > 0) { ShmPsuGrouping->GroupCollection[group].ExtendQuantityLimit = MAX_GROUP_QUANTITY; ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.MorePowerRequest = true; LOG_INFO("Gun %d Start Extend Capability", group + 1); } #endif ShmPsuGrouping->GroupCollection[group].ExtendQuantityLimit = 0; int reason = IsExtendConflict(group); char *str_conflict_reason[] = {STR_EXTEND_CONFLICT_NONE, STR_EXTEND_CONFLICT_AVAILABLE, STR_EXTEND_CONFLICT_AVERAGE, STR_EXTEND_CONFLICT_PRIORITY, STR_EXTEND_CONFLICT_UNKNOWN}; if(reason == _CONFLICT_NONE) { ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.MorePowerRequest = true; LOG_INFO("Gun %d Start Extend Capability", group + 1); } else { LOG_INFO("Gun %d Extend Capability Conflict: %s", group + 1, str_conflict_reason[reason]); } ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ExtendAvailable = false; } } } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.ExtendCapabilityCtrlValue != 0) { CleanSmoothDerating(group); MasterExtendCapabilityProcess(group); } // need derating if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.DeratingCtrlValue != 0 && !ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.StopChargingRequest) { CleanSmoothDerating(group); PsuGroupDeratingProcess(group); } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.StopChargingRequest) { ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.DeratingCtrlValue = 0; ShmPsuGrouping->GroupOutput[group].GTargetVoltage = 0; ShmPsuGrouping->GroupOutput[group].GTargetCurrent = 0; ShmPsuGrouping->TotalGroupOutput[group].GTargetVoltage = 0; ShmPsuGrouping->TotalGroupOutput[group].GTargetCurrent = 0; CleanSmoothDerating(group); MasterStopChargingProcess(group); } else { UpdateGunLoading(group); UpdatePsuGroupOutputConfig(group); UpdateMasterPsuGroupLoading(group); PsuGroupOutputConfigCheck(group); } ShowGunVoltageCurrent(group); SetPsuGroupOutput(group); break; case _GROLE_SLAVE: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; PSU_LOG("===== PSU Group[%02X] ===== Slave", group); GetClockTime(&_PsuGroupRole_time[group]); } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.SlaveCtrlValue != 0) { SlaveStopChargingProcess(group); } else { if(IsPsuGroupAllAlarm(group) || IsPsuGroupAllFault(group)) { if(!ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.SlavePowerOffRequest) { LOG_INFO("Gun %d PsuGroup (slave) All Alarm/Fault, Need Power Off", group + 1); } ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.SlavePowerOffRequest = true; } else { SetPsuGroupOutput(group); } } break; case _GROLE_PREPARE_SWITCH_OFF: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; PSU_LOG("===== PSU Group[%02X] ===== Prepare Off", group); GetClockTime(&_PsuGroupRole_time[group]); } time = GetTimeoutValue(_PsuGroupRole_time[group]) / uSEC_VAL; if(time >= MAX_PREPARE_SWITCH_OFF_TIME) { // timeout shall not happen SetPsuGroupRole(group, _GROLE_SLAVE_POWER_OFF); } else { SetPsuGroupOutput(group); } break; case _GROLE_SLAVE_POWER_OFF: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; PSU_LOG("===== PSU Group[%02X] ===== Slave Power Off", group); GetClockTime(&_PsuGroupRole_time[group]); } time = GetTimeoutValue(_PsuGroupRole_time[group]) / uSEC_VAL; if(time >= MIN_POWER_OFF_TIME && (ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent <= MAX_PSU_POWER_OFF_CURRENT || _isTriggerShutdown)) { SetPsuGroupRole(group, _GROLE_SWITCH_OFF_OK); } else { ShmPsuGrouping->GroupOutput[group].GTargetVoltage = 0; ShmPsuGrouping->GroupOutput[group].GTargetCurrent = 0; SetPsuGroupOutput(group); } break; case _GROLE_SWITCH_OFF_OK: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; PSU_LOG("===== PSU Group[%02X] ===== Switch Off OK, %d.%d V, %d.%d A", group, (ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage / 10), (ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage % 10), (ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent / 10), (ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent % 10)); GetClockTime(&_PsuGroupRole_time[group]); } break; case _GROLE_WAIT_IDLE: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; PSU_LOG("===== PSU Group[%02X] ===== Wait Idle, %d.%d V, %d.%d A", group, (ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage / 10), (ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage % 10), (ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent / 10), (ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent % 10)); GetClockTime(&_PsuGroupRole_time[group]); } break; case _GROLE_WAIT_SLAVE: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; PSU_LOG("===== PSU Group[%02X] ===== Wait Slave", group); GetClockTime(&_PsuGroupRole_time[group]); } time = GetTimeoutValue(_PsuGroupRole_time[group]) / uSEC_VAL; if(ShmPsuGrouping->GroupCollection[group].ReservedTarget != 0) { if(time >= WAIT_SLAVE_TO_CHARGING && (ShmPsuGrouping->GroupCollection[group].ReservedTarget - 1) == group) { SetPsuGroupRole(group, _GROLE_REQUEST_TO_CHARGING); ShmPsuGrouping->GroupCollection[group].GroupCtrl.bits.ChargingRequest = true; ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.SlaveCtrlValue = 0; break; } } if(time >= WAIT_SLAVE_TIMEOUT) { PSU_LOG("Group[%02X] Wait Slave Timeout", group); SetPsuGroupToIdle(group); } break; case _GROLE_PREPARE_ATTACH_ON: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; PSU_LOG("===== PSU Group[%02X] ===== Prepare Attach On", group); GetClockTime(&_PsuGroupRole_time[group]); } SetPsuGroupOutput(group); break; case _GROLE_PRECHARGE_READY: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; PSU_LOG("===== PSU Group[%02X] ===== Precharge %d.%d V Ready", group, (ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage / 10), (ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage % 10)); GetClockTime(&_PsuGroupRole_time[group]); } break; case _GROLE_EXTEND_STOP: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; PSU_LOG("===== PSU Group[%02X] ===== Extend Stop, %d.%d V", group, (ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage / 10), (ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage % 10)); GetClockTime(&_PsuGroupRole_time[group]); } time = GetTimeoutValue(_PsuGroupRole_time[group]) / uSEC_VAL; if(time >= MIN_POWER_OFF_TIME || (ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent <= MAX_PSU_POWER_OFF_CURRENT && ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage <= MAX_PSU_POWER_OFF_VOLTAGE)) { SetPsuGroupToIdle(group); } else { ShmPsuGrouping->GroupOutput[group].GTargetVoltage = 0; ShmPsuGrouping->GroupOutput[group].GTargetCurrent = 0; SetPsuGroupOutput(group); } break; case _GROLE_REQUEST_TO_CHARGING: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; PSU_LOG("===== PSU Group[%02X] ===== Request To Charging", group); GetClockTime(&_PsuGroupRole_time[group]); } if(ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.IdleCtrlValue != 0) { ChargingRequestProcess(group); } break; case _GROLE_TERMINATE: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; PSU_LOG("===== PSU Group[%02X] ===== Terminate", group); GetClockTime(&_PsuGroupRole_time[group]); } break; case _GROLE_WAIT_TERMINATED: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; PSU_LOG("===== PSU Group[%02X] ===== Wait Terminated", group); GetClockTime(&_PsuGroupRole_time[group]); } break; case _GROLE_DUMMY_MASTER: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; PSU_LOG("===== PSU Group[%02X] ===== Dummy Master", group); GetClockTime(&_PsuGroupRole_time[group]); } DummuMasterProcess(group); break; case _GROLE_DUMMY_FAULT: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; PSU_LOG("===== PSU Group[%02X] ===== Dummy Master Fault", group); GetClockTime(&_PsuGroupRole_time[group]); } time = GetTimeoutValue(_PsuGroupRole_time[group]) / uSEC_VAL; if(time >= WAIT_DUMMY_FAULT_TIME) { SetPsuGroupToIdle(group); } break; case _GROLE_NONE: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; PSU_LOG("===== PSU Group[%02X] ===== None", group); GetClockTime(&_PsuGroupRole_time[group]); } break; case _GROLE_NO_RESOURCE: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; PSU_LOG("===== PSU Group[%02X] ===== No Resource", group); GetClockTime(&_PsuGroupRole_time[group]); } if(GetPsuGroupAvailable(group) > 0) { SetPsuGroupRole(group, _GROLE_IDLE); } else if(CheckAlternateMaster(group, &partner, YES)) { SetPsuGroupRole(group, _GROLE_IDLE); } break; default: if(ShmPsuGrouping->GroupCollection[group].PreRole != role) { ShmPsuGrouping->GroupCollection[group].PreRole = role; PSU_LOG("===== PSU Group[%02X] ===== Unknown Role = %d", group, role); GetClockTime(&_PsuGroupRole_time[group]); } SetPsuGroupRole(group, _GROLE_NONE); break; } } } // only for test & debug purpose void PsuSimulationSetting(void) { ShmPsuData->Work_Step = _WORK_CHARGING; ShmPsuData->PsuGroup[0].GroupPresentPsuQuantity = 3; ShmPsuData->PsuGroup[1].GroupPresentPsuQuantity = 3; ShmPsuData->PsuGroup[2].GroupPresentPsuQuantity = 3; ShmPsuData->PsuGroup[3].GroupPresentPsuQuantity = 3; ShmSysConfigAndInfo->SysInfo.ConnectorInfo[0].RemoteMaxPhysicalVoltage = 9500; ShmSysConfigAndInfo->SysInfo.ConnectorInfo[0].RemoteMaxPhysicalCurrent = 5000; ShmSysConfigAndInfo->SysInfo.ConnectorInfo[1].RemoteMaxPhysicalVoltage = 9500; ShmSysConfigAndInfo->SysInfo.ConnectorInfo[1].RemoteMaxPhysicalCurrent = 2000; ShmSysConfigAndInfo->SysInfo.ConnectorInfo[2].RemoteMaxPhysicalVoltage = 9500; ShmSysConfigAndInfo->SysInfo.ConnectorInfo[2].RemoteMaxPhysicalCurrent = 5000; ShmSysConfigAndInfo->SysInfo.ConnectorInfo[3].RemoteMaxPhysicalVoltage = 9500; ShmSysConfigAndInfo->SysInfo.ConnectorInfo[3].RemoteMaxPhysicalCurrent = 2500; } // only for test & debug purpose void PsuGroupOutputSimulation(void) { byte master = 0; unsigned short pVoltage = 0, pCurrent = 0; unsigned short gVoltage = 0, gCurrent = 0; // psu output voltage & current simulation for(int i = 0; i < ShmPsuData->GroupCount; i++) { pVoltage = ShmPsuGrouping->GroupOutput[i].GTargetVoltage; pCurrent = ShmPsuGrouping->GroupOutput[i].GTargetCurrent; ShmPsuData->PsuGroup[i].GroupPresentOutputVoltage = pVoltage; ShmPsuData->PsuGroup[i].GroupPresentOutputCurrent = pCurrent; ShmPsuData->PsuGroup[i].GroupPresentOutputPower = (pVoltage * pCurrent) / 100 / 100; } // psu AvailableCurrent & GroupAvailablePower simulation for(int i = 0; i < ShmPsuData->GroupCount; i++) { if(ShmPsuData->PsuGroup[i].GroupPresentOutputVoltage == 0) { ShmPsuData->PsuGroup[i].GroupAvailableCurrent = ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity * 1000; } else { if(ShmPsuData->PsuGroup[i].GroupPresentOutputVoltage <= 3000) { ShmPsuData->PsuGroup[i].GroupAvailableCurrent = ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity * 1000; } else { ShmPsuData->PsuGroup[i].GroupAvailableCurrent = (30000 * 100 * ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity) / ShmPsuData->PsuGroup[i].GroupPresentOutputVoltage; } } ShmPsuData->PsuGroup[i].GroupAvailablePower = ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity * 300; } for(int i = 0; i < ShmPsuData->GroupCount; i++) { master = ShmChargerInfo->PsuGrouping.GroupCollection[i].TargetGroup; if(master == 0) { // calculate PresentChargingVoltage and PresentChargingCurrent of self group chargingInfo[i]->PresentChargingVoltage = (float)ShmPsuData->PsuGroup[i].GroupPresentOutputVoltage / 10; chargingInfo[i]->PresentChargingCurrent = (float)ShmPsuData->PsuGroup[i].GroupPresentOutputCurrent / 10; } else { if(i == (master - 1)) { gVoltage = ShmPsuData->PsuGroup[i].GroupPresentOutputVoltage; gCurrent = ShmPsuData->PsuGroup[i].GroupPresentOutputCurrent; for(byte j = 0; j < ShmPsuGrouping->GroupCollection[i].Partner.Quantity; j++) { byte slave = ShmPsuGrouping->GroupCollection[i].Partner.Member[j]; if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE || ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_PREPARE_SWITCH_OFF || ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE_POWER_OFF) { gCurrent += ShmPsuData->PsuGroup[slave].GroupPresentOutputCurrent; } } chargingInfo[i]->PresentChargingVoltage = (float)gVoltage / 10; chargingInfo[i]->PresentChargingCurrent = (float)gCurrent / 10; } } } } // only for test & debug purpose void PsuGroupAvailableSimulation(void) { unsigned char master = 0; int _groupCurrent = 0, _groupPower = 0; for(int i = 0; i < ShmPsuData->GroupCount; i++) { master = ShmChargerInfo->PsuGrouping.GroupCollection[i].TargetGroup; // calculate output group capability if(master == 0) { chargingInfo[i]->AvailableChargingCurrent = ShmPsuData->PsuGroup[i].GroupAvailableCurrent; chargingInfo[i]->AvailableChargingPower = ShmPsuData->PsuGroup[i].GroupAvailablePower; } else { _groupCurrent = ShmPsuData->PsuGroup[master - 1].GroupAvailableCurrent; _groupPower = ShmPsuData->PsuGroup[master - 1].GroupAvailablePower; for(byte j = 0; j < ShmPsuGrouping->GroupCollection[master - 1].Partner.Quantity; j++) { byte slave = ShmPsuGrouping->GroupCollection[master - 1].Partner.Member[j]; if(ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_SLAVE || ShmPsuGrouping->GroupCollection[slave].Role == _GROLE_PREPARE_SWITCH_OFF) { _groupCurrent += ShmPsuData->PsuGroup[slave].GroupAvailableCurrent; _groupPower += ShmPsuData->PsuGroup[slave].GroupAvailablePower; } } if(ShmPsuGrouping->GroupCollection[master - 1].GroupCtrl.bits.DeratingConfirmed) { chargingInfo[master - 1]->AvailableChargingCurrent = ShmPsuGrouping->GroupCollection[master - 1].ReAssignAvailableCurrent; } else { chargingInfo[master - 1]->AvailableChargingCurrent = _groupCurrent; } chargingInfo[master - 1]->AvailableChargingPower = _groupPower; chargingInfo[master - 1]->MaximumChargingVoltage = 9500; if((master - 1) != i) { chargingInfo[i]->AvailableChargingCurrent = 0; chargingInfo[i]->AvailableChargingPower = 0; chargingInfo[i]->RealRatingPower = 0; chargingInfo[i]->MaximumChargingVoltage = 0; } } } } void CapabilitySimulation(void) { unsigned short voltage = 0, current = 0, power = 0; unsigned short limitPower = 0, limitCurrent = 0; unsigned char inUsingCnt = 0; for(int i = 0; i < GENERAL_GUN_QUANTITY; i++) { if(ShmChargerInfo->PsuGrouping.GroupCollection[i].Role == _GROLE_MASTER) { inUsingCnt += ShmChargerInfo->PsuGrouping.GroupCollection[i].GunPsuQuantity; } } for(int i = 0; i < ShmPsuData->GroupCount; i++) { voltage = chargingInfo[i]->MaximumChargingVoltage; current = chargingInfo[i]->AvailableChargingCurrent; power = chargingInfo[i]->AvailableChargingPower; // ********** GetPhysicalLimitVoltageAndCurrent ********** if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].RemoteMaxPhysicalVoltage != 0 && ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].RemoteMaxPhysicalVoltage <= voltage) { voltage = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].RemoteMaxPhysicalVoltage; } if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].RemoteMaxPhysicalCurrent != 0 && ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].RemoteMaxPhysicalCurrent <= current) { current = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].RemoteMaxPhysicalCurrent; } // ********** GetModelNameLimitPower ********** if(ShmChargerInfo->PsuGrouping.GroupCollection[i].GunPsuQuantity != 0 && inUsingCnt != 0 && ShmChargerInfo->Control.ChargerRatingPower != 0) { limitPower = ShmChargerInfo->Control.ChargerRatingPower; if(ShmChargerInfo->Control.CabinetRole == _CROLE_MASTER) { limitPower += ShmChargerInfo->ParallelCabinet.TotalParallelPower; } limitPower = (limitPower * ShmChargerInfo->PsuGrouping.GroupCollection[i].GunPsuQuantity) / inUsingCnt; } if(limitPower != 0 && limitPower <= power) { power = limitPower; } // ********** GetConfigLimitPowerAndCurrent ********** if(ShmChargerInfo->PsuGrouping.GroupCollection[i].GunPsuQuantity != 0 && inUsingCnt != 0 && ShmSysConfigAndInfo->SysConfig.MaxChargingPower != 0) { limitPower = ShmSysConfigAndInfo->SysConfig.MaxChargingPower * 10; limitPower = (limitPower * ShmChargerInfo->PsuGrouping.GroupCollection[i].GunPsuQuantity) / inUsingCnt; } ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].MaxTotalChargingPower = limitPower; if(ShmChargerInfo->PsuGrouping.GroupCollection[i].GunPsuQuantity != 0 && inUsingCnt != 0 && ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent != 0) { limitCurrent = ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent * 10; limitCurrent = (limitCurrent * ShmChargerInfo->PsuGrouping.GroupCollection[i].GunPsuQuantity) / inUsingCnt; } ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].MaxTotalChargingCurrent = limitCurrent; if(limitPower != 0 && limitPower <= power) { power = limitPower; } if(limitCurrent != 0 && limitCurrent <= current) { current = limitCurrent; } ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].CapabilityVoltage = voltage; ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].CapabilityCurrent = current; ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].CapabilityPower = power; } } void PsuGroupingInitial(void) { for(int i = 0; i < ShmPsuData->GroupCount; i++) { ShmPsuGrouping->GroupCollection[i].Role = 0; ShmPsuGrouping->GroupCollection[i].PreRole = 0xFF; memset(&ShmPsuGrouping->GroupCollection[i].Partner, 0x00, sizeof(PsuGroupPartner)); memset(&ShmPsuGrouping->GroupCollection[i].PossibleMember, 0x00, sizeof(PsuGroupPartner)); ShmPsuGrouping->GroupCollection[i].TargetGroup = 0; ShmPsuGrouping->GroupCollection[i].ReservedTarget = 0; memset(&ShmPsuGrouping->GroupCollection[i].GroupCtrl, 0x00, sizeof(PsuGroupControl)); ShmPsuGrouping->GroupCollection[i].ReAssignAvailableCurrent = 0; ShmPsuGrouping->GroupCollection[i].ParallelCheck = 0; ShmPsuGrouping->GroupCollection[i].GunLoading = 0; memset(&ShmPsuGrouping->GroupOutput[i], 0x00, sizeof(GroupOutputConfigInfo)); } } void PsuCommLostCheck(void) { if(ShmPsuData->Work_Step != INITIAL_START && ShmPsuData->Work_Step != _NO_WORKING && ShmPsuData->Work_Step != _INIT_PSU_STATUS) { if(!isCommStart) { isCommStart = true; ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt = 0; lostCnt = 0; GetClockTime(&_PsuCommCheck_time); } if((GetTimeoutValue(_PsuCommCheck_time) / uSEC_VAL) >= PSU_COMM_CHECK_TIME) { ShmChargerInfo->Control.CommInfo.PsuComm.CommCnt = ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt; ShmChargerInfo->Control.CommInfo.PsuComm.RxCnt = 0; if(ShmChargerInfo->Control.CommInfo.PsuComm.CommCnt > COMM_LOST_CRITICAL) { if(ShmChargerInfo->Control.PsuCtrl.bits.CommunicationLost) { LOG_INFO("Psu Communication Recovery"); } ShmChargerInfo->Control.PsuCtrl.bits.CommunicationLost = NO; lostCnt = 0; } else { lostCnt++; if(lostCnt >= LOST_CNT_CRITICAL) { if(!ShmChargerInfo->Control.PsuCtrl.bits.CommunicationLost) { LOG_INFO("Psu Communication Lost"); } ShmChargerInfo->Control.PsuCtrl.bits.CommunicationLost = YES; } } GetClockTime(&_PsuCommCheck_time); } } else { isCommStart = false; ShmChargerInfo->Control.PsuCtrl.bits.CommunicationLost = NO; lostCnt = 0; /* if(ShmChargerInfo->Control.PsuCtrl.bits.Paused) { system("ifconfig can1 down"); sleep(1); system("ifconfig can1 up"); sleep(1); LOG_INFO("Psu Can Port Down & Up"); } ShmChargerInfo->Control.PsuCtrl.bits.Paused = NO; */ } } void InitialGunLimitSequence(void) { for(int i = 0; i < MAX_GROUP_QUANTITY; i++) { _GunIndexOfPrioritySequence[i] = i; } } bool IsShutdownTrigger(void) { if(ShmChargerInfo->Control.RelayCtrl.bits.AcContactorOffByPsu == YES || ShmChargerInfo->Control.RelayCtrl.bits.AcContactorOffByEmergency == YES) { if(!_isTriggerShutdown) { PSU_LOG("Psu Shutdown Flag Is Trigger!"); } _isTriggerShutdown = true; return true; } if(_isTriggerShutdown) { PSU_LOG("Psu Shutdown Flag Recover"); } _isTriggerShutdown = false; return false; } bool IsShutdownCompleted(void) { bool done = false; if(IsShutdownTrigger()) { done = true; for(int i = 0; i < GENERAL_GUN_QUANTITY; i++) { if(ShmPsuGrouping->GroupCollection[i].Role != _GROLE_IDLE) { done = false; break; } } if(done) { if(!_isShutdownCompleted) { PSU_LOG("Psu Shutdown Completed!"); } _isShutdownCompleted = true; } return done; } if(_isShutdownCompleted) { PSU_LOG("Psu Shutdown Clear!"); } _isShutdownCompleted = false; return done; } void PsuIndication(void) { if(ShmChargerInfo->Control.LibCtrl.bits.InfyPwrLib) { for(int i = 0; i < MAX_PSU_MODULE_QUANTITY; i++) { if(ShmPsuPosition->SingleInfyPwrState[i].InfyPwrStateFlag.bits.Indicated) { LedSingleOnOff(i, _PSU_ON); LOG_INFO("Set Psu[%2d] Led Blinking", i); _Psu_Indication_Enable[i] = true; _Psu_Indication_Count[i] = PSU_INDICATION_TIME; ShmPsuPosition->SingleInfyPwrState[i].InfyPwrStateFlag.bits.Indicated = false; } else { if(_Psu_Indication_Enable[i]) { _Psu_Indication_Count[i]--; if(_Psu_Indication_Count[i] == 0) { LedSingleOnOff(i, _PSU_OFF); LOG_INFO("Set Psu[%2d] Led Static", i); _Psu_Indication_Enable[i] = false; } } } } } if(ShmChargerInfo->Control.LibCtrl.bits.PhPwrLib) { } } int main(void) { byte _TotalModuleCount = 0; byte _PrePsuWorkStep = 0; byte isInitialComp = NO; if(InitShareMemory() == FAIL) { #ifdef SystemLogMessage LOG_ERROR("InitShareMemory NG"); #endif if(ShmStatusCodeData != NULL) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.FailToCreateShareMemory = 1; } sleep(5); return 0; } LOG_INFO("Psu Task PID = %d", getpid()); signal(SIGCHLD, SIG_IGN); // register callback function RefreshPsuIndex(&FindPsuIndex); RefreshGroup(&GetGroupCallback); RefreshAlarmStatus(&GetAlarmStatusCallback); RefreshInfyPwrAlarmFlag(&GetInfyPwrAlarmFlagCallback); RefreshPhPwrAlarmFlag(&GetPhPwrAlarmFlagCallback); RefreshAmbient(&GetAmbientCallback); RefreshModuleCount(&GetModuleCountCallback); RefreshSysModuleCount(&GetSysModuleCountCallback); RefreshAvailableCap(&GetAvailableCapCallback); RefreshFwDcVersion(&GetDcFwCallback); RefreshFwPfcVersion(&GetPfcFwCallback); RefreshInputVol(&GetInputVoltageCallback); RefreshGetOutput(&GetPresentOutputCallback); RefreshFanSpeedInfo(&GetFanSpeedCallback); RefreshInletTemp(&GetInletTempCallback); RefreshExletTemp(&GetExletTempCallback); RefreshOutletTemp(&GetOutletTempCallback); RefreshOtherTemp(&GetOtherTempCallback); RefreshIavailable(&GetIavailableCallback); RefreshGetOutputF(&GetPresentOutputFCallback); RefreshGetModuleOutput(&GetModuleOutputCallback); RefreshGetErrorRecord(&GetErrorRecordCallback); // GetPresentOutputCallback & GetStatusCallback AutoMode_RefreshOutputAndTemp(&GetOutputAndTempCallback); // GetStatusCallback AutoMode_RefreshModuleStatus(&GetModuleStatusCallback); // GetInputVoltageCallback AutoMode_RefreshModuleInput(&GetModuleInputCallback); sleep(2); InitialGunLimitSequence(); _gunCount = GENERAL_GUN_QUANTITY; _maxGroupCount = MAX_GROUP_QUANTITY; _PrePsuWorkStep = _INIT_PSU_STATUS; ShmPsuData->Work_Step = INITIAL_START; isInitialComp = NO; isCommStart = false; _isTriggerShutdown = false; _isShutdownCompleted = false; LOG_INFO("PSU Work Status = %d", ShmPsuData->Work_Step); // initial object Initialization(); InitialPsuData(); //libInitialize = InitialCommunication(); Run_PsuRxCommProcess(); //main loop while (1) { PsuCommLostCheck(); IsShutdownCompleted(); // 斷電狀態 if (ShmChargerInfo->Control.RelayCtrl.bits.AcContactor == NO || ShmChargerInfo->Control.PsuCtrl.bits.NeedSelfTest == YES || ShmChargerInfo->Control.PsuCtrl.bits.Paused == YES || _isShutdownCompleted) { //一但 AC Off PSU 斷電全部的 PSU Group ID 會全部清 0 if (!isInitialComp) { _PrePsuWorkStep = _INIT_PSU_STATUS; ShmPsuData->Work_Step = INITIAL_START; psuCmdSeq = _PSU_CMD_STATUS; _TotalModuleCount = 0; PsuGroupingInitial(); sleep(2); InitialPsuData(); isInitialComp = YES; } if(ShmChargerInfo->Control.PsuCtrl.bits.NeedSelfTest) { ShmChargerInfo->Control.PsuCtrl.bits.NeedSelfTest = NO; ShmChargerInfo->Control.PsuCtrl.bits.SelfTestOK = NO; memset(ShmChargerInfo->Control.PsuInitQuantity, 0x00, sizeof(ShmChargerInfo->Control.PsuInitQuantity)); LOG_INFO("Psu Need Execute Self Test!"); } sleep(1); continue; } else { if(isInitialComp) { system("ifconfig can1 down"); sleep(1); system("ifconfig can1 up"); LOG_INFO("Psu Can Port Down & Up"); } isInitialComp = NO; } // only for test & debug purpose if(ShmChargerInfo->Control.TestCtrl.bits.ChargingSimulation) { PsuSimulationSetting(); PsuGroupOutputSimulation(); PsuGroupAvailableSimulation(); CapabilitySimulation(); } // 自檢失敗 if (ShmPsuData->Work_Step == _NO_WORKING) { LOG_INFO("== PSU == self test fail."); sleep(5); } if((GetTimeoutValue(_PsuReceiveRecoveryCheck_time) / uSEC_VAL) >= PSU_TASK_CHECK_TIME) { //PsuReceiveRecoveryCheck(); if(!Is_PsuRxComm_Alive()) { Run_PsuRxCommProcess(); } GetClockTime(&_PsuReceiveRecoveryCheck_time); } switch(ShmPsuData->Work_Step) { case INITIAL_START: { if(_PrePsuWorkStep != ShmPsuData->Work_Step) { _PrePsuWorkStep = ShmPsuData->Work_Step; LOG_INFO("== PSU == INITIAL_START"); } sleep(5); PsuGroupOnOff(SYSTEM_CMD, _PSU_OFF); SetWalkInConfig(SYSTEM_CMD, NO, 0); for (byte index = 0; index < ShmPsuData->GroupCount; index++) { isStartOutputSwitch[index] = false; } ShmPsuData->Work_Step = GET_PSU_COUNT; } break; case GET_PSU_COUNT: { if(_PrePsuWorkStep != ShmPsuData->Work_Step) { _PrePsuWorkStep = ShmPsuData->Work_Step; LOG_INFO("== PSU == GET_PSU_COUNT"); GetClockTime(&_PsuWorkStep_time); GetClockTime(&_cmdSubPriority_time); } int time = GetTimeoutValue(_PsuWorkStep_time) / uSEC_VAL; int interval = GetTimeoutValue(_cmdSubPriority_time) / uSEC_VAL; if(interval >= GET_PSU_COUNT_INTERVAL) { _TotalModuleCount = 0; for (byte index = 0; index < ShmPsuData->GroupCount; index++) { // 總和各群模組數量 _TotalModuleCount += ShmPsuData->PsuGroup[index].GroupPresentPsuQuantity; } LOG_INFO("== PSU == indexCount = %d, moduleCount = %d, sysCount = %d", ShmPsuData->GroupCount, _TotalModuleCount, ShmPsuData->SystemInitialPsuQuantity); // 判斷系統數量與各群數量一致 if(_TotalModuleCount == ShmPsuData->SystemInitialPsuQuantity && _TotalModuleCount > 0 && time > GET_PSU_COUNT_TIME) { LOG_INFO("Psu Count = %d", _TotalModuleCount); for(int i = 0; i < MAX_GROUP_QUANTITY; i++) { ShmChargerInfo->Control.PsuInitQuantity[i] = ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity; } ShmPsuData->Work_Step = Get_PSU_LOCATION; } else { // 發送取得目前全部模組數量 GetSysModuleCount(); for (byte index = 0; index < ShmPsuData->GroupCount; index++) { // 取各群模組數量 GetModuleCount(index); } } GetClockTime(&_cmdSubPriority_time); } } break; case Get_PSU_LOCATION: { if(_PrePsuWorkStep != ShmPsuData->Work_Step) { _PrePsuWorkStep = ShmPsuData->Work_Step; LOG_INFO("== PSU == Get_PSU_LOCATION"); // clean psu location info memset(ShmPsuPosition, 0x00, sizeof(PsuPositionInfoData)); GetClockTime(&_cmdSubPriority_time); } int interval = GetTimeoutValue(_cmdSubPriority_time) / mSEC_VAL; if(interval >= GET_PSU_LOCATION_INTERVAL) { for(byte index = 0; index < ShmPsuData->GroupCount; index++) { if(ShmPsuData->PsuGroup[index].GroupPresentPsuQuantity > 0) { // 取得狀態 : 支援模塊不須按照順序功能 GetStatus(index); } } GetClockTime(&_cmdSubPriority_time); } if(ShmPsuPosition->PsuLocationInit) { for(int i = 0; i < _maxGroupCount; i++) { UpdateGunTotalPsuQuantity(i); #if 1 if(ShmPsuPosition->GroupLocationInfo[i].GroupPsuQuantity > 0) { ShowGroupMember(i); } #endif } //ShmPsuData->Work_Step = Get_PSU_VERSION; ShmPsuData->Work_Step = PSU_COUNT_CONFIRM; } if(ShmPsuPosition->ReInitPsuLocation) { LOG_INFO("Retry Psu Location Initialization"); ShmPsuData->Work_Step = GET_PSU_COUNT; } } break; case PSU_COUNT_CONFIRM: { if(_PrePsuWorkStep != ShmPsuData->Work_Step) { _PrePsuWorkStep = ShmPsuData->Work_Step; LOG_INFO("== PSU == PSU_COUNT_CONFIRM"); GetClockTime(&_PsuWorkStep_time); GetClockTime(&_cmdSubPriority_time); } int time = GetTimeoutValue(_PsuWorkStep_time) / uSEC_VAL; int interval = GetTimeoutValue(_cmdSubPriority_time) / mSEC_VAL; if(interval > PSU_COUNT_CONFIRM_INTERVAL) { _TotalModuleCount = 0; for (byte index = 0; index < _maxGroupCount; index++) { // 總和各群模組數量 _TotalModuleCount += ShmPsuData->PsuGroup[index].GroupPresentPsuQuantity; } if(time > PSU_COUNT_CONFIRM_TIME) { if(_TotalModuleCount == ShmPsuData->SystemInitialPsuQuantity && _TotalModuleCount > 0) { ShmPsuData->Work_Step = Get_PSU_VERSION; } else { LOG_INFO("Total PSU = %d, System PSU Quantity = %d", _TotalModuleCount, ShmPsuData->SystemInitialPsuQuantity); LOG_INFO("PSU Quantity Confirm Fail"); ShmPsuData->Work_Step = GET_PSU_COUNT; } break; } // 發送取得目前全部模組數量 GetSysModuleCount(); for (byte index = 0; index < ShmPsuData->GroupCount; index++) { // 取各群模組數量 GetModuleCount(index); } GetClockTime(&_cmdSubPriority_time); } } break; case Get_PSU_VERSION: { if(_PrePsuWorkStep != ShmPsuData->Work_Step) { _PrePsuWorkStep = ShmPsuData->Work_Step; LOG_INFO("== PSU == Get_PSU_VERSION"); GetClockTime(&_cmdSubPriority_time); // clean version info memset(ShmPsuData->PsuVersion, 0x00, sizeof(ShmPsuData->PsuVersion)); } int interval = GetTimeoutValue(_cmdSubPriority_time) / mSEC_VAL; if (interval >= GET_PSU_VERSION_INTERVAL) { bool isGetVersion = true; for(byte psu = 0; psu < ShmPsuData->SystemInitialPsuQuantity; psu++) { if (strcmp((char *)ShmPsuData->PsuVersion[psu].FwPrimaryVersion, "") == EQUAL) { isGetVersion = false; break; } } if(isGetVersion) { #if 1 for(int i = 0; i < _maxGroupCount; i++) { if(ShmPsuPosition->GroupLocationInfo[i].GroupPsuQuantity > 0) { ShowPsuVersion(i); } } #endif ShmPsuData->Work_Step = GET_SYS_CAP; } else { for(byte group = 0; group < _maxGroupCount; group++) { if(ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity > 0) { // 取版號 GetAllModuleVer(group); } } } GetClockTime(&_cmdSubPriority_time); } } break; case GET_SYS_CAP: { if(_PrePsuWorkStep != ShmPsuData->Work_Step) { _PrePsuWorkStep = ShmPsuData->Work_Step; LOG_INFO("== PSU == GET_SYS_CAP"); GetClockTime(&_PsuWorkStep_time); GetClockTime(&_cmdSubPriority_time); } int time = GetTimeoutValue(_PsuWorkStep_time) / uSEC_VAL; int interval = GetTimeoutValue(_cmdSubPriority_time) / mSEC_VAL; if (interval >= GET_PSU_CAP_INTERVAL) { if(time > GET_PSU_CAP_TIME && ShmPsuData->SystemAvailablePower > 0 && ShmPsuData->SystemAvailableCurrent > 0) { #if 1 for(int i = 0; i < _maxGroupCount; i++) { if(ShmPsuPosition->GroupLocationInfo[i].GroupPsuQuantity > 0) { ShowGroupAvailableCurrentPower(i); } } #endif // 判斷系統輸出額定功率與電流 LOG_INFO("SystemAvailableCurrent = %d, SystemAvailablePower = %d", ShmPsuData->SystemAvailableCurrent, ShmPsuData->SystemAvailablePower); ShmPsuData->Work_Step = BOOTING_COMPLETE; } else { for(byte index = 0; index < ShmPsuData->GroupCount; index++) { if(ShmPsuData->PsuGroup[index].GroupPresentPsuQuantity > 0) { // 取系統總輸出能力 GetModuleCap(index); } } } GetClockTime(&_cmdSubPriority_time); } } break; case BOOTING_COMPLETE: { if(_PrePsuWorkStep != ShmPsuData->Work_Step) { _PrePsuWorkStep = ShmPsuData->Work_Step; LOG_INFO("== PSU == BOOTING_COMPLETE"); } if(ShmChargerInfo->Control.PsuCtrl.bits.SelfTestOK) { ShmPsuData->Work_Step = _WORK_CHARGING; } else { LOG_INFO("== PSU == Self Test OK!"); } ShmChargerInfo->Control.PsuCtrl.bits.SelfTestOK = true; } break; case _WORK_CHARGING: { if(_PrePsuWorkStep != ShmPsuData->Work_Step) { _PrePsuWorkStep = ShmPsuData->Work_Step; LOG_INFO("== PSU == _WORK_CHARGING"); GetClockTime(&_PsuWorkStep_time); GetClockTime(&_cmdSubPriority_time); PsuGroupingInitial(); } int time = GetTimeoutValue(_cmdSubPriority_time) / 1000; // 低 Priority 的指令 if (time >= 1000) { GetSysModuleCount(); for(int i = 0; i < MAX_GROUP_QUANTITY; i++) { if(ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity > 0) { GetStatus(i); GetModuleCount(i); GetModuleInputVol(i); if(IsPsuGroupAnyAlarm(i) || IsPsuGroupAnyFault(i)) { GetErrorRecord(i); } } } PsuIndication(); for(int i = 0; i < MAX_GUN_QUANTITY; i++) { UpdateGunTotalPsuQuantity(i); } GetClockTime(&_cmdSubPriority_time); } CheckPsuAlarmStatus(); CheckPsuErrRecord(); PsuGroupRoutineQuery(); PsuGroupControlProcess(); break; } case _TEST_MODE: { // 在測試模式中,保持與模塊的通訊 int time = GetTimeoutValue(_cmdSubPriority_time) / 1000; if (time > 1500) { for (byte index = 0; index < ShmPsuData->GroupCount; index++) { // 取系統總輸出能力 GetModuleCap(index); // 取各群輸出電壓電流 (float) GetModuleOutputF(index); } GetClockTime(&_cmdSubPriority_time); } byte _switch = 0x00; if ((chargingInfo[0]->EvBatterytargetVoltage * 10) > 0 && (chargingInfo[0]->EvBatterytargetCurrent * 10) > 0) _switch = 0x01; for (byte _groupCount_1 = 0; _groupCount_1 < conn_1_count; _groupCount_1++) { SetDirModulePresentOutput(connector_1[_groupCount_1], (chargingInfo[0]->EvBatterytargetVoltage * 10), (chargingInfo[0]->EvBatterytargetCurrent * 10), _switch, _switch); } for (byte _groupCount_2 = 0; _groupCount_2 < conn_2_count; _groupCount_2++) { SetDirModulePresentOutput(connector_2[_groupCount_2], (chargingInfo[0]->EvBatterytargetVoltage * 10), (chargingInfo[0]->EvBatterytargetCurrent * 10), _switch, _switch); } } break; case _INIT_PSU_STATUS: if(_PrePsuWorkStep != ShmPsuData->Work_Step) { _PrePsuWorkStep = ShmPsuData->Work_Step; LOG_INFO("== PSU == _INIT_PSU_STATUS"); GetClockTime(&_cmdSubPriority_time); } break; default: break; } usleep(20000); } return FAIL; }