/****************************************************************************
* Copyright (c) 2018, Broadcom Inc.                                         *
*                                                                           *
* All Rights Reserved.                                                      *
*                                                                           *
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Inc.;             *
* the contents of this file may not be disclosed to third parties, copied   *
* or duplicated in any form, in whole or in part, without the prior         *
* written permission of Broadcom Inc.                                       *
*****************************************************************************/

/**
 * @file    sdk_trace.h
 * @brief   header file to use debug traces
 * @details header file to use debug traces
 */

#ifndef _DSP_SDK_TRACE_H_
#define _DSP_SDK_TRACE_H_

#define TRACE_COMPILE_LEVEL 0

/**
 * @brief Module ID to be used for trace
 */
enum
{

    MODULE_ID_DSP        = 0x20,
    /* for application use */
    APPL_MODULE_ID_MODU0 = 0x4A,
    APPL_MODULE_ID_MODU1 = 0x4B,
    APPL_MODULE_ID_MODU2 = 0x4C
};

/*******************************************************************************
* Function Prototypes
*******************************************************************************/

/**
 * @brief Store traces into ring buffer.
 */
void dbfw_StoreTrace(UINT32 level_module_id, UINT32 id, ...);

/*
 * The definitions below need to be aligned with internal firmware
 * Later addendum also needs to be updated to firmware before use
 */

/*
 * @brief Mask set to be used in mask parameter index 0 of Sdk_DebugTraceSet()
 */
#define BRCM_TRACE_MASK_DSP              (1 << 0)
#define BRCM_TRACE_MASK_SH               (1 << 1)
#define BRCM_TRACE_MASK_WL               (1 << 2)
#define BRCM_TRACE_MASK_HCI_MSG          (1 << 3)
#define BRCM_TRACE_MASK_BTE_USB          (1 << 4)
#define BRCM_TRACE_MASK_BTE_SERIAL       (1 << 5)
#define BRCM_TRACE_MASK_BTE_SOCKET       (1 << 6)
#define BRCM_TRACE_MASK_BTE_GEN          (1 << 7) /* Used for general traces not in specific module stack ID */
#define BRCM_TRACE_MASK_BTE_GKI          (1 << 8)
#define BRCM_TRACE_MASK_BTE_HCI          (1 << 9)
#define BRCM_TRACE_MASK_BTE_L2CAP        (1 << 10)
#define BRCM_TRACE_MASK_BTE_SMP          (1 << 11)
#define BRCM_TRACE_MASK_BTE_SDP          (1 << 12)
#define BRCM_TRACE_MASK_BTE_BTM          (1 << 13)
#define BRCM_TRACE_MASK_BTE_GAP          (1 << 14)
#define BRCM_TRACE_MASK_BTE_ATT          (1 << 15)
#define BRCM_TRACE_MASK_BTE_GATT         (1 << 16)
#define BRCM_TRACE_MASK_BTE_RFCOMM       (1 << 17)
#define BRCM_TRACE_MASK_BTE_AVDTP        (1 << 18)
#define BRCM_TRACE_MASK_BTE_AVCTP        (1 << 19)
#define BRCM_TRACE_MASK_BTE_SPP          (1 << 20)
#define BRCM_TRACE_MASK_BTE_HFP          (1 << 21)
#define BRCM_TRACE_MASK_BTE_HID          (1 << 22)
#define BRCM_TRACE_MASK_BTE_AVRCP        (1 << 23)
#define BRCM_TRACE_MASK_BTE_A2DP         (1 << 24)
#define BRCM_TRACE_MASK_BTE_LPST         (1 << 25)

