subghz_receiver.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. #include "subghz_receiver.h"
  2. #include "../subghz_i.h"
  3. #include <math.h>
  4. #include <furi.h>
  5. #include <furi-hal.h>
  6. #include <input/input.h>
  7. #include <gui/elements.h>
  8. #include <notification/notification-messages.h>
  9. #include <lib/subghz/protocols/subghz_protocol_princeton.h>
  10. #include <assets_icons.h>
  11. #define FRAME_HEIGHT 12
  12. #define MAX_LEN_PX 100
  13. #define MENU_ITEMS 4
  14. #define COUNT_FREQUNCY_SCANER 3
  15. const uint32_t subghz_frequencies_scanner[] = {
  16. /* 300 - 348 */
  17. 315000000,
  18. /* 387 - 464 */
  19. 433920000, /* LPD433 mid */
  20. /* 779 - 928 */
  21. 868350000,
  22. };
  23. typedef enum {
  24. ReceiverSceneStart,
  25. ReceiverSceneMain,
  26. ReceiverSceneConfig,
  27. ReceiverSceneInfo,
  28. } SubghzReceiverScene;
  29. typedef enum {
  30. SubGhzHopperStateOFF,
  31. SubGhzHopperStatePause,
  32. SubGhzHopperStateRunnig,
  33. } SubGhzHopperState;
  34. static const Icon* ReceiverItemIcons[] = {
  35. [TYPE_PROTOCOL_UNKNOWN] = &I_quest_7x8,
  36. [TYPE_PROTOCOL_STATIC] = &I_unlock_7x8,
  37. [TYPE_PROTOCOL_DYNAMIC] = &I_lock_7x8,
  38. };
  39. struct SubghzReceiver {
  40. View* view;
  41. SubghzReceiverCallback callback;
  42. void* context;
  43. SubGhzWorker* worker;
  44. SubGhzProtocol* protocol;
  45. osTimerId timer;
  46. SubGhzHopperState hopper_state;
  47. };
  48. typedef struct {
  49. string_t text;
  50. uint16_t scene;
  51. SubGhzProtocolCommon* protocol_result;
  52. SubGhzHistory* history;
  53. uint8_t frequency;
  54. uint8_t temp_frequency;
  55. uint32_t real_frequency;
  56. uint8_t tab_idx;
  57. uint8_t menu_idx;
  58. uint16_t idx;
  59. uint16_t list_offset;
  60. uint16_t history_item;
  61. bool menu;
  62. } SubghzReceiverModel;
  63. void subghz_receiver_set_callback(
  64. SubghzReceiver* subghz_receiver,
  65. SubghzReceiverCallback callback,
  66. void* context) {
  67. furi_assert(subghz_receiver);
  68. furi_assert(callback);
  69. subghz_receiver->callback = callback;
  70. subghz_receiver->context = context;
  71. }
  72. void subghz_receiver_set_protocol(
  73. SubghzReceiver* subghz_receiver,
  74. SubGhzProtocolCommon* protocol_result,
  75. SubGhzProtocol* protocol) {
  76. furi_assert(subghz_receiver);
  77. with_view_model(
  78. subghz_receiver->view, (SubghzReceiverModel * model) {
  79. model->protocol_result = protocol_result;
  80. return true;
  81. });
  82. subghz_receiver->protocol = protocol;
  83. }
  84. SubGhzProtocolCommon* subghz_receiver_get_protocol(SubghzReceiver* subghz_receiver) {
  85. furi_assert(subghz_receiver);
  86. SubGhzProtocolCommon* result = NULL;
  87. with_view_model(
  88. subghz_receiver->view, (SubghzReceiverModel * model) {
  89. result = model->protocol_result;
  90. return false;
  91. });
  92. return result;
  93. }
  94. void subghz_receiver_set_worker(SubghzReceiver* subghz_receiver, SubGhzWorker* worker) {
  95. furi_assert(subghz_receiver);
  96. subghz_receiver->worker = worker;
  97. }
  98. static void subghz_receiver_update_offset(SubghzReceiver* subghz_receiver) {
  99. furi_assert(subghz_receiver);
  100. with_view_model(
  101. subghz_receiver->view, (SubghzReceiverModel * model) {
  102. size_t history_item = model->history_item;
  103. uint16_t bounds = history_item > 3 ? 2 : history_item;
  104. if(history_item > 3 && model->idx >= history_item - 1) {
  105. model->list_offset = model->idx - 3;
  106. } else if(model->list_offset < model->idx - bounds) {
  107. model->list_offset = CLAMP(model->list_offset + 1, history_item - bounds, 0);
  108. } else if(model->list_offset > model->idx - bounds) {
  109. model->list_offset = CLAMP(model->idx - 1, history_item - bounds, 0);
  110. }
  111. return true;
  112. });
  113. }
  114. static void subghz_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) {
  115. canvas_set_color(canvas, ColorBlack);
  116. canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT);
  117. canvas_set_color(canvas, ColorWhite);
  118. canvas_draw_dot(canvas, 0, 0 + idx * FRAME_HEIGHT);
  119. canvas_draw_dot(canvas, 1, 0 + idx * FRAME_HEIGHT);
  120. canvas_draw_dot(canvas, 0, (0 + idx * FRAME_HEIGHT) + 1);
  121. canvas_draw_dot(canvas, 0, (0 + idx * FRAME_HEIGHT) + 11);
  122. canvas_draw_dot(canvas, scrollbar ? 121 : 126, 0 + idx * FRAME_HEIGHT);
  123. canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11);
  124. }
  125. void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
  126. bool scrollbar = model->history_item > 4;
  127. string_t str_buff;
  128. char buffer[64];
  129. string_init(str_buff);
  130. canvas_clear(canvas);
  131. canvas_set_color(canvas, ColorBlack);
  132. switch(model->scene) {
  133. case ReceiverSceneMain:
  134. for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) {
  135. size_t idx = CLAMP(i + model->list_offset, model->history_item, 0);
  136. subghz_history_get_text_item_menu(model->history, str_buff, idx);
  137. elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX);
  138. if(model->idx == idx) {
  139. subghz_receiver_draw_frame(canvas, i, scrollbar);
  140. } else {
  141. canvas_set_color(canvas, ColorBlack);
  142. }
  143. canvas_draw_icon(
  144. canvas,
  145. 1,
  146. 2 + i * FRAME_HEIGHT,
  147. ReceiverItemIcons[subghz_history_get_type_protocol(model->history, idx)]);
  148. canvas_draw_str(canvas, 15, 9 + i * FRAME_HEIGHT, string_get_cstr(str_buff));
  149. string_clean(str_buff);
  150. }
  151. if(scrollbar) {
  152. elements_scrollbar_pos(canvas, 126, 0, 49, model->idx, model->history_item);
  153. }
  154. canvas_set_color(canvas, ColorBlack);
  155. canvas_set_font(canvas, FontPrimary);
  156. snprintf(
  157. buffer,
  158. sizeof(buffer),
  159. "%03ld.%03ld OOK",
  160. model->real_frequency / 1000000 % 1000,
  161. model->real_frequency / 1000 % 1000);
  162. canvas_draw_str(canvas, 60, 61, buffer);
  163. elements_button_left(canvas, "Config");
  164. break;
  165. case ReceiverSceneStart:
  166. canvas_draw_icon(canvas, 0, 0, &I_RFIDDolphinReceive_97x61);
  167. canvas_invert_color(canvas);
  168. canvas_draw_box(canvas, 80, 2, 20, 20);
  169. canvas_invert_color(canvas);
  170. canvas_draw_icon(canvas, 75, 8, &I_sub1_10px);
  171. canvas_set_font(canvas, FontPrimary);
  172. canvas_draw_str(canvas, 63, 40, "Scanning...");
  173. canvas_set_color(canvas, ColorBlack);
  174. canvas_set_font(canvas, FontPrimary);
  175. snprintf(
  176. buffer,
  177. sizeof(buffer),
  178. "%03ld.%03ld OOK",
  179. model->real_frequency / 1000000 % 1000,
  180. model->real_frequency / 1000 % 1000);
  181. canvas_draw_str(canvas, 60, 61, buffer);
  182. elements_button_left(canvas, "Config");
  183. break;
  184. case ReceiverSceneConfig:
  185. if(model->frequency < subghz_frequencies_count) {
  186. snprintf(
  187. buffer,
  188. sizeof(buffer),
  189. "Frequency: < %03ld.%03ldMHz >",
  190. model->real_frequency / 1000000 % 1000,
  191. model->real_frequency / 1000 % 1000);
  192. canvas_draw_str(canvas, 0, 8, buffer);
  193. } else {
  194. canvas_draw_str(canvas, 0, 8, "Frequency: <auto>");
  195. }
  196. elements_button_center(canvas, "Save");
  197. break;
  198. case ReceiverSceneInfo:
  199. canvas_set_font(canvas, FontSecondary);
  200. elements_multiline_text(canvas, 0, 8, string_get_cstr(model->text));
  201. snprintf(
  202. buffer,
  203. sizeof(buffer),
  204. "%03ld.%03ld",
  205. subghz_history_get_frequency(model->history, model->idx) / 1000000 % 1000,
  206. subghz_history_get_frequency(model->history, model->idx) / 1000 % 1000);
  207. canvas_draw_str(canvas, 90, 8, buffer);
  208. if(model->protocol_result && model->protocol_result->to_save_string &&
  209. strcmp(model->protocol_result->name, "KeeLoq")) {
  210. elements_button_right(canvas, "Save");
  211. elements_button_center(canvas, "Send");
  212. }
  213. break;
  214. default:
  215. break;
  216. }
  217. string_clear(str_buff);
  218. }
  219. bool subghz_receiver_input(InputEvent* event, void* context) {
  220. furi_assert(context);
  221. uint8_t scene = 0;
  222. SubghzReceiver* subghz_receiver = context;
  223. with_view_model(
  224. subghz_receiver->view, (SubghzReceiverModel * model) {
  225. scene = model->scene;
  226. return false;
  227. });
  228. if(scene != ReceiverSceneInfo && event->type != InputTypeShort) return false;
  229. bool can_be_saved = false;
  230. switch(scene) {
  231. case ReceiverSceneMain:
  232. if(event->key == InputKeyBack) {
  233. return false;
  234. } else if(event->key == InputKeyUp) {
  235. with_view_model(
  236. subghz_receiver->view, (SubghzReceiverModel * model) {
  237. if(model->idx != 0) model->idx--;
  238. return true;
  239. });
  240. } else if(event->key == InputKeyDown) {
  241. with_view_model(
  242. subghz_receiver->view, (SubghzReceiverModel * model) {
  243. if(model->idx != subghz_history_get_item(model->history) - 1) model->idx++;
  244. return true;
  245. });
  246. } else if(event->key == InputKeyLeft) {
  247. subghz_receiver->hopper_state = SubGhzHopperStatePause;
  248. with_view_model(
  249. subghz_receiver->view, (SubghzReceiverModel * model) {
  250. model->scene = ReceiverSceneConfig;
  251. model->temp_frequency = model->frequency;
  252. return true;
  253. });
  254. subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context);
  255. } else if(event->key == InputKeyOk) {
  256. with_view_model(
  257. subghz_receiver->view, (SubghzReceiverModel * model) {
  258. string_clean(model->text);
  259. model->protocol_result = subghz_protocol_get_by_name(
  260. subghz_receiver->protocol,
  261. subghz_history_get_name(model->history, model->idx));
  262. if(model->protocol_result->to_load_protocol != NULL) {
  263. model->protocol_result->to_load_protocol(
  264. model->protocol_result,
  265. subghz_history_get_raw_data(model->history, model->idx));
  266. model->protocol_result->to_string(model->protocol_result, model->text);
  267. model->scene = ReceiverSceneInfo;
  268. }
  269. return true;
  270. });
  271. }
  272. break;
  273. case ReceiverSceneInfo:
  274. with_view_model(
  275. subghz_receiver->view, (SubghzReceiverModel * model) {
  276. can_be_saved =
  277. (model->protocol_result && model->protocol_result->to_save_string &&
  278. strcmp(model->protocol_result->name, "KeeLoq"));
  279. return false;
  280. });
  281. if(event->key == InputKeyBack && event->type == InputTypeShort) {
  282. with_view_model(
  283. subghz_receiver->view, (SubghzReceiverModel * model) {
  284. subghz_rx_end(subghz_receiver->worker);
  285. model->real_frequency =
  286. subghz_rx(subghz_receiver->worker, subghz_frequencies[model->frequency]);
  287. subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
  288. model->scene = ReceiverSceneMain;
  289. return true;
  290. });
  291. subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context);
  292. } else if(can_be_saved && event->key == InputKeyRight) {
  293. subghz_receiver->callback(SubghzReceverEventSave, subghz_receiver->context);
  294. return false;
  295. } else if(can_be_saved && event->key == InputKeyOk && event->type == InputTypePress) {
  296. subghz_receiver->hopper_state = SubGhzHopperStatePause;
  297. subghz_rx_end(subghz_receiver->worker);
  298. subghz_receiver->callback(SubghzReceverEventSendStart, subghz_receiver->context);
  299. return true;
  300. } else if(can_be_saved && event->key == InputKeyOk && event->type == InputTypeRelease) {
  301. subghz_receiver->callback(SubghzReceverEventSendStop, subghz_receiver->context);
  302. return true;
  303. }
  304. break;
  305. case ReceiverSceneConfig:
  306. if(event->key == InputKeyBack) {
  307. with_view_model(
  308. subghz_receiver->view, (SubghzReceiverModel * model) {
  309. model->frequency = model->temp_frequency;
  310. model->real_frequency = subghz_frequencies[model->frequency];
  311. subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
  312. if(subghz_history_get_item(model->history) == 0) {
  313. model->scene = ReceiverSceneStart;
  314. } else {
  315. model->scene = ReceiverSceneMain;
  316. }
  317. return true;
  318. });
  319. subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context);
  320. } else if(event->key == InputKeyOk) {
  321. with_view_model(
  322. subghz_receiver->view, (SubghzReceiverModel * model) {
  323. if(model->frequency < subghz_frequencies_count) {
  324. subghz_rx_end(subghz_receiver->worker);
  325. model->real_frequency = subghz_rx(
  326. subghz_receiver->worker, subghz_frequencies[model->frequency]);
  327. subghz_receiver->hopper_state = SubGhzHopperStateOFF;
  328. } else {
  329. osTimerStart(subghz_receiver->timer, 1024 / 10);
  330. subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
  331. }
  332. if(subghz_history_get_item(model->history) == 0) {
  333. model->scene = ReceiverSceneStart;
  334. } else {
  335. model->scene = ReceiverSceneMain;
  336. }
  337. return true;
  338. });
  339. subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context);
  340. } else {
  341. with_view_model(
  342. subghz_receiver->view, (SubghzReceiverModel * model) {
  343. bool model_updated = false;
  344. if(event->key == InputKeyLeft) {
  345. if(model->frequency > 0) model->frequency--;
  346. model_updated = true;
  347. } else if(event->key == InputKeyRight) {
  348. if(model->frequency < subghz_frequencies_count) model->frequency++;
  349. model_updated = true;
  350. }
  351. if(model_updated) {
  352. model->real_frequency = subghz_frequencies[model->frequency];
  353. }
  354. return model_updated;
  355. });
  356. }
  357. break;
  358. case ReceiverSceneStart:
  359. if(event->key == InputKeyBack) {
  360. return false;
  361. } else if(event->key == InputKeyLeft) {
  362. subghz_receiver->hopper_state = SubGhzHopperStatePause;
  363. with_view_model(
  364. subghz_receiver->view, (SubghzReceiverModel * model) {
  365. model->temp_frequency = model->frequency;
  366. model->scene = ReceiverSceneConfig;
  367. return true;
  368. });
  369. subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context);
  370. }
  371. break;
  372. default:
  373. break;
  374. }
  375. subghz_receiver_update_offset(subghz_receiver);
  376. return true;
  377. }
  378. void subghz_receiver_text_callback(string_t text, void* context) {
  379. furi_assert(context);
  380. SubghzReceiver* subghz_receiver = context;
  381. with_view_model(
  382. subghz_receiver->view, (SubghzReceiverModel * model) {
  383. string_set(model->text, text);
  384. model->scene = ReceiverSceneMain;
  385. return true;
  386. });
  387. }
  388. void subghz_receiver_protocol_callback(SubGhzProtocolCommon* parser, void* context) {
  389. furi_assert(context);
  390. SubghzReceiver* subghz_receiver = context;
  391. with_view_model(
  392. subghz_receiver->view, (SubghzReceiverModel * model) {
  393. model->protocol_result = parser;
  394. subghz_history_set_frequency_preset(
  395. model->history,
  396. model->history_item,
  397. model->real_frequency,
  398. FuriHalSubGhzPresetOok650Async);
  399. subghz_history_add_to_history(model->history, parser);
  400. model->history_item = subghz_history_get_item(model->history);
  401. model->scene = ReceiverSceneMain;
  402. return true;
  403. });
  404. subghz_protocol_reset(subghz_receiver->protocol);
  405. subghz_receiver_update_offset(subghz_receiver);
  406. }
  407. static void subghz_receiver_timer_callback(void* context) {
  408. furi_assert(context);
  409. SubghzReceiver* subghz_receiver = context;
  410. switch(subghz_receiver->hopper_state) {
  411. case SubGhzHopperStateOFF:
  412. return;
  413. break;
  414. case SubGhzHopperStatePause:
  415. osTimerStart(subghz_receiver->timer, 1024 / 10);
  416. return;
  417. break;
  418. default:
  419. break;
  420. }
  421. float rssi = -127.0f;
  422. with_view_model(
  423. subghz_receiver->view, (SubghzReceiverModel * model) {
  424. // See RSSI Calculation timings in CC1101 17.3 RSSI
  425. rssi = furi_hal_subghz_get_rssi();
  426. // Stay if RSSI is high enough
  427. if(rssi > -90.0f) {
  428. osTimerStart(subghz_receiver->timer, 1024 / 4);
  429. return false;
  430. } else {
  431. osTimerStart(subghz_receiver->timer, 1024 / 10);
  432. }
  433. // Select next frequency
  434. if(model->frequency < COUNT_FREQUNCY_SCANER - 1) {
  435. model->frequency++;
  436. } else {
  437. model->frequency = 0;
  438. }
  439. // Restart radio
  440. subghz_rx_end(subghz_receiver->worker);
  441. subghz_protocol_reset(subghz_receiver->protocol);
  442. model->real_frequency =
  443. subghz_rx(subghz_receiver->worker, subghz_frequencies_scanner[model->frequency]);
  444. return true;
  445. });
  446. }
  447. void subghz_receiver_enter(void* context) {
  448. furi_assert(context);
  449. SubghzReceiver* subghz_receiver = context;
  450. //Start CC1101 Rx
  451. subghz_begin(FuriHalSubGhzPresetOok650Async);
  452. with_view_model(
  453. subghz_receiver->view, (SubghzReceiverModel * model) {
  454. subghz_rx_end(subghz_receiver->worker);
  455. model->frequency = subghz_frequencies_433_92;
  456. model->real_frequency =
  457. subghz_rx(subghz_receiver->worker, subghz_frequencies[model->frequency]);
  458. if(subghz_history_get_item(model->history) == 0) {
  459. model->scene = ReceiverSceneStart;
  460. } else {
  461. model->scene = ReceiverSceneMain;
  462. }
  463. return true;
  464. });
  465. subghz_protocol_enable_dump(
  466. subghz_receiver->protocol, subghz_receiver_protocol_callback, subghz_receiver);
  467. }
  468. void subghz_receiver_exit(void* context) {
  469. furi_assert(context);
  470. SubghzReceiver* subghz_receiver = context;
  471. osTimerStop(subghz_receiver->timer);
  472. with_view_model(
  473. subghz_receiver->view, (SubghzReceiverModel * model) {
  474. string_clean(model->text);
  475. return true;
  476. });
  477. // Stop CC1101 Rx
  478. subghz_rx_end(subghz_receiver->worker);
  479. subghz_sleep();
  480. }
  481. SubghzReceiver* subghz_receiver_alloc() {
  482. SubghzReceiver* subghz_receiver = furi_alloc(sizeof(SubghzReceiver));
  483. // View allocation and configuration
  484. subghz_receiver->view = view_alloc();
  485. view_allocate_model(subghz_receiver->view, ViewModelTypeLocking, sizeof(SubghzReceiverModel));
  486. view_set_context(subghz_receiver->view, subghz_receiver);
  487. view_set_draw_callback(subghz_receiver->view, (ViewDrawCallback)subghz_receiver_draw);
  488. view_set_input_callback(subghz_receiver->view, subghz_receiver_input);
  489. view_set_enter_callback(subghz_receiver->view, subghz_receiver_enter);
  490. view_set_exit_callback(subghz_receiver->view, subghz_receiver_exit);
  491. with_view_model(
  492. subghz_receiver->view, (SubghzReceiverModel * model) {
  493. string_init(model->text);
  494. model->history = subghz_history_alloc();
  495. return true;
  496. });
  497. subghz_receiver->timer =
  498. osTimerNew(subghz_receiver_timer_callback, osTimerOnce, subghz_receiver, NULL);
  499. subghz_receiver->hopper_state = SubGhzHopperStateOFF;
  500. return subghz_receiver;
  501. }
  502. void subghz_receiver_free(SubghzReceiver* subghz_receiver) {
  503. furi_assert(subghz_receiver);
  504. with_view_model(
  505. subghz_receiver->view, (SubghzReceiverModel * model) {
  506. string_clear(model->text);
  507. subghz_history_free(model->history);
  508. return false;
  509. });
  510. osTimerDelete(subghz_receiver->timer);
  511. view_free(subghz_receiver->view);
  512. free(subghz_receiver);
  513. }
  514. View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver) {
  515. furi_assert(subghz_receiver);
  516. return subghz_receiver->view;
  517. }
  518. uint32_t subghz_receiver_get_frequency(SubghzReceiver* subghz_receiver) {
  519. furi_assert(subghz_receiver);
  520. uint32_t frequency;
  521. with_view_model(
  522. subghz_receiver->view, (SubghzReceiverModel * model) {
  523. frequency = subghz_history_get_frequency(model->history, model->idx);
  524. return false;
  525. });
  526. return frequency;
  527. }
  528. FuriHalSubGhzPreset subghz_receiver_get_preset(SubghzReceiver* subghz_receiver) {
  529. furi_assert(subghz_receiver);
  530. FuriHalSubGhzPreset preset;
  531. with_view_model(
  532. subghz_receiver->view, (SubghzReceiverModel * model) {
  533. preset = subghz_history_get_preset(model->history, model->idx);
  534. return false;
  535. });
  536. return preset;
  537. }
  538. void subghz_receiver_frequency_preset_to_str(SubghzReceiver* subghz_receiver, string_t output) {
  539. furi_assert(subghz_receiver);
  540. uint32_t frequency;
  541. uint32_t preset;
  542. with_view_model(
  543. subghz_receiver->view, (SubghzReceiverModel * model) {
  544. frequency = subghz_history_get_frequency(model->history, model->idx);
  545. preset = (uint32_t)subghz_history_get_preset(model->history, model->idx);
  546. return false;
  547. });
  548. string_cat_printf(
  549. output,
  550. "Frequency: %d\n"
  551. "Preset: %d\n",
  552. (int)frequency,
  553. (int)preset);
  554. }