infrared_remote.c 8.3 KB

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