esp_event_cxx.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // Copyright 2019 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. #include "esp_event_cxx.hpp"
  14. #ifdef __cpp_exceptions
  15. using namespace idf::event;
  16. using namespace std;
  17. namespace idf {
  18. namespace event {
  19. const std::chrono::milliseconds PLATFORM_MAX_DELAY_MS(portMAX_DELAY *portTICK_PERIOD_MS);
  20. ESPEventReg::ESPEventReg(std::function<void(const ESPEvent &, void*)> cb,
  21. const ESPEvent& ev,
  22. std::shared_ptr<ESPEventAPI> api)
  23. : cb(cb), event(ev), api(api)
  24. {
  25. if (!cb) throw EventException(ESP_ERR_INVALID_ARG);
  26. if (!api) throw EventException(ESP_ERR_INVALID_ARG);
  27. esp_err_t reg_result = api->handler_register(ev.base, ev.id.get_id(), event_handler_hook, this, &instance);
  28. if (reg_result != ESP_OK) {
  29. throw ESPEventRegisterException(reg_result, event);
  30. }
  31. }
  32. ESPEventReg::~ESPEventReg()
  33. {
  34. api->handler_unregister(event.base, event.id.get_id(), instance);
  35. }
  36. void ESPEventReg::dispatch_event_handling(ESPEvent event, void *event_data)
  37. {
  38. cb(event, event_data);
  39. }
  40. void ESPEventReg::event_handler_hook(void *handler_arg,
  41. esp_event_base_t event_base,
  42. int32_t event_id,
  43. void *event_data)
  44. {
  45. ESPEventReg *object = static_cast<ESPEventReg*>(handler_arg);
  46. object->dispatch_event_handling(ESPEvent(event_base, ESPEventID(event_id)), event_data);
  47. }
  48. ESPEventRegTimed::ESPEventRegTimed(std::function<void(const ESPEvent &, void*)> cb,
  49. const ESPEvent& ev,
  50. std::function<void(const ESPEvent &)> timeout_cb,
  51. const std::chrono::microseconds &timeout,
  52. std::shared_ptr<ESPEventAPI> api)
  53. : ESPEventReg(cb, ev, api), timeout_cb(timeout_cb)
  54. {
  55. if (!timeout_cb || timeout < MIN_TIMEOUT) {
  56. throw EventException(ESP_ERR_INVALID_ARG);
  57. }
  58. const esp_timer_create_args_t oneshot_timer_args {
  59. timer_cb_hook,
  60. static_cast<void*>(this),
  61. ESP_TIMER_TASK,
  62. "event",
  63. false // skip_unhandled_events
  64. };
  65. esp_err_t res = esp_timer_create(&oneshot_timer_args, &timer);
  66. if (res != ESP_OK) {
  67. throw EventException(res);
  68. }
  69. esp_err_t timer_result = esp_timer_start_once(timer, timeout.count());
  70. if (timer_result != ESP_OK) {
  71. esp_timer_delete(timer);
  72. throw EventException(timer_result);
  73. }
  74. }
  75. ESPEventRegTimed::~ESPEventRegTimed()
  76. {
  77. std::lock_guard<mutex> guard(timeout_mutex);
  78. esp_timer_stop(timer);
  79. esp_timer_delete(timer);
  80. // TODO: is it guaranteed that there is no pending timer callback for timer?
  81. }
  82. void ESPEventRegTimed::dispatch_event_handling(ESPEvent event, void *event_data)
  83. {
  84. if (timeout_mutex.try_lock()) {
  85. esp_timer_stop(timer);
  86. cb(event, event_data);
  87. timeout_mutex.unlock();
  88. }
  89. }
  90. void ESPEventRegTimed::timer_cb_hook(void *arg)
  91. {
  92. ESPEventRegTimed *object = static_cast<ESPEventRegTimed *>(arg);
  93. if (object->timeout_mutex.try_lock()) {
  94. object->timeout_cb(object->event);
  95. object->api->handler_unregister(object->event.base, object->event.id.get_id(), object->instance);
  96. object->timeout_mutex.unlock();
  97. }
  98. }
  99. ESPEventLoop::ESPEventLoop(std::shared_ptr<ESPEventAPI> api) : api(api) {
  100. if (!api) throw EventException(ESP_ERR_INVALID_ARG);
  101. }
  102. ESPEventLoop::~ESPEventLoop() { }
  103. unique_ptr<ESPEventReg> ESPEventLoop::register_event(const ESPEvent &event,
  104. function<void(const ESPEvent &, void*)> cb)
  105. {
  106. return unique_ptr<ESPEventReg>(new ESPEventReg(cb, event, api));
  107. }
  108. std::unique_ptr<ESPEventRegTimed> ESPEventLoop::register_event_timed(const ESPEvent &event,
  109. std::function<void(const ESPEvent &, void*)> cb,
  110. const std::chrono::microseconds &timeout,
  111. std::function<void(const ESPEvent &)> timer_cb)
  112. {
  113. return std::unique_ptr<ESPEventRegTimed>(new ESPEventRegTimed(cb, event, timer_cb, timeout, api));
  114. }
  115. void ESPEventLoop::post_event_data(const ESPEvent &event,
  116. const chrono::milliseconds &wait_time)
  117. {
  118. esp_err_t result = api->post(event.base,
  119. event.id.get_id(),
  120. nullptr,
  121. 0,
  122. convert_ms_to_ticks(wait_time));
  123. if (result != ESP_OK) {
  124. throw ESPException(result);
  125. }
  126. }
  127. ESPEventHandlerSync::ESPEventHandlerSync(std::shared_ptr<ESPEventLoop> event_loop,
  128. size_t queue_max_size,
  129. TickType_t queue_send_timeout)
  130. : send_queue_errors(0),
  131. queue_send_timeout(queue_send_timeout),
  132. event_loop(event_loop)
  133. {
  134. if (!event_loop) throw EventException(ESP_ERR_INVALID_ARG);
  135. if (queue_max_size < 1) throw EventException(ESP_ERR_INVALID_ARG);
  136. event_queue = xQueueCreate(queue_max_size, sizeof(EventResult));
  137. if (event_queue == nullptr) {
  138. esp_event_loop_delete_default();
  139. throw EventException(ESP_FAIL);
  140. }
  141. }
  142. ESPEventHandlerSync::~ESPEventHandlerSync()
  143. {
  144. vQueueDelete(event_queue);
  145. }
  146. ESPEventHandlerSync::EventResult ESPEventHandlerSync::wait_event()
  147. {
  148. EventResult event_result;
  149. BaseType_t result = pdFALSE;
  150. while (result != pdTRUE) {
  151. result = xQueueReceive(event_queue, &event_result, convert_ms_to_ticks(PLATFORM_MAX_DELAY_MS));
  152. }
  153. return event_result;
  154. }
  155. ESPEventHandlerSync::EventResultTimed ESPEventHandlerSync::wait_event_for(const std::chrono::milliseconds &timeout)
  156. {
  157. EventResult event_result;
  158. BaseType_t result = xQueueReceive(event_queue, &event_result, convert_ms_to_ticks(timeout));
  159. EventResultTimed event_result_timed(event_result, result != pdTRUE);
  160. return event_result_timed;
  161. }
  162. void ESPEventHandlerSync::listen_to(const ESPEvent &event)
  163. {
  164. std::shared_ptr<ESPEventReg> reg = event_loop->register_event(event, [this](const ESPEvent &event, void *data) {
  165. EventResult result(event, data);
  166. post_event(result);
  167. });
  168. registry.push_back(reg);
  169. }
  170. void ESPEventHandlerSync::post_event(const EventResult &event_result)
  171. {
  172. BaseType_t result = xQueueSendToBack(event_queue, (void *) &event_result, queue_send_timeout);
  173. if (result != pdTRUE) {
  174. ++send_queue_errors;
  175. }
  176. }
  177. size_t ESPEventHandlerSync::get_send_queue_errors() const
  178. {
  179. return send_queue_errors;
  180. }
  181. TickType_t convert_ms_to_ticks(const std::chrono::milliseconds &time)
  182. {
  183. return time.count() / portTICK_PERIOD_MS;
  184. }
  185. } // namespace event
  186. } // namespace idf
  187. #endif // __cpp_exceptions