EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

Software architecture using C for mid-range PIC.

Started by Fevric J. Glandules September 9, 2009
In article <h8en5s$ets$1@news.tornevall.net>, fjg@invalid.invalid says...
> Hans-Bernhard Br=F6ker wrote: >=20 > > Fevric J. Glandules wrote: > >> Hans-Bernhard Br=F6ker wrote: > >>> Fevric J. Glandules wrote: > > > >> The command set is fixed, and consists of about 30 ASCII triplets, and=
=20
> >> with any luck won't change too much.
So put the list of triplets in a command table, that means it is easy to maintain, then have a matching table of functions to jump to. If you are clever then if the last digit refers to a mode you only match the first two and then process the last digit appropraitely. Especially if the command set is two digit alpha for function and third digit is numerical parameter. With a command table you can choose whether to match all three or the first 1 or 2 characters, so the rest are checked by the called=20 function. Alternatively you can decode the last digit if it is always numerical and pass that to the called function.
> > Encoding a mere 30 commands as three-letter tokens is excessively=20 > > redundant. I would strongly suggest to abbreviate further, to one or=
=20
> > two letters. =20 >=20 > So would I <grin> but the spec says (e.g.) "0x01 0x44 0x45 0x41 0x03" > [0] i.e. "start-byte ascii ascii ascii end-byte" and the chip that's > talking to me says the same too. I'm not designing [1], I'm > implementing. If the spec says "jump" I ask "how high?". Only if=20 > the spec says "jump off a cliff" do I raise objections.
A scan of command table is easy to write in C or even assembler. If all commands start and end with the same byte sequence the processing can be easier, and these bytes handled before processing the data between the terminators by scanning a command table. Also a command table allows you later add a four or larger command as=20 well. =20
> >> Meanwhile I've got a little less than 4K of RAM to play with <grin>.
In 1983 I wrote an application to control TV studio Digital Video Effects controller on an 8 bit micro, that had debug routines to enable the maintenance and developers to examine memory, registers, devices and had a command line structure that decoded additional numerical/alpha=20 parameters. This sat in an 8 bit processor with external RAM of 2kBytes for the whole application with over 1kBytes of the RAM spare! All written in assembler. I have since rewritten and used similar code or reused similar code in C.
> > You could still use a perfect hash function. That would basically=20 > > amount to letting a machine condense your command set to single letters=
,=20
> > in whichever way it liked. > > > > Or you could combine all three letters into a single number, then=20 > > switch() directly on that: > > > > =09switch((u16)buf[0]<<16 + (u16)buf[1]<<8 + (u16)buf[2]<<0) > > > > and let the compiler decide how to implement that most efficiently. >=20 > Let me guess - you live in a 32 bit world, right? <grin>
I have done command table with index jump on an 8 bit processor, it is nothing new. If you build the right flexibility into the command table handling once, you can make all your command processing easier and smaller. Some of my command table implementations, include=20 =09min. max character match =09min, max parameters on same line =09System mode that command can be entered in =09different tables sometimes for which mode of operation. =09function(s) to call. (same code different table) Then generalised functions deal with parsing, function calling, parameter checks, parameter conversions, error reporting handling.
> This is an 8 bit chip, and from what I've seen of its output, the=20 > C18 compiler isn't all that brilliant [2]. I think this is very > much a case of using C as a "high level assembler" - assume that > the compiler will treat everything literally and if it does manage > to optimise every now and then, it's a bonus.
I personally would not use a PIC, but have used various small processors to do this sort of command processing, even ones with binary packet transmissions. --=20 Paul Carpenter | paul@pcserviceselectronics.co.uk <http://www.pcserviceselectronics.co.uk/> PC Services <http://www.pcserviceselectronics.co.uk/fonts/> Timing Diagram Font <http://www.gnuh8.org.uk/> GNU H8 - compiler & Renesas H8/H8S/H8 Tiny <http://www.badweb.org.uk/> For those web sites you hate
Paul Carpenter wrote:

> So put the list of triplets in a command table, that means it is easy to > maintain, then have a matching table of functions to jump to. >
Table driven methods are invariably the best way to deal with this, as there will always be more commands later. The standard way here is to define the parse table as a n way linked list of nodes, where each node has a table of valid chars at that node, and associated links to either another node or function pointer to exec the command. As the syntax is defined by the structure of the tree, it can handle command sequences of any length. It works well for small and large command sets and the code to drive it just becomes a list processor, around a dozen lines of C from start to end. Also, you only have to write the code once, a new syntax just needs a new set of node definitions. Regards, Chris
ChrisQ wrote:

> Table driven methods are invariably the best way to deal with this, as > there will always be more commands later. The standard way here is to > define the parse table as a n way linked list of nodes, where each node > has a table of valid chars at that node, and associated links to either > another node or function pointer to exec the command. As the syntax is > defined by the structure of the tree, it can handle command sequences of > any length.
And if you are lazy and don't want to write tree tables by hand, you can use flex for it. This one, just in case you don't know it: http://flex.sourceforge.net -- Frank Buss, fb@frank-buss.de http://www.frank-buss.de, http://www.it4-systems.de
On Sep 12, 5:24=A0pm, Frank Buss <f...@frank-buss.de> wrote:
> ChrisQ wrote: > > Table driven methods are invariably the best way to deal with this, as > > there will always be more commands later. The standard way here is to > > define the parse table as a n way linked list of nodes, where each node > > has a table of valid chars at that node, and associated links to either > > another node or function pointer to exec the command. As the syntax is > > defined by the structure of the tree, it can handle command sequences o=
f
> > any length. > > And if you are lazy and don't want to write tree tables by hand, you can > use flex for it. This one, just in case you don't know it: > > http://flex.sourceforge.net > > --
Or if more lazy and using C define a structure that contains a pointer to a const string and a pointer to the function that handles that particular string. Declare an intitilised array of this structure. Also been using it since the assembler days on a Z80 and now on the 8052 and the PIC in C.
Rocky wrote:

