Better error handling in parser_register_cmd()
[bertos.git] / bertos / mware / parser.h
index 7271fb925630eb990288331faf1f31b7a1104710..281db3964c05e51c8a85fe110daf8a670fb3947b 100644 (file)
  * All Rights Reserved.
  * -->
  *
- * \version $Id$
+ * \defgroup parser Simple RPC machinery
+ * \ingroup mware
+ * \{
  *
- * \author Bernardo Innocenti <bernie@develer.com>
+ * \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
+ *
+ * <b>Configuration file</b>: cfg_parser.h
+ *
+ * \author Bernie Innocenti <bernie@codewiz.org>
  * \author Stefano Fedrigo <aleph@develer.com>
  * \author Giovanni Bajo <rasky@develer.com>
  *
- * \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 <cpu/types.h>
+#include "cfg/cfg_parser.h"
 
-/** Max number of arguments and results for each command */
-#define PARSER_MAX_ARGS       8
+#include <cpu/types.h>
+#include <cfg/debug.h>
 
 /**
  * Error generated by the commands through the return code.
@@ -85,21 +157,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
+ *
+ * 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 cmd Command template describing the command
+ * \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 +236,29 @@ 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]);
 
-/**
- * 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 +269,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 */