Re: Serial device open(2) hang.
Re: Serial device open(2) hang.
- Subject: Re: Serial device open(2) hang.
- From: David Elliott <email@hidden>
- Date: Sun, 28 Jun 2009 00:14:11 -0400
Hi Steve,
On Jun 27, 2009, at 8:55 PM, Steve Checkoway wrote:
I have a Keyspan USA-49WLC USB to 4 serial ports adapter which, when
plugged in, correctly shows 4 /dev/tty.USA* and 4 /dev/cu.USA*
devices. I'm trying to talk to a microcontroller on the other end of
the serial, reading and writing data, so the first step I'm taking
is to open(2) the appropriate tty. As far as I can tell, this is
hanging until I unplug the USB cable. Once I unplug it, it returns
-1.
Change your open call to O_RDWR | O_NONBLOCK. This will cause open
not to block thus allowing you to get a working file descriptor and
keeping a handle open to the device (this is important).
Once you have that you need to run stty against it or I suppose you
can use termios functions but honestly I am not all that familiar with
serial programming, I just happened to be doing it the other week on
another project.
What I came up with was this:
void stty_serial(int ser)
{
pid_t pid = fork();
if(pid < 0)
{
fprintf(stderr, "Couldn't fork to exec stty\n");
return;
}
else if(pid > 0)
{
// parent.. wait for child
int stat_loc;
waitpid(pid, &stat_loc, 0);
return;
}
// child
if(dup2(ser, STDIN_FILENO) != 0)
{
fprintf(stderr,"Shit\n");
_exit(1);
}
// Make sure (now duped) stdin; stdout; and stderr stay open
across exec
fcntl(STDIN_FILENO, F_SETFD, 0);
fcntl(STDOUT_FILENO, F_SETFD, 0);
fcntl(STDERR_FILENO, F_SETFD, 0);
execlp("/bin/stty", "/bin/stty", "115200", "raw", "clocal",
"crtscts", NULL);
// NOTREACHED (or at least.. shouldn't be)
fprintf(stderr, "Failed exec\n");
_exit(1);
for(;;)
;
}
The argument to the function is the fd returned from open. The stty
setting you need more than anything is the clocal setting which causes
it to ignore the modem control signals (DSR/DTR I think). Without
that, open blocks. Once I have run this function I use fcntl(ser,
F_SETFL, fcntl(ser, F_GETFL) & ~O_NONBLOCK); to put the fd back into
blocking mode.
I got most of my clues here from the manpage for stty. What isn't
mentioned though is that you can't just run stty and then run your
program because once the last open file descriptor to a port is
closed, everything resets to the defaults, e.g. 9600 baud, -clocal,
etc. So it seems to me that stty can never really be run effectively
except in the case as above where it's run on an already open file
descriptor dup2'd into the child process.
An alternative might be to open with O_NONBLOCK then you could
probably get away with system("stty -f /dev/tty.wtf 115200 raw clocal
crtscts") to set your params. But I figured that fork/dup2/exec was
probably a better way to go about it.
Hope that helps. And maybe someone else with more serial programming
experience could chime in. But this worked for me.
This same code, when run on Linux using /dev/ttyS0, works as I
would expect: It prints "Opening a file" and then "Opened!".
Is this a problem with the Keyspan driver or (as is more likely) am
I doing something wrong?
I believe it's a behavioral difference between Linux and BSD.
Oh, one other little gotcha before you run into it as I did. The poll
system call on OS X does not support tty devices. So use select
instead. I had recalled back in the day that poll was not supported
at all on OS X (except through a bit of code that translated it into
select). But I did not realize, and did not notice the warning in the
BUGS section of its manpage, that when Apple finally did implement
poll they did not allow it to support devices, only network sockets.
-Dave
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden