/*
Copyright 2007, Freie Universitaet Berlin. All rights reserved.

These sources were developed at the Freie Universität Berlin, Computer
Systems and Telematics group.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

- Neither the name of Freie Universitaet Berlin (FUB) nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

This software is provided by FUB and the contributors on an "as is"
basis, without any representations or warranties of any kind, express
or implied including, but not limited to, representations or
warranties of non-infringement, merchantability or fitness for a
particular purpose. In no event shall FUB or contributors be liable
for any direct, indirect, incidental, special, exemplary, or
consequential damages (including, but not limited to, procurement of
substitute goods or services; loss of use, data, or profits; or
business interruption) however caused and on any theory of liability,
whether in contract, strict liability, or tort (including negligence
or otherwise) arising in any way out of the use of this software, even
if advised of the possibility of such damage.

This implementation was developed by the CST group at the FUB.

For documentation and questions please use the web site
http://scatterweb.mi.fu-berlin.de and the mailinglist
scatterweb@lists.spline.inf.fu-berlin.de (subscription via the Website).
Berlin, 2007
*/

/**
 * \defgroup		cmd		Command Engine

<h2>Overview</h2>

<p>ScatterWeb command engine is the core interface to access the sensor network.
It supports both human and machine access modes. The command protocol is
optimized for the binary machine access mode. The ASCII based human access mode
is embedded in the binary protocol.</p>
<p>For each command request an optional reply is generated either by the command
or the command egine (default reply). Replies (outbound) can be sent unsolicited.</p>
<p>The binary-mode protocol allows efficient and transparent transport of
commands. Packets can be induced via serial interface to any node and optionally
be forwarded transparently through radio. Requests are processed by handlers
without any parsing. If requested a custom or default reply is sent back. </p>
<p>The ASCII-mode protocol allows easy access to the network for human testers.
Command strings are readable and can be easily written on a terminal. These
commands are internally parsed and translated into the binary command protocol.
Command name and arguments remain untouched. Arguments need to be parsed
individually by each command which makes this protocol heavy-weight. If
requested a custom or default reply is sent pack and printed out at the
originating gateway node.</p>

<ul>
<li>\ref cmd_interior or "How-To write command handlers"</li>
<li>\ref cmd_exterior or "Interfacing the nodes"</li>
<li>\ref cmd_spec</li>
<li><a href="group__commands.html">Command Documentation</a></li>
<li>Properties: ScatterWeb.Cmd.Properties.h</li>
</ul>
*/

/**
 * @file		ScatterWeb.Cmd.h
 * @ingroup		cmd
 * @brief		The ScatterWeb Command Engine provides functions that allow you to connect and
 * interact with nodes through the radio and serial interface.
 *
 * @author        FU Berlin Students, Marco Hutta, Michael Baar
 * @version       $Revision: 429 $
 * @since         1.0
 */

#ifndef ScatterWeb_CMD
#define ScatterWeb_CMD

/******************************************************************************
 * @name Module default configuration
 */
//@{
#ifndef CMD_ASCII_MODE
	/**
	 * @brief Feature switch to compile ascii mode command interface
	 * @since libscatterweb 1.2
	 * @ingroup conf
	 */
	#define CMD_ASCII_MODE		1
#endif

#ifndef CMD_ENABLE_LOGGING
	/**
	 * @brief Enable logging output for debugging purposes
	 * @since libscatterweb 1.2
	 * @ingroup conf
	 */
	#define CMD_ENABLE_LOGGING	0
#endif

/// ascii representations of binary requests start with this character
#define	CMD_BINARY_IN_MARKER			'>'
/// printouts of binary replies start with this character
#define CMD_BINARY_OUT_MARKER			'<'
/// if a line starts with this character, the command is forwarded to the address following
#define CMD_ASCII_FWD_MARKER			'@'
/// used to mark (outgoing) comments
#define CMD_ASCII_COMMENT_MARKER		'#'
/// if this follows #CMD_ASCII_FWD_MARKER, it is expanded to #SUBNET_BROADCAST
#define CMD_ASCII_FWD_BROADCAST			'*'
/// maximum number of character allowed for the name of an ascii mode command (\ref command)
#define CMD_ASCII_MAX_NAME_LENGTH		16
//@}


