subghz_read_raw.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. #include "subghz_read_raw.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 <assets_icons.h>
  9. #define SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE 100
  10. #define TAG "SubGhzReadRAW"
  11. struct SubGhzReadRAW {
  12. View* view;
  13. SubGhzReadRAWCallback callback;
  14. void* context;
  15. };
  16. typedef struct {
  17. FuriString* frequency_str;
  18. FuriString* preset_str;
  19. FuriString* sample_write;
  20. FuriString* file_name;
  21. uint8_t* rssi_history;
  22. uint8_t rssi_curret;
  23. bool rssi_history_end;
  24. uint8_t ind_write;
  25. uint8_t ind_sin;
  26. SubGhzReadRAWStatus status;
  27. float raw_threshold_rssi;
  28. } SubGhzReadRAWModel;
  29. void subghz_read_raw_set_callback(
  30. SubGhzReadRAW* subghz_read_raw,
  31. SubGhzReadRAWCallback callback,
  32. void* context) {
  33. furi_assert(subghz_read_raw);
  34. furi_assert(callback);
  35. subghz_read_raw->callback = callback;
  36. subghz_read_raw->context = context;
  37. }
  38. void subghz_read_raw_add_data_statusbar(
  39. SubGhzReadRAW* instance,
  40. const char* frequency_str,
  41. const char* preset_str) {
  42. furi_assert(instance);
  43. with_view_model(
  44. instance->view,
  45. SubGhzReadRAWModel * model,
  46. {
  47. furi_string_set(model->frequency_str, frequency_str);
  48. furi_string_set(model->preset_str, preset_str);
  49. },
  50. true);
  51. }
  52. void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi, bool trace) {
  53. furi_assert(instance);
  54. uint8_t u_rssi = 0;
  55. if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) {
  56. u_rssi = 0;
  57. } else {
  58. u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7);
  59. }
  60. with_view_model(
  61. instance->view,
  62. SubGhzReadRAWModel * model,
  63. {
  64. model->rssi_curret = u_rssi;
  65. if(trace) {
  66. model->rssi_history[model->ind_write++] = u_rssi;
  67. } else {
  68. model->rssi_history[model->ind_write] = u_rssi;
  69. }
  70. if(model->ind_write > SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE) {
  71. model->rssi_history_end = true;
  72. model->ind_write = 0;
  73. }
  74. },
  75. true);
  76. }
  77. void subghz_read_raw_update_sample_write(SubGhzReadRAW* instance, size_t sample) {
  78. furi_assert(instance);
  79. with_view_model(
  80. instance->view,
  81. SubGhzReadRAWModel * model,
  82. { furi_string_printf(model->sample_write, "%zu spl.", sample); },
  83. false);
  84. }
  85. void subghz_read_raw_stop_send(SubGhzReadRAW* instance) {
  86. furi_assert(instance);
  87. with_view_model(
  88. instance->view,
  89. SubGhzReadRAWModel * model,
  90. {
  91. switch(model->status) {
  92. case SubGhzReadRAWStatusTXRepeat:
  93. case SubGhzReadRAWStatusLoadKeyTXRepeat:
  94. instance->callback(SubGhzCustomEventViewReadRAWSendStart, instance->context);
  95. break;
  96. case SubGhzReadRAWStatusTX:
  97. model->status = SubGhzReadRAWStatusIDLE;
  98. break;
  99. case SubGhzReadRAWStatusLoadKeyTX:
  100. model->status = SubGhzReadRAWStatusLoadKeyIDLE;
  101. break;
  102. default:
  103. FURI_LOG_W(TAG, "unknown status");
  104. model->status = SubGhzReadRAWStatusIDLE;
  105. break;
  106. }
  107. },
  108. true);
  109. }
  110. void subghz_read_raw_update_sin(SubGhzReadRAW* instance) {
  111. furi_assert(instance);
  112. with_view_model(
  113. instance->view,
  114. SubGhzReadRAWModel * model,
  115. {
  116. if(model->ind_sin++ > 62) {
  117. model->ind_sin = 0;
  118. }
  119. },
  120. true);
  121. }
  122. static int8_t subghz_read_raw_tab_sin(uint8_t x) {
  123. const uint8_t tab_sin[64] = {0, 3, 6, 9, 12, 16, 19, 22, 25, 28, 31, 34, 37,
  124. 40, 43, 46, 49, 51, 54, 57, 60, 63, 65, 68, 71, 73,
  125. 76, 78, 81, 83, 85, 88, 90, 92, 94, 96, 98, 100, 102,
  126. 104, 106, 107, 109, 111, 112, 113, 115, 116, 117, 118, 120, 121,
  127. 122, 122, 123, 124, 125, 125, 126, 126, 126, 127, 127, 127};
  128. int8_t r = tab_sin[((x & 0x40) ? -x - 1 : x) & 0x3f];
  129. if(x & 0x80) return -r;
  130. return r;
  131. }
  132. void subghz_read_raw_draw_sin(Canvas* canvas, SubGhzReadRAWModel* model) {
  133. #define SUBGHZ_RAW_SIN_AMPLITUDE 11
  134. for(int i = 113; i > 0; i--) {
  135. canvas_draw_line(
  136. canvas,
  137. i,
  138. 32 - subghz_read_raw_tab_sin(i + model->ind_sin * 16) / SUBGHZ_RAW_SIN_AMPLITUDE,
  139. i + 1,
  140. 32 + subghz_read_raw_tab_sin((i + model->ind_sin * 16 + 1) * 2) /
  141. SUBGHZ_RAW_SIN_AMPLITUDE);
  142. canvas_draw_line(
  143. canvas,
  144. i + 1,
  145. 32 - subghz_read_raw_tab_sin(i + model->ind_sin * 16) / SUBGHZ_RAW_SIN_AMPLITUDE,
  146. i + 2,
  147. 32 + subghz_read_raw_tab_sin((i + model->ind_sin * 16 + 1) * 2) /
  148. SUBGHZ_RAW_SIN_AMPLITUDE);
  149. }
  150. }
  151. void subghz_read_raw_draw_scale(Canvas* canvas, SubGhzReadRAWModel* model) {
  152. #define SUBGHZ_RAW_TOP_SCALE 14
  153. #define SUBGHZ_RAW_END_SCALE 115
  154. if(model->rssi_history_end == false) {
  155. for(int i = SUBGHZ_RAW_END_SCALE; i > 0; i -= 15) {
  156. canvas_draw_line(canvas, i, SUBGHZ_RAW_TOP_SCALE, i, SUBGHZ_RAW_TOP_SCALE + 4);
  157. canvas_draw_line(canvas, i - 5, SUBGHZ_RAW_TOP_SCALE, i - 5, SUBGHZ_RAW_TOP_SCALE + 2);
  158. canvas_draw_line(
  159. canvas, i - 10, SUBGHZ_RAW_TOP_SCALE, i - 10, SUBGHZ_RAW_TOP_SCALE + 2);
  160. }
  161. } else {
  162. for(int i = SUBGHZ_RAW_END_SCALE - model->ind_write % 15; i > -15; i -= 15) {
  163. canvas_draw_line(canvas, i, SUBGHZ_RAW_TOP_SCALE, i, SUBGHZ_RAW_TOP_SCALE + 4);
  164. if(SUBGHZ_RAW_END_SCALE > i + 5)
  165. canvas_draw_line(
  166. canvas, i + 5, SUBGHZ_RAW_TOP_SCALE, i + 5, SUBGHZ_RAW_TOP_SCALE + 2);
  167. if(SUBGHZ_RAW_END_SCALE > i + 10)
  168. canvas_draw_line(
  169. canvas, i + 10, SUBGHZ_RAW_TOP_SCALE, i + 10, SUBGHZ_RAW_TOP_SCALE + 2);
  170. }
  171. }
  172. }
  173. void subghz_read_raw_draw_rssi(Canvas* canvas, SubGhzReadRAWModel* model) {
  174. int ind = 0;
  175. int base = 0;
  176. uint8_t width = 2;
  177. if(model->rssi_history_end == false) {
  178. for(int i = model->ind_write; i >= 0; i--) {
  179. canvas_draw_line(canvas, i, 47, i, 47 - model->rssi_history[i]);
  180. }
  181. canvas_draw_line(
  182. canvas, model->ind_write + 1, 47, model->ind_write + 1, 47 - model->rssi_curret);
  183. if(model->ind_write > 3) {
  184. canvas_draw_line(
  185. canvas, model->ind_write - 1, 47, model->ind_write - 1, 47 - model->rssi_curret);
  186. for(uint8_t i = 13; i < 47; i += width * 2) {
  187. canvas_draw_line(canvas, model->ind_write, i, model->ind_write, i + width);
  188. }
  189. canvas_draw_line(canvas, model->ind_write - 2, 12, model->ind_write + 2, 12);
  190. canvas_draw_line(canvas, model->ind_write - 1, 13, model->ind_write + 1, 13);
  191. }
  192. } else {
  193. int i = 0;
  194. base = SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE - model->ind_write;
  195. for(i = SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE; i > 0; i--) {
  196. ind = i - base;
  197. if(ind < 0) ind += SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE;
  198. canvas_draw_line(canvas, i, 47, i, 47 - model->rssi_history[ind]);
  199. }
  200. canvas_draw_line(
  201. canvas,
  202. SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE - 1,
  203. 47,
  204. SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE - 1,
  205. 47 - model->rssi_curret);
  206. canvas_draw_line(
  207. canvas,
  208. SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE + 1,
  209. 47,
  210. SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE + 1,
  211. 47 - model->rssi_curret);
  212. for(uint8_t i = 13; i < 47; i += width * 2) {
  213. canvas_draw_line(
  214. canvas,
  215. SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE,
  216. i,
  217. SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE,
  218. i + width);
  219. }
  220. canvas_draw_line(
  221. canvas,
  222. SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE - 2,
  223. 12,
  224. SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE + 2,
  225. 12);
  226. canvas_draw_line(
  227. canvas,
  228. SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE - 1,
  229. 13,
  230. SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE + 1,
  231. 13);
  232. }
  233. }
  234. void subghz_read_raw_draw_threshold_rssi(Canvas* canvas, SubGhzReadRAWModel* model) {
  235. uint8_t x = 118;
  236. uint8_t y = 48;
  237. if(model->raw_threshold_rssi > SUBGHZ_RAW_TRESHOLD_MIN) {
  238. uint8_t x = 118;
  239. y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7);
  240. uint8_t width = 3;
  241. for(uint8_t i = 0; i < x; i += width * 2) {
  242. canvas_draw_line(canvas, i, y, i + width, y);
  243. }
  244. }
  245. canvas_draw_line(canvas, x, y - 2, x, y + 2);
  246. canvas_draw_line(canvas, x - 1, y - 1, x - 1, y + 1);
  247. canvas_draw_dot(canvas, x - 2, y);
  248. }
  249. void subghz_read_raw_draw(Canvas* canvas, SubGhzReadRAWModel* model) {
  250. uint8_t graphics_mode = 1;
  251. canvas_set_color(canvas, ColorBlack);
  252. canvas_set_font(canvas, FontSecondary);
  253. canvas_draw_str(canvas, 5, 7, furi_string_get_cstr(model->frequency_str));
  254. canvas_draw_str(canvas, 40, 7, furi_string_get_cstr(model->preset_str));
  255. canvas_draw_str_aligned(
  256. canvas, 126, 0, AlignRight, AlignTop, furi_string_get_cstr(model->sample_write));
  257. canvas_draw_line(canvas, 0, 14, 115, 14);
  258. canvas_draw_line(canvas, 0, 48, 115, 48);
  259. canvas_draw_line(canvas, 115, 14, 115, 48);
  260. switch(model->status) {
  261. case SubGhzReadRAWStatusIDLE:
  262. elements_button_left(canvas, "Erase");
  263. elements_button_center(canvas, "Send");
  264. elements_button_right(canvas, "Save");
  265. break;
  266. case SubGhzReadRAWStatusLoadKeyIDLE:
  267. elements_button_left(canvas, "New");
  268. elements_button_center(canvas, "Send");
  269. elements_button_right(canvas, "More");
  270. elements_text_box(
  271. canvas,
  272. 4,
  273. 20,
  274. 110,
  275. 30,
  276. AlignCenter,
  277. AlignCenter,
  278. furi_string_get_cstr(model->file_name),
  279. true);
  280. break;
  281. case SubGhzReadRAWStatusTX:
  282. case SubGhzReadRAWStatusTXRepeat:
  283. case SubGhzReadRAWStatusLoadKeyTX:
  284. case SubGhzReadRAWStatusLoadKeyTXRepeat:
  285. graphics_mode = 0;
  286. elements_button_center(canvas, "Send");
  287. break;
  288. case SubGhzReadRAWStatusStart:
  289. elements_button_left(canvas, "Config");
  290. elements_button_center(canvas, "REC");
  291. break;
  292. default:
  293. elements_button_center(canvas, "Stop");
  294. break;
  295. }
  296. if(graphics_mode == 0) {
  297. subghz_read_raw_draw_sin(canvas, model);
  298. } else {
  299. subghz_read_raw_draw_rssi(canvas, model);
  300. subghz_read_raw_draw_scale(canvas, model);
  301. subghz_read_raw_draw_threshold_rssi(canvas, model);
  302. canvas_set_font_direction(canvas, CanvasDirectionBottomToTop);
  303. canvas_draw_str(canvas, 128, 40, "RSSI");
  304. canvas_set_font_direction(canvas, CanvasDirectionLeftToRight);
  305. }
  306. }
  307. bool subghz_read_raw_input(InputEvent* event, void* context) {
  308. furi_assert(context);
  309. SubGhzReadRAW* instance = context;
  310. if((event->key == InputKeyOk) &&
  311. (event->type == InputTypeLong || event->type == InputTypeRepeat)) {
  312. //we check that if we hold the transfer button,
  313. //further check of events is not needed, we exit
  314. return false;
  315. } else if(event->key == InputKeyOk && event->type == InputTypePress) {
  316. uint8_t ret = false;
  317. with_view_model(
  318. instance->view,
  319. SubGhzReadRAWModel * model,
  320. {
  321. switch(model->status) {
  322. case SubGhzReadRAWStatusIDLE:
  323. // Start TX
  324. instance->callback(SubGhzCustomEventViewReadRAWSendStart, instance->context);
  325. model->status = SubGhzReadRAWStatusTXRepeat;
  326. ret = true;
  327. break;
  328. case SubGhzReadRAWStatusTX:
  329. // Start TXRepeat
  330. model->status = SubGhzReadRAWStatusTXRepeat;
  331. break;
  332. case SubGhzReadRAWStatusLoadKeyIDLE:
  333. // Start Load Key TX
  334. instance->callback(SubGhzCustomEventViewReadRAWSendStart, instance->context);
  335. model->status = SubGhzReadRAWStatusLoadKeyTXRepeat;
  336. ret = true;
  337. break;
  338. case SubGhzReadRAWStatusLoadKeyTX:
  339. // Start Load Key TXRepeat
  340. model->status = SubGhzReadRAWStatusLoadKeyTXRepeat;
  341. break;
  342. default:
  343. break;
  344. }
  345. },
  346. ret);
  347. } else if(event->key == InputKeyOk && event->type == InputTypeRelease) {
  348. with_view_model(
  349. instance->view,
  350. SubGhzReadRAWModel * model,
  351. {
  352. if(model->status == SubGhzReadRAWStatusTXRepeat) {
  353. // Stop repeat TX
  354. model->status = SubGhzReadRAWStatusTX;
  355. } else if(model->status == SubGhzReadRAWStatusLoadKeyTXRepeat) {
  356. // Stop repeat TX
  357. model->status = SubGhzReadRAWStatusLoadKeyTX;
  358. }
  359. },
  360. false);
  361. } else if(event->key == InputKeyBack && event->type == InputTypeShort) {
  362. with_view_model(
  363. instance->view,
  364. SubGhzReadRAWModel * model,
  365. {
  366. switch(model->status) {
  367. case SubGhzReadRAWStatusREC:
  368. //Stop REC
  369. instance->callback(SubGhzCustomEventViewReadRAWIDLE, instance->context);
  370. model->status = SubGhzReadRAWStatusIDLE;
  371. break;
  372. case SubGhzReadRAWStatusLoadKeyTX:
  373. //Stop TxRx
  374. instance->callback(SubGhzCustomEventViewReadRAWTXRXStop, instance->context);
  375. model->status = SubGhzReadRAWStatusLoadKeyIDLE;
  376. break;
  377. case SubGhzReadRAWStatusTX:
  378. //Stop TxRx
  379. instance->callback(SubGhzCustomEventViewReadRAWTXRXStop, instance->context);
  380. model->status = SubGhzReadRAWStatusIDLE;
  381. break;
  382. case SubGhzReadRAWStatusLoadKeyIDLE:
  383. //Exit
  384. instance->callback(SubGhzCustomEventViewReadRAWBack, instance->context);
  385. break;
  386. default:
  387. //Exit
  388. instance->callback(SubGhzCustomEventViewReadRAWBack, instance->context);
  389. break;
  390. }
  391. },
  392. true);
  393. } else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
  394. with_view_model(
  395. instance->view,
  396. SubGhzReadRAWModel * model,
  397. {
  398. if(model->status == SubGhzReadRAWStatusStart) {
  399. //Config
  400. instance->callback(SubGhzCustomEventViewReadRAWConfig, instance->context);
  401. } else if(
  402. (model->status == SubGhzReadRAWStatusIDLE) ||
  403. (model->status == SubGhzReadRAWStatusLoadKeyIDLE)) {
  404. //Erase
  405. model->status = SubGhzReadRAWStatusStart;
  406. model->rssi_history_end = false;
  407. model->ind_write = 0;
  408. furi_string_set(model->sample_write, "0 spl.");
  409. furi_string_reset(model->file_name);
  410. instance->callback(SubGhzCustomEventViewReadRAWErase, instance->context);
  411. }
  412. },
  413. true);
  414. } else if(event->key == InputKeyRight && event->type == InputTypeShort) {
  415. with_view_model(
  416. instance->view,
  417. SubGhzReadRAWModel * model,
  418. {
  419. if(model->status == SubGhzReadRAWStatusIDLE) {
  420. //Save
  421. instance->callback(SubGhzCustomEventViewReadRAWSave, instance->context);
  422. } else if(model->status == SubGhzReadRAWStatusLoadKeyIDLE) {
  423. //More
  424. instance->callback(SubGhzCustomEventViewReadRAWMore, instance->context);
  425. }
  426. },
  427. true);
  428. } else if(event->key == InputKeyOk && event->type == InputTypeShort) {
  429. with_view_model(
  430. instance->view,
  431. SubGhzReadRAWModel * model,
  432. {
  433. if(model->status == SubGhzReadRAWStatusStart) {
  434. //Record
  435. instance->callback(SubGhzCustomEventViewReadRAWREC, instance->context);
  436. model->status = SubGhzReadRAWStatusREC;
  437. model->ind_write = 0;
  438. model->rssi_history_end = false;
  439. } else if(model->status == SubGhzReadRAWStatusREC) {
  440. //Stop
  441. instance->callback(SubGhzCustomEventViewReadRAWIDLE, instance->context);
  442. model->status = SubGhzReadRAWStatusIDLE;
  443. }
  444. },
  445. true);
  446. }
  447. return true;
  448. }
  449. void subghz_read_raw_set_status(
  450. SubGhzReadRAW* instance,
  451. SubGhzReadRAWStatus status,
  452. const char* file_name,
  453. float raw_threshold_rssi) {
  454. furi_assert(instance);
  455. switch(status) {
  456. case SubGhzReadRAWStatusStart:
  457. with_view_model(
  458. instance->view,
  459. SubGhzReadRAWModel * model,
  460. {
  461. model->status = SubGhzReadRAWStatusStart;
  462. model->rssi_history_end = false;
  463. model->ind_write = 0;
  464. furi_string_reset(model->file_name);
  465. furi_string_set(model->sample_write, "0 spl.");
  466. model->raw_threshold_rssi = raw_threshold_rssi;
  467. },
  468. true);
  469. break;
  470. case SubGhzReadRAWStatusIDLE:
  471. with_view_model(
  472. instance->view,
  473. SubGhzReadRAWModel * model,
  474. { model->status = SubGhzReadRAWStatusIDLE; },
  475. true);
  476. break;
  477. case SubGhzReadRAWStatusLoadKeyTX:
  478. with_view_model(
  479. instance->view,
  480. SubGhzReadRAWModel * model,
  481. {
  482. model->status = SubGhzReadRAWStatusLoadKeyIDLE;
  483. model->rssi_history_end = false;
  484. model->ind_write = 0;
  485. furi_string_set(model->file_name, file_name);
  486. furi_string_set(model->sample_write, "RAW");
  487. },
  488. true);
  489. break;
  490. case SubGhzReadRAWStatusSaveKey:
  491. with_view_model(
  492. instance->view,
  493. SubGhzReadRAWModel * model,
  494. {
  495. model->status = SubGhzReadRAWStatusLoadKeyIDLE;
  496. if(!model->ind_write) {
  497. furi_string_set(model->file_name, file_name);
  498. furi_string_set(model->sample_write, "RAW");
  499. } else {
  500. furi_string_reset(model->file_name);
  501. }
  502. },
  503. true);
  504. break;
  505. default:
  506. FURI_LOG_W(TAG, "unknown status");
  507. break;
  508. }
  509. }
  510. void subghz_read_raw_enter(void* context) {
  511. furi_assert(context);
  512. //SubGhzReadRAW* instance = context;
  513. }
  514. void subghz_read_raw_exit(void* context) {
  515. furi_assert(context);
  516. SubGhzReadRAW* instance = context;
  517. with_view_model(
  518. instance->view,
  519. SubGhzReadRAWModel * model,
  520. {
  521. if(model->status != SubGhzReadRAWStatusIDLE &&
  522. model->status != SubGhzReadRAWStatusStart &&
  523. model->status != SubGhzReadRAWStatusLoadKeyIDLE) {
  524. instance->callback(SubGhzCustomEventViewReadRAWIDLE, instance->context);
  525. model->status = SubGhzReadRAWStatusStart;
  526. }
  527. },
  528. true);
  529. }
  530. SubGhzReadRAW* subghz_read_raw_alloc() {
  531. SubGhzReadRAW* instance = malloc(sizeof(SubGhzReadRAW));
  532. // View allocation and configuration
  533. instance->view = view_alloc();
  534. view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubGhzReadRAWModel));
  535. view_set_context(instance->view, instance);
  536. view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_read_raw_draw);
  537. view_set_input_callback(instance->view, subghz_read_raw_input);
  538. view_set_enter_callback(instance->view, subghz_read_raw_enter);
  539. view_set_exit_callback(instance->view, subghz_read_raw_exit);
  540. with_view_model(
  541. instance->view,
  542. SubGhzReadRAWModel * model,
  543. {
  544. model->frequency_str = furi_string_alloc();
  545. model->preset_str = furi_string_alloc();
  546. model->sample_write = furi_string_alloc();
  547. model->file_name = furi_string_alloc();
  548. model->rssi_history = malloc(SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE * sizeof(uint8_t));
  549. model->raw_threshold_rssi = -127.0f;
  550. },
  551. true);
  552. return instance;
  553. }
  554. void subghz_read_raw_free(SubGhzReadRAW* instance) {
  555. furi_assert(instance);
  556. with_view_model(
  557. instance->view,
  558. SubGhzReadRAWModel * model,
  559. {
  560. furi_string_free(model->frequency_str);
  561. furi_string_free(model->preset_str);
  562. furi_string_free(model->sample_write);
  563. furi_string_free(model->file_name);
  564. free(model->rssi_history);
  565. },
  566. true);
  567. view_free(instance->view);
  568. free(instance);
  569. }
  570. View* subghz_read_raw_get_view(SubGhzReadRAW* instance) {
  571. furi_assert(instance);
  572. return instance->view;
  573. }