I am trying to write and read data to a serial port file /dev/ttyUSB0, If the operation is unsuccessful for 5 sec I will move ahead. To implement this I chose using the select() system call. However, the exact case in which I am using it seems to not work as expected. Following code:
Simply, I need to check status from 8 devices. So I must write() first a query command. Then wait for a response from the device for timeout seconds.
This procedure should be done for all 8 devices connected on UART.
I am not sure if I must re initialize fdset for using select.
Result: First time select waits for 5 sec timeout. But after that it immediately shows "timeout" without waiting.
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 10;
for(i=0; i <= noOfDevicesDiscovered; i++)
{
if( i < 9 && i > 0)
{
uart_init();
printf("ID: %d\n", i);
address = ((i-1)<<1) | 0x01;
command = 0xA0;
fd_set set;
FD_ZERO(&set);
FD_SET(uart_fd, &set);
write(uart_fd, &address, 1);
write(uart_fd, &command, 1);
rv = select(uart_fd + 1, &set, NULL, NULL, &timeout);
if(rv == -1)
perror("select\n");
else if(rv == 0)
{
printf("timeout\n");
new.level = 0;
new.address = i;
fwrite(&new, sizeof(struct Light_Info), 1, fptr);
continue;
}
else
{
read( uart_fd, &level, 1 );
new.level = level;
}
new.address = i;
fwrite(&new, sizeof(struct Light_Info), 1, fptr);
close(uart_fd);
FD_ZERO(&set);
}
}
How can we solve this.
You need to reinitialise "timeout" after each call of select. From the select man page; "On Linux, select() modifies timeout to reflect the amount of time not slept". So in your case, after the first select call, your timeout values are all 0. Hence subsequent calls to select will timeout immediately.
Related
Is there a way to change the timeout on select() on an FD that's opened for a serial port on the fly? Like, in Thread1, it's set to NULL which means it's going to block until there's any data on the FD. Now, I'd want to change its behavior such that Thread2 sets a timeout on the select in Thread1 which timesout after a specified timeout.
Is it in any way feasible?
Assuming here Thread1 runs first so select() initially starts with no timeout and the timeout is then modified by Thread2 as it runs later (while Thread1 is still waiting on the select())...
int timeout = 5;
struct timeval timeSpec = {timeout, 0};
void *pTimeout = NULL;
void *Thread2(void *)
{
while(1)
{
pTimeout = &timeSpec; // have select() timeout in 5 seconds from now on...
}
}
void *Thread1(void *)
{
fd_set fdset;
while(1)
{
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
ret = select (fd + 1, &fdset, NULL, NULL, pTimeout);
if (ret < 0)
{
// error handling
}
else if (ret == 0)
{
// timeout -- error handling
}
else
{
if (FD_ISSET(fd, &fdset))
{
bytesRead = read(fd, buffer, bytesToRead); // blocking read call
if (ret < 0)
{
// error handling
}
}
}
}
}
I have developed a C program that receive can traffics from vcan0 interface.
I would like to add timeout on reception, I mean when a timeout expired (10 seconds for example) with no data received during this time, I print "no data received during 10 seconds" and I make a reboot of my pc(the reboot is made if a specific condition is satisfied).
I have tested with select function I get the timeout but when the specific condition is not satisfied I can't receive can traffics anymore.
should I add something for reactivate reception when I have timeout and specific condition is not satisfied? if yes how?
My program is like this:
...
while(1)
{
FD_ZERO(&set); /* clear the set */
FD_SET(filedesc, &set); /* add our file descriptor to the set */
timeout.tv_sec = 0;
timeout.tv_usec = 10000000; // 10 second
rv = select(fd_max + 1, &set, NULL, NULL, &timeout);
if(rv == -1)
perror("select"); /* an error accured */
else if(rv == 0)
{
printf("no data received within 10 second"); /* a timeout occured */
if (specific condition is true)
{
reboot(RB_AUTOBOOT);
}
}
else
int s;
/* loop on all sockets */
for(i=s;i<=fd_max;i++)
{
read( i, buff, len );
/* some other instruction*/
}
}
...
I have problem with a webcam. It can be a hardware one but i'm convinced it is no.
With all apps I can see the stream but suddenly it freezes.
Because of the following output from used app when the problem occurs:
v4l: timeout (got SIGALRM), hardware/driver problems?
I have checked out the code and the interesting part:
/* How many seconds to wait before deciding it's a driver problem. */
#define SYNC_TIMEOUT 3
int alarms;
void sigalarm(int signal)
{
alarms++;
}
.................................................................................
void wait_for_frame_v4l1( input_t *vidin, int frameid )
{
alarms = 0;
alarm(SYNC_TIMEOUT);
if (ioctl(vidin->fd, VIDIOCSYNC, vidin->buf + frameid) < 0 )
fprintf(stderr, "input: Can't wait for frame %d: %s\n", frameid, strerror(errno));
if (alarms)
fprintf(stderr, "v4l: timeout (got SIGALRM), hardware/driver problems?");
alarm(0);
}
From which I conclude that SYNC_TIMEOUT could be problem. The value is 3 secondes which seems to be quite enough.
My request is to help me chage code to don't block indefinitely waiting for frames:
If no frame arrives within 100 ms, then timeout and give the GUI the chance to update itself.
Not all devices can free wheel, so app should support such devices without blocking the GUI.
How can I do sub-second waiting?
v4l2 devices work very well with this:
/* How many milliseconds to wait before deciding it's a driver problem. */
#define SYNC_TIMEOUT_MSECS 100
int wait_for_frame_v4l2(input_t * vidin)
{
struct timeval timeout;
fd_set rdset;
int n;
FD_ZERO(&rdset);
FD_SET(vidin->fd, &rdset);
timeout.tv_sec = 0;
timeout.tv_usec = SYNC_TIMEOUT_MSECS * 1000;
n = select(vidin->fd + 1, &rdset, 0, 0, &timeout);
if(n == -1) {
fprintf(stderr, "input: Can't wait for frame: %s\n", strerror(errno));
} else if(n == 0) {
sigalarm(0);
return 1;
}
return 0;
}
but I have v4l1 device.
What (usb) webcam and kernel version are you using?
Update your driver/kernel
If it's an USB-Cam, try connecting without an USB-hub
The VIDIOCSYNC ioctl on vidin->fd suspends execution until vidin->buf has been filled. You can wait for a filled buffer to become available via select or poll
Hi I'm creating a proxyserver that wait for packets from client with an UDP connection and checks if all of them are effectively arrived or same of them have been rejected .
In that case I should send an "ack" to the clients for each lost packet (with send_ack() ) but just after have sent the first ack the "if part" of the select loops sending unlimited acks never going back to the "else part" were the select listen data from client (receive _pkt() function )
fd_set rset, allset;
int maxfd, nready;
struct timeval timeout;
timeout.tv_sec = 4;
timeout.tv_usec = 150000;
maxfd = socketfd;
FD_ZERO(&allset);
FD_SET(socketfd, &allset);
rset = allset;
for( i=0; ;i++){
do {
nready=select( (maxfd +1), &rset, NULL, NULL, &timeout);
} while ((nready<0) & (errno==EINTR));
if( nready<0) {
perror("Error main: select failed: ");
exit(32);
}
if( nready==0){
send_ack(socketfd,head);
}
else{
receive_pkt(socketfd, head);
}
}
Hope it's enough clear, thanks for the advices!
On some systems (Linux in particular), a select call modifies the timeout to show how much time is left. So in your case, if it waits 3 seconds for a packet, timeout will be reduced to 1.15 seconds, and after a total of 4.15 seconds, timeout will be 0, so later calls to select will immediately return with nready == 0.
If you want to wait again after sending an ack, you need to reset the timeout to non-zero.
One has to reset the fd_set rset before every call to select. The select call expects a bit set of field descriptors to monitor and overwrites with a bit set of field descriptors with notifications to read.
for( i=0; ;i++){
do {
rset = allset;
nready=select( (maxfd +1), &rset, NULL, NULL, &timeout);
} while ((nready<0) & (errno==EINTR));
I am reading/writing to a pipe created by pipe(pipe_fds). So basically with following code, I am reading from that pipe:
fp = fdopen(pipe_fds[0], "r");
And when ever I get something, I print it out by:
while (fgets(buf, 200, fp)) {
printf("%s", buf);
}
What I want is, when for certain amount of time nothing appears on the pipe to read from, I want to know about it and do:
printf("dummy");
Can this be achieved by select() ? Any pointers on how to do that will be great.
Let's say you wanted to wait 5 seconds and then if nothing was written to the pipe, you print out "dummy."
fd_set set;
struct timeval timeout;
/* Initialize the file descriptor set. */
FD_ZERO(&set);
FD_SET(pipe_fds[0], &set);
/* Initialize the timeout data structure. */
timeout.tv_sec = 5;
timeout.tv_usec = 0;
/* In the interest of brevity, I'm using the constant FD_SETSIZE, but a more
efficient implementation would use the highest fd + 1 instead. In your case
since you only have a single fd, you can replace FD_SETSIZE with
pipe_fds[0] + 1 thereby limiting the number of fds the system has to
iterate over. */
int ret = select(FD_SETSIZE, &set, NULL, NULL, &timeout);
// a return value of 0 means that the time expired
// without any acitivity on the file descriptor
if (ret == 0)
{
printf("dummy");
}
else if (ret < 0)
{
// error occurred
}
else
{
// there was activity on the file descripor
}
IIRC, select has a timeout that you then check with FD_ISSET to tell if it was I/O or not that returned.