//---------------------------------------------------------------------------

#pragma hdrstop

#include "USBComm.h"
#include "common.h"
#include "MultiLanguage.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)

#define COMMAND_TYPE_NORMAL		0
#define COMMAND_TYPE_EXTRA		1

#define COMMAND_STATUS_NONE				0
#define COMMAND_STATUS_PENDING			1
#define COMMAND_STATUS_READY			2
#define COMMAND_STATUS_SENDING			3
#define COMMAND_STATUS_WAITING			4
#define COMMAND_STATUS_POLLING			5
#define COMMAND_STATUS_RECEIVE_READY	6
#define COMMAND_STATUS_RECEVING			7
#define COMMAND_STATUS_COMPLETE			8

#define OVERLAP_STATE_NONE				0
#define OVERLAP_STATE_PENDING			1
#define OVERLAP_STATE_READY				2
#define OVERLAP_STATE_POLLING			3
#define OVERLAP_STATE_COMPLETE			4

#define DF_STATUS_IDLE				0
#define DF_STATUS_SENDING			1
#define DF_STATUS_RECEVING			2

#define DEFAULT_WAITING_TIME        3000		// 3000ms
#define DEVICE_RESET_WAIT_TIME		1000
//#define DEVICE_RESET_WAIT_TIME		10000

#define BULKUSB_IOCTL_INDEX             0x0000
#define IOCTL_SETUP_IO 				CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_BULKUSB_RESET_PIPE 	CTL_CODE(FILE_DEVICE_UNKNOWN, BULKUSB_IOCTL_INDEX + 2, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_BULKUSB_RESET_DEVICE  CTL_CODE(FILE_DEVICE_UNKNOWN, BULKUSB_IOCTL_INDEX + 1, METHOD_BUFFERED, FILE_ANY_ACCESS)

