How to format this data to send to a serial port?

Viewed 256

I am trying to send commands and receive data from a hardware device via a serial port in Windows.

The documentation has the following information:

enter image description here

There is also an example command given in the documentation, which looks like this:

Client: $02 $30 $34 $30 $31 $30 $33 $32 $41 $03

which should result in the returned data:

$02 $30 $34 $30 $35 $30 $33 $30 $32 $33 $30 $32 $37 $41 $36 $44 $33 $03

When I send the command in full $02 $30 $34 $30 $31 $30 $33 $32 $41 $03 as Hex, in a serial port monitor application, I indeed get the data return. In my c++ application however, I get nothing.

I am using boost::asio in c++, and have the following code:

int main(int argc, char* argv[])
{
        asio::io_service io;
        asio::serial_port port(io);

        port.open("COM4");
        port.set_option(asio::serial_port_base::baud_rate(115200)); 
        
        uint8_t obuf[512]; // arbitrary size, larger than largest expected buffer
        for (size_t i = 0; i < 512; ++i) obuf[i] = 0;

        while (true)
        {
            port.write_some(boost::asio::buffer(char(0x02) + "0401032A" + char(0x03), 10));

            //$02 $30 $34 $30 $31 $30 $33 $32 $41 $03
            std::cout << "reading" << std::endl;
            asio::read(port, asio::buffer(obuf,10));
    
            std::cout << obuf << std::endl; 
    
        }
    

    std::cin.get();
}

Where am I going wrong in the formatting here? How can I send this command '$02 $30 $34 $30 $31 $30 $33 $32 $41 $03' as ASCI to a port in c++?

1 Answers

This is a bug:

 char(0x02) + "0401032A" + char(0x03)

It adds integral types (char, char const* and char). What you likely wanted is

 char(0x02) + std::string("0401032A") + char(0x03), 10)

 // or

 char(0x02) + "0401032A"s + char(0x03)

 // or indeed, much simpler:
 "\x02" "0401032A0\x03"s

Keep in mind that if you want to construct a std::string from a literal constant using the constructor, you may have to specify a length when the data includes embedded NUL characters.

This is not required for ""s" and ""sv literals, so usually you should prefer them

Side Note

Use asio::write instead of write_some so you get more guarantees that the whole buffer is transmitted (except of course in the face of errors).

Also use the return value to resize your actual message received.

Improvement suggestions:

#include <boost/asio.hpp>
#include <boost/asio/serial_port.hpp>
#include <iostream>
namespace asio = boost::asio;
using namespace std::literals;

int main()
{
    asio::io_service  io;
    asio::serial_port port(io);

    port.open("COM4");
    port.set_option(asio::serial_port_base::baud_rate(115200));

    while (true) {
        boost::asio::write(port, boost::asio::buffer("\x02"
                                               "0401032A0\x03"sv));

        //$02 $30 $34 $30 $31 $30 $33 $32 $41 $03
        std::cout << "reading" << std::endl;
        std::vector<uint8_t> obuf(10, 0);
        auto n = asio::read(port, asio::buffer(obuf));
        obuf.resize(n);

        for (int i : obuf) {
            std::cout << std::hex << std::showbase << " " << i;
        }
        std::cout << std::endl;
    }
}
Related