esp_uart_spinel_interface.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. // Copyright 2021 Espressif Systems (Shanghai) CO 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_uart_spinel_interface.hpp"
  14. #include <errno.h>
  15. #include <fcntl.h>
  16. #include <sys/select.h>
  17. #include <sys/unistd.h>
  18. #include "esp_check.h"
  19. #include "esp_err.h"
  20. #include "esp_log.h"
  21. #include "esp_openthread_common_macro.h"
  22. #include "esp_openthread_types.h"
  23. #include "esp_openthread_uart.h"
  24. #include "esp_vfs_dev.h"
  25. #include "core/common/code_utils.hpp"
  26. #include "core/common/logging.hpp"
  27. #include "driver/uart.h"
  28. #include "lib/platform/exit_code.h"
  29. #include "openthread/platform/time.h"
  30. namespace esp {
  31. namespace openthread {
  32. UartSpinelInterface::UartSpinelInterface(
  33. ot::Spinel::SpinelInterface::ReceiveFrameCallback callback,
  34. void *callback_context,
  35. ot::Spinel::SpinelInterface::RxFrameBuffer &frame_buffer)
  36. : m_receiver_frame_callback(callback)
  37. , m_receiver_frame_context(callback_context)
  38. , m_receive_frame_buffer(frame_buffer)
  39. , m_hdlc_decoder(frame_buffer, HandleHdlcFrame, this)
  40. , m_uart_fd(-1)
  41. {
  42. }
  43. UartSpinelInterface::~UartSpinelInterface(void)
  44. {
  45. }
  46. esp_err_t UartSpinelInterface::Init(const esp_openthread_uart_config_t &radio_uart_config)
  47. {
  48. m_uart_rx_buffer = static_cast<uint8_t *>(heap_caps_malloc(kMaxFrameSize, MALLOC_CAP_8BIT));
  49. if (m_uart_rx_buffer == NULL) {
  50. return ESP_ERR_NO_MEM;
  51. }
  52. return InitUart(radio_uart_config);
  53. }
  54. esp_err_t UartSpinelInterface::Deinit(void)
  55. {
  56. if (m_uart_rx_buffer) {
  57. heap_caps_free(m_uart_rx_buffer);
  58. }
  59. m_uart_rx_buffer = NULL;
  60. return DeinitUart();
  61. }
  62. otError UartSpinelInterface::SendFrame(const uint8_t *frame, uint16_t length)
  63. {
  64. otError error = OT_ERROR_NONE;
  65. ot::Hdlc::FrameBuffer<kMaxFrameSize> encoder_buffer;
  66. ot::Hdlc::Encoder hdlc_encoder(encoder_buffer);
  67. SuccessOrExit(error = hdlc_encoder.BeginFrame());
  68. SuccessOrExit(error = hdlc_encoder.Encode(frame, length));
  69. SuccessOrExit(error = hdlc_encoder.EndFrame());
  70. SuccessOrExit(error = Write(encoder_buffer.GetFrame(), encoder_buffer.GetLength()));
  71. exit:
  72. if (error != OT_ERROR_NONE) {
  73. otLogCritPlat("send radio frame failed");
  74. } else {
  75. otLogDebgPlat("sent radio frame");
  76. }
  77. return error;
  78. }
  79. void UartSpinelInterface::Process(const esp_openthread_mainloop_context_t &mainloop)
  80. {
  81. if (FD_ISSET(m_uart_fd, &mainloop.read_fds)) {
  82. otLogDebgPlat("radio uart read event");
  83. TryReadAndDecode();
  84. }
  85. }
  86. void UartSpinelInterface::Update(esp_openthread_mainloop_context_t &mainloop)
  87. {
  88. // Register only READ events for radio UART and always wait
  89. // for a radio WRITE to complete.
  90. FD_SET(m_uart_fd, &mainloop.read_fds);
  91. if (m_uart_fd > mainloop.max_fd) {
  92. mainloop.max_fd = m_uart_fd;
  93. }
  94. }
  95. int UartSpinelInterface::TryReadAndDecode(void)
  96. {
  97. uint8_t buffer[UART_FIFO_LEN];
  98. ssize_t rval;
  99. do {
  100. rval = read(m_uart_fd, buffer, sizeof(buffer));
  101. if (rval > 0) {
  102. m_hdlc_decoder.Decode(buffer, static_cast<uint16_t>(rval));
  103. }
  104. } while (rval > 0);
  105. if ((rval < 0) && (errno != EAGAIN) && (errno != EWOULDBLOCK)) {
  106. ESP_ERROR_CHECK(TryRecoverUart());
  107. }
  108. return rval;
  109. }
  110. otError UartSpinelInterface::WaitForWritable(void)
  111. {
  112. otError error = OT_ERROR_NONE;
  113. struct timeval timeout = {kMaxWaitTime / MS_PER_S, (kMaxWaitTime % MS_PER_S) *US_PER_MS};
  114. uint64_t now = otPlatTimeGet();
  115. uint64_t end = now + kMaxWaitTime * US_PER_MS;
  116. fd_set write_fds;
  117. fd_set error_fds;
  118. int rval;
  119. while (true) {
  120. FD_ZERO(&write_fds);
  121. FD_ZERO(&error_fds);
  122. FD_SET(m_uart_fd, &write_fds);
  123. FD_SET(m_uart_fd, &error_fds);
  124. rval = select(m_uart_fd + 1, NULL, &write_fds, &error_fds, &timeout);
  125. if (rval > 0) {
  126. if (FD_ISSET(m_uart_fd, &write_fds)) {
  127. ExitNow();
  128. } else if (FD_ISSET(m_uart_fd, &error_fds)) {
  129. ExitNow(error = OT_ERROR_FAILED);
  130. }
  131. } else if ((rval < 0) && (errno != EINTR)) {
  132. ESP_ERROR_CHECK(TryRecoverUart());
  133. ExitNow(error = OT_ERROR_FAILED);
  134. }
  135. now = otPlatTimeGet();
  136. if (end > now) {
  137. uint64_t remain = end - now;
  138. timeout.tv_sec = static_cast<time_t>(remain / 1000000);
  139. timeout.tv_usec = static_cast<suseconds_t>(remain % 1000000);
  140. } else {
  141. break;
  142. }
  143. }
  144. error = OT_ERROR_FAILED;
  145. exit:
  146. return error;
  147. }
  148. otError UartSpinelInterface::Write(const uint8_t *aFrame, uint16_t length)
  149. {
  150. otError error = OT_ERROR_NONE;
  151. while (length) {
  152. ssize_t rval;
  153. rval = write(m_uart_fd, aFrame, length);
  154. if (rval > 0) {
  155. assert(rval <= length);
  156. length -= static_cast<uint16_t>(rval);
  157. aFrame += static_cast<uint16_t>(rval);
  158. continue;
  159. } else if (rval < 0) {
  160. ESP_ERROR_CHECK(TryRecoverUart());
  161. ExitNow(error = OT_ERROR_FAILED);
  162. }
  163. SuccessOrExit(error = WaitForWritable());
  164. }
  165. exit:
  166. return error;
  167. }
  168. otError UartSpinelInterface::WaitForFrame(uint64_t timeout_us)
  169. {
  170. otError error = OT_ERROR_NONE;
  171. struct timeval timeout;
  172. fd_set read_fds;
  173. fd_set error_fds;
  174. int rval;
  175. FD_ZERO(&read_fds);
  176. FD_ZERO(&error_fds);
  177. FD_SET(m_uart_fd, &read_fds);
  178. FD_SET(m_uart_fd, &error_fds);
  179. timeout.tv_sec = static_cast<time_t>(timeout_us / US_PER_S);
  180. timeout.tv_usec = static_cast<suseconds_t>(timeout_us % US_PER_S);
  181. rval = select(m_uart_fd + 1, &read_fds, NULL, &error_fds, &timeout);
  182. if (rval > 0) {
  183. if (FD_ISSET(m_uart_fd, &read_fds)) {
  184. TryReadAndDecode();
  185. } else if (FD_ISSET(m_uart_fd, &error_fds)) {
  186. ESP_ERROR_CHECK(TryRecoverUart());
  187. ExitNow(error = OT_ERROR_FAILED);
  188. }
  189. } else if (rval == 0) {
  190. ExitNow(error = OT_ERROR_RESPONSE_TIMEOUT);
  191. } else {
  192. ESP_ERROR_CHECK(TryRecoverUart());
  193. ExitNow(error = OT_ERROR_FAILED);
  194. }
  195. exit:
  196. return error;
  197. }
  198. void UartSpinelInterface::HandleHdlcFrame(void *context, otError error)
  199. {
  200. static_cast<UartSpinelInterface *>(context)->HandleHdlcFrame(error);
  201. }
  202. void UartSpinelInterface::HandleHdlcFrame(otError error)
  203. {
  204. if (error == OT_ERROR_NONE) {
  205. otLogDebgPlat("received hdlc radio frame");
  206. m_receiver_frame_callback(m_receiver_frame_context);
  207. } else {
  208. otLogCritPlat("dropping radio frame: %s", otThreadErrorToString(error));
  209. m_receive_frame_buffer.DiscardFrame();
  210. }
  211. }
  212. esp_err_t UartSpinelInterface::InitUart(const esp_openthread_uart_config_t &radio_uart_config)
  213. {
  214. char uart_path[16];
  215. m_uart_config = radio_uart_config;
  216. ESP_RETURN_ON_ERROR(esp_openthread_uart_init_port(&radio_uart_config), OT_PLAT_LOG_TAG,
  217. "esp_openthread_uart_init_port failed");
  218. // We have a driver now installed so set up the read/write functions to use driver also.
  219. esp_vfs_dev_uart_port_set_tx_line_endings(m_uart_config.port, ESP_LINE_ENDINGS_LF);
  220. esp_vfs_dev_uart_port_set_rx_line_endings(m_uart_config.port, ESP_LINE_ENDINGS_LF);
  221. snprintf(uart_path, sizeof(uart_path), "/dev/uart/%d", radio_uart_config.port);
  222. m_uart_fd = open(uart_path, O_RDWR | O_NONBLOCK);
  223. return m_uart_fd >= 0 ? ESP_OK : ESP_FAIL;
  224. }
  225. esp_err_t UartSpinelInterface::DeinitUart(void)
  226. {
  227. if (m_uart_fd != -1) {
  228. close(m_uart_fd);
  229. m_uart_fd = -1;
  230. return uart_driver_delete(m_uart_config.port);
  231. } else {
  232. return ESP_ERR_INVALID_STATE;
  233. }
  234. }
  235. esp_err_t UartSpinelInterface::TryRecoverUart(void)
  236. {
  237. ESP_RETURN_ON_ERROR(DeinitUart(), OT_PLAT_LOG_TAG, "DeInitUart failed");
  238. ESP_RETURN_ON_ERROR(InitUart(m_uart_config), OT_PLAT_LOG_TAG, "InitUart failed");
  239. return ESP_OK;
  240. }
  241. } // namespace openthread
  242. } // namespace esp