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>
This commit is contained in:
		
							parent
							
								
									5e35e51c57
								
							
						
					
					
						commit
						f61a8fda53
					
				| @ -1,4 +1,5 @@ | |||||||
| #include <cli/cli.h> | #include <cli/cli.h> | ||||||
|  | #include <cli/cli_i.h> | ||||||
| #include <infrared.h> | #include <infrared.h> | ||||||
| #include <infrared_worker.h> | #include <infrared_worker.h> | ||||||
| #include <furi_hal_infrared.h> | #include <furi_hal_infrared.h> | ||||||
| @ -6,12 +7,24 @@ | |||||||
| #include <toolbox/args.h> | #include <toolbox/args.h> | ||||||
| 
 | 
 | ||||||
| #include "infrared_signal.h" | #include "infrared_signal.h" | ||||||
|  | #include "infrared_brute_force.h" | ||||||
|  | 
 | ||||||
|  | #include "m-dict.h" | ||||||
|  | #include "m-string.h" | ||||||
| 
 | 
 | ||||||
| #define INFRARED_CLI_BUF_SIZE 10 | #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_rx(Cli* cli, FuriString* args); | ||||||
| static void infrared_cli_start_ir_tx(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_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 { | static const struct { | ||||||
|     const char* cmd; |     const char* cmd; | ||||||
| @ -20,6 +33,7 @@ static const struct { | |||||||
|     {.cmd = "rx", .process_function = infrared_cli_start_ir_rx}, |     {.cmd = "rx", .process_function = infrared_cli_start_ir_rx}, | ||||||
|     {.cmd = "tx", .process_function = infrared_cli_start_ir_tx}, |     {.cmd = "tx", .process_function = infrared_cli_start_ir_tx}, | ||||||
|     {.cmd = "decode", .process_function = infrared_cli_process_decode}, |     {.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) { | 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_MIN_FREQUENCY, | ||||||
|         INFRARED_MAX_FREQUENCY); |         INFRARED_MAX_FREQUENCY); | ||||||
|     printf("\tir decode <input_file> [<output_file>]\r\n"); |     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) { | 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); |     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) { | static void infrared_cli_start_ir(Cli* cli, FuriString* args, void* context) { | ||||||
|     UNUSED(context); |     UNUSED(context); | ||||||
|     if(furi_hal_infrared_is_busy()) { |     if(furi_hal_infrared_is_busy()) { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Travis Montoya
						Travis Montoya