sws@holin.ATT.COM (Steve Spear) (02/09/90)
I've been trying to write a simple single character I/O routine for Xenix serial ports to port a FIDO-net bbs package to Xenix. Unfortunately I've only been sucessfull with writing out the port - I never see anything come back. I open the modem line with open( "/dev/tty1A", O_RDWR | O_NDELAY ) and the handle comes back just fine. Then I set the line settings with IOCTL and do a write( handle, "ATZ\r", 4 ). I see the data go out the port on the data scope and the modem flashes and returns OK on the data scope, but when I do a read( handle, &ch, 1 ) I never get anything. Does someone have a small sample program I could look at to get this working? Also just out of curiosity what do the devices /dev/ttyp0 - /dev/ttyp7 do? Any help would be greatly appreciated.
karl@ddsw1.MCS.COM (Karl Denninger) (02/13/90)
In article <890@holin.ATT.COM> sws@holin.ATT.COM (Steve Spear) writes: >I've been trying to write a simple single character I/O routine for Xenix >serial ports to port a FIDO-net bbs package to Xenix. Unfortunately I've >only been sucessfull with writing out the port - I never see anything come >back. I open the modem line with open( "/dev/tty1A", O_RDWR | O_NDELAY ) >and the handle comes back just fine. Then I set the line settings with IOCTL >and do a write( handle, "ATZ\r", 4 ). I see the data go out the port on the >data scope and the modem flashes and returns OK on the data scope, but when >I do a read( handle, &ch, 1 ) I never get anything. Does someone have a small >sample program I could look at to get this working? > >Also just out of curiosity what do the devices /dev/ttyp0 - /dev/ttyp7 do? > >Any help would be greatly appreciated. Don't use "O_NDELAY" except to open the port initially. Then, turn it OFF with a fcntl() call (turn on CLOCAL with an ioctl() first). Now you can read/write to the port, and have it block correctly for input. Once you have a connection (ie: "CONNECT" from a modem), turn off CLOCAL with another ioctl so you can sense the carrier detect. A rough order of operations is: #include <fcntl.h> #include <termio.h> struct termio tbuf; int oldflag, x; x = open("/dev/tty1A", O_RDWR|O_NDELAY); /* It's a good idea to check */ /* and make sure you do open! */ ioctl(x, TCGETA, &tbuf); tbuf.c_cflag |= CLOCAL; ioctl(x, TCSETAW, &tbuf); /* Turn on CLOCAL, no carrier detect */ oldflag = fcntl(x, F_GETFL, 0); /* Disable NDELAY */ fcntl(x, F_SETFL, oldflag & ~O_NDELAY); ..... (read/write the port you just opened) Once you detect a carrier from the modem (ie: "CONNECT"), you do: ioctl(x, TCGETA, &tbuf); tbuf.c_cflag &= ~CLOCAL; /* Clear CLOCAL */ ioctl(x, TCSETAW, &tbuf); /* Now carrier is sensed */ ..... continue onward ..... This ensures that you will get a signal if the carrier drops (ie: the modem hangs up for no good reason). You MUST be sure you have a connection before you turn the CLOCAL off, else you'll get that signal immediately (which if not trapped terminates your process!) It's a good idea to do the clocal thing, although not strictly necessary -- if you don't mind the line hanging for a nice long time (until your program either times out or you find it hung :-). Do be aware that at least one "smart" board manufacturer (name deleted to protect the guilty) botches the handling of this particular sequence.... If you don't turn off O_NDELAY, you should effectively be "busy-waiting"; the reads will return zero unless there is a character in the buffer right >now<. Then, you should get the character. O_NDELAY means literally "no delay", and you get exactly that -- no waiting for the characters to enter the stream. Sometimes this is what you want. Most (95+%) of the time it is NOT what you want, as you effectively are busy-waiting (which is a very bad programming practice under a multitasking operating system!) -- Karl Denninger (karl@ddsw1.MCS.COM, <well-connected>!ddsw1!karl) Public Access Data Line: [+1 708 566-8911], Voice: [+1 708 566-8910] Macro Computer Solutions, Inc. "Quality Solutions at a Fair Price"