//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//// MAIN
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
int _tmain(int argc, _TCHAR* argv[])
{
  GUID guidDeviceInterface = CWinUSBComm::m_WinUSBCommInterfaceGUID; //in the INF file

  BOOL bResult = TRUE;

  PIPE_ID PipeID;

  HANDLE hDeviceHandle = INVALID_HANDLE_VALUE;
  WINUSB_INTERFACE_HANDLE hWinUSBHandle = INVALID_HANDLE_VALUE;

  UCHAR DeviceSpeed;
  ULONG cbSize = 0;

  BYTE * pbyDataToDevice = NULL;
  BYTE * pbyDataFromDevice = NULL;

  SetConsoleTitle(_T("WinUSBComm Test"));

  bResult = GetDeviceHandle(guidDeviceInterface, &hDeviceHandle);
  if(!bResult)
  {
    goto done;
  }

  bResult = GetWinUSBHandle(hDeviceHandle, &hWinUSBHandle);
  if(!bResult)
  {
    goto done;
  }

  bResult = GetUSBDeviceSpeed(hWinUSBHandle, &DeviceSpeed);
  if(!bResult)
  {
    goto done;
  }

  bResult = QueryDeviceEndpoints(hWinUSBHandle, &PipeID);
  if(!bResult)
  {
    goto done;
  }

  BOOL bRepeat = FALSE;

  BYTE byVersion = winusbcommversion1;

  bResult = GetDataFromDefaultEndpoint(hWinUSBHandle, winusbcomm2commandGetVersion, (BYTE *)&byVersion, sizeof(byVersion));
  
  EWinUSBCommVersion eVersion = ( byVersion <= winusbcommversion1 ) ? winusbcommversion1 : (EWinUSBCommVersion)byVersion;

  BYTE byGetCommBufferSizeCmd = ( winusbcommversion1 == eVersion ) ? winusbctrlGETBUFFSIZE : winusbcomm2commandGetBufferSize;
  BYTE byResetCmd = ( winusbcommversion1 == eVersion ) ? winusbctrlRESET : winusbcomm2commandReset;
  BYTE byGetReturnSizeCmd = ( winusbcommversion1 == eVersion ) ? winusbctrlGETDATASIZE : winusbcomm2commandGetReturnSize;

  DWORD dwMaxBufferSize = 0;
  bResult = GetDataFromDefaultEndpoint(hWinUSBHandle, byGetCommBufferSizeCmd, (BYTE *)&dwMaxBufferSize, sizeof(dwMaxBufferSize));
  if(!bResult)
  {
    goto done;
  }           

  pbyDataToDevice = new BYTE[dwMaxBufferSize];
  for ( DWORD I = 0; I < dwMaxBufferSize; I++ )
  {
    pbyDataToDevice[I] = (BYTE) I;
  }
  pbyDataFromDevice = new BYTE[dwMaxBufferSize];

  LARGE_INTEGER countStart;
  DWORD dwNumDataTransered = 0;
  DWORD dwNumLoops = 100;
  QueryPerformanceCounter(&countStart);

  if ( winusbcommversion1 == eVersion )
  {
    // send some data over control EP
    BYTE abyCtrlEPTestData[4] = { 4, 3, '2', '1' };
    bResult = SendDatatoDefaultEndpoint(hWinUSBHandle, winusbctrlEXAMPLEDATA4B, abyCtrlEPTestData, 4);
    if(!bResult)
    {
      goto done;
    }
  }
  do
  {
    // put device to receiving state
    bResult = SendDatatoDefaultEndpoint(hWinUSBHandle, byResetCmd);
    if(!bResult)
    {
      goto done;
    }

    if ( winusbcommversion1 != eVersion )
    {
      // notify device how much data will be sent next
      bResult = SendDatatoDefaultEndpoint(hWinUSBHandle, winusbcomm2commandFollowingPacketSize, (BYTE *)&dwMaxBufferSize, 4);
      if(!bResult)
      {
        goto done;
      }
    }

    // send the data
    bResult = WriteToBulkEndpoint(hWinUSBHandle, &PipeID.PipeOutId, &cbSize, pbyDataToDevice, dwMaxBufferSize);
    if(!bResult)
    {
      goto done;
    }

    dwNumDataTransered += dwMaxBufferSize;

    if ( winusbcommversion1 == eVersion )
    {
      // notify device that all is sent
      bResult = SendDatatoDefaultEndpoint(hWinUSBHandle, winusbctrlTXDONE);
      if(!bResult)
      {
        goto done;
      }

      // poll status and wait until idle
      BYTE byCommStatus = winusbcommPROCESSING;
      while ( winusbcommPROCESSING == byCommStatus )
      {
        bResult = GetDataFromDefaultEndpoint(hWinUSBHandle, winusbctrlGETSTATUS, &byCommStatus, sizeof(byCommStatus));
        if(!bResult)
        {
          goto done;
        }
        dwNumDataTransered += 1;
        // timeout here if needed
      }

      // check if idle
      if ( winusbcommIDLE != byCommStatus )
      {
        goto done;
      }
    }

    // get how much data is to read from device
    DWORD dwResponseByteCount = 0;
    do
    {
      bResult = GetDataFromDefaultEndpoint(hWinUSBHandle, byGetReturnSizeCmd, (BYTE *)&dwResponseByteCount, sizeof(dwResponseByteCount));
      if(!bResult)
      {
        goto done;
      }
      // timeout here if needed
    } while ( !dwResponseByteCount );
    dwNumDataTransered += sizeof(dwResponseByteCount);
    
    // response byte count must match sent count; application XORs the data and sends it back
    if ( dwMaxBufferSize != dwResponseByteCount )
    {
      goto done;
    }

    // read data back
    bResult = ReadFromBulkEndpoint(hWinUSBHandle, &PipeID.PipeInId, cbSize, pbyDataFromDevice, dwResponseByteCount);
    if(!bResult)
    {
      goto done;
    }

    dwNumDataTransered += dwResponseByteCount;

// At first I had data XORed in the device and sent back. I was later interested in transfer speed.
//     BOOL bMatch = TRUE;
//     for ( DWORD I = 0; I < dwResponseByteCount; I++ )
//     {
//       if ( pbyDataToDevice[I] != (pbyDataFromDevice[I]))// ^ 0xFF) )
//       {
//         bMatch = FALSE;
//         break;
//       }
//     }
// 
//     printf("Data %s\n", bMatch ? "matched" : "didn't match");
  } while ( --dwNumLoops );

  LARGE_INTEGER countEnd;
  QueryPerformanceCounter(&countEnd);

  LARGE_INTEGER f;
  QueryPerformanceFrequency( &f );

  LARGE_INTEGER elapsedCount;
  elapsedCount.QuadPart = countEnd.QuadPart - countStart.QuadPart;

  DOUBLE elapsed = (DOUBLE)elapsedCount.QuadPart / (DOUBLE)f.QuadPart;
  DOUBLE rate = (DOUBLE)dwNumDataTransered / elapsed;

  rate /= 1024;
  printf("Data speed: %f kbps = %f kBps\n", rate * 8, rate);
  system("PAUSE");
done:
  if ( INVALID_HANDLE_VALUE != hDeviceHandle )
  {
    CloseHandle(hDeviceHandle);
  }
  if ( INVALID_HANDLE_VALUE != hWinUSBHandle )
  {
    WinUsb_Free(hWinUSBHandle);
  }
  if ( pbyDataToDevice ) delete[] pbyDataToDevice;
  if ( pbyDataFromDevice ) delete[] pbyDataFromDevice;
}
void main()
{ 

	UCHAR buf[2];

	THREAD_PARAM thread_param;

	DWORD dwThreadId;

    GUID guidDeviceInterface = USB_RS232_DEVICE_INTERFACE; //in the INF file

    BOOL bResult = TRUE;

    PIPE_ID PipeID;

    HANDLE hDeviceHandle = INVALID_HANDLE_VALUE;
    WINUSB_INTERFACE_HANDLE hWinUSBHandle = INVALID_HANDLE_VALUE;
    
    UCHAR DeviceSpeed;
    ULONG cbSize = 0;


    bResult = GetDeviceHandle(guidDeviceInterface, &hDeviceHandle);
    if(!bResult) {
        goto done;
    }

    bResult = GetWinUSBHandle(hDeviceHandle, &hWinUSBHandle);
    if(!bResult) {
        goto done;
    }

    bResult = GetUSBDeviceSpeed(hWinUSBHandle, &DeviceSpeed);
    if(!bResult) {
        goto done;
    }

    bResult = QueryDeviceEndpoints(hWinUSBHandle, &PipeID);
    if(!bResult) {
        goto done;
    }

//    bResult = SendDatatoDefaultEndpoint(hWinUSBHandle);
//    if(!bResult) {
//        goto done;
//    }



	thread_param.hWinUSBHandle = hWinUSBHandle;
	thread_param.PipeInId = PipeID.PipeInId;


	if (!CreateThread (NULL, 
		0, 
		(LPTHREAD_START_ROUTINE)&comReadThread,
		(LPVOID)&thread_param,
		0,
		&dwThreadId)) {
	
		printf ("Fail to Create Read Thread\n");
		goto done;
	}


	printf ("\n===============================================================\n");


	buf[1] = '\n';

	while(1) {
		buf[0] = _getch();
		
		if (buf[0] == 27) { // Escape key
			goto done;
		}


		if (buf[0] == '\r') {
			WriteToBulkEndpoint(hWinUSBHandle, &PipeID.PipeOutId, &cbSize, buf, 2);
		} else {
			WriteToBulkEndpoint(hWinUSBHandle, &PipeID.PipeOutId, &cbSize, buf, 1);
		}
		
		
	} // End of while loop
    

done:
    CloseHandle(hDeviceHandle);
    WinUsb_Free(hWinUSBHandle);

    
} // End of main()