TI Utilities API
Log.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019-2024 Texas Instruments Incorporated - https://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 
473 #ifndef ti_log_Log__include
474 #define ti_log_Log__include
475 
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 
530 #define Log_MODULE_DEFINE(name, init) const Log_Module LogMod_ ## name = init
531 
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 
571 #define Log_MODULE_USE(name) extern const Log_Module LogMod_ ## name
572 
579 #define LOG_MODULE_SYM(name) LogMod_ ## name
580 
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 
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 
909 #define Log_EVENT_USE(name) extern const char[] LogSymbol_ ## name;
910 
911 
926 #define Log_buf(module, level, format, data, size) _Log_buf_B(module, level, format, data, size)
927 
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 {
1012  Log_INFO = 16,
1014  Log_ERROR = 256,
1015  Log_ALL = 1 + 4 + 16 + 64 + 256,
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;
1037  uint32_t levels;
1038 };
1039 
1041 #if defined (__cplusplus)
1042 }
1043 #endif
1044 
1045 #endif // ti_log_Log__include
Definition: Log.h:1010
Log_Level
Definition: Log.h:1009
const Log_buf_fxn buf
Definition: Log.h:1036
void(* Log_printf_fxn)(const Log_Module *handle, uint32_t header, uint32_t headerPtr, uint32_t numArgs,...)
Definition: Log.h:1021
Definition: Log.h:1016
const Log_printf_fxn printf
Definition: Log.h:1035
Definition: Log.h:1011
void(* Log_buf_fxn)(const Log_Module *handle, uint32_t header, uint32_t headerPtr, uint8_t *data, size_t size)
Definition: Log.h:1027
Definition: Log.h:1033
#define _Log_DEFINE_LOG_VERSION(module, version)
Definition: Log.h:1002
Definition: Log.h:1015
Definition: Log.h:1014
uint32_t levels
Definition: Log.h:1037
Definition: Log.h:1012
Definition: Log.h:1013
void * sinkConfig
Definition: Log.h:1034
© Copyright 1995-2024, Texas Instruments Incorporated. All rights reserved.
Trademarks | Privacy policy | Terms of use | Terms of sale