timed-remote

Flipper Zero app for sending delayed IR commands
git clone git://src.adamsgaard.dk/timed-remote # fast
git clone https://src.adamsgaard.dk/timed-remote.git # slow
Log | Files | Refs | README | LICENSE Back to index

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 }