__attribute__((packed))

/**
 * @brief	Binary Command Id
 * @internal
 */
typedef struct cmd_binid {
	uint8_t			protocol;	///< protocol number (1-255)
	uint8_t			function;	///< function number (1-255)
} cmd_binid_t;

__attribute__((packed))
/**
 * @brief Header for binary commands
 *
 * For details see @ref cmd_spec.
 **/
typedef struct {
	/**
	 * @brief Command protocol control flags
	 *
	 * A combination of flags controlling command processing.
	 *
	 * @see CMD_REQFLAG_REPLY, CMD_REQFLAG_ASCII
	 * @see CMD_RPLFLAG_ERROR, CMD_RPLFLAG_ASCII
	 *
	 */
	uint8_t				flags;
	/**
	 * @brief Command protocol message reference number
	 *
	 * This number should be increased for every request made and shall always be greater than zero.
	 * It is returned unchanged with each response send to the request.
	 */
	uint8_t				msgref;
	/**
	 * @brief Command protocol binary command id
	 *
	 * Identifies a binary mode command. For Ascii-mode command, the variable length command name starts
	 * at this offset and is terminated by a NUL character.
	 */
	cmd_binid_t			id;
} cmd_header_t;

typedef struct cmd_args {
	const cmd_header_t (*const	request);
	const char*					args;				///< pointer to command arguments
	const uint16_t				arg_size;			///< size of command arguments
	const cmd_header_t*			response;
	char (*const				response_args);		///< pointer to buffer for command response
	const uint16_t				response_bufsize;
	//void(*)(void*)			fpSendAsyncResponse,
} cmd_args_t;


/**
 * @brief Binary mode command handler function prototype
 *
 * A function of this type is generated by the BINCMD_HANDLER and BINCMD macros
 *
 * @see	#BINCMD
 * @see #BINCMD_HANDLER
 * @since 1.1
 */
typedef int(*fp_intcmdhandler)(const cmd_args_t*	args);

/**
 * @brief	ASCII mode command handler function prototype
 * @see		command
 * @since         1.1
 */
typedef void(*fp_cmdhandler)(const cmd_args_t*	args);

/**
 * @brief	Command directory entry
 * @internal
 * @since	1.0
 * @version	1.1
 */
typedef struct {
	uint8_t					flags;			/// Command Definition Flags
	union {
		fp_intcmdhandler	binary;
		fp_cmdhandler		ascii;
	} delegate;
	union {
		uint16_t				raw;
		const char*			ascName;
		struct cmd_binid	binId;
	} id;
	uint16_t* ptr;
} command_t;

/******************************************************************************
 * @name Command Definition Flags
 *
 * These commands can be used when declaring commands usign the COMMAND and
 * BINCMD macros.
 *
 * @since	1.0
 * @version	1.1
 */
//@{
enum CMD_FLAGS {
	CMDFLAG_NONE = 0x00,								/// Command with no flags
	CMDFLAG_DEFAULT = CMDFLAG_NONE,
	CMDFLAG_SERIAL = 0x02, 							///< Command with this flag access uart directly with prints.
	CMDFLAG_PROPERTY = 0x04,						///< Declares this command is used to access a property (property_t accessed via command_t.ptr), do not use it directly, use the PROPERTY MACRO
	CMDFLAG_ASCII = 0x80								///< Command uses binary mode (ascii mode if bit not set)
};
//@}

/******************************************************************************
 * @name Bincmd Protocols
 */
//@{

/**
 * @brief	Function that serves as handler for all protocol functions for which no specific handler has been defined.
 *
 * @see		#BINCMD_HANDLER
 */
