I'm learning by doing how to connect a gadget to my PC via RS-232. The CPU is a TI TMS320F2812. At first I wish to implement a simple terminal server on my gadget so that I can command it and set some parameters with text commands typed into a serial terminal.
The TI code generation tools include a run time support library (rts.lib) which includes most of C stdio.h calls. It also has a means to register one's driver functions modeled after read(), write(), etc. so that any peripheral IO may take place via stdio.h calls.
I have chosen not to do this with the serial communications interfaces (SCI) for the reason that serial IO is not very file-like, and also that the amount of code that will pull in from rts.lib is undesirable. So I have written my own low-level drivers and higher-level IO calls, but modeled as close as possible to C stdio.h in usage.
Since the "streams" in this case are always a SCI peripheral, I have named all the calls SCIx_yyyy() where x is either 'a' or 'b' and "yyyy" is a name similar to a C stdio.h call.
Unlike the usual low-level/high-level hierarchy however, I have reversed the roles of SCIx_putc()/SCIx_getc() such that they are the lowest-level calls. This is because the interface is fundamentally a character at a time, rather than a block interface. So it makes sense to have the character calls at the lowest level. Error checking also has to be done on a char by char basis, so this pretty much cements this decision.
On top of those are SCIx_puts() and SCIx_gets() and later I will write SCIx_read() and SCIx_write() for binary block IO.
Now things get interesting because if for instance I'm calling SCIx_gets() and a terminal is sending data, then the terminal typically terminates a line with '\r' rather than '\n' which a traditional gets() expects. Also, standard gets() returns when an EOF occurs, but on a serial link EOF might be returned from SCIx_getc() simply because the next char hasn't arrived yet. This latter situation I've dealt with by having SCIx_gets() return NULL immediately if called and no char is available (like the standard behavior). But if it is called and finds one char, it then blocks and keeps polling SCIx_getc() despite EOFs until either the buffer is full or a line termination char is encountered.
To deal with line termination characters I have configurable modes for SCIx_gets() so that I can tell it to end the string reading if '\n' or either of ('\r' || '\n') is found. I can also configure it to store or not store the line terminating char into the buffer. Thus, I can make it act like gets() or fgets() regarding whether the 'newline' is stored into the buffer. But it always acts like fgets() by respecting a buffer size argument!
Now I've discovered another complication. Some terminals when in local echo mode return the cursor to the left and give a new line when is pressed (minicom) while others only return to the left with no newline (TerraTerm).
This has led me to question which way is better, to use local echo or not? Not using it is sounding better the more I think about it. The reasons are: 1. you know for sure the gadget received your command because it must echo it back to you. So if you don't see anything while you type, then you know something's broke. 2. No local echo means the gadget has total control over the cursor in the terminal, so you don't have to worry about whether one terminal returns and newlines, vs. just returning when is pressed.
Ok. So I'll probably move away from local echo. But now another complication: What to do when the user hits backspace?!?! Or any other special keys?
Backspace seems like an important one, since implementing it as an actual backspace could be valuable. The other keys can just send their jibberish, and the command parser will just reject this forcing a re-type.
I think as long as I'm not relying on local echo, then actually there's little worry of my gadget getting something different than what the user thinks they sent.
The bad thing is, this means I have to write more code into SCIx_gets() to do the echoing. Because the way things are organized now, remote echoing would have to be done at that level.
This is the first time I've tried to do anything like this. If you'd like to comment on the concepts of my design and the path I'm taking, or how folks "usually do it" please do so.
Thanks for input.