> Or if more lazy and using C define a structure that contains a pointer > to a const string and a pointer to the function that handles that > particular string. Declare an intitilised array of this structure. > Also been using it since the assembler days on a Z80 and now on the > 8052 and the PIC in C.
Yes, this is possible for very simple protocols. If you have many commands or some kind of syntax, flex is better, because you can match tokens with regular expressions. Maybe combined with Yacc, or your own simple recursive descent parser. -- Frank Buss, fb@frank-buss.de http://www.frank-buss.de, http://www.it4-systems.de

Fevric J. Glandules wrote:

> Bob wrote: > > >>I'm always amazed at how hung-up programmers get about parsing. If you >>have the authority to define the command set, you can make it easy on >>yourself by having fixed length commands; Even a single character (A - >>Z, e.g.) might suffice. > > > That's probably what I would have done; OTOH at least they are all > exactly three characters long.
Create an unambiguous fixed width binary protocol over RS-232. Implement some basic integrity checking (such as checksums) so the occasional garbage characters would not be interpreted as the valid commands. Create a PC GUI application to communicate to your device. The common users love GUI and hate command line and batch files. Depending on your application, it could make sense to stick with a standard protocol, such as MODBUS. This makes the things lot simpler for both developers and users. Vladimir Vassilevsky DSP and Mixed Signal Design Consultant http://www.abvolt.com
Frank Buss wrote:
> Rocky wrote: > >> Or if more lazy and using C define a structure that contains a pointer >> to a const string and a pointer to the function that handles that >> particular string. Declare an intitilised array of this structure. >> Also been using it since the assembler days on a Z80 and now on the >> 8052 and the PIC in C. > > Yes, this is possible for very simple protocols. If you have many commands > or some kind of syntax, flex is better, because you can match tokens with > regular expressions. Maybe combined with Yacc, or your own simple recursive > descent parser. >
I've never used flex or yacc, perhaps because every time I look at it, it seems to be more than I really need for simple command parser. It's probably very good if you want to write a compiler, but most embedded command processors use a simple syntax to reduce processing overhead. Have also looked at tcl some years ago, but once again, more than is really needed to do the job, or there were bits I just didn't like, or just simply that it's easier to pull a previous library module out, copy, edit, resave under a new name, to do the job. What would be ideal would be a sort of half way house between flex and table editing manually. Something that is aware of the defined data structures and allows some sort of simplified formal language specification, which then gets compiled into the tables. The key thing here is 'aware of the data structures', which basically means do it yourself. Thus, all there is at present is a set of macros to make the table editing easier. There's a lot of difference between a true command language syntax, for example 'set voltage 24-e3', where it's often easier to use a tokeniser followed by lexical and syntax analysis and the sort of fixed format protocol embedded commands: cmd arg1 arg2 ... arg-n cmd is fixed at 1 to n chars long, with a variable number of args. It's quite easy to write a completely deterministic parser for this using the tree of nodes method, with everything that doesn't match defined as an error. Because there's not much of it, it's quite easy to follow and understand. Contrast that with the typical method of deeply indented case statements implementation, which just becomes unreadable after a couple of pages :-)... Regards, Chris
Vladimir Vassilevsky wrote:
> > > Fevric J. Glandules wrote: > >> Bob wrote: >> >> >>> I'm always amazed at how hung-up programmers get about parsing. If >>> you have the authority to define the command set, you can make it >>> easy on yourself by having fixed length commands; Even a single >>> character (A - Z, e.g.) might suffice. >> >> >> That's probably what I would have done; OTOH at least they are all >> exactly three characters long. > > > Create an unambiguous fixed width binary protocol over RS-232. Implement > some basic integrity checking (such as checksums) so the occasional > garbage characters would not be interpreted as the valid commands. > Create a PC GUI application to communicate to your device. The common > users love GUI and hate command line and batch files. Depending on your > application, it could make sense to stick with a standard protocol, such > as MODBUS. This makes the things lot simpler for both developers and users. > > > Vladimir Vassilevsky > DSP and Mixed Signal Design Consultant > http://www.abvolt.com
DO NOT use MODBUS. The protocol has tight timing requirements for the characters in a packet and for the intervals between packets. It is practically impossible to create a MODBUS program with proper timing running in a PC (Windows or whatever). Yes, there are MODBUS programs for PC's, but I have not seen yet one with the timing according to the bus specifications. -- Tauno Voipio tauno voipio (at) iki fi
Fevric J. Glandules wrote:

> Let me guess - you live in a 32 bit world, right? <grin>
Erm ... no.
> This is an 8 bit chip, and from what I've seen of its output, the > C18 compiler isn't all that brilliant [2].
Well, I won't be held liable for you having bad tools. If you really can't trust your C compiler to generate efficient code for a sparse switch on a non-minimal integer type, and since you appear to be allergic to any and all code generators, go ahead and code it yourself: binary search in a table of {command_string,action_function} structs, sorted by command_string. Points will be deducted for using any standard library function like bsearch(), of course. ;-)
ChrisQ wrote:

> understand. Contrast that with the typical method of deeply indented > case statements implementation, which just becomes unreadable after a > couple of pages :-)...
Yes, I think my switch / case thing is headed for /dev/null. Thanks to all for the pointers. I'll be looking into some sort of command table / tree in due course.

The 2024 Embedded Online Conference