ir_helper.c (4619B)
1 #include "ir_helper.h" 2 3 #include <flipper_format/flipper_format.h> 4 #include <furi.h> 5 #include <infrared/worker/infrared_worker.h> 6 #include <lib/infrared/signal/infrared_error_code.h> 7 #include <storage/storage.h> 8 9 #define IR_FILE_HEADER "IR signals file" 10 #define IR_FILE_VERSION 1 11 12 /* ========== Signal List ========== */ 13 14 IrSignalList *ir_signal_list_alloc(void) { 15 IrSignalList *list = malloc(sizeof(IrSignalList)); 16 list->items = NULL; 17 list->count = 0; 18 list->capacity = 0; 19 return list; 20 } 21 22 void ir_signal_list_free(IrSignalList *list) { 23 if (!list) 24 return; 25 26 for (size_t i = 0; i < list->count; i++) { 27 if (list->items[i].signal) { 28 infrared_signal_free(list->items[i].signal); 29 } 30 if (list->items[i].name) { 31 furi_string_free(list->items[i].name); 32 } 33 } 34 if (list->items) { 35 free(list->items); 36 } 37 free(list); 38 } 39 40 static void ir_signal_list_add(IrSignalList *list, InfraredSignal *signal, 41 const char *name) { 42 if (list->count >= list->capacity) { 43 size_t new_capacity = list->capacity == 0 ? 8 : list->capacity * 2; 44 list->items = realloc(list->items, new_capacity * sizeof(IrSignalItem)); 45 list->capacity = new_capacity; 46 } 47 48 list->items[list->count].signal = signal; 49 list->items[list->count].name = furi_string_alloc_set(name); 50 list->count++; 51 } 52 53 /* ========== File I/O ========== */ 54 55 bool ir_helper_load_file(const char *path, IrSignalList *list) { 56 Storage *storage = furi_record_open(RECORD_STORAGE); 57 FlipperFormat *ff = flipper_format_file_alloc(storage); 58 bool success = false; 59 60 do { 61 if (!flipper_format_file_open_existing(ff, path)) 62 break; 63 64 /* Verify header */ 65 FuriString *filetype = furi_string_alloc(); 66 uint32_t version; 67 bool header_ok = flipper_format_read_header(ff, filetype, &version); 68 furi_string_free(filetype); 69 if (!header_ok) 70 break; 71 72 /* Read all signals */ 73 FuriString *signal_name = furi_string_alloc(); 74 while (true) { 75 InfraredSignal *signal = infrared_signal_alloc(); 76 InfraredErrorCode err = infrared_signal_read(signal, ff, signal_name); 77 if (err == InfraredErrorCodeNone) { 78 ir_signal_list_add(list, signal, furi_string_get_cstr(signal_name)); 79 } else { 80 infrared_signal_free(signal); 81 break; 82 } 83 } 84 furi_string_free(signal_name); 85 86 success = true; 87 } while (false); 88 89 flipper_format_free(ff); 90 furi_record_close(RECORD_STORAGE); 91 return success; 92 } 93 94 /* ========== Transmit ========== */ 95 96 void ir_helper_transmit(InfraredSignal *signal) { 97 infrared_signal_transmit(signal); 98 } 99 100 /* ========== File Browser ========== */ 101 102 bool ir_helper_list_files(const char *dir_path, FuriString ***files, 103 size_t *count) { 104 Storage *storage = furi_record_open(RECORD_STORAGE); 105 File *dir = storage_file_alloc(storage); 106 107 *files = NULL; 108 *count = 0; 109 110 if (!storage_dir_open(dir, dir_path)) { 111 storage_file_free(dir); 112 furi_record_close(RECORD_STORAGE); 113 return false; 114 } 115 116 /* First pass: count .ir files */ 117 FileInfo file_info; 118 char name_buf[256]; 119 size_t file_count = 0; 120 121 while (storage_dir_read(dir, &file_info, name_buf, sizeof(name_buf))) { 122 if (!(file_info.flags & FSF_DIRECTORY)) { 123 size_t len = strlen(name_buf); 124 if (len > 3 && strcmp(name_buf + len - 3, ".ir") == 0) { 125 file_count++; 126 } 127 } 128 } 129 130 if (file_count == 0) { 131 storage_dir_close(dir); 132 storage_file_free(dir); 133 furi_record_close(RECORD_STORAGE); 134 return true; /* Success, but no files */ 135 } 136 137 /* Allocate array */ 138 *files = malloc(file_count * sizeof(FuriString *)); 139 *count = file_count; 140 141 /* Second pass: collect filenames - close and reopen directory */ 142 storage_dir_close(dir); 143 if (!storage_dir_open(dir, dir_path)) { 144 free(*files); 145 *files = NULL; 146 *count = 0; 147 storage_file_free(dir); 148 furi_record_close(RECORD_STORAGE); 149 return false; 150 } 151 152 size_t idx = 0; 153 154 while (storage_dir_read(dir, &file_info, name_buf, sizeof(name_buf)) && 155 idx < file_count) { 156 if (!(file_info.flags & FSF_DIRECTORY)) { 157 size_t len = strlen(name_buf); 158 if (len > 3 && strcmp(name_buf + len - 3, ".ir") == 0) { 159 (*files)[idx] = furi_string_alloc_set(name_buf); 160 idx++; 161 } 162 } 163 } 164 165 storage_dir_close(dir); 166 storage_file_free(dir); 167 furi_record_close(RECORD_STORAGE); 168 return true; 169 } 170 171 void ir_helper_free_file_list(FuriString **files, size_t count) { 172 if (!files) 173 return; 174 for (size_t i = 0; i < count; i++) { 175 if (files[i]) { 176 furi_string_free(files[i]); 177 } 178 } 179 free(files); 180 }