3

What I'm trying to do:

I'm trying to write win console which will communicate with my ATMega2560 board via UART. Now it should send string saved in stringToSend to the MCU which should be send back to the PC. String sent from MCU should be saved in receivedString and then written to the win console window.

What the code does:

What it does now is that after I send the string to MCU it will come back, but on the console I see an unexpected sequence of '╠' characters preceding the echoed string, just like this:

You sent:

╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠Sended test string!


EDIT: Number of characters is consistent if BUFFER_SIZE is constant, but it scales with BUFFER_SIZE:

  • If BUFFER_SIZE = 124 then there's 132 of these characters
  • If BUFFER_SIZE = 1024 then there's 1032 of these characters
  • If BUFFER_SIZE = 1 then there's 9 of these characters

Weird things (probably just for me):

  • The weirdest thing is that when I use breakpoints and look into receivedString the string from stringToSend isn't there BUT it will appear in the console.
  • When I send data via Termite (console for sending data via serial communication) the problem disappear and after that I'm receiving ONLY the right string even with my console.

The questions:

  • Am I supposed to setup some bit/flag in the MCU which cause this behavior?
  • May it be problem with format of the string?
  • Am I just completely missing something what I should do before/after I send the data from PC/MCU?

What did I try:

  • I tried to find some solution on internet but I can't find nothing
  • As experimentation I tried nothing because honestly I'm completely clueless what the problem could be

I would really appreciate any help even with refactoring/other coding tips.


Answers to comments:

  1. Could you print values as hexadecimal and add number of these elements?

The output:

ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc >ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc >ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc >ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc >ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc 53 65 6e 64 65 64 20 74 65 73 74 20 73 74 72 69 6e 67 21

Number of these characters is always BUFFER_SIZE + 8 and the character in decimal is represented as -52


Solution:

  • I already added 4th parameter into functions WriteFile() and ReadFile() and the problem wasn't there (but it definitely can cause some problems because documentation says the last two parameters can't be both NULL).
  • I found somewhere in documentation that ReadFile() should always come after event occurs and function WaitCommEvent() catch it. The type of event is set by SetCommMask(mainCom, EV_RXCHAR) so it occur when there's character in input buffer (there's documentation to function SetCommMask()). This solution shows the error is caused by the board which doesn't send the data because WaitCommEvent() will end up in infinite loop waiting for receiving data. However without using WaitCommEvent() it seems like the sent data are held by some kind of memory and read from there so even when the board doesn't send them, they're printed (I really don't understand why but see @thebusybee answer). What actually repair the problem is just simple reconnecting the board every time I boot windows (after reconnecting is everything functional even with using WaitCommEvent()) which leads me into completely different question if windows is sending some weird stuff into USB ports when booting so it mess with the board but that's for another topic. It could by also caused by windows using different communication parameters (as baud rate etc.) while booting. But that's for another/different question.
