subghz_read_raw.c 19 KB

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