X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fmware%2Fparser.h;h=ca7a7a2891f9fe627776fce6b6b85962587f54e7;hb=39e200e1f43474a96888f97e2271728c9605ccbe;hp=3c2f2a5fb5a822bc09303f88a8fe2a94ddfeb62d;hpb=d6aafcb0363974688e68f2325cf18f8087e07448;p=bertos.git diff --git a/bertos/mware/parser.h b/bertos/mware/parser.h index 3c2f2a5f..ca7a7a28 100644 --- a/bertos/mware/parser.h +++ b/bertos/mware/parser.h @@ -30,12 +30,82 @@ * All Rights Reserved. * --> * + * \defgroup parser Simple RPC machinery + * \ingroup mware + * \{ + * + * \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 Channel protocol parser and commands. - * * $WIZ$ module_name = "parser" * $WIZ$ module_configuration = "bertos/cfg/cfg_parser.h" * $WIZ$ module_depends = "kfile", "hashtable" @@ -48,6 +118,7 @@ #include "cfg/cfg_parser.h" #include +#include /** * Error generated by the commands through the return code. @@ -57,11 +128,18 @@ typedef enum RC_ERROR = -1, ///< Reply with error. RC_OK = 0, ///< No reply (ignore reply arguments). RC_REPLY = 1, ///< Reply command arguments. - RC_SKIP = 2 ///< Skip following commands + RC_SKIP = 2, ///< Skip following commands + RC_CLAMPED = 3, ///< argument values have been clamped. } 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[]); @@ -86,21 +164,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. * - * \param cmd Command template describing the command + * 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 + * + * 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); /** @@ -112,24 +243,14 @@ 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 * @@ -140,35 +261,10 @@ INLINE bool parser_execute_cmd(const struct CmdTemplate* templ, parms args[CONFI 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); - -/** - * 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[CONFIG_PARSER_MAX_ARGS]); - +bool get_word(const char **begin, const char **end); #if CONFIG_ENABLE_COMPAT_BEHAVIOUR /** @@ -184,5 +280,6 @@ bool parser_get_cmd_id(const char* line, unsigned long* ID); #endif +/** \} */ // defgroup parser #endif /* MWARE_PARSER_H */