Ron Eggler <
ronDOT...@tscheemail.com> writes:
>Scott Lurndal wrote:
>
>>>FD_ZERO(&rdfs);
>>>FD_SET(0, &rdfs);
>>
>> Try FD_SET(fd, &rdfs) instead.
>
>HI Scott,
>Yep, that was it! Thanks! That made it work! However, my select always
>returns 1 (even if I wait second only but there's a whole bunch of more
>Bytes coming back from my device...
Select returns the number of file descriptors which have had read/write
events triggered, not the number of bytes ready to read (man select(2)).
You must either read one byte and return to the select, or read multiple
bytes on a file descriptor set to non-blocking (man open(2)) and return
to the select. In either case, message boundary detection is your responsibility.
There is no standard API to determine how many bytes are pending to be
read. Some implementations support a non-standard PEEK ioctl(2) that
can be used, but the traditional approach is to use non-blocking file
descriptors with select (or I prefer poll(2)).
scott
This is parts of the serial port receive thread from an application I wrote, I
left out the code to detect end of message since that is protocol specific
(likely to be a CRLF pair for a weather station) and the protocol I use
with this code is decidedly non-standard (from an old mainframe).
int s_fd;
ssize_t diag;
char recvbuf[2048];
char *rbp = recvbuf;
size_t received = 0ul;
pollfd fdlist[2];
int timeout = -1;
s_fd = ::open(s_devname, O_RDWR|O_NOCTTY|O_NONBLOCK, 0);
if (s_fd == -1) {
lp->log("%s Unable to open serial device '%s': %s\n",
s_logstr, s_devname, strerror(errno));
goto leave;
}
if (!::isatty(s_fd)) {
lp->log("%s '%s' is not a serial device\n",
s_logstr, s_devname);
goto leave;
}
diag = ::tcgetattr(s_fd, &s_term_attr_orig);
if (diag == -1) {
lp->log("%s Unable to get terminal attributes: %s\n",
s_logstr, strerror(errno));
goto leave;
}
cfmakeraw(&s_term_attr);
cfsetispeed(&s_term_attr, termios_baud);
cfsetospeed(&s_term_attr, termios_baud);
s_term_attr.c_lflag = 0;
diag = ::tcsetattr(s_fd, TCSANOW, &s_term_attr);
if (diag == -1) {
lp->log("%s Unable to set terminal attributes: %s\n",
s_logstr, strerror(errno));
goto leave;
}
memset(fdlist, 0, sizeof(fdlist));
fdlist[0].fd = s_fd;
fdlist[0].events = POLLIN|POLLERR|POLLHUP;
fdlist[1].fd = s_cmd_pipe[0];
fdlist[1].events = POLLIN|POLLERR|POLLHUP;
while (!s_terminate) {
lock_thread();
if (s_send_queue.is_empty()) {
fdlist[0].events &= ~POLLOUT;
} else {
fdlist[0].events |= POLLOUT;
}
unlock_thread();
fdlist[0].revents = fdlist[1].revents = 0;
diag = ::poll(fdlist, 2, timeout);
if (diag == -1) {
if (errno == EINTR) continue;
s_logger->log("%s RS232 poll failed on device '%s': %s\n",
s_logstr, s_devname, strerror(errno));
s_terminate = true;
continue;
}
if (diag == 0) {
s_logger->log("%s timeout detected on poll\n", s_logstr);
continue;
}
if (fdlist[0].revents & POLLOUT) {
/*
* The serial port is ready for output. Send the next
* pending message.
*/
lock_thread();
c_dlist_iterator di(&s_send_queue);
while (di.next()) {
s_msg *mp = (s_msg *)di.curr();
mp->remove();
send_message(mp, false, NULL);
break;
}
unlock_thread();
}
if ((fdlist[0].revents & (POLLIN|POLLHUP)) == 0) continue;
diag = ::read(s_fd, rbp, sizeof(recvbuf) - received);
if (diag == -1) {
s_logger->log("%s Unable to read from RS232 device '%s': %s\n",
s_logstr, s_devname, strerror(errno));
continue;
}
if (complete message received) { /// ADD YOUR CODE HERE TO DETERMINE END OF MESSAGE
get_transport()->receive_callback(this, (uint8 *)recvbuf, received);
} else {
// skip past bytes already received and go back and poll for more
rbp += diag, received += diag;
}
}