subghz_read_raw.c 19 KB

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