infrared_remote_app.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  1. #include <furi.h>
  2. #include <furi_hal.h>
  3. #include <infrared_worker.h>
  4. #include <gui/gui.h>
  5. #include <input/input.h>
  6. #include <dialogs/dialogs.h>
  7. #include <ir_remote_icons.h>
  8. #include <infrared/infrared_settings.h>
  9. #include <toolbox/saved_struct.h>
  10. #include <notification/notification.h>
  11. #include <notification/notification_messages.h>
  12. #include "infrared_signal.h"
  13. #include "infrared_remote.h"
  14. #include "infrared_remote_button.h"
  15. #define TAG "ir_remote"
  16. #include <flipper_format/flipper_format.h>
  17. typedef struct {
  18. int status;
  19. ViewPort* view_port;
  20. FuriString* up_button;
  21. FuriString* down_button;
  22. FuriString* left_button;
  23. FuriString* right_button;
  24. FuriString* ok_button;
  25. FuriString* back_button;
  26. FuriString* up_hold_button;
  27. FuriString* down_hold_button;
  28. FuriString* left_hold_button;
  29. FuriString* right_hold_button;
  30. FuriString* ok_hold_button;
  31. InfraredWorker* infrared_worker;
  32. } IRApp;
  33. // Screen is 128x64 px
  34. static void app_draw_callback(Canvas* canvas, void* ctx) {
  35. // Show config is incorrect when cannot read the remote file
  36. // Showing button string in the screen, upper part is short press, lower part is long press
  37. IRApp* app = ctx;
  38. if(app->status) {
  39. canvas_clear(canvas);
  40. view_port_set_orientation(app->view_port, ViewPortOrientationHorizontal);
  41. canvas_set_font(canvas, FontPrimary);
  42. canvas_draw_str_aligned(canvas, 62, 5, AlignCenter, AlignTop, "Config is incorrect.");
  43. canvas_set_font(canvas, FontSecondary);
  44. canvas_draw_str_aligned(canvas, 62, 30, AlignCenter, AlignTop, "Please configure map.");
  45. canvas_draw_str_aligned(canvas, 62, 60, AlignCenter, AlignBottom, "Press Back to Exit.");
  46. } else {
  47. canvas_clear(canvas);
  48. view_port_set_orientation(app->view_port, ViewPortOrientationVertical);
  49. canvas_draw_icon(canvas, 1, 5, &I_ButtonUp_7x4);
  50. canvas_draw_icon(canvas, 1, 15, &I_ButtonDown_7x4);
  51. canvas_draw_icon(canvas, 2, 23, &I_ButtonLeft_4x7);
  52. canvas_draw_icon(canvas, 2, 33, &I_ButtonRight_4x7);
  53. canvas_draw_icon(canvas, 0, 42, &I_Ok_btn_9x9);
  54. canvas_draw_icon(canvas, 0, 53, &I_back_10px);
  55. //Labels
  56. canvas_set_font(canvas, FontSecondary);
  57. canvas_draw_str_aligned(
  58. canvas, 32, 8, AlignCenter, AlignCenter, furi_string_get_cstr(app->up_button));
  59. canvas_draw_str_aligned(
  60. canvas, 32, 18, AlignCenter, AlignCenter, furi_string_get_cstr(app->down_button));
  61. canvas_draw_str_aligned(
  62. canvas, 32, 28, AlignCenter, AlignCenter, furi_string_get_cstr(app->left_button));
  63. canvas_draw_str_aligned(
  64. canvas, 32, 38, AlignCenter, AlignCenter, furi_string_get_cstr(app->right_button));
  65. canvas_draw_str_aligned(
  66. canvas, 32, 48, AlignCenter, AlignCenter, furi_string_get_cstr(app->ok_button));
  67. canvas_draw_str_aligned(
  68. canvas, 32, 58, AlignCenter, AlignCenter, furi_string_get_cstr(app->back_button));
  69. canvas_draw_line(canvas, 0, 65, 64, 65);
  70. canvas_draw_icon(canvas, 1, 70, &I_ButtonUp_7x4);
  71. canvas_draw_icon(canvas, 1, 80, &I_ButtonDown_7x4);
  72. canvas_draw_icon(canvas, 2, 88, &I_ButtonLeft_4x7);
  73. canvas_draw_icon(canvas, 2, 98, &I_ButtonRight_4x7);
  74. canvas_draw_icon(canvas, 0, 107, &I_Ok_btn_9x9);
  75. canvas_draw_icon(canvas, 0, 118, &I_back_10px);
  76. canvas_draw_str_aligned(
  77. canvas, 32, 73, AlignCenter, AlignCenter, furi_string_get_cstr(app->up_hold_button));
  78. canvas_draw_str_aligned(
  79. canvas, 32, 83, AlignCenter, AlignCenter, furi_string_get_cstr(app->down_hold_button));
  80. canvas_draw_str_aligned(
  81. canvas, 32, 93, AlignCenter, AlignCenter, furi_string_get_cstr(app->left_hold_button));
  82. canvas_draw_str_aligned(
  83. canvas,
  84. 32,
  85. 103,
  86. AlignCenter,
  87. AlignCenter,
  88. furi_string_get_cstr(app->right_hold_button));
  89. canvas_draw_str_aligned(
  90. canvas, 32, 113, AlignCenter, AlignCenter, furi_string_get_cstr(app->ok_hold_button));
  91. canvas_draw_str_aligned(canvas, 32, 123, AlignCenter, AlignCenter, "Exit App");
  92. }
  93. }
  94. static void app_input_callback(InputEvent* input_event, void* ctx) {
  95. furi_assert(ctx);
  96. FuriMessageQueue* event_queue = ctx;
  97. furi_message_queue_put(event_queue, input_event, FuriWaitForever);
  98. }
  99. int32_t infrared_remote_app(char* p) {
  100. FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
  101. // App button string
  102. IRApp* app = malloc(sizeof(IRApp));
  103. app->up_button = furi_string_alloc();
  104. app->down_button = furi_string_alloc();
  105. app->left_button = furi_string_alloc();
  106. app->right_button = furi_string_alloc();
  107. app->ok_button = furi_string_alloc();
  108. app->back_button = furi_string_alloc();
  109. app->up_hold_button = furi_string_alloc();
  110. app->down_hold_button = furi_string_alloc();
  111. app->left_hold_button = furi_string_alloc();
  112. app->right_hold_button = furi_string_alloc();
  113. app->ok_hold_button = furi_string_alloc();
  114. app->view_port = view_port_alloc();
  115. app->infrared_worker = infrared_worker_alloc();
  116. // Configure view port
  117. view_port_draw_callback_set(app->view_port, app_draw_callback, app);
  118. view_port_input_callback_set(app->view_port, app_input_callback, event_queue);
  119. // Register view port in GUI
  120. Gui* gui = furi_record_open(RECORD_GUI);
  121. gui_add_view_port(gui, app->view_port, GuiLayerFullscreen);
  122. InputEvent event;
  123. FuriString* map_file = furi_string_alloc();
  124. Storage* storage = furi_record_open(RECORD_STORAGE);
  125. FlipperFormat* ff = flipper_format_file_alloc(storage);
  126. if(!storage_file_exists(storage, IR_REMOTE_PATH)) {
  127. storage_common_mkdir(storage, IR_REMOTE_PATH); //Make Folder If dir not exist
  128. }
  129. bool res;
  130. if(p && strlen(p)) {
  131. furi_string_set(map_file, p);
  132. res = true;
  133. } else {
  134. DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
  135. DialogsFileBrowserOptions browser_options;
  136. dialog_file_browser_set_basic_options(&browser_options, ".txt", &I_sub1_10px);
  137. browser_options.base_path = IR_REMOTE_PATH;
  138. furi_string_set(map_file, IR_REMOTE_PATH);
  139. res = dialog_file_browser_show(dialogs, map_file, map_file, &browser_options);
  140. furi_record_close(RECORD_DIALOGS);
  141. }
  142. // if user didn't choose anything, free everything and exit
  143. if(!res) {
  144. FURI_LOG_I(TAG, "exit");
  145. flipper_format_free(ff);
  146. furi_record_close(RECORD_STORAGE);
  147. furi_string_free(app->up_button);
  148. furi_string_free(app->down_button);
  149. furi_string_free(app->left_button);
  150. furi_string_free(app->right_button);
  151. furi_string_free(app->ok_button);
  152. furi_string_free(app->back_button);
  153. furi_string_free(app->up_hold_button);
  154. furi_string_free(app->down_hold_button);
  155. furi_string_free(app->left_hold_button);
  156. furi_string_free(app->right_hold_button);
  157. furi_string_free(app->ok_hold_button);
  158. view_port_enabled_set(app->view_port, false);
  159. gui_remove_view_port(gui, app->view_port);
  160. view_port_free(app->view_port);
  161. free(app);
  162. furi_message_queue_free(event_queue);
  163. furi_record_close(RECORD_GUI);
  164. return 255;
  165. }
  166. InfraredRemote* remote = infrared_remote_alloc();
  167. FuriString* remote_path = furi_string_alloc();
  168. InfraredSignal* up_signal = infrared_signal_alloc();
  169. InfraredSignal* down_signal = infrared_signal_alloc();
  170. InfraredSignal* left_signal = infrared_signal_alloc();
  171. InfraredSignal* right_signal = infrared_signal_alloc();
  172. InfraredSignal* ok_signal = infrared_signal_alloc();
  173. InfraredSignal* back_signal = infrared_signal_alloc();
  174. InfraredSignal* up_hold_signal = infrared_signal_alloc();
  175. InfraredSignal* down_hold_signal = infrared_signal_alloc();
  176. InfraredSignal* left_hold_signal = infrared_signal_alloc();
  177. InfraredSignal* right_hold_signal = infrared_signal_alloc();
  178. InfraredSignal* ok_hold_signal = infrared_signal_alloc();
  179. InfraredSignal* active_signal = NULL;
  180. bool is_transmitting = false;
  181. bool up_enabled = false;
  182. bool down_enabled = false;
  183. bool left_enabled = false;
  184. bool right_enabled = false;
  185. bool ok_enabled = false;
  186. bool back_enabled = false;
  187. bool up_hold_enabled = false;
  188. bool down_hold_enabled = false;
  189. bool left_hold_enabled = false;
  190. bool right_hold_enabled = false;
  191. bool ok_hold_enabled = false;
  192. if(!flipper_format_file_open_existing(ff, furi_string_get_cstr(map_file))) {
  193. FURI_LOG_E(TAG, "Could not open MAP file %s", furi_string_get_cstr(map_file));
  194. app->status = 1;
  195. } else {
  196. //Filename Assignment/Check Start
  197. if(!flipper_format_read_string(ff, "REMOTE", remote_path)) {
  198. FURI_LOG_E(TAG, "Could not read REMOTE string");
  199. app->status = 1;
  200. } else {
  201. if(!infrared_remote_load(remote, remote_path)) {
  202. FURI_LOG_E(TAG, "Could not load ir file: %s", furi_string_get_cstr(remote_path));
  203. app->status = 1;
  204. } else {
  205. FURI_LOG_I(TAG, "Loaded REMOTE file: %s", furi_string_get_cstr(remote_path));
  206. }
  207. }
  208. //assign variables to values within map file
  209. //set missing filenames to N/A
  210. //assign button signals
  211. size_t index = 0;
  212. if(!flipper_format_read_string(ff, "UP", app->up_button)) {
  213. FURI_LOG_W(TAG, "Could not read UP string");
  214. furi_string_set(app->up_button, "N/A");
  215. } else {
  216. if(!infrared_remote_find_button_by_name(
  217. remote, furi_string_get_cstr(app->up_button), &index)) {
  218. FURI_LOG_W(TAG, "Error");
  219. } else {
  220. up_signal =
  221. infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
  222. up_enabled = true;
  223. }
  224. }
  225. if(!flipper_format_read_string(ff, "DOWN", app->down_button)) {
  226. FURI_LOG_W(TAG, "Could not read DOWN string");
  227. furi_string_set(app->down_button, "N/A");
  228. } else {
  229. if(!infrared_remote_find_button_by_name(
  230. remote, furi_string_get_cstr(app->down_button), &index)) {
  231. FURI_LOG_W(TAG, "Error");
  232. } else {
  233. down_signal =
  234. infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
  235. down_enabled = true;
  236. }
  237. }
  238. if(!flipper_format_read_string(ff, "LEFT", app->left_button)) {
  239. FURI_LOG_W(TAG, "Could not read LEFT string");
  240. furi_string_set(app->left_button, "N/A");
  241. } else {
  242. if(!infrared_remote_find_button_by_name(
  243. remote, furi_string_get_cstr(app->left_button), &index)) {
  244. FURI_LOG_W(TAG, "Error");
  245. } else {
  246. left_signal =
  247. infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
  248. left_enabled = true;
  249. }
  250. }
  251. if(!flipper_format_read_string(ff, "RIGHT", app->right_button)) {
  252. FURI_LOG_W(TAG, "Could not read RIGHT string");
  253. furi_string_set(app->right_button, "N/A");
  254. } else {
  255. if(!infrared_remote_find_button_by_name(
  256. remote, furi_string_get_cstr(app->right_button), &index)) {
  257. FURI_LOG_W(TAG, "Error");
  258. } else {
  259. right_signal =
  260. infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
  261. right_enabled = true;
  262. }
  263. }
  264. if(!flipper_format_read_string(ff, "OK", app->ok_button)) {
  265. FURI_LOG_W(TAG, "Could not read OK string");
  266. furi_string_set(app->ok_button, "N/A");
  267. } else {
  268. if(!infrared_remote_find_button_by_name(
  269. remote, furi_string_get_cstr(app->ok_button), &index)) {
  270. FURI_LOG_W(TAG, "Error");
  271. } else {
  272. ok_signal =
  273. infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
  274. ok_enabled = true;
  275. }
  276. }
  277. if(!flipper_format_read_string(ff, "BACK", app->back_button)) {
  278. FURI_LOG_W(TAG, "Could not read BACK string");
  279. furi_string_set(app->back_button, "N/A");
  280. } else {
  281. if(!infrared_remote_find_button_by_name(
  282. remote, furi_string_get_cstr(app->back_button), &index)) {
  283. FURI_LOG_W(TAG, "Error");
  284. } else {
  285. back_signal =
  286. infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
  287. back_enabled = true;
  288. }
  289. }
  290. if(!flipper_format_read_string(ff, "UPHOLD", app->up_hold_button)) {
  291. FURI_LOG_W(TAG, "Could not read UPHOLD string");
  292. furi_string_set(app->up_hold_button, "N/A");
  293. } else {
  294. if(!infrared_remote_find_button_by_name(
  295. remote, furi_string_get_cstr(app->up_hold_button), &index)) {
  296. FURI_LOG_W(TAG, "Error");
  297. } else {
  298. up_hold_signal =
  299. infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
  300. up_hold_enabled = true;
  301. }
  302. }
  303. if(!flipper_format_read_string(ff, "DOWNHOLD", app->down_hold_button)) {
  304. FURI_LOG_W(TAG, "Could not read DOWNHOLD string");
  305. furi_string_set(app->down_hold_button, "N/A");
  306. } else {
  307. if(!infrared_remote_find_button_by_name(
  308. remote, furi_string_get_cstr(app->down_hold_button), &index)) {
  309. FURI_LOG_W(TAG, "Error");
  310. } else {
  311. down_hold_signal =
  312. infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
  313. down_hold_enabled = true;
  314. }
  315. }
  316. if(!flipper_format_read_string(ff, "LEFTHOLD", app->left_hold_button)) {
  317. FURI_LOG_W(TAG, "Could not read LEFTHOLD string");
  318. furi_string_set(app->left_hold_button, "N/A");
  319. } else {
  320. if(!infrared_remote_find_button_by_name(
  321. remote, furi_string_get_cstr(app->left_hold_button), &index)) {
  322. FURI_LOG_W(TAG, "Error");
  323. } else {
  324. left_hold_signal =
  325. infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
  326. left_hold_enabled = true;
  327. }
  328. }
  329. if(!flipper_format_read_string(ff, "RIGHTHOLD", app->right_hold_button)) {
  330. FURI_LOG_W(TAG, "Could not read RIGHTHOLD string");
  331. furi_string_set(app->right_hold_button, "N/A");
  332. } else {
  333. if(!infrared_remote_find_button_by_name(
  334. remote, furi_string_get_cstr(app->right_hold_button), &index)) {
  335. FURI_LOG_W(TAG, "Error");
  336. } else {
  337. right_hold_signal =
  338. infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
  339. right_hold_enabled = true;
  340. }
  341. }
  342. if(!flipper_format_read_string(ff, "OKHOLD", app->ok_hold_button)) {
  343. FURI_LOG_W(TAG, "Could not read OKHOLD string");
  344. furi_string_set(app->ok_hold_button, "N/A");
  345. } else {
  346. if(!infrared_remote_find_button_by_name(
  347. remote, furi_string_get_cstr(app->ok_hold_button), &index)) {
  348. FURI_LOG_W(TAG, "Error");
  349. } else {
  350. ok_hold_signal =
  351. infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
  352. ok_hold_enabled = true;
  353. }
  354. }
  355. }
  356. furi_string_free(remote_path);
  357. flipper_format_free(ff);
  358. furi_record_close(RECORD_STORAGE);
  359. bool otg_was_enabled = furi_hal_power_is_otg_enabled();
  360. InfraredSettings settings = {0};
  361. infrared_settings_load(&settings);
  362. if(settings.tx_pin < FuriHalInfraredTxPinMax) {
  363. furi_hal_infrared_set_tx_output(settings.tx_pin);
  364. if(settings.otg_enabled != otg_was_enabled) {
  365. if(settings.otg_enabled) {
  366. furi_hal_power_enable_otg();
  367. } else {
  368. furi_hal_power_disable_otg();
  369. }
  370. }
  371. } else {
  372. FuriHalInfraredTxPin tx_pin_detected = furi_hal_infrared_detect_tx_output();
  373. furi_hal_infrared_set_tx_output(tx_pin_detected);
  374. if(tx_pin_detected != FuriHalInfraredTxPinInternal) {
  375. furi_hal_power_enable_otg();
  376. }
  377. }
  378. bool running = true;
  379. NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
  380. if(app->status) {
  381. view_port_update(app->view_port);
  382. while(running) {
  383. if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) {
  384. if(event.type == InputTypeShort) {
  385. switch(event.key) {
  386. case InputKeyBack:
  387. running = false;
  388. break;
  389. default:
  390. break;
  391. }
  392. }
  393. }
  394. }
  395. } else {
  396. view_port_update(app->view_port);
  397. while(running) {
  398. if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) {
  399. // short press signal
  400. if(event.type == InputTypeShort) {
  401. switch(event.key) {
  402. case InputKeyUp:
  403. if(up_enabled) {
  404. active_signal = up_signal;
  405. FURI_LOG_I(TAG, "up");
  406. }
  407. break;
  408. case InputKeyDown:
  409. if(down_enabled) {
  410. active_signal = down_signal;
  411. FURI_LOG_I(TAG, "down");
  412. }
  413. break;
  414. case InputKeyRight:
  415. if(right_enabled) {
  416. active_signal = right_signal;
  417. FURI_LOG_I(TAG, "right");
  418. }
  419. break;
  420. case InputKeyLeft:
  421. if(left_enabled) {
  422. active_signal = left_signal;
  423. FURI_LOG_I(TAG, "left");
  424. }
  425. break;
  426. case InputKeyOk:
  427. if(ok_enabled) {
  428. active_signal = ok_signal;
  429. FURI_LOG_I(TAG, "ok");
  430. }
  431. break;
  432. case InputKeyBack:
  433. if(back_enabled) {
  434. active_signal = back_signal;
  435. FURI_LOG_I(TAG, "back");
  436. }
  437. break;
  438. default:
  439. running = false;
  440. break;
  441. }
  442. // long press signal
  443. } else if(event.type == InputTypeLong) {
  444. switch(event.key) {
  445. case InputKeyUp:
  446. if(up_hold_enabled) {
  447. active_signal = up_hold_signal;
  448. FURI_LOG_I(TAG, "up!");
  449. }
  450. break;
  451. case InputKeyDown:
  452. if(down_hold_enabled) {
  453. active_signal = down_hold_signal;
  454. FURI_LOG_I(TAG, "down!");
  455. }
  456. break;
  457. case InputKeyRight:
  458. if(right_hold_enabled) {
  459. active_signal = right_hold_signal;
  460. FURI_LOG_I(TAG, "right!");
  461. }
  462. break;
  463. case InputKeyLeft:
  464. if(left_hold_enabled) {
  465. active_signal = left_hold_signal;
  466. FURI_LOG_I(TAG, "left!");
  467. }
  468. break;
  469. case InputKeyOk:
  470. if(ok_hold_enabled) {
  471. active_signal = ok_hold_signal;
  472. FURI_LOG_I(TAG, "ok!");
  473. }
  474. break;
  475. default:
  476. running = false;
  477. break;
  478. }
  479. } else if(event.type == InputTypeRelease && is_transmitting) {
  480. notification_message(notification, &sequence_blink_stop);
  481. infrared_worker_tx_stop(app->infrared_worker);
  482. is_transmitting = false;
  483. active_signal = NULL;
  484. }
  485. if(active_signal != NULL &&
  486. (event.type == InputTypeShort || event.type == InputTypeLong)) {
  487. if(is_transmitting) {
  488. infrared_worker_tx_stop(app->infrared_worker);
  489. }
  490. if(infrared_signal_is_raw(active_signal)) {
  491. InfraredRawSignal* raw_signal =
  492. infrared_signal_get_raw_signal(active_signal);
  493. infrared_worker_set_raw_signal(
  494. app->infrared_worker,
  495. raw_signal->timings,
  496. raw_signal->timings_size,
  497. raw_signal->frequency,
  498. raw_signal->duty_cycle);
  499. } else {
  500. InfraredMessage* message = infrared_signal_get_message(active_signal);
  501. infrared_worker_set_decoded_signal(app->infrared_worker, message);
  502. }
  503. infrared_worker_tx_set_get_signal_callback(
  504. app->infrared_worker, infrared_worker_tx_get_signal_steady_callback, app);
  505. infrared_worker_tx_start(app->infrared_worker);
  506. notification_message(notification, &sequence_blink_start_magenta);
  507. is_transmitting = true;
  508. }
  509. }
  510. view_port_update(app->view_port);
  511. }
  512. }
  513. furi_hal_infrared_set_tx_output(FuriHalInfraredTxPinInternal);
  514. if(furi_hal_power_is_otg_enabled() != otg_was_enabled) {
  515. if(otg_was_enabled) {
  516. furi_hal_power_enable_otg();
  517. } else {
  518. furi_hal_power_disable_otg();
  519. }
  520. }
  521. // Free all things
  522. furi_string_free(app->up_button);
  523. furi_string_free(app->down_button);
  524. furi_string_free(app->left_button);
  525. furi_string_free(app->right_button);
  526. furi_string_free(app->ok_button);
  527. furi_string_free(app->back_button);
  528. furi_string_free(app->up_hold_button);
  529. furi_string_free(app->down_hold_button);
  530. furi_string_free(app->left_hold_button);
  531. furi_string_free(app->right_hold_button);
  532. furi_string_free(app->ok_hold_button);
  533. if(is_transmitting) {
  534. infrared_worker_tx_stop(app->infrared_worker);
  535. notification_message(notification, &sequence_blink_stop);
  536. }
  537. infrared_worker_free(app->infrared_worker);
  538. infrared_remote_free(remote);
  539. view_port_enabled_set(app->view_port, false);
  540. gui_remove_view_port(gui, app->view_port);
  541. view_port_free(app->view_port);
  542. free(app);
  543. furi_message_queue_free(event_queue);
  544. furi_record_close(RECORD_NOTIFICATION);
  545. furi_record_close(RECORD_GUI);
  546. return 0;
  547. }