#ifndef PHSTBDBG_H
#define PHSTBDBG_H

/*  Copyright (C) 2005 Koninklijke Philips Electronics N.V.
    All Rights Reserved.
*//**
    @file   phStbDbg.h
    @brief  Cutdown version of tmDbg for Linux without tmosal.

@b  Component:  phStbDbg.

*//*

Rev Date        Author      Comments
--------------------------------------------------------------------------------
  1 20050628    batelaan    Original
  2 20050628    batelaan    Crosscheck fixes.
  3 20050628    batelaan    Crosscheck fixes.
  4 20050705    batelaan    Enable use in Linux kernel modules.
4.1.1 20050811  batelaan    Ensure it compiles under WinCE AND Linux AND TCS
  5 20050729    batelaan    Enhance registration of modules.
  6 20050809    batelaan    Remove TMDBG_MAX_UNIT_NAME_LEN; removed struct tmDbgUnit 
  7 20050809    batelaan    Merged.
  8 20050938    batelaan    Cause an unregistered component to always print
                            (handy for discovering this anomaly).
  9 20060124    batelaan    Add extern "C" for use with C++
--------------------------------------------------------------------------------
    For consistency and standardisation retain the Section Separators.
*/

/* On TriMedia we use the standard tmDbg library, otherwise we use our own reduced
   functionality macros defined inside this file. */
#ifdef __TCS__
#include <tmDbg.h>
#else

#include <phStbCommon.h>
#include <tmFlags.h>
#ifdef MODULE
  #include <linux/module.h>
#endif

#ifdef __cplusplus
extern "C"
{
#endif

/** Linux device name used by this module for controlling DBG settings. */
#define PH_STBDBG_DEVNAME "phdbg"

/* These are the flags that are used for the units
 * need to be defined in a separate header file and based on 
 * DBG_CUSTOM_START. */
#define DBG_DEFAULT             0x0001u
#define DBG_STATE               0x0002u
#define DBG_EVENTIN             0x0004u
#define DBG_EVENTOUT            0x0008u
#define DBG_INTERFACE_ENTER     0x0010u
#define DBG_INTERFACE_LEAVE     0x0020u
#define DBG_INTERNAL_ENTER      0x0040u
#define DBG_INTERNAL_LEAVE      0x0080u
/* Intentionally placed here, to let level 1 start at a good location
   (while 1 is taken by default). */
#define DBG_LEVEL_1             0x0100u
#define DBG_LEVEL_2             0x0200u
#define DBG_LEVEL_3             0x0400u
#define DBG_LEVEL_4             0x0800u
#define DBG_LEVEL_5             0x1000u
#define DBG_EXTERNAL_CALL       0x2000u
#define DBG_EXTERNAL_RETURN     0x4000u
#define DBG_WARNING             0x8000u
#define DBG_CUSTOM_START    0x00010000u
#define DBG_LEVEL_1_AND_BELOW   0x0100u
#define DBG_LEVEL_2_AND_BELOW   0x0300u
#define DBG_LEVEL_3_AND_BELOW   0x0700u
#define DBG_LEVEL_4_AND_BELOW   0x0f00u
#define DBG_LEVEL_5_AND_BELOW   0x1f00u
#define DBG_ALL_FLAGS       0xffffffffu
#define DBG_NO_FLAGS        0x00000000u

#define DBG_ROOT                gphStbDbg_DbgUnit




/******************************************************************************/
/* COMMON */
/******************************************************************************/

/******************************************************************************/
/* MODES */
/******************************************************************************/

#if (!defined(DBG_DISABLE_ALL) && \
    ((defined(DBG_ENABLE_ALL)) || \
    (defined(TMFL_REL_DEBUG) && (TMFL_REL == TMFL_REL_DEBUG)) ||\
    (defined(TMFL_REL_TRACE) && (TMFL_REL == TMFL_REL_TRACE))))
/* If DBG_DISABLE_ALL is defined, all debug macros for the current
 * file are disabled (as if it were compiled for release). This is
 * a convenient way to disable the debug library for certain files.
 * If DBG_ENABLE_ALL is defined, all macros are enabled. This is a 
 * convinient way to include debug statements even when not building
 * in debug mode. */
/***************************/
/* TRACE AND DEBUG SECTION */
/***************************/

#define TMDBG_PRINTS_ARE_ENABLED 1
#define TMDBG_ASSERTS_ARE_ENABLED 1

#elif (defined(DBG_ENABLE_ASSERTS)) || (TMFL_REL == TMFL_REL_ASSERT) || \
    ((TMFL_REL == TMFL_REL_RETAIL) && (!defined(NDEBUG)))

/* If DBG_ENABLE_ASSERTS is defined, only DBG_INIT, DBG_UNINIT, DBG_ASSERT, 
 * DBG_ASSERT2, and DBG_DETECT_ERROR are defined. This is a good way to reduce
 * the amount of debug overhead, while maintaining the protection the assert
 * statements offer. */
