2003-08-20 07:22:40 +00:00
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if defined(WIN32) && !defined(HAVE_TERMIOS_H)
|
2003-10-17 22:53:54 +00:00
|
|
|
|
|
|
|
|
|
#undef DEBUG
|
|
|
|
|
#undef TRACE
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
#define DEBUG_VERBOSE
|
|
|
|
|
#define DEBUG_ERRORS
|
|
|
|
|
#define report(a) fprintf(stderr,a)
|
|
|
|
|
#define report_warning(a) fprintf(stderr,a)
|
|
|
|
|
#define report_error(a) fprintf(stderr,a)
|
|
|
|
|
#else
|
2003-08-15 01:15:45 +00:00
|
|
|
|
#define report(a) do {} while (0)
|
|
|
|
|
#define report_warning(a) do {} while (0)
|
|
|
|
|
#define report_error(a) do {} while (0)
|
2003-10-17 22:53:54 +00:00
|
|
|
|
#endif /* DEBUG */
|
2003-08-15 01:15:45 +00:00
|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
|
| rxtx is a native interface to serial ports in java.
|
|
|
|
|
| Copyright 1997-2002 by Trent Jarvi taj@www.linux.org.uk.
|
2008-11-05 23:00:20 +00:00
|
|
|
|
| Copyright 1997-2006 by Trent Jarvi taj@www.linux.org.uk.
|
2003-08-15 01:15:45 +00:00
|
|
|
|
|
|
|
|
|
|
| This library is free software; you can redistribute it and/or
|
|
|
|
|
| modify it under the terms of the GNU Library General Public
|
|
|
|
|
| License as published by the Free Software Foundation; either
|
|
|
|
|
| version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
|
| If you compile this program with cygwin32 tools this package falls
|
|
|
|
|
| under the GPL. See COPYING.CYGNUS for details.
|
|
|
|
|
|
|
|
|
|
|
| This library is distributed in the hope that it will be useful,
|
|
|
|
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
| Library General Public License for more details.
|
|
|
|
|
|
|
|
|
|
|
| You should have received a copy of the GNU Library General Public
|
|
|
|
|
| License along with this library; if not, write to the Free
|
|
|
|
|
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
|
|
2008-11-05 23:00:20 +00:00
|
|
|
|
| This file was taken from rxtx-2.1-7 and adaptated for Hamlib.
|
2003-08-15 01:15:45 +00:00
|
|
|
|
--------------------------------------------------------------------------*/
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <time.h>
|
2003-10-17 22:53:54 +00:00
|
|
|
|
#include <limits.h>
|
2003-08-15 01:15:45 +00:00
|
|
|
|
#include "win32termios.h"
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* odd malloc.h error with lcc compiler
|
|
|
|
|
* winsock has FIONREAD with lcc
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef __LCC__
|
|
|
|
|
# include <winsock.h>
|
|
|
|
|
#else
|
|
|
|
|
# include <malloc.h>
|
|
|
|
|
#endif /* __LCC__ */
|
|
|
|
|
|
|
|
|
|
#define SIGIO 0
|
|
|
|
|
|
|
|
|
|
int my_errno;
|
|
|
|
|
extern int errno;
|
|
|
|
|
struct termios_list
|
|
|
|
|
{
|
|
|
|
|
char filename[80];
|
|
|
|
|
int my_errno;
|
|
|
|
|
int interrupt;
|
|
|
|
|
int event_flag;
|
|
|
|
|
int tx_happened;
|
|
|
|
|
unsigned long *hComm;
|
|
|
|
|
struct termios *ttyset;
|
|
|
|
|
struct serial_struct *sstruct;
|
|
|
|
|
/* for DTR DSR */
|
|
|
|
|
unsigned char MSR;
|
|
|
|
|
struct async_struct *astruct;
|
|
|
|
|
struct serial_icounter_struct *sis;
|
|
|
|
|
int open_flags;
|
|
|
|
|
OVERLAPPED rol;
|
|
|
|
|
OVERLAPPED wol;
|
|
|
|
|
OVERLAPPED sol;
|
|
|
|
|
int fd;
|
|
|
|
|
struct termios_list *next;
|
|
|
|
|
struct termios_list *prev;
|
|
|
|
|
};
|
|
|
|
|
struct termios_list *first_tl = NULL;
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
serial_test
|
|
|
|
|
|
|
|
|
|
accept: filename to test
|
|
|
|
|
perform:
|
|
|
|
|
return: 1 on success 0 on failure
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: CreateFile CloseHandle
|
|
|
|
|
comments: if the file opens it should be ok.
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
int win32_serial_test( char * filename )
|
|
|
|
|
{
|
|
|
|
|
unsigned long *hcomm;
|
|
|
|
|
int ret;
|
|
|
|
|
hcomm = CreateFile( filename, GENERIC_READ |GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0 );
|
|
|
|
|
if ( hcomm == INVALID_HANDLE_VALUE )
|
2008-11-05 23:00:20 +00:00
|
|
|
|
{
|
|
|
|
|
if (GetLastError() == ERROR_ACCESS_DENIED)
|
|
|
|
|
{
|
|
|
|
|
ret = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-08-15 01:15:45 +00:00
|
|
|
|
else
|
2008-11-05 23:00:20 +00:00
|
|
|
|
{
|
2003-08-15 01:15:45 +00:00
|
|
|
|
ret = 1;
|
2008-11-05 23:00:20 +00:00
|
|
|
|
}
|
2003-08-15 01:15:45 +00:00
|
|
|
|
CloseHandle( hcomm );
|
|
|
|
|
return(ret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void termios_setflags( int fd, int termios_flags[] )
|
|
|
|
|
{
|
|
|
|
|
struct termios_list *index = find_port( fd );
|
|
|
|
|
int i, result;
|
|
|
|
|
int windows_flags[11] = { 0, EV_RXCHAR, EV_TXEMPTY, EV_CTS, EV_DSR,
|
|
|
|
|
EV_RING|0x2000, EV_RLSD, EV_ERR,
|
|
|
|
|
EV_ERR, EV_ERR, EV_BREAK
|
|
|
|
|
};
|
|
|
|
|
if( !index )
|
|
|
|
|
{
|
|
|
|
|
LEAVE( "termios_setflags" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
index->event_flag = 0;
|
|
|
|
|
for(i=0;i<11;i++)
|
|
|
|
|
if( termios_flags[i] )
|
|
|
|
|
index->event_flag |= windows_flags[i];
|
|
|
|
|
result = SetCommMask( index->hComm, index->event_flag );
|
|
|
|
|
/*
|
|
|
|
|
This is rank. 0x2000 was used to detect the trailing edge of ring.
|
|
|
|
|
The leading edge is detedted by EV_RING.
|
|
|
|
|
|
|
|
|
|
The trailing edge is reliable. The leading edge is not.
|
|
|
|
|
Softie no longer allows the trailing edge to be detected in NTsp2
|
|
|
|
|
and beyond.
|
|
|
|
|
|
|
|
|
|
So... Try the reliable option above and if it fails, use the less
|
|
|
|
|
reliable means.
|
|
|
|
|
|
|
|
|
|
The screams for a giveio solution that bypasses the kernel.
|
|
|
|
|
*/
|
|
|
|
|
if( index->event_flag & 0x2000 && result == 0 )
|
|
|
|
|
{
|
|
|
|
|
index->event_flag &= ~0x2000;
|
|
|
|
|
SetCommMask( index->hComm, index->event_flag );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
get_fd()
|
|
|
|
|
|
|
|
|
|
accept: filename
|
|
|
|
|
perform: find the file descriptor associated with the filename
|
|
|
|
|
return: fd
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments: This is not currently called by anything
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int get_fd( char *filename )
|
|
|
|
|
{
|
|
|
|
|
struct termios_list *index = first_tl;
|
|
|
|
|
|
|
|
|
|
ENTER( "get_fd" );
|
|
|
|
|
if( !index )
|
|
|
|
|
{
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while( strcmp( index->filename, filename ) )
|
|
|
|
|
{
|
|
|
|
|
index = index->next;
|
|
|
|
|
if( !index->next )
|
|
|
|
|
return( -1 );
|
|
|
|
|
}
|
|
|
|
|
LEAVE( "get_fd" );
|
|
|
|
|
return( index->fd );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
get_filename()
|
|
|
|
|
|
|
|
|
|
accept: file descriptor
|
|
|
|
|
perform: find the filename associated with the file descriptor
|
|
|
|
|
return: the filename associated with the fd
|
|
|
|
|
exceptions: None
|
|
|
|
|
win32api: None
|
|
|
|
|
comments: This is not currently called by anything
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
char *get_filename( int fd )
|
|
|
|
|
{
|
|
|
|
|
struct termios_list *index = first_tl;
|
|
|
|
|
|
|
|
|
|
ENTER( "get_filename" );
|
|
|
|
|
if( !index )
|
|
|
|
|
return( "bad" );
|
|
|
|
|
while( index->fd != fd )
|
|
|
|
|
{
|
|
|
|
|
if( index->next == NULL )
|
|
|
|
|
return( "bad" );
|
|
|
|
|
index = index->next;
|
|
|
|
|
}
|
|
|
|
|
LEAVE( "get_filename" );
|
|
|
|
|
return( index->filename );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
dump_termios_list()
|
|
|
|
|
|
|
|
|
|
accept: string to print out.
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments: used only for debugging eg serial_close()
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
void dump_termios_list( char *foo )
|
|
|
|
|
{
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
struct termios_list *index = first_tl;
|
|
|
|
|
printf( "============== %s start ===============\n", foo );
|
|
|
|
|
if ( index )
|
|
|
|
|
{
|
|
|
|
|
printf( "%i filename | %s\n", index->fd, index->filename );
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
if ( index->next )
|
|
|
|
|
{
|
|
|
|
|
printf( "%i filename | %s\n", index->fd, index->filename );
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
printf( "============== %s end ===============\n", foo );
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
set_errno()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments: FIXME
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
void set_errno( int error )
|
|
|
|
|
{
|
|
|
|
|
my_errno = error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
usleep()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: Sleep()
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
void usleep( unsigned long usec )
|
|
|
|
|
{
|
|
|
|
|
Sleep( usec/1000 );
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
CBR_toB()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int CBR_to_B( int Baud )
|
|
|
|
|
{
|
|
|
|
|
ENTER( "CBR_to_B" );
|
|
|
|
|
switch ( Baud )
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
case 0: return( B0 );
|
|
|
|
|
case 50: return( B50 );
|
|
|
|
|
case 75: return( B75 );
|
|
|
|
|
case CBR_110: return( B110 );
|
|
|
|
|
case 134: return( B134 );
|
|
|
|
|
case 150: return( B150 );
|
|
|
|
|
case 200: return( B200 );
|
|
|
|
|
case CBR_300: return( B300 );
|
|
|
|
|
case CBR_600: return( B600 );
|
|
|
|
|
case CBR_1200: return( B1200 );
|
|
|
|
|
case 1800: return( B1800 );
|
|
|
|
|
case CBR_2400: return( B2400 );
|
|
|
|
|
case CBR_4800: return( B4800 );
|
|
|
|
|
case CBR_9600: return( B9600 );
|
2008-11-05 23:00:20 +00:00
|
|
|
|
case CBR_14400: return( B14400 );
|
2003-08-15 01:15:45 +00:00
|
|
|
|
case CBR_19200: return( B19200 );
|
|
|
|
|
case CBR_28800: return( B28800 );
|
|
|
|
|
case CBR_38400: return( B38400 );
|
|
|
|
|
case CBR_57600: return( B57600 );
|
|
|
|
|
case CBR_115200: return( B115200 );
|
|
|
|
|
case CBR_128000: return( B128000 );
|
|
|
|
|
case CBR_230400: return( B230400 );
|
2008-11-05 23:00:20 +00:00
|
|
|
|
case CBR_256000: return( B256000 );
|
2003-08-15 01:15:45 +00:00
|
|
|
|
case CBR_460800: return( B460800 );
|
|
|
|
|
case CBR_500000: return( B500000 );
|
|
|
|
|
case CBR_576000: return( B576000 );
|
|
|
|
|
case CBR_921600: return( B921600 );
|
|
|
|
|
case CBR_1000000: return( B1000000 );
|
|
|
|
|
case CBR_1152000: return( B1152000 );
|
|
|
|
|
case CBR_1500000: return( B1500000 );
|
|
|
|
|
case CBR_2000000: return( B2000000 );
|
|
|
|
|
case CBR_2500000: return( B2500000 );
|
|
|
|
|
case CBR_3000000: return( B3000000 );
|
|
|
|
|
case CBR_3500000: return( B3500000 );
|
|
|
|
|
case CBR_4000000: return( B4000000 );
|
|
|
|
|
default:
|
|
|
|
|
set_errno(EINVAL );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
B_to_CBR()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api:
|
|
|
|
|
comments: None
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int B_to_CBR( int Baud )
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
ENTER( "B_to_CBR" );
|
|
|
|
|
switch ( Baud )
|
|
|
|
|
{
|
|
|
|
|
case 0: ret = 0; break;
|
|
|
|
|
case B50: ret = 50; break;
|
|
|
|
|
case B75: ret = 75; break;
|
|
|
|
|
case B110: ret = CBR_110; break;
|
|
|
|
|
case B134: ret = 134; break;
|
|
|
|
|
case B150: ret = 150; break;
|
|
|
|
|
case B200: ret = 200; break;
|
|
|
|
|
case B300: ret = CBR_300; break;
|
|
|
|
|
case B600: ret = CBR_600; break;
|
|
|
|
|
case B1200: ret = CBR_1200; break;
|
|
|
|
|
case B1800: ret = 1800; break;
|
|
|
|
|
case B2400: ret = CBR_2400; break;
|
|
|
|
|
case B4800: ret = CBR_4800; break;
|
|
|
|
|
case B9600: ret = CBR_9600; break;
|
2008-11-05 23:00:20 +00:00
|
|
|
|
case B14400: ret = CBR_14400; break;
|
2003-08-15 01:15:45 +00:00
|
|
|
|
case B19200: ret = CBR_19200; break;
|
|
|
|
|
case B38400: ret = CBR_38400; break;
|
|
|
|
|
case B57600: ret = CBR_57600; break;
|
|
|
|
|
case B115200: ret = CBR_115200; break;
|
|
|
|
|
case B128000: ret = CBR_128000; break;
|
|
|
|
|
case B256000: ret = CBR_256000; break;
|
|
|
|
|
case B230400: ret = CBR_230400; break;
|
|
|
|
|
case B460800: ret = CBR_460800; break;
|
|
|
|
|
case B500000: ret = CBR_500000; break;
|
|
|
|
|
case B576000: ret = CBR_576000; break;
|
|
|
|
|
case B921600: ret = CBR_921600; break;
|
|
|
|
|
case B1000000: ret = CBR_1000000; break;
|
|
|
|
|
case B1152000: ret = CBR_1152000; break;
|
|
|
|
|
case B1500000: ret = CBR_1500000; break;
|
|
|
|
|
case B2000000: ret = CBR_2000000; break;
|
|
|
|
|
case B2500000: ret = CBR_2500000; break;
|
|
|
|
|
case B3000000: ret = CBR_3000000; break;
|
|
|
|
|
case B3500000: ret = CBR_3500000; break;
|
|
|
|
|
case B4000000: ret = CBR_4000000; break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
fprintf( stderr, "B_to_CBR: invalid baudrate: %#o\n",
|
|
|
|
|
Baud );
|
|
|
|
|
set_errno( EINVAL );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
LEAVE( "B_to_CBR" );
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
bytesize_to_termios()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int bytesize_to_termios( int ByteSize )
|
|
|
|
|
{
|
|
|
|
|
ENTER( "bytesize_to_termios" );
|
|
|
|
|
switch ( ByteSize )
|
|
|
|
|
{
|
|
|
|
|
case 5: return( CS5 );
|
|
|
|
|
case 6: return( CS6 );
|
|
|
|
|
case 7: return( CS7 );
|
|
|
|
|
case 8:
|
|
|
|
|
default: return( CS8 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
termios_to_bytesize()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int termios_to_bytesize( int cflag )
|
|
|
|
|
{
|
|
|
|
|
ENTER( "termios_to_bytesize" );
|
|
|
|
|
switch ( cflag & CSIZE )
|
|
|
|
|
{
|
|
|
|
|
case CS5: return( 5 );
|
|
|
|
|
case CS6: return( 6 );
|
|
|
|
|
case CS7: return( 7 );
|
|
|
|
|
case CS8:
|
|
|
|
|
default: return( 8 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-08-01 23:13:17 +00:00
|
|
|
|
#if 0
|
2003-08-15 01:15:45 +00:00
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
get_dos_port()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
const char *get_dos_port( char const *name )
|
|
|
|
|
{
|
|
|
|
|
ENTER( "get_dos_port" );
|
|
|
|
|
if ( !strcmp( name, "/dev/cua0" ) ) return( "COM1" );
|
|
|
|
|
if ( !strcmp( name, "/dev/cua1" ) ) return( "COM2" );
|
|
|
|
|
if ( !strcmp( name, "/dev/cua2" ) ) return( "COM3" );
|
|
|
|
|
if ( !strcmp( name, "/dev/cua3" ) ) return( "COM4" );
|
|
|
|
|
LEAVE( "get_dos_port" );
|
|
|
|
|
return( ( const char * ) name );
|
|
|
|
|
}
|
2004-08-01 23:13:17 +00:00
|
|
|
|
#endif
|
2003-08-15 01:15:45 +00:00
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
ClearErrors()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform: keep track of errors for the eventLoop() (SerialImp.c)
|
|
|
|
|
return: the return value of ClearCommError()
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: ClearCommError()
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int ClearErrors( struct termios_list *index, COMSTAT *Stat )
|
|
|
|
|
{
|
|
|
|
|
unsigned long ErrCode;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
ret = ClearCommError( index->hComm, &ErrCode, Stat );
|
|
|
|
|
if ( ret == 0 )
|
|
|
|
|
{
|
|
|
|
|
YACK();
|
|
|
|
|
return( ret );
|
|
|
|
|
}
|
|
|
|
|
#ifdef DEBUG_ERRORS
|
|
|
|
|
if ( ErrCode )
|
|
|
|
|
{
|
|
|
|
|
printf("%i frame %i %i overrun %i %i parity %u %i brk %i %i\n",
|
|
|
|
|
(int) ErrCode,
|
|
|
|
|
(int) ErrCode & CE_FRAME,
|
|
|
|
|
index->sis->frame,
|
|
|
|
|
(int) (ErrCode & CE_OVERRUN) | ( ErrCode & CE_RXOVER ),
|
|
|
|
|
index->sis->overrun,
|
|
|
|
|
(int) ErrCode & CE_RXPARITY,
|
|
|
|
|
index->sis->parity,
|
|
|
|
|
(int) ErrCode & CE_BREAK,
|
|
|
|
|
index->sis->brk
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
#endif /* DEBUG_ERRORS */
|
|
|
|
|
if( ErrCode & CE_FRAME )
|
|
|
|
|
{
|
|
|
|
|
index->sis->frame++;
|
|
|
|
|
ErrCode &= ~CE_FRAME;
|
|
|
|
|
}
|
|
|
|
|
#ifdef LIFE_IS_GOOD
|
|
|
|
|
FIXME OVERRUN is spewing
|
|
|
|
|
if( ErrCode & CE_OVERRUN )
|
|
|
|
|
{
|
|
|
|
|
index->sis->overrun++;
|
|
|
|
|
ErrCode &= ~CE_OVERRUN;
|
|
|
|
|
}
|
|
|
|
|
/* should this be here? */
|
|
|
|
|
else if( ErrCode & CE_RXOVER )
|
|
|
|
|
{
|
|
|
|
|
index->sis->overrun++;
|
|
|
|
|
ErrCode &= ~CE_OVERRUN;
|
|
|
|
|
}
|
|
|
|
|
#endif /* LIFE_IS_GOOD */
|
|
|
|
|
if( ErrCode & CE_RXPARITY )
|
|
|
|
|
{
|
|
|
|
|
index->sis->parity++;
|
|
|
|
|
ErrCode &= ~CE_RXPARITY;
|
|
|
|
|
}
|
|
|
|
|
if( ErrCode & CE_BREAK )
|
|
|
|
|
{
|
|
|
|
|
index->sis->brk++;
|
|
|
|
|
ErrCode &= ~CE_BREAK;
|
|
|
|
|
}
|
|
|
|
|
return( ret );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
FillDCB()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: GetCommState(), SetCommState(), SetCommTimeouts()
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
BOOL FillDCB( DCB *dcb, unsigned long *hCommPort, COMMTIMEOUTS Timeout )
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
ENTER( "FillDCB" );
|
|
|
|
|
dcb->DCBlength = sizeof( dcb );
|
|
|
|
|
if ( !GetCommState( hCommPort, dcb ) )
|
|
|
|
|
{
|
|
|
|
|
report( "GetCommState\n" );
|
|
|
|
|
return( -1 );
|
|
|
|
|
}
|
|
|
|
|
dcb->BaudRate = CBR_9600 ;
|
|
|
|
|
dcb->ByteSize = 8;
|
|
|
|
|
dcb->Parity = NOPARITY;
|
|
|
|
|
dcb->StopBits = ONESTOPBIT;
|
|
|
|
|
dcb->fDtrControl = DTR_CONTROL_ENABLE;
|
|
|
|
|
dcb->fRtsControl = RTS_CONTROL_ENABLE;
|
|
|
|
|
dcb->fOutxCtsFlow = FALSE;
|
|
|
|
|
dcb->fOutxDsrFlow = FALSE;
|
|
|
|
|
dcb->fDsrSensitivity = FALSE;
|
|
|
|
|
dcb->fOutX = FALSE;
|
|
|
|
|
dcb->fInX = FALSE;
|
|
|
|
|
dcb->fTXContinueOnXoff = FALSE;
|
|
|
|
|
dcb->XonChar = 0x11;
|
|
|
|
|
dcb->XoffChar = 0x13;
|
|
|
|
|
dcb->XonLim = 0;
|
|
|
|
|
dcb->XoffLim = 0;
|
|
|
|
|
dcb->fParity = TRUE;
|
|
|
|
|
if ( EV_BREAK|EV_CTS|EV_DSR|EV_ERR|EV_RING|( EV_RLSD & EV_RXFLAG ) )
|
|
|
|
|
dcb->EvtChar = '\n';
|
|
|
|
|
else dcb->EvtChar = '\0';
|
|
|
|
|
if ( !SetCommState( hCommPort, dcb ) )
|
|
|
|
|
{
|
|
|
|
|
report( "SetCommState\n" );
|
|
|
|
|
YACK();
|
|
|
|
|
return( -1 );
|
|
|
|
|
}
|
|
|
|
|
if ( !SetCommTimeouts( hCommPort, &Timeout ) )
|
|
|
|
|
{
|
|
|
|
|
YACK();
|
|
|
|
|
report( "SetCommTimeouts\n" );
|
|
|
|
|
return( -1 );
|
|
|
|
|
}
|
|
|
|
|
LEAVE( "FillDCB" );
|
|
|
|
|
return ( TRUE ) ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
serial_close()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: SetCommMask(), CloseHandle()
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int win32_serial_close( int fd )
|
|
|
|
|
{
|
|
|
|
|
struct termios_list *index;
|
|
|
|
|
/* char message[80]; */
|
|
|
|
|
|
2008-11-05 23:00:20 +00:00
|
|
|
|
ENTER( "serial_close" );
|
2003-08-15 01:15:45 +00:00
|
|
|
|
if( !first_tl || !first_tl->hComm )
|
|
|
|
|
{
|
|
|
|
|
report( "gotit!" );
|
|
|
|
|
return( 0 );
|
|
|
|
|
}
|
|
|
|
|
index = find_port( fd );
|
|
|
|
|
if ( !index )
|
|
|
|
|
{
|
2008-11-05 23:00:20 +00:00
|
|
|
|
LEAVE( "serial_close" );
|
2003-08-15 01:15:45 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* WaitForSingleObject( index->wol.hEvent, INFINITE ); */
|
|
|
|
|
/*
|
|
|
|
|
if ( index->hComm != INVALID_HANDLE_VALUE )
|
|
|
|
|
{
|
|
|
|
|
if ( !SetCommMask( index->hComm, EV_RXCHAR ) )
|
|
|
|
|
{
|
|
|
|
|
YACK();
|
|
|
|
|
report( "eventLoop hung\n" );
|
|
|
|
|
}
|
|
|
|
|
CloseHandle( index->hComm );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2008-11-05 23:00:20 +00:00
|
|
|
|
sprintf( message, "serial_ close(): Invalid Port Reference for %s\n",
|
2003-08-15 01:15:45 +00:00
|
|
|
|
index->filename );
|
|
|
|
|
report( message );
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
if ( index->next && index->prev )
|
|
|
|
|
{
|
|
|
|
|
index->next->prev = index->prev;
|
|
|
|
|
index->prev->next = index->next;
|
|
|
|
|
}
|
|
|
|
|
else if ( index->prev )
|
|
|
|
|
{
|
|
|
|
|
index->prev->next = NULL;
|
|
|
|
|
}
|
|
|
|
|
else if ( index->next )
|
|
|
|
|
{
|
|
|
|
|
index->next->prev = NULL;
|
|
|
|
|
first_tl = index->next;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
first_tl = NULL;
|
|
|
|
|
if ( index )
|
|
|
|
|
{
|
|
|
|
|
if ( index->rol.hEvent ) CloseHandle( index->rol.hEvent );
|
|
|
|
|
if ( index->wol.hEvent ) CloseHandle( index->wol.hEvent );
|
|
|
|
|
if ( index->sol.hEvent ) CloseHandle( index->sol.hEvent );
|
|
|
|
|
if ( index->hComm ) CloseHandle( index->hComm );
|
|
|
|
|
if ( index->ttyset ) free( index->ttyset );
|
|
|
|
|
if ( index->astruct ) free( index->astruct );
|
|
|
|
|
if ( index->sstruct ) free( index->sstruct );
|
|
|
|
|
if ( index->sis ) free( index->sis );
|
|
|
|
|
/* had problems with strdup
|
|
|
|
|
if ( index->filename ) free( index->filename );
|
|
|
|
|
*/
|
|
|
|
|
free( index );
|
|
|
|
|
}
|
2008-11-05 23:00:20 +00:00
|
|
|
|
LEAVE( "serial_close" );
|
2003-08-15 01:15:45 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
cfmakeraw()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
void cfmakeraw( struct termios *s_termios )
|
|
|
|
|
{
|
|
|
|
|
ENTER( "cfmakeraw" );
|
|
|
|
|
s_termios->c_iflag &= ~( IGNBRK|BRKINT|PARMRK|ISTRIP
|
|
|
|
|
|INLCR|IGNCR|ICRNL|IXON );
|
|
|
|
|
s_termios->c_oflag &= ~OPOST;
|
|
|
|
|
s_termios->c_lflag &= ~( ECHO|ECHONL|ICANON|ISIG|IEXTEN );
|
|
|
|
|
s_termios->c_cflag &= ~( CSIZE|PARENB );
|
|
|
|
|
s_termios->c_cflag |= CS8;
|
|
|
|
|
LEAVE( "cfmakeraw" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
init_termios()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api:
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
BOOL init_serial_struct( struct serial_struct *sstruct )
|
|
|
|
|
{
|
|
|
|
|
ENTER( "init_serial_struct" );
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
FIXME
|
|
|
|
|
|
|
|
|
|
This needs to use inb() to read the actual baud_base
|
|
|
|
|
and divisor from the UART registers. Question is how
|
|
|
|
|
far do we take this?
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
sstruct->custom_divisor = 0;
|
|
|
|
|
sstruct->baud_base = 115200;
|
|
|
|
|
|
|
|
|
|
/* not currently used check values before using */
|
|
|
|
|
|
|
|
|
|
/* unsigned short */
|
|
|
|
|
|
|
|
|
|
sstruct->close_delay = 0;
|
|
|
|
|
sstruct->closing_wait = 0;
|
|
|
|
|
sstruct->iomem_reg_shift = 0;
|
|
|
|
|
|
|
|
|
|
/* int */
|
|
|
|
|
|
|
|
|
|
sstruct->type = 0;
|
|
|
|
|
sstruct->line = 0;
|
|
|
|
|
sstruct->irq = 0;
|
|
|
|
|
sstruct->flags = 0;
|
|
|
|
|
sstruct->xmit_fifo_size = 0;
|
|
|
|
|
sstruct->hub6 = 0;
|
|
|
|
|
|
|
|
|
|
/* unsigned int */
|
|
|
|
|
|
|
|
|
|
sstruct->port = 0;
|
|
|
|
|
sstruct->port_high = 0;
|
|
|
|
|
|
|
|
|
|
/* char */
|
|
|
|
|
|
|
|
|
|
sstruct->io_type = 0;
|
|
|
|
|
|
|
|
|
|
/* unsigned char * */
|
|
|
|
|
|
|
|
|
|
sstruct->iomem_base = NULL;
|
|
|
|
|
|
|
|
|
|
LEAVE( "init_serial_struct" );
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
init_termios()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api:
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
BOOL init_termios(struct termios *ttyset )
|
|
|
|
|
{
|
|
|
|
|
ENTER( "init_termios" );
|
|
|
|
|
if ( !ttyset )
|
|
|
|
|
return FALSE;
|
|
|
|
|
memset( ttyset, 0, sizeof( struct termios ) );
|
|
|
|
|
cfsetospeed( ttyset, B9600 );
|
|
|
|
|
cfmakeraw( ttyset );
|
|
|
|
|
ttyset->c_cc[VINTR] = 0x03; /* 0: C-c */
|
|
|
|
|
ttyset->c_cc[VQUIT] = 0x1c; /* 1: C-\ */
|
|
|
|
|
ttyset->c_cc[VERASE] = 0x7f; /* 2: <del> */
|
|
|
|
|
ttyset->c_cc[VKILL] = 0x15; /* 3: C-u */
|
|
|
|
|
ttyset->c_cc[VEOF] = 0x04; /* 4: C-d */
|
|
|
|
|
ttyset->c_cc[VTIME] = 0; /* 5: read timeout */
|
|
|
|
|
ttyset->c_cc[VMIN] = 1; /* 6: read returns after this
|
|
|
|
|
many bytes */
|
|
|
|
|
ttyset->c_cc[VSUSP] = 0x1a; /* 10: C-z */
|
|
|
|
|
ttyset->c_cc[VEOL] = '\r'; /* 11: */
|
|
|
|
|
ttyset->c_cc[VREPRINT] = 0x12; /* 12: C-r */
|
|
|
|
|
/*
|
|
|
|
|
ttyset->c_cc[VDISCARD] = 0x; 13: IEXTEN only
|
|
|
|
|
*/
|
|
|
|
|
ttyset->c_cc[VWERASE] = 0x17; /* 14: C-w */
|
|
|
|
|
ttyset->c_cc[VLNEXT] = 0x16; /* 15: C-w */
|
|
|
|
|
ttyset->c_cc[VEOL2] = '\n'; /* 16: */
|
|
|
|
|
LEAVE( "init_termios" );
|
|
|
|
|
return TRUE;
|
|
|
|
|
/* default VTIME = 0, VMIN = 1: read blocks forever until one byte */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
port_opened()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int port_opened( const char *filename )
|
|
|
|
|
{
|
|
|
|
|
struct termios_list *index = first_tl;
|
|
|
|
|
|
|
|
|
|
ENTER( "port_opened" );
|
|
|
|
|
if ( ! index )
|
|
|
|
|
return 0;
|
|
|
|
|
if( !strcmp( index->filename, filename ) )
|
|
|
|
|
return index->fd;
|
|
|
|
|
while ( index->next )
|
|
|
|
|
{
|
|
|
|
|
index = index->next;
|
|
|
|
|
if( !strcmp( index->filename, filename ) )
|
|
|
|
|
return index->fd;
|
|
|
|
|
}
|
|
|
|
|
LEAVE( "port_opened" );
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
open_port()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: CreateFile(), SetupComm(), CreateEvent()
|
|
|
|
|
comments:
|
|
|
|
|
FILE_FLAG_OVERLAPPED allows one to break out the select()
|
|
|
|
|
so RXTXPort.close() does not hang.
|
|
|
|
|
|
|
|
|
|
The setDTR() and setDSR() are the functions that noticed
|
|
|
|
|
to be blocked in the java close. Basically ioctl(TIOCM[GS]ET)
|
|
|
|
|
are where it hangs.
|
|
|
|
|
|
|
|
|
|
FILE_FLAG_OVERLAPPED also means we need to create valid OVERLAPPED
|
|
|
|
|
structure in Serial_select.
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int open_port( struct termios_list *port )
|
|
|
|
|
{
|
|
|
|
|
ENTER( "open_port" );
|
|
|
|
|
port->hComm = CreateFile( port->filename,
|
|
|
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
OPEN_EXISTING,
|
|
|
|
|
FILE_FLAG_OVERLAPPED,
|
|
|
|
|
0
|
|
|
|
|
);
|
|
|
|
|
if ( port->hComm == INVALID_HANDLE_VALUE )
|
|
|
|
|
{
|
|
|
|
|
YACK();
|
|
|
|
|
set_errno( EINVAL );
|
|
|
|
|
/*
|
2008-11-05 23:00:20 +00:00
|
|
|
|
printf( "serial_open failed %s\n", port->filename );
|
2003-08-15 01:15:45 +00:00
|
|
|
|
*/
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if( !SetupComm( port->hComm, 2048, 1024 ) )
|
|
|
|
|
{
|
|
|
|
|
YACK();
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset( &port->rol, 0, sizeof( OVERLAPPED ) );
|
|
|
|
|
memset( &port->wol, 0, sizeof( OVERLAPPED ) );
|
|
|
|
|
memset( &port->sol, 0, sizeof( OVERLAPPED ) );
|
|
|
|
|
|
|
|
|
|
port->rol.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
|
|
|
|
|
|
|
|
|
|
if ( !port->rol.hEvent )
|
|
|
|
|
{
|
|
|
|
|
YACK();
|
|
|
|
|
report( "Could not create read overlapped\n" );
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
port->sol.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
|
|
|
|
|
|
|
|
|
|
if ( !port->sol.hEvent )
|
|
|
|
|
{
|
|
|
|
|
YACK();
|
|
|
|
|
report( "Could not create select overlapped\n" );
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
port->wol.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
|
|
|
|
|
|
|
|
|
|
if ( !port->wol.hEvent )
|
|
|
|
|
{
|
|
|
|
|
YACK();
|
|
|
|
|
report( "Could not create write overlapped\n" );
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
LEAVE( "open_port" );
|
|
|
|
|
return( 0 );
|
|
|
|
|
fail:
|
|
|
|
|
return( -1 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
termios_list()
|
|
|
|
|
|
|
|
|
|
accept: fd which is a fake # for the port assigned when the port
|
|
|
|
|
is opened
|
|
|
|
|
perform: walk through a double linked list to see if the given
|
|
|
|
|
fd is in any of the termios_list members.
|
|
|
|
|
return: the termios_list if it is found.
|
|
|
|
|
NULL if no matches are found.
|
|
|
|
|
exceptions: None
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
struct termios_list *find_port( int fd )
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
char message[80];
|
|
|
|
|
struct termios_list *index = first_tl;
|
|
|
|
|
|
|
|
|
|
ENTER( "find_port" );
|
|
|
|
|
if ( fd <= 0 || !first_tl ) goto fail;
|
|
|
|
|
|
|
|
|
|
while( index->fd )
|
|
|
|
|
{
|
|
|
|
|
if ( index->fd == fd )
|
|
|
|
|
{
|
|
|
|
|
LEAVE( "find_port" );
|
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
if ( !index->next )
|
|
|
|
|
break;
|
|
|
|
|
index = index->next;
|
|
|
|
|
}
|
|
|
|
|
fail:
|
|
|
|
|
sprintf( message, "No info known about the port. %i\n", fd );
|
|
|
|
|
report( message );
|
|
|
|
|
set_errno( EBADF );
|
|
|
|
|
LEAVE( "find_port" );
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
get_free_fd()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int get_free_fd()
|
|
|
|
|
{
|
|
|
|
|
int next, last;
|
|
|
|
|
struct termios_list *index = first_tl;
|
|
|
|
|
|
|
|
|
|
ENTER( "get_free_fd" );
|
|
|
|
|
if ( !index )
|
|
|
|
|
{
|
|
|
|
|
return( 1 );
|
|
|
|
|
}
|
|
|
|
|
if ( !index->fd )
|
|
|
|
|
{
|
|
|
|
|
report( "!index->fd\n" );
|
|
|
|
|
return( 1 );
|
|
|
|
|
}
|
|
|
|
|
if ( index->fd > 1)
|
|
|
|
|
{
|
|
|
|
|
first_tl = index;
|
|
|
|
|
return ( 1 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
last = index->fd;
|
|
|
|
|
|
|
|
|
|
while( index->next )
|
|
|
|
|
{
|
|
|
|
|
next = index->next->fd;
|
|
|
|
|
if ( next != last + 1 )
|
|
|
|
|
{
|
|
|
|
|
return( last + 1 );
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
index = index->next;
|
|
|
|
|
last = next;
|
|
|
|
|
}
|
|
|
|
|
LEAVE( "get_free_fd" );
|
|
|
|
|
return( index->fd + 1 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
add_port()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
struct termios_list *add_port( const char *filename )
|
|
|
|
|
{
|
|
|
|
|
struct termios_list *index = first_tl;
|
|
|
|
|
struct termios_list *port;
|
|
|
|
|
|
|
|
|
|
ENTER( "add_port" );
|
|
|
|
|
|
|
|
|
|
port = malloc( sizeof( struct termios_list ) );
|
|
|
|
|
if( !port )
|
|
|
|
|
goto fail;
|
|
|
|
|
memset( port, 0, sizeof( struct termios_list ) );
|
|
|
|
|
|
|
|
|
|
port->ttyset = malloc( sizeof( struct termios ) );
|
|
|
|
|
if( ! port->ttyset )
|
|
|
|
|
goto fail;
|
|
|
|
|
memset( port->ttyset, 0, sizeof( struct termios ) );
|
|
|
|
|
|
|
|
|
|
port->sstruct = malloc( sizeof( struct serial_struct ) );
|
|
|
|
|
if( ! port->sstruct )
|
|
|
|
|
goto fail;
|
|
|
|
|
memset( port->sstruct, 0, sizeof( struct serial_struct ) );
|
|
|
|
|
port->sis = malloc( sizeof( struct serial_icounter_struct ) );
|
|
|
|
|
if( ! port->sis )
|
|
|
|
|
goto fail;
|
|
|
|
|
memset( port->sis, 0, sizeof( struct serial_icounter_struct ) );
|
|
|
|
|
|
|
|
|
|
/* FIXME the async_struct is being defined by mingw32 headers?
|
|
|
|
|
port->astruct = malloc( sizeof( struct async_struct ) );
|
|
|
|
|
if( ! port->astruct )
|
|
|
|
|
goto fail;
|
|
|
|
|
memset( port->astruct, 0, sizeof( struct async_struct ) );
|
|
|
|
|
*/
|
|
|
|
|
port->MSR = 0;
|
|
|
|
|
|
|
|
|
|
strcpy(port->filename, filename );
|
|
|
|
|
/* didnt free well? strdup( filename ); */
|
|
|
|
|
if( ! port->filename )
|
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
port->fd = get_free_fd();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( !first_tl )
|
|
|
|
|
{
|
|
|
|
|
port->prev = NULL;
|
|
|
|
|
first_tl = port;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
while ( index->next )
|
|
|
|
|
index = index->next;
|
|
|
|
|
if ( port == first_tl )
|
|
|
|
|
{
|
|
|
|
|
port->prev = NULL;
|
|
|
|
|
port->next = first_tl;
|
|
|
|
|
first_tl->prev = port;
|
|
|
|
|
first_tl = port;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
port->prev = index;
|
|
|
|
|
index->next = port;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
port->next = NULL;
|
|
|
|
|
LEAVE( "add_port" );
|
|
|
|
|
return port;
|
|
|
|
|
|
|
|
|
|
fail:
|
|
|
|
|
report( "add_port: Out Of Memory\n");
|
|
|
|
|
if ( port->ttyset ) free( port->ttyset );
|
|
|
|
|
if ( port->astruct ) free( port->astruct );
|
|
|
|
|
if ( port->sstruct ) free( port->sstruct );
|
|
|
|
|
if ( port->sis ) free( port->sis );
|
|
|
|
|
/* had problems with strdup
|
|
|
|
|
if ( port->filename ) free( port->filename );
|
|
|
|
|
*/
|
|
|
|
|
if ( port ) free( port );
|
|
|
|
|
return port;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
check_port_capabilities()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: GetCommProperties(), GetCommState()
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int check_port_capabilities( struct termios_list *index )
|
|
|
|
|
{
|
|
|
|
|
COMMPROP cp;
|
|
|
|
|
DCB dcb;
|
|
|
|
|
char message[80];
|
|
|
|
|
|
|
|
|
|
ENTER( "check_port_capabilities" );
|
|
|
|
|
/* check for capabilities */
|
|
|
|
|
GetCommProperties( index->hComm, &cp );
|
|
|
|
|
if ( !( cp.dwProvCapabilities & PCF_DTRDSR ) )
|
|
|
|
|
{
|
|
|
|
|
sprintf( message,
|
|
|
|
|
"%s: no DTR & DSR support\n", index->filename );
|
|
|
|
|
report( message );
|
|
|
|
|
}
|
|
|
|
|
if ( !( cp.dwProvCapabilities & PCF_RLSD ) )
|
|
|
|
|
{
|
|
|
|
|
sprintf( message, "%s: no carrier detect (RLSD) support\n",
|
|
|
|
|
index->filename );
|
|
|
|
|
report( message );
|
|
|
|
|
}
|
|
|
|
|
if ( !( cp.dwProvCapabilities & PCF_RTSCTS ) )
|
|
|
|
|
{
|
|
|
|
|
sprintf( message,
|
|
|
|
|
"%s: no RTS & CTS support\n", index->filename );
|
|
|
|
|
report( message );
|
|
|
|
|
}
|
|
|
|
|
if ( !( cp.dwProvCapabilities & PCF_TOTALTIMEOUTS ) )
|
|
|
|
|
{
|
|
|
|
|
sprintf( message, "%s: no timeout support\n", index->filename );
|
|
|
|
|
report( message );
|
|
|
|
|
}
|
|
|
|
|
if ( !GetCommState( index->hComm, &dcb ) )
|
|
|
|
|
{
|
|
|
|
|
YACK();
|
|
|
|
|
report( "GetCommState\n" );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
LEAVE( "check_port_capabilities" );
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
serial_open()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int win32_serial_open( const char *filename, int flags, ... )
|
|
|
|
|
{
|
|
|
|
|
struct termios_list *index;
|
|
|
|
|
char message[80];
|
|
|
|
|
|
|
|
|
|
ENTER( "serial_open" );
|
|
|
|
|
if ( port_opened( filename ) )
|
|
|
|
|
{
|
|
|
|
|
report( "Port is already opened\n" );
|
|
|
|
|
return( -1 );
|
|
|
|
|
}
|
|
|
|
|
index = add_port( filename );
|
|
|
|
|
if( !index )
|
|
|
|
|
{
|
2008-11-05 23:00:20 +00:00
|
|
|
|
report( "serial_open !index\n" );
|
2003-08-15 01:15:45 +00:00
|
|
|
|
return( -1 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
index->interrupt = 0;
|
|
|
|
|
index->tx_happened = 0;
|
|
|
|
|
if ( open_port( index ) )
|
|
|
|
|
{
|
2008-11-05 23:00:20 +00:00
|
|
|
|
sprintf( message, "serial_open(): Invalid Port Reference for %s\n",
|
2003-08-15 01:15:45 +00:00
|
|
|
|
filename );
|
|
|
|
|
report( message );
|
2008-11-05 23:00:20 +00:00
|
|
|
|
win32_serial_close( index->fd );
|
2003-08-15 01:15:45 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( check_port_capabilities( index ) )
|
|
|
|
|
{
|
|
|
|
|
report( "check_port_capabilites!" );
|
2008-11-05 23:00:20 +00:00
|
|
|
|
win32_serial_close( index->fd );
|
2003-08-15 01:15:45 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
init_termios( index->ttyset );
|
|
|
|
|
init_serial_struct( index->sstruct );
|
|
|
|
|
|
|
|
|
|
/* set default condition */
|
|
|
|
|
tcsetattr( index->fd, 0, index->ttyset );
|
|
|
|
|
|
|
|
|
|
/* if opened with non-blocking, then operating non-blocking */
|
|
|
|
|
if ( flags & O_NONBLOCK )
|
|
|
|
|
index->open_flags = O_NONBLOCK;
|
|
|
|
|
else
|
|
|
|
|
index->open_flags = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( !first_tl->hComm )
|
|
|
|
|
{
|
|
|
|
|
sprintf( message, "open(): Invalid Port Reference for %s\n",
|
|
|
|
|
index->filename );
|
|
|
|
|
report( message );
|
|
|
|
|
}
|
|
|
|
|
if ( first_tl->hComm == INVALID_HANDLE_VALUE )
|
|
|
|
|
report( "serial_open: test\n" );
|
|
|
|
|
LEAVE( "serial_open" );
|
|
|
|
|
return( index->fd );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
serial_write()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: WriteFile(), GetLastError(),
|
|
|
|
|
WaitForSingleObject(), GetOverlappedResult(),
|
|
|
|
|
FlushFileBuffers(), Sleep()
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int win32_serial_write( int fd, const char *Str, int length )
|
|
|
|
|
{
|
|
|
|
|
unsigned long nBytes;
|
|
|
|
|
struct termios_list *index;
|
2008-11-05 23:00:20 +00:00
|
|
|
|
/* COMSTAT Stat; */
|
2003-08-15 01:15:45 +00:00
|
|
|
|
int old_flag;
|
|
|
|
|
|
|
|
|
|
ENTER( "serial_write" );
|
|
|
|
|
|
|
|
|
|
if ( fd <= 0 )
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
index = find_port( fd );
|
|
|
|
|
if ( !index )
|
|
|
|
|
{
|
|
|
|
|
LEAVE( "serial_write");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
old_flag = index->event_flag;
|
|
|
|
|
/*
|
|
|
|
|
index->event_flag &= ~EV_TXEMPTY;
|
|
|
|
|
SetCommMask( index->hComm, index->event_flag );
|
|
|
|
|
index->tx_happened = 1;
|
|
|
|
|
*/
|
|
|
|
|
index->wol.Offset = index->wol.OffsetHigh = 0;
|
|
|
|
|
ResetEvent( index->wol.hEvent );
|
|
|
|
|
if ( !WriteFile( index->hComm, Str, length, &nBytes, &index->wol ) )
|
|
|
|
|
{
|
|
|
|
|
WaitForSingleObject( index->wol.hEvent,100 );
|
|
|
|
|
if ( GetLastError() != ERROR_IO_PENDING )
|
|
|
|
|
{
|
2008-11-05 23:00:20 +00:00
|
|
|
|
/* ClearErrors( index, &Stat ); */
|
2003-08-15 01:15:45 +00:00
|
|
|
|
report( "serial_write error\n" );
|
2008-11-05 23:00:20 +00:00
|
|
|
|
/* report("Condition 1 Detected in write()\n"); */
|
2003-08-15 01:15:45 +00:00
|
|
|
|
YACK();
|
|
|
|
|
errno = EIO;
|
|
|
|
|
nBytes=-1;
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
/* This is breaking on Win2K, WinXP for some reason */
|
|
|
|
|
else while( !GetOverlappedResult( index->hComm, &index->wol,
|
|
|
|
|
&nBytes, TRUE ) )
|
|
|
|
|
{
|
|
|
|
|
if ( GetLastError() != ERROR_IO_INCOMPLETE )
|
|
|
|
|
{
|
2008-11-05 23:00:20 +00:00
|
|
|
|
/* report("Condition 2 Detected in write()\n"); */
|
2003-08-15 01:15:45 +00:00
|
|
|
|
YACK();
|
|
|
|
|
errno = EIO;
|
|
|
|
|
nBytes = -1;
|
|
|
|
|
goto end;
|
2008-11-05 23:00:20 +00:00
|
|
|
|
/* ClearErrors( index, &Stat ); */
|
2003-08-15 01:15:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2008-11-05 23:00:20 +00:00
|
|
|
|
/* Write finished synchronously. That is ok!
|
|
|
|
|
* I have seen this with USB to Serial
|
|
|
|
|
* devices like TI's.
|
|
|
|
|
*/
|
2003-08-15 01:15:45 +00:00
|
|
|
|
}
|
|
|
|
|
end:
|
|
|
|
|
/* FlushFileBuffers( index->hComm ); */
|
|
|
|
|
index->event_flag |= EV_TXEMPTY;
|
2008-11-05 23:00:20 +00:00
|
|
|
|
/* ClearErrors( index, &Stat ); */
|
2003-08-15 01:15:45 +00:00
|
|
|
|
SetCommMask( index->hComm, index->event_flag );
|
2008-11-05 23:00:20 +00:00
|
|
|
|
/* ClearErrors( index, &Stat ); */
|
2003-08-15 01:15:45 +00:00
|
|
|
|
index->event_flag = old_flag;
|
|
|
|
|
index->tx_happened = 1;
|
|
|
|
|
LEAVE( "serial_write" );
|
|
|
|
|
return nBytes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
serial_read()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: ReadFile(), GetLastError(), WaitForSingleObject()
|
|
|
|
|
GetOverLappedResult()
|
|
|
|
|
comments: If setting errno make sure not to use EWOULDBLOCK
|
|
|
|
|
In that case use EAGAIN. See SerialImp.c:testRead()
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int win32_serial_read( int fd, void *vb, int size )
|
|
|
|
|
{
|
|
|
|
|
long start, now;
|
|
|
|
|
unsigned long nBytes = 0, total = 0, error;
|
|
|
|
|
/* unsigned long waiting = 0; */
|
|
|
|
|
int err, vmin;
|
|
|
|
|
struct termios_list *index;
|
|
|
|
|
char message[80];
|
|
|
|
|
COMSTAT stat;
|
|
|
|
|
clock_t c;
|
|
|
|
|
unsigned char *dest = vb;
|
|
|
|
|
|
|
|
|
|
start = GetTickCount();
|
|
|
|
|
ENTER( "serial_read" );
|
|
|
|
|
|
|
|
|
|
if ( fd <= 0 )
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
index = find_port( fd );
|
|
|
|
|
if ( !index )
|
|
|
|
|
{
|
|
|
|
|
LEAVE( "serial_read" );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* FIXME: CREAD: without this, data cannot be read
|
|
|
|
|
FIXME: PARMRK: mark framing & parity errors
|
|
|
|
|
FIXME: IGNCR: ignore \r
|
|
|
|
|
FIXME: ICRNL: convert \r to \n
|
|
|
|
|
FIXME: INLCR: convert \n to \r
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if ( index->open_flags & O_NONBLOCK )
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
vmin = 0;
|
|
|
|
|
/* pull mucho-cpu here? */
|
|
|
|
|
do {
|
|
|
|
|
#ifdef DEBUG_VERBOSE
|
|
|
|
|
report( "vmin=0\n" );
|
|
|
|
|
#endif /* DEBUG_VERBOSE */
|
|
|
|
|
ret = ClearErrors( index, &stat);
|
|
|
|
|
/*
|
|
|
|
|
usleep(1000);
|
|
|
|
|
usleep(50);
|
|
|
|
|
*/
|
|
|
|
|
/* we should use -1 instead of 0 for disabled timeout */
|
|
|
|
|
now = GetTickCount();
|
|
|
|
|
if ( index->ttyset->c_cc[VTIME] &&
|
|
|
|
|
now-start >= (index->ttyset->c_cc[VTIME]*100)) {
|
|
|
|
|
/*
|
|
|
|
|
sprintf( message, "now = %i start = %i time = %i total =%i\n", now, start, index->ttyset->c_cc[VTIME]*100, total);
|
|
|
|
|
report( message );
|
|
|
|
|
*/
|
|
|
|
|
return total; /* read timeout */
|
|
|
|
|
}
|
|
|
|
|
} while( stat.cbInQue < size && size > 1 );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* VTIME is in units of 0.1 seconds */
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_VERBOSE
|
|
|
|
|
report( "vmin!=0\n" );
|
|
|
|
|
#endif /* DEBUG_VERBOSE */
|
|
|
|
|
vmin = index->ttyset->c_cc[VMIN];
|
|
|
|
|
|
|
|
|
|
c = clock() + index->ttyset->c_cc[VTIME] * CLOCKS_PER_SEC / 10;
|
|
|
|
|
do {
|
|
|
|
|
error = ClearErrors( index, &stat);
|
|
|
|
|
usleep(1000);
|
|
|
|
|
} while ( c > clock() );
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
total = 0;
|
|
|
|
|
while ( size > 0 )
|
|
|
|
|
{
|
|
|
|
|
nBytes = 0;
|
2008-11-05 23:00:20 +00:00
|
|
|
|
/* ret = ClearErrors( index, &stat); */
|
2003-08-15 01:15:45 +00:00
|
|
|
|
|
|
|
|
|
index->rol.Offset = index->rol.OffsetHigh = 0;
|
|
|
|
|
ResetEvent( index->rol.hEvent );
|
|
|
|
|
|
|
|
|
|
err = ReadFile( index->hComm, dest + total, size, &nBytes, &index->rol );
|
|
|
|
|
#ifdef DEBUG_VERBOSE
|
|
|
|
|
/* warning Roy Rogers! */
|
|
|
|
|
sprintf(message, " ========== ReadFile = %i %s\n",
|
|
|
|
|
( int ) nBytes, (char *) dest + total );
|
|
|
|
|
report( message );
|
|
|
|
|
#endif /* DEBUG_VERBOSE */
|
|
|
|
|
size -= nBytes;
|
|
|
|
|
total += nBytes;
|
|
|
|
|
|
|
|
|
|
if ( !err )
|
|
|
|
|
{
|
|
|
|
|
switch ( GetLastError() )
|
|
|
|
|
{
|
|
|
|
|
case ERROR_BROKEN_PIPE:
|
|
|
|
|
report( "ERROR_BROKEN_PIPE\n ");
|
|
|
|
|
nBytes = 0;
|
|
|
|
|
break;
|
|
|
|
|
case ERROR_MORE_DATA:
|
|
|
|
|
/*
|
|
|
|
|
usleep(1000);
|
|
|
|
|
*/
|
|
|
|
|
report( "ERROR_MORE_DATA\n" );
|
|
|
|
|
break;
|
|
|
|
|
case ERROR_IO_PENDING:
|
|
|
|
|
while( ! GetOverlappedResult(
|
|
|
|
|
index->hComm,
|
|
|
|
|
&index->rol,
|
|
|
|
|
&nBytes,
|
|
|
|
|
TRUE ) )
|
|
|
|
|
{
|
|
|
|
|
if( GetLastError() !=
|
|
|
|
|
ERROR_IO_INCOMPLETE )
|
|
|
|
|
{
|
|
|
|
|
ClearErrors(
|
|
|
|
|
index,
|
|
|
|
|
&stat);
|
|
|
|
|
return( total );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
size -= nBytes;
|
|
|
|
|
total += nBytes;
|
|
|
|
|
if (size > 0) {
|
|
|
|
|
now = GetTickCount();
|
|
|
|
|
sprintf(message, "size > 0: spent=%ld have=%d\n", now-start, index->ttyset->c_cc[VTIME]*100);
|
|
|
|
|
report( message );
|
|
|
|
|
/* we should use -1 for disabled
|
|
|
|
|
timouts */
|
|
|
|
|
if ( index->ttyset->c_cc[VTIME] && now-start >= (index->ttyset->c_cc[VTIME]*100)) {
|
|
|
|
|
report( "TO " );
|
|
|
|
|
/* read timeout */
|
|
|
|
|
return total;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sprintf(message, "end nBytes=%ld] ", nBytes);
|
|
|
|
|
report( message );
|
|
|
|
|
/*
|
|
|
|
|
usleep(1000);
|
|
|
|
|
*/
|
|
|
|
|
report( "ERROR_IO_PENDING\n" );
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/*
|
|
|
|
|
usleep(1000);
|
|
|
|
|
*/
|
|
|
|
|
YACK();
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
usleep(1000);
|
|
|
|
|
*/
|
|
|
|
|
ClearErrors( index, &stat);
|
|
|
|
|
return( total );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
LEAVE( "serial_read" );
|
|
|
|
|
return total;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef asdf
|
|
|
|
|
int win32_serial_read( int fd, void *vb, int size )
|
|
|
|
|
{
|
|
|
|
|
long start, now;
|
|
|
|
|
unsigned long nBytes = 0, total = 0, error;
|
|
|
|
|
/* unsigned long waiting = 0; */
|
|
|
|
|
int err, vmin;
|
|
|
|
|
struct termios_list *index;
|
|
|
|
|
char message[80];
|
|
|
|
|
COMSTAT Stat;
|
|
|
|
|
clock_t c;
|
|
|
|
|
unsigned char *dest = vb;
|
|
|
|
|
|
|
|
|
|
start = GetTickCount();
|
|
|
|
|
ENTER( "serial_read" );
|
|
|
|
|
|
|
|
|
|
if ( fd <= 0 )
|
|
|
|
|
{
|
|
|
|
|
printf("1\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
index = find_port( fd );
|
|
|
|
|
if ( !index )
|
|
|
|
|
{
|
|
|
|
|
LEAVE( "serial_read 7" );
|
|
|
|
|
errno = EIO;
|
|
|
|
|
printf("2\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* FIXME: CREAD: without this, data cannot be read
|
|
|
|
|
FIXME: PARMRK: mark framing & parity errors
|
|
|
|
|
FIXME: IGNCR: ignore \r
|
|
|
|
|
FIXME: ICRNL: convert \r to \n
|
|
|
|
|
FIXME: INLCR: convert \n to \r
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
ClearErrors( index, &Stat );
|
|
|
|
|
if ( index->open_flags & O_NONBLOCK )
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
vmin = 0;
|
|
|
|
|
/* pull mucho-cpu here? */
|
|
|
|
|
do {
|
|
|
|
|
#ifdef DEBUG_VERBOSE
|
|
|
|
|
report( "vmin=0\n" );
|
|
|
|
|
#endif /* DEBUG_VERBOSE */
|
|
|
|
|
ret = ClearErrors( index, &Stat);
|
|
|
|
|
/*
|
|
|
|
|
usleep(1000);
|
|
|
|
|
usleep(50);
|
|
|
|
|
*/
|
|
|
|
|
/* we should use -1 instead of 0 for disabled timeout */
|
|
|
|
|
now = GetTickCount();
|
|
|
|
|
if ( index->ttyset->c_cc[VTIME] &&
|
|
|
|
|
now-start >= (index->ttyset->c_cc[VTIME]*100)) {
|
|
|
|
|
/*
|
|
|
|
|
sprintf( message, "now = %i start = %i time = %i total =%i\n", now, start, index->ttyset->c_cc[VTIME]*100, total);
|
|
|
|
|
report( message );
|
|
|
|
|
*/
|
|
|
|
|
errno = EAGAIN;
|
|
|
|
|
printf("3\n");
|
|
|
|
|
return -1; /* read timeout */
|
|
|
|
|
}
|
|
|
|
|
} while( Stat.cbInQue < size && size > 1 );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* VTIME is in units of 0.1 seconds */
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_VERBOSE
|
|
|
|
|
report( "vmin!=0\n" );
|
|
|
|
|
#endif /* DEBUG_VERBOSE */
|
|
|
|
|
vmin = index->ttyset->c_cc[VMIN];
|
|
|
|
|
|
|
|
|
|
c = clock() + index->ttyset->c_cc[VTIME] * CLOCKS_PER_SEC / 10;
|
|
|
|
|
do {
|
|
|
|
|
error = ClearErrors( index, &Stat);
|
|
|
|
|
usleep(1000);
|
|
|
|
|
} while ( c > clock() );
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
total = 0;
|
|
|
|
|
while ( size > 0 )
|
|
|
|
|
{
|
|
|
|
|
nBytes = 0;
|
2008-11-05 23:00:20 +00:00
|
|
|
|
/* ret = ClearErrors( index, &Stat); */
|
2003-08-15 01:15:45 +00:00
|
|
|
|
|
|
|
|
|
index->rol.Offset = index->rol.OffsetHigh = 0;
|
|
|
|
|
ResetEvent( index->rol.hEvent );
|
|
|
|
|
|
|
|
|
|
err = ReadFile( index->hComm, dest + total, size, &nBytes, &index->rol );
|
|
|
|
|
#ifdef DEBUG_VERBOSE
|
|
|
|
|
/* warning Roy Rogers! */
|
|
|
|
|
sprintf(message, " ========== ReadFile = %i %s\n",
|
|
|
|
|
( int ) nBytes, (char *) dest + total );
|
|
|
|
|
report( message );
|
|
|
|
|
#endif /* DEBUG_VERBOSE */
|
|
|
|
|
size -= nBytes;
|
|
|
|
|
total += nBytes;
|
|
|
|
|
|
|
|
|
|
if ( !err )
|
|
|
|
|
{
|
|
|
|
|
switch ( GetLastError() )
|
|
|
|
|
{
|
|
|
|
|
case ERROR_BROKEN_PIPE:
|
|
|
|
|
report( "ERROR_BROKEN_PIPE\n ");
|
|
|
|
|
nBytes = 0;
|
|
|
|
|
break;
|
|
|
|
|
case ERROR_MORE_DATA:
|
|
|
|
|
/*
|
|
|
|
|
usleep(1000);
|
|
|
|
|
*/
|
|
|
|
|
report( "ERROR_MORE_DATA\n" );
|
|
|
|
|
break;
|
|
|
|
|
case ERROR_IO_PENDING:
|
|
|
|
|
while( ! GetOverlappedResult(
|
|
|
|
|
index->hComm,
|
|
|
|
|
&index->rol,
|
|
|
|
|
&nBytes,
|
|
|
|
|
TRUE ) )
|
|
|
|
|
{
|
|
|
|
|
if( GetLastError() !=
|
|
|
|
|
ERROR_IO_INCOMPLETE )
|
|
|
|
|
{
|
|
|
|
|
ClearErrors(
|
|
|
|
|
index,
|
|
|
|
|
&Stat);
|
|
|
|
|
printf("4\n");
|
|
|
|
|
return( total );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
size -= nBytes;
|
|
|
|
|
total += nBytes;
|
|
|
|
|
if (size > 0) {
|
|
|
|
|
now = GetTickCount();
|
|
|
|
|
sprintf(message, "size > 0: spent=%ld have=%d\n", now-start, index->ttyset->c_cc[VTIME]*100);
|
|
|
|
|
report( message );
|
|
|
|
|
/* we should use -1 for disabled
|
|
|
|
|
timouts */
|
|
|
|
|
if ( index->ttyset->c_cc[VTIME] && now-start >= (index->ttyset->c_cc[VTIME]*100)) {
|
|
|
|
|
report( "TO " );
|
|
|
|
|
/* read timeout */
|
|
|
|
|
printf("5\n");
|
|
|
|
|
return total;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sprintf(message, "end nBytes=%ld] ", nBytes);
|
|
|
|
|
report( message );
|
|
|
|
|
/*
|
|
|
|
|
usleep(1000);
|
|
|
|
|
*/
|
|
|
|
|
report( "ERROR_IO_PENDING\n" );
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/*
|
|
|
|
|
usleep(1000);
|
|
|
|
|
*/
|
|
|
|
|
YACK();
|
|
|
|
|
errno = EIO;
|
|
|
|
|
printf("6\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
usleep(1000);
|
|
|
|
|
*/
|
|
|
|
|
ClearErrors( index, &Stat);
|
|
|
|
|
printf("7\n");
|
|
|
|
|
return( total );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
LEAVE( "serial_read" );
|
|
|
|
|
ClearErrors( index, &Stat);
|
|
|
|
|
return total;
|
|
|
|
|
}
|
|
|
|
|
#endif /* asdf */
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
cfsetospeed()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int cfsetospeed( struct termios *s_termios, speed_t speed )
|
|
|
|
|
{
|
|
|
|
|
char message[80];
|
|
|
|
|
ENTER( "cfsetospeed" );
|
|
|
|
|
if ( speed & ~CBAUD )
|
|
|
|
|
{
|
|
|
|
|
sprintf( message, "cfsetospeed: not speed: %#o\n", speed );
|
|
|
|
|
report( message );
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
s_termios->c_ispeed = s_termios->c_ospeed = speed;
|
|
|
|
|
/* clear baudrate */
|
|
|
|
|
s_termios->c_cflag &= ~CBAUD;
|
|
|
|
|
if( speed )
|
|
|
|
|
{
|
|
|
|
|
s_termios->c_cflag |= speed;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* PC blows up with speed 0 handled in Java */
|
|
|
|
|
s_termios->c_cflag |= B9600;
|
|
|
|
|
}
|
|
|
|
|
LEAVE( "cfsetospeed" );
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
cfsetispeed()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int cfsetispeed( struct termios *s_termios, speed_t speed )
|
|
|
|
|
{
|
|
|
|
|
return cfsetospeed( s_termios, speed );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
cfsetspeed()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int cfsetspeed( struct termios *s_termios, speed_t speed )
|
|
|
|
|
{
|
|
|
|
|
return cfsetospeed( s_termios, speed );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
cfgetospeed()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
speed_t cfgetospeed( struct termios *s_termios )
|
|
|
|
|
{
|
|
|
|
|
ENTER( "cfgetospeed" );
|
|
|
|
|
return s_termios->c_ospeed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
cfgetispeed()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
speed_t cfgetispeed( struct termios *s_termios )
|
|
|
|
|
{
|
|
|
|
|
ENTER( "cfgetospeed" );
|
|
|
|
|
return s_termios->c_ispeed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
serial_struct_to_DCB()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
int serial_struct_to_DCB( struct serial_struct *sstruct, DCB *dcb )
|
|
|
|
|
{
|
|
|
|
|
/* 5 Baud rate fix
|
|
|
|
|
sstruct.baud_base
|
|
|
|
|
sstruct.custom_divisor = ( sstruct.baud_base/cspeed );
|
|
|
|
|
*/
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
termios_to_DCB()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
int termios_to_DCB( struct termios *s_termios, DCB *dcb )
|
|
|
|
|
{
|
|
|
|
|
ENTER( "termios_to_DCB" );
|
|
|
|
|
s_termios->c_ispeed = s_termios->c_ospeed = s_termios->c_cflag & CBAUD;
|
|
|
|
|
dcb->BaudRate = B_to_CBR( s_termios->c_ispeed );
|
|
|
|
|
dcb->ByteSize = termios_to_bytesize( s_termios->c_cflag );
|
|
|
|
|
|
|
|
|
|
if ( s_termios->c_cflag & PARENB )
|
|
|
|
|
{
|
|
|
|
|
if ( s_termios->c_cflag & PARODD
|
|
|
|
|
&& s_termios->c_cflag & CMSPAR )
|
|
|
|
|
{
|
|
|
|
|
dcb->Parity = MARKPARITY;
|
|
|
|
|
}
|
|
|
|
|
else if ( s_termios->c_cflag & PARODD )
|
|
|
|
|
{
|
|
|
|
|
dcb->Parity = ODDPARITY;
|
|
|
|
|
}
|
|
|
|
|
else if ( s_termios->c_cflag & CMSPAR )
|
|
|
|
|
{
|
|
|
|
|
dcb->Parity = SPACEPARITY;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dcb->Parity = EVENPARITY;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dcb->Parity = NOPARITY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( s_termios->c_cflag & CSTOPB ) dcb->StopBits = TWOSTOPBITS;
|
|
|
|
|
else dcb->StopBits = ONESTOPBIT;
|
|
|
|
|
|
|
|
|
|
if ( s_termios->c_cflag & HARDWARE_FLOW_CONTROL )
|
|
|
|
|
{
|
|
|
|
|
dcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
|
|
|
|
|
dcb->fOutxCtsFlow = TRUE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dcb->fRtsControl = RTS_CONTROL_DISABLE;
|
|
|
|
|
dcb->fOutxCtsFlow = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LEAVE( "termios_to_DCB" );
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
DCB_to_serial_struct()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
int DCB_to_serial_struct( DCB *dcb, struct serial_struct *sstruct )
|
|
|
|
|
{
|
|
|
|
|
return( 0 );
|
|
|
|
|
}
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
DCB_to_termios()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
void DCB_to_termios( DCB *dcb, struct termios *s_termios )
|
|
|
|
|
{
|
|
|
|
|
ENTER( "DCB_to_termios" );
|
|
|
|
|
s_termios->c_ispeed = CBR_to_B( dcb->BaudRate );
|
|
|
|
|
s_termios->c_ospeed = s_termios->c_ispeed;
|
|
|
|
|
s_termios->c_cflag |= s_termios->c_ispeed & CBAUD;
|
|
|
|
|
LEAVE( "DCB_to_termios" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
show_DCB()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
void show_DCB( myDCB )
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_HOSED
|
|
|
|
|
char message[80];
|
|
|
|
|
|
|
|
|
|
sprintf( message, "DCBlength: %ld\n", myDCB.DCBlength );
|
|
|
|
|
report( message );
|
|
|
|
|
sprintf( "BaudRate: %ld\n", myDCB.BaudRate );
|
|
|
|
|
report( message );
|
|
|
|
|
if ( myDCB.fBinary )
|
|
|
|
|
report( "fBinary\n" );
|
|
|
|
|
if ( myDCB.fParity )
|
|
|
|
|
{
|
|
|
|
|
report( "fParity: " );
|
|
|
|
|
if ( myDCB.fErrorChar )
|
|
|
|
|
{
|
|
|
|
|
sprintf( message, "fErrorChar: %#x\n", myDCB.ErrorChar );
|
|
|
|
|
report( message );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
report( "fErrorChar == false\n" );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( myDCB.fOutxCtsFlow )
|
|
|
|
|
report( "fOutxCtsFlow\n" );
|
|
|
|
|
if ( myDCB.fOutxDsrFlow )
|
|
|
|
|
report( "fOutxDsrFlow\n" );
|
|
|
|
|
if ( myDCB.fDtrControl & DTR_CONTROL_HANDSHAKE );
|
|
|
|
|
report( "DTR_CONTROL_HANDSHAKE\n" );
|
|
|
|
|
if ( myDCB.fDtrControl & DTR_CONTROL_ENABLE );
|
|
|
|
|
report( "DTR_CONTROL_ENABLE\n" );
|
|
|
|
|
if ( myDCB.fDtrControl & DTR_CONTROL_DISABLE );
|
|
|
|
|
report( "DTR_CONTROL_DISABLE\n" );
|
|
|
|
|
if ( myDCB.fDsrSensitivity )
|
|
|
|
|
report( "fDsrSensitivity\n" );
|
|
|
|
|
if ( myDCB.fTXContinueOnXoff )
|
|
|
|
|
report( "fTXContinueOnXoff\n" );
|
|
|
|
|
if ( myDCB.fOutX )
|
|
|
|
|
report( "fOutX\n" );
|
|
|
|
|
if ( myDCB.fInX )
|
|
|
|
|
report( "fInX\n" );
|
|
|
|
|
if ( myDCB.fNull )
|
|
|
|
|
report( "fNull\n" );
|
|
|
|
|
if ( myDCB.fRtsControl & RTS_CONTROL_TOGGLE )
|
|
|
|
|
report( "RTS_CONTROL_TOGGLE\n" );
|
|
|
|
|
if ( myDCB.fRtsControl == 0 )
|
|
|
|
|
report( "RTS_CONTROL_HANDSHAKE ( fRtsControl==0 )\n" );
|
|
|
|
|
if ( myDCB.fRtsControl & RTS_CONTROL_HANDSHAKE )
|
|
|
|
|
report( "RTS_CONTROL_HANDSHAKE\n" );
|
|
|
|
|
if ( myDCB.fRtsControl & RTS_CONTROL_ENABLE )
|
|
|
|
|
report( "RTS_CONTROL_ENABLE\n" );
|
|
|
|
|
if ( myDCB.fRtsControl & RTS_CONTROL_DISABLE )
|
|
|
|
|
report( "RTS_CONTROL_DISABLE\n" );
|
|
|
|
|
if ( myDCB.fAbortOnError )
|
|
|
|
|
report( "fAbortOnError\n" );
|
|
|
|
|
sprintf( message, "XonLim: %d\n", myDCB.XonLim );
|
|
|
|
|
report( message );
|
|
|
|
|
sprintf( message, "XoffLim: %d\n", myDCB.XoffLim );
|
|
|
|
|
report( message );
|
|
|
|
|
sprintf( message, "ByteSize: %d\n", myDCB.ByteSize );
|
|
|
|
|
report( message );
|
|
|
|
|
switch ( myDCB.Parity )
|
|
|
|
|
{
|
|
|
|
|
case EVENPARITY:
|
|
|
|
|
report( "EVENPARITY" );
|
|
|
|
|
break;
|
|
|
|
|
case MARKPARITY:
|
|
|
|
|
report( "MARKPARITY" );
|
|
|
|
|
break;
|
|
|
|
|
case NOPARITY:
|
|
|
|
|
report( "NOPARITY" );
|
|
|
|
|
break;
|
|
|
|
|
case ODDPARITY:
|
|
|
|
|
report( "ODDPARITY" );
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
sprintf( message,
|
|
|
|
|
"unknown Parity (%#x ):", myDCB.Parity );
|
|
|
|
|
report( message );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
report( "\n" );
|
|
|
|
|
switch( myDCB.StopBits )
|
|
|
|
|
{
|
|
|
|
|
case ONESTOPBIT:
|
|
|
|
|
report( "ONESTOPBIT" );
|
|
|
|
|
break;
|
|
|
|
|
case ONE5STOPBITS:
|
|
|
|
|
report( "ONE5STOPBITS" );
|
|
|
|
|
break;
|
|
|
|
|
case TWOSTOPBITS:
|
|
|
|
|
report( "TWOSTOPBITS" );
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
report( "unknown StopBits (%#x ):", myDCB.StopBits );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
report( "\n" );
|
|
|
|
|
sprintf( message, "XonChar: %#x\n", myDCB.XonChar );
|
|
|
|
|
report( message );
|
|
|
|
|
sprintf( message, "XoffChar: %#x\n", myDCB.XoffChar );
|
|
|
|
|
report( message );
|
|
|
|
|
sprintf( message, "EofChar: %#x\n", myDCB.EofChar );
|
|
|
|
|
report( message );
|
|
|
|
|
sprintf( message, "EvtChar: %#x\n", myDCB.EvtChar );
|
|
|
|
|
report( message );
|
|
|
|
|
report( "\n" );
|
|
|
|
|
#endif /* DEBUG_HOSED */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
tcgetattr()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: GetCommState(), GetCommTimeouts()
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int tcgetattr( int fd, struct termios *s_termios )
|
|
|
|
|
{
|
|
|
|
|
DCB myDCB;
|
|
|
|
|
COMMTIMEOUTS timeouts;
|
|
|
|
|
struct termios_list *index;
|
|
|
|
|
char message[80];
|
|
|
|
|
|
|
|
|
|
ENTER( "tcgetattr" );
|
|
|
|
|
if ( fd <= 0 )
|
|
|
|
|
return 0;
|
|
|
|
|
index = find_port( fd );
|
|
|
|
|
if ( !index )
|
|
|
|
|
{
|
|
|
|
|
LEAVE( "tcgetattr" );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if ( !GetCommState( index->hComm, &myDCB ) )
|
|
|
|
|
{
|
|
|
|
|
sprintf( message, "GetCommState failed\n" );
|
|
|
|
|
report( message );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
memcpy( s_termios, index->ttyset, sizeof( struct termios ) );
|
|
|
|
|
|
|
|
|
|
show_DCB( myDCB );
|
|
|
|
|
|
|
|
|
|
/***** input mode flags (c_iflag ) ****/
|
|
|
|
|
/* parity check enable */
|
|
|
|
|
if ( myDCB.fParity )
|
|
|
|
|
{
|
|
|
|
|
s_termios->c_iflag |= INPCK;
|
|
|
|
|
s_termios->c_iflag &= ~IGNPAR;
|
|
|
|
|
} else {
|
|
|
|
|
s_termios->c_iflag &= ~INPCK;
|
|
|
|
|
s_termios->c_iflag |= IGNPAR;
|
|
|
|
|
}
|
|
|
|
|
/* FIXME: IGNBRK: ignore break */
|
|
|
|
|
/* FIXME: BRKINT: interrupt on break */
|
|
|
|
|
|
|
|
|
|
if ( myDCB.fOutX )
|
|
|
|
|
{
|
|
|
|
|
s_termios->c_iflag |= IXON;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* IXON: output start/stop control */
|
|
|
|
|
s_termios->c_iflag &= ~IXON;
|
|
|
|
|
}
|
|
|
|
|
if ( myDCB.fInX )
|
|
|
|
|
{
|
|
|
|
|
s_termios->c_iflag |= IXOFF;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* IXOFF: input start/stop control */
|
|
|
|
|
s_termios->c_iflag &= ~IXOFF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( myDCB.fTXContinueOnXoff )
|
|
|
|
|
{
|
|
|
|
|
s_termios->c_iflag |= IXANY;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* IXANY: any char restarts output */
|
|
|
|
|
s_termios->c_iflag &= ~IXANY;
|
|
|
|
|
}
|
|
|
|
|
/* FIXME: IMAXBEL: if input buffer full, send bell */
|
|
|
|
|
|
|
|
|
|
/***** control mode flags (c_cflag ) *****/
|
|
|
|
|
/* FIXME: CLOCAL: DONT send SIGHUP on modem disconnect */
|
|
|
|
|
/* FIXME: HUPCL: generate modem disconnect when all has closed or
|
|
|
|
|
exited */
|
|
|
|
|
/* CSTOPB two stop bits ( otherwise one) */
|
|
|
|
|
if ( myDCB.StopBits == TWOSTOPBITS )
|
|
|
|
|
{
|
|
|
|
|
s_termios->c_cflag |= CSTOPB;
|
|
|
|
|
}
|
|
|
|
|
if ( myDCB.StopBits == ONESTOPBIT )
|
|
|
|
|
{
|
|
|
|
|
s_termios->c_cflag &= ~CSTOPB;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* PARENB enable parity bit */
|
|
|
|
|
s_termios->c_cflag &= ~( PARENB | PARODD | CMSPAR );
|
|
|
|
|
myDCB.fParity = 1;
|
|
|
|
|
if( myDCB.fParity )
|
|
|
|
|
{
|
|
|
|
|
report( "tcgetattr getting parity\n" );
|
|
|
|
|
s_termios->c_cflag |= PARENB;
|
|
|
|
|
if ( myDCB.Parity == MARKPARITY )
|
|
|
|
|
{
|
|
|
|
|
s_termios->c_cflag |= ( PARODD | CMSPAR );
|
|
|
|
|
}
|
|
|
|
|
else if ( myDCB.Parity == SPACEPARITY )
|
|
|
|
|
{
|
|
|
|
|
s_termios->c_cflag |= CMSPAR;
|
|
|
|
|
}
|
|
|
|
|
else if ( myDCB.Parity == ODDPARITY )
|
|
|
|
|
{
|
|
|
|
|
report( "ODDPARITY\n" );
|
|
|
|
|
s_termios->c_cflag |= PARODD;
|
|
|
|
|
}
|
|
|
|
|
else if ( myDCB.Parity == EVENPARITY )
|
|
|
|
|
{
|
|
|
|
|
report( "EVENPARITY\n" );
|
|
|
|
|
s_termios->c_cflag &= ~PARODD;
|
|
|
|
|
}
|
|
|
|
|
else if ( myDCB.Parity == NOPARITY )
|
|
|
|
|
{
|
|
|
|
|
s_termios->c_cflag &= ~(PARODD | CMSPAR | PARENB);
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
s_termios->c_cflag &= ~PARENB;
|
|
|
|
|
}
|
|
|
|
|
/* CSIZE */
|
|
|
|
|
s_termios->c_cflag |= bytesize_to_termios( myDCB.ByteSize );
|
|
|
|
|
/* HARDWARE_FLOW_CONTROL: hardware flow control */
|
|
|
|
|
if (( myDCB.fOutxCtsFlow == TRUE ) ||
|
|
|
|
|
( myDCB.fRtsControl == RTS_CONTROL_HANDSHAKE))
|
|
|
|
|
{
|
|
|
|
|
s_termios->c_cflag |= HARDWARE_FLOW_CONTROL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
s_termios->c_cflag &= ~HARDWARE_FLOW_CONTROL;
|
|
|
|
|
}
|
|
|
|
|
/* MDMBUF: carrier based flow control of output */
|
|
|
|
|
/* CIGNORE: tcsetattr will ignore control modes & baudrate */
|
|
|
|
|
|
|
|
|
|
/***** NOT SUPPORTED: local mode flags (c_lflag) *****/
|
|
|
|
|
/* ICANON: canonical (not raw) mode */
|
|
|
|
|
/* ECHO: echo back to terminal */
|
|
|
|
|
/* ECHOE: echo erase */
|
|
|
|
|
/* ECHOPRT: hardcopy echo erase */
|
|
|
|
|
/* ECHOK: show KILL char */
|
|
|
|
|
/* ECHOKE: BSD ECHOK */
|
|
|
|
|
/* ECHONL: ICANON only: echo newline even with no ECHO */
|
|
|
|
|
/* ECHOCTL: if ECHO, then control-A are printed as '^A' */
|
|
|
|
|
/* ISIG: recognize INTR, QUIT & SUSP */
|
|
|
|
|
/* IEXTEN: implmentation defined */
|
|
|
|
|
/* NOFLSH: dont clear i/o queues on INTR, QUIT or SUSP */
|
|
|
|
|
/* TOSTOP: background process generate SIGTTOU */
|
|
|
|
|
/* ALTWERASE: alt-w erase distance */
|
|
|
|
|
/* FLUSHO: user DISCARD char */
|
|
|
|
|
/* NOKERNINFO: disable STATUS char */
|
|
|
|
|
/* PENDIN: input line needsd reprinting, set by REPRINT char */
|
|
|
|
|
/***** END - NOT SUPPORTED *****/
|
|
|
|
|
|
|
|
|
|
/***** control characters (c_cc[NCCS] ) *****/
|
|
|
|
|
|
|
|
|
|
if ( !GetCommTimeouts( index->hComm, &timeouts ) )
|
|
|
|
|
{
|
|
|
|
|
YACK();
|
|
|
|
|
report( "GetCommTimeouts\n" );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s_termios->c_cc[VTIME] = timeouts.ReadTotalTimeoutConstant/100;
|
|
|
|
|
/*
|
|
|
|
|
handled in SerialImp.c?
|
|
|
|
|
s_termios->c_cc[VMIN] = ?
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
s_termios->c_cc[VSTART] = myDCB.XonChar;
|
|
|
|
|
s_termios->c_cc[VSTOP] = myDCB.XoffChar;
|
|
|
|
|
s_termios->c_cc[VEOF] = myDCB.EofChar;
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_VERBOSE
|
|
|
|
|
sprintf( message,
|
|
|
|
|
"tcgetattr: VTIME:%d, VMIN:%d\n", s_termios->c_cc[VTIME],
|
|
|
|
|
s_termios->c_cc[VMIN] );
|
|
|
|
|
report( message );
|
|
|
|
|
#endif /* DEBUG_VERBOSE */
|
|
|
|
|
|
|
|
|
|
/***** line discipline ( c_line ) ( == c_cc[33] ) *****/
|
|
|
|
|
|
|
|
|
|
DCB_to_termios( &myDCB, s_termios ); /* baudrate */
|
|
|
|
|
LEAVE( "tcgetattr" );
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
`TCSANOW'
|
|
|
|
|
Make the change immediately.
|
|
|
|
|
|
|
|
|
|
`TCSADRAIN'
|
|
|
|
|
Make the change after waiting until all queued output has
|
|
|
|
|
been written. You should usually use this option when
|
|
|
|
|
changing parameters that affect output.
|
|
|
|
|
|
|
|
|
|
`TCSAFLUSH'
|
|
|
|
|
This is like `TCSADRAIN', but also discards any queued input.
|
|
|
|
|
|
|
|
|
|
`TCSASOFT'
|
|
|
|
|
This is a flag bit that you can add to any of the above
|
|
|
|
|
alternatives. Its meaning is to inhibit alteration of the
|
|
|
|
|
state of the terminal hardware. It is a BSD extension; it is
|
|
|
|
|
only supported on BSD systems and the GNU system.
|
|
|
|
|
|
|
|
|
|
Using `TCSASOFT' is exactly the same as setting the `CIGNORE'
|
|
|
|
|
bit in the `c_cflag' member of the structure TERMIOS-P points
|
|
|
|
|
to. *Note Control Modes::, for a description of `CIGNORE'.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
tcsetattr()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: GetCommState(), GetCommTimeouts(), SetCommState(),
|
|
|
|
|
SetCommTimeouts()
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
int tcsetattr( int fd, int when, struct termios *s_termios )
|
|
|
|
|
{
|
|
|
|
|
int vtime;
|
|
|
|
|
DCB dcb;
|
|
|
|
|
COMMTIMEOUTS timeouts;
|
|
|
|
|
struct termios_list *index;
|
|
|
|
|
|
|
|
|
|
ENTER( "tcsetattr" );
|
|
|
|
|
if ( fd <= 0 )
|
|
|
|
|
return 0;
|
|
|
|
|
index = find_port( fd );
|
|
|
|
|
if ( !index )
|
|
|
|
|
{
|
|
|
|
|
LEAVE( "tcsetattr" );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
fflush( stdout );
|
|
|
|
|
if ( s_termios->c_lflag & ICANON )
|
|
|
|
|
{
|
|
|
|
|
report( "tcsetattr: no canonical mode support\n" );
|
|
|
|
|
/* and all other c_lflags too */
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if ( !GetCommState( index->hComm, &dcb ) )
|
|
|
|
|
{
|
|
|
|
|
YACK();
|
|
|
|
|
report( "tcsetattr:GetCommState\n" );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if ( !GetCommTimeouts( index->hComm, &timeouts ) )
|
|
|
|
|
{
|
|
|
|
|
YACK();
|
|
|
|
|
report( "tcsetattr:GetCommTimeouts\n" );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** control flags, c_cflag **/
|
|
|
|
|
if ( !( s_termios->c_cflag & CIGNORE ) )
|
|
|
|
|
{
|
|
|
|
|
dcb.fParity=1;
|
|
|
|
|
/* CIGNORE: ignore control modes and baudrate */
|
|
|
|
|
/* baudrate */
|
|
|
|
|
if ( termios_to_DCB( s_termios, &dcb ) < 0 ) return -1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** input flags, c_iflag **/
|
|
|
|
|
/* This is wrong. It disables Parity FIXME
|
|
|
|
|
if( ( s_termios->c_iflag & INPCK ) && !( s_termios->c_iflag & IGNPAR ) )
|
|
|
|
|
{
|
|
|
|
|
dcb.fParity = TRUE;
|
|
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
dcb.fParity = FALSE;
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
/* not in win95?
|
|
|
|
|
Some years later...
|
|
|
|
|
eww.. FIXME This is used for changing the Parity
|
|
|
|
|
error character
|
|
|
|
|
|
|
|
|
|
I think this code is hosed. See VEOF below
|
|
|
|
|
|
|
|
|
|
Trent
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if ( s_termios->c_iflag & ISTRIP ) dcb.fBinary = FALSE;
|
|
|
|
|
/* ISTRIP: strip to seven bits */
|
|
|
|
|
else dcb.fBinary = TRUE;
|
|
|
|
|
|
|
|
|
|
/* FIXME: IGNBRK: ignore break */
|
|
|
|
|
/* FIXME: BRKINT: interrupt on break */
|
|
|
|
|
if ( s_termios->c_iflag & IXON )
|
|
|
|
|
{
|
|
|
|
|
dcb.fOutX = TRUE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dcb.fOutX = FALSE;
|
|
|
|
|
}
|
|
|
|
|
if ( s_termios->c_iflag & IXOFF )
|
|
|
|
|
{
|
|
|
|
|
dcb.fInX = TRUE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dcb.fInX = FALSE;
|
|
|
|
|
}
|
|
|
|
|
dcb.fTXContinueOnXoff = ( s_termios->c_iflag & IXANY ) ? TRUE : FALSE;
|
|
|
|
|
/* FIXME: IMAXBEL: if input buffer full, send bell */
|
|
|
|
|
|
|
|
|
|
/* no DTR control in termios? */
|
|
|
|
|
dcb.fDtrControl = DTR_CONTROL_ENABLE;
|
|
|
|
|
/* no DSR control in termios? */
|
|
|
|
|
dcb.fOutxDsrFlow = FALSE;
|
|
|
|
|
/* DONT ignore rx bytes when DSR is OFF */
|
|
|
|
|
dcb.fDsrSensitivity = FALSE;
|
|
|
|
|
dcb.XonChar = s_termios->c_cc[VSTART];
|
|
|
|
|
dcb.XoffChar = s_termios->c_cc[VSTOP];
|
|
|
|
|
dcb.XonLim = 0; /* ? */
|
|
|
|
|
dcb.XoffLim = 0; /* ? */
|
|
|
|
|
dcb.EofChar = s_termios->c_cc[VEOF];
|
|
|
|
|
if( dcb.EofChar != '\0' )
|
|
|
|
|
{
|
|
|
|
|
dcb.fBinary = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dcb.fBinary = 1;
|
|
|
|
|
}
|
|
|
|
|
if ( EV_BREAK|EV_CTS|EV_DSR|EV_ERR|EV_RING | ( EV_RLSD & EV_RXFLAG ) )
|
|
|
|
|
dcb.EvtChar = '\n';
|
|
|
|
|
else
|
|
|
|
|
dcb.EvtChar = '\0';
|
|
|
|
|
|
|
|
|
|
if ( !SetCommState( index->hComm, &dcb ) )
|
|
|
|
|
{
|
|
|
|
|
report( "SetCommState error\n" );
|
|
|
|
|
YACK();
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_VERBOSE
|
|
|
|
|
sprintf( message, "VTIME:%d, VMIN:%d\n", s_termios->c_cc[VTIME],
|
|
|
|
|
s_termios->c_cc[VMIN] );
|
|
|
|
|
report( message );
|
|
|
|
|
#endif /* DEBUG_VERBOSE */
|
|
|
|
|
vtime = s_termios->c_cc[VTIME] * 100;
|
|
|
|
|
timeouts.ReadTotalTimeoutConstant = vtime;
|
|
|
|
|
timeouts.ReadIntervalTimeout = 0;
|
|
|
|
|
timeouts.ReadTotalTimeoutMultiplier = 0;
|
|
|
|
|
|
|
|
|
|
timeouts.WriteTotalTimeoutConstant = vtime;
|
|
|
|
|
timeouts.WriteTotalTimeoutMultiplier = 0;
|
|
|
|
|
/* max between bytes */
|
|
|
|
|
if ( s_termios->c_cc[VMIN] > 0 && vtime > 0 )
|
|
|
|
|
{
|
|
|
|
|
/* read blocks forever on VMIN chars */
|
|
|
|
|
} else if ( s_termios->c_cc[VMIN] == 0 && vtime == 0 )
|
|
|
|
|
{
|
|
|
|
|
/* read returns immediately */
|
|
|
|
|
timeouts.ReadIntervalTimeout = MAXDWORD;
|
|
|
|
|
timeouts.ReadTotalTimeoutConstant = 0;
|
|
|
|
|
timeouts.ReadTotalTimeoutMultiplier = 0;
|
|
|
|
|
}
|
|
|
|
|
#ifdef DEBUG_VERBOSE
|
|
|
|
|
sprintf( message, "ReadIntervalTimeout=%ld\n",
|
|
|
|
|
timeouts.ReadIntervalTimeout );
|
|
|
|
|
report( message );
|
|
|
|
|
sprintf( message, "c_cc[VTIME] = %d, c_cc[VMIN] = %d\n",
|
|
|
|
|
s_termios->c_cc[VTIME], s_termios->c_cc[VMIN] );
|
|
|
|
|
report( message );
|
|
|
|
|
sprintf( message, "ReadTotalTimeoutConstant: %ld\n",
|
|
|
|
|
timeouts.ReadTotalTimeoutConstant );
|
|
|
|
|
report( message );
|
|
|
|
|
sprintf( message, "ReadIntervalTimeout : %ld\n",
|
|
|
|
|
timeouts.ReadIntervalTimeout );
|
|
|
|
|
report( message );
|
|
|
|
|
sprintf( message, "ReadTotalTimeoutMultiplier: %ld\n",
|
|
|
|
|
timeouts.ReadTotalTimeoutMultiplier );
|
|
|
|
|
report( message );
|
|
|
|
|
#endif /* DEBUG_VERBOSE */
|
|
|
|
|
if ( !SetCommTimeouts( index->hComm, &timeouts ) )
|
|
|
|
|
{
|
|
|
|
|
YACK();
|
|
|
|
|
report( "SetCommTimeouts\n" );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
memcpy( index->ttyset, s_termios, sizeof( struct termios ) );
|
|
|
|
|
LEAVE( "tcsetattr" );
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
tcsendbreak()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments:
|
|
|
|
|
break for duration*0.25 seconds or
|
|
|
|
|
0.25 seconds if duration = 0.
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int tcsendbreak( int fd, int duration )
|
|
|
|
|
{
|
|
|
|
|
struct termios_list *index;
|
|
|
|
|
COMSTAT Stat;
|
|
|
|
|
|
|
|
|
|
ENTER( "tcsendbreak" );
|
|
|
|
|
|
|
|
|
|
index = find_port( fd );
|
|
|
|
|
|
|
|
|
|
if ( !index )
|
|
|
|
|
{
|
|
|
|
|
LEAVE( "tcdrain" );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( duration <= 0 ) duration = 1;
|
|
|
|
|
|
|
|
|
|
if( !SetCommBreak( index->hComm ) )
|
|
|
|
|
ClearErrors( index, &Stat );
|
|
|
|
|
/* 0.25 seconds == 250000 usec */
|
|
|
|
|
usleep( duration * 250000 );
|
|
|
|
|
if( !ClearCommBreak( index->hComm ) )
|
|
|
|
|
ClearErrors( index, &Stat );
|
|
|
|
|
LEAVE( "tcsendbreak" );
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
tcdrain()
|
|
|
|
|
|
|
|
|
|
accept: file descriptor
|
|
|
|
|
perform: wait for ouput to be written.
|
|
|
|
|
return: 0 on success, -1 otherwise
|
|
|
|
|
exceptions: None
|
|
|
|
|
win32api: FlushFileBuffers
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int tcdrain ( int fd )
|
|
|
|
|
{
|
|
|
|
|
struct termios_list *index;
|
|
|
|
|
char message[80];
|
|
|
|
|
int old_flag;
|
|
|
|
|
|
|
|
|
|
ENTER( "tcdrain" );
|
|
|
|
|
index = find_port( fd );
|
|
|
|
|
|
|
|
|
|
if ( !index )
|
|
|
|
|
{
|
|
|
|
|
LEAVE( "tcdrain" );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
old_flag = index->event_flag;
|
|
|
|
|
/*
|
|
|
|
|
index->event_flag &= ~EV_TXEMPTY;
|
|
|
|
|
SetCommMask( index->hComm, index->event_flag );
|
|
|
|
|
index->tx_happened = 1;
|
|
|
|
|
*/
|
|
|
|
|
if ( !FlushFileBuffers( index->hComm ) )
|
|
|
|
|
{
|
|
|
|
|
/* FIXME Need to figure out what the various errors are in
|
|
|
|
|
windows. YACK() should report them and we can
|
|
|
|
|
handle them as we find them
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Something funky is happening on NT. GetLastError =
|
|
|
|
|
0.
|
|
|
|
|
*/
|
|
|
|
|
sprintf( message, "FlushFileBuffers() %i\n",
|
|
|
|
|
(int) GetLastError() );
|
|
|
|
|
report( message );
|
|
|
|
|
if( GetLastError() == 0 )
|
|
|
|
|
{
|
|
|
|
|
set_errno( 0 );
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
set_errno( EAGAIN );
|
|
|
|
|
YACK();
|
|
|
|
|
LEAVE( "tcdrain" );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
sprintf( message, "FlushFileBuffers() %i\n",
|
|
|
|
|
(int) GetLastError() );
|
|
|
|
|
report( message );
|
|
|
|
|
*/
|
|
|
|
|
LEAVE( "tcdrain success" );
|
|
|
|
|
index->event_flag |= EV_TXEMPTY;
|
|
|
|
|
SetCommMask( index->hComm, index->event_flag );
|
|
|
|
|
index->event_flag = old_flag;
|
|
|
|
|
/*
|
|
|
|
|
index->tx_happened = 1;
|
|
|
|
|
*/
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
tcflush()
|
|
|
|
|
|
|
|
|
|
accept: file descriptor, queue_selector
|
|
|
|
|
perform: discard data not transmitted or read
|
|
|
|
|
TCIFLUSH: flush data not read
|
|
|
|
|
TCOFLUSH: flush data not transmitted
|
|
|
|
|
TCIOFLUSH: flush both
|
|
|
|
|
return: 0 on success, -1 on error
|
|
|
|
|
exceptions: none
|
|
|
|
|
win32api: PurgeComm
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int tcflush( int fd, int queue_selector )
|
|
|
|
|
{
|
|
|
|
|
struct termios_list *index;
|
|
|
|
|
int old_flag;
|
|
|
|
|
|
|
|
|
|
index = find_port( fd );
|
|
|
|
|
if( !index)
|
|
|
|
|
{
|
|
|
|
|
LEAVE( "tclflush" );
|
|
|
|
|
return(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
old_flag = index->event_flag;
|
|
|
|
|
/*
|
|
|
|
|
index->event_flag &= ~EV_TXEMPTY;
|
|
|
|
|
SetCommMask( index->hComm, index->event_flag );
|
|
|
|
|
index->tx_happened = 1;
|
|
|
|
|
*/
|
|
|
|
|
ENTER( "tcflush" );
|
|
|
|
|
if ( !index )
|
|
|
|
|
{
|
|
|
|
|
LEAVE( "tcflush" );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
index->tx_happened = 1;
|
|
|
|
|
switch( queue_selector )
|
|
|
|
|
{
|
|
|
|
|
case TCIFLUSH:
|
|
|
|
|
if ( !PurgeComm( index->hComm, PURGE_RXABORT ) )
|
|
|
|
|
{
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case TCOFLUSH:
|
|
|
|
|
if ( !PurgeComm( index->hComm, PURGE_TXABORT ) )
|
|
|
|
|
{
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case TCIOFLUSH:
|
|
|
|
|
if ( !PurgeComm( index->hComm, PURGE_TXABORT ) )
|
|
|
|
|
{
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
if ( !PurgeComm( index->hComm, PURGE_RXABORT ) )
|
|
|
|
|
{
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/*
|
|
|
|
|
set_errno( ENOTSUP );
|
|
|
|
|
*/
|
|
|
|
|
report( "tcflush: Unknown queue_selector\n" );
|
|
|
|
|
LEAVE( "tcflush" );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
index->event_flag |= EV_TXEMPTY;
|
|
|
|
|
SetCommMask( index->hComm, index->event_flag );
|
|
|
|
|
index->event_flag = old_flag;
|
|
|
|
|
index->tx_happened = 1;
|
|
|
|
|
LEAVE( "tcflush" );
|
|
|
|
|
return( 0 );
|
|
|
|
|
|
|
|
|
|
/* FIXME Need to figure out what the various errors are in
|
|
|
|
|
windows. YACK() should report them and we can
|
|
|
|
|
handle them as we find them
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
fail:
|
|
|
|
|
LEAVE( "tcflush" );
|
|
|
|
|
set_errno( EAGAIN );
|
|
|
|
|
YACK();
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
tcflow()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments: FIXME
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int tcflow( int fd, int action )
|
|
|
|
|
{
|
|
|
|
|
ENTER( "tcflow" );
|
|
|
|
|
switch ( action )
|
|
|
|
|
{
|
|
|
|
|
/* Suspend transmission of output */
|
|
|
|
|
case TCOOFF: break;
|
|
|
|
|
/* Restart transmission of output */
|
|
|
|
|
case TCOON: break;
|
|
|
|
|
/* Transmit a STOP character */
|
|
|
|
|
case TCIOFF: break;
|
|
|
|
|
/* Transmit a START character */
|
|
|
|
|
case TCION: break;
|
|
|
|
|
default: return -1;
|
|
|
|
|
}
|
|
|
|
|
LEAVE( "tcflow" );
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
fstat()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api:
|
|
|
|
|
comments: this is just to keep the eventLoop happy.
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
2004-08-01 23:13:17 +00:00
|
|
|
|
#if 0
|
2003-08-15 01:15:45 +00:00
|
|
|
|
int fstat( int fd, ... )
|
|
|
|
|
{
|
|
|
|
|
return( 0 );
|
|
|
|
|
}
|
2004-08-01 23:13:17 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2003-08-15 01:15:45 +00:00
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
ioctl()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: GetCommError(), GetCommModemStatus, EscapeCommFunction()
|
|
|
|
|
comments: FIXME
|
|
|
|
|
the DCB struct is:
|
|
|
|
|
|
|
|
|
|
typedef struct _DCB
|
|
|
|
|
{
|
|
|
|
|
unsigned long DCBlength, BaudRate, fBinary:1, fParity:1;
|
|
|
|
|
unsigned long fOutxCtsFlow:1, fOutxDsrFlow:1, fDtrControl:2;
|
|
|
|
|
unsigned long fDsrSensitivity:1, fTXContinueOnXoff:1;
|
|
|
|
|
unsigned long fOutX:1, fInX:1, fErrorChar:1, fNull:1;
|
|
|
|
|
unsigned long fRtsControl:2, fAbortOnError:1, fDummy2:17;
|
|
|
|
|
WORD wReserved, XonLim, XoffLim;
|
|
|
|
|
BYTE ByteSize, Parity, StopBits;
|
|
|
|
|
char XonChar, XoffChar, ErrorChar, EofChar, EvtChar;
|
|
|
|
|
WORD wReserved1;
|
|
|
|
|
} DCB;
|
|
|
|
|
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
2004-08-01 23:13:17 +00:00
|
|
|
|
int win32_serial_ioctl( int fd, int request, ... )
|
2003-08-15 01:15:45 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned long dwStatus = 0;
|
|
|
|
|
va_list ap;
|
|
|
|
|
int *arg, ret, result, old_flag;
|
|
|
|
|
char message[80];
|
|
|
|
|
|
|
|
|
|
#ifdef TIOCGSERIAL
|
|
|
|
|
DCB *dcb;
|
|
|
|
|
struct serial_struct *sstruct;
|
|
|
|
|
#endif /* TIOCGSERIAL */
|
|
|
|
|
COMSTAT Stat;
|
|
|
|
|
|
|
|
|
|
struct termios_list *index;
|
|
|
|
|
struct async_struct *astruct;
|
|
|
|
|
struct serial_multiport_struct *mstruct;
|
|
|
|
|
#ifdef TIOCGICOUNT
|
|
|
|
|
struct serial_icounter_struct *sistruct;
|
|
|
|
|
#endif /* TIOCGICOUNT */
|
|
|
|
|
|
|
|
|
|
ENTER( "ioctl" );
|
|
|
|
|
if ( fd <= 0 )
|
|
|
|
|
return 0;
|
|
|
|
|
index = find_port( fd );
|
|
|
|
|
if ( !index )
|
|
|
|
|
{
|
|
|
|
|
LEAVE( "ioctl" );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
va_start( ap, request );
|
|
|
|
|
|
2008-11-05 23:00:20 +00:00
|
|
|
|
ret = ClearErrors( index, &Stat );
|
|
|
|
|
if (ret == 0)
|
|
|
|
|
{
|
|
|
|
|
set_errno( EBADFD );
|
|
|
|
|
YACK();
|
|
|
|
|
report( "ClearError Failed! ernno EBADFD" );
|
|
|
|
|
arg = va_arg( ap, int * );
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2003-08-15 01:15:45 +00:00
|
|
|
|
switch( request )
|
|
|
|
|
{
|
|
|
|
|
case TCSBRK:
|
|
|
|
|
arg = va_arg( ap, int * );
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
|
case TCSBRKP:
|
|
|
|
|
arg = va_arg( ap, int * );
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
|
case TIOCGSOFTCAR:
|
|
|
|
|
arg = va_arg( ap, int * );
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
|
case TIOCSSOFTCAR:
|
|
|
|
|
arg = va_arg( ap, int * );
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
|
|
2004-08-01 23:13:17 +00:00
|
|
|
|
case TIOCCBRK:
|
|
|
|
|
case TIOCSBRK:
|
|
|
|
|
arg = va_arg( ap, int * );
|
|
|
|
|
if ( EscapeCommFunction( index->hComm,
|
|
|
|
|
( request == TIOCSBRK ) ? SETBREAK :
|
|
|
|
|
CLRBREAK ) )
|
|
|
|
|
report( "EscapeCommFunction: True\n" );
|
|
|
|
|
else
|
|
|
|
|
report( "EscapeCommFunction: False\n" );
|
|
|
|
|
break;
|
|
|
|
|
|
2003-08-15 01:15:45 +00:00
|
|
|
|
case TIOCMGET:
|
|
|
|
|
arg = va_arg( ap, int * );
|
|
|
|
|
/* DORITOS */
|
|
|
|
|
if ( !GetCommModemStatus( index->hComm, &dwStatus ) )
|
|
|
|
|
report_error( "GetCommMOdemStatus failed!\n" );
|
|
|
|
|
if ( dwStatus & MS_RLSD_ON ) *arg |= TIOCM_CAR;
|
|
|
|
|
else *arg &= ~TIOCM_CAR;
|
|
|
|
|
if ( dwStatus & MS_RING_ON ) *arg |= TIOCM_RNG;
|
|
|
|
|
else *arg &= ~TIOCM_RNG;
|
|
|
|
|
if ( dwStatus & MS_DSR_ON ) *arg |= TIOCM_DSR;
|
|
|
|
|
else *arg &= ~TIOCM_DSR;
|
|
|
|
|
if ( dwStatus & MS_CTS_ON ) *arg |= TIOCM_CTS;
|
|
|
|
|
else *arg &= ~TIOCM_CTS;
|
|
|
|
|
/* I'm not seeing a way to read the MSR directly
|
|
|
|
|
we store the state using TIOCM_*
|
|
|
|
|
|
|
|
|
|
Trent
|
|
|
|
|
*/
|
|
|
|
|
if ( index->MSR & TIOCM_DTR )
|
|
|
|
|
*arg |= TIOCM_DTR;
|
|
|
|
|
else *arg &= ~TIOCM_DTR;
|
|
|
|
|
if ( index->MSR & TIOCM_RTS )
|
|
|
|
|
*arg |= TIOCM_RTS;
|
|
|
|
|
else *arg &= ~TIOCM_RTS;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
TIOCM_LE
|
|
|
|
|
TIOCM_ST
|
|
|
|
|
TIOCM_SR
|
|
|
|
|
*/
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return( 0 );
|
|
|
|
|
case TIOCMBIS:
|
|
|
|
|
arg = va_arg( ap, int * );
|
2004-08-01 23:13:17 +00:00
|
|
|
|
if ( *arg & TIOCM_DTR )
|
|
|
|
|
{
|
|
|
|
|
index->MSR |= TIOCM_DTR;
|
|
|
|
|
|
|
|
|
|
if (EscapeCommFunction( index->hComm, SETDTR))
|
|
|
|
|
report( "EscapeCommFunction: True\n" );
|
|
|
|
|
else
|
|
|
|
|
report( "EscapeCommFunction: False\n" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( *arg & TIOCM_RTS )
|
|
|
|
|
{
|
|
|
|
|
index->MSR |= TIOCM_RTS;
|
|
|
|
|
|
|
|
|
|
if(EscapeCommFunction( index->hComm, SETRTS))
|
|
|
|
|
report( "EscapeCommFunction: True\n" );
|
|
|
|
|
else
|
|
|
|
|
report( "EscapeCommFunction: False\n" );
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2003-08-15 01:15:45 +00:00
|
|
|
|
case TIOCMBIC:
|
|
|
|
|
arg = va_arg( ap, int * );
|
2004-08-01 23:13:17 +00:00
|
|
|
|
if ( *arg & TIOCM_DTR )
|
|
|
|
|
{
|
|
|
|
|
index->MSR &= ~TIOCM_DTR;
|
|
|
|
|
if ( EscapeCommFunction( index->hComm, CLRDTR))
|
|
|
|
|
report( "EscapeCommFunction: True\n" );
|
|
|
|
|
else
|
|
|
|
|
report( "EscapeCommFunction: False\n" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( *arg & TIOCM_RTS )
|
|
|
|
|
{
|
|
|
|
|
index->MSR &= ~TIOCM_RTS;
|
|
|
|
|
if( EscapeCommFunction( index->hComm, CLRRTS))
|
|
|
|
|
report( "EscapeCommFunction: True\n" );
|
|
|
|
|
else
|
|
|
|
|
report( "EscapeCommFunction: False\n" );
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2003-08-15 01:15:45 +00:00
|
|
|
|
case TIOCMSET:
|
|
|
|
|
arg = va_arg( ap, int * );
|
|
|
|
|
if (( *arg & TIOCM_DTR) == (index->MSR & TIOCM_DTR) )
|
|
|
|
|
{
|
|
|
|
|
report( "DTR is unchanged\n" );
|
|
|
|
|
}
|
|
|
|
|
sprintf(message, "DTR %i %i\n", *arg&TIOCM_DTR, index->MSR & TIOCM_DTR );
|
|
|
|
|
report( message );
|
|
|
|
|
if ( *arg & TIOCM_DTR )
|
|
|
|
|
{
|
|
|
|
|
index->MSR |= TIOCM_DTR;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
index->MSR &= ~TIOCM_DTR;
|
|
|
|
|
}
|
|
|
|
|
if ( EscapeCommFunction( index->hComm,
|
|
|
|
|
( *arg & TIOCM_DTR ) ? SETDTR :
|
|
|
|
|
CLRDTR ) )
|
|
|
|
|
report( "EscapeCommFunction: True\n" );
|
|
|
|
|
else
|
|
|
|
|
report( "EscapeCommFunction: False\n" );
|
|
|
|
|
if ( (*arg & TIOCM_RTS) == ( index->MSR & TIOCM_RTS) )
|
|
|
|
|
{
|
|
|
|
|
report( "RTS is unchanged\n" );
|
|
|
|
|
}
|
|
|
|
|
sprintf( message, "RTS %i %i\n", *arg&TIOCM_RTS, index->MSR & TIOCM_RTS );
|
|
|
|
|
report( message );
|
|
|
|
|
if ( *arg & TIOCM_RTS )
|
|
|
|
|
{
|
|
|
|
|
index->MSR |= TIOCM_RTS;
|
|
|
|
|
result &= SETRTS;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
index->MSR &= ~TIOCM_RTS;
|
|
|
|
|
result &= CLRRTS;
|
|
|
|
|
}
|
|
|
|
|
if( EscapeCommFunction( index->hComm,
|
|
|
|
|
( *arg & TIOCM_RTS ) ? SETRTS : CLRRTS ) )
|
|
|
|
|
report( "EscapeCommFunction: True\n" );
|
|
|
|
|
else
|
|
|
|
|
report( "EscapeCommFunction: False\n" );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
#ifdef TIOCGSERIAL
|
|
|
|
|
case TIOCGSERIAL:
|
|
|
|
|
report( "TIOCGSERIAL\n" );
|
|
|
|
|
|
|
|
|
|
dcb = malloc( sizeof( DCB ) );
|
|
|
|
|
if( !dcb )
|
|
|
|
|
{
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
memset( dcb, 0, sizeof( DCB ) );
|
|
|
|
|
GetCommState( index->hComm, dcb );
|
|
|
|
|
|
|
|
|
|
sstruct = va_arg( ap, struct serial_struct * );
|
|
|
|
|
if ( DCB_to_serial_struct( dcb, sstruct ) < 0 )
|
|
|
|
|
{
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
index->sstruct = sstruct;
|
|
|
|
|
|
|
|
|
|
report( "TIOCGSERIAL\n" );
|
|
|
|
|
free(dcb);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
#endif /* TIOCGSERIAL */
|
|
|
|
|
#ifdef TIOCSSERIAL
|
|
|
|
|
case TIOCSSERIAL:
|
|
|
|
|
report( "TIOCSSERIAL\n" );
|
|
|
|
|
|
|
|
|
|
dcb = malloc( sizeof( DCB ) );
|
|
|
|
|
if( !dcb )
|
|
|
|
|
{
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
memset( dcb, 0, sizeof( DCB ) );
|
|
|
|
|
GetCommState( index->hComm, dcb );
|
|
|
|
|
|
|
|
|
|
index->sstruct = va_arg( ap, struct serial_struct * );
|
|
|
|
|
if ( serial_struct_to_DCB( index->sstruct, dcb ) < 0 )
|
|
|
|
|
{
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
report( "TIOCSSERIAL\n" );
|
|
|
|
|
free(dcb);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
#endif /* TIOCSSERIAL */
|
|
|
|
|
case TIOCSERCONFIG:
|
|
|
|
|
case TIOCSERGETLSR:
|
|
|
|
|
arg = va_arg( ap, int * );
|
|
|
|
|
/*
|
|
|
|
|
do {
|
|
|
|
|
wait = WaitForSingleObject( index->sol.hEvent, 5000 );
|
|
|
|
|
} while ( wait == WAIT_TIMEOUT );
|
|
|
|
|
*/
|
|
|
|
|
ret = ClearErrors( index, &Stat );
|
|
|
|
|
if ( ret == 0 )
|
|
|
|
|
{
|
|
|
|
|
/* FIXME ? */
|
|
|
|
|
set_errno( EBADFD );
|
|
|
|
|
YACK();
|
|
|
|
|
report( "TIOCSERGETLSR EBADFD" );
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if ( (int ) Stat.cbOutQue == 0 )
|
|
|
|
|
{
|
|
|
|
|
/* output is empty */
|
|
|
|
|
if( index->tx_happened == 1 )
|
|
|
|
|
{
|
|
|
|
|
old_flag = index->event_flag;
|
|
|
|
|
index->event_flag &= ~EV_TXEMPTY;
|
|
|
|
|
SetCommMask( index->hComm,
|
|
|
|
|
index->event_flag );
|
|
|
|
|
index->event_flag = old_flag;
|
|
|
|
|
*arg = 1;
|
|
|
|
|
index->tx_happened = 0;
|
|
|
|
|
report( "ioctl: ouput empty\n" );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*arg = 0;
|
|
|
|
|
}
|
|
|
|
|
ret = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* still data out there */
|
|
|
|
|
*arg = 0;
|
|
|
|
|
ret = 0;
|
|
|
|
|
}
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return(0);
|
|
|
|
|
break;
|
|
|
|
|
case TIOCSERGSTRUCT:
|
|
|
|
|
astruct = va_arg( ap, struct async_struct * );
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
|
case TIOCSERGETMULTI:
|
|
|
|
|
mstruct = va_arg( ap, struct serial_multiport_struct * );
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
|
case TIOCSERSETMULTI:
|
|
|
|
|
mstruct = va_arg( ap, struct serial_multiport_struct * );
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
|
case TIOCMIWAIT:
|
|
|
|
|
arg = va_arg( ap, int * );
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
|
/*
|
|
|
|
|
On linux this fills a struct with all the line info
|
|
|
|
|
(data available, bytes sent, ...
|
|
|
|
|
*/
|
|
|
|
|
#ifdef TIOCGICOUNT
|
|
|
|
|
case TIOCGICOUNT:
|
|
|
|
|
sistruct= va_arg( ap, struct serial_icounter_struct * );
|
|
|
|
|
ret = ClearErrors( index, &Stat );
|
|
|
|
|
if ( ret == 0 )
|
|
|
|
|
{
|
|
|
|
|
/* FIXME ? */
|
|
|
|
|
report( "TIOCGICOUNT failed\n" );
|
|
|
|
|
set_errno( EBADFD );
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if( sistruct->frame != index->sis->frame )
|
|
|
|
|
{
|
|
|
|
|
sistruct->frame = index->sis->frame;
|
|
|
|
|
/*
|
|
|
|
|
printf( "---------------frame = %i\n", sistruct->frame++ );
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
if( sistruct->overrun != index->sis->overrun )
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
printf( "---------------overrun\n" );
|
|
|
|
|
*/
|
|
|
|
|
sistruct->overrun = index->sis->overrun;
|
2008-11-05 23:00:20 +00:00
|
|
|
|
/* ErrCode &= ~CE_OVERRUN; */
|
2003-08-15 01:15:45 +00:00
|
|
|
|
}
|
|
|
|
|
if( sistruct->parity != index->sis->parity )
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
printf( "---------------parity\n" );
|
|
|
|
|
*/
|
|
|
|
|
sistruct->parity = index->sis->parity;
|
|
|
|
|
}
|
|
|
|
|
if( sistruct->brk != index->sis->brk )
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
printf( "---------------brk\n" );
|
|
|
|
|
*/
|
|
|
|
|
sistruct->brk = index->sis->brk;
|
|
|
|
|
}
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return 0;
|
|
|
|
|
/* abolete ioctls */
|
|
|
|
|
#endif /* TIOCGICOUNT */
|
|
|
|
|
case TIOCSERGWILD:
|
|
|
|
|
case TIOCSERSWILD:
|
|
|
|
|
report( "TIOCSER[GS]WILD absolete\n" );
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return 0;
|
|
|
|
|
/* number of bytes available for reading */
|
|
|
|
|
case FIONREAD:
|
|
|
|
|
arg = va_arg( ap, int * );
|
|
|
|
|
ret = ClearErrors( index, &Stat );
|
|
|
|
|
if ( ret == 0 )
|
|
|
|
|
{
|
|
|
|
|
/* FIXME ? */
|
|
|
|
|
report( "FIONREAD failed\n" );
|
|
|
|
|
set_errno( EBADFD );
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
*arg = ( int ) Stat.cbInQue;
|
|
|
|
|
#ifdef DEBUG_VERBOSE
|
|
|
|
|
sprintf( message, "FIONREAD: %i bytes available\n",
|
|
|
|
|
(int) Stat.cbInQue );
|
|
|
|
|
report( message );
|
|
|
|
|
if( *arg )
|
|
|
|
|
{
|
|
|
|
|
sprintf( message, "FIONREAD: %i\n", *arg );
|
|
|
|
|
report( message );
|
|
|
|
|
}
|
|
|
|
|
#endif /* DEBUG_VERBOSE */
|
|
|
|
|
ret = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* pending bytes to be sent */
|
|
|
|
|
case TIOCOUTQ:
|
|
|
|
|
arg = va_arg( ap, int * );
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
|
default:
|
|
|
|
|
sprintf( message,
|
|
|
|
|
"FIXME: ioctl: unknown request: %#x\n",
|
|
|
|
|
request );
|
|
|
|
|
report( message );
|
|
|
|
|
va_end( ap );
|
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
|
}
|
|
|
|
|
va_end( ap );
|
|
|
|
|
LEAVE( "ioctl" );
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
fcntl()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return:
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: None
|
|
|
|
|
comments: FIXME
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int fcntl( int fd, int command, ... )
|
|
|
|
|
{
|
|
|
|
|
int arg, ret = 0;
|
|
|
|
|
va_list ap;
|
|
|
|
|
struct termios_list *index;
|
|
|
|
|
char message[80];
|
|
|
|
|
|
|
|
|
|
ENTER( "fcntl" );
|
|
|
|
|
if ( fd <= 0 )
|
|
|
|
|
return 0;
|
|
|
|
|
index = find_port( fd );
|
|
|
|
|
if ( !index )
|
|
|
|
|
{
|
|
|
|
|
LEAVE( "fcntl" );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
va_start( ap, command );
|
|
|
|
|
|
|
|
|
|
arg = va_arg( ap, int );
|
|
|
|
|
switch ( command )
|
|
|
|
|
{
|
|
|
|
|
case F_SETOWN: /* set ownership of fd */
|
|
|
|
|
break;
|
|
|
|
|
case F_SETFL: /* set operating flags */
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
sprintf( message, "F_SETFL fd=%d flags=%d\n", fd, arg );
|
|
|
|
|
report( message );
|
|
|
|
|
#endif
|
|
|
|
|
index->open_flags = arg;
|
|
|
|
|
break;
|
|
|
|
|
case F_GETFL: /* get operating flags */
|
|
|
|
|
ret = index->open_flags;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
sprintf( message, "unknown fcntl command %#x\n", command );
|
|
|
|
|
report( message );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
va_end( ap );
|
|
|
|
|
LEAVE( "fcntl" );
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
termios_interrupt_event_loop()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return: let Serial_select break out so the thread can die
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api:
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
void termios_interrupt_event_loop( int fd, int flag )
|
|
|
|
|
{
|
|
|
|
|
struct termios_list * index = find_port( fd );
|
|
|
|
|
if ( !index )
|
|
|
|
|
{
|
|
|
|
|
LEAVE( "termios_interrupt_event_loop" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
index->event_flag = 0;
|
|
|
|
|
TRENT SetCommMask( index->hComm, index->event_flag );
|
|
|
|
|
usleep(2000);
|
|
|
|
|
tcdrain( index->fd );
|
|
|
|
|
SetEvent( index->sol.hEvent );
|
|
|
|
|
*/
|
|
|
|
|
index->interrupt = flag;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
Serial_select()
|
|
|
|
|
|
|
|
|
|
accept:
|
|
|
|
|
perform:
|
|
|
|
|
return: number of fd's changed on success or -1 on error.
|
|
|
|
|
exceptions:
|
|
|
|
|
win32api: SetCommMask(), GetCommEvent(), WaitSingleObject()
|
|
|
|
|
comments:
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
#ifndef __LCC__
|
|
|
|
|
int win32_serial_select( int n, fd_set *readfds, fd_set *writefds,
|
|
|
|
|
fd_set *exceptfds, struct timeval *timeout )
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
unsigned long dwCommEvent, wait = WAIT_TIMEOUT;
|
|
|
|
|
int fd = n-1;
|
|
|
|
|
struct termios_list *index;
|
|
|
|
|
char message[80];
|
|
|
|
|
COMSTAT Stat;
|
2003-10-17 22:53:54 +00:00
|
|
|
|
int ret;
|
2003-08-15 01:15:45 +00:00
|
|
|
|
|
|
|
|
|
ENTER( "serial_select" );
|
|
|
|
|
if ( fd <= 0 )
|
|
|
|
|
{
|
|
|
|
|
/* Baby did a bad baad thing */
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
index = find_port( fd );
|
2003-10-17 22:53:54 +00:00
|
|
|
|
|
|
|
|
|
if ( !index )
|
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
#define DATA_AVAILABLE 1
|
|
|
|
|
|
|
|
|
|
//nativeSetEventFlag( fd, SerialPortEvent.DATA_AVAILABLE, enable );
|
|
|
|
|
if (readfds) {
|
|
|
|
|
int eventflags[12];
|
|
|
|
|
memset(eventflags, 0, sizeof(eventflags));
|
|
|
|
|
|
|
|
|
|
eventflags[DATA_AVAILABLE] = 1;
|
|
|
|
|
termios_setflags( fd, eventflags );
|
|
|
|
|
}
|
|
|
|
|
|
2003-08-15 01:15:45 +00:00
|
|
|
|
if ( !index || !index->event_flag )
|
|
|
|
|
{
|
|
|
|
|
/* still setting up the port? hold off for a Sec so
|
|
|
|
|
things can fire up
|
|
|
|
|
|
|
|
|
|
this does happen. loops ~twice on a 350 Mzh with
|
|
|
|
|
usleep(1000000)
|
|
|
|
|
*/
|
|
|
|
|
usleep(10000);
|
2003-10-17 22:53:54 +00:00
|
|
|
|
LEAVE( "serial_uselect" );
|
2003-08-15 01:15:45 +00:00
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ResetEvent( index->wol.hEvent );
|
|
|
|
|
ResetEvent( index->sol.hEvent );
|
|
|
|
|
ResetEvent( index->rol.hEvent );
|
2003-10-17 22:53:54 +00:00
|
|
|
|
ret = ClearErrors( index, &Stat );
|
|
|
|
|
#if 1
|
|
|
|
|
if ( ret == 0 ) {
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
/* look only after read */
|
|
|
|
|
if (readfds && !writefds && !exceptfds) {
|
|
|
|
|
int timeout_usec = timeout ? timeout->tv_sec*1000000 + timeout->tv_usec : INT_MAX;
|
|
|
|
|
|
|
|
|
|
while (timeout_usec > 0) {
|
2004-08-01 23:13:17 +00:00
|
|
|
|
sprintf( message, "wait for data in read buffer%d\n", (int)Stat.cbInQue );
|
2003-10-17 22:53:54 +00:00
|
|
|
|
report( message );
|
|
|
|
|
|
|
|
|
|
if (Stat.cbInQue != 0) {
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usleep(10000);
|
|
|
|
|
/* FIXME: not very accurate wrt process time */
|
|
|
|
|
timeout_usec -= 10000;
|
|
|
|
|
|
|
|
|
|
report( "sleep...\n" );
|
|
|
|
|
|
|
|
|
|
ret = ClearErrors( index, &Stat );
|
|
|
|
|
if ( ret == 0 ) {
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2003-08-15 01:15:45 +00:00
|
|
|
|
while ( wait == WAIT_TIMEOUT && index->sol.hEvent )
|
|
|
|
|
{
|
|
|
|
|
if( index->interrupt == 1 )
|
|
|
|
|
{
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
SetCommMask( index->hComm, index->event_flag );
|
|
|
|
|
ClearErrors( index, &Stat );
|
|
|
|
|
if ( !WaitCommEvent( index->hComm, &dwCommEvent,
|
|
|
|
|
&index->sol ) )
|
|
|
|
|
{
|
|
|
|
|
/* WaitCommEvent failed probably overlapped though */
|
|
|
|
|
if ( GetLastError() != ERROR_IO_PENDING )
|
|
|
|
|
{
|
|
|
|
|
ClearErrors( index, &Stat );
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
/* thought so... */
|
|
|
|
|
}
|
|
|
|
|
/* could use the select timeout here but it should not
|
|
|
|
|
be needed
|
|
|
|
|
*/
|
|
|
|
|
ClearErrors( index, &Stat );
|
|
|
|
|
wait = WaitForSingleObject( index->sol.hEvent, 100 );
|
|
|
|
|
switch ( wait )
|
|
|
|
|
{
|
|
|
|
|
case WAIT_OBJECT_0:
|
|
|
|
|
goto end;
|
|
|
|
|
case WAIT_TIMEOUT:
|
|
|
|
|
goto timeout;
|
|
|
|
|
case WAIT_ABANDONED:
|
|
|
|
|
default:
|
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
end:
|
|
|
|
|
/* You may want to chop this out for lower latency */
|
2003-10-17 22:53:54 +00:00
|
|
|
|
usleep(1000);
|
2003-08-15 01:15:45 +00:00
|
|
|
|
LEAVE( "serial_select" );
|
|
|
|
|
return( 1 );
|
|
|
|
|
timeout:
|
|
|
|
|
LEAVE( "serial_select" );
|
|
|
|
|
return( 0 );
|
|
|
|
|
fail:
|
|
|
|
|
YACK();
|
|
|
|
|
sprintf( message, "< select called error %i\n", n );
|
|
|
|
|
report( message );
|
|
|
|
|
errno = EBADFD;
|
|
|
|
|
LEAVE( "serial_select" );
|
|
|
|
|
return( 1 );
|
|
|
|
|
}
|
|
|
|
|
#ifdef asdf
|
|
|
|
|
int win32_serial_select( int n, fd_set *readfds, fd_set *writefds,
|
|
|
|
|
fd_set *exceptfds, struct timeval *timeout )
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
unsigned long nBytes, dwCommEvent, wait = WAIT_TIMEOUT;
|
|
|
|
|
int fd = n-1;
|
|
|
|
|
struct termios_list *index;
|
|
|
|
|
char message[80];
|
|
|
|
|
|
|
|
|
|
ENTER( "serial_select" );
|
|
|
|
|
if ( fd <= 0 )
|
|
|
|
|
{
|
|
|
|
|
usleep(1000);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
index = find_port( fd );
|
|
|
|
|
if ( !index )
|
|
|
|
|
{
|
|
|
|
|
LEAVE( "serial_select" );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if( index->interrupt == 1 )
|
|
|
|
|
{
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
while(!index->event_flag )
|
|
|
|
|
{
|
|
|
|
|
usleep(1000);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while ( wait == WAIT_TIMEOUT && index->sol.hEvent )
|
|
|
|
|
{
|
|
|
|
|
if( index->interrupt == 1 )
|
|
|
|
|
{
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
if( !index->sol.hEvent )
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if ( !WaitCommEvent( index->hComm, &dwCommEvent,
|
|
|
|
|
&index->sol ) )
|
|
|
|
|
{
|
|
|
|
|
/* WaitCommEvent failed */
|
|
|
|
|
if( index->interrupt == 1 )
|
|
|
|
|
{
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
if ( GetLastError() != ERROR_IO_PENDING )
|
|
|
|
|
{
|
|
|
|
|
sprintf( message, "WaitCommEvent filename = %s\n", index->filename);
|
|
|
|
|
report( message );
|
|
|
|
|
return(1);
|
|
|
|
|
/*
|
|
|
|
|
goto fail;
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
if( index->interrupt == 1 )
|
|
|
|
|
{
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
wait = WaitForSingleObject( index->sol.hEvent, 1000 );
|
|
|
|
|
switch ( wait )
|
|
|
|
|
{
|
|
|
|
|
case WAIT_OBJECT_0:
|
|
|
|
|
if( index->interrupt == 1 )
|
|
|
|
|
{
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
if( !index->sol.hEvent ) return(1);
|
|
|
|
|
if (!GetOverlappedResult( index->hComm,
|
|
|
|
|
&index->sol, &nBytes, TRUE ))
|
|
|
|
|
{
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
else if( index->tx_happened == 1 )
|
|
|
|
|
{
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
goto end;
|
|
|
|
|
break;
|
|
|
|
|
case WAIT_TIMEOUT:
|
|
|
|
|
default:
|
|
|
|
|
return(1); /* WaitFor error */
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
end:
|
|
|
|
|
/*
|
|
|
|
|
usleep(1000);
|
|
|
|
|
*/
|
|
|
|
|
LEAVE( "serial_select" );
|
|
|
|
|
return( 1 );
|
|
|
|
|
#ifdef asdf
|
|
|
|
|
/* FIXME this needs to be cleaned up... */
|
|
|
|
|
fail:
|
|
|
|
|
sprintf( message, "< select called error %i\n", n );
|
|
|
|
|
YACK();
|
|
|
|
|
report( message );
|
|
|
|
|
set_errno( EBADFD );
|
|
|
|
|
LEAVE( "serial_select" );
|
|
|
|
|
return( 1 );
|
|
|
|
|
#endif /* asdf */
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endif /* asdf */
|
|
|
|
|
#endif /* __LCC__ */
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
termiosSetParityError()
|
|
|
|
|
|
|
|
|
|
accept: fd The device opened
|
|
|
|
|
perform: Get the Parity Error Char
|
|
|
|
|
return: the Parity Error Char
|
|
|
|
|
exceptions: none
|
|
|
|
|
win32api: GetCommState()
|
|
|
|
|
comments: No idea how to do this in Unix (handle in read?)
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
int termiosGetParityErrorChar( int fd )
|
|
|
|
|
{
|
|
|
|
|
struct termios_list *index;
|
|
|
|
|
DCB dcb;
|
|
|
|
|
|
|
|
|
|
ENTER( "termiosGetParityErrorChar" );
|
|
|
|
|
index = find_port( fd );
|
|
|
|
|
if( !index )
|
|
|
|
|
{
|
|
|
|
|
LEAVE( "termiosGetParityErrorChar" );
|
|
|
|
|
return(-1);
|
|
|
|
|
}
|
|
|
|
|
GetCommState( index->hComm, &dcb );
|
|
|
|
|
LEAVE( "termiosGetParityErrorChar" );
|
|
|
|
|
return( dcb.ErrorChar );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
termiosSetParityError()
|
|
|
|
|
|
|
|
|
|
accept: fd The device opened, value the new Parity Error Char
|
|
|
|
|
perform: Set the Parity Error Char
|
|
|
|
|
return: void
|
|
|
|
|
exceptions: none
|
|
|
|
|
win32api: GetCommState(), SetCommState()
|
|
|
|
|
comments: No idea how to do this in Unix (handle in read?)
|
|
|
|
|
----------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
void termiosSetParityError( int fd, char value )
|
|
|
|
|
{
|
|
|
|
|
DCB dcb;
|
|
|
|
|
struct termios_list *index;
|
|
|
|
|
|
|
|
|
|
ENTER( "termiosGetParityErrorChar" );
|
|
|
|
|
index = find_port( fd );
|
|
|
|
|
if ( !index )
|
|
|
|
|
{
|
|
|
|
|
LEAVE( "termiosSetParityError" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
GetCommState( index->hComm, &dcb );
|
|
|
|
|
dcb.ErrorChar = value;
|
|
|
|
|
SetCommState( index->hComm, &dcb );
|
|
|
|
|
LEAVE( "termiosGetParityErrorChar" );
|
|
|
|
|
}
|
|
|
|
|
/*----------------------- END OF LIBRARY -----------------*/
|
|
|
|
|
|
|
|
|
|
#endif /* WIN32 */
|