Page 1 of 1

Para Antonio Linhares (comm.c , BuildCommDCB, SetCommState)

Posted: Fri Oct 21, 2005 3:32 am
by Gilson Lopes
Antonio

1-) Fiz algumas alteracoes no fonte COMM.C para FWH.
Espero que sirva outros usuarios.
2-) Gostaria muito que se agregasse as futuras versoes de FWH
(nao estou sendo pretencioso). Acontece que a toda atualizacao
recompilo o codigo e atacho a FIVEHC.LIB
3-) Segue pequeno exemplo de como usar SetCommState() em
WinXP/NT que é uma dor de cabeça para muitos usuarios.


/////////////////
COMM.C
////////////////

#include <WinTen.h>
#include <Windows.h>
#include <ClipApi.h>

#ifdef __FLAT__
int OpenComm( LPCSTR lpszDevControl, unsigned int cbInQueue,
unsigned int cbOutQueue );
int CloseComm( int idComDev );
int FlushComm( int idComDev, int fnQueue );
int WriteComm( int idComDev, LPCVOID lpvBuf, int cbWrite );
int ReadComm( int idComDev, LPVOID lpvBuf, int cbRead );
int GetCommError( int idComDev, COMSTAT * lpStat );
BOOL EnableCommNotification( int idComDev, HWND hwnd,
int cbWriteNotify, int cbOutQueue );
DWORD ThreadCommNotification( LPVOID data );
int GetCommHandle( int idComDev );
#endif

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

CLIPPER OPENCOMM( PARAMS ) // cPortName, nInQueue, nOutQueue --> nPortId
{
WORD cbInQueue = IF( ISNUM( 2 ), _parni( 2 ), 1024 );
WORD cbOutQueue = IF( ISNUM( 3 ), _parni( 3 ), 128 );

_retni( OpenComm( _parc( 1 ), cbInQueue, cbOutQueue ) );
}

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

CLIPPER CLOSECOMM( PARAMS )
{
_retl( CloseComm( _parni( 1 ) ) == 0 );
}

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

CLIPPER WRITECOMM( PARAMS )
{
_retni( WriteComm( _parni( 1 ), _parc( 2 ), _parclen( 2 ) ) );
}

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

CLIPPER READCOMM( PARAMS ) // ( nId, @ cBuffer ) --> nBytesRead
{
_retni( ReadComm( _parni( 1 ), _parc( 2 ), _parclen( 2 ) ) );
}

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

#ifdef __HARBOUR__
CLIPPER BUILDCOMMDCB( PARAMS ) // () cInfoDef, @ cDeviceBlock --> lOk
#else
CLIPPER BUILDCOMMD( PARAMS ) // CB() cInfoDef, @ cDeviceBlock --> lOk
#endif
{
DCB dcb;

#ifdef __FLAT__
if( BuildCommDCB( _parc( 1 ), &dcb ) ) // OK
#else
if( BuildCommDCB( _parc( 1 ), &dcb ) == 0 ) // OK
#endif
{
_storclen( ( char * ) &dcb, sizeof( dcb ), 2 );
_retl( TRUE );
}
else // Error
{
_storc( "", 2 );
_retl( FALSE );
}
}

//----------------------------------------------------------------------------//
/*
#ifdef __HARBOUR__
CLIPPER GETCOMMSTATE( PARAMS ) // () cInfoDef, @ cDeviceBlock --> lOk
#else
CLIPPER GETCOMMSTA( PARAMS ) // TE() cInfoDef, @ cDeviceBlock --> lOk
#endif
{
DCB dcb;

#ifdef __FLAT__
if( GetCommState( (HANDLE) GetCommHandle( _parni( 1 ) ), &dcb ) ) // OK
#else
if( GetCommState( ( int ) GetCommHandle( _parni( 1 ) ), &dcb ) == 0 ) // OK
#endif
{
_storclen( ( char * ) &dcb, sizeof( dcb ), 2 );
_retl( TRUE );
}
else // Error
{
_storc( "", 2 );
_retl( FALSE );
}
}
*/

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

/*
#ifdef __HARBOUR__
CLIPPER GETCOMMHANDLE( PARAMS ) // () idCommDev ==> nHandle
#else
CLIPPER GETCOMMHAN( PARAMS ) //DLE()
#endif
{
_retni( GetCommHandle( _parni( 1 ) ) );
}
*/

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

#ifdef __HARBOUR__
CLIPPER SETCOMMSTATE( PARAMS ) // ()
#else
CLIPPER SETCOMMSTA( PARAMS ) // TE()
#endif
{
#ifdef __FLAT__
_retl( SetCommState( (HANDLE) GetCommHandle( _parni( 1 ) ), ( DCB FAR * ) _parc( 2 ) ) );
#else
_retl( SetCommState( ( DCB FAR * ) _parc( 1 ) ) == 0 );
#endif
}

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

