#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			10

#define SELF_TEST			0

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

void trim(char *s);
int mystrcmp(char *p1,char *p2);
void substr(char *dest, const char* src, unsigned int start, unsigned int cnt);
void split(char **arr, char *str, const char *del);

bool libInitialize = false;
byte gun_count = CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY;
byte getAvailableCapOffset = 5;
byte deratingKeepCount = 0;

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

int cmdDelayTime = 20000;

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];
	time_t CurrentTime;
	struct tm *tm;
	va_list args;

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

	memset(Buf,0,sizeof(Buf));
	CurrentTime = time(NULL);
	tm=localtime(&CurrentTime);
	sprintf(Buf,"echo \"%04d-%02d-%02d %02d:%02d:%02d - %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,
			buffer,
			tm->tm_year+1900,tm->tm_mon+1);
	system(Buf);

	return rc;
}

int DiffTimeb(struct timeb ST, struct timeb ET)
{
	//return milli-second
	unsigned int StartTime,StopTime;

	StartTime=(unsigned int)ST.time;
	StopTime=(unsigned int)ET.time;
	return (StopTime-StartTime)*1000+ET.millitm-ST.millitm;
}

void PRINTF_FUNC(char *string, ...)
{
	if (DEBUG)
	{
		va_list args;
		char buffer[4096];

		va_start(args, string);
		vsnprintf(buffer, sizeof(buffer), string, args);
		va_end(args);
		printf("%s \n", buffer);
	}
}
//=================================
// Common routine
//=================================
char* getTimeString(void)
{
	char *result=malloc(21);
	time_t timep;
	struct tm *p;
	time(&timep);
	p=gmtime(&timep);

	sprintf(result, "[%04d-%02d-%02d %02d:%02d:%02d]", (1900+p->tm_year), (1+p->tm_mon), p->tm_mday, p->tm_hour, p->tm_hour, p->tm_sec);

	return result;
}

void trim(char *s)
{
    int i=0, j, k, l=0;

    while((s[i]==' ')||(s[i]=='\t')||(s[i]=='\n'))
        i++;

    j = strlen(s)-1;
    while((s[j]==' ')||(s[j]=='\t')||(s[j]=='\n'))
        j--;

    if(i==0 && j==strlen(s)-1) { }
    else if(i==0) s[j+1] = '\0';
    else {
        for(k=i; k<=j; k++) s[l++] = s[k];
        s[l] = '\0';
    }
}

int mystrcmp(char *p1,char *p2)
{
    while(*p1==*p2)
    {
        if(*p1=='\0' || *p2=='\0')
            break;
        p1++;
        p2++;
    }
    if(*p1=='\0' && *p2=='\0')
        return(PASS);
    else
        return(FAIL);
}

void substr(char *dest, const char* src, unsigned int start, unsigned int cnt)
{
	strncpy(dest, src + start, cnt);
	dest[cnt] = 0;
}

void split(char **arr, char *str, const char *del)
{
	char *s = strtok(str, del);

	while(s != NULL)
	{
		*arr++ = s;
		s = strtok(NULL, del);
	}
}

//=================================
// ReAssigned PSU Function
//=================================
void ReAssignedResource()
{
	int index = 0;
	struct PsuModuleData PsuModule[ShmPsuData->SystemPresentPsuQuantity];

	for (byte i = 0; i < 4; i++)
	{
		for(byte psuCount = 0; psuCount < ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity; psuCount++)
		{
			memcpy(&PsuModule[index], &ShmPsuData->PsuGroup[i].PsuModule[psuCount], sizeof(struct PsuModuleData));
			index++;
		}
		ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity = 0;
	}

	for(int i = 0; i < ShmPsuData->SystemPresentPsuQuantity; i++)
	{
		byte group = PsuModule[i].FireWireIndex;

		memcpy(&ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity],
				&PsuModule[i], sizeof(struct PsuModuleData));

		PRINTF_FUNC("ReAssignedResource : PhysicalID = %d, Address = %d, group = %d \n",
				ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].PhysicalID,
				ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].Address,
				group);
//		printf("ReAssignedResource : PhysicalID = %d, Address = %d, group = %d \n",
//				ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].PhysicalID,
//				ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].Address,
//				group);

		PsuAddressAssignment(ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].PhysicalID,
				group);
		ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity++;
	}
}

