subghz_read_raw.c 19 KB

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