//**************************************************************************************************
// COM-PORT OPERATIONS — SEND/RECEIVE:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include "Precompiled.h"
#include "SharedIncludes.h"
namespace XDeviceAccess {
//==================================================================================================

void ComPortHelpers::Send( IntPtr portHandle, IntPtr overlappedStructurePtr,
                           array<byte>^ outputBuffer, int bytesToSend,
                           int timeout )
{
   HPointerArgChecking::VerifyNotNull( overlappedStructurePtr );
   HANDLE hPort = (HANDLE)portHandle;
   auto pOverlapped = (OVERLAPPED*)($PVOID)overlappedStructurePtr;
   pin_ptr<byte> pbDataOutputBuffer = &outputBuffer[ 0 ];
   if ( !::PurgeComm( hPort, PURGE_RXCLEAR | PURGE_TXCLEAR ) )
      throw IntInteropExceptionCreator::CreateFromWin32Error();
   if ( !::WriteFile( hPort, pbDataOutputBuffer, bytesToSend, NULL, pOverlapped ) &&
        ::GetLastError() != ERROR_IO_PENDING )
      throw IntInteropExceptionCreator::CreateFromWin32Error();
   try
   {
      DWORD dwBytesWritten, dwWaitResult;
      switch ( dwWaitResult = ::WaitForSingleObject( pOverlapped->hEvent, timeout ) )
      {
      case WAIT_OBJECT_0:
         if ( !::GetOverlappedResult( hPort, pOverlapped, &dwBytesWritten, FALSE ) )
            throw IntInteropExceptionCreator::CreateFromWin32Error();
         return;
      case WAIT_TIMEOUT:
         throw gcnew InternalInteropException(HLocal::_TXT(
            "Package sending timeout is exceeded (COM-port).",
            "Превышен таймаут отправной посылки (COM-порт)." ));
      case WAIT_FAILED:
         throw IntInteropExceptionCreator::CreateFromWin32Error();
      default:
         throw gcnew InternalInteropException(HLocal::_TXT(
            "Unknown error during package sending (COM-port).",
            "Неизвестная ошибка при отправке посылки (COM-порт)." ));
      }
   }
   finally
   {
      CancelIo( hPort );
   }
}

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

bool ComPortHelpers::Receive( IntPtr portHandle, IntPtr overlappedStructurePtr,
                              array<byte>^ inputBuffer, int bytesToReceive,
                              int timeout )
{
   HPointerArgChecking::VerifyNotNull( overlappedStructurePtr );
   HANDLE hPort = (HANDLE)portHandle;
   auto pOverlapped = (OVERLAPPED*)($PVOID)overlappedStructurePtr;
   pin_ptr<byte> pbInputBuffer = &inputBuffer[ 0 ];
   if ( !::ReadFile( hPort, pbInputBuffer, bytesToReceive, NULL, pOverlapped ) &&
        ::GetLastError() != ERROR_IO_PENDING )
      throw IntInteropExceptionCreator::CreateFromWin32Error();
   try
   {
      DWORD dwBytesRead;
      switch ( ::WaitForSingleObject( pOverlapped->hEvent, timeout ) )
      {
      case WAIT_OBJECT_0:
         if ( !::GetOverlappedResult( hPort, pOverlapped, &dwBytesRead, FALSE ) )
            throw IntInteropExceptionCreator::CreateFromWin32Error();
         if ( dwBytesRead != bytesToReceive )
            throw gcnew InternalInteropException(HLocal::_TXT(
               "Number of readed bytes is unexpectedly differrent from requested "\
               "data size of asynchronous operation (COM-port).",
               "Неожиданно отличное от запрошенного число считанных байт "\
               "отложенной ассинхронной операции (COM-порт)." ));
         return true;
      case WAIT_TIMEOUT:
         return false;
      case WAIT_FAILED:
         throw IntInteropExceptionCreator::CreateFromWin32Error();
      default:
         throw gcnew InternalInteropException(HLocal::_TXT(
            "Unknown error during waiting of responce package (COM-port).",
            "Неизвестная ошибка при ожидании ответной посылки (COM-порт)." ));
      }
   }
   finally
   {
      ::CancelIo( hPort );
   }
}

//==================================================================================================
} // XDeviceAccess
