uart.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. #include "seos_i.h"
  2. #include "uart.h"
  3. #define TAG "SeosUART"
  4. #define SEOS_UART_BAUD 460800
  5. static void seos_uart_on_irq_rx_dma_cb(
  6. FuriHalSerialHandle* handle,
  7. FuriHalSerialRxEvent ev,
  8. size_t size,
  9. void* context) {
  10. SeosUart* seos_uart = (SeosUart*)context;
  11. if(ev & (FuriHalSerialRxEventData | FuriHalSerialRxEventIdle)) {
  12. uint8_t data[FURI_HAL_SERIAL_DMA_BUFFER_SIZE] = {0};
  13. while(size) {
  14. size_t ret = furi_hal_serial_dma_rx(
  15. handle,
  16. data,
  17. (size > FURI_HAL_SERIAL_DMA_BUFFER_SIZE) ? FURI_HAL_SERIAL_DMA_BUFFER_SIZE : size);
  18. furi_stream_buffer_send(seos_uart->rx_stream, data, ret, 0);
  19. size -= ret;
  20. };
  21. furi_thread_flags_set(furi_thread_get_id(seos_uart->thread), WorkerEvtRxDone);
  22. }
  23. }
  24. void seos_uart_disable(SeosUart* seos_uart) {
  25. furi_assert(seos_uart);
  26. furi_thread_flags_set(furi_thread_get_id(seos_uart->thread), WorkerEvtStop);
  27. furi_thread_join(seos_uart->thread);
  28. furi_thread_free(seos_uart->thread);
  29. free(seos_uart);
  30. }
  31. void seos_uart_serial_init(SeosUart* seos_uart, uint8_t uart_ch) {
  32. furi_assert(!seos_uart->serial_handle);
  33. SeosUartConfig cfg = seos_uart->cfg;
  34. seos_uart->serial_handle = furi_hal_serial_control_acquire(uart_ch);
  35. furi_assert(seos_uart->serial_handle);
  36. furi_hal_serial_init(seos_uart->serial_handle, cfg.baudrate);
  37. furi_hal_serial_dma_rx_start(
  38. seos_uart->serial_handle, seos_uart_on_irq_rx_dma_cb, seos_uart, false);
  39. }
  40. void seos_uart_serial_deinit(SeosUart* seos_uart) {
  41. furi_assert(seos_uart->serial_handle);
  42. furi_hal_serial_deinit(seos_uart->serial_handle);
  43. furi_hal_serial_control_release(seos_uart->serial_handle);
  44. seos_uart->serial_handle = NULL;
  45. }
  46. void seos_uart_set_baudrate(SeosUart* seos_uart, uint32_t baudrate) {
  47. if(baudrate != 0) {
  48. furi_hal_serial_set_br(seos_uart->serial_handle, baudrate);
  49. } else {
  50. FURI_LOG_I(TAG, "No baudrate specified");
  51. }
  52. }
  53. size_t seos_uart_process_buffer(SeosUart* seos_uart, uint8_t* cmd, size_t cmd_len) {
  54. if(cmd_len < 2) {
  55. return cmd_len;
  56. }
  57. size_t consumed = 0;
  58. do {
  59. if(seos_uart->receive_callback) {
  60. consumed =
  61. seos_uart->receive_callback(seos_uart->receive_callback_context, cmd, cmd_len);
  62. }
  63. if(consumed > 0) {
  64. memset(cmd, 0, consumed);
  65. cmd_len -= consumed;
  66. if(cmd_len > 0) {
  67. memmove(cmd, cmd + consumed, cmd_len);
  68. }
  69. /*
  70. memset(display, 0, SEOS_UART_RX_BUF_SIZE);
  71. for(uint8_t i = 0; i < cmd_len; i++) {
  72. snprintf(display + (i * 2), sizeof(display), "%02x", cmd[i]);
  73. }
  74. FURI_LOG_I(TAG, "cmd is now %d bytes: %s", cmd_len, display);
  75. */
  76. }
  77. } while(consumed > 0 && cmd_len > 0);
  78. return cmd_len;
  79. }
  80. int32_t seos_uart_worker(void* context) {
  81. SeosUart* seos_uart = (SeosUart*)context;
  82. furi_thread_set_current_priority(FuriThreadPriorityHighest);
  83. memcpy(&seos_uart->cfg, &seos_uart->cfg_new, sizeof(SeosUartConfig));
  84. seos_uart->rx_stream = furi_stream_buffer_alloc(SEOS_UART_RX_BUF_SIZE, 1);
  85. seos_uart->tx_sem = furi_semaphore_alloc(1, 1);
  86. seos_uart->tx_thread =
  87. furi_thread_alloc_ex("SeosUartTxWorker", 1.5 * 1024, seos_uart_tx_thread, seos_uart);
  88. seos_uart_serial_init(seos_uart, seos_uart->cfg.uart_ch);
  89. seos_uart_set_baudrate(seos_uart, seos_uart->cfg.baudrate);
  90. furi_thread_flags_set(furi_thread_get_id(seos_uart->tx_thread), WorkerEvtDevRx);
  91. furi_thread_start(seos_uart->tx_thread);
  92. uint8_t cmd[SEOS_UART_RX_BUF_SIZE];
  93. size_t cmd_len = 0;
  94. while(1) {
  95. uint32_t events =
  96. furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, FuriFlagWaitAny, FuriWaitForever);
  97. furi_check(!(events & FuriFlagError));
  98. if(events & WorkerEvtStop) {
  99. memset(cmd, 0, cmd_len);
  100. cmd_len = 0;
  101. break;
  102. }
  103. if(events & (WorkerEvtRxDone | WorkerEvtDevTxComplete)) {
  104. size_t len = furi_stream_buffer_receive(
  105. seos_uart->rx_stream, seos_uart->rx_buf, SEOS_UART_RX_BUF_SIZE, 0);
  106. if(len > 0) {
  107. furi_delay_ms(5); //WTF
  108. /*
  109. char display[SEOS_UART_RX_BUF_SIZE * 2 + 1] = {0};
  110. for(uint8_t i = 0; i < len; i++) {
  111. snprintf(display + (i * 2), sizeof(display), "%02x", seos_uart->rx_buf[i]);
  112. }
  113. FURI_LOG_D(TAG, "RECV %d bytes: %s", len, display);
  114. */
  115. if(cmd_len + len > SEOS_UART_RX_BUF_SIZE) {
  116. FURI_LOG_I(TAG, "OVERFLOW: %d + %d", cmd_len, len);
  117. memset(cmd, 0, cmd_len);
  118. cmd_len = 0;
  119. }
  120. memcpy(cmd + cmd_len, seos_uart->rx_buf, len);
  121. cmd_len += len;
  122. cmd_len = seos_uart_process_buffer(seos_uart, cmd, cmd_len);
  123. }
  124. }
  125. }
  126. seos_uart_serial_deinit(seos_uart);
  127. furi_thread_flags_set(furi_thread_get_id(seos_uart->tx_thread), WorkerEvtTxStop);
  128. furi_thread_join(seos_uart->tx_thread);
  129. furi_thread_free(seos_uart->tx_thread);
  130. furi_stream_buffer_free(seos_uart->rx_stream);
  131. furi_semaphore_free(seos_uart->tx_sem);
  132. return 0;
  133. }
  134. SeosUart* seos_uart_enable(SeosUartConfig* cfg) {
  135. SeosUart* seos_uart = malloc(sizeof(SeosUart));
  136. memcpy(&(seos_uart->cfg_new), cfg, sizeof(SeosUartConfig));
  137. seos_uart->thread =
  138. furi_thread_alloc_ex("SeosUartWorker", 5 * 1024, seos_uart_worker, seos_uart);
  139. furi_thread_start(seos_uart->thread);
  140. return seos_uart;
  141. }
  142. int32_t seos_uart_tx_thread(void* context) {
  143. SeosUart* seos_uart = (SeosUart*)context;
  144. furi_thread_set_current_priority(FuriThreadPriorityHighest);
  145. while(1) {
  146. uint32_t events =
  147. furi_thread_flags_wait(WORKER_ALL_TX_EVENTS, FuriFlagWaitAny, FuriWaitForever);
  148. furi_check(!(events & FuriFlagError));
  149. if(events & WorkerEvtTxStop) break;
  150. if(events & WorkerEvtDevRx) {
  151. if(seos_uart->tx_len > 0) {
  152. /*
  153. char display[SEOS_UART_RX_BUF_SIZE * 2 + 1] = {0};
  154. for(uint8_t i = 0; i < seos_uart->tx_len; i++) {
  155. snprintf(display + (i * 2), sizeof(display), "%02x", seos_uart->tx_buf[i]);
  156. }
  157. FURI_LOG_D(TAG, "SEND %d bytes: %s", seos_uart->tx_len, display);
  158. */
  159. furi_hal_serial_tx(seos_uart->serial_handle, seos_uart->tx_buf, seos_uart->tx_len);
  160. }
  161. }
  162. }
  163. return 0;
  164. }
  165. void seos_uart_get_config(SeosUart* seos_uart, SeosUartConfig* cfg) {
  166. furi_assert(seos_uart);
  167. furi_assert(cfg);
  168. memcpy(cfg, &(seos_uart->cfg_new), sizeof(SeosUartConfig));
  169. }
  170. SeosUart* seos_uart_alloc() {
  171. SeosUartConfig cfg = {.uart_ch = FuriHalSerialIdLpuart, .baudrate = SEOS_UART_BAUD};
  172. SeosUart* seos_uart;
  173. FURI_LOG_I(TAG, "Enable UART");
  174. seos_uart = seos_uart_enable(&cfg);
  175. seos_uart_get_config(seos_uart, &cfg);
  176. return seos_uart;
  177. }
  178. void seos_uart_free(SeosUart* seos_uart) {
  179. seos_uart_disable(seos_uart);
  180. }
  181. void seos_uart_send(SeosUart* seos_uart, uint8_t* buffer, size_t len) {
  182. memset(seos_uart->tx_buf, 0, sizeof(seos_uart->tx_buf));
  183. memcpy(seos_uart->tx_buf, buffer, len);
  184. seos_uart->tx_len = len;
  185. furi_thread_flags_set(furi_thread_get_id(seos_uart->tx_thread), WorkerEvtDevRx);
  186. }
  187. void seos_uart_set_receive_callback(
  188. SeosUart* seos_uart,
  189. SeosUartReceiveCallback callback,
  190. void* context) {
  191. seos_uart->receive_callback = callback;
  192. seos_uart->receive_callback_context = context;
  193. }