The key to the ASCII approach is to design the protocol so that the parser is as simple as possible. Ideally, parser = small finite state machine, so that protocol = regular grammar. Write the protocol and the parser together. If the parser starts to get tricky, change the protocol.
This may result in a protocol with false hopes for human-
writability, which will utterly fail as soon as someone else tries to communicate with it, finding all those nice little "design simplifications" that prevent it from working using anything else than your specific encoder.
Well, when it's an actual human commanding it, we can at least use our fairly complex
AI system to automatically adjust timing, sequencing, parsing... But it'll get fairly difficult when we need to write some code to do that. So, we end up looking at your parser code (if available), or documentation, and work it out "manually". In which case, ASCII becomes totally unimportant, and most likely only an extra complication. The only advantage left is human-
readability. (Well, you can do worse: for example, use XML, and you won't have either human-writability or human-readability, yet you have hopes for both!)
I spent days trying to initialize a LIDAR which has total of 7 bits of configuration and command space, which would fit inside one single octet without any framing issues, but instead it implements an "easy" ASCII interface, with tens of pages of documentation, with all kinds of nasty surprises regarding timing - for example, it just outright ignores
some commands at
some times (and doesn't give feedback on success/failure) and replies back unexpected things, so you need a fairly complicated parser in the FSM. The funniest part? After configuration and turn-on command (which could have been one freaking single byte), it switches to a simple binary interface (which just works) for the data, since the actual data would have too much bandwidth for ASCII overhead
. So there is no human readability anyway.
In simple projects, I tend to use this ASCII format:
Commands (PC->MCU): everything must fit in one byte. If not, go for something else. For example, I have used these:
c: start charging
d: start discharging
s: stop
Or in another project:
o: open the door
c: close the door
s: stop the door
Status (MCU->PC): Everything is a label=value pair, separated with spaces
time=100 curr_limit_setpoint=123 power=234 voltage=4200
This is far from perfect, but there is certain simplicity in it; especially the fact that the MCU parser will be simple-and-robust as hell because there is no framing or any state in the parser.
And, this is well controllable by both human and simple computer programs; and it's human readable (as long as one line of status fits nicely on the terminal screen line) - I tend to pad values with leading zeroes to force nice alignment. Haven't seen any problems parsing that - all atoi() and scanf() style implementations work with leading zeroes just fine.