TI Utilities API
Log.h
Go to the documentation of this file.
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 
498 #ifndef ti_log_Log__include
499 #define ti_log_Log__include
500 
503 
504 #include <stdint.h>
505 #include <stddef.h>
506 
507 #if defined (__cplusplus)
508 extern "C" {
509 #endif
510 
511 /*
512  * ======== ti_log_Log_ENABLE ========
513  * Enable instrumentation using link-time optimization implementation
514  *
515  * Define this symbol to add instrumentation at compile time.
516  * It must be defined before including this header file.
517  */
518 
519 #if defined(DOXYGEN) || ti_log_Log_ENABLE
520 /*
521  * =============================
522  * ======== Log Enabled ========
523  * =============================
524  */
525 
529 #define Log_TI_LOG_VERSION 0.1.0
530 
565 #define Log_MODULE_DEFINE(name, init) const Log_Module LogMod_ ## name = init
566 
586 #if defined(DOXYGEN) || defined(__IAR_SYSTEMS_ICC__)
587 #define Log_MODULE_DEFINE_WEAK(name, init) const __weak Log_Module LogMod_ ## name = init
588 #elif defined(__TI_COMPILER_VERSION__) || (defined(__clang__) && defined(__ti_version__)) || defined(__GNUC__)
589 #define Log_MODULE_DEFINE_WEAK(name, init) const Log_Module LogMod_ ## name __attribute__((weak)) = init
590 #else
591 #error "Incompatible compiler: Logging is currently supported by the following \
592 compilers: TI ARM Compiler, TI CLANG Compiler, GCC, IAR. Please migrate to a \
593 supported compiler."
594 #endif
595 
606 #define Log_MODULE_USE(name) extern const Log_Module LogMod_ ## name
607 
614 #define LOG_MODULE_SYM(name) LogMod_ ## name
615 
618 /* This macro protects against side effects of the C preprocessor expansion
619  * of log statements. Each log API should be guarded by it.
620  * An article explaining this behavior can be found here:
621  * https://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html
622  */
623 #define _Log_GUARD_MACRO(x) do{ x }while(0)
624 
625 /*
626  *
627  * ======== Log Private Macros ========
628  *
629  * The following macros are intended to be private to the log module and
630  * are not intended for use by the user. Private macros will start with _Log.
631  *
632  * In the case of multi level macros (macros that invoke other macros), a
633  * letter is appended at the end of the definition. With each level of nesting,
634  * the appended letter is incremented.
635  *
636  * For example: _Log_test --> _Log_test_A --> _Log_test_B
637  */
638 /* Extracts the first/remaining argument from __VA_ARGS__ */
639 #define _Log_CAR_ARG(N, ...) N
640 #define _Log_CDR_ARG(N, ...) __VA_ARGS__
641 
642 
643 /*
644  * ======== Meta string tokenization macros ========
645  */
646 /* Helper macro to concatenate two symbols */
647 #define _Log_CONCAT2_A(x,y) x ## _ ## y
648 #define _Log_CONCAT2(x,y) _Log_CONCAT2_A(x,y)
649 #define _Log_CONCAT3(x,y,z) _Log_CONCAT2(x,_Log_CONCAT2(y,z))
650 
651 /* Helper macro to concatenate two symbols */
652 #define _Log__TOKEN2STRING_A(x) #x
653 #define _Log_TOKEN2STRING(x) _Log__TOKEN2STRING_A(x)
654 
655 /* Macro to place meta string in a memory section separated by record separator */
656 #define _Log_APPEND_META_TO_FORMAT(opcode, \
657  file, \
658  line, \
659  level, \
660  module, \
661  format, \
662  nargs) \
663  _Log_TOKEN2STRING(opcode) "\x1e" \
664  _Log_TOKEN2STRING(file) "\x1e" \
665  _Log_TOKEN2STRING(line) "\x1e" \
666  _Log_TOKEN2STRING(level) "\x1e" \
667  _Log_TOKEN2STRING(module) "\x1e" \
668  _Log_TOKEN2STRING(format) "\x1e" \
669  _Log_TOKEN2STRING(nargs)
670 
671 /* Place a string in trace format section named ".log_data" locally
672  * This section must exist in the linker file
673  */
674 #if defined(__IAR_SYSTEMS_ICC__)
675 #define _Log_PLACE_FORMAT_IN_SECTOR(name, opcode, level, module, format, nargs)\
676  __root static const char name[] @ ".log_data" = \
677  _Log_APPEND_META_TO_FORMAT(opcode, \
678  __FILE__, \
679  __LINE__, \
680  level, \
681  module, \
682  format, \
683  nargs); \
684  __root static const char * const _Log_CONCAT2(Ptr, name) @ _Log_TOKEN2STRING(_Log_CONCAT2(.log_ptr, module)) = name;
685 #elif defined(__TI_COMPILER_VERSION__) || (defined(__clang__) && defined(__ti_version__)) || defined(__GNUC__)
686 #define _Log_PLACE_FORMAT_IN_SECTOR(name, opcode, level, module, format, nargs)\
687  static const char name[] \
688  __attribute__((used,section(".log_data"))) = \
689  _Log_APPEND_META_TO_FORMAT(opcode, \
690  __FILE__, \
691  __LINE__, \
692  level, \
693  module, \
694  format, \
695  nargs); \
696  static const char * const _Log_CONCAT2(Ptr, name) \
697  __attribute__((used,section(_Log_TOKEN2STRING(_Log_CONCAT3(.log_ptr, __LINE__, module))))) = name;
698 #else
699 #error "Incompatible compiler: Logging is currently supported by the following \
700 compilers: TI ARM Compiler, TI CLANG Compiler, GCC, IAR. Please migrate to a \
701 supported compiler."
702 #endif
703 
704 /*
705  * ======== Variadic macro workaround ========
706  */
707 /* Helper macro to count the number of arguments in __VA_ARGS_ */
708 #define _Log_NUMARGS(...) _Log_NUMARGS_A(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0)
709 #define _Log_NUMARGS_A(...) _Log_NUMARGS_B(__VA_ARGS__)
710 #define _Log_NUMARGS_B(_first, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
711 
712 /*
713  * Helper to select arg/noarg variant macro since empty va_arg fails
714  * when arguments are expected. Eg
715  * Log_VARIANT(test, A, 7, "Hello") -> test__noarg(A, 7, "Hello")
716  * Log_VARIANT(test, A, 7, "Hello %d", 42) -> test__arg1(A, 7, "Hello %d", 42)
717  */
718 #define _Log_VARIANT(x, module, level, ...) \
719  _Log_CONCAT2(x, _Log_NUMARGS_B(__VA_ARGS__, _arg8, _arg7, _arg6, _arg5, _arg4, _arg3, _arg2, _arg1, _noarg)) ( module, level, __VA_ARGS__ )
720 
721 /*
722  * ======== Module-level preprocessor include macros ========
723  */
724 
725 /* Helper macro to extract the second argument of a variable number of input
726  * args
727  */
728 #define _Log_SECOND_ARG(x, y, ...) y
729 
730 /* Temporary token name.
731  * Name must end in "1" for preprocessor substitution below to work.
732  */
733 #define _Log_TOKEN_1 0,
734 
735 /* Helper macro to check whether a symbol is defined with a non-zero value.
736  * If x is a preprocessor define, the conversion below shows the macro output:
737  * x = 0 -> 0
738  * x = 1 -> 1
739  * x (no value) -> 0
740  * (undefined) -> 0
741  */
742 #define _Log_DEFINED(x) _Log_DEFINED_A(x)
743 
744 /* If x is 1, _Log_TOKEN_##y turns into _Log_TOKEN_1 and is replaced with "0,"
745  * If x is anything else, _Log_TOKEN_##y turns into _Log_TOKEN_y.
746  */
747 #define _Log_DEFINED_A(y) _Log_DEFINED_B(_Log_TOKEN_##y)
748 
749 /* If z is "0,", _Log_SECOND_ARG is called with the triplet "0, 1, 0" and
750  * selects the second item in it, 1.
751  * If z is anything else, _Log_SECOND_ARG is called with the tuple "z 1, 0" and
752  * selects the second item in it, 0.
753  */
754 #define _Log_DEFINED_B(z) _Log_SECOND_ARG(z 1, 0)
755 
756 /* Empty Log buf macro to use when a log module is not enabled in the
757  * preprocessor during compilation
758  */
759 #define _Log_buf_C_0(module, level, format, data, size)
760 
761 /* Log_buf macro to use when a log module is enabled in the preprocessor during
762  * compilation.
763  */
764 #define _Log_buf_C_1(module, level, format, data, size) \
765  _Log_GUARD_MACRO( \
766  Log_MODULE_USE(module); \
767  if ((level) & LogMod_ ## module.levels) { \
768  _Log_PLACE_FORMAT_IN_SECTOR(_Log_CONCAT2(LogSymbol, __LINE__), \
769  LOG_OPCODE_BUFFER, \
770  level, \
771  LogMod_ ## module, \
772  format, \
773  0); \
774  LogMod_ ## module.buf(&LogMod_ ## module, \
775  (uint32_t)&_Log_CONCAT2(LogSymbol, __LINE__), \
776  (uint32_t)&_Log_CONCAT3(Ptr, LogSymbol, __LINE__), \
777  data, \
778  size); \
779  } \
780  )
781 
782 /* First level indirection macro for Log_buf that delegates between an empty
783  * implementation and the actual log emission based on whether a module is
784  * enabled in the preprocessor during compilation.
785  *
786  * The _Log_DEFINED() macro generates a token output of [0, 1] that is then
787  * concatenated with "_Log_buf_C" to form the correct delegate macro name.
788  *
789  * The expected module define name is ti_log_Log_ENABLE_ | <module> and must be
790  * set to 1. E.g. "-Dti_log_Log_ENABLE_MyLogModule=1". Just defining the symbol in
791  * the preprocessor will not emit any logs.
792  */
793 #define _Log_buf_B(module, level, format, data, size) \
794  _Log_CONCAT2(_Log_buf_C, _Log_DEFINED(ti_log_Log_ENABLE_ ## module))(module, level, format, data, size)
795 
796 /* Redirects to cast all printf arguments to uintptr_t to avoid surprises if
797  * passing wider values and the compiler silently allows it.
798  *
799  * These redirects also allow us to select which delegate function pointer to
800  * load from the #Log_Module. There are dedicated wrappers for certain printf
801  * argument counts.
802  *
803  * - 0-3 args redirect to dedicated functions to avoid loading the argument
804  * count when LTO is enabled.
805  * - 4-8 args redirect to a generic implementation.
806  *
807  * The 4-8 args break point is a compromise between how often the wrapper can
808  * be expected to be used in an average application and the constant overhead
809  * associated with providing it at all. There is also overhead per Log_Module
810  * for each additional arg count wrapper used. This overhead is eliminated when
811  * LTO is enabled though.
812  */
813 #define _Log_printf__arg1(module, level, fmt, a0) \
814  module.printf1(&module, \
815  (uint32_t)&_Log_CONCAT2(LogSymbol, __LINE__), \
816  (uint32_t)&_Log_CONCAT3(Ptr, LogSymbol, __LINE__), \
817  (uintptr_t)a0)
818 #define _Log_printf__arg2(module, level, fmt, a0, a1) \
819  module.printf2(&module, \
820  (uint32_t)&_Log_CONCAT2(LogSymbol, __LINE__), \
821  (uint32_t)&_Log_CONCAT3(Ptr, LogSymbol, __LINE__), \
822  (uintptr_t)a0, \
823  (uintptr_t)a1)
824 #define _Log_printf__arg3(module, level, fmt, a0, a1, a2) \
825  module.printf3(&module, \
826  (uint32_t)&_Log_CONCAT2(LogSymbol, __LINE__), \
827  (uint32_t)&_Log_CONCAT3(Ptr, LogSymbol, __LINE__), \
828  (uintptr_t)a0, \
829  (uintptr_t)a1, \
830  (uintptr_t)a2)
831 #define _Log_printf__arg4(module, level, fmt, a0, a1, a2, a3) \
832  _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \
833  (uintptr_t)a1, \
834  (uintptr_t)a2, \
835  (uintptr_t)a3)
836 #define _Log_printf__arg5(module, level, fmt, a0, a1, a2, a3, a4) \
837  _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \
838  (uintptr_t)a1, \
839  (uintptr_t)a2, \
840  (uintptr_t)a3, \
841  (uintptr_t)a4)
842 #define _Log_printf__arg6(module, level, fmt, a0, a1, a2, a3, a4, a5) \
843  _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \
844  (uintptr_t)a1, \
845  (uintptr_t)a2, \
846  (uintptr_t)a3, \
847  (uintptr_t)a4, \
848  (uintptr_t)a5)
849 #define _Log_printf__arg7(module, level, fmt, a0, a1, a2, a3, a4, a5, a6) \
850  _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \
851  (uintptr_t)a1, \
852  (uintptr_t)a2, \
853  (uintptr_t)a3, \
854  (uintptr_t)a4, \
855  (uintptr_t)a5, \
856  (uintptr_t)a6)
857 #define _Log_printf__arg8(module, level, fmt, a0, a1, a2, a3, a4, a5, a6, a7) \
858  _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \
859  (uintptr_t)a1, \
860  (uintptr_t)a2, \
861  (uintptr_t)a3, \
862  (uintptr_t)a4, \
863  (uintptr_t)a5, \
864  (uintptr_t)a6, \
865  (uintptr_t)a7)
866 
867 #define _Log_printf__arg(module, level, ...) \
868  module.printf(&module, \
869  (uint32_t)&_Log_CONCAT2(LogSymbol, __LINE__), \
870  (uint32_t)&_Log_CONCAT3(Ptr, LogSymbol, __LINE__), \
871  _Log_NUMARGS(__VA_ARGS__), \
872  _Log_CDR_ARG(__VA_ARGS__))
873 
874 #define _Log_printf__noarg(module, level, ...) \
875  module.printf0(&module, \
876  (uint32_t)&_Log_CONCAT2(LogSymbol, __LINE__), \
877  (uint32_t)&_Log_CONCAT3(Ptr, LogSymbol, __LINE__))
878 
879 /* Empty Log_printf macro to use when a log module is not enabled in the
880  * preprocessor during compilation
881  */
882 #define _Log_printf_C_0(opcode, module, level, ...)
883 
884 /* Log_printf macro to use when a log module is enabled in the preprocessor during
885  * compilation.
886  */
887 #define _Log_printf_C_1(opcode, module, level, ...) \
888  _Log_GUARD_MACRO( \
889  Log_MODULE_USE(module); \
890  if (((LogMod_ ## module.dynamicLevelsPtr != NULL) && ((level) & *LogMod_ ## module.dynamicLevelsPtr)) || \
891  ((level) & LogMod_ ## module.levels)) { \
892  _Log_PLACE_FORMAT_IN_SECTOR(_Log_CONCAT2(LogSymbol, __LINE__), \
893  opcode, \
894  level, \
895  LogMod_ ## module, \
896  _Log_CAR_ARG(__VA_ARGS__), \
897  _Log_NUMARGS(__VA_ARGS__)) \
898  _Log_VARIANT(_Log_printf, LogMod_ ## module, level, __VA_ARGS__); \
899  } \
900  )
901 
902 /* First level indirection macro for Log_printf that delegates between an empty
903  * implementation and the actual log emission based on whether a module is
904  * enabled in the preprocessor during compilation.
905  *
906  * The _Log_DEFINED() macro generates a token output of [0, 1] that is then
907  * concatenated with "_Log_buf_C" to form the correct delegate macro name.
908  *
909  * The expected module define name is ti_log_Log_ENABLE_ | <module> and must be
910  * set to 1. E.g. "-Dti_log_Log_ENABLE_MyLogModule=1". Just defining the symbol
911  * in the preprocessor will not emit any logs.
912  */
913 #define _Log_printf_B(opcode, module, level, ...) \
914  _Log_CONCAT2(_Log_printf_C, _Log_DEFINED(ti_log_Log_ENABLE_ ## module))(opcode, module, level, __VA_ARGS__)
915 
932 #define Log_buf(module, level, format, data, size) _Log_buf_B(module, level, format, data, size)
933 
953 #define Log_printf(module, level, ...) _Log_printf_B(LOG_OPCODE_FORMATED_TEXT, module, level, __VA_ARGS__)
954 
959 #if defined(__IAR_SYSTEMS_ICC__)
960 #define _Log_DEFINE_LOG_VERSION(module, version) \
961  __root static const char _Log_CONCAT2(Log_ti_log_version, __COUNTER__)[] @ ".log_data" = \
962  _Log_APPEND_META_TO_FORMAT(LOG_OPCODE_VERSION, \
963  module, \
964  version, \
965  0, \
966  0, \
967  0, \
968  0)
969 #elif defined(__TI_COMPILER_VERSION__) || (defined(__clang__) && defined(__ti_version__)) || defined(__GNUC__)
970 #define _Log_DEFINE_LOG_VERSION(module, version) \
971  static const char _Log_CONCAT2(Log_ti_log_version, __COUNTER__)[] \
972  __attribute__((used,section(".log_data"))) = \
973  _Log_APPEND_META_TO_FORMAT(LOG_OPCODE_VERSION, \
974  module, \
975  version, \
976  0, \
977  0, \
978  0, \
979  0)
980 #else
981 #error "Incompatible compiler: Logging is currently supported by the following \
982 compilers: TI ARM Compiler, TI CLANG Compiler, GCC, IAR. Please migrate to a \
983 supported compiler."
984 #endif
985 
986 /* Generate a symbol in the elf file that defines the version of the Log API */
987 _Log_DEFINE_LOG_VERSION(Log, Log_TI_LOG_VERSION);
988 
1001 #define Log_MODULE_SET_LEVELS(module, levels) \
1002  _Log_GUARD_MACRO( \
1003  Log_MODULE_USE(module); \
1004  if (LogMod_ ## module.dynamicLevelsPtr != NULL) { \
1005  *LogMod_ ## module.dynamicLevelsPtr = levels; \
1006  } \
1007  )
1008 
1018 #define Log_MODULE_GET_LEVELS(module) \
1019  _Log_GUARD_MACRO( \
1020  Log_MODULE_USE(module); \
1021  if (LogMod_ ## module.dynamicLevelsPtr != NULL) { \
1022  *LogMod_ ## module.dynamicLevelsPtr; \
1023  } \
1024  else { \
1025  LogMod_ ## module.levels; \
1026  } \
1027  )
1028 
1029 #else /* defined(DOXYGEN) || ti_log_Log_ENABLE */
1030 
1031 /*
1032  * =================================================
1033  * ======== Log Disabled (default behavior) ========
1034  * =================================================
1035  */
1036 
1037 #define Log_MODULE_DEFINE(...)
1038 #define Log_MODULE_DEFINE_WEAK(name, init)
1039 #define Log_MODULE_USE(...)
1040 #define Log_printf(module, level, ...)
1041 #define Log_buf(module, level, ...)
1042 #define _Log_DEFINE_LOG_VERSION(module, version)
1043 #define Log_MODULE_SET_LEVELS(module, levels)
1044 #define Log_MODULE_GET_LEVELS(module)
1045 
1046 #endif /* defined(DOXYGEN) || ti_log_Log_ENABLE */
1047 
1048 
1049 
1056 typedef enum Log_Level {
1061  Log_DEBUG = 1 << 0,
1062 
1072  Log_VERBOSE = 1 << 2,
1073 
1081  Log_INFO = 1 << 4,
1082 
1097  Log_WARNING = 1 << 6,
1098 
1110  Log_ERROR = 1 << 8,
1111 
1116 
1121 } Log_Level;
1122 
1123 typedef const struct Log_Module Log_Module;
1124 
1125 typedef void (*Log_printf_fxn)(const Log_Module *handle,
1126  uint32_t header,
1127  uint32_t headerPtr,
1128  uint32_t numArgs,
1129  ...);
1130 
1131 typedef void (*Log_printfN_fxn)(const Log_Module *handle,
1132  uint32_t header,
1133  uint32_t headerPtr,
1134  ...);
1135 
1136 typedef void (*Log_buf_fxn)(const Log_Module *handle,
1137  uint32_t header,
1138  uint32_t headerPtr,
1139  uint8_t *data,
1140  size_t size);
1141 
1147 struct Log_Module {
1148  void *sinkConfig;
1155  uint32_t levels;
1156  uint32_t* const dynamicLevelsPtr;
1157 };
1158 
1160 #if defined (__cplusplus)
1161 }
1162 #endif
1163 
1164 #endif // ti_log_Log__include
Definition: Log.h:1061
void(* Log_printfN_fxn)(const Log_Module *handle, uint32_t header, uint32_t headerPtr,...)
Definition: Log.h:1131
Log_Level
Log level bitmask values.
Definition: Log.h:1056
const Log_buf_fxn buf
Definition: Log.h:1154
Definition: Log.h:1120
void(* Log_printf_fxn)(const Log_Module *handle, uint32_t header, uint32_t headerPtr, uint32_t numArgs,...)
Definition: Log.h:1125
const Log_printf_fxn printf
Definition: Log.h:1149
Definition: Log.h:1072
void(* Log_buf_fxn)(const Log_Module *handle, uint32_t header, uint32_t headerPtr, uint8_t *data, size_t size)
Definition: Log.h:1136
const Log_printfN_fxn printf0
Definition: Log.h:1150
Log module.
Definition: Log.h:1147
Definition: Log.h:1115
uint32_t *const dynamicLevelsPtr
Definition: Log.h:1156
Definition: Log.h:1110
uint32_t levels
Definition: Log.h:1155
Definition: Log.h:1081
#define Log_TI_LOG_VERSION
Log version.
Definition: Log.h:529
const Log_printfN_fxn printf1
Definition: Log.h:1151
Definition: Log.h:1097
const Log_printfN_fxn printf3
Definition: Log.h:1153
const Log_printfN_fxn printf2
Definition: Log.h:1152
void * sinkConfig
Definition: Log.h:1148
© Copyright 1995-2025, Texas Instruments Incorporated. All rights reserved.
Trademarks | Privacy policy | Terms of use | Terms of sale