Terminal server design & serial driver subsystem

Hi:

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.

--
Good day!

________________________________________
 Click to see the full signature
Reply to
Chris Carlen
Loading thread data ...

I always ignore block- or line-oriented serial I/O, and implement character-based I/O. I don't use local echo for the reasons you describe, and implement all upper-level functions myself based on what character is received (CR or LF act as line ends, and I implement backspace "manually"). I also actively limit the number of characters received in a single line, of course.

Hope this helps,

Steve

formatting link

Reply to
Steve at fivetrees

Hi Chris, welcome to the world of embedded serial interfaces.

[%X]

[%X]

[%X]
[%X]

Seems that what you need is a good primer on serial communication protocols. The following links may be a useful start but I am also listing a couple of books that may also help you out.

Books:- "Frontpanel - Designing Software for Embedded User Interfaces" by Niall Murphy. R&D Books ISBN 0-87930-528-2

"The Hackers Handbook III" by Hugo Cornwall Century-Hutchinson Ltd. ISBN

0-7126-1147.

This is not specific to any protocol but has some useful advice about the things to consider in system interfaces.

Getting a decent and robust interface does take some work. However, if you are methodical about considering the potential problems that the interface may face and can code the simplest interface that will deal with all of those problems then you should get a robust end result.

I have worked with serial protocols a lot in my years in the computing and embedded systems industry. There are very many standard protocols available and selecting which one you use can sometimes be more arduous than just sitting down and designing your own.

As you have declared you are doing your protocol on a character by character basis it is worthwhile getting to understand the ASCII control characters and their purpose (where the Hackers handbook helps a bit). There are other references that can also help there and I think some of those are listed in the links above. Playtime in protocol development can be very rewarding in terms of your deeper understanding so go ahead and play (so long as you are only playing safely).

Considering where you are working I would have thought your own company library would have had some useful books on the topic.

--
********************************************************************
Paul E. Bennett ....................
 Click to see the full signature
Reply to
Paul E. Bennett

Judging from who do you work for, is your gadget a nuke or something like that? Just don't forget to ask for the user confirmation before a bang :-)

Strongly agree. I don't like the libraries like that and always develop the low level drivers of my own.

[...]

I use the terminal I/O only for the debug purpose. The upper level interface to it is identical to stdio:

printf(UART *uart, char *format, ...) sscanf(UART *uart, char *format, ...) etc.

Any combination of CR, LF and \0 is considered to be the terminator of the line.

For the actual product, I use application specific binary protocols over RS-232 and the PC host application programs. It is hardly possible to make a convenient and robust user interface using just standard terminal i/o.

Vladimir Vassilevsky DSP and Mixed Signal Consultant

formatting link

Reply to
Vladimir Vassilevsky

Don't worry, it's just a small 350kT one.

Seriously though, I don't work in that field. I work in engine research. This project is for a tool that I will use to develop a new engine controller system for our engine research labs. The tool is a dual shaft encoder simulator, which simulates the signals coming from a crankshaft QEP and a camshaft gray-code encoder.

I like to gain a large degree of confidence with a new method before deploying on the finl product. So I often test things out at the development tool level.

Well I'm not sure I will go all the way up to printf/sscanf.

I see.

Really? This sounds kind of funny. What about SCPI? Actually, I am interested in text-based interface because I'd like to move in the direction of implementing SCPI subsets for my custom instruments.

Also, there is the terminal interface to my OS, Linux, which seems robust.

What do you mean by: > It is hardly possible to make a > convenient and robust user interface using just standard terminal i/o.

Thanks for the reply.

--
Good day!

________________________________________
 Click to see the full signature
Reply to
Chris Carlen

Thanks for the input.

Question: what do you mean, >...I implement > backspace "manually").

--
Good day!

________________________________________
 Click to see the full signature
Reply to
Chris Carlen

Way too primitive and limited.

I would use a sensible GUI over whatever protocol at low level.

My desktop OS is XP, and I see no reasons to complain about it either.

  1. With the standard terminal I/O, you can only enter parametes. It is very inconvenient to tweak the values. Something like a slider bar is much more suitable for that purpose.
  2. As you already noticed, editing of the entered line is very inconvenient in a terminal. You should process not only backspace but arrow buttons, tabs, Ctrl-Y, Ctrl-C and such.
  3. Using the dumb terminal, you have to do all of the necessary calculations, range and parameter dependency checks on your target device. Because of that, the terminal I/O part of firmware can grow to the huge size, and it is also prone to errors. It is lot more convenient to do all of that on the desktop computer.

Vladimir Vassilevsky

DSP and Mixed Signal Design Consultant

formatting link

Reply to
Vladimir Vassilevsky

Not sure what Steve does, but here's how I do it:

