1

In Arduino data can be read as follows:

void setup() {
    Serial.begin(9600);
}

String Comand = "";
void loop() {
    if (Serial.available() > 0) //If there is data read 
        {
        char c = Serial.read(); //get byte
        if(c!='\n')
        {
          Comand+=c;
        }
        else
        {
          if(Comand == "MyComand")
          {
            Serial.println("Comand 1");
          }
          //else
          //...
          Comand = "";
        }
    }
}

С++ boost asio Here is an example of c ++ playback of data from the port, but what function to check if there is anything to read?

#include <boost/asio.hpp>
#include <windows.h>

//....

int main(int, char**)
{
    {
        boost::asio::io_service io;
        boost::asio::serial_port serial(io,"COM5");
        serial.set_option(boost::asio::serial_port_base::baud_rate(9600));

        std::string s = "MyComand\n";
        boost::asio::write(serial,boost::asio::buffer(s.c_str(),s.size()));
        std::string result;

        //while serial data > 0 ???  How to check
        {
            using namespace boost;
            char c;
            asio::read(serial,asio::buffer(&c,1));
            result+=c;
        }

        std::cout<<result.c_str();

    }

return 0;
}

If I read in a cycle, and there is no data, the program will stop and wait for the data, it does not suit me. How to check if there is data before trying to read.

1 Answers1

1

The idea of asynchronous IO is that you donot check whether data is available. Instead, you defer the completion of the read until that is the case.

Now, you're using Asio to still do synchronous IO. And your requirement is:

If I read in a cycle, and there is no data, the program will stop and wait for the data, it does not suit me.

Synchronous IO implies blocking reads. You can make it return whatever is available:

while (auto n = serial.read_some(asio::buffer(buf))) {
    result.append(buf.data(), n);
    std::cout << "Received " << n
              << " bytes, total length: " << result.length() << "\n";
}

But read_some is still blocking:

This function is used to read data from the serial port. The function call will block until one or more bytes of data has been read successfully, or until an error occurs.

So, the only real alternative for serial ports is to use the async interface:

std::string result;
std::array<char, 32> buf;

std::function<void(error_code, size_t)> read_loop;
read_loop = [&](error_code ec, size_t n) {
    if (ec.failed())
        return;
    std::cout << "Received " << n
              << " bytes, total length: " << result.length() << "\n";
    result.append(buf.data(), n);
    serial.async_read_some(asio::buffer(buf), read_loop);
};
read_loop(error_code{}, 0);

Now you have a new "problem": how to integrate your application logic into this. The fact that you're printing the request suggests to me that you're not receiving an unbounded stream of binary data. Instead, consider simplifying for your application logic to read just what you need, perhaps with a timeout. See e.g. asio_read_some countinue reading to get all data

sehe
  • 374,641
  • 47
  • 450
  • 633
  • I showed a primitive example, in fact the program is much more complex with a graphical interface that has to write or read data after a command in the non-volatile memory of the microcontroller, the flow is intermittent and responds to requests. In any case, thank you, I'll try to work with your example, it's a pity that there is no such test for synchronous use. read_some is a good idea. – Юрій Писанка Mar 22 '22 at 11:19
  • I guess it's because there is no portable API to implement such a function - e.g. sockets [have it](https://www.boost.org/doc/libs/1_78_0/doc/html/boost_asio/reference/basic_socket/available/overload1.html). You can always implement what you would like (["in the queue"](https://stackoverflow.com/questions/71568361/boost-asio-serial-port-how-to-find-out-the-size-of-the-buffer-in-the-queue-for-r/71570945?noredirect=1#:~:text=in%20the%20queue)) by letting a background thread fill a queue. Then you can always ask your own queue how much data is pending. – sehe Mar 22 '22 at 11:33
  • An important question arose while serial.read_some or asio :: serial_port are waiting to be visited in a separate thread, can I send boost :: asio :: write? – Юрій Писанка Mar 22 '22 at 19:38
  • To where? Not on the same IO object, so you need to also queue those. In Asio patterns, these operations would be serialized with a strand. – sehe Mar 22 '22 at 19:40
  • Thank you, this is not critical for my client-server program, but I will consider sockets in the future. – Юрій Писанка Mar 22 '22 at 19:49
  • At least for sockets I know full-duplex is fine (so you can write and read simultaneously as long as (a) read don't overlap (b) writes don't overlap (c) accesses to the IO object are synchronized) – sehe Mar 22 '22 at 19:53