1
0
mirror of https://github.com/elua/elua.git synced 2025-01-08 20:56:17 +08:00

Merged Mike King's patch for serial_win32.c

This commit is contained in:
Mike King 2011-05-07 22:04:09 +03:00 committed by Bogdan Marinescu
parent 6cd2ba8366
commit 328bdb6094

View File

@ -8,17 +8,24 @@
#include "serial.h"
#define WIN_ERROR ( HANDLE )-1
#define WIN_MAX_PORT_NAME 1024
#define WIN_MAX_PORT_NAME MAX_PATH
#define MAX_HANDLES 1024
static HANDLE sel_handlers[ MAX_HANDLES ];
static int sel_handler_map[ MAX_HANDLES ];
static HANDLE sel_handlers[ MAX_HANDLES ]; // XXX: consider making this an static variable of ser_select_byte
static int sel_handler_map[ MAX_HANDLES ]; // XXX: consider making this an static variable of ser_select_byte
static void init_ov( OVERLAPPED* o )
{
HANDLE temp = o->hEvent;
memset( o, 0, sizeof( OVERLAPPED ) );
o->hEvent = temp;
}
// Helper: set timeout
static int ser_win32_set_timeouts( HANDLE hComm, DWORD ri, DWORD rtm, DWORD rtc, DWORD wtm, DWORD wtc )
{
{
COMMTIMEOUTS timeouts;
if( GetCommTimeouts( hComm, &timeouts ) == FALSE )
{
CloseHandle( hComm );
@ -29,18 +36,18 @@ static int ser_win32_set_timeouts( HANDLE hComm, DWORD ri, DWORD rtm, DWORD rtc,
timeouts.ReadTotalTimeoutMultiplier = rtc;
timeouts.WriteTotalTimeoutConstant = wtm;
timeouts.WriteTotalTimeoutMultiplier = wtc;
if( SetCommTimeouts( hComm, &timeouts ) == FALSE )
{
CloseHandle( hComm );
return SER_ERR;
}
if( SetCommTimeouts( hComm, &timeouts ) == FALSE )
{
CloseHandle( hComm );
return SER_ERR;
}
return SER_OK;
}
// Helper: set communication timeout
static int ser_set_timeout_ms( HANDLE hComm, u32 timeout )
{
{
if( timeout == SER_NO_TIMEOUT )
return ser_win32_set_timeouts( hComm, MAXDWORD, 0, 0, 0, 0 );
else if( timeout == SER_INF_TIMEOUT )
@ -55,8 +62,8 @@ ser_handler ser_open( const char* sername )
char portname[ WIN_MAX_PORT_NAME + 1 ];
HANDLE hComm;
ser_handler hnd;
portname[ 0 ] = portname[ WIN_MAX_PORT_NAME ] = '\0';
portname[ WIN_MAX_PORT_NAME ] = '\0';
_snprintf( portname, WIN_MAX_PORT_NAME, "\\\\.\\%s", sername );
hComm = CreateFile( portname, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0 );
if( hComm == INVALID_HANDLE_VALUE )
@ -70,10 +77,17 @@ ser_handler ser_open( const char* sername )
memset( hnd, 0, sizeof( SERIAL_DATA ) );
hnd->hnd = hComm;
hnd->fWaitingOnRead = FALSE;
if( ( hnd->o.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) ) == NULL )
if( ( hnd->o.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) ) == NULL )
{
free( hnd );
return SER_HANDLER_INVALID;
if( ( hnd->o_wr.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) ) == NULL )
return SER_HANDLER_INVALID;
}
if( ( hnd->o_wr.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) ) == NULL )
{
free( hnd );
CloseHandle( hnd->o.hEvent );
return SER_HANDLER_INVALID;
}
return hnd;
}
@ -81,7 +95,7 @@ ser_handler ser_open( const char* sername )
void ser_close( ser_handler id )
{
CloseHandle( id->o.hEvent );
CloseHandle( id->o_wr.hEvent );
CloseHandle( id->o_wr.hEvent );
CloseHandle( id->hnd );
free( id );
}
@ -90,12 +104,13 @@ int ser_setup( ser_handler id, u32 baud, int databits, int parity, int stopbits,
{
HANDLE hComm = id->hnd;
DCB dcb;
if( GetCommState( hComm, &dcb ) == FALSE )
{
CloseHandle( hComm );
return SER_ERR;
}
dcb.DCBlength = sizeof(DCB);
if( GetCommState( hComm, &dcb ) == FALSE )
{
CloseHandle( hComm );
return SER_ERR;
}
dcb.BaudRate = baud;
dcb.ByteSize = databits;
dcb.Parity = parity == SER_PARITY_NONE ? NOPARITY : ( parity == SER_PARITY_EVEN ? EVENPARITY : ODDPARITY );
@ -120,59 +135,63 @@ int ser_setup( ser_handler id, u32 baud, int databits, int parity, int stopbits,
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
dcb.fOutxCtsFlow = TRUE;
}
if( SetCommState( hComm, &dcb ) == 0 )
if( SetCommState( hComm, &dcb ) == FALSE )
{
CloseHandle( hComm );
return SER_ERR;
}
if( ser_win32_set_timeouts( hComm, 0, 0, 0, 0, 0 ) == SER_ERR )
{
CloseHandle( hComm );
return SER_ERR;
}
FlushFileBuffers( hComm );
return SER_OK;
}
// Read up to the specified number of bytes, return bytes actually read
u32 ser_read( ser_handler id, u8* dest, u32 maxsize, u32 timeout )
static u32 ser_read_internal( ser_handler id, u32 timeout )
{
HANDLE hComm = id->hnd;
DWORD readbytes = 0;
if( !id->fWaitingOnRead )
DWORD dwRes = WaitForSingleObject( id->o.hEvent, timeout == SER_INF_TIMEOUT ? INFINITE : timeout );
if( dwRes == WAIT_OBJECT_0 )
{
if( ReadFile( hComm, dest, maxsize, &readbytes, &id->o ) == FALSE )
{
if( GetLastError() != ERROR_IO_PENDING )
return 0;
else
id->fWaitingOnRead = TRUE;
}
else
return readbytes;
if( !GetOverlappedResult( hComm, &id->o, &readbytes, TRUE ) )
readbytes = 0;
}
else if( dwRes == WAIT_TIMEOUT )
{
CancelIo( hComm );
GetOverlappedResult( hComm, &id->o, &readbytes, TRUE );
readbytes = 0;
}
ResetEvent( id->o.hEvent );
return readbytes;
}
// Read up to the specified number of bytes, return bytes actually read
u32 ser_read( ser_handler id, u8* dest, u32 maxsize, u32 timeout )
{
DWORD readbytes = 0;
if( id->fWaitingOnRead )
{
DWORD dwRes = WaitForSingleObject( id->o.hEvent, timeout == SER_INF_TIMEOUT ? INFINITE : timeout );
if( dwRes == WAIT_OBJECT_0 )
{
if( !GetOverlappedResult( hComm, &id->o, &readbytes, TRUE ) )
readbytes = 0;
}
else if( dwRes == WAIT_TIMEOUT )
{
CancelIo( hComm );
GetOverlappedResult( hComm, &id->o, &readbytes, TRUE );
readbytes = 0;
}
ResetEvent( id->o.hEvent );
}
id->fWaitingOnRead = FALSE;
readbytes = ser_read_internal( id, timeout );
dest[0] = id->databuf;
}
else
{
init_ov( &id->o );
if( ReadFile( id->hnd, dest, maxsize, &readbytes, &id->o ) )
return readbytes;
if( GetLastError() != ERROR_IO_PENDING )
return 0;
id->fWaitingOnRead = TRUE; // XXX: consider removing statement
readbytes = ser_read_internal( id, timeout );
}
id->fWaitingOnRead = FALSE;
return readbytes;
}
@ -180,41 +199,25 @@ u32 ser_read( ser_handler id, u8* dest, u32 maxsize, u32 timeout )
int ser_read_byte( ser_handler id, u32 timeout )
{
u8 data;
int res = ser_read( id, &data, 1, timeout );
return res == 1 ? data : -1;
return ser_read( id, &data, 1, timeout ) == 1 ? data : -1;
}
// Write up to the specified number of bytes, return bytes actually written
u32 ser_write( ser_handler id, const u8 *src, u32 size )
{
HANDLE hComm = id->hnd;
DWORD written = 0;
BOOL fWaitingOnWrite = FALSE;
HANDLE temp = id->o_wr.hEvent;
memset( &id->o_wr, 0, sizeof( OVERLAPPED ) );
id->o_wr.hEvent = temp;
if( WriteFile( hComm, src, size, &written, &id->o_wr ) == FALSE )
{
if( GetLastError() != ERROR_IO_PENDING )
return 0;
else
fWaitingOnWrite = TRUE;
}
else
DWORD written;
init_ov( &id->o_wr );
if( WriteFile( hComm, src, size, &written, &id->o_wr ) )
return written;
if( GetLastError() != ERROR_IO_PENDING )
return 0;
if( !GetOverlappedResult( hComm, &id->o_wr, &written, TRUE ) )
written = 0;
ResetEvent( id->o_wr.hEvent );
if( fWaitingOnWrite )
{
DWORD dwRes = WaitForSingleObject( id->o_wr.hEvent, INFINITE );
if( dwRes == WAIT_OBJECT_0 )
if( !GetOverlappedResult( hComm, &id->o_wr, &written, FALSE ) )
written = 0;
ResetEvent( id->o_wr.hEvent );
}
return written;
return written;
}
// Write a byte to the serial port
@ -228,73 +231,57 @@ u32 ser_write_byte( ser_handler id, u8 data )
// otherwise
int ser_select_byte( ser_handler *pobjects, unsigned nobjects, int timeout )
{
int i, idx;
int i;
DWORD readbytes;
int res = -1;
unsigned num_wait = 0;
ser_handler hnd;
HANDLE temp;
if( nobjects >= MAXIMUM_WAIT_OBJECTS )
return -1;
// Try to read directly first
for( i = 0; i < nobjects; i ++ )
{
temp = pobjects[ i ]->o.hEvent;
memset( &pobjects[ i ]->o, 0, sizeof( OVERLAPPED ) );
pobjects[ i ]->o.hEvent = temp;
{
if( !pobjects[ i ]->fWaitingOnRead )
{
if( ReadFile( pobjects[ i ]->hnd, &pobjects[ i ]->databuf, 1, &readbytes, &pobjects[ i ]->o ) == FALSE )
{
if( GetLastError() != ERROR_IO_PENDING )
return -1;
else
{
pobjects[ i ]->fWaitingOnRead = TRUE;
sel_handler_map[ num_wait ] = i;
sel_handlers[ num_wait ++ ] = pobjects[ i ]->o.hEvent;
}
}
else
{
if( readbytes == 1 )
return pobjects[ i ]->databuf | ( i << 8 );
else
return -1;
}
}
else
{
sel_handler_map[ num_wait ] = i;
sel_handlers[ num_wait ++ ] = pobjects[ i ]->o.hEvent;
}
init_ov( &pobjects[ i ]->o );
if( ReadFile( pobjects[ i ]->hnd, &pobjects[ i ]->databuf, 1, &readbytes, &pobjects[ i ]->o ) )
return readbytes != 1 ? -1 : pobjects[ i ]->databuf | ( i << 8 );
if( GetLastError() != ERROR_IO_PENDING )
return -1;
pobjects[ i ]->fWaitingOnRead = TRUE;
}
sel_handler_map[ num_wait ] = i;
sel_handlers[ num_wait ++ ] = pobjects[ i ]->o.hEvent;
}
if( num_wait > 0 )
if( num_wait == 0 )
return -1;
DWORD dwRes = WaitForMultipleObjects( num_wait, sel_handlers, FALSE, timeout == SER_INF_TIMEOUT ? INFINITE : timeout );
if( dwRes >= WAIT_OBJECT_0 && dwRes < WAIT_OBJECT_0 + num_wait )
{
idx = -1;
DWORD dwRes = WaitForMultipleObjects( num_wait, sel_handlers, FALSE, timeout == SER_INF_TIMEOUT ? INFINITE : timeout );
if( dwRes >= WAIT_OBJECT_0 && dwRes < WAIT_OBJECT_0 + num_wait )
i = dwRes - WAIT_OBJECT_0;
hnd = pobjects[ sel_handler_map[ i ] ];
hnd->fWaitingOnRead = FALSE;
if( GetOverlappedResult( hnd->hnd, &hnd->o, &readbytes, TRUE ) && readbytes == 1 )
res = hnd->databuf | ( sel_handler_map[ i ] << 8 );
ResetEvent( hnd->o.hEvent );
}
else if( dwRes == WAIT_TIMEOUT )
{
for( i = 0; i < num_wait; i ++ )
{
i = idx = dwRes - WAIT_OBJECT_0;
hnd = pobjects[ sel_handler_map[ i ] ];
hnd->fWaitingOnRead = FALSE;
if( GetOverlappedResult( hnd->hnd, &hnd->o, &readbytes, TRUE ) && readbytes == 1 )
res = hnd->databuf | ( sel_handler_map[ i ] << 8 );
ResetEvent( hnd->o.hEvent );
CancelIo( hnd->hnd );
}
else if( dwRes == WAIT_TIMEOUT )
{
for( i = 0; i < num_wait; i ++ )
{
hnd = pobjects[ sel_handler_map[ i ] ];
hnd->fWaitingOnRead = FALSE;
CancelIo( hnd->hnd );
GetOverlappedResult( hnd->hnd, &hnd->o, &readbytes, TRUE );
ResetEvent( hnd->o.hEvent );
}
}
}
return res;
WaitForMultipleObjects( num_wait, sel_handlers, TRUE, INFINITE );
for( i = 0; i < num_wait; i ++ )
ResetEvent( pobjects[ sel_handler_map[ i ] ]->o.hEvent );
}
return res;
}