1200 lines
30 KiB
C++
1200 lines
30 KiB
C++
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: ComPort.cpp
|
|
* Content: Serial communications port management class
|
|
*
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 01/20/98 jtk Created
|
|
***************************************************************************/
|
|
|
|
#include "dnmdmi.h"
|
|
|
|
|
|
//**********************************************************************
|
|
// Constant definitions
|
|
//**********************************************************************
|
|
|
|
//
|
|
// number of BITS in a serial BYTE
|
|
//
|
|
#define BITS_PER_BYTE 8
|
|
|
|
//
|
|
// maximum size of baud rate string
|
|
//
|
|
#define MAX_BAUD_STRING_SIZE 7
|
|
|
|
//
|
|
// default size of buffers when parsing
|
|
//
|
|
#define DEFAULT_COMPONENT_BUFFER_SIZE 1000
|
|
|
|
//
|
|
// device ID assigned to 'all adapters'
|
|
//
|
|
#define ALL_ADAPTERS_DEVICE_ID 0
|
|
|
|
//
|
|
// NULL token
|
|
//
|
|
#define NULL_TOKEN '\0'
|
|
|
|
//**********************************************************************
|
|
// Macro definitions
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Structure definitions
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Variable definitions
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Function prototypes
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Function definitions
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CComPort::CComPort - constructor
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
//
|
|
// Notes: Do not allocate anything in a constructor
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ComPort::ComPort"
|
|
|
|
CComPort::CComPort():
|
|
m_pOwningPool( NULL )
|
|
{
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CComPort::~CComPort - destructor
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ComPort::~ComPort"
|
|
|
|
CComPort::~CComPort()
|
|
{
|
|
DNASSERT( m_pOwningPool == NULL );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CComPort::ReturnSelfToPool - return this item to the pool
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ComPort::ReturnSelfToPool"
|
|
|
|
void CComPort::ReturnSelfToPool( void )
|
|
{
|
|
DNASSERT( m_pOwningPool != NULL );
|
|
m_pOwningPool->Release( this );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CComPort::EnumAdapters - enumerate adapters
|
|
//
|
|
// Entry: Pointer to enum adapters data
|
|
//
|
|
// Exit: Error code
|
|
//
|
|
// Note: This function uses an array of valid endpoints and attempts to open
|
|
// each comport. COM0 is reserved as the 'all adapters' ID.
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ComPort::EnumAdapters"
|
|
|
|
HRESULT CComPort::EnumAdapters( SPENUMADAPTERSDATA *const pEnumAdaptersData ) const
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hTempResult;
|
|
BOOL fPortAvailable[ MAX_DATA_PORTS ];
|
|
DWORD dwValidPortCount;
|
|
WCHAR *pWorkingString;
|
|
INT_PTR iIdx;
|
|
INT_PTR iOutputIdx;
|
|
DWORD dwRequiredDataSize = 0;
|
|
DWORD dwConvertedStringSize;
|
|
DWORD dwRemainingStringSize;
|
|
|
|
|
|
DEBUG_ONLY( DNASSERT( m_fInitialized != FALSE ) );
|
|
DNASSERT( pEnumAdaptersData != NULL );
|
|
DNASSERT( ( pEnumAdaptersData->pAdapterData != NULL ) || ( pEnumAdaptersData->dwAdapterDataSize == 0 ) );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
|
|
hr = GenerateAvailableComPortList( fPortAvailable, LENGTHOF( fPortAvailable ) - 1, &dwValidPortCount );
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to generate list of available comports!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
|
|
dwRequiredDataSize = sizeof( *pEnumAdaptersData->pAdapterData ) * dwValidPortCount;
|
|
|
|
iIdx = LENGTHOF( fPortAvailable );
|
|
while ( iIdx > 0 )
|
|
{
|
|
iIdx--;
|
|
|
|
//
|
|
// compute exact size based on the com port number
|
|
//
|
|
if ( fPortAvailable[ iIdx ] != FALSE )
|
|
{
|
|
if ( iIdx > 100 )
|
|
{
|
|
dwRequiredDataSize += sizeof( *pEnumAdaptersData->pAdapterData->pwszName ) * 7;
|
|
}
|
|
else
|
|
{
|
|
if ( iIdx > 10 )
|
|
{
|
|
dwRequiredDataSize += sizeof( *pEnumAdaptersData->pAdapterData->pwszName ) * 6;
|
|
}
|
|
else
|
|
{
|
|
dwRequiredDataSize += sizeof( *pEnumAdaptersData->pAdapterData->pwszName ) * 5;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( pEnumAdaptersData->dwAdapterDataSize < dwRequiredDataSize )
|
|
{
|
|
hr = DPNERR_BUFFERTOOSMALL;
|
|
pEnumAdaptersData->dwAdapterDataSize = dwRequiredDataSize;
|
|
DPFX(DPFPREP, 8, "Buffer too small when enumerating comport adapters!" );
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// if there are no adapters, bail
|
|
//
|
|
if ( dwValidPortCount == 0 )
|
|
{
|
|
// debug me!
|
|
DNASSERT( FALSE );
|
|
DNASSERT( dwRequiredDataSize == 0 );
|
|
DNASSERT( pEnumAdaptersData->dwAdapterCount == 0 );
|
|
goto Exit;
|
|
}
|
|
|
|
DNASSERT( dwValidPortCount >= 1 );
|
|
dwRemainingStringSize = ( dwRequiredDataSize - ( ( sizeof( *pEnumAdaptersData->pAdapterData ) ) * dwValidPortCount ) ) / sizeof( *pEnumAdaptersData->pAdapterData->pwszName );
|
|
|
|
//
|
|
// we've got enough space, start building structures
|
|
//
|
|
DEBUG_ONLY( memset( pEnumAdaptersData->pAdapterData, 0xAA, dwRequiredDataSize ) );
|
|
pEnumAdaptersData->dwAdapterCount = dwValidPortCount;
|
|
|
|
DBG_CASSERT( sizeof( &pEnumAdaptersData->pAdapterData[ dwValidPortCount ] ) == sizeof( WCHAR* ) );
|
|
pWorkingString = reinterpret_cast<WCHAR*>( &pEnumAdaptersData->pAdapterData[ dwValidPortCount ] );
|
|
|
|
iIdx = 1;
|
|
iOutputIdx = 0;
|
|
while ( iIdx < MAX_DATA_PORTS )
|
|
{
|
|
//
|
|
// convert to guid if it's valid
|
|
//
|
|
if ( fPortAvailable[ iIdx ] != FALSE )
|
|
{
|
|
TCHAR TempBuffer[ (COM_PORT_STRING_LENGTH + 1) ];
|
|
|
|
|
|
//
|
|
// convert device ID to a string and check for local buffer overrun
|
|
//
|
|
DEBUG_ONLY( TempBuffer[ LENGTHOF( TempBuffer ) - 1 ] = 0x5a );
|
|
|
|
ComDeviceIDToString( TempBuffer, iIdx );
|
|
DEBUG_ONLY( DNASSERT( TempBuffer[ LENGTHOF( TempBuffer ) - 1 ] == 0x5a ) );
|
|
|
|
#ifdef UNICODE
|
|
dwConvertedStringSize = lstrlen(TempBuffer) + 1;
|
|
lstrcpy(pWorkingString, TempBuffer);
|
|
#else
|
|
dwConvertedStringSize = dwRemainingStringSize;
|
|
hTempResult = AnsiToWide( TempBuffer, -1, pWorkingString, &dwConvertedStringSize );
|
|
DNASSERT( hTempResult == DPN_OK );
|
|
#endif
|
|
DNASSERT( dwRemainingStringSize >= dwConvertedStringSize );
|
|
dwRemainingStringSize -= dwConvertedStringSize;
|
|
|
|
pEnumAdaptersData->pAdapterData[ iOutputIdx ].dwFlags = 0;
|
|
pEnumAdaptersData->pAdapterData[ iOutputIdx ].pvReserved = NULL;
|
|
pEnumAdaptersData->pAdapterData[ iOutputIdx ].dwReserved = NULL;
|
|
DeviceIDToGuid( &pEnumAdaptersData->pAdapterData[ iOutputIdx ].guid, iIdx, &g_SerialSPEncryptionGuid );
|
|
pEnumAdaptersData->pAdapterData[ iOutputIdx ].pwszName = pWorkingString;
|
|
|
|
pWorkingString = &pWorkingString[ dwConvertedStringSize ];
|
|
iOutputIdx++;
|
|
DEBUG_ONLY( dwValidPortCount-- );
|
|
}
|
|
|
|
iIdx++;
|
|
}
|
|
|
|
DEBUG_ONLY( DNASSERT( dwValidPortCount == 0 ) );
|
|
DNASSERT( dwRemainingStringSize == 0 );
|
|
|
|
Exit:
|
|
//
|
|
// set size of output data
|
|
//
|
|
pEnumAdaptersData->dwAdapterDataSize = dwRequiredDataSize;
|
|
|
|
return hr;
|
|
|
|
Failure:
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CComPort::BindToNetwork - bind to the 'network'
|
|
//
|
|
// Entry: Device ID
|
|
// Pointer to device context (CComPortData)
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ComPort::BindToNetwork"
|
|
|
|
HRESULT CComPort::BindToNetwork( const DWORD dwDeviceID, const void *const pDeviceContext )
|
|
{
|
|
HRESULT hr;
|
|
const CComPortData *pComPortData;
|
|
|
|
|
|
DNASSERT( pDeviceContext != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
pComPortData = static_cast<const CComPortData*>( pDeviceContext );
|
|
m_ComPortData.Copy( pComPortData );
|
|
|
|
//
|
|
// open port
|
|
//
|
|
DNASSERT( m_hFile == INVALID_HANDLE_VALUE );
|
|
m_hFile = CreateFile( m_ComPortData.ComPortName(), // comm port
|
|
GENERIC_READ | GENERIC_WRITE, // read/write access
|
|
0, // don't share file with others
|
|
NULL, // default sercurity descriptor
|
|
OPEN_EXISTING, // comm port must exist to be opened
|
|
FILE_FLAG_OVERLAPPED, // use overlapped I/O
|
|
NULL // no handle for template file
|
|
);
|
|
if ( m_hFile == INVALID_HANDLE_VALUE )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
hr = DPNERR_NOCONNECTION;
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "CreateFile() failed!" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// bind to completion port for NT
|
|
//
|
|
#ifdef WINNT
|
|
HANDLE hCompletionPort;
|
|
|
|
|
|
hCompletionPort = CreateIoCompletionPort( m_hFile, // current file handle
|
|
GetSPData()->GetThreadPool()->GetIOCompletionPort(), // handle of completion port
|
|
IO_COMPLETION_KEY_IO_COMPLETE, // completion key
|
|
0 // number of concurrent threads (default to number of processors)
|
|
);
|
|
if ( hCompletionPort == NULL )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Cannot bind comport to completion port!" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
}
|
|
DNASSERT( hCompletionPort == GetSPData()->GetThreadPool()->GetIOCompletionPort() );
|
|
#endif
|
|
|
|
//
|
|
// set bit rate, etc.
|
|
//
|
|
hr = SetPortState();
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Problem with SetPortState" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// set general comminications paramters (timeouts, etc.)
|
|
//
|
|
hr = SetPortCommunicationParameters();
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to set communication paramters!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// start receiving
|
|
//
|
|
hr = StartReceiving();
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to start receiving!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
|
|
Exit:
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Problem with CComPort::Open" );
|
|
DisplayDNError( 0, hr );
|
|
}
|
|
|
|
return hr;
|
|
|
|
Failure:
|
|
if ( m_hFile != NULL )
|
|
{
|
|
CloseHandle( m_hFile );
|
|
m_hFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
// Close();
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CComPort::UnbindFromNetwork - unbind to the 'network'
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ComPort::UnbindFromNetwork"
|
|
|
|
void CComPort::UnbindFromNetwork( void )
|
|
{
|
|
CReadIOData * pReadData;
|
|
|
|
|
|
DPFX(DPFPREP, 6, "(0x%p) Enter", this);
|
|
|
|
|
|
DNASSERT( GetState() == DATA_PORT_STATE_UNBOUND );
|
|
|
|
if ( GetHandle() != INVALID_HANDLE_VALUE )
|
|
{
|
|
GetSPData()->GetThreadPool()->CloseDataPortHandle( this );
|
|
DNASSERT( GetHandle() == INVALID_HANDLE_VALUE );
|
|
}
|
|
|
|
//
|
|
// if there's a com file, purge all communications and close it
|
|
//
|
|
if ( m_hFile != INVALID_HANDLE_VALUE )
|
|
{
|
|
DPFX(DPFPREP, 6, "Flushing and closing COM port file handle 0x%p.", m_hFile);
|
|
|
|
//
|
|
// wait until all writes have completed
|
|
//
|
|
if ( FlushFileBuffers( m_hFile ) == FALSE )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Problem with FlushFileBuffers() when closing com port!" );
|
|
DisplayErrorCode( 0, dwError );
|
|
}
|
|
|
|
|
|
//
|
|
// force all communication to complete
|
|
//
|
|
if ( PurgeComm( m_hFile, ( PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ) ) == FALSE )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Problem with PurgeComm() when closing com port!" );
|
|
DisplayErrorCode( 0, dwError );
|
|
}
|
|
|
|
|
|
#ifdef WIN95
|
|
pReadData = this->GetActiveRead();
|
|
|
|
//
|
|
// if there is a pending read, wait until it completes
|
|
//
|
|
|
|
if ( pReadData != NULL )
|
|
{
|
|
//
|
|
// pull it out of the list so the regular receive thread doesn't catch the completion
|
|
//
|
|
GetSPData()->GetThreadPool()->LockReadData();
|
|
pReadData->m_OutstandingReadListLinkage.RemoveFromList();
|
|
GetSPData()->GetThreadPool()->UnlockReadData();
|
|
|
|
|
|
if ( pReadData->Win9xOperationPending() != FALSE )
|
|
{
|
|
DWORD dwAttempt;
|
|
|
|
|
|
dwAttempt = 0;
|
|
|
|
WaitAgain:
|
|
DPFX(DPFPREP, 1, "Checking if read 0x%p has completed.", pReadData );
|
|
|
|
if ( GetOverlappedResult( m_hFile,
|
|
pReadData->Overlap(),
|
|
&pReadData->jkm_dwOverlappedBytesReceived,
|
|
FALSE
|
|
) != FALSE )
|
|
{
|
|
DBG_CASSERT( ERROR_SUCCESS == 0 );
|
|
pReadData->m_dwWin9xReceiveErrorReturn = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
//
|
|
// other error, stop if not 'known'
|
|
//
|
|
dwError = GetLastError();
|
|
switch( dwError )
|
|
{
|
|
//
|
|
// ERROR_IO_INCOMPLETE = treat as I/O complete. Event isn't
|
|
// signalled, but that's expected because
|
|
// it's cleared before checking for I/O
|
|
//
|
|
case ERROR_IO_INCOMPLETE:
|
|
{
|
|
pReadData->jkm_dwOverlappedBytesReceived = pReadData->m_dwBytesToRead;
|
|
pReadData->m_dwWin9xReceiveErrorReturn = ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// ERROR_IO_PENDING = io still pending
|
|
//
|
|
case ERROR_IO_PENDING:
|
|
{
|
|
dwAttempt++;
|
|
if (dwAttempt <= 6)
|
|
{
|
|
DPFX(DPFPREP, 1, "Read data 0x%p has not completed yet, waiting for %u ms.",
|
|
pReadData, (dwAttempt * 100));
|
|
|
|
SleepEx(dwAttempt, TRUE);
|
|
|
|
goto WaitAgain;
|
|
}
|
|
|
|
DPFX(DPFPREP, 0, "Read data 0x%p still not marked as completed, ignoring.",
|
|
pReadData);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// ERROR_OPERATION_ABORTED = operation was cancelled (COM port closed)
|
|
// ERROR_INVALID_HANDLE = operation was cancelled (COM port closed)
|
|
//
|
|
case ERROR_OPERATION_ABORTED:
|
|
case ERROR_INVALID_HANDLE:
|
|
{
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DisplayErrorCode( 0, dwError );
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
|
|
pReadData->m_dwWin9xReceiveErrorReturn = dwError;
|
|
}
|
|
|
|
|
|
DNASSERT( pReadData->Win9xOperationPending() != FALSE );
|
|
pReadData->SetWin9xOperationPending( FALSE );
|
|
|
|
DNASSERT( pReadData->DataPort() == this );
|
|
this->ProcessReceivedData( pReadData->jkm_dwOverlappedBytesReceived, pReadData->m_dwWin9xReceiveErrorReturn );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// it's not pending Win9x style, ignore it and hope a receive
|
|
// thread picked up the completion
|
|
//
|
|
DPFX(DPFPREP, 8, "Read data 0x%p not pending Win9x style, assuming receive thread picked up completion." );
|
|
}
|
|
#endif
|
|
|
|
if ( CloseHandle( m_hFile ) == FALSE )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Problem with CloseHandle(): 0x%x", dwError );
|
|
}
|
|
|
|
m_hFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
SetLinkDirection( LINK_DIRECTION_UNKNOWN );
|
|
|
|
|
|
DPFX(DPFPREP, 6, "(0x%p) Leave", this);
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CComPort::BindEndpoint - bind endpoint to this data port
|
|
//
|
|
// Entry: Pointer to endpoint
|
|
// Endpoint type
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ComPort::BindEndpoint"
|
|
HRESULT CComPort::BindEndpoint( CEndpoint *const pEndpoint, const ENDPOINT_TYPE EndpointType )
|
|
{
|
|
HRESULT hr;
|
|
IDirectPlay8Address *pDeviceAddress;
|
|
IDirectPlay8Address *pHostAddress;
|
|
|
|
|
|
DNASSERT( pEndpoint != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
pDeviceAddress = NULL;
|
|
pHostAddress = NULL;
|
|
|
|
Lock();
|
|
|
|
//
|
|
// we're only allowed one endpoint of any given type so determine which
|
|
// type end then bind the endpoint
|
|
//
|
|
switch ( EndpointType )
|
|
{
|
|
case ENDPOINT_TYPE_CONNECT:
|
|
case ENDPOINT_TYPE_CONNECT_ON_LISTEN:
|
|
{
|
|
if ( m_hConnectEndpoint != INVALID_HANDLE_VALUE )
|
|
{
|
|
hr = DPNERR_ALREADYINITIALIZED;
|
|
DPFX(DPFPREP, 0, "Attempted to bind connect endpoint when one already exists!" );
|
|
goto Failure;
|
|
}
|
|
|
|
m_hConnectEndpoint = pEndpoint->GetHandle();
|
|
|
|
if ( EndpointType == ENDPOINT_TYPE_CONNECT )
|
|
{
|
|
SPIE_CONNECTADDRESSINFO ConnectAddressInfo;
|
|
HRESULT hTempResult;
|
|
|
|
|
|
//
|
|
// set addresses in addressing information
|
|
//
|
|
pDeviceAddress = ComPortData()->DP8AddressFromComPortData( ADDRESS_TYPE_LOCAL_ADAPTER );
|
|
pHostAddress = ComPortData()->DP8AddressFromComPortData( ADDRESS_TYPE_REMOTE_HOST );
|
|
|
|
memset( &ConnectAddressInfo, 0x00, sizeof( ConnectAddressInfo ) );
|
|
ConnectAddressInfo.pDeviceAddress = pDeviceAddress;
|
|
ConnectAddressInfo.pHostAddress = pHostAddress;
|
|
ConnectAddressInfo.hCommandStatus = DPN_OK;
|
|
ConnectAddressInfo.pCommandContext = pEndpoint->GetCommandData()->GetUserContext();
|
|
|
|
if ( ( ConnectAddressInfo.pDeviceAddress == NULL ) ||
|
|
( ConnectAddressInfo.pHostAddress == NULL ) )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to build addresses to indicate serial connect addressing!" );
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
hTempResult = IDP8SPCallback_IndicateEvent( GetSPData()->DP8SPCallbackInterface(), // interface
|
|
SPEV_CONNECTADDRESSINFO, // event type
|
|
&ConnectAddressInfo // pointer to data
|
|
);
|
|
DNASSERT( hTempResult == DPN_OK );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ENDPOINT_TYPE_LISTEN:
|
|
{
|
|
SPIE_LISTENADDRESSINFO ListenAddressInfo;
|
|
HRESULT hTempResult;
|
|
|
|
|
|
if ( m_hListenEndpoint != INVALID_HANDLE_VALUE )
|
|
{
|
|
hr = DPNERR_ALREADYINITIALIZED;
|
|
DPFX(DPFPREP, 0, "Attempted to bind listen endpoint when one already exists!" );
|
|
goto Failure;
|
|
}
|
|
m_hListenEndpoint = pEndpoint->GetHandle();
|
|
|
|
//
|
|
// set addressing information
|
|
//
|
|
pDeviceAddress = ComPortData()->DP8AddressFromComPortData( ADDRESS_TYPE_LOCAL_ADAPTER );
|
|
DNASSERT( pHostAddress == NULL );
|
|
|
|
memset( &ListenAddressInfo, 0x00, sizeof( ListenAddressInfo ) );
|
|
ListenAddressInfo.pDeviceAddress = pDeviceAddress;
|
|
ListenAddressInfo.hCommandStatus = DPN_OK;
|
|
ListenAddressInfo.pCommandContext = pEndpoint->GetCommandData()->GetUserContext();
|
|
|
|
if ( ListenAddressInfo.pDeviceAddress == NULL )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to build addresses to indicate serial listen addressing!" );
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
hTempResult = IDP8SPCallback_IndicateEvent( GetSPData()->DP8SPCallbackInterface(), // interface
|
|
SPEV_LISTENADDRESSINFO, // event type
|
|
&ListenAddressInfo // pointer to data
|
|
);
|
|
DNASSERT( hTempResult == DPN_OK );
|
|
|
|
break;
|
|
}
|
|
|
|
case ENDPOINT_TYPE_ENUM:
|
|
{
|
|
SPIE_ENUMADDRESSINFO EnumAddressInfo;
|
|
HRESULT hTempResult;
|
|
|
|
|
|
if ( m_hEnumEndpoint != INVALID_HANDLE_VALUE )
|
|
{
|
|
hr = DPNERR_ALREADYINITIALIZED;
|
|
DPFX(DPFPREP, 0, "Attempted to bind enum endpoint when one already exists!" );
|
|
goto Exit;
|
|
}
|
|
m_hEnumEndpoint = pEndpoint->GetHandle();
|
|
|
|
//
|
|
// indicate addressing to a higher layer
|
|
//
|
|
pDeviceAddress = ComPortData()->DP8AddressFromComPortData( ADDRESS_TYPE_LOCAL_ADAPTER );
|
|
pHostAddress = ComPortData()->DP8AddressFromComPortData( ADDRESS_TYPE_REMOTE_HOST );
|
|
|
|
memset( &EnumAddressInfo, 0x00, sizeof( EnumAddressInfo ) );
|
|
EnumAddressInfo.pDeviceAddress = pDeviceAddress;
|
|
EnumAddressInfo.pHostAddress = pHostAddress;
|
|
EnumAddressInfo.hCommandStatus = DPN_OK;
|
|
EnumAddressInfo.pCommandContext = pEndpoint->GetCommandData()->GetUserContext();
|
|
|
|
if ( ( EnumAddressInfo.pDeviceAddress == NULL ) ||
|
|
( EnumAddressInfo.pHostAddress == NULL ) )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to build addresses to indicate serial enum addressing!" );
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
hTempResult = IDP8SPCallback_IndicateEvent( GetSPData()->DP8SPCallbackInterface(),
|
|
SPEV_ENUMADDRESSINFO,
|
|
&EnumAddressInfo
|
|
);
|
|
DNASSERT( hTempResult == DPN_OK );
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// invalid case, we should never be here
|
|
//
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// add these references before the lock is released to prevent them from
|
|
// being immediately cleaned
|
|
//
|
|
pEndpoint->SetDataPort( this );
|
|
pEndpoint->AddRef();
|
|
|
|
//
|
|
// if this was a connect or enum, indicate that the outgoing connection is
|
|
// ready.
|
|
//
|
|
if ( ( EndpointType == ENDPOINT_TYPE_CONNECT ) ||
|
|
( EndpointType == ENDPOINT_TYPE_ENUM ) )
|
|
{
|
|
pEndpoint->OutgoingConnectionEstablished( DPN_OK );
|
|
}
|
|
|
|
Unlock();
|
|
|
|
Exit:
|
|
if ( pHostAddress != NULL )
|
|
{
|
|
IDirectPlay8Address_Release( pHostAddress );
|
|
pHostAddress = NULL;
|
|
}
|
|
|
|
if ( pDeviceAddress != NULL )
|
|
{
|
|
IDirectPlay8Address_Release( pDeviceAddress );
|
|
pDeviceAddress = NULL;
|
|
}
|
|
|
|
return hr;
|
|
|
|
Failure:
|
|
Unlock();
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CComPort::UnbindEndpoint - unbind endpoint from this data port
|
|
//
|
|
// Entry: Pointer to endpoint
|
|
// Endpoint type
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ComPort::UnbindEndpoint"
|
|
void CComPort::UnbindEndpoint( CEndpoint *const pEndpoint, const ENDPOINT_TYPE EndpointType )
|
|
{
|
|
DNASSERT( pEndpoint != NULL );
|
|
|
|
Lock();
|
|
|
|
DNASSERT( pEndpoint->GetDataPort() == this );
|
|
switch ( EndpointType )
|
|
{
|
|
case ENDPOINT_TYPE_CONNECT_ON_LISTEN:
|
|
case ENDPOINT_TYPE_CONNECT:
|
|
{
|
|
DNASSERT( m_hConnectEndpoint != INVALID_HANDLE_VALUE );
|
|
m_hConnectEndpoint = INVALID_HANDLE_VALUE;
|
|
break;
|
|
}
|
|
|
|
case ENDPOINT_TYPE_LISTEN:
|
|
{
|
|
DNASSERT( m_hListenEndpoint != INVALID_HANDLE_VALUE );
|
|
m_hListenEndpoint = INVALID_HANDLE_VALUE;
|
|
break;
|
|
}
|
|
|
|
case ENDPOINT_TYPE_ENUM:
|
|
{
|
|
DNASSERT( m_hEnumEndpoint != INVALID_HANDLE_VALUE );
|
|
m_hEnumEndpoint = INVALID_HANDLE_VALUE;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
|
|
Unlock();
|
|
|
|
pEndpoint->SetDataPort( NULL );
|
|
pEndpoint->DecRef();
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CComPort::PoolAllocFunction - called when new pool item is allocated
|
|
//
|
|
// Entry: Pointer to context
|
|
//
|
|
// Exit: Boolean inidcating success
|
|
// TRUE = success
|
|
// FALSE = failure
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ComPort::PoolAllocFunction"
|
|
|
|
BOOL CComPort::PoolAllocFunction( DATA_PORT_POOL_CONTEXT *pContext )
|
|
{
|
|
DNASSERT( pContext != NULL );
|
|
DNASSERT( pContext->pSPData->GetType() == TYPE_SERIAL );
|
|
DNASSERT( GetActiveRead() == NULL );
|
|
DNASSERT( GetHandle() == INVALID_HANDLE_VALUE );
|
|
|
|
return TRUE;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CComPort::PoolInitFunction - called when new pool item is removed from pool
|
|
//
|
|
// Entry: Pointer to context
|
|
//
|
|
// Exit: Boolean inidcating success
|
|
// TRUE = success
|
|
// FALSE = failure
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ComPort::PoolInitFunction"
|
|
|
|
BOOL CComPort::PoolInitFunction( DATA_PORT_POOL_CONTEXT *pContext )
|
|
{
|
|
BOOL fReturn;
|
|
HRESULT hTempResult;
|
|
|
|
|
|
DNASSERT( pContext != NULL );
|
|
DNASSERT( pContext->pSPData->GetType() == TYPE_SERIAL );
|
|
|
|
fReturn = TRUE;
|
|
DNASSERT( GetActiveRead() == NULL );
|
|
DNASSERT( GetHandle() == INVALID_HANDLE_VALUE );
|
|
|
|
hTempResult = CDataPort::Initialize( pContext->pSPData );
|
|
if ( hTempResult != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to initalize DataPort base class!" );
|
|
DisplayDNError( 0, hTempResult );
|
|
fReturn = FALSE;
|
|
}
|
|
|
|
return fReturn;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CComPort::PoolReleaseFunction - called when new pool item is returned to pool
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ComPort::PoolReleaseFunction"
|
|
|
|
void CComPort::PoolReleaseFunction( void )
|
|
{
|
|
CDataPort::Deinitialize();
|
|
m_ComPortData.Reset();
|
|
DNASSERT( GetActiveRead() == NULL );
|
|
DNASSERT( GetHandle() == INVALID_HANDLE_VALUE );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CComPort::PoolDeallocFunction - called when new pool item is deallocated
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ComPort::PoolDeallocFunction"
|
|
|
|
void CComPort::PoolDeallocFunction( void )
|
|
{
|
|
DNASSERT( GetActiveRead() == NULL );
|
|
DNASSERT( GetHandle() == INVALID_HANDLE_VALUE );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CComPort::SetPortState - set communications port state
|
|
// description
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ComPort::SetPortState"
|
|
|
|
HRESULT CComPort::SetPortState( void )
|
|
{
|
|
DCB Dcb;
|
|
HRESULT hr;
|
|
|
|
|
|
DNASSERT( m_hFile != INVALID_HANDLE_VALUE );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
memset( &Dcb, 0x00, sizeof( Dcb ) );
|
|
Dcb.DCBlength = sizeof( Dcb );
|
|
|
|
//
|
|
// set parameters
|
|
//
|
|
Dcb.BaudRate = GetBaudRate(); // current baud rate
|
|
Dcb.fBinary = TRUE; // binary mode, no EOF check (MUST BE TRUE FOR WIN32!)
|
|
|
|
//
|
|
// parity
|
|
//
|
|
if ( GetParity() != NOPARITY )
|
|
{
|
|
Dcb.fParity = TRUE;
|
|
}
|
|
else
|
|
{
|
|
Dcb.fParity = FALSE;
|
|
}
|
|
|
|
//
|
|
// are we using RTS?
|
|
//
|
|
if ( ( GetFlowControl() == FLOW_RTS ) ||
|
|
( GetFlowControl() == FLOW_RTSDTR ) )
|
|
{
|
|
Dcb.fOutxCtsFlow = TRUE; // allow RTS/CTS
|
|
Dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; // handshake with RTS/CTS
|
|
}
|
|
else
|
|
{
|
|
Dcb.fOutxCtsFlow = FALSE; // disable RTS/CTS
|
|
Dcb.fRtsControl = RTS_CONTROL_ENABLE; // always be transmit ready
|
|
}
|
|
|
|
//
|
|
// are we using DTR?
|
|
//
|
|
if ( ( GetFlowControl() == FLOW_DTR ) ||
|
|
( GetFlowControl() == FLOW_RTSDTR ) )
|
|
{
|
|
Dcb.fOutxDsrFlow = TRUE; // allow DTR/DSR
|
|
Dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; // handshake with DTR/DSR
|
|
}
|
|
else
|
|
{
|
|
Dcb.fOutxDsrFlow = FALSE; // disable DTR/DSR
|
|
Dcb.fDtrControl = DTR_CONTROL_ENABLE; // always be ready
|
|
}
|
|
|
|
|
|
//
|
|
// DSR sensitivity
|
|
//
|
|
Dcb.fDsrSensitivity = FALSE; // TRUE = incoming data dropped if DTR is not set
|
|
|
|
//
|
|
// continue sending after Xoff
|
|
//
|
|
Dcb.fTXContinueOnXoff= FALSE; // TRUE = continue to send data after XOFF has been received
|
|
// and there's room in the buffer
|
|
|
|
|
|
//
|
|
// are we using Xon/Xoff?
|
|
//
|
|
if ( GetFlowControl() == FLOW_XONXOFF )
|
|
{
|
|
Dcb.fOutX = TRUE;
|
|
Dcb.fInX = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// disable Xon/Xoff
|
|
Dcb.fOutX = FALSE;
|
|
Dcb.fInX = FALSE;
|
|
}
|
|
|
|
//
|
|
// replace erroneous bytes with 'Error Byte'
|
|
//
|
|
Dcb.fErrorChar = FALSE; // TRUE = replace bytes with parity errors with
|
|
// an error character
|
|
|
|
//
|
|
// drop NULL characters
|
|
//
|
|
Dcb.fNull = FALSE; // TRUE = remove NULLs from input stream
|
|
|
|
//
|
|
// stop on error
|
|
//
|
|
Dcb.fAbortOnError = FALSE; // TRUE = abort reads/writes on error
|
|
|
|
//
|
|
// reserved, set to zero!
|
|
//
|
|
Dcb.fDummy2 = NULL; // reserved
|
|
|
|
//
|
|
// reserved
|
|
//
|
|
Dcb.wReserved = NULL; // not currently used
|
|
|
|
//
|
|
// buffer size before sending Xon/Xoff
|
|
//
|
|
Dcb.XonLim = XON_LIMIT; // transmit XON threshold
|
|
Dcb.XoffLim = XOFF_LIMIT; // transmit XOFF threshold
|
|
|
|
//
|
|
// size of a 'byte'
|
|
//
|
|
Dcb.ByteSize = BITS_PER_BYTE; // number of bits/byte, 4-8
|
|
|
|
//
|
|
// set parity type
|
|
//
|
|
DNASSERT( GetParity() < 256 );
|
|
Dcb.Parity = static_cast<BYTE>( GetParity() );
|
|
|
|
//
|
|
// stop bits
|
|
//
|
|
DNASSERT( GetStopBits() < 256 );
|
|
Dcb.StopBits = static_cast<BYTE>( GetStopBits() ); // 0,1,2 = 1, 1.5, 2
|
|
|
|
//
|
|
// Xon/Xoff characters
|
|
//
|
|
Dcb.XonChar = ASCII_XON; // Tx and Rx XON character
|
|
Dcb.XoffChar = ASCII_XOFF; // Tx and Rx XOFF character
|
|
|
|
//
|
|
// error replacement character
|
|
//
|
|
Dcb.ErrorChar = NULL_TOKEN; // error replacement character
|
|
|
|
//
|
|
// EOF character
|
|
//
|
|
Dcb.EofChar = NULL_TOKEN; // end of input character
|
|
|
|
//
|
|
// event signal character
|
|
//
|
|
Dcb.EvtChar = NULL_TOKEN; // event character
|
|
|
|
Dcb.wReserved1 = 0; // reserved; do not use
|
|
|
|
//
|
|
// set the state of the communication port
|
|
//
|
|
if ( SetCommState( m_hFile, &Dcb ) == FALSE )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
hr = DPNERR_GENERIC;
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "SetCommState failed!" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
//**********************************************************************
|
|
|