Data Structures | Macros | Typedefs | Functions | Variables
LogSinkUART.h File Reference

Detailed Description

PRELIMINARY LogSinkUART interface


Warning
These APIs are PRELIMINARY

The LogSinkUART module is a sink that can be used in conjunction with the Log.h API in source/ti/log/ and the logging tools available in tools/log/tiutils. The API defined in this file is made available to the Logging framework and used as a transport layer for Log.h. For more information about the Log API, see the Log documentation.

To use the UART sink, ensure that the correct library for your device is linked in and include this header file as follows:

This module implements two functions that are required by the Log API:

Whenever a log statement that uses LogSinkUART as its sink is called, the log module delegates to one of the functions above.

Overview

LogSinkUART is a sink/transport layer that asynchronously outputs encoded log statements over UART. It uses the UART2 driver to stream data out onto a user-selectable pin, which can be received and processed by a host-side tool. For more information about the host-side tool, see tools/log/tiutils.

At the log-site the sink separates the generation of the log record from the transportation of the record off the device. Deferring the transportation to a later point of the program execution is done to minimze the runtime intrusion that would be caused by synchronously outputing the log statements through the relatively slow UART. The first part generates and stores the log statements into an intermediate storage synchronously. The second part uses the idle task of the OS, executed when no other tasks or interrupts are running, to move the data stored in the intermediate storage off the device.

By transmitting messages asynchronously the readout at the host-side is also asynchronous. As a consequence, the receiving of log statements at the host-side can be deferred from their execution in the program.

This sink requires no special hardware to capture and decode the logs beyond a basic UART-to-USB bridge.

The data flow at a high level is:

  1. Log statement captured at the log site with timestamp
  2. Log data marshalled into a log packet
  3. Log packet moved to ring buffer working as intermediate storage
  4. Intermediate storage flushed via the UART2 driver when nothing else is happening through a function installed in the Idle-loop/task
  5. Data sent out on the UART line
  6. Data received by listening COM port on host
  7. Data decoded by host and fed through remainder of host logging infrastructure
  8. Logs visualised in Wireshark or dumped to console / log file
Note
Throughout this documentation and API the term "packet" is used instead of the term "record". Both terms are equivalent and can be used interchangeably.

Considerations

When using this sink consider the following:


Design Architecture

The LogSinkUART implementation is based on the following architecture.

Packet Transmission Format

All log packets begin with a 32-bit metadata pointer followed by a 32-bit timestamp. The next fields depend on the type of log statement:

If a packet would overflow the ring buffer, a 32-bit overflow packet is placed instead. It is the original metadata pointer modified to be identified as an overflow packet. The host-side tool decodes it and displays an overflow message, indicating that at least that message would have overflowed. When this is observed, it is recommended to either resize the ring buffer or disable some log statements.

Note
If the intermediate ring buffer is full no new oveflow or log packets will be stored.

Each log statement used will occupy the following amount of SRAM:

Log statement type Log statement size (bytes)
Log_printf 8 + 4 * number_of_arguments
Log_buf 12 + buffer_size
Overflow 4

Packet Framing

The host-side must receive and properly handle a continuous stream of in-phase, uncorrupted packets. Starting decoding in the middle of a packet would lead to incorrect synchronisation and decoding. This is solved by sending an initial 64-bit reset-frame. The reset-frame consists of a pre-determined 32-bit sequence followed by 32 bits indicating how the timestamp is formatted. After receiving the reset-frame, the host-side tool knows that the next 32 bits will be a metadata-pointer followed by a timestamp. The number of arguments for each frame is extracted from the .out file. This determines the length of the current packet and when the metadata pointer from the next packet is expected.

Flushing the data

A hook function installed in the Idle-loop/task is run when no other tasks or interrupts are running. It flushes as many log packets as possible from the intermediate storage via the UART2 driver set in nonblocking mode. In this mode, UART2_write() will copy as much data into the transmit buffer as space allows and return immediately. The maximum space allowed, and therefore the amount of data sent out every time that the hook function is called, is determined by the size of the TX Ring Buffer.

