Recalculate timeout after select() when reading from serial port?
Web Server forum
Back To The Forum Home!Search!Private Messaging System

Web Server Talk Web Server Talk > Unix and Linux reviews > Free Unix support > Unix Programming > Recalculate timeout after select() when reading from serial port?




  Last Thread   Next Thread Next
  Show Printable Version Email this Page Subscribe to this Thread      Post New Thread    Post A Reply      

    Recalculate timeout after select() when reading from serial port?  
Jef Driesen


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
09-07-07 12:24 PM

I'm writing an application that needs to communicate with a device
attached to a serial port. For reading data, I want to be able to
specify a total timeout value.

The code I'm using now (see below) assumes that select() modifies the
timeout structure to indicate the remaining time. This works on my linux
system, but according to the man pages, this is not portable. So I want
to recalculate the timeout myself. My first idea was to use the
gettimeofday() function. But that function does calculate the elapsed
real time, not the system time spend in the select call. This results in
a different behavior when the select call is interrupted by a signal
(which is detected as in the helper function myselect() below). Is there
a better way to recalculate the timeout?

int g_timeout = 1000O; // Timeout in milliseconds

int serial_read (int fd, void* buffer, unsigned int count)
{
// Initialize the file descriptor set.
fd_set fds;
FD_ZERO (&fds);
FD_SET (fd, &fds);

// Initialize the timeout.
struct timeval tv
tv.tv_sec  = (g_timeout / 1000);
tv.tv_usec = (g_timeout % 1000) * 1000;

int nbytes = 0;
while (nbytes < count) {
// See if there is data available.
int rc = select (fd + 1, &fds, NULL, NULL, &tv);
// TODO: Recalculate timeout here!
if (rc < 0) {
return -1; // Error during select call.
} else if (rc == 0)
break; // Timeout.

// Read the available data.
int n = read (fd, buffer + nbytes, count - nbytes);
if (n < 0) {
return -1; // Error during read call.
} else if (n == 0)
break; // EOF reached.

// Increase the number of bytes read.
nbytes += n;
}

// Return the number of bytes read.
return nbytes;
}

int myread (int fd, void* buffer, unsigned int count)
{
int rc = 0;
do {
rc = read (fd, buffer, count);
} while (rc < 0 && errno == EINTR)
return rc;
}

int myselect (int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout)
{
int rc = 0;
do {
rc = select (nfds, readfds, writefds, exceptfds, timeout);
// TODO: Recalculate timeout here!
} while (rc < 0 && errno == EINTR)
return rc;
}





[ Post a follow-up to this message ]



    Re: Recalculate timeout after select() when reading from serial port?  
Alex Fraser


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
09-08-07 12:36 AM

"Jef Driesen" <jefdriesen@hotmail.com.invalid> wrote in message
news:fbr7lf$r2o$1@ikaria.belnet.be...
> I'm writing an application that needs to communicate with a device
> attached to a serial port. For reading data, I want to be able to specify
> a total timeout value.
>
> The code I'm using now (see below) assumes that select() modifies the
> timeout structure to indicate the remaining time. This works on my linux
> system, but according to the man pages, this is not portable.

If you're not multiplexing multiple descriptors, the simplest solution is to
use alarm() and a blocking read(). The SIGALRM handler need only set a flag,
which you can test if read() indicates EINTR.

> So I want to recalculate the timeout myself. My first idea was to use the
> gettimeofday() function. But that function does calculate the elapsed real
> time, not the system time spend in the select call. This results in a
> different behavior when the select call is interrupted by a signal (which
> is detected as in the helper function myselect() below).

Using gettimeofday() should generally work fine (I write "generally" because
the time it returns is not necessarily monotonic). How did you try to use
it? You should call gettimeofday() once and compute when you should timeout
(expiry = now + timeout), then call it just before each call to select() and
compute the remaining time (select_timeout = expiry - now).

> Is there a better way to recalculate the timeout?

I did once wonder about using setitimer()/getitimer() to make a
high-resolution, monotonic counter (because monotonicity is usually
desirable for timeouts), but the principle is no different to using
gettimeofday().

Alex







[ Post a follow-up to this message ]



    Re: Recalculate timeout after select() when reading from serial port?  
Chris Friesen


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
09-08-07 12:36 AM

Alex Fraser wrote:

> Using gettimeofday() should generally work fine (I write "generally" becau
se
> the time it returns is not necessarily monotonic).

clock_gettime() can be used to get a monotonic timestamp.

Chris





[ Post a follow-up to this message ]



    Re: Recalculate timeout after select() when reading from serial port?  
Alex Fraser


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
09-08-07 12:36 AM

"Chris Friesen" <cbf123@mail.usask.ca> wrote in message
news:46E1A63B.8020403@mail.usask.ca...
> Alex Fraser wrote: 
>
> clock_gettime() can be used to get a monotonic timestamp.

I was under the impression that CLOCK_MONOTONIC is not widely supported,
while the alternative I considered (interval timers) was reasonably well
supported.

I would be very interested to hear if this is wrong.

Alex







[ Post a follow-up to this message ]



    Re: Recalculate timeout after select() when reading from serial port?  
Jef Driesen


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
09-10-07 12:17 PM

Alex Fraser wrote:
> "Jef Driesen" <jefdriesen@hotmail.com.invalid> wrote in message
> news:fbr7lf$r2o$1@ikaria.belnet.be... 
>
> If you're not multiplexing multiple descriptors, the simplest solution is 
to
> use alarm() and a blocking read(). The SIGALRM handler need only set a fla
g,
> which you can test if read() indicates EINTR.

As far as I know, a blocking read from a serial port is quite difficult
to do. I have no idea how to change the settings c_cc[VMIN] and
c_cc[VTIME] of the termios structure to do that. The termios structure
is also not very flexible to implement timeouts, and that's why I used
select().

Note: My application needs to run on windows too, and for that reason
I'm writing a tiny wrapper library for the serial communication, hiding
the platform specific stuff. For a consistent result on all platforms,
the behavior of the timeouts should be as close as possible to the win32
COMMTIMEOUTS [1].

[1] http://msdn2.microsoft.com/en-US/library/aa363190.aspx
 
>
> Using gettimeofday() should generally work fine (I write "generally" becau
se
> the time it returns is not necessarily monotonic). How did you try to use
> it? You should call gettimeofday() once and compute when you should timeou
t
> (expiry = now + timeout), then call it just before each call to select() a
nd
> compute the remaining time (select_timeout = expiry - now).

I implemented it almost exactly as you wrote it, with the exception that
I calculate the remaining time *after* the select call.
 
>
> I did once wonder about using setitimer()/getitimer() to make a
> high-resolution, monotonic counter (because monotonicity is usually
> desirable for timeouts), but the principle is no different to using
> gettimeofday().





[ Post a follow-up to this message ]



    Sponsored Links  




 





   All times are GMT. The time now is 04:22 AM.      Post New Thread    Post A Reply      
  Last Thread   Next Thread Next


Most Popular forums 

Forum Jump:
Rate This Thread:

Forum Rules:
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is OFF
vB code is ON
Smilies are ON
[IMG] code is OFF
 
Medical and Health forum | Computer Games Reviews | Graphics design forum

Back To The Top
Home | Usercp | Faq | Register