#include 	"Module_PsuComm.h"

#define ARRAY_SIZE(A)		(sizeof(A) / sizeof(A[0]))
#define PASS				1
#define FAIL				-1
#define YES					1
#define NO					0
#define DERATING_COUNT		30
#define DERATING_GAP		30
#define ELEMENT_NOT_FIND	255
#define CHK_VOL_RANGE		50
#define CHK_CUR_RANGE		10
#define DERATING_RANGE		100
#define ZERO_CURRENT		10			// �ӭȶ��O���̤p�� 1A
#define ZERO_VOLTAGE		50
#define STOP_CURRENT		30
#define PSU_MIN_CUR			1000
#define PSU_MIN_VOL			1500
#define PRE_CHARG_STEP_CUR	30
#define PRE_CHARG_RANGE		50
#define EQUAL				0
#define CMD_DELAY_TIME 		25000
#define LOG_VOL_GAP			50
#define LOG_CUR_GAP			5
#define PSU_MIN_OUTPUT_CUR	1

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

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

byte startModuleFlag = false;

float chargingOutputLogInfo[2][4];

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);

	if (ShmSysConfigAndInfo->SysConfig.SwitchDebugFlag == YES)
	{
		sprintf(Buf,"%02d:%02d:%02d:%03d - %s",
			tm->tm_hour,tm->tm_min,tm->tm_sec,SeqEndTime.millitm, buffer);
		printf("%s \n", Buf);
	}
	else
	{
		sprintf(Buf,"echo \"%04d-%02d-%02d %02d:%02d:%02d:%03d - %s\" >> /Storage/SystemLog/[%04d.%02d]SystemLog_%s",
			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,
			ShmSysConfigAndInfo->SysConfig.SerialNumber);
		system(Buf);
	}

	return rc;
}

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

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

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

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

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

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

	return _group;
}

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

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

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

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

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

	return false;
}

//=================================
// Alarm code mapping to share memory Function
//=================================
// �ˬ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(i)
				{
					case 0:
					{
						if (bitIndex == 0)
							ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuOutputShortCircuit = YES;
						else if (bitIndex == 5)
							ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = YES;
					}
						break;
				case 1:
					{
						if (bitIndex == 1)
							ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFailureAlarm = YES;
						else if (bitIndex == 2)
							ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuProtectionAlarm = YES;
						else if (bitIndex == 3)
							ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFanFailureAlarm = YES;
						else if (bitIndex == 4)
							ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuCriticalPointOTP = YES;
						else if (bitIndex == 5)
							ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = YES;
					}
					break;
				case 2:
					{
						if (bitIndex == 0)
							ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuPowerLimitedState = YES;
						else if (bitIndex == 1)
							ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDuplicateID = YES;
						else if (bitIndex == 2)
							ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseOnputImbalance = YES;
						else if (bitIndex == 3)
							ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseInputInadequate = YES;
						else if (bitIndex == 4)
							ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseInputInadequate = YES;
						else if (bitIndex == 5)
							ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputUVP = YES;
						else if (bitIndex == 6)
							ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputOVP = YES;
					}
					break;
				}
			}
//			else
//			{
//				switch (byteIndex) {
//				case 0: {
//					if (bitIndex == 0)
//						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuOutputShortCircuit = NO;
//					else if (bitIndex == 5)
//						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = NO;
//				}
//					break;
//				case 1: {
//					if (bitIndex == 1)
//						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFailureAlarm = NO;
//					else if (bitIndex == 2)
//						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuProtectionAlarm = NO;
//					else if (bitIndex == 3)
//						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFanFailureAlarm = NO;
//					else if (bitIndex == 4)
//						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuCriticalPointOTP = NO;
//					else if (bitIndex == 5)
//						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = NO;
//				}
//					break;
//				case 2: {
//					if (bitIndex == 1)
//						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDuplicateID = NO;
//					if (bitIndex == 2)
//						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseOnputImbalance = NO;
//					else if (bitIndex == 3)
//						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseInputInadequate = NO;
//					else if (bitIndex == 4)
//						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseInputInadequate = NO;
//					else if (bitIndex == 5)
//						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputUVP = NO;
//					else if (bitIndex == 6)
//						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputOVP = NO;
//				}
//					break;
//				}
//			}
		}
	}
}

//=================================
// Callback Function
//=================================
// no using -- GetOutputAndTempCallback
void GetStatusCallback(byte group, byte SN, byte temp, int alarm)
{
	bool isFind = false;

	if ((conn_1_count + conn_2_count) != ShmPsuData->SystemPresentPsuQuantity)
	{
		if (group == 0)
		{
			for(byte psuIndex = 0; psuIndex < conn_1_count; psuIndex++)
			{
				if (connector_1[psuIndex] == SN)
				{
					isFind = true;
					break;
				}
			}

			if(!isFind)
			{
				connector_1[conn_1_count] = SN;
				conn_1_count++;
			}
		}
		else if (group == 1)
		{
			for(byte psuIndex = 0; psuIndex < conn_2_count; psuIndex++)
			{
				if (connector_2[psuIndex] == SN)
				{
					isFind = true;
					break;
				}
			}

			if(!isFind)
			{
				connector_2[conn_2_count] = SN;
				conn_2_count++;
			}
		}
	}

	if ((conn_1_count + conn_2_count) == ShmPsuData->SystemPresentPsuQuantity)
	{
		// Arrangment
		for(byte psuIndex = 0; psuIndex < conn_1_count; psuIndex++)
		{
			connector_1[psuIndex] = psuIndex;
		}

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

		for(byte psuIndex = 0; psuIndex < conn_1_count; psuIndex++)
			PRINTF_FUNC("DC Left Gun - PSU Number = %d \n", connector_1[psuIndex]);

		for(byte psuIndex = 0; psuIndex < conn_2_count; psuIndex++)
			PRINTF_FUNC("DC Right Gun - PSU Number = %d \n", connector_2[psuIndex]);

		if (ShmSysConfigAndInfo->SysConfig.TotalConnectorCount > 1)
		{
			// ���j�~�ݭn�Ҽ{�O�_�Ҷ� switch �����F
			char EvsePower[2];
			byte maxCount = 0;
			int power = 0;

			EvsePower[2] = '\0';
			if (strlen((char *) ShmSysConfigAndInfo->SysConfig.ModelName) >= 6)
			{
				strncpy(EvsePower, (char *)(ShmSysConfigAndInfo->SysConfig.ModelName + 4), 2);
				power = atoi(EvsePower);
			}

			// �W�L 90 KW �� 360 KW
			if (power < 30 || power == 36)
				power *= 10;

			maxCount = ((power / 30) + 1) / 2;

			if (conn_1_count > maxCount ||
					conn_2_count > maxCount)
			{
				ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDipSwitchStestFail = YES;
			}
		}
	}
}
// no using -- GetOutputAndTempCallback End

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

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

	//unsigned short maxCurrent = ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent * 10;
	unsigned short maxCurrent = ShmPsuData->SystemAvailableCurrent;
	//unsigned short maxPower = ShmSysConfigAndInfo->SysConfig.MaxChargingPower * 10;
	unsigned short maxPower = ShmPsuData->SystemAvailablePower;

	if (ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent * 10 != 0 &&
			ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent * 10 < maxCurrent)
		maxCurrent = ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent * 10;

	if (ShmSysConfigAndInfo->SysConfig.MaxChargingPower * 10 != 0 &&
			ShmSysConfigAndInfo->SysConfig.MaxChargingPower * 10 < maxPower)
		maxPower = ShmSysConfigAndInfo->SysConfig.MaxChargingPower * 10;

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

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

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

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

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

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

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

	if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX)
	{
		for (byte groupIndex = 0; groupIndex < _gunCount; groupIndex++)
		{
			if (chargingInfo[groupIndex]->EvBatteryMaxVoltage > 0)
			{
				_chargingVol = chargingInfo[groupIndex]->EvBatteryMaxVoltage;
				_targetVol = chargingInfo[groupIndex]->EvBatterytargetVoltage;
				break;
			}
		}
	}

