boost C++ read from serial port with timeout example
2017-06-07 16:27
976 查看
from: http://www.ridgesolutions.ie/index.php/2012/12/13/boost-c-read-from-serial-port-with-timeout-example/
If you are doing any serial port communications these days in C++ and would like your code to be portable, then you are probably using boost’s asio::serial_port class.
One complication with using serial_port (and boost::asio more generally) is that it doesn’t provide a direct facility to allow synchronous blocking reads to time-out and return if no data arrives within a specified time period. Here is a little example that tries to read a character from COM3 (on windows..)
In this example read() will block forever if no data arrives to the serial port, this is not always what you want, especially when dealing with possibly noisy or unreliable rs232 communication.
In order to take advantage of read time-outs you have to issue asynchronous reads and incorporate a deadline_timer which will cancel the read after a specified time, i.e. if the read hasn’t received the data it was expecting before the deadline_timer expires, then it will be cancelled.
Using asynchronous IO in boost is a bit involved and it can be quite quite messy, so I have written small class called blocking_reader which will block while trying to read a single character, and will time out if a character hasn’t been received in a specified number of milliseconds. It can be used like this:
The above code isn’t the most sensible or efficient but it shows the use of blocking_reader, which in this case times out reads after 500ms.
You open the serial_port as normal and then pass it to blocking_reader’s constructor along with a timeout value. You then use blocking_reader.read_char() to read a single character. If the read times out then read_char() will return false (otherwise it will return true!)
The code for blocking_reader can be downloaded from here, I have also included it below:
If you are doing any serial port communications these days in C++ and would like your code to be portable, then you are probably using boost’s asio::serial_port class.
One complication with using serial_port (and boost::asio more generally) is that it doesn’t provide a direct facility to allow synchronous blocking reads to time-out and return if no data arrives within a specified time period. Here is a little example that tries to read a character from COM3 (on windows..)
#include <boost/asio/serial_port.hpp> #include <boost/asio.hpp> using namespace boost; char read_char() { asio::io_service io; asio::serial_port port(io); port.open("COM3"); port.set_option(asio::serial_port_base::baud_rate(115200)); char c; // Read 1 character into c, this will block // forever if no character arrives. asio::read(port, asio::buffer(&c,1)); port.close(); return c; }
In this example read() will block forever if no data arrives to the serial port, this is not always what you want, especially when dealing with possibly noisy or unreliable rs232 communication.
In order to take advantage of read time-outs you have to issue asynchronous reads and incorporate a deadline_timer which will cancel the read after a specified time, i.e. if the read hasn’t received the data it was expecting before the deadline_timer expires, then it will be cancelled.
Using asynchronous IO in boost is a bit involved and it can be quite quite messy, so I have written small class called blocking_reader which will block while trying to read a single character, and will time out if a character hasn’t been received in a specified number of milliseconds. It can be used like this:
#include <string> #include <boost/asio/serial_port.hpp> #include <boost/asio.hpp> #include "blocking_reader.h" using namespace boost; std::string read_response() { asio::io_service io; asio::serial_port port(io); port.open("COM3"); port.set_option(asio::serial_port_base::baud_rate(115200)); // A blocking reader for this port that // will time out a read after 500 milliseconds. blocking_reader reader(port, 500); char c; std::string rsp; // read from the serial port until we get a // \n or until a read times-out (500ms) while (reader.read_char(c) && c != '\n') { rsp += c; } if (c != '\n') { // it must have timed out. throw std::exception("Read timed out!"); } return rsp; }
The above code isn’t the most sensible or efficient but it shows the use of blocking_reader, which in this case times out reads after 500ms.
You open the serial_port as normal and then pass it to blocking_reader’s constructor along with a timeout value. You then use blocking_reader.read_char() to read a single character. If the read times out then read_char() will return false (otherwise it will return true!)
The code for blocking_reader can be downloaded from here, I have also included it below:
// // blocking_reader.h - a class that provides basic support for // blocking & time-outable single character reads from // boost::asio::serial_port. // // use like this: // // blocking_reader reader(port, 500); // // char c; // // if (!reader.read_char(c)) // return false; // // Kevin Godden, www.ridgesolutions.ie // #include <boost/asio/serial_port.hpp> #include <boost/bind.hpp> class blocking_reader { boost::asio::serial_port& port; size_t timeout; char c; boost::asio::deadline_timer timer; bool read_error; // Called when an async read completes or has been cancelled void read_complete(const boost::system::error_code& error, size_t bytes_transferred) { read_error = (error || bytes_transferred == 0); // Read has finished, so cancel the // timer. timer.cancel(); } // Called when the timer's deadline expires. void time_out(const boost::system::error_code& error) { // Was the timeout was cancelled? if (error) { // yes return; } // no, we have timed out, so kill // the read operation // The read callback will be called // with an error port.cancel(); } public: // Constructs a blocking reader, pass in an open serial_port and // a timeout in milliseconds. blocking_reader(boost::asio::serial_port& port, size_t timeout) : port(port), timeout(timeout), timer(port.get_io_service()), read_error(true) { } // Reads a character or times out // returns false if the read times out bool read_char(char& val) { val = c = '\0'; // After a timeout & cancel it seems we need // to do a reset for subsequent reads to work. port.get_io_service().reset(); // Asynchronously read 1 character. boost::asio::async_read(port, boost::asio::buffer(&c, 1), boost::bind(&blocking_reader::read_complete, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); // Setup a deadline time to implement our timeout. timer.expires_from_now(boost::posix_time::milliseconds(timeout)); timer.async_wait(boost::bind(&blocking_reader::time_out, this, boost::asio::placeholders::error)); // This will block until a character is read // or until the it is cancelled. port.get_io_service().run(); if (!read_error) val = c; return !read_error; } };
相关文章推荐
- boost c++ lib on linux (1) - regex example with binary boost lib Regex
- C++ boost::asio::serial_port 串口通信类 使用 封装
- C++ boost::asio::serial_port 串口通信类 使用 封装 [大三四八九月实习]
- How to read a PCap file from Wireshark with C++
- How to read a PCap file from Wireshark with C++
- What is the best way to port from Objective-C to C++?
- C++ Read Data from File into Struct
- A PicRS232 control with a PIC microcontroller serial port
- Embedding Python in C++ Applications with boost::python
- C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond
- SerialPort Read读取数据出问题
- How to get the password text in a text with password property from another process using C++ - 用C++如何从不同进程获取密码框文本
- Calculate the CDF of Poisson Distribution with Boost C++ Library
- boost asio serial_port 读写串口
- USBView & How to get the Serial Number from a USB disk & qextserialport
- ORA-39050: parameter _log_private_parallelism is incompatible with parameter _redo_read_from_memory
- Method:Openwrt lua with serial port communication
- Using Boost C++ libraries with gcc g++ under Windows(cygwin+netbeans)
- Regular Expressions in C++ with Boost.Regex(4)
- Dual-Port Block RAM with Two Write Ports and Byte-wide Write Enable in Read-First Mode