1 /*
2  * Copyright (c) 2018 Oticon A/S
3  * Copyright (c) 2023 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /*
9  * Utility functions for printing info/warning/error messages and exit execution.
10  *
11  * These functions provide an optional but recommended way of printing messages from
12  * programs which use bsim. By using this functions you ensure both a consistent,
13  * not-interleaved message output.
14  *
15  * Several types of traces can be done: Errors, Warnings, Info, Debug and "raw" messages.
16  * By default, errors and warnings will be printed to the process stderr, the rest to stdout.
17  *
18  * Info, debug and "raw" messages have an associated verbosity level: an integer between 0 and 9.
19  * Users have the option (thru the command line argument `-v=<verbosity_level>`) to select up to
20  * which verbosity they want messages to be displayed. Any message over the selected verbosity
21  * will be discarded.
22  *
23  * All messages will be prefixed with a small string given by the program
24  * (typically 5 characters long).
25  * For Physical layer simulation programs, this will be a short of the Phy name;
26  * For devices typically "d_<%02i>:", where %02i will be the device number,
27  * using at least 2 digits.
28  *
29  * Error and warning traces will, by default and when routed to a tty, be colored.
30  * Coloring will be disabled by default when printing to a file or another process.
31  * Coloring can be controlled with command line options.
32  *
33  * "Exit" traces can also be produced, this will print an error, and exit the program execution.
34  * In this case the registered main exit cleanup function will be called.
35  *
36  * The main API for users are the bs_trace_{exit|error|warning|info|debug|raw}[_line][_time] macros.
37  * The "_line" variants will print the file and line from which the trace originated together with the
38  * message.
39  * The "_time" variants will also print the current simulated time (as reported by the time function
40  * registered with `bs_trace_register_time_function()` )
41  * "_manual_time" versions exists only to support bizarre use cases, and it is recommended to not use
42  * them in general.
43  *
44  * All these macros have printf() like semantics (after the verbosity level).
45  */
46 
47 #ifndef UTIL_BS_TRACING_H
48 #define UTIL_BS_TRACING_H
49 
50 #ifdef __cplusplus
51 extern "C"{
52 #endif
53 
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <stdarg.h>
57 #include <stddef.h>
58 #include "bs_types.h"
59 #include "bs_utils.h"
60 
61 typedef uint8_t (*main_cleanup_f)(void);
62 typedef bs_time_t (*time_f)(void);
63 
64 /*
65  * Disable color in traces
66  *
67  * This is an API meant for the controlling program.
68  * Normal users of this functionality are not expected to call it.
69  */
70 void bs_trace_disable_color(char * argv, int offset);
71 
72 /*
73  * Enable color in traces.
74  * This will only enable color when printing to a tty.
75  *
76  * This is an API meant for the controlling program.
77  * Normal users of this functionality are not expected to call it.
78  */
79 void bs_trace_enable_color(char * argv, int offset);
80 
81 /*
82  * For color in traces enabled.
83  * Even if not printing to a tty.
84  *
85  * This is an API meant for the controlling program.
86  * Normal users of this functionality are not expected to call it.
87  */
88 void bs_trace_force_color(char * argv, int offset);
89 
90 /*
91  * Is <file_number> connected to a tty.
92  * Where file_number is 0 for stdout, 1 for stderr.
93  *
94  * returns: 1 if a tty, 0 otherwise.
95  *
96  * This is an API meant for the controlling program.
97  * Normal users of this functionality are not expected to call it.
98  */
99 int bs_trace_is_tty(int file_number);
100 
101 /*
102  * Set the tracing level.
103  *
104  * Normally this function will be only called from the command
105  * from the command line argument parsing.
106  */
107 void bs_trace_set_level(int new_trace_level);
108 
109 /*
110  * Will a message with a given verbosity level be printed or discarded
111  *
112  * Returns 1 if it will be printed, 0 otherwise.
113  */
114 int bs_trace_will_it_be_traced(int this_message_trace_level);
115 
116 /*
117  * Register the function to be called from the exit() APIs to terminate
118  * the program. If none is registered the libC standard exit() will be called.
119  */
120 void bs_trace_register_cleanup_function(main_cleanup_f cleanup_f);
121 
122 /*
123  * Register a function which returns the current simulated time
124  */
125 void bs_trace_register_time_function(time_f t_f);
126 
127 /*
128  * Set prefix for prints
129  */
130 void bs_trace_set_prefix(const char* prefix);
131 
132 /*
133  * Set prefix for prints: Phy variant
134  */
135 void bs_trace_set_prefix_phy(const char* prefix);
136 
137 /*
138  * Set prefix for prints: device variant
139  */
140 void bs_trace_set_prefix_dev(int device_nbr);
141 
142 /*
143  * Exit without printing an error message
144  */
145 void bs_trace_silent_exit(uint8_t code);
146 
147 typedef enum {BS_TRACE_EXIT = 0, /*To Stdout, with EXIT prefix*/
148               BS_TRACE_ERROR,    /*To Stderr, with ERROR prefix*/
149               BS_TRACE_WARNING,  /*To Stderr, with WARNING prefix*/
150               BS_TRACE_INFO,     /*To Stdout, with INFO prefix*/
151               BS_TRACE_DEBUG,    /*To Stdout, with DEBUG prefix*/
152               BS_TRACE_RAW,      /*To Stdout, no extra prefix */
153               } base_trace_type_t;
154 typedef enum { BS_TRACE_NOTIME = 0, BS_TRACE_TIME_PROVIDED, BS_TRACE_AUTOTIME} base_trace_timed_type_t;
155 
156 /*
157  * Underlying functions for the bs_trace_ macros.
158  *
159  * It is recommended to use the bs_trace_ macros defined below instead
160  */
161 void bs_trace_print(base_trace_type_t type,
162                     const char *caller_filename, unsigned int caller_line,
163                     int this_message_trace_level,
164                     base_trace_timed_type_t time_type, bs_time_t time,
165                     const char *format, ...);
166 void bs_trace_vprint(base_trace_type_t type,
167                      const char *caller_filename, unsigned int caller_line,
168                      int this_message_trace_level,
169                      base_trace_timed_type_t time_type, bs_time_t time,
170                      const char *format, va_list variable_args);
171 
172 #define bs_trace_exit(...)                  do { bs_trace_print(BS_TRACE_EXIT   ,NULL,    0,       5,BS_TRACE_NOTIME,       0,__VA_ARGS__); \
173                                                BS_UNREACHABLE; } while(0)
174 #define bs_trace_exit_line(...)             do { bs_trace_print(BS_TRACE_EXIT   ,__FILE__,__LINE__,5,BS_TRACE_NOTIME,       0,__VA_ARGS__); \
175                                                BS_UNREACHABLE; } while(0)
176 #define bs_trace_exit_line_time(...)        do { bs_trace_print(BS_TRACE_EXIT   ,__FILE__,__LINE__,5,BS_TRACE_AUTOTIME,     0,__VA_ARGS__); \
177                                                BS_UNREACHABLE; } while(0)
178 #define bs_trace_exit_time_line(...)        do { bs_trace_print(BS_TRACE_EXIT   ,__FILE__,__LINE__,5,BS_TRACE_AUTOTIME,     0,__VA_ARGS__); \
179                                                BS_UNREACHABLE; } while(0)
180 #define bs_trace_exit_time(...)             do { bs_trace_print(BS_TRACE_EXIT   ,NULL,    0,       5,BS_TRACE_AUTOTIME,     0,__VA_ARGS__); \
181                                                BS_UNREACHABLE; } while(0)
182 
183 #define bs_trace_error(...)                 do { bs_trace_print(BS_TRACE_ERROR  ,NULL,    0,       0,BS_TRACE_NOTIME,       0,__VA_ARGS__); \
184                                                BS_UNREACHABLE; } while(0)
185 #define bs_trace_error_line(...)            do { bs_trace_print(BS_TRACE_ERROR  ,__FILE__,__LINE__,0,BS_TRACE_NOTIME,       0,__VA_ARGS__); \
186                                                BS_UNREACHABLE; } while(0)
187 #define bs_trace_error_line_time(...)       do { bs_trace_print(BS_TRACE_ERROR  ,__FILE__,__LINE__,0,BS_TRACE_AUTOTIME,     0,__VA_ARGS__); \
188                                                BS_UNREACHABLE; } while(0)
189 #define bs_trace_error_time_line(...)       do { bs_trace_print(BS_TRACE_ERROR  ,__FILE__,__LINE__,0,BS_TRACE_AUTOTIME,     0,__VA_ARGS__); \
190                                                BS_UNREACHABLE; } while(0)
191 #define bs_trace_error_time(...)            do { bs_trace_print(BS_TRACE_ERROR  ,NULL,    0,       0,BS_TRACE_AUTOTIME,     0,__VA_ARGS__); \
192                                                BS_UNREACHABLE; } while(0)
193 #define bs_trace_error_manual_time(t,...)   do { bs_trace_print(BS_TRACE_ERROR  ,NULL,    0,       0,BS_TRACE_TIME_PROVIDED,t,__VA_ARGS__); \
194                                                BS_UNREACHABLE; } while(0)
195 
196 #define bs_trace_warning(...)               bs_trace_print(BS_TRACE_WARNING,NULL,    0,       0,BS_TRACE_NOTIME,       0,__VA_ARGS__)
197 #define bs_trace_warning_line(...)          bs_trace_print(BS_TRACE_WARNING,__FILE__,__LINE__,0,BS_TRACE_NOTIME,       0,__VA_ARGS__)
198 #define bs_trace_warning_line_time(...)     bs_trace_print(BS_TRACE_WARNING,__FILE__,__LINE__,0,BS_TRACE_AUTOTIME,     0,__VA_ARGS__)
199 #define bs_trace_warning_time_line(...)     bs_trace_print(BS_TRACE_WARNING,__FILE__,__LINE__,0,BS_TRACE_AUTOTIME,     0,__VA_ARGS__)
200 #define bs_trace_warning_time(...)          bs_trace_print(BS_TRACE_WARNING,NULL,    0,       0,BS_TRACE_AUTOTIME,     0,__VA_ARGS__)
201 #define bs_trace_warning_manual_time(t,...) bs_trace_print(BS_TRACE_WARNING  ,NULL,    0,       0,BS_TRACE_TIME_PROVIDED,t,__VA_ARGS__)
202 #define bs_trace_warning_manual_time_line(t,...) bs_trace_print(BS_TRACE_WARNING  ,__FILE__,__LINE__,       0,BS_TRACE_TIME_PROVIDED,t,__VA_ARGS__)
203 
204 #define bs_trace_info(l,...)                bs_trace_print(BS_TRACE_INFO   ,NULL,    0,       l,BS_TRACE_NOTIME,       0,__VA_ARGS__)
205 #define bs_trace_info_line(l,...)           bs_trace_print(BS_TRACE_INFO   ,__FILE__,__LINE__,l,BS_TRACE_NOTIME,       0,__VA_ARGS__)
206 #define bs_trace_info_line_time(l,...)      bs_trace_print(BS_TRACE_INFO   ,__FILE__,__LINE__,l,BS_TRACE_AUTOTIME,     0,__VA_ARGS__)
207 #define bs_trace_info_time_line(l,...)      bs_trace_print(BS_TRACE_INFO   ,__FILE__,__LINE__,l,BS_TRACE_AUTOTIME,     0,__VA_ARGS__)
208 #define bs_trace_info_time(l,...)           bs_trace_print(BS_TRACE_INFO   ,NULL,    0,       l,BS_TRACE_AUTOTIME,     0,__VA_ARGS__)
209 
210 #define bs_trace_debug(l,...)               bs_trace_print(BS_TRACE_DEBUG  ,NULL,    0,       l,BS_TRACE_NOTIME,       0,__VA_ARGS__)
211 #define bs_trace_debug_line(l,...)          bs_trace_print(BS_TRACE_DEBUG  ,__FILE__,__LINE__,l,BS_TRACE_NOTIME,       0,__VA_ARGS__)
212 #define bs_trace_debug_line_time(l,...)     bs_trace_print(BS_TRACE_DEBUG  ,__FILE__,__LINE__,l,BS_TRACE_AUTOTIME,     0,__VA_ARGS__)
213 #define bs_trace_debug_time_line(l,...)     bs_trace_print(BS_TRACE_DEBUG  ,__FILE__,__LINE__,l,BS_TRACE_AUTOTIME,     0,__VA_ARGS__)
214 #define bs_trace_debug_time(l,...)          bs_trace_print(BS_TRACE_DEBUG  ,NULL,    0,       l,BS_TRACE_AUTOTIME,     0,__VA_ARGS__)
215 
216 #define bs_trace_raw(l,...)                 bs_trace_print(BS_TRACE_RAW    ,NULL,    0,       l,BS_TRACE_NOTIME,       0,__VA_ARGS__)
217 #define bs_trace_raw_line(l,...)            bs_trace_print(BS_TRACE_RAW    ,__FILE__,__LINE__,l,BS_TRACE_NOTIME,       0,__VA_ARGS__)
218 #define bs_trace_raw_line_time(l,...)       bs_trace_print(BS_TRACE_RAW    ,__FILE__,__LINE__,l,BS_TRACE_AUTOTIME,     0,__VA_ARGS__)
219 #define bs_trace_raw_time_line(l,...)       bs_trace_print(BS_TRACE_RAW    ,__FILE__,__LINE__,l,BS_TRACE_AUTOTIME,     0,__VA_ARGS__)
220 #define bs_trace_raw_time(l,...)            bs_trace_print(BS_TRACE_RAW    ,NULL,    0,       l,BS_TRACE_AUTOTIME,     0,__VA_ARGS__)
221 #define bs_trace_raw_manual_time(l,t,...)   bs_trace_print(BS_TRACE_RAW    ,NULL,    0,       l,BS_TRACE_TIME_PROVIDED,t,__VA_ARGS__)
222 
223 #ifdef __cplusplus
224 }
225 #endif
226 
227 #endif /* UTIL_BS_TRACING_H */
228