Logging User Guide#

This section describes the logging framework used to push important information on target logging interface in a compressed format.

The logging framework is designed to provide standard printf() like experience to the developers without overloading the debug target(UART by default) with redundant information. The framework compresses the amount of log data that is pushed on to the target.

In order to achieve this compression,

  • SAPI and FW Logs follows strict Syntax rules.

  • A pre-build analyzer tool converts all static information(read-only component of SAPI and FW logs) in log description file placed in the build system.

  • A C framework embedded within SAPI and FW emits the dynamic components of logs along with an identifier and compressed timestamp(conditionally).

  • The compressed logs are processed offline by a decoder to regenerate the human readable log data.

Compression Numbers in different scenarios#

Scenario

Number of bytes emitted

No Debug Arguments, first 32 Debug IDs

1 Byte

No Debug Arguments, 32-4096 Debug IDs

2 bytes

Cost of Timestamp

1 byte if temporal spacing between two consecutive logs is more than 1ms. 2 bytes if temporal spacing between two consecutive logs is more than 127ms

Cost of each fixed length argument

Number of bytes in argument

Cost of string

Length of string(Null terminated)

SAPI Logging#

Enable/Disable SAPI Logs#

Compile time switch SAPI_LOGGING_ENABLE should be enabled for SAPI logs to be active. If the compile switch SAPI_LOGGING_ENABLE is not present, SAPI log instances are considered as void statements and shall not generate any code.

Syntax for SAPI Logging calls#

The calls to SAPI Logs should strictly follow below syntax.

SL_PRINTF(DEBUG_ELEMENT, COMPONENT, LOG_LEVEL, Format, <Arguments>);

DEBUG_ELEMENT#

The DEBUG_ELEMENT is the unique identifier for a logging call. In order to add a new logging call, user is just required to mention a new DEBUG_ELEMENT in the fucntion call, user is not required to define this new DEBUG_ELEMENT. A pre-processing tool shall search for all occurences of SL_PRINTF calls in the source files and prepare an enum with all unique DEBUG_ELEMENTS.

COMPONENT#

The component the module to which the debug log belongs to. Currently supported list of components is:

  • BLE

  • BLUETOOTH

  • COMMON

  • CRYPTO

  • DRIVER

  • FW_UPDATE

  • NETWORK

  • WLAN

Log Levels#

The level of active logs can be controlled through compile switch CONFIG_DEBUG_LEVEL present in rsi_user.h. The compile switch define can be initialized with one of four possible enum values:

  • LOG_OFF

  • LOG_ERROR

  • LOG_WARNING

  • LOG_INFO

As the enums suggest, LOG_OFF turns off logging, LOG_ERROR provides minimum logging and LOG_INFO provides maximum logging.

e.g. Suppose the user configures CONFIG_DEBUG_LEVEL to LOG_ERROR then only SL_PRINTF calls having debug level as LOG_ERROR will be processed. Similarly, if the user configures CONFIG_DEBUG_LEVEL to LOG_WARNING then SL_PRINTF calls with LOG_ERROR and LOG_WARNING debug levels will be processed.

>Note! It is not intended to use LOG_OFF as a debug level in any SL_PRINTF call.

Format#

Format defines how additional arguments in the logging call should be treated. The format is parsed by the pre-processing tool and information is stored in build system. The format information is latter used to display the decoded logs.

Important rules:

  • Each argument defination should be separated by ','

  • Each Argument defination should comprise of a Display Name and properties, separated by ':'

  • The display name is what will be visible in decoded output log against each argument.

  • sign should be used only to identify debug argument property. Number of % signs denotes number of arguments that are being pased in the debug log.

  • b stands for 1 byte argument which should be displayed in decimal format.

  • w stands for 2 byte argument which should be displayed in decimal format.

  • d stands for 4 byte argument which should be displayed in decimal format.

  • s stands for a variable length string which should always be terminated by NULL character.

  • %1x stands for 1 byte argument which should be displayed in Hexadecimal format.

  • %2x stands for 2 byte argument which should be displayed in Hexadecimal format.

  • %4x stands for 4 byte argument which should be displayed in Hexadecimal format.

The format is also used by pre-processing tool to identify number of arguments in given debug call and define SL_PRINTF call for given DEBUG_ELEMENT accordingly. There is no limit to number of times logging call is made with same DEBUG_ELEMENT but the format should remain the same for each of these calls. The pre-processor tool shall throw error if any descripancy is found in format.

Arguments#

For a fixed length argument, parameters shall be passed by value. For strings, parameters shall be passed by reference.

>Note! The format and arguments fields are optional. SL_PRINTF call shall have only three mandatory arguments(DEBUG_ELEMENT, COMPONENT and LOG_LEVEL) if an argument is not required in the call.

Pre-Processing tool#

The advanced_logs_generator.py is a pre-processing python script present at the path: <SDK>\utilities\advanced_logging\app_logging. This tool is used to generate the debug_auto_gen.h file at the path: <SDK>\sapi\include. The debug_auto_gen.h comprises all the enumerations of all DEBUG_ELEMENTS and declarations required for the logging framework.

