/*
 * Module_SmartBox.c
 *
 *  Created on: 2022�~5��3��
 *      Author: 7564
 */

#include "Module_SmartBox.h"

struct SysConfigAndInfo			*ShmSysConfigAndInfo;
struct StatusCodeData 			*ShmStatusCodeData;
struct PsuData 					*ShmPsuData;
struct DcCommonInformation		*ShmDcCommonData;
struct SmartBoxData				*ShmSmartBoxData;

struct ChargingInfoData *chargingInfo[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY];
byte ConnectorUsingSeq[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY][4] =
{{0, 2, 3, 1}, {1, 3, 2, 0}};

struct timespec _log_time;

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

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_Log",
			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 ", buffer);
}
//==========================================
// 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 ShmSysConfigAndInfoKey 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;
   	}

   	//creat ShmStatusCodeData
   	if ((MeterSMId = shmget(ShmStatusCodeKey, sizeof(struct StatusCodeData),  0777)) < 0)
    {
		#ifdef SystemLogMessage
   		DEBUG_ERROR("shmget ShmStatusCodeKey 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;
   	}

   	//creat ShmPsuData
	if ((MeterSMId = shmget(ShmPsuKey, sizeof(struct PsuData),  0777)) < 0)
	{
		#ifdef SystemLogMessage
		DEBUG_ERROR("shmget ShmPsuKey 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;
	}

	if ((MeterSMId = shmget(ShmCommonKey, sizeof(struct DcCommonInformation), IPC_CREAT | 0777)) < 0)
	{
		#ifdef SystemLogMessage
	   	DEBUG_ERROR("shmget ShmCommonKey NG \n");
	   	#endif
	   	result = FAIL;
	}
	else if ((ShmDcCommonData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
	{
		#ifdef SystemLogMessage
	   	DEBUG_ERROR("shmat ShmDcCommonData NG \n");
	   	#endif
	   	result = FAIL;
	}

	if ((MeterSMId = shmget ( ShmSmartBoxKey, sizeof(struct SmartBoxData), IPC_CREAT | 0777 )) < 0)
	{
		#ifdef SystemLogMessage
	   	DEBUG_ERROR("shmat ShmSmartBoxKey NG \n");
	   	#endif
		return FAIL;
	}
	else if ((ShmSmartBoxData = shmat ( MeterSMId, NULL, 0 )) == (void *) - 1)
	{
		#ifdef SystemLogMessage
	   	DEBUG_ERROR("shmat ShmSmartBoxData NG \n");
	   	#endif
		return FAIL;
	}

    return result;
}

//==========================================
// Public 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;
}

void Initialization()
{
	bool isPass = false;
	while(!isPass)
	{
		isPass = true;
		for (byte _index = 0; _index < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; _index++)
		{
			if (!FindChargingInfoData(_index, &chargingInfo[0]))
			{
				DEBUG_ERROR("SmartBox (main) : FindChargingInfoData false \n");
				isPass = false;
				break;
			}
		}
		sleep(1);
	}

	for (byte _index = 0; _index < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; _index++)
	{
		ShmSmartBoxData->Dynamic4Fetch[_index].ShareGroup = NONE_GROUP_CAN_SELECTED;
		ShmSmartBoxData->Dynamic4Fetch[_index].TargetRelay = NONE_RELAY_SELECTED;
		ShmSmartBoxData->Dynamic4Fetch[_index].FetchLoopStep = _PSU_DYNAMIC_FETCH_STEP_NONE;

		ShmSmartBoxData->Dynamic4Release[_index].ReleaseGroup = NONE_GROUP_CAN_SELECTED;
		ShmSmartBoxData->Dynamic4Release[_index].TargetRelay = NONE_RELAY_SELECTED;
		ShmSmartBoxData->Dynamic4Release[_index].ReleaseLoopStep = _PSU_DYNAMIC_RELEASE_STEP_NONE;

		ShmSmartBoxData->ConnectorUsingGroupCount[_index] = 0;
	}
}

void PrintfLog()
{
	if (ShmPsuData->Work_Step != _WORK_CHARGING)
	{
		PRINTF_FUNC ( "****************************************************************** \n" );
		PRINTF_FUNC ( "SystemPresentPsuQuantity = %d \n", ShmPsuData->SystemPresentPsuQuantity);
		PRINTF_FUNC ( "SystemAvailableCurrent = %d (A) \n", ShmPsuData->SystemAvailableCurrent / 10);
		PRINTF_FUNC ( "SystemAvailablePower = %d (kw) \n", ShmPsuData->SystemAvailablePower / 10);
		PRINTF_FUNC ( "GroupCount = %d \n", ShmPsuData->GroupCount );

		for (int _count = 0; _count < ARRAY_SIZE(ConnectorUsingSeq[0]); _count ++)
		{
			PRINTF_FUNC ( "----------------------------------------------------------------- \n" );
			PRINTF_FUNC ( "Group Index = %d, UsingTarget for Gun-%d \n", _count, ShmPsuData->PsuGroup[_count].UsingTarget);
			PRINTF_FUNC ( "GroupPresentPsuQuantity = %d \n", ShmPsuData->PsuGroup[_count].GroupPresentPsuQuantity );
			PRINTF_FUNC ( "GroupTargetOutputVoltage = %d (V) \n", ShmPsuData->PsuGroup[_count].GroupTargetOutputVoltage / 10);
			PRINTF_FUNC ( "GroupTargetOutputCurrent = %d (A) \n", ShmPsuData->PsuGroup[_count].GroupTargetOutputCurrent / 10);
			PRINTF_FUNC ( "GroupAvailableCurrent = %d (A) \n", ShmPsuData->PsuGroup[_count].GroupAvailableCurrent / 10);
			PRINTF_FUNC ( "GroupAvailablePower = %d (kw) \n", ShmPsuData->PsuGroup[_count].GroupAvailablePower / 10);
			PRINTF_FUNC ( "GroupMaxVoltage = %d (V) \n", ShmPsuData->PsuGroup[_count].GroupMaxVoltage / 10);
			PRINTF_FUNC ( "GroupPresentOutputVoltage = %.1f (V) \n", (double)ShmPsuData->PsuGroup[_count].GroupPresentOutputVoltage / 10);
			PRINTF_FUNC ( "GroupPresentOutputCurrent = %.1f (A) \n", (double)ShmPsuData->PsuGroup[_count].GroupPresentOutputCurrent / 10);
			PRINTF_FUNC ( "GroupPresentOutputPower = %d \n", ShmPsuData->PsuGroup[_count].GroupPresentOutputPower );
			PRINTF_FUNC ( "TotalRatingPower = %f \n", (double)ShmPsuData->PsuGroup[_count].TotalRatingPower);
			PRINTF_FUNC ( "TotalIAvailableCurrent = %f \n", (double)ShmPsuData->PsuGroup[_count].TotalIAvailableCurrent / 10);
		}
	}
	else
	{
		for (byte conn = 0; conn < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; conn++)
		{
			byte totalUsingGpCount = 0;
			byte totalQuantity = 0;
			unsigned short _targetVol = 0 , _targetCur = 0;
			unsigned short _avaCur = 0 , _avaPow = 0;
			unsigned short _outputVol = 0 , _outputCur = 0;
			unsigned short _ratingPow = 0;

			for (byte gp = 0; gp < ShmSmartBoxData->ConnectorUsingGroupCount[conn]; gp++)
			{
				if (ShmPsuData->PsuGroup[ConnectorUsingSeq[conn][gp]].UsingTarget == GUN_LEFT)
				{
					totalUsingGpCount++;
					byte tarGp = ConnectorUsingSeq[conn][gp];

					totalQuantity += ShmPsuData->PsuGroup[tarGp].GroupPresentPsuQuantity;
					_targetVol = ShmPsuData->PsuGroup[tarGp].GroupTargetOutputVoltage / 10;
					_targetCur += ShmPsuData->PsuGroup[tarGp].GroupTargetOutputCurrent / 10;
					_avaCur += ShmPsuData->PsuGroup[tarGp].GroupAvailableCurrent / 10;
					_avaPow += ShmPsuData->PsuGroup[tarGp].GroupAvailablePower / 10;
					_outputVol = (double)ShmPsuData->PsuGroup[tarGp].GroupPresentOutputVoltage / 10;
					_outputCur = (double)ShmPsuData->PsuGroup[tarGp].GroupPresentOutputCurrent / 10;
					_ratingPow += ShmPsuData->PsuGroup[tarGp].TotalRatingPower;
				}
			}

			if (totalUsingGpCount > 0)
			{
				PRINTF_FUNC ( "----------------------------------------------------------------- \n" );
				PRINTF_FUNC ( "Group Index = %d, totalUsingGpCount = %d \n", conn, totalUsingGpCount);
				PRINTF_FUNC ( "totalQuantity = %d \n", totalQuantity);
				PRINTF_FUNC ( "_targetVol = %d (V), _targetCur = %d (A) \n", _targetVol, _targetCur);
				PRINTF_FUNC ( "_avaCur = %d (A), _avaPow = %d (kw) \n", _avaCur, _avaPow);
				PRINTF_FUNC ( "_outputVol = %d (V), _outputCur = %d (A) \n", _outputVol, _outputCur);
				PRINTF_FUNC ( "_ratingPow = %d \n", _ratingPow);
			}

			for (byte gp = 0; gp < ShmSmartBoxData->ConnectorUsingGroupCount[conn]; gp++)
			{
				if (ShmPsuData->PsuGroup[ConnectorUsingSeq[conn][gp]].UsingTarget == GUN_RIGHT)
				{
					totalUsingGpCount++;
					byte tarGp = ConnectorUsingSeq[conn][gp];

					totalQuantity += ShmPsuData->PsuGroup [tarGp].GroupPresentPsuQuantity;
					_targetVol = ShmPsuData->PsuGroup [tarGp].GroupTargetOutputVoltage / 10;
					_targetCur += ShmPsuData->PsuGroup [tarGp].GroupTargetOutputCurrent / 10;
					_avaCur += ShmPsuData->PsuGroup [tarGp].GroupAvailableCurrent / 10;
					_avaPow += ShmPsuData->PsuGroup [tarGp].GroupAvailablePower / 10;
					_outputVol = (double) ShmPsuData->PsuGroup [tarGp].GroupPresentOutputVoltage / 10;
					_outputCur = (double) ShmPsuData->PsuGroup [tarGp].GroupPresentOutputCurrent / 10;
					_ratingPow += ShmPsuData->PsuGroup [tarGp].TotalRatingPower;
				}
			}

			if (totalUsingGpCount > 0)
			{
				PRINTF_FUNC ( "----------------------------------------------------------------- \n" );
				PRINTF_FUNC ( "Group Index = %d, totalUsingGpCount = %d \n", conn, totalUsingGpCount);
				PRINTF_FUNC ( "totalQuantity = %d \n", totalQuantity);
				PRINTF_FUNC ( "_targetVol = %d (V), _targetCur = %d (A) \n", _targetVol, _targetCur);
				PRINTF_FUNC ( "_avaCur = %d (A), _avaPow = %d (kw) \n", _avaCur, _avaPow);
				PRINTF_FUNC ( "_outputVol = %d (V), _outputCur = %d (A) \n", _outputVol, _outputCur);
				PRINTF_FUNC ( "_ratingPow = %d \n", _ratingPow);
			}
		}
	}
}

void GetSystemMaxVoltage()
{
	if (ShmSysConfigAndInfo->SysInfo.BootingStatus == BOOTTING)
	{
		int _sysVol = 0;

		for (byte group = 0; group < ShmPsuData->GroupCount; group++)
		{
			if (ShmPsuData->PsuGroup[group].GroupMaxVoltage > _sysVol)
				_sysVol = ShmPsuData->PsuGroup[group].GroupMaxVoltage;
		}

		for (byte gun_index = 0; gun_index < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; gun_index++)
		{
			if (chargingInfo[gun_index]->MaximumChargingVoltage != _sysVol)
			{
				chargingInfo[gun_index]->MaximumChargingVoltage = _sysVol;
			}
		}
	}
}

void GetTimespecFunc(struct timespec *time)
{
	clock_gettime(CLOCK_MONOTONIC, time);
}

long int GetTimeoutValue(struct timespec *startTime)
{
	struct timespec endTime;

	clock_gettime(CLOCK_MONOTONIC, &endTime);
	return 1000 * (endTime.tv_sec - startTime->tv_sec) + (endTime.tv_nsec - startTime->tv_nsec) / 1000000;
}

//==========================================
// Relay Processing
//==========================================
void SmartRelayCheck()
{
	/*
	---------------------------------------
	G_0 -----------(R1)----------------> Gun - 0
				| -> R3
	G_2 --------|
				| -> R4
	G_3 --------|
				| -> R5
	G_1 -----------(R2)----------------> Gun - 1
	---------------------------------------
	R3 ON �ɾ� : G_2 �ݩ� Gun-0 ��X�BG_0�ݩ� Gun - 1 ��X
	R4 ON �ɾ� : G_3 �ݩ� Gun-0 ��X�BG_2�ݩ� Gun - 1 ��X
	R5 ON �ɾ� : G_3 �ݩ� Gun-1 ��X�BG_1�ݩ� Gun - 0 ��X
	-------------------------
	���yPSU�|�Ӹs�Ψ��X��ShareGroup�����ȦU�ݩ���ӿ�X
	*/
	byte _buff[3] = {0};

	for (byte group = 0; group < ShmPsuData->GroupCount; group++)
	{
		switch(group)
		{
			case _PSU_GROUP_INDEX_0:
			{
				if (ShmPsuData->PsuGroup[group].UsingTarget == GUN_RIGHT)
				{
					// �p�G�O�зǫ~
					if(ShmDcCommonData->systemType == _SYSTEM_TYPE_STANDARD)
					{
						_buff[_RELAY_SWITCH_NAME_R4] = 0x01;
						_buff[_RELAY_SWITCH_NAME_R5] = 0x01;
					}
					else
					{
						// R3 ON
						_buff[_RELAY_SWITCH_NAME_R3] = 0x01;
					}
				}
			}
				break;
			case _PSU_GROUP_INDEX_2:
			{
				if (ShmPsuData->PsuGroup[group].UsingTarget == GUN_LEFT)
				{
					// R3 ON
					_buff[_RELAY_SWITCH_NAME_R3] = 0x01;
				}

				if (ShmPsuData->PsuGroup[group].UsingTarget == GUN_RIGHT)
				{
					// R4 ON
					_buff[_RELAY_SWITCH_NAME_R4] = 0x01;
				}
			}
				break;
			case _PSU_GROUP_INDEX_3:
			{
				if (ShmPsuData->PsuGroup[group].UsingTarget == GUN_LEFT)
				{
					// R4 ON
					_buff[_RELAY_SWITCH_NAME_R4] = 0x01;
				}

				if (ShmPsuData->PsuGroup[group].UsingTarget == GUN_RIGHT)
				{
					// R5 ON
					_buff[_RELAY_SWITCH_NAME_R5] = 0x01;
				}
			}
				break;
			case _PSU_GROUP_INDEX_1:
			{
				if (ShmPsuData->PsuGroup[group].UsingTarget == GUN_LEFT)
				{
					// �p�G�O�зǫ~
					if(ShmDcCommonData->systemType == _SYSTEM_TYPE_STANDARD)
					{
						_buff[_RELAY_SWITCH_NAME_R4] = 0x01;
						_buff[_RELAY_SWITCH_NAME_R5] = 0x01;
					}
					else
					{
						// R5 ON
						_buff[_RELAY_SWITCH_NAME_R5] = 0x01;
					}
				}
			}
				break;
		}
	}

	for (byte _Conn = 0; _Conn < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; _Conn++)
	{
		if (ShmSmartBoxData->Dynamic4Fetch[_Conn].FetchLoopStep >= _PSU_DYNAMIC_FETCH_STEP_RELAY)
		{
			byte targetGroup = ShmSmartBoxData->Dynamic4Fetch[_Conn].ShareGroup;

			switch(targetGroup)
			{
				case _PSU_GROUP_INDEX_0:
				{
					if (ShmPsuData->PsuGroup[targetGroup].UsingTarget == GUN_RIGHT)
					{
						// �p�G�O�зǫ~
						if(ShmDcCommonData->systemType == _SYSTEM_TYPE_STANDARD)
						{
							_buff[_RELAY_SWITCH_NAME_R4] = 0x01;
							_buff[_RELAY_SWITCH_NAME_R5] = 0x01;
							ShmSmartBoxData->Dynamic4Fetch[_Conn].TargetRelay = _RELAY_SWITCH_NAME_R4;
						}
						else
						{
							// R3 ON -- P
							_buff[_RELAY_SWITCH_NAME_R3] = 0x01;
							ShmSmartBoxData->Dynamic4Fetch[_Conn].TargetRelay = _RELAY_SWITCH_NAME_R3;
						}
					}
				}
					break;
				case _PSU_GROUP_INDEX_2:
				{
					if (ShmPsuData->PsuGroup[targetGroup].UsingTarget == GUN_LEFT)
					{
						// R3 ON -- P
						_buff[_RELAY_SWITCH_NAME_R3] = 0x01;
						ShmSmartBoxData->Dynamic4Fetch[_Conn].TargetRelay = _RELAY_SWITCH_NAME_R3;
					}

					if (ShmPsuData->PsuGroup[targetGroup].UsingTarget == GUN_RIGHT)
					{
						// R4 ON -- P
						_buff[_RELAY_SWITCH_NAME_R4] = 0x01;
						ShmSmartBoxData->Dynamic4Fetch[_Conn].TargetRelay = _RELAY_SWITCH_NAME_R4;
					}
				}
					break;
				case _PSU_GROUP_INDEX_3:
				{
					if (ShmPsuData->PsuGroup[targetGroup].UsingTarget == GUN_LEFT)
					{
						// R4 ON -- P
						_buff[_RELAY_SWITCH_NAME_R4] = 0x01;
						ShmSmartBoxData->Dynamic4Fetch[_Conn].TargetRelay = _RELAY_SWITCH_NAME_R4;
					}

					if (ShmPsuData->PsuGroup[targetGroup].UsingTarget == GUN_RIGHT)
					{
						// R5 ON -- P
						_buff[_RELAY_SWITCH_NAME_R5] = 0x01;
						ShmSmartBoxData->Dynamic4Fetch[_Conn].TargetRelay = _RELAY_SWITCH_NAME_R5;
					}
				}
					break;
				case _PSU_GROUP_INDEX_1:
				{
					if (ShmPsuData->PsuGroup[targetGroup].UsingTarget == GUN_LEFT)
					{
						// �p�G�O�зǫ~
						if(ShmDcCommonData->systemType == _SYSTEM_TYPE_STANDARD)
						{
							_buff[_RELAY_SWITCH_NAME_R4] = 0x01;
							_buff[_RELAY_SWITCH_NAME_R5] = 0x01;
							ShmSmartBoxData->Dynamic4Fetch[_Conn].TargetRelay = _RELAY_SWITCH_NAME_R4;
						}
						else
						{
							// R5 ON -- P
							_buff[_RELAY_SWITCH_NAME_R5] = 0x01;
							ShmSmartBoxData->Dynamic4Fetch[_Conn].TargetRelay = _RELAY_SWITCH_NAME_R5;
						}
					}
				}
					break;
			}
		}

		if (ShmSmartBoxData->Dynamic4Release[_Conn].ReleaseLoopStep >= _PSU_DYNAMIC_RELEASE_STEP_RELAYOFF)
		{
			byte targetGroup = ShmSmartBoxData->Dynamic4Release[_Conn].ReleaseGroup;

			switch(targetGroup)
			{
				case _PSU_GROUP_INDEX_0:
				{
					if (ShmPsuData->PsuGroup[targetGroup].UsingTarget == GUN_RIGHT)
					{
						// R3 OFF
						_buff[_RELAY_SWITCH_NAME_R3] = 0x00;
						ShmSmartBoxData->Dynamic4Release[_Conn].TargetRelay = _RELAY_SWITCH_NAME_R3;

						// �p�G�O�зǫ~
						if(ShmDcCommonData->systemType == _SYSTEM_TYPE_STANDARD)
						{
							_buff[_RELAY_SWITCH_NAME_R4] = 0x00;
							_buff[_RELAY_SWITCH_NAME_R5] = 0x00;
							ShmSmartBoxData->Dynamic4Release[_Conn].TargetRelay = _RELAY_SWITCH_NAME_R4;
						}
					}
				}
					break;
				case _PSU_GROUP_INDEX_2:
				{
					if (ShmPsuData->PsuGroup[targetGroup].UsingTarget == GUN_LEFT)
					{
						// R3 OFF
						_buff[_RELAY_SWITCH_NAME_R3] = 0x00;
						ShmSmartBoxData->Dynamic4Release[_Conn].TargetRelay = _RELAY_SWITCH_NAME_R3;
					}

					if (ShmPsuData->PsuGroup[targetGroup].UsingTarget == GUN_RIGHT)
					{
						// R5 OFF
						_buff[_RELAY_SWITCH_NAME_R4] = 0x00;
						ShmSmartBoxData->Dynamic4Release[_Conn].TargetRelay = _RELAY_SWITCH_NAME_R4;
					}
				}
					break;
				case _PSU_GROUP_INDEX_3:
				{
					if (ShmPsuData->PsuGroup[targetGroup].UsingTarget == GUN_LEFT)
					{
						// R4 OFF
						_buff[_RELAY_SWITCH_NAME_R4] = 0x00;
						ShmSmartBoxData->Dynamic4Release[_Conn].TargetRelay = _RELAY_SWITCH_NAME_R4;
					}

					if (ShmPsuData->PsuGroup[targetGroup].UsingTarget == GUN_RIGHT)
					{
						// R5 OFF
						_buff[_RELAY_SWITCH_NAME_R5] = 0x00;
						ShmSmartBoxData->Dynamic4Release[_Conn].TargetRelay = _RELAY_SWITCH_NAME_R5;
					}
				}
					break;
				case _PSU_GROUP_INDEX_1:
				{
					if (ShmPsuData->PsuGroup[targetGroup].UsingTarget == GUN_LEFT)
					{
						// �p�G�O�зǫ~
						if(ShmDcCommonData->systemType == _SYSTEM_TYPE_STANDARD)
						{
							_buff[_RELAY_SWITCH_NAME_R4] = 0x00;
							_buff[_RELAY_SWITCH_NAME_R5] = 0x00;
							ShmSmartBoxData->Dynamic4Release[_Conn].TargetRelay = _RELAY_SWITCH_NAME_R4;
						}
						else
						{
							// R4 OFF
							_buff[_RELAY_SWITCH_NAME_R5] = 0x00;
							ShmSmartBoxData->Dynamic4Release[_Conn].TargetRelay = _RELAY_SWITCH_NAME_R5;
						}
					}
				}
					break;
			}
		}
	}

	memcpy(ShmSmartBoxData->ParallelRelayStatus, _buff, sizeof(_buff));
}

//==========================================
// Sub Processing
//==========================================
void Assign2ConnectorProcessing(byte _targetConn)
{
	// �ھڲ{�b�Ӻj���쪺�s�ƶq, �̶��h�]�w�s���ϥΥؼЬ��� /�k�j
	// �@���]�w�ӼҶ��ؼЬ��� /�k�j��AAssignedPwr2Connector function �|�N�ӼҶ�����T����������/�k�j
	for (byte aGp = 0; aGp < ShmSmartBoxData->ConnectorUsingGroupCount[_targetConn]; aGp++)
	{
		if (ShmPsuData->PsuGroup[ConnectorUsingSeq[_targetConn][aGp]].IsUsing == YES)
		{
			ShmPsuData->PsuGroup[ConnectorUsingSeq[_targetConn][aGp]].UsingTarget = _targetConn;
		}
	}
}

// �N_group�Ӹs���Ҷ��t��_targetConn�j��
void AddGroup2Connector(byte _targetConn, byte _group)
{
	ShmPsuData->PsuGroup[_group].IsUsing = YES;
	if ((ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf == YES && _targetConn == GUN_RIGHT) ||
			(ShmDcCommonData->systemType == _SYSTEM_TYPE_STANDARD && ShmSmartBoxData->ConnectorUsingGroupCount[_targetConn] > 0))
		ShmSmartBoxData->ConnectorUsingGroupCount[_targetConn] = 4;
	else
		ShmSmartBoxData->ConnectorUsingGroupCount[_targetConn]++;
	// ������۹�s
	Assign2ConnectorProcessing(_targetConn);
}

// �NtargetGp�Ӹs���Ҷ��q_targetConn�j������
bool ReleaseConnectorProcessing(byte _targetConn, byte targetGp)
{
	bool result = false;

	if (ShmPsuData->PsuGroup[targetGp].PwSwitchStatus == _PSU_POWER_STATUS_OFF)
	{
		result = true;
		ShmPsuData->PsuGroup[targetGp].UsingTarget = GUN_CHECK;
		ShmPsuData->PsuGroup[targetGp].IsUsing = NO;
		ShmSmartBoxData->ConnectorUsingGroupCount[_targetConn]--;
	}

	return result;
}

//==========================================
// Fetch fork
//==========================================
void InitializeDynamicFetch(byte _targetConn)
{
	ShmSmartBoxData->Dynamic4Fetch[_targetConn].ShareGroup = NONE_GROUP_CAN_SELECTED;
	ShmSmartBoxData->Dynamic4Fetch[_targetConn].TargetRelay = NONE_RELAY_SELECTED;
	ShmSmartBoxData->Dynamic4Fetch[_targetConn].ShareTargetCurrent = 0;
	ShmSmartBoxData->SmartChk[_targetConn].IsFetchStart = NO;
}

void FetchLoopProcessing(byte _targetConn)
{
	byte targetGroup = ShmSmartBoxData->Dynamic4Fetch[_targetConn].ShareGroup;
	if (targetGroup == NONE_GROUP_CAN_SELECTED &&
			ShmSmartBoxData->Dynamic4Fetch[_targetConn].FetchLoopStep >= _PSU_DYNAMIC_FETCH_STEP_TG_VOL)
	{
		ShmSmartBoxData->Dynamic4Fetch[_targetConn].FetchLoopStep = _PSU_DYNAMIC_FETCH_STEP_FINISH;
	}

	// �� target vol ����n�٬O�η��e���u�q�� ? �i�H�ոլ�~
	float EvVoltage = chargingInfo[_targetConn]->EvBatterytargetVoltage * 10;

	switch(ShmSmartBoxData->Dynamic4Fetch[_targetConn].FetchLoopStep)
	{
		case _PSU_DYNAMIC_FETCH_STEP_NONE:
		case _PSU_DYNAMIC_FETCH_STEP_WAIT:{ } break;
		case _PSU_DYNAMIC_FETCH_STEP_TG_VOL:
		{
			// �Ӹs����
			if (ShmPsuData->PsuGroup[targetGroup].GroupPresentOutputVoltage != 0)
			{
				PRINTF_FUNC("EV_ReqVoltage = %f, targetGroup = %d, Group_CurVoltage = %d \n",
						EvVoltage, targetGroup, ShmPsuData->PsuGroup[targetGroup].GroupPresentOutputVoltage);
			}

			if (EvVoltage <= PSU_MIN_VOL)
			{
				PRINTF_FUNC("***** FETCH_STEP_ABORT ***** (Gun - %d) \n", _targetConn);
				ShmSmartBoxData->Dynamic4Fetch[_targetConn].FetchLoopStep = _PSU_DYNAMIC_FETCH_STEP_ABORT;
			}
			else if (ShmPsuData->PsuGroup[targetGroup].GroupPresentOutputVoltage >= EvVoltage - PSU_TG_VOL_GAP)
			{
				PRINTF_FUNC("***** FETCH_STEP_RELAY ***** (Gun - %d) \n", _targetConn);
				ShmPsuData->PsuGroup[targetGroup].UsingTarget = _targetConn;
				ShmSmartBoxData->Dynamic4Fetch[_targetConn].FetchLoopStep = _PSU_DYNAMIC_FETCH_STEP_RELAY;
			}
		}
			break;
		case _PSU_DYNAMIC_FETCH_STEP_RELAY:
		{
			// �f�W������ Relay
			if (ShmSmartBoxData->Dynamic4Fetch[_targetConn].TargetRelay < ARRAY_SIZE(ShmSmartBoxData->ParallelRelayStatus))
			{
				if (ShmSmartBoxData->ParallelRelayStatus[ShmSmartBoxData->Dynamic4Fetch[_targetConn].TargetRelay] == YES)
				{
					if (ShmSmartBoxData->RcbParallelStatus[ShmSmartBoxData->Dynamic4Fetch[_targetConn].TargetRelay] == YES)
					{
						PRINTF_FUNC("***** FETCH_STEP_CUR_SHARE ***** (Gun - %d) \n", _targetConn);
						ShmSmartBoxData->Dynamic4Fetch[_targetConn].FetchLoopStep = _PSU_DYNAMIC_FETCH_STEP_CUR_SHARE;
					}
				}
			}
		}
			break;
		case _PSU_DYNAMIC_FETCH_STEP_CUR_SHARE:
		{
			// ���y : �ؼйq�y = ���e�q�y / (�쥻��X�s�Ӽ� + share group �Ӽ�)
			PRINTF_FUNC("GroupPresent = %d (0.1A), ShareTarget = %d (0.1A), CurrentPresent = %.1f \n",
					ShmPsuData->PsuGroup[targetGroup].GroupPresentOutputCurrent,
					ShmSmartBoxData->Dynamic4Fetch[_targetConn].ShareTargetCurrent,
					chargingInfo[_targetConn]->PresentChargingCurrent);

			if ((ShmPsuData->PsuGroup[targetGroup].GroupPresentOutputCurrent >= ShmSmartBoxData->Dynamic4Fetch[_targetConn].ShareTargetCurrent - PSU_TG_CUR_GAP &&
					ShmPsuData->PsuGroup[targetGroup].GroupPresentOutputCurrent <= ShmSmartBoxData->Dynamic4Fetch[_targetConn].ShareTargetCurrent + PSU_TG_CUR_GAP) ||
					chargingInfo[_targetConn]->PresentChargingCurrent <= PSU_MIN_CUR)
			{
				PRINTF_FUNC("***** FETCH_STEP_WATI_FINISH ***** (Gun - %d) \n", _targetConn);
				ShmSmartBoxData->Dynamic4Fetch[_targetConn].FetchLoopStep = _PSU_DYNAMIC_FETCH_STEP_WATI_FINISH;
			}

		}
			break;
		case _PSU_DYNAMIC_FETCH_STEP_WATI_FINISH:
		{
			AddGroup2Connector(_targetConn, targetGroup);
			GetTimespecFunc(&ShmSmartBoxData->SmartChk[_targetConn].FetchLoopTime);
			PRINTF_FUNC("***** FETCH_STEP_FINISH ***** (Gun - %d) \n", _targetConn);
			ShmSmartBoxData->Dynamic4Fetch[_targetConn].ShareGroup = NONE_GROUP_CAN_SELECTED;
			ShmSmartBoxData->Dynamic4Fetch[_targetConn].FetchLoopStep = _PSU_DYNAMIC_FETCH_STEP_FINISH;
		}
			break;
		case _PSU_DYNAMIC_FETCH_STEP_FINISH:
		{
			// ����
			int _t = GetTimeoutValue(&ShmSmartBoxData->SmartChk[_targetConn].FetchLoopTime);

			if (_t >= FETCH_FINISH_WAIT_TIME)
			{
				InitializeDynamicFetch(_targetConn);
				PRINTF_FUNC("***** FETCH_STEP_NONE ***** (Gun - %d) \n", _targetConn);
				ShmSmartBoxData->Dynamic4Fetch[_targetConn].FetchLoopStep = _PSU_DYNAMIC_FETCH_STEP_NONE;
			}
		}
			break;
		case _PSU_DYNAMIC_FETCH_STEP_ABORT:
		{
			// ���_
			if (ShmPsuData->PsuGroup[targetGroup].IsUsing)
			{
				ShmPsuData->PsuGroup[targetGroup].IsUsing = NO;
				ShmPsuData->PsuGroup[targetGroup].UsingTarget = GUN_CHECK;
			}

			GetTimespecFunc(&ShmSmartBoxData->SmartChk[_targetConn].FetchLoopTime);
			ShmSmartBoxData->Dynamic4Fetch[_targetConn].FetchLoopStep = _PSU_DYNAMIC_FETCH_STEP_FINISH;
		}
			break;
	}
}

byte CheckRemainPwrByConIndex(byte _targetConn)
{
	byte result = NONE_GROUP_CAN_SELECTED;

	// �Ӻj�w�g�ϥΪ��s�ƶq
	byte usingCount = ShmSmartBoxData->ConnectorUsingGroupCount[_targetConn];

	for (byte Gp = usingCount; Gp < ARRAY_SIZE(ConnectorUsingSeq[_targetConn]); Gp++)
	{
		// �P�_�O�_���Ӻj�U�@�ӥi�θs�����A
		if (ShmPsuData->PsuGroup[ConnectorUsingSeq[_targetConn][Gp]].IsUsing == NO &&
				ShmPsuData->PsuGroup[ConnectorUsingSeq[_targetConn][Gp]].GroupPresentPsuQuantity > 0)
		{
			result = ConnectorUsingSeq[_targetConn][Gp];
			break;
		}
	}

	return result;
}

void Chk2StopFetchStep(byte _targetConn)
{
	// �}�l�y�{��,�N���y�{�����a~
	if (ShmSmartBoxData->Dynamic4Fetch[_targetConn].FetchLoopStep > _PSU_DYNAMIC_FETCH_STEP_NONE &&
			ShmSmartBoxData->Dynamic4Fetch[_targetConn].FetchLoopStep < _PSU_DYNAMIC_FETCH_STEP_TG_VOL)
	{
		PRINTF_FUNC("***** FETCH_STEP_ABORT ***** (Gun - %d) \n", _targetConn);
		ShmSmartBoxData->Dynamic4Fetch[_targetConn].FetchLoopStep = _PSU_DYNAMIC_FETCH_STEP_ABORT;
	}
}

bool GetCanFetchResult(byte gun_index)
{
	// �p�G���e��X�����ڥi���Ѫ���q (�Z�� <= CAP_GAP_FETCH <3KW>)
	// ���� EvBatterytargetVoltage ��]�O�p�O�|�N�ӭȰ����P���B�z�覡
	float needPower = chargingInfo[gun_index]->PresentChargingVoltage *
			chargingInfo[gun_index]->EvBatterytargetCurrent / 100;

	ShmSmartBoxData->ConnectorStatus[gun_index].NeedToFetch =
		(needPower > 0 && needPower >= chargingInfo[gun_index]->RealRatingPower - CAP_GAP_FETCH) ? true : false;

	if (!ShmSmartBoxData->ConnectorStatus[gun_index].NeedToFetch)
	{
		// �Ҽ{�C���Ҷ��̤j��X�q�y�� 100A
		ShmSmartBoxData->ConnectorStatus[gun_index].NeedToFetch = (chargingInfo[gun_index]->EvBatterytargetCurrent >=
			chargingInfo[gun_index]->AvailableChargingCurrent - LIMIT_PWR_MODULE_GAP) ? true : false;

	}

	return ShmSmartBoxData->ConnectorStatus[gun_index].NeedToFetch;
}

void FetchFork()
{
	pid_t fetchPid;

	fetchPid = fork();

	if(fetchPid > 0)
	{
		bool isPass = false;
		struct ChargingInfoData *_chargingData[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY];

		while(!isPass)
		{
			isPass = true;
			for (byte _index = 0; _index < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; _index++)
			{
				if (!FindChargingInfoData(_index, &_chargingData[0]))
				{
					DEBUG_ERROR("Smartbox (FetchFork) : FindChargingInfoData false \n");
					isPass = false;
					break;
				}
			}
			sleep(1);
		}

		while(1)
		{
			for (byte gun_index = 0; gun_index < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; gun_index++)
			{
				if (chargingInfo[gun_index]->SystemStatus == SYS_MODE_IDLE ||
						chargingInfo[gun_index]->SystemStatus == SYS_MODE_RESERVATION ||
						chargingInfo[gun_index]->SystemStatus == SYS_MODE_MAINTAIN ||
						chargingInfo[gun_index]->SystemStatus == SYS_MODE_FAULT)
				{
					ShmSmartBoxData->ConnectorStatus[gun_index].NeedToFetch = NO;

					if (ShmSmartBoxData->ConnectorStatus[gun_index].ConnectorStaus != _CONNECTOR_STATUS_NONE)
						ShmSmartBoxData->ConnectorStatus[gun_index].ConnectorStaus = _CONNECTOR_STATUS_NONE;
				}
				// ��R�q�޿�ӻ�,�R�q�j�u���ݨD
				else if (chargingInfo[gun_index]->SystemStatus >= SYS_MODE_MODE_REASSIGN_CHECK &&
						chargingInfo[gun_index]->SystemStatus <= SYS_MODE_REASSIGN)
				{
					// �P�_�Ӹs�O�_�Q�ϥΤ�
					if (ShmPsuData->PsuGroup[gun_index].IsUsing)
					{
						// �p�G�ϥΤ� : ���ݧ�o���Ҷ����X
						ShmSmartBoxData->ConnectorStatus[gun_index].ConnectorStaus = _CONNECTOR_STATUS_WAIT;
					}
					else
					{
						// �����P�N�Ӹs���X
						InitializeDynamicFetch(gun_index);
						ShmSmartBoxData->ConnectorStatus[gun_index].ConnectorStaus = _CONNECTOR_STATUS_USING;
					}
				}
				else if (chargingInfo[gun_index]->SystemStatus == SYS_MODE_PREPARING)
				{
					// �o�Ӷ��q�u�|�����ݩ�Ӻj���Ҷ��s
					if (ShmDcCommonData->systemType == _SYSTEM_TYPE_SIMPLE)
					{
						// ���� : �j��ϥβĹs�s
					    AddGroup2Connector(gun_index, _PSU_GROUP_INDEX_0);
					}
					else
					{
						if (!ShmPsuData->PsuGroup[gun_index].IsUsing)
						{
							// �Ĥ@�� : Gun index
							// �ĤG�� : Psu Group index
							AddGroup2Connector(gun_index, gun_index);
						}
					}
				}
				else if (chargingInfo[gun_index]->SystemStatus == SYS_MODE_CHARGING)
				{
					// �P�_�O�_�i�H�λݭn���Ѧh�l�s��X
					byte chkRemainGp = NONE_GROUP_CAN_SELECTED;

					if (ShmSmartBoxData->Dynamic4Fetch[gun_index].ShareGroup == NONE_GROUP_CAN_SELECTED)
						chkRemainGp = CheckRemainPwrByConIndex(gun_index);
					else
						chkRemainGp = ShmSmartBoxData->Dynamic4Fetch[gun_index].ShareGroup;

					ShmSmartBoxData->ConnectorStatus[gun_index].NeedToFetch = GetCanFetchResult(gun_index);

					if (ShmDcCommonData->systemType != _SYSTEM_TYPE_SIMPLE &&
							ShmSmartBoxData->Dynamic4Release[gun_index].ReleaseLoopStep == _PSU_DYNAMIC_RELEASE_STEP_NONE &&
							((ShmSmartBoxData->ConnectorStatus[gun_index].NeedToFetch &&
							chkRemainGp != NONE_GROUP_CAN_SELECTED &&
							ShmSmartBoxData->Dynamic4Fetch[gun_index].FetchLoopStep <= _PSU_DYNAMIC_FETCH_STEP_WAIT) ||
							ShmDcCommonData->smartFetchRun[gun_index])
							)
					{
						if (!ShmSmartBoxData->SmartChk[gun_index].IsFetchStart)
						{
							// �P�_�O�_�i�H�λݭn���Ѧh�l�s��X
							PRINTF_FUNC("Fetch Target = %d, Target Group = %d \n", gun_index, chkRemainGp);
							// ��w�ؼиs,�ʺA���t�}�l
							// �Ӹs�Ҷ��Y�Q��w, �w���t�~�@�s�]�i�J�ۦP�޿�,�w���m�P�@�Ӹs������
							ShmPsuData->PsuGroup[chkRemainGp].IsUsing = YES;

							ShmSmartBoxData->Dynamic4Fetch[gun_index].ShareGroup = chkRemainGp;
							PRINTF_FUNC("***** FETCH_STEP_WAIT ***** (Gun - %d) \n", gun_index);
							ShmSmartBoxData->Dynamic4Fetch[gun_index].FetchLoopStep = _PSU_DYNAMIC_FETCH_STEP_WAIT;

							// �˼ƶi�J�ʺA���t�޿� - Fetch loop
							ShmSmartBoxData->SmartChk [gun_index].IsFetchStart = YES;
							// ���󦨥�, �˼� FETCH_SMART_CHK_TIME <5s>
							GetTimespecFunc(&ShmSmartBoxData->SmartChk[gun_index].FetchLoopTime);
						}
						else
						{
							if (ShmSmartBoxData->Dynamic4Fetch[gun_index].FetchLoopStep == _PSU_DYNAMIC_FETCH_STEP_WAIT)
							{
								int _t = GetTimeoutValue(&ShmSmartBoxData->SmartChk[gun_index].FetchLoopTime);

								if (_t >= FETCH_SMART_CHK_TIME)
								{
									PRINTF_FUNC("***** FETCH_STEP_TG_VOL ***** (Gun - %d) \n", gun_index);
									ShmSmartBoxData->Dynamic4Fetch[gun_index].FetchLoopStep = _PSU_DYNAMIC_FETCH_STEP_TG_VOL;

									ShmDcCommonData->smartFetchRun[gun_index] = NO;
								}
							}
						}
					}
					else
					{
						// �ʺA���t�����_
						Chk2StopFetchStep(gun_index);
					}
				}
				FetchLoopProcessing(gun_index);
			}

			usleep(50000);
		}
	}
}

//==========================================
// Release fork
//==========================================
void InitializeDynamicRelease(byte _targetConn)
{
	ShmSmartBoxData->Dynamic4Release[_targetConn].ReleaseGroup = NONE_GROUP_CAN_SELECTED;
	ShmSmartBoxData->Dynamic4Release[_targetConn].TargetRelay = NONE_RELAY_SELECTED;
	ShmSmartBoxData->Dynamic4Release[_targetConn].LimitCurCap = 0;
	ShmSmartBoxData->Dynamic4Release[_targetConn].LimitPwrCap = 0;
	ShmSmartBoxData->Dynamic4Release[_targetConn].LimitCur = 0;
	ShmSmartBoxData->Dynamic4Release[_targetConn].LimitPwr = 0;
	ShmSmartBoxData->Dynamic4Release[_targetConn].AutoRelease = NO;
	ShmSmartBoxData->Dynamic4Release[_targetConn].ReleaseLoopStep = _PSU_DYNAMIC_FETCH_STEP_FINISH;
}

byte CheckReleasePwrByConIndex(byte _targetConn)
{
	byte result = NONE_GROUP_CAN_SELECTED;

	// �Ӻj�w�g�ϥΪ��s�ƶq
	byte usingCount = ShmSmartBoxData->ConnectorUsingGroupCount[_targetConn];

	// ���i��̫�@�Ӥ]��������
	if (usingCount - 1 > 0)
		result = ConnectorUsingSeq[_targetConn][usingCount - 1];

	return result;
}

void ReleaseLoopProcessing(byte _targetConn)
{
	byte targetGroup = ShmSmartBoxData->Dynamic4Release[_targetConn].ReleaseGroup;

	switch(ShmSmartBoxData->Dynamic4Release[_targetConn].ReleaseLoopStep)
	{
		case _PSU_DYNAMIC_RELEASE_STEP_NONE:
		case _PSU_DYNAMIC_RELEASE_STEP_WAIT: {} break;
		case _PSU_DYNAMIC_RELEASE_STEP_LIMIT:
		{
			// ���ӭn�q���i��X����q�P�q�y
			// if the current and power limits are below their capacity
//			if (ShmSmartBoxData->Dynamic4Release[_targetConn].LimitPwr <= ShmSmartBoxData->Dynamic4Release[_targetConn].LimitPwrCap ||
//					chargingInfo[_targetConn]->PresentChargingCurrent * 10 <= PSU_LIMIT_CUR)

			if (ShmSmartBoxData->Dynamic4Release[_targetConn].LimitPwr <= ShmSmartBoxData->Dynamic4Release[_targetConn].LimitPwrCap)
			{
				PRINTF_FUNC("***** RELEASE_STEP_CUR_SHARE ***** (Gun - %d) \n", _targetConn);
				ShmSmartBoxData->Dynamic4Release[_targetConn].ReleaseLoopStep = _PSU_DYNAMIC_RELEASE_STEP_CUR_SHARE;
			}
		}
			break;
		case _PSU_DYNAMIC_RELEASE_STEP_CUR_SHARE:
		{
			PRINTF_FUNC("targetGroup = %d, GroupPresentOutputCurrent = %.1f \n",
					targetGroup,
					ShmPsuData->PsuGroup[targetGroup].GroupPresentOutputCurrent);

			// if the output current is below their capacity for 5s
			int _t = GetTimeoutValue(&ShmSmartBoxData->SmartChk[_targetConn].ReleaseLoopTime);

			if (ShmPsuData->PsuGroup[targetGroup].GroupPresentOutputCurrent <= RELEASE_STEP_CUR_SHARE &&
					_t >= WAIT_FOR_LIMIT_STABLE)
			{
				PRINTF_FUNC("***** RELEASE_STEP_RELAYOFF ***** (Gun - %d) \n", _targetConn);
				ShmSmartBoxData->Dynamic4Release[_targetConn].ReleaseLoopStep = _PSU_DYNAMIC_RELEASE_STEP_RELAYOFF;
			}
		}
			break;
		case _PSU_DYNAMIC_RELEASE_STEP_RELAYOFF:
		{
			// ��������� Relay
			PRINTF_FUNC("TargetRelay (%d), targetGroup = %d, ParallelRelayStatus = (%d), RcbParallelStatus = (%d) \n",
					ShmSmartBoxData->Dynamic4Release[_targetConn].TargetRelay, targetGroup,
					ShmSmartBoxData->ParallelRelayStatus[ShmSmartBoxData->Dynamic4Release[_targetConn].TargetRelay],
					ShmSmartBoxData->RcbParallelStatus[ShmSmartBoxData->Dynamic4Release[_targetConn].TargetRelay]);

			if (ShmSmartBoxData->Dynamic4Release[_targetConn].TargetRelay < ARRAY_SIZE(ShmSmartBoxData->ParallelRelayStatus))
			{
				if (ShmSmartBoxData->ParallelRelayStatus[ShmSmartBoxData->Dynamic4Release[_targetConn].TargetRelay] == NO)
				{
					if (ShmSmartBoxData->RcbParallelStatus[ShmSmartBoxData->Dynamic4Release[_targetConn].TargetRelay] == NO)
					{
						PRINTF_FUNC("***** RELEASE_STEP_WATI_FINISH ***** (Gun - %d) \n", _targetConn);
						ShmSmartBoxData->Dynamic4Release[_targetConn].ReleaseLoopStep = _PSU_DYNAMIC_RELEASE_STEP_WAIT_FINISH;
					}
				}
			}
		}
			break;
		case _PSU_DYNAMIC_RELEASE_STEP_WAIT_FINISH:
		{
			if(ReleaseConnectorProcessing(_targetConn, targetGroup))
			{
				GetTimespecFunc ( & ShmSmartBoxData->SmartChk [_targetConn].ReleaseLoopTime );
				PRINTF_FUNC("***** RELEASE_STEP_FINISH ***** (Gun - %d) \n", _targetConn);
				InitializeDynamicRelease(_targetConn);
				ShmSmartBoxData->Dynamic4Release[_targetConn].ReleaseLoopStep = _PSU_DYNAMIC_RELEASE_STEP_FINISH;
			}
		}
			break;
		case _PSU_DYNAMIC_RELEASE_STEP_FINISH:
		{
			// ����
			int _t = GetTimeoutValue(&ShmSmartBoxData->SmartChk[_targetConn].ReleaseLoopTime);

			if (_t >= RELEASE_FINISH_WAIT_TIME)
			{
				PRINTF_FUNC("***** RELEASE_STEP_NONE ***** (Gun - %d) \n", _targetConn);
				ShmSmartBoxData->SmartChk[_targetConn].IsReleaseStart = NO;
				ShmSmartBoxData->Dynamic4Release[_targetConn].ReleaseLoopStep = _PSU_DYNAMIC_RELEASE_STEP_NONE;
			}
		}
			break;
		case _PSU_DYNAMIC_RELEASE_STEP_ABORT:
		{
			GetTimespecFunc(& ShmSmartBoxData->SmartChk [_targetConn].ReleaseLoopTime);
			PRINTF_FUNC("***** RELEASE_STEP_FINISH ***** (Gun - %d) \n", _targetConn);
			InitializeDynamicRelease(_targetConn);
			ShmSmartBoxData->Dynamic4Release[_targetConn].ReleaseLoopStep = _PSU_DYNAMIC_RELEASE_STEP_FINISH;
		}
			break;
	}
}

void Chk2StopReleaseStep(byte _targetConn)
{
	// �}�l�y�{��,�N���y�{�����a~
	if (ShmSmartBoxData->Dynamic4Release [_targetConn].ReleaseGroup > _PSU_DYNAMIC_RELEASE_STEP_NONE &&
			ShmSmartBoxData->Dynamic4Release [_targetConn].ReleaseGroup < _PSU_DYNAMIC_RELEASE_STEP_LIMIT)
	{
		PRINTF_FUNC ( "***** RELEASE_STEP_ABORT ***** (Gun - %d) \n", _targetConn );
		//ShmSmartBoxData->Dynamic4Release [_targetConn].ReleaseGroup = _PSU_DYNAMIC_RELEASE_STEP_ABORT;
	}
	else
		ShmSmartBoxData->SmartChk[_targetConn].IsReleaseStart = NO;
}

bool GetCanReleaseResult(byte gun_index, byte releaseGp)
{
	bool result = false;
	unsigned short releasePwr = ShmPsuData->PsuGroup[releaseGp].TotalRatingPower * 10;
	float needPower = chargingInfo[gun_index]->PresentChargingVoltage *
				chargingInfo[gun_index]->EvBatterytargetCurrent / 100;

	result = (chargingInfo[gun_index]->RealRatingPower > 0 && releasePwr > 0 &&
			needPower < chargingInfo[gun_index]->RealRatingPower - releasePwr - CAP_GAP_RELEASE) ? true : false;

	if (result)
	{
		// afterReleaseMdCur �C�ӼҶ��̤j 100A : 1A
		float afterReleaseMdCur = chargingInfo[gun_index]->AvailableChargingCurrent -
				ShmPsuData->PsuGroup[releaseGp].GroupAvailableCurrent;

		result = (chargingInfo[gun_index]->EvBatterytargetCurrent >= afterReleaseMdCur - LIMIT_PWR_MODULE_GAP) ? false : true;
	}

	return result;
}

void ReleaseFork()
{
	pid_t releasePid;

	releasePid = fork();

	if(releasePid > 0)
	{
		bool isPass = false;
		struct ChargingInfoData *_chargingData[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY];

		while(!isPass)
		{
			isPass = true;
			for (byte _index = 0; _index < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; _index++)
			{
				if (!FindChargingInfoData(_index, &_chargingData[0]))
				{
					DEBUG_ERROR("Smartbox (ReleaseFork) : FindChargingInfoData false \n");
					isPass = false;
					break;
				}
			}
			sleep(1);
		}

		while(1)
		{
			for (byte gun_index = 0; gun_index < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; gun_index++)
			{
				if (chargingInfo[gun_index]->SystemStatus == SYS_MODE_CHARGING)
				{
					// ���X�h�l�s : �n�P�_�ҭn���X�s�үണ�Ѫ��̤j��q RealRatingPower
					// �����O�_���U�@�ӭn���X���s
					byte releaseGp = CheckReleasePwrByConIndex(gun_index);
					if (releaseGp != NONE_GROUP_CAN_SELECTED)
					{
						bool canRelease = GetCanReleaseResult(gun_index, releaseGp);

						if (chargingInfo[gun_index]->Type != _Type_Test &&
								ShmSmartBoxData->Dynamic4Fetch[gun_index].FetchLoopStep == _PSU_DYNAMIC_FETCH_STEP_NONE &&
								(ShmSmartBoxData->AnotherConnectorStatus[gun_index].ConnectorStaus == _CONNECTOR_STATUS_WAIT ||
								(ShmSmartBoxData->AnotherConnectorStatus[gun_index].NeedToFetch &&
									SMART_MODE && chargingInfo[gun_index]->_TakePsuGpCount > ShmDcCommonData->halfGroupCount) ||
								canRelease ||
								ShmDcCommonData->smartReleaseRun[gun_index])
							)
						{
							//PRINTF_FUNC("RealRatingPower = %d \n", chargingInfo[gun_index]->RealRatingPower);
							//PRINTF_FUNC("releasePwr = %d, needPower = %f \n", releasePwr, needPower);

							if (ShmSmartBoxData->Dynamic4Release[gun_index].ReleaseLoopStep == _PSU_DYNAMIC_RELEASE_STEP_NONE)
							{
								if (!ShmSmartBoxData->SmartChk[gun_index].IsReleaseStart)
								{
									PRINTF_FUNC("***** Entry release chk (Gun_%d).. ***** \n", gun_index);
									ShmSmartBoxData->SmartChk[gun_index].IsReleaseStart = YES;
									ShmSmartBoxData->Dynamic4Release[gun_index].CheckOutPwrIsStable = chargingInfo[gun_index]->PresentChargingPower;
									GetTimespecFunc(&ShmSmartBoxData->SmartChk[gun_index].ReleaseLoopTime);
								}
								else
								{
									int _delayt = GetTimeoutValue(&ShmSmartBoxData->SmartChk[gun_index].ReleaseLoopTime);

									// �C�����ݤ@����X��q�O�_í�w, í�w�h�i�J���t
									if (_delayt >= RELEASE_STABLE_CHK_TIME)
									{
										if (chargingInfo[gun_index]->PresentChargingPower >
												ShmSmartBoxData->Dynamic4Release[gun_index].CheckOutPwrIsStable + STABLE_CAP_GAP)
										{
											ShmSmartBoxData->Dynamic4Release[gun_index].CheckOutPwrIsStable = chargingInfo[gun_index]->PresentChargingPower;
											GetTimespecFunc(&ShmSmartBoxData->SmartChk[gun_index].ReleaseLoopTime);
										}
										else
										{
											// �i�Jí�w
											PRINTF_FUNC("***** RELEASE_STEP_WAIT ***** \n");
											ShmSmartBoxData->Dynamic4Release[gun_index].ReleaseLoopStep = _PSU_DYNAMIC_RELEASE_STEP_WAIT;
											GetTimespecFunc(&ShmSmartBoxData->SmartChk[gun_index].ReleaseLoopTime);
										}
									}
								}
							}
							else if (ShmSmartBoxData->Dynamic4Release[gun_index].ReleaseLoopStep == _PSU_DYNAMIC_RELEASE_STEP_WAIT)
							{
								int _delayt = GetTimeoutValue(&ShmSmartBoxData->SmartChk[gun_index].ReleaseLoopTime);

								// �C�����ݤ@����X��q�O�_í�w, í�w�h�i�J���t
								if (_delayt >= RELEASE_SMART_CHK_TIME)
								{
									PRINTF_FUNC("***** RELEASE_STEP_LIMIT ***** \n");
									ShmSmartBoxData->Dynamic4Release[gun_index].ReleaseGroup = releaseGp;
									ShmSmartBoxData->Dynamic4Release[gun_index].ReleaseLoopStep = _PSU_DYNAMIC_RELEASE_STEP_LIMIT;
									ShmDcCommonData->smartReleaseRun[gun_index] = NO;
								}
							}
						}
						else
						{
							// �ʺA���t�����_
							Chk2StopReleaseStep(gun_index);
						}
					}
				}
				else if (chargingInfo[gun_index]->SystemStatus == SYS_MODE_IDLE ||
						chargingInfo[gun_index]->SystemStatus == SYS_MODE_FAULT ||
						chargingInfo[gun_index]->SystemStatus == SYS_MODE_RESERVATION ||
						(chargingInfo[gun_index]->SystemStatus >= SYS_MODE_TERMINATING &&
							chargingInfo[gun_index]->SystemStatus <= SYS_MODE_ALARM))
				{
					if (ShmSmartBoxData->ConnectorStatus[gun_index].ConnectorStaus == _CONNECTOR_STATUS_NONE)
					{
						byte totoalUsingGpCount = ShmSmartBoxData->ConnectorUsingGroupCount[gun_index];

						for (byte _gp = 0; _gp < totoalUsingGpCount; _gp++)
						{
							PRINTF_FUNC("ConnectorUsingSeq[%d][%d] = %d \n", gun_index, _gp, ConnectorUsingSeq[gun_index][_gp]);
							ReleaseConnectorProcessing(gun_index, ConnectorUsingSeq[gun_index][_gp]);
						}

						if (ShmSmartBoxData->Dynamic4Fetch[gun_index].ShareGroup != NONE_GROUP_CAN_SELECTED &&
								ShmSmartBoxData->Dynamic4Fetch[gun_index].FetchLoopStep < _PSU_DYNAMIC_FETCH_STEP_FINISH)
							ShmSmartBoxData->Dynamic4Fetch[gun_index].FetchLoopStep = _PSU_DYNAMIC_FETCH_STEP_ABORT;

						ShmSmartBoxData->Dynamic4Release[gun_index].ReleaseLoopStep = _PSU_DYNAMIC_RELEASE_STEP_NONE;
					}

					if (ShmSmartBoxData->ConnectorStatus[gun_index].NeedToFetch)
						ShmSmartBoxData->ConnectorStatus[gun_index].NeedToFetch = NO;
				}

				ReleaseLoopProcessing(gun_index);
			}

			usleep(50000);
		}
	}
}

//==========================================
// Main Function
//==========================================
void TakeAnotherGunStatus(byte target)
{
	byte another = 0;

	if (target == 0)
		another = 1;

	ShmSmartBoxData->AnotherConnectorStatus[another].ConnectorStaus = ShmSmartBoxData->ConnectorStatus[target].ConnectorStaus;
	ShmSmartBoxData->AnotherConnectorStatus[another].NeedToFetch = ShmSmartBoxData->ConnectorStatus[target].NeedToFetch;
}

void AssignedPwr2Connector()
{
	for(byte _gun = 0; _gun < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; _gun++)
	{
		byte usingGroupCount = 0;
		float availablePwr = 0, availableCur = 0, iAvailableCur = 0, totalPsuCount = 0, kwAvailablePwr = 0;
		float outputVol = 0, outputCur = 0;
		float limitCur = 0, limitPwr = 0, remainCur = 0;

		for (byte group = 0; group < ShmPsuData->GroupCount; group++)
		{
			if (ShmPsuData->PsuGroup[group].UsingTarget == _gun)
			{
				usingGroupCount++;
				if (group != ShmSmartBoxData->Dynamic4Fetch[_gun].ShareGroup &&
						(group != ShmSmartBoxData->Dynamic4Release[_gun].ReleaseGroup ||
							ShmSmartBoxData->Dynamic4Release[_gun].ReleaseLoopStep <= _PSU_DYNAMIC_RELEASE_STEP_WAIT_FINISH))
				{
					availablePwr += ShmPsuData->PsuGroup[group].GroupAvailablePower;
					availableCur += ShmPsuData->PsuGroup[group].GroupAvailableCurrent;
					iAvailableCur += ShmPsuData->PsuGroup[group].TotalIAvailableCurrent;
					totalPsuCount += ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity;
					if (ShmPsuData->PsuGroup[group].TotalRatingPower <= 15 ||
							ShmPsuData->PsuGroup[group].TotalRatingPower > 30)
						kwAvailablePwr += (ShmPsuData->PsuGroup[group].GroupAvailablePower) / 10;
					else
						kwAvailablePwr += ShmPsuData->PsuGroup[group].TotalRatingPower;
				}

				// Release Loop �� : ��ڤW~ �q�y�|�� ....
				// �o�q, �u���٭n�d�����Ҷ���X�q�y�P��q�N�n
				if (group != ShmSmartBoxData->Dynamic4Release[_gun].ReleaseGroup &&
						ShmSmartBoxData->Dynamic4Release[_gun].ReleaseLoopStep == _PSU_DYNAMIC_RELEASE_STEP_LIMIT)
				{
					limitCur += ShmPsuData->PsuGroup[group].GroupTargetOutputCurrent;
					remainCur += ShmPsuData->PsuGroup[group].TotalIAvailableCurrent;
					limitPwr += ShmPsuData->PsuGroup[group].TotalRatingPower;
				}

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

				if (outputVol < ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage ||
						outputVol == 0)
					outputVol = ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage;
			}
		}

		chargingInfo[_gun]->AvailableChargingPower = availablePwr;
		chargingInfo[_gun]->AvailableChargingCurrent = availableCur;
		chargingInfo[_gun]->DeratingChargingCurrent = iAvailableCur;
		chargingInfo[_gun]->_TotalPsuCount = totalPsuCount;
		chargingInfo[_gun]->PresentChargingVoltage = outputVol / 10;

		// �b�C��̤j 1KW ��X��~ ���ڭ̰����@�U~
		if (chargingInfo[_gun]->SystemStatus == SYS_MODE_CHARGING)
		{
			if (chargingInfo[_gun]->RealMaxPower <= 10 && outputCur < (chargingInfo[_gun]->RealMaxCurrent * 0.9))
				outputCur = (chargingInfo[_gun]->RealMaxCurrent * 0.9);
		}

		chargingInfo[_gun]->PresentChargingCurrent = outputCur / 10;
		chargingInfo[_gun]->RealRatingPower = kwAvailablePwr * 10;
		chargingInfo[_gun]->_TakePsuGpCount = usingGroupCount;

		// ���j�ݭn�O�o�t�~�@��j�����A
		if (ShmSysConfigAndInfo->SysConfig.TotalConnectorCount > 1)
			TakeAnotherGunStatus(_gun);

		// �� Release group ���̤j�q�y
		if (ShmSmartBoxData->Dynamic4Release[_gun].ReleaseLoopStep == _PSU_DYNAMIC_RELEASE_STEP_LIMIT &&
				ShmSmartBoxData->Dynamic4Release[_gun].LimitPwrCap == 0)
		{
			// limitCur : �U���Ѿl�s���ݨD�q�y
			//ShmSmartBoxData->Dynamic4Release[_gun].LimitCurCap = limitCur;

			// Release ���y�Q�k(�`��) : �p�G�O����������۵M����~ ���ӳ��|�]���y�覡
			// ���p�@ : �s1 : 30A�A�s2 : 30A �@ 60A ��X�A�B��ڤW�s1 �i���Ѫ��q�y�� 75A (400V ��X)
			// ���p�G : �s1 : 75A�A�s2 : 75A �@ 150A ��X�A�B��ڤW�s1 �i���Ѫ��q�y�� 75A (400V ��X)
			// ���p�T : �s1 : 70A�A�s2 : 70A �@ 140A ��X�A�B��ڤW�s1 �i���Ѫ��q�y�� 75A (400V ��X)
			// ---------------------------------------------
			// ���p�@ : 60A  <= �s1�i���Ѫ� 75A : ���y
			// ���p�@ : 150A > �s1�i���Ѫ� 75A 	: �������_
			// ���p�@ : 140A > �s1�i���Ѫ� 75A 	: �������_
			if (chargingInfo[_gun]->PresentChargingCurrent <= remainCur)
			{
				PRINTF_FUNC("PresentChargingCurrent = %f, remainCur = %f \n", chargingInfo[_gun]->PresentChargingCurrent, remainCur / 10);
				limitCur = chargingInfo[_gun]->PresentChargingCurrent * 10;
				ShmSmartBoxData->Dynamic4Release[_gun].AutoRelease = YES;
			}
			else
				PRINTF_FUNC("limitCur = %f \n", limitCur);
			ShmSmartBoxData->Dynamic4Release[_gun].LimitCurCap = limitCur;
			ShmSmartBoxData->Dynamic4Release[_gun].LimitPwrCap = limitPwr * 10;
		}
	}
}

void CollectGroupInformation(byte group)
{
	int _groupPower = 0 , _groupCurrent = 0 , _groupMaxVoltage = 0;
	int Iavail = 0, Pavail = 0;
	unsigned short _outputVolBuf = 0, _outputCurBuf = 0;

	for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index ++)
	{
		// Cap
		_groupCurrent += ShmPsuData->PsuGroup[group].PsuModule[index].AvailableCurrent;
		_groupPower += ShmPsuData->PsuGroup[group].PsuModule[index].AvailablePower;

		if (ShmPsuData->PsuGroup[group].PsuModule[index].PresentMaxOutputVoltage > _groupMaxVoltage)
			_groupMaxVoltage = ShmPsuData->PsuGroup[group].PsuModule[index].PresentMaxOutputVoltage;

		// Iavailable
		Iavail += ShmPsuData->PsuGroup[group].PsuModule[index].IAvailableCurrent;
		Pavail += ShmPsuData->PsuGroup[group].PsuModule[index].KwAvailablePower;

		// output
		_outputCurBuf += ShmPsuData->PsuGroup[group].PsuModule[index].PresentOutputCurrent;

		if (_outputVolBuf == 0 ||
					(ShmPsuData->PsuGroup[group].PsuModule[index].PresentOutputVoltage > PSU_MIN_VOL &&
					_outputVolBuf < ShmPsuData->PsuGroup[group].PsuModule[index].PresentOutputVoltage))
		{
			_outputVolBuf = ShmPsuData->PsuGroup[group].PsuModule[index].PresentOutputVoltage;
		}
	}

	ShmPsuData->PsuGroup[group].GroupMaxVoltage = _groupMaxVoltage;
	ShmPsuData->PsuGroup[group].GroupAvailableCurrent = _groupCurrent;
	ShmPsuData->PsuGroup[group].GroupAvailablePower = _groupPower;

	ShmPsuData->PsuGroup[group].TotalIAvailableCurrent = Iavail;
	ShmPsuData->PsuGroup[group].TotalRatingPower = Pavail;

	ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage = _outputVolBuf;
	ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent = _outputCurBuf;
}

void CollectPsuInformation()
{
	int _sysPwr = 0, _sysCur = 0, _sysVol = 0;

	for (byte group = 0; group < ShmPsuData->GroupCount; group++)
	{
		// ���s��T
		CollectGroupInformation(group);

		// ��z�t�θ�T
		_sysPwr += ShmPsuData->PsuGroup[group].GroupAvailablePower;
		_sysCur += ShmPsuData->PsuGroup[group].GroupAvailableCurrent;

		if (ShmPsuData->PsuGroup[group].GroupMaxVoltage > _sysVol)
			_sysVol = ShmPsuData->PsuGroup[group].GroupMaxVoltage;
	}

	// �t��,�q��,�q�y,��q
	ShmPsuData->SystemAvailableCurrent = _sysCur;
	ShmPsuData->SystemAvailablePower = _sysPwr;
	GetSystemMaxVoltage();
}

//==========================================
// Main Loop
//==========================================
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;
	}

	Initialization();

	// ��R�q�j�ާ@ : �N�Ҷ����X�ӻP�ɤW�Ѿl���Ҷ��\�v
	FetchFork();
	ReleaseFork();

	GetTimespecFunc(&_log_time);
	while(1)
	{
		if (ShmPsuData->Work_Step >= GET_SYS_CAP)
		{
			// �����Ӧ� PSU ����T
			CollectPsuInformation();
			// �N�s��T���t��������ϥΤ��R�q�j
			AssignedPwr2Connector();

			int time = GetTimeoutValue(&_log_time);

			if (time < 0)
				GetTimespecFunc(&_log_time);

			// �C Priority �����O
			if (time > 5000)
			{
				//PrintfLog();
				GetTimespecFunc(&_log_time);
			}
		}

		if (ShmDcCommonData->systemType != _SYSTEM_TYPE_SIMPLE &&
				ShmPsuData->Work_Step == _WORK_CHARGING)
		{
			// ��������
			SmartRelayCheck();
		}
		usleep(50000);
	}

	return -1;
}