CLIPPER FLUSHCOMM( PARAMS )
{
_retni( FlushComm( _parni( 1 ), _parni( 2 ) ) );
}

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

#ifdef __HARBOUR__
CLIPPER GETCOMMERROR( PARAMS ) // ()
#else
CLIPPER GETCOMMERR( PARAMS ) // OR()
#endif
{
COMSTAT stat;

_retni( GetCommError( _parni( 1 ), ( PCOUNT() > 1 ) ? &stat: 0 ) );

if( ( int ) PCOUNT() > 1 )
_storclen( ( char * ) &stat, sizeof( COMSTAT ), 2 );
}

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

#ifdef __HARBOUR__
CLIPPER ENABLECOMMNOTIFICATION( PARAMS ) // ( nComDev, hWnd, nInBytes, nOutBytes )
// --> <lSuccess>
#else
CLIPPER ENABLECOMM( PARAMS ) // NOTIFICATION( nComDev, hWnd, nInBytes, nOutBytes )
#endif // --> <lSuccess>
{
_retl( EnableCommNotification( _parni( 1 ), ( HWND ) _parni( 2 ),
_parni( 3 ), _parni( 4 ) ) );
}

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

#ifdef __HARBOUR__
CLIPPER ESCAPECOMMFUNCTION( PARAMS ) // ( nComDev, nFunctionCode )
// --> <lSuccess>
#else
CLIPPER ESCAPECOMM( PARAMS ) // FUNCTION( nComDev, nFunctionCode )
// --> <lSuccess>
#endif
{
_retl( ! EscapeCommFunction( ( HANDLE ) _parnl( 1 ), _parni( 2 ) ) );
}

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

#ifdef __FLAT__

typedef struct _tagCOMMST
{
HANDLE hComm;
HANDLE hThread;
HWND hWndEv;
int cbWriteNotify;
int cbOutQueue;
}COMMST, *LPCOMMST;

int OpenComm( LPCSTR lpszDevControl, UINT cbInQueue, UINT cbOutQueue )
{
char port[ 16 ];
HANDLE hComm;
LPCOMMST Com = ( LPCOMMST ) LocalLock( LocalAlloc( LPTR, sizeof( COMMST ) ) );
COMMTIMEOUTS ct;

wsprintf( port, "\\%s", lpszDevControl );

Com->hComm = CreateFile( port, GENERIC_WRITE | GENERIC_READ, 0, NULL,
OPEN_EXISTING, 0, NULL );
SetupComm( Com->hComm, cbInQueue, cbOutQueue );

ct.ReadIntervalTimeout = MAXDWORD;
ct.ReadTotalTimeoutMultiplier = 0;
ct.ReadTotalTimeoutConstant = 0;
ct.WriteTotalTimeoutMultiplier = 10;
ct.WriteTotalTimeoutConstant = 1000;
SetCommTimeouts( Com->hComm, &ct );

return ( int ) Com;
}

int CloseComm( int idComDev )
{
int nRet;
LPCOMMST Com = ( LPCOMMST )idComDev;

TerminateThread( Com->hThread, 0 );

nRet = ( int )( CloseHandle( Com->hComm ) ? 0 : -1 );
LocalFree( LocalHandle( ( LPVOID ) Com ) );

return nRet;
}

int FlushComm( int idComDev, int fnQueue )
{
LPCOMMST Com = ( LPCOMMST )idComDev;
return ( int ) FlushFileBuffers( Com->hComm );
}

int GetCommHandle( int idComDev )
{
LPCOMMST Com = ( LPCOMMST )idComDev;
return ( int ) Com->hComm ;
}

int WriteComm( int idComDev, LPCVOID lpvBuf, int cbWrite )
{
DWORD dw = 0;
LPCOMMST Com = ( LPCOMMST )idComDev;
WriteFile( Com->hComm, lpvBuf, ( DWORD )cbWrite, &dw, NULL );
return ( int ) dw ? dw : -1;
}

int ReadComm( int idComDev, LPVOID lpvBuf, int cbRead )
{
DWORD dw = 0;
LPCOMMST Com = ( LPCOMMST )idComDev;
ReadFile( Com->hComm, lpvBuf, ( DWORD )cbRead, &dw, NULL );
return ( int ) dw ? dw : -1;
}

//COMSTAT existen en 16 y en 32
int GetCommError( int idComDev, COMSTAT * lpStat )
{
LPCOMMST Com = ( LPCOMMST )idComDev;
DWORD nRetErrors = 0;

ClearCommError( Com->hComm, &nRetErrors, lpStat );

return ( int )nRetErrors;
}


