Hi Everyone,
I'm testing some software on DragonFly. There's not much to it. It
talks to the modem, and sends an ATZ and then reads the response.
Linux, FreeBSD, NetBSD, OpenBSD and OS X are OK.
My test rig is DragonFly 5.6-RELEASE x86_64 (fully patched) with a
USR5637 modem, https://www.amazon.com/gp/product/B0013FDLM0. The modem
is located at /dev/cuaU0.
DragonFly hangs on the call to tcdrain(3). Looking at the man page I
don't see any special handling. Cf.,
http://man.dragonflybsd.org/?command=tcdrain.
Attached is the reproducer. The trace is:
% ./test.exe
Setting TIOCEXCL
Getting tty
Setting tty options
Flushing tty
Setting tty
Writing ATZ
Waiting for write <<-- call to tcdrain(fd)
Thanks.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if defined(__linux__)
# define MODEM "/dev/ttyACM0"
#elif defined(__APPLE__)
# define MODEM "/dev/cu.usbmodem001"
#elif defined(__NetBSD__)
# define MODEM "/dev/dtyU0"
#elif defined(__bsdi__) || defined(__DragonFly__)
# define MODEM "/dev/cuaU0"
#endif
static void make_blocking(int fd)
{
const int old = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, old & ~(int)O_NONBLOCK);
}
static void make_nonblocking(int fd)
{
const int old = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, old | (int)O_NONBLOCK);
}
/* gcc -Wall -g3 -O1 -std=c99 test.c -o test.exe */
int main(int argc, char* argv[])
{
int fd = open(MODEM, O_RDWR | O_NOCTTY | O_SYNC);
if (fd == -1) {
printf("open failed\n");
goto finish;
}
printf("Setting TIOCEXCL\n");
/* Mark the fd as exclusive so ModemManager */
/* and friends cannot open and muck with state. */
if (ioctl(fd, TIOCEXCL, NULL) == -1) {
printf("ioctl failed\n");
goto finish;
}
printf("Getting tty\n");
struct termios tty;
if (tcgetattr(fd, &tty) != 0) {
printf("tcgetattr failed\n");
goto finish;
}
printf("Setting tty options\n");
cfmakeraw(&tty);
tty.c_cflag |= (CLOCAL | CRTSCTS);
// tty.c_cflag &= ~CSTOPB; /* 1 stop bit */
// tty.c_cflag |= CSTOPB; /* 2 stop bit */
cfsetospeed(&tty, B57600);
cfsetispeed(&tty, B57600);
printf("Flushing tty\n");
if (tcflush(fd, TCIOFLUSH) != 0) {
printf("tcflush failed\n");
goto finish;
}
printf("Setting tty\n");
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("tcsetattr failed\n");
goto finish;
}
/*** Write ***/
printf("Writing ATZ\n");
ssize_t res = write(fd, "ATZ\r", 4);
if (res == -1) {
printf("write failed\n");
goto finish;
}
printf("Waiting for write\n");
res = tcdrain(fd);
if (res == -1) {
printf("tcdrain failed\n");
goto finish;
}
printf("Wrote: ATZ\n");
/*** Read ***/
printf("Reading response\n");
make_blocking(fd);
for ( ; ; )
{
unsigned char buf[512];
res = read(fd, buf, sizeof(buf));
if (res == -1 && errno == EWOULDBLOCK) {
break;
}
else if (res == -1) {
printf("read failed\n");
goto finish;
}
make_nonblocking(fd);
buf[res] = '\0';
printf("Read: %s\n", buf);
}
finish:
if (fd != -1)
close(fd);
return 0;
}