ASCII decimal 10 is line feed (<LF>
). ASCII decimal 13 is carrige return (<LF>
).
You're most likely victium of implicit <CR><LF>
⇄ <LF>
conversion; Wikipedia explains it in detail but in summary it's rooted in technological history:
When computers were given text input/output capabilities for the first time, this was not done through displays, but teletypes. A teletype is essentially a mechanical typewriter, where each "key" can be hit also by an electrical signal.
Typewriters, and thereby teletypes distinguished between advancing the paper a line (line feed), and returning the carrige (the typing head) back to the start of a line.
The ASCII encoding was created as essentially a 1:1 mapping of the functions of a typewriter to binary patterns.
The net effect was, that in order to start a new line on a teletype you'd have to send a line feed (<LF>
) together with a carrige return (<CR>
), the order of the two doesn't exactly matter, the physical effect is practically the same.
However different operating systems settled on different default conventions how to store and transmit newlines:
MS-DOS and by inheritance Windows chose to explicitly store both <CR>
and <LF>
in that order.
Unix chose to store the <LF>
only and translate it into a <CR><LF>
sequence when sending it to a teletype, and do it vice-versa on reception. Linux adopted this Unix convention.
When it comes to the transmission over a serial link, the default however always has been, that for a newline a (<CR>,<LF>)
pair should be transmitted, in expectation of the other end being a teletype. And this is, what's likely going on here! The actual data transmitted over the wire is a <CR><LF>
but the receiving OS having inherited the ways of Unix silently converts it into a plain <LF>
. And for any number bigger than 255 this conversion will happen to its lower 8 byte, together with dropping a whole byte.
Of course this default behavior can be reconfigured, namely through termios/ioctl_tty on the opened serial port, specifically the output and input option flags (namely the flags OPOST
, ONLCR
, ONLCR
, OCRNL
, ONLRET
, INLCR
, IGNCR
, ICRNL
).
However I strongly suggest you don't fiddle with these flags and instead take the following two lessions to heart:
Plain text is the universal exchange format! (i.e. don't submit raw binary over a wire, if you can avoid it, but send it as – also human readable – text)
Be liberal in reading what you receive; be conservative in what you send! (i.e. write your program in a way, that reading data is not dependent on a strict order and format of the data, i.e. may tolerate any kind of newline sequence or number of whitespace delimiting field; but also send data in a strict regular way so that less liberal receivers don't choke on it)