How fail-safe is \n\r as stop bytes?
There are different ways to prevent this:
- Make sure you never send a 10/13 combination in your regular messages (so only as stop bytes). E.g. to send 20 21 22 23 24 25:
20 21 22 23 24 25 10 13
- Escape 10 and 13 (or all non ASCII characters with an escape character e.g. . So to send 20 21 10 13 25 26 send: (see comment of/credits for: DanW)
20 21 1b 10 1b 13 25 26
- Define a packet when sending messages. E.g. if you want to send message 20 21 22 23 24 25 than instead add the number of bytes to sent, so the package is:
< nr_of_data_bytes > < data >
If your messages are max 256 bytes send:
06 20 21 22 23 24 25
So you know after receiving 6 data bytes that is the end; you don't have to send a 10 13 afterwards. And you can send 10 13 inside a message. If your messages can be longer, you can use 2 bytes for the data size.
Update 1: Another way of defining packets
Another alternative is to send commands which have a specific length and can have many variances, e.g.
10 20 30 (Command 10 which always has 2 data bytes)
11 30 40 50 (Command 11 which always has 3 data bytes)
12 06 10 11 12 13 14 15 (Command 12 + 1 byte for the number of data bytes that follow)
13 01 02 01 02 03 ... (Command 13 + 2 bytes (01 02 for 256 + 2 = 258 data bytes that follow)
14 80 90 10 13 (Command 14 that is followed by an ASCII string ending with 10 13)
Update 2: Bad connection/byte losses
All of the above only work when the UART line is sending bytes correctly. If you want to use more reliable ways of sending, there are also many possibilities. Below are a few:
- Sending a checksum within the package (check google for CRC: Cyclic Redundancy Check). If the CRC is ok, the receiver knows the message has been sent ok (with high probability).
- If you need a message to be resent, than an acknowledgement (ACK/reply) mechanism needs to be used (e.g. sender sends something, receiver receives corrupt data, sends a NACK (not acknowledged), sender can than send again.
- Timeout: In case the receiver does not get an ACK or NACK in time, a message needs to be resend.
Note that all above mechanism can be simple or as complicated as you want (or need) to be. In case of resending message, also a mechanism for identifying messages is needed (e.g. adding a sequence number into the package).
How fail-safe is \n\r as stop bytes?
If you send send arbitrary data -> probably not fail-safe enough.
A common solution is to use escaping:
Let's define that the characters 0x02 (STX - frame start) and 0x03 (ETX - frame end) need to be unique within the transmitted data stream. This way the start and the end of a message can be safely detected.
If one of these characters should be send within the message frame, it is replaced by prefixing an escape character (ESC = 0x1b) and adding 0x20 to the original character.
Original character replaced by
0x02 -> 0x1b 0x22
0x03 -> 0x1b 0x23
0x1b -> 0x1b 0x3b
The receiver reverses this process: Anytime he receives an escape character, this character is dropped and the next character is subtracted by 0x20.
This only adds some processing overhead but is 100% reliable (assuming no transmission errors occur, which you could/should verify by additionally implementing a checksum mechanism).
You know, ASCII already has bytes for these functions.
- 0x01 : start of heading -- start byte
- 0x02 : start of text -- end headers, begin payload
- 0x03 : end of text -- end payload
- 0x04 : end of transmission -- stop byte
- 0x17 : end of transmission block -- message continues in next block
It also has codes for various uses inside the payload.
- 0x1b : escape (escape the next character -- use in payload to indicate next character is not one of the structure describing codes used in your protocol)
- 0x1c, 0x1d, 0x1e, 0x1f : file, group, record, and unit separator, respectively -- used as simultaneous stop and start byte for parts of hierarchical data
Your protocol should specify the finest granularity of ACK (0x06) and NAK (0x15), so that negative acknowledged data can be retransmitted. Down to this finest granularity, it is wise to have a length field immediately after any (unescaped) start indicator and (as explained in other answer(s)) it is wise to follow any (unescaped) stop indicator with a CRC.