#include "Module_PsuComm.h"

#define ARRAY_SIZE(A)       (sizeof(A) / sizeof(A[0]))
#define PASS                1
#define FAIL                -1
#define YES                 1
#define NO                  0
#define DERATING            30
#define ELEMENT_NOT_FIND    255
#define CHK_VOL_RANGE       50
#define CHK_CUR_RANGE       10
#define DERATING_RANGE      100
#define ZERO_CURRENT        10          // 該值須保持最小為 1A
#define ZERO_VOLTAGE        50
#define STOP_CURRENT        30
#define PSU_MIN_CUR         1000
#define PRE_CHARG_STEP_CUR  30
#define PRE_CHARG_RANGE     5
#define EQUAL               0

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

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

float carReqVol = 0;
float carReqCur = 0;
float evseOutVol = 0;
float evseOutCur = 0;

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

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

unsigned long GetTimeoutValue(struct timeval _sour_time);

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

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

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

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

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

    sprintf(Buf,"echo \"%04d-%02d-%02d %02d:%02d:%02d.%03d - %s\" >> /Storage/SystemLog/[%04d.%02d]SystemLog",
            tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,SeqEndTime.millitm,
            buffer,
            tm->tm_year+1900,tm->tm_mon+1);
    system(Buf);

    return rc;
}

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

    if (ShmSysConfigAndInfo->SysConfig.SwitchDebugFlag == YES)
        printf("%s \n", buffer);
    else
        DEBUG_INFO("%s \n", buffer);
}
//=================================
// Common routine
//=================================
size_t FindIndex(const int a[], size_t size, int value, byte group)
{
    size_t index = 0;

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

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

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

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

    return _group;
}

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

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

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

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

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

    return false;
}

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

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

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

//=================================
// Callback Function
//=================================
void GetStatusCallback(byte group, byte address, byte temp, int alarm)
{
    if (IsOverModuleCount(address))
        return;

    byte group1 = FindTargetGroup(address);

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

    ShmPsuData->PsuGroup[group1].PsuModule[address].CriticalTemp1 = temp;
    ShmPsuData->PsuGroup[group1].PsuModule[address].CriticalTemp2 = temp;
    ShmPsuData->PsuGroup[group1].PsuModule[address].CriticalTemp3 = temp;
    ShmPsuData->PsuGroup[group1].PsuModule[address].ExletTemp = temp;
    ShmPsuData->PsuGroup[group1].PsuModule[address].AlarmCode = alarm;
    AbnormalStopAnalysis(group1, alarm);
    //printf("alarm = %d \n", alarm);
}

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

void GetMaxPowerAndCur(unsigned char mode, int ratingCur, int *pow, int *cur)
{
    unsigned short maxCurrent = ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent * 10;
    unsigned short maxPower = ShmSysConfigAndInfo->SysConfig.MaxChargingPower * 10;

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

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

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

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

void GetAvailableCapCallback(byte address, short maxVol, short minVol, short maxCur, short totalPow)
{
    int _groupPower = 0, _groupCurrent = 0;
    byte group = FindTargetGroup(address);

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

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

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

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

    chargingInfo[group]->MaximumChargingVoltage = maxVol;

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

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

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

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

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

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

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

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

void GetFwCallback(byte address, short dcSwVer, short pfcSwVer, short hwVer)
{
    if (IsOverModuleCount(address))
        return;

    byte group = FindTargetGroup(address);

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

void GetInputVoltageCallback(byte address, unsigned short vol1, unsigned short vol2, unsigned short vol3)
{
    if (IsOverModuleCount(address))
        return;

    byte group = FindTargetGroup(address);

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

    ShmPsuData->PsuGroup[group].PsuModule[address].InputVoltageL1 = vol1;
    ShmPsuData->PsuGroup[group].PsuModule[address].InputVoltageL2 = vol2;
    ShmPsuData->PsuGroup[group].PsuModule[address].InputVoltageL3 = vol3;
}

void GetPresentOutputCallback(byte group, unsigned short outVol, unsigned short outCur)
{
    unsigned short outputVol = outVol;
    unsigned short outputCur = outCur;

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

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

        for (byte index = 0; index < ShmPsuData->GroupCount; index++)
        {
            if (ShmPsuData->PsuGroup[index].GroupPresentOutputVoltage > outputVol)
                outputVol = ShmPsuData->PsuGroup[index].GroupPresentOutputVoltage;

            outputCur += ShmPsuData->PsuGroup[index].GroupPresentOutputCurrent;
        }

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

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

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

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

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

//  PRINTF_FUNC("Gun_%d, PresentChargingCurrent = %f \n", group,
//          chargingInfo[group]->PresentChargingCurrent);
}

void GetFanSpeedCallback(byte address, unsigned int fanSpeed)
{
    if (IsOverModuleCount(address))
        return;

    byte group = FindTargetGroup(address);

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

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

void GetIavailableCallback(byte address, unsigned short Iavail, unsigned short Vext)
{
    if (IsOverModuleCount(address))
        return;

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

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

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

    bool isPass = true;
    int totalCur = 0;

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

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

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

//==========================================
// 特規用指令
//==========================================
void GetOutputAndTempCallback(byte address, unsigned short outputVol,
        unsigned short outputCur, unsigned short outputPower, unsigned char Temperature)
{
//    PRINTF_FUNC("***Output Value and Temp*** address = %d, Vol = %d, Cur = %d, Pow = %d, Temp = %d \n",
//            address, outputVol, outputCur, outputPower, Temperature);
}

void GetModuleStatusCallback(byte address, unsigned char isErr, unsigned char status,
        unsigned char err1, unsigned char err2, unsigned char err3, unsigned char err4)
{
//    PRINTF_FUNC("***Status*** address = %d, isErr = %d, status = %d, err1 = %d, err2 = %d, err3 = %d, err4 = %d \n",
//            address, isErr, status, err1, err2, err3, err4);
}

void GetModuleInputCallback(byte address, unsigned short inputR,
        unsigned short inputS, unsigned short 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;

    for (byte _groupCount = 0; _groupCount < ARRAY_SIZE(ShmPsuData->PsuGroup);  _groupCount++)
    {
        ShmPsuData->PsuGroup[_groupCount].GroupPresentPsuQuantity = 0;
        ShmPsuData->PsuGroup[_groupCount].GroupAvailablePower = 0;
        ShmPsuData->PsuGroup[_groupCount].GroupAvailableCurrent = 0;
    }

    ShmPsuData->Work_Step = _INIT_PSU_STATUS;
}

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

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

    char EvsePower[2];

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

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

                conn_2_count = count - conn_1_count;
            }

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

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

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

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

void CheckSmartChargingStep(bool isWaitingAver, bool isCharging)
{
    if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_PREPARE_M_TO_A)
    {
        if (isWaitingAver)
        {
            if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX)
            {
                PRINTF_FUNC("=============Smart Charging : _REASSIGNED_GET_NEW_CAP============= Step 2 \n");
                ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_GET_NEW_CAP;
            }
            else
            {
                PRINTF_FUNC("=============Smart Charging : _REASSIGNED_NONE============= Step 0 \n");
                ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_NONE;
            }
        }
    }
    else  if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag ==  _REASSIGNED_PREPARE_A_TO_M)
    {
        if (isCharging)
        {
            if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER)
            {
                PRINTF_FUNC("=============Smart Charging : _REASSIGNED_ADJUST_A_TO_M============= Step 12 \n");
                ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_ADJUST_A_TO_M;
            }
            else
            {
                PRINTF_FUNC("=============Smart Charging_1  : _REASSIGNED_COMP============= Step 15 \n");
                ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_COMP;
            }
        }
        else
        {
            PRINTF_FUNC("=============Smart Charging_2 : _REASSIGNED_COMP============= Step 15 \n");
            ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_COMP;
        }
    }
}

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

    PRINTF_FUNC("InitShareMemory OK\n");

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

    AutoMode_RefreshOutputAndTemp(&GetOutputAndTempCallback);
    AutoMode_RefreshModuleStatus(&GetModuleStatusCallback);
    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)
            {
                InitialPsuData();
                ShmPsuData->Work_Step = INITIAL_START;
                isInitialComp = YES;
            }
            sleep(1);
            continue;
        }
        else
            isInitialComp = NO;

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

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

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

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

                        // 取版號
                        GetModuleVer(index);
                    }

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

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

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

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

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

                        // 取系統總輸出能力
                        GetModuleCap(index);
                    }
                    _getCapDelayCount--;
                    gettimeofday(&_cmdSubPriority_time, NULL);
                }

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

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

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

                // 低 Priority 的指令
                if (time > 1500)
                {
                    isCharging = false;
                    isWaitingAver = false;
                    isReadToCharging = false;
                    for (byte index = 0; index < ShmPsuData->GroupCount; index++)
                    {
                        // Pooling Status
                        GetStatus(index);

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

                        // 取得模塊輸入電壓
                        GetModuleInput(index);

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

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

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

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

                for (byte groupIndex = 0; groupIndex < _gunCount; groupIndex++)
                {
                    GetModuleOutput(groupIndex);
                    // 針對各槍當前狀態,傳送需要回傳的資料指令
                    if (((chargingInfo[groupIndex]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[groupIndex]->SystemStatus <= S_CHARGING) && chargingInfo[groupIndex]->RelayK1K2Status) ||
                        (chargingInfo[groupIndex]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[groupIndex]->SystemStatus <= S_CHARGING && chargingInfo[groupIndex]->Type == _Type_GB) ||
                        (chargingInfo[groupIndex]->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingInfo[groupIndex]->SystemStatus <= S_CCS_PRECHARGE_ST1))
                    {
                        if (chargingInfo[groupIndex]->EvBatterytargetVoltage > 0 &&
                            carReqVol != chargingInfo[groupIndex]->EvBatterytargetVoltage)
                        {
                            carReqVol = chargingInfo[groupIndex]->EvBatterytargetVoltage;
                            DEBUG_INFO("ev need vol = %f \n", chargingInfo[groupIndex]->EvBatterytargetVoltage);
                        }

                        if (chargingInfo[groupIndex]->EvBatterytargetCurrent > 0 &&
                            carReqCur != chargingInfo[groupIndex]->EvBatterytargetCurrent)
                        {
                            carReqCur = chargingInfo[groupIndex]->EvBatterytargetCurrent;
                            DEBUG_INFO("ev need cur = %f \n", chargingInfo[groupIndex]->EvBatterytargetCurrent);
                        }

                        if (time > 1500)
                        {
                            if (chargingInfo[groupIndex]->FireChargingVoltage > 0 &&
                                evseOutVol != (chargingInfo[groupIndex]->FireChargingVoltage / 10))
                            {
                                evseOutVol = (chargingInfo[groupIndex]->FireChargingVoltage / 10);
                                PRINTF_FUNC("groupIndex = %d, evse output vol = %f \n", groupIndex,
                                    chargingInfo[groupIndex]->FireChargingVoltage);
                            }

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

                        if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX)
                        {
//                          PRINTF_FUNC("index = %d, SystemStatus = %d, Ev = %f, curCur = %f \n", groupIndex,
//                                  chargingInfo[groupIndex]->SystemStatus, chargingInfo[groupIndex]->EvBatterytargetCurrent,
//                                  (chargingInfo[groupIndex]->PresentChargingCurrent * 10));
                            // 智能判斷 Start -----------------------------------------------------------
                            if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_GET_NEW_CAP)
                            {
                                if (ShmPsuData->SystemAvailableCurrent != chargingInfo[groupIndex]->AvailableChargingCurrent)
                                {
                                    // 車端要求電流為該充電槍的額定輸出電流的範圍內
                                    if (chargingInfo[groupIndex]->EvBatterytargetCurrent <= chargingInfo[groupIndex]->AvailableChargingCurrent ||
                                        deratingKeepCount >= DERATING)
                                    {
                                        // 車端降載完成
                                        PRINTF_FUNC("=============Smart Charging : _REASSIGNED_ADJUST_M_TO_A============= Step 3 \n");
                                        ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_ADJUST_M_TO_A;
                                        gettimeofday(&_derating_time, NULL);
                                        deratingKeepCount = 0;
                                    }
                                    else
                                    {
                                        deratingKeepCount++;
                                    }
                                }

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

                                // 需求電流不降低的情況下 -> 依然要切
                                if (chargingInfo[groupIndex]->AvailableChargingCurrent < chargingInfo[groupIndex]->EvBatterytargetCurrent)
                                {
                                    PRINTF_FUNC("** _REASSIGNED_ADJUST_M_TO_A ** Gun_%d, AvailableChargingCurrent = %f, EvBatterytargetCurrent = %f \n", groupIndex,
                                            (chargingInfo[groupIndex]->PresentChargingCurrent * 10),
                                            chargingInfo[groupIndex]->AvailableChargingCurrent);
                                    for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++)
                                    {
                                        if (chargingInfo[subIndex]->SystemStatus == S_REASSIGN)
                                        {
                                            if ((ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent) <= CHK_CUR_RANGE)
                                                isChanged = true;
                                            break;
                                        }
                                    }

                                    // 這狀況下輸出端的電流載滿載衝的狀況下,並不會降電流
                                    // 所以只能拉載到該槍端的最大輸出能力
//                                  if ((chargingInfo[groupIndex]->PresentChargingCurrent * 10) >= chargingInfo[groupIndex]->AvailableChargingCurrent - CHK_CUR_RANGE ||
//                                          (chargingInfo[groupIndex]->PresentChargingCurrent * 10) <= CHK_CUR_RANGE)
//                                  {
//                                      isChanged = true;
//                                  }
                                }
                                else if (((chargingInfo[groupIndex]->PresentChargingCurrent * 10) >= ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent - CHK_CUR_RANGE) &&
                                        ((chargingInfo[groupIndex]->PresentChargingCurrent * 10) <= ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent + CHK_CUR_RANGE))
                                {
                                    for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++)
                                    {
                                        if (chargingInfo[subIndex]->SystemStatus == S_REASSIGN)
                                        {
                                            if ((ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent) <= CHK_CUR_RANGE)
                                                isChanged = true;
                                            break;
                                        }
                                    }
                                }

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

                                    // 輸出端與車端要求電流接近
                                    PRINTF_FUNC("=============Smart Charging : _REASSIGNED_RELAY_M_TO_A============= Step 4 \n");
                                    ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_RELAY_M_TO_A;
                                }
                            }

                            if (ShmPsuData->SystemAvailablePower > 0)
                            {
                                // 調整輸出電流 : 漸進調整方式
                                if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_ADJUST_M_TO_A)
                                {
                                    // 當前充電中的目標電壓
                                    float targetVol = chargingInfo[groupIndex]->EvBatterytargetVoltage;
                                    // 當前充電中的目標電流
                                    //float targetCur = 0;
                                    // 準備切出去的模塊電流
                                    float deratingCur = 0;

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

                                    if (reassignIndex != ELEMENT_NOT_FIND)
                                    {
                                        //int derating = GetTimeoutValue(_derating_time) / 1000;

                                        //if (derating > 1000)
                                        {
                                            if (ShmPsuData->PsuGroup[reassignIndex].GroupPresentOutputCurrent > 0)
                                            {
                                                deratingCur = ShmPsuData->PsuGroup[reassignIndex].GroupPresentOutputCurrent - DERATING_RANGE;
                                                if (deratingCur <= CHK_CUR_RANGE)
                                                    deratingCur = CHK_CUR_RANGE;

                                                PresentOutputVol(reassignIndex, targetVol, deratingCur);
                                                gettimeofday(&_derating_time, NULL);
                                            }
                                        }

                                        // ***********直接降低要移除的模塊電流即可*************
                                        // 因為爬的速度沒有降的速度快,所以採兩倍速度爬升
//                                      targetCur = ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent + (DERATING_RANGE * 2);
//                                      if (targetCur >= chargingInfo[groupIndex]->EvBatterytargetCurrent)
//                                              targetCur = chargingInfo[groupIndex]->EvBatterytargetCurrent;

                                        if (targetVol == 0)
                                        {
                                            SwitchPower(SYSTEM_CMD, PSU_POWER_OFF);
                                            FlashLed(SYSTEM_CMD, PSU_FLASH_NORMAL);
                                        }
                                        else
                                        {
                                            SwitchPower(SYSTEM_CMD, PSU_POWER_ON);
                                            FlashLed(SYSTEM_CMD, PSU_FLASH_ON);
                                        }
                                    }
                                }
                                else
                                {
                                    // 該充電槍的目標電壓與目標電流
                                    PresentOutputVol(SYSTEM_CMD,
                                        chargingInfo[groupIndex]->EvBatterytargetVoltage,
                                        chargingInfo[groupIndex]->EvBatterytargetCurrent);

                                    if (chargingInfo[groupIndex]->EvBatterytargetVoltage == 0)
                                    {
                                        SwitchPower(SYSTEM_CMD, PSU_POWER_OFF);
                                        FlashLed(SYSTEM_CMD, PSU_FLASH_NORMAL);
                                    }
                                    else
                                    {
                                        SwitchPower(SYSTEM_CMD, PSU_POWER_ON);
                                        FlashLed(SYSTEM_CMD, PSU_FLASH_ON);
                                    }
                                }
                            }
                        }
                        else if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER)
                        {
                            // 智能判斷 Start -----------------------------------------------------------
                            if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_ADJUST_A_TO_M)
                            {
                                bool balanceVol = true;

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

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

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

                                if (idleCurrent >= chargingCurrent - PRE_CHARG_RANGE)
                                {
                                    PRINTF_FUNC("=============Smart Charging_0 : _REASSIGNED_COMP============= Step 15 \n");
                                    ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_COMP;
                                }
                            }

                            if (chargingInfo[groupIndex]->AvailableChargingCurrent > 0)
                            {
                                if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_ADJUST_A_TO_M)
                                {
                                    for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++)
                                    {
                                        if (chargingInfo[subIndex]->SystemStatus == S_IDLE ||
                                            chargingInfo[subIndex]->SystemStatus == S_RESERVATION ||
                                            chargingInfo[subIndex]->SystemStatus == S_REASSIGN_CHECK)
                                        {
                                            // 閒置模塊升壓,另對剛分配近來的模塊,預上升電流值 (preChargingCur)
                                            PresentOutputVol(subIndex,
                                                    chargingInfo[groupIndex]->EvBatterytargetVoltage,
                                                    ZERO_CURRENT + preChargingTarget);

                                            preChargingCur = ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent;
                                        }
                                        else
                                        {
                                            PRINTF_FUNC("CurOutputCurrent = %d \n", ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent + preChargingCur);
                                            // 充電中的模塊維持輸出
                                            PresentOutputVol(subIndex,
                                                chargingInfo[subIndex]->EvBatterytargetVoltage,
                                                chargingInfo[subIndex]->EvBatterytargetCurrent - preChargingCur);

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

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

                                        if (chargingInfo[groupIndex]->EvBatterytargetVoltage == 0)
                                        {
                                            SwitchPower(subIndex, PSU_POWER_OFF);
                                            FlashLed(subIndex, PSU_FLASH_NORMAL);
                                        }
                                        else
                                        {
                                            SwitchPower(subIndex, PSU_POWER_ON);
                                            FlashLed(subIndex, PSU_FLASH_ON);
                                        }
                                    }
                                }
                                else
                                {
                                    PresentOutputVol(groupIndex,
                                        chargingInfo[groupIndex]->EvBatterytargetVoltage,
                                        chargingInfo[groupIndex]->EvBatterytargetCurrent);

                                    if (chargingInfo[groupIndex]->EvBatterytargetVoltage == 0)
                                    {
                                        SwitchPower(groupIndex, PSU_POWER_OFF);
                                        FlashLed(groupIndex, PSU_FLASH_NORMAL);
                                    }
                                    else
                                    {
                                        SwitchPower(groupIndex, PSU_POWER_ON);
                                        FlashLed(groupIndex, PSU_FLASH_ON);
                                    }
                                }
                            }
                        }
                    }
                    else if (chargingInfo[groupIndex]->SystemStatus >= S_TERMINATING &&
                             chargingInfo[groupIndex]->SystemStatus <= S_COMPLETE)
                    {
                        if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX)
                        {
                            if (!isCharging)
                            {
                                SwitchPower(SYSTEM_CMD, PSU_POWER_OFF);
                                FlashLed(SYSTEM_CMD, PSU_FLASH_NORMAL);

                                if (chargingInfo[groupIndex]->SystemStatus == S_COMPLETE)
                                {
                                    if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_PREPARE_M_TO_A &&
                                        ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A)
                                    {
                                        // 代表在切換的過程中,停止充電了
                                        if ((chargingInfo[groupIndex]->PresentChargingCurrent * 10) <= STOP_CURRENT)
                                            ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_RELAY_M_TO_A;
                                    }
                                }
                            }
                            else if (chargingInfo[groupIndex]->SystemStatus == S_COMPLETE)
                            {
                                // 代表充電的槍依舊在充電,欲進入充電的槍取消充電了
                                if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_PREPARE_M_TO_A &&
                                    ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A)
                                {
                                    ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_NONE;
                                }
                            }
                        }
                        else if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER)
                        {
                            if (!isReadToCharging)
                            {
                                SwitchPower(SYSTEM_CMD, PSU_POWER_OFF);
                                FlashLed(SYSTEM_CMD, PSU_FLASH_NORMAL);
                            }
                            else
                            {
                                SwitchPower(groupIndex, PSU_POWER_OFF);
                                FlashLed(groupIndex, PSU_FLASH_NORMAL);
                            }

                            if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_WAITING)
                                ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_COMP;
                            else
                                ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_NONE;
                        }
                    }
                }
                    break;
            }
        }
        usleep(20000);
    }
    return FAIL;
}