Bytes are not sent to the serial driver buffer - c

I have this program:
// C headers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
// POSIX headers
#include <unistd.h>
#include <sys/ioctl.h>
// Other headers
#include "ZL_sleep.h"
#include "ZL_utf8.h"
#include "ZL_serial.h"
#define BS 4 // Buffer size
int main(int argc, char * argv[]){
int32_t p; // Port
int32_t r; // Read finished
uint8_t b[BS]; // Buffer
uint32_t n; // Number of bytes to be read from driver buffer
if(argc != 2){
printf("ERROR: Supply a \"serial port\" device file.");
exit(EXIT_FAILURE);
}
p = ZL_open_tty(argv[1]);
if(p < 0){
perror("ERROR: open()");
exit(EXIT_FAILURE);
}
while(1){
memset(b, '\0', BS);
r = read(p, b, BS);
if(r < 0){
if(errno == EAGAIN){
}
else{
perror("ERROR: read()");
close(p);
exit(EXIT_FAILURE);
}
}
ZL_utf8_print_bytes(b, BS);
putchar('\n');
}
close(p);
return EXIT_SUCCESS;
}
that uses function ZL_utf8_print_bytes() that prints the buffer bytes (one by one in a for loop). It also calls function ZL_open_tty() and passes the argv[1] (/dev/pts/1) to it as an argument.
Function ZL_open_tty() function sets O_NONBLOCK flag with open() in order for open() to return immediately i.e. "nonblocking" with whatever status. Then before any other I/O function is used, function clears O_NONBLOCK flag and switches back to "blocking". It then sets VMIN and VTIME so that read():
blocks until VMIN or more bytes is received/exists in driver
buffer. (It may block indefinitely)
uint32_t ZL_open_tty(const char * terminal){
uint32_t fd; // File's descriptor
uint32_t fl; // File's flags
struct termios fo; // File's options
fd = open(terminal, O_RDWR | O_NOCTTY | O_NONBLOCK);
if(fd < 0){
return -1;
}
fl = fcntl(fd, F_GETFL, 0);
if(fl < 0){
perror("ERROR: fcntl():");
return -1;
}
fcntl(fd, F_SETFL, fl & ~(O_NONBLOCK | O_APPEND | O_DSYNC | O_RSYNC | O_SYNC));
tcgetattr(fd, &fo);
fo.c_cc[VMIN] = 1;
fo.c_cc[VTIME] = 0;
tcsetattr(fd, TCSANOW, &fo);
fputs("─────────────────────────────────────────────────── terminal settings\n", stdout);
printf("VMIN = %d\n", fo.c_cc[VMIN]);
printf("VTIME = %d\n", fo.c_cc[VTIME]);
putchar('\n');
return(fd);
Afterwards my program enters an endless while loop where read() blocks until I enter any key when keyboard focus is in /dev/pts/1.
The problem that I am facing is that sometimes I press a key in /dev/pts/1 and bytes registered with this key aren't transmitted to the driver buffer?! Bytes just stays in the /dev/pts/1. This happens with ASCII (1-byte) characters and UTF8 (multi-byte) bytes...
I know that read() tries to read requested amount of bytes (BS) from the driver buffer. But it reads less bytes if there aren't BS bytes available in the driver buffer. So... if some bytes would arrive later it could read them later. But these bytes never arrive to the driver buffer for some reason...
What could be causing bytes not to arrive in the driver buffer and remain forever in the /dev/pts/1?

The pts was created when a virtual terminal was attached to the system (usually ssh). The pts was connected as stdin/stdout for a shell which was started for the connection, therefore you already have a process attached to the pts and reading from it.
Once you attach your application, you effectively start a race between both processes (your application and the shell), so whoever is faster will receive the content of the buffer. The character had not remained in the buffer of the pts, rather it was read by the shell attached to the pts.
To be able to read without interruption from the attached process, you need to intercept the buffer of the pts by informing the master multiplexer ptmx, see more in ptmx(4). You can study how it's done in the interceptty

Related

Entire characters in the text file is not getting transmitted in Hi 3520D

I am trying to read some data from a text file and writing it to the ttyUSB* socket id.
I am using Hi3520d Dvr. I have it's RS485 port connected to a "RS485 to RS232 converter". This converter is connected to the PC through a USB port.
The text file is getting read properly to the buffer, but while writing last few lines of the text is not transmitting. This is happening with file with size more than 4.5kb exactly and without usleep() function.
I am using minicom on linux terminal to display both read and written text.
Thanks in advance for looking into this.
#include <stdio.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#define Bdrate B9600
int Intserial(char *dev, int Baudrate)
{
//printf("Insterial func\n");
int sid;
int iDebug = -1;
struct termios serial_struct;
sid = open(dev, O_RDWR | O_NOCTTY | O_NDELAY);
if (sid > 0)
{
memset(&serial_struct, 0, sizeof(serial_struct)); /* clear the new struct */
serial_struct.c_cflag = Baudrate | CS8 | CLOCAL | CREAD;
serial_struct.c_iflag = IGNPAR;
serial_struct.c_oflag = 0;
serial_struct.c_lflag = 0;
serial_struct.c_cc[VMIN] = 0; /* block untill n bytes are received */
serial_struct.c_cc[VTIME] = 0; /* block untill a timer expires (n * 100 mSec.) */
iDebug = tcsetattr(sid, TCSANOW, &serial_struct);
if (iDebug < 0)
{
printf("Err 0\n"); //Unable to set serial port parameters
return (0);
}
}
else
{
printf("Err 1\n"); //Serial port not open
return (0);
}
//printf("sid is %d \n",sid);
return (sid);
}
int main()
{
int sid1 = -1, size = 0, i = 0, x, w;
size_t ln;
FILE *fd;
char buf[2233];
fd = fopen("h.txt", "r");
if (fd)
{
sid1 = Intserial("/dev/ttyAMA1", Bdrate); //RS485 port of Hi3520d
if (sid1 > -1)
{
system("himm 0x200F004C 0"); // commands transmitting and recieving
system("himm 0x201A0400 1");
system("himm 0x201a0004 1");
while (!feof(fd))
{
memset(buf, 0, sizeof(buf));
fread(buf, sizeof(buf), 1, fd);
printf("%s", buf);
write(sid1, buf, sizeof(buf));
usleep(5);
}
getchar();
}
else
printf("com port cant open\r\n ");
fclose(fd);
close(sid1);
}
else
printf("File cant open\r\n");
printf("task completed............\r\n");
}
You have to observe return value of fread for number of bytes read by fread function. the actual read size may not equal to bytes requested, also you have to pass number of bytes read by fread (as valid bytes in buffer) to write function as number of bytes to write.
The code should be something like this
memset(buf,0,sizeof(buf));
size_t bytesRead = fread(buf,sizeof(buf),1,fd);
if(bytesRead > 0)
write(sid1,buf, bytesRead);
Also as LPs said, fread doesn't end buffer with termination character, so passing buffer filled by fread to printf("%s") will be undefined behavior
There are numerous issues with your code, but the salient cause of "the text is not transmitting" is probably the failure to check the return value of
write(sid1, buf, sizeof(buf));
Because the serial terminal was opened in non-blocking mode, each write() will return immediately, before the data has been actually transmitted.
Since the serial terminal is configured for a rather slow 9600 baud, the data could be queued up in the line discipline buffer and other intermediate buffers.
The line discipline buffer is typically 4096 bytes long.
Assuming that the fread() operations are always successful (which you seem to have verified), then the second iteration of the write() of 2233 bytes could potentially saturate the line discipline buffer, and return with a short write return value (which would be ignored).
The third iteration of the write(), if it's quick enough, could then be outright rejected with a return value of -1 and an errno of EAGAIN to indicate that the write would block.
This error condition would be silently ignored, and this 2233 bytes of data will never be transmitted.
This seems to correlate perfectly with your observation of "last few lines of the text is not transmitting ... with file with size more than 4.5kb exactly and without usleep() function."
ADDENDUM
Revised code for blocking mode, proper terminal setup, and checking of return values is shown below.
A corrected version of #e.jahandar's suggestion and comments from #LPs are also incorporated.
...
sid = open(dev, O_RDWR | O_NOCTTY);
if (sid < 0) {
printf("Err 1\n"); //Serial port not open
return (-1);
}
if (tcgetattr(sid, &serial_struct) < 0) {
printf("Err 2\n");
return (-2);
}
cfsetospeed(&serial_struct, (speed_t)Baudrate);
cfsetispeed(&serial_struct, (speed_t)Baudrate);
cfmakeraw(&serial_struct);
serial_struct.c_cc[VMIN] = 1;
serial_struct.c_cc[VTIME] = 10;
serial_struct.c_cflag &= ~CSTOPB;
serial_struct.c_cflag &= ~CRTSCTS; /* no HW flow control? */
serial_struct.c_cflag |= CLOCAL | CREAD;
if (tcsetattr(sid, TCSANOW, &serial_struct) < 0) {
printf("Err 3\n"); //Unable to set serial port parameters
return (-3);
}
...
#define BUFSIZE 2233
char buf[BUFSIZE + 1];
...
size_t frv;
ssize_t wrv;
...
do {
frv = fread(buf, 1, BUFSIZE, fd);
buf[frv] = 0; /* terminate string for printf */
if (frv > 0) {
wrv = write(sid1, buf, frv);
if (wrv < frv) {
/* handle error or short write */
}
} else
break;
} while (1);
...

Redundancy when reading USB serial port (C;Mac OSX;Arduino)

I'm writing a simple C program that can read data from a USB port that is connected to my Arduino device. The Arduino outputs data at a baud rate of 9600 in chunks of 4 bytes.
I want the input from the Arduino to my computer to look something like this:
136.134.132.130.129.127.126.124.121.119.117.115.113.111.
However, I'm getting something like this:
271.274.281..2.4062.4022.40225.4021
Question: How do I get the input in my C program to neatly synchronize with out loosing data/ rereading data? Are there some kind of flags that could tell my program when the port has new data?
Code:
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <sys/types.h>
int open_port(void)
{
int fd; /* File descriptor for the port */
fd = open("/dev/tty.usbmodemfd121", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
perror("open_port: Unable to open /dev/tty");
}
else
fcntl(fd, F_SETFL, 0);
struct termios options;
tcgetattr(fd,&options);
cfsetospeed(&options,B9600);
options.c_cflag |=(CLOCAL | CREAD);
tcsetattr(fd, TCSANOW, &options);
return (fd);
}
int main (){
int i;
for(i=0; i<50; i++){
fcntl(open_port(), F_SETFL, FNDELAY);
char buf[5];
size_t nbytes;
ssize_t bytes_read;
nbytes = sizeof(buf);
bytes_read = read(open_port(), buf, nbytes);
printf("%s ", buf);
buf[0]=0;
}
return 0;
}
Your program does not properly open() the serial port for reading it.
In fact it repeatedly opens it two times every iteration of the for loop.
The device should be opened only once by your program.
Instead of
for (i=0; i<50; i++) {
fcntl(open_port(), F_SETFL, FNDELAY);
bytes_read = read(open_port(), buf, nbytes);
}
the main program should be structured like
fd = open_port();
if (fd < 0) {
/* handle error condition */
}
rc = fcntl(fd, F_SETFL, FNDELAY);
if (rc < 0) {
/* handle error condition */
}
for (i=0; i<50; i++) {
bytes_read = read(fd, buf, nbytes);
if (bytes_read < 0) {
/* handle error condition */
}
}
close(fd);
Your program is too "simple". It sets only a few attributes, and doesn't bother to check the return codes of system calls.
Is this supposed to be canonical or non-canonical (aka raw) mode (i.e. is the data ASCII text or binary)?
Refer to this Serial Programming Guide for proper setup of the serial port.
read data from a USB port
USB is a bus.
The device your program reads from is a serial port attached to that USBus.
Second coding issue
Your original code may print garbage data.
nbytes = sizeof(buf);
bytes_read = read(open_port(), buf, nbytes);
printf("%s ", buf);
buf[0]=0;
The bytes returned by the read() operation are not likely to be terminated by a NULL byte, so a string operation on that read buffer could exceed the bounds of the allocated array.
Code that would not misbehave would be something like:
nbytes = sizeof(buf) - 1;
bytes_read = read(fd, buf, nbytes);
if (bytes_read < 0) {
/* handle error condition */
} else {
buf[bytes_read] = 0; /* append terminator */
printf("%s ", buf);
}
Note that nbytes is one less than the allocated size of the buffer.
This is to ensure that there is an available byte to store the string terminator byte when the read() operation returns a "full" buffer of nbytes.
For efficiency the assignment of nbytes should be performed before entering the for loop, rather than within the loop.

Linux Serial Port in C [duplicate]

This question already has answers here:
Reading from a serial port after writing on it
(5 answers)
Closed 8 years ago.
I have written a program in c for reading and writing serial port.But the problem is I am using while loop and it is continuously sending the command over the serial port.
I want to write some command on serial port
wait for answer
write another command
wait for some answer and so on
My code goes like this:-
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
#include <errno.h>
#include <time.h>
int main()
{
printf("\n");
printf("Please wait till serial Port is being Initialized .... \n");
sleep(2);
printf("\n................. Initializing ................\n");
sleep(2);
printf("\n");
printf("\n\n");
static int fd = 0;
int len;
char res[100];
char s[100] = " Hellow World";
struct termios options;
//==================================================================
// hard coaded port ttyO3
//==================================================================
fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
fcntl(fd, F_SETFL, O_NONBLOCK);
//==================================================================
// Error Handling
//==================================================================
if (fd < 0)
{
printf("Serial open error %d %s\n", errno, strerror(errno));
}
printf("\n");
printf("\n==================================================\n");
//==================================================================
// Get the current options for the port...
//==================================================================
tcgetattr(fd, &options);
//==================================================================
// Set the baud rates to 115200...
//==================================================================
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
//=================================================================
// Enable the receiver and set local mode..
//==================================================================
options.c_cflag |= (CLOCAL | CREAD);
//==================================================================
// Set the new options for the port...
//==================================================================
tcsetattr(fd, TCSANOW,&options);
while(1)
{
write(fd,s,strlen((char*)s));
sleep(1);
len = read(fd,res,100);
if (len < 0)
{
if (errno == EAGAIN)
{
continue;
}
else
{
printf("read error %d %s\n", errno, strerror(errno));
}
}
else
{
res[len < 100 ? len:100] ='\0';
printf("read %d chars: %s\n",len, res);
}
}
close(fd);
}
where am I getting wrong.
Thanks and Regards
It looks like the file descriptor is opened as non-blocking (fcntl(fd, F_SETFL, O_NONBLOCK);). You must have some blocking operation if you want to wait for data to be read.
You can make the file descriptor blocking, or use some asynchronous manager like select.
Since you make your file descriptor non-blocking (twice), you have to as the system to wait between the steps. A common way to do this is the select system call, which you can use to wait until there is something to read from the file descriptor.
Can be done something like this:
write(...);
fd_set poll_set;
FD_ZERO(&poll_set);
FD_SET(fd, &poll_set);
/* Wait, with no timeout, for something to be readable */
int rc = select(fd + 1, &poll_set, NULL, NULL, NULL);
if (rc == -1)
{
perror("select");
}
else
{
/* Continue to next step, where you read */
}
Also note that the read-calls may actually not receive the complete messages in the first attempt. You may have to read multiple times to get the complete message. If your messages are of a fixed size, then read in a loop while decreasing the amount of bytes to read until you have received the complete message. If your message have a end-of-message marker, then read byte by byte until you receive it. If your messages contain a header with the message size, then use the first fixed-size read method twice, once to get the header and once to get the data.

Why is this message not only displayed when a file is written to (using the poll C Linux function)?

I was reading about poll in C programming and built an application given on the poll(2) man page.
Here is the example:
#include<stdio.h>
#include <stropts.h>
#include <poll.h>
#include <fcntl.h>
int main() {
struct pollfd fds[2];
int timeout_msecs = -1;
int ret;
int i;
/* Open STREAMS device. */
fds[0].fd = open("/home/jeshwanth/mywork/poll/dev0", O_RDONLY);
fds[1].fd = open("/home/jeshwanth/mywork/poll/dev1", O_RDONLY);
fds[0].events = POLLOUT | POLLWRBAND;
fds[1].events = POLLOUT | POLLWRBAND;
while (1) {
ret = poll(fds, 2, timeout_msecs);
if (ret > 0) {
/* An event on one of the fds has occurred. */
for (i = 0; i < 2; i++) {
if (fds[i].revents != 0) {
/* Priority data may be written on device number i. */
printf(
"Priority Data may be written on device number %d POLLWRBAND\n",
i);
}
if (fds[i].revents = !0) {
/* Data may be written on device number i. */
printf("Data may be written on device number %d POLLOUT\n",
i);
}
if (fds[i].revents = !0) {
/* A hangup has occurred on device number i. */
printf("A hangup has occurred on device number %d\n", i);
}
}
}
}
return 0;
}
Note: dev0 and dev1 are normal files. When I run the program, if no event occurred in dev0 and dev1, the message is displayed. But I was expecting when some write into the file happens, only then should it display the message. Am I wrong?
Polling it for output readiness doesn't mean you will get notified when some output occurs: it means that you'll get notified when there is output buffer space available so you can output (but you should still check the return value of your output function. The buffer state may have changed between polling and outputting; always check return values).
Minimal FIFO named pipe example
You won't be able to see anything interesting with regular files, since those always give POLLIN immediately: How can select() wait on regular file descriptors (non-sockets)?
The simplest way to play around with poll is to use named pipes as shown below. This should prepare you for their major application: sockets and device files.
Source below. Usage:
sudo mknod poll0.tmp p
sudo mknod poll1.tmp p
sudo chmod 666 poll*.tmp
./poll.out
On another shell:
printf a > poll0.tmp
printf b > poll1.tmp
Output:
loop
POLLIN i=0 n=1 buf=a
loop
POLLHUP i=0
loop
POLLIN i=1 n=1 buf=b
POLLHUP i=1
loop
So notice how poll waits for the reads without looping.
Cooler example:
(while true; do date; sleep 1; done) > poll0.tmp &
(while true; do date; sleep 2; done) > poll1.tmp &
0 gets written every one second, and 1 every two seconds, which shows how poll() is dealing with both inputs concurrently, without stalling each other.
Source:
#define _XOPEN_SOURCE 700
#include <fcntl.h> /* creat, O_CREAT */
#include <poll.h> /* poll */
#include <stdio.h> /* printf, puts, snprintf */
#include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS */
#include <unistd.h> /* read */
int main(void) {
enum { N = 2 };
char buf[1024], path[1024];
int fd, i, n;
short revents;
struct pollfd pfds[N];
for (i = 0; i < N; ++i) {
snprintf(path, sizeof(path), "poll%d.tmp", i);
/* O_NONBLOCK is required or else the open blocks
* until the other side of the pipe opens. */
fd = open(path, O_RDONLY | O_NONBLOCK);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
pfds[i].fd = fd;
/* Only events in this mask will be listened to.
* However, there are also some events that are unmaskable,
* notably POLLHUP when pipe closes! */
pfds[i].events = POLLIN;
}
while (1) {
puts("loop");
i = poll(pfds, N, -1);
if (i == -1) {
perror("poll");
exit(EXIT_FAILURE);
}
for (i = 0; i < N; ++i) {
revents = pfds[i].revents;
if (revents & POLLIN) {
n = read(pfds[i].fd, buf, sizeof(buf));
printf("POLLIN i=%d n=%d buf=%.*s\n", i, n, n, buf);
}
if (revents & POLLHUP) {
printf("POLLHUP i=%d\n", i);
/* This happens when the other side closed.
* This event is only cleared when we close the reader. */
/* poll won't set POLLHUP anymore once all fds are closed.
* Any futher polls on this will give the POLLNVAL event instead. */
close(pfds[i].fd);
/* negative fds are ignored. So if we negate an FD,
* we can both turn if off for a while, and turn it on
* later on by re-nagating it. */
pfds[i].fd *= -1;
}
}
}
}
Compile with:
gcc -o poll.out -std=c99 poll.c
Tested in Ubuntu 14.04.
GitHub upstream.
The lines:
close(pfds[i].fd);
pfds[i].fd *= -1;
are required or else you get POLLHUP forever, see also: How to use the poll C function to watch named pipes in Linux?
For even more fun, create a Linux kernel module what implements the poll fops: How to add poll function to the kernel module code?
I'll give you a hint on how to correct it. revents is interpreted as several bit flags.
/* check for priority write readiness */
if (fds[i].revents & POLLWRBAND) {
printf("Priority Data may be written on device number %d POLLWRBAND\n", i);
}
/* check for write readiness */
if (fds[i].revents & POLLOUT) {
printf("Data may be written on device number %d POLLOUT\n", i);
}
/* check for hang-up */
if (fds[i].revents & POLLHUP) {
printf("A hangup has occurred on device number %d\n", i);
}

How can I implement timeout for read() when reading from a serial port (C/C++)

I am reading bytes from a serial port in C++ using a file descriptor and the posix/unix read() function. In this example, I am reading 1 byte from the serial port (baud rate settings and similiar are omitted for clarity):
#include <termios.h>
#include <fcntl.h>
#include <unistd.h>
int main(void)
{
int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);
char buf[1];
int bytesRead = read(fd, buf, 1);
close(fd);
return 0;
}
If the device connected to /dev/ttyS0 does not send any information, the program will hang. How can I set a timeout?
I have tried setting a time out like this:
struct termios options;
tcgetattr(fd, &options);
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 10;
tcsetattr(fd, TCSANOW, &options);
I thought it was supposed to give 1 second timeout, but it makes no difference. I think I have misunderstood VMIN and VTIME. What is VMIN and VTIME used for?
Then I searched the web and found somebody talking about the select() function. Is that the solution and if so, how would one apply that to the program above to make 1 second timeout?
Any help is appreciated. Thanks in advance :-)
Yes, use select(2). Pass in a file descriptor set containing just your fd in the read set and empty write/exception sets, and pass in an appropriate timeout. For example:
int fd = open(...);
// Initialize file descriptor sets
fd_set read_fds, write_fds, except_fds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&except_fds);
FD_SET(fd, &read_fds);
// Set timeout to 1.0 seconds
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
// Wait for input to become ready or until the time out; the first parameter is
// 1 more than the largest file descriptor in any of the sets
if (select(fd + 1, &read_fds, &write_fds, &except_fds, &timeout) == 1)
{
// fd is ready for reading
}
else
{
// timeout or error
}
What is VMIN and VTIME used for?
If MIN > 0 and TIME = 0, MIN sets the number of characters to receive
before the read is satisfied. As TIME is zero, the timer is not used.
If MIN = 0 and TIME > 0, TIME serves as a timeout value. The read will
be satisfied if a single character is read, or TIME is exceeded (t =
TIME *0.1 s). If TIME is exceeded, no character will be returned.
If MIN > 0 and TIME > 0, TIME serves as an inter-character timer. The
read will be satisfied if MIN characters are received, or the time
between two characters exceeds TIME. The timer is restarted every time
a character is received and only becomes active after the first
character has been received.
If MIN = 0 and TIME = 0, read will be satisfied immediately. The
number of characters currently available, or the number of characters
requested will be returned. According to Antonino (see contributions),
you could issue a fcntl(fd, F_SETFL, FNDELAY); before reading to get
the same result.
Source : http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html
You can attempt capture signal to stop read operation. use alarm(1) before read, and if read function did not returned, alarm will send SIGALRM signal, then you can create signal processing function to capture this signal, like this:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
static jmp_buf env_alarm;
static void sig_alarm(int signo)
{
longjmp(env_alarm, 1);
}
int main(void)
{
int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);
char buf[1];
if (signal(SIGALRM, sig_alarm) == SIG_ERR)
{
exit(0);
}
if (setjmp(env_alarm) != 0)
{
close(fd);
printf("Timeout Or Error\n");
exit(0);
}
alarm(1);
int bytesRead = read(fd, buf, 1);
alarm(0);
close(fd);
return 0;
}
But use select or poll or epoll will be better if your program is big.
select() is the way I would solve this problem.
There are several pages on the internet that will give info on how to use select(), such as http://www.unixguide.net/unix/programming/2.1.1.shtml
There are several possible approaches. If the program will eventually be timing more than one i/o operation, select() is the clear choice.
However, if the only input is from this i/o, then selecting non-blocking i/o and timing is a straightforward method. I have expanded it from single character i/o to multi-character to make it a more generally complete example:
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <sys/time.h>
int main(void)
{
int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY); // sometimes "O_NONBLOCK"
char buf[10];
int done = 0, inbuf = 0;
struct timeval start, now;
gettimeofday (&start, NULL);
while (!done)
{
int bytesRead = read(fd, &buf[inbuf], sizeof buf - inbuf);
if (bytesRead < 0)
{
error_processing_here();
continue;
}
if (bytesRead == 0) // no data read to read
{
gettimeofday (&now, NULL);
if ((now.tv.sec - start.tv_sec) * 1000000 +
now.tv.usec - start.tv_usec > timeout_value_in_microsecs)
{
done = 2; // timeout
continue;
}
sleep(1); // not timed out yet, sleep a second
continue;
}
inbuf += bytesRead;
if (we have read all we want)
done = 1;
}
if (done == 2)
timeout_condition_handling();
close(fd);
return 0;
}

Resources