453 lines
19 KiB
C
453 lines
19 KiB
C
/**
|
|
******************************************************************************
|
|
* @file trace.h
|
|
*
|
|
* @brief Declaration for trace buffer.
|
|
*
|
|
* Copyright (C) ListenAI 2024-2025
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
#ifndef _TRACE_H_
|
|
#define _TRACE_H_
|
|
|
|
//#include "rwnx_config.h"
|
|
//#include "co_int.h"
|
|
//#include "co_bool.h"
|
|
#include "stdbool.h"
|
|
|
|
#if NX_TRACE
|
|
#define TRACE_FILE_ID_SIZE 9
|
|
#define CO_BIT(pos) (1UL << (pos))
|
|
/**
|
|
******************************************************************************
|
|
* @addtogroup TRACE
|
|
* @details
|
|
*
|
|
* @b Usage: \n
|
|
* You can add:
|
|
* - an unfiltered trace point using @ref TRACE macro for printf like trace and
|
|
* @ref TRACE_BUF to trace a buffer.
|
|
* - a filterable trace point (i.e. that can be disabled/enabled at run-time)
|
|
* using the @ref TRACE_FILT or @ref TRACE_BUF_FILT macros.
|
|
*
|
|
* Unfiltered trace points are always traced.\n
|
|
* A filterable trace point is traced if the bit of the trace point level is
|
|
* set in the current filter for the component. See trace_level_<compo> for
|
|
* trace level specific to a given component.\n
|
|
*
|
|
* You can then use @ref trace_set_filter to change the current filter of a
|
|
* given component. As @ref trace_compo_level is stored in shared_memory Host
|
|
* can also directly modify its content.
|
|
* @{
|
|
******************************************************************************
|
|
*/
|
|
|
|
/**
|
|
******************************************************************************
|
|
* @brief Initialize trace buffer.
|
|
*
|
|
* Normal usage would be to initialize trace buffer at boot with:
|
|
* - @p force set to false, so that if fw jumps back to boot code (e.g. by
|
|
* dereferencing invalid pointer), it will appear in the trace.
|
|
* - @p loop set to true to keep the latest trace.
|
|
*
|
|
* In some specific debug cases, it may be useful to start the trace after a
|
|
* specific event and to not use a circular buffer so that it ensure that trace
|
|
* that happened just after that specific event is kept. In this case set @p
|
|
* force to true and @p loop to false.
|
|
*
|
|
* @param[in] force Force buffer initialization even if trace buffer has
|
|
* already been initialized.
|
|
* @param[in] loop Whether trace buffer must be used circular buffer or not
|
|
******************************************************************************
|
|
*/
|
|
void trace_init(bool force, bool loop);
|
|
|
|
/**
|
|
******************************************************************************
|
|
* @brief Add a trace point in the buffer
|
|
*
|
|
* This function must NOT be called directly. use @ref TRACE, @ref TRACE_BUF
|
|
* or any of the TRACE_<LVL> macro instead.
|
|
*
|
|
* @param[in] id Unique trace id
|
|
* @param[in] nb_param Number of parameters to trace
|
|
* @param[in] param Table of parameters
|
|
* @param[in] trace_buf boolean indicating if TRACE_BUF macro is used. \n
|
|
* if true, param = [buffer size, buffer address(16 LSB),
|
|
* buffer address(16 MSB)]
|
|
******************************************************************************
|
|
*/
|
|
void trace(uint32_t id, uint16_t nb_param, uint16_t *param, bool trace_buf);
|
|
|
|
/**
|
|
******************************************************************************
|
|
* @brief Modify trace level on a given component
|
|
*
|
|
* @param[in] compo_id Component id (@ref trace_compo).
|
|
* use TRACE_COMPO_MAX to configure all components.
|
|
* @param[in] level Trace level to activate on the component.
|
|
******************************************************************************
|
|
*/
|
|
void trace_set_filter(unsigned int compo_id, unsigned int level);
|
|
|
|
/**
|
|
******************************************************************************
|
|
* @brief File ID offset in the 24bits trace ID.
|
|
*
|
|
* TRACE_FILE_ID_SIZE is passed on the compilation line so that its value can
|
|
* easily be shared with the trace dictionary generator.
|
|
* Its value is the same for all files.
|
|
******************************************************************************
|
|
*/
|
|
#define TRACE_FILE_ID_OFT (24 - TRACE_FILE_ID_SIZE)
|
|
|
|
/**
|
|
******************************************************************************
|
|
* @brief Unique Trace ID for current file/line
|
|
*
|
|
* TRACE_FILE_ID is passed on the compilation line and is different for each file.
|
|
******************************************************************************
|
|
*/
|
|
#define TRACE_ID ((TRACE_FILE_ID << TRACE_FILE_ID_OFT) + __LINE__)
|
|
|
|
/**
|
|
******************************************************************************
|
|
* @brief Macro used to add a unfiltered trace point in the trace buffer
|
|
*
|
|
* It should be called with a printf like prototype, and will call @ref trace
|
|
* function with a unique trace id (@ref TRACE_ID) and the parameters correctly
|
|
* formatted.
|
|
*
|
|
* Current format string supported by the decoder are:
|
|
* - For character :\n
|
|
* use format \%c and pass directly the character as parameter
|
|
* @verbatim TRACE("first char is %c", string[0]) @endverbatim
|
|
*
|
|
* - For 16bits value :\n
|
|
* Use one of the following format \%d, \%u, \%x, \%X and pass directly the
|
|
* value as parameter.
|
|
* @verbatim TRACE("this is a 16bit value %d", myval) @endverbatim
|
|
* It is also possible to add formatting option
|
|
* @verbatim TRACE("this is a 16bit value 0x%04x", myval) @endverbatim
|
|
*
|
|
* - For 32bits value :\n
|
|
* Use one of the following format \%ld, \%lu, \%lx, \%lX and pass the value
|
|
* using @ref TR_32 macro.
|
|
* @verbatim TRACE("this is a 32bit value 0x%08lx", TR_32(myval)) @endverbatim
|
|
*
|
|
* - For a string :\n
|
|
* Use format \%s and pass string using @ref TR_STR_8 macro.
|
|
* @verbatim TRACE("SSID = %s", TR_STR_8(param->ssid)) @endverbatim
|
|
* @note As implied by the name, string are currently limited to 8 characters.
|
|
*
|
|
* - For a pointer :\n
|
|
* Use format \%p and pass the value using @ref TR_PTR macro.
|
|
* @verbatim TRACE("buffer address is %p", TR_PTR(buffer)) @endverbatim
|
|
* @note \%p is actually just a shortcut for \%08lx
|
|
*
|
|
* - For a MAC address :\n
|
|
* Use format \%pM and pass the value using @ref TR_MAC macro.
|
|
* @verbatim TRACE("vif mac = %pM", TR_MAC(mac_addr)) @endverbatim
|
|
*
|
|
* - For a file name : \n
|
|
* Use format \%F and pass TRACE_FILE_ID as parameter
|
|
* @verbatim TRACE("Error in file %F", TRACE_FILE_ID) @endverbatim
|
|
*
|
|
* - For @ref ke_msg_id_t :\n
|
|
* Use format \%kM and pass the message id directly. Using this format it just
|
|
* like a simple 16bits value, but it also indicates the decoder to translate
|
|
* the message id into its real name (if found inside the dictionary).
|
|
* @verbatim TRACE("msg received is receive [%kM]", msg_id)
|
|
=> msg received is [MM_VERSION_REQ] @endverbatim
|
|
*
|
|
* - For @ref ke_task_id_t :\n
|
|
* Use format \%kT and pass the task id directly. Using this format it just
|
|
* like a simple 16bits value, but it also indicates the decoder to translate
|
|
* the task id into its real name (if found inside the dictionary) and index.
|
|
* @verbatim TRACE("send message to task [%kT]", msg_id)
|
|
=> send message to task [ME(0)] @endverbatim
|
|
*
|
|
* - For @ref ke_state_t :\n
|
|
* Use format \%kS and pass \b both the task id and the state index. Using this
|
|
* format is like tracing 2 16bits value, but it also indicates the decoder to
|
|
* translate these values into a task name and a state name. (task id is needed
|
|
* because state enum is specific to each task).
|
|
* @verbatim TRACE("set [%kS]", task_id, state)
|
|
=> set SCANU(0):SCANU_IDLE @endverbatim
|
|
*
|
|
* - For a timestamp :\n
|
|
* Use format \%t and pass the timestamp value as a 32bits value in microsecond
|
|
* (same format as returned by @ref hal_machw_time).
|
|
* The decoder will format the timestamp value like the timestamp of the trace
|
|
* (i.e. \<s>.\<ms>_\<us>) and will show the delta between the timestamp parameter
|
|
* and the timestamp of the trace.
|
|
* @verbatim TRACE("Timer set at %t", TR_32(timer_date))
|
|
=> Timer set at @23.234_789 (+25.35 ms) @endverbatim
|
|
*
|
|
* - For a Frame Control :\n
|
|
* Use format \%fc and pass the value as a 16bits value.
|
|
* The decoder will parse this value as a frame control field (as found in MAC header)
|
|
* @verbatim TRACE("Received frame: %fc", mac_hdr->fctl)
|
|
=> Received frame: Association response @endverbatim
|
|
*
|
|
* - For a IPv4 address :\n
|
|
* Use format \%pI4 and pass the value using @ref TR_IP4 macro.
|
|
* @verbatim TRACE("ip = %pI4", TR_IP4(ip4_addr)) @endverbatim
|
|
*
|
|
* - For a IPv6 address :\n
|
|
* Use format \%pI6 or \%pI6c and pass the value using @ref TR_IP6 macro.
|
|
* @verbatim TRACE("ipv6 = %pI6", TR_IP6(ip6_addr)) @endverbatim
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
#define TRACE(a, ...) { \
|
|
uint16_t __p[] = { __VA_ARGS__ }; \
|
|
trace(TRACE_ID, sizeof(__p) / sizeof(__p[0]), __p, false); \
|
|
}
|
|
|
|
/**
|
|
******************************************************************************
|
|
* @brief Macro used to add an unfiltered trace containing a dump of a buffer in
|
|
* the trace buffer
|
|
*
|
|
* It will call @ref trace function with a unique trace id (@ref TRACE_ID) and
|
|
* the parameters correctly formatted.
|
|
*
|
|
* The format string supported by the decoder is:\n
|
|
* <b> %pB(F|s)?(number_of_characters)?(word_size)?(representation)? </b>
|
|
*
|
|
* - number_of_characters :\n
|
|
* optional group indicating the number of words to print in one line.\n
|
|
* Default value : 8\n
|
|
* @verbatim TRACE_BUF("my_buf: %pB4", my_buf_len, my_buf);
|
|
=> my_buf: 00 10 00 20
|
|
40 FF 00 1A @endverbatim
|
|
*
|
|
* - word_size :\n
|
|
* Optional group indication the size of a word.\n
|
|
* Default value : b\n
|
|
* Possible values: \n
|
|
* -# b: byte
|
|
* -# h: half-word(16 bits)
|
|
* -# w: word(32 bits)\n
|
|
* @verbatim TRACE_BUF("my_buf: %pB4h", my_buf_len, my_buf);
|
|
=> my_buf: 0010 0020 40FF 001A@endverbatim
|
|
|
|
* - representation :\n
|
|
* Optional group indicating the print format of a word\n
|
|
* Default value: x\n
|
|
* Possible values: \n
|
|
* -# d: decimal
|
|
* -# x: hexadecimal
|
|
* -# c: char\n
|
|
* @verbatim TRACE_BUF("my_buf: %pB4hd", my_buf_len, my_buf);
|
|
=> my_buf: 16 32 16639 26@endverbatim
|
|
*
|
|
* - 802.11 Frame: \n
|
|
* If format \%pBF is used (instead of only \%pB), then the decoder will treat the buffer
|
|
* as a 802.11 frame. It will then parse the MAC header and dump the rest of the frame
|
|
* just like any other buffer using number_of_characters/word_size/representation
|
|
* parameters if set.
|
|
* @verbatim TRACE_BUF("received frame: %pBF12bx", my_buf_len, my_buf);
|
|
=> received frame: Authentication Dur=60us Seq=1322 frag=0
|
|
A1=aa:06:cc:dd:ee:fe A2=c4:04:15:3d:41:e8 A3=c4:04:15:3d:41:e8
|
|
00 00 02 00 00 00 dd 09 00 10 18 02
|
|
00 00 1c 00 00 @endverbatim
|
|
*
|
|
* - String buffer: \n
|
|
* If the format \%pBs is used (instead of only \%pB), then the decoder will treat the
|
|
* buffer as a string buffer. The decoder will stop buffer processing on first null
|
|
* byte (even if there is more data dumped). number_of_characters can be set to limit
|
|
* the size of the decoder output per line. If the limit is reached the decoder acts as
|
|
* if a '\n' character was present in the dump.
|
|
* If set word_size and representation are ignored.
|
|
* @verbatim TRACE_BUF("command buffer: %pBs", my_buf_len, my_buf);
|
|
=> command buffer: This is a string split
|
|
into 2 lines @endverbatim
|
|
*
|
|
* @verbatim TRACE_BUF("command buffer: %pBs8", my_buf_len, my_buf);
|
|
=> command buffer: This is
|
|
a string
|
|
split
|
|
into 2 l
|
|
ines @endverbatim
|
|
*
|
|
*
|
|
*
|
|
* @param[in] format string specifying how to interpret the data
|
|
* @param[in] size size of the buffer in bytes (independent from
|
|
* number_of_characters in the conversion specification)
|
|
* @param[in] buf buffer to dump
|
|
******************************************************************************
|
|
*/
|
|
#define TRACE_BUF(format, size, buf) { \
|
|
uint16_t __p[] = {(uint16_t)(size), (uint16_t)((uint32_t)buf), \
|
|
(uint16_t)(((uint32_t)buf) >> 16)}; \
|
|
uint16_t __size = 1 + (size + 1 + ((uint32_t)buf & 0x1)) / 2; \
|
|
trace(TRACE_ID, __size, __p, true); \
|
|
}
|
|
|
|
/**
|
|
******************************************************************************
|
|
* @brief Macro to trace a 32bits parameters
|
|
*
|
|
* To be used with \%ld, \%lu, \%lx, \%lX format
|
|
* @param[in] a A 32bit value
|
|
******************************************************************************
|
|
*/
|
|
#define TR_32(a) (uint16_t)((uint32_t)(a) >> 16), (uint16_t)((uint32_t)(a))
|
|
|
|
/**
|
|
******************************************************************************
|
|
* @brief Macro to trace a 64bits parameters
|
|
*
|
|
* To be used with \%lld, \%llu, \%llx, \%llX format
|
|
* @param[in] a A 64bit value
|
|
******************************************************************************
|
|
*/
|
|
#define TR_64(a) TR_32(((uint64_t)(a) >> 32)), TR_32(a)
|
|
|
|
/**
|
|
******************************************************************************
|
|
* @brief Macro to trace a pointer
|
|
*
|
|
* To be used with \%p format
|
|
* @param[in] p A 32bit address
|
|
******************************************************************************
|
|
*/
|
|
#define TR_PTR(p) TR_32(p)
|
|
|
|
/**
|
|
******************************************************************************
|
|
* @brief Macro to trace a MAC address
|
|
*
|
|
* To be used with \%pM format
|
|
* @param[in] m Address on a MAC address
|
|
******************************************************************************
|
|
*/
|
|
#define TR_MAC(m) ((uint16_t *)(m))[0], ((uint16_t *)(m))[1], ((uint16_t *)(m))[2]
|
|
|
|
/**
|
|
******************************************************************************
|
|
* @brief Macro to trace a IPv4 address
|
|
*
|
|
* To be used with \%pI4 format
|
|
* @param[in] m Address on an IPv4 address (Not the ip address as 32bit value)
|
|
******************************************************************************
|
|
*/
|
|
#define TR_IP4(m) TR_32(*((uint32_t *)m))
|
|
|
|
/**
|
|
******************************************************************************
|
|
* @brief Macro to trace a IPv6 address
|
|
*
|
|
* To be used with \%pI6, \%ipI6c format
|
|
* @param[in] m Address on an IPv6 address
|
|
******************************************************************************
|
|
*/
|
|
#define TR_IP6(m) ((uint16_t *)(m))[0], ((uint16_t *)(m))[1], ((uint16_t *)(m))[2] \
|
|
((uint16_t *)(m))[3], ((uint16_t *)(m))[4], ((uint16_t *)(m))[5] \
|
|
((uint16_t *)(m))[6], ((uint16_t *)(m))[7]
|
|
|
|
/// internal
|
|
#ifdef CFG_RWTL
|
|
#define _PTR_ALIGN(p) ((uint16_t *)p)
|
|
/**
|
|
******************************************************************************
|
|
* @brief Macro to trace a string
|
|
*
|
|
* To be used with \%s format. Trace only the 8 first characters of the string
|
|
* @note Using this macro will always store 8bytes in the trace buffer, and
|
|
* decoder will stop as soon as it read 8 characters or '\0' is found.
|
|
******************************************************************************
|
|
*/
|
|
#define TR_STR_8(s) (0x0800), \
|
|
(_PTR_ALIGN(s)[0] & 0xFF) + ((_PTR_ALIGN(s)[1] & 0xFF) << 8), \
|
|
(_PTR_ALIGN(s)[2] & 0xFF) + ((_PTR_ALIGN(s)[3] & 0xFF) << 8), \
|
|
(_PTR_ALIGN(s)[4] & 0xFF) + ((_PTR_ALIGN(s)[5] & 0xFF) << 8), \
|
|
(_PTR_ALIGN(s)[6] & 0xFF) + ((_PTR_ALIGN(s)[7] & 0xFF) << 8)
|
|
|
|
|
|
#else
|
|
#define _PTR_ALIGN(p) ((uint16_t *)((uint32_t)p & ~0x1))
|
|
/**
|
|
******************************************************************************
|
|
* @brief Macro to trace a string
|
|
*
|
|
* To be used with \%s format. Trace only the 8 first characters of the string
|
|
* @note Using this macro will always store 8bytes in the trace buffer, and
|
|
* decoder will stop as soon as it read 8 characters or '\0' is found.
|
|
******************************************************************************
|
|
*/
|
|
#define TR_STR_8(s) (0x0800 + (uint16_t)((uint32_t)(s) & 0x1)), \
|
|
_PTR_ALIGN(s)[0], _PTR_ALIGN(s)[1], \
|
|
_PTR_ALIGN(s)[2], _PTR_ALIGN(s)[3]
|
|
|
|
#endif
|
|
|
|
/**
|
|
******************************************************************************
|
|
* @brief Acts like @ref TRACE macro if bit @p lvl is set in trace level for
|
|
* @p compo. Does nothing otherwise.
|
|
* @param[in] compo Name of the component from @ref trace_compo.
|
|
* TRACE_COMPO_ prefix should be omitted.
|
|
* @param[in] lvl Trace level form one of trace_level_... enum.
|
|
* TRACE_LVL_ prefix should be omitted
|
|
******************************************************************************
|
|
*/
|
|
#define TRACE_FILT(compo, lvl, ...) \
|
|
if (trace_compo_level[TRACE_COMPO_ ## compo] & CO_BIT(TRACE_LVL_ ## lvl)) \
|
|
{ \
|
|
TRACE(__VA_ARGS__) \
|
|
}
|
|
|
|
/**
|
|
******************************************************************************
|
|
* @brief Acts like @ref TRACE_BUF macro if bit @p lvl is set in trace level
|
|
* for @p compo. Does nothing otherwise.
|
|
* @param[in] compo Name of the component from @ref trace_compo.
|
|
* TRACE_COMPO_ prefix should be omitted.
|
|
* @param[in] lvl Trace level form one of trace_level_... enum.
|
|
* TRACE_LVL_ prefix should be omitted
|
|
******************************************************************************
|
|
*/
|
|
#define TRACE_BUF_FILT(compo, lvl, ...) \
|
|
if (trace_compo_level[TRACE_COMPO_ ## compo] & CO_BIT(TRACE_LVL_ ## lvl)) \
|
|
{ \
|
|
TRACE_BUF(__VA_ARGS__) \
|
|
}
|
|
|
|
/**
|
|
******************************************************************************
|
|
* @brief Test whether a specific compo/lvl is currently being traced.
|
|
*
|
|
* Can be used to skip several calls TRACE_FILT(compo, lvl, ...).
|
|
*
|
|
* @param[in] compo Name of the component from @ref trace_compo.
|
|
* TRACE_COMPO_ prefix should be omitted.
|
|
* @param[in] lvl Trace level form one of trace_level_... enum.
|
|
* TRACE_LVL_ prefix should be omitted
|
|
******************************************************************************
|
|
*/
|
|
#define TRACE_FILT_ON(compo, lvl) \
|
|
(trace_compo_level[TRACE_COMPO_ ## compo] & CO_BIT(TRACE_LVL_ ## lvl))
|
|
|
|
#else /* ! NX_TRACE */
|
|
|
|
#define TRACE(...)
|
|
#define TRACE_BUF(...)
|
|
#define TRACE_FILT(...)
|
|
#define TRACE_BUF_FILT(...)
|
|
#define TRACE_FILT_ON(...) 0
|
|
static inline void trace_init(bool force, bool loop) {}
|
|
|
|
#endif /* NX_TRACE*/
|
|
|
|
#include "trace_compo.h"
|
|
|
|
#endif /* _TRACE_H_ */
|
|
|
|
/// @} end of group
|