infrared_remote.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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*
  82. infrared_remote_get_button_by_name(InfraredRemote* remote, const char* name) {
  83. for(size_t i = 0; i < InfraredButtonArray_size(remote->buttons); i++) {
  84. InfraredRemoteButton* button = *InfraredButtonArray_get(remote->buttons, i);
  85. if(!strcmp(infrared_remote_button_get_name(button), name)) {
  86. return button;
  87. }
  88. }
  89. return NULL;
  90. }
  91. bool infrared_remote_add_button(InfraredRemote* remote, const char* name, InfraredSignal* signal) {
  92. InfraredRemoteButton* button = infrared_remote_button_alloc();
  93. infrared_remote_button_set_name(button, name);
  94. infrared_remote_button_set_signal(button, signal);
  95. InfraredButtonArray_push_back(remote->buttons, button);
  96. return infrared_remote_store(remote);
  97. }
  98. void infrared_remote_push_button(InfraredRemote* remote, const char* name, InfraredSignal* signal) {
  99. InfraredRemoteButton* button = infrared_remote_button_alloc();
  100. infrared_remote_button_set_name(button, name);
  101. infrared_remote_button_set_signal(button, signal);
  102. InfraredButtonArray_push_back(remote->buttons, button);
  103. }
  104. bool infrared_remote_rename_button(InfraredRemote* remote, const char* new_name, size_t index) {
  105. furi_assert(index < InfraredButtonArray_size(remote->buttons));
  106. InfraredRemoteButton* button = *InfraredButtonArray_get(remote->buttons, index);
  107. infrared_remote_button_set_name(button, new_name);
  108. return infrared_remote_store(remote);
  109. }
  110. bool infrared_remote_delete_button(InfraredRemote* remote, size_t index) {
  111. furi_assert(index < InfraredButtonArray_size(remote->buttons));
  112. InfraredRemoteButton* button;
  113. InfraredButtonArray_pop_at(&button, remote->buttons, index);
  114. infrared_remote_button_free(button);
  115. return infrared_remote_store(remote);
  116. }
  117. bool infrared_remote_delete_button_by_name(InfraredRemote* remote, const char* name) {
  118. size_t index = 0;
  119. if(!infrared_remote_find_button_by_name(remote, name, &index)) return false;
  120. return infrared_remote_delete_button(remote, index);
  121. }
  122. void infrared_remote_move_button(InfraredRemote* remote, size_t index_orig, size_t index_dest) {
  123. furi_assert(index_orig < InfraredButtonArray_size(remote->buttons));
  124. furi_assert(index_dest < InfraredButtonArray_size(remote->buttons));
  125. InfraredRemoteButton* button;
  126. InfraredButtonArray_pop_at(&button, remote->buttons, index_orig);
  127. InfraredButtonArray_push_at(remote->buttons, index_dest, button);
  128. }
  129. bool infrared_remote_store(InfraredRemote* remote) {
  130. Storage* storage = furi_record_open(RECORD_STORAGE);
  131. FlipperFormat* ff = flipper_format_file_alloc(storage);
  132. const char* path = furi_string_get_cstr(remote->path);
  133. FURI_LOG_I(TAG, "store file: \'%s\'", path);
  134. bool success = flipper_format_file_open_always(ff, path) &&
  135. flipper_format_write_header_cstr(ff, "IR signals file", 1);
  136. if(success) {
  137. InfraredButtonArray_it_t it;
  138. for(InfraredButtonArray_it(it, remote->buttons); !InfraredButtonArray_end_p(it);
  139. InfraredButtonArray_next(it)) {
  140. InfraredRemoteButton* button = *InfraredButtonArray_cref(it);
  141. success = infrared_signal_save(
  142. infrared_remote_button_get_signal(button),
  143. ff,
  144. infrared_remote_button_get_name(button));
  145. if(!success) {
  146. break;
  147. }
  148. }
  149. }
  150. flipper_format_free(ff);
  151. furi_record_close(RECORD_STORAGE);
  152. return success;
  153. }
  154. bool infrared_remote_load(InfraredRemote* remote, FuriString* path) {
  155. Storage* storage = furi_record_open(RECORD_STORAGE);
  156. FlipperFormat* ff = flipper_format_buffered_file_alloc(storage);
  157. FuriString* buf;
  158. buf = furi_string_alloc();
  159. FURI_LOG_I(TAG, "load file: \'%s\'", furi_string_get_cstr(path));
  160. bool success = false;
  161. do {
  162. if(!flipper_format_buffered_file_open_existing(ff, furi_string_get_cstr(path))) break;
  163. uint32_t version;
  164. if(!flipper_format_read_header(ff, buf, &version)) break;
  165. if(!furi_string_equal(buf, "IR signals file") || (version != 1)) break;
  166. path_extract_filename(path, buf, true);
  167. infrared_remote_clear_buttons(remote);
  168. infrared_remote_set_name(remote, furi_string_get_cstr(buf));
  169. infrared_remote_set_path(remote, furi_string_get_cstr(path));
  170. for(bool can_read = true; can_read;) {
  171. InfraredRemoteButton* button = infrared_remote_button_alloc();
  172. can_read = infrared_signal_read(infrared_remote_button_get_signal(button), ff, buf);
  173. if(can_read) {
  174. infrared_remote_button_set_name(button, furi_string_get_cstr(buf));
  175. InfraredButtonArray_push_back(remote->buttons, button);
  176. } else {
  177. infrared_remote_button_free(button);
  178. }
  179. }
  180. success = true;
  181. } while(false);
  182. furi_string_free(buf);
  183. flipper_format_free(ff);
  184. furi_record_close(RECORD_STORAGE);
  185. return success;
  186. }
  187. bool infrared_remote_remove(InfraredRemote* remote) {
  188. Storage* storage = furi_record_open(RECORD_STORAGE);
  189. FS_Error status = storage_common_remove(storage, furi_string_get_cstr(remote->path));
  190. infrared_remote_reset(remote);
  191. furi_record_close(RECORD_STORAGE);
  192. return (status == FSE_OK || status == FSE_NOT_EXIST);
  193. }