#include "Module_PsuComm.h"

#define ARRAY_SIZE(A)       (sizeof(A) / sizeof(A[0]))
#define PASS                1
#define FAIL                -1
#define YES                 1
#define NO                  0
#define DERATING_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_MIN_CUR         1000
#define PSU_MIN_VOL         1500
#define PRE_CHARG_STEP_CUR  30
#define PRE_CHARG_RANGE     50
#define EQUAL               0

struct SysConfigAndInfo         *ShmSysConfigAndInfo;
struct StatusCodeData           *ShmStatusCodeData;
struct PsuData                  *ShmPsuData;

bool libInitialize = false;
byte getAvailableCapOffset = 5;
byte deratingKeepCount = 0;

float evseOutVol = 0;
float evseOutCur = 0;

void PRINTF_FUNC(char *string, ...);

#define DEBUG_INFO(format, args...)     StoreLogMsg("[%s:%d][%s][Info] "format, __FILE__, __LINE__, __FUNCTION__, ##args)
#define DEBUG_WARN(format, args...)     StoreLogMsg("[%s:%d][%s][Warn] "format, __FILE__, __LINE__, __FUNCTION__, ##args)
#define DEBUG_ERROR(format, args...)    StoreLogMsg("[%s:%d][%s][Error] "format, __FILE__, __LINE__, __FUNCTION__, ##args)

unsigned long GetTimeoutValue(struct timeval _sour_time);

unsigned long GetTimeoutValue(struct timeval _sour_time)
{
    struct timeval _end_time;
    gettimeofday(&_end_time, NULL);

    return 1000000 * (_end_time.tv_sec - _sour_time.tv_sec) + _end_time.tv_usec - _sour_time.tv_usec;
}

int StoreLogMsg(const char *fmt, ...)
{
    char Buf[4096+256];
    char buffer[4096];
    va_list args;
    struct timeb  SeqEndTime;
    struct tm *tm;

    va_start(args, fmt);
    int rc = vsnprintf(buffer, sizeof(buffer), fmt, args);
    va_end(args);

    memset(Buf,0,sizeof(Buf));
    ftime(&SeqEndTime);
    SeqEndTime.time = time(NULL);
    tm=localtime(&SeqEndTime.time);

    if (ShmSysConfigAndInfo->SysConfig.SwitchDebugFlag == YES)
    {
        sprintf(Buf,"%02d:%02d:%02d.%03d - %s",
                tm->tm_hour,tm->tm_min,tm->tm_sec,SeqEndTime.millitm, buffer);
        printf("%s \n", Buf);
    }
    else
    {
        sprintf(Buf,"echo \"%04d-%02d-%02d %02d:%02d:%02d.%03d - %s\" >> /Storage/SystemLog/[%04d.%02d]SystemLog",
                tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,SeqEndTime.millitm,
                buffer,
                tm->tm_year+1900,tm->tm_mon+1);
        system(Buf);
    }

    return rc;
}

void PRINTF_FUNC(char *string, ...)
{
    va_list args;
    char buffer[4096];
    va_start(args, string);
    vsnprintf(buffer, sizeof(buffer), string, args);
    va_end(args);

    DEBUG_INFO("%s \n", buffer);
}
//=================================
// Common routine
//=================================
size_t FindIndex(const int a[], size_t size, int value, byte group)
{
    size_t index = 0;

    while ( index < size && a[index] != value ) ++index;
    return (index == size ? ELEMENT_NOT_FIND : group);
}

byte FindTargetGroup(byte address)
{
    byte _group = ELEMENT_NOT_FIND;

    if (ShmPsuData->GroupCount == 1)
        _group = 0;
    else
    {
        _group = FindIndex(connector_1, ShmPsuData->PsuGroup[0].GroupPresentPsuQuantity, address, 0);

        if (_group == ELEMENT_NOT_FIND)
            _group = FindIndex(connector_2, ShmPsuData->PsuGroup[1].GroupPresentPsuQuantity, address, 1);
    }

    return _group;
}

bool IsOverModuleCount(byte count)
{
    bool result = false;

    if (count >= ShmPsuData->SystemPresentPsuQuantity)
        result = true;

    return result;
}
//=================================
// Save data to share memory Function
//=================================
bool FindChargingInfoData(byte target, struct ChargingInfoData **chargingData)
{
    for (byte index = 0; index < CHAdeMO_QUANTITY; index++)
    {
        if (ShmSysConfigAndInfo->SysInfo.ChademoChargingData[index].Index == target)
        {
            chargingData[target] = &ShmSysConfigAndInfo->SysInfo.ChademoChargingData[index];
            return true;
        }
    }

    for (byte index = 0; index < CCS_QUANTITY; index++)
    {
        if (ShmSysConfigAndInfo->SysInfo.CcsChargingData[index].Index == target)
        {
            chargingData[target] = &ShmSysConfigAndInfo->SysInfo.CcsChargingData[index];
            return true;
        }
    }

    for (byte index = 0; index < GB_QUANTITY; index++)
    {
        if (ShmSysConfigAndInfo->SysInfo.GbChargingData[index].Index == target)
        {
            chargingData[target] = &ShmSysConfigAndInfo->SysInfo.GbChargingData[index];
            return true;
        }
    }

    return false;
}

