#include <iostream>
#include <boost/asio.hpp>

using namespace std;
using namespace boost;

using Time = asio::steady_timer::duration; using Error = const error_code&;
class Reader  {
public:
    using Bytes = std::vector<std::byte>;

    Reader(const string& nameA, const string& nameB)
        : io_(), portA_(io_, nameA), portB_(io_, nameB), timer_(io_) {
    }
    ~Reader() { portA_.close(); portB_.close(); }

    const Bytes& read_data(size_t size, Time timeout) {
        timer_.expires_from_now(timeout);
        timer_.async_wait ( [=](Error e){this->timerEvent(e);} );

        portA_.async_read_some( asio::buffer(tabA, BUFFER_SIZE),
                               [=](Error e,size_t expected_size){ this->readA(e,size);});

        portB_.async_read_some( asio::buffer(tabB, BUFFER_SIZE),
                               [=](Error e,size_t expected_size){this->readB(e,size);});
        io_.run();

        return buffer_;
    }
private:
    asio::io_service io_;
    asio::serial_port portA_;
    asio::serial_port portB_;
    asio::steady_timer timer_;

    static const size_t BUFFER_SIZE = 1;
    std::byte tabA [BUFFER_SIZE]; //wielkosc bufora = 1
    std::byte tabB [BUFFER_SIZE];
    Bytes buffer_;

    void readA(Error error, size_t expected_size) {
      if( error ) return;
      buffer_.push_back(tabA[0]);
      if(buffer_.size()>=expected_size){
        timer_.cancel();
		portB_.cancel(); //nie czekamy na dane z portu B
        return;
      }
      portA_.async_read_some( asio::buffer(tabA, BUFFER_SIZE),
                              [=](Error e,size_t expected_size){ this->readA(e,expected_size);});
    }

    void readB(Error error, size_t expected_size) {
      if( error ) return;
      buffer_.push_back(tabB[0]);
      if(buffer_.size()>=expected_size){
        timer_.cancel();
		portA_.cancel(); //nie czekamy na dane z portu A
        return;
      }
      portB_.async_read_some( asio::buffer(tabB, BUFFER_SIZE),
                               [=](Error e,size_t expected_size){this->readB(e,expected_size);});
    }

    void timerEvent(Error error) {
      if( error ) return;
      portA_.cancel();
	  portB_.cancel();
    }
  };

