|
|
|
|
|
|
|
||
|
||
|
|
||
May 1999 |
Revision 1.02 |
|
Persistor Instruments Inc. |
© 1998 All rights reserved. |
|
PicoDOS, while useful as a standalone program, has many more uses behind the scenes. While it is theoretically true that you can have a Persistor performing meaningful tasks without PicoDOS, we can hardly imagine it. PicoDOS provides valuable services that you can take advantage of from your own applications. It also provides all the POSIX-like file access routines and manages the DOS compatible file system for CompactFlash cards.
![]()
This section describes CMD - a modular, table driven command processor for dispatching commands sequences based on text strings with optional parameters. CMDs design was driven by two principal goals: an easily learned and consistent interface for casual users, and an easily learned and consistent interface for programmers to allow quick and predictable modifications and customizations.
Part one of this document is an overview of the capabilities and components that make up the CMD package. Part two describes CMDs syntax and user interface in interactive and batch modes for incorporation into end user documentation. Part three explains how to quickly create parameterized commands to add new functionality. Part four finishes with some details on CMDs implementation.
In the Examples folder in MotoCross Support, you will find a multi-target project called CMD Demos. This project contains three examples of gradually increasing complexity that you can use for examples and reference.
To the user, CMD appears as a fairly standard command line interface, similar to DOS or UNIX shell commands, and with only a few very well defined rules. The user sees a command prompt, then types in the command request with the appropriate arguments. The general format of a CMD command string is shown below and described in detail in the interactive mode section.
CMD[.opts][<delim>ARG...][/REP][;{<cmdstr>}...]<eos>
To the programmer, CMD appears as a well ordered table of command strings, prompts, help text and function pointers to implement the commands, formatted as shown below. Also make note of the #define macro before the table. This can be defined in only one source file in your project, but must be defined before any table definition as well as before the inclusion of cf1pico.h for CMD to work. This means that if you have multiple command tables, you must either put all of them in one source module or make sure that the file that contains the #define is first in the link order.
#define PD_CMD_BUILD_LINKS
#include <cf1pico.h>
CmdTable DemoCmdTable[] =
{
// PROMPT HANDLER 2COLS DEF CR ABV HEADER TEXT
"CMDDemo>" ,PDCCmdStdInteractive, 0, 10, 1, 1, "CMD Processor Demo\n"
// COMMAND COMMAND MIN PRV CR NUM SHORT HELP TEXT
// NAME FUNCTION REQ LEV REP BASE EMPTY STRING "" TO
// (CONSTANT) POINTER ARG REQ OK 0=NO OMIT FROM HELP LIST
,"DEMO" ,OurDemoCommand, 0, 0, 0, 0, "Our command"
,"EXIT" ,PDCCmdStdBreak, 0, 0, 0, 0, "Back to command mode"
,"QUIT" ,PDCCmdStdBreak, 0, 0, 0, 0, "Back to command mode"
,"HELP" ,PDCCmdStdHelp, 0, 0, 0, 0, ""
,"HE" ,PDCCmdStdHelp, 0, 0, 0, 0, ""
,"H" ,PDCCmdStdHelp, 0, 0, 0, 0, ""
,"?" ,PDCCmdStdHelp, 0, 0, 0, 0, ""
,"RES" ,PDCResetCmd, 0, 0, 0, 0, ""
,"CMD" ,PDCCmdStdCmdTest, 0, 0, 0, 10, ""
// TERMINATING ENTRY (!!!!This must be present at end of table !!!!)
,"" , 0, 0, 0, 0, 0, 0
};
For all but the most complex applications, the programmer needs only to define a table and add about a half - dozen lines of code to start the command processor running. To further simplify programming, CMD pre-parses the command line and provides a suite of utility functions to simplify extracting argument values, allowing you to focus coding efforts on task at hand.
This section describes the user interface as implemented using the standard CMD default behaviors. To learn how to add, modify, or remove commands and arguments, refer to the next section on adding commands. To customize the user interface, refer to the last section on implementation details.
Cmd operates on strings containing one or more command sequences. Command sequences consist of a command token (substring) separated from optional arguments. You can use upper or lower case characters since CMD always converts your input to upper case (except for arguments inside pairs of double-quotes). The command token is matched (exact match only) against the entries in the command table. If no match is found, CMD returns an error string suitable for display. If a match is found, CMD verifies the parameters against rules in the command table, returning either an error string, or the result of executing the function associated with the command.
Before the associated function gets called by CMD, the optional arguments and parameters will have already been parsed and prepared for use by the function. Below is the format of a CMD command string, followed by a detailed description:
[???]CMD[.opts][<delim>ARG...][/REP][;{<cmdstr>}...]<eos>
[???]
This is an optional prompting string provided by the implementer to indicate the current operating mode, and therefore hinting at the current allowable command set. Prompts are usually a two to five character word or acronym followed by a right angle bracket ('>').
[.opts]
This field allows you to modify the behavior of a command with character flags that are easily checked by the associated function. Displaying memory is typical example of opts usage. The default memory display might be a line of hex bytes, but could be changed to word, long word, or disassembled instructions with the following variants.
md 01000 (standard byte display) md.i 01000 (instruction display) md.w 01000 (word display) md.w 01000 (long word display)
<delim>
Arguments to commands must be separated by recognizable delimiting characters. Cmd recognizes a period ('.'), space (' '), tab ('\t'), or comma (',') as valid delimiters. Anywhere space or tab characters are allowed, multiple instances of the space or tab characters are simply skipped.
ARG...
Each command may contain up to eight arguments separated by the delimiters described above. The argument field is either a string argument or a numeric value. String arguments may be enclosed by double quote characters, otherwise they are converted to all upper case.
Numeric values may be decimal, hexadecimal, octal, or binary numbers, with the default radix determined by the implementation (typically decimal). All values must be in the range -2147483648 to +2147483647 ($0 to $FFFFFFFF). The default radix may be overridden by prefixing numeric entries with the following characters:
decimal number # hex number $ or 0 (zero) octal number @ binary number % - decimal number -
[/REP]
Each command may specify an optional repeat count after all of the arguments. Repeat is flagged by a slash character ('/') followed by a numeric value meeting the same requirements stated for arguments, with zero or negative arguments ignored. Be aware that a large repeat count may not leave you with a mechanism to escape from the execution loop.
[;{<cmdstr>}...]
The semicolon separates multiple commands on a single line. The number of command strings is limited only by the maximum line size which is typically eighty characters.
<eos>
This is the end of string marker, which is either a newline character ('\n', 0x0A) or a null character (zero).
Though not intrinsic to the CMD operation, most implementations will take advantage of CMDs built-in help menu tools. Usually, help can be invoked by typing one of the following:
H HE HELP ?
This will usually result in a display like the one shown below:
CMD>help ---- CMD Template Test ---- GO Don't do anything NEG Display inverse of X ADD Display sum of X + Y ERR Generate an error QUIT Quit HELP Help
CMD commands are made up of five fields and organized into a unordered table array. cf1pico.h defines these entries as:
typedef struct CmdTable
{
char *cmdchrs; // command token to match
cmdfptr handler; // its associated C function
char minParmCount; // minimum required parameters
char privLevel; // privilege level to invoke
char crRepOk; // repeat on just CR
char numBase; // default for scan (0 is no scan)
char *help; // help text for menus
} CmdTable, *CmdTablePtr;
The fields of the first command entry in each CMD table has a special meaning. The rest all follow the rules. Both meanings are described below.
cmdchrs
For the first entry, this field is the default prompt string used by the standard CMD interactive dispatch routines. For the remaining entries, this field is the command string that gets compared to the user's entry. The comparison is case insensitive, but must otherwise be a complete match (not substring).
handler
For the first entry, this field specifies the C function used by the standard CMD interactive dispatch routines, and is usually the predefined function CmdStdInteractive(). For the remaining entries, this field is a pointer to the C function to call on a match. It 's return type and parameters must match the standard for CMD function handlers, which is:
char *FunctionName (CmdInfoPtr cip);
minParmCount
For the first entry, this field specifies an optional double column format for use by the standard CMD interactive help routines. For the remaining entries, this field contains the minimum number of parameters (arguments) that must be present or an error is generated.
privLevel
For the first entry, this field sets the initial command table privilege level. For the remaining entries, this field is a numerical privilege level that must be greater than or equal to the current command table privilege level to be visible in help menus, or to be called on a command match.
crRepOk
For the first entry this specifies wether to allow the option of "repeat on CR" behavior to the remainder of the commands. For each command's table entry, if allowed by the first line option, this option designates whether the command should exhibit the repeat on CR Behavior. This behavior is more applicable to some situations than others. This is why we offer this option.
numBase
This slot in thge first line is almost completely unrelated and specifies whether or not you would like the CMD processor to match abbreviated command names. If two command share similar spellings this could be undesirable. The numBase entry in each individual command indicates the default radix for numbers appearing on the command line with no explicit radix specifier. If numBase is 0, the parser will not scan for numeric arguments and all numbers will be treated as strings. If numBase is anything but 0, any radix specifier on the command line will override the default scanning radix specified here.
help
For the first entry, this field contains the header text for the standard CMD interactive help routines. For the remaining entries, this field contains help text for each of the commands. If the field is an empty string, help does not display this entry which is useful for providing hidden commands. To force the standard CMD help routines to display the command, use a space string (" ") in the help field.
Standard interactive mode is the most common usage for CMD, where a user interacts with your application by typing in commands, which in turn invoke your functions, causing some output of information, and repeating the cycle. This is particularly easy to do with the two public CMD functions shown below in a hypothetical main function:
main()
{
CmdInfo ci;
CmdStdSetup(&ci, MyTable, 0);
while (CmdStdRun(&ci) != CMD_BREAK)
{
if (ci.errmes)
printf("\n%s", ci.errmes);
fflush(NULL);
}
In this example, we declare an automatic (local, on the stack) CmdInfo structure variable, then call CmdStdSetup() to perform some magic (not really, but necessary) to prepare it for use. The next line calls CmdStdRun with a pointer to our CmdInfo structure, which by default prints the prompt string from the first table entry, then inputs a line of text from the user, parses the command and arguments into tokens, searches the table, and invokes a handler if it finds a match. If no match exists, or if the invoked function returns a nonzero value, it's assumed to be pointing to an error string. Note that our only way out of this loop is if something returns the special code CMD_BREAK, which is exactly what the function CmdStdBreak() does for us. The following six functions are what makes this all possible:
void CmdStdSetup(CmdInfoPtr cip, CmdTablePtr ctp, short (*altgets)(char *, short));
Given a pointer to a CmdInfo structure, this function sets up all of the fields with safe default values in preparation for further standard interactive mode calls, using information from the required pointer to the target command table. The altgets field allows you to choose the standard C library gets() function by simply passing zero, or specify a more appropriate line input function, perhaps with better line editing capabilities.
char *CmdStdRun(CmdInfoPtr cip);
This function simply makes an indirect call to the handler attached to the first entry in the command table. This is almost always CmdStdInteractive, described below.
char *PDCCmdStdInteractive(CmdInfoPtr cip);
This routine emits a prompt string, using the text from the first entry in the command table, then inputs a line of text from the user. It calls CmdParse() and CmdDispatch() to parse and dispatch based on the user input.
char *PDCCmdStdBreak(CmdInfoPtr cip);
This routine simply returns the special code CMD_BREAK.
char *PDCCmdStdHelp(CmdInfoPtr cip);
This routine walks through the command table and generates a one or two column help menu from the two text fields in each entry. It skip over entries with the empty string for the help field, and it also skips over entries which have a lower privilege level than the current default.
char *PDCCmdStdCmdTest(CmdInfoPtr cip);
This is a great routine for debugging your own command handlers. If your custom handler is misbehaving, feed this routine the same parameter strings, and it will decode and display the various fields that your routine is working with.
All of the functions associated with command have the same return type and calling conventions. All functions must return zero to indicate successful completion, or they should return a pointer to an error message suitable for printf'ing to the user. Nonzero return codes terminate multiple and iterated commands when using the CMD interactive dispatch routines.
The only parameter passed to a CMD command function is a pointer to a CmdInfo pointer, defined in "cmd.h" and described below:
typedef struct CmdInfo
{
CmdTablePtr ctp; // working command table
CmdTablePtr altctp; // secondary command table
char privLevel; // working privilege level
char justCR; // last was just carriage return
char abbrevOk; // accept abbreviated commands (default)
char justCROk; // accept CR repeat commands (default)
char optDelims; // default as #defined
char lineDelim; // default as #defined
char repChar; // default as #defined
char rangeChar; // default as #defined
short argc; // number of arguments (incl. command
#define ARGS (cip->argc-1) // convient argument accessor
CmdParam argv[CMDMAXARGS]; // arguments
char line[CMDLINELEN]; // entire command line (verbatim)
char *options; // command modifiers (typ. CMD.mmm)
char *errmes; // last error message
long repeat; // number of times to execute
getsfptr altgets; // zero defaults to stdlib gets()
} CmdInfo, *CmdInfoPtr;
Inside your command handler, you will generally deal with this structure indirectly through function calls to CMD utility routines. The one exception is the argc field, and the argv array which contains the arguments you will probably reference directly. The argv array contains pointers to structures with the following definition:
typedef struct
{
char *str; // pointer to argument text
long value; // value if numeric (isval true)
int isval : 1; // arg contains value
int isrange : 1; // args form range of values
} CmdParam, *CmdParamPtr;
For a command line in the form: "add 1 2", cip->argv[0].str is "ADD", cip->argv[1].str is "1", and cip->argv[0].str is "2". On entry to your routine, the value and isval fields will be zero until you call the CmdExtractArgValues() routine described below.
One of the most useful features of CMD is its ability to provide access to PicoDOS functionality in your command line interfaces. By making the appropriate CmdTable entires, you can replicate the functionality of any of the following PicoDOS commands, by using the corresponding function name indicated in the table below as the handler function.
|
|
|
|
MM |
PDCMemModCmd |
|
MD |
PDCMemDispCmd |
|
ML |
PDCMemListCmd |
|
PS |
PDCPortSetCmd |
|
PC |
PDCPortClrCmd |
|
PR |
PDCPortReadCmd |
|
PT |
PDCPortToggleCmd |
|
PM |
PDCPortMirrorCmd |
|
COPY |
PDCCopyCmd |
|
DATE, TIME |
PDCDateTimeCmd |
|
DEL, ERASE |
PDCDelCmd |
|
DIR |
PDCDirCmd |
|
FORMAT |
PDCFormatCmd |
|
TYPE |
PDCTypeCmd |
|
REN |
PDCRenCmd |
|
VER |
PDCVerCmd |
|
XS |
PDCXSCmd |
|
XR |
PDCXRCmd |
|
YS |
PDCYSCmd |
|
YR |
PDCYRCmd |
|
BAUD |
PDCBaudCmd |
|
DUMP |
PDCDumpCmd |
|
CAPTURE |
PDCCaptureCmd |
|
RES |
PDCResetCmd |
|
|
|
|
|
|
Tel: 508-759-6434 |
|
Fax: 508-759-6436 |
|
|
||