Wartiik
  • 33
  • 5
  • 1
    You have two "newline"s in your format string for the output: `"\nYou sent: \n\n%s\n\n"`. This inserts an empty line. – the busybee Jan 08 '23 at 11:46
  • @thebusybee So I edited question and to clarify, my problem are these `╠` before the correct string not empty lines. – Wartiik Jan 08 '23 at 12:26
  • 1
    I note that `receivedString` is declared with 124 elements, but more than 124 characters are being printed in the in the slot represented by the corresponding `%s` in the output format. However, I don't see any reason why the `ReadFile()` call presented would read that many bytes. It might be worthwhile to use the fourth parameter of `ReadFile()` to get that function's own idea of how many bytes it read. – John Bollinger Jan 08 '23 at 13:32
  • Is the number of `╠` characters consistent from run to run? – John Bollinger Jan 08 '23 at 13:42
  • I don't know whether it is significant, but your `stringToSend` array ends with *two* null characters (one explicit in the initializer and one implicit). You write both to the serial port, and allow for reading both back. However, the MCU code expects only one null or newline character to terminate a message, and it will send back only one (per message). – John Bollinger Jan 08 '23 at 13:53
  • @JohnBollinger So I quickly tested how many characters are there and yes, It's consistent but if I change `BUFFER_SIZE` then there will appear more of them so It's increasing with `BUFFER_SIZE`. For the info if `BUFFER_SIZE = 124` then there's __132__ these characters. When I increase the value to `BUFFER_SIZE = 1024` then there's __1032__ of these characters. If I change `stringToSend[] = "A\0"` and decrease `BUFFER_SIZE = 1` then there's __9__ of these characters. – Wartiik Jan 08 '23 at 13:55
  • So it's `BUFFER_SIZE + 8`, then. Interesting. That very much suggests that the problem is on the Windows side, because the buffer size is never communicated to the MCU. – John Bollinger Jan 08 '23 at 13:57
  • 1
    I don't think it should be necessary in this case, but what if you declare `receivedString` with an initializer? `char receivedString[BUFFER_SIZE] = {0};` – John Bollinger Jan 08 '23 at 14:03
  • 1
    According to [the docs](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile), the fourth and fifth parameters to `ReadFile()` cannot both be null. – John Bollinger Jan 08 '23 at 14:09
  • So If I initialize `receivedString` like that it will return nothing and at the end of the program `receivedString` just string full of `\0` – Wartiik Jan 08 '23 at 14:11
  • 1
    What seems to be happening is that the data read by `ReadFile()` are going to the wrong place -- 8 bytes after the end of the `receivedString` buffer. I don't know why that would be, but do not overlook my previous comment about the parameters to `ReadFile()` -- the last two should not both be null. The same applies to `WriteFile()`, too. – John Bollinger Jan 08 '23 at 14:13
  • You might need to [edit] the title as well, because it prominently asks about this empty line and says nothing on the real problem. – the busybee Jan 09 '23 at 08:31
  • Well, thanks for your try. Unfortunately it says just the same in other words. But your real issue is not the empty line, this is clear from your format string. The real issue is the wrong place the received string is stored, as you in the meantime revealed. Would you mind to edit it again? – the busybee Jan 09 '23 at 16:37
  • @thebusybee Can you please tell me how would you title this problem? Honestly I was thinking just like "What I was searching to find the solution before I asked question here" and that's it. I have no problem with editing I just really don't know how to name it better – Wartiik Jan 09 '23 at 20:31
  • What do you think of "Why do I receive characters at an offset in the buffer when using ReadFile()?" and tags for winapi and serial-communication? – the busybee Jan 09 '23 at 20:36
  • Sounds good to me so I changed it, hope now is everything alright. Thanks for helping me with that – Wartiik Jan 09 '23 at 20:42
  • 1
    `receivedString, sizeof( stringToSend )` - copy/pasta bug? Should be `sizeof( receivedString )`. You also didn't check how many bytes were read. I suspect that zero bytes were read, so you are printing uninitialized data. – Raymond Chen Jan 09 '23 at 20:43
  • @RaymondChen This function parametr is telling maximum possible amount of bytes which will be read that's why it's alright because in this example I'm trying to send string so I can't read more bytes then I sent. – Wartiik Jan 09 '23 at 20:47
  • Why, @RaymondChen? The program indeed expects to receive `sizeof( stringToSend )` bytes. If `stringToSend` were larger than `receivedString` then that would be an issue, but it's not. – John Bollinger Jan 09 '23 at 20:47
  • Another experiment: Instead of printing the received characters as a single string, would you mind to print each of them as hex? And the number of received characters? It could be helpful to see the bytes that are rendered here as `╠`. – the busybee Jan 09 '23 at 21:28
  • You're lucky that `sizeof(stringToSend)` is less than `BUFFER_SIZE`. If you really intended to receive only `sizeof(stringToSend)` bytes, then why is the size of `receivedString` unrelated to `sizeof(stringToSend)`? Someday, you'll make `stringToSend` bigger, and then `receivedString` will not be big enough and you get a buffer overflow and a CVE. – Raymond Chen Jan 09 '23 at 22:17
  • @RaymondChen Oh yes, you definetly got point there. I didn't realize that I'm actually making the string just for 124 chars so it may overflow really easily. Thank's for that. – Wartiik Jan 09 '23 at 23:05

1 Answers1

3

ReadFile() does not read any bytes from the serial device because of your erroneous call with both last parameters set to NULL. However, ReadFile() did not return FALSE.

The values 0xCC (printed sign-extended as 0xFFFFFFCC) that are filled into receivedString are used as debug aid.

Your PC's compiler apparently locates the variable receivedString before the variable stringToSend on the stack. The additional bytes are most probably canary words.

When you now print receivedString, the function printf scans through the memory until it finds a terminating '\0'. This is the case after the contents of stringToSend was scanned additionally and copied to the output. So what you see is not received by ReadFile(), but the existing characters of stringToSend, which happens to be exactly what you expect to receive.

This visualizes the memory situation:

(lower address)... receivedString padding stringToSend ...(higher address)
0xCC, 0xCC, ... 0xCC 0xCC, ... 0xCC 'S', 'e', ... '!', '\0'

What should you do?

  1. Never ignore any return and output values. Check the number of actually read bytes, in this case.
  2. Always read the documentation of a function and use it accordingly. Commonly, and I'm afraid to say this, especially on Windows, the principle "garbage in, garbage out" holds true.
the busybee
  • 10,755
  • 3
  • 13
  • 30