//=================================
// 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
//=================================
// �ˬd Byte ���Y�� Bit ����
// _byte : �����ܪ� byte
// _bit : �� byte ���ĴX�� 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 == 1)
							ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDuplicateID = YES;
						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 GetPsuRequestCallback(byte phy_id, char *serial_number)
{
	if (ShmSysConfigAndInfo->SysInfo.AcContactorStatus == NO)
		return;

	// ********************** �C���e�q��A�ݧP�_�n��Ҧ����Ҷ����t����� Group **********************
	byte group = 0;
	if(ShmSysConfigAndInfo->SysInfo.BootingStatus == BOOTTING || gun_count == 1)
	{
		// ��l�ƪ��A�A�h���������t��P�Ӹs
		group = 0;
	}
	else
	{
		group = ShmSysConfigAndInfo->SysInfo.CurGunSelected;
	}

	bool isNewPsu = true;
	for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++)
	{
		if (ShmPsuData->PsuGroup[group].PsuModule[index].PhysicalID == phy_id &&
			strncmp((char *)ShmPsuData->PsuGroup[group].PsuModule[index].SerialNumber, serial_number, 7) == 0)
		{
			isNewPsu = false;
		}
	}

	if (isNewPsu)
	{
		ShmPsuData->SystemPresentPsuQuantity++;
		PRINTF_FUNC("get psu********Membar = %d, group = %d \n", ShmPsuData->SystemPresentPsuQuantity, group);

		if (ShmPsuData->Work_Step >= _TEST_LINE_STEP && ShmPsuData->Work_Step <= _TEST_COMPLETE)
		{
			// �w�g�i�J���u�W�����Ұʧ@
			//ShmPsuData->NeedBackTest = YES;
		}
		else if (ShmPsuData->Work_Step == _WORK_CHARGING)
		{
			// �@���i�J���u�A���t�@�Ӥ��|�Ψ쪺���ӼҶ�
			group++;
		}

		ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].Address = ShmPsuData->SystemPresentPsuQuantity;
		ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].PhysicalID = phy_id;
		ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].AssignID = (group >> 6) + ShmPsuData->SystemPresentPsuQuantity;
		strcpy((char *)ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].SerialNumber, serial_number);
		ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity++;

		byte isFind = false;
		for (byte index = 0; index < conn_1_count; index++)
		{
			PRINTF_FUNC("connector_1[%d] = %d, phy_id = %d \n", index, connector_1[index], phy_id);
			if (connector_1[index] == phy_id)
			{
				isFind = true;
				ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].FireWireIndex = 0;
				break;
			}
		}

		if (!isFind)
		{
			for (byte index = 0; index < conn_2_count; index++)
			{
				PRINTF_FUNC("connector_2[%d] = %d, phy_id = %d \n", index, connector_2[index], phy_id);
				if (connector_2[index] == phy_id)
				{
					isFind = true;
					ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].FireWireIndex = 1;
					break;
				}
			}
		}

		//PsuAddressAssignment(phy_id, serial_number, ShmPsuData->SystemPresentPsuQuantity, group);
		PsuAddressAssignment(phy_id, group);

		if (ShmPsuData->Work_Step != _WORK_CHARGING)
		{
			ShmPsuData->GroupCount = group + 1;
		}
	}
}

void SaveStatusCallback(byte group, byte address, char cri_temp1, int alarm)
{
	//EVSE
	for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++)
	{
		if (ShmPsuData->PsuGroup[group].PsuModule[index].PhysicalID == address)
	    {
			ShmPsuData->PsuGroup[group].PsuModule[index].CriticalTemp1 = cri_temp1;
	    	ShmPsuData->PsuGroup[group].PsuModule[index].AlarmCode = alarm;
	    	AbnormalStopAnalysis(group, alarm);
	    	break;
	    }
	}
}

//�ҲդT�V��J�q��
void SavePresentInputVoltageCallback(byte address, unsigned short vol1, unsigned short vol2, unsigned short vol3)
{
	//EVSE
	//search group
    for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++)
    { 
    	for (byte index = 0; index < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; index++)
    	{
    	    //search id
    		if (ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PhysicalID == address)
    		{
    		    //update module msg
    			ShmPsuData->PsuGroup[groupIndex].PsuModule[index].InputVoltageL1 = vol1;
    			ShmPsuData->PsuGroup[groupIndex].PsuModule[index].InputVoltageL2 = vol2;
    			ShmPsuData->PsuGroup[groupIndex].PsuModule[index].InputVoltageL3 = vol3;
    			break;
    		}
    	}
    }
}

// �Ҷ���X���q���q�y
void SavePresentOutputCallback(byte address, unsigned short out_vol, unsigned short out_cur)
{
	unsigned short outputVol = 0;
	unsigned short outputCur = 0;
	unsigned short group = 0;
	bool isChange = false;

	// PSU
	for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++)
    {
    	for (int index = 0; index < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; index++)
    	{
    		if (ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PhysicalID == address)
    		{
    		    //�p�G�^�����Ҳդ��O ver1.09 ���ϥμҲտ�X�q��
    		    /*
    			if(InfyPwrModelVerIs109 == 0)
    			{
    			    ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PresentOutputVoltage = out_vol;
    			}
    			*/
    			ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PresentOutputVoltage = out_vol;
    			ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PresentOutputCurrent = out_cur;   			
    			
    		    for (int loop = 0; loop < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; loop++)
    		    {
    		        //update voltage
   		            if (ShmPsuData->PsuGroup[groupIndex].PsuModule[loop].PresentOutputVoltage > outputVol)
   		            {
    			        outputVol = ShmPsuData->PsuGroup[groupIndex].PsuModule[loop].PresentOutputVoltage;
    			    }
    			    //update total current
    			    outputCur += ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PresentOutputCurrent;
    			    group = groupIndex;
    			    isChange = true;
    		    }
    		}

            /*
    		if (ShmPsuData->PsuGroup[group].PsuModule[index].PresentOutputVoltage > outputVol)
    			outputVol = ShmPsuData->PsuGroup[group].PsuModule[index].PresentOutputVoltage;

    		outputCur += ShmPsuData->PsuGroup[group].PsuModule[index].PresentOutputCurrent;
    		*/
    	}
    }

	if (isChange)
	{
		// PSU Group
		// �q��
		ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage = outputVol;
		// �q�y
		ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent = outputCur;

		//EVSE - �j�ݪ���X�q��
		chargingInfo[group]->PresentChargingVoltage = ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage;
		//EVSE - �j�ݪ���X�q�y
		chargingInfo[group]->PresentChargingCurrent = ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent;
	}

	//printf("GroupPresentOutputVoltage = %d \n", ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage);
	//printf("GroupPresentOutputCurrent = %d \n", ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent);
}

//PSU able_power = KW (��� 0.1) exp. 300 = 30kw
//PSU able_cur = A (��� 0.1) exp. 400 = 40A
void SaveAvailableCapCallback(byte address, unsigned short maxv, unsigned short minv, unsigned short able_cur, unsigned short able_power)
{
	unsigned int power = 0;
	unsigned int current = 0;
	unsigned int power_derating = 0;
	unsigned int current_derating = 0;
	unsigned int group = 0;
	bool isChange = false;
	//bool sameGroup = false;

    //search group
	//printf("GroupCount = %d \n", ShmPsuData->GroupCount);
    for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++)
    {        
    	//printf("GroupPresentPsuQuantity = %d \n", ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity);
    	for (int index = 0; index < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; index++)
    	{
    	    //search group-id
    		//printf("PhysicalID = %d, address = %d \n", ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PhysicalID, address);
    		if (ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PhysicalID == address)
    		{
    		    //����s�ӼҲո�T    
    			ShmPsuData->PsuGroup[groupIndex].PsuModule[index].AvailablePower = able_power;

    			//�q���b 150V �ɨϥ��B�w�q�y
    			if(ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PresentOutputVoltage < 1500)
    			{
    			    ShmPsuData->PsuGroup[groupIndex].PsuModule[index].AvailableCurrent = able_cur;
    			}
    			//�p�G�^�����Ҳդ��O ver1.09 �� �� (�p�G�^�����ҲլO ver1.09 �����^���i��X�q�y���~�h�ϥ��B�w����i��X�q�y)
    			/*
    			if(InfyPwrModelVerIs109 == 0 ||
    			    (InfyPwrModelVerIs109 == 1 && ShmPsuData->PsuGroup[groupIndex].PsuModule[index].AvailableCurrent == 0))
    			{
    			        ShmPsuData->PsuGroup[groupIndex].PsuModule[index].AvailableCurrent = able_cur;
    			}
    			*/
    		    //�ӹ������Ҳոs���s�p���`�X		    
    		    for (int loop = 0; loop < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; loop++)
    		    {
    		    	// ����
//    		    	if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_GET_NEW_CAP &&
//    		    			ShmSysConfigAndInfo->SysInfo.ReAssignedFlag < _REASSIGNED_COMP)
//    		    	{
//    		    		if (ShmPsuData->PsuGroup[group].PsuModule[index].FireWireIndex == group)
//    		    		{
//    		    			power_derating += ShmPsuData->PsuGroup[group].PsuModule[index].AvailablePower;
//    		    			current_derating += ShmPsuData->PsuGroup[group].PsuModule[index].AvailableCurrent;
//    		    		}
//    		    	}

    		        power += ShmPsuData->PsuGroup[groupIndex].PsuModule[loop].AvailablePower;
    			    current += ShmPsuData->PsuGroup[groupIndex].PsuModule[loop].AvailableCurrent;
    			    group = groupIndex;
    			    isChange = true;
    		    }
    		}
    	}
    }
    
    if (current_derating == 0)
    {
    	current_derating = current;
    }

    if (power_derating == 0)
    {
    	power_derating = power;
    }

	if (isChange)
	{
		// PSU Group
		// Available Power
		ShmPsuData->PsuGroup[group].GroupAvailablePower = power;
		// Available Current
		ShmPsuData->PsuGroup[group].GroupAvailableCurrent = current;

		chargingInfo[group]->MaximumChargingVoltage = maxv;
		chargingInfo[group]->AvailableChargingCurrent =	ShmPsuData->PsuGroup[group].GroupAvailableCurrent;
		chargingInfo[group]->AvailableChargingPower = ShmPsuData->PsuGroup[group].GroupAvailablePower;
		chargingInfo[group]->DeratingChargingCurrent = current_derating;
		chargingInfo[group]->DeratingChargingPower = power_derating;

		PRINTF_FUNC("group = %d, AvailableChargingCurrent = %f, GroupAvailablePower = %f, DeratingChargingCurrent = %f, DeratingChargingPower = %f \n",
							group, chargingInfo[group]->AvailableChargingCurrent, chargingInfo[group]->AvailableChargingPower,
							chargingInfo[group]->DeratingChargingCurrent, chargingInfo[group]->DeratingChargingPower);
	}
}

