[FL-1929, FL-2164] IR App migrate to FFF (#949)
* IR app move to FFF * [FL-2164] Hide unimplemented submenus * Fix brute force fail * Fix FFF endless reading * Reformat TV bruteforce lib to FFF * fixes & cleanup * Infrared: switch to constexpr. Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									389ff92cc1
								
							
						
					
					
						commit
						990a065bd0
					
				| @ -11,6 +11,7 @@ | |||||||
| #include <m-string.h> | #include <m-string.h> | ||||||
| #include <irda_transmit.h> | #include <irda_transmit.h> | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
|  | #include "../helpers/irda_parser.h" | ||||||
| 
 | 
 | ||||||
| static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) { | static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) { | ||||||
|     furi_assert(received_signal); |     furi_assert(received_signal); | ||||||
| @ -83,41 +84,17 @@ static void irda_cli_print_usage(void) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool parse_message(const char* str, IrdaMessage* message) { | static bool parse_message(const char* str, IrdaMessage* message) { | ||||||
|     uint32_t command = 0; |  | ||||||
|     uint32_t address = 0; |  | ||||||
|     char protocol_name[32]; |     char protocol_name[32]; | ||||||
|     int parsed = sscanf(str, "%31s %lX %lX", protocol_name, &address, &command); |     int parsed = sscanf(str, "%31s %lX %lX", protocol_name, &message->address, &message->command); | ||||||
| 
 | 
 | ||||||
|     if(parsed != 3) { |     if(parsed != 3) { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     IrdaProtocol protocol = irda_get_protocol_by_name(protocol_name); |     message->protocol = irda_get_protocol_by_name(protocol_name); | ||||||
| 
 |  | ||||||
|     if(!irda_is_protocol_valid(protocol)) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     uint32_t address_length = irda_get_protocol_address_length(protocol); |  | ||||||
|     uint32_t address_mask = (1LU << address_length) - 1; |  | ||||||
|     if(address != (address & address_mask)) { |  | ||||||
|         printf("Address out of range (mask 0x%08lX): 0x%lX\r\n", address_mask, address); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     uint32_t command_length = irda_get_protocol_command_length(protocol); |  | ||||||
|     uint32_t command_mask = (1LU << command_length) - 1; |  | ||||||
|     if(command != (command & command_mask)) { |  | ||||||
|         printf("Command out of range (mask 0x%08lX): 0x%lX\r\n", command_mask, command); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     message->protocol = protocol; |  | ||||||
|     message->address = address; |  | ||||||
|     message->command = command; |  | ||||||
|     message->repeat = false; |     message->repeat = false; | ||||||
| 
 | 
 | ||||||
|     return true; |     return irda_parser_is_parsed_signal_valid(message); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool parse_signal_raw( | static bool parse_signal_raw( | ||||||
| @ -135,14 +112,6 @@ static bool parse_signal_raw( | |||||||
|     *duty_cycle = (float)atoi(duty_cycle_str) / 100; |     *duty_cycle = (float)atoi(duty_cycle_str) / 100; | ||||||
|     str += strlen(frequency_str) + strlen(duty_cycle_str) + 10; |     str += strlen(frequency_str) + strlen(duty_cycle_str) + 10; | ||||||
| 
 | 
 | ||||||
|     if((*frequency > IRDA_MAX_FREQUENCY) || (*frequency < IRDA_MIN_FREQUENCY)) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if((*duty_cycle <= 0) || (*duty_cycle > 1)) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     uint32_t timings_cnt_max = *timings_cnt; |     uint32_t timings_cnt_max = *timings_cnt; | ||||||
|     *timings_cnt = 0; |     *timings_cnt = 0; | ||||||
| 
 | 
 | ||||||
| @ -159,15 +128,7 @@ static bool parse_signal_raw( | |||||||
|         ++*timings_cnt; |         ++*timings_cnt; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(*timings_cnt > 0) { |     return irda_parser_is_raw_signal_valid(*frequency, *duty_cycle, *timings_cnt); | ||||||
|         printf("\r\nTransmit:"); |  | ||||||
|         for(size_t i = 0; i < *timings_cnt; ++i) { |  | ||||||
|             printf(" %ld", timings[i]); |  | ||||||
|         } |  | ||||||
|         printf("\r\n"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return (parsed == 2) && (*timings_cnt > 0); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void irda_cli_start_ir_tx(Cli* cli, string_t args, void* context) { | void irda_cli_start_ir_tx(Cli* cli, string_t args, void* context) { | ||||||
| @ -180,8 +141,8 @@ void irda_cli_start_ir_tx(Cli* cli, string_t args, void* context) { | |||||||
|     const char* str = string_get_cstr(args); |     const char* str = string_get_cstr(args); | ||||||
|     uint32_t frequency; |     uint32_t frequency; | ||||||
|     float duty_cycle; |     float duty_cycle; | ||||||
|     uint32_t* timings = (uint32_t*)furi_alloc(sizeof(uint32_t) * 512); |     uint32_t timings_cnt = MAX_TIMINGS_AMOUNT; | ||||||
|     uint32_t timings_cnt = 512; |     uint32_t* timings = (uint32_t*)furi_alloc(sizeof(uint32_t) * timings_cnt); | ||||||
| 
 | 
 | ||||||
|     if(parse_message(str, &message)) { |     if(parse_message(str, &message)) { | ||||||
|         irda_send(&message, 1); |         irda_send(&message, 1); | ||||||
|  | |||||||
							
								
								
									
										145
									
								
								applications/irda/helpers/irda_parser.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								applications/irda/helpers/irda_parser.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,145 @@ | |||||||
|  | 
 | ||||||
|  | #include "../irda_app_signal.h" | ||||||
|  | #include "irda.h" | ||||||
|  | #include "irda/helpers/irda_parser.h" | ||||||
|  | #include "irda_worker.h" | ||||||
|  | #include "m-string.h" | ||||||
|  | #include <flipper_file.h> | ||||||
|  | #include <memory> | ||||||
|  | #include <string> | ||||||
|  | #include <furi_hal_irda.h> | ||||||
|  | 
 | ||||||
|  | #define TAG "IrdaParser" | ||||||
|  | 
 | ||||||
|  | bool irda_parser_save_signal(FlipperFile* ff, const IrdaAppSignal& signal, const std::string& name) { | ||||||
|  |     furi_assert(ff); | ||||||
|  |     furi_assert(!name.empty()); | ||||||
|  | 
 | ||||||
|  |     bool result = false; | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         if(!flipper_file_write_comment_cstr(ff, "")) break; | ||||||
|  |         if(!flipper_file_write_string_cstr(ff, "name", name.c_str())) break; | ||||||
|  |         if(signal.is_raw()) { | ||||||
|  |             furi_assert(signal.get_raw_signal().timings_cnt <= MAX_TIMINGS_AMOUNT); | ||||||
|  |             auto raw_signal = signal.get_raw_signal(); | ||||||
|  |             if(!flipper_file_write_string_cstr(ff, "type", "raw")) break; | ||||||
|  |             if(!flipper_file_write_uint32(ff, "frequency", &raw_signal.frequency, 1)) break; | ||||||
|  |             if(!flipper_file_write_float(ff, "duty_cycle", &raw_signal.duty_cycle, 1)) break; | ||||||
|  |             if(!flipper_file_write_uint32(ff, "data", raw_signal.timings, raw_signal.timings_cnt)) | ||||||
|  |                 break; | ||||||
|  |         } else { | ||||||
|  |             auto parsed_signal = signal.get_message(); | ||||||
|  |             const char* protocol_name = irda_get_protocol_name(parsed_signal.protocol); | ||||||
|  |             if(!flipper_file_write_string_cstr(ff, "type", "parsed")) break; | ||||||
|  |             if(!flipper_file_write_string_cstr(ff, "protocol", protocol_name)) break; | ||||||
|  |             if(!flipper_file_write_hex(ff, "address", (uint8_t*)&parsed_signal.address, 4)) break; | ||||||
|  |             if(!flipper_file_write_hex(ff, "command", (uint8_t*)&parsed_signal.command, 4)) break; | ||||||
|  |         } | ||||||
|  |         result = true; | ||||||
|  |     } while(0); | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool irda_parser_read_signal(FlipperFile* ff, IrdaAppSignal& signal, std::string& name) { | ||||||
|  |     furi_assert(ff); | ||||||
|  | 
 | ||||||
|  |     bool result = false; | ||||||
|  |     string_t read_string; | ||||||
|  |     string_init(read_string); | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         if(!flipper_file_read_string(ff, "name", read_string)) break; | ||||||
|  |         name = string_get_cstr(read_string); | ||||||
|  |         if(!flipper_file_read_string(ff, "type", read_string)) break; | ||||||
|  |         if(!string_cmp_str(read_string, "raw")) { | ||||||
|  |             uint32_t* timings = nullptr; | ||||||
|  |             uint32_t timings_cnt = 0; | ||||||
|  |             uint32_t frequency = 0; | ||||||
|  |             float duty_cycle = 0; | ||||||
|  | 
 | ||||||
|  |             if(!flipper_file_read_uint32(ff, "frequency", &frequency, 1)) break; | ||||||
|  |             if(!flipper_file_read_float(ff, "duty_cycle", &duty_cycle, 1)) break; | ||||||
|  |             if(!flipper_file_get_value_count(ff, "data", &timings_cnt)) break; | ||||||
|  |             if(timings_cnt > MAX_TIMINGS_AMOUNT) break; | ||||||
|  |             timings = (uint32_t*)furi_alloc(sizeof(uint32_t) * timings_cnt); | ||||||
|  |             if(flipper_file_read_uint32(ff, "data", timings, timings_cnt)) { | ||||||
|  |                 signal.set_raw_signal(timings, timings_cnt, frequency, duty_cycle); | ||||||
|  |                 result = true; | ||||||
|  |             } | ||||||
|  |             free(timings); | ||||||
|  |         } else if(!string_cmp_str(read_string, "parsed")) { | ||||||
|  |             IrdaMessage parsed_signal; | ||||||
|  |             if(!flipper_file_read_string(ff, "protocol", read_string)) break; | ||||||
|  |             parsed_signal.protocol = irda_get_protocol_by_name(string_get_cstr(read_string)); | ||||||
|  |             if(!flipper_file_read_hex(ff, "address", (uint8_t*)&parsed_signal.address, 4)) break; | ||||||
|  |             if(!flipper_file_read_hex(ff, "command", (uint8_t*)&parsed_signal.command, 4)) break; | ||||||
|  |             if(!irda_parser_is_parsed_signal_valid(&parsed_signal)) break; | ||||||
|  |             signal.set_message(&parsed_signal); | ||||||
|  |             result = true; | ||||||
|  |         } else { | ||||||
|  |             FURI_LOG_E(TAG, "Unknown type of signal (allowed - raw/parsed) "); | ||||||
|  |         } | ||||||
|  |     } while(0); | ||||||
|  | 
 | ||||||
|  |     string_clear(read_string); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool irda_parser_is_parsed_signal_valid(const IrdaMessage* signal) { | ||||||
|  |     furi_assert(signal); | ||||||
|  |     bool result = true; | ||||||
|  | 
 | ||||||
|  |     if(!irda_is_protocol_valid(signal->protocol)) { | ||||||
|  |         FURI_LOG_E(TAG, "Unknown protocol"); | ||||||
|  |         result = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     uint32_t address_length = irda_get_protocol_address_length(signal->protocol); | ||||||
|  |     uint32_t address_mask = (1LU << address_length) - 1; | ||||||
|  |     if(signal->address != (signal->address & address_mask)) { | ||||||
|  |         FURI_LOG_E( | ||||||
|  |             TAG, | ||||||
|  |             "Address is out of range (mask 0x%08lX): 0x%lX\r\n", | ||||||
|  |             address_mask, | ||||||
|  |             signal->address); | ||||||
|  |         result = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     uint32_t command_length = irda_get_protocol_command_length(signal->protocol); | ||||||
|  |     uint32_t command_mask = (1LU << command_length) - 1; | ||||||
|  |     if(signal->command != (signal->command & command_mask)) { | ||||||
|  |         FURI_LOG_E( | ||||||
|  |             TAG, | ||||||
|  |             "Command is out of range (mask 0x%08lX): 0x%lX\r\n", | ||||||
|  |             command_mask, | ||||||
|  |             signal->command); | ||||||
|  |         result = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool irda_parser_is_raw_signal_valid(uint32_t frequency, float duty_cycle, uint32_t timings_cnt) { | ||||||
|  |     bool result = true; | ||||||
|  | 
 | ||||||
|  |     if((frequency > IRDA_MAX_FREQUENCY) || (frequency < IRDA_MIN_FREQUENCY)) { | ||||||
|  |         FURI_LOG_E( | ||||||
|  |             TAG, | ||||||
|  |             "Frequency is out of range (%lX - %lX): %lX", | ||||||
|  |             IRDA_MIN_FREQUENCY, | ||||||
|  |             IRDA_MAX_FREQUENCY, | ||||||
|  |             frequency); | ||||||
|  |         result = false; | ||||||
|  |     } else if((duty_cycle <= 0) || (duty_cycle > 1)) { | ||||||
|  |         FURI_LOG_E(TAG, "Duty cycle is out of range (0 - 1): %f", duty_cycle); | ||||||
|  |         result = false; | ||||||
|  |     } else if((timings_cnt <= 0) || (timings_cnt > MAX_TIMINGS_AMOUNT)) { | ||||||
|  |         FURI_LOG_E( | ||||||
|  |             TAG, "Timings amount is out of range (0 - %lX): %lX", MAX_TIMINGS_AMOUNT, timings_cnt); | ||||||
|  |         result = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								applications/irda/helpers/irda_parser.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								applications/irda/helpers/irda_parser.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "../irda_app_signal.h" | ||||||
|  | #include <flipper_file.h> | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | bool irda_parser_save_signal(FlipperFile* ff, const IrdaAppSignal& signal, const std::string& name); | ||||||
|  | bool irda_parser_read_signal(FlipperFile* ff, IrdaAppSignal& signal, std::string& name); | ||||||
|  | bool irda_parser_is_parsed_signal_valid(const IrdaMessage* signal); | ||||||
|  | bool irda_parser_is_raw_signal_valid(uint32_t frequency, float duty_cycle, uint32_t timings_cnt); | ||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "irda_app.h" | #include "irda_app.h" | ||||||
| #include "irda/irda_app_file_parser.h" |  | ||||||
| #include <irda_worker.h> | #include <irda_worker.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| @ -13,11 +12,9 @@ int32_t IrdaApp::run(void* args) { | |||||||
|     bool exit = false; |     bool exit = false; | ||||||
| 
 | 
 | ||||||
|     if(args) { |     if(args) { | ||||||
|         std::string remote_name; |         std::string full_name = static_cast<const char*>(args); | ||||||
|         { |         std::string remote_name(full_name, full_name.find_last_of('/') + 1, full_name.size()); | ||||||
|             IrdaAppFileParser file_parser; |         remote_name.erase(remote_name.find_last_of('.')); | ||||||
|             remote_name = file_parser.make_name(static_cast<const char*>(args)); |  | ||||||
|         } |  | ||||||
|         bool result = remote_manager.load(remote_name); |         bool result = remote_manager.load(remote_name); | ||||||
|         if(result) { |         if(result) { | ||||||
|             current_scene = IrdaApp::Scene::Remote; |             current_scene = IrdaApp::Scene::Remote; | ||||||
|  | |||||||
| @ -90,9 +90,15 @@ public: | |||||||
|     IrdaApp(); |     IrdaApp(); | ||||||
|     ~IrdaApp(); |     ~IrdaApp(); | ||||||
| 
 | 
 | ||||||
|  |     static constexpr const char* irda_directory = "/any/irda"; | ||||||
|  |     static constexpr const char* irda_extension = ".ir"; | ||||||
|  |     static constexpr const uint32_t max_raw_timings_in_signal = 512; | ||||||
|  |     static constexpr const uint32_t max_line_length = | ||||||
|  |         (9 + 1) * IrdaApp::max_raw_timings_in_signal + 100; | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     static inline const uint8_t text_store_size = 128; |     static constexpr const uint8_t text_store_size = 128; | ||||||
|     static inline const uint8_t text_store_max = 2; |     static constexpr const uint8_t text_store_max = 2; | ||||||
|     char text_store[text_store_max][text_store_size + 1]; |     char text_store[text_store_max][text_store_size + 1]; | ||||||
|     bool learn_new_remote; |     bool learn_new_remote; | ||||||
|     EditElement element; |     EditElement element; | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| #include "irda_app_brute_force.h" |  | ||||||
| #include "irda/irda_app_file_parser.h" |  | ||||||
| 
 | 
 | ||||||
|  | #include "helpers/irda_parser.h" | ||||||
|  | #include "irda_app_brute_force.h" | ||||||
|  | #include "irda_app_signal.h" | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <m-string.h> | #include <m-string.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| @ -12,57 +13,59 @@ void IrdaAppBruteForce::add_record(int index, const char* name) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool IrdaAppBruteForce::calculate_messages() { | bool IrdaAppBruteForce::calculate_messages() { | ||||||
|     bool fs_res = false; |     bool result = false; | ||||||
|     furi_assert(!file_parser); |  | ||||||
| 
 | 
 | ||||||
|     file_parser = std::make_unique<IrdaAppFileParser>(); |     Storage* storage = static_cast<Storage*>(furi_record_open("storage")); | ||||||
|     fs_res = file_parser->open_irda_file_read(universal_db_filename); |     FlipperFile* ff = flipper_file_alloc(storage); | ||||||
|     if(!fs_res) { |     result = flipper_file_open_existing(ff, universal_db_filename); | ||||||
|         file_parser.reset(); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     while(1) { |     if(result) { | ||||||
|         auto file_signal = file_parser->read_signal(); |         IrdaAppSignal signal; | ||||||
|         if(!file_signal) break; |  | ||||||
| 
 | 
 | ||||||
|         auto element = records.find(file_signal->name); |         string_t signal_name; | ||||||
|  |         string_init(signal_name); | ||||||
|  |         while(flipper_file_read_string(ff, "name", signal_name)) { | ||||||
|  |             auto element = records.find(string_get_cstr(signal_name)); | ||||||
|             if(element != records.cend()) { |             if(element != records.cend()) { | ||||||
|                 ++element->second.amount; |                 ++element->second.amount; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         string_clear(signal_name); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     file_parser->close(); |     flipper_file_close(ff); | ||||||
|     file_parser.reset(); |     flipper_file_free(ff); | ||||||
| 
 |     furi_record_close("storage"); | ||||||
|     return true; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IrdaAppBruteForce::stop_bruteforce() { | void IrdaAppBruteForce::stop_bruteforce() { | ||||||
|     furi_assert((current_record.size())); |     furi_assert((current_record.size())); | ||||||
| 
 | 
 | ||||||
|     if(current_record.size()) { |     if(current_record.size()) { | ||||||
|         furi_assert(file_parser); |         furi_assert(ff); | ||||||
|         current_record.clear(); |         current_record.clear(); | ||||||
|         file_parser->close(); |         flipper_file_close(ff); | ||||||
|         file_parser.reset(); |         flipper_file_free(ff); | ||||||
|  |         furi_record_close("storage"); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool IrdaAppBruteForce::send_next_bruteforce(void) { | bool IrdaAppBruteForce::send_next_bruteforce(void) { | ||||||
|     furi_assert(current_record.size()); |     furi_assert(current_record.size()); | ||||||
|     furi_assert(file_parser); |     furi_assert(ff); | ||||||
| 
 |  | ||||||
|     std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> file_signal; |  | ||||||
| 
 | 
 | ||||||
|  |     IrdaAppSignal signal; | ||||||
|  |     std::string signal_name; | ||||||
|  |     bool result = false; | ||||||
|     do { |     do { | ||||||
|         file_signal = file_parser->read_signal(); |         result = irda_parser_read_signal(ff, signal, signal_name); | ||||||
|     } while(file_signal && current_record.compare(file_signal->name)); |     } while(result && current_record.compare(signal_name)); | ||||||
| 
 | 
 | ||||||
|     if(file_signal) { |     if(result) { | ||||||
|         file_signal->signal.transmit(); |         signal.transmit(); | ||||||
|     } |     } | ||||||
|     return !!file_signal; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool IrdaAppBruteForce::start_bruteforce(int index, int& record_amount) { | bool IrdaAppBruteForce::start_bruteforce(int index, int& record_amount) { | ||||||
| @ -80,10 +83,13 @@ bool IrdaAppBruteForce::start_bruteforce(int index, int& record_amount) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(record_amount) { |     if(record_amount) { | ||||||
|         file_parser = std::make_unique<IrdaAppFileParser>(); |         Storage* storage = static_cast<Storage*>(furi_record_open("storage")); | ||||||
|         result = file_parser->open_irda_file_read(universal_db_filename); |         ff = flipper_file_alloc(storage); | ||||||
|  |         result = flipper_file_open_existing(ff, universal_db_filename); | ||||||
|         if(!result) { |         if(!result) { | ||||||
|             file_parser.reset(); |             flipper_file_close(ff); | ||||||
|  |             flipper_file_free(ff); | ||||||
|  |             furi_record_close("storage"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,14 +1,13 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "irda_app_file_parser.h" |  | ||||||
| 
 |  | ||||||
| #include <unordered_map> | #include <unordered_map> | ||||||
| #include <memory> | #include <memory> | ||||||
|  | #include <flipper_file.h> | ||||||
| 
 | 
 | ||||||
| class IrdaAppBruteForce { | class IrdaAppBruteForce { | ||||||
|     const char* universal_db_filename; |     const char* universal_db_filename; | ||||||
|     std::string current_record; |     std::string current_record; | ||||||
|     std::unique_ptr<IrdaAppFileParser> file_parser; |     FlipperFile* ff; | ||||||
| 
 | 
 | ||||||
|     typedef struct { |     typedef struct { | ||||||
|         int index; |         int index; | ||||||
|  | |||||||
| @ -1,396 +0,0 @@ | |||||||
| #include "irda_app_file_parser.h" |  | ||||||
| #include "irda_app_remote_manager.h" |  | ||||||
| #include "irda_app_signal.h" |  | ||||||
| 
 |  | ||||||
| #include <m-string.h> |  | ||||||
| #include <cstdio> |  | ||||||
| #include <text_store.h> |  | ||||||
| #include <irda.h> |  | ||||||
| #include <string_view> |  | ||||||
| #include <furi.h> |  | ||||||
| #include <furi_hal_irda.h> |  | ||||||
| #include <file_worker_cpp.h> |  | ||||||
| 
 |  | ||||||
| #define TAG "IrdaFileParser" |  | ||||||
| 
 |  | ||||||
| bool IrdaAppFileParser::open_irda_file_read(const char* name) { |  | ||||||
|     std::string full_filename; |  | ||||||
|     if(name[0] != '/') |  | ||||||
|         full_filename = make_full_name(name); |  | ||||||
|     else |  | ||||||
|         full_filename = name; |  | ||||||
| 
 |  | ||||||
|     return file_worker.open(full_filename.c_str(), FSAM_READ, FSOM_OPEN_EXISTING); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool IrdaAppFileParser::open_irda_file_write(const char* name) { |  | ||||||
|     std::string dirname(irda_directory); |  | ||||||
|     auto full_filename = make_full_name(name); |  | ||||||
| 
 |  | ||||||
|     if(!file_worker.mkdir(dirname.c_str())) return false; |  | ||||||
| 
 |  | ||||||
|     return file_worker.open(full_filename.c_str(), FSAM_WRITE, FSOM_CREATE_ALWAYS); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| size_t IrdaAppFileParser::stringify_message( |  | ||||||
|     const IrdaAppSignal& signal, |  | ||||||
|     const char* name, |  | ||||||
|     char* buf, |  | ||||||
|     size_t buf_size) { |  | ||||||
|     auto message = signal.get_message(); |  | ||||||
|     auto protocol = message.protocol; |  | ||||||
|     size_t written = 0; |  | ||||||
| 
 |  | ||||||
|     written += sniprintf( |  | ||||||
|         buf, |  | ||||||
|         buf_size, |  | ||||||
|         "%.31s %.31s A:%0*lX C:%0*lX\n", |  | ||||||
|         name, |  | ||||||
|         irda_get_protocol_name(protocol), |  | ||||||
|         ROUND_UP_TO(irda_get_protocol_address_length(protocol), 4), |  | ||||||
|         message.address, |  | ||||||
|         ROUND_UP_TO(irda_get_protocol_command_length(protocol), 4), |  | ||||||
|         message.command); |  | ||||||
| 
 |  | ||||||
|     furi_assert(written < buf_size); |  | ||||||
|     if(written >= buf_size) { |  | ||||||
|         written = 0; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return written; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| size_t IrdaAppFileParser::stringify_raw_signal( |  | ||||||
|     const IrdaAppSignal& signal, |  | ||||||
|     const char* name, |  | ||||||
|     char* buf, |  | ||||||
|     size_t buf_size) { |  | ||||||
|     size_t written = 0; |  | ||||||
|     int duty_cycle = 100 * IRDA_COMMON_DUTY_CYCLE; |  | ||||||
|     written += sniprintf( |  | ||||||
|         &buf[written], |  | ||||||
|         max_line_length - written, |  | ||||||
|         "%.31s RAW F:%d DC:%d", |  | ||||||
|         name, |  | ||||||
|         IRDA_COMMON_CARRIER_FREQUENCY, |  | ||||||
|         duty_cycle); |  | ||||||
| 
 |  | ||||||
|     auto& raw_signal = signal.get_raw_signal(); |  | ||||||
|     for(size_t i = 0; i < raw_signal.timings_cnt; ++i) { |  | ||||||
|         written += sniprintf(&buf[written], buf_size - written, " %ld", raw_signal.timings[i]); |  | ||||||
|         if(written > buf_size) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     written += snprintf(&buf[written], buf_size - written, "\n"); |  | ||||||
| 
 |  | ||||||
|     furi_assert(written < buf_size); |  | ||||||
|     if(written >= buf_size) { |  | ||||||
|         written = 0; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return written; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool IrdaAppFileParser::save_signal(const IrdaAppSignal& signal, const char* name) { |  | ||||||
|     char* buf = new char[max_line_length]; |  | ||||||
|     size_t buf_cnt = 0; |  | ||||||
|     bool write_result = false; |  | ||||||
| 
 |  | ||||||
|     if(signal.is_raw()) { |  | ||||||
|         buf_cnt = stringify_raw_signal(signal, name, buf, max_line_length); |  | ||||||
|     } else { |  | ||||||
|         buf_cnt = stringify_message(signal, name, buf, max_line_length); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(buf_cnt) { |  | ||||||
|         write_result = file_worker.write(buf, buf_cnt); |  | ||||||
|     } |  | ||||||
|     delete[] buf; |  | ||||||
|     return write_result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> IrdaAppFileParser::read_signal(void) { |  | ||||||
|     string_t line; |  | ||||||
|     string_init(line); |  | ||||||
|     string_reserve(line, max_line_length); |  | ||||||
|     std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> file_signal; |  | ||||||
| 
 |  | ||||||
|     while(!file_signal && |  | ||||||
|           file_worker.read_until_buffered(line, file_buf, &file_buf_cnt, sizeof(file_buf))) { |  | ||||||
|         if(string_empty_p(line)) { |  | ||||||
|             continue; |  | ||||||
|         } |  | ||||||
|         auto c_str = string_get_cstr(line); |  | ||||||
|         file_signal = parse_signal(c_str); |  | ||||||
|         if(!file_signal) { |  | ||||||
|             file_signal = parse_signal_raw(c_str); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     string_clear(line); |  | ||||||
| 
 |  | ||||||
|     return file_signal; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> |  | ||||||
|     IrdaAppFileParser::parse_signal(const std::string& str) const { |  | ||||||
|     char protocol_name[32]; |  | ||||||
|     uint32_t address; |  | ||||||
|     uint32_t command; |  | ||||||
|     auto irda_file_signal = std::make_unique<IrdaFileSignal>(); |  | ||||||
| 
 |  | ||||||
|     int parsed = std::sscanf( |  | ||||||
|         str.c_str(), |  | ||||||
|         "%31s %31s A:%lX C:%lX", |  | ||||||
|         irda_file_signal->name, |  | ||||||
|         protocol_name, |  | ||||||
|         &address, |  | ||||||
|         &command); |  | ||||||
| 
 |  | ||||||
|     if(parsed != 4) { |  | ||||||
|         return nullptr; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     IrdaProtocol protocol = irda_get_protocol_by_name(protocol_name); |  | ||||||
| 
 |  | ||||||
|     if(!irda_is_protocol_valid((IrdaProtocol)protocol)) { |  | ||||||
|         size_t end_of_str = MIN(str.find_last_not_of(" \t\r\n") + 1, (size_t)30); |  | ||||||
|         FURI_LOG_E( |  | ||||||
|             TAG, "Unknown protocol(\'%.*s...\'): \'%s\'", end_of_str, str.c_str(), protocol_name); |  | ||||||
|         return nullptr; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     uint32_t address_length = irda_get_protocol_address_length(protocol); |  | ||||||
|     uint32_t address_mask = (1LU << address_length) - 1; |  | ||||||
|     if(address != (address & address_mask)) { |  | ||||||
|         size_t end_of_str = MIN(str.find_last_not_of(" \t\r\n") + 1, (size_t)30); |  | ||||||
|         FURI_LOG_E( |  | ||||||
|             TAG, |  | ||||||
|             "Signal(\'%.*s...\'): address is too long (mask for this protocol is 0x%08X): 0x%X", |  | ||||||
|             end_of_str, |  | ||||||
|             str.c_str(), |  | ||||||
|             address_mask, |  | ||||||
|             address); |  | ||||||
|         return nullptr; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     uint32_t command_length = irda_get_protocol_command_length(protocol); |  | ||||||
|     uint32_t command_mask = (1LU << command_length) - 1; |  | ||||||
|     if(command != (command & command_mask)) { |  | ||||||
|         size_t end_of_str = MIN(str.find_last_not_of(" \t\r\n") + 1, (size_t)30); |  | ||||||
|         FURI_LOG_E( |  | ||||||
|             TAG, |  | ||||||
|             "Signal(\'%.*s...\'): command is too long (mask for this protocol is 0x%08X): 0x%X", |  | ||||||
|             end_of_str, |  | ||||||
|             str.c_str(), |  | ||||||
|             command_mask, |  | ||||||
|             command); |  | ||||||
|         return nullptr; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     IrdaMessage message = { |  | ||||||
|         .protocol = protocol, |  | ||||||
|         .address = address, |  | ||||||
|         .command = command, |  | ||||||
|         .repeat = false, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     irda_file_signal->signal.set_message(&message); |  | ||||||
| 
 |  | ||||||
|     return irda_file_signal; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const char* find_first_not_of(const char* str, char symbol) { |  | ||||||
|     const char* str_start = nullptr; |  | ||||||
|     while(str != str_start) { |  | ||||||
|         str_start = str; |  | ||||||
|         str = strchr(str, symbol); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return str; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int remove_args32(std::string_view& str, size_t num) { |  | ||||||
|     int removed_length = 0; |  | ||||||
| 
 |  | ||||||
|     while(num--) { |  | ||||||
|         char buf[32]; |  | ||||||
| 
 |  | ||||||
|         size_t index = str.find_first_not_of(" \t"); |  | ||||||
|         if(index == std::string_view::npos) break; |  | ||||||
|         removed_length += index; |  | ||||||
|         str.remove_prefix(index); |  | ||||||
| 
 |  | ||||||
|         if(str.empty()) break; |  | ||||||
| 
 |  | ||||||
|         int parsed = std::sscanf(str.data(), "%31s", buf); |  | ||||||
|         if(!parsed) break; |  | ||||||
| 
 |  | ||||||
|         size_t len = strlen(buf); |  | ||||||
|         if(!len) break; |  | ||||||
|         removed_length += len; |  | ||||||
|         str.remove_prefix(len); |  | ||||||
| 
 |  | ||||||
|         if(str.empty()) break; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return removed_length; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> |  | ||||||
|     IrdaAppFileParser::parse_signal_raw(const std::string& string) const { |  | ||||||
|     uint32_t frequency; |  | ||||||
|     uint32_t duty_cycle; |  | ||||||
|     std::string_view str(string.c_str()); |  | ||||||
|     auto irda_file_signal = std::make_unique<IrdaFileSignal>(); |  | ||||||
| 
 |  | ||||||
|     int parsed = std::sscanf( |  | ||||||
|         str.data(), "%31s RAW F:%ld DC:%ld", irda_file_signal->name, &frequency, &duty_cycle); |  | ||||||
| 
 |  | ||||||
|     if(parsed != 3) { |  | ||||||
|         return nullptr; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if((frequency < IRDA_MIN_FREQUENCY) || (frequency > IRDA_MAX_FREQUENCY)) { |  | ||||||
|         size_t end_of_str = MIN(string.find_last_not_of(" \t\r\n") + 1, (size_t)30); |  | ||||||
|         FURI_LOG_E( |  | ||||||
|             TAG, |  | ||||||
|             "RAW signal(\'%.*s...\'): frequency is out of bounds (%ld-%ld): %ld", |  | ||||||
|             end_of_str, |  | ||||||
|             string.c_str(), |  | ||||||
|             IRDA_MIN_FREQUENCY, |  | ||||||
|             IRDA_MAX_FREQUENCY, |  | ||||||
|             frequency); |  | ||||||
|         return nullptr; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if((duty_cycle == 0) || (duty_cycle > 100)) { |  | ||||||
|         size_t end_of_str = MIN(string.find_last_not_of(" \t\r\n") + 1, (size_t)30); |  | ||||||
|         FURI_LOG_E( |  | ||||||
|             TAG, |  | ||||||
|             "RAW signal(\'%.*s...\'): duty cycle is out of bounds (0-100): %ld", |  | ||||||
|             end_of_str, |  | ||||||
|             string.c_str(), |  | ||||||
|             duty_cycle); |  | ||||||
|         return nullptr; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     int header_len = remove_args32(str, 4); |  | ||||||
| 
 |  | ||||||
|     size_t last_valid_ch = str.find_last_not_of(" \t\r\n"); |  | ||||||
|     if(last_valid_ch != std::string_view::npos) { |  | ||||||
|         str.remove_suffix(str.size() - last_valid_ch - 1); |  | ||||||
|     } else { |  | ||||||
|         FURI_LOG_E(TAG, "RAW signal(\'%.*s\'): no timings", header_len, string.c_str()); |  | ||||||
|         return nullptr; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /* move allocated timings into raw signal object */ |  | ||||||
|     IrdaAppSignal::RawSignal raw_signal = { |  | ||||||
|         .timings_cnt = 0, .timings = new uint32_t[max_raw_timings_in_signal]}; |  | ||||||
|     bool result = false; |  | ||||||
| 
 |  | ||||||
|     while(!str.empty()) { |  | ||||||
|         char buf[10]; |  | ||||||
|         size_t index = str.find_first_not_of(" \t", 1); |  | ||||||
|         if(index == std::string_view::npos) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         str.remove_prefix(index); |  | ||||||
|         parsed = std::sscanf(str.data(), "%9s", buf); |  | ||||||
|         if(parsed != 1) { |  | ||||||
|             FURI_LOG_E( |  | ||||||
|                 TAG, |  | ||||||
|                 "RAW signal(\'%.*s...\'): failed on timing[%ld] \'%*s\'", |  | ||||||
|                 header_len, |  | ||||||
|                 string.c_str(), |  | ||||||
|                 raw_signal.timings_cnt, |  | ||||||
|                 str.size(), |  | ||||||
|                 str.data()); |  | ||||||
|             result = false; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         str.remove_prefix(strlen(buf)); |  | ||||||
| 
 |  | ||||||
|         int value = atoi(buf); |  | ||||||
|         if(value <= 0) { |  | ||||||
|             FURI_LOG_E( |  | ||||||
|                 TAG, |  | ||||||
|                 "RAW signal(\'%.*s...\'): failed on timing[%ld] \'%s\'", |  | ||||||
|                 header_len, |  | ||||||
|                 string.c_str(), |  | ||||||
|                 raw_signal.timings_cnt, |  | ||||||
|                 buf); |  | ||||||
|             result = false; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(raw_signal.timings_cnt >= max_raw_timings_in_signal) { |  | ||||||
|             FURI_LOG_E( |  | ||||||
|                 TAG, |  | ||||||
|                 "RAW signal(\'%.*s...\'): too much timings (max %ld)", |  | ||||||
|                 header_len, |  | ||||||
|                 string.c_str(), |  | ||||||
|                 max_raw_timings_in_signal); |  | ||||||
|             result = false; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         raw_signal.timings[raw_signal.timings_cnt] = value; |  | ||||||
|         ++raw_signal.timings_cnt; |  | ||||||
|         result = true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(result) { |  | ||||||
|         /* copy timings instead of moving them to occupy less than max_raw_timings_in_signal */ |  | ||||||
|         irda_file_signal->signal.copy_raw_signal(raw_signal.timings, raw_signal.timings_cnt); |  | ||||||
|     } else { |  | ||||||
|         irda_file_signal.reset(); |  | ||||||
|     } |  | ||||||
|     delete[] raw_signal.timings; |  | ||||||
|     return irda_file_signal; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool IrdaAppFileParser::is_irda_file_exist(const char* name, bool* exist) { |  | ||||||
|     std::string full_path = make_full_name(name); |  | ||||||
|     return file_worker.is_file_exist(full_path.c_str(), exist); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| std::string IrdaAppFileParser::make_full_name(const std::string& remote_name) const { |  | ||||||
|     return std::string("") + irda_directory + "/" + remote_name + irda_extension; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| std::string IrdaAppFileParser::make_name(const std::string& full_name) const { |  | ||||||
|     std::string str(full_name, full_name.find_last_of('/') + 1, full_name.size()); |  | ||||||
|     str.erase(str.find_last_of('.')); |  | ||||||
| 
 |  | ||||||
|     return str; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool IrdaAppFileParser::remove_irda_file(const char* name) { |  | ||||||
|     std::string full_filename = make_full_name(name); |  | ||||||
|     return file_worker.remove(full_filename.c_str()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool IrdaAppFileParser::rename_irda_file(const char* old_name, const char* new_name) { |  | ||||||
|     std::string old_filename = make_full_name(old_name); |  | ||||||
|     std::string new_filename = make_full_name(new_name); |  | ||||||
|     return file_worker.rename(old_filename.c_str(), new_filename.c_str()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool IrdaAppFileParser::close() { |  | ||||||
|     return file_worker.close(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool IrdaAppFileParser::check_errors() { |  | ||||||
|     return file_worker.check_errors(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| std::string IrdaAppFileParser::file_select(const char* selected) { |  | ||||||
|     auto filename_ts = std::make_unique<TextStore>(IrdaAppRemoteManager::max_remote_name_length); |  | ||||||
|     bool result; |  | ||||||
| 
 |  | ||||||
|     result = file_worker.file_select( |  | ||||||
|         irda_directory, irda_extension, filename_ts->text, filename_ts->text_size, selected); |  | ||||||
| 
 |  | ||||||
|     return result ? std::string(filename_ts->text) : std::string(); |  | ||||||
| } |  | ||||||
| @ -1,56 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include "irda_app_signal.h" |  | ||||||
| 
 |  | ||||||
| #include <irda.h> |  | ||||||
| #include <file_worker_cpp.h> |  | ||||||
| #include <memory> |  | ||||||
| #include <string> |  | ||||||
| #include <cstdint> |  | ||||||
| 
 |  | ||||||
| class IrdaAppFileParser { |  | ||||||
| public: |  | ||||||
|     typedef struct { |  | ||||||
|         char name[32]; |  | ||||||
|         IrdaAppSignal signal; |  | ||||||
|     } IrdaFileSignal; |  | ||||||
| 
 |  | ||||||
|     bool open_irda_file_read(const char* filename); |  | ||||||
|     bool open_irda_file_write(const char* filename); |  | ||||||
|     bool is_irda_file_exist(const char* filename, bool* exist); |  | ||||||
|     bool rename_irda_file(const char* filename, const char* newname); |  | ||||||
|     bool remove_irda_file(const char* name); |  | ||||||
|     bool close(); |  | ||||||
|     bool check_errors(); |  | ||||||
| 
 |  | ||||||
|     std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> read_signal(); |  | ||||||
|     bool save_signal(const IrdaAppSignal& signal, const char* name); |  | ||||||
|     std::string file_select(const char* selected); |  | ||||||
| 
 |  | ||||||
|     std::string make_name(const std::string& full_name) const; |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     size_t stringify_message( |  | ||||||
|         const IrdaAppSignal& signal, |  | ||||||
|         const char* name, |  | ||||||
|         char* content, |  | ||||||
|         size_t content_len); |  | ||||||
|     size_t stringify_raw_signal( |  | ||||||
|         const IrdaAppSignal& signal, |  | ||||||
|         const char* name, |  | ||||||
|         char* content, |  | ||||||
|         size_t content_len); |  | ||||||
|     std::unique_ptr<IrdaFileSignal> parse_signal(const std::string& str) const; |  | ||||||
|     std::unique_ptr<IrdaFileSignal> parse_signal_raw(const std::string& str) const; |  | ||||||
|     std::string make_full_name(const std::string& name) const; |  | ||||||
| 
 |  | ||||||
|     static inline const char* const irda_directory = "/any/irda"; |  | ||||||
|     static inline const char* const irda_extension = ".ir"; |  | ||||||
|     static inline const uint32_t max_raw_timings_in_signal = 512; |  | ||||||
|     static inline const uint32_t max_line_length = |  | ||||||
|         (9 + 1) * IrdaAppFileParser::max_raw_timings_in_signal + 100; |  | ||||||
| 
 |  | ||||||
|     FileWorkerCpp file_worker; |  | ||||||
|     char file_buf[128]; |  | ||||||
|     size_t file_buf_cnt = 0; |  | ||||||
| }; |  | ||||||
| @ -1,5 +1,8 @@ | |||||||
|  | #include <file_worker_cpp.h> | ||||||
|  | #include <flipper_file.h> | ||||||
| #include "irda_app_remote_manager.h" | #include "irda_app_remote_manager.h" | ||||||
| #include "irda_app_file_parser.h" | #include "irda/helpers/irda_parser.h" | ||||||
|  | #include "irda/irda_app_signal.h" | ||||||
| 
 | 
 | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
| @ -8,23 +11,32 @@ | |||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <gui/modules/button_menu.h> | #include <gui/modules/button_menu.h> | ||||||
| #include <storage/storage.h> | #include <storage/storage.h> | ||||||
|  | #include "irda_app.h" | ||||||
| 
 | 
 | ||||||
| static const std::string default_remote_name = "remote"; | static const std::string default_remote_name = "remote"; | ||||||
| 
 | 
 | ||||||
| std::string IrdaAppRemoteManager::find_vacant_remote_name(const std::string& name) { | std::string IrdaAppRemoteManager::make_full_name(const std::string& remote_name) const { | ||||||
|     IrdaAppFileParser file_parser; |     return std::string("") + IrdaApp::irda_directory + "/" + remote_name + IrdaApp::irda_extension; | ||||||
|     bool exist = true; | } | ||||||
| 
 | 
 | ||||||
|     if(!file_parser.is_irda_file_exist(name.c_str(), &exist)) { | std::string IrdaAppRemoteManager::find_vacant_remote_name(const std::string& name) { | ||||||
|  |     bool exist = true; | ||||||
|  |     FileWorkerCpp file_worker; | ||||||
|  | 
 | ||||||
|  |     if(!file_worker.is_file_exist(make_full_name(name).c_str(), &exist)) { | ||||||
|         return std::string(); |         return std::string(); | ||||||
|     } else if(!exist) { |     } else if(!exist) { | ||||||
|         return name; |         return name; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     uint32_t i = 1; |  | ||||||
|     /* if suggested name is occupied, try another one (name2, name3, etc) */ |     /* if suggested name is occupied, try another one (name2, name3, etc) */ | ||||||
|     while(file_parser.is_irda_file_exist((name + std::to_string(++i)).c_str(), &exist) && exist) |     uint32_t i = 1; | ||||||
|         ; |     bool file_worker_result = false; | ||||||
|  |     std::string new_name; | ||||||
|  |     do { | ||||||
|  |         new_name = make_full_name(name + std::to_string(++i)); | ||||||
|  |         file_worker_result = file_worker.is_file_exist(new_name.c_str(), &exist); | ||||||
|  |     } while(file_worker_result && exist); | ||||||
| 
 | 
 | ||||||
|     return !exist ? name + std::to_string(i) : std::string(); |     return !exist ? name + std::to_string(i) : std::string(); | ||||||
| } | } | ||||||
| @ -70,9 +82,9 @@ const IrdaAppSignal& IrdaAppRemoteManager::get_button_data(size_t index) const { | |||||||
| 
 | 
 | ||||||
| bool IrdaAppRemoteManager::delete_remote() { | bool IrdaAppRemoteManager::delete_remote() { | ||||||
|     bool result; |     bool result; | ||||||
|     IrdaAppFileParser file_parser; |     FileWorkerCpp file_worker; | ||||||
|  |     result = file_worker.remove(make_full_name(remote->name).c_str()); | ||||||
| 
 | 
 | ||||||
|     result = file_parser.remove_irda_file(remote->name.c_str()); |  | ||||||
|     reset_remote(); |     reset_remote(); | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| @ -125,8 +137,10 @@ bool IrdaAppRemoteManager::rename_remote(const char* str) { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     IrdaAppFileParser file_parser; |     FileWorkerCpp file_worker; | ||||||
|     bool result = file_parser.rename_irda_file(remote->name.c_str(), new_name.c_str()); |     std::string old_filename = make_full_name(remote->name); | ||||||
|  |     std::string new_filename = make_full_name(new_name); | ||||||
|  |     bool result = file_worker.rename(old_filename.c_str(), new_filename.c_str()); | ||||||
| 
 | 
 | ||||||
|     remote->name = new_name; |     remote->name = new_name; | ||||||
| 
 | 
 | ||||||
| @ -148,45 +162,62 @@ size_t IrdaAppRemoteManager::get_number_of_buttons() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool IrdaAppRemoteManager::store(void) { | bool IrdaAppRemoteManager::store(void) { | ||||||
|     IrdaAppFileParser file_parser; |     bool result = false; | ||||||
|     bool result = true; |     FileWorkerCpp file_worker; | ||||||
| 
 | 
 | ||||||
|     if(!file_parser.open_irda_file_write(remote->name.c_str())) { |     if(!file_worker.mkdir(IrdaApp::irda_directory)) return false; | ||||||
|         return false; | 
 | ||||||
|  |     Storage* storage = static_cast<Storage*>(furi_record_open("storage")); | ||||||
|  |     FlipperFile* ff = flipper_file_alloc(storage); | ||||||
|  | 
 | ||||||
|  |     FURI_LOG_I("RemoteManager", "store file: \'%s\'", make_full_name(remote->name).c_str()); | ||||||
|  |     result = flipper_file_open_always(ff, make_full_name(remote->name).c_str()); | ||||||
|  |     if(result) { | ||||||
|  |         result = flipper_file_write_header_cstr(ff, "IR signals file", 1); | ||||||
|     } |     } | ||||||
| 
 |     if(result) { | ||||||
|         for(const auto& button : remote->buttons) { |         for(const auto& button : remote->buttons) { | ||||||
|         bool result = file_parser.save_signal(button.signal, button.name.c_str()); |             result = irda_parser_save_signal(ff, button.signal, button.name.c_str()); | ||||||
|             if(!result) { |             if(!result) { | ||||||
|             result = false; |  | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     file_parser.close(); |     flipper_file_close(ff); | ||||||
| 
 |     flipper_file_free(ff); | ||||||
|  |     furi_record_close("storage"); | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool IrdaAppRemoteManager::load(const std::string& name) { | bool IrdaAppRemoteManager::load(const std::string& remote_name) { | ||||||
|     bool fs_res = false; |     bool result = false; | ||||||
|     IrdaAppFileParser file_parser; |     Storage* storage = static_cast<Storage*>(furi_record_open("storage")); | ||||||
|  |     FlipperFile* ff = flipper_file_alloc(storage); | ||||||
| 
 | 
 | ||||||
|     fs_res = file_parser.open_irda_file_read(name.c_str()); |     FURI_LOG_I("RemoteManager", "load file: \'%s\'", make_full_name(remote_name).c_str()); | ||||||
|     if(!fs_res) { |     result = flipper_file_open_existing(ff, make_full_name(remote_name).c_str()); | ||||||
|         return false; |     if(result) { | ||||||
|  |         string_t header; | ||||||
|  |         string_init(header); | ||||||
|  |         uint32_t version; | ||||||
|  |         result = flipper_file_read_header(ff, header, &version); | ||||||
|  |         if(result) { | ||||||
|  |             result = !string_cmp_str(header, "IR signals file") && (version == 1); | ||||||
|  |         } | ||||||
|  |         string_clear(header); | ||||||
|  |     } | ||||||
|  |     if(result) { | ||||||
|  |         remote = std::make_unique<IrdaAppRemote>(remote_name); | ||||||
|  |         IrdaAppSignal signal; | ||||||
|  |         std::string signal_name; | ||||||
|  |         while(irda_parser_read_signal(ff, signal, signal_name)) { | ||||||
|  |             remote->buttons.emplace_back(signal_name.c_str(), std::move(signal)); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     remote = std::make_unique<IrdaAppRemote>(name); |     flipper_file_close(ff); | ||||||
| 
 |     flipper_file_free(ff); | ||||||
|     while(1) { |     furi_record_close("storage"); | ||||||
|         auto file_signal = file_parser.read_signal(); |     return result; | ||||||
|         if(!file_signal) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         remote->buttons.emplace_back(file_signal->name, file_signal->signal); |  | ||||||
|     } |  | ||||||
|     file_parser.close(); |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -20,6 +20,11 @@ public: | |||||||
|         : name(name) |         : name(name) | ||||||
|         , signal(signal) { |         , signal(signal) { | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     IrdaAppRemoteButton(const char* name, IrdaAppSignal&& signal) | ||||||
|  |         : name(name) | ||||||
|  |         , signal(std::move(signal)) { | ||||||
|  |     } | ||||||
|     ~IrdaAppRemoteButton() { |     ~IrdaAppRemoteButton() { | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| @ -47,8 +52,8 @@ class IrdaAppRemoteManager { | |||||||
|     std::string make_remote_name(const std::string& full_name) const; |     std::string make_remote_name(const std::string& full_name) const; | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|     static inline const uint32_t max_button_name_length = 22; |     static constexpr const uint32_t max_button_name_length = 22; | ||||||
|     static inline const uint32_t max_remote_name_length = 22; |     static constexpr const uint32_t max_remote_name_length = 22; | ||||||
|     bool add_remote_with_button(const char* button_name, const IrdaAppSignal& signal); |     bool add_remote_with_button(const char* button_name, const IrdaAppSignal& signal); | ||||||
|     bool add_button(const char* button_name, const IrdaAppSignal& signal); |     bool add_button(const char* button_name, const IrdaAppSignal& signal); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,10 +1,16 @@ | |||||||
| #include "irda_app_signal.h" | #include "irda_app_signal.h" | ||||||
| #include <irda_transmit.h> | #include <irda_transmit.h> | ||||||
| 
 | 
 | ||||||
| void IrdaAppSignal::copy_timings(const uint32_t* timings, size_t size) { | void IrdaAppSignal::copy_raw_signal( | ||||||
|  |     const uint32_t* timings, | ||||||
|  |     size_t size, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     float duty_cycle) { | ||||||
|     furi_assert(size); |     furi_assert(size); | ||||||
|     furi_assert(timings); |     furi_assert(timings); | ||||||
| 
 | 
 | ||||||
|  |     payload.raw.frequency = frequency; | ||||||
|  |     payload.raw.duty_cycle = duty_cycle; | ||||||
|     payload.raw.timings_cnt = size; |     payload.raw.timings_cnt = size; | ||||||
|     if(size) { |     if(size) { | ||||||
|         payload.raw.timings = new uint32_t[size]; |         payload.raw.timings = new uint32_t[size]; | ||||||
| @ -13,83 +19,100 @@ void IrdaAppSignal::copy_timings(const uint32_t* timings, size_t size) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IrdaAppSignal::clear_timings() { | void IrdaAppSignal::clear_timings() { | ||||||
|     if(!decoded) { |     if(raw_signal) { | ||||||
|         delete[] payload.raw.timings; |         delete[] payload.raw.timings; | ||||||
|         payload.raw.timings_cnt = 0; |         payload.raw.timings_cnt = 0; | ||||||
|         payload.raw.timings = nullptr; |         payload.raw.timings = nullptr; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| IrdaAppSignal::IrdaAppSignal(const uint32_t* timings, size_t timings_cnt) { | IrdaAppSignal::IrdaAppSignal( | ||||||
|     decoded = false; |     const uint32_t* timings, | ||||||
|     copy_timings(timings, timings_cnt); |     size_t timings_cnt, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     float duty_cycle) { | ||||||
|  |     raw_signal = true; | ||||||
|  |     copy_raw_signal(timings, timings_cnt, frequency, duty_cycle); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| IrdaAppSignal::IrdaAppSignal(const IrdaMessage* irda_message) { | IrdaAppSignal::IrdaAppSignal(const IrdaMessage* irda_message) { | ||||||
|     decoded = true; |     raw_signal = false; | ||||||
|     payload.message = *irda_message; |     payload.message = *irda_message; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| IrdaAppSignal& IrdaAppSignal::operator=(const IrdaAppSignal& other) { | IrdaAppSignal& IrdaAppSignal::operator=(const IrdaAppSignal& other) { | ||||||
|     clear_timings(); |     clear_timings(); | ||||||
|     decoded = other.decoded; |     raw_signal = other.raw_signal; | ||||||
|     if(decoded) { |     if(!raw_signal) { | ||||||
|         payload.message = other.payload.message; |         payload.message = other.payload.message; | ||||||
|     } else { |     } else { | ||||||
|         copy_timings(other.payload.raw.timings, other.payload.raw.timings_cnt); |         copy_raw_signal( | ||||||
|  |             other.payload.raw.timings, | ||||||
|  |             other.payload.raw.timings_cnt, | ||||||
|  |             other.payload.raw.frequency, | ||||||
|  |             other.payload.raw.duty_cycle); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return *this; |     return *this; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| IrdaAppSignal::IrdaAppSignal(const IrdaAppSignal& other) { | IrdaAppSignal::IrdaAppSignal(const IrdaAppSignal& other) { | ||||||
|     decoded = other.decoded; |     raw_signal = other.raw_signal; | ||||||
|     if(decoded) { |     if(!raw_signal) { | ||||||
|         payload.message = other.payload.message; |         payload.message = other.payload.message; | ||||||
|     } else { |     } else { | ||||||
|         copy_timings(other.payload.raw.timings, other.payload.raw.timings_cnt); |         copy_raw_signal( | ||||||
|  |             other.payload.raw.timings, | ||||||
|  |             other.payload.raw.timings_cnt, | ||||||
|  |             other.payload.raw.frequency, | ||||||
|  |             other.payload.raw.duty_cycle); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| IrdaAppSignal::IrdaAppSignal(IrdaAppSignal&& other) { | IrdaAppSignal::IrdaAppSignal(IrdaAppSignal&& other) { | ||||||
|     clear_timings(); |     clear_timings(); | ||||||
| 
 | 
 | ||||||
|     decoded = other.decoded; |     raw_signal = other.raw_signal; | ||||||
|     if(decoded) { |     if(!raw_signal) { | ||||||
|         payload.message = other.payload.message; |         payload.message = other.payload.message; | ||||||
|     } else { |     } else { | ||||||
|         furi_assert(other.payload.raw.timings_cnt > 0); |         furi_assert(other.payload.raw.timings_cnt > 0); | ||||||
| 
 | 
 | ||||||
|         payload.raw.timings = other.payload.raw.timings; |         payload.raw.timings = other.payload.raw.timings; | ||||||
|         payload.raw.timings_cnt = other.payload.raw.timings_cnt; |         payload.raw.timings_cnt = other.payload.raw.timings_cnt; | ||||||
|  |         payload.raw.frequency = other.payload.raw.frequency; | ||||||
|  |         payload.raw.duty_cycle = other.payload.raw.duty_cycle; | ||||||
|         other.payload.raw.timings = nullptr; |         other.payload.raw.timings = nullptr; | ||||||
|         other.payload.raw.timings_cnt = 0; |         other.payload.raw.timings_cnt = 0; | ||||||
|  |         other.raw_signal = false; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IrdaAppSignal::set_message(const IrdaMessage* irda_message) { | void IrdaAppSignal::set_message(const IrdaMessage* irda_message) { | ||||||
|     clear_timings(); |     clear_timings(); | ||||||
|     decoded = true; |     raw_signal = false; | ||||||
|     payload.message = *irda_message; |     payload.message = *irda_message; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IrdaAppSignal::set_raw_signal(uint32_t* timings, size_t timings_cnt) { | void IrdaAppSignal::set_raw_signal( | ||||||
|  |     uint32_t* timings, | ||||||
|  |     size_t timings_cnt, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     float duty_cycle) { | ||||||
|     clear_timings(); |     clear_timings(); | ||||||
|     decoded = false; |     raw_signal = true; | ||||||
|     payload.raw.timings = timings; |     copy_raw_signal(timings, timings_cnt, frequency, duty_cycle); | ||||||
|     payload.raw.timings_cnt = timings_cnt; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void IrdaAppSignal::copy_raw_signal(uint32_t* timings, size_t timings_cnt) { |  | ||||||
|     clear_timings(); |  | ||||||
|     decoded = false; |  | ||||||
|     copy_timings(timings, timings_cnt); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IrdaAppSignal::transmit() const { | void IrdaAppSignal::transmit() const { | ||||||
|     if(decoded) { |     if(!raw_signal) { | ||||||
|         irda_send(&payload.message, 1); |         irda_send(&payload.message, 1); | ||||||
|     } else { |     } else { | ||||||
|         irda_send_raw(payload.raw.timings, payload.raw.timings_cnt, true); |         irda_send_raw_ext( | ||||||
|  |             payload.raw.timings, | ||||||
|  |             payload.raw.timings_cnt, | ||||||
|  |             true, | ||||||
|  |             payload.raw.frequency, | ||||||
|  |             payload.raw.duty_cycle); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -9,21 +9,24 @@ public: | |||||||
|     typedef struct { |     typedef struct { | ||||||
|         size_t timings_cnt; |         size_t timings_cnt; | ||||||
|         uint32_t* timings; |         uint32_t* timings; | ||||||
|  |         uint32_t frequency; | ||||||
|  |         float duty_cycle; | ||||||
|     } RawSignal; |     } RawSignal; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     bool decoded; |     bool raw_signal; | ||||||
|     union { |     union { | ||||||
|         IrdaMessage message; |         IrdaMessage message; | ||||||
|         RawSignal raw; |         RawSignal raw; | ||||||
|     } payload; |     } payload; | ||||||
| 
 | 
 | ||||||
|     void copy_timings(const uint32_t* timings, size_t size); |     void | ||||||
|  |         copy_raw_signal(const uint32_t* timings, size_t size, uint32_t frequency, float duty_cycle); | ||||||
|     void clear_timings(); |     void clear_timings(); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|     IrdaAppSignal() { |     IrdaAppSignal() { | ||||||
|         decoded = true; |         raw_signal = false; | ||||||
|         payload.message.protocol = IrdaProtocolUnknown; |         payload.message.protocol = IrdaProtocolUnknown; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -31,7 +34,11 @@ public: | |||||||
|         clear_timings(); |         clear_timings(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     IrdaAppSignal(const uint32_t* timings, size_t timings_cnt); |     IrdaAppSignal( | ||||||
|  |         const uint32_t* timings, | ||||||
|  |         size_t timings_cnt, | ||||||
|  |         uint32_t frequency, | ||||||
|  |         float duty_cycle); | ||||||
|     IrdaAppSignal(const IrdaMessage* irda_message); |     IrdaAppSignal(const IrdaMessage* irda_message); | ||||||
| 
 | 
 | ||||||
|     IrdaAppSignal(const IrdaAppSignal& other); |     IrdaAppSignal(const IrdaAppSignal& other); | ||||||
| @ -40,22 +47,22 @@ public: | |||||||
|     IrdaAppSignal& operator=(const IrdaAppSignal& signal); |     IrdaAppSignal& operator=(const IrdaAppSignal& signal); | ||||||
| 
 | 
 | ||||||
|     void set_message(const IrdaMessage* irda_message); |     void set_message(const IrdaMessage* irda_message); | ||||||
|     void set_raw_signal(uint32_t* timings, size_t timings_cnt); |     void | ||||||
|     void copy_raw_signal(uint32_t* timings, size_t timings_cnt); |         set_raw_signal(uint32_t* timings, size_t timings_cnt, uint32_t frequency, float duty_cycle); | ||||||
| 
 | 
 | ||||||
|     void transmit() const; |     void transmit() const; | ||||||
| 
 | 
 | ||||||
|     bool is_raw(void) const { |     bool is_raw(void) const { | ||||||
|         return !decoded; |         return raw_signal; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const IrdaMessage& get_message(void) const { |     const IrdaMessage& get_message(void) const { | ||||||
|         furi_assert(decoded); |         furi_assert(!raw_signal); | ||||||
|         return payload.message; |         return payload.message; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const RawSignal& get_raw_signal(void) const { |     const RawSignal& get_raw_signal(void) const { | ||||||
|         furi_assert(!decoded); |         furi_assert(raw_signal); | ||||||
|         return payload.raw; |         return payload.raw; | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| #include "../irda_app.h" | #include "../irda_app.h" | ||||||
| #include "../irda_app_event.h" | #include "../irda_app_event.h" | ||||||
|  | #include "irda.h" | ||||||
| #include <irda_worker.h> | #include <irda_worker.h> | ||||||
| 
 | 
 | ||||||
| static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) { | static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) { | ||||||
| @ -15,7 +16,8 @@ static void signal_received_callback(void* context, IrdaWorkerSignal* received_s | |||||||
|         const uint32_t* timings; |         const uint32_t* timings; | ||||||
|         size_t timings_cnt; |         size_t timings_cnt; | ||||||
|         irda_worker_get_raw_signal(received_signal, &timings, &timings_cnt); |         irda_worker_get_raw_signal(received_signal, &timings, &timings_cnt); | ||||||
|         IrdaAppSignal signal(timings, timings_cnt); |         IrdaAppSignal signal( | ||||||
|  |             timings, timings_cnt, IRDA_COMMON_CARRIER_FREQUENCY, IRDA_COMMON_DUTY_CYCLE); | ||||||
|         app->set_received_signal(signal); |         app->set_received_signal(signal); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| #include "../irda_app.h" | #include "../irda_app.h" | ||||||
|  | #include <file_worker_cpp.h> | ||||||
| #include "irda.h" | #include "irda.h" | ||||||
| #include "../irda_app_file_parser.h" |  | ||||||
| #include <memory> | #include <memory> | ||||||
| 
 | 
 | ||||||
| static void dialog_result_callback(DialogExResult result, void* context) { | static void dialog_result_callback(DialogExResult result, void* context) { | ||||||
| @ -76,8 +76,8 @@ bool IrdaAppSceneLearnSuccess::on_event(IrdaApp* app, IrdaAppEvent* event) { | |||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         case DialogExResultRight: { |         case DialogExResultRight: { | ||||||
|             IrdaAppFileParser file_parser; |             FileWorkerCpp file_worker; | ||||||
|             if(file_parser.check_errors()) { |             if(file_worker.check_errors()) { | ||||||
|                 app->switch_to_next_scene(IrdaApp::Scene::LearnEnterName); |                 app->switch_to_next_scene(IrdaApp::Scene::LearnEnterName); | ||||||
|             } else { |             } else { | ||||||
|                 app->switch_to_previous_scene(); |                 app->switch_to_previous_scene(); | ||||||
|  | |||||||
| @ -1,21 +1,35 @@ | |||||||
| #include "../irda_app.h" | #include "../irda_app.h" | ||||||
| #include "irda/irda_app_event.h" | #include "irda/irda_app_event.h" | ||||||
|  | #include <text_store.h> | ||||||
|  | #include <file_worker_cpp.h> | ||||||
| 
 | 
 | ||||||
| void IrdaAppSceneRemoteList::on_enter(IrdaApp* app) { | void IrdaAppSceneRemoteList::on_enter(IrdaApp* app) { | ||||||
|     IrdaAppFileParser file_parser; |     furi_assert(app); | ||||||
|     bool success = false; | 
 | ||||||
|  |     FileWorkerCpp file_worker; | ||||||
|  |     bool result = false; | ||||||
|  |     bool file_select_result; | ||||||
|     auto remote_manager = app->get_remote_manager(); |     auto remote_manager = app->get_remote_manager(); | ||||||
|     auto last_selected_remote = remote_manager->get_remote_name(); |     auto last_selected_remote = remote_manager->get_remote_name(); | ||||||
|     auto selected_file = file_parser.file_select( |     const char* last_selected_remote_name = | ||||||
|         last_selected_remote.size() ? last_selected_remote.c_str() : nullptr); |         last_selected_remote.size() ? last_selected_remote.c_str() : nullptr; | ||||||
|     if(!selected_file.empty()) { |     auto filename_ts = std::make_unique<TextStore>(IrdaAppRemoteManager::max_remote_name_length); | ||||||
|         if(remote_manager->load(selected_file)) { | 
 | ||||||
|  |     file_select_result = file_worker.file_select( | ||||||
|  |         IrdaApp::irda_directory, | ||||||
|  |         IrdaApp::irda_extension, | ||||||
|  |         filename_ts->text, | ||||||
|  |         filename_ts->text_size, | ||||||
|  |         last_selected_remote_name); | ||||||
|  | 
 | ||||||
|  |     if(file_select_result) { | ||||||
|  |         if(remote_manager->load(std::string(filename_ts->text))) { | ||||||
|             app->switch_to_next_scene(IrdaApp::Scene::Remote); |             app->switch_to_next_scene(IrdaApp::Scene::Remote); | ||||||
|             success = true; |             result = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(!success) { |     if(!result) { | ||||||
|         app->switch_to_previous_scene(); |         app->switch_to_previous_scene(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -21,9 +21,6 @@ void IrdaAppSceneUniversal::on_enter(IrdaApp* app) { | |||||||
|     Submenu* submenu = view_manager->get_submenu(); |     Submenu* submenu = view_manager->get_submenu(); | ||||||
| 
 | 
 | ||||||
|     submenu_add_item(submenu, "TV's", SubmenuIndexUniversalTV, submenu_callback, app); |     submenu_add_item(submenu, "TV's", SubmenuIndexUniversalTV, submenu_callback, app); | ||||||
|     submenu_add_item(submenu, "Audio Players", SubmenuIndexUniversalAudio, submenu_callback, app); |  | ||||||
|     submenu_add_item( |  | ||||||
|         submenu, "Air Conditioners", SubmenuIndexUniversalAirConditioner, submenu_callback, app); |  | ||||||
|     submenu_set_selected_item(submenu, submenu_item_selected); |     submenu_set_selected_item(submenu, submenu_item_selected); | ||||||
|     submenu_item_selected = 0; |     submenu_item_selected = 0; | ||||||
| 
 | 
 | ||||||
|  | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -435,5 +435,6 @@ bool file_worker_is_file_exist(FileWorker* file_worker, const char* filename, bo | |||||||
|     storage_file_close(file); |     storage_file_close(file); | ||||||
|     storage_file_free(file); |     storage_file_free(file); | ||||||
| 
 | 
 | ||||||
|     return file_worker_check_common_errors(file_worker); |     bool result = file_worker_check_common_errors(file_worker); | ||||||
|  |     return result; | ||||||
| } | } | ||||||
|  | |||||||
| @ -159,7 +159,7 @@ bool flipper_file_get_value_count(FlipperFile* flipper_file, const char* key, ui | |||||||
|             if(last) break; |             if(last) break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     } while(true); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     if(!storage_file_seek(flipper_file->file, position, true)) { |     if(!storage_file_seek(flipper_file->file, position, true)) { | ||||||
|         result = false; |         result = false; | ||||||
|  | |||||||
| @ -7,8 +7,8 @@ | |||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #define IRDA_COMMON_CARRIER_FREQUENCY 38000 | #define IRDA_COMMON_CARRIER_FREQUENCY ((uint32_t)38000) | ||||||
| #define IRDA_COMMON_DUTY_CYCLE 0.33 | #define IRDA_COMMON_DUTY_CYCLE ((float)0.33) | ||||||
| 
 | 
 | ||||||
| /* if we want to see splitted raw signals during brutforce,
 | /* if we want to see splitted raw signals during brutforce,
 | ||||||
|  * we have to have RX raw timing delay less than TX */ |  * we have to have RX raw timing delay less than TX */ | ||||||
|  | |||||||
| @ -326,7 +326,6 @@ void irda_worker_tx_start(IrdaWorker* instance) { | |||||||
| 
 | 
 | ||||||
|     osEventFlagsClear(instance->events, IRDA_WORKER_ALL_EVENTS); |     osEventFlagsClear(instance->events, IRDA_WORKER_ALL_EVENTS); | ||||||
|     furi_thread_set_callback(instance->thread, irda_worker_tx_thread); |     furi_thread_set_callback(instance->thread, irda_worker_tx_thread); | ||||||
|     furi_thread_start(instance->thread); |  | ||||||
| 
 | 
 | ||||||
|     instance->tx.steady_signal_sent = false; |     instance->tx.steady_signal_sent = false; | ||||||
|     instance->tx.need_reinitialization = false; |     instance->tx.need_reinitialization = false; | ||||||
| @ -335,6 +334,7 @@ void irda_worker_tx_start(IrdaWorker* instance) { | |||||||
|         irda_worker_furi_hal_message_sent_isr_callback, instance); |         irda_worker_furi_hal_message_sent_isr_callback, instance); | ||||||
| 
 | 
 | ||||||
|     instance->state = IrdaWorkerStateStartTx; |     instance->state = IrdaWorkerStateStartTx; | ||||||
|  |     furi_thread_start(instance->thread); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void irda_worker_furi_hal_message_sent_isr_callback(void* context) { | static void irda_worker_furi_hal_message_sent_isr_callback(void* context) { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Albert Kharisov
						Albert Kharisov