#define CMD_FUNCTION_HANDLER	0

#define CMD_PROTOCOL_STATE		0	///< state messages
#define CMD_FUNC_STATE_BUSY		1	///< can't process request, busy

#define CMD_PROTOCOL_SYSTEM		1	///< system control and information
#define CMD_FUNC_SYSTEM_INFO	1	///< node identification property
#define CMD_FUNC_SYSTEM_ID		10	///< node identification property

#define CMD_PROTOCOL_TEST		254	///< system test
//@}

#define CMD_SUCCESS				0
#define	CMD_ERROR				-1

/******************************************************************************
 * @name Bincmd packet types
 */
//@{
#define CMD_REQ_PACKET				0x30 ///< Command request
#define CMD_RPL_PACKET				0x31 ///< Command reply
//@}

/******************************************************************************
 * @name Command protocol control flags
 */

/**
 * @brief Ascii mode command (run an ascii command through binary protocol)
 *
 * The three byte command code must correspond to an ascii command code and the payload
 * corresponds to the argument string for ASCII mode commands.
 * In this way ASCII modes can be called (and do reply) using the binary mode protocol.
 * Command arguments and results are strings see \ref cmd_exterior
 */
#define	CMD_REQFLAG_REPLY			0x02				///< Send reply (send none if not set)
#define CMD_REQFLAG_ASCII			0x80				///< Ascii mode request (request from ascii command through binary protocol)

#define	CMD_RPLFLAG_ERROR			0x02				///< Error occured (no error if not set)
#define CMD_RPLFLAG_ASCII			CMD_REQFLAG_ASCII	///< Ascii mode reply (reply from ascii command through binary protocol)
//@}

/**
 * @name Standard argument types
 */
//@{



//@}

/**
 * @brief	Enables the Command module
 * @since	1.2
 */
void Cmd_on();

/**
 * @brief	Handler for incoming command packets from the radio interface
 * @return	true, if packet is handled
 * @since	1.0
 * @version	1.2
 */
bool Cmd_radioHandler(struct netpacket_handler_args* args);

/**
 * @brief	Handler for incoming lines from the serial interface
 * @since	1.0
 * @version	1.2
 */
void Cmd_serialHandler(char* line);

/**
 * @brief Invoke a binary mode command
 *
 * Use this function if you need to invoke a binary mode command manually in code.
 *
 * @param[in]	cmd_header			Pointer to buffer with command header and arguments
 * @param[in]	size				Number of bytes in buffer cmd_header
 * @param[in]	rpl_buffer			Pointer to any reply buffer
 * @param[in]	rpl_buffersize		Size of reply buffer
 * @param[in]	directConnection	Set to true for manual invocation of this function
 * @return		Number of bytes written to rpl_buffer
 */
int Cmd_Run(
		const cmd_header_t (*const	cmd_header),
		const char*					args,
		const int					argsize,
		void*						rpl_buffer,
		const int					rpl_buffersize,
		bool						directConnection
);

#if CMD_ASCII_MODE
	/**
	 * @brief	Prepares the argument string for the use of Cmd_GetNextArg
	 *
	 * Replaces spaces in the argument string by null characters, such that
	 * argument strings returned by Cmd_GetNextArg will be null-terminated.
	 *
	 * @see Cmd_GetNextArg
	 */
	uint16_t Cmd_SplitArgs(const char* args);

	/**
	 * @brief	Get pointer to next argument for an ascii command request
	 *
	 * Use this function in COMMAND procedures to find arguments in the args string
	 * passed to each command. The function works on argument lists that are separated
	 * by spaces.
	 *
	 * @param	arg		Pointer to current argument
	 * @return			Pointer to next argument or null
	 *
	 * @note	You need to run Cmd_SplitArgs before using this function.
	 * @see	Cmd_SplitArgs
	 */
	const char* Cmd_GetNextArg(const char (*const arg));
#endif