//=================================
// Alarm code mapping to share memory Function
//=================================
// 檢查 Byte 中某個 Bit 的值
// _byte : 欲改變的 byte
// _bit : 該 byte 的第幾個 bit
unsigned char mask_table[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
unsigned char DetectBitValue(unsigned char _byte, unsigned char _bit)
{
    return ( _byte & mask_table[_bit] ) != 0x00;
}

void AbnormalStopAnalysis(byte gun_index, int errCode)
{
    for (char i = 0; i < 3; i++)
    {
        unsigned char byteIndex = (errCode >> (8 * i)) & 0xff;

        for (char bitIndex = 0; bitIndex < 8; bitIndex++)
        {
            if(DetectBitValue(byteIndex , bitIndex) == 1)
            {
                switch(byteIndex)
                {
                    case 0:
                    {
                        if (bitIndex == 0)
                            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuOutputShortCircuit = YES;
                        else if (bitIndex == 5)
                            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = YES;
                    }
                        break;
                    case 1:
                    {
                        if (bitIndex == 1)
                            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFailureAlarm = YES;
                        else if (bitIndex == 2)
                            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuProtectionAlarm = YES;
                        else if (bitIndex == 3)
                            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFanFailureAlarm = YES;
                        else if (bitIndex == 4)
                            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuCriticalPointOTP = YES;
                        else if (bitIndex == 5)
                            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = YES;
                    }
                    break;
                    case 2:
                    {
                        if (bitIndex == 0)
                            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuPowerLimitedState = YES;
                        else if (bitIndex == 1)
                            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDuplicateID = YES;
                        else if (bitIndex == 2)
                            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseOnputImbalance = YES;
                        else if (bitIndex == 3)
                            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseInputInadequate = YES;
                        else if (bitIndex == 4)
                            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseInputInadequate = YES;
                        else if (bitIndex == 5)
                            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputUVP = YES;
                        else if (bitIndex == 6)
                            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputOVP = YES;
                    }
                    break;
                }
            }
//          else
//          {
//              switch (byteIndex) {
//              case 0: {
//                  if (bitIndex == 0)
//                      ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuOutputShortCircuit = NO;
//                  else if (bitIndex == 5)
//                      ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = NO;
//              }
//                  break;
//              case 1: {
//                  if (bitIndex == 1)
//                      ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFailureAlarm = NO;
//                  else if (bitIndex == 2)
//                      ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuProtectionAlarm = NO;
//                  else if (bitIndex == 3)
//                      ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFanFailureAlarm = NO;
//                  else if (bitIndex == 4)
//                      ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuCriticalPointOTP = NO;
//                  else if (bitIndex == 5)
//                      ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = NO;
//              }
//                  break;
//              case 2: {
//                  if (bitIndex == 1)
//                      ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDuplicateID = NO;
//                  if (bitIndex == 2)
//                      ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseOnputImbalance = NO;
//                  else if (bitIndex == 3)
//                      ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseInputInadequate = NO;
//                  else if (bitIndex == 4)
//                      ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseInputInadequate = NO;
//                  else if (bitIndex == 5)
//                      ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputUVP = NO;
//                  else if (bitIndex == 6)
//                      ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputOVP = NO;
//              }
//                  break;
//              }
//          }
        }
    }
}

//=================================
// Callback Function
//=================================
// no using -- GetOutputAndTempCallback
void GetStatusCallback(byte group, byte address, byte temp, int alarm)
{
//  if (ShmPsuData->Work_Step == INITIAL_START)
//      return;
//
//  if (IsOverModuleCount(address))
//      return;
//
//  byte group1 = FindTargetGroup(address);
//
//  if (group1 == 1)
//      address -= ShmPsuData->PsuGroup[group1 - 1].GroupPresentPsuQuantity;
//
//  ShmPsuData->PsuGroup[group1].PsuModule[address].CriticalTemp1 = temp;
//  ShmPsuData->PsuGroup[group1].PsuModule[address].CriticalTemp2 = temp;
//  ShmPsuData->PsuGroup[group1].PsuModule[address].CriticalTemp3 = temp;
//  ShmPsuData->PsuGroup[group1].PsuModule[address].ExletTemp = temp;
//  ShmPsuData->PsuGroup[group1].PsuModule[address].AlarmCode = alarm;
//  AbnormalStopAnalysis(group1, alarm);

//  PRINTF_FUNC("***Status*** address = %d, temp = %d, err1 = %d, err2 = %d, err3 = %d, err4 = %d \n",
//          address, temp,
//          (alarm >> 24) & 0xFF,
//          (alarm >> 16) & 0xFF,
//          (alarm >> 8) & 0xFF,
//          alarm & 0xFF);
}
// no using -- GetOutputAndTempCallback End

void GetModuleCountCallback(byte group, byte count)
{
    if (group == SYSTEM_CMD)
        ShmPsuData->SystemPresentPsuQuantity = count;
    else
    {
        ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity = count;
    }
}

void GetMaxPowerAndCur(unsigned char mode, int ratingCur, int *pow, int *cur)
{
    if (ShmPsuData->Work_Step < GET_SYS_CAP)
        return;

    unsigned short maxCurrent = ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent * 10;
    unsigned short maxPower = ShmSysConfigAndInfo->SysConfig.MaxChargingPower * 10;

    if (mode == _MAIN_CHARGING_MODE_AVER)
    {
        maxCurrent /= 2;
        maxPower /= 2;
    }

    if (maxPower != 0 && maxPower <= *pow)
        *pow = maxPower;

    if (maxCurrent != 0 && maxCurrent <= *cur)
        *cur = maxCurrent;

    if (ratingCur != 0 && ratingCur <= *cur)
        *cur = ratingCur;
}

void GetAvailableCapCallback(byte address, short maxVol, short minVol, short maxCur, short totalPow)
{
    if (ShmPsuData->Work_Step < GET_SYS_CAP)
        return;

    int _groupPower = 0, _groupCurrent = 0;
    byte group = FindTargetGroup(address);

    if (group == 1)
        address -= ShmPsuData->PsuGroup[group - 1].GroupPresentPsuQuantity;

    if (chargingInfo[group]->DeratingChargingCurrent == 0)
        ShmPsuData->PsuGroup[group].PsuModule[address].AvailableCurrent = PSU_MIN_CUR;
    else
        ShmPsuData->PsuGroup[group].PsuModule[address].AvailableCurrent = maxCur;

    ShmPsuData->PsuGroup[group].PsuModule[address].AvailablePower = totalPow;
    // 總和該 Group 的可輸出電流
    for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++)
    {
        _groupCurrent += ShmPsuData->PsuGroup[group].PsuModule[index].AvailableCurrent;
        _groupPower += ShmPsuData->PsuGroup[group].PsuModule[index].AvailablePower;
    }

    // 各群得到最大輸出能力 (電流、Power)
    ShmPsuData->PsuGroup[group].GroupAvailableCurrent = _groupCurrent;
    ShmPsuData->PsuGroup[group].GroupAvailablePower = _groupPower;

    chargingInfo[group]->MaximumChargingVoltage = maxVol;

    int _power = 0, _current = 0, _ratingcurrent = 0;
    bool isGetAllDeratingCurrent = true;

    for (byte index = 0; index < ShmPsuData->GroupCount; index++)
    {
        _power += ShmPsuData->PsuGroup[index].GroupAvailablePower;
        _current += ShmPsuData->PsuGroup[index].GroupAvailableCurrent;
        _ratingcurrent += chargingInfo[index]->DeratingChargingCurrent;
        if (ShmPsuData->PsuGroup[index].GroupPresentOutputVoltage >= PSU_MIN_VOL &&
            chargingInfo[index]->DeratingChargingCurrent == 0)
            isGetAllDeratingCurrent = false;
    }

    // 如果不是所有群都得到 Derating current,則先不採樣該次的 ratingCurrent
    if (!isGetAllDeratingCurrent) _ratingcurrent = 0;

    ShmPsuData->SystemAvailableCurrent = _current;
    ShmPsuData->SystemAvailablePower = _power;

    if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER ||
        (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_GET_NEW_CAP &&
         ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A))
    {
        int halfPow = ShmPsuData->PsuGroup[group].GroupAvailablePower;
        int halfCur = ShmPsuData->PsuGroup[group].GroupAvailableCurrent;
        int ratingCur = chargingInfo[group]->DeratingChargingCurrent;

        if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_GET_NEW_CAP &&
            ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A)
        {
            if (chargingInfo[group]->DividChargingCurrent == 0)
                return;
            else
            {
                halfCur = chargingInfo[group]->DividChargingCurrent;
                ratingCur = 0;
            }
        }

        GetMaxPowerAndCur(_MAIN_CHARGING_MODE_AVER, ratingCur, &halfPow, &halfCur);

//      if ((ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_GET_NEW_CAP &&
//               ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A))
//      {
//          chargingInfo[group]->AvailableChargingCurrent = DERATING_RANGE;
//          chargingInfo[group]->AvailableChargingPower = ShmPsuData->PsuGroup[group].GroupAvailablePower;
//      }
//      else
        {
            // 以下狀況 -> 槍資訊中的最大輸出能力,為該群的輸出能力
            // 1. 如不是最大充
            // 2. 智能切換成均充過程
            chargingInfo[group]->AvailableChargingCurrent = halfCur;
            chargingInfo[group]->AvailableChargingPower = halfPow;

            if(chargingInfo[group]->DeratingChargingCurrent > 0)
            {
                chargingInfo[group]->RealRatingPower = (chargingInfo[group]->DeratingChargingCurrent * chargingInfo[group]->PresentChargingVoltage) / 100000;
            }
            //printf("(Aver.) RealRatingPower = %d \n", chargingInfo[group]->RealRatingPower);
        }
    }
    else if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX)
    {
        GetMaxPowerAndCur(_MAIN_CHARGING_MODE_MAX, _ratingcurrent, &_power, &_current);

        if (ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf == YES)
        {
            for (byte count = 0; count < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; count++)
            {
                chargingInfo[count]->MaximumChargingVoltage = maxVol;
                chargingInfo[count]->AvailableChargingCurrent = _current;
                chargingInfo[count]->AvailableChargingPower = _power;
            }
        }
        else
        {
            // 如果是最大充,該槍資訊中的輸出能力為各群輸出能力的和
            chargingInfo[group]->AvailableChargingCurrent = _current;
            chargingInfo[group]->AvailableChargingPower = _power;
        }

        if(_ratingcurrent > 0)
        {
            chargingInfo[group]->RealRatingPower = (_ratingcurrent * chargingInfo[group]->PresentChargingVoltage) / 100000;
        }
        //printf("(Max.) RealRatingPower = %d \n", chargingInfo[group]->RealRatingPower);
    }
}

void GetFwCallback(byte address, short dcSwVer, short pfcSwVer, short hwVer)
{
    if (ShmPsuData->Work_Step < GET_SYS_CAP)
        return;

    if (IsOverModuleCount(address))
        return;

    byte group = FindTargetGroup(address);

    sprintf((char *)ShmPsuData->PsuVersion[address].FwPrimaryVersion, "DC %d.%02d", (dcSwVer & 0xFF00) >> 8, dcSwVer & 0xFF);
    sprintf((char *)ShmPsuData->PsuVersion[address].FwSecondVersion, "PFC %d.%02d", (pfcSwVer & 0xFF00) >> 8, pfcSwVer & 0xFF);
    if (group == 1)
        address -= ShmPsuData->PsuGroup[group - 1].GroupPresentPsuQuantity;
    sprintf((char *)ShmPsuData->PsuGroup[group].PsuModule[address].FwVersion, "DC %d.%02d", (dcSwVer & 0xFF00) >> 8, dcSwVer & 0xFF);
    //DEBUG_INFO("fw Ver. = %s \n", ShmPsuData->PsuGroup[group].PsuModule[address].FwVersion);
}