/******************/
/* ASSERT SECTION */
/******************/

#define TMDBG_PRINTS_ARE_ENABLED 0
#define TMDBG_ASSERTS_ARE_ENABLED 1

#else   

/* The release version of the header file. Most macros
 * translate to nothing, except the ones that are used in
 * an expression. */
/******************/
/* RETAIL SECTION */
/******************/

#define TMDBG_PRINTS_ARE_ENABLED 0
#define TMDBG_ASSERTS_ARE_ENABLED 0

#endif

#if TMDBG_PRINTS_ARE_ENABLED || TMDBG_ASSERTS_ARE_ENABLED 

#define DBG_INIT() \
    tmDbg_Init();
extern Void tmDbg_Init(Void);

#else
#define DBG_INIT()
#endif


#if TMDBG_PRINTS_ARE_ENABLED
typedef struct tmDbgUnit {
    UInt32 flgs;
    Char name[1];
} tmDbgUnit_t;
typedef tmDbgUnit_t *ptmDbgUnit_t;

/** Returns true if debug unit has the flags set.
    If the uid is NULL then always return true. Also checks if any of the flags
    are set in the DBG_ROOT unit.
*/
#define DBG_PRINT_CHECK(uid, flags)  \
    (((uid) == NULL) || ((flags & (((DBG_ROOT->flgs)) | ((uid)->flgs))) != 0U))

#ifdef MODULE
  #define __DBG_EXPORT(uid) EXPORT_SYMBOL(uid);
#else
  #define __DBG_EXPORT(uid) 
#endif

#define __DBG_UNIT(uid,__access) \
  __access ptmDbgUnit_t uid; \
  __DBG_EXPORT(uid)

#define DBG_UNIT(uid)           __DBG_UNIT(uid,/**/)
#define DBG_UNIT_STATIC(uid)    __DBG_UNIT(uid,static)
#define DBG_UNIT_EXTERN(uid)    extern ptmDbgUnit_t uid;
#define DBG_UNIT_PARAM(uid)     ptmDbgUnit_t uid
#define DBG_UNIT_AS_PARAM(uid)  uid

DBG_UNIT_EXTERN(gphStbDbg_DbgUnit)
    
#define DBG_IS_UNKNOWN(uid) \
    ( (uid) == Null )

#define DBG_REGISTER_MODULE(uid, __name)                        \
    tmDbg_RegisterModule( &(uid), __name );

extern Void
tmDbg_RegisterModule(
    ptmDbgUnit_t          * ppUnit,     // O: The registered debug unit will be
                                        //    stored here.
    const Char*             pUnitName   // I: A pointer to the name or GUID. 
    );


#define DBG_ATTACH_MODULE(uid, name, prereg)    \
    DBG_REGISTER_MODULE(uid, name)
    
#define DBG_ATTACH_COMPONENT(uid, type, name, prereg) \
    DBG_REGISTER_MODULE(uid, name)


#define DBG_DETACH_MODULE(uid) \
    (uid) = NULL;

#define DBG_DETACH_COMPONENT(uid) \
    (uid) = NULL;


extern Void tmDbg_Print(ptmDbgUnit_t uid, UInt32 flags, Char *fmt, ...);

#define DBG_PRINT(param)                        \
    tmDbg_Print param ;

#define DBG_PRINT0(uid, flags, message)     \
    if ( DBG_PRINT_CHECK(uid, flags) )      \
    {                                       \
        tmDbg_Print( uid, flags, message );  \
    }

#define DBG_PRINT1(uid, flags, message, p1)     \
    if ( DBG_PRINT_CHECK(uid, flags) )          \
    {                                           \
        tmDbg_Print( uid, flags, message, p1 );  \
    }

#define DBG_PRINT2(uid, flags, message, p1, p2)                 \
    if ( DBG_PRINT_CHECK(uid, flags) )  \
    {                                   \
        tmDbg_Print( uid, flags, message, p1, p2 );          \
    }

#define DBG_PRINT3(uid, flags, message, p1, p2, p3)             \
    if ( DBG_PRINT_CHECK(uid, flags) )  \
    {                                   \
        tmDbg_Print( uid, flags, message, p1, p2, p3 );          \
    }

#define DBG_PRINT4(uid, flags, message, p1, p2, p3, p4)             \
    if ( DBG_PRINT_CHECK(uid, flags) )  \
    {                                   \
        tmDbg_Print( uid, flags, message, p1, p2, p3, p4 );      \
    }

#define DBG_PRINT5(uid, flags, message, p1, p2, p3, p4, p5)         \
    if ( DBG_PRINT_CHECK(uid, flags) )  \
    {                                   \
        tmDbg_Print( uid, flags, message, p1, p2, p3, p4, p5 );      \
    }

#define DBG_PRINT6(uid, flags, message, p1, p2, p3, p4, p5, p6)         \
    if ( DBG_PRINT_CHECK(uid, flags) )  \
    {                                   \
        tmDbg_Print( uid, flags, message, p1, p2, p3, p4, p5, p6 );  \
    }

#define DBG_PRINT7(uid, flags, message, p1, p2, p3, p4, p5, p6, p7)     \
    if ( DBG_PRINT_CHECK(uid, flags) )  \
    {                                   \
        tmDbg_Print( uid, flags, message, p1, p2, p3, p4, p5, p6, p7 );  \
    }

#define DBG_PRINT8(uid, flags, message, p1, p2, p3, p4, p5, p6, p7, p8)     \
    if ( DBG_PRINT_CHECK(uid, flags) )  \
    {                                   \
        tmDbg_Print( uid, flags, message, p1, p2, p3, p4, p5, p6, p7, p8 );\
    }

#define DBG_PRINT9(uid, flags, message, p1, p2, p3, p4, p5, p6, p7, p8, p9) \
    if ( DBG_PRINT_CHECK(uid, flags) )  \
    {                                   \
        tmDbg_Print( uid, flags, message, p1, p2, p3, p4, p5, p6, p7, p8, p9 );\
    }

#define DBG_SET_FLAGS(uid, flags) \
    tmDbg_SetFlags( uid, flags );

#define tmDbg_SetFlags(uid, flags) (uid)->flgs = (flags);

#define DBG_GET_FLAGS(uid, flags)  \
    (flags = tmDbg_GetFlags( uid ))

#define tmDbg_GetFlags(uid) ((uid)->flgs)

#define DBG_ENABLE_FLAGS(uid, flags)        \
    tmDbg_SetFlags( uid, tmDbg_GetFlags( uid ) | (flags) );

#define DBG_DISABLE_FLAGS(uid, flags)       \
    tmDbg_SetFlags( uid, tmDbg_GetFlags( uid ) & ~(flags) );

#else
   /* debug prints are off */
#define DBG_UNIT(uid)
#define DBG_UNIT_EXTERN(uid)
#define DBG_UNIT_STATIC(uid)
#define DBG_UNIT_PARAM(uid)     int uid
#define DBG_UNIT_AS_PARAM(uid)  0

#define DBG_IS_UNKNOWN(uid)     0

#define DBG_REGISTER_MODULE(uid, name)
#define DBG_UNREGISTER_MODULE(uid)

#define DBG_PRINT(param)
#define DBG_PRINT0(uid, flags, message)
#define DBG_PRINT1(uid, flags, message, p1)
#define DBG_PRINT2(uid, flags, message, p1, p2)
#define DBG_PRINT3(uid, flags, message, p1, p2, p3)
#define DBG_PRINT4(uid, flags, message, p1, p2, p3, p4)
#define DBG_PRINT5(uid, flags, message, p1, p2, p3, p4, p5)
#define DBG_PRINT6(uid, flags, message, p1, p2, p3, p4, p5, p6) 
#define DBG_PRINT7(uid, flags, message, p1, p2, p3, p4, p5, p6, p7)
#define DBG_PRINT8(uid, flags, message, p1, p2, p3, p4, p5, p6, p7, p8)
#define DBG_PRINT9(uid, flags, message, p1, p2, p3, p4, p5, p6, p7, p8, p9)

#define DBG_AGGREGATE_LINK(puid, chuid)
#define DBG_SET_FLAGS(uid, flags)
#define DBG_GET_FLAGS(uid, flags)   flags = 0;
#define DBG_ENABLE_FLAGS(uid, flags)
#define DBG_DISABLE_FLAGS(uid, flags)

#endif

#if TMDBG_ASSERTS_ARE_ENABLED

#define DBG_ASSERT(assertion)                                               \
    if (!(assertion))                                                       \
    {                                                                       \
        tmDbg_AssertError( #assertion, __FILE__, __LINE__,                  \
                           0);                                              \
    }

#define DBG_ASSERT2(assertion, message)                                     \
    if (!(assertion))                                                       \
    {                                                                       \
        tmDbg_AssertError( #assertion, __FILE__, __LINE__,                  \
                           tmDbg_StrAssertFormat message); \
    }


extern Void tmDbg_AssertError(
    const Char *assertion,
    const Char *file,
    UInt line,
    const Char *msg);
extern Char *tmDbg_StrAssertFormat(Char *fmt, ...);
    
#else  /* !TMDBG_ASSERTS_ARE_ENABLED */
#define DBG_ASSERT(assertion)
#define DBG_ASSERT2(assertion, message)
#endif


#if defined(__cplusplus)
}
#endif

#endif /* __linux__ */

#endif /* PHSTBDBG_H */