/** @brief Used to enable all Host stack traces (Mask[0]) */
#define SDK_TRACE_MASK0_ALL_STACK \
    (UINT32)(BRCM_TRACE_MASK_DSP | BRCM_TRACE_MASK_SH | BRCM_TRACE_MASK_BTE_GEN | BRCM_TRACE_MASK_BTE_GKI \
    | BRCM_TRACE_MASK_BTE_HCI | BRCM_TRACE_MASK_BTE_L2CAP | BRCM_TRACE_MASK_BTE_SMP | BRCM_TRACE_MASK_BTE_SDP \
    | BRCM_TRACE_MASK_BTE_BTM | BRCM_TRACE_MASK_BTE_ATT | BRCM_TRACE_MASK_BTE_GATT | BRCM_TRACE_MASK_BTE_RFCOMM \
    | BRCM_TRACE_MASK_BTE_AVDTP | BRCM_TRACE_MASK_BTE_AVCTP | BRCM_TRACE_MASK_BTE_SPP | BRCM_TRACE_MASK_BTE_HFP \
    | BRCM_TRACE_MASK_BTE_LPST | BRCM_TRACE_MASK_BTE_AVRCP | BRCM_TRACE_MASK_BTE_A2DP)

/*
 * @brief set to be used in mask parameter index 1 of Sdk_DebugTraceSet()
 */
/* for SDK APIs */
#define SDK_TRACE_MASK_GEN               (1 << 0)    /* Used for general traces not in specific module SDK ID */
#define SDK_TRACE_MASK_OS                (1 << 1)    /* SDK API and shim for memory, timers, queues, etc */
#define SDK_TRACE_MASK_FS                (1 << 2)    /* SDK API and shim for file system (including FileX) */
#define SDK_TRACE_MASK_BTA               (1 << 3)    /* Bluetooth Adaptation Layer (ex. bta_dm) */
/* for additional SDK modules */
#define SDK_TRACE_MASK_MODU0             (1 << 4)
#define SDK_TRACE_MASK_MODU1             (1 << 5)
#define SDK_TRACE_MASK_MODU2             (1 << 6)
#define SDK_TRACE_MASK_MODU3             (1 << 7)
#define SDK_TRACE_MASK_MODU4             (1 << 8)
#define SDK_TRACE_MASK_MODU5             (1 << 9)
/* for application use */
#define APPL_TRACE_MASK_MODU0             (1 << 10)
#define APPL_TRACE_MASK_MODU1             (1 << 11)
#define APPL_TRACE_MASK_MODU2             (1 << 12)

/** @brief The trace mask set for SDK use */
#define SDK_TRACE_MASK1_ALL_SDK \
    (UINT32)(SDK_TRACE_MASK_GEN | SDK_TRACE_MASK_OS | SDK_TRACE_MASK_FS | SDK_TRACE_MASK_BTA \
    | SDK_TRACE_MASK_MODU0 | SDK_TRACE_MASK_MODU1 | SDK_TRACE_MASK_MODU2    \
    | SDK_TRACE_MASK_MODU3 | SDK_TRACE_MASK_MODU4 | SDK_TRACE_MASK_MODU5)

/** @brief The trace mask set for APP use */
#define SDK_TRACE_MASK1_ALL_APP (APPL_TRACE_MASK_MODU0 | APPL_TRACE_MASK_MODU1 | APPL_TRACE_MASK_MODU2)


/** @brief Trace mode */
enum
{
    SDK_TRACE_STOP = 0,
    SDK_TRACE_START = 2
};

/** @brief Trace level. Should be the same as those defined in dbfw.h */
enum
{
    APPL_TRACE_DEBUG = 0,
    APPL_TRACE_INFO = 1,
    APPL_TRACE_WARNING = 2,
    APPL_TRACE_CRITICAL = 3
};
enum
{
    TRACE_DEBUG         = 0,
    TRACE_INFO          = 1,
    TRACE_WARNING       = 2,
    TRACE_COND_CRITICAL = 3,
    TRACE_CRITICAL      = 4
};

/** @brief Trace level to the cores */
typedef struct
{
    UINT8               trace_level_cm4;    /**< trace level config to CM4. */
    UINT8               trace_level_dsp;    /**< trace level config to DSP. */
    UINT8               trace_level_sh;     /**< trace level config to SH. */
} tSDK_TRACE_LEVEL;