// no using -- GetInputVoltageCallback
void GetInputVoltageCallback(byte address, unsigned short vol1, unsigned short vol2, unsigned short vol3)
{
//  if (ShmPsuData->Work_Step < GET_SYS_CAP)
//      return;
//
//  if (IsOverModuleCount(address))
//      return;
//
//  byte group = FindTargetGroup(address);
//
//  if (group == 1)
//      address -= ShmPsuData->PsuGroup[group - 1].GroupPresentPsuQuantity;
//
//  ShmPsuData->PsuGroup[group].PsuModule[address].InputVoltageL1 = vol1;
//  ShmPsuData->PsuGroup[group].PsuModule[address].InputVoltageL2 = vol2;
//  ShmPsuData->PsuGroup[group].PsuModule[address].InputVoltageL3 = vol3;
//
//  PRINTF_FUNC("***Input*** address = %d, R = %d, S = %d, T = %d, gp = %d \n",
//              address, vol1, vol2, vol3, group);
}
// no using -- GetInputVoltageCallback End

// no using -- GetOutputAndTempCallback
void GetPresentOutputCallback(byte group, unsigned short outVol, unsigned short outCur)
{
//  if (ShmPsuData->Work_Step < GET_SYS_CAP)
//      return;

    //if (outCur != ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent)
    //{
    //  PRINTF_FUNC("Gp_%d, gp output cur = %d \n", group, outCur);
    //}

//  // PSU Group - 電壓
//  ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage = outVol;
//  // PSU Group - 電流
//  ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent = outCur;
//
//  if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX ||
//          (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER &&
//          (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_WAITING &&
//          ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_COMP))
//      )
//  {
//      unsigned short outputVol = 0;
//      unsigned short outputCur = 0;
//
//      for (byte index = 0; index < ShmPsuData->GroupCount; index++)
//      {
//          bool needtoAdd = true;
//
//          if (ShmPsuData->PsuGroup[index].GroupPresentOutputVoltage > outputVol)
//              outputVol = ShmPsuData->PsuGroup[index].GroupPresentOutputVoltage;
//
//          if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_ADJUST_M_TO_A &&
//                  ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A)
//          {
////                PRINTF_FUNC("Gp_%d, DividChargingCurrent = %d \n", index,
////                        chargingInfo[index]->DividChargingCurrent);
//              if (chargingInfo[index]->DividChargingCurrent == 0)
//                  needtoAdd = false;
//          }
//
//          if (needtoAdd)
//              outputCur += ShmPsuData->PsuGroup[index].GroupPresentOutputCurrent;
//      }
//
//      // 黑白機
//      if (ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf == YES)
//      {
//          for (byte count = 0; count < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; count++)
//          {
//              float _vol_buf = outputVol;
//              float _cur_buf = outputCur;
//
//              // EVSE - 電壓
//              _vol_buf /= 10;
//              chargingInfo[count]->PresentChargingVoltage = _vol_buf;
//              // EVSE - 電流
//              _cur_buf /= 10;
//              chargingInfo[count]->PresentChargingCurrent = _cur_buf;
//          }
//      }
//
//      if ((chargingInfo[group]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[group]->SystemStatus <= S_COMPLETE) ||
//          (chargingInfo[group]->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingInfo[group]->SystemStatus <= S_CCS_PRECHARGE_ST1))
//      {
//          float _vol_buf = outputVol;
//          float _cur_buf = outputCur;
//
//          // EVSE - 電壓
//          _vol_buf /= 10;
//          chargingInfo[group]->PresentChargingVoltage = _vol_buf;
//          // EVSE - 電流
//          _cur_buf /= 10;
//          chargingInfo[group]->PresentChargingCurrent = _cur_buf;
//      }
//  }
//  else
//  {
//      float _vol_buf = ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage;
//      float _cur_buf = ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent;
//
//      // EVSE - 電壓
//      _vol_buf /= 10;
//      chargingInfo[group]->PresentChargingVoltage = _vol_buf;
//      // EVSE - 電流
//      _cur_buf /= 10;
//      chargingInfo[group]->PresentChargingCurrent = _cur_buf;
//  }
//
//  PRINTF_FUNC("Gun_%d, PresentChargingVoltage = %f, PresentChargingCurrent = %f \n", group,
//          chargingInfo[group]->PresentChargingVoltage,
//          chargingInfo[group]->PresentChargingCurrent);
}
// no using -- GetOutputAndTempCallback End

void GetFanSpeedCallback(byte address, unsigned int fanSpeed)
{
    if (ShmPsuData->Work_Step < GET_SYS_CAP)
        return;

    if (IsOverModuleCount(address))
        return;

    byte group = FindTargetGroup(address);

    if (group == 1)
        address -= ShmPsuData->PsuGroup[group - 1].GroupPresentPsuQuantity;

    ShmPsuData->PsuGroup[group].PsuModule[address].FanSpeed_1 = fanSpeed;
    ShmPsuData->PsuGroup[group].PsuModule[address].FanSpeed_2 = fanSpeed;
    ShmPsuData->PsuGroup[group].PsuModule[address].FanSpeed_3 = fanSpeed;
    ShmPsuData->PsuGroup[group].PsuModule[address].FanSpeed_4 = fanSpeed;
}

void GetIavailableCallback(byte address, unsigned short Iavail, unsigned short Vext)
{
    if (ShmPsuData->Work_Step < GET_SYS_CAP)
        return;

    if (IsOverModuleCount(address))
        return;

    //PRINTF_FUNC("address = %d, Iavail = %d \n", address, Iavail);
    byte group = FindTargetGroup(address);

    if (group == 1)
        address -= ShmPsuData->PsuGroup[group - 1].GroupPresentPsuQuantity;

    //PRINTF_FUNC("group = %d, address_%d, Iavail = %d \n", group, address, Iavail);
    ShmPsuData->PsuGroup[group].PsuModule[address].IAvailableCurrent = Iavail;

    bool isPass = true;
    int totalCur = 0;

    if (Iavail == 0)
    {
        for (byte count = 0; count < 2; count++)
        {
            chargingInfo[group]->SampleChargingCur[count] = Iavail;
        }
    }
    else
    {
        // 該群的可輸出電流
        for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++)
        {
            totalCur += ShmPsuData->PsuGroup[group].PsuModule[index].IAvailableCurrent;
        }

        for (byte count = 0; count < 2; count++)
        {
            if (chargingInfo[group]->SampleChargingCur[count] == 0)
            {
                chargingInfo[group]->SampleChargingCur[count] = totalCur;
                return;
            }
            else
            {
                if (chargingInfo[group]->SampleChargingCur[count] != totalCur)
                {
                    chargingInfo[group]->SampleChargingCur[count] = totalCur;
                    isPass = false;
                    break;
                }
            }
        }
    }

    if (isPass)
    {
        //PRINTF_FUNC("rating pass value = %d \n", totalCur);
        chargingInfo[group]->DeratingChargingCurrent = totalCur;
    }
}