Whenever the user wants to add a new SAPI logging call, a new debug_auto_gen.h needs to be generated using the advanced_log_generator.py pre-processing tool.

>Note! The pre-processing tool should be invoked mandatorily if a new(unique) SAPI logging call is introduced. The autogenerated files are already updated as part of the release package for all existing SAPI logging calls.

Given below is an example of adding the new SAPI logging call and execution of the advanced_log_generator.py.

e.g. Let's add a new SL_PRINTF call similar to an existing error case SL_PRINTF call present in the rsi_config_ipaddress API.

After_adding_call

Now let's execute the advanced_log_generator.py to get the new SAPI logging elements and declarations in debug_auto_gen.h file

Preprocessing_tool_execution

>Note! For successful execution of advanced_log_generator.py or sapi_log_decoder.py python scripts, it is recommended to use Python version 3.9 or higher.

Python_Version

Upon execution of the tool, changes like those shown below take place in the debug_auto_gen.h & manifest.json files.

In debug_auto_gen.h,

debug_auto_gen_1

debug_auto_gen_2

debug_auto_gen_3

and in manifest.json,

entry_in_manifest

There is another file named manifest.json which is present in the same folder. This JSON file comprises metadata corresponding to all SAPI logging calls required at the time of decoding the logs.

Decoding SAPI Logs#

The decoder tool sapi_log_decoder.py is a python tool present in the utilities\advanced_logging\app_logging folder. The decoder tool takes the encoded logs as the input and searches for #@$ in the start of line. The tool expects the rest of the line to have heaxdecimal numbers which are then decoded to generate human readable text file.

Given below is an example of the SAPI logs, before and after decoding.

Before_Decoding

After_Decoding

Firmware Logging#

Enable/Disable Firmware Logs#

Compile time switch FW_LOGGING_ENABLE should be enabled for firmware logs to be active. If the compile switch FW_LOGGING_ENABLE is not present, firmware log instances are considered as void statements and shall not generate any code. The level of active firmware logs can be controlled using sl_set_fw_component_log_levels followed by sl_fw_log_configure calls. User is required to add sl_fw_logging.c and firmware_logging_util.c to the project. The latter file has a reference implementation to manage the received firmware logging messages. Refer to the code snippet below to configure firmware logging.

//! Set log levels for firmware components
sl_set_fw_component_log_levels(&fw_component_log_level);

//! Configure firmware logging
status = sl_fw_log_configure(FW_LOG_ENABLE,
                             FW_TSF_GRANULARITY_US,
                             &fw_component_log_level,
                             FW_LOG_BUFFER_SIZE,
                             sl_fw_log_callback);
if (status != RSI_SUCCESS) {
  LOG_PRINT("\r\n Firmware Logging Init Failed\r\n");
} else {
  LOG_PRINT("\r\n Firmware Logging Init success\r\n");
}

>Note! For more details can refer tcp_logging_stats

Firmware Log Components#

The component to which the debug log belongs to. Current supported list of components is:

  • COMMON - common section among all protocols

  • CM_PM - Coex manager and power manager logs are used to debug issues involving multi protocols and power save.

  • WLAN_LMAC - LMAC logs are used to debug Transmit/Receive related issues

  • WLAN_UMAC - UMAC logs are used to debug Supplicant, SME, APME layers issues

  • WLAN_NETSTACK - Network stack logs are used to debug TCP/IP and application layers issues

  • BT_BLE_CTRL - Bluetooth and Bluetooth Low Power controller logs are used to debug issues in controller

  • BT_BLE_STACK - Bluetooth and Bluetooth Low Power controller logs are used to debug issues in stack

Firmware Logging Parameters#

Applications for which firmware logging has been enabled, contain parameters that can be configured according to the users requirements and constraints.

Component Log Levels#

The level of active logs of individual firmware components can be controlled through compile switches in application configuration files. The compile switch define can be initialized with one of five possible values:

  • FW_LOG_OFF

  • FW_LOG_ERROR

  • FW_LOG_WARN

  • FW_LOG_TRACE

  • FW_LOG_INFO

Log Buffer Size#

Determines the size of log packet recieved from firmware. The log buffer size can vary from a minimum of 2048 bytes to a maximum of 4096 bytes. The size can be varied with increments of 512 bytes. Any size below the minimum size or more than maximum size will be replaced with corresponding limits.

Log Queue Size#

Determines the number of elements in the firmware log queue. The log queue ensures that debug logs arriving from firmware are not lost when previously received logs are being processed. For a larger queue size, more debug logs can be stored in the queue. It has a minimum value of 1.

Increasing the log queue size increases the memory required by the firmware logging framework, during application initialization.

Decoding Firmware Logs#

The decoder tool fw_log_decoder.py is a python tool present in the utilities\advanced_logging\firmware_logging folder.

The decoder tool takes the encoded logs as the input and searches for &^$ in the start of line. The tool expects the rest of the line to have heaxdecimal numbers which are then decoded to generate human readable text file. Given below is an example of the firmware logs, before and after decoding. Before_Decoding

After_Decoding