//	PRINTF_FUNC("group = %d, DeratingChargingCurrent = %f, RealRatingPower = %d \n",
//					group, chargingInfo[group]->DeratingChargingCurrent, chargingInfo[group]->RealRatingPower);

	if (chargingInfo[group]->DeratingChargingCurrent == 0)
	{
		// �b�٨S���o�u���i��X���q�y�e�A�̷� GFD ���q�o�쪺�u�� POWER / �Ҷ��Ӽ� / ���l�q���̤j�q��
		if (ShmPsuData->PsuGroup[group].GroupRealOutputPower > 0 && _chargingVol > 0)
		{
//			printf("GroupRealOutputPower = %d, GroupPresentPsuQuantity = %d\n",
//					ShmPsuData->PsuGroup[group].GroupRealOutputPower,
//					ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity);

			ShmPsuData->PsuGroup[group].PsuModule[address].AvailableCurrent =
					((ShmPsuData->PsuGroup[group].GroupRealOutputPower / ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity) * 1000 / (int)_chargingVol) * 10;

//			PRINTF_FUNC(" *1* AvailableCurrent = %d \n",
//				ShmPsuData->PsuGroup[group].PsuModule[address].AvailableCurrent);
		}
		else
		{
			// �`�@ : ����Ҷ��̤j��X��O (���� Derating ���A)�A�ҥH�o��ݭn�����ڥi��X���q�y
			if (ShmPsuData->PsuGroup[group].PsuModule[address].AvailableCurrent <= 0)
				ShmPsuData->PsuGroup[group].PsuModule[address].AvailableCurrent = PSU_MIN_CUR;

//			PRINTF_FUNC(" *2* group = %d, AvailableCurrent = %d \n",
//				group, ShmPsuData->PsuGroup[group].PsuModule[address].AvailableCurrent);
		}
//		PRINTF_FUNC("group = %d, address = %d, AvailableCurrent = %d \n",
//				group, address, ShmPsuData->PsuGroup[group].PsuModule[address].AvailableCurrent);
	}
	else
	{
		ShmPsuData->PsuGroup[group].PsuModule[address].AvailableCurrent = maxCur;
	}

	ShmPsuData->PsuGroup[group].PsuModule[address].AvailablePower = totalPow;
	// �`�M�� Group ���i��X�q�y
	for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++)
	{
		_groupCurrent += ShmPsuData->PsuGroup[group].PsuModule[index].AvailableCurrent;
		_groupPower += ShmPsuData->PsuGroup[group].PsuModule[index].AvailablePower;
	}

	// �U�s�o��̤j��X��O (�q�y�BPower)
	ShmPsuData->PsuGroup[group].GroupAvailableCurrent = _groupCurrent;
	ShmPsuData->PsuGroup[group].GroupAvailablePower = _groupPower;

	chargingInfo[group]->MaximumChargingVoltage = maxVol;

	int _power = 0, _current = 0, _ratingcurrent = 0, _sysRealPower = 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;
		_sysRealPower += ShmPsuData->PsuGroup[index].GroupRealOutputPower;
		if (ShmPsuData->PsuGroup[index].GroupPresentOutputVoltage >= PSU_MIN_VOL &&
				chargingInfo[index]->DeratingChargingCurrent == 0)
			isGetAllDeratingCurrent = false;
	}

	// �p�G���O�Ҧ��s���o�� Derating current�A�h�����ļ˸Ӧ��� ratingCurrent
	if (!isGetAllDeratingCurrent) _ratingcurrent = 0;
	// �]���`�@�A���קK�@�ȧ��ܳq�����l�q�γ̤j�i��X�q�y�Ұ�������
	// �Ӧ]�� rating value �@�볣�|�p��Ҷ����̤j�i��X�q�y
	// �ҥH�p�G�ӭȤj��b�`�@�ҭ����X�q�y�A�h�H���Ȭ��D
	if (_ratingcurrent != 0) _current = _ratingcurrent;

	//printf("=============== _current ==================== %d \n", _current);
	//printf("=============== _ratingcurrent ==================== %d \n", _ratingcurrent);
	if (ShmSysConfigAndInfo->SysInfo.BootingStatus == BOOTTING)
	{
		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;
		int gpRealPow = ShmPsuData->PsuGroup[group].GroupRealOutputPower;

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

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

//		if ((ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_GET_NEW_CAP &&
//				 ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A))
//		{
//			chargingInfo[group]->AvailableChargingCurrent =	DERATING_RANGE;
//			chargingInfo[group]->AvailableChargingPower = ShmPsuData->PsuGroup[group].GroupAvailablePower;
//		}
//		else
		{
			// �H�U���p -> �j��T�����̤j��X��O�A���Ӹs����X��O
			// 1. �p���O�̤j�R
			// 2. ������������R�L�{
			chargingInfo[group]->AvailableChargingCurrent =	halfCur;
			chargingInfo[group]->AvailableChargingPower = halfPow;
			chargingInfo[group]->RealRatingPower = gpRealPow;

			if(chargingInfo[group]->DeratingChargingCurrent > 0)
			{
				unsigned short _powBuf = 0;
				_powBuf = ((chargingInfo[group]->DeratingChargingCurrent / 10) * ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage / 10) / 1000; // ���O KW

				if (_powBuf > ShmPsuData->PsuGroup[group].GroupRealOutputPower ||
						chargingInfo[group]->EvBatterytargetVoltage > 0)
				{
					ShmPsuData->PsuGroup[group].GroupRealOutputPower = _powBuf;
//					PRINTF_FUNC("group = %d, DeratingChargingCurrent = %f, RealRatingPower = %d \n",
//								group, chargingInfo[group]->DeratingChargingCurrent, chargingInfo[group]->RealRatingPower);
				}
			}
			//printf("(Aver.) RealRatingPower = %d \n", chargingInfo[group]->RealRatingPower);
		}
	}
	else if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX)
	{
		//PRINTF_FUNC("group = %d, Final = %d \n", group, _current);
		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;
				chargingInfo[count]->RealRatingPower = _sysRealPower;
			}
		}
		else
		{
			// �p�G�O�̤j�R�A�Ӻj��T������X��O���U�s��X��O���M
			chargingInfo[group]->AvailableChargingCurrent =	_current;
			chargingInfo[group]->AvailableChargingPower = _power;
			chargingInfo[group]->RealRatingPower = _sysRealPower;
		}

		if(chargingInfo[group]->DeratingChargingCurrent > 0)
		{
			unsigned short _powBuf = 0;
			_powBuf = ((chargingInfo[group]->DeratingChargingCurrent / 10) * ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage / 10) / 1000; // ���O KW

			if (_powBuf > ShmPsuData->PsuGroup[group].GroupRealOutputPower ||
					chargingInfo[group]->EvBatterytargetVoltage > 0 ||
					_targetVol > 0)
			{
				ShmPsuData->PsuGroup[group].GroupRealOutputPower = _powBuf;
			}
		}
	}
}

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

	if (IsOverModuleCount(address))
		return;

	byte group = FindTargetGroup(address);

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

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

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

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