//==========================================
// 特規用指令
//==========================================
void GetOutputAndTempCallback(byte address, unsigned short outputVol_s,
                              unsigned short outputCur_s, unsigned short outputPower,
                              unsigned char Temperature)
{
    if (ShmPsuData->Work_Step < GET_SYS_CAP)
        return;

    unsigned short outVol = outputVol_s;
    unsigned short outCur = outputCur_s;

    if (IsOverModuleCount(address))
        return;

    byte group = FindTargetGroup(address);

    if (group == 1)
        address -= ShmPsuData->PsuGroup[group - 1].GroupPresentPsuQuantity;

    // PSU Group - 電壓
    ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage = outVol;
    // PSU Group - 電流
    ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent = outCur;

    if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX ||
        (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER &&
         (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_WAITING &&
          ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_COMP)))
    {
        unsigned short outputVol = 0;
        unsigned short outputCur = 0;

        for (byte index = 0; index < ShmPsuData->GroupCount; index++)
        {
            bool needtoAdd = true;

            if (ShmPsuData->PsuGroup[index].GroupPresentOutputVoltage > outputVol)
                outputVol = ShmPsuData->PsuGroup[index].GroupPresentOutputVoltage;

            if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_ADJUST_M_TO_A &&
                ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A)
            {
                if (chargingInfo[index]->DividChargingCurrent == 0)
                    needtoAdd = false;
            }

            if (needtoAdd)
                outputCur += ShmPsuData->PsuGroup[index].GroupPresentOutputCurrent;
        }

        // 黑白機
        if (ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf == YES)
        {
            for (byte count = 0; count < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; count++)
            {
                float _vol_buf = outputVol;
                float _cur_buf = outputCur;

                // EVSE - 電壓
                _vol_buf /= 10;
                chargingInfo[count]->PresentChargingVoltage = _vol_buf;
                // EVSE - 電流
                _cur_buf /= 10;
                chargingInfo[count]->PresentChargingCurrent = _cur_buf;
            }
        }

        if ((chargingInfo[group]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[group]->SystemStatus <= S_COMPLETE) ||
            (chargingInfo[group]->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingInfo[group]->SystemStatus <= S_CCS_PRECHARGE_ST1))
        {
            float _vol_buf = outputVol;
            float _cur_buf = outputCur;

            // EVSE - 電壓
            _vol_buf /= 10;
            chargingInfo[group]->PresentChargingVoltage = _vol_buf;
            // EVSE - 電流
            _cur_buf /= 10;
            chargingInfo[group]->PresentChargingCurrent = _cur_buf;
        }
    }
    else
    {
        float _vol_buf = ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage;
        float _cur_buf = ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent;

        // EVSE - 電壓
        _vol_buf /= 10;
        chargingInfo[group]->PresentChargingVoltage = _vol_buf;
        // EVSE - 電流
        _cur_buf /= 10;
        chargingInfo[group]->PresentChargingCurrent = _cur_buf;
    }

    ShmPsuData->PsuGroup[group].PsuModule[address].CriticalTemp1 = Temperature;
    ShmPsuData->PsuGroup[group].PsuModule[address].CriticalTemp2 = Temperature;
    ShmPsuData->PsuGroup[group].PsuModule[address].CriticalTemp3 = Temperature;
    ShmPsuData->PsuGroup[group].PsuModule[address].ExletTemp = Temperature;

//  PRINTF_FUNC("***Output Value and Temp*** group = %d, Vol = %d, Cur = %d \n",
//          group, outputVol_s, outputCur_s);
}

void GetModuleStatusCallback(byte address, unsigned char isErr, unsigned char status,
                             unsigned char err1, unsigned char err2, unsigned char err3,
                             unsigned char err4)
{
    if (ShmPsuData->Work_Step < GET_SYS_CAP)
        return;

    if (IsOverModuleCount(address))
        return;

    byte group1 = FindTargetGroup(address);

    if (group1 == 1)
        address -= ShmPsuData->PsuGroup[group1 - 1].GroupPresentPsuQuantity;

    int alarm = (err2 << 24) | (err3 << 16) | (err4 << 8);

//  ShmPsuData->PsuGroup[group1].PsuModule[address].CriticalTemp1 = temp;
//  ShmPsuData->PsuGroup[group1].PsuModule[address].CriticalTemp2 = temp;
//  ShmPsuData->PsuGroup[group1].PsuModule[address].CriticalTemp3 = temp;
//  ShmPsuData->PsuGroup[group1].PsuModule[address].ExletTemp = temp;
    ShmPsuData->PsuGroup[group1].PsuModule[address].AlarmCode = alarm;
    AbnormalStopAnalysis(group1, alarm);

    // err2 == state 2
    // err3 == state 1
    // err4 == state 0
    //PRINTF_FUNC("***Status*** address = %d, alarm = %d \n", address, alarm);
}

void GetModuleInputCallback(byte address, unsigned short inputR,
                            unsigned short inputS, unsigned short inputT)
{
    if (ShmPsuData->Work_Step < GET_SYS_CAP)
        return;

    if (IsOverModuleCount(address))
        return;

    byte group = FindTargetGroup(address);

    if (group == 1)
        address -= ShmPsuData->PsuGroup[group - 1].GroupPresentPsuQuantity;

    ShmPsuData->PsuGroup[group].PsuModule[address].InputVoltageL1 = inputR;
    ShmPsuData->PsuGroup[group].PsuModule[address].InputVoltageL2 = inputS;
    ShmPsuData->PsuGroup[group].PsuModule[address].InputVoltageL3 = inputT;

//    PRINTF_FUNC("***Input*** address = %d, R = %d, S = %d, T = %d \n",
//            address, inputR, inputS, 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
        DEBUG_ERROR("shmget ShmSysConfigAndInfo NG %d \n");
        #endif
        result = FAIL;
    }
    else if ((ShmSysConfigAndInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("shmat ShmSysConfigAndInfo NG \n");
        #endif
        result = FAIL;
     }
    else
    {}

    //creat ShmStatusCodeData
    if ((MeterSMId = shmget(ShmStatusCodeKey, sizeof(struct StatusCodeData),  0777)) < 0)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("shmget ShmStatusCodeData NG \n");
        #endif
        result = FAIL;
    }
    else if ((ShmStatusCodeData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("shmat ShmStatusCodeData NG \n");
        #endif
        result = FAIL;
    }
    else
    {}

    //creat ShmPsuData
    if ((MeterSMId = shmget(ShmPsuKey, sizeof(struct PsuData),  0777)) < 0)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("shmget ShmPsuData NG \n");
        #endif
        result = FAIL;
    }
    else if ((ShmPsuData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("shmat ShmPsuData NG \n");
        #endif
        result = FAIL;
     }
    memset(ShmPsuData,0,sizeof(struct PsuData));

    return result;
}

//================================================
// Main process
//================================================
void InitialPsuData()
{
    ShmPsuData->SystemPresentPsuQuantity = 0;
    ShmPsuData->SystemAvailablePower = 0;

    PRINTF_FUNC("************ psu Group = %d \n", 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;
    }
}

void Initialization()
{
    bool isPass = false;
    while(!isPass)
    {
        isPass = true;
        for (byte _index = 0; _index < _gunCount; _index++)
        {
            if (!FindChargingInfoData(_index, &chargingInfo[0]))
            {
                DEBUG_ERROR("Module_PsuComm : FindChargingInfoData false \n");
                isPass = false;
                break;
            }
        }
    }

    if (ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf == YES)
        ShmPsuData->GroupCount = 1;
    else
        ShmPsuData->GroupCount = _gunCount;

    char EvsePower[2];

    EvsePower[2] = '\0';
    char count = 0;
    byte psuTarIndex = 0;
    // 解析 ModelName 取得各槍各有幾個 PSU 及編號
    if (strlen((char *) ShmSysConfigAndInfo->SysConfig.ModelName) >= 6)
    {
        strncpy(EvsePower, (char *)(ShmSysConfigAndInfo->SysConfig.ModelName + 4), 2);
        if (strcmp(EvsePower, "15") == EQUAL)
            count = 5;
        else if (strcmp(EvsePower, "30") == EQUAL)
            count = 1;
        else if (strcmp(EvsePower, "60") == EQUAL)
            count = 2;
        else if (strcmp(EvsePower, "18") == EQUAL)
            count = 6;
        else if (strcmp(EvsePower, "36") == EQUAL)
            count = 12;

        if (count > 0)
        {
            if (ShmPsuData->GroupCount == 1)
                conn_1_count = count;
            else if (ShmPsuData->GroupCount == 2)
            {
                if(count % 2 > 0)
                    conn_1_count = (count / 2) + 1;
                else
                    conn_1_count = (count / 2);

                conn_2_count = count - conn_1_count;
            }

            for(byte psuIndex = 0; psuIndex < conn_1_count; psuIndex++)
            {
                connector_1[psuIndex] = psuTarIndex;
                psuTarIndex++;
            }

            for(byte psuIndex = 0; psuIndex < conn_2_count; psuIndex++)
            {
                connector_2[psuIndex] = psuTarIndex;
                psuTarIndex++;
            }

            for(byte psuIndex = 0; psuIndex < conn_1_count; psuIndex++)
                PRINTF_FUNC("Connector 1 - Number = %d \n", connector_1[psuIndex]);

            for(byte psuIndex = 0; psuIndex < conn_2_count; psuIndex++)
                PRINTF_FUNC("Connector 2 - Number = %d \n", connector_2[psuIndex]);
        }
        else
            DEBUG_ERROR("Module_PsuComm : Can't parsing model name. \n");
    }
}

