Boost Windows 2 1 Serial Port
In part I 1 of this article, we used Boost libraries under both Windows and Linux to communicate with a GPS receiver connected to a serial port. Boost Asio 2 was used for asynchronous I/O to read data from the receiver in a platform-independent manner, with other Boost libraries in supporting roles.
Usb Serial Port Windows 10
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..)
2 4 6 8 10 12 14 16 18 20 22 | #include <boost/asio.hpp> usingnamespaceboost; charread_char(){ asio::serial_port port(io); port.open('COM3'); port.set_option(asio::serial_port_base::baud_rate(115200)); charc; // Read 1 character into c, this will block asio::read(port,asio::buffer(&c,1)); port.close(); returnc; |
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.
Boost Windows 2 1 Serial Port Driver
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:
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 | #include <boost/asio/serial_port.hpp> #include 'blocking_reader.h' usingnamespaceboost; std::stringread_response(){ asio::io_service io; port.set_option(asio::serial_port_base::baud_rate(115200)); // A blocking reader for this port that blocking_reader reader(port,500); charc; std::stringrsp; // read from the serial port until we get a while(reader.read_char(c)&&c!='n'){ } if(c!='n'){ throwstd::exception('Read timed out!'); } |
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:
Boost Windows 2 1 Serial Port 1
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 | // blocking_reader.h - a class that provides basic support for // blocking & time-outable single character reads from // // // // // return false; // Kevin Godden, www.ridgesolutions.ie #include <boost/bind.hpp> classblocking_reader boost::asio::serial_port&port; charc; boolread_error; // Called when an async read completes or has been cancelled voidread_complete(constboost::system::error_code&error, // timer. } // Called when the timer's deadline expires. voidtime_out(constboost::system::error_code&error){ // Was the timeout was cancelled? // yes } // no, we have timed out, so kill // The read callback will be called port.cancel(); // Constructs a blocking reader, pass in an open serial_port and blocking_reader(boost::asio::serial_port&port,size_t timeout): timer(port.get_io_service()), // returns false if the read times out // to do a reset for subsequent reads to work. boost::asio::async_read(port,boost::asio::buffer(&c,1), this, 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, // or until the it is cancelled. val=c; return!read_error; }; |