I'm currently trying to communicate with an external device using the serial port, and it works just fine... if the device is connected. However, since there is no guarantee that it is (and i have multiple serial ports to choose from), it would be ideal if i could use the VMIN=0 / VTIME>0 timed read to probe the ports (and generally prevent my application from blocking indefinitely, in case the device is detached during operation).
Here is my code to open a serial port, and set it to noncanonical mode. But even though i set VTIME to 5 (which should be half a second) and VMIN to 0 (so that the timeout starts immediately), read() just blocks indefinitely if no device is attached.
int32_t OpenDevice(char* device)
{
if (access(device, R_OK | W_OK))
{
LOG(Log_Error, "%s() access(): %s", __func__, strerror(errno));
goto ERR_ACCESS;
}
int32_t fd = open(device, O_RDWR | O_NOCTTY);
if (fd == -1)
{
LOG(Log_Error, "%s() open(): %s", __func__, strerror(errno));
goto ERR_OPEN;
}
struct termios tios;
if (tcgetattr(fd, &tios))
{
LOG(Log_Error, "%s() tcgetattr(): %s", __func__, strerror(errno));
goto ERR_GETATTR;
}
cfmakeraw(&tios);
if (cfsetspeed(&tios, B115200))
{
LOG(Log_Error, "%s() cfsetspeed(): %s", __func__, strerror(errno));
goto ERR_SETSPEED;
}
tios.c_cflag |= CLOCAL | CREAD;
tios.c_cflag &= ~CRTSCTS;
tios.c_cc[VMIN] = 0;
tios.c_cc[VTIME] = 5;
if (tcsetattr(fd, TCSANOW, &tios))
{
LOG(Log_Error, "%s() tcsetattr(): %s", __func__, strerror(errno));
goto ERR_SETATTR;
}
struct termios tios_new;
tcgetattr(fd, &tios_new);
if (memcmp(&tios_new, &tios, sizeof(tios)))
{
LOG(Log_Error, "%s() failed to set attributes", __func__);
goto ERR_SETATTR;
}
return fd;
ERR_SETATTR:
ERR_SETSPEED:
ERR_GETATTR:
close(fd);
ERR_OPEN:
ERR_ACCESS:
return -1;
}
I don't know if it matters, but my application is not running on a PC, but on a Cyclone V SoC (from Altera/Intel) with a Cortex-A9 dual core CPU. The driver used is CONFIG_SERIAL_ALTERA_UART, which creates several /dev/ttyAL devices. The OS itself is a version from Altera's git repository, with the PREEMPT_RT patchset already included (rel_socfpga-4.1.22-ltsi-rt_16.10.02_pr).
PS: I know i could just use select() and call it a day, but i would prefer to keep my code simple instead of adding a bunch of overhead just to get that timeout.
Thanks in advance for any advice on this problem.