Skip to content

Instantly share code, notes, and snippets.

@michalpelka
Last active October 16, 2016 20:02
Show Gist options
  • Save michalpelka/9942df29a9c2887a7b15f75dfbebc170 to your computer and use it in GitHub Desktop.
Save michalpelka/9942df29a9c2887a7b15f75dfbebc170 to your computer and use it in GitHub Desktop.
#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