//	// PSU Group - �q��
//	ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage = outVol;
//	// PSU Group - �q�y
//	ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent = outCur;
//
//	if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX ||
//			(ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER &&
//			(ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_WAITING &&
//			ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_COMP))
//		)
//	{
//		unsigned short outputVol = 0;
//		unsigned short outputCur = 0;
//
//		for (byte index = 0; index < ShmPsuData->GroupCount; index++)
//		{
//			bool needtoAdd = true;
//
//			if (ShmPsuData->PsuGroup[index].GroupPresentOutputVoltage > outputVol)
//				outputVol = ShmPsuData->PsuGroup[index].GroupPresentOutputVoltage;
//
//			if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_ADJUST_M_TO_A &&
//					ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A)
//			{
////				PRINTF_FUNC("Gp_%d, DividChargingCurrent = %d \n", index,
////						chargingInfo[index]->DividChargingCurrent);
//				if (chargingInfo[index]->DividChargingCurrent == 0)
//					needtoAdd = false;
//			}
//
//			if (needtoAdd)
//				outputCur += ShmPsuData->PsuGroup[index].GroupPresentOutputCurrent;
//		}
//
//		// �¥վ�
//		if (ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf == YES)
//		{
//			for (byte count = 0; count < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; count++)
//			{
//				float _vol_buf = outputVol;
//				float _cur_buf = outputCur;
//
//				// EVSE - �q��
//				_vol_buf /= 10;
//				chargingInfo[count]->PresentChargingVoltage = _vol_buf;
//				// EVSE - �q�y
//				_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 - �q��
//			_vol_buf /= 10;
//			chargingInfo[group]->PresentChargingVoltage = _vol_buf;
//			// EVSE - �q�y
//			_cur_buf /= 10;
//			chargingInfo[group]->PresentChargingCurrent = _cur_buf;
//		}
//	}
//	else
//	{
//		float _vol_buf = ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage;
//		float _cur_buf = ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent;
//
//		// EVSE - �q��
//		_vol_buf /= 10;
//		chargingInfo[group]->PresentChargingVoltage = _vol_buf;
//		// EVSE - �q�y
//		_cur_buf /= 10;
//		chargingInfo[group]->PresentChargingCurrent = _cur_buf;
//	}
//
//	PRINTF_FUNC("Gun_%d, PresentChargingVoltage = %f, PresentChargingCurrent = %f \n", group,
//			chargingInfo[group]->PresentChargingVoltage,
//			chargingInfo[group]->PresentChargingCurrent);
}
// no using -- GetOutputAndTempCallback End

void GetMisCallback(byte address, unsigned int value, byte type)
{
	if (ShmPsuData->Work_Step < GET_SYS_CAP)
		return;

	if (IsOverModuleCount(address))
		return;

	byte group = FindTargetGroup(address);

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

	if (type == 1)
	{
		ShmPsuData->PsuGroup[group].PsuModule[address].FanSpeed_1 = value;
		ShmPsuData->PsuGroup[group].PsuModule[address].FanSpeed_2 = value;
		ShmPsuData->PsuGroup[group].PsuModule[address].FanSpeed_3 = value;
		ShmPsuData->PsuGroup[group].PsuModule[address].FanSpeed_4 = value;
	}
	else if (type == 2)
	{
		//printf("DC - group = %d, index = %d, value = %d \n", group, address, value);
//		ShmPsuData->PsuGroup[group].PsuModule[address].CriticalTemp1 = value;
//		ShmPsuData->PsuGroup[group].PsuModule[address].CriticalTemp2 = value;
//		ShmPsuData->PsuGroup[group].PsuModule[address].CriticalTemp3 = value;
		ShmPsuData->PsuGroup[group].PsuModule[address].ExletTemp = value;
	}
	else if (type == 3)
	{
		printf("PFC - group = %d, index = %d, value = %d \n", group, address, value);
	}
}

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

	if (IsOverModuleCount(address))
		return;

	// �g�� 0.1
	//ShmPsuData->PsuGroup[address].GroupTargetOutputVoltage = Vext;
	//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;
	byte sampleCount = 8;

	if (Iavail == 0)
	{
		for (byte count = 0; count < sampleCount; count++)
		{
			chargingInfo[group]->SampleChargingCur[count] = Iavail;
		}
	}
	else
	{
		// �Ӹs���i��X�q�y
		for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++)
		{
			totalCur += ShmPsuData->PsuGroup[group].PsuModule[index].IAvailableCurrent;
		}

		for (byte count = 0; count < sampleCount; 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)
	{
//		if (totalCur != 0)
//				PRINTF_FUNC("group = %d, rating pass value = %d \n", group, totalCur);

		chargingInfo[group]->DeratingChargingCurrent = totalCur;
	}
}