- First make sure you're not at the start of your linebuffer

- Decrement linebuffer input size, to delete the char there

- Send to the terminal. Because alone often just moves the cursor left without erasing.

--
Stef    (remove caps, dashes and .invalid from e-mail address to reply by mail)
Reply to
Stef

Bingo!

;)

Steve

formatting link

Reply to
Steve at fivetrees

GUIs and terminals are two completely different kinds of user interfaces. If all you have is a terminal, that's what you use. If you want to wrap the terminal in a GUI and only send commands that the GUI has assembled, you can do that to - but it's a different ballgame. You can run a terminal with any serial terminal programme. A GUI needs a custom application - just to drive a serial link. Sometimes it makes sense, sometimes not.

With terminals, you have to support things like backspace - i.e. support humans. If you're dealing with a non-human protocol, you don't need to support live typing, and you can do all sorts of other things - like including a checksum. Even then, I tend to prefer an ASCII-based interface - firstly, it's human-readable, and secondly, it allows you (and your application) to distinguish data from control characters. Binary data is all very well, but....

Steve (probably not making a whole lot of sense - long day, long drive, dinner & two glasses of wine....)

formatting link

Reply to
Steve at fivetrees

As one who does include some primitive editing in the interface (simple line editing things like back-space, left and right arrow keys etc.) I think Vladimir is overstating the complexity of such. Yes, it does take some work to process those editing characters but they are very useful during the initial bring-up phase when you often have not yet formulated the GUI interfaces that would get the command strings totally correct before sending them down the wires or over the ether.

If you need some simple editing stuff, look at the sources for one of the free primitive Forth's which tend to have some simple line editors included.

--
********************************************************************
Paul E. Bennett ....................
 Click to see the full signature
Reply to
Paul E. Bennett

More than good enough if the time lag to see the effect of the tweak is more than a few seconds.

If it's going to be a robust device you will need all the range and paremeter checks on it anyway. To do otherwise strikes me as a trifle, umm........., optimistic.

Robert

--
Posted via a free Usenet account from http://www.teranews.com
Reply to
Robert Adsett

Thanks for the input.

I don't think I'll have trouble dealing with the editing. I wrote some editing string get routines in 8086 .asm a long time ago. I'll probably keep it limited to BS in the beginning, unless I get inspired to make it more thorough.

I'm convinced that a terminal interface is a good thing for initial development, and as a fall-back in case the later GUI app can't install on a PC, or a PC dies, and another needs to pinch hit to keep the lab running for an experiment. It's that fall-back that also makes the terminal interface attractive.

But I do appreciate the caution that it can develop to be a bigger thing than expected. At this point, I don't think it should be a problem.

Probably the next challenge will be figuring out how to tell the host to receive binary block data, and then get back out of that mode. Perhaps Xmodem, but maybe something simpler to start out.

Good day!

--
_____________________
Christopher R. Carlen
 Click to see the full signature
Reply to
CC

You have the right approach in my book. I tended to prefer Y-Modem for binary transfer. However, depending on your required level of communication integrity you might need to consider protocols that truly fully recover from errors in transmission. We will leave that for another day to suggest something as I am sure you will ask if you need any suggestions on that front.

--
********************************************************************
Paul E. Bennett ....................
 Click to see the full signature
Reply to
Paul E. Bennett

Which is probably what he would say in either case. ;)

--
Grant Edwards                   grante             Yow! I joined scientology
                                  at               at a garage sale!!
 Click to see the full signature
Reply to
Grant Edwards

The input can be checked on the PC side. The device should only verify the CRC over the block of parameters.

The problem is in the parameter dependencies. If A is set to 1 then B should be set to 2 and C should be close to (foo/bar) but no higher then sin(log(12345.6*(A+B)). There is no elegant way of implementation that using the terminal.

Vladimir Vassilevsky

DSP and Mixed Signal Design Consultant

formatting link

Reply to
Vladimir Vassilevsky

Nope, I don't buy that. The device should (I'm tempted to say must) be responsible for ensuring that its parameters are in the valid range.

Communations integrity is a good thing but it's no substitute for ensuring that the parameter you've recieved correctly are valid and consistent.

There's no elegant way of doing that. Full stop.

There are several possibilities here - You could be working with the wrong set of parameters. A different organization may result in a less entangled set. Not a likely possibilty if care has been taken but worth exploring. - Parameters may need to be set in order, i.e. it may be necessary to raise the power limit before raisin the current. - It may be necessary to change a block of values before thay are committed.

I would not be willing to rely on a PC program to ensure that parameters were valid. Too limiting and too risky.

Robert

--
Posted via a free Usenet account from http://www.teranews.com
Reply to
Robert Adsett

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.