Last active
October 16, 2016 20:02
-
-
Save michalpelka/9942df29a9c2887a7b15f75dfbebc170 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <boost/asio/serial_port.hpp> | |
#include <boost/asio.hpp> | |
using namespace boost; | |
#include <boost/asio/serial_port.hpp> | |
#include <boost/bind.hpp> | |
#ifndef WINDOWS | |
#include <termios.h> | |
#endif | |
class blocking_reader | |
{ | |
boost::asio::serial_port& port; | |
size_t timeout; | |
char c; | |
char buffer[1000]; | |
boost::asio::deadline_timer timer; | |
std::stringstream _stream; | |
int _extra_chars_to_read; | |
bool _delimiter_found; | |
char _delimiter; | |
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); | |
timer.cancel(); | |
} | |
void read_complete_readsome(const boost::system::error_code& error, | |
size_t bytes_transferred) { | |
read_error = (error || bytes_transferred == 0); | |
timer.cancel(); | |
} | |
void read_char(const boost::system::error_code& error, | |
size_t bytes_transferred) { | |
read_error = (error || bytes_transferred == 0); | |
if (bytes_transferred) | |
{ | |
_stream << c; | |
if (c== _delimiter) _delimiter_found = true; | |
if (_delimiter_found&& _extra_chars_to_read-- == 0) | |
{ | |
timer.cancel(); | |
} | |
else | |
{ | |
boost::asio::async_read(port, boost::asio::buffer(&c, 1), | |
boost::bind(&blocking_reader::read_char, | |
this, | |
boost::asio::placeholders::error, | |
boost::asio::placeholders::bytes_transferred)); | |
} | |
} | |
} | |
// Called when the timer's deadline expires. | |
void time_out(const boost::system::error_code& error) { | |
// Was the timeout was cancelled? | |
if (error) { | |
return; | |
} | |
// no, we have timed out, so kill | |
// the read operation | |
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) { | |
} | |
bool flush() | |
{ | |
#ifdef WINDOWS | |
return false; | |
#endif | |
// call low level unix port feature | |
return (0 == ::tcflush(port.lowest_layer().native_handle(), TCIOFLUSH)); | |
} | |
bool read_some(std::string &data) | |
{ | |
port.get_io_service().reset(); | |
port.async_read_some(boost::asio::buffer(buffer, 1000), boost::bind(&blocking_reader::read_complete_readsome, | |
this, | |
boost::asio::placeholders::error, | |
boost::asio::placeholders::bytes_transferred)); | |
timer.expires_from_now(boost::posix_time::milliseconds(timeout)); | |
timer.async_wait(boost::bind(&blocking_reader::time_out, | |
this, boost::asio::placeholders::error)); | |
port.get_io_service().run(); | |
data = std::string(buffer); | |
return !read_error; | |
} | |
bool read_until(std::string &data, char delimiter, int extraChars=0) | |
{ | |
_stream.str(""); | |
_extra_chars_to_read = extraChars; | |
_delimiter = delimiter; | |
port.get_io_service().reset(); | |
boost::asio::async_read(port, boost::asio::buffer(&c, 1), | |
boost::bind(&blocking_reader::read_char, | |
this, | |
boost::asio::placeholders::error, | |
boost::asio::placeholders::bytes_transferred)); | |
timer.expires_from_now(boost::posix_time::milliseconds(timeout)); | |
timer.async_wait(boost::bind(&blocking_reader::time_out, | |
this, boost::asio::placeholders::error)); | |
port.get_io_service().run(); | |
if (!read_error) | |
data = _stream.str(); | |
return !read_error; | |
} | |
// 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; | |
} | |
}; | |
int main() { | |
asio::io_service io; | |
asio::serial_port port(io); | |
port.open("/dev/ttyUSB0"); | |
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, 5000); | |
reader.flush(); | |
char c; | |
std::string rsp; | |
reader.read_until(rsp, '_', 1); | |
//reader.read_until(rsp, '\n', 1); | |
// if (c != '\n') { | |
// // it must have timed out. | |
// throw std::string("Read timed out!"); | |
// } | |
std::cout << rsp << "\n"; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment