|Serial C And The Raspberry Pi|
|Written by Harry Fairhead|
|Monday, 29 August 2016|
Page 5 of 5
Polling for data
You can set up a software interrupt to signal when there is data to be read and you can use another thread to process it, but the majority of serial applications work best with a simple polling loop and you can do the job with a blocking or non-blocking call.
For example, suppose you have just sent a command to a device and now you need to wait for it to respond. Suppose the response is a block of code always less than 100 bytes and after this has been transmitted nothing happens until the next command is sent to the device.
To do the job with a blocking call we can read one block of data at a time by setting c_cc[VTIME] and c_cc[VMIN] correctly. As we are only expecting fewer than 100 bytes we can set c_cc[VMIN] to 100 and be safe that the call to read will not return before reading all of the characters sent by the device.
Setting c_cc[VTIME]=1 means that if there is more than a one tenth of a second pause between bytes then the block is assumed complete and the read returns with the data. Of course, if the device pauses for more than 0.1s and it hasn't finished then the block will be received incomplete. However, in many cases this is unlikely and when it does happen represents an error that needs a complete retry.
An example program using this method is:
This will work with a loopback connection and you don't need to wait for the transmitted data to be received because you have a 0.1 time out between characters that effectively waits for the data. All that matters is that at least one character has been received. The pause of 0.1 seconds before testing to see if there are any characters in the buffer is reasonable as you have the same inter-character time out.
This works well in situations where you have a send-receive command-response setup, but it has some disadvantages. The first is that your program is halted while the block of data comes in. If it has nothing else to do this acceptable.
An alternative is to spin the data transfer off onto a different thread, but even in this case there is also the small problem of 0.1s wasted at the end of the transmission to confirm that the block has been sent. This is often acceptable as well.
Polling for data with non-blocking
An alternative way of doing the same job is to use a polling loop and read in the data a character at a time. The problem in this case is knowing when the block of data is complete. You can do this by arranging for the sending device to indicate the number of bytes to be transferred or by sending a flag byte to indicate the end of the block. However it is done, you have to have some way of knowing that a block is complete.
In this example the end of the block is marked by a null byte as if it was a string. The non-blocking read is created by setting c_cc[VTIME] =0 and c_cc[VMIN]=0 but you could do it another way.
Notice that the work is done in the while loop and also notice that we don't wait for the transmitted data to be available as a block. There is no overall timeout and if the transmitting device never sends a null then the loop never ends. In practice you would need to include an overall timeout for the loop. In this example we do send the null at the end of the string and so it should end as long as there isn't a transmission problem.
Receiving A Big Block
What if you want to receive a block that might be bigger than 511 characters but you still want an inter-character time out?
The answer is that you can write your own function that does the job.
The algorithm is simple. Peek a the number of bytes in the serial buffer. If it has reached the maximum size that you want to deal with then read the buffer. If it hasn't then wait for the specified time out and peek a the number of characters in the buffer. If it hasn't increased the time out is up and you read as many characters that are available in the buffer. Otherwise you wait another time out period to see if more data comes in.
The function is:
Blocking v non-blocking
This use of completely non-blocking reads is the typical way that serial port communications is handled. This is mostly because the range of behavior that you can program using blocking reads isn't appreciated. You don't just have a choice of blocking v non-blocking. You can set a timeout between characters and a minimum number of characters to wait for and a maximum to return. When you don't know how much data is going to be sent, only an upper limit to a block of data, then blocking reads are simpler and preferable as long as you set a timeout and a minimum character size.
Notice that a blocking read doesn't load the processor because the thread is suspended while the driver waits for data. A polling blocking read, on the other hand, occupies a single core 100% of the time but it can be doing other things as well as checking for data. Using 100% of a core doesn't matter so much if you have other cores to keep the system working and it doesn't matter at all if you haven't got anything else for the core to do.
In more complicated situations you may have to use a separate thread to poll or wait for blocked calls, but this isn't as necessary as you might think. Neither is the use of a software interrupt to service incoming data, as most transactions are of a command- response nature.
Linux serial port handling is much more subtle than you might have imagined.
or email your comment to: firstname.lastname@example.org
|Last Updated ( Thursday, 01 December 2016 )|