void GetPresentOutputFCallback(byte group, float outVol, float outCur)
{
	// isinf : -1 = �t�L�a�A1 = ���L�a�A0 = ��L
	if (isinf(outVol) == 0)
		ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage = (unsigned short)(outVol * 10);
	else
		ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage = 0;

	if (isinf(outCur) == 0)
		ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent = (unsigned short)(outCur * 10);
	else
		ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent = 0;

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

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

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

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

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

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

			if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_ADJUST_M_TO_A &&
					ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A)
			{
				if (chargingInfo[_maxTOaver]->DividChargingCurrent != 0)
				{
					float _cur_buf = outputCur;
					_cur_buf /= 10;
					chargingInfo[_maxTOaver]->PresentChargingCurrent = _cur_buf;
				}
			}

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

					// EVSE - �q��
					_vol_buf /= 10;
					chargingInfo[count]->PresentChargingVoltage = _vol_buf;

					_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) ||
					chargingInfo[group]->SystemStatus == S_ALARM)
			{
				float _vol_buf = outputVol;
				float _cur_buf = outputCur;

				// EVSE - �q��
				_vol_buf /= 10;
				chargingInfo[group]->PresentChargingVoltage = _vol_buf;

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

			// EVSE - �q��
			_vol_buf /= 10;
			chargingInfo[group]->PresentChargingVoltage = _vol_buf;

			_cur_buf /= 10;
			chargingInfo[group]->PresentChargingCurrent = _cur_buf;
		}
}

//==========================================
// �S�W���O
//==========================================
void GetOutputAndTempCallback(byte address, unsigned short outputVol_s,
		unsigned short outputCur_s, unsigned short outputPower, unsigned char Temperature)
{
	if (ShmPsuData->Work_Step < GET_SYS_CAP)
		return;

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

	if (IsOverModuleCount(address))
		return;

	byte group = FindTargetGroup(address);

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

//	// PSU Group - �q��
//	ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage = outVol;
//	// PSU Group - �q�y
//	ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent = outCur;
//	// PSU Group - ��q
//	ShmPsuData->PsuGroup[group].GroupPresentOutputPower = outVol * outCur;
//
//	if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX ||
//				(ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER &&
//				(ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_WAITING &&
//				ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_COMP))
//			)
//	{
//		unsigned short outputVol = 0;
//		unsigned short outputCur = 0;
//		unsigned char _maxTOaver = 0;
//
//		for (byte index = 0; index < ShmPsuData->GroupCount; index++)
//		{
//			bool needtoAdd = true;
//
//			if (ShmPsuData->PsuGroup[index].GroupPresentOutputVoltage > outputVol)
//				outputVol = ShmPsuData->PsuGroup[index].GroupPresentOutputVoltage;
//
////			if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_ADJUST_M_TO_A &&
////					ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A)
////			{
////				if (chargingInfo[index]->DividChargingCurrent == 0)
////					needtoAdd = false;
////				else
////					_maxTOaver = index;
////			}
//
//			if (needtoAdd)
//				outputCur += ShmPsuData->PsuGroup[index].GroupPresentOutputCurrent;
//		}
//
//		if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_ADJUST_M_TO_A &&
//				ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A)
//		{
//			if (chargingInfo[_maxTOaver]->DividChargingCurrent != 0)
//			{
//				float _cur_buf = outputCur;
//				_cur_buf /= 10;
//				chargingInfo[_maxTOaver]->PresentChargingCurrent = _cur_buf;
//			}
//		}
//
//		// �¥վ�
//		if (ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf == YES)
//		{
//			for (byte count = 0; count < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; count++)
//			{
//				float _vol_buf = outputVol;
//				float _cur_buf = outputCur;
//
//				// EVSE - �q��
//				_vol_buf /= 10;
//				chargingInfo[count]->PresentChargingVoltage = _vol_buf;
//
//				_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 - �q��
//			_vol_buf /= 10;
//			chargingInfo[group]->PresentChargingVoltage = _vol_buf;
//
//			_cur_buf /= 10;
//			chargingInfo[group]->PresentChargingCurrent = _cur_buf;
//		}
//	}
//	else
//	{
//		float _vol_buf = ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage;
//		float _cur_buf = ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent;
//
//		// EVSE - �q��
//		_vol_buf /= 10;
//		chargingInfo[group]->PresentChargingVoltage = _vol_buf;
//
//		_cur_buf /= 10;
//		chargingInfo[group]->PresentChargingCurrent = _cur_buf;
//	}

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

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

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

	if (IsOverModuleCount(address))
		return;

	byte group1 = FindTargetGroup(address);

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

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

	ShmPsuData->PsuGroup[group1].PsuModule[address].AlarmCode = alarm;
	//AbnormalStopAnalysis(group1, alarm);
}

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

	if (IsOverModuleCount(address))
		return;

	byte group = FindTargetGroup(address);

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

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

	//PRINTF_FUNC("***Input*** address = %d, R = %d, S = %d, T = %d \n",
	//		address, inputR, inputS, inputT);
}

//==========================================
// Init all share memory
//==========================================
int InitShareMemory()
{
	int result = PASS;
	int MeterSMId;

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

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

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

    return result;
}