void CheckSmartChargingStep(bool isWaitingAver, bool isCharging, bool canAverageCharging)
{
    if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_PREPARE_M_TO_A)
    {
        if (isWaitingAver)
        {
            if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX)
            {
                ShmSysConfigAndInfo->SysInfo.CanAverageCharging = canAverageCharging;

                if (canAverageCharging)
                {
                    PRINTF_FUNC("=============Smart Charging : _REASSIGNED_GET_NEW_CAP============= Step 2 \n");
                    ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_GET_NEW_CAP;
                }
                else
                {
                    PRINTF_FUNC("=============Smart Charging : _REASSIGNED_NONE============= Step 0 \n");
                    ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_NONE;
                }
            }
            else
            {
                PRINTF_FUNC("=============Smart Charging : _REASSIGNED_NONE============= Step 0 \n");
                ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_NONE;
            }
        }
    }
    else  if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag ==  _REASSIGNED_PREPARE_A_TO_M)
    {
        if (isCharging)
        {
            if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER)
            {
                PRINTF_FUNC("=============Smart Charging : _REASSIGNED_ADJUST_A_TO_M============= Step 12 \n");
                preChargingCur = preChargingTarget = 0;
                gettimeofday(&_max_time, NULL);
                ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_ADJUST_A_TO_M;
            }
            else
            {
                PRINTF_FUNC("=============Smart Charging_1  : _REASSIGNED_COMP============= Step 15 \n");
                ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_COMP;
            }
        }
        else
        {
            PRINTF_FUNC("=============Smart Charging_2 : _REASSIGNED_COMP============= Step 15 \n");
            ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_COMP;
        }
    }
}

