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 (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 }