#define SDK_TRACE_NUM_OF_MASK_SET       2
typedef UINT32 tSDK_TRACE_MASK[SDK_TRACE_NUM_OF_MASK_SET]; /* Trace mask for SDK API */

/** @brief Trace configuration passed to API */
typedef struct
{
    tSDK_TRACE_MASK     mask_set;    /**< trace mask set to enable/disable traces from the modules. */
    tSDK_TRACE_LEVEL    level;       /**< trace level to be used in the cores . */
    UINT8               enable;      /**< trace enable or disable. */
} tSDK_TRACE_CONFIG;

/// @cond (1)

#define CONCATENATE_DIRECT(s1, s2) s1##s2
#define CONCATENATE(s1, s2) CONCATENATE_DIRECT(s1, s2)

#define PP_NARG(...) PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N(_0,_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define PP_RSEQ_N() 8,7,6,5,4,3,2,1,0

#define PP_NARG_DECORATED(...) PP_NARG_DEC_(__VA_ARGS__,PP_RSEQ_DEC_N())
#define PP_NARG_DEC_(...) PP_ARG_DEC_N(__VA_ARGS__)
#define PP_ARG_DEC_N(_0,_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define PP_RSEQ_DEC_N() _8_,_7_,_6_,_5_,_4_,_3_,_2_,_1_,_0_

#define PP_NARG_LIM_0_
#define PP_NARG_LIM_1_
#define PP_NARG_LIM_2_
#define PP_NARG_LIM_3_
#define PP_NARG_LIM_4_
#define PP_NARG_LIM_5_
#define PP_NARG_LIM_6_
#define PP_NARG_LIM_7_
#define PP_NARG_LIMIT_CHECK(x) CONCATENATE(PP_NARG_LIM,x)

#define PACK_TRACE_MODULE(trace_lvl, mod_id) ((trace_lvl << 3) | (mod_id << 5))

typedef struct
{
    UINT32 mask;
    char name[252];
} SDK_LOG_DATA_t;

extern void dbfw_storeTrace(UINT32 level_module_id, UINT32 id, ...);

