1 /* 2 * Copyright (c) 2019-2024 Texas Instruments Incorporated - http://www.ti.com 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of Texas Instruments Incorporated nor the names of 17 * its contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /** 34 * @file ti/log/Log.h 35 * 36 * @addtogroup ti_log_LOG Log Interface 37 * 38 * @brief The Log module provides APIs to instrument source code 39 * 40 * To access the LOG APIs, the application should include its header file as 41 * follows: 42 * @code 43 * #include <ti/log/Log.h> 44 * @endcode 45 * 46 * ## Beta Disclaimer ## 47 * The logging ecosystem are to be considered beta quality. They are not 48 * recommended for use in production code by TI. APIs and behaviour will change 49 * in future releases. Please report issues or feedback to [__E2E__][e2e]. 50 * 51 * [e2e]: https://e2e.ti.com/ 52 * 53 * ## Definitions ## 54 * 55 * The following terms are used throughout the log documentation. 56 * 57 * | Term | Definition | 58 * |---------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 59 * | `LogModule` | A parameter passed to Log APIs to indicate which software module the log statement originated from. Modules also control the routing of logs to sinks. | 60 * | `LogLevel` | The severity or importance of a given log statement. | 61 * | `Sink` | Also simply called a logger. This is a transport specific logger implementation. <br> The Logging framework is flexible such that multiple sinks may exist in a single firmware image. | 62 * | `CallSite` | A specific invocation of a Log API in a given file or program. | 63 * | `Record` | The binary representation of a log when it is stored or transported by a given sink. The log record format varies slightly with each sink depending on their implementation and needs. However, they all convey the same information. | 64 * | Link Time Optimization (LTO) | A feature of some toolchains that can significantly reduce the code overhead of the log statements through a process called dead code elimination. In order to maximize the benefits of this, all static libraries and application files should have LTO enabled. | 65 * 66 * ## Summary ## 67 * 68 * The following sections describe the usage of the TI logging system 69 * implementation. This document will focus on the target (i.e. code that runs) 70 * on the embedded device. For associated PC tooling, please see the 71 * [README](../../../tools/log/tiutils/Readme.html) in the tools/log/tiutils/ 72 * folder. 73 * 74 * Design Philosophy: 75 * 76 * * Logs target code should be as efficient as possible. 77 * * This means that Log APIs should minimize FLASH, RAM, and execution 78 * overhead. 79 * * Complexity should be pushed to host side tooling where possible. 80 * * Even if this means that PC setup/tooling requirements are more complex. 81 * * Multiple log sink implementations shall be able to exist in a system. 82 * * Where applicable, multiple instances should be supported (e.g. multiple 83 * circular buffers to collect logs) 84 * * It shall be possible to remove logging entirely using the preprocessor 85 * * Configuration of logging should be deferred to application compile and 86 * link time. 87 * * That means that the end application builder should make decisions about 88 * the logging settings. This means that TI provided libraries are not 89 * opinionated about what log levels should be enabled or how modules 90 * should be routed to sinks. 91 * * TI's logging system will leverage SysConfig out of the box, but it should 92 * be possible to configure and use logging easily without the needing 93 * SysConfig. 94 * 95 * ## Stated Limitations ## 96 * 97 * * It is not possible to control which log sink is used for each call site. 98 * Routing of logs is controlled at a module level. 99 * * A maximum of 8 arguments is supported for variadic APIs. 100 * 101 * ## Anatomy of Log Statement ## 102 * 103 * At the core of the logging implementation is heavy use of the C 104 * preprocessor. When reading an application, the Log APIs may look like 105 * function calls, but the preprocessor expands them heavily. 106 * 107 * There are several ways in which the preprocessor is used. 108 * 109 * ### Global ### 110 * 1. To enable/disable logs globally. If `ti_log_Log_ENABLE` is not defined, 111 * all statements are removed by the preprocessor. This does not rely on LTO 112 * or any other optimization. It removes any traces of logs from the 113 * program. 114 * 115 * This define is pushed to `ti_utils_build_compiler.opt` whenever any Log 116 * module is enabled in SysConfig. 117 * 118 * ### Module ### 119 * 1. To enable/disable logs by module. If 120 * `ti_log_Log_ENABLE_<MyLogModuleName>=1` is not defined, all statements 121 * using that Log module are removed by the preprocessor. This does not rely 122 * on LTO or any other optimization. Removing the define removes all traces 123 * of the log from the compiled code. Just defining the symbol name 124 * `ti_log_Log_ENABLE_<MyLogModuleName>` without setting it to 1 will not 125 * include Log statements during compilation. 126 * 127 * These defines are automatically pushed to `ti_utils_build_compiler.opt` 128 * for all modules configured in SysConfig. 129 * 130 * Some TI libraries that have logging enabled also contain multiple log 131 * modules. Enabling only a subset of Log modules via the preprocessor will 132 * not cause the Log statements associated with the remaining Log modules to 133 * be removed since this is a compile-time event. The Log statements 134 * associated with individual modules can be removed from logging-enabled TI 135 * libraries by recompiling those libraries without the module-level flags 136 * in question. 137 * 138 * ### Per Log Statement ### 139 * 1. (Level filtering): Insert the if statement that checks if the log level 140 * of the statement has been enabled in its module configuration. If the log 141 * level is not enabled, the process ends here. 142 * 143 * 2. (String declaration): Automate placement of constant strings, format 144 * strings, and pointers to these strings in the the nonloadable metadata 145 * section of the out file. This saves FLASH on the target. Each string 146 * contains a large amount of data, including the following: 147 * 148 * * File and line number of the log statement 149 * * The log level and module of the log statement 150 * * The format string 151 * * The number of arguments 152 * 153 * 3. (Argument counting): Log APIs are variadic in nature, up to 8 arguments 154 * are supported. However, at preprocess time, the number of arguments must 155 * be known. 156 * 157 * 4. (Name spacing): Routing from module to sink. The module parameter of the 158 * Log API controls which sink its log statements will be routed to. The 159 * preprocessor does name expansion to look up the enabled log levels and 160 * selected sink function pointers from the module's configuration 161 * structure. NOTE: The used sink may require initialization. Please verify 162 * with the specific sink documentation on how to initialize the sink. 163 * 164 * 5. (Sink API Invocation): With the names resolved and levels checked, the 165 * logger is now ready to execute the sink function. This is done via 166 * function pointer. 167 * 168 * An simplified pseudo-C implementation of what `Log_printf(LogModule_App1, 169 * Log_DEBUG, "Hello World!");` would expand to is shown below. This will not 170 * compile and is not extensive, just for illustration. 171 * 172 * @code 173 * // Global log enable check, wrapped around each log site 174 * #if defined(ti_log_Log_ENABLE) 175 * #if ti_log_Log_ENABLE_LogModule_App1 == 1 176 * // Check if the level of this specific log statement has been enabled by the module 177 * if (LogMod_LogModule_App1.levels & level) { 178 * // Note that ^^ is the record separator. Pack meta information into format string. This is stored off target. 179 * const string logMeta = "LOG_OPCODE_FORMATED_TEXT^^"../../log.c"^^80^^Log_DEBUG^^LogMod_LogModule_App1^^"Hello World!"^^0"; 180 * // Route log to the selected sink implementation. This is done via function pointer. 181 * // The 0 indicates no arguments. If runtime arguments were provided, they would follow. 182 * LogMod_LogModule_App1.printf(pointerToModuleConfig, 0); 183 * } 184 * #endif 185 * #endif 186 * @endcode 187 * 188 * From here, the logger has transferred control over to the sink 189 * implementation, which varies based on the transport (e.g. circular buffer in 190 * memory or UART). 191 * 192 * ## Modules ## 193 * 194 * When adding log statements to the target software, it is recommended to 195 * create a logging module for each software component in the image. Modules 196 * enable the reader to understand where the log record originated from. Some 197 * log visualizers may allow the reader to filter or sort log statements by 198 * module. It is also recommended to namespace modules. 199 * 200 * For example, a good module name for the `UART` driver that exists in 201 * `source/ti/drivers`, could be `ti_drivers_UART`. 202 * 203 * Modules also control the routing of log records to a sink. Routing is 204 * controlled via the LogModule panel in SysConfig, but can be changed in plain 205 * C code using the macro @ref Log_MODULE_DEFINE and passing the sink specific 206 * `Log_MODULE_INIT_` to the `init` parameter within the @ref Log_MODULE_DEFINE 207 * macro. An example for the LogBuf sink is below, it will do the following 208 * 209 * 1. Create a module called `LogModule_App1`. 210 * 1. Initialize the module for use with the buffer based LogSink. Use buffer 211 * instance called `CONFIG_ti_log_LogSinkBuf_0`. 212 * 1. Enable only the `Log_ERROR` level. Other logs will not be stored. 213 * 214 * @code 215 * #include <ti/log/Log.h> 216 * #include <ti/log/LogSinkBuf.h> 217 * Log_MODULE_DEFINE(LogModule_App1, Log_MODULE_INIT_SINK_BUF(CONFIG_ti_log_LogSinkBuf_0, Log_ERROR)); 218 * @endcode 219 * 220 * TI created libraries will never use @ref Log_MODULE_DEFINE. This leaves the 221 * choice of routing logs to their sinks to the end application writer. This is 222 * recommended when creating any static libraries to defer the final logging 223 * decisions to link time. 224 * 225 * Each new module will instantiate a Log_Module structure with a `levels` 226 * bitmap and pointers to the selected sink implementation and sink 227 * configuration. See the @ref Log_Module structure for more information. 228 * 229 * ## Levels ## 230 * Log levels are a way to indicate the severity or importance of the contents 231 * of a particular log call site. Each call site takes an argument that allows 232 * the user to specify the level. As with modules, log visualization tools 233 * allow the user to sort or filter on a given level. This can help the reader 234 * to find important or relevant log statements in visualization. 235 * 236 * Log levels are also used to control the emission of logs. Each call site 237 * will check that the level is enabled before calling the underlying log API. 238 * 239 * Depending on optimization, the check at each log statement for whether the 240 * given level is enabled or not may end up being optimized away, and the 241 * entire log statement may be optimized away if the log level is not enabled. 242 * 243 * @code 244 * if ((level) & module.levels) {// Call Log API 245 * } 246 * @endcode 247 * 248 * Optimization level `-flto` for both the TICLANG toolchain and GCC will 249 * typically be able to optimize the above statement. 250 * 251 * @remark 252 * 253 * ## Log Metadata ## 254 * 255 * Each time a Log API is invoked, a metadata string is placed in the .out 256 * file. This string contains information about the API type, file, line 257 * module, level, and other information associated with the log call site. Each 258 * call site emits a string to a specific memory section called `.log_data`. In 259 * addition to this, a pointer to the string in .log_data is stored in another 260 * section called `.log_ptr`. Because the .log_ptr section is always in the 261 * same location, and each entry is the same size, an indexing-scheme can be 262 * used to refer to each log-string. Entry 0 in .log_ptr would point to the 263 * first string, entry 1 would point to the second string, etc. This Is 264 * necessary on some devices where transmitting an entire 32-bit address as a 265 * reference to the string is not possible, and instead an 8-bit index can be 266 * transmitted across the Log sink implementation instead. In order to use 267 * logging, this section should be added to the linker command file. By 268 * default, this section points to a nonloadable region of memory. Meaning that 269 * the metadata will not be loaded on the target device. Instead, the various 270 * logging visualization tools such as wireshark and TI ROV2 will read the 271 * metadata from this section and properly decode the log statements. The 272 * benefit of this approach is that very little memory is consumed on target. 273 * Additionally, the log transport only needs to store or send pointers to this 274 * meta section when a log API is called. 275 * 276 * This approach minimizes the amount of memory consumed on device and bytes 277 * sent over the transport. This section can be loaded on target if desired or 278 * if you are creating a custom logger. The design does not preclude this. 279 * 280 * In order to use the logging framework, the log section must be added to the 281 * linker command file. Here is a sample for the TI linker. Other examples can 282 * be found in the TI provided linker files for each toolchain. 283 * 284 * @code 285 * MEMORY 286 * { 287 * // List other memory regions here 288 * LOG_DATA (R) : origin = 0x90000000, length = 0x40000 289 * LOG_PTR (R) : origin = 0x94000008, length = 0x40000 290 * } 291 * SECTIONS 292 * { 293 * .log_data : > LOG_DATA, type = COPY 294 * .log_ptr : { *(.log_ptr*) } > LOG_PTR align 4, type = COPY 295 * } 296 * @endcode 297 * 298 * ## Sinks ## 299 * 300 * Sinks are responsible for storing or transporting the log record. In general 301 * there are two categories of sinks: 302 * 303 * 1. Those that perform storage of logs. 304 * 2. Those that stream logs over a transport medium, and thus do not perform 305 * storage. 306 * 307 * Sinks may vary in their implementation based on the nature of the storage or 308 * transport that they support, but they all have the following in common: 309 * 310 * * Are named ti_log_LogSink<SinkName>. Where `<SinkName>` is the name of the 311 * sink. 312 * * Must implement the Log_printf and Log_buf APIs from this file. 313 * * Must provide _USE, _INIT, and _DEFINE macros. 314 * 315 * In addition, some sinks require initialization. This will be listed in the 316 * documentation for the sink implementation. Sinks are closely tied to their 317 * associated host side tooling. Since the log statements are not parsed at all 318 * by the target code, this must be delegated to a program running on a PC. 319 * While the binary format of log records may vary across sink implementations, 320 * it is suggested that each log record contain: 321 * 322 * 1. Timestamp 323 * 1. Pointer to metadata string. This will be looked up by the PC side tooling 324 * in the out file. 325 * 1. Runtime arguments 326 * 327 * This is the minimum amount of information needed to decode a log statement. 328 * 329 * # Usage # 330 * This section provides a basic @ref ti_log_LOG_Synopsis "usage summary" and a 331 * set of @ref ti_log_LOG_Examples "examples" in the form of commented code 332 * fragments. Detailed descriptions of the LOG APIs are provided in subsequent 333 * sections. 334 * 335 * @anchor ti_log_LOG_Synopsis 336 * ### Synopsis ### 337 * 338 * @code 339 * // Import the Log header 340 * #include <ti/log/Log.h> 341 * 342 * // Define your log module and log sink 343 * // If using SysConfig, it will be done automatically, or it can be done manually: 344 * // Use helper macro from <ti/log/LogSinkBuf.h> to make a sink instance (buffer + config) with 100 entries. 345 * Log_SINK_BUF_DEFINE(MyBufferSink, LogSinkBuf_Type_CIRCULAR, 100); 346 * 347 * // Use helper macro from <ti/log/Log.h> to make a module pointing at the new sink instance. 348 * // This example will enable all log levels 349 * Log_MODULE_DEFINE(MyModule, Log_MODULE_INIT_SINK_BUF(MyBufferSink, Log_ALL)) 350 * 351 * // Some log sinks may require special initialization to configure hardware. Refer to the documentation of 352 * // the sink you wish to use. For example, LogSinkITM must be initialised like this before it can be used: 353 * // LogSinkITM_init(); 354 * 355 * // Invoke one of the log APIs you want to use for either pre-defined events or formatted strings 356 * Log_printf(MyModule, Log_DEBUG, "The answer is %d", 42); 357 * uint8_t buffer[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 358 * Log_buf(MyModule, Log_VERBOSE, buffer, sizeof(buffer)); 359 * @endcode 360 * 361 * 362 * 363 * @anchor ti_log_LOG_Examples 364 * ### Examples ### 365 * * @ref ti_utils_LOG_Example_event "Log Event" 366 * * @ref ti_utils_LOG_Example_printf "Log printf" 367 * * @ref ti_utils_LOG_Example_buf "Logging buffers" 368 * 369 * @anchor ti_utils_LOG_Example_event **Log Event**: 370 * 371 * The following example demonstrates how to create a log event object and use 372 * it in the code. There are two steps to using a log event: 1. instantiation 373 * and 2. call site(s). Instantiation creates the event and the necessary 374 * metadata, and call site is where the event is actually recorded by the 375 * logger framework. 376 * 377 * @code 378 * // Create a log event data type called LogEvent_count 379 * // The log module is MyModule 380 * // The format string is "count=%d" -- this should describe what the event does 381 * 382 * Log_EVENT_DEFINE(LogEvent_count, "count=%d"); 383 * @endcode 384 * 385 * Later on, in the application, the count event is consumed. Note the log 386 * module must match between event creation and call site. In the code below, a 387 * LogEvent record is created for serialization or stage by the Log sink. 388 * 389 * @code 390 * Log_EVENT_USE(LogEvent_count); // If not defined in same file 391 * // ... 392 * Log_event(MyModule, Log_DEBUG, LogEvent_count, count++); 393 * @endcode 394 * 395 * @anchor ti_utils_LOG_Example_printf **Log Printf**: 396 * 397 * The following example demonstrates use of the Log printf API. in code. Log 398 * will embed the format string in the call site and will take arguments using 399 * varadic arguments. 400 * 401 * @code 402 * Log_printf(MyModule, Log_DEBUG, "Hello World!"); 403 * @endcode 404 * 405 * The arguments are type-casted into a uintptr_t, which is an unsigned integer 406 * type. This limits the supported format specifiers to the following: 407 * - Unsigned decimal integer: \%u 408 * - Unsigned hexadecimal integer: \%x 409 * - Unsigned hexadecimal integer (capital letters): \%X 410 * - Character: \%c 411 * - Signed decimal integer for positive values: \%i, \%d 412 * - Signed octal for positive values: \%o 413 * 414 * @anchor ti_utils_LOG_Example_buf **Log Buf**: 415 * 416 * The following example demonstrates use of the Log buf API. in code. 417 * 418 * Buf will embed the format string in the call site and will take the buffer 419 * as a pointer and length. Buffers are treated as arrays of bytes. The buffer 420 * API should only be used when it is necessary to log data that is only 421 * available at runtime. It will actually send or store the entire contents of 422 * the buffer, so this API should be used sparingly as it is costly in terms of 423 * runtime and memory overhead. 424 * 425 * @code 426 * uint8_t bufferToLog[] = {0, 1, 2, 3, 4, 5}; 427 * Log_buf(ti_log_LogMain, Log_DEBUG, "The contents of bufferToLog are: ", bufferToLog, sizeof(bufferToLog)); 428 * @endcode 429 * 430 * @anchor ti_utils_LOG_Example_guide **Log API usage**: 431 * 432 * For a uniform experience with the logging tool, users are recommended to 433 * follow certain guidelines regarding the Log API. Typical use-cases for each 434 * API call is described below 435 * 436 * #### Log_printf #### 437 * 438 * Log_printf should be the default mechanism for emitting a log statement 439 * within an application. Along with the Log-levels, Log_printf should be used 440 * to communicate debug information as a formatted string, which accepts 441 * variadic arguments. In this case, a pointer to the string and the arguments 442 * themselves are transported by the Log sink. 443 * 444 * @code 445 * Log_printf(MyLibraryLogModule, Log_ERROR, "Library function received illegal argument: %d", arg); 446 * @endcode 447 * 448 * #### Log_event #### 449 * 450 * Log_event is meant to represent more generic debug-information, and 451 * typically something that can occur from anywhere in the application, as 452 * opposed to being localized in a single library. Events can also be defined 453 * once and referenced from anywhere in the application, so the same event can 454 * be used by multiple libraries. A generic example would be an event such as 455 * "Entering critical section" 456 * 457 * @code 458 * Log_EVENT_DEFINE(LogEvent_enterCritical, "Entering critical section"); 459 * 460 * Log_EVENT_USE(LogEvent_enterCritical); // If not defined in same file 461 * // ... 462 * Log_event(MyModule, Log_DEBUG, LogEvent_enterCritical); 463 * @endcode 464 * 465 * #### Log_buf #### 466 * 467 * When the debug-information to be emitted is a large amount of dynamic data, 468 * and is not suitable as an argument to printf, then Log_buf should be used. 469 * Log_buf can transport the contents of large dynamic buffers, and as a 470 * consequence has a larger overhead and should be used sparsely. 471 */ 472 473 #ifndef ti_log_Log__include 474 #define ti_log_Log__include 475 476 /*! @ingroup ti_log_LOG */ 477 /*@{*/ 478 479 /* 480 * ======== Log.h ======== 481 * @brief Contains Log library APIs 482 */ 483 #include <stdint.h> 484 #include <stddef.h> 485 486 #if defined (__cplusplus) 487 extern "C" { 488 #endif 489 490 /* 491 * ======== ti_log_Log_ENABLE ======== 492 * Enable instrumentation using link-time optimization implementation 493 * 494 * Define this symbol to add instrumentation at compile time. 495 * It must be defined before including this header file. 496 */ 497 #if ti_log_Log_ENABLE 498 /* 499 * ============================= 500 * ======== Log Enabled ======== 501 * ============================= 502 */ 503 504 #define Log_TI_LOG_VERSION 0.1.0 505 /** 506 * @brief Defines a log module 507 * 508 * Log modules are like namespaces for log statements, but also controls the 509 * enabled log levels and decides where the log statement is redirected. 510 * 511 * @param[in] name Name of the log module. Gets prefixed with `LogMod_`. 512 * @param[in] init Initialization macro from the wanted sink 513 * 514 * This is a helper to define `Log_Module LogMod_yourName` and initialize it 515 * with the configuration and functions of the wanted log sink. 516 * 517 * For example, you have already used the sink definition macros found in 518 * LogSinkITM.h, and now you want to define a new module that uses this: 519 * 520 * `Log_MODULE_DEFINE(MyDriver, Log_MODULE_INIT_SINK_ITM(Log_DEBUG | Log_ERROR))` 521 * 522 * Perhaps you used the LogSinkBuf.h helper macro which needs a unique name 523 * per instance and made a separate buffer for critical errors: 524 * 525 * `Log_MODULE_DEFINE(MyCritical, Log_MODULE_INIT_SINK_BUF(criticalBuf, Log_ERROR)` 526 * 527 * You would use this in your application via 528 * `Log(MyCritical, Log_ERROR, "Oops")` 529 */ 530 #define Log_MODULE_DEFINE(name, init) const Log_Module LogMod_ ## name = init 531 532 /** 533 * @brief Defines Log module as weak 534 * 535 * If there are multiple modules containing Log statements per library, 536 * special care must be taken not to create link-time failures. 537 * Whether Log statements from a library are present in the final binary is 538 * determined by the library configuration the application links against 539 * (instrumented vs uninstrumented). 540 * Each Log statement has a link-time dependency on its Log module. Enabling 541 * only a subset of Log modules contained within the library will cause any 542 * Log statements from other Log modules of that library to fail at link-time. 543 * This is avoided by declaring a weak instance of each Log module in C code 544 * that is compiled into the library. That way, the SysConfig-generated Log 545 * module definitions will override the weak library ones but they are there 546 * if SysConfig does not define that particular module. 547 * 548 * @param[in] name Name of the log module. Gets prefixed with `LogMod_`. 549 * @param[in] init Initialization value of the Log_Module struct. 550 */ 551 #if defined(__IAR_SYSTEMS_ICC__) 552 #define Log_MODULE_DEFINE_WEAK(name, init) const __weak Log_Module LogMod_ ## name = init 553 #elif defined(__TI_COMPILER_VERSION__) || (defined(__clang__) && defined(__ti_version__)) || defined(__GNUC__) 554 #define Log_MODULE_DEFINE_WEAK(name, init) const Log_Module LogMod_ ## name __attribute__((weak)) = init 555 #else 556 #error "Incompatible compiler: Logging is currently supported by the following \ 557 compilers: TI ARM Compiler, TI CLANG Compiler, GCC, IAR. Please migrate to a \ 558 a supported compiler." 559 #endif 560 561 /** 562 * @brief Declares a reference to a log module 563 * 564 * Declares that a log module is defined in another file so that it can be 565 * used in the file with this macro in it. 566 * 567 * @note This is done automatically for `Log` and `Log_buf` statements. 568 * 569 * @param[in] name Name of the log module. Gets prefixed with `LogMod_`. 570 */ 571 #define Log_MODULE_USE(name) extern const Log_Module LogMod_ ## name 572 573 /** 574 * @brief Resolves to the symbol name of the log module 575 * 576 * Provided for forward compatibility purposes should you have a need to 577 * reference the log module symbol directly. 578 */ 579 #define LOG_MODULE_SYM(name) LogMod_ ## name 580 581 /** @cond NODOC */ 582 583 /* This macro protects against side effects of the C preprocessor expansion 584 * of log statements. Each log API should be guarded by it. 585 * An article explaining this behavior can be found here: 586 * https://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html 587 */ 588 #define _Log_GUARD_MACRO(x) do{ x }while(0) 589 590 /* 591 * 592 * ======== Log Private Macros ======== 593 * 594 * The following macros are intended to be private to the log module and 595 * are not intended for use by the user. Private macros will start with _Log. 596 * 597 * In the case of multi level macros (macros that invoke other macros), a 598 * letter is appended at the end of the definition. With each level of nesting, 599 * the appended letter is incremented. 600 * 601 * For example: _Log_test --> _Log_test_A --> _Log_test_B 602 */ 603 /* Extracts the first/remaining argument from __VA_ARGS__ */ 604 #define _Log_CAR_ARG(N, ...) N 605 #define _Log_CDR_ARG(N, ...) __VA_ARGS__ 606 607 608 /* 609 * ======== Meta string tokenization macros ======== 610 */ 611 /* Helper macro to concatenate two symbols */ 612 #define _Log_CONCAT2_A(x,y) x ## _ ## y 613 #define _Log_CONCAT2(x,y) _Log_CONCAT2_A(x,y) 614 #define _Log_CONCAT3(x,y,z) _Log_CONCAT2(x,_Log_CONCAT2(y,z)) 615 616 /* Helper macro to concatenate two symbols */ 617 #define _Log__TOKEN2STRING_A(x) #x 618 #define _Log_TOKEN2STRING(x) _Log__TOKEN2STRING_A(x) 619 620 /* Macro to place meta string in a memory section separated by record separator */ 621 #define _Log_APPEND_META_TO_FORMAT(opcode, \ 622 file, \ 623 line, \ 624 level, \ 625 module, \ 626 format, \ 627 nargs) \ 628 _Log_TOKEN2STRING(opcode) "\x1e" \ 629 _Log_TOKEN2STRING(file) "\x1e" \ 630 _Log_TOKEN2STRING(line) "\x1e" \ 631 _Log_TOKEN2STRING(level) "\x1e" \ 632 _Log_TOKEN2STRING(module) "\x1e" \ 633 _Log_TOKEN2STRING(format) "\x1e" \ 634 _Log_TOKEN2STRING(nargs) 635 636 /* Place a string in trace format section named ".log_data" locally 637 * This section must exist in the linker file 638 */ 639 #if defined(__IAR_SYSTEMS_ICC__) 640 #define _Log_PLACE_FORMAT_IN_SECTOR(name, opcode, level, module, format, nargs)\ 641 __root static const char name[] @ ".log_data" = \ 642 _Log_APPEND_META_TO_FORMAT(opcode, \ 643 __FILE__, \ 644 __LINE__, \ 645 level, \ 646 module, \ 647 format, \ 648 nargs); \ 649 __root static const char * const _Log_CONCAT2(Ptr, name) @ _Log_TOKEN2STRING(_Log_CONCAT2(.log_ptr, module)) = name; 650 #elif defined(__TI_COMPILER_VERSION__) || (defined(__clang__) && defined(__ti_version__)) || defined(__GNUC__) 651 #define _Log_PLACE_FORMAT_IN_SECTOR(name, opcode, level, module, format, nargs)\ 652 static const char name[] \ 653 __attribute__((used,section(".log_data"))) = \ 654 _Log_APPEND_META_TO_FORMAT(opcode, \ 655 __FILE__, \ 656 __LINE__, \ 657 level, \ 658 module, \ 659 format, \ 660 nargs); \ 661 static const char * const _Log_CONCAT2(Ptr, name) \ 662 __attribute__((used,section(_Log_TOKEN2STRING(_Log_CONCAT3(.log_ptr, __LINE__, module))))) = name; 663 #else 664 #error "Incompatible compiler: Logging is currently supported by the following \ 665 compilers: TI ARM Compiler, TI CLANG Compiler, GCC, IAR. Please migrate to a \ 666 a supported compiler." 667 #endif 668 669 /* 670 * ======== Variadic macro workaround ======== 671 */ 672 /* Helper macro to count the number of arguments in __VA_ARGS_ */ 673 #define _Log_NUMARGS(...) _Log_NUMARGS_A(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0) 674 #define _Log_NUMARGS_A(...) _Log_NUMARGS_B(__VA_ARGS__) 675 #define _Log_NUMARGS_B(_first, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N 676 677 /* 678 * Helper to select arg/noarg variant macro since empty va_arg fails 679 * when arguments are expected. Eg 680 * Log_VARIANT(test, A, 7, "Hello") -> test__noarg(A, 7, "Hello") 681 * Log_VARIANT(test, A, 7, "Hello %d", 42) -> test__arg1(A, 7, "Hello %d", 42) 682 */ 683 #define _Log_VARIANT(x, module, level, ...) \ 684 _Log_CONCAT2(x, _Log_NUMARGS_B(__VA_ARGS__, _arg8, _arg7, _arg6, _arg5, _arg4, _arg3, _arg2, _arg1, _noarg)) ( module, level, __VA_ARGS__ ) 685 686 /* 687 * ======== Module-level preprocessor include macros ======== 688 */ 689 690 /* Helper macro to extract the second argument of a variable number of input 691 * args 692 */ 693 #define _Log_SECOND_ARG(x, y, ...) y 694 695 /* Temporary token name. 696 * Name must end in "1" for preprocessor substitution below to work. 697 */ 698 #define _Log_TOKEN_1 0, 699 700 /* Helper macro to check whether a symbol is defined with a non-zero value. 701 * If x is a preprocessor define, the conversion below shows the macro output: 702 * x = 0 -> 0 703 * x = 1 -> 1 704 * x (no value) -> 0 705 * (undefined) -> 0 706 */ 707 #define _Log_DEFINED(x) _Log_DEFINED_A(x) 708 709 /* If x is 1, _Log_TOKEN_##y turns into _Log_TOKEN_1 and is replaced with "0," 710 * If x is anything else, _Log_TOKEN_##y turns into _Log_TOKEN_y. 711 */ 712 #define _Log_DEFINED_A(y) _Log_DEFINED_B(_Log_TOKEN_##y) 713 714 /* If z is "0,", _Log_SECOND_ARG is called with the triplet "0, 1, 0" and 715 * selects the second item in it, 1. 716 * If z is anything else, _Log_SECOND_ARG is called with the tuple "z 1, 0" and 717 * selects the second item in it, 0. 718 */ 719 #define _Log_DEFINED_B(z) _Log_SECOND_ARG(z 1, 0) 720 721 /* Empty Log buf macro to use when a log module is not enabled in the 722 * preprocessor during compilation 723 */ 724 #define _Log_buf_C_0(module, level, format, data, size) 725 726 /* Log_buf macro to use when a log module is enabled in the preprocessor during 727 * compilation. 728 */ 729 #define _Log_buf_C_1(module, level, format, data, size) \ 730 _Log_GUARD_MACRO( \ 731 Log_MODULE_USE(module); \ 732 if ((Log_ENABLED & LogMod_ ## module.levels) && ((level) & LogMod_ ## module.levels)) { \ 733 _Log_PLACE_FORMAT_IN_SECTOR(_Log_CONCAT2(LogSymbol, __LINE__), \ 734 LOG_OPCODE_BUFFER, \ 735 level, \ 736 LogMod_ ## module, \ 737 format, \ 738 0); \ 739 LogMod_ ## module.buf(&LogMod_ ## module, \ 740 (uint32_t)&_Log_CONCAT2(LogSymbol, __LINE__), \ 741 (uint32_t)&_Log_CONCAT3(Ptr, LogSymbol, __LINE__), \ 742 data, \ 743 size); \ 744 } \ 745 ) 746 747 /* First level indirection macro for Log_buf that delegates between an empty 748 * implementation and the actual log emission based on whether a module is 749 * enabled in the preprocessor during compilation. 750 * 751 * The _Log_DEFINED() macro generates a token output of [0, 1] that is then 752 * concatenated with "_Log_buf_C" to form the correct delegate macro name. 753 * 754 * The expected module define name is ti_log_Log_ENABLE_ | <module> and must be 755 * set to 1. E.g. "-Dti_log_Log_ENABLE_MyLogModule=1". Just defining the symbol in 756 * the preprocessor will not emit any logs. 757 */ 758 #define _Log_buf_B(module, level, format, data, size) \ 759 _Log_CONCAT2(_Log_buf_C, _Log_DEFINED(ti_log_Log_ENABLE_ ## module))(module, level, format, data, size) 760 761 /* 762 * Redirects to cast all printf arguments to uintptr_t to avoid surprises if 763 * passing wider values and the compiler silently allows it. 764 */ 765 #define _Log_printf__arg1(module, level, fmt, a0) \ 766 _Log_printf__arg(module, level, fmt, (uintptr_t)a0) 767 #define _Log_printf__arg2(module, level, fmt, a0, a1) \ 768 _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \ 769 (uintptr_t)a1) 770 #define _Log_printf__arg3(module, level, fmt, a0, a1, a2) \ 771 _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \ 772 (uintptr_t)a1, \ 773 (uintptr_t)a2) 774 #define _Log_printf__arg4(module, level, fmt, a0, a1, a2, a3) \ 775 _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \ 776 (uintptr_t)a1, \ 777 (uintptr_t)a2, \ 778 (uintptr_t)a3) 779 #define _Log_printf__arg5(module, level, fmt, a0, a1, a2, a3, a4) \ 780 _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \ 781 (uintptr_t)a1, \ 782 (uintptr_t)a2, \ 783 (uintptr_t)a3, \ 784 (uintptr_t)a4) 785 #define _Log_printf__arg6(module, level, fmt, a0, a1, a2, a3, a4, a5) \ 786 _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \ 787 (uintptr_t)a1, \ 788 (uintptr_t)a2, \ 789 (uintptr_t)a3, \ 790 (uintptr_t)a4, \ 791 (uintptr_t)a5) 792 #define _Log_printf__arg7(module, level, fmt, a0, a1, a2, a3, a4, a5, a6) \ 793 _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \ 794 (uintptr_t)a1, \ 795 (uintptr_t)a2, \ 796 (uintptr_t)a3, \ 797 (uintptr_t)a4, \ 798 (uintptr_t)a5, \ 799 (uintptr_t)a6) 800 #define _Log_printf__arg8(module, level, fmt, a0, a1, a2, a3, a4, a5, a6, a7) \ 801 _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \ 802 (uintptr_t)a1, \ 803 (uintptr_t)a2, \ 804 (uintptr_t)a3, \ 805 (uintptr_t)a4, \ 806 (uintptr_t)a5, \ 807 (uintptr_t)a6, \ 808 (uintptr_t)a7) 809 810 #define _Log_printf__arg(module, level, ...) \ 811 module.printf(&module, \ 812 (uint32_t)&_Log_CONCAT2(LogSymbol, __LINE__), \ 813 (uint32_t)&_Log_CONCAT3(Ptr, LogSymbol, __LINE__), \ 814 _Log_NUMARGS(__VA_ARGS__), \ 815 _Log_CDR_ARG(__VA_ARGS__)) 816 817 #define _Log_printf__noarg(module, level, ...) \ 818 module.printf(&module, \ 819 (uint32_t)&_Log_CONCAT2(LogSymbol, __LINE__), \ 820 (uint32_t)&_Log_CONCAT3(Ptr, LogSymbol, __LINE__), \ 821 _Log_NUMARGS(__VA_ARGS__)) 822 823 /* Empty Log_printf macro to use when a log module is not enabled in the 824 * preprocessor during compilation 825 */ 826 #define _Log_printf_C_0(opcode, module, level, ...) 827 828 /* Log_printf macro to use when a log module is enabled in the preprocessor during 829 * compilation. 830 */ 831 #define _Log_printf_C_1(opcode, module, level, ...) \ 832 _Log_GUARD_MACRO( \ 833 Log_MODULE_USE(module); \ 834 if ((Log_ENABLED & LogMod_ ## module.levels) && \ 835 ((level) & LogMod_ ## module.levels)) { \ 836 _Log_PLACE_FORMAT_IN_SECTOR(_Log_CONCAT2(LogSymbol, __LINE__), \ 837 opcode, \ 838 level, \ 839 LogMod_ ## module, \ 840 _Log_CAR_ARG(__VA_ARGS__), \ 841 _Log_NUMARGS(__VA_ARGS__)) \ 842 _Log_VARIANT(_Log_printf, LogMod_ ## module, level, __VA_ARGS__); \ 843 } \ 844 ) 845 846 /* First level indirection macro for Log_printf that delegates between an empty 847 * implementation and the actual log emission based on whether a module is 848 * enabled in the preprocessor during compilation. 849 * 850 * The _Log_DEFINED() macro generates a token output of [0, 1] that is then 851 * concatenated with "_Log_buf_C" to form the correct delegate macro name. 852 * 853 * The expected module define name is ti_log_Log_ENABLE_ | <module> and must be 854 * set to 1. E.g. "-Dti_log_Log_ENABLE_MyLogModule=1". Just defining the symbol in 855 * the preprocessor will not emit any logs. 856 */ 857 #define _Log_printf_B(opcode, module, level, ...) \ 858 _Log_CONCAT2(_Log_printf_C, _Log_DEFINED(ti_log_Log_ENABLE_ ## module))(opcode, module, level, __VA_ARGS__) 859 860 /** @endcond */ 861 862 /** 863 * @brief Construct a log event object 864 * 865 * Use this marco to define a log event object. The object is global, and may 866 * be used in other files by invoking Log_EVENT_USE(name) there. 867 * 868 * @param[in] name Event variable name, to be passed to Log_event API 869 * @param[in] fmt Restricted format string. Note `%s` is not supported. 870 * Supported format specifiers include: `%c`, `%f`, 871 * `%d`, `%x` 872 */ 873 #if defined(__IAR_SYSTEMS_ICC__) 874 #define Log_EVENT_DEFINE(name, fmt) \ 875 __root const char LogSymbol_ ## name[] @ ".log_data" = \ 876 _Log_APPEND_META_TO_FORMAT(LOG_EVENT_CONSTRUCT, \ 877 __FILE__, \ 878 __LINE__, \ 879 name, \ 880 global, \ 881 fmt, \ 882 0) 883 884 #elif defined(__TI_COMPILER_VERSION__) || (defined(__clang__) && defined(__ti_version__)) || defined(__GNUC__) 885 #define Log_EVENT_DEFINE(name, fmt) \ 886 const char LogSymbol_ ## name[] \ 887 __attribute__((used,section(".log_data"))) = \ 888 _Log_APPEND_META_TO_FORMAT(LOG_EVENT_CONSTRUCT, \ 889 __FILE__, \ 890 __LINE__, \ 891 name, \ 892 global, \ 893 fmt, \ 894 0) 895 #else 896 #error "Incompatible compiler: Logging is currently supported by the following \ 897 compilers: TI ARM Compiler, TI CLANG Compiler, GCC, IAR. Please migrate to a \ 898 a supported compiler." 899 #endif 900 901 /** 902 * @brief Declare usage of a log event symbol defined elsewhere 903 * 904 * Use this marco to declare a log event symbol for use. It's just a fancy 905 * `extern` macro. 906 * 907 * @param[in] name Event variable name, to be passed to Log_event API 908 */ 909 #define Log_EVENT_USE(name) extern const char[] LogSymbol_ ## name; 910 911 912 /** 913 * @brief Log a continuous block of memory 914 * 915 * Use this macro to send out runtime data from the device. This API should be 916 * used when the data is non constant and can only be derived at runtime. It 917 * is the most intrusive in terms of record overhead and instructions used. 918 * 919 * @param[in] module Log module that the buffer originated from 920 * @param[in] level log level of type @ref Log_Level 921 * @param[in] format Restricted format string. 922 * @param[in] data Pointer to array of bytes (uint8_t *) 923 * @param[in] size Size in bytes of array to send 924 * 925 */ 926 #define Log_buf(module, level, format, data, size) _Log_buf_B(module, level, format, data, size) 927 928 /** 929 * @brief Emit a log event 930 * 931 * Use this marco to enable printf style logging. This API offers the most 932 * flexibility as the construction of the format string is embedded in the call 933 * site of the API. It also supports true variadic arguments. 934 * 935 * @param[in] module Log module that the buffer originated from 936 * @param[in] level Log level of type @ref Log_Level 937 * @param[in] event Event to be logged. Can be either a constructed 938 * Log_EVENT symbol, or a printf-like format-string 939 * @param[in] ... Variable amount of arguments. Must match your 940 * event or format-string. 941 * 942 * Examples: 943 * `Log_printf(MyTimingEvent, t.start)`, `Log_printf("Hello World")`, `Log_printf("Age: %d", 42)` 944 * 945 * @note All arguments are treated as 32-bit wide and are promoted or 946 * truncated accordingly. 947 */ 948 #define Log_printf(module, level, ...) _Log_printf_B(LOG_OPCODE_FORMATED_TEXT, module, level, __VA_ARGS__) 949 950 #define Log_event(module, level, ...) _Log_printf_B(LOG_OPCODE_EVENT, module, level, __VA_ARGS__) 951 952 /* Macro for defining the version of the Log API */ 953 954 955 956 #if defined(__IAR_SYSTEMS_ICC__) 957 #define _Log_DEFINE_LOG_VERSION(module, version) \ 958 __root static const char _Log_CONCAT2(Log_ti_log_version, __COUNTER__)[] @ ".log_data" = \ 959 _Log_APPEND_META_TO_FORMAT(LOG_OPCODE_VERSION, \ 960 module, \ 961 version, \ 962 0, \ 963 0, \ 964 0, \ 965 0) 966 #elif defined(__TI_COMPILER_VERSION__) || (defined(__clang__) && defined(__ti_version__)) || defined(__GNUC__) 967 #define _Log_DEFINE_LOG_VERSION(module, version) \ 968 static const char _Log_CONCAT2(Log_ti_log_version, __COUNTER__)[] \ 969 __attribute__((used,section(".log_data"))) = \ 970 _Log_APPEND_META_TO_FORMAT(LOG_OPCODE_VERSION, \ 971 module, \ 972 version, \ 973 0, \ 974 0, \ 975 0, \ 976 0) 977 #else 978 #error "Incompatible compiler: Logging is currently supported by the following \ 979 compilers: TI ARM Compiler, TI CLANG Compiler, GCC, IAR. Please migrate to a \ 980 a supported compiler." 981 #endif 982 983 /* Generate a symbol in the elf file that defines the version of the Log API */ 984 _Log_DEFINE_LOG_VERSION(Log, Log_TI_LOG_VERSION); 985 986 #else /* ti_log_Log_ENABLE */ 987 988 /* 989 * ================================================= 990 * ======== Log Disabled (default behavior) ======== 991 * ================================================= 992 */ 993 994 #define Log_MODULE_DEFINE(...) 995 #define Log_MODULE_DEFINE_WEAK(name, init) 996 #define Log_MODULE_USE(...) 997 #define Log_EVENT_DEFINE(name, fmt) 998 #define Log_EVENT_USE(name, fmt) 999 #define Log_printf(module, level, ...) 1000 #define Log_event(module, level, ...) 1001 #define Log_buf(module, level, ...) 1002 #define _Log_DEFINE_LOG_VERSION(module, version) 1003 1004 #endif /* ti_log_Log_ENABLE */ 1005 1006 /* 1007 * ======== Log_Level ======== 1008 */ 1009 typedef enum Log_Level { 1010 Log_DEBUG = 1, /*!< This should be the default level, reserved to be used by users to insert into applications for debugging. Exported libraries should avoid using this level. */ 1011 Log_VERBOSE = 4, /*!< This level is recommended to be used in libraries to emit verbose information */ 1012 Log_INFO = 16, /*!< This level is recommended to be used in libraries to emit simple information */ 1013 Log_WARNING = 64, /*!< This level is recommended to be used in libraries to emit warnings. It is up to the library developer to decide what constitutes a warning, but it should typically indicate something unexpected, but not something that leads to system failure */ 1014 Log_ERROR = 256, /*!< This level is recommended to be used in libraries to emit errors. Typically, this should be used when something has failed and the system is unable to continue correct operation */ 1015 Log_ALL = 1 + 4 + 16 + 64 + 256, /*!< This enables all levels */ 1016 Log_ENABLED = 512 /*!< This is used to enable or disable the log module, independently of the log levels */ 1017 } Log_Level; 1018 1019 typedef const struct Log_Module Log_Module; 1020 1021 typedef void (*Log_printf_fxn)(const Log_Module *handle, 1022 uint32_t header, 1023 uint32_t headerPtr, 1024 uint32_t numArgs, 1025 ...); 1026 1027 typedef void (*Log_buf_fxn)(const Log_Module *handle, 1028 uint32_t header, 1029 uint32_t headerPtr, 1030 uint8_t *data, 1031 size_t size); 1032 1033 struct Log_Module { 1034 void *sinkConfig; 1035 const Log_printf_fxn printf; 1036 const Log_buf_fxn buf; 1037 uint32_t levels; 1038 }; 1039 1040 /*! @} */ 1041 #if defined (__cplusplus) 1042 } 1043 #endif 1044 1045 #endif // ti_log_Log__include 1046