1
votes

I have problems with writing data to serial port with boost. I use slightly modified minicom_client class from here: https://code.google.com/p/vkbrd/source/browse/trunk/src/Dg5Emulator/MiniComClient.h https://code.google.com/p/vkbrd/source/browse/trunk/src/Dg5Emulator/MiniComClient.cpp

First 17 bytes in message are sent good, but rest is substituted by:

FD FD FD FD AB AB AB AB AB AB AB AB EE FE EE FE 00 00 00 etc

Message length is correct.

When I call

for (int i = 0; i < 128; ++i)
    miniComClient.do_write(i);

I receive this on the second side:

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F FD FD FD FD AB AB AB AB 
AB AB AB AB EE FE EE FE 00 00 00 00 00 00 00 00 2E F1 5C 42 BD 8B 07 18 
40 6D C1 03 E8 9E 40 02 00 00 00 00 00 00 00 00 04 00 00 00 01 00 00 00 
F4 62 00 00 FD FD FD FD 40 54 40 02 FD FD FD FD AB AB AB AB AB AB AB AB 
00 00 00 00 00 00 00 00 2F F1 5C 43 BF 8B 07 18 A0 A3 3B 02 38 A5 3B 02 
00 00 00 00 00 00 00 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 
FD FD FD FD AB AB AB AB AB AB AB AB EE FE EE FE 00 00 00 00 00 00 00 00 
2E F1 5C 42 BD 8B 07 18 40 6D C1 03 E8 9E 40 02 00 00 00 00 00 00 00 00 
04 00 00 00 01 00 00 00 F4 62 00 00 FD FD FD FD 40 54 40 02 FD FD FD FD 
AB AB AB AB AB AB AB AB 00 00 00 00 00 00 00 00 2F F1 5C 43 BF 8B 07 18 
A0 A3 3B 02 38 A5 3B 02 00 00 00 00 00 00 00 00   

I have triple checked baud rate, stop bits and parity.

Is there some way to change send buffer size? Maybe this is some other problem.

2
please include relevant source code in your questionSam Miller
I've added links to both header and source, with modifications explained in my answer.Dorian

2 Answers

3
votes

Values like 0xfdfdfdfd, 0xabababab and 0xfeeefeee are magic numbers.

In other words, you are looking at uninitialized memory allocated from the heap. It is a pretty standard bug in serial port programming to assume that you get the entire message with one read. That only ever happens when you debug your program, slowing it down enough. Never when it runs at full speed, serial ports are very slow devices. You must pay attention to bytes_transferred in the read_complete() function and not interpret received data until you received all the bytes. This requires keeping track of the total, buffering partial data and having a good idea when the full response was received.

The byte value where the data turns into garbage is a magic number as well. 0x10 is the ASCII code for the Line Feed control character. Which is very often used as the End-Of-Message indicator. Be sure to configure whatever software you use on the other end of the wire to not check for a line terminator and only display the bytes it actually receives.

0
votes

The reason of this problem is my "slight" modification to original code.

I wanted to make writing whole byte array simpler (instead of calling do_write() in loop), so I've added method:

void miniComClient::do_write_buffer( QByteArray msg )
    bool write_in_progress = !writeMsgs.empty(); // is there anything currently being written? 

    for(int i = 0; i < msg.size(); ++i)
        writeMsgs.push_back(msg[i]); // store in write buffer 

    if (!write_in_progress) // if nothing is currently being written, then start 
            write_start();
}

But the worst thing was my try to optimize things, so I've modified write_start() to something like this (send everything in buffer instead of just next byte):

void miniComClient::write_start( void )
{
    // Start an asynchronous write and call write_complete when it completes or fails 
    boost::asio::async_write(serialPort, 
            boost::asio::buffer(&writeMsgs.front(), writeMsgs.size()), 
            boost::bind(&miniComClient::write_complete, 
            this, 
            boost::asio::placeholders::error));
}

This was a terrible mistake, because writeMsgs is of type std:deque so it is not stored continuously in memory, so it sends some bytes from the point I wanted, and garbage after that.