A Command Interpreter with support for used defined commands, subsystems, macros, help and parameter parsing.
cmdb.h
- Committer:
- wvd_vegt
- Date:
- 2011-02-11
- Revision:
- 6:76b033971c3c
- Parent:
- 5:68d3a351c3ea
- Child:
- 7:269c2445b8f5
File content as of revision 6:76b033971c3c:
/* mbed Command Interpreter Library * Copyright (c) 2011 wvd_vegt * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MBED_CMDB_H #define MBED_CMDB_H #include "mbed.h" #include <vector> //Max size of an Ansi escape code. #define MAX_ESC_LEN 5 //Max (strlen) of a Param. #define MAX_PARM_LEN 32 //Max eight parms. #define MAX_ARGS 8 //Max 132 characters commandline. #define MAX_CMD_LEN 132 //'Show' hidden subsystems and commands. #define SHOWHIDDEN #define MIN_BYTE -128 #define MAX_BYTE +127 #define MIN_SHORT -32768 #define MAX_SHORT +32767 #define MIN_INT -32768 #define MAX_INT +32767 //TODO Make sure we use id and array index properly!! struct cmdb_cmd { public: char *cmdstr; int subs; int id; //Changed to int as signed char won't compile char *parms; char *cmddescr; char *parmdescr; cmdb_cmd(char *_cmdstr, int _subs, int _id, char *_parms, char *_cmddescr, char *_parmdescr = "") { cmdstr = (char*)malloc(strlen(_cmdstr)+1); strcpy(cmdstr,_cmdstr); subs = _subs; id = _id; parms = (char*)malloc(strlen(_parms)+1); strcpy(parms,_parms); cmddescr = (char*)malloc(strlen(_cmddescr)+1); strcpy(cmddescr,_cmddescr); parmdescr = (char*)malloc(strlen(_parmdescr)+1); strcpy(parmdescr,_parmdescr); } }; //----Escape Codes and Strings const char cr = '\r'; const char lf = '\n'; const char bell = '\7'; const char esc = '\033'; const char sp = ' '; const char crlf[] = "\r\n\0"; const char bs[] = "\b \b\0"; const char boldon[] = "\033[1m\0"; const char boldoff[] = "\033[0m\0"; const char cls[] = "\033[2J\0"; const char home[] = "\033[H\0"; const char prompt[] = "CMD>"; //Before including this file, define CID_LAST as the last value from the enum with commands. //#define CMD_TBL_LEN CID_LAST #define SUBSYSTEM -1 #define GLOBALCMD -2 #define HIDDENSUB -3 #define CID_BOOT 9990 #define CID_MACRO 9991 #define CID_RUN 9992 #define CID_MACROS 9993 #define CID_ECHO 9994 #define CID_BOLD 9995 #define CID_CLS 9996 #define CID_IDLE 9997 #define CID_HELP 9998 #define CID_LAST 9999 //You need to add the following commands to your command table. //Optional const cmdb_cmd BOOT("Boot",GLOBALCMD,CID_BOOT,"","Boot"); //Optional const cmdb_cmd MACRO("Macro",GLOBALCMD,CID_MACRO,"%s","Define macro (sp->_, cr->|)","command(s)"); const cmdb_cmd RUN("Run",GLOBALCMD,CID_RUN,"","Run a macro"); const cmdb_cmd MACROS("Macros",GLOBALCMD,CID_MACROS,"","List macro(s)"); //Optional const cmdb_cmd ECHO("Echo",GLOBALCMD,CID_ECHO,"%bu","Echo On|Off (1|0)","state"); const cmdb_cmd BOLD("Bold",GLOBALCMD,CID_BOLD,"%bu","Bold On|Off (1|0)","state"); const cmdb_cmd CLS("Cls",GLOBALCMD,CID_CLS,"","Clears the terminal screen"); //Mandatory! const cmdb_cmd IDLE("Idle",GLOBALCMD,CID_IDLE,"","Deselect Subsystems"); //Mandatory! const cmdb_cmd HELP("Help",GLOBALCMD,CID_HELP,"%s","Help"); #define ESC_TBL_LEN 4 struct esc_st { char *escstr; int id; }; enum { EID_CURSOR_UP, EID_CURSOR_DOWN, EID_CURSOR_RIGHT, EID_CURSOR_LEFT, EID_LAST }; const struct esc_st esc_tbl [ESC_TBL_LEN] = { { "\033[A", EID_CURSOR_UP }, { "\033[B", EID_CURSOR_DOWN }, { "\033[C", EID_CURSOR_RIGHT }, { "\033[D", EID_CURSOR_LEFT }, }; //class Cmdb; //See http://stackoverflow.com/questions/9410/how-do-you-pass-a-function-as-a-parameter-in-c //void func ( void (*f)(Cmdb&, int) ); //Define a const struct cmbd_cmd cmdb_tbl [CMD_TBL_LEN] {}; that is passed into the constructor. /** Command Interpreter class.<br/> * <br/> * Steps to take:<br/> * <br/> * 1) Create a std::vector<cmdb_cmd> and fill it with at least<br/> * the mandatory commands IDLE and HELP.<br/> * 2) Create an Cmdb class instance and pass it both the vector and<br/> * a Serial port object like Serial serial(USBTX, USBRX);<br/> * 3) Feed the interpreter with characters received from your serial port.<br/> * Note Cmdb self does not retrieve input it must be handed to it<br/> * 4) Handle commands added by the application by the Id and parameters passed.<br/> * */ class Cmdb { public: /** Create a Command Interpreter. * * See http://www.newty.de/fpt/fpt.html#chapter2 for function pointers. * * @param serial a Serial port used for communication. * @param cmds a vector with the command table. */ Cmdb(const Serial& serial, const std::vector<cmdb_cmd>& cmds, void (*cmdb_callback)(Cmdb&,int) ); /** Checks if the macro buffer has any characters left. * * @returns true if any characters left. */ bool cmdb_macro_hasnext(); /** Gets the next character from the macro buffer and * advances the macro buffer pointer. * * Do not call if no more characters are left! * * @returns the next character. */ char cmdb_macro_next(); /** Gets the next character from the macro buffer * but does not advance the macro buffer pointer. * * Do not call if no more characters are left! * * @returns the next character. */ char cmdb_macro_peek(); /** Resets the macro buffer and macro buffer pointer. * */ void cmdb_macro_reset(); /** Checks if the serial port has any characters * left to read by calling serial.readable(). * * @returns true if any characters available. */ bool cmdb_hasnext(); /** Gets the next character from the serial port by * calling serial.getc(). * * Do not call if no characters are left! * * @returns the next character. */ char cmdb_next(); /** Add a character to the command being processed. * If a cr is added, the command is parsed and executed if possible * If supported special keys are encountered (like backspace, delete and cursor up) they are processed. * * @parmam c the character to add. * * @returns true if a command was recognized and executed. */ bool cmdb_scan(const char c); //Output. int cmdb_printf(const char *format, ...); int cmdb_print(const char *msg); char cmdb_printch(const char ch); //------------------------------------------------------------------------------ //----These helper functions retieve parameters in the correct format. //------------------------------------------------------------------------------ //TODO Add tests for correct type of parameter. bool BOOLPARM(int ndx) { return parms[ndx].val.uc!=0; } unsigned char BYTEPARM(int ndx) { return parms[ndx].val.uc; } char CHARPARM(int ndx) { return parms[ndx].val.c; } unsigned int WORDPARM(int ndx) { return parms[ndx].val.ui; } unsigned int UINTPARM(int ndx) { return parms[ndx].val.ui; } int INTPARM(int ndx) { return parms[ndx].val.i; } unsigned long DWORDPARM(int ndx) { return parms[ndx].val.ul; } long LONGPARM(int ndx) { return parms[ndx].val.l; } float FLOATPARM(int ndx) { return parms[ndx].val.f; } char* STRINGPARM(int ndx) { return parms[ndx].val.s; } private: //See http://www.newty.de/fpt/fpt.html#chapter2 for function pointers. //C++ member //void (Cmdb::*cmdb_callback)(Cmdb&,int); //C function void (*cmdb_callback)(Cmdb&,int); //void(*_cmdb_callback)(Cmdb&,int); /** Searches the escape code list for a match. * * @param char* escstr the escape code to lookup. * * @returns the index of the escape code or -1. */ int cmdb_escid_search(char *escstr); /** Checks if the command table for a match. * * @param char* cmdstr the command to lookup. * * @returns the id of the command or -1. */ int cmdb_cmdid_search(char *cmdstr); /** Converts an command id to an index of the command table. * * @param cmdid the command id to lookup. * * @returns the index of the command or -1. */ int cmdb_cmdid_index(int cmdid); /** Initializes the parser. * * @parm full if true the macro buffer is also cleared else only the command interpreter is reset. */ void cmdb_init(const char full); /** Writes a prompt to the serial port. * */ void cmdb_prompt(void); /** Called by cmdb_cmd_dispatch it parses the command against the command table. * * @param cmd the command and paramaters to parse. * * @returns the id of the parsed command. */ int cmdb_parse(char *cmd); /** Called by cmdb_scan it processes the arguments and dispatches the command. * * Note: This member calls the cmdb_callback callback function. * * @param cmd the command to dispatch. */ void cmdb_cmd_dispatcher(char *cmd); /** Generates Help from the command table and prints it. * * @param pre leading text * @param ndx the index of the command in the command table. * @param post trailing text. */ void cmdb_cmdhelp(char *pre, int ndx, char *post); //Utilities. void zeromemory(char *p,unsigned int siz); int stricmp (char *s1, char *s2); //Storage, see http://www.cplusplus.com/reference/stl/vector/ std::vector<cmdb_cmd> _cmds; Serial _serial; bool echo; bool bold; int CMD_TBL_LEN; //Macro's. int macro_ptr; char macro_buf[1 + MAX_CMD_LEN]; enum parmtype { PARM_UNUSED, //0 PARM_FLOAT, //1 (f) PARM_LONG, //2 (l/ul) PARM_INT, //3 (i/ui) PARM_SHORT, //4 (w/uw) PARM_CHAR, //5 (c/uc) PARM_STRING //6 (s) }; union value { float f; unsigned long ul; long l; int i; unsigned int ui; short w; unsigned short uw; char c; unsigned char uc; char s[MAX_PARM_LEN]; }; struct parm { enum parmtype type; union value val; }; //------------------------------------------------------------------------------ //----Buffers //------------------------------------------------------------------------------ char cmdbuf [1 + MAX_CMD_LEN]; // command buffer char cmdndx; // command index char lstbuf [1 + MAX_CMD_LEN]; // last command buffer char escbuf [1 + MAX_ESC_LEN]; // command buffer unsigned char escndx; // command index struct parm parms[MAX_ARGS]; int noparms; int subsystem; int argcnt; //No of arguments found in command int argfnd; //No of arguments to find in parameter definition. int error; //strtoXX() Error detection }; #endif