views:

76

answers:

2

I am writing a C program that will read and write from/to a serial port. Each write will be followed by a read which will contain data based on the write. I will have about 16 different writes to perform, each followed by a read.

I am still new to serial programming and am trying to determine how to approach this. Should the program block during each write/read (basically having a big while(1) loop of writes and reads)?

Is it possible to have one thread sending writes while another thread performs the reads? Can a callback be created for allowing a thread to know when data is available to be read from the serial port?

Thanks for the help.

Edit:

OS: Linux

+1  A: 

It sounds like a simple loop with a read and a write will be enough. If you want more control (like writing a keep-alive after X seconds of no input) use select or poll; they allow you to "sense" if data is available, so a read will not block (however, you should still read non-blocking in case something happens between the select and the read). Multithreading doesn't make sense in this case.

select and poll also allow you to test if writing will block; again, write non-blocking just to be sure. You generally don't want your process to be hanging in some blocking system call, ever, apart from select or poll, that is. (at least, I don't)

Use ioctl to set various parameters on the serial line. Use

$ strace -o /tmp/strace.minicom -f minicom

to launch minicom (or any other terminal program) and see what they do to get things working, if you're stuck. And as always, see man select/poll/read/ioctl for more information.

mvds
A: 

There are several ways to go about this in general. The best choice is likely dependant on what type of data you are looking when you read the serial port and how you want to go about dealing with errors in that data.

The fist way would be to open the serial file for blocking IO and do:

while (question) {
    write(ser_fd, question.data, question.len);
    sleep(1);
    ioctl(ser_fd, FIONREAD, &answer.len);
    answer.data = realloc(answer.data, answer.len);
    read(ser_fd, question.answer, question.answer_len);
    question = next(question);
    answer = next(answer);
}

Though I didn't do any error handling in this.

If you want to be able to timeout waiting for a reply to come in the serial port then that changes things a lot. You should look into using either select, pselect, poll, ppoll, or the epoll family of system calls. These allow your program to block (sleep) until there is data ready to be read in. Then you can loop around a poll and read until you have either completed your answer or run out of time.

Another option is to try to use SIGIO, but I don't recommend this. It's not easy to get this right and difficult to debug.

Additionally you may be able to use SIGALRM to knock you out of your read call to act as a timeout for that.

If you are trying to use the stdio input and output routines then this is much more difficult. You will be stuck with something like the first method without being able to ask about how much data is ready.

nategoose