app_trace_util.c 6.4 KB

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