/**
 * @name Command definition macros
 */
//@{

/**
 * @brief Define binary mode protocol handler
 *
 * If a protocol handler for a protocol is defined is it run for all commands
 * of that protocol.
 * This macro is a shortcut and creates a binary command with
 * function = #CMD_FUNCTION_HANDLER .
 *
 * @since 1.1
 */
#define BINCMD_HANDLER(_protocol, _flags, _args) 					\
	BINCMD_2(														\
		_protocol ,													\
		0 ,															\
		_flags ,													\
		_args														\
	)
/**
 * @brief Define binary mode command
 *
 * \li command protocol number (1-255)
 * \li command function number (1-22)
 * \li flags
 * \li name of command request variable (of type cmd_header_t*)
 * 		Any command request arguments follow after the command header.
 * \li size of command request (header + optional arguments)
 * \li name of command reply variable (of type cmd_header_t*)
 * 		Any additional result data can be appended to the command header. Usually by
 * 		casting this parameter to a custom struct. The maximum size of the additional data is #TERM_BUFSIZE.
 * \li return: either size of command reply (header + optional additional data) or true/false
 * 		to return default success or error reply
 *
 * Example: \code
BINCMD( CMD_PROTOCOL_SYSTEM, CMD_FUNC_SYSTEM_NODE, CMDFLAG_DEFAULT, pcmd, size, reply ) {
	// see if request has one int argument
	if( size == sizeof(cmd_intarg_t) ) {
		// set node id from argument
		Configuration.id.address.node = ((cmd_intarg_t*)pcmd)->intval;
	}

	// reply with current node id
	((cmd_intarg_t*)preply)->intval = Configuration.id.address.node;
	return sizeof(cmd_intarg_t);
}

 * \endcode
 * @see cmd_header_t, bincmd_int_t
 * @since 1.1
 */
#define BINCMD(_protocol, _function, _flags, _args)					\
	BINCMD_2(														\
		_protocol ,													\
		_function , 												\
		_flags ,													\
		_args											\
	)
#define BINCMD_2( _protocol, _function, _flags, _args)	\
	BINCMD_3(														\
		p##_protocol##f##_function ,								\
		_protocol ,													\
		_function , 												\
		_flags ,													\
		_args											\
	)
	#define BINCMD_3( _name, _protocol, _function, _flags, _args )	\
	extern int cmd_##_name (const cmd_args_t* _args);				\
    __attribute__((section(".commands")))							\
    const command_t cmd_##_name##_tableentry = { _flags , {cmd_##_name}, {(uint16_t)(((_function)<< 8)|(_protocol)) } }; \
    __attribute__((noinline))										\
    int cmd_##_name (const cmd_args_t* _args)

#if CMD_ASCII_MODE
	/**
	* @brief	Use this MACRO to declare terminal command functions
	*
	* COMMAND([name], [flags], [args])
	* generates a function
	* void cmd_[name] (const cmd_args_t [args])
	*
	* @since         1.1
	*/
	#define COMMAND_HEADER(_cmd, _flags, _args, _ptr )								\
		extern void cmd_##_cmd (const cmd_args_t* _args );		\
		const char cmd_name_##_cmd [] = #_cmd; 					\
		__attribute__((section(".commands")))							\
		const command_t cmd_##_cmd##_tableentry = { (_flags | CMDFLAG_ASCII) , {(fp_intcmdhandler)cmd_##_cmd} , {(uint16_t)cmd_name_##_cmd }, _ptr }; 	\
		__attribute__((noinline)) 													\
		void cmd_##_cmd (const cmd_args_t* _args)

	#define COMMAND(_cmd, _flags, _args )		\
		COMMAND_HEADER(_cmd, _flags, _args, 0)

#else
	#define COMMAND(_cmd, _flags, _args )								\
		__attribute__((unused))														\
	    void cmd_##_cmd (const cmd_args_t* _args)
#endif
//@}

#endif
