/*
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	logging		Logging
 * \ingroup		cmd
 */

/**
 * @file	ScatterWeb.Debuglog.h
 * @brief	ScatterWeb logging functions for debugging purposes
 * @ingroup	logging 
 *
 * @since	1.1
 * @date	Feb 2007
 * 
 * @author Michael Baar
 * 
 * This module allows to output logging messages from a node either through
 * a direct serial connection or local radio broadcast. When using radio a
 * node must implement listener functionality and receive #DEBUGLOG_PACKET
 * packets and print them using the :Debuglog_write_packet function.
 * 
 * By using the LOG-macros debug messages can be enabled or disabled by the
 * precompiler. DEBUGLOG_LEVEL needs to be defined the AppConf.h. During runtime
 * the loglevel can be selected through the nodes loglevel setting
 * (rlo, slo commands).
 * 
 * This module is not referenced by the ScatterWeb system and needs to be included
 * separately to be used. If it is not used it will not get linked to the application
 * image.
 */

#ifndef SCATTERWEB_DEBUGLOG_H_
#define SCATTERWEB_DEBUGLOG_H_


/**
 * @name Debug Output Log Levels
 */
///@{

/**
 @brief	Radio debug output.

 @since	1.0
 */
#define DEBUG_RADIO     (0x80)

/**
 @brief	Dco adjusting debug output.

 @since	1.0
 */
#define DEBUG_DCO       (0x40)

/**
 * No output
 * @since 1.1
 */
#define NONE			(0x00)

/**
 @brief	Comm_print(), Comm_log(LOW) get through.

 @since	1.0
 */
#define LOW             (0x01)

/**
 @brief	Comm_print(), Comm_log(LOW), Comm_log(MEDIUM) get through.

 @since	1.0
 */
#define MEDIUM          (0x02)

/**
 @brief	Comm_print(), Comm_log(LOW), Comm_log(MEDIUM), Comm_log(HIGH) get through.

 @since	1.0
 */
#define HIGH            (0x04)

/**
 @brief	All get through.

 @since	1.0
 */
#define VERBOSE         (0x05)

///@}

/******************************************************************************
 * @name Typedefs
 * @{
 */
#define DEBUGLOG_LEVEL_MASK	0x0F	///< mask level bits

/// Test if a certain level is reached
#define DEBUGLOG_LEVEL_TEST(level)		((Debuglog_level & DEBUGLOG_LEVEL_MASK) >= level)

/// Test if a certain level is reached and debugging for the given component is active
#define DEBUGLOG_LEVEL_TESTHW(component, level)		(((Debuglog_level & component) == component) && DEBUGLOG_LEVEL_TEST( level ))

/// Test if a certain level is reached and debugging for the given component is active
#define DEBUGLOG_LEVEL_TESTHWRANGE(component, levelmin, levelmax)		( DEBUGLOG_LEVEL_TESTHW( component, levelmin ) && !DEBUGLOG_LEVEL_TEST(( levelmax + 1 )) )

///@}

extern const char Debuglog_level_strings[];

typedef void(*fp_log_t)(uint8_t, const char*, ...);

/**
 * @name		Handling of debuglog messages
 */
//@{

/**
 * @brief		Set handler for debug output
 * @param[in]	handler		Pointer to debuglog output handler
 *
 * Enables logging output on a specific interface.
 *
 * @see Debuglog_null, Debuglog_serial, Debuglog_radio
 */
void Debuglog_setHandler(fp_log_t handler);

/**
 * @brief		Output all logging data to the serial port (default)
 *
 * Output is produced in the following form:
 * <code>#&lt;level&gt;:&lt;message&gt;</code>
 */
void Debuglog_serial(uint8_t level, const char *fmt, ...);

/**
 * @brief		Output all logging data through radio broadcast
 * 
 * Use Debuglog_print_packet to print received data (e.g. at a gateway node).
 *
 * @see Debuglog_print_packet
 */
void Debuglog_radio(uint8_t level, const char* fmt, ...);