#define min(x, y)	(x < y ? x : y)
//---------------------------------------------------------------------------
//TCommandUnit
//---------------------------------------------------------------------------
__fastcall TCommandUnit::TCommandUnit()
{
	Complete = false;
	Result = true;
	Type = COMMAND_TYPE_NORMAL;
	Overlapped = false;
	CompletionRoutine = NULL;
	DFStatus = DF_STATUS_IDLE;
	TransferTimeOut = DEFAULT_WAITING_TIME;
}
//---------------------------------------------------------------------------
__fastcall TUSBComm::TUSBComm()
{
	DeviceHandle = NULL;
	FConnected = false;
	LastErrorMessage = "";
	FDeviceName = "";

	FAbort = false;
	AutoRecover = false;
	FMaxWaitingTime = DEFAULT_WAITING_TIME;
	PacketID = 0;
	FIgnoreState = false;
	FVirtualState = false;

	FBusy = false;
	ProtocolVer = NEW_USB_PROTOCOL_VER;

	ol.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
}
//---------------------------------------------------------------------------
__fastcall TUSBComm::~TUSBComm()
{
	if (FConnected) Disconnect();
	CloseHandle(ol.hEvent);
}
//---------------------------------------------------------------------------
bool __fastcall TUSBComm::Connect(AnsiString deviceName)
{
	bool returnValue = true;
    if (FConnected) Disconnect();
    //DeviceHandle = CreateFile(deviceName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
    DeviceHandle = CreateFileA(deviceName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
    if (DeviceHandle == INVALID_HANDLE_VALUE)
	{
		LastErrorMessage = SysErrorMessage(GetLastError());
        returnValue = false;
    }

    if (returnValue == true)
	{
        FDeviceName = deviceName;
        FConnected = true;
	}
	else
    {
		FDeviceName = "";
        FConnected = false;
    }

	FIgnoreState = false;
    return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall TUSBComm::Disconnect(void)
{
	if (DeviceHandle)
	{
		CloseHandle(DeviceHandle);
		DeviceHandle = NULL;
	}
	FConnected = false;
	FDeviceName = "";

	return true;
}
//---------------------------------------------------------------------------
bool __fastcall TUSBComm::RequestCommand(unsigned short command, void *data, unsigned int dataLength,
	void *receiveBuffer, unsigned int receiveBufferMaxSize)
{
	if (FBusy)
	{
		LastErrorMessage = "Communication is in progress.";
		return false;
	}
	FBusy = true;
	if (!Connected)
	{
		LastErrorMessage = "The device is not connected.";
		FBusy = false;
		return false;
	}
	else if (FIgnoreState)
	{
		FBusy = false;
		return false;
	}

	// make command unit
	TCommandUnit *aCommandUnit = new TCommandUnit;
	aCommandUnit->Type = COMMAND_TYPE_NORMAL;
	aCommandUnit->Command = command;
	aCommandUnit->ShortData = data;
	aCommandUnit->ShortDataLength = dataLength;
	aCommandUnit->ReceiveBuffer = receiveBuffer;
	aCommandUnit->ReceiveBufferMaxSize = receiveBufferMaxSize;
	aCommandUnit->TransferTimeOut = FMaxWaitingTime;
	aCommandUnit->Status = COMMAND_STATUS_PENDING;

	if (ProtocolVer == NEW_USB_PROTOCOL_VER)
	{
		ProcessCommand(aCommandUnit);
	}
	else
	{
		ProcessCommand_OldVer(aCommandUnit);
	}

	bool result = aCommandUnit->Result;
	delete aCommandUnit;
	if (result == false)
	{
//		RecoverDevice();
	}
	FBusy = false;
	return result;
}
//---------------------------------------------------------------------------
bool __fastcall TUSBComm::RequestCommandEx(unsigned short command, void *shortData, unsigned int shortDataLength,
	void *longData, unsigned int longDataLength, void *receiveBuffer, unsigned int receiveBufferMaxSize,
	TUSBCompletionRoutine CompletionRoutine, TOverlapIOStr *OverlapIOStr)
{
	if (FBusy)
	{
		LastErrorMessage = "Communication is in progress.";
		return false;
	}
	FBusy = true;

	if (!Connected)
    {
    	LastErrorMessage = "The device is not connected.";
        FBusy = false;
        return false;
	}
	else if (FIgnoreState)
	{
        FBusy = false;
		return false;
	}

	// make command unit
	TCommandUnit *aCommandUnit = new TCommandUnit;
	aCommandUnit->Type = COMMAND_TYPE_EXTRA;
	aCommandUnit->Command = command;
	aCommandUnit->ShortData = shortData;
	aCommandUnit->ShortDataLength = shortDataLength;
	aCommandUnit->LongData = longData;
	aCommandUnit->LongDataLength = longDataLength;
	aCommandUnit->ReceiveBuffer = receiveBuffer;
	aCommandUnit->ReceiveBufferMaxSize = receiveBufferMaxSize;
	aCommandUnit->TransferTimeOut = FMaxWaitingTime;
	aCommandUnit->Status = COMMAND_STATUS_PENDING;
	if (CompletionRoutine)
	{
		aCommandUnit->Overlapped = true;
		aCommandUnit->OverlapState = OVERLAP_STATE_PENDING;
		aCommandUnit->CompletionRoutine = CompletionRoutine;
		aCommandUnit->OverlapIOStr = OverlapIOStr;
	}
	else
	{
		aCommandUnit->Overlapped = false;
	}

	// wait until command queue is empty
	unsigned long pollingStartTime = GetTickCount();

	pollingStartTime = GetTickCount();
/*
	if (!aCommandUnit->Overlapped)
	{
		// wait until end of transfer
		while(!aCommandUnit->Complete)
		{
			if (GetTickCount() - pollingStartTime > FMaxWaitingTime + THREAD_WAITING_DELAY)
			{
				LastErrorMessage = "통신 Timeout이 발생했습니다. Command = " + AnsiString((char)((aCommandUnit->Command >> 8) & 0xFF)) +
					AnsiString((char)(aCommandUnit->Command & 0xFF)) + ", Status = " + IntToStr(aCommandUnit->Status)
					+ ", DF Status = " + IntToStr(aCommandUnit->DFStatus);
//	            RecoverDevice();
				return false;
			}
		}
		bool result = aCommandUnit->Result;
		delete aCommandUnit;
		if (result == false)
		{
//			RecoverDevice();
		}
		return result;
	}
	else
	{
		OverlapThread->AddOverlapCommand(aCommandUnit);
		return true;
	}
*/
	//ProcessCommand(aCommandUnit);
	if (ProtocolVer == NEW_USB_PROTOCOL_VER)
	{
		ProcessCommand(aCommandUnit);
	}
	else
	{
		ProcessCommand_OldVer(aCommandUnit);
	}
	bool result = aCommandUnit->Result;
	delete aCommandUnit;
	FBusy = false;
	return result;
}
//---------------------------------------------------------------------------
AnsiString __fastcall TUSBComm::GetLastErrorMessage(void)
{
	return LastErrorMessage;
}
//---------------------------------------------------------------------------
void __fastcall TUSBComm::SetDefaultMaxWaitingTime(void)
{
	FMaxWaitingTime = DEFAULT_WAITING_TIME;
}
//---------------------------------------------------------------------------
void __fastcall TUSBComm::ProcessCommand(TCommandUnit *aCommandUnit)
{
	unsigned int responseData[1];
	unsigned int receivedLength;
	unsigned int lastStatusTime;
	lastStatusTime = GetTickCount();

	while (!FAbort)
    {
		bool bSuccess = true;

		if (aCommandUnit->Status == COMMAND_STATUS_PENDING)
		{
			aCommandUnit->Status = COMMAND_STATUS_READY;
		}

		if (aCommandUnit->Status == COMMAND_STATUS_READY || aCommandUnit->Status == COMMAND_STATUS_WAITING)
		{
			aCommandUnit->Status = COMMAND_STATUS_SENDING;
			if (aCommandUnit->Type == COMMAND_TYPE_NORMAL)
			{
				aCommandUnit->DFStatus = DF_STATUS_SENDING;
				if (!SendCommand(aCommandUnit->Command, aCommandUnit->ShortData, aCommandUnit->ShortDataLength, CMD_TYPE_APP_REQUEST, aCommandUnit->TransferTimeOut))
				{
					bSuccess = false;
				}
				if (bSuccess)
				{
					aCommandUnit->DFStatus = DF_STATUS_RECEVING;
					if (!ReceiveCommand(responseData, 4, &receivedLength, aCommandUnit->TransferTimeOut))
					{
						bSuccess = false;
					}
				}
				aCommandUnit->DFStatus = DF_STATUS_IDLE;
				aCommandUnit->Result = bSuccess;
			}
			else		// ex type
			{
				aCommandUnit->DFStatus = DF_STATUS_SENDING;
				if (!SendCommandEx(aCommandUnit->Command, aCommandUnit->ShortData, aCommandUnit->ShortDataLength,
					aCommandUnit->LongData, aCommandUnit->LongDataLength, CMD_TYPE_APP_REQUEST, aCommandUnit->TransferTimeOut))
				{
					bSuccess = false;
				}
				if (bSuccess)
				{
					aCommandUnit->DFStatus = DF_STATUS_RECEVING;
					if (!ReceiveCommand(responseData, 4, &receivedLength, aCommandUnit->TransferTimeOut))
					{
						bSuccess = false;
					}
				}
				aCommandUnit->DFStatus = DF_STATUS_IDLE;
				aCommandUnit->Result = bSuccess;
			}

			if (bSuccess)
			{
				if (responseData[0])
				{
					aCommandUnit->Status = COMMAND_STATUS_POLLING;
				}
				else
				{
					aCommandUnit->Status = COMMAND_STATUS_WAITING;
				}
			}
			else
			{
				if (AutoRecover)
				{
					RecoverDevice();
					aCommandUnit->Status = COMMAND_STATUS_READY;
				}
				else
				{
					aCommandUnit->Result = false;
					aCommandUnit->Complete = true;
					aCommandUnit->Status = COMMAND_STATUS_COMPLETE;
				}
			}
		}
		else if (aCommandUnit->Status == COMMAND_STATUS_POLLING)
		{
			aCommandUnit->DFStatus = DF_STATUS_SENDING;
			if (!SendCommand(aCommandUnit->Command, NULL, 0, CMD_TYPE_APP_POLLING_RESULT, aCommandUnit->TransferTimeOut))
			{
				bSuccess = false;
			}
			if (bSuccess)
			{
				aCommandUnit->DFStatus = DF_STATUS_RECEVING;
				if (!ReceiveCommand(responseData, 4, &receivedLength, aCommandUnit->TransferTimeOut))
				{
					bSuccess = false;
				}
			}
			aCommandUnit->DFStatus = DF_STATUS_IDLE;
			if (bSuccess)
			{
				if (responseData[0])
				{
					aCommandUnit->Status = COMMAND_STATUS_RECEIVE_READY;
				}
			}
			else
			{
				if (AutoRecover)
				{
					RecoverDevice();
					aCommandUnit->Status = COMMAND_STATUS_READY;
				}
				else
				{
					aCommandUnit->Result = false;
					aCommandUnit->Complete = true;
					aCommandUnit->Status = COMMAND_STATUS_COMPLETE;
				}
			}
		}
		else if (aCommandUnit->Status == COMMAND_STATUS_RECEIVE_READY)
		{
			aCommandUnit->Status = COMMAND_STATUS_RECEVING;
			aCommandUnit->DFStatus = DF_STATUS_SENDING;
			if (!SendCommand(aCommandUnit->Command, NULL, 0, CMD_TYPE_APP_RECEIVE_RESULT, aCommandUnit->TransferTimeOut))
			{
				bSuccess = false;
			}
			if (bSuccess)
			{
				if (aCommandUnit->ReceiveBufferMaxSize % 4 == 0)
				{
					aCommandUnit->DFStatus = DF_STATUS_RECEVING;
					if (!ReceiveCommand(aCommandUnit->ReceiveBuffer, aCommandUnit->ReceiveBufferMaxSize, &receivedLength, aCommandUnit->TransferTimeOut))
					{
						bSuccess = false;
					}
				}
				else
				{
					unsigned char *tempBuffer = new unsigned char[(aCommandUnit->ReceiveBufferMaxSize + 3) / 4 * 4];
					aCommandUnit->DFStatus = DF_STATUS_RECEVING;
					if (!ReceiveCommand(tempBuffer, (aCommandUnit->ReceiveBufferMaxSize + 3) / 4 * 4, &receivedLength, aCommandUnit->TransferTimeOut))
					{
						bSuccess = false;
					}
					else
					{
						if (receivedLength > aCommandUnit->ReceiveBufferMaxSize)
						{
							receivedLength = aCommandUnit->ReceiveBufferMaxSize;
						}
						memcpy(aCommandUnit->ReceiveBuffer, tempBuffer, receivedLength);
					}
					delete[] tempBuffer;
				}
			}
			aCommandUnit->DFStatus = DF_STATUS_IDLE;

			if (bSuccess)
			{
				aCommandUnit->Result = true;
				aCommandUnit->Complete = true;
				aCommandUnit->Status = COMMAND_STATUS_COMPLETE;
			}
			else
			{
				if (AutoRecover)
				{
					RecoverDevice();
					aCommandUnit->Status = COMMAND_STATUS_READY;
				}
				else
				{
					aCommandUnit->Result = false;
					aCommandUnit->Complete = true;
					aCommandUnit->Status = COMMAND_STATUS_COMPLETE;
				}
			}
		}
		else if (aCommandUnit->Status == COMMAND_STATUS_COMPLETE)
		{
			break;
		}
		//Sleep(100);
	}
}
//---------------------------------------------------------------------------
bool __fastcall TUSBComm::SendData(void *data, int dataLength, unsigned int writeStartTime, int timeout)
{
	DWORD dwWriteSize, error;
	bool returnValue = true;
		if (!WriteFile(DeviceHandle, data, dataLength, &dwWriteSize, &ol))
		{
			do
			{
				error = GetLastError();
				if (error == ERROR_IO_PENDING || error == ERROR_IO_INCOMPLETE)
				{
					if (GetTickCount() - writeStartTime > timeout)
					{
						LastErrorMessage = "USB Write timeout occurs";
						returnValue = false;
						break;
					}
				}
				else
				{
          LastErrorMessage = "USB Write Failed";
					returnValue = false;
					break;
				}
			}
			while (GetOverlappedResult(DeviceHandle, &ol, &dwWriteSize, FALSE) == FALSE);
		}

		if (returnValue == true && dwWriteSize != dataLength)
		{
       LastErrorMessage = "USB read timeout occurs (S)";
			returnValue = false;
		}
	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall TUSBComm::SendCommand(unsigned short command, void *data, unsigned int dataLength,
	unsigned short type, int timeout)
{
	bool returnValue = true;
	int transferDataLength = (dataLength + 3) / 4 * 4;

	TXDataHeader.Header      		= USB_PACKET_HEADER;
	TXDataHeader.Command     		= command;
	TXDataHeader.SmallDataLength 	= transferDataLength;
	TXDataHeader.LargeDataLength  	= 0;
	TXDataHeader.RequestKind 		= type;

	unsigned int writeStartTime = GetTickCount();

	try
	{
	// send header
		if (!SendData(&TXDataHeader, sizeof(TUSBDataHeader), writeStartTime, timeout))
		{
			throw Exception("Can not Send Header");                                           //수정
		}

		int remainDataSize = transferDataLength;
		unsigned char *pTransferData = (unsigned char *)data;

		while (remainDataSize > 0)
		{
			int sendDataLength = min(remainDataSize, USB_MAX_TRANSFER_SIZE);
			if (!SendData(pTransferData, sendDataLength, writeStartTime, timeout))
			{
				throw Exception("Can not Send Data");                                     // 수정
			}
			pTransferData += sendDataLength;
			remainDataSize -= sendDataLength;
		}
	}
	catch (...)
	{
		returnValue = false;
	}
	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall TUSBComm::SendCommandEx(unsigned short command, void *shortData, unsigned int shortDataLength,
	void *longData, unsigned int longDataLength, unsigned short type, int timeout)
{
	bool returnValue = true;
	int transferShortDataLength = (shortDataLength + 3) / 4 * 4;
	int transferLongDataLength = (longDataLength + 3) / 4 * 4;

	TXDataHeader.Header      		= USB_PACKET_HEADER;
	TXDataHeader.Command     		= command;
	TXDataHeader.SmallDataLength 	= transferShortDataLength;
	TXDataHeader.LargeDataLength  	= transferLongDataLength;
	TXDataHeader.RequestKind 		= type;


	unsigned char *pTransferData;
	unsigned int writeStartTime = GetTickCount();

	try
	{
	// send header
		if (!SendData(&TXDataHeader, sizeof(TUSBDataHeader), writeStartTime, timeout))
		{
			throw Exception("Can not Send Header");
		}

		int remainShortDataSize = transferShortDataLength;
		pTransferData = (unsigned char *)shortData;
		while (remainShortDataSize > 0)
		{
			int sendDataLength = min(remainShortDataSize, USB_MAX_TRANSFER_SIZE);
			if (!SendData(pTransferData, sendDataLength, writeStartTime, timeout))
			{
				throw Exception("Can not Send Small Data");
			}
			pTransferData += sendDataLength;
			remainShortDataSize -= sendDataLength;
		}

		int remainLongDataSize = transferLongDataLength;
		pTransferData = (unsigned char *)longData;
		while (remainLongDataSize > 0)
		{
			int sendDataLength = min(remainLongDataSize, USB_MAX_TRANSFER_SIZE);
			if (!SendData(pTransferData, sendDataLength, writeStartTime, timeout))
			{
				throw Exception("Can not Send Large Data");
			}
			pTransferData += sendDataLength;
			remainLongDataSize -= sendDataLength;
		}
	}
	catch (...)
	{
		returnValue = false;
	}

	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall TUSBComm::ReceiveData(void *data, int dataLength, int *readCount, unsigned int readStartTime, int timeout)
{
	DWORD dwReadSize, error;
	bool returnValue = true;

	if (!ReadFile(DeviceHandle, data, dataLength, &dwReadSize, &ol))
	{
		do
		{
			error = GetLastError();
			if (error == ERROR_IO_PENDING || error == ERROR_IO_INCOMPLETE)
			{
				if (GetTickCount() - readStartTime > timeout)
				{
         LastErrorMessage = "USB read timeout occurs";
					returnValue = false;
					break;
				}
			}
			else
			{
	 LastErrorMessage = "USB reading failure";
				returnValue = false;
				break;
			}
		}
		while (GetOverlappedResult(DeviceHandle, &ol, &dwReadSize, FALSE) == FALSE);
	}
	if (returnValue == true && dataLength != dwReadSize)
	{
        LastErrorMessage = "USB read size error";
		returnValue = false;
	}
	*readCount = dwReadSize;
	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall TUSBComm::ReceiveCommand(void *receiveBuffer, unsigned int receiveBufferMaxSize,
	unsigned int *receivedLength, int timeout)
{
	bool returnValue = true;
	unsigned int rxCount;
	DWORD dwReadSize;
	unsigned int dataSize;
	int readCount;
	int dataPos = 0;
	unsigned char *buffer;
	unsigned int bufferMaxSize;
	if (receiveBuffer == NULL)
	{
		//buffer = (unsigned char *)RXPacketBuf + USB_PACKET_HEADER_SIZE * sizeof(int);
		//bufferMaxSize = (PACKET_MAX_SIZE - USB_PACKET_HEADER_SIZE) * sizeof(int);
		buffer = NULL;
		bufferMaxSize = 0;
	}
	else
	{
		buffer = (unsigned char *)receiveBuffer;
		bufferMaxSize = receiveBufferMaxSize;
	}

	DWORD error;
	BOOL ret;
	bool bError = false;
	unsigned int readStartTime = GetTickCount();


	try
	{
	// read Header
		if (!ReceiveData(&RXDataHeader, sizeof(TUSBDataHeader), &readCount, readStartTime, timeout))
		{
			throw Exception("Can not Receive Header");
		}

		if (readCount != sizeof(TUSBDataHeader))
		{
     LastErrorMessage = "USB read size err (H)";
			throw Exception("Wrong Header Size");
		}

		if (RXDataHeader.Header != USB_PACKET_HEADER)
		{
     LastErrorMessage = "Wrong Header";
			throw Exception("To be received data are too large.");
		}

		if (RXDataHeader.SmallDataLength > 0)
		{
			if (dataPos + RXDataHeader.SmallDataLength <= bufferMaxSize)
			{
				if (!ReceiveData(&buffer[dataPos], RXDataHeader.SmallDataLength, &readCount, readStartTime, timeout))
				{
					throw Exception("Can not Receive Small Data");
				}
				dataPos += RXDataHeader.SmallDataLength;
			}
			else
			{
       LastErrorMessage = "To be received data are too large.";
				throw Exception("To be received data are too large.");
			}
		}

		if (RXDataHeader.LargeDataLength > 0)
		{
			if (dataPos + RXDataHeader.LargeDataLength <= bufferMaxSize)
			{
				int remainDataSize = RXDataHeader.LargeDataLength;
				int readLength;
				while (remainDataSize)
				{
					if (remainDataSize < USB_MAX_TRANSFER_SIZE)
					{
						readLength = remainDataSize;
					}
					else
					{
						readLength = USB_MAX_TRANSFER_SIZE;
					}

					if (!ReceiveData(&buffer[dataPos], readLength, &readCount, readStartTime, timeout))
					{
						throw Exception("Can not Receive Large Data");
					}
					dataPos += readLength;
					remainDataSize -= readLength;
				}
			}
			else
			{

       LastErrorMessage = "To be received data are too large(L).";
				throw Exception("To be received data are too large(L).");
			}
		}
	}
	catch (...)
	{
		returnValue = false;
	}

    *receivedLength = dataPos;
    return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall TUSBComm::RecoverDevice(void)
{
	bool returnValue;
	DWORD readByte;
//	TUSBControlData USBControlData;
//	USBControlData.func = CONTROL_FUNC_RESET;
    FIgnoreState = false;

	try
	{
		TTransferInfo transferInfo;
		transferInfo.Size = 0;
		transferInfo.Index = 0;
		transferInfo.Type = TRANSFER_INFO_TYPE_RESET;

		if (DeviceHandle)
		{
			if (!CancelIo(DeviceHandle))
			{
			       throw(Exception(SysErrorMessage(GetLastError())));
			}
			// reset pipe
//			DeviceIoControl(DeviceHandle, IOCTL_BULKUSB_RESET_PIPE, NULL, 0, NULL, 0, &readByte, &ol);
/*
			if (!DeviceIoControl(DeviceHandle, IOCTL_BULKUSB_RESET_DEVICE, NULL, 0, NULL, 0, &readByte, &ol))
			{
				throw(Exception("<IoControl failure> " + SysErrorMessage(GetLastError())));
			}
*/

			if (!DeviceIoControl(DeviceHandle, IOCTL_SETUP_IO, &transferInfo, sizeof(TTransferInfo), NULL, 0, &readByte, &ol))
			{
			       throw(Exception("<IoControl failure> " + SysErrorMessage(GetLastError())));
			}
			if (!CloseHandle(DeviceHandle))
			{
			       throw(Exception(SysErrorMessage(GetLastError())));
			}
			DeviceHandle = NULL;
			Sleep(DEVICE_RESET_WAIT_TIME);
		}
		Sleep(DEVICE_RESET_WAIT_TIME);
		DeviceHandle = CreateFileA(FDeviceName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
		if (DeviceHandle == INVALID_HANDLE_VALUE)
		{
			FConnected = false;
			returnValue = false;
		       throw(Exception(SysErrorMessage(GetLastError())));
		}
		else
		{
			FConnected = true;
			returnValue = true;
		}

//	returnValue = DeviceIoControl(DeviceHandle, IOCTL_SETUP_IO, &USBControlData, sizeof(TUSBControlData), NULL, 0, &readByte, &ol);
/*
		returnValue = DeviceIoControl(DeviceHandle, IOCTL_SETUP_IO, &transferInfo, sizeof(TTransferInfo), NULL, 0, &readByte, &ol);
		if (!returnValue)
		{
			//LastErrorMessage = "<IoControl failure> " + SysErrorMessage(GetLastError());
			throw(Exception("<IoControl failure> " + SysErrorMessage(GetLastError())));
		}
*/
//		Sleep(DEVICE_RESET_WAIT_TIME);

	}
	catch (Exception &ec)
	{
		LastErrorMessage = ec.Message;
		if (DeviceHandle != INVALID_HANDLE_VALUE && DeviceHandle != NULL)
		{
			CloseHandle(DeviceHandle);
			DeviceHandle = NULL;
			Sleep(DEVICE_RESET_WAIT_TIME);
		}
		DeviceHandle = CreateFileA(FDeviceName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
		if (DeviceHandle == INVALID_HANDLE_VALUE)
		{
			FConnected = false;
			returnValue = false;
		}
		else
		{
			FConnected = true;
			returnValue = true;
		}
	}

	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall TUSBComm::RequestStallTest(int stallEvent)
{
/*
	bool returnValue = true;
	unsigned char TXPacketBuf[PACKET_MAX_SIZE], RXPacketBuf[PACKET_MAX_SIZE];
	TUSBPacket *TXPacket = (TUSBPacket *)TXPacketBuf;
	TUSBPacket *RXPacket = (TUSBPacket *)RXPacketBuf;
	DWORD dwWriteSize, dwReadSize;
	int stallMode[1];
	if (stallEvent == 0)
	{
		stallMode[0] = stallEvent;
		int dataLength = sizeof(int);
		int readLength = 10;
		TXPacket->header      = 0xA5A5;
		TXPacket->mode        = 1;
		TXPacket->shortLength = SizeOfWord(dataLength) + USB_PACKET_HEADER_SIZE;
	    TXPacket->longLength  = 0;
	    TXPacket->type        = CMD_TYPE_STALL_TEST;
	    TXPacket->command     = CMD_ECHO;
	    TXPacket->source      = BOARD_ID_PC;
	    TXPacket->destination = BOARD_ID_SPB(1);
	    TXPacket->packetID    = 0;

        memcpy(TXPacket->data, stallMode, dataLength);

		if (WriteFile(DeviceHandle, TXPacket, TXPacket->shortLength * sizeof(int), &dwWriteSize, NULL))
		{

	    }
	    else
	    {
	        returnValue = false;
	        LastErrorMessage = "USB 쓰기 실패(H) : " + SysErrorMessage(GetLastError());
	    }
		if (!returnValue) return returnValue;
		if (ReadFile(DeviceHandle, RXPacket, USB_PACKET_HEADER_SIZE * sizeof(int), &dwReadSize, NULL))
		{
        	if (ReadFile(DeviceHandle, RXPacket->data, readLength, &dwReadSize, NULL))
            {
                returnValue = true;
			}
            else
            {
            	returnValue = false;
                LastErrorMessage = "USB 읽기 실패(S) : " + SysErrorMessage(GetLastError());
//                    error = true;
			}
	    }
	    else
	    {
	    	returnValue = false;
	        LastErrorMessage = "USB 읽기 실패(H) : " + SysErrorMessage(GetLastError());
		}
    }
    return returnValue;
*/    
}
//---------------------------------------------------------------------------
void __fastcall TUSBComm::ProtocolCheck(void)
{
	unsigned int echoTX, echoRX;
	// new protocol 을 이용해서 2회 전송 시도
	ProtocolVer = NEW_USB_PROTOCOL_VER;
	if (RequestCommand(CMD_ECHO, &echoTX, 4, &echoRX, 4))
	{
		return;
	}
	RecoverDevice();
	if (RequestCommand(CMD_ECHO, &echoTX, 4, &echoRX, 4))
	{
		return;
	}
	RecoverDevice();
	// old protocol 을 이용해서 2회 전송 시도
	ProtocolVer = OLD_USB_PROTOCOL_VER;
	if (RequestCommand(CMD_ECHO, &echoTX, 4, &echoRX, 4))
	{
		return;
	}
	if (RequestCommand(CMD_ECHO, &echoTX, 4, &echoRX, 4))
	{
		return;
	}
	// 실패시 New Protocol로 간주한다.
	ProtocolVer = NEW_USB_PROTOCOL_VER;
}
//---------------------------------------------------------------------------
void __fastcall TUSBComm::ProcessCommand_OldVer(TCommandUnit *aCommandUnit)
{
	unsigned int responseData[1];
	unsigned int receivedLength;
	unsigned int lastStatusTime;
	lastStatusTime = GetTickCount();

	while (!FAbort)
	{
		bool bSuccess = true;

		if (aCommandUnit->Status == COMMAND_STATUS_PENDING)
		{
			aCommandUnit->Status = COMMAND_STATUS_READY;
		}

		if (aCommandUnit->Status == COMMAND_STATUS_READY || aCommandUnit->Status == COMMAND_STATUS_WAITING)
		{
			aCommandUnit->Status = COMMAND_STATUS_SENDING;
			if (aCommandUnit->Type == COMMAND_TYPE_NORMAL)
			{
				aCommandUnit->DFStatus = DF_STATUS_SENDING;
				if (!SendCommand_OldVer(aCommandUnit->Command, aCommandUnit->ShortData, aCommandUnit->ShortDataLength, CMD_TYPE_APP_REQUEST, aCommandUnit->TransferTimeOut))
				{
					bSuccess = false;
				}
				if (bSuccess)
				{
					aCommandUnit->DFStatus = DF_STATUS_RECEVING;
					if (!ReceiveCommand_OldVer(responseData, 4, &receivedLength, aCommandUnit->TransferTimeOut))
					{
						bSuccess = false;
					}
				}
				aCommandUnit->DFStatus = DF_STATUS_IDLE;
				aCommandUnit->Result = bSuccess;
			}
			else		// ex type
			{
				aCommandUnit->DFStatus = DF_STATUS_SENDING;
				if (!SendCommandEx_OldVer(aCommandUnit->Command, aCommandUnit->ShortData, aCommandUnit->ShortDataLength,
					aCommandUnit->LongData, aCommandUnit->LongDataLength, CMD_TYPE_APP_REQUEST, aCommandUnit->TransferTimeOut))
				{
					bSuccess = false;
				}
				if (bSuccess)
				{
					aCommandUnit->DFStatus = DF_STATUS_RECEVING;
					if (!ReceiveCommand_OldVer(responseData, 4, &receivedLength, aCommandUnit->TransferTimeOut))
					{
						bSuccess = false;
					}
				}
				aCommandUnit->DFStatus = DF_STATUS_IDLE;
				aCommandUnit->Result = bSuccess;
			}

			if (bSuccess)
			{
				if (responseData[0])
				{
					aCommandUnit->Status = COMMAND_STATUS_POLLING;
				}
				else
				{
					aCommandUnit->Status = COMMAND_STATUS_WAITING;
				}
			}
			else
			{
				if (AutoRecover)
				{
					RecoverDevice();
					aCommandUnit->Status = COMMAND_STATUS_READY;
				}
				else
				{
					aCommandUnit->Result = false;
					aCommandUnit->Complete = true;
					aCommandUnit->Status = COMMAND_STATUS_COMPLETE;
				}
			}
		}
		else if (aCommandUnit->Status == COMMAND_STATUS_POLLING)
		{
			aCommandUnit->DFStatus = DF_STATUS_SENDING;
			if (!SendCommand_OldVer(aCommandUnit->Command, NULL, 0, CMD_TYPE_APP_POLLING_RESULT, aCommandUnit->TransferTimeOut))
			{
				bSuccess = false;
			}
			if (bSuccess)
			{
				aCommandUnit->DFStatus = DF_STATUS_RECEVING;
				if (!ReceiveCommand_OldVer(responseData, 4, &receivedLength, aCommandUnit->TransferTimeOut))
				{
					bSuccess = false;
				}
			}
			aCommandUnit->DFStatus = DF_STATUS_IDLE;
			if (bSuccess)
			{
				if (responseData[0])
				{
					aCommandUnit->Status = COMMAND_STATUS_RECEIVE_READY;
				}
			}
			else
			{
				if (AutoRecover)
				{
					RecoverDevice();
					aCommandUnit->Status = COMMAND_STATUS_READY;
				}
				else
				{
					aCommandUnit->Result = false;
					aCommandUnit->Complete = true;
					aCommandUnit->Status = COMMAND_STATUS_COMPLETE;
				}
			}
		}
		else if (aCommandUnit->Status == COMMAND_STATUS_RECEIVE_READY)
		{
			aCommandUnit->Status = COMMAND_STATUS_RECEVING;
			aCommandUnit->DFStatus = DF_STATUS_SENDING;
			if (!SendCommand_OldVer(aCommandUnit->Command, NULL, 0, CMD_TYPE_APP_RECEIVE_RESULT, aCommandUnit->TransferTimeOut))
			{
				bSuccess = false;
			}
			if (bSuccess)
			{
				if (aCommandUnit->ReceiveBufferMaxSize % 4 == 0)
				{
					aCommandUnit->DFStatus = DF_STATUS_RECEVING;
					if (!ReceiveCommand_OldVer(aCommandUnit->ReceiveBuffer, aCommandUnit->ReceiveBufferMaxSize, &receivedLength, aCommandUnit->TransferTimeOut))
					{
						bSuccess = false;
					}
				}
				else
				{
					unsigned char *tempBuffer = new unsigned char[(aCommandUnit->ReceiveBufferMaxSize + 3) / 4 * 4];
					aCommandUnit->DFStatus = DF_STATUS_RECEVING;
					if (!ReceiveCommand_OldVer(tempBuffer, (aCommandUnit->ReceiveBufferMaxSize + 3) / 4 * 4, &receivedLength, aCommandUnit->TransferTimeOut))
					{
						bSuccess = false;
					}
					else
					{
						if (receivedLength > aCommandUnit->ReceiveBufferMaxSize)
						{
							receivedLength = aCommandUnit->ReceiveBufferMaxSize;
						}
						memcpy(aCommandUnit->ReceiveBuffer, tempBuffer, receivedLength);
					}
					delete[] tempBuffer;
				}
			}
			aCommandUnit->DFStatus = DF_STATUS_IDLE;

			if (bSuccess)
			{
				aCommandUnit->Result = true;
				aCommandUnit->Complete = true;
				aCommandUnit->Status = COMMAND_STATUS_COMPLETE;
			}
			else
			{
				if (AutoRecover)
				{
					RecoverDevice();
					aCommandUnit->Status = COMMAND_STATUS_READY;
				}
				else
				{
					aCommandUnit->Result = false;
					aCommandUnit->Complete = true;
					aCommandUnit->Status = COMMAND_STATUS_COMPLETE;
				}
			}
		}
		else if (aCommandUnit->Status == COMMAND_STATUS_COMPLETE)
		{
			break;
		}
		//Sleep(100);
	}
}
//---------------------------------------------------------------------------
bool __fastcall TUSBComm::SendCommand_OldVer(unsigned short command, void *data, unsigned int dataLength,
	unsigned short type, int timeout)
{
	bool returnValue = true;
	DWORD dwWriteSize;
	int transferDataLength = (dataLength + 3) / 4 * 4;
	TUSBDataHeader_OldVer TXDataHeader;
	TTransferPacket_OldVer USBTxPacket;


	TXDataHeader.header      = 0xA5A5;
	TXDataHeader.shortLength = SizeOfWord(transferDataLength) + USB_PACKET_HEADER_SIZE_OLDVER;
	TXDataHeader.longLength  = 0;
	TXDataHeader.type        = type;
	TXDataHeader.command     = command;
	TXDataHeader.source      = BOARD_ID_PC;
	TXDataHeader.destination = BOARD_ID_SPB(1);
	TXDataHeader.dataID      = PacketID++;

	DWORD dwWrite;
	DWORD error;
	unsigned int writeStartTime = GetTickCount();

	int remainSize = USB_PACKET_HEADER_SIZE_OLDVER * 4 + transferDataLength;
	int copyLength;
	unsigned char *pTransferData = NULL;
	int transferLength;
	unsigned int packetIndex = 0;
	
	while (remainSize > 0)
	{
		if (pTransferData == NULL)		// first data
		{								// copy header

			memcpy(USBTxPacket.Data, &TXDataHeader, USB_PACKET_HEADER_SIZE_OLDVER * 4);
			transferLength = USB_PACKET_HEADER_SIZE_OLDVER * 4;
			if (transferDataLength > 0)
			{
				copyLength = min(transferDataLength, USB_TRANSFER_MAX_SIZE_OLDVER - transferLength);
				pTransferData = (unsigned char *)data;
				memcpy(USBTxPacket.Data + USB_PACKET_HEADER_SIZE_OLDVER * 4, pTransferData, copyLength);
				transferLength += copyLength;
				pTransferData += copyLength;
				remainSize = transferDataLength - copyLength;
			}
			else
			{
				remainSize = 0;
			}
		}
		else
		{
			copyLength = min(remainSize, USB_TRANSFER_MAX_SIZE_OLDVER);
			memcpy(USBTxPacket.Data, pTransferData, copyLength);
			pTransferData += copyLength;
			remainSize -= copyLength;
			transferLength = copyLength;
		}

		USBTxPacket.PacketIndex = packetIndex;
		USBTxPacket.Checksum = CheckSum((unsigned int *)USBTxPacket.Data, transferLength / 4);
		transferLength += 8;

		if (!WriteFile(DeviceHandle, &USBTxPacket, transferLength, &dwWriteSize, &ol))
		{
			if (GetLastError() == ERROR_IO_PENDING)
			{
				while(!GetOverlappedResult(DeviceHandle, &ol, &dwWriteSize, FALSE))
				{
					error = GetLastError();
					if (error == ERROR_IO_INCOMPLETE)
					{
						if (GetTickCount() - writeStartTime > timeout)
						{
							LastErrorMessage = "USB Write timeout occurs";
							returnValue = false;
							break;
						}
					}
					else
					{
					LastErrorMessage = "USB Write Failed";
						returnValue = false;
						break;
					}
				}
			}
		}
		
		if (dwWriteSize != transferLength)
		{
			 LastErrorMessage = "USB Write Failed";

			returnValue = false;
			break;
		}

		if (returnValue == false) break;
		packetIndex++;
	}



	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall TUSBComm::SendCommandEx_OldVer(unsigned short command, void *shortData, unsigned int shortDataLength,
	void *longData, unsigned int longDataLength, unsigned short type, int timeout)
{
	bool returnValue = true;
	DWORD dwWriteSize;
	int transferShortDataLength = (shortDataLength + 3) / 4 * 4;
	int transferLongDataLength = (longDataLength + 3) / 4 * 4;

	TUSBDataHeader_OldVer TXDataHeader;
	TTransferPacket_OldVer USBTxPacket;	
	TXDataHeader.header      = 0xA5A5;
	TXDataHeader.shortLength = SizeOfWord(transferShortDataLength) + USB_PACKET_HEADER_SIZE_OLDVER;
	TXDataHeader.longLength  = SizeOfWord(transferLongDataLength);
	TXDataHeader.type        = type;
	TXDataHeader.command     = command;
	TXDataHeader.source      = BOARD_ID_PC;
	TXDataHeader.destination = BOARD_ID_SPB(1);
	TXDataHeader.dataID      = PacketID++;

	DWORD dwWrite;
	DWORD error;
	unsigned int writeStartTime = GetTickCount();

	int remainShortDataSize = USB_PACKET_HEADER_SIZE_OLDVER * 4 + transferShortDataLength;
	int remainLongDataSize = transferLongDataLength;
	int copyLength;
	unsigned char *pTransferData = NULL;
	int transferLength;
	unsigned int packetIndex = 0;

	while (remainShortDataSize > 0 || remainLongDataSize > 0)
	{
		if (pTransferData == NULL)		// first data
		{								// copy header
			memcpy(USBTxPacket.Data, &TXDataHeader, USB_PACKET_HEADER_SIZE_OLDVER * 4);
			transferLength = USB_PACKET_HEADER_SIZE_OLDVER * 4;
			if (transferShortDataLength > 0)
			{
				copyLength = min(transferShortDataLength, USB_TRANSFER_MAX_SIZE_OLDVER - transferLength);
				pTransferData = (unsigned char *)shortData;
				memcpy(USBTxPacket.Data + USB_PACKET_HEADER_SIZE_OLDVER * 4, pTransferData, copyLength);
				transferLength += copyLength;
				pTransferData += copyLength;
				remainShortDataSize = transferShortDataLength - copyLength;
				if (remainShortDataSize == 0)
				{
					if (remainLongDataSize > 0)
					{
						pTransferData = (unsigned char *)longData;
					}
				}
			}
			else
			{
				remainShortDataSize = 0;
				if (remainLongDataSize > 0)
				{
					pTransferData = (unsigned char *)longData;
				}
			}
		}
		else if (remainShortDataSize > 0)
		{
			copyLength = min(remainShortDataSize, USB_TRANSFER_MAX_SIZE_OLDVER);
			memcpy(USBTxPacket.Data, pTransferData, copyLength);
			pTransferData += copyLength;
			remainShortDataSize -= copyLength;
			transferLength = copyLength;
			if (remainShortDataSize == 0)
			{
				if (remainLongDataSize > 0)
				{
					pTransferData = (unsigned char *)longData;
				}
			}
		}
		else if (remainLongDataSize > 0)
		{
			copyLength = min(remainLongDataSize, USB_TRANSFER_MAX_SIZE_OLDVER);
			memcpy(USBTxPacket.Data, pTransferData, copyLength);
			pTransferData += copyLength;
			remainLongDataSize -= copyLength;
			transferLength = copyLength;
		}

		USBTxPacket.PacketIndex = packetIndex;
		USBTxPacket.Checksum = CheckSum((unsigned int *)USBTxPacket.Data, transferLength / 4);
		transferLength += 8;

		if (!WriteFile(DeviceHandle, &USBTxPacket, transferLength, &dwWriteSize, &ol))
		{
			if (GetLastError() == ERROR_IO_PENDING)
			{
				while(!GetOverlappedResult(DeviceHandle, &ol, &dwWriteSize, FALSE))
				{
					error = GetLastError();
					if (error == ERROR_IO_INCOMPLETE)
					{
						if (GetTickCount() - writeStartTime > timeout)
						{
						LastErrorMessage = "USB Write timeout occurs";
							returnValue = false;
							break;
						}
					}
					else
					{
						 LastErrorMessage = "USB Write Failed";
						returnValue = false;
						break;
					}
				}
			}
		}

		if (dwWriteSize != transferLength)
		{
			LastErrorMessage = "USB Write Failed";
			returnValue = false;
			break;
		}
		if (returnValue == false) break;
		packetIndex++;
	}

	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall TUSBComm::ReceiveCommand_OldVer(void *receiveBuffer, unsigned int receiveBufferMaxSize,
	unsigned int *receivedLength, int timeout)
{
	bool returnValue = true;
	unsigned int rxCount;
	DWORD dwReadSize;
	unsigned int dataSize;
	int dataPos = 0;
	unsigned char *buffer;
	unsigned int bufferMaxSize;
	unsigned char RXPacketBuf[PACKET_MAX_SIZE_OLDVER];
	TUSBDataHeader_OldVer RXDataHeader;
	TTransferPacket_OldVer USBRxPacket;

	if (receiveBuffer == NULL)
	{
		buffer = (unsigned char *)RXPacketBuf + USB_PACKET_HEADER_SIZE_OLDVER * sizeof(int);
		bufferMaxSize = (PACKET_MAX_SIZE_OLDVER - USB_PACKET_HEADER_SIZE_OLDVER) * sizeof(int);
	}
	else
	{
		buffer = (unsigned char *)receiveBuffer;
		bufferMaxSize = receiveBufferMaxSize;
	}

    DWORD error;
	BOOL ret;
	bool bError = false;
	unsigned int readStartTime = GetTickCount();

		ret = ReadFile(DeviceHandle, &RXDataHeader, USB_PACKET_HEADER_SIZE_OLDVER * sizeof(int), &dwReadSize, &ol);
		if (!ret)
		{
			if (GetLastError() == ERROR_IO_PENDING)
			{
				while(!GetOverlappedResult(DeviceHandle, &ol, &dwReadSize, FALSE))
				{
					error = GetLastError();
					if (error == ERROR_IO_INCOMPLETE)
					{
						if (GetTickCount() - readStartTime > timeout)
						//if (GetTickCount() - readStartTime > 1000)
						{
							LastErrorMessage = "USB read timeout occurs";
							bError = true;
							break;
						}
					}
					else
					{
				                  	LastErrorMessage = "USB reading failure";
						bError = true;
						break;
					}
				}
			}
			else
			{
		                 	LastErrorMessage = "USB reading failure";
				bError = true;
			}
		}
		if (!bError)
		{
			rxCount = dwReadSize;
			if (rxCount != USB_PACKET_HEADER_SIZE_OLDVER * sizeof(int))
			{
/*
				ret = ReadFile(DeviceHandle, &RXDataHeader, USB_PACKET_HEADER_SIZE * sizeof(int), &dwReadSize, &ol);
				if (!ret)
				{
					if (GetLastError() == ERROR_IO_PENDING)
					{
						while(!GetOverlappedResult(DeviceHandle, &ol, &dwReadSize, FALSE))
						{
							error = GetLastError();
							if (error == ERROR_IO_INCOMPLETE)
							{
								if (GetTickCount() - readStartTime > timeout)
								//if (GetTickCount() - readStartTime > 1000)
								{
									LastErrorMessage = "USB 읽기 타임아웃 발생2 : " + SysErrorMessage(GetLastError());
									bError = true;
									break;
								}
							}
							else
							{
								LastErrorMessage = "USB 읽기 실패2 : " + SysErrorMessage(GetLastError());
								bError = true;
								break;
							}
						}
					}
					else
					{
						LastErrorMessage = "USB 읽기 실패2 : " + SysErrorMessage(GetLastError());
						bError = true;
					}
				}
*/
       LastErrorMessage = "USB read size error";
//				ReadFile(DeviceHandle, &RXDataHeader, USB_PACKET_HEADER_SIZE * sizeof(int), &dwReadSize, &ol);
//        LastErrorMessage = TempString;
				bError = true;
				returnValue = false;
/*
				if (rxCount != USB_PACKET_HEADER_SIZE * sizeof(int))
				{
					LastErrorMessage = "USB read size err (H) : " + IntToStr(rxCount);
					bError = true;
				}
*/
			}

			if (!bError && USB_PACKET_HEADER_SIZE_OLDVER < RXDataHeader.shortLength)
			{
				dataSize = (RXDataHeader.shortLength - USB_PACKET_HEADER_SIZE_OLDVER) * sizeof(int);
				if (dataPos + dataSize <= bufferMaxSize)
				{
					ol.Offset = 0;
					ol.OffsetHigh = 0;
					readStartTime = GetTickCount();
					ret = ReadFile(DeviceHandle, &buffer[dataPos], dataSize, &dwReadSize, &ol);
					if (!ret)
					{
						if (GetLastError() == ERROR_IO_PENDING)
						{
							while(!GetOverlappedResult(DeviceHandle, &ol, &dwReadSize, FALSE))
							{
								error = GetLastError();
								if (error == ERROR_IO_INCOMPLETE)
								{
									if (GetTickCount() - readStartTime > timeout)
									//if (GetTickCount() - readStartTime > 1000)
									{
                   LastErrorMessage = "USB read timeout occurs (S)";
										bError = true;
										break;
									}
								}
								else
								{
                  LastErrorMessage = "USB reading failure (S)";
									bError = true;
									break;
								}
							}
						}
					}
					if (!bError)
					{
						dataPos += dataSize;
						returnValue = true;
					}
					else
					{
						returnValue = false;
					}
				}
				else
				{
					returnValue = false;
          LastErrorMessage = "To be received data are too large.";
				}
			}


			if (returnValue == true && RXDataHeader.longLength > 0)
			{
				dataSize = RXDataHeader.longLength * sizeof(int);
				if (dataPos + dataSize <= bufferMaxSize)
				{
					int dataRemain = dataSize;
					int dataLength;
					while (dataRemain)
					{
						if (dataRemain < 64 * 1024)
						{
							dataLength = dataRemain;
						}
						else
						{
							dataLength = 64 * 1024;
						}
						ol.Offset = 0;
						ol.OffsetHigh = 0;
						readStartTime = GetTickCount();
						ret = ReadFile(DeviceHandle, &buffer[dataPos], dataLength, &dwReadSize, &ol);
						if (!ret)
						{
							if (GetLastError() == ERROR_IO_PENDING)
							{
								while(!GetOverlappedResult(DeviceHandle, &ol, &dwReadSize, FALSE))
								{
									error = GetLastError();
									if (error == ERROR_IO_INCOMPLETE)
									{
										if (GetTickCount() - readStartTime > timeout)
										//if (GetTickCount() - readStartTime > 1000)
										{
                      LastErrorMessage = "USB read time-out occurs (L)";
											bError = true;
											break;
										}
									}
									else
									{
                   LastErrorMessage = "USB reading failure (L)";
										bError = true;
										break;
									}
								}
							}
						}
						if (!bError)
						{
							dataPos += dataLength;
							returnValue = true;
						}
						else
						{
							returnValue = false;
						}
						if (returnValue == false) break;
						else dataRemain -= dataLength;
					}
				}
				else
				{
					returnValue = false;
          LastErrorMessage = "To be received data are too large(L)";
				}
	        }
		}
	    else
	    {
	    	returnValue = false;
//	        *LastErrorMessage = "USB 읽기 실패(H) : " + SysErrorMessage(GetLastError());
		}


    *receivedLength = dataPos;
    return returnValue;
}
//---------------------------------------------------------------------------