int main(void)
{
    if(InitShareMemory() == FAIL)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("InitShareMemory NG\n");
        #endif
        if(ShmStatusCodeData != NULL)
        {
            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.FailToCreateShareMemory = 1;
        }
        sleep(5);
        return 0;
    }

    PRINTF_FUNC("InitShareMemory OK\n");

    // register callback function
    RefreshStatus(&GetStatusCallback);
    RefreshModuleCount(&GetModuleCountCallback);
    RefreshAvailableCap(&GetAvailableCapCallback);
    RefreshFwVersion(&GetFwCallback);
    RefreshInputVol(&GetInputVoltageCallback);
    RefreshGetOutput(&GetPresentOutputCallback);
    RefreshFanInfo(&GetFanSpeedCallback);
    RefreshIavailable(&GetIavailableCallback);

    // GetPresentOutputCallback & GetStatusCallback
    AutoMode_RefreshOutputAndTemp(&GetOutputAndTempCallback);
    // GetStatusCallback
    AutoMode_RefreshModuleStatus(&GetModuleStatusCallback);
    // GetInputVoltageCallback
    AutoMode_RefreshModuleInput(&GetModuleInputCallback);

    sleep(2);
    _gunCount = ShmSysConfigAndInfo->SysConfig.TotalConnectorCount;
    // initial object
    InitialPsuData();
    Initialization();
    libInitialize = InitialCommunication();
    byte isInitialComp = NO;
    PRINTF_FUNC("ALTERNATIVE_CONG = %d \n", ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf);
    //main loop
    while (libInitialize)
    {
        // 斷電狀態
        if (ShmSysConfigAndInfo->SysInfo.AcContactorStatus == NO)
        {
            //一但 AC Off PSU 斷電全部的 PSU Group ID 會全部清 0
            if (!isInitialComp)
            {
                ShmPsuData->Work_Step = INITIAL_START;
                InitialPsuData();
                isInitialComp = YES;
            }
            sleep(1);
            continue;
        }
        else
            isInitialComp = NO;

        // 自檢失敗
        if (ShmPsuData->Work_Step == _NO_WORKING)
        {
            PRINTF_FUNC("== PSU == self test fail. \n");
            sleep(5);
        }

        switch(ShmPsuData->Work_Step)
        {
            case INITIAL_START:
            {
                PRINTF_FUNC("== PSU == INITIAL_START \n");
                gettimeofday(&_cmdSubPriority_time, NULL);
                sleep(5);
                SwitchPower(SYSTEM_CMD, PSU_POWER_OFF);
                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:
            {
                int time = GetTimeoutValue(_cmdSubPriority_time) / 1000;
                byte moduleCount = 0;

                if (time > 2000)
                {
                    PRINTF_FUNC("== PSU == indexCount = %d, moduleCount = %d, sysCount = %d\n",
                                ShmPsuData->GroupCount, moduleCount, ShmPsuData->SystemPresentPsuQuantity);
//                  if (ShmPsuData->GroupCount == 0)
//                      ShmPsuData->GroupCount = ShmSysConfigAndInfo->SysConfig.TotalConnectorCount;
                    // 分別取各群模組數量
                    for (byte index = 0; index < ShmPsuData->GroupCount; index++)
                    {
                        // 總和各群模組數量
                        moduleCount += ShmPsuData->PsuGroup[index].GroupPresentPsuQuantity;

                        // 取各群模組數量
                        GetModuleCount(index);
                    }

                    // 發送取得目前全部模組數量
                    GetModuleCount(SYSTEM_CMD);

                    // 判斷系統數量與各群數量一致
                    if(moduleCount == ShmPsuData->SystemPresentPsuQuantity && moduleCount > 0)
                    {
                        PRINTF_FUNC("Psu Count = %d \n", moduleCount);
                        if (ShmSysConfigAndInfo->SysInfo.BootingStatus == BOOTTING)
                        {
                            // 電樁在 Booting 的狀態 - 自檢
                            PRINTF_FUNC("== PSU == GET_SYS_CAP \n");
                            ShmPsuData->Work_Step = GET_SYS_CAP;
                        }
                        else
                        {
                            PRINTF_FUNC("== PSU == _WORK_CHARGING \n");
                            ShmPsuData->Work_Step = _WORK_CHARGING;

                            //sdlu test
                            gettimeofday(&_test_time, NULL);
                        }
                    }

                    _getCapDelayCount = 7;
                    gettimeofday(&_cmdSubPriority_time, NULL);
                }
            }
                break;
            case GET_SYS_CAP:
            {
                int time = GetTimeoutValue(_cmdSubPriority_time) / 1000;

                if (time > 1000)
                {
                    for (byte index = 0; index < ShmPsuData->GroupCount; index++)
                    {
                        // Pooling Status
                        //GetStatus(index);

                        // 取系統總輸出能力
                        GetModuleCap(index);

                        // 取版號
                        GetModuleVer(index);
                    }
                    _getCapDelayCount--;
                    gettimeofday(&_cmdSubPriority_time, NULL);
                }

                // 判斷系統輸出額定功率與電流
                if (ShmPsuData->SystemAvailablePower > 0 && ShmPsuData->SystemAvailableCurrent > 0 &&
                    _getCapDelayCount <= 0)
                {
                    PRINTF_FUNC("SystemAvailableCurrent = %d, SystemAvailablePower = %d \n",
                                ShmPsuData->SystemAvailableCurrent, ShmPsuData->SystemAvailablePower);

                    PRINTF_FUNC("== PSU == BOOTING_COMPLETE \n");
                    ShmPsuData->Work_Step = BOOTING_COMPLETE;
                }
            }
                break;
            case BOOTING_COMPLETE:
            {
                bool isSelfTestPass = true;
                for (byte groupIndex = 0; groupIndex < _gunCount; groupIndex++)
                {
                    if (chargingInfo[groupIndex]->SystemStatus == S_BOOTING)
                    {
                        isSelfTestPass = false;
                    }
                }

                if (isSelfTestPass)
                    ShmPsuData->Work_Step = _WORK_CHARGING;
                sleep(1);
            }
                break;
            case _WORK_CHARGING:
            {
                int time = GetTimeoutValue(_cmdSubPriority_time) / 1000;

                // 低 Priority 的指令
                if (time > 1500)
                {
                    isCharging = false;
                    isWaitingAver = false;
                    isReadToCharging = false;
                    CanAverageCharging = true;

                    for (byte index = 0; index < ShmPsuData->GroupCount; index++)
                    {
                        // Pooling Status
                        //GetStatus(index);

                        // 取得模塊輸出額定電流能力
                        GetModuleIavailable(index);

                        if (chargingInfo[index]->SystemStatus == S_CHARGING)
                        {
                            isCharging = true;
                            if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_PREPARE_M_TO_A)
                            {
                                if (toAverVolPoint > 0 &&
                                    toAverVolPoint == (chargingInfo[index]->EvBatterytargetCurrent * 10))
                                {
                                    // 欲最大充 -> 均充需要等待充電中的輸出電流拉高到目標電流
                                    if ((chargingInfo[index]->PresentChargingCurrent * 10) >=
                                        (chargingInfo[index]->EvBatterytargetCurrent * 10) - CHK_CUR_RANGE)
                                    {
                                        if (toAverVolCount == 0)
                                            isWaitingAver = true;
                                        else
                                            toAverVolCount--;
                                    }
                                }
                                else
                                {
                                    toAverVolPoint = (chargingInfo[index]->EvBatterytargetCurrent * 10);
                                    toAverVolCount = 3;
                                }
                            }
                            else
                            {
                                toAverVolPoint = 0;
                                toAverVolCount = 3;
                            }
                        }

                        if ((chargingInfo[index]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[index]->SystemStatus <= S_CHARGING) ||
                            (chargingInfo[index]->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingInfo[index]->SystemStatus <= S_CCS_PRECHARGE_ST1))
                        {
                            isReadToCharging = true;
                        }

                        if (chargingInfo[index]->DeratingChargingCurrent < STOP_CURRENT)
                        {
                            CanAverageCharging = false;
                        }
                    }

                    gettimeofday(&_cmdSubPriority_time, NULL);
                    CheckSmartChargingStep(isWaitingAver, isCharging, CanAverageCharging);
                }

                for (byte groupIndex = 0; groupIndex < _gunCount; groupIndex++)
                {
                    // 取系統總輸出能力
                    GetModuleCap(groupIndex);

                    // 針對各槍當前狀態,傳送需要回傳的資料指令
                    if (((chargingInfo[groupIndex]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[groupIndex]->SystemStatus <= S_CHARGING) && chargingInfo[groupIndex]->RelayK1K2Status) ||
                        (chargingInfo[groupIndex]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[groupIndex]->SystemStatus <= S_CHARGING && chargingInfo[groupIndex]->Type == _Type_GB) ||
                        (chargingInfo[groupIndex]->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingInfo[groupIndex]->SystemStatus <= S_CCS_PRECHARGE_ST1))
                    {
                        if (time > 1500)
                        {
                            if (chargingInfo[groupIndex]->FireChargingVoltage > 0 &&
                                evseOutVol != (chargingInfo[groupIndex]->FireChargingVoltage / 10))
                            {
                                evseOutVol = (chargingInfo[groupIndex]->FireChargingVoltage / 10);
                                PRINTF_FUNC("groupIndex = %d, ev need vol = %f, evse output vol = %f \n", groupIndex,
                                            (chargingInfo[groupIndex]->EvBatterytargetVoltage * 10),
                                            chargingInfo[groupIndex]->FireChargingVoltage);
                            }

                            if ((chargingInfo[groupIndex]->PresentChargingCurrent * 10) > 0 &&
                                evseOutCur != (chargingInfo[groupIndex]->PresentChargingCurrent * 10))
                            {
                                evseOutCur = (chargingInfo[groupIndex]->PresentChargingCurrent * 10);
                                PRINTF_FUNC("groupIndex = %d, evse output cur = %f \n", groupIndex,
                                            (chargingInfo[groupIndex]->EvBatterytargetCurrent * 10),
                                            (chargingInfo[groupIndex]->PresentChargingCurrent * 10));
                            }
                        }

                        if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX)
                        {
//                          PRINTF_FUNC("index = %d, SystemStatus = %d, Ev = %f, curCur = %f \n", groupIndex,
//                                  chargingInfo[groupIndex]->SystemStatus, chargingInfo[groupIndex]->EvBatterytargetCurrent,
//                                  (chargingInfo[groupIndex]->PresentChargingCurrent * 10));
                            // 智能判斷 Start -----------------------------------------------------------
                            if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_GET_NEW_CAP &&
                                ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A)
                            {
                                if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_GET_NEW_CAP)
                                {
                                    //PRINTF_FUNC("group = %d, GroupPresentOutputCurrent = %d \n",
                                    //      groupIndex, ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent);

                                    if (chargingInfo[groupIndex]->DividChargingCurrent == 0)
                                    {
                                        chargingInfo[groupIndex]->DividChargingCurrent = ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent;
                                    }
                                }
                                PRINTF_FUNC("Index = %d, DividChargingCurrent = %f \n", groupIndex, chargingInfo[groupIndex]->DividChargingCurrent);
                            }
                            else
                            {
                                chargingInfo[groupIndex]->DividChargingCurrent = 0;
                            }

                            if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_GET_NEW_CAP)
                            {
                                if (ShmPsuData->SystemAvailableCurrent != chargingInfo[groupIndex]->AvailableChargingCurrent)
                                {
                                    // 車端要求電流為該充電槍的額定輸出電流的範圍內
                                    if ((chargingInfo[groupIndex]->EvBatterytargetCurrent * 10) <= ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent + DERATING_GAP ||
                                        deratingKeepCount >= DERATING_COUNT)
                                    {
                                        // 車端降載完成
                                        PRINTF_FUNC("Index = %d, newEvCurrent = %f \n", groupIndex, (chargingInfo[groupIndex]->EvBatterytargetCurrent * 10));
                                        PRINTF_FUNC("=============Smart Charging : _REASSIGNED_ADJUST_M_TO_A============= Step 3 \n");
                                        ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_ADJUST_M_TO_A;
                                        gettimeofday(&_derating_time, NULL);
                                        deratingKeepCount = 0;
                                    }
                                    else
                                    {
                                        deratingKeepCount++;
                                        PRINTF_FUNC("** Step 2 ** : Index = %d, EvBatterytargetCurrent = %f, TargetCurrent = %d, Count = %d \n",
                                                    groupIndex,
                                                    (chargingInfo[groupIndex]->EvBatterytargetCurrent * 10),
                                                    (ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent + DERATING_GAP),
                                                    deratingKeepCount);
                                    }
                                }

                            }
                            else if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_ADJUST_M_TO_A)
                            {
                                bool isChanged = false;

                                if (chargingInfo[groupIndex]->AvailableChargingCurrent <= (chargingInfo[groupIndex]->EvBatterytargetCurrent * 10))
                                {
                                    PRINTF_FUNC("** _REASSIGNED_ADJUST_M_TO_A ** Gun_%d, PresentChargingCurrent = %f, AvailableChargingCurrent = %f, EvBatterytargetCurrent = %f \n", groupIndex,
                                                (chargingInfo[groupIndex]->PresentChargingCurrent * 10),
                                                chargingInfo[groupIndex]->AvailableChargingCurrent,
                                                (chargingInfo[groupIndex]->EvBatterytargetCurrent * 10));

                                    for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++)
                                    {
                                        if (chargingInfo[subIndex]->SystemStatus == S_REASSIGN)
                                        {
                                            // 當 B 模塊輸出電流小於 5A 及退開 relay
                                            if ((ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent) <= 50)
                                                isChanged = true;
                                            break;
                                        }
                                    }
                                }
                                else if (((chargingInfo[groupIndex]->PresentChargingCurrent * 10) >= ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent - CHK_CUR_RANGE) &&
                                         ((chargingInfo[groupIndex]->PresentChargingCurrent * 10) <= ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent + CHK_CUR_RANGE))
                                {
                                    for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++)
                                    {
                                        if (chargingInfo[subIndex]->SystemStatus == S_REASSIGN)
                                        {
                                            if ((ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent) <= CHK_CUR_RANGE)
                                                isChanged = true;
                                            break;
                                        }
                                    }
                                }

                                if (isChanged)
                                {
                                    PRINTF_FUNC("** _REASSIGNED_ADJUST_M_TO_A To 4** Gun_%d, PresentChargingCurrent = %f, GroupPresentOutputCurrent = %d \n", groupIndex,
                                                (chargingInfo[groupIndex]->PresentChargingCurrent * 10),
                                                ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent);

                                    // 輸出端與車端要求電流接近
                                    PRINTF_FUNC("=============Smart Charging : _REASSIGNED_RELAY_M_TO_A============= Step 4 \n");
                                    ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_RELAY_M_TO_A;
                                }
                                else
                                {
                                    if ((GetTimeoutValue(_derating_time) / 1000) > 1000)
                                    {
                                        gettimeofday(&_derating_time, NULL);
                                    }
                                }
                            }

                            //if (ShmPsuData->SystemAvailablePower > 0)
                            {
                                // 調整輸出電流 : 漸進調整方式
                                if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_GET_NEW_CAP &&
                                    ShmSysConfigAndInfo->SysInfo.ReAssignedFlag < _REASSIGNED_RELAY_M_TO_A)
                                {
                                    if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_ADJUST_M_TO_A)
                                    {
                                        // 當前充電中的目標電壓
                                        float targetVol = (chargingInfo[groupIndex]->EvBatterytargetVoltage * 10);
                                        byte reassignIndex = ELEMENT_NOT_FIND;

                                        // 找到等待分配的槍
                                        for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++)
                                        {
                                            if (chargingInfo[subIndex]->SystemStatus == S_REASSIGN)
                                            {
                                                reassignIndex = subIndex;
                                                break;
                                            }
                                        }

                                        if (reassignIndex != ELEMENT_NOT_FIND)
                                        {
                                            if ((GetTimeoutValue(_derating_time) / 1000) <= 50)
                                            {
                                                // A 模塊維持當前電壓電流
                                                //PRINTF_FUNC("A : index = %d, cur = %d \n", groupIndex, ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent);
                                                //PresentOutputVol(groupIndex, targetVol, ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent);
                                                //PRINTF_FUNC("set out (%d) value = %f******** 1 \n", groupIndex, chargingInfo[groupIndex]->EvBatterytargetCurrent);
                                                PresentOutputVol(groupIndex, targetVol, (chargingInfo[groupIndex]->EvBatterytargetCurrent * 10));
//                                          }
//
//                                          if ((GetTimeoutValue(_derating_time) / 1000) <= 50)
//                                          {
                                                // 直接拉掉 B 模塊的電流
                                                //PRINTF_FUNC("B : index = %d, cur = %d \n", reassignIndex, CHK_CUR_RANGE);
                                                //PRINTF_FUNC("set out (%d) value = %d******** 2 \n", reassignIndex, CHK_CUR_RANGE);
                                                PresentOutputVol(reassignIndex, targetVol, CHK_CUR_RANGE);
                                            }
                                        }
                                    }

                                    if ((chargingInfo[groupIndex]->EvBatterytargetVoltage * 10) == 0)
                                    {
                                        //PRINTF_FUNC("sys ******** 1 \n");
                                        bool isNeedToClosePower = false;
                                        for (byte index = 0; index < ShmPsuData->GroupCount; index++)
                                        {
                                            if (isStartOutputSwitch[index])
                                            {
                                                isNeedToClosePower = true;
                                            }
                                            isStartOutputSwitch[index] = false;
                                        }

                                        if (isNeedToClosePower)
                                        {
                                            SwitchPower(SYSTEM_CMD, PSU_POWER_OFF);
                                            FlashLed(SYSTEM_CMD, PSU_FLASH_NORMAL);
                                        }
                                    }
                                }
                                else if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_RELAY_M_TO_A)
                                {
                                    //PRINTF_FUNC("set out (%d) value = %f******** 3 \n", groupIndex, chargingInfo[groupIndex]->EvBatterytargetCurrent);
                                    PresentOutputVol(groupIndex,
                                                     (chargingInfo[groupIndex]->EvBatterytargetVoltage * 10),
                                                     (chargingInfo[groupIndex]->EvBatterytargetCurrent * 10));
                                }
                                else
                                {
                                    PRINTF_FUNC("set out (sys) value = %f, smart step = %d******** 4 \n",
                                                chargingInfo[groupIndex]->EvBatterytargetCurrent, ShmSysConfigAndInfo->SysInfo.ReAssignedFlag);
                                    // 該充電槍的目標電壓與目標電流
                                    PresentOutputVol(SYSTEM_CMD,
                                                     (chargingInfo[groupIndex]->EvBatterytargetVoltage * 10),
                                                     (chargingInfo[groupIndex]->EvBatterytargetCurrent * 10));

                                    if ((chargingInfo[groupIndex]->EvBatterytargetVoltage * 10) == 0)
                                    {
                                        //PRINTF_FUNC("sys ******** 2 \n");
                                        bool isNeedToClosePower = false;
                                        for (byte index = 0; index < ShmPsuData->GroupCount; index++)
                                        {
                                            if (isStartOutputSwitch[index])
                                            {
                                                isNeedToClosePower = true;
                                            }
                                            isStartOutputSwitch[index] = false;
                                        }

                                        if (isNeedToClosePower)
                                        {
                                            SwitchPower(SYSTEM_CMD, PSU_POWER_OFF);
                                            FlashLed(SYSTEM_CMD, PSU_FLASH_NORMAL);
                                        }
                                    }
                                    else
                                    {
                                        bool isNeedToOpenPower = false;
                                        for (byte index = 0; index < ShmPsuData->GroupCount; index++)
                                        {
                                            if (!isStartOutputSwitch[index])
                                            {
                                                isNeedToOpenPower = true;
                                            }
                                            isStartOutputSwitch[index] = true;
                                        }

                                        if (isNeedToOpenPower)
                                        {
                                            SwitchPower(SYSTEM_CMD, PSU_POWER_ON);
                                            FlashLed(SYSTEM_CMD, PSU_FLASH_ON);
                                        }
                                    }
                                }
                            }
                        }
                        else if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER)
                        {
                            // 智能判斷 Start -----------------------------------------------------------
                            if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_ADJUST_A_TO_M)
                            {
                                bool balanceVol = true;

                                for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++)
                                {
                                    if (chargingInfo[subIndex]->SystemStatus == S_IDLE ||
                                        chargingInfo[subIndex]->SystemStatus == S_RESERVATION)
                                    {
                                        // 各群電壓接近平衡
                                        if (((chargingInfo[subIndex]->PresentChargingVoltage * 10) < (chargingInfo[groupIndex]->PresentChargingVoltage * 10) - ZERO_VOLTAGE) ||
                                            ((chargingInfo[subIndex]->PresentChargingVoltage * 10) < (chargingInfo[groupIndex]->EvBatterytargetVoltage * 10) - CHK_VOL_RANGE))
                                        {
                                            PRINTF_FUNC("** _REASSIGNED_ADJUST_A_TO_M ** Gun_%d, PresentChargingVoltage = %f, PresentChargingVoltage_V = %f, EvBatterytargetVoltage = %f \n", subIndex,
                                                        (chargingInfo[subIndex]->PresentChargingVoltage * 10),
                                                        ((chargingInfo[groupIndex]->PresentChargingVoltage * 10) - ZERO_VOLTAGE),
                                                        ((chargingInfo[groupIndex]->EvBatterytargetVoltage * 10) - CHK_VOL_RANGE));
                                            balanceVol = false;
                                        }
                                        break;
                                    }
                                }

                                if (balanceVol)
                                {
                                    // 閒置端與車端要求電壓接近
                                    PRINTF_FUNC("=============Smart Charging : _REASSIGNED_RELAY_A_TO_M============= Step 13 \n");
                                    ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_RELAY_A_TO_M;
                                }
                                else
                                {
                                    if ((GetTimeoutValue(_max_time) / 1000) > 500)
                                    {
                                        gettimeofday(&_max_time, NULL);
                                    }
                                }
                            }
                            else if(ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_WAITING)
                            {
                                int idleCurrent = 0;
                                int chargingCurrent = 0;

                                for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++)
                                {
                                    if (chargingInfo[subIndex]->SystemStatus == S_IDLE ||
                                        chargingInfo[subIndex]->SystemStatus == S_RESERVATION ||
                                        chargingInfo[subIndex]->SystemStatus == S_REASSIGN_CHECK)
                                        idleCurrent = ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent;
                                    else
                                        chargingCurrent = ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent;
                                }

                                if (idleCurrent >= chargingCurrent - PRE_CHARG_RANGE)
                                {
                                    PRINTF_FUNC("=============Smart Charging_0 : _REASSIGNED_COMP============= Step 15 \n");
                                    ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_COMP;
                                }
                                else
                                {
                                    if ((GetTimeoutValue(_max_time) / 1000) > 500)
                                    {
                                        gettimeofday(&_max_time, NULL);
                                    }
                                }
                            }

                            if (chargingInfo[groupIndex]->AvailableChargingCurrent > 0)
                            {
                                if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_ADJUST_A_TO_M)
                                {
                                    byte reassignIndex = ELEMENT_NOT_FIND;

                                    for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++)
                                    {
                                        if (chargingInfo[subIndex]->SystemStatus == S_IDLE ||
                                            chargingInfo[subIndex]->SystemStatus == S_RESERVATION ||
                                            chargingInfo[subIndex]->SystemStatus == S_REASSIGN_CHECK)
                                        {
                                            reassignIndex = subIndex;
//                                          if ((GetTimeoutValue(_max_time) / 1000) <= 50)
//                                          {
//                                              // 閒置模塊升壓,另對剛分配近來的模塊,預上升電流值 (preChargingCur)
//                                              PresentOutputVol(subIndex,
//                                                      chargingInfo[groupIndex]->EvBatterytargetVoltage,
//                                                      ZERO_CURRENT + preChargingTarget);
//                                          }
                                            //PRINTF_FUNC("preChargingCur = %d \n", preChargingCur);
                                            if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_WAITING)
                                            {
                                                preChargingCur = ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent;
                                            }
                                            else
                                                preChargingCur = 0;
                                        }
                                        else
                                        {
                                            //PRINTF_FUNC("CurOutputCurrent = %d \n", ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent - preChargingCur);
                                            // 充電中的模塊維持輸出
//                                          if ((GetTimeoutValue(_max_time) / 1000) <= 50)
//                                          {
//                                              PresentOutputVol(subIndex,
//                                                  chargingInfo[subIndex]->EvBatterytargetVoltage,
//                                                  chargingInfo[subIndex]->EvBatterytargetCurrent - preChargingCur);
//                                          }

                                            if ((ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_WAITING) &&
                                                (preChargingCur >= preChargingTarget - ZERO_CURRENT))
                                                preChargingTarget += PRE_CHARG_STEP_CUR;

                                            if (preChargingTarget >= (chargingInfo[subIndex]->EvBatterytargetCurrent * 10) / 2)
                                                preChargingTarget = (chargingInfo[subIndex]->EvBatterytargetCurrent * 10) / 2;
                                        }
                                    }

                                    if (reassignIndex != ELEMENT_NOT_FIND)
                                    {
                                        if ((GetTimeoutValue(_max_time) / 1000) <= 50)
                                        {
                                            //PRINTF_FUNC("set out (%d) value = %d******** 5 \n", reassignIndex, ZERO_CURRENT + preChargingTarget);
                                            // 閒置模塊升壓,另對剛分配近來的模塊,預上升電流值 (preChargingCur)
                                            PresentOutputVol(reassignIndex,
                                                             (chargingInfo[groupIndex]->EvBatterytargetVoltage * 10),
                                                             ZERO_CURRENT + preChargingTarget);

                                            byte _ovCahrgingCur = 0;
                                            if (preChargingCur > PRE_CHARG_STEP_CUR)
                                                _ovCahrgingCur = PRE_CHARG_STEP_CUR;

                                            //PRINTF_FUNC("set out (%d) value = %f******** 6 \n", groupIndex, chargingInfo[groupIndex]->EvBatterytargetCurrent - preChargingCur - _ovCahrgingCur);
                                            PresentOutputVol(groupIndex,
                                                             (chargingInfo[groupIndex]->EvBatterytargetVoltage * 10),
                                                             (chargingInfo[groupIndex]->EvBatterytargetCurrent * 10) - preChargingCur - _ovCahrgingCur);
                                        }
                                    }

                                    if ((chargingInfo[groupIndex]->EvBatterytargetVoltage * 10) == 0)
                                    {
                                        //PRINTF_FUNC("sys ******** 3 \n");
                                        bool isNeedToClosePower = false;
                                        for (byte index = 0; index < ShmPsuData->GroupCount; index++)
                                        {
                                            if (isStartOutputSwitch[index])
                                            {
                                                isNeedToClosePower = true;
                                            }
                                            isStartOutputSwitch[index] = false;
                                        }

                                        if (isNeedToClosePower)
                                        {
                                            SwitchPower(SYSTEM_CMD, PSU_POWER_OFF);
                                            FlashLed(SYSTEM_CMD, PSU_FLASH_NORMAL);
                                        }
                                    }
                                    else
                                    {
                                        bool isNeedToOpenPower = false;
                                        for (byte index = 0; index < ShmPsuData->GroupCount; index++)
                                        {
                                            if (!isStartOutputSwitch[index])
                                            {
                                                isNeedToOpenPower = true;
                                            }
                                            isStartOutputSwitch[index] = true;
                                        }

                                        if (isNeedToOpenPower)
                                        {
                                            SwitchPower(SYSTEM_CMD, PSU_POWER_ON);
                                            FlashLed(SYSTEM_CMD, PSU_FLASH_ON);
                                        }
                                    }
                                }
                                else
                                {
                                    //PRINTF_FUNC("set out (%d) value = %f******** 7 \n", groupIndex, chargingInfo[groupIndex]->EvBatterytargetCurrent);
                                    PresentOutputVol(groupIndex,
                                                     (chargingInfo[groupIndex]->EvBatterytargetVoltage * 10),
                                                     (chargingInfo[groupIndex]->EvBatterytargetCurrent * 10));

                                    if ((chargingInfo[groupIndex]->EvBatterytargetVoltage * 10) == 0)
                                    {
                                        //PRINTF_FUNC("%d ******** 4 \n", groupIndex);
                                        if (isStartOutputSwitch[groupIndex])
                                        {
                                            isStartOutputSwitch[groupIndex] = false;
                                            SwitchPower(groupIndex, PSU_POWER_OFF);
                                            FlashLed(groupIndex, PSU_FLASH_NORMAL);
                                        }
                                    }
                                    else
                                    {
                                        if (!isStartOutputSwitch[groupIndex])
                                        {
                                            isStartOutputSwitch[groupIndex] = true;
                                            SwitchPower(groupIndex, PSU_POWER_ON);
                                            FlashLed(groupIndex, PSU_FLASH_ON);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    else if (chargingInfo[groupIndex]->SystemStatus >= S_TERMINATING &&
                             chargingInfo[groupIndex]->SystemStatus <= S_COMPLETE)
                    {
                        if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX)
                        {
                            if (!isCharging)
                            {
                                //PRINTF_FUNC("sys ******** 5 \n");
                                bool isNeedToClosePower = false;
                                for (byte index = 0; index < ShmPsuData->GroupCount; index++)
                                {
                                    if (isStartOutputSwitch[index])
                                    {
                                        isNeedToClosePower = true;
                                    }
                                    isStartOutputSwitch[index] = false;
                                }

                                if (isNeedToClosePower)
                                {
                                    SwitchPower(SYSTEM_CMD, PSU_POWER_OFF);
                                    FlashLed(SYSTEM_CMD, PSU_FLASH_NORMAL);
                                }

                                if (chargingInfo[groupIndex]->SystemStatus == S_COMPLETE)
                                {
                                    if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_PREPARE_M_TO_A &&
                                        ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A)
                                    {
                                        // 代表在切換的過程中,停止充電了
                                        if ((chargingInfo[groupIndex]->PresentChargingCurrent * 10) <= STOP_CURRENT)
                                            ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_RELAY_M_TO_A;
                                    }
                                }
                            }
                            else if (chargingInfo[groupIndex]->SystemStatus == S_COMPLETE)
                            {
                                // 代表充電的槍依舊在充電,欲進入充電的槍取消充電了
                                if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_PREPARE_M_TO_A &&
                                    ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A)
                                {
                                    ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_NONE;
                                }
                            }
                        }
                        else if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER)
                        {
                            if (!isReadToCharging)
                            {
                                bool isNeedToClosePower = false;
                                for (byte index = 0; index < ShmPsuData->GroupCount; index++)
                                {
                                    if (isStartOutputSwitch[index])
                                    {
                                        isNeedToClosePower = true;
                                    }
                                    isStartOutputSwitch[index] = false;
                                }

                                if (isNeedToClosePower)
                                {
                                    SwitchPower(SYSTEM_CMD, PSU_POWER_OFF);
                                    FlashLed(SYSTEM_CMD, PSU_FLASH_NORMAL);
                                }
                            }
                            else
                            {
                                if (isStartOutputSwitch[groupIndex])
                                {
                                    isStartOutputSwitch[groupIndex] = false;
                                    SwitchPower(groupIndex, PSU_POWER_OFF);
                                    FlashLed(groupIndex, PSU_FLASH_NORMAL);
                                }
                            }

                            if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_WAITING)
                                ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_COMP;
                            else
                                ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_NONE;
                        }
                    }
                    else if ((chargingInfo[groupIndex]->SystemStatus >= S_PREPARNING && chargingInfo[groupIndex]->SystemStatus <= S_PREPARING_FOR_EV) &&
                             ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER)
                    {
                        //PRINTF_FUNC("%d ******** 7 \n", groupIndex);
                        if (isStartOutputSwitch[groupIndex])
                        {
                            isStartOutputSwitch[groupIndex] = false;
                            SwitchPower(groupIndex, PSU_POWER_OFF);
                            FlashLed(groupIndex, PSU_FLASH_NORMAL);
                        }
                    }
                }
                    break;
            }
        }
        usleep(20000);
    }
    return FAIL;
}