void GetBarCodeCallback(byte address, char *serial_number , unsigned short module_ver)
{
	//EVSE
	for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++)
	{
    	for (byte index = 0; index < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; index++)
    	{
    		if (ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PhysicalID == address)
    		{
    		    ShmPsuData->PsuGroup[groupIndex].PsuModule[index].FwVersion[0] = (module_ver >> 8) & 0xFF;
    			ShmPsuData->PsuGroup[groupIndex].PsuModule[index].FwVersion[1] = (module_ver) & 0xFF;
    		    //strcpy((char *)ShmPsuData->PsuGroup[groupIndex].PsuModule[ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity].SerialNumber, serial_number);
    		}
    	}
	}
}

void GetMiscInfoCallback(byte address, unsigned short CmdType , unsigned int value)
{
	//EVSE
	for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++)
    {
    	for (byte index = 0; index < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; index++)
    	{
    		if (ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PhysicalID == address)
    		{
    		    if(CmdType == MISC_REQCMD_DC_BOARD_TMP){
    		        //�ƭȥ��B�z
    		        ShmPsuData->PsuGroup[groupIndex].PsuModule[index].CriticalTemp2 = (byte)value;
    		    }else if(CmdType == MISC_REQCMD_PFC_BOARD_TMP){
    		        //�ƭȥ��B�z
    		        ShmPsuData->PsuGroup[groupIndex].PsuModule[index].CriticalTemp3 = (byte)value;
    		    }else if(CmdType == MISC_REQCMD_FAN_SPEED){
    		        //�ƭȥ��B�z
    		        ShmPsuData->PsuGroup[groupIndex].PsuModule[index].FanSpeed_1 = (unsigned short)value;
    		    }
    		}
    	}
	}

	//�ȩw�p�G���^ misc �N�{�w�^������ 1.9 ��
	//InfyPwrModelVerIs109 = 1;
	//printf("Get Misc : %d \n",InfyPwrModelVerIs109);
}

