infrared_remote.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. This file was taken from the project:
  3. https://github.com/DarkFlippers/unleashed-firmware
  4. The original project is licensed under the GNU GPLv3
  5. Modifications made:
  6. - Added function infrared_remote_get_button_by_name()
  7. */
  8. #include "infrared_remote.h"
  9. #include <stdbool.h>
  10. #include <stddef.h>
  11. #include <stdlib.h>
  12. #include <m-array.h>
  13. #include <toolbox/path.h>
  14. #include <storage/storage.h>
  15. #include <core/common_defines.h>
  16. #define TAG "InfraredRemote"
  17. ARRAY_DEF(InfraredButtonArray, InfraredRemoteButton*, M_PTR_OPLIST);
  18. struct InfraredRemote {
  19. InfraredButtonArray_t buttons;
  20. FuriString* name;
  21. FuriString* path;
  22. };
  23. static void infrared_remote_clear_buttons(InfraredRemote* remote) {
  24. InfraredButtonArray_it_t it;
  25. for(InfraredButtonArray_it(it, remote->buttons); !InfraredButtonArray_end_p(it);
  26. InfraredButtonArray_next(it)) {
  27. infrared_remote_button_free(*InfraredButtonArray_cref(it));
  28. }
  29. InfraredButtonArray_reset(remote->buttons);
  30. }
  31. InfraredRemote* infrared_remote_alloc() {
  32. InfraredRemote* remote = malloc(sizeof(InfraredRemote));
  33. InfraredButtonArray_init(remote->buttons);
  34. remote->name = furi_string_alloc();
  35. remote->path = furi_string_alloc();
  36. return remote;
  37. }
  38. void infrared_remote_free(InfraredRemote* remote) {
  39. infrared_remote_clear_buttons(remote);
  40. InfraredButtonArray_clear(remote->buttons);
  41. furi_string_free(remote->path);
  42. furi_string_free(remote->name);
  43. free(remote);
  44. }
  45. void infrared_remote_reset(InfraredRemote* remote) {
  46. infrared_remote_clear_buttons(remote);
  47. furi_string_reset(remote->name);
  48. furi_string_reset(remote->path);
  49. }
  50. void infrared_remote_set_name(InfraredRemote* remote, const char* name) {
  51. furi_string_set(remote->name, name);
  52. }
  53. const char* infrared_remote_get_name(InfraredRemote* remote) {
  54. return furi_string_get_cstr(remote->name);
  55. }
  56. void infrared_remote_set_path(InfraredRemote* remote, const char* path) {
  57. furi_string_set(remote->path, path);
  58. }
  59. const char* infrared_remote_get_path(InfraredRemote* remote) {
  60. return furi_string_get_cstr(remote->path);
  61. }
  62. size_t infrared_remote_get_button_count(InfraredRemote* remote) {
  63. return InfraredButtonArray_size(remote->buttons);
  64. }
  65. InfraredRemoteButton* infrared_remote_get_button(InfraredRemote* remote, size_t index) {
  66. furi_assert(index < InfraredButtonArray_size(remote->buttons));
  67. return *InfraredButtonArray_get(remote->buttons, index);
  68. }
  69. bool infrared_remote_find_button_by_name(InfraredRemote* remote, const char* name, size_t* index) {
  70. for(size_t i = 0; i < InfraredButtonArray_size(remote->buttons); i++) {
  71. InfraredRemoteButton* button = *InfraredButtonArray_get(remote->buttons, i);
  72. if(!strcmp(infrared_remote_button_get_name(button), name)) {
  73. *index = i;
  74. return true;
  75. }
  76. }
  77. return false;
  78. }
  79. InfraredRemoteButton* infrared_remote_get_button_by_name(InfraredRemote* remote, const char* name) {
  80. for(size_t i = 0; i < InfraredButtonArray_size(remote->buttons); i++) {
  81. InfraredRemoteButton* button = *InfraredButtonArray_get(remote->buttons, i);
  82. if(!strcmp(infrared_remote_button_get_name(button), name)) {
  83. return button;
  84. }
  85. }
  86. return NULL;
  87. }
  88. bool infrared_remote_add_button(InfraredRemote* remote, const char* name, InfraredSignal* signal) {
  89. InfraredRemoteButton* button = infrared_remote_button_alloc();
  90. infrared_remote_button_set_name(button, name);
  91. infrared_remote_button_set_signal(button, signal);
  92. InfraredButtonArray_push_back(remote->buttons, button);
  93. return infrared_remote_store(remote);
  94. }
  95. bool infrared_remote_rename_button(InfraredRemote* remote, const char* new_name, size_t index) {
  96. furi_assert(index < InfraredButtonArray_size(remote->buttons));
  97. InfraredRemoteButton* button = *InfraredButtonArray_get(remote->buttons, index);
  98. infrared_remote_button_set_name(button, new_name);
  99. return infrared_remote_store(remote);
  100. }
  101. bool infrared_remote_delete_button(InfraredRemote* remote, size_t index) {
  102. furi_assert(index < InfraredButtonArray_size(remote->buttons));
  103. InfraredRemoteButton* button;
  104. InfraredButtonArray_pop_at(&button, remote->buttons, index);
  105. infrared_remote_button_free(button);
  106. return infrared_remote_store(remote);
  107. }
  108. void infrared_remote_move_button(InfraredRemote* remote, size_t index_orig, size_t index_dest) {
  109. furi_assert(index_orig < InfraredButtonArray_size(remote->buttons));
  110. furi_assert(index_dest < InfraredButtonArray_size(remote->buttons));
  111. InfraredRemoteButton* button;
  112. InfraredButtonArray_pop_at(&button, remote->buttons, index_orig);
  113. InfraredButtonArray_push_at(remote->buttons, index_dest, button);
  114. }
  115. bool infrared_remote_store(InfraredRemote* remote) {
  116. Storage* storage = furi_record_open(RECORD_STORAGE);
  117. FlipperFormat* ff = flipper_format_file_alloc(storage);
  118. const char* path = furi_string_get_cstr(remote->path);
  119. FURI_LOG_I(TAG, "store file: \'%s\'", path);
  120. bool success = flipper_format_file_open_always(ff, path) &&
  121. flipper_format_write_header_cstr(ff, "IR signals file", 1);
  122. if(success) {
  123. InfraredButtonArray_it_t it;
  124. for(InfraredButtonArray_it(it, remote->buttons); !InfraredButtonArray_end_p(it);
  125. InfraredButtonArray_next(it)) {
  126. InfraredRemoteButton* button = *InfraredButtonArray_cref(it);
  127. success = infrared_signal_save(
  128. infrared_remote_button_get_signal(button),
  129. ff,
  130. infrared_remote_button_get_name(button));
  131. if(!success) {
  132. break;
  133. }
  134. }
  135. }
  136. flipper_format_free(ff);
  137. furi_record_close(RECORD_STORAGE);
  138. return success;
  139. }
  140. bool infrared_remote_load(InfraredRemote* remote, FuriString* path) {
  141. Storage* storage = furi_record_open(RECORD_STORAGE);
  142. FlipperFormat* ff = flipper_format_buffered_file_alloc(storage);
  143. FuriString* buf;
  144. buf = furi_string_alloc();
  145. FURI_LOG_I(TAG, "load file: \'%s\'", furi_string_get_cstr(path));
  146. bool success = false;
  147. do {
  148. if(!flipper_format_buffered_file_open_existing(ff, furi_string_get_cstr(path))) break;
  149. uint32_t version;
  150. if(!flipper_format_read_header(ff, buf, &version)) break;
  151. if(!furi_string_equal(buf, "IR signals file") || (version != 1)) break;
  152. path_extract_filename(path, buf, true);
  153. infrared_remote_clear_buttons(remote);
  154. infrared_remote_set_name(remote, furi_string_get_cstr(buf));
  155. infrared_remote_set_path(remote, furi_string_get_cstr(path));
  156. for(bool can_read = true; can_read;) {
  157. InfraredRemoteButton* button = infrared_remote_button_alloc();
  158. can_read = infrared_signal_read(infrared_remote_button_get_signal(button), ff, buf);
  159. if(can_read) {
  160. infrared_remote_button_set_name(button, furi_string_get_cstr(buf));
  161. InfraredButtonArray_push_back(remote->buttons, button);
  162. } else {
  163. infrared_remote_button_free(button);
  164. }
  165. }
  166. success = true;
  167. } while(false);
  168. furi_string_free(buf);
  169. flipper_format_free(ff);
  170. furi_record_close(RECORD_STORAGE);
  171. return success;
  172. }
  173. bool infrared_remote_remove(InfraredRemote* remote) {
  174. Storage* storage = furi_record_open(RECORD_STORAGE);
  175. FS_Error status = storage_common_remove(storage, furi_string_get_cstr(remote->path));
  176. infrared_remote_reset(remote);
  177. furi_record_close(RECORD_STORAGE);
  178. return (status == FSE_OK || status == FSE_NOT_EXIST);
  179. }