site_archiver@lists.apple.com Delivered-To: darwin-dev@lists.apple.com Hi Steve, On Jun 28, 2009, at 2:03 PM, Steve Checkoway wrote: On Jun 27, 2009, at 9:14 PM, David Elliott wrote: The file that the code snippet comes from can be found in SVN here: http://tgwbd.org/svn/Darwin/SerialKDPProxy/trunk/src/SerialKDPProxy.c Probably of no interest to you but there you have it. #include <stdio.h> #include <stdlib.h> #include <termios.h> #include <fcntl.h> int main(int ac, char *av[]) { int fd; int flags; struct termios termios; if (ac != 2) { fprintf(stderr, "usage: ser <devicename>\n"); exit(2); } /* Open with non-blocking I/O because we are using the wrong device */ if ((fd = open(av[1], O_RDWR | O_NDELAY)) == -1) { perror("open"); exit(1); } /* get the current settings */ if (tcgetattr(fd, &termios) == -1) { perror("tcgetattr"); exit(1); } /* tell it to ignore modem control signals */ termios.c_cflag |= CLOCAL; /* Set the input/output speed */ /* NOTE: B115200 not available in a strict POSIX environment */ if (cfsetispeed(&termios, B115200) == -1) { perror("cfsetispeed"); exit(1); } if (cfsetospeed(&termios, B115200) == -1) { perror("cfsetispeed"); exit(1); } if (tcsetattr(fd, TCSANOW, &termios) == -1) { perror("tcgetattr"); exit(1); } /* Turn blocking I/O back on */ if ((flags = fcntl(fd, F_GETFL)) == -1) { perror("tcgetattr"); exit(1); } flags &= ~O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) == -1) { perror("tcgetattr"); exit(1); } printf("Do the rest of your stuff here...\n"); exit(0); } -- Terry _______________________________________________ Do not post admin requests to the list. They will be ignored. Darwin-dev mailing list (Darwin-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/darwin-dev/site_archiver%40lists.appl... On Jun 28, 2009, at 2:22 PM, David Elliott wrote: 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: This worked perfectly! I now have my computer talking to itself via a null modem cable with both ends plugged into the usb to serial adapter. Time to see if I can talk to this microcontroller. Glad to hear it. If you look over on darwin-kernel I've just posted a message about SerialKDPProxy which is where that code comes from. That is the project I referred to that I happened to be working on the other week. And Kevin (kvv) is right. I could have and probably should have used posix_spawn rather than fork/dup2/exec except I completely forgot that it existed in relatively modern POSIX. -Dave There are two types of serial devices; those that have modem-control, and those that don't. Your open is hanging because you are opening a modem-control device, but you are doing it without a real null-modem cable. A real null- modem cable would be holding DCD and RTS high, so the open would complete because it believed that carrier was present and hardware flow control, if enabled, was actively soliciting output (this is the crtscts you're enabling, probably unnecessarily, unless the device on the other end needs it). You can either elect to open the other (non-modem control) device, or you can use O_NONBLOCK. If you use the O_NONBLOCK, on the modem control device, you should set the CLOCAL flag to indicate that it's a local connection (this is the same as using the non-modem control device). Since O_NONBLOCK also sets non-blocking I/O, after setting the CLOCAL flag, you're going to want to use fcntl() to clear non- blocking I/O, or you will have to be careful to internally buffer the data yourself. Generally, it's usually easier to just treat everything as a modem- control device, just in case the vendor messed up the non-modem- control driver. You also really don't want to use the fork/exec or spawn of an stty approach, since not all serial devices support non-exclusive opens, and the stty as a child process gets its descriptor from the parent process, and if it's an exclusive open, it can fail based on what the device driver implements under the covers. For example, there have historically been RS-422 cards that fanned out to multiple serial ports on a daughter box, and supported only a single unidirectional I/ O channel; you read, or you write, but you don't both read and write at the same time. Similarly, if you were on a SVR3 system, then you would need to deal with the partial open hack, since getty attempts to open the device exclusively, and if you are switching off, you have to force the O_EXCL flag off by doing a blocking open and alarming out of it followed by a non-blocking open. For SVR4 / Solaris streams-based serial devices, you also have to pop of the canonical processing module, which is pushed on to the tty by the kernel. Also, you will want to make sure that if your program is multithreaded that it correctly uses pthread_kill() to interrupt outstanding operations on the other threads before you close the device, since BSD- based systems don't do a drain-wait and won't interrupt the outstanding blocking read/write call merely because you're closing the descriptor out from under them. Yeah, that means you have to record outstanding reads and writes and the threads involved in your own session structure and resource-track them yourself. This is basically becauses you can't do an arbitrary wakeup, since there are multiple addresses that the underlying driver might be sleeping on, and you won't know which one is the right one, based on whether you're in a mutext in the line discipline, the termios processing, a separate "other" line discipline, or an IOWorkloop or a mutex in the subclass of the IOSerialFamily. For Mac OS X, and other UNIX conformant systems, it's basically something like: This email sent to site_archiver@lists.apple.com