#define SDK_FW_LOG(level, name, fmt, ...) {  \
    static SDK_LOG_DATA_t CONCATENATE(__log_data__,name) __attribute__ ((section("log_data"))) = {(level | (PP_NARG(1, ##__VA_ARGS__))), fmt}; \
    PP_NARG_LIMIT_CHECK(PP_NARG_DECORATED(1, ##__VA_ARGS__)); \
    dbfw_storeTrace(level | (PP_NARG(1, ##__VA_ARGS__)), (UINT32)&CONCATENATE(__log_data__,name), ##__VA_ARGS__); \
}


#if defined(DEBUG) || defined(WIN32)
#define APPL_TRACE_DEBUG(module, msg, ...)   debug_Printf(msg, ##__VA_ARGS__)
#define APPL_TRACE_INFO(module, msg, ...)    debug_Printf(msg, ##__VA_ARGS__)
#define APPL_TRACE_WARNING(module, msg, ...) debug_Printf(msg, ##__VA_ARGS__)
#define APPL_TRACE_CRITICAL(module, msg, ...) debug_Printf(msg, ##__VA_ARGS__)
#else
#define APPL_TRACE_DEBUG(module, msg, ...)   SDK_FW_LOG(PACK_TRACE_MODULE(APPL_TRACE_DEBUG, module), CONCATENATE(FID2,__LINE__), msg, ##__VA_ARGS__)
#define APPL_TRACE_INFO(module, msg, ...)    SDK_FW_LOG(PACK_TRACE_MODULE(APPL_TRACE_INFO, module), CONCATENATE(FID2,__LINE__), msg, ##__VA_ARGS__)
#define APPL_TRACE_WARNING(module, msg, ...) SDK_FW_LOG(PACK_TRACE_MODULE(APPL_TRACE_WARNING, module), CONCATENATE(FID2,__LINE__), msg, ##__VA_ARGS__)
#define APPL_TRACE_CRITICAL(module, msg, ...) SDK_FW_LOG(PACK_TRACE_MODULE(APPL_TRACE_CRITICAL, module), CONCATENATE(FID2,__LINE__), msg, ##__VA_ARGS__)
#endif
/// @endcond

/** @brief Debug trace APIs which support argument entities up to 7 */
#define APPL_TRACE_ID0(level, msg, ...) level(APPL_MODULE_ID_MODU0, msg, ##__VA_ARGS__)
#define APPL_TRACE_ID1(level, msg, ...) level(APPL_MODULE_ID_MODU1, msg, ##__VA_ARGS__)
#define APPL_TRACE_ID2(level, msg, ...) level(APPL_MODULE_ID_MODU2, msg, ##__VA_ARGS__)


/*******************************************************************************
* Defines & Macros
*******************************************************************************/
/* Trace Variable Format */
/* UINT32 x 1 */
#define TVF_D(x)            (UINT32)(x)
/* UINT16 x 2 */
#define TVF_WW(x,y)         (UINT32)((((UINT32)(x) << 16) & 0xFFFF0000) | ((UINT32)(y) & 0x0000FFFF))
/* UINT8 x 2 */
#define TVF_BB(x,y)         (UINT32)((((UINT32)(x) <<  8) & 0x0000FF00) | ((UINT32)(y) & 0x000000FF))
/* UINT8 x 2 + UINT16 */
#define TVF_BBW(x,y,z)      TVF_WW(TVF_BB(x,y), z)
/* UINT16 + UINT8 x 2 */
#define TVF_WBB(x,y,z)      TVF_WW(x, TVF_BB(y,z))
/* UINT8 x 4 */
#define TVF_BBBB(x,y,z,w)   TVF_WW(TVF_BB(x, y), TVF_BB(z, w))

// merge precompiler strings
#define CONCATENATE_DIRECT(s1, s2) s1##s2
#define CONCATENATE(s1, s2) CONCATENATE_DIRECT(s1, s2)

/**
 * PP_NARG will return 1 if __VA_ARGS__ is empty, so be sure to add a dummy arg (and RSEQ to 8)
 * if TRACE(level, module, "format", arg1, arg2)
 * then PP_NARG(1, arg1, arg2)
 * then PP_NARG_(1, arg1, arg2, PP_RSEQ_N())
 * then PP_ARG_N(1, arg1, arg2, 8, 7, 6, 5, 4, 3, 2, 1, 0)
 * which returns N = 2
 */
#define PP_NARG(...) PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N(_0,_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define PP_RSEQ_N() 8,7,6,5,4,3,2,1,0

/* here PP_NARG_DECORATED returns "_<number of args>_" for use in limit check */
#define PP_NARG_DECORATED(...) PP_NARG_DEC_(__VA_ARGS__,PP_RSEQ_DEC_N())
#define PP_NARG_DEC_(...) PP_ARG_DEC_N(__VA_ARGS__)
#define PP_ARG_DEC_N(_0,_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define PP_RSEQ_DEC_N() _8_,_7_,_6_,_5_,_4_,_3_,_2_,_1_,_0_

/* define valid empty macros that PP_NARG_LIMIT_CHECK can resolve to if we have a valid number of args (0-7) */
#define PP_NARG_LIM_0_
#define PP_NARG_LIM_1_
#define PP_NARG_LIM_2_
#define PP_NARG_LIM_3_
#define PP_NARG_LIM_4_
#define PP_NARG_LIM_5_
#define PP_NARG_LIM_6_
#define PP_NARG_LIM_7_
#define PP_NARG_LIMIT_CHECK(x) CONCATENATE(PP_NARG_LIM,x)

#define PACK_TRACE_MODULE(trace_lvl, mod_id) ((trace_lvl << 3) | (mod_id << 5))
#define DBFW_MASK2LEVEL(mask)     ((mask >> 3) & 0x3)
#define DBFW_MASK2MODULE(mask)  ((mask >> 5) & 0x7F)
#define DBFW_MASK2LEN(mask)   (mask & 0x7)


typedef struct {
    UINT32 mask;
    char name[252];
} LOG_DATA_t;

/**
 * macro at base of debug TRACE messages
 * the goal is to create a unique identifier with mask bits and number of args resolved by compiler
 * also storage is declared to associate the identifier with the format string
 * the storage declared will not be part of image, but can be recovered from elf file
 * NOTE: '##' prefix is a GNU-style extension to remove ',' when __VA_ARGS__ is empty
 */
#define FW_LOG(level, name, fmt, ...) {  \
    static LOG_DATA_t CONCATENATE(__log_data__,name) __attribute__ ((section(".log_data"))) = {(level | (PP_NARG(1, ##__VA_ARGS__))), fmt}; \
    PP_NARG_LIMIT_CHECK(PP_NARG_DECORATED(1, ##__VA_ARGS__)); \
    dbfw_StoreTrace(level | (PP_NARG(1, ##__VA_ARGS__)), (UINT32)&CONCATENATE(__log_data__,name), ##__VA_ARGS__); \
}


#if !defined(TRACE_COMPILE_LEVEL)
#define TRACE_COMPILE_LEVEL 0
#endif

#if (TRACE_COMPILE_LEVEL == 0)
#define TRACE_TRACE_DEBUG(module, msg, ...) FW_LOG(PACK_TRACE_MODULE(TRACE_DEBUG, module), CONCATENATE(FID2,__LINE__), msg, ##__VA_ARGS__)
#endif

#if (TRACE_COMPILE_LEVEL <= 1)
#define TRACE_TRACE_INFO(module, msg, ...) FW_LOG(PACK_TRACE_MODULE(TRACE_INFO, module), CONCATENATE(FID2,__LINE__), msg, ##__VA_ARGS__)
#endif

#if (TRACE_COMPILE_LEVEL <= 2)
#define TRACE_TRACE_WARNING(module, msg, ...) FW_LOG(PACK_TRACE_MODULE(TRACE_WARNING, module), CONCATENATE(FID2,__LINE__), msg, ##__VA_ARGS__)
#endif

#if (TRACE_COMPILE_LEVEL <= 3)
#define TRACE_TRACE_CRITICAL(module, msg, ...) FW_LOG(PACK_TRACE_MODULE(TRACE_CRITICAL, module), CONCATENATE(FID2,__LINE__), msg, ##__VA_ARGS__)

#define TRACE_TRACE_COND_CRITICAL(module, msg, ...) FW_LOG(PACK_TRACE_MODULE(TRACE_COND_CRITICAL, module), CONCATENATE(FID2,__LINE__), msg, ##__VA_ARGS__)

#endif

#if !defined(TRACE_TRACE_CRITICAL)
#define TRACE_TRACE_CRITICAL(module, msg, ...)
#endif

#if !defined(TRACE_TRACE_COND_CRITICAL)
#define TRACE_TRACE_COND_CRITICAL(module, msg, ...)
#endif

#if !defined(TRACE_TRACE_WARNING)
#define TRACE_TRACE_WARNING(module, msg, ...)
#endif

#if !defined(TRACE_TRACE_INFO)
#define TRACE_TRACE_INFO(module, msg, ...)
#endif

#if !defined(TRACE_TRACE_DEBUG)
#define TRACE_TRACE_DEBUG(module, msg, ...)
#endif

#define TRACE(level, module, msg, ...) TRACE_##level(module, msg, ##__VA_ARGS__)

#endif  /* end of _DSP_SDK_TRACE_H_ */