void SaveHardwareVersion(byte group, byte address, int hw_ver)
{
	//EVSE
	for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++)
	{
		if (ShmPsuData->PsuGroup[group].PsuModule[index].Address == address)
		{
			ShmPsuData->PsuGroup[group].PsuModule[index].FwVersion[0] = (hw_ver >> 24) & 0xFF;
			ShmPsuData->PsuGroup[group].PsuModule[index].FwVersion[1] = (hw_ver >> 16) & 0xFF;
			ShmPsuData->PsuGroup[group].PsuModule[index].FwVersion[2] = (hw_ver >> 8) & 0xFF;
			ShmPsuData->PsuGroup[group].PsuModule[index].FwVersion[3] = hw_ver & 0xFF;
			break;
		}
	}
}


//Vext      �ҲդG�����q��
//Iavail    �Ҳեثe�]���Ҧ]�����u����X�q�y
void SavePresentModeleVextIavailCallback(byte address, unsigned short Vext, unsigned short Iavail)
{
	//EVSE
	//search group
    for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++)
    {
    	for (byte index = 0; index < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; index++)
    	{
    	    //search id
    		if (ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PhysicalID == address)
    		{
    		    //update module msg
    		    //ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PresentOutputVoltage = Vext;
    		    //
    		    if(ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PresentOutputVoltage >= 1500)
    		    {
    			    ShmPsuData->PsuGroup[groupIndex].PsuModule[index].AvailableCurrent = Iavail;
    			}
    			//printf("Vext = %d I = %d \n", Vext,Iavail);
    			break;
    		}
    	}
    }
}

void GetOutputPowerSwitchStatusCallback(byte address, unsigned char value)
{
    for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++)
    {
    	for (byte index = 0; index < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; index++)
    	{
    		if (ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PhysicalID == address)
    		{
    			//printf("PowerSwitch = %d, group = %d, address = %d \n", value, group, address);
    			if(value){
    			    ShmPsuData->PsuGroup[groupIndex].PsuModule[index].OutputPowerSwitch = 0x00;
    			}else{
    			    ShmPsuData->PsuGroup[groupIndex].PsuModule[index].OutputPowerSwitch = 0x01;
    			}
    			
    			break;
    		}
    	}
    }
}

//==========================================
// 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("EvComm (main) : FindChargingInfoData false \n");
				isPass = false;
				break;
			}
		}
	}
	conn_1_count = sizeof(connector_1)/sizeof(connector_1[0]);
	conn_2_count = sizeof(connector_2)/sizeof(connector_2[0]);
}

