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;
}

Reply via email to