//================================================
// Log function
//================================================
void OutputChargingLogFuncion(byte groupIndex)
{
	// �C�L�ɾ� : �ݨD���ܩο�X�q���P�������t�W�L 5V �Ϊ̿�X�q�y�P�������t�W�L 0.5A
	if (chargingOutputLogInfo[groupIndex][_CHARGING_LOG_NEED_VOL] != chargingInfo[groupIndex]->EvBatterytargetVoltage * 10 ||
			(chargingInfo[groupIndex]->FireChargingVoltage <= chargingOutputLogInfo[groupIndex][_CHARGING_LOG_OUTPUT_VOL] - LOG_VOL_GAP ||
					chargingInfo[groupIndex]->FireChargingVoltage >= chargingOutputLogInfo[groupIndex][_CHARGING_LOG_OUTPUT_VOL] + LOG_VOL_GAP))
	{
		chargingOutputLogInfo[groupIndex][_CHARGING_LOG_NEED_VOL] = chargingInfo[groupIndex]->EvBatterytargetVoltage * 10;
		chargingOutputLogInfo[groupIndex][_CHARGING_LOG_OUTPUT_VOL] = chargingInfo[groupIndex]->FireChargingVoltage;

		PRINTF_FUNC("Conn %d, EV Req Voltage : %.1f, EVSE Output Voltage = %.1f \n", groupIndex,
				chargingOutputLogInfo[groupIndex][_CHARGING_LOG_NEED_VOL] / 10,
				chargingOutputLogInfo[groupIndex][_CHARGING_LOG_OUTPUT_VOL] / 10);
	}

	if (chargingOutputLogInfo[groupIndex][_CHARGING_LOG_NEED_CUR] != chargingInfo[groupIndex]->EvBatterytargetCurrent * 10 ||
			(chargingInfo[groupIndex]->PresentChargingCurrent <= chargingOutputLogInfo[groupIndex][_CHARGING_LOG_OUTPUT_CUR] - LOG_CUR_GAP ||
					chargingInfo[groupIndex]->PresentChargingCurrent >= chargingOutputLogInfo[groupIndex][_CHARGING_LOG_OUTPUT_CUR] + LOG_CUR_GAP))
	{
		chargingOutputLogInfo[groupIndex][_CHARGING_LOG_NEED_CUR] = chargingInfo[groupIndex]->EvBatterytargetCurrent * 10;
		chargingOutputLogInfo[groupIndex][_CHARGING_LOG_OUTPUT_CUR] = chargingInfo[groupIndex]->PresentChargingCurrent;

		PRINTF_FUNC("Conn %d, EV Req Current : %.1f, EVSE Output Current = %.1f \n", groupIndex,
				chargingOutputLogInfo[groupIndex][_CHARGING_LOG_NEED_CUR] / 10,
				chargingOutputLogInfo[groupIndex][_CHARGING_LOG_OUTPUT_CUR]);
	}
}

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

	PRINTF_FUNC("InitialPsuData : PSU Group = %d \n", ShmPsuData->GroupCount);
	for (byte _groupCount = 0; _groupCount < ShmPsuData->GroupCount; _groupCount++)
	{
		ShmPsuData->PsuGroup[_groupCount].GroupPresentPsuQuantity = 0;
		ShmPsuData->PsuGroup[_groupCount].GroupAvailablePower = 0;
		ShmPsuData->PsuGroup[_groupCount].GroupAvailableCurrent = 0;

		chargingInfo[_groupCount]->PresentChargingVoltage = 0;
		chargingInfo[_groupCount]->PresentChargingCurrent = 0;
	}
}

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

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

	ShmPsuData->SystemAvailableCurrent = 0;
	ShmPsuData->SystemAvailablePower = 0;
}

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

				if (canAverageCharging)
				{
					PRINTF_FUNC("======= Only to get the charging side capacity (Step 2) ======= \n");
					ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_GET_NEW_CAP;
				}
				else
				{
					PRINTF_FUNC("=============Smart Charging : _REASSIGNED_NONE============= Step 0 \n");
					ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_NONE;
				}
			}
			else
			{
				PRINTF_FUNC("=============Smart Charging Aver mode : _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("======= To raise voltage of idle module to charing voltage (Step 12) ======= \n");
				preChargingCur = preChargingTarget = 0;
				gettimeofday(&_max_time, NULL);
				ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_ADJUST_A_TO_M;
			}
			else
			{
				PRINTF_FUNC("======= The Change to maximum charge mode is complete. (Step 15) ======= \n");
				ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_COMP;
			}
		}
		else
		{
			PRINTF_FUNC("======= The Change to maximum charge mode is complete. (Step 15) ======= \n");
			ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_COMP;
		}
	}
}

void PreCheckSmartChargingStep()
{
	isCharging = false;
	isWaitingAver = false;
	isReadToCharging = false;
	CanAverageCharging = true;

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

		// ���o�Ҷ���X�B�w�q�y��O
		//GetModuleIavailable(index);

		if (chargingInfo[index]->SystemStatus == S_CHARGING)
		{
			isCharging = true;
			if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_PREPARE_M_TO_A)
			{
				if (toAverVolPoint == (chargingInfo[index]->EvBatterytargetCurrent * 10))
				{
					// ���̤j�R -> ���R�ݭn���ݥR�q������X�q�y�԰���ؼйq�y
//					chargingInfo[index]->PresentChargingCurrent = 60;
//					if ((chargingInfo[index]->PresentChargingCurrent * 10) >=
//							(chargingInfo[index]->EvBatterytargetCurrent * 10) - CHK_CUR_RANGE)
					{
						if (toAverVolCount == 0)
							isWaitingAver = true;
						else
							toAverVolCount--;
					}
				}
				else
				{
					toAverVolPoint = (chargingInfo[index]->EvBatterytargetCurrent * 10);
					toAverVolCount = 3;
				}
			}
			else
			{
				toAverVolPoint = 0;
				toAverVolCount = 3;
			}
		}
		else if (chargingInfo[index]->SystemStatus == S_COMPLETE ||
				chargingInfo[index]->SystemStatus == S_ALARM)
		{
			if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_PREPARE_M_TO_A)
			{
				ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_RELAY_M_TO_A;
			}
		}

		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;
		}

		// ���i�� : �]���q���ޤɹL�{~ �]�O < STOP_CURRENT
//		if (chargingInfo[index]->DeratingChargingCurrent < STOP_CURRENT)
//		{
//			CanAverageCharging = false;
//		}
	}

	CheckSmartChargingStep(isWaitingAver, isCharging, CanAverageCharging);
}

