subghz_receiver.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  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. uint32_t event_key_sequence;
  50. };
  51. typedef struct {
  52. string_t text;
  53. uint16_t scene;
  54. SubGhzProtocolCommon* protocol_result;
  55. SubGhzHistory* history;
  56. uint8_t frequency;
  57. uint8_t temp_frequency;
  58. uint32_t real_frequency;
  59. uint16_t idx;
  60. uint16_t list_offset;
  61. uint16_t history_item;
  62. bool menu;
  63. } SubghzReceiverModel;
  64. void subghz_receiver_set_callback(
  65. SubghzReceiver* subghz_receiver,
  66. SubghzReceiverCallback callback,
  67. void* context) {
  68. furi_assert(subghz_receiver);
  69. furi_assert(callback);
  70. subghz_receiver->callback = callback;
  71. subghz_receiver->context = context;
  72. }
  73. void subghz_receiver_set_protocol(
  74. SubghzReceiver* subghz_receiver,
  75. SubGhzProtocolCommon* protocol_result,
  76. SubGhzProtocol* protocol) {
  77. furi_assert(subghz_receiver);
  78. with_view_model(
  79. subghz_receiver->view, (SubghzReceiverModel * model) {
  80. model->protocol_result = protocol_result;
  81. return true;
  82. });
  83. subghz_receiver->protocol = protocol;
  84. }
  85. SubGhzProtocolCommon* subghz_receiver_get_protocol(SubghzReceiver* subghz_receiver) {
  86. furi_assert(subghz_receiver);
  87. SubGhzProtocolCommon* result = NULL;
  88. with_view_model(
  89. subghz_receiver->view, (SubghzReceiverModel * model) {
  90. result = model->protocol_result;
  91. return false;
  92. });
  93. return result;
  94. }
  95. void subghz_receiver_set_worker(SubghzReceiver* subghz_receiver, SubGhzWorker* worker) {
  96. furi_assert(subghz_receiver);
  97. subghz_receiver->worker = worker;
  98. }
  99. static void subghz_receiver_update_offset(SubghzReceiver* subghz_receiver) {
  100. furi_assert(subghz_receiver);
  101. with_view_model(
  102. subghz_receiver->view, (SubghzReceiverModel * model) {
  103. size_t history_item = model->history_item;
  104. uint16_t bounds = history_item > 3 ? 2 : history_item;
  105. if(history_item > 3 && model->idx >= history_item - 1) {
  106. model->list_offset = model->idx - 3;
  107. } else if(model->list_offset < model->idx - bounds) {
  108. model->list_offset = CLAMP(model->list_offset + 1, history_item - bounds, 0);
  109. } else if(model->list_offset > model->idx - bounds) {
  110. model->list_offset = CLAMP(model->idx - 1, history_item - bounds, 0);
  111. }
  112. return true;
  113. });
  114. }
  115. static void subghz_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) {
  116. canvas_set_color(canvas, ColorBlack);
  117. canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT);
  118. canvas_set_color(canvas, ColorWhite);
  119. canvas_draw_dot(canvas, 0, 0 + idx * FRAME_HEIGHT);
  120. canvas_draw_dot(canvas, 1, 0 + idx * FRAME_HEIGHT);
  121. canvas_draw_dot(canvas, 0, (0 + idx * FRAME_HEIGHT) + 1);
  122. canvas_draw_dot(canvas, 0, (0 + idx * FRAME_HEIGHT) + 11);
  123. canvas_draw_dot(canvas, scrollbar ? 121 : 126, 0 + idx * FRAME_HEIGHT);
  124. canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11);
  125. }
  126. void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
  127. bool scrollbar = model->history_item > 4;
  128. string_t str_buff;
  129. char buffer[64];
  130. uint32_t frequency;
  131. string_init(str_buff);
  132. canvas_clear(canvas);
  133. canvas_set_color(canvas, ColorBlack);
  134. switch(model->scene) {
  135. case ReceiverSceneMain:
  136. for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) {
  137. size_t idx = CLAMP(i + model->list_offset, model->history_item, 0);
  138. subghz_history_get_text_item_menu(model->history, str_buff, idx);
  139. elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX);
  140. if(model->idx == idx) {
  141. subghz_receiver_draw_frame(canvas, i, scrollbar);
  142. } else {
  143. canvas_set_color(canvas, ColorBlack);
  144. }
  145. canvas_draw_icon(
  146. canvas,
  147. 1,
  148. 2 + i * FRAME_HEIGHT,
  149. ReceiverItemIcons[subghz_history_get_type_protocol(model->history, idx)]);
  150. canvas_draw_str(canvas, 15, 9 + i * FRAME_HEIGHT, string_get_cstr(str_buff));
  151. string_clean(str_buff);
  152. }
  153. if(scrollbar) {
  154. elements_scrollbar_pos(canvas, 128, 0, 49, model->idx, model->history_item);
  155. }
  156. canvas_set_color(canvas, ColorBlack);
  157. canvas_set_font(canvas, FontSecondary);
  158. elements_button_left(canvas, "Config");
  159. canvas_draw_line(canvas, 46, 51, 125, 51);
  160. if(subghz_history_get_text_space_left(model->history, str_buff)) {
  161. canvas_draw_str(canvas, 54, 62, string_get_cstr(str_buff));
  162. } else {
  163. if((model->real_frequency / 1000 % 10) > 4) {
  164. frequency = model->real_frequency + 10000;
  165. } else {
  166. frequency = model->real_frequency;
  167. }
  168. snprintf(
  169. buffer,
  170. sizeof(buffer),
  171. "%03ld.%02ld",
  172. frequency / 1000000 % 1000,
  173. frequency / 10000 % 100);
  174. canvas_draw_str(canvas, 44, 62, buffer);
  175. canvas_draw_str(canvas, 79, 62, "AM");
  176. canvas_draw_str(canvas, 96, 62, string_get_cstr(str_buff));
  177. }
  178. break;
  179. case ReceiverSceneStart:
  180. canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52);
  181. canvas_set_font(canvas, FontPrimary);
  182. canvas_draw_str(canvas, 63, 46, "Scanning...");
  183. canvas_set_color(canvas, ColorBlack);
  184. canvas_set_font(canvas, FontSecondary);
  185. elements_button_left(canvas, "Config");
  186. if((model->real_frequency / 1000 % 10) > 4) {
  187. frequency = model->real_frequency + 10000;
  188. } else {
  189. frequency = model->real_frequency;
  190. }
  191. snprintf(
  192. buffer,
  193. sizeof(buffer),
  194. "%03ld.%02ld",
  195. frequency / 1000000 % 1000,
  196. frequency / 10000 % 100);
  197. canvas_draw_str(canvas, 44, 62, buffer);
  198. canvas_draw_str(canvas, 79, 62, "AM");
  199. subghz_history_get_text_space_left(model->history, str_buff);
  200. canvas_draw_str(canvas, 96, 62, string_get_cstr(str_buff));
  201. canvas_draw_line(canvas, 46, 51, 125, 51);
  202. break;
  203. case ReceiverSceneConfig:
  204. if(model->frequency < subghz_frequencies_count) {
  205. snprintf(
  206. buffer,
  207. sizeof(buffer),
  208. "Frequency: < %03ld.%03ldMHz >",
  209. model->real_frequency / 1000000 % 1000,
  210. model->real_frequency / 1000 % 1000);
  211. canvas_draw_str(canvas, 0, 8, buffer);
  212. canvas_draw_str(canvas, 0, 18, "Frequency Hopping: <OFF>");
  213. } else {
  214. canvas_draw_str(canvas, 0, 8, "Frequency: < --- >");
  215. canvas_draw_str(canvas, 0, 18, "Frequency Hopping: <ON>");
  216. }
  217. canvas_draw_str(canvas, 0, 28, "Modulation: <AM>");
  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. void subghz_receiver_history_full(void* context) {
  242. furi_assert(context);
  243. SubghzReceiver* subghz_receiver = context;
  244. subghz_receiver->callback(SubghzReceverEventSendHistoryFull, subghz_receiver->context);
  245. subghz_receiver->hopper_state = SubGhzHopperStateOFF;
  246. }
  247. bool subghz_receiver_input(InputEvent* event, void* context) {
  248. furi_assert(context);
  249. uint8_t scene = 0;
  250. SubghzReceiver* subghz_receiver = context;
  251. with_view_model(
  252. subghz_receiver->view, (SubghzReceiverModel * model) {
  253. scene = model->scene;
  254. return false;
  255. });
  256. bool can_be_saved = false;
  257. switch(scene) {
  258. case ReceiverSceneMain:
  259. if(event->key == InputKeyBack && event->type == InputTypeShort) {
  260. with_view_model(
  261. subghz_receiver->view, (SubghzReceiverModel * model) {
  262. model->idx = 0;
  263. model->list_offset = 0;
  264. model->history_item = 0;
  265. subghz_history_clean(model->history);
  266. return true;
  267. });
  268. return false;
  269. } else if(
  270. event->key == InputKeyUp &&
  271. (event->type == InputTypeShort || event->type == InputTypeRepeat)) {
  272. with_view_model(
  273. subghz_receiver->view, (SubghzReceiverModel * model) {
  274. if(model->idx != 0) model->idx--;
  275. return true;
  276. });
  277. } else if(
  278. event->key == InputKeyDown &&
  279. (event->type == InputTypeShort || event->type == InputTypeRepeat)) {
  280. with_view_model(
  281. subghz_receiver->view, (SubghzReceiverModel * model) {
  282. if(model->idx != subghz_history_get_item(model->history) - 1) model->idx++;
  283. return true;
  284. });
  285. } else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
  286. subghz_receiver->hopper_state = SubGhzHopperStatePause;
  287. with_view_model(
  288. subghz_receiver->view, (SubghzReceiverModel * model) {
  289. model->scene = ReceiverSceneConfig;
  290. model->temp_frequency = model->frequency;
  291. return true;
  292. });
  293. subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context);
  294. } else if(event->key == InputKeyOk && event->type == InputTypeShort) {
  295. subghz_receiver->event_key_sequence = event->sequence;
  296. with_view_model(
  297. subghz_receiver->view, (SubghzReceiverModel * model) {
  298. string_clean(model->text);
  299. model->protocol_result = subghz_protocol_get_by_name(
  300. subghz_receiver->protocol,
  301. subghz_history_get_name(model->history, model->idx));
  302. if(model->protocol_result->to_load_protocol != NULL) {
  303. model->protocol_result->to_load_protocol(
  304. model->protocol_result,
  305. subghz_history_get_raw_data(model->history, model->idx));
  306. model->protocol_result->to_string(model->protocol_result, model->text);
  307. model->scene = ReceiverSceneInfo;
  308. }
  309. return true;
  310. });
  311. }
  312. break;
  313. case ReceiverSceneInfo:
  314. with_view_model(
  315. subghz_receiver->view, (SubghzReceiverModel * model) {
  316. can_be_saved =
  317. (model->protocol_result && model->protocol_result->to_save_string &&
  318. strcmp(model->protocol_result->name, "KeeLoq"));
  319. return false;
  320. });
  321. if(event->key == InputKeyBack && event->type == InputTypeShort) {
  322. with_view_model(
  323. subghz_receiver->view, (SubghzReceiverModel * model) {
  324. subghz_rx_end(subghz_receiver->worker);
  325. model->real_frequency =
  326. subghz_rx(subghz_receiver->worker, subghz_frequencies[model->frequency]);
  327. subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
  328. model->scene = ReceiverSceneMain;
  329. return true;
  330. });
  331. subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context);
  332. } else if(can_be_saved && event->key == InputKeyRight) {
  333. subghz_receiver->callback(SubghzReceverEventSave, subghz_receiver->context);
  334. return false;
  335. } else if(
  336. can_be_saved && event->key == InputKeyOk && event->type == InputTypePress &&
  337. subghz_receiver->event_key_sequence != event->sequence) {
  338. subghz_receiver->hopper_state = SubGhzHopperStatePause;
  339. subghz_rx_end(subghz_receiver->worker);
  340. subghz_receiver->callback(SubghzReceverEventSendStart, subghz_receiver->context);
  341. return true;
  342. } else if(
  343. can_be_saved && event->key == InputKeyOk && event->type == InputTypeRelease &&
  344. subghz_receiver->event_key_sequence != event->sequence) {
  345. subghz_receiver->callback(SubghzReceverEventSendStop, subghz_receiver->context);
  346. return true;
  347. }
  348. break;
  349. case ReceiverSceneConfig:
  350. if(event->type != InputTypeShort) return false;
  351. if(event->key == InputKeyBack) {
  352. with_view_model(
  353. subghz_receiver->view, (SubghzReceiverModel * model) {
  354. model->frequency = model->temp_frequency;
  355. model->real_frequency = subghz_frequencies[model->frequency];
  356. subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
  357. if(subghz_history_get_item(model->history) == 0) {
  358. model->scene = ReceiverSceneStart;
  359. } else {
  360. model->scene = ReceiverSceneMain;
  361. }
  362. return true;
  363. });
  364. subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context);
  365. } else if(event->key == InputKeyOk) {
  366. with_view_model(
  367. subghz_receiver->view, (SubghzReceiverModel * model) {
  368. if(model->frequency < subghz_frequencies_count) {
  369. subghz_rx_end(subghz_receiver->worker);
  370. model->real_frequency = subghz_rx(
  371. subghz_receiver->worker, subghz_frequencies[model->frequency]);
  372. subghz_receiver->hopper_state = SubGhzHopperStateOFF;
  373. } else {
  374. osTimerStart(subghz_receiver->timer, 1024 / 10);
  375. subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
  376. }
  377. if(subghz_history_get_item(model->history) == 0) {
  378. model->scene = ReceiverSceneStart;
  379. } else {
  380. model->scene = ReceiverSceneMain;
  381. }
  382. return true;
  383. });
  384. subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context);
  385. } else {
  386. with_view_model(
  387. subghz_receiver->view, (SubghzReceiverModel * model) {
  388. bool model_updated = false;
  389. if(event->key == InputKeyLeft) {
  390. if(model->frequency > 0) model->frequency--;
  391. model_updated = true;
  392. } else if(event->key == InputKeyRight) {
  393. if(model->frequency < subghz_frequencies_count) model->frequency++;
  394. model_updated = true;
  395. }
  396. if(model_updated) {
  397. model->real_frequency = subghz_frequencies[model->frequency];
  398. }
  399. return model_updated;
  400. });
  401. }
  402. break;
  403. case ReceiverSceneStart:
  404. if(event->type != InputTypeShort) return false;
  405. if(event->key == InputKeyBack) {
  406. return false;
  407. } else if(event->key == InputKeyLeft) {
  408. subghz_receiver->hopper_state = SubGhzHopperStatePause;
  409. with_view_model(
  410. subghz_receiver->view, (SubghzReceiverModel * model) {
  411. model->temp_frequency = model->frequency;
  412. model->scene = ReceiverSceneConfig;
  413. return true;
  414. });
  415. subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context);
  416. }
  417. break;
  418. default:
  419. break;
  420. }
  421. subghz_receiver_update_offset(subghz_receiver);
  422. if(scene != ReceiverSceneInfo) {
  423. with_view_model(
  424. subghz_receiver->view, (SubghzReceiverModel * model) {
  425. if(subghz_history_get_text_space_left(model->history, NULL)) {
  426. subghz_receiver_history_full(subghz_receiver);
  427. }
  428. return false;
  429. });
  430. }
  431. return true;
  432. }
  433. void subghz_receiver_text_callback(string_t text, void* context) {
  434. furi_assert(context);
  435. SubghzReceiver* subghz_receiver = context;
  436. with_view_model(
  437. subghz_receiver->view, (SubghzReceiverModel * model) {
  438. string_set(model->text, text);
  439. model->scene = ReceiverSceneMain;
  440. return true;
  441. });
  442. }
  443. void subghz_receiver_protocol_callback(SubGhzProtocolCommon* parser, void* context) {
  444. furi_assert(context);
  445. SubghzReceiver* subghz_receiver = context;
  446. with_view_model(
  447. subghz_receiver->view, (SubghzReceiverModel * model) {
  448. model->protocol_result = parser;
  449. subghz_history_set_frequency_preset(
  450. model->history,
  451. model->history_item,
  452. model->real_frequency,
  453. FuriHalSubGhzPresetOok650Async);
  454. subghz_history_add_to_history(model->history, parser);
  455. model->history_item = subghz_history_get_item(model->history);
  456. model->scene = ReceiverSceneMain;
  457. if(subghz_history_get_text_space_left(model->history, NULL)) {
  458. subghz_receiver_history_full(subghz_receiver);
  459. }
  460. return true;
  461. });
  462. subghz_protocol_reset(subghz_receiver->protocol);
  463. subghz_receiver_update_offset(subghz_receiver);
  464. }
  465. static void subghz_receiver_timer_callback(void* context) {
  466. furi_assert(context);
  467. SubghzReceiver* subghz_receiver = context;
  468. switch(subghz_receiver->hopper_state) {
  469. case SubGhzHopperStatePause:
  470. return;
  471. break;
  472. case SubGhzHopperStateOFF:
  473. osTimerStop(subghz_receiver->timer);
  474. return;
  475. break;
  476. case SubGhzHopperStateRSSITimeOut:
  477. if(subghz_receiver->hopper_timeout != 0) {
  478. subghz_receiver->hopper_timeout--;
  479. return;
  480. }
  481. break;
  482. default:
  483. break;
  484. }
  485. float rssi = -127.0f;
  486. with_view_model(
  487. subghz_receiver->view, (SubghzReceiverModel * model) {
  488. if(subghz_receiver->hopper_state != SubGhzHopperStateRSSITimeOut) {
  489. // See RSSI Calculation timings in CC1101 17.3 RSSI
  490. rssi = furi_hal_subghz_get_rssi();
  491. // Stay if RSSI is high enough
  492. if(rssi > -90.0f) {
  493. subghz_receiver->hopper_timeout = 10;
  494. subghz_receiver->hopper_state = SubGhzHopperStateRSSITimeOut;
  495. return false;
  496. }
  497. } else {
  498. subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
  499. }
  500. // Select next frequency
  501. if(model->frequency < COUNT_FREQUNCY_HOPPER - 1) {
  502. model->frequency++;
  503. } else {
  504. model->frequency = 0;
  505. }
  506. // Restart radio
  507. furi_hal_subghz_idle();
  508. subghz_protocol_reset(subghz_receiver->protocol);
  509. model->real_frequency = furi_hal_subghz_set_frequency_and_path(
  510. subghz_frequencies_hopper[model->frequency]);
  511. furi_hal_subghz_rx();
  512. return true;
  513. });
  514. }
  515. void subghz_receiver_enter(void* context) {
  516. furi_assert(context);
  517. SubghzReceiver* subghz_receiver = context;
  518. //Start CC1101 Rx
  519. subghz_begin(FuriHalSubGhzPresetOok650Async);
  520. with_view_model(
  521. subghz_receiver->view, (SubghzReceiverModel * model) {
  522. subghz_rx_end(subghz_receiver->worker);
  523. model->frequency = subghz_frequencies_433_92;
  524. model->real_frequency =
  525. subghz_rx(subghz_receiver->worker, subghz_frequencies[model->frequency]);
  526. if(subghz_history_get_item(model->history) == 0) {
  527. model->scene = ReceiverSceneStart;
  528. } else {
  529. model->scene = ReceiverSceneMain;
  530. }
  531. return true;
  532. });
  533. subghz_protocol_enable_dump(
  534. subghz_receiver->protocol, subghz_receiver_protocol_callback, subghz_receiver);
  535. }
  536. void subghz_receiver_exit(void* context) {
  537. furi_assert(context);
  538. SubghzReceiver* subghz_receiver = context;
  539. osTimerStop(subghz_receiver->timer);
  540. with_view_model(
  541. subghz_receiver->view, (SubghzReceiverModel * model) {
  542. string_clean(model->text);
  543. return true;
  544. });
  545. // Stop CC1101 Rx
  546. subghz_rx_end(subghz_receiver->worker);
  547. subghz_sleep();
  548. }
  549. SubghzReceiver* subghz_receiver_alloc() {
  550. SubghzReceiver* subghz_receiver = furi_alloc(sizeof(SubghzReceiver));
  551. // View allocation and configuration
  552. subghz_receiver->view = view_alloc();
  553. view_allocate_model(subghz_receiver->view, ViewModelTypeLocking, sizeof(SubghzReceiverModel));
  554. view_set_context(subghz_receiver->view, subghz_receiver);
  555. view_set_draw_callback(subghz_receiver->view, (ViewDrawCallback)subghz_receiver_draw);
  556. view_set_input_callback(subghz_receiver->view, subghz_receiver_input);
  557. view_set_enter_callback(subghz_receiver->view, subghz_receiver_enter);
  558. view_set_exit_callback(subghz_receiver->view, subghz_receiver_exit);
  559. with_view_model(
  560. subghz_receiver->view, (SubghzReceiverModel * model) {
  561. string_init(model->text);
  562. model->history = subghz_history_alloc();
  563. return true;
  564. });
  565. subghz_receiver->timer =
  566. osTimerNew(subghz_receiver_timer_callback, osTimerPeriodic, subghz_receiver, NULL);
  567. subghz_receiver->hopper_state = SubGhzHopperStateOFF;
  568. return subghz_receiver;
  569. }
  570. void subghz_receiver_free(SubghzReceiver* subghz_receiver) {
  571. furi_assert(subghz_receiver);
  572. with_view_model(
  573. subghz_receiver->view, (SubghzReceiverModel * model) {
  574. string_clear(model->text);
  575. subghz_history_free(model->history);
  576. return false;
  577. });
  578. osTimerDelete(subghz_receiver->timer);
  579. view_free(subghz_receiver->view);
  580. free(subghz_receiver);
  581. }
  582. View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver) {
  583. furi_assert(subghz_receiver);
  584. return subghz_receiver->view;
  585. }
  586. uint32_t subghz_receiver_get_frequency(SubghzReceiver* subghz_receiver) {
  587. furi_assert(subghz_receiver);
  588. uint32_t frequency;
  589. with_view_model(
  590. subghz_receiver->view, (SubghzReceiverModel * model) {
  591. frequency = subghz_history_get_frequency(model->history, model->idx);
  592. return false;
  593. });
  594. return frequency;
  595. }
  596. FuriHalSubGhzPreset subghz_receiver_get_preset(SubghzReceiver* subghz_receiver) {
  597. furi_assert(subghz_receiver);
  598. FuriHalSubGhzPreset preset;
  599. with_view_model(
  600. subghz_receiver->view, (SubghzReceiverModel * model) {
  601. preset = subghz_history_get_preset(model->history, model->idx);
  602. return false;
  603. });
  604. return preset;
  605. }
  606. void subghz_receiver_frequency_preset_to_str(SubghzReceiver* subghz_receiver, string_t output) {
  607. furi_assert(subghz_receiver);
  608. uint32_t frequency;
  609. uint32_t preset;
  610. with_view_model(
  611. subghz_receiver->view, (SubghzReceiverModel * model) {
  612. frequency = subghz_history_get_frequency(model->history, model->idx);
  613. preset = (uint32_t)subghz_history_get_preset(model->history, model->idx);
  614. return false;
  615. });
  616. string_cat_printf(
  617. output,
  618. "Frequency: %d\n"
  619. "Preset: %d\n",
  620. (int)frequency,
  621. (int)preset);
  622. }