1 // Copyright 2017 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 #include "freertos/FreeRTOS.h"
16 #include "freertos/task.h"
17 #include "esp_app_trace_util.h"
18 #include "sdkconfig.h"
19 #if CONFIG_IDF_TARGET_ESP32
20 #include "esp32/clk.h"
21 #elif CONFIG_IDF_TARGET_ESP32S2
22 #include "esp32s2/clk.h"
23 #elif CONFIG_IDF_TARGET_ESP32S3
24 #include "esp32s3/clk.h"
25 #elif CONFIG_IDF_TARGET_ESP32C3
26 #include "esp32c3/clk.h"
27 #endif
28
29 ///////////////////////////////////////////////////////////////////////////////
30 ///////////////////////////////// TIMEOUT /////////////////////////////////////
31 ///////////////////////////////////////////////////////////////////////////////
32
33 #define ESP_APPTRACE_CPUTICKS2US(_t_, _cpu_freq_) ((_t_)/(_cpu_freq_/1000000))
34 #define ESP_APPTRACE_US2CPUTICKS(_t_, _cpu_freq_) ((_t_)*(_cpu_freq_/1000000))
35
esp_apptrace_tmo_check(esp_apptrace_tmo_t * tmo)36 esp_err_t esp_apptrace_tmo_check(esp_apptrace_tmo_t *tmo)
37 {
38 int cpu_freq = esp_clk_cpu_freq();
39 if (tmo->tmo != ESP_APPTRACE_TMO_INFINITE) {
40 unsigned cur = portGET_RUN_TIME_COUNTER_VALUE();
41 if (tmo->start <= cur) {
42 tmo->elapsed = ESP_APPTRACE_CPUTICKS2US(cur - tmo->start, cpu_freq);
43 } else {
44 tmo->elapsed = ESP_APPTRACE_CPUTICKS2US(0xFFFFFFFF - tmo->start + cur, cpu_freq);
45 }
46 if (tmo->elapsed >= tmo->tmo) {
47 return ESP_ERR_TIMEOUT;
48 }
49 }
50 return ESP_OK;
51 }
52
53 ///////////////////////////////////////////////////////////////////////////////
54 ///////////////////////////////// LOCK ////////////////////////////////////////
55 ///////////////////////////////////////////////////////////////////////////////
56
esp_apptrace_lock_take(esp_apptrace_lock_t * lock,esp_apptrace_tmo_t * tmo)57 esp_err_t esp_apptrace_lock_take(esp_apptrace_lock_t *lock, esp_apptrace_tmo_t *tmo)
58 {
59 int res;
60
61 while (1) {
62 // do not overwrite lock->int_state before we actually acquired the mux
63 unsigned int_state = portENTER_CRITICAL_NESTED();
64 // FIXME: if mux is busy it is not good idea to loop during the whole tmo with disabled IRQs.
65 // So we check mux state using zero tmo, restore IRQs and let others tasks/IRQs to run on this CPU
66 // while we are doing our own tmo check.
67 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
68 bool success = vPortCPUAcquireMutexTimeout(&lock->mux, 0, __FUNCTION__, __LINE__);
69 #else
70 bool success = vPortCPUAcquireMutexTimeout(&lock->mux, 0);
71 #endif
72 if (success) {
73 lock->int_state = int_state;
74 return ESP_OK;
75 }
76 portEXIT_CRITICAL_NESTED(int_state);
77 // we can be preempted from this place till the next call (above) to portENTER_CRITICAL_NESTED()
78 res = esp_apptrace_tmo_check(tmo);
79 if (res != ESP_OK) {
80 break;
81 }
82 }
83 return res;
84 }
85
esp_apptrace_lock_give(esp_apptrace_lock_t * lock)86 esp_err_t esp_apptrace_lock_give(esp_apptrace_lock_t *lock)
87 {
88 // save lock's irq state value for this CPU
89 unsigned int_state = lock->int_state;
90 // after call to the following func we can not be sure that lock->int_state
91 // is not overwritten by other CPU who has acquired the mux just after we released it. See esp_apptrace_lock_take().
92 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
93 vPortCPUReleaseMutex(&lock->mux, __FUNCTION__, __LINE__);
94 #else
95 vPortCPUReleaseMutex(&lock->mux);
96 #endif
97 portEXIT_CRITICAL_NESTED(int_state);
98 return ESP_OK;
99 }
100
101 ///////////////////////////////////////////////////////////////////////////////
102 ////////////////////////////// RING BUFFER ////////////////////////////////////
103 ///////////////////////////////////////////////////////////////////////////////
104
esp_apptrace_rb_produce(esp_apptrace_rb_t * rb,uint32_t size)105 uint8_t *esp_apptrace_rb_produce(esp_apptrace_rb_t *rb, uint32_t size)
106 {
107 uint8_t *ptr = rb->data + rb->wr;
108 // check for avalable space
109 if (rb->rd <= rb->wr) {
110 // |?R......W??|
111 if (rb->wr + size >= rb->size) {
112 if (rb->rd == 0) {
113 return NULL; // cannot wrap wr
114 }
115 if (rb->wr + size == rb->size) {
116 rb->wr = 0;
117 } else {
118 // check if we can wrap wr earlier to get space for requested size
119 if (size > rb->rd - 1) {
120 return NULL; // cannot wrap wr
121 }
122 // shrink buffer a bit, full size will be restored at rd wrapping
123 rb->cur_size = rb->wr;
124 rb->wr = 0;
125 ptr = rb->data;
126 if (rb->rd == rb->cur_size) {
127 rb->rd = 0;
128 if (rb->cur_size < rb->size) {
129 rb->cur_size = rb->size;
130 }
131 }
132 rb->wr += size;
133 }
134 } else {
135 rb->wr += size;
136 }
137 } else {
138 // |?W......R??|
139 if (size > rb->rd - rb->wr - 1) {
140 return NULL;
141 }
142 rb->wr += size;
143 }
144 return ptr;
145 }
146
esp_apptrace_rb_consume(esp_apptrace_rb_t * rb,uint32_t size)147 uint8_t *esp_apptrace_rb_consume(esp_apptrace_rb_t *rb, uint32_t size)
148 {
149 uint8_t *ptr = rb->data + rb->rd;
150 if (rb->rd <= rb->wr) {
151 // |?R......W??|
152 if (rb->rd + size > rb->wr) {
153 return NULL;
154 }
155 rb->rd += size;
156 } else {
157 // |?W......R??|
158 if (rb->rd + size > rb->cur_size) {
159 return NULL;
160 } else if (rb->rd + size == rb->cur_size) {
161 // restore full size usage
162 if (rb->cur_size < rb->size) {
163 rb->cur_size = rb->size;
164 }
165 rb->rd = 0;
166 } else {
167 rb->rd += size;
168 }
169 }
170 return ptr;
171 }
172
esp_apptrace_rb_read_size_get(esp_apptrace_rb_t * rb)173 uint32_t esp_apptrace_rb_read_size_get(esp_apptrace_rb_t *rb)
174 {
175 uint32_t size = 0;
176 if (rb->rd <= rb->wr) {
177 // |?R......W??|
178 size = rb->wr - rb->rd;
179 } else {
180 // |?W......R??|
181 size = rb->cur_size - rb->rd;
182 }
183 return size;
184 }
185
esp_apptrace_rb_write_size_get(esp_apptrace_rb_t * rb)186 uint32_t esp_apptrace_rb_write_size_get(esp_apptrace_rb_t *rb)
187 {
188 uint32_t size = 0;
189 if (rb->rd <= rb->wr) {
190 // |?R......W??|
191 size = rb->size - rb->wr;
192 if (size && rb->rd == 0) {
193 size--;
194 }
195 } else {
196 // |?W......R??|
197 size = rb->rd - rb->wr - 1;
198 }
199 return size;
200 }
201