spectrum_analyzer_worker.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. #include "spectrum_analyzer.h"
  2. #include "spectrum_analyzer_worker.h"
  3. #include <furi_hal.h>
  4. #include <furi.h>
  5. #include "helpers/radio_device_loader.h"
  6. #include <lib/drivers/cc1101_regs.h>
  7. struct SpectrumAnalyzerWorker {
  8. FuriThread* thread;
  9. bool should_work;
  10. SpectrumAnalyzerWorkerCallback callback;
  11. void* callback_context;
  12. const SubGhzDevice* radio_device;
  13. uint32_t channel0_frequency;
  14. uint32_t spacing;
  15. uint8_t width;
  16. float max_rssi;
  17. uint8_t max_rssi_dec;
  18. uint8_t max_rssi_channel;
  19. uint8_t channel_ss[NUM_CHANNELS];
  20. };
  21. /* set the channel bandwidth */
  22. void spectrum_analyzer_worker_set_filter(SpectrumAnalyzerWorker* instance) {
  23. uint8_t filter_config[2][2] = {
  24. {CC1101_MDMCFG4, 0},
  25. {0, 0},
  26. };
  27. // FURI_LOG_D("SpectrumWorker", "spectrum_analyzer_worker_set_filter: width = %u", instance->width);
  28. /* channel spacing should fit within 80% of channel filter bandwidth */
  29. switch(instance->width) {
  30. case NARROW:
  31. filter_config[0][1] = 0xFC; /* 39.2 kHz / .8 = 49 kHz --> 58 kHz */
  32. break;
  33. case ULTRAWIDE:
  34. filter_config[0][1] = 0x0C; /* 784 kHz / .8 = 980 kHz --> 812 kHz */
  35. break;
  36. default:
  37. filter_config[0][1] = 0x6C; /* 196 kHz / .8 = 245 kHz --> 270 kHz */
  38. break;
  39. }
  40. UNUSED(filter_config);
  41. // furi_hal_subghz_load_registers((uint8_t*)filter_config);
  42. }
  43. static int32_t spectrum_analyzer_worker_thread(void* context) {
  44. furi_assert(context);
  45. SpectrumAnalyzerWorker* instance = context;
  46. FURI_LOG_D("SpectrumWorker", "spectrum_analyzer_worker_thread: Start");
  47. // Start CC1101
  48. subghz_devices_reset(instance->radio_device);
  49. subghz_devices_load_preset(instance->radio_device, FuriHalSubGhzPresetOok650Async, NULL);
  50. subghz_devices_set_frequency(instance->radio_device, 433920000);
  51. subghz_devices_flush_rx(instance->radio_device);
  52. subghz_devices_set_rx(instance->radio_device);
  53. const uint8_t radio_config[] = {
  54. CC1101_FSCTRL0,
  55. 0x00,
  56. CC1101_FSCTRL1,
  57. 0x12,
  58. CC1101_AGCCTRL2,
  59. 0xC0,
  60. CC1101_MDMCFG4,
  61. 0x6C,
  62. CC1101_TEST2,
  63. 0x88,
  64. CC1101_TEST1,
  65. 0x31,
  66. CC1101_TEST0,
  67. 0x09,
  68. /* End */
  69. 0,
  70. 0,
  71. // ook_async_patable
  72. 0x00,
  73. 0xC0, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03
  74. 0x00,
  75. 0x00,
  76. 0x00,
  77. 0x00,
  78. 0x00,
  79. 0x00,
  80. };
  81. while(instance->should_work) {
  82. furi_delay_ms(50);
  83. // FURI_LOG_T("SpectrumWorker", "spectrum_analyzer_worker_thread: Worker Loop");
  84. subghz_devices_idle(instance->radio_device);
  85. subghz_devices_load_preset(
  86. instance->radio_device, FuriHalSubGhzPresetCustom, (uint8_t*)radio_config);
  87. // TODO: Check filter!
  88. // spectrum_analyzer_worker_set_filter(instance);
  89. instance->max_rssi_dec = 0;
  90. // Visit each channel non-consecutively
  91. for(uint8_t ch_offset = 0, chunk = 0; ch_offset < CHUNK_SIZE;
  92. ++chunk >= NUM_CHUNKS && ++ch_offset && (chunk = 0)) {
  93. uint8_t ch = chunk * CHUNK_SIZE + ch_offset;
  94. if(subghz_devices_is_frequency_valid(
  95. instance->radio_device,
  96. instance->channel0_frequency + (ch * instance->spacing)))
  97. subghz_devices_set_frequency(
  98. instance->radio_device,
  99. instance->channel0_frequency + (ch * instance->spacing));
  100. subghz_devices_set_rx(instance->radio_device);
  101. furi_delay_ms(3);
  102. // dec dBm
  103. //max_ss = 127 -> -10.5
  104. //max_ss = 0 -> -74.0
  105. //max_ss = 255 -> -74.5
  106. //max_ss = 128 -> -138.0
  107. instance->channel_ss[ch] = (subghz_devices_get_rssi(instance->radio_device) + 138) * 2;
  108. if(instance->channel_ss[ch] > instance->max_rssi_dec) {
  109. instance->max_rssi_dec = instance->channel_ss[ch];
  110. instance->max_rssi = (instance->channel_ss[ch] / 2) - 138;
  111. instance->max_rssi_channel = ch;
  112. }
  113. subghz_devices_idle(instance->radio_device);
  114. }
  115. // FURI_LOG_T("SpectrumWorker", "channel_ss[0]: %u", instance->channel_ss[0]);
  116. // Report results back to main thread
  117. if(instance->callback) {
  118. instance->callback(
  119. (void*)&(instance->channel_ss),
  120. instance->max_rssi,
  121. instance->max_rssi_dec,
  122. instance->max_rssi_channel,
  123. instance->callback_context);
  124. }
  125. }
  126. return 0;
  127. }
  128. SpectrumAnalyzerWorker* spectrum_analyzer_worker_alloc() {
  129. FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_alloc: Start");
  130. SpectrumAnalyzerWorker* instance = malloc(sizeof(SpectrumAnalyzerWorker));
  131. instance->thread = furi_thread_alloc();
  132. furi_thread_set_name(instance->thread, "SpectrumWorker");
  133. furi_thread_set_stack_size(instance->thread, 2048);
  134. furi_thread_set_context(instance->thread, instance);
  135. furi_thread_set_callback(instance->thread, spectrum_analyzer_worker_thread);
  136. subghz_devices_init();
  137. instance->radio_device =
  138. radio_device_loader_set(instance->radio_device, SubGhzRadioDeviceTypeExternalCC1101);
  139. FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_alloc: End");
  140. return instance;
  141. }
  142. void spectrum_analyzer_worker_free(SpectrumAnalyzerWorker* instance) {
  143. FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_free");
  144. furi_assert(instance);
  145. furi_thread_free(instance->thread);
  146. subghz_devices_sleep(instance->radio_device);
  147. radio_device_loader_end(instance->radio_device);
  148. subghz_devices_deinit();
  149. free(instance);
  150. }
  151. void spectrum_analyzer_worker_set_callback(
  152. SpectrumAnalyzerWorker* instance,
  153. SpectrumAnalyzerWorkerCallback callback,
  154. void* context) {
  155. furi_assert(instance);
  156. instance->callback = callback;
  157. instance->callback_context = context;
  158. }
  159. void spectrum_analyzer_worker_set_frequencies(
  160. SpectrumAnalyzerWorker* instance,
  161. uint32_t channel0_frequency,
  162. uint32_t spacing,
  163. uint8_t width) {
  164. furi_assert(instance);
  165. FURI_LOG_D(
  166. "SpectrumWorker",
  167. "spectrum_analyzer_worker_set_frequencies - channel0_frequency= %lu - spacing = %lu - width = %u",
  168. channel0_frequency,
  169. spacing,
  170. width);
  171. instance->channel0_frequency = channel0_frequency;
  172. instance->spacing = spacing;
  173. instance->width = width;
  174. }
  175. void spectrum_analyzer_worker_start(SpectrumAnalyzerWorker* instance) {
  176. FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_start");
  177. furi_assert(instance);
  178. furi_assert(instance->should_work == false);
  179. instance->should_work = true;
  180. furi_thread_start(instance->thread);
  181. }
  182. void spectrum_analyzer_worker_stop(SpectrumAnalyzerWorker* instance) {
  183. FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_stop");
  184. furi_assert(instance);
  185. furi_assert(instance->should_work == true);
  186. instance->should_work = false;
  187. furi_thread_join(instance->thread);
  188. }