subghz_tx_rx_worker.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. #include "subghz_tx_rx_worker.h"
  2. #include <stream_buffer.h>
  3. #include <furi.h>
  4. #define TAG "SubGhzTxRxWorker"
  5. #define GUBGHZ_TXRX_WORKER_BUF_SIZE 2048
  6. //you can not set more than 62 because it will not fit into the FIFO CC1101
  7. #define GUBGHZ_TXRX_WORKER_MAX_TXRX_SIZE 60
  8. #define GUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF 40
  9. struct SubGhzTxRxWorker {
  10. FuriThread* thread;
  11. StreamBufferHandle_t stream_tx;
  12. StreamBufferHandle_t stream_rx;
  13. volatile bool worker_running;
  14. volatile bool worker_stoping;
  15. SubGhzTxRxWorkerStatus satus;
  16. uint32_t frequency;
  17. SubGhzTxRxWorkerCallbackHaveRead callback_have_read;
  18. void* context_have_read;
  19. };
  20. bool subghz_tx_rx_worker_write(SubGhzTxRxWorker* instance, uint8_t* data, size_t size) {
  21. furi_assert(instance);
  22. bool ret = false;
  23. size_t stream_tx_free_byte = xStreamBufferSpacesAvailable(instance->stream_tx);
  24. if(size && (stream_tx_free_byte >= size)) {
  25. if(xStreamBufferSend(
  26. instance->stream_tx, data, size, GUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF) ==
  27. size) {
  28. ret = true;
  29. }
  30. }
  31. return ret;
  32. }
  33. size_t subghz_tx_rx_worker_available(SubGhzTxRxWorker* instance) {
  34. furi_assert(instance);
  35. return xStreamBufferBytesAvailable(instance->stream_rx);
  36. }
  37. size_t subghz_tx_rx_worker_read(SubGhzTxRxWorker* instance, uint8_t* data, size_t size) {
  38. furi_assert(instance);
  39. size_t len = 0;
  40. size_t stream_rx_byte = xStreamBufferBytesAvailable(instance->stream_rx);
  41. if(stream_rx_byte > 0) {
  42. if(stream_rx_byte <= size) {
  43. len = xStreamBufferReceive(
  44. instance->stream_rx,
  45. data,
  46. stream_rx_byte,
  47. GUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF);
  48. } else {
  49. len = xStreamBufferReceive(
  50. instance->stream_rx, data, size, GUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF);
  51. }
  52. }
  53. return len;
  54. }
  55. void subghz_tx_rx_worker_set_callback_have_read(
  56. SubGhzTxRxWorker* instance,
  57. SubGhzTxRxWorkerCallbackHaveRead callback,
  58. void* context) {
  59. furi_assert(instance);
  60. furi_assert(callback);
  61. furi_assert(context);
  62. instance->callback_have_read = callback;
  63. instance->context_have_read = context;
  64. }
  65. bool subghz_tx_rx_worker_rx(SubGhzTxRxWorker* instance, uint8_t* data, uint8_t* size) {
  66. uint8_t timeout = 20;
  67. bool ret = false;
  68. if(instance->satus != SubGhzTxRxWorkerStatusRx) {
  69. furi_hal_subghz_rx();
  70. instance->satus = SubGhzTxRxWorkerStatusRx;
  71. osDelay(1);
  72. }
  73. //waiting for reception to complete
  74. while(hal_gpio_read(&gpio_cc1101_g0)) {
  75. osDelay(1);
  76. if(!--timeout) {
  77. FURI_LOG_W(TAG, "RX cc1101_g0 timeout");
  78. furi_hal_subghz_flush_rx();
  79. furi_hal_subghz_rx();
  80. break;
  81. }
  82. }
  83. if(furi_hal_subghz_rx_pipe_not_empty()) {
  84. if(furi_hal_subghz_is_rx_data_crc_valid()) {
  85. furi_hal_subghz_read_packet(data, size);
  86. ret = true;
  87. }
  88. furi_hal_subghz_flush_rx();
  89. furi_hal_subghz_rx();
  90. }
  91. return ret;
  92. }
  93. void subghz_tx_rx_worker_tx(SubGhzTxRxWorker* instance, uint8_t* data, size_t size) {
  94. uint8_t timeout = 40;
  95. if(instance->satus != SubGhzTxRxWorkerStatusIDLE) {
  96. furi_hal_subghz_idle();
  97. }
  98. furi_hal_subghz_write_packet(data, size);
  99. instance->satus = SubGhzTxRxWorkerStatusTx;
  100. furi_hal_subghz_tx(); //start send
  101. while(!hal_gpio_read(&gpio_cc1101_g0)) { // Wait for GDO0 to be set -> sync transmitted
  102. osDelay(1);
  103. if(!--timeout) {
  104. FURI_LOG_W(TAG, "TX !cc1101_g0 timeout");
  105. break;
  106. }
  107. }
  108. while(hal_gpio_read(&gpio_cc1101_g0)) { // Wait for GDO0 to be cleared -> end of packet
  109. osDelay(1);
  110. if(!--timeout) {
  111. FURI_LOG_W(TAG, "TX cc1101_g0 timeout");
  112. break;
  113. }
  114. }
  115. furi_hal_subghz_idle();
  116. instance->satus = SubGhzTxRxWorkerStatusIDLE;
  117. }
  118. /** Worker thread
  119. *
  120. * @param context
  121. * @return exit code
  122. */
  123. static int32_t subghz_tx_rx_worker_thread(void* context) {
  124. SubGhzTxRxWorker* instance = context;
  125. FURI_LOG_I(TAG, "Worker start");
  126. furi_hal_subghz_reset();
  127. furi_hal_subghz_idle();
  128. furi_hal_subghz_load_preset(FuriHalSubGhzPresetMSK99_97KbAsync);
  129. hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
  130. furi_hal_subghz_set_frequency_and_path(instance->frequency);
  131. furi_hal_subghz_flush_rx();
  132. uint8_t data[GUBGHZ_TXRX_WORKER_MAX_TXRX_SIZE] = {0};
  133. size_t size_tx = 0;
  134. uint8_t size_rx[1] = {0};
  135. uint8_t timeout_tx = 0;
  136. bool callback_rx = false;
  137. while(instance->worker_running) {
  138. //transmit
  139. size_tx = xStreamBufferBytesAvailable(instance->stream_tx);
  140. if(size_tx > 0 && !timeout_tx) {
  141. timeout_tx = 20; //20ms
  142. if(size_tx > GUBGHZ_TXRX_WORKER_MAX_TXRX_SIZE) {
  143. xStreamBufferReceive(
  144. instance->stream_tx,
  145. &data,
  146. GUBGHZ_TXRX_WORKER_MAX_TXRX_SIZE,
  147. GUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF);
  148. subghz_tx_rx_worker_tx(instance, data, GUBGHZ_TXRX_WORKER_MAX_TXRX_SIZE);
  149. } else {
  150. //todo checking that he managed to write all the data to the TX buffer
  151. xStreamBufferReceive(
  152. instance->stream_tx, &data, size_tx, GUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF);
  153. subghz_tx_rx_worker_tx(instance, data, size_tx);
  154. }
  155. } else {
  156. //recive
  157. if(subghz_tx_rx_worker_rx(instance, data, size_rx)) {
  158. if(xStreamBufferSpacesAvailable(instance->stream_rx) >= size_rx[0]) {
  159. if(instance->callback_have_read &&
  160. xStreamBufferBytesAvailable(instance->stream_rx) == 0) {
  161. callback_rx = true;
  162. }
  163. //todo checking that he managed to write all the data to the RX buffer
  164. xStreamBufferSend(
  165. instance->stream_rx,
  166. &data,
  167. size_rx[0],
  168. GUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF);
  169. if(callback_rx) {
  170. instance->callback_have_read(instance->context_have_read);
  171. callback_rx = false;
  172. }
  173. } else {
  174. //todo RX buffer overflow
  175. }
  176. }
  177. }
  178. if(timeout_tx) timeout_tx--;
  179. osDelay(1);
  180. }
  181. furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate);
  182. furi_hal_subghz_sleep();
  183. FURI_LOG_I(TAG, "Worker stop");
  184. return 0;
  185. }
  186. SubGhzTxRxWorker* subghz_tx_rx_worker_alloc() {
  187. SubGhzTxRxWorker* instance = furi_alloc(sizeof(SubGhzTxRxWorker));
  188. instance->thread = furi_thread_alloc();
  189. furi_thread_set_name(instance->thread, "SubghzTxRxWorker");
  190. furi_thread_set_stack_size(instance->thread, 2048);
  191. furi_thread_set_context(instance->thread, instance);
  192. furi_thread_set_callback(instance->thread, subghz_tx_rx_worker_thread);
  193. instance->stream_tx =
  194. xStreamBufferCreate(sizeof(uint8_t) * GUBGHZ_TXRX_WORKER_BUF_SIZE, sizeof(uint8_t));
  195. instance->stream_rx =
  196. xStreamBufferCreate(sizeof(uint8_t) * GUBGHZ_TXRX_WORKER_BUF_SIZE, sizeof(uint8_t));
  197. instance->satus = SubGhzTxRxWorkerStatusIDLE;
  198. instance->worker_stoping = true;
  199. return instance;
  200. }
  201. void subghz_tx_rx_worker_free(SubGhzTxRxWorker* instance) {
  202. furi_assert(instance);
  203. vStreamBufferDelete(instance->stream_tx);
  204. vStreamBufferDelete(instance->stream_rx);
  205. furi_thread_free(instance->thread);
  206. free(instance);
  207. }
  208. bool subghz_tx_rx_worker_start(SubGhzTxRxWorker* instance, uint32_t frequency) {
  209. furi_assert(instance);
  210. furi_assert(!instance->worker_running);
  211. bool res = false;
  212. xStreamBufferReset(instance->stream_tx);
  213. xStreamBufferReset(instance->stream_rx);
  214. instance->worker_running = true;
  215. furi_thread_start(instance->thread);
  216. if(furi_hal_subghz_is_tx_allowed(frequency)) {
  217. instance->frequency = frequency;
  218. res = true;
  219. }
  220. return res;
  221. }
  222. void subghz_tx_rx_worker_stop(SubGhzTxRxWorker* instance) {
  223. furi_assert(instance);
  224. furi_assert(instance->worker_running);
  225. instance->worker_running = false;
  226. furi_thread_join(instance->thread);
  227. }
  228. bool subghz_tx_rx_worker_is_running(SubGhzTxRxWorker* instance) {
  229. furi_assert(instance);
  230. return instance->worker_running;
  231. }