On Sun, Nov 24, 2019 at 10:10 PM Philip Guenther <[email protected]> wrote:
>
> On Sun, Nov 24, 2019 at 3:11 AM Jeffrey Walton <[email protected]> wrote:
>>
>> I am struggling to get a USB modem and terminal configured properly
>> under OpenBSD. The same code on Linux is fine. The symptom I am seeing
>> is a hung read() after issuing ATZ\r to the modem.
>>
>> I'm guessing there's an uninitialized field in my struct termios tty.
>
> I'm not sure what you mean by that. Do you mean you're concerned that you're
> you making a tcsetattr(3) call on an incompletely initialized structure? Or
> do you mean you're concerned that the initial configuration of the tty
> provided by the kernel is in a "not good" state?
I think cfmakeraw is not initializing the structure properly. It is an
intermittent failure.
Attached is a reproducer. Valgrind lights up like a christmas tree on
the reproducer. The results are so bad I am pretty sure the problem is
with Valgrind, not the reproducer.
Jeff
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#if defined(__linux__)
# define MODEM "/dev/ttyACM0"
#elif defined(__APPLE__)
# define MODEM "/dev/cu.usbmodem0000001"
#elif defined(__OpenBSD__)
# 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;
}
if (ioctl(fd, TIOCEXCL, NULL) == -1) {
printf("ioctl failed\n");
goto finish;
}
struct termios tty;
memset(&tty, 0, sizeof(tty));
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);
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("tcsetattr failed\n");
goto finish;
}
if (tcflush(fd, TCIOFLUSH) != 0) {
printf("tcflush failed\n");
goto finish;
}
/*********** Write ***********/
ssize_t res = write(fd, "ATZ\r", 4);
if (res == -1) {
printf("write failed\n");
goto finish;
}
res = tcdrain(fd);
if (res == -1) {
printf("tcdrain failed\n");
goto finish;
}
printf("Wrote: ATZ\n");
/*********** Read ***********/
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;
}