/**
 * @brief		No output
 */
void Debuglog_null(uint8_t level, const char* fmt, ...);
//@}

/**
 * @brief Debuglog messsage writer
 * @param[in]	header		Header of packet to print
 * @param[in]	payload		Payload of packet
 * @param[in]	size		Size of payload
 * 
 * Writes Debuglog packets received to RS232.
 *
 * Output is produced in the following form:
 * <code>[&lt;node&gt;] #&lt;level&gt;:&lt;message&gt;</code>
 */
void Debuglog_print_packet(netheader_t header, const void* payload, uint16_t size);

/**
 * @brief	Value of the log level
 *
 * <p>A combination of hardware flags, to enable detailed low-level debug for specific modules
 * plus one overall loglevel value.
 * <p>Hardware flags:<ul>
 * <li>DEBUG_DCO
 * <li>DEBUG_RADIO
 * </ul>
 * <p>Overall loglevel
 * <ul>
 * <li>NONE
 * <li>LOW
 * <li>MEDIUM
 * <li>HIGH
 * <li>VERBOSE
 * </ul>
 * 
 * @since         1.0
 * @see CMD_ASCII(llv)
 */
extern uint8_t	Debuglog_level;

/******************************************************************************
 * @name Logging macros
 * 
 * The following macros are for logging output. They allow compile level
 * switching of logging functionality.
 * \p To use a certain debug level during runtime #DEBUGLOG_LEVEL needs to be
 * defined to a value greater than or equal to this debug level. Macros with a
 * debug level higher than #DEBUGLOG_LEVEL are removed automatically by the
 * precompiler.
 */
//@{
#if (DEBUGLOG_LEVEL & DEBUGLOG_LEVEL_MASK) > NONE
	extern fp_log_t Debuglog_print;
	#define LOG(_mode, _format, args...)  Debuglog_print( _mode ,  _format , ##args)
#else
	#define LOG(_mode, _format, ...)
#endif

#if (DEBUGLOG_LEVEL & DEBUGLOG_LEVEL_MASK) >= LOW
	#define LOG_LOW(_format, args...)		LOG(LOW, _format, ##args)
#else
  #define LOG_LOW(...)
#endif

#if (DEBUGLOG_LEVEL & DEBUGLOG_LEVEL_MASK) >= MEDIUM
	#define LOG_MEDIUM(_format, args...)  LOG(MEDIUM, _format, ##args)
#else
	#define LOG_MEDIUM(...)
#endif

#if (DEBUGLOG_LEVEL & DEBUGLOG_LEVEL_MASK) >= HIGH
	#define LOG_HIGH(_format, args...)    LOG(HIGH, _format, ##args)
#else
	#define LOG_HIGH(...)
#endif
  
#if (DEBUGLOG_LEVEL & DEBUGLOG_LEVEL_MASK) >= VERBOSE
	#define LOG_VERBOSE(_format, args...)	LOG(VERBOSE , _format , ##args)
#else
	#define LOG_VERBOSE(...)
#endif

#if (DEBUGLOG_LEVEL & ~DEBUGLOG_LEVL_MASK) > 0
	#define LOG_HARDWARE(_flag, _format, ...) \
										Debuglog_serial( _flag , _format, __VA_ARGS__)
#else
	#define LOG_HARDWARE(...)
#endif

#define DEBUGLOG_STRINGIFY(x) #x
#define DEBUGLOG_AT __FILE__ ":" DEBUGLOG_STRINGIFY(__LINE__) 
	
#if WITH_ASSERT
	void _assert(char*, unsigned);
	#define ASSERT(f)					\
		if(f)							\
			{}							\
		else							\
			LOG(LOW, "\nAssertion failed: "DEBUGLOG_AT"\n")
#else
	#define ASSERT(f)
#endif

#define PANICASSERT(reason, f)			\
	if(f)								\
		{}								\
	else								\
		System_panic(reason, DEBUGLOG_AT);
	
	
//@}

#endif /*SCATTERWEB_DEBUGLOG_H_*/