DWORD ThreadCommNotification( LPVOID data )
{
LPCOMMST Com = ( LPCOMMST )data;
DWORD dwEvtMask;
int dwReceived = 0, dwSent = 0;

GetCommMask( Com->hComm, &dwEvtMask );
SetCommMask( Com->hComm, EV_RXCHAR | EV_RXFLAG | dwEvtMask );

for( ; ; )
{
WaitCommEvent( Com->hComm, &dwEvtMask, NULL );

if( dwEvtMask & EV_RXCHAR )
{
dwReceived++;
if( dwReceived == Com->cbWriteNotify )
{
dwReceived = 0;
PostMessage( Com->hWndEv, WM_COMMNOTIFY, ( WPARAM )Com, ( LPARAM )0x01 ); //CN_RECEIVE
}
}
else
{
if( dwSent & EV_RXFLAG )
{
dwSent++;
if( dwSent == Com->cbOutQueue )
{
dwSent = 0;
PostMessage( Com->hWndEv, WM_COMMNOTIFY, ( WPARAM )Com, ( LPARAM )0x02 ); //CN_TRANSMIT
}
}
}
PostMessage( Com->hWndEv, WM_COMMNOTIFY, ( WPARAM )Com, ( LPARAM )0x04 ); //CN_EVENT
}
// return 0;
}

BOOL EnableCommNotification( int idComDev, HWND hwnd, int cbWriteNotify, int cbOutQueue )
{
LPCOMMST Com = ( LPCOMMST )idComDev;
DWORD ThId;

Com->hWndEv = hwnd;
Com->cbWriteNotify = cbWriteNotify;
Com->cbOutQueue = cbOutQueue;
Com->hThread = CreateThread( NULL, NULL,
( LPTHREAD_START_ROUTINE )ThreadCommNotification,( LPVOID ) Com, NULL, &ThId );

return TRUE;
}

#endif

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








/////////////////
SAMPLE PRG
////////////////

// Teste de uso da porta COMM

//
// exemplo de uso de porta COMM
//

/*

... sua rotina

nPortA:= InitComm( "COM1", "19200,n,8,1" )
if nPortA > 0
// ... Porta aberta com sucesso...
endif

nPortB:= InitComm( "COM2", "4800,n,8,1" ) // usando uma outra porta
if nPortB > 0
// ... Porta aberta com sucesso...
endif


... sua rotina


if nPortA > 0 // COMM aberta
CloseComm( nPortA )
endif

if nPortB > 0 // COMM aberta
CloseComm( nPortB )
endif

... sua rotina

QUIT

*/

////////////////////////////////////////////////
// InitComm( c_Porta_Comm, cProperties ) //Ex: InitiComm( "COM1", "4800,n,8,1" )
////////////////////////////////////////////////
Function InitComm( cPort, cProp )
local nComm, sComm:="", lOkComm:= .f.

if empty( cPort)
cPort:= "COM1"
endif

if empty( cProp )
cProp:= "19200,n,8,1"
endif

if ( nComm := OpenComm( cPort, 2048, 512 ) ) < 1
MsgStop( cPort + " - Nao disponivel.")
retu 0
endif

if !BuildCommDcb( cPort + ":" + cProp, @sComm )
MsgStop( cPort + " - Nao ativa.")
CloseComm( nComm )
retu 0
endif

sComm:= AdjustDCB( sComm ) // corrige DCB

if !SetCommState( nComm, sComm)
MsgStop( cPort + " - Nao ativa.")
CloseComm( nComm )
retu 0
endif

if !writeComm(nComm, "}}}}}}" )<>6
MsgStop( cPort + " - falha gravacao.")
CloseComm( nComm )
retu 0
endif

if !FlushComm(nComm,0) = 1
MsgStop( cPort + " - falha fluxo.")
CloseComm( nComm )
retu 0
endif

retu nComm


Function AdjustDCB( _dcb )

// Obs
//
// no WinXp/NT, a funcao BuildCommDCB() retorna estrutura DCB com valores
// de threshold para XonLim e XoffLim, e, se o controle de fluxo nao estiver
// configurado para Xon/Xoff a funcao SetCommState() retorna falso.
// A solucao esta em zerar os valores de threshold para XonLim e XoffLim

// _dcb:= subs( _dcb,1,14) + L2Bin( 0 ) + subs( _dcb,19 ) // XonLim,XoffLim set to 0
// retu ( _dcb )

// Obs 2
// Consulte estrutura DCB p/ alterar outros valores conforme necessidade

// Ex.: Setar Binary Mode e habilitar DTR
//
// habilitar DTR eh obrigatorio para quem utiliza conversor RS232<->485
// e tambem para alguns conversores USB<->RS232
//
// 1h=binary_mode_true + 10h=Ctr_DTR_Enable == 11h == chr(17)
// alterar byte 9 do DCB ( total da estrutura DCB = 28 bytes )
// _dcb:= subs( _dcb, 1, 8) + chr( 17 ) + chr( 0 ) + subs( _dcb, 10, 4) + ;
// L2Bin( 0 ) + subs( _dcb, 19 )
// retu ( _dcb )

retu subs( _dcb,1,14) + L2Bin( 0 ) + subs( _dcb,19 )
[/list]