ir_helper.c (4898B)
1 #include <flipper_format/flipper_format.h> 2 #include <furi.h> 3 #include <infrared/worker/infrared_worker.h> 4 #include <lib/infrared/signal/infrared_error_code.h> 5 #include <stdlib.h> 6 #include <storage/storage.h> 7 #include <string.h> 8 9 #include "ir_helper.h" 10 11 static bool ir_add_signal(IrSignalList *, InfraredSignal *, const char *); 12 static bool ir_is_file(const FileInfo *, const char *); 13 14 IrSignalList * 15 ir_list_alloc(void) 16 { 17 IrSignalList *list; 18 19 list = malloc(sizeof(IrSignalList)); 20 if (list == NULL) 21 return NULL; 22 23 list->items = NULL; 24 list->count = 0; 25 list->capacity = 0; 26 27 return list; 28 } 29 30 void 31 ir_list_free(IrSignalList *list) 32 { 33 size_t i; 34 35 if (list == NULL) 36 return; 37 38 for (i = 0; i < list->count; i++) { 39 if (list->items[i].signal != NULL) 40 infrared_signal_free(list->items[i].signal); 41 if (list->items[i].name != NULL) 42 furi_string_free(list->items[i].name); 43 } 44 free(list->items); 45 free(list); 46 } 47 48 bool 49 ir_load(const char *path, IrSignalList *list) 50 { 51 InfraredErrorCode err; 52 InfraredSignal *signal; 53 FlipperFormat *ff; 54 FuriString *filetype; 55 FuriString *sig; 56 Storage *storage; 57 uint32_t version; 58 bool header_ok; 59 bool success; 60 61 if (path == NULL || list == NULL) 62 return false; 63 64 storage = furi_record_open(RECORD_STORAGE); 65 if (storage == NULL) 66 return false; 67 68 ff = flipper_format_file_alloc(storage); 69 if (ff == NULL) { 70 furi_record_close(RECORD_STORAGE); 71 return false; 72 } 73 74 success = false; 75 filetype = NULL; 76 sig = NULL; 77 78 do { 79 if (!flipper_format_file_open_existing(ff, path)) 80 break; 81 82 filetype = furi_string_alloc(); 83 if (filetype == NULL) 84 break; 85 86 header_ok = flipper_format_read_header(ff, filetype, &version); 87 if (!header_ok) 88 break; 89 90 sig = furi_string_alloc(); 91 if (sig == NULL) 92 break; 93 94 for (;;) { 95 signal = infrared_signal_alloc(); 96 if (signal == NULL) 97 break; 98 99 err = infrared_signal_read(signal, ff, sig); 100 if (err == InfraredErrorCodeNone) { 101 if (!ir_add_signal( 102 list, 103 signal, 104 furi_string_get_cstr(sig))) { 105 infrared_signal_free(signal); 106 break; 107 } 108 } else { 109 infrared_signal_free(signal); 110 break; 111 } 112 } 113 success = true; 114 } while (false); 115 116 if (filetype != NULL) 117 furi_string_free(filetype); 118 if (sig != NULL) 119 furi_string_free(sig); 120 121 flipper_format_free(ff); 122 furi_record_close(RECORD_STORAGE); 123 124 return success; 125 } 126 127 void 128 ir_tx(InfraredSignal *signal) 129 { 130 infrared_signal_transmit(signal); 131 } 132 133 bool 134 ir_files(const char *dir_path, FuriString ***files, size_t *count) 135 { 136 FuriString **next_files; 137 Storage *storage; 138 FileInfo file_info; 139 size_t capacity; 140 char name_buf[256]; 141 File *dir; 142 bool dir_open; 143 bool ok; 144 145 if (dir_path == NULL || files == NULL || count == NULL) 146 return false; 147 148 *files = NULL; 149 *count = 0; 150 capacity = 0; 151 dir_open = false; 152 ok = false; 153 154 storage = furi_record_open(RECORD_STORAGE); 155 if (storage == NULL) 156 return false; 157 158 dir = storage_file_alloc(storage); 159 if (dir == NULL) 160 goto done; 161 162 if (!storage_dir_open(dir, dir_path)) 163 goto done; 164 dir_open = true; 165 166 while (storage_dir_read(dir, &file_info, name_buf, sizeof(name_buf))) { 167 if (!ir_is_file(&file_info, name_buf)) 168 continue; 169 170 if (*count >= capacity) { 171 size_t new_capacity; 172 173 new_capacity = capacity == 0 ? 8 : capacity * 2; 174 next_files = realloc(*files, new_capacity * sizeof(FuriString *)); 175 if (next_files == NULL) { 176 ir_files_free(*files, *count); 177 *files = NULL; 178 *count = 0; 179 goto done; 180 } 181 *files = next_files; 182 capacity = new_capacity; 183 } 184 185 (*files)[*count] = furi_string_alloc_set(name_buf); 186 if ((*files)[*count] == NULL) { 187 ir_files_free(*files, *count); 188 *files = NULL; 189 *count = 0; 190 goto done; 191 } 192 (*count)++; 193 } 194 195 ok = true; 196 197 done: 198 if (dir != NULL) { 199 if (dir_open) 200 storage_dir_close(dir); 201 storage_file_free(dir); 202 } 203 furi_record_close(RECORD_STORAGE); 204 return ok; 205 } 206 207 void 208 ir_files_free(FuriString **files, size_t count) 209 { 210 size_t i; 211 212 if (files == NULL) 213 return; 214 215 for (i = 0; i < count; i++) { 216 if (files[i] != NULL) 217 furi_string_free(files[i]); 218 } 219 free(files); 220 } 221 222 static bool 223 ir_add_signal(IrSignalList *list, InfraredSignal *signal, const char *name) 224 { 225 IrSignalItem *items; 226 size_t new_capacity; 227 228 if (list->count >= list->capacity) { 229 new_capacity = list->capacity == 0 ? 8 : list->capacity * 2; 230 items = realloc(list->items, new_capacity * sizeof(IrSignalItem)); 231 if (items == NULL) 232 return false; 233 list->items = items; 234 list->capacity = new_capacity; 235 } 236 237 list->items[list->count].signal = signal; 238 list->items[list->count].name = furi_string_alloc_set(name); 239 if (list->items[list->count].name == NULL) 240 return false; 241 242 list->count++; 243 return true; 244 } 245 246 static bool 247 ir_is_file(const FileInfo *file_info, const char *name) 248 { 249 size_t len; 250 251 if ((file_info->flags & FSF_DIRECTORY) || name == NULL) 252 return false; 253 254 len = strlen(name); 255 if (len <= 3) 256 return false; 257 258 return strcmp(name + len - 3, ".ir") == 0; 259 }