/ components / app_trace / app_trace_util.c
app_trace_util.c
  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  #endif
 26  
 27  ///////////////////////////////////////////////////////////////////////////////
 28  ///////////////////////////////// TIMEOUT /////////////////////////////////////
 29  ///////////////////////////////////////////////////////////////////////////////
 30  
 31  #define ESP_APPTRACE_CPUTICKS2US(_t_, _cpu_freq_)       ((_t_)/(_cpu_freq_/1000000))
 32  #define ESP_APPTRACE_US2CPUTICKS(_t_, _cpu_freq_)       ((_t_)*(_cpu_freq_/1000000))
 33  
 34  esp_err_t esp_apptrace_tmo_check(esp_apptrace_tmo_t *tmo)
 35  {
 36      int cpu_freq = esp_clk_cpu_freq();
 37      if (tmo->tmo != ESP_APPTRACE_TMO_INFINITE) {
 38          unsigned cur = portGET_RUN_TIME_COUNTER_VALUE();
 39          if (tmo->start <= cur) {
 40              tmo->elapsed = ESP_APPTRACE_CPUTICKS2US(cur - tmo->start, cpu_freq);
 41          } else {
 42              tmo->elapsed = ESP_APPTRACE_CPUTICKS2US(0xFFFFFFFF - tmo->start + cur, cpu_freq);
 43          }
 44          if (tmo->elapsed >= tmo->tmo) {
 45              return ESP_ERR_TIMEOUT;
 46          }
 47      }
 48      return ESP_OK;
 49  }
 50  
 51  ///////////////////////////////////////////////////////////////////////////////
 52  ///////////////////////////////// LOCK ////////////////////////////////////////
 53  ///////////////////////////////////////////////////////////////////////////////
 54  
 55  esp_err_t esp_apptrace_lock_take(esp_apptrace_lock_t *lock, esp_apptrace_tmo_t *tmo)
 56  {
 57      int res;
 58  
 59      while (1) {
 60          // do not overwrite lock->int_state before we actually acquired the mux
 61          unsigned int_state = portENTER_CRITICAL_NESTED();
 62          // FIXME: if mux is busy it is not good idea to loop during the whole tmo with disabled IRQs.
 63          // So we check mux state using zero tmo, restore IRQs and let others tasks/IRQs to run on this CPU
 64          // while we are doing our own tmo check.
 65  #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
 66          bool success = vPortCPUAcquireMutexTimeout(&lock->mux, 0, __FUNCTION__, __LINE__);
 67  #else
 68          bool success = vPortCPUAcquireMutexTimeout(&lock->mux, 0);
 69  #endif
 70          if (success) {
 71              lock->int_state = int_state;
 72              return ESP_OK;
 73          }
 74          portEXIT_CRITICAL_NESTED(int_state);
 75          // we can be preempted from this place till the next call (above) to portENTER_CRITICAL_NESTED()
 76          res = esp_apptrace_tmo_check(tmo);
 77          if (res != ESP_OK) {
 78              break;
 79          }
 80      }
 81      return res;
 82  }
 83  
 84  esp_err_t esp_apptrace_lock_give(esp_apptrace_lock_t *lock)
 85  {
 86      // save lock's irq state value for this CPU
 87      unsigned int_state = lock->int_state;
 88      // after call to the following func we can not be sure that lock->int_state
 89      // is not overwritten by other CPU who has acquired the mux just after we released it. See esp_apptrace_lock_take().
 90  #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
 91      vPortCPUReleaseMutex(&lock->mux, __FUNCTION__, __LINE__);
 92  #else
 93      vPortCPUReleaseMutex(&lock->mux);
 94  #endif
 95      portEXIT_CRITICAL_NESTED(int_state);
 96      return ESP_OK;
 97  }
 98  
 99  ///////////////////////////////////////////////////////////////////////////////
100  ////////////////////////////// RING BUFFER ////////////////////////////////////
101  ///////////////////////////////////////////////////////////////////////////////
102  
103  uint8_t *esp_apptrace_rb_produce(esp_apptrace_rb_t *rb, uint32_t size)
104  {
105      uint8_t *ptr = rb->data + rb->wr;
106      // check for avalable space
107      if (rb->rd <= rb->wr) {
108          // |?R......W??|
109          if (rb->wr + size >= rb->size) {
110              if (rb->rd == 0) {
111                  return NULL; // cannot wrap wr
112              }
113              if (rb->wr + size == rb->size) {
114                  rb->wr = 0;
115              } else {
116                  // check if we can wrap wr earlier to get space for requested size
117                  if (size > rb->rd - 1) {
118                      return NULL; // cannot wrap wr
119                  }
120                  // shrink buffer a bit, full size will be restored at rd wrapping
121                  rb->cur_size = rb->wr;
122                  rb->wr = 0;
123                  ptr = rb->data;
124                  if (rb->rd == rb->cur_size) {
125                      rb->rd = 0;
126                      if (rb->cur_size < rb->size) {
127                          rb->cur_size = rb->size;
128                      }
129                  }
130                  rb->wr += size;
131              }
132          } else {
133              rb->wr += size;
134          }
135      } else {
136          // |?W......R??|
137          if (size > rb->rd - rb->wr - 1) {
138              return NULL;
139          }
140          rb->wr += size;
141      }
142      return ptr;
143  }
144  
145  uint8_t *esp_apptrace_rb_consume(esp_apptrace_rb_t *rb, uint32_t size)
146  {
147      uint8_t *ptr = rb->data + rb->rd;
148      if (rb->rd <= rb->wr) {
149          // |?R......W??|
150          if (rb->rd + size > rb->wr) {
151              return NULL;
152          }
153          rb->rd += size;
154      } else {
155          // |?W......R??|
156          if (rb->rd + size > rb->cur_size) {
157              return NULL;
158          } else if (rb->rd + size == rb->cur_size) {
159              // restore full size usage
160              if (rb->cur_size < rb->size) {
161                  rb->cur_size = rb->size;
162              }
163              rb->rd = 0;
164          } else {
165              rb->rd += size;
166          }
167      }
168      return ptr;
169  }
170  
171  uint32_t esp_apptrace_rb_read_size_get(esp_apptrace_rb_t *rb)
172  {
173      uint32_t size = 0;
174      if (rb->rd <= rb->wr) {
175          // |?R......W??|
176          size = rb->wr - rb->rd;
177      } else {
178          // |?W......R??|
179          size = rb->cur_size - rb->rd;
180      }
181      return size;
182  }
183  
184  uint32_t esp_apptrace_rb_write_size_get(esp_apptrace_rb_t *rb)
185  {
186      uint32_t size = 0;
187      if (rb->rd <= rb->wr) {
188          // |?R......W??|
189          size = rb->size - rb->wr;
190          if (size && rb->rd == 0) {
191              size--;
192          }
193      } else {
194          // |?W......R??|
195          size = rb->rd - rb->wr - 1;
196      }
197      return size;
198  }