X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fmware%2Fparser.h;h=d681f724d297daaf9ec89553840dd5563dff9d24;hb=362204d3e1aabcfde4877219d5ea3406e2d6f9ef;hp=7271fb925630eb990288331faf1f31b7a1104710;hpb=8541a61b6b304f8c61c03a2b7c8cc59e60bc9e0b;p=bertos.git diff --git a/bertos/mware/parser.h b/bertos/mware/parser.h index 7271fb92..d681f724 100644 --- a/bertos/mware/parser.h +++ b/bertos/mware/parser.h @@ -30,23 +30,95 @@ * All Rights Reserved. * --> * - * \version $Id$ + * \defgroup parser Simple RPC machinery + * \ingroup mware + * \{ * - * \author Bernardo Innocenti + * \brief Channel protocol parser and commands. + * + * This module provides a simple text based RPC implementation. + * Often there is the need to give a command to the device and receive results + * back. Each command may have a variable number of input and output + * parameters, with variable type, and a return code which indicates if the + * command was successfully executed or not; this module provides the machinery + * to facilitate the above RPC scenario. + * You will need to write the RPC input and reply code as well as + * the definition of the commands. + * + * Commands are defined using a CmdTemplate struct containing: + * - command name: the string that will be matched by the parser; + * - command arguments: a string representing type and number of input + * arguments; + * - command output: a string representing type and number of output arguments; + * - function callback: function implementing the command. + * + * Once you have declared the commands, you need to register them in the + * parser with the function parser_register_cmd(). + * You are strongly encouraged to use MAKE_CMD() (or alternatively + * MAKE_TEMPLATE()) and REGISTER_CMD() to declare and register commands. + * + * A command line can be parsed with the following steps: + * - find the corresponding command template with parser_get_cmd_template() + * - extract command arguments with parser_get_cmd_arguments() + * - execute the command with parser_execute_cmd() + * + * You can also provide interactive command line completion using + * parser_rl_match(). + * + * Example: + * \code + * // Declare a buzzer command + * MAKE_CMD(beep, "d", "", + * ({ + * buz_beep(args[1].l); + * RC_OK; + * }), 0) + * + * // initialize the parser + * parser_init(); + * REGISTER_CMD(beep); + * + * // parse an input line + * char buf[80]; + * // read line from somewhere + * rpc_get(buf); + * // now parse the line + * const struct CmdTemplate *templ; + * templ = parser_get_cmd_template(buf); + * + * // Take arguments (optionally check errors) + * parms args[PARSER_MAX_ARGS]; + * parser_get_cmd_arguments(buf, templ, args); + * //Execute command + * if(!parser_execute_cmd(templ, args)) + * { + * // error + * } + * // Now args contain the outputs of the function, you can send it + * // back to the caller + * rpc_reply(args) + * + * \endcode + * + * Configuration file: cfg_parser.h + * + * \author Bernie Innocenti * \author Stefano Fedrigo * \author Giovanni Bajo * - * \brief serial protocol parser and commands. + * $WIZ$ module_name = "parser" + * $WIZ$ module_configuration = "bertos/cfg/cfg_parser.h" + * $WIZ$ module_depends = "kfile", "hashtable" */ #ifndef MWARE_PARSER_H #define MWARE_PARSER_H -#include +#include "cfg/cfg_parser.h" -/** Max number of arguments and results for each command */ -#define PARSER_MAX_ARGS 8 +#include +#include /** * Error generated by the commands through the return code. @@ -59,8 +131,14 @@ typedef enum RC_SKIP = 2 ///< Skip following commands } ResultCode; +typedef struct +{ + const char *p; + int sz; +} str_parm; + /** union that contains parameters passed to and from commands */ -typedef union { long l; const char *s; } parms; +typedef union { long l; str_parm s; } parms; /** pointer to commands */ typedef ResultCode (*CmdFuncPtr)(parms args_results[]); @@ -85,21 +163,74 @@ struct CmdTemplate uint16_t flags; ///< Currently unused. }; +#define REGISTER_FUNCTION parser_register_cmd + /** - * Initialize the parser module + * Utility function to register a command. * - * \note This function must be called before any other function in this module + * \param NAME Command name to register */ -void parser_init(void); +#define REGISTER_CMD(NAME) \ + do { \ + if (!REGISTER_FUNCTION(&cmd_ ## NAME ## _template)) \ + ASSERT2(0, "Error in registering command, no space left"); \ + } while (0) +/** + * Utility macro to create a command template. + * + * It requires that a callback function with name \a cmd_NAME + * is already defined. + * \param NAME Command name + * \param ARGS Input arguments + * \param RES Output arguments + * \param FLAGS Command flags + */ +#define MAKE_TEMPLATE(NAME, ARGS, RES, FLAGS) \ +const struct CmdTemplate cmd_ ## NAME ## _template = \ +{ \ + #NAME, ARGS, RES, cmd_ ## NAME, FLAGS \ +}; /** - * Register a new command into the parser + * Utility macro to create command templates and callback functions. + * + * Example for a version command: + * \code + * MAKE_CMD(ver, "", "ddd", + * ({ + * args[1].l = VERS_MAJOR; + * args[2].l = VERS_MINOR; + * args[3].l = VERS_REV; + * RC_OK; + * }), 0); + * \endcode * - * \param cmd Command template describing the command + * Remember that input and output parameters start from index 1, since + * args[0] is the command itself. + * The last line is the return value of the function. + * + * \param NAME Command name matched by the parser + * \param ARGS Input arguments to the command + * \param RES Output arguments of the command + * \param BODY Command body, expressed with C 'statement expression' + * \param FLAGS Command flags + */ +#define MAKE_CMD(NAME, ARGS, RES, BODY, FLAGS) \ +static ResultCode cmd_ ## NAME (parms *args) \ +{ \ + return (ResultCode)BODY; \ +} \ +MAKE_TEMPLATE(NAME, ARGS, RES, FLAGS) + +/** + * Initialize the parser module * + * \note This function must be called before any other function in this module */ -void parser_register_cmd(const struct CmdTemplate* cmd); +void parser_init(void); + +bool parser_register_cmd(const struct CmdTemplate* cmd); /** @@ -111,64 +242,30 @@ void parser_register_cmd(const struct CmdTemplate* cmd); */ const char* parser_rl_match(void* dummy, const char* word, int word_len); - -/** - * \brief Command input handler. - * - * Process the input, calling the requested command - * (if found) and calling printResult() to give out - * the result (on device specified with parameter fd). - * - * \param line Text line to be processed (ASCIIZ) - * - * \return true if everything is OK, false in case of errors - */ bool parser_process_line(const char* line); - /** * Execute a command with its arguments, and fetch its results. * + * The \a args paramenter is value-result: it provides input arguments to + * the callback function and it stores output values on return. + * * \param templ Template of the command to be executed * \param args Arguments for the command, and will contain the results * * \return False if the command returned an error, true otherwise */ -INLINE bool parser_execute_cmd(const struct CmdTemplate* templ, parms args[PARSER_MAX_ARGS]) +INLINE bool parser_execute_cmd(const struct CmdTemplate* templ, parms args[CONFIG_PARSER_MAX_ARGS]) { return (templ->func(args) == 0); } - -/** - * Find the template for the command contained in the text line. - * The template can be used to tokenize the command and interpret - * it. - * - * This function can be used to find out which command is contained - * in a given text line without parsing all the parameters and - * executing it. - * - * \param line Text line to be processed (ASCIIZ) - * - * \return The command template associated with the command contained - * in the line, or NULL if the command is invalid. - */ const struct CmdTemplate* parser_get_cmd_template(const char* line); +bool parser_get_cmd_arguments(const char* line, const struct CmdTemplate* templ, parms args[CONFIG_PARSER_MAX_ARGS]); +bool get_word(const char **begin, const char **end); -/** - * Extract the arguments for the command contained in the text line. - * - * \param line Text line to be processed (ASCIIZ) - * \param templ Command template for this line - * \param args Will contain the extracted parameters - * - * \return True if everything OK, false in case of parsing error. - */ -bool parser_get_cmd_arguments(const char* line, const struct CmdTemplate* templ, parms args[PARSER_MAX_ARGS]); - - +#if CONFIG_ENABLE_COMPAT_BEHAVIOUR /** * Extract the ID from the command text line. * @@ -179,7 +276,9 @@ bool parser_get_cmd_arguments(const char* line, const struct CmdTemplate* templ, * */ bool parser_get_cmd_id(const char* line, unsigned long* ID); +#endif +/** \} */ // defgroup parser #endif /* MWARE_PARSER_H */