infrared_remote.c 8.2 KB

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