void Await()
{
	usleep(CMD_DELAY_TIME);
}

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);
	RefreshMisInfo(&GetMisCallback);
	RefreshIavailable(&GetIavailableCallback);
	RefreshGetOutputF(&GetPresentOutputFCallback);

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

	sleep(2);
	_gunCount = ShmSysConfigAndInfo->SysConfig.TotalConnectorCount;
	// initial object
	InitialPsuData();
	Initialization();
	libInitialize = InitialCommunication();
    byte isInitialComp = NO;
    if (ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf == YES)
    {
    	PRINTF_FUNC("Alter native mode. \n");
    }

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

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

		switch(ShmPsuData->Work_Step)
		{
			case INITIAL_START:
			{
				PRINTF_FUNC("== PSU == INITIAL_START \n");
				gettimeofday(&_cmdSubPriority_time, NULL);
				sleep(5);
				SwitchPower(SYSTEM_CMD, PSU_POWER_OFF);
				SetWalkInConfig(SYSTEM_CMD, NO, 0);
				for (byte index = 0; index < ShmPsuData->GroupCount; index++)
					isStartOutputSwitch[index] = false;
				ShmPsuData->Work_Step = GET_PSU_COUNT;
			}
				break;
			case GET_PSU_COUNT:
			{
				int time = GetTimeoutValue(_cmdSubPriority_time) / 1000;
				byte moduleCount = 0;

				// �o�e���o�ثe�����Ҳռƶq
				GetModuleCount(SYSTEM_CMD);

				if (time > 2000)
				{
//					if (ShmPsuData->GroupCount == 0)
//						ShmPsuData->GroupCount = ShmSysConfigAndInfo->SysConfig.TotalConnectorCount;
					// ���O���U�s�Ҳռƶq
					for (byte index = 0; index < ShmPsuData->GroupCount; index++)
					{
						// �`�M�U�s�Ҳռƶq
						moduleCount += ShmPsuData->PsuGroup[index].GroupPresentPsuQuantity;

						// ���U�s�Ҳռƶq
						GetModuleCount(index);
					}
					PRINTF_FUNC("== PSU == Connector Count = %d, moduleCount = %d, sysCount = %d\n",
							ShmPsuData->GroupCount, moduleCount, ShmPsuData->SystemPresentPsuQuantity);

					// �P�_�t�μƶq�P�U�s�ƶq�@�P
					if(moduleCount == ShmPsuData->SystemPresentPsuQuantity && moduleCount > 0)
					{
						if (ShmSysConfigAndInfo->SysInfo.BootingStatus == BOOTTING)
						{
							// �q�Φb Booting �����A - ����
							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;
						}
					}

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

				if (time > 500)
				{
					bool isFinish = true;
					for (byte psuCount = 0; psuCount < ShmPsuData->SystemPresentPsuQuantity; psuCount++)
					{
						if (strcmp((char *)ShmPsuData->PsuVersion[psuCount].FwPrimaryVersion, "") == EQUAL ||
								ShmPsuData->SystemAvailablePower <= 0 || ShmPsuData->SystemAvailableCurrent <= 0)
						{
							isFinish = false;
							break;
						}
					}

					if (!isFinish)
					{
						for (byte index = 0; index < ShmPsuData->GroupCount; index++)
						{
							if (psuCmdSeq == _PSU_CMD_STATUS)
							{
								// ���o���A : �䴩�Ҷ��������Ӷ��ǥ\��
								GetStatus(index);
							}
							else if (psuCmdSeq == _PSU_CMD_CAP)
							{
								// ���t���`��X��O
								GetModuleCap(index);
							}
							else if (psuCmdSeq == _PSU_CMD_VERSION)
							{
								// ������
								GetModuleVer(index);
							}
						}

						if (psuCmdSeq == _PSU_CMD_STATUS)
							psuCmdSeq = _PSU_CMD_CAP;
						else if (psuCmdSeq == _PSU_CMD_CAP)
							psuCmdSeq = _PSU_CMD_VERSION;
						else
							psuCmdSeq = _PSU_CMD_STATUS;
					}
					else
					{
						// �P�_�t�ο�X�B�w�\�v�P�q�y
						PRINTF_FUNC("SystemAvailableCurrent = %d, SystemAvailablePower = %d \n",
							ShmPsuData->SystemAvailableCurrent, ShmPsuData->SystemAvailablePower);

						PRINTF_FUNC("== PSU == BOOTING_COMPLETE \n");
						ShmPsuData->Work_Step = BOOTING_COMPLETE;
					}

					gettimeofday(&_cmdSubPriority_time, NULL);
					gettimeofday(&_log_time, NULL);
				}
			}
				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;

				// �C Priority �����O
				if (time > 1500)
				{
					PreCheckSmartChargingStep();
					startModuleFlag = true;
					gettimeofday(&_cmdSubPriority_time, NULL);
				}

				for (byte groupIndex = 0; groupIndex < _gunCount; groupIndex++)
				{
					if (psuCmdSeq == _PSU_CMD_CAP)
					{
						// ���t���`��X��O
						GetModuleCap(groupIndex);
					}
					else if (psuCmdSeq == _PSU_CMD_OUTPUT)
					{
						// ���U�s��X�q���q�y (float)
						GetModuleOutputF(groupIndex);
					}
					else if (psuCmdSeq == _PSU_CMD_IVAILIABLE)
					{
						// ���o�Ҷ���X�B�w�q�y��O
						GetModuleIavailable(groupIndex);
					}
					else if (psuCmdSeq == _PSU_CMD_TEMP)
					{
						// ���o�Ҷ��ū�
						GetDcTemperature(groupIndex);
					}
				}

				Await();

				if (psuCmdSeq == _PSU_CMD_CAP)
					psuCmdSeq = _PSU_CMD_OUTPUT;
				else if (psuCmdSeq == _PSU_CMD_OUTPUT)
					psuCmdSeq = _PSU_CMD_IVAILIABLE;
				else if (psuCmdSeq == _PSU_CMD_IVAILIABLE)
					psuCmdSeq = _PSU_CMD_TEMP;
				else
					psuCmdSeq = _PSU_CMD_CAP;

				for (byte groupIndex = 0; groupIndex < _gunCount; groupIndex++)
				{
					// �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_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 (GetTimeoutValue(_log_time) / 1000 > 1000)
						{
							OutputChargingLogFuncion(groupIndex);
							gettimeofday(&_log_time, NULL);
						}

						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));
							// ����P�_ Start -----------------------------------------------------------
							if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_GET_NEW_CAP &&
								ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A)
							{
								if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_GET_NEW_CAP)
								{
									if (chargingInfo[groupIndex]->DividChargingCurrent == 0)
									{
										chargingInfo[groupIndex]->DividChargingCurrent = ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent;
									}
								}

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

							if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_GET_NEW_CAP)
							{
								//if (ShmPsuData->SystemAvailableCurrent != chargingInfo[groupIndex]->AvailableChargingCurrent)
								{
									// ���ݭn�D�q�y���ӥR�q�j���B�w��X�q�y���d��
									if ((chargingInfo[groupIndex]->EvBatterytargetCurrent * 10) <= ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent + DERATING_GAP ||
										deratingKeepCount >= DERATING_COUNT)
									{
										// ���ݭ�������
										PRINTF_FUNC("Index = %d, newEvCurrent = %f \n", groupIndex, (chargingInfo[groupIndex]->EvBatterytargetCurrent * 10));
										PRINTF_FUNC("======= Get the charging current req of EV and shutdown the module of stop side (Step 3) ======= \n");
										ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_ADJUST_M_TO_A;
										gettimeofday(&_derating_time, NULL);
										deratingKeepCount = 0;
									}
									else
									{
										deratingKeepCount++;
										PRINTF_FUNC("Max To Ava mode (2) : Index = %d, EvBatterytargetCurrent = %f, TargetCurrent = %d, Count = %d \n",
											groupIndex,
											(chargingInfo[groupIndex]->EvBatterytargetCurrent * 10),
											(ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent + DERATING_GAP),
											deratingKeepCount);
									}
								}
							}
							else if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_ADJUST_M_TO_A)
							{
								bool isChanged = false;

								PRINTF_FUNC("Max To Ava mode (3-1) : Gun_%d, PresentChargingCurrent = %f, AvailableChargingCurrent = %f, EvBatterytargetCurrent = %f, GroupPresentOutputCurrent = %d \n", groupIndex,
									(chargingInfo[groupIndex]->PresentChargingCurrent * 10),
									chargingInfo[groupIndex]->AvailableChargingCurrent,
									(chargingInfo[groupIndex]->EvBatterytargetCurrent * 10),
									ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent);

								if (chargingInfo[groupIndex]->AvailableChargingCurrent <= (chargingInfo[groupIndex]->EvBatterytargetCurrent * 10))
								{
									for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++)
									{
										if (chargingInfo[subIndex]->SystemStatus == S_REASSIGN)
										{
											// �� B �Ҷ���X�q�y�p�� 5A �ΰh�} relay
											if ((ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent) <= 50)
												isChanged = true;
											break;
										}
									}
								}
