TI Utilities API
Log.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019-2023 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 
542 #define Log_MODULE_USE(name) extern const Log_Module LogMod_ ## name
543 
550 #define LOG_MODULE_SYM(name) LogMod_ ## name
551 
554 /* This macro protects against side effects of the C preprocessor expansion
555  * of log statements. Each log API should be guarded by it.
556  * An article explaining this behavior can be found here:
557  * https://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html
558  */
559 #define _Log_GUARD_MACRO(x) do{ x }while(0)
560 
561 /*
562  *
563  * ======== Log Private Macros ========
564  *
565  * The following macros are intended to be private to the log module and
566  * are not intended for use by the user. Private macros will start with _Log.
567  *
568  * In the case of multi level macros (macros that invoke other macros), a
569  * letter is appended at the end of the definition. With each level of nesting,
570  * the appended letter is incremented.
571  *
572  * For example: _Log_test --> _Log_test_A --> _Log_test_B
573  */
574 /* Extracts the first/remaining argument from __VA_ARGS__ */
575 #define _Log_CAR_ARG(N, ...) N
576 #define _Log_CDR_ARG(N, ...) __VA_ARGS__
577 
578 
579 /*
580  * ======== Meta string tokenization macros ========
581  */
582 /* Helper macro to concatenate two symbols */
583 #define _Log_CONCAT2_A(x,y) x ## _ ## y
584 #define _Log_CONCAT2(x,y) _Log_CONCAT2_A(x,y)
585 #define _Log_CONCAT3(x,y,z) _Log_CONCAT2(x,_Log_CONCAT2(y,z))
586 
587 /* Helper macro to concatenate two symbols */
588 #define _Log__TOKEN2STRING_A(x) #x
589 #define _Log_TOKEN2STRING(x) _Log__TOKEN2STRING_A(x)
590 
591 /* Macro to place meta string in a memory section separated by record separator */
592 #define _Log_APPEND_META_TO_FORMAT(opcode, \
593  file, \
594  line, \
595  level, \
596  module, \
597  format, \
598  nargs) \
599  _Log_TOKEN2STRING(opcode) "\x1e" \
600  _Log_TOKEN2STRING(file) "\x1e" \
601  _Log_TOKEN2STRING(line) "\x1e" \
602  _Log_TOKEN2STRING(level) "\x1e" \
603  _Log_TOKEN2STRING(module) "\x1e" \
604  _Log_TOKEN2STRING(format) "\x1e" \
605  _Log_TOKEN2STRING(nargs)
606 
607 /* Place a string in trace format section named ".log_data" locally
608  * This section must exist in the linker file
609  */
610 #if defined(__IAR_SYSTEMS_ICC__)
611 #define _Log_PLACE_FORMAT_IN_SECTOR(name, opcode, level, module, format, nargs)\
612  __root static const char name[] @ ".log_data" = \
613  _Log_APPEND_META_TO_FORMAT(opcode, \
614  __FILE__, \
615  __LINE__, \
616  level, \
617  module, \
618  format, \
619  nargs); \
620  __root static const char * const _Log_CONCAT2(Ptr, name) @ _Log_TOKEN2STRING(_Log_CONCAT2(.log_ptr, module)) = name;
621 #elif defined(__TI_COMPILER_VERSION__) || (defined(__clang__) && defined(__ti_version__)) || defined(__GNUC__)
622 #define _Log_PLACE_FORMAT_IN_SECTOR(name, opcode, level, module, format, nargs)\
623  static const char name[] \
624  __attribute__((used,section(".log_data"))) = \
625  _Log_APPEND_META_TO_FORMAT(opcode, \
626  __FILE__, \
627  __LINE__, \
628  level, \
629  module, \
630  format, \
631  nargs); \
632  static const char * const _Log_CONCAT2(Ptr, name) \
633  __attribute__((used,section(_Log_TOKEN2STRING(_Log_CONCAT3(.log_ptr, __LINE__, module))))) = name;
634 #else
635 #error Incompatible compiler: Logging is currently supported by the following \
636 compilers: TI ARM Compiler, TI CLANG Compiler, GCC, IAR. Please migrate to a \
637 a supported compiler.
638 #endif
639 
640 /*
641  * ======== Variadic macro workaround ========
642  */
643 /* Helper macro to count the number of arguments in __VA_ARGS_ */
644 #define _Log_NUMARGS(...) _Log_NUMARGS_A(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0)
645 #define _Log_NUMARGS_A(...) _Log_NUMARGS_B(__VA_ARGS__)
646 #define _Log_NUMARGS_B(_first, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
647 
648 /*
649  * Helper to select arg/noarg variant macro since empty va_arg fails
650  * when arguments are expected. Eg
651  * Log_VARIANT(test, A, 7, "Hello") -> test__noarg(A, 7, "Hello")
652  * Log_VARIANT(test, A, 7, "Hello %d", 42) -> test__arg1(A, 7, "Hello %d", 42)
653  */
654 #define _Log_VARIANT(x, module, level, ...) \
655  _Log_CONCAT2(x, _Log_NUMARGS_B(__VA_ARGS__, _arg8, _arg7, _arg6, _arg5, _arg4, _arg3, _arg2, _arg1, _noarg)) ( module, level, __VA_ARGS__ )
656 
657 /*
658  * ======== Module-level preprocessor include macros ========
659  */
660 
661 /* Helper macro to extract the second argument of a variable number of input
662  * args
663  */
664 #define _Log_SECOND_ARG(x, y, ...) y
665 
666 /* Temporary token name.
667  * Name must end in "1" for preprocessor substitution below to work.
668  */
669 #define _Log_TOKEN_1 0,
670 
671 /* Helper macro to check whether a symbol is defined with a non-zero value.
672  * If x is a preprocessor define, the conversion below shows the macro output:
673  * x = 0 -> 0
674  * x = 1 -> 1
675  * x (no value) -> 0
676  * (undefined) -> 0
677  */
678 #define _Log_DEFINED(x) _Log_DEFINED_A(x)
679 
680 /* If x is 1, _Log_TOKEN_##y turns into _Log_TOKEN_1 and is replaced with "0,"
681  * If x is anything else, _Log_TOKEN_##y turns into _Log_TOKEN_y.
682  */
683 #define _Log_DEFINED_A(y) _Log_DEFINED_B(_Log_TOKEN_##y)
684 
685 /* If z is "0,", _Log_SECOND_ARG is called with the triplet "0, 1, 0" and
686  * selects the second item in it, 1.
687  * If z is anything else, _Log_SECOND_ARG is called with the tuple "z 1, 0" and
688  * selects the second item in it, 0.
689  */
690 #define _Log_DEFINED_B(z) _Log_SECOND_ARG(z 1, 0)
691 
692 /* Empty Log buf macro to use when a log module is not enabled in the
693  * preprocessor during compilation
694  */
695 #define _Log_buf_C_0(module, level, format, data, size)
696 
697 /* Log_buf macro to use when a log module is enabled in the preprocessor during
698  * compilation.
699  */
700 #define _Log_buf_C_1(module, level, format, data, size) \
701  _Log_GUARD_MACRO( \
702  Log_MODULE_USE(module); \
703  if ((Log_ENABLED & LogMod_ ## module.levels) && ((level) & LogMod_ ## module.levels)) { \
704  _Log_PLACE_FORMAT_IN_SECTOR(_Log_CONCAT2(LogSymbol, __LINE__), \
705  LOG_OPCODE_BUFFER, \
706  level, \
707  LogMod_ ## module, \
708  format, \
709  0); \
710  LogMod_ ## module.buf(&LogMod_ ## module, \
711  (uint32_t)&_Log_CONCAT2(LogSymbol, __LINE__), \
712  (uint32_t)&_Log_CONCAT3(Ptr, LogSymbol, __LINE__), \
713  data, \
714  size); \
715  } \
716  )
717 
718 /* First level indirection macro for Log_buf that delegates between an empty
719  * implementation and the actual log emission based on whether a module is
720  * enabled in the preprocessor during compilation.
721  *
722  * The _Log_DEFINED() macro generates a token output of [0, 1] that is then
723  * concatenated with "_Log_buf_C" to form the correct delegate macro name.
724  *
725  * The expected module define name is ti_log_Log_ENABLE_ | <module> and must be
726  * set to 1. E.g. "-Dti_log_Log_ENABLE_MyLogModule=1". Just defining the symbol in
727  * the preprocessor will not emit any logs.
728  */
729 #define _Log_buf_B(module, level, format, data, size) \
730  _Log_CONCAT2(_Log_buf_C, _Log_DEFINED(ti_log_Log_ENABLE_ ## module))(module, level, format, data, size)
731 
732 /*
733  * Redirects to cast all printf arguments to uintptr_t to avoid surprises if
734  * passing wider values and the compiler silently allows it.
735  */
736 #define _Log_printf__arg1(module, level, fmt, a0) \
737  _Log_printf__arg(module, level, fmt, (uintptr_t)a0)
738 #define _Log_printf__arg2(module, level, fmt, a0, a1) \
739  _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \
740  (uintptr_t)a1)
741 #define _Log_printf__arg3(module, level, fmt, a0, a1, a2) \
742  _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \
743  (uintptr_t)a1, \
744  (uintptr_t)a2)
745 #define _Log_printf__arg4(module, level, fmt, a0, a1, a2, a3) \
746  _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \
747  (uintptr_t)a1, \
748  (uintptr_t)a2, \
749  (uintptr_t)a3)
750 #define _Log_printf__arg5(module, level, fmt, a0, a1, a2, a3, a4) \
751  _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \
752  (uintptr_t)a1, \
753  (uintptr_t)a2, \
754  (uintptr_t)a3, \
755  (uintptr_t)a4)
756 #define _Log_printf__arg6(module, level, fmt, a0, a1, a2, a3, a4, a5) \
757  _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \
758  (uintptr_t)a1, \
759  (uintptr_t)a2, \
760  (uintptr_t)a3, \
761  (uintptr_t)a4, \
762  (uintptr_t)a5)
763 #define _Log_printf__arg7(module, level, fmt, a0, a1, a2, a3, a4, a5, a6) \
764  _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \
765  (uintptr_t)a1, \
766  (uintptr_t)a2, \
767  (uintptr_t)a3, \
768  (uintptr_t)a4, \
769  (uintptr_t)a5, \
770  (uintptr_t)a6)
771 #define _Log_printf__arg8(module, level, fmt, a0, a1, a2, a3, a4, a5, a6, a7) \
772  _Log_printf__arg(module, level, fmt, (uintptr_t)a0, \
773  (uintptr_t)a1, \
774  (uintptr_t)a2, \
775  (uintptr_t)a3, \
776  (uintptr_t)a4, \
777  (uintptr_t)a5, \
778  (uintptr_t)a6, \
779  (uintptr_t)a7)
780 
781 #define _Log_printf__arg(module, level, ...) \
782  module.printf(&module, \
783  (uint32_t)&_Log_CONCAT2(LogSymbol, __LINE__), \
784  (uint32_t)&_Log_CONCAT3(Ptr, LogSymbol, __LINE__), \
785  _Log_NUMARGS(__VA_ARGS__), \
786  _Log_CDR_ARG(__VA_ARGS__))
787 
788 #define _Log_printf__noarg(module, level, ...) \
789  module.printf(&module, \
790  (uint32_t)&_Log_CONCAT2(LogSymbol, __LINE__), \
791  (uint32_t)&_Log_CONCAT3(Ptr, LogSymbol, __LINE__), \
792  _Log_NUMARGS(__VA_ARGS__))
793 
794 /* Empty Log_printf macro to use when a log module is not enabled in the
795  * preprocessor during compilation
796  */
797 #define _Log_printf_C_0(opcode, module, level, ...)
798 
799 /* Log_printf macro to use when a log module is enabled in the preprocessor during
800  * compilation.
801  */
802 #define _Log_printf_C_1(opcode, module, level, ...) \
803  _Log_GUARD_MACRO( \
804  Log_MODULE_USE(module); \
805  if ((Log_ENABLED & LogMod_ ## module.levels) && \
806  ((level) & LogMod_ ## module.levels)) { \
807  _Log_PLACE_FORMAT_IN_SECTOR(_Log_CONCAT2(LogSymbol, __LINE__), \
808  opcode, \
809  level, \
810  LogMod_ ## module, \
811  _Log_CAR_ARG(__VA_ARGS__), \
812  _Log_NUMARGS(__VA_ARGS__)) \
813  _Log_VARIANT(_Log_printf, LogMod_ ## module, level, __VA_ARGS__); \
814  } \
815  )
816 
817 /* First level indirection macro for Log_printf that delegates between an empty
818  * implementation and the actual log emission based on whether a module is
819  * enabled in the preprocessor during compilation.
820  *
821  * The _Log_DEFINED() macro generates a token output of [0, 1] that is then
822  * concatenated with "_Log_buf_C" to form the correct delegate macro name.
823  *
824  * The expected module define name is ti_log_Log_ENABLE_ | <module> and must be
825  * set to 1. E.g. "-Dti_log_Log_ENABLE_MyLogModule=1". Just defining the symbol in
826  * the preprocessor will not emit any logs.
827  */
828 #define _Log_printf_B(opcode, module, level, ...) \
829  _Log_CONCAT2(_Log_printf_C, _Log_DEFINED(ti_log_Log_ENABLE_ ## module))(opcode, module, level, __VA_ARGS__)
830 
844 #if defined(__IAR_SYSTEMS_ICC__)
845 #define Log_EVENT_DEFINE(name, fmt) \
846  __root const char LogSymbol_ ## name[] @ ".log_data" = \
847  _Log_APPEND_META_TO_FORMAT(LOG_EVENT_CONSTRUCT, \
848  __FILE__, \
849  __LINE__, \
850  name, \
851  global, \
852  fmt, \
853  0)
854 
855 #elif defined(__TI_COMPILER_VERSION__) || (defined(__clang__) && defined(__ti_version__)) || defined(__GNUC__)
856 #define Log_EVENT_DEFINE(name, fmt) \
857  const char LogSymbol_ ## name[] \
858  __attribute__((used,section(".log_data"))) = \
859  _Log_APPEND_META_TO_FORMAT(LOG_EVENT_CONSTRUCT, \
860  __FILE__, \
861  __LINE__, \
862  name, \
863  global, \
864  fmt, \
865  0)
866 #else
867 #error Incompatible compiler: Logging is currently supported by the following \
868 compilers: TI ARM Compiler, TI CLANG Compiler, GCC, IAR. Please migrate to a \
869 a supported compiler.
870 #endif
871 
880 #define Log_EVENT_USE(name) extern const char[] LogSymbol_ ## name;
881 
882 
897 #define Log_buf(module, level, format, data, size) _Log_buf_B(module, level, format, data, size)
898 
919 #define Log_printf(module, level, ...) _Log_printf_B(LOG_OPCODE_FORMATED_TEXT, module, level, __VA_ARGS__)
920 
921 #define Log_event(module, level, ...) _Log_printf_B(LOG_OPCODE_EVENT, module, level, __VA_ARGS__)
922 
923 /* Macro for defining the version of the Log API */
924 
925 
926 
927 #if defined(__IAR_SYSTEMS_ICC__)
928 #define _Log_DEFINE_LOG_VERSION(module, version) \
929  __root static const char _Log_CONCAT2(Log_ti_log_version, __COUNTER__)[] @ ".log_data" = \
930  _Log_APPEND_META_TO_FORMAT(LOG_OPCODE_VERSION, \
931  module, \
932  version, \
933  0, \
934  0, \
935  0, \
936  0)
937 #elif defined(__TI_COMPILER_VERSION__) || (defined(__clang__) && defined(__ti_version__)) || defined(__GNUC__)
938 #define _Log_DEFINE_LOG_VERSION(module, version) \
939  static const char _Log_CONCAT2(Log_ti_log_version, __COUNTER__)[] \
940  __attribute__((used,section(".log_data"))) = \
941  _Log_APPEND_META_TO_FORMAT(LOG_OPCODE_VERSION, \
942  module, \
943  version, \
944  0, \
945  0, \
946  0, \
947  0)
948 #else
949 #error Incompatible compiler: Logging is currently supported by the following \
950 compilers: TI ARM Compiler, TI CLANG Compiler, GCC, IAR. Please migrate to a \
951 a supported compiler.
952 #endif
953 
954 /* Generate a symbol in the elf file that defines the version of the Log API */
955 _Log_DEFINE_LOG_VERSION(Log, Log_TI_LOG_VERSION);
956 
957 #else /* ti_log_Log_ENABLE */
958 
959 /*
960  * =================================================
961  * ======== Log Disabled (default behavior) ========
962  * =================================================
963  */
964 
965 #define Log_MODULE_DEFINE(...)
966 #define Log_MODULE_USE(...)
967 #define Log_EVENT_DEFINE(name, fmt)
968 #define Log_EVENT_USE(name, fmt)
969 #define Log_printf(module, level, ...)
970 #define Log_event(module, level, ...)
971 #define Log_buf(module, level, ...)
972 #define _Log_DEFINE_LOG_VERSION(module, version)
973 
974 #endif /* ti_log_Log_ENABLE */
975 
976 /*
977  * ======== Log_Level ========
978  */
979 typedef enum Log_Level {
980  Log_DEBUG = 1,
982  Log_INFO = 16,
983  Log_WARNING = 64,
984  Log_ERROR = 256,
985  Log_ALL = 1 + 4 + 16 + 64 + 256,
986  Log_ENABLED = 512
987 } Log_Level;
988 
989 typedef const struct Log_Module Log_Module;
990 
991 typedef void (*Log_printf_fxn)(const Log_Module *handle,
992  uint32_t header,
993  uint32_t headerPtr,
994  uint32_t numArgs,
995  ...);
996 
997 typedef void (*Log_buf_fxn)(const Log_Module *handle,
998  uint32_t header,
999  uint32_t headerPtr,
1000  uint8_t *data,
1001  size_t size);
1002 
1003 struct Log_Module {
1004  void *sinkConfig;
1007  uint32_t levels;
1008 };
1009 
1010 
1012 #if defined (__cplusplus)
1013 }
1014 #endif
1015 
1016 #endif // ti_log_Log__include
Definition: Log.h:980
Log_Level
Definition: Log.h:979
const Log_buf_fxn buf
Definition: Log.h:1006
void(* Log_printf_fxn)(const Log_Module *handle, uint32_t header, uint32_t headerPtr, uint32_t numArgs,...)
Definition: Log.h:991
Definition: Log.h:986
const Log_printf_fxn printf
Definition: Log.h:1005
Definition: Log.h:981
void(* Log_buf_fxn)(const Log_Module *handle, uint32_t header, uint32_t headerPtr, uint8_t *data, size_t size)
Definition: Log.h:997
Definition: Log.h:1003
#define _Log_DEFINE_LOG_VERSION(module, version)
Definition: Log.h:972
Definition: Log.h:985
Definition: Log.h:984
uint32_t levels
Definition: Log.h:1007
Definition: Log.h:982
Definition: Log.h:983
void * sinkConfig
Definition: Log.h:1004
© Copyright 1995-2023, Texas Instruments Incorporated. All rights reserved.
Trademarks | Privacy policy | Terms of use | Terms of sale