1 /*
2  * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #ifndef ESP_APP_TRACE_UTIL_H_
7 #define ESP_APP_TRACE_UTIL_H_
8 
9 #ifdef __cplusplus
10 extern "C" {
11 #endif
12 
13 #include "freertos/FreeRTOS.h"
14 #include "esp_err.h"
15 #include "esp_timer.h"
16 
17 /** Infinite waiting timeout */
18 #define ESP_APPTRACE_TMO_INFINITE               ((uint32_t)-1)
19 
20 /** Structure which holds data necessary for measuring time intervals.
21  *
22  *  After initialization via esp_apptrace_tmo_init() user needs to call esp_apptrace_tmo_check()
23  *  periodically to check timeout for expiration.
24  */
25 typedef struct {
26     int64_t   start;   ///< time interval start (in us)
27     int64_t   tmo;     ///< timeout value (in us)
28     int64_t   elapsed; ///< elapsed time (in us)
29 } esp_apptrace_tmo_t;
30 
31 /**
32  * @brief Initializes timeout structure.
33  *
34  * @param tmo       Pointer to timeout structure to be initialized.
35  * @param user_tmo  Timeout value (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
36 */
esp_apptrace_tmo_init(esp_apptrace_tmo_t * tmo,uint32_t user_tmo)37 static inline void esp_apptrace_tmo_init(esp_apptrace_tmo_t *tmo, uint32_t user_tmo)
38 {
39     tmo->start = esp_timer_get_time();
40     tmo->tmo = user_tmo == ESP_APPTRACE_TMO_INFINITE ? (int64_t)-1 : (int64_t)user_tmo;
41     tmo->elapsed = 0;
42 }
43 
44 /**
45  * @brief Checks timeout for expiration.
46  *
47  * @param tmo Pointer to timeout structure.
48  *
49  * @return number of remaining us till tmo.
50  */
51 esp_err_t esp_apptrace_tmo_check(esp_apptrace_tmo_t *tmo);
52 
esp_apptrace_tmo_remaining_us(esp_apptrace_tmo_t * tmo)53 static inline uint32_t esp_apptrace_tmo_remaining_us(esp_apptrace_tmo_t *tmo)
54 {
55     return tmo->tmo != (int64_t)-1 ? (tmo->elapsed - tmo->tmo) : ESP_APPTRACE_TMO_INFINITE;
56 }
57 
58 /** Tracing module synchronization lock */
59 typedef struct {
60     portMUX_TYPE mux;
61     unsigned int_state;
62 } esp_apptrace_lock_t;
63 
64 /**
65  * @brief Initializes lock structure.
66  *
67  * @param lock Pointer to lock structure to be initialized.
68  */
esp_apptrace_lock_init(esp_apptrace_lock_t * lock)69 static inline void esp_apptrace_lock_init(esp_apptrace_lock_t *lock)
70 {
71     portMUX_INITIALIZE(&lock->mux);
72     lock->int_state = 0;
73 }
74 
75 /**
76  * @brief Tries to acquire lock in specified time period.
77  *
78  * @param lock Pointer to lock structure.
79  * @param tmo  Pointer to timeout struct.
80  *
81  * @return ESP_OK on success, otherwise \see esp_err_t
82  */
83 esp_err_t esp_apptrace_lock_take(esp_apptrace_lock_t *lock, esp_apptrace_tmo_t *tmo);
84 
85 /**
86  * @brief Releases lock.
87  *
88  * @param lock Pointer to lock structure.
89  *
90  * @return ESP_OK on success, otherwise \see esp_err_t
91  */
92 esp_err_t esp_apptrace_lock_give(esp_apptrace_lock_t *lock);
93 
94 /** Ring buffer control structure.
95  *
96  * @note For purposes of application tracing module if there is no enough space for user data and write pointer can be wrapped
97  *       current ring buffer size can be temporarily shrinked in order to provide buffer with requested size.
98  */
99 typedef struct {
100     uint8_t *data;      ///< pointer to data storage
101     volatile uint32_t size;      ///< size of data storage
102     volatile uint32_t cur_size;  ///< current size of data storage
103     volatile uint32_t rd;        ///< read pointer
104     volatile uint32_t wr;        ///< write pointer
105 } esp_apptrace_rb_t;
106 
107 /**
108  * @brief Initializes ring buffer control  structure.
109  *
110  * @param rb   Pointer to ring buffer structure to be initialized.
111  * @param data Pointer to buffer to be used as ring buffer's data storage.
112  * @param size Size of buffer to be used as ring buffer's data storage.
113  */
esp_apptrace_rb_init(esp_apptrace_rb_t * rb,uint8_t * data,uint32_t size)114 static inline void esp_apptrace_rb_init(esp_apptrace_rb_t *rb, uint8_t *data, uint32_t size)
115 {
116     rb->data = data;
117     rb->size = rb->cur_size = size;
118     rb->rd = 0;
119     rb->wr = 0;
120 }
121 
122 /**
123  * @brief Allocates memory chunk in ring buffer.
124  *
125  * @param rb   Pointer to ring buffer structure.
126  * @param size Size of the memory to allocate.
127  *
128  * @return Pointer to the allocated memory or NULL in case of failure.
129  */
130 uint8_t *esp_apptrace_rb_produce(esp_apptrace_rb_t *rb, uint32_t size);
131 
132 /**
133  * @brief Consumes memory chunk in ring buffer.
134  *
135  * @param rb   Pointer to ring buffer structure.
136  * @param size Size of the memory to consume.
137  *
138  * @return Pointer to consumed memory chunk or NULL in case of failure.
139  */
140 uint8_t *esp_apptrace_rb_consume(esp_apptrace_rb_t *rb, uint32_t size);
141 
142 /**
143  * @brief Gets size of memory which can consumed with single call to esp_apptrace_rb_consume().
144  *
145  * @param rb Pointer to ring buffer structure.
146  *
147  * @return Size of memory which can consumed.
148  *
149  * @note Due to read pointer wrapping returned size can be less then the total size of available data.
150  */
151 uint32_t esp_apptrace_rb_read_size_get(esp_apptrace_rb_t *rb);
152 
153 /**
154  * @brief Gets size of memory which can produced with single call to esp_apptrace_rb_produce().
155  *
156  * @param rb Pointer to ring buffer structure.
157  *
158  * @return Size of memory which can produced.
159  *
160  * @note Due to write pointer wrapping returned size can be less then the total size of available data.
161  */
162 uint32_t esp_apptrace_rb_write_size_get(esp_apptrace_rb_t *rb);
163 
164 int esp_apptrace_log_lock(void);
165 void esp_apptrace_log_unlock(void);
166 
167 #define ESP_APPTRACE_LOG( format, ... )   \
168     do { \
169         esp_apptrace_log_lock(); \
170         esp_rom_printf(format, ##__VA_ARGS__); \
171         esp_apptrace_log_unlock(); \
172     } while(0)
173 
174 #define ESP_APPTRACE_LOG_LEV( _L_, level, format, ... )   \
175     do { \
176         if (LOG_LOCAL_LEVEL >= level) { \
177             ESP_APPTRACE_LOG(LOG_FORMAT(_L_, format), esp_log_early_timestamp(), TAG, ##__VA_ARGS__); \
178         } \
179     } while(0)
180 
181 #define ESP_APPTRACE_LOGE( format, ... )  ESP_APPTRACE_LOG_LEV(E, ESP_LOG_ERROR, format, ##__VA_ARGS__)
182 #define ESP_APPTRACE_LOGW( format, ... )  ESP_APPTRACE_LOG_LEV(W, ESP_LOG_WARN, format, ##__VA_ARGS__)
183 #define ESP_APPTRACE_LOGI( format, ... )  ESP_APPTRACE_LOG_LEV(I, ESP_LOG_INFO, format, ##__VA_ARGS__)
184 #define ESP_APPTRACE_LOGD( format, ... )  ESP_APPTRACE_LOG_LEV(D, ESP_LOG_DEBUG, format, ##__VA_ARGS__)
185 #define ESP_APPTRACE_LOGV( format, ... )  ESP_APPTRACE_LOG_LEV(V, ESP_LOG_VERBOSE, format, ##__VA_ARGS__)
186 #define ESP_APPTRACE_LOGO( format, ... )  ESP_APPTRACE_LOG_LEV(E, ESP_LOG_NONE, format, ##__VA_ARGS__)
187 
188 #ifdef __cplusplus
189 }
190 #endif
191 
192 #endif //ESP_APP_TRACE_UTIL_H_
193