The Idle-loop/task will always be run before the power management loop.

Since each OS has a different implementation of the Idle-loop/task, the installation of the hook function will also be different for each OS. The automatic installation is currently supported for FreeRTOS and TI-RTOS 7 when using SysConfig.


Usage

To use the UART LogSink the application calls the following APIs:

Details on usage are provided in the following subsections.

Examples

Initializing a UART LogSink

If LogSinkUART is enabled through SysConfig, then LogSinkUART_init() will be automatically called from Board_init(). If SysConfig is not used, the user must initialize the log sink. LogSinkUART_init() can also be called after a sink has been finalized with LogSinkUART_finalize(). To initialize a sink, first include the ti_log_config.h library containing the expansion of the sink name. Afterwards, call the initialize function passing as an argument the name of the sink to be initialized.

#include "ti_log_config.h"
LogSinkUART_init(sink_name);

Flushing UART sinks

LogSinkUART_flush() will be called automatically in the Idle-loop/task for FreeRTOS and TI-RTOS 7. Despite this, the user can still manually call the function to send out as much data as possible from all the existing ring buffers when desired. The flush function can be called from either a task or interrupt context.

Finalizing a UART LogSink

LogSinkUART_finalize() will cancel all ongoing UART writes and call UART2_close(). All log packets remaining in the intermediate storage will be lost when calling LogSinkUART_init() because the ring buffer will be reset. All log statements after a finalize call will also be lost due to the reset of the ring buffer when initializing the sink. To finalize a sink first include the ti_log_config.h library containing the expansion of the sink name. Afterwards, call the finalize function passing as an argument the name of the sink to be finalized.

#include "ti_log_config.h"

Protect log statements

To ensure that logs are correctly ordered when put back together on the host, log statements can be called from a context where HWI are disabled. This also ensures that the recorded timestamp is faithful to when the log statement was executed.

Logs can end up ordered out as a consequence of a log call being preempted by a higher priority task with other log statements. The following example shows how a log statement can be protected to ensure that the execution sequence is mantained in the ordering on the host-side.

uint32_t key;
key = HwiP_disable();
Log_printf(MyModule, Log_DEBUG, "The answer is %d", 42);

Configuration

In order to use the LogSinkUART APIs, the application is required to provide sink-specific configuration in the ti_log_config.c file. The LogSinkUART interface defines a configuration data structure:

