Просмотр исходного кода

Feature/infrared add remote to cli (#1856)

* Initial testing of remote using cli
* More fixes for cli ir remote
* Fixes. Turns off power now
* Finished adding other tv remote commands
* Changed if-else formatting
* Cleaned up unused variables
* Updating cli unviersal remote to accept tv, ac and more modular. Listing signals still does not work properly
* Using mlib dictionary to get unique signals from files for ir universal list
* Fixing progress bar
* Added error checking for invalid signal to stop freezing cli
* Added error checking for arg length
* Api symbols was changed somehow.. changed back and updated the argument check to account for newline
* Fixing string compares and argument length issue
* Freeing InfraredBruteForce in cli brute force signals

Co-authored-by: sqlsquirreltm <sqlsquirreltm>
Co-authored-by: あく <alleteam@gmail.com>
Travis Montoya 3 лет назад
Родитель
Сommit
f61a8fda53
1 измененных файлов с 178 добавлено и 0 удалено
  1. 178 0
      applications/main/infrared/infrared_cli.c

+ 178 - 0
applications/main/infrared/infrared_cli.c

@@ -1,4 +1,5 @@
 #include <cli/cli.h>
+#include <cli/cli_i.h>
 #include <infrared.h>
 #include <infrared_worker.h>
 #include <furi_hal_infrared.h>
@@ -6,12 +7,24 @@
 #include <toolbox/args.h>
 
 #include "infrared_signal.h"
+#include "infrared_brute_force.h"
+
+#include "m-dict.h"
+#include "m-string.h"
 
 #define INFRARED_CLI_BUF_SIZE 10
 
+DICT_DEF2(dict_signals, string_t, STRING_OPLIST, int, M_DEFAULT_OPLIST)
+
+enum RemoteTypes { TV = 0, AC = 1 };
+
 static void infrared_cli_start_ir_rx(Cli* cli, FuriString* args);
 static void infrared_cli_start_ir_tx(Cli* cli, FuriString* args);
 static void infrared_cli_process_decode(Cli* cli, FuriString* args);
+static void infrared_cli_process_universal(Cli* cli, FuriString* args);
+static void infrared_cli_list_remote_signals(enum RemoteTypes remote_type);
+static void
+    infrared_cli_brute_force_signals(Cli* cli, enum RemoteTypes remote_type, FuriString* signal);
 
 static const struct {
     const char* cmd;
@@ -20,6 +33,7 @@ static const struct {
     {.cmd = "rx", .process_function = infrared_cli_start_ir_rx},
     {.cmd = "tx", .process_function = infrared_cli_start_ir_tx},
     {.cmd = "decode", .process_function = infrared_cli_process_decode},
+    {.cmd = "universal", .process_function = infrared_cli_process_universal},
 };
 
 static void signal_received_callback(void* context, InfraredWorkerSignal* received_signal) {
@@ -90,6 +104,8 @@ static void infrared_cli_print_usage(void) {
         INFRARED_MIN_FREQUENCY,
         INFRARED_MAX_FREQUENCY);
     printf("\tir decode <input_file> [<output_file>]\r\n");
+    printf("\tir universal <tv, ac> <signal name>\r\n");
+    printf("\tir universal list <tv, ac>\r\n");
 }
 
 static bool infrared_cli_parse_message(const char* str, InfraredSignal* signal) {
@@ -328,6 +344,168 @@ static void infrared_cli_process_decode(Cli* cli, FuriString* args) {
     furi_record_close(RECORD_STORAGE);
 }
 
+static void infrared_cli_process_universal(Cli* cli, FuriString* args) {
+    enum RemoteTypes Remote;
+
+    FuriString* command;
+    FuriString* remote;
+    FuriString* signal;
+    command = furi_string_alloc();
+    remote = furi_string_alloc();
+    signal = furi_string_alloc();
+
+    do {
+        if(!args_read_string_and_trim(args, command)) {
+            infrared_cli_print_usage();
+            break;
+        }
+
+        if(furi_string_cmp_str(command, "list") == 0) {
+            args_read_string_and_trim(args, remote);
+            if(furi_string_cmp_str(remote, "tv") == 0) {
+                Remote = TV;
+            } else if(furi_string_cmp_str(remote, "ac") == 0) {
+                Remote = AC;
+            } else {
+                printf("Invalid remote type.\r\n");
+                break;
+            }
+            infrared_cli_list_remote_signals(Remote);
+            break;
+        }
+
+        if(furi_string_cmp_str(command, "tv") == 0) {
+            Remote = TV;
+        } else if(furi_string_cmp_str(command, "ac") == 0) {
+            Remote = AC;
+        } else {
+            printf("Invalid remote type.\r\n");
+            break;
+        }
+
+        args_read_string_and_trim(args, signal);
+        if(furi_string_empty(signal)) {
+            printf("Must supply a valid signal for type of remote selected.\r\n");
+            break;
+        }
+
+        infrared_cli_brute_force_signals(cli, Remote, signal);
+        break;
+
+    } while(false);
+
+    furi_string_free(command);
+    furi_string_free(remote);
+    furi_string_free(signal);
+}
+
+static void infrared_cli_list_remote_signals(enum RemoteTypes remote_type) {
+    Storage* storage = furi_record_open(RECORD_STORAGE);
+    FlipperFormat* ff = flipper_format_buffered_file_alloc(storage);
+    dict_signals_t signals_dict;
+    string_t key;
+    const char* remote_file = NULL;
+    bool success = false;
+    int max = 1;
+
+    switch(remote_type) {
+    case TV:
+        remote_file = EXT_PATH("infrared/assets/tv.ir");
+        break;
+    case AC:
+        remote_file = EXT_PATH("infrared/assets/ac.ir");
+        break;
+    default:
+        break;
+    }
+
+    dict_signals_init(signals_dict);
+    string_init(key);
+
+    success = flipper_format_buffered_file_open_existing(ff, remote_file);
+    if(success) {
+        FuriString* signal_name;
+        signal_name = furi_string_alloc();
+        printf("Valid signals:\r\n");
+        while(flipper_format_read_string(ff, "name", signal_name)) {
+            string_set_str(key, furi_string_get_cstr(signal_name));
+            int* v = dict_signals_get(signals_dict, key);
+            if(v != NULL) {
+                (*v)++;
+                max = M_MAX(*v, max);
+            } else {
+                dict_signals_set_at(signals_dict, key, 1);
+            }
+        }
+        dict_signals_it_t it;
+        for(dict_signals_it(it, signals_dict); !dict_signals_end_p(it); dict_signals_next(it)) {
+            const struct dict_signals_pair_s* pair = dict_signals_cref(it);
+            printf("\t%s\r\n", string_get_cstr(pair->key));
+        }
+        furi_string_free(signal_name);
+    }
+
+    string_clear(key);
+    dict_signals_clear(signals_dict);
+    flipper_format_free(ff);
+    furi_record_close(RECORD_STORAGE);
+}
+
+static void
+    infrared_cli_brute_force_signals(Cli* cli, enum RemoteTypes remote_type, FuriString* signal) {
+    InfraredBruteForce* brute_force = infrared_brute_force_alloc();
+    const char* remote_file = NULL;
+    uint32_t i = 0;
+    bool success = false;
+
+    switch(remote_type) {
+    case TV:
+        remote_file = EXT_PATH("infrared/assets/tv.ir");
+        break;
+    case AC:
+        remote_file = EXT_PATH("infrared/assets/ac.ir");
+        break;
+    default:
+        break;
+    }
+
+    infrared_brute_force_set_db_filename(brute_force, remote_file);
+    infrared_brute_force_add_record(brute_force, i++, furi_string_get_cstr(signal));
+
+    success = infrared_brute_force_calculate_messages(brute_force);
+    if(success) {
+        uint32_t record_count;
+        uint32_t index = 0;
+        int records_sent = 0;
+        bool running = false;
+
+        running = infrared_brute_force_start(brute_force, index, &record_count);
+        if(record_count <= 0) {
+            printf("Invalid signal.\n");
+            infrared_brute_force_reset(brute_force);
+            return;
+        }
+
+        printf("Sending %ld codes to the tv.\r\n", record_count);
+        printf("Press Ctrl-C to stop.\r\n");
+        while(running) {
+            running = infrared_brute_force_send_next(brute_force);
+
+            if(cli_cmd_interrupt_received(cli)) break;
+
+            printf("\r%d%% complete.", (int)((float)records_sent++ / (float)record_count * 100));
+            fflush(stdout);
+        }
+
+        infrared_brute_force_stop(brute_force);
+    } else {
+        printf("Invalid signal.\r\n");
+    }
+
+    infrared_brute_force_reset(brute_force);
+    infrared_brute_force_free(brute_force);
+}
+
 static void infrared_cli_start_ir(Cli* cli, FuriString* args, void* context) {
     UNUSED(context);
     if(furi_hal_infrared_is_busy()) {