Serial I/O null read problem?
Steve Spear
sws at holin.ATT.COM
Fri Mar 9 04:00:25 AEST 1990
Can someone please explain to me why the code below can read every character
except NULL from a terminal or serial port? I'm primarily using this on Xenix
but it failed on Unix also. I'm using it for an Xmodem receiver and it drops
any block with a NULL ( ascii 0 ) in it. Since the last xmodem block is full
of zeros for padding the last block always fails. Somehow it only gets half the
nulls in the block and then times out. This is the simplest case I have for
the problem - please excuse the sloppy code - just hacking it up to get an idea
of whats going on. I've been porting a multiuser bbs from dos to Xenix and
everything seems to be working but receiving NULL's - argh!!! I've read all I
can in the Xenix and Unix manuals and no mention of a problem with NULL -
thanks
steve spear
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <memory.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
#include <malloc.h>
#include <time.h>
#include <signal.h>
#include <errno.h>
static char *portname = "/dev/tty";
static int termfd;
static struct termio tio, oldtio;
typedef int bool;
#define TRUE 1
#define FALSE 0
#define XENIX TRUE
static struct termio tiosave;
void setblock( int fd, bool on )
{
static int blockf, nonblockf;
static bool first = TRUE;
int flags;
if ( first )
{
first = FALSE;
if ( ( flags = fcntl( fd, F_GETFL, 0 ) ) == -1 )
printf( "setblock error" );
blockf = flags & O_NDELAY;
nonblockf = flags | O_NDELAY;
}
( void ) fcntl( fd, F_SETFL, on ? blockf : nonblockf );
}
static int readcond( int fd, char *buf, unsigned nbytes, bool block )
{
int retval;
#ifdef XENIX
if ( !block && rdchk( fd ) == 0 )
return( 0 );
#else
setblock( fd, block );
#endif
retval = read( fd, buf, nbytes );
return( retval );
}
#define EMPTY '\0'
static char cbuf = EMPTY;
bool cready()
{
if ( cbuf != EMPTY )
return( TRUE );
switch( readcond( termfd, &cbuf, 1, FALSE ) )
{
case -1 :
printf( "read error" );
break;
case 0 :
return( FALSE );
default :
return( TRUE );
}
}
int cget()
{
int retval;
char c;
if ( cbuf != EMPTY )
{
c = cbuf;
cbuf = EMPTY;
return( c & 0377 );
}
retval = readcond( termfd, &c, 1, TRUE );
switch( retval )
{
case -1 :
printf( "read 2 error" );
case 0 :
return( -1 );
default :
return( c & 0377 );
}
}
void termopen( void )
{
int fd2;
termfd = open( portname, O_RDWR | O_NDELAY );
if ( termfd != -1 )
{
ioctl( termfd, TCGETA, &oldtio ); /* get orig modem settings*/
ioctl( termfd, TCGETA, &tio ); /* get orig modem settings*/
tio.c_lflag &= ~(ISIG|ICANON|ECHO);
tio.c_iflag |= (BRKINT|IGNPAR);
tio.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF
|INPCK|ISTRIP);
tio.c_oflag &= ~OPOST;
tio.c_cc[ VMIN ] = 1;
tio.c_cc[ VTIME ] = 10;
ioctl( termfd, TCSETAW, &tio ); /* set the new settings */
}
fd2 = open( portname, O_RDWR );
close( termfd );
termfd = fd2;
}
void termclose( void )
{
unsetraw();
}
void main()
{
int k;
termopen();
while ( TRUE )
{
k = cget();
if ( k == 'q' )
break;
printf( "%c", k );
if ( !cready() )
printf( "\r\n" );
}
termclose();
}
More information about the Comp.unix.xenix
mailing list