//								else if (((chargingInfo[groupIndex]->PresentChargingCurrent * 10) >= ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent - CHK_CUR_RANGE) &&
//									((chargingInfo[groupIndex]->PresentChargingCurrent * 10) <= ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent + CHK_CUR_RANGE))
								else if (chargingInfo[groupIndex]->PresentChargingCurrent == 0)
								{
									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("Max To Ava mode (3-2) : Gun_%d, PresentChargingCurrent = %f, GroupPresentOutputCurrent = %d \n", groupIndex,
										(chargingInfo[groupIndex]->PresentChargingCurrent * 10),
										ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent);

									// ��X�ݻP���ݭn�D�q�y����
									PRINTF_FUNC("======= disable the Parallel relay (Step 4) ======= \n");
									ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_RELAY_M_TO_A;
								}
								else
								{
									if ((GetTimeoutValue(_derating_time) / 1000) > 1000)
									{
										gettimeofday(&_derating_time, NULL);
									}
								}
							}

							// �վ��X�q�y : ���i�վ�覡
							if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_GET_NEW_CAP &&
									ShmSysConfigAndInfo->SysInfo.ReAssignedFlag < _REASSIGNED_RELAY_M_TO_A)
							{
								if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_ADJUST_M_TO_A)
								{
									// ���e�R�q�����ؼйq��
									float targetVol = (chargingInfo[groupIndex]->EvBatterytargetVoltage * 10);
									byte reassignIndex = ELEMENT_NOT_FIND;

									// ��쵥�ݤ��t���j
									for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++)
									{
										if (chargingInfo[subIndex]->SystemStatus == S_REASSIGN)
										{
											reassignIndex = subIndex;
											break;
										}
									}

									if (reassignIndex != ELEMENT_NOT_FIND)
									{
										if ((GetTimeoutValue(_derating_time) / 1000) <= 150 ||
											chargingInfo[groupIndex]->MaxChargingToAverPassFlag == 0)
										{
											chargingInfo[groupIndex]->MaxChargingToAverPassFlag = 1;

											if(chargingInfo[groupIndex]->EvBatterytargetCurrent <= PSU_MIN_OUTPUT_CUR)
												chargingInfo[groupIndex]->EvBatterytargetCurrent = PSU_MIN_OUTPUT_CUR;
											PresentOutputVol(groupIndex, targetVol, (chargingInfo[groupIndex]->EvBatterytargetCurrent * 10)); Await();

											PresentOutputVol(reassignIndex, targetVol, CHK_CUR_RANGE); Await();
										}
									}
								}

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

									if (isNeedToClosePower)
									{
										SwitchPower(SYSTEM_CMD, PSU_POWER_OFF);
										FlashLed(SYSTEM_CMD, PSU_FLASH_NORMAL);
									}
								}
							}
							else if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_RELAY_M_TO_A)
							{
								//PRINTF_FUNC("set out (%d) value = %f******** 3 \n", groupIndex, chargingInfo[groupIndex]->EvBatterytargetCurrent);
								if(chargingInfo[groupIndex]->EvBatterytargetCurrent <= PSU_MIN_OUTPUT_CUR)
									chargingInfo[groupIndex]->EvBatterytargetCurrent = PSU_MIN_OUTPUT_CUR;
								PresentOutputVol(groupIndex,
									(chargingInfo[groupIndex]->EvBatterytargetVoltage * 10),
									(chargingInfo[groupIndex]->EvBatterytargetCurrent * 10)); Await();
							}
							else if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX)
							{
								if(chargingInfo[groupIndex]->EvBatterytargetCurrent <= PSU_MIN_OUTPUT_CUR)
									chargingInfo[groupIndex]->EvBatterytargetCurrent = PSU_MIN_OUTPUT_CUR;

								PresentOutputVol(SYSTEM_CMD,
									(chargingInfo[groupIndex]->EvBatterytargetVoltage * 10),
									(chargingInfo[groupIndex]->EvBatterytargetCurrent * 10));

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

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

									if (isNeedToOpenPower || startModuleFlag)
									{
										SwitchPower(SYSTEM_CMD, PSU_POWER_ON);
										FlashLed(SYSTEM_CMD, PSU_FLASH_ON);
									}
								}
							}
						}
						else if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER)
						{
							bool abnormalOutput = false;

							// ����P�_ 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_FAULT ||
											chargingInfo[subIndex]->SystemStatus == S_RESERVATION)
									{
										// �U�s�q�����񥭿�
										if (((chargingInfo[subIndex]->PresentChargingVoltage * 10) < (chargingInfo[groupIndex]->PresentChargingVoltage * 10) - ZERO_VOLTAGE) ||
												((chargingInfo[subIndex]->PresentChargingVoltage * 10) < (chargingInfo[groupIndex]->EvBatterytargetVoltage * 10) - CHK_VOL_RANGE))
										{
											PRINTF_FUNC("Ava To Max mode (12) : Gun_%d, PresentChargingVoltage = %f, PresentChargingVoltage_V = %f, EvBatterytargetVoltage = %f \n", subIndex,
												(chargingInfo[subIndex]->PresentChargingVoltage * 10),
												((chargingInfo[groupIndex]->PresentChargingVoltage * 10) - ZERO_VOLTAGE),
												((chargingInfo[groupIndex]->EvBatterytargetVoltage * 10) - CHK_VOL_RANGE));
											balanceVol = false;
										}
										break;
									}
								}

								if (balanceVol)
								{
									// ���m�ݻP���ݭn�D�q������
									PRINTF_FUNC("======= Enable the Parallel relay (Step 13) ======= \n");
									ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_RELAY_A_TO_M;
								}
								else
								{
									if ((GetTimeoutValue(_max_time) / 1000) > 500)
									{
										gettimeofday(&_max_time, NULL);
									}
								}
							}
							else if(ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_WAITING)
							{
								int idleCurrent = 0;
								int chargingCurrent = 0;
								float outCurrent = 0;

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

								// �q�ο�X�q�y�������A
								if (chargingCurrent + idleCurrent <= outCurrent - PRE_CHARG_RANGE)
									abnormalOutput = true;

								if (idleCurrent >= chargingCurrent - PRE_CHARG_RANGE)
								{
									PRINTF_FUNC("======= The Change to maximum charge mode is complete. (Step 15) ======= \n");
									ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_COMP;
								}
								else
								{
									if ((GetTimeoutValue(_max_time) / 1000) > 300)
									{
										gettimeofday(&_max_time, NULL);
									}
								}
							}

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

									for (byte subIndex = 0; subIndex < ShmPsuData->GroupCount; subIndex++)
									{
										if (chargingInfo[subIndex]->SystemStatus == S_IDLE ||
												chargingInfo[subIndex]->SystemStatus == S_RESERVATION ||
												chargingInfo[subIndex]->SystemStatus == S_FAULT ||
												chargingInfo[subIndex]->SystemStatus == S_REASSIGN_CHECK)
										{
											reassignIndex = subIndex;

											if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_WAITING)
											{
												preChargingCur = ShmPsuData->PsuGroup[subIndex].GroupPresentOutputCurrent;
											}
											else
												preChargingCur = 0;
										}
										else
										{
											if ((ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_WAITING) &&
													(preChargingCur >= preChargingTarget - ZERO_CURRENT))
												preChargingTarget += PRE_CHARG_STEP_CUR;

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

									if (reassignIndex != ELEMENT_NOT_FIND)
									{
										if ((GetTimeoutValue(_max_time) / 1000) <= 150)
										{
											//PRINTF_FUNC("set out (%d) value = %d******** 5 \n", reassignIndex, ZERO_CURRENT + preChargingTarget);
											// ���m�Ҷ������A�t�����t��Ӫ��Ҷ��A�w�W�ɹq�y�� (preChargingCur)
											PresentOutputVol(reassignIndex,
												(chargingInfo[groupIndex]->EvBatterytargetVoltage * 10),
												ZERO_CURRENT + preChargingTarget); Await();
										}

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

//										if (abnormalOutput)
//										{
//											PRINTF_FUNC("set out (%d) value = %f******** 6 \n", groupIndex, chargingInfo[groupIndex]->EvBatterytargetCurrent - preChargingCur - _ovCahrgingCur);
//											PresentOutputVol(groupIndex,
//												(chargingInfo[groupIndex]->EvBatterytargetVoltage * 10),
//												ShmPsuData->PsuGroup[groupIndex].GroupPresentOutputCurrent - preChargingCur - _ovCahrgingCur); Await();
//										}
//										else
										{
											PresentOutputVol(groupIndex,
												(chargingInfo[groupIndex]->EvBatterytargetVoltage * 10),
												(chargingInfo[groupIndex]->EvBatterytargetCurrent * 10) - preChargingCur - _ovCahrgingCur); Await();
										}
									}

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

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

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

									PresentOutputVol(groupIndex,
										(chargingInfo[groupIndex]->EvBatterytargetVoltage * 10),
										(chargingInfo[groupIndex]->EvBatterytargetCurrent * 10)); Await();

									if ((chargingInfo[groupIndex]->EvBatterytargetVoltage * 10) == 0)
									{
										if (isStartOutputSwitch[groupIndex])
										{
											isStartOutputSwitch[groupIndex] = false;
											SwitchPower(groupIndex, PSU_POWER_OFF); Await();
											FlashLed(groupIndex, PSU_FLASH_NORMAL); Await();
										}
									}
									else
									{
										if (!isStartOutputSwitch[groupIndex] || startModuleFlag)
										{
											isStartOutputSwitch[groupIndex] = true;
											SwitchPower(groupIndex, PSU_POWER_ON); Await();
											FlashLed(groupIndex, PSU_FLASH_ON); Await();
										}
									}
								}
							}
						}
					}
					else if ((chargingInfo[groupIndex]->SystemStatus >= S_TERMINATING &&
								chargingInfo[groupIndex]->SystemStatus <= S_COMPLETE) ||
								chargingInfo[groupIndex]->SystemStatus == S_ALARM)
					{
						if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX)
						{
							if (!isCharging)
							{
								bool isNeedToClosePower = false;
								for (byte index = 0; index < ShmPsuData->GroupCount; index++)
								{
									if (isStartOutputSwitch[index])
									{
										isNeedToClosePower = true;
									}
									isStartOutputSwitch[index] = false;
								}

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

								if (chargingInfo[groupIndex]->SystemStatus == S_COMPLETE)
								{
									if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_PREPARE_M_TO_A &&
											ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A)
									{
										// �N���b�������L�{���A����R�q�F
										if ((chargingInfo[groupIndex]->PresentChargingCurrent * 10) <= STOP_CURRENT)
												ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_RELAY_M_TO_A;
									}
								}
							}
							else if (chargingInfo[groupIndex]->SystemStatus == S_COMPLETE)
							{
								// �N���R�q���j���¦b�R�q�A���i�J�R�q���j�����R�q�F
								if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_PREPARE_M_TO_A &&
										ShmSysConfigAndInfo->SysInfo.ReAssignedFlag <= _REASSIGNED_RELAY_M_TO_A)
								{
									ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_NONE;
								}
							}
						}
						else if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER)
						{
							if (!isReadToCharging)
							{
								bool isNeedToClosePower = false;
								for (byte index = 0; index < ShmPsuData->GroupCount; index++)
								{
									if (isStartOutputSwitch[index])
									{
										isNeedToClosePower = true;
									}
									isStartOutputSwitch[index] = false;
								}

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

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

				startModuleFlag = false;
				break;
			}
			case _TEST_MODE:
			{
				// �b���ռҦ����A�O���P�Ҷ����q�T
				int time = GetTimeoutValue(_cmdSubPriority_time) / 1000;

				if (time > 1500)
				{
					for (byte index = 0; index < ShmPsuData->GroupCount; index++)
					{
						// ���t���`��X��O
						GetModuleCap(index); Await();

						// ���U�s��X�q���q�y (float)
						GetModuleOutputF(index); Await();
					}

					gettimeofday(&_cmdSubPriority_time, NULL);
				}

				byte _switch = 0x00;
				if ((chargingInfo[0]->EvBatterytargetVoltage * 10) > 0 && (chargingInfo[0]->EvBatterytargetCurrent * 10) > 0)
					_switch = 0x01;

				for (byte _groupCount_1 = 0; _groupCount_1 < conn_1_count; _groupCount_1++)
				{
					SetDirModulePresentOutput(connector_1[_groupCount_1],
						(chargingInfo[0]->EvBatterytargetVoltage * 10),
						(chargingInfo[0]->EvBatterytargetCurrent * 10),
						_switch, _switch); Await();
				}

				for (byte _groupCount_2 = 0; _groupCount_2 < conn_2_count; _groupCount_2++)
				{
					SetDirModulePresentOutput(connector_2[_groupCount_2],
						(chargingInfo[0]->EvBatterytargetVoltage * 10),
						(chargingInfo[0]->EvBatterytargetCurrent * 10),
						_switch, _switch); Await();
				}
			}
				break;
		}
		usleep(20000);
	}
	return FAIL;
}