typedef struct {
void *object;
void const *hwAttrs;

The application must declare an array of LogSinkUART_Config elements, named LogSinkUART_config[]. Each element of LogSinkUART_config[] must be populated with pointers to a sink specific object, and hardware attributes. The hardware attributes define properties such as the UART peripheral's attributes, and a pointer to the intermediate ring buffer and its size. These are automatically assigned through SysConfig. Each element in LogSinkUART_config[] corresponds to a UART sink instance, and none of the elements should have NULL pointers.

The configuration for the UART LogSink is based on the driver's configuration. Refer to the Driver's Configuration section for driver configuration information.

To automatically initialize a UART sink when initializing the board, LogSinkUART_init() is called inside Board_init() in ti_drivers_config.c. To have acces to the function and get the expansion of the sink name, include the following libraries:

#include "ti_log_config.h"

#include <stdint.h>
#include <stddef.h>
#include <ti/log/Log.h>
#include <ti/drivers/UART2.h>
#include <ti/drivers/utils/RingBuf.h>
Include dependency graph for LogSinkUART.h:

Go to the source code of this file.

Data Structures

struct  LogSinkUART_HWAttrs
 LogSinkUART Hardware attributes. More...
 
struct  LogSinkUART_Object
 LogSinkUART Object. More...
 
struct  LogSinkUART_Config
 LogSinkUART Global configuration. More...
 
struct  LogSinkUART_Instance
 LogSinkUART Sink parameters. More...
 

Macros

#define Log_TI_LOG_SINK_UART_VERSION   0.1.0
 LogSinkUART version. More...
 
#define Log_SINK_UART_DEFINE(name)   LogSinkUART_Instance LogSinkUART_##name##_Config = {.index = name}
 Create a LogsinkUART instance called name. More...
 
#define Log_SINK_UART_USE(name)   extern LogSinkUART_Instance LogSinkUART_##name##_Config
 Use a LogSinkUART instance called name when not created in the same file. More...
 
#define Log_MODULE_INIT_SINK_UART(name, _levels)
 Initialize a LogSinkUART instance called name with log _levels. More...
 

Typedefs

typedef LogSinkUART_InstanceLogSinkUART_Handle
 A handle for the LogSinkUART_Instance structure. More...
 

Functions

void LogSinkUART_flush (void)
 Flush all the LogSinkUART sinks. More...
 
void LogSinkUART_init (uint_least8_t index)
 Initialize a given LogSinkUART sink. More...
 
void LogSinkUART_finalize (uint_least8_t index)
 Finalize a given LogSinkUART sink. More...
 

Variables

const LogSinkUART_Config LogSinkUART_config []
 Array with the configuration of each sink. More...
 

Macro Definition Documentation

§ Log_TI_LOG_SINK_UART_VERSION

#define Log_TI_LOG_SINK_UART_VERSION   0.1.0

LogSinkUART version.

§ Log_SINK_UART_DEFINE

#define Log_SINK_UART_DEFINE (   name)    LogSinkUART_Instance LogSinkUART_##name##_Config = {.index = name}

Create a LogsinkUART instance called name.

§ Log_SINK_UART_USE

#define Log_SINK_UART_USE (   name)    extern LogSinkUART_Instance LogSinkUART_##name##_Config

Use a LogSinkUART instance called name when not created in the same file.

§ Log_MODULE_INIT_SINK_UART

#define Log_MODULE_INIT_SINK_UART (   name,
  _levels 
)
Value:
{ \
.sinkConfig = &LogSinkUART_##name##_Config, .printf = ti_log_LogSinkUART_printf, \
.buf = ti_log_LogSinkUART_buf, .levels = _levels, \
}

Initialize a LogSinkUART instance called name with log _levels.

Typedef Documentation

§ LogSinkUART_Handle

A handle for the LogSinkUART_Instance structure.

Function Documentation

§ LogSinkUART_flush()

void LogSinkUART_flush ( void  )

Flush all the LogSinkUART sinks.

Function to flush each of the LogSinkUART sinks in the order they are added. For each sink it will read its ring buffer and put as much data as possible on the UART interface. The flush can occur in task or interrupt context.

§ LogSinkUART_init()

void LogSinkUART_init ( uint_least8_t  index)

Initialize a given LogSinkUART sink.

Function to initialize a given LogSinkUART sink specified by the particular index value. It constructs a ring buffer, sets up the UART2 attributes, opens the given UART peripheral and sends a reset frame over UART.

Parameters
[in]indexLogical sink number for the LogSinkUART indexed into the LogSinkUART_config table

The UART peripheral is set to send only mode, with the following fixed parameters:

dataLength = UART2_DataLen_8;
stopBits = UART2_StopBits_1;

The baudRate and parityType can be configured from SysConfig. The size of the ring buffer can also be set from the SysConfig.

§ LogSinkUART_finalize()

void LogSinkUART_finalize ( uint_least8_t  index)

Finalize a given LogSinkUART sink.

Function to finalize a given LogSinkUART sink specified by the particular index value. It cancels any ongoing write operation over the given UART peripheral and closes it.

Parameters
[in]indexLogical sink number for the LogSinkUART indexed into the LogSinkUART_config table

Variable Documentation

§ LogSinkUART_config

const LogSinkUART_Config LogSinkUART_config[]

Array with the configuration of each sink.

© Copyright 1995-2024, Texas Instruments Incorporated. All rights reserved.
Trademarks | Privacy policy | Terms of use | Terms of sale