int main(void)
{
	PRINTF_FUNC("Psu Task boot .... \n");
	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
	GetPsuAddressReq(&GetPsuRequestCallback);
	RefreshSerialNumber(&GetBarCodeCallback);
	RefreshVextAndIavail(&SavePresentModeleVextIavailCallback);
	RefreshMiscInfo(&GetMiscInfoCallback);

	RefreshStatus(&SaveStatusCallback);
	RefreshInputVol(&SavePresentInputVoltageCallback);
	RefreshGetOutput(&SavePresentOutputCallback);
	RefreshAvailableCap(&SaveAvailableCapCallback);
	RefreshOutputPowerSwitch(&GetOutputPowerSwitchStatusCallback);

	// initial object
	InitialPsuData();
	Initialization();
	libInitialize = InitialCommunication();

    byte priorityLow = 1;
    byte isInitialComp = NO;
	//main loop
	while (libInitialize)
	{
		// �_�q���A
		if (ShmSysConfigAndInfo->SysInfo.AcContactorStatus == NO)
		{
			//�@�� AC Off PSU �_�q������ PSU Group ID �|�����M 0
			if (!isInitialComp)
			{
				InitialPsuData();
				ShmPsuData->Work_Step = ASSIGN_START;
				isInitialComp = YES;
			}
			sleep(1);
			continue;
		}
		else
			isInitialComp = NO;

		// update psu fw req
//		if(psu update req ?)
//		{
//
//			continue;
//		}

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

		switch(ShmPsuData->Work_Step)
		{
			case ASSIGN_START:
			{
				PRINTF_FUNC("== PSU == ASSIGN_COMP \n");
				sleep(5);
				gettimeofday(&_id_assign_time, NULL);
				ShmPsuData->Work_Step = ASSIGN_COMP;
			}
				break;
			case ASSIGN_COMP:
			{
				if (priorityLow == 1)
				{
					//�p�G�٥����o�Ҳռƶq
					if(ShmPsuData->SystemPresentPsuQuantity == 0)
					{
						EnableDipAddrMode();
						usleep(cmdDelayTime);
				        //�o�e���o�ثe�����Ҳռƶq (�^�����}�����������Ҳդ��۳q�T)
				        RequestModuleTotalMumbert();
				        usleep(cmdDelayTime);
					}
					//�v���o�Ҳռƶq (�ثe�٥����t�s�թҥH���ϥιw�] 0)
					else
					{
				    	for (byte psuIndex = 0;	psuIndex < ShmPsuData->PsuGroup[0].GroupPresentPsuQuantity;	psuIndex++)
				    	{
				            //get status
				    		GetStatus(0, NONE_CARE_ADDRESS);
				    		usleep(cmdDelayTime);
				            //get barcode & ver
				    		GetSerialNumber(0, NONE_CARE_ADDRESS);
				    		usleep(cmdDelayTime);

				    		GetMiscInfo(0, NONE_CARE_ADDRESS, MISC_REQCMD_DC_BOARD_TMP);
				    		usleep(cmdDelayTime);
				    		GetMiscInfo(0, NONE_CARE_ADDRESS, MISC_REQCMD_PFC_BOARD_TMP);
				    		usleep(cmdDelayTime);
				    		GetMiscInfo(0, NONE_CARE_ADDRESS, MISC_REQCMD_PFC_BOARD_TMP);
				    		usleep(cmdDelayTime);
				    	}
					}
					//printf("Get Misc2 : %d \n",InfyPwrModelVerIs109);
				}

				priorityLow >= 20 ? priorityLow = 1 : priorityLow++;
				// ���� 10 ��
				if (GetTimeoutValue(_id_assign_time) >= 10000000)
				{
					ShmPsuData->Work_Step = ENABLE_POW;
					PRINTF_FUNC("INFYPWR Num = %d \n", ShmPsuData->SystemPresentPsuQuantity);
					PRINTF_FUNC("== PSU == ENABLE_POW \n");
				}
			}
				break;
			case ENABLE_POW:
			{
				if (ShmSysConfigAndInfo->SysInfo.BootingStatus == BOOTTING)
				{
					// �q�Φb Booting �����A - ����
					PRINTF_FUNC("== PSU == _TEST_LINE_STEP \n");
					ShmPsuData->Work_Step = _TEST_LINE_STEP;
				}
				else
				{
					PRINTF_FUNC("== PSU == _WORK_CHARGING \n");
					ShmPsuData->Work_Step = _WORK_CHARGING;
					gettimeofday(&_workModePriority_time, NULL);
				}
			}
				break;
			case _TEST_LINE_STEP:
			{
				PRINTF_FUNC("cur total psu count = %d \n", ShmPsuData->SystemPresentPsuQuantity);
				if (ShmPsuData->PsuGroup[0].GroupPresentPsuQuantity <= 0)
				{
					sleep(1);
					// ��ܿ��~
					ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuNoResource = YES;
					continue;
				}

				ShmPsuData->Work_Step = _TEST_POWER_STEP;
			}
				break;
			case _TEST_POWER_STEP:
			{
				if(!_chkTotalCapStart)
				{
					_chkTotalCapStart = true;
					gettimeofday(&_chk_cap_time, NULL);
				}

				// ��l�ơB�����Ҧ����Ҷ�
				//EnableOutputPower(0, NONE_CARE_ADDRESS, SWITCH_OFF);
				for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++)
				{
					GetStatus(groupIndex, NONE_CARE_ADDRESS);
					usleep(cmdDelayTime);
				}

				for (byte psuCount = 0; psuCount < ShmPsuData->SystemPresentPsuQuantity; psuCount++)
				{
					GetAvailableCap(psuCount, NONE_CARE_ADDRESS,  0);
				}

				usleep(cmdDelayTime);
				if (GetTimeoutValue(_chk_cap_time) >= 2000000)
				{
					PRINTF_FUNC("AvailableChargingCurrent = %f, AvailableChargingPower = %f \n",
							chargingInfo[0]->AvailableChargingCurrent, chargingInfo[0]->AvailableChargingPower);
					for (byte index = 0; index < ShmPsuData->PsuGroup[0].GroupPresentPsuQuantity; index++)
					{
						PRINTF_FUNC("index = %d, fire index = %d, phy addr = %d \n",
								index, recordPsuData[index]._fire_index, recordPsuData[index]._phy_addr);
					}

					PRINTF_FUNC("== PSU == TEST_COMPLETE \n");
					ShmPsuData->Work_Step = _TEST_COMPLETE;
				}
			}
				break;
			case _TEST_COMPLETE:
			{
			    priorityLow = 1;
				sleep(1);
			}
				break;
			case _WORK_CHARGING:
			{
				int time = GetTimeoutValue(_workModePriority_time) / 1000;
				//printf("GroupCount = %d \n", ShmPsuData->GroupCount);
				//printf("cur total psu count = %d \n", ShmPsuData->SystemPresentPsuQuantity);

				// ������t : �ˬd�Ӻj�O�_���Ҷ����ΡA���h�L�����s���t�����i�J�R�q
				if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_PREPARE)
				{
					if (ShmPsuData->PsuGroup[ShmSysConfigAndInfo->SysInfo.CurGunSelected].GroupPresentPsuQuantity > 0)
					{
						PRINTF_FUNC("=============Smart Charging : _REASSIGNED_NONE============= Step 0 \n");
						ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_NONE;
					}
					else
					{
						PRINTF_FUNC("=============Smart Charging : _REASSIGNED_GET_NEW_CAP============= Step 2 \n");
						ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_GET_NEW_CAP;
					}
				}

				if (time > 1000)
				{
					for (byte psuCount = 0; psuCount < ShmPsuData->GroupCount; psuCount++)
					{
						GetAvailableCap(psuCount, NONE_CARE_ADDRESS,  0);
					}
					usleep(cmdDelayTime);
				}

				for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++)
				{
					if (time > 1000)
					{
						GetStatus(groupIndex, NONE_CARE_ADDRESS);
						usleep(cmdDelayTime);
					    /*
    					GetMiscInfo(SET_GROUP_CMD, 0, MISC_REQCMD_DC_BOARD_TMP);
    					usleep(cmdDelayTime);
    					GetMiscInfo(SET_GROUP_CMD, 0, MISC_REQCMD_PFC_BOARD_TMP);
    					usleep(cmdDelayTime);
    					GetMiscInfo(SET_GROUP_CMD, 0, MISC_REQCMD_PFC_BOARD_TMP);
    					usleep(cmdDelayTime);
    					*/
//						if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_GET_NEW_CAP)
//						{
//							if (groupIndex != ShmSysConfigAndInfo->SysInfo.CurGunSelected)
//							{
//								if (chargingInfo[groupIndex]->SystemStatus >= S_CHARGING &&	chargingInfo[groupIndex]->SystemStatus <= S_COMPLETE)
//								{
//									if (chargingInfo[groupIndex]->DeratingChargingCurrent < chargingInfo[groupIndex]->AvailableChargingCurrent)
//									{
//										// ���ݻݨD�q�y���C�ܭ������q�y
//										PRINTF_FUNC("Smart Charging : index = %d, EvBatterytargetCurrent = %f, DeratingChargingCurrent = %f \n",
//										groupIndex, chargingInfo[groupIndex]->EvBatterytargetCurrent, chargingInfo[groupIndex]->DeratingChargingCurrent);
//
//										if ((chargingInfo[groupIndex]->EvBatterytargetCurrent <= chargingInfo[groupIndex]->DeratingChargingCurrent) ||
//											deratingKeepCount >= DERATING)
//										{
//											// ���ݭ�������
//											PRINTF_FUNC("=============Smart Charging : _REASSIGNED_MAIN============= Step 3 \n");
//											ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_MAIN;
//										}
//										else
//										{
//											deratingKeepCount++;
//										}
//									}
//								}
//							}
//						}
//						else
//							deratingKeepCount = 0;
//
//						if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_MAIN)
//						{
//							PRINTF_FUNC("=============Smart Charging : _REASSIGNED_ADJUST============= Step 4 \n");
//							//���s���t�Ҳ�
//							ReAssignedResource();
//							gettimeofday(&_derating_time, NULL);
//							ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_ADJUST;
//						}

						gettimeofday(&_workModePriority_time, NULL);
					}

					GetPresentOutput(groupIndex, NONE_CARE_ADDRESS);
					usleep(cmdDelayTime);
					//GetVextAndIavail(SET_MODULE_CMD, 0);

					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 (chargingInfo[groupIndex]->FireChargingVoltage > 0 &&
							evseOutVol != chargingInfo[groupIndex]->FireChargingVoltage)
					{
						evseOutVol = chargingInfo[groupIndex]->FireChargingVoltage;
						PRINTF_FUNC("groupIndex = %d, evse output vol = %f \n", groupIndex,	chargingInfo[groupIndex]->FireChargingVoltage);
					}

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

					// �w��U�j���e���A�A�ǰe�ݭn�^�Ǫ���ƫ��O
					if (((chargingInfo[groupIndex]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[groupIndex]->SystemStatus <= S_CHARGING) && chargingInfo[groupIndex]->RelayK1K2Status) ||
							chargingInfo[groupIndex]->SystemStatus == S_REASSIGN ||
							(chargingInfo[groupIndex]->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingInfo[groupIndex]->SystemStatus <= S_CCS_PRECHARGE_ST1))
					{
						if (ShmPsuData->PsuGroup[groupIndex].GroupAvailableCurrent > 0)
						{
//							if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_ADJUST &&
//									ShmSysConfigAndInfo->SysInfo.ReAssignedFlag < _REASSIGNED_COMP )
//							{
//								// �p�G���ݭn�D���q�y�W�L�����A�h�H�����q�y���D
//								if (chargingInfo[groupIndex]->EvBatterytargetCurrent >= chargingInfo[groupIndex]->DeratingChargingCurrent)
//								{
//									chargingInfo[groupIndex]->EvBatterytargetCurrent = chargingInfo[groupIndex]->DeratingChargingCurrent;
//								}
//
//								if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_ADJUST)
//								{
//									deratingTime = GetTimeoutValue(_derating_time) / 1000;
//									if (deratingTime > 3000)
//									{
//										deratingTime = 0;
//										PRINTF_FUNC("=============Smart Charging : _REASSIGNED_RELAY============= Step 5 \n");
//										ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_RELAY;
//									}
//
//									for(int i = 0; i < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; i++)
//									{
//										PRINTF_FUNC("*********_REASSIGNED_ADJUST : groupIndex = %d, outputCur = %d, outputVol = %d \n",
//											groupIndex,
//										ShmPsuData->PsuGroup[groupIndex].PsuModule[i].PresentOutputCurrent,
//										ShmPsuData->PsuGroup[groupIndex].PsuModule[i].PresentOutputVoltage);
//									}
//								}
//
//								// �ӥR�q�j���ؼйq���P�ؼйq�y
//								SetPresentOutput(groupIndex, NONE_CARE_ADDRESS,
//										chargingInfo[groupIndex]->EvBatterytargetVoltage,
//										chargingInfo[groupIndex]->EvBatterytargetCurrent,
//										chargingInfo[groupIndex]->DeratingChargingCurrent);
//								usleep(cmdDelayTime);
//							}
//							else
							{
								// �ӥR�q�j���ؼйq���P�ؼйq�y
								SetPresentOutput(groupIndex, NONE_CARE_ADDRESS,
										chargingInfo[groupIndex]->EvBatterytargetVoltage,
										chargingInfo[groupIndex]->EvBatterytargetCurrent,
										chargingInfo[groupIndex]->AvailableChargingCurrent);
								usleep(cmdDelayTime);
							}
						}

						if (chargingInfo[groupIndex]->EvBatterytargetVoltage == 0)
						{
							EnableOutputPower(groupIndex, NONE_CARE_ADDRESS, SWITCH_OFF);
							usleep(cmdDelayTime);
							EnableGreenLedFlash(groupIndex , NONE_CARE_ADDRESS , SWITCH_OFF);
							usleep(cmdDelayTime);
						}
						else
						{
							EnableOutputPower(groupIndex, NONE_CARE_ADDRESS, SWITCH_ON);
							usleep(cmdDelayTime);
							EnableGreenLedFlash(groupIndex , NONE_CARE_ADDRESS, SWITCH_ON);
							usleep(cmdDelayTime);
						}
					}
					else if (chargingInfo[groupIndex]->SystemStatus >= S_TERMINATING &&
							chargingInfo[groupIndex]->SystemStatus <= S_COMPLETE)
					{
						SetPresentOutput(groupIndex, NONE_CARE_ADDRESS, ZERO_VOL, ZERO_CUR, chargingInfo[groupIndex]->AvailableChargingCurrent);
						usleep(cmdDelayTime);
						EnableGreenLedFlash(groupIndex , NONE_CARE_ADDRESS , SWITCH_OFF);
						usleep(cmdDelayTime);
						EnableOutputPower(groupIndex, NONE_CARE_ADDRESS, SWITCH_OFF);
						usleep(cmdDelayTime);
					}
				}
				priorityLow >= 200 ? priorityLow = 1 : priorityLow++;
				break;
			}
		}
	}
	return FAIL;
}