infrared_remote.c 6.4 KB

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