subghz_receiver.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  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_HOPPER 3
  15. const uint32_t subghz_frequencies_hopper[] = {
  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. SubGhzHopperStateRSSITimeOut,
  34. } SubGhzHopperState;
  35. static const Icon* ReceiverItemIcons[] = {
  36. [TYPE_PROTOCOL_UNKNOWN] = &I_quest_7x8,
  37. [TYPE_PROTOCOL_STATIC] = &I_unlock_7x8,
  38. [TYPE_PROTOCOL_DYNAMIC] = &I_lock_7x8,
  39. };
  40. struct SubghzReceiver {
  41. View* view;
  42. SubghzReceiverCallback callback;
  43. void* context;
  44. SubGhzWorker* worker;
  45. SubGhzProtocol* protocol;
  46. osTimerId timer;
  47. SubGhzHopperState hopper_state;
  48. uint8_t hopper_timeout;
  49. };
  50. typedef struct {
  51. string_t text;
  52. uint16_t scene;
  53. SubGhzProtocolCommon* protocol_result;
  54. SubGhzHistory* history;
  55. uint8_t frequency;
  56. uint8_t temp_frequency;
  57. uint32_t real_frequency;
  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. uint32_t frequency;
  130. string_init(str_buff);
  131. canvas_clear(canvas);
  132. canvas_set_color(canvas, ColorBlack);
  133. switch(model->scene) {
  134. case ReceiverSceneMain:
  135. for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) {
  136. size_t idx = CLAMP(i + model->list_offset, model->history_item, 0);
  137. subghz_history_get_text_item_menu(model->history, str_buff, idx);
  138. elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX);
  139. if(model->idx == idx) {
  140. subghz_receiver_draw_frame(canvas, i, scrollbar);
  141. } else {
  142. canvas_set_color(canvas, ColorBlack);
  143. }
  144. canvas_draw_icon(
  145. canvas,
  146. 1,
  147. 2 + i * FRAME_HEIGHT,
  148. ReceiverItemIcons[subghz_history_get_type_protocol(model->history, idx)]);
  149. canvas_draw_str(canvas, 15, 9 + i * FRAME_HEIGHT, string_get_cstr(str_buff));
  150. string_clean(str_buff);
  151. }
  152. if(scrollbar) {
  153. elements_scrollbar_pos(canvas, 126, 0, 49, model->idx, model->history_item);
  154. }
  155. canvas_set_color(canvas, ColorBlack);
  156. canvas_set_font(canvas, FontSecondary);
  157. elements_button_left(canvas, "Conf");
  158. if((model->real_frequency / 1000 % 10) > 4) {
  159. frequency = model->real_frequency + 10000;
  160. } else {
  161. frequency = model->real_frequency;
  162. }
  163. snprintf(
  164. buffer,
  165. sizeof(buffer),
  166. "%03ld.%02ld",
  167. frequency / 1000000 % 1000,
  168. frequency / 10000 % 100);
  169. canvas_draw_str(canvas, 40, 62, buffer);
  170. canvas_draw_str(canvas, 75, 62, "AM");
  171. subghz_history_get_text_space_left(model->history, str_buff);
  172. canvas_draw_str(canvas, 94, 62, string_get_cstr(str_buff));
  173. canvas_draw_line(canvas, 38, 51, 125, 51);
  174. break;
  175. case ReceiverSceneStart:
  176. canvas_draw_icon(canvas, 0, 0, &I_RFIDDolphinReceive_97x61);
  177. canvas_invert_color(canvas);
  178. canvas_draw_box(canvas, 80, 2, 20, 20);
  179. canvas_invert_color(canvas);
  180. canvas_draw_icon(canvas, 75, 8, &I_sub1_10px);
  181. canvas_set_font(canvas, FontPrimary);
  182. canvas_draw_str(canvas, 63, 40, "Scanning...");
  183. canvas_set_color(canvas, ColorBlack);
  184. canvas_set_font(canvas, FontSecondary);
  185. elements_button_left(canvas, "Conf");
  186. canvas_invert_color(canvas);
  187. canvas_draw_box(canvas, 38, 52, 10, 10);
  188. canvas_invert_color(canvas);
  189. if((model->real_frequency / 1000 % 10) > 4) {
  190. frequency = model->real_frequency + 10000;
  191. } else {
  192. frequency = model->real_frequency;
  193. }
  194. snprintf(
  195. buffer,
  196. sizeof(buffer),
  197. "%03ld.%02ld",
  198. frequency / 1000000 % 1000,
  199. frequency / 10000 % 100);
  200. canvas_draw_str(canvas, 40, 62, buffer);
  201. canvas_draw_str(canvas, 75, 62, "AM");
  202. subghz_history_get_text_space_left(model->history, str_buff);
  203. canvas_draw_str(canvas, 94, 62, string_get_cstr(str_buff));
  204. canvas_draw_line(canvas, 48, 51, 125, 51);
  205. break;
  206. case ReceiverSceneConfig:
  207. if(model->frequency < subghz_frequencies_count) {
  208. snprintf(
  209. buffer,
  210. sizeof(buffer),
  211. "Frequency: < %03ld.%03ldMHz >",
  212. model->real_frequency / 1000000 % 1000,
  213. model->real_frequency / 1000 % 1000);
  214. canvas_draw_str(canvas, 0, 8, buffer);
  215. } else {
  216. canvas_draw_str(canvas, 0, 8, "Frequency: <auto>");
  217. }
  218. elements_button_center(canvas, "Save");
  219. break;
  220. case ReceiverSceneInfo:
  221. canvas_set_font(canvas, FontSecondary);
  222. elements_multiline_text(canvas, 0, 8, string_get_cstr(model->text));
  223. snprintf(
  224. buffer,
  225. sizeof(buffer),
  226. "%03ld.%03ld",
  227. subghz_history_get_frequency(model->history, model->idx) / 1000000 % 1000,
  228. subghz_history_get_frequency(model->history, model->idx) / 1000 % 1000);
  229. canvas_draw_str(canvas, 90, 8, buffer);
  230. if(model->protocol_result && model->protocol_result->to_save_string &&
  231. strcmp(model->protocol_result->name, "KeeLoq")) {
  232. elements_button_right(canvas, "Save");
  233. elements_button_center(canvas, "Send");
  234. }
  235. break;
  236. default:
  237. break;
  238. }
  239. string_clear(str_buff);
  240. }
  241. bool subghz_receiver_input(InputEvent* event, void* context) {
  242. furi_assert(context);
  243. uint8_t scene = 0;
  244. SubghzReceiver* subghz_receiver = context;
  245. with_view_model(
  246. subghz_receiver->view, (SubghzReceiverModel * model) {
  247. scene = model->scene;
  248. return false;
  249. });
  250. if(scene != ReceiverSceneInfo && event->type != InputTypeShort) return false;
  251. bool can_be_saved = false;
  252. switch(scene) {
  253. case ReceiverSceneMain:
  254. if(event->key == InputKeyBack) {
  255. with_view_model(
  256. subghz_receiver->view, (SubghzReceiverModel * model) {
  257. model->idx = 0;
  258. model->list_offset = 0;
  259. model->history_item = 0;
  260. subghz_history_clean(model->history);
  261. return true;
  262. });
  263. return false;
  264. } else if(event->key == InputKeyUp) {
  265. with_view_model(
  266. subghz_receiver->view, (SubghzReceiverModel * model) {
  267. if(model->idx != 0) model->idx--;
  268. return true;
  269. });
  270. } else if(event->key == InputKeyDown) {
  271. with_view_model(
  272. subghz_receiver->view, (SubghzReceiverModel * model) {
  273. if(model->idx != subghz_history_get_item(model->history) - 1) model->idx++;
  274. return true;
  275. });
  276. } else if(event->key == InputKeyLeft) {
  277. subghz_receiver->hopper_state = SubGhzHopperStatePause;
  278. with_view_model(
  279. subghz_receiver->view, (SubghzReceiverModel * model) {
  280. model->scene = ReceiverSceneConfig;
  281. model->temp_frequency = model->frequency;
  282. return true;
  283. });
  284. subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context);
  285. } else if(event->key == InputKeyOk) {
  286. with_view_model(
  287. subghz_receiver->view, (SubghzReceiverModel * model) {
  288. string_clean(model->text);
  289. model->protocol_result = subghz_protocol_get_by_name(
  290. subghz_receiver->protocol,
  291. subghz_history_get_name(model->history, model->idx));
  292. if(model->protocol_result->to_load_protocol != NULL) {
  293. model->protocol_result->to_load_protocol(
  294. model->protocol_result,
  295. subghz_history_get_raw_data(model->history, model->idx));
  296. model->protocol_result->to_string(model->protocol_result, model->text);
  297. model->scene = ReceiverSceneInfo;
  298. }
  299. return true;
  300. });
  301. }
  302. break;
  303. case ReceiverSceneInfo:
  304. with_view_model(
  305. subghz_receiver->view, (SubghzReceiverModel * model) {
  306. can_be_saved =
  307. (model->protocol_result && model->protocol_result->to_save_string &&
  308. strcmp(model->protocol_result->name, "KeeLoq"));
  309. return false;
  310. });
  311. if(event->key == InputKeyBack && event->type == InputTypeShort) {
  312. with_view_model(
  313. subghz_receiver->view, (SubghzReceiverModel * model) {
  314. subghz_rx_end(subghz_receiver->worker);
  315. model->real_frequency =
  316. subghz_rx(subghz_receiver->worker, subghz_frequencies[model->frequency]);
  317. subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
  318. model->scene = ReceiverSceneMain;
  319. return true;
  320. });
  321. subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context);
  322. } else if(can_be_saved && event->key == InputKeyRight) {
  323. subghz_receiver->callback(SubghzReceverEventSave, subghz_receiver->context);
  324. return false;
  325. } else if(can_be_saved && event->key == InputKeyOk && event->type == InputTypePress) {
  326. subghz_receiver->hopper_state = SubGhzHopperStatePause;
  327. subghz_rx_end(subghz_receiver->worker);
  328. subghz_receiver->callback(SubghzReceverEventSendStart, subghz_receiver->context);
  329. return true;
  330. } else if(can_be_saved && event->key == InputKeyOk && event->type == InputTypeRelease) {
  331. subghz_receiver->callback(SubghzReceverEventSendStop, subghz_receiver->context);
  332. return true;
  333. }
  334. break;
  335. case ReceiverSceneConfig:
  336. if(event->key == InputKeyBack) {
  337. with_view_model(
  338. subghz_receiver->view, (SubghzReceiverModel * model) {
  339. model->frequency = model->temp_frequency;
  340. model->real_frequency = subghz_frequencies[model->frequency];
  341. subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
  342. if(subghz_history_get_item(model->history) == 0) {
  343. model->scene = ReceiverSceneStart;
  344. } else {
  345. model->scene = ReceiverSceneMain;
  346. }
  347. return true;
  348. });
  349. subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context);
  350. } else if(event->key == InputKeyOk) {
  351. with_view_model(
  352. subghz_receiver->view, (SubghzReceiverModel * model) {
  353. if(model->frequency < subghz_frequencies_count) {
  354. subghz_rx_end(subghz_receiver->worker);
  355. model->real_frequency = subghz_rx(
  356. subghz_receiver->worker, subghz_frequencies[model->frequency]);
  357. subghz_receiver->hopper_state = SubGhzHopperStateOFF;
  358. } else {
  359. osTimerStart(subghz_receiver->timer, 1024 / 10);
  360. subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
  361. }
  362. if(subghz_history_get_item(model->history) == 0) {
  363. model->scene = ReceiverSceneStart;
  364. } else {
  365. model->scene = ReceiverSceneMain;
  366. }
  367. return true;
  368. });
  369. subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context);
  370. } else {
  371. with_view_model(
  372. subghz_receiver->view, (SubghzReceiverModel * model) {
  373. bool model_updated = false;
  374. if(event->key == InputKeyLeft) {
  375. if(model->frequency > 0) model->frequency--;
  376. model_updated = true;
  377. } else if(event->key == InputKeyRight) {
  378. if(model->frequency < subghz_frequencies_count) model->frequency++;
  379. model_updated = true;
  380. }
  381. if(model_updated) {
  382. model->real_frequency = subghz_frequencies[model->frequency];
  383. }
  384. return model_updated;
  385. });
  386. }
  387. break;
  388. case ReceiverSceneStart:
  389. if(event->key == InputKeyBack) {
  390. return false;
  391. } else if(event->key == InputKeyLeft) {
  392. subghz_receiver->hopper_state = SubGhzHopperStatePause;
  393. with_view_model(
  394. subghz_receiver->view, (SubghzReceiverModel * model) {
  395. model->temp_frequency = model->frequency;
  396. model->scene = ReceiverSceneConfig;
  397. return true;
  398. });
  399. subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context);
  400. }
  401. break;
  402. default:
  403. break;
  404. }
  405. subghz_receiver_update_offset(subghz_receiver);
  406. return true;
  407. }
  408. void subghz_receiver_text_callback(string_t text, void* context) {
  409. furi_assert(context);
  410. SubghzReceiver* subghz_receiver = context;
  411. with_view_model(
  412. subghz_receiver->view, (SubghzReceiverModel * model) {
  413. string_set(model->text, text);
  414. model->scene = ReceiverSceneMain;
  415. return true;
  416. });
  417. }
  418. void subghz_receiver_protocol_callback(SubGhzProtocolCommon* parser, void* context) {
  419. furi_assert(context);
  420. SubghzReceiver* subghz_receiver = context;
  421. with_view_model(
  422. subghz_receiver->view, (SubghzReceiverModel * model) {
  423. model->protocol_result = parser;
  424. subghz_history_set_frequency_preset(
  425. model->history,
  426. model->history_item,
  427. model->real_frequency,
  428. FuriHalSubGhzPresetOok650Async);
  429. subghz_history_add_to_history(model->history, parser);
  430. model->history_item = subghz_history_get_item(model->history);
  431. model->scene = ReceiverSceneMain;
  432. return true;
  433. });
  434. subghz_protocol_reset(subghz_receiver->protocol);
  435. subghz_receiver_update_offset(subghz_receiver);
  436. }
  437. static void subghz_receiver_timer_callback(void* context) {
  438. furi_assert(context);
  439. SubghzReceiver* subghz_receiver = context;
  440. switch(subghz_receiver->hopper_state) {
  441. case SubGhzHopperStatePause:
  442. return;
  443. break;
  444. case SubGhzHopperStateOFF:
  445. osTimerStop(subghz_receiver->timer);
  446. return;
  447. break;
  448. case SubGhzHopperStateRSSITimeOut:
  449. if(subghz_receiver->hopper_timeout != 0) {
  450. subghz_receiver->hopper_timeout--;
  451. return;
  452. }
  453. break;
  454. default:
  455. break;
  456. }
  457. float rssi = -127.0f;
  458. with_view_model(
  459. subghz_receiver->view, (SubghzReceiverModel * model) {
  460. if(subghz_receiver->hopper_state != SubGhzHopperStateRSSITimeOut) {
  461. // See RSSI Calculation timings in CC1101 17.3 RSSI
  462. rssi = furi_hal_subghz_get_rssi();
  463. // Stay if RSSI is high enough
  464. if(rssi > -90.0f) {
  465. subghz_receiver->hopper_timeout = 10;
  466. subghz_receiver->hopper_state = SubGhzHopperStateRSSITimeOut;
  467. return false;
  468. }
  469. } else {
  470. subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
  471. }
  472. // Select next frequency
  473. if(model->frequency < COUNT_FREQUNCY_HOPPER - 1) {
  474. model->frequency++;
  475. } else {
  476. model->frequency = 0;
  477. }
  478. // Restart radio
  479. subghz_rx_end(subghz_receiver->worker);
  480. subghz_protocol_reset(subghz_receiver->protocol);
  481. model->real_frequency =
  482. subghz_rx(subghz_receiver->worker, subghz_frequencies_hopper[model->frequency]);
  483. return true;
  484. });
  485. }
  486. void subghz_receiver_enter(void* context) {
  487. furi_assert(context);
  488. SubghzReceiver* subghz_receiver = context;
  489. //Start CC1101 Rx
  490. subghz_begin(FuriHalSubGhzPresetOok650Async);
  491. with_view_model(
  492. subghz_receiver->view, (SubghzReceiverModel * model) {
  493. subghz_rx_end(subghz_receiver->worker);
  494. model->frequency = subghz_frequencies_433_92;
  495. model->real_frequency =
  496. subghz_rx(subghz_receiver->worker, subghz_frequencies[model->frequency]);
  497. if(subghz_history_get_item(model->history) == 0) {
  498. model->scene = ReceiverSceneStart;
  499. } else {
  500. model->scene = ReceiverSceneMain;
  501. }
  502. return true;
  503. });
  504. subghz_protocol_enable_dump(
  505. subghz_receiver->protocol, subghz_receiver_protocol_callback, subghz_receiver);
  506. }
  507. void subghz_receiver_exit(void* context) {
  508. furi_assert(context);
  509. SubghzReceiver* subghz_receiver = context;
  510. osTimerStop(subghz_receiver->timer);
  511. with_view_model(
  512. subghz_receiver->view, (SubghzReceiverModel * model) {
  513. string_clean(model->text);
  514. return true;
  515. });
  516. // Stop CC1101 Rx
  517. subghz_rx_end(subghz_receiver->worker);
  518. subghz_sleep();
  519. }
  520. SubghzReceiver* subghz_receiver_alloc() {
  521. SubghzReceiver* subghz_receiver = furi_alloc(sizeof(SubghzReceiver));
  522. // View allocation and configuration
  523. subghz_receiver->view = view_alloc();
  524. view_allocate_model(subghz_receiver->view, ViewModelTypeLocking, sizeof(SubghzReceiverModel));
  525. view_set_context(subghz_receiver->view, subghz_receiver);
  526. view_set_draw_callback(subghz_receiver->view, (ViewDrawCallback)subghz_receiver_draw);
  527. view_set_input_callback(subghz_receiver->view, subghz_receiver_input);
  528. view_set_enter_callback(subghz_receiver->view, subghz_receiver_enter);
  529. view_set_exit_callback(subghz_receiver->view, subghz_receiver_exit);
  530. with_view_model(
  531. subghz_receiver->view, (SubghzReceiverModel * model) {
  532. string_init(model->text);
  533. model->history = subghz_history_alloc();
  534. return true;
  535. });
  536. subghz_receiver->timer =
  537. osTimerNew(subghz_receiver_timer_callback, osTimerPeriodic, subghz_receiver, NULL);
  538. subghz_receiver->hopper_state = SubGhzHopperStateOFF;
  539. return subghz_receiver;
  540. }
  541. void subghz_receiver_free(SubghzReceiver* subghz_receiver) {
  542. furi_assert(subghz_receiver);
  543. with_view_model(
  544. subghz_receiver->view, (SubghzReceiverModel * model) {
  545. string_clear(model->text);
  546. subghz_history_free(model->history);
  547. return false;
  548. });
  549. osTimerDelete(subghz_receiver->timer);
  550. view_free(subghz_receiver->view);
  551. free(subghz_receiver);
  552. }
  553. View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver) {
  554. furi_assert(subghz_receiver);
  555. return subghz_receiver->view;
  556. }
  557. uint32_t subghz_receiver_get_frequency(SubghzReceiver* subghz_receiver) {
  558. furi_assert(subghz_receiver);
  559. uint32_t frequency;
  560. with_view_model(
  561. subghz_receiver->view, (SubghzReceiverModel * model) {
  562. frequency = subghz_history_get_frequency(model->history, model->idx);
  563. return false;
  564. });
  565. return frequency;
  566. }
  567. FuriHalSubGhzPreset subghz_receiver_get_preset(SubghzReceiver* subghz_receiver) {
  568. furi_assert(subghz_receiver);
  569. FuriHalSubGhzPreset preset;
  570. with_view_model(
  571. subghz_receiver->view, (SubghzReceiverModel * model) {
  572. preset = subghz_history_get_preset(model->history, model->idx);
  573. return false;
  574. });
  575. return preset;
  576. }
  577. void subghz_receiver_frequency_preset_to_str(SubghzReceiver* subghz_receiver, string_t output) {
  578. furi_assert(subghz_receiver);
  579. uint32_t frequency;
  580. uint32_t preset;
  581. with_view_model(
  582. subghz_receiver->view, (SubghzReceiverModel * model) {
  583. frequency = subghz_history_get_frequency(model->history, model->idx);
  584. preset = (uint32_t)subghz_history_get_preset(model->history, model->idx);
  585. return false;
  586. });
  587. string_cat_printf(
  588. output,
  589. "Frequency: %d\n"
  590. "Preset: %d\n",
  591. (int)frequency,
  592. (int)preset);
  593. }