Home > Software engineering >  boost::asio SerialPort unable to receive data
boost::asio SerialPort unable to receive data

Time:09-08

I am unable to receive data over serial port in boost::asio while using asynchronous. When I use synchronous routines I am able to receive data.

Code :

SerialPort.cpp

bool SerialPort::read_async(std::uint32_t read_timeout)
{
    try
    {
        if (read_timeout not_eq SerialPort::ignore_timeout)
            this->read_timeout = read_timeout;//If read_timeout is not set to ignore_timeout, update the read_timeout else use old read_timeout
        this->port.async_read_some(boost::asio::buffer(this->read_buffer.data(), this->read_buffer.size()),
            boost::bind(&SerialPort::read_handler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
        return true;
    }
    catch (const std::exception& ex)
    {
        PLOG_ERROR << ex.what();
        return false;
    }
}

void SerialPort::read_handler(const boost::system::error_code& error, std::size_t bytes_transferred)
{
    std::string received_data_buffer;
    std::transform(this->read_buffer.begin(), this->read_buffer.begin()   bytes_transferred,
        std::back_inserter(received_data_buffer), [](std::byte character) {
            return static_cast<char>(character);
        });
    PLOG_INFO << "In Read Buffer : " << received_data_buffer;
}

bool SerialPort::open_port(void)
{
    try
    {
        this->port.open(this->port_name);
        return true;
    }
    catch (const std::exception& ex)
    {
        PLOG_FATAL << ex.what();
    }
    return false;
}

SerialPort.hpp

class SerialPort
{
private:
    boost::asio::io_context         io;
    boost::asio::serial_port        port;
    boost::asio::serial_port::native_handle_type    native_port;
    std::string                     port_name;
    const static std::uint32_t      READ_BUFFER_MAX_LENGTH{ 8096 };

    std::array<std::byte, SerialPort::READ_BUFFER_MAX_LENGTH> read_buffer;//Used in synchronous read 
    
    void                            read_handler(
        const boost::system::error_code& error, // Result of operation.
        std::size_t bytes_transferred       // Number of bytes read.
    );
    //boost::asio::deadline_timer       timer;

public:
    SerialPort() : io(), port(io), thread_sync_read()
    {
    }
    ~SerialPort();

    bool                            open_port(void);

    bool                            read_async(std::uint32_t read_timeout = SerialPort::ignore_timeout);

};

main.cpp

SerialPort sp;

int main()
{
    sp.open_port("COM11");
    sp.write_sync("Testing123");
    sp.read_async();

    while (true)
    {
    }
    return 0;
}

CodePudding user response:

You're supposedly trying to do some operations asynchronously.

Firstly, mixing synchronous and asynchronous operations is not always advisable. Some services/IO objects might hold inner state that assumes one or the other.

Secondly, the asynchronous operation requires the io_service to be run. That doesn't happen. You could make it explicit instead of the current while() loop.

#include <boost/asio.hpp>
#include <boost/bind/bind.hpp>
#include <iostream>
namespace asio = boost::asio;
using boost::system::error_code;

std::ostream PLOG_INFO(std::clog.rdbuf());
std::ostream PLOG_ERROR(std::clog.rdbuf());
std::ostream PLOG_FATAL(std::clog.rdbuf());

class SerialPort
{
public:
  SerialPort()
      : io_()
      , port_(io_) /*, thread_sync_read()*/
  {}
  ~SerialPort() = default;

  bool open_port(std::string name);

  static constexpr uint32_t ignore_timeout = -1;
  bool read_async(std::uint32_t read_timeout = SerialPort::ignore_timeout);
  void run() { io_.run(); }

private:
  static constexpr uint32_t READ_BUFFER_MAX_LENGTH{8096};

  asio::io_context          io_;
  asio::serial_port         port_;
  std::string               port_name_;
  uint32_t                  read_timeout_ = ignore_timeout;
  // asio::deadline_timer   timer;

  std::array<std::byte, READ_BUFFER_MAX_LENGTH> read_buffer_;

  void read_handler(error_code error, size_t bytes_transferred);
};

bool SerialPort::read_async(std::uint32_t read_timeout) {
    try {
        if (read_timeout != SerialPort::ignore_timeout)
            read_timeout_ =
                read_timeout; // If read_timeout is not set to ignore_timeout,
                              // update the read_timeout else use old
                              // read_timeout
        port_.async_read_some(
            asio::buffer(read_buffer_.data(), read_buffer_.size()),
            boost::bind(&SerialPort::read_handler, this,
                        asio::placeholders::error,
                        asio::placeholders::bytes_transferred));
        return true;
    } catch (const std::exception& ex) {
        PLOG_ERROR << ex.what() << std::endl;
        return false;
    }
}

void SerialPort::read_handler(error_code error, size_t bytes_transferred) {
    std::string s;
    std::transform(
        read_buffer_.begin(), read_buffer_.begin()   bytes_transferred,
        std::back_inserter(s),
        [](std::byte character) { return static_cast<char>(character); });
    PLOG_INFO << "In Read Buffer : " << s << " (" << error.message() << ")" << std::endl;
}

bool SerialPort::open_port(std::string name) {
    try {
        port_name_ = std::move(name);
        port_.open(port_name_);
        return true;
    } catch (std::exception const& ex) {
        PLOG_FATAL << ex.what() << std::endl;
        return false;
    }
}

SerialPort sp;

int main(int argc, char** argv) {
    sp.open_port(argc > 1 ? argv[1] : "COM11");
    // sp.write_sync("Testing123");
    sp.read_async();

    sp.run();
}
  • Related