subghz_tx_rx_worker.c 8.2 KB

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