diff options
author | Albert Kharisov <ah@bright-box.com> | 2021-07-16 19:43:54 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-16 19:43:54 +0300 |
commit | 13c5a8cb200df8e771d9f3fd2f5eb133d569017b (patch) | |
tree | 427f585f55dda4ecaa4c89df279fce204fb005b6 /applications/irda | |
parent | a2dfa33a9f6dbc3503978e701fa458ebcd3983f2 (diff) |
[FL-1505] Add RAW format (#576)
* Add RAW format
* F5 stubs for build to pass
* Fix saving decoded signal error
* Irda: set ISR before starting timer, remove explicit NVIC configuration
Co-authored-by: あく <alleteam@gmail.com>
Diffstat (limited to 'applications/irda')
20 files changed, 598 insertions, 681 deletions
diff --git a/applications/irda/cli/irda-cli.cpp b/applications/irda/cli/irda-cli.cpp index 6a95e1d6..fb5be8fd 100644 --- a/applications/irda/cli/irda-cli.cpp +++ b/applications/irda/cli/irda-cli.cpp @@ -1,24 +1,48 @@ -#include "app-template.h" -#include "cli/cli.h" -#include "cmsis_os2.h" +#include <api-hal-delay.h> +#include <irda.h> +#include <app-template.h> +#include <cli/cli.h> +#include <cmsis_os2.h> +#include <irda_worker.h> #include <furi.h> #include <api-hal-irda.h> -#include "irda.h" #include <sstream> #include <string> #include <m-string.h> +#include <irda_transmit.h> -typedef struct IrdaCli { - IrdaDecoderHandler* handler; - osMessageQueueId_t message_queue; -} IrdaCli; - -static void irda_rx_callback(void* ctx, bool level, uint32_t duration) { - IrdaCli* irda_cli = (IrdaCli*)ctx; - const IrdaMessage* message; - message = irda_decode(irda_cli->handler, level, duration); - if(message) { - osMessageQueuePut(irda_cli->message_queue, message, 0, 0); +static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) { + furi_assert(received_signal); + char buf[100]; + size_t buf_cnt; + Cli* cli = (Cli*)context; + + if(irda_worker_signal_is_decoded(received_signal)) { + const IrdaMessage* message = irda_worker_get_decoded_message(received_signal); + buf_cnt = sniprintf( + buf, + sizeof(buf), + "%s, A:0x%0*lX, C:0x%0*lX%s\r\n", + irda_get_protocol_name(message->protocol), + irda_get_protocol_address_length(message->protocol), + message->address, + irda_get_protocol_command_length(message->protocol), + message->command, + message->repeat ? " R" : ""); + cli_write(cli, (uint8_t*)buf, buf_cnt); + } else { + const uint32_t* timings; + size_t timings_cnt; + irda_worker_get_raw_signal(received_signal, &timings, &timings_cnt); + + buf_cnt = sniprintf(buf, sizeof(buf), "RAW, %d samples:\r\n", timings_cnt); + cli_write(cli, (uint8_t*)buf, buf_cnt); + for(size_t i = 0; i < timings_cnt; ++i) { + buf_cnt = sniprintf(buf, sizeof(buf), "%lu ", timings[i]); + cli_write(cli, (uint8_t*)buf, buf_cnt); + } + buf_cnt = sniprintf(buf, sizeof(buf), "\r\n"); + cli_write(cli, (uint8_t*)buf, buf_cnt); } } @@ -27,30 +51,19 @@ static void irda_cli_start_ir_rx(Cli* cli, string_t args, void* context) { printf("IRDA is busy. Exit."); return; } - IrdaCli irda_cli; - irda_cli.handler = irda_alloc_decoder(); - irda_cli.message_queue = osMessageQueueNew(2, sizeof(IrdaMessage), NULL); - api_hal_irda_rx_irq_init(); - api_hal_irda_rx_irq_set_callback(irda_rx_callback, &irda_cli); + + IrdaWorker* worker = irda_worker_alloc(); + irda_worker_set_context(worker, cli); + irda_worker_start(worker); + irda_worker_set_received_signal_callback(worker, signal_received_callback); printf("Receiving IRDA...\r\nPress Ctrl+C to abort\r\n"); while(!cli_cmd_interrupt_received(cli)) { - IrdaMessage message; - if(osOK == osMessageQueueGet(irda_cli.message_queue, &message, NULL, 50)) { - printf( - "%s, A:0x%0*lX, C:0x%0*lX%s\r\n", - irda_get_protocol_name(message.protocol), - irda_get_protocol_address_length(message.protocol), - message.address, - irda_get_protocol_command_length(message.protocol), - message.command, - message.repeat ? " R" : ""); - } + delay(50); } - api_hal_irda_rx_irq_deinit(); - irda_free_decoder(irda_cli.handler); - osMessageQueueDelete(irda_cli.message_queue); + irda_worker_stop(worker); + irda_worker_free(worker); } static void irda_cli_print_usage(void) { @@ -63,38 +76,93 @@ static void irda_cli_print_usage(void) { printf("\r\n"); } -static void irda_cli_start_ir_tx(Cli* cli, string_t args, void* context) { - if(api_hal_irda_rx_irq_is_busy()) { - printf("IRDA is busy. Exit."); - return; - } - +static bool parse_message(const char* str, IrdaMessage* message) { uint32_t command = 0; uint32_t address = 0; char protocol_name[32]; - int parsed = sscanf(string_get_cstr(args), "%31s %lX %lX", protocol_name, &address, &command); + int parsed = sscanf(str, "%31s %lX %lX", protocol_name, &address, &command); if(parsed != 3) { - printf("Wrong arguments.\r\n"); - irda_cli_print_usage(); - return; + return false; } IrdaProtocol protocol = irda_get_protocol_by_name(protocol_name); if(!irda_is_protocol_valid(protocol)) { - printf("Unknown protocol.\r\n"); - irda_cli_print_usage(); + return false; + } + + message->protocol = protocol; + message->address = address; + message->command = command; + message->repeat = false; + + return true; +} + +static bool parse_signal_raw( + const char* str, + uint32_t* timings, + uint32_t* timings_cnt, + float* duty_cycle, + float* frequency) { + char frequency_str[10]; + char duty_cycle_str[10]; + int parsed = sscanf(str, "RAW F:%9s DC:%9s", frequency_str, duty_cycle_str); + if(parsed != 2) return false; + + *frequency = atoi(frequency_str); + *duty_cycle = (float)atoi(duty_cycle_str) / 100; + str += strlen(frequency_str) + strlen(duty_cycle_str) + 10; + + uint32_t timings_cnt_max = *timings_cnt; + *timings_cnt = 0; + + while(1) { + char timing_str[10]; + for(; *str == ' '; ++str) + ; + if(1 != sscanf(str, "%9s", timing_str)) break; + str += strlen(timing_str); + uint32_t timing = atoi(timing_str); + if(timing <= 0) break; + if(*timings_cnt >= timings_cnt_max) break; + timings[*timings_cnt] = timing; + ++*timings_cnt; + } + + printf("\r\nTransmit:"); + for(size_t i = 0; i < *timings_cnt; ++i) { + printf(" %ld", timings[i]); + } + printf("\r\n"); + + return true; +} + +static void irda_cli_start_ir_tx(Cli* cli, string_t args, void* context) { + if(api_hal_irda_rx_irq_is_busy()) { + printf("IRDA is busy. Exit."); return; } - IrdaMessage message = { - .protocol = protocol, - .address = address, - .command = command, - .repeat = false, - }; - irda_send(&message, 1); + IrdaMessage message; + const char* str = string_get_cstr(args); + float frequency; + float duty_cycle; + uint32_t* timings = (uint32_t*)furi_alloc(sizeof(uint32_t) * 1000); + uint32_t timings_cnt = 1000; + + if(parse_message(str, &message)) { + irda_send(&message, 1); + } else if(parse_signal_raw(str, timings, &timings_cnt, &duty_cycle, &frequency)) { + irda_send_raw_ext(timings, timings_cnt, true, duty_cycle, frequency); + } else { + printf("Wrong arguments.\r\n"); + irda_cli_print_usage(); + } + + free(timings); } extern "C" void irda_cli_init() { diff --git a/applications/irda/irda-app-brute-force.cpp b/applications/irda/irda-app-brute-force.cpp index 4866a524..21491e76 100644 --- a/applications/irda/irda-app-brute-force.cpp +++ b/applications/irda/irda-app-brute-force.cpp @@ -16,7 +16,7 @@ bool IrdaAppBruteForce::calculate_messages() { file_parser.reset(); while(1) { - auto message = file_parser.read_message(&file); + auto message = file_parser.read_signal(&file); if(!message) break; auto element = records.find(message->name); if(element != records.cend()) { @@ -37,19 +37,19 @@ void IrdaAppBruteForce::stop_bruteforce() { } // TODO: [FL-1418] replace with timer-chained consequence of messages. -bool IrdaAppBruteForce::send_next_bruteforce(const IrdaAppSignalTransceiver& transceiver) { +bool IrdaAppBruteForce::send_next_bruteforce(void) { furi_assert(current_record.size()); - std::unique_ptr<IrdaAppFileParser::IrdaFileMessage> message; + std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> file_signal; do { - message = file_parser.read_message(&file); - } while(message && current_record.compare(message->name)); + file_signal = file_parser.read_signal(&file); + } while(file_signal && current_record.compare(file_signal->name)); - if(message) { - transceiver.send_message(&message->message); + if(file_signal) { + file_signal->signal.transmit(); } - return !!message; + return !!file_signal; } bool IrdaAppBruteForce::start_bruteforce(int index, int& record_amount) { diff --git a/applications/irda/irda-app-brute-force.hpp b/applications/irda/irda-app-brute-force.hpp index 09a5002e..62b8f34e 100644 --- a/applications/irda/irda-app-brute-force.hpp +++ b/applications/irda/irda-app-brute-force.hpp @@ -2,7 +2,6 @@ #include "furi/check.h" #include <unordered_map> #include "irda-app-file-parser.hpp" -#include "irda-app-transceiver.hpp" class IrdaAppBruteForce { @@ -26,7 +25,7 @@ class IrdaAppBruteForce { public: bool calculate_messages(); void stop_bruteforce(); - bool send_next_bruteforce(const IrdaAppSignalTransceiver& receiver); + bool send_next_bruteforce(); bool start_bruteforce(int index, int& record_amount); void add_record(int index, const char* name); diff --git a/applications/irda/irda-app-file-parser.cpp b/applications/irda/irda-app-file-parser.cpp index 07c104b8..e0e274e5 100644 --- a/applications/irda/irda-app-file-parser.cpp +++ b/applications/irda/irda-app-file-parser.cpp @@ -1,26 +1,83 @@ #include "irda-app-file-parser.hpp" +#include "irda-app-remote-manager.hpp" +#include "irda-app-signal.h" +#include <irda.h> +#include <cstdio> +#include <stdint.h> +#include <string_view> +#include <furi.h> -std::unique_ptr<IrdaAppFileParser::IrdaFileMessage> IrdaAppFileParser::read_message(File* file) { +uint32_t const IrdaAppFileParser::max_line_length = ((9 + 1) * 512 + 100); + +std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> IrdaAppFileParser::read_signal(File* file) { while(1) { auto str = getline(file); if(str.empty()) return nullptr; - auto message = parse_message(str); + auto message = parse_signal(str); + if(!message.get()) { + message = parse_signal_raw(str); + } if(message) return message; } } -std::unique_ptr<IrdaAppFileParser::IrdaFileMessage> - IrdaAppFileParser::parse_message(const std::string& str) const { +bool IrdaAppFileParser::store_signal(File* file, const IrdaAppSignal& signal, const char* name) { + char* content = new char[max_line_length]; + size_t written = 0; + + if(!signal.is_raw()) { + auto message = signal.get_message(); + auto protocol = message.protocol; + + sniprintf( + content, + max_line_length, + "%.31s %.31s A:%0*lX C:%0*lX\n", + name, + irda_get_protocol_name(protocol), + irda_get_protocol_address_length(protocol), + message.address, + irda_get_protocol_command_length(protocol), + message.command); + written = strlen(content); + } else { + int duty_cycle = 100 * IRDA_COMMON_DUTY_CYCLE; + written += sniprintf( + &content[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( + &content[written], max_line_length - written, " %ld", raw_signal.timings[i]); + furi_assert(written <= max_line_length); + } + written += snprintf(&content[written], max_line_length - written, "\n"); + } + furi_assert(written < max_line_length); + + size_t write_count = 0; + write_count = get_fs_api().file.write(file, content, written); + delete[] content; + return (file->error_id == FSE_OK) && (write_count == written); +} + +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_message = std::make_unique<IrdaFileMessage>(); + auto irda_file_signal = std::make_unique<IrdaFileSignal>(); int parsed = std::sscanf( str.c_str(), "%31s %31s A:%lX C:%lX", - irda_file_message->name, + irda_file_signal->name, protocol_name, &address, &command); @@ -47,12 +104,97 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileMessage> return nullptr; } - irda_file_message->message = { + IrdaMessage message = { .protocol = protocol, .address = address, .command = command, .repeat = false, }; - return irda_file_message; + 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; +} + +std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> + IrdaAppFileParser::parse_signal_raw(const std::string& string) const { + char protocol_name[32]; + uint32_t frequency; + uint32_t duty_cycle; + int str_len = string.size(); + std::string_view str(string.c_str()); + auto irda_file_signal = std::make_unique<IrdaFileSignal>(); + + int parsed = std::sscanf( + str.data(), + "%31s %31s F:%ld DC:%ld", + irda_file_signal->name, + protocol_name, + &frequency, + &duty_cycle); + + if(parsed != 4) { + return nullptr; + } + + char dummy[100] = {0}; + int header_len = 0; + header_len = sniprintf( + dummy, + sizeof(dummy), + "%.31s %.31s F:%ld DC:%ld", + irda_file_signal->name, + protocol_name, + frequency, + duty_cycle); + + furi_assert(header_len < str_len); + str.remove_prefix(header_len); + + /* move allocated timings into raw signal object */ + IrdaAppSignal::RawSignal raw_signal = {.timings_cnt = 0, .timings = new uint32_t[500]}; + bool result = false; + + while(!str.empty()) { + char buf[10]; + size_t index = str.find_first_not_of(' ', 1); + if(index == std::string_view::npos) { + result = true; + break; + } + str.remove_prefix(index); + parsed = std::sscanf(str.data(), "%9s", buf); + if(parsed != 1) { + break; + } + str.remove_prefix(strlen(buf)); + + int value = atoi(buf); + if(value <= 0) { + break; + } + raw_signal.timings[raw_signal.timings_cnt] = value; + ++raw_signal.timings_cnt; + if(raw_signal.timings_cnt >= 500) { + break; + } + } + + if(result) { + irda_file_signal->signal.set_raw_signal(raw_signal.timings, raw_signal.timings_cnt); + } else { + (void)irda_file_signal.release(); + delete[] raw_signal.timings; + } + return irda_file_signal; } diff --git a/applications/irda/irda-app-file-parser.hpp b/applications/irda/irda-app-file-parser.hpp index 55b27971..86a69a72 100644 --- a/applications/irda/irda-app-file-parser.hpp +++ b/applications/irda/irda-app-file-parser.hpp @@ -1,17 +1,26 @@ #pragma once -#include "file_reader/file_reader.hpp" -#include "irda.h" +#include <file_reader/file_reader.h> +#include <irda.h> +#include "irda-app-remote-manager.hpp" class IrdaAppFileParser : public FileReader { public: typedef struct { char name[32]; - IrdaMessage message; - } IrdaFileMessage; + IrdaAppSignal signal; + } IrdaFileSignal; - std::unique_ptr<IrdaAppFileParser::IrdaFileMessage> read_message(File* file); + IrdaAppFileParser() { + /* Assume we can save max 512 samples */ + set_max_line_length(max_line_length); + } + + std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> read_signal(File* file); + bool store_signal(File* file, const IrdaAppSignal& signal, const char* name); private: - std::unique_ptr<IrdaFileMessage> parse_message(const std::string& str) const; + static const uint32_t max_line_length; + std::unique_ptr<IrdaFileSignal> parse_signal(const std::string& str) const; + std::unique_ptr<IrdaFileSignal> parse_signal_raw(const std::string& str) const; }; diff --git a/applications/irda/irda-app-remote-manager.cpp b/applications/irda/irda-app-remote-manager.cpp index 4ae6c00c..1eef6b4d 100644 --- a/applications/irda/irda-app-remote-manager.cpp +++ b/applications/irda/irda-app-remote-manager.cpp @@ -33,16 +33,15 @@ static std::string } } -bool IrdaAppRemoteManager::add_button(const char* button_name, const IrdaMessage* message) { - remote->buttons.emplace_back(button_name, message); +bool IrdaAppRemoteManager::add_button(const char* button_name, const IrdaAppSignal& signal) { + remote->buttons.emplace_back(button_name, signal); return store(); } bool IrdaAppRemoteManager::add_remote_with_button( const char* button_name, - const IrdaMessage* message) { + const IrdaAppSignal& signal) { furi_check(button_name != nullptr); - furi_check(message != nullptr); std::vector<std::string> remote_list; bool result = get_remote_list(remote_list); @@ -51,7 +50,7 @@ bool IrdaAppRemoteManager::add_remote_with_button( auto new_name = find_vacant_name(remote_list, default_remote_name); remote = std::make_unique<IrdaAppRemote>(new_name); - return add_button(button_name, message); + return add_button(button_name, signal); } IrdaAppRemote::IrdaAppRemote(const std::string& name) @@ -70,12 +69,12 @@ std::vector<std::string> IrdaAppRemoteManager::get_button_list(void) const { return name_vector; } -const IrdaMessage* IrdaAppRemoteManager::get_button_data(size_t index) const { +const IrdaAppSignal& IrdaAppRemoteManager::get_button_data(size_t index) const { furi_check(remote.get() != nullptr); auto& buttons = remote->buttons; furi_check(index < buttons.size()); - return &buttons.at(index).message; + return buttons.at(index).signal; } std::string IrdaAppRemoteManager::make_filename(const std::string& name) const { @@ -166,7 +165,6 @@ size_t IrdaAppRemoteManager::get_number_of_buttons() { bool IrdaAppRemoteManager::store(void) { File file; - uint16_t write_count; std::string dirname(std::string("/") + irda_directory); IrdaAppFileParser file_parser; @@ -186,25 +184,9 @@ bool IrdaAppRemoteManager::store(void) { return false; } - char content[128]; - for(const auto& button : remote->buttons) { - auto protocol = button.message.protocol; - - sniprintf( - content, - sizeof(content), - "%.31s %.31s A:%0*lX C:%0*lX\n", - button.name.c_str(), - irda_get_protocol_name(protocol), - irda_get_protocol_address_length(protocol), - button.message.address, - irda_get_protocol_command_length(protocol), - button.message.command); - - auto content_len = strlen(content); - write_count = file_parser.get_fs_api().file.write(&file, content, content_len); - if(file.error_id != FSE_OK || write_count != content_len) { + bool result = file_parser.store_signal(&file, button.signal, button.name.c_str()); + if(!result) { file_parser.get_sd_api().show_error( file_parser.get_sd_api().context, "Cannot write\nto key file"); file_parser.get_fs_api().file.close(&file); @@ -267,9 +249,9 @@ bool IrdaAppRemoteManager::load(const std::string& name) { remote = std::make_unique<IrdaAppRemote>(name); while(1) { - auto message = file_parser.read_message(&file); - if(!message) break; - remote->buttons.emplace_back(message->name, &message->message); + auto file_signal = file_parser.read_signal(&file); + if(!file_signal.get()) break; + remote->buttons.emplace_back(file_signal->name, file_signal->signal); } file_parser.get_fs_api().file.close(&file); diff --git a/applications/irda/irda-app-remote-manager.hpp b/applications/irda/irda-app-remote-manager.hpp index f7f068cd..fda82e7e 100644 --- a/applications/irda/irda-app-remote-manager.hpp +++ b/applications/irda/irda-app-remote-manager.hpp @@ -1,4 +1,5 @@ #pragma once +#include <irda_worker.h> #include <stdint.h> #include <string> #include <vector> @@ -6,14 +7,16 @@ #include <irda.h> #include <sd-card-api.h> #include <filesystem-api.h> +#include "irda-app-signal.h" + class IrdaAppRemoteButton { friend class IrdaAppRemoteManager; std::string name; - IrdaMessage message; + IrdaAppSignal signal; public: - IrdaAppRemoteButton(const char* name, const IrdaMessage* message) - : name(name), message (*message) {} + IrdaAppRemoteButton(const char* name, const IrdaAppSignal& signal) + : name(name), signal (signal) {} ~IrdaAppRemoteButton() {} }; @@ -38,8 +41,8 @@ class IrdaAppRemoteManager { std::string make_filename(const std::string& name) const; public: - bool add_remote_with_button(const char* button_name, const IrdaMessage* message); - bool add_button(const char* button_name, const IrdaMessage* message); + bool add_remote_with_button(const char* button_name, const IrdaAppSignal& signal); + bool add_button(const char* button_name, const IrdaAppSignal& signal); int find_remote_name(const std::vector<std::string>& strings); bool rename_button(uint32_t index, const char* str); @@ -50,7 +53,7 @@ public: std::string get_button_name(uint32_t index); std::string get_remote_name(); size_t get_number_of_buttons(); - const IrdaMessage* get_button_data(size_t button_index) const; + const IrdaAppSignal& get_button_data(size_t index) const; bool delete_button(uint32_t index); bool delete_remote(); diff --git a/applications/irda/irda-app-signal.cpp b/applications/irda/irda-app-signal.cpp new file mode 100644 index 00000000..0a9a7956 --- /dev/null +++ b/applications/irda/irda-app-signal.cpp @@ -0,0 +1,95 @@ +#include "irda-app-signal.h" +#include <irda_transmit.h> + +void IrdaAppSignal::copy_timings(const uint32_t* timings, size_t size) { + furi_assert(size); + furi_assert(timings); + + if(size) { + payload.raw.timings = new uint32_t[size]; + payload.raw.timings_cnt = size; + memcpy(payload.raw.timings, timings, size * sizeof(uint32_t)); + } +} + +void IrdaAppSignal::clear_timings() { + if(!decoded) { + delete[] payload.raw.timings; + payload.raw.timings_cnt = 0; + payload.raw.timings = nullptr; + } +} + +IrdaAppSignal::IrdaAppSignal(const uint32_t* timings, size_t timings_cnt) { + decoded = false; + copy_timings(timings, timings_cnt); +} + +IrdaAppSignal::IrdaAppSignal(const IrdaMessage* irda_message) { + decoded = true; + payload.message = *irda_message; +} + +IrdaAppSignal& IrdaAppSignal::operator=(const IrdaAppSignal& other) { + clear_timings(); + decoded = other.decoded; + if(decoded) { + payload.message = other.payload.message; + } else { + copy_timings(other.payload.raw.timings, other.payload.raw.timings_cnt); + } + + return *this; +} + +IrdaAppSignal::IrdaAppSignal(const IrdaAppSignal& other) { + decoded = other.decoded; + if(decoded) { + payload.message = other.payload.message; + } else { + copy_timings(other.payload.raw.timings, other.payload.raw.timings_cnt); + } +} + +IrdaAppSignal::IrdaAppSignal(IrdaAppSignal&& other) { + clear_timings(); + + decoded = other.decoded; + if(decoded) { + payload.message = other.payload.message; + } else { + furi_assert(other.payload.raw.timings_cnt > 0); + + payload.raw.timings = other.payload.raw.timings; + payload.raw.timings_cnt = other.payload.raw.timings_cnt; + other.payload.raw.timings = nullptr; + other.payload.raw.timings_cnt = 0; + } +} + +void IrdaAppSignal::set_message(const IrdaMessage* irda_message) { + clear_timings(); + decoded = true; + payload.message = *irda_message; +} + +void IrdaAppSignal::set_raw_signal(uint32_t* timings, size_t timings_cnt) { + clear_timings(); + decoded = false; + payload.raw.timings = timings; + 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 { + if(decoded) { + irda_send(&payload.message, 1); + } else { + irda_send_raw(payload.raw.timings, payload.raw.timings_cnt, true); + } +} diff --git a/applications/irda/irda-app-signal.h b/applications/irda/irda-app-signal.h new file mode 100644 index 00000000..9701e2c1 --- /dev/null +++ b/applications/irda/irda-app-signal.h @@ -0,0 +1,61 @@ +#pragma once +#include <irda_worker.h> +#include <stdint.h> +#include <string> +#include <irda.h> + +class IrdaAppSignal { +public: + typedef struct { + size_t timings_cnt; + uint32_t* timings; + } RawSignal; + +private: + bool decoded; + union { + IrdaMessage message; + RawSignal raw; + } payload; + + void copy_timings(const uint32_t* timings, size_t size); + void clear_timings(); + +public: + IrdaAppSignal() { + decoded = true; + payload.message.protocol = IrdaProtocolUnknown; + } + + ~IrdaAppSignal() { + clear_timings(); + } + + IrdaAppSignal(const uint32_t* timings, size_t timings_cnt); + IrdaAppSignal(const IrdaMessage* irda_message); + + IrdaAppSignal(const IrdaAppSignal& other); + IrdaAppSignal(IrdaAppSignal&& other); + + IrdaAppSignal& operator=(const IrdaAppSignal& signal); + + void set_message(const IrdaMessage* irda_message); + void set_raw_signal(uint32_t* timings, size_t timings_cnt); + void copy_raw_signal(uint32_t* timings, size_t timings_cnt); + + void transmit() const; + + bool is_raw(void) const { + return !decoded; + } + + const IrdaMessage& get_message(void) const { + furi_assert(decoded); + return payload.message; + } + + const RawSignal& get_raw_signal(void) const { + furi_assert(!decoded); + return payload.raw; + } +}; diff --git a/applications/irda/irda-app-transceiver.cpp b/applications/irda/irda-app-transceiver.cpp deleted file mode 100644 index c9f7d19c..00000000 --- a/applications/irda/irda-app-transceiver.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "irda-app.hpp" -#include "irda.h" -#include <api-hal-irda.h> - -void IrdaAppSignalTransceiver::irda_rx_callback(void* ctx, bool level, uint32_t duration) { - IrdaAppEvent event; - const IrdaMessage* irda_message; - IrdaAppSignalTransceiver* this_ = static_cast<IrdaAppSignalTransceiver*>(ctx); - - irda_message = irda_decode(this_->decoder, level, duration); - if(irda_message) { - this_->message = *irda_message; - event.type = IrdaAppEvent::Type::IrdaMessageReceived; - osStatus_t result = osMessageQueuePut(this_->event_queue, &event, 0, 0); - furi_check(result == osOK); - } -} - -IrdaAppSignalTransceiver::IrdaAppSignalTransceiver(void) - : capture_started(false) - , decoder(irda_alloc_decoder()) { -} - -IrdaAppSignalTransceiver::~IrdaAppSignalTransceiver() { - capture_stop(); - irda_free_decoder(decoder); -} - -void IrdaAppSignalTransceiver::capture_once_start(osMessageQueueId_t queue) { - event_queue = queue; - irda_reset_decoder(decoder); - if(!capture_started) { - capture_started = true; - api_hal_irda_rx_irq_set_callback(IrdaAppSignalTransceiver::irda_rx_callback, this); - api_hal_irda_rx_irq_init(); - } -} - -void IrdaAppSignalTransceiver::capture_stop(void) { - IrdaAppEvent event; - - if(capture_started) { - capture_started = false; - api_hal_irda_rx_irq_deinit(); - while(osMessageQueueGet(this->event_queue, &event, 0, 0) == osOK) - ; - } -} - -IrdaMessage* IrdaAppSignalTransceiver::get_last_message(void) { - return &message; -} - -void IrdaAppSignalTransceiver::send_message(const IrdaMessage* message) const { - irda_send(message, 1); -} diff --git a/applications/irda/irda-app-transceiver.hpp b/applications/irda/irda-app-transceiver.hpp deleted file mode 100644 index e0c75b5b..00000000 --- a/applications/irda/irda-app-transceiver.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include <furi.h> -#include <irda.h> - -class IrdaAppSignalTransceiver { -public: - IrdaAppSignalTransceiver(void); - ~IrdaAppSignalTransceiver(void); - void capture_once_start(osMessageQueueId_t event_queue); - void capture_stop(void); - IrdaMessage* get_last_message(void); - void send_message(const IrdaMessage* message) const; - -private: - bool capture_started; - osMessageQueueId_t event_queue; - static void irda_rx_callback(void* ctx, bool level, uint32_t duration); - IrdaDecoderHandler* decoder; - IrdaMessage message; -}; - diff --git a/applications/irda/irda-app.cpp b/applications/irda/irda-app.cpp index 4437ed96..6cd342ba 100644 --- a/applications/irda/irda-app.cpp +++ b/applications/irda/irda-app.cpp @@ -1,4 +1,5 @@ #include "irda-app.hpp" +#include <irda_worker.h> #include <furi.h> #include <gui/gui.h> #include <input/input.h> @@ -99,10 +100,6 @@ IrdaAppRemoteManager* IrdaApp::get_remote_manager() { return &remote_manager; } -IrdaAppSignalTransceiver* IrdaApp::get_transceiver() { - return &transceiver; -} - void IrdaApp::set_text_store(uint8_t index, const char* text...) { furi_check(index < text_store_max); @@ -220,3 +217,15 @@ void IrdaApp::notify_green_on() { void IrdaApp::notify_green_off() { notification_message(notification, &sequence_reset_green); } + +IrdaWorker* IrdaApp::get_irda_worker() { + return irda_worker; +} + +const IrdaAppSignal& IrdaApp::get_received_signal() const { + return received_signal; +} + +void IrdaApp::set_received_signal(const IrdaAppSignal& signal) { + received_signal = signal; +} diff --git a/applications/irda/irda-app.hpp b/applications/irda/irda-app.hpp index 0e76fc87..233c4c9f 100644 --- a/applications/irda/irda-app.hpp +++ b/applications/irda/irda-app.hpp @@ -7,10 +7,10 @@ #include "scene/irda-app-scene.hpp" #include "irda-app-view-manager.hpp" #include "irda-app-remote-manager.hpp" -#include "irda-app-transceiver.hpp" #include <forward_list> #include <stdint.h> #include <notification/notification-messages.h> +#include <irda_worker.h> class IrdaApp { @@ -51,11 +51,15 @@ public: bool switch_to_previous_scene(uint8_t count = 1); Scene get_previous_scene(); IrdaAppViewManager* get_view_manager(); - IrdaAppSignalTransceiver* get_transceiver(); void set_text_store(uint8_t index, const char* text...); char* get_text_store(uint8_t index); uint8_t get_text_store_size(); IrdaAppRemoteManager* get_remote_manager(); + + IrdaWorker* get_irda_worker(); + const IrdaAppSignal& get_received_signal() const; + void set_received_signal(const IrdaAppSignal& signal); + void search_and_switch_to_previous_scene(const std::initializer_list<Scene>& scenes_list); void set_edit_element(EditElement value); @@ -87,8 +91,10 @@ public: IrdaApp() { notification = static_cast<NotificationApp*>(furi_record_open("notification")); + irda_worker = irda_worker_alloc(); } ~IrdaApp() { + irda_worker_free(irda_worker); furi_record_close("notification"); for (auto &it : scenes) delete it.second; @@ -103,9 +109,10 @@ private: uint32_t current_button; NotificationApp* notification; - IrdaAppSignalTransceiver transceiver; IrdaAppViewManager view_manager; IrdaAppRemoteManager remote_manager; + IrdaWorker* irda_worker; + IrdaAppSignal received_signal; std::forward_list<Scene> previous_scenes_list; Scene current_scene = Scene::Start; diff --git a/applications/irda/irda_app_old.c b/applications/irda/irda_app_old.c deleted file mode 100644 index abfc30d6..00000000 --- a/applications/irda/irda_app_old.c +++ /dev/null @@ -1,434 +0,0 @@ -#include <furi.h> -#include <api-hal.h> -#include <gui/gui.h> -#include <input/input.h> -#include <cli/cli.h> -#include <notification/notification-messages.h> - -#include <api-hal-irda.h> -#include "irda.h" - -typedef enum { - EventTypeTick, - EventTypeKey, - EventTypeRX, -} EventType; - -typedef IrdaMessage IrDAPacket; - -typedef struct { - union { - InputEvent input; - IrDAPacket rx; - } value; - EventType type; -} AppEvent; - -//typedef struct { -// IrdaProtocol protocol; -// uint32_t address; -// uint32_t command; -//} IrDAPacket; - -#define IRDA_PACKET_COUNT 8 - -typedef struct { - osMessageQueueId_t cli_ir_rx_queue; - Cli* cli; - bool cli_cmd_is_active; -} IrDAApp; - -typedef struct { - uint8_t mode_id; - uint16_t carrier_freq; - uint8_t carrier_duty_cycle_id; - - uint8_t packet_id; - IrDAPacket packets[IRDA_PACKET_COUNT]; -} State; - -typedef void (*ModeInput)(AppEvent*, State*); -typedef void (*ModeRender)(Canvas*, State*); - -void input_carrier(AppEvent* event, State* state); -void render_carrier(Canvas* canvas, State* state); -void input_packet(AppEvent* event, State* state); -void render_packet(Canvas* canvas, State* state); - -typedef struct { - ModeRender render; - ModeInput input; -} Mode; - -const Mode modes[] = { - {.render = render_carrier, .input = input_carrier}, - {.render = render_packet, .input = input_packet}, -}; - -const float duty_cycles[] = {0.1, 0.25, 0.333, 0.5, 1.0}; - -void render_carrier(Canvas* canvas, State* state) { - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 2, 25, "carrier mode >"); - canvas_draw_str(canvas, 2, 37, "? /\\ freq | \\/ duty cycle"); - { - char buf[24]; - sprintf(buf, "frequency: %u Hz", state->carrier_freq); - canvas_draw_str(canvas, 2, 50, buf); - sprintf( - buf, "duty cycle: %d/1000", (int)(duty_cycles[state->carrier_duty_cycle_id] * 1000)); - canvas_draw_str(canvas, 2, 62, buf); - } -} - -void input_carrier(AppEvent* event, State* state) { - if(event->value.input.key == InputKeyOk) { - if(event->value.input.type == InputTypePress) { - api_hal_irda_pwm_set(duty_cycles[state->carrier_duty_cycle_id], state->carrier_freq); - } else if(event->value.input.type == InputTypeRelease) { - api_hal_irda_pwm_stop(); - } - } - - if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyUp) { - if(state->carrier_freq < 45000) { - state->carrier_freq += 1000; - } else { - state->carrier_freq = 33000; - } - } - - if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyDown) { - uint8_t duty_cycles_count = sizeof(duty_cycles) / sizeof(duty_cycles[0]); - if(state->carrier_duty_cycle_id < (duty_cycles_count - 1)) { - state->carrier_duty_cycle_id++; - } else { - state->carrier_duty_cycle_id = 0; - } - } -} - -void render_packet(Canvas* canvas, State* state) { - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 2, 25, "< packet mode"); - canvas_draw_str(canvas, 2, 37, "? /\\ \\/ packet"); - { - char buf[30]; - sprintf( - buf, - "P[%d]: %s 0x%lX 0x%lX", - state->packet_id, - irda_get_protocol_name(state->packets[state->packet_id].protocol), - state->packets[state->packet_id].address, - state->packets[state->packet_id].command); - canvas_draw_str(canvas, 2, 50, buf); - } -} - -void input_packet(AppEvent* event, State* state) { - if(event->value.input.key == InputKeyOk) { - if(event->value.input.type == InputTypeShort) { - IrdaMessage message = { - .protocol = state->packets[state->packet_id].protocol, - .address = state->packets[state->packet_id].address, - .command = state->packets[state->packet_id].command, - }; - irda_send(&message, 1); - } - } - - if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyDown) { - if(state->packet_id < (IRDA_PACKET_COUNT - 1)) { - state->packet_id++; - }; - } - - if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyUp) { - if(state->packet_id > 0) { - state->packet_id--; - }; - } -} - -static void render_callback(Canvas* canvas, void* ctx) { - State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25); - - if(state != NULL) { - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 2, 12, "irda test"); - - modes[state->mode_id].render(canvas, state); - - release_mutex((ValueMutex*)ctx, state); - } -} - -static void input_callback(InputEvent* input_event, void* ctx) { - osMessageQueueId_t event_queue = ctx; - - AppEvent event; - event.type = EventTypeKey; - event.value.input = *input_event; - osMessageQueuePut(event_queue, &event, 0, 0); -} - -void init_packet( - State* state, - uint8_t index, - IrdaProtocol protocol, - uint32_t address, - uint32_t command) { - if(index >= IRDA_PACKET_COUNT) return; - state->packets[index].protocol = protocol; - state->packets[index].address = address; - state->packets[index].command = command; -} - -void irda_cli_cmd_rx(Cli* cli, string_t args, void* context) { - furi_assert(context); - IrDAPacket packet; - IrDAApp* app = context; - app->cli_cmd_is_active = true; - bool exit = false; - - printf("Reading income packets...\r\nPress Ctrl+C to abort\r\n"); - while(!exit) { - exit = cli_cmd_interrupt_received(app->cli); - osStatus status = osMessageQueueGet(app->cli_ir_rx_queue, &packet, 0, 5); - if(status == osOK) { - printf( - "%s " - "Address:0x%02X Command: 0x%02X %s\r\n", - irda_get_protocol_name(packet.protocol), - (uint8_t)packet.address, - (uint8_t)packet.command, - packet.repeat ? "R" : ""); - } - } - printf("Interrupt command received"); - app->cli_cmd_is_active = false; - return; -} - -void irda_cli_cmd_tx(Cli* cli, string_t args, void* context) { - furi_assert(context); - ValueMutex* state_mutex = context; - // Read protocol name - IrdaProtocol protocol; - string_t protocol_str; - string_init(protocol_str); - size_t ws = string_search_char(args, ' '); - if(ws == STRING_FAILURE) { - printf("Invalid input. Use ir_tx PROTOCOL ADDRESS COMMAND"); - string_clear(protocol_str); - return; - } else { - string_set_n(protocol_str, args, 0, ws); - string_right(args, ws); - string_strim(args); - } - if(!string_cmp_str(protocol_str, "NEC")) { - protocol = IrdaProtocolNEC; - } else if(!string_cmp_str(protocol_str, "SAMSUNG")) { - protocol = IrdaProtocolSamsung32; - } else { - printf("Incorrect protocol. Valid protocols: `NEC`, `SAMSUNG`"); - string_clear(protocol_str); - return; - } - string_clear(protocol_str); - // Read address - uint16_t address = strtoul(string_get_cstr(args), NULL, 16); - ws = string_search_char(args, ' '); - if(!(ws == 4 || ws == 6)) { - printf("Invalid address format. Use 4 [0-F] hex digits in 0xXXXX or XXXX formats"); - return; - } - string_right(args, ws); - string_strim(args); - // Read command - uint16_t command = strtoul(string_get_cstr(args), NULL, 16); - ws = string_search_char(args, '\0'); - if(!(ws == 4 || ws == 6)) { - printf("Invalid command format. Use 4 [0-F] hex digits in 0xXXXX or XXXX formats"); - return; - } - - State* state = (State*)acquire_mutex(state_mutex, 25); - if(state == NULL) { - printf("IRDA resources busy\r\n"); - return; - } - - IrdaMessage message = { - .protocol = protocol, - .address = address, - .command = command, - }; - irda_send(&message, 1); - release_mutex(state_mutex, state); - return; -} - -typedef struct { - osMessageQueueId_t event_queue; - IrdaDecoderHandler* handler; -} IsrContext; - -void irda_rx_callback(void* ctx, bool level, uint32_t duration) { - IsrContext* isr_context = ctx; - const IrdaMessage* message = irda_decode(isr_context->handler, level, duration); - AppEvent event; - event.type = EventTypeRX; - - if(message) { - event.value.rx = *message; - furi_check(osMessageQueuePut(isr_context->event_queue, &event, 0, 0) == osOK); - } -} - -int32_t irda2(void* p) { - osMessageQueueId_t event_queue = osMessageQueueNew(32, sizeof(AppEvent), NULL); - - State _state; - uint8_t mode_count = sizeof(modes) / sizeof(modes[0]); - uint8_t duty_cycles_count = sizeof(duty_cycles) / sizeof(duty_cycles[0]); - - _state.carrier_duty_cycle_id = duty_cycles_count - 2; - _state.carrier_freq = 36000; - _state.mode_id = 0; - _state.packet_id = 0; - - IrDAApp irda_app; - irda_app.cli = furi_record_open("cli"); - irda_app.cli_ir_rx_queue = osMessageQueueNew(1, sizeof(IrDAPacket), NULL); - irda_app.cli_cmd_is_active = false; - - NotificationApp* notification = furi_record_open("notification"); - - for(uint8_t i = 0; i < IRDA_PACKET_COUNT; i++) { - init_packet(&_state, i, 0, 0, 0); - } - - init_packet(&_state, 0, IrdaProtocolNEC, 0x00, 0x11); - init_packet(&_state, 1, IrdaProtocolNEC, 0x08, 0x59); - init_packet(&_state, 2, IrdaProtocolNEC, 0x00, 0x10); - init_packet(&_state, 3, IrdaProtocolNEC, 0x00, 0x15); - init_packet(&_state, 4, IrdaProtocolNEC, 0x00, 0x25); - init_packet(&_state, 5, IrdaProtocolSamsung32, 0x0E, 0x0C); - init_packet(&_state, 6, IrdaProtocolSamsung32, 0x0E, 0x0D); - init_packet(&_state, 7, IrdaProtocolSamsung32, 0x0E, 0x0E); - - ValueMutex state_mutex; - if(!init_mutex(&state_mutex, &_state, sizeof(State))) { - printf("cannot create mutex\r\n"); - return 255; - } - - ViewPort* view_port = view_port_alloc(); - - view_port_draw_callback_set(view_port, render_callback, &state_mutex); - view_port_input_callback_set(view_port, input_callback, event_queue); - - cli_add_command(irda_app.cli, "ir_rx", irda_cli_cmd_rx, &irda_app); - cli_add_command(irda_app.cli, "ir_tx", irda_cli_cmd_tx, &state_mutex); - - // Open GUI and register view_port - Gui* gui = furi_record_open("gui"); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - IsrContext isr_context = { - .handler = irda_alloc_decoder(), - .event_queue = event_queue, - }; - api_hal_irda_rx_irq_init(); - api_hal_irda_rx_irq_set_callback(irda_rx_callback, &isr_context); - - AppEvent event; - while(1) { - osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 500); - - if(event_status == osOK) { - if(event.type == EventTypeKey) { - State* state = (State*)acquire_mutex_block(&state_mutex); - - // press events - if(event.value.input.type == InputTypeShort && - event.value.input.key == InputKeyBack) { - release_mutex(&state_mutex, state); - - // remove all view_ports create by app - gui_remove_view_port(gui, view_port); - view_port_free(view_port); - - // free decoder - delete_mutex(&state_mutex); - osMessageQueueDelete(event_queue); - osMessageQueueDelete(irda_app.cli_ir_rx_queue); - cli_delete_command(irda_app.cli, "ir_rx"); - cli_delete_command(irda_app.cli, "ir_tx"); - furi_record_close("cli"); - furi_record_close("notification"); - api_hal_irda_rx_irq_deinit(); - irda_free_decoder(isr_context.handler); - - // exit - return 0; - } - - if(event.value.input.type == InputTypeShort && - event.value.input.key == InputKeyLeft) { - if(state->mode_id > 0) { - state->mode_id--; - } - } - - if(event.value.input.type == InputTypeShort && - event.value.input.key == InputKeyRight) { - if(state->mode_id < (mode_count - 1)) { - state->mode_id++; - } - } - - modes[state->mode_id].input(&event, state); - - release_mutex(&state_mutex, state); - view_port_update(view_port); - - } else if(event.type == EventTypeRX) { - notification_message(notification, &sequence_blink_red_10); - - // save only if we in packet mode - State* state = (State*)acquire_mutex_block(&state_mutex); - IrDAPacket packet = event.value.rx; - - if(state->mode_id == 1) { - printf("P=%s ", irda_get_protocol_name(packet.protocol)); - printf("A=0x%02lX ", packet.address); - printf("C=0x%02lX ", packet.command); - if(packet.repeat) { - printf("R"); - } - printf("\r\n"); - // Save packet to state - memcpy(&(state->packets[state->packet_id]), &packet, sizeof(IrDAPacket)); - } - if(irda_app.cli_cmd_is_active) { - // Send decoded packet to cli - osMessageQueuePut(irda_app.cli_ir_rx_queue, &packet, 0, 0); - } - - release_mutex(&state_mutex, state); - view_port_update(view_port); - - // blink anyway - notification_message(notification, &sequence_blink_green_10); - } - - } else { - // event timeout - } - } -} diff --git a/applications/irda/scene/irda-app-scene-edit-delete.cpp b/applications/irda/scene/irda-app-scene-edit-delete.cpp index da817cba..c16ee7f2 100644 --- a/applications/irda/scene/irda-app-scene-edit-delete.cpp +++ b/applications/irda/scene/irda-app-scene-edit-delete.cpp @@ -20,17 +20,26 @@ void IrdaAppSceneEditDelete::on_enter(IrdaApp* app) { auto remote_manager = app->get_remote_manager(); if(app->get_edit_element() == IrdaApp::EditElement::Button) { - auto message = remote_manager->get_button_data(app->get_current_button()); + auto signal = remote_manager->get_button_data(app->get_current_button()); dialog_ex_set_header(dialog_ex, "Delete button?", 64, 6, AlignCenter, AlignCenter); - app->set_text_store( - 0, - "%s\n%s\nA=0x%0*lX C=0x%0*lX", - remote_manager->get_button_name(app->get_current_button()).c_str(), - irda_get_protocol_name(message->protocol), - irda_get_protocol_address_length(message->protocol), - message->address, - irda_get_protocol_command_length(message->protocol), - message->command); + if(!signal.is_raw()) { + auto message = &signal.get_message(); + app->set_text_store( + 0, + "%s\n%s\nA=0x%0*lX C=0x%0*lX", + remote_manager->get_button_name(app->get_current_button()).c_str(), + irda_get_protocol_name(message->protocol), + irda_get_protocol_address_length(message->protocol), + message->address, + irda_get_protocol_command_length(message->protocol), + message->command); + } else { + app->set_text_store( + 0, + "%s\nRAW\n%ld samples", + remote_manager->get_button_name(app->get_current_button()).c_str(), + signal.get_raw_signal().timings_cnt); + } } else { dialog_ex_set_header(dialog_ex, "Delete remote?", 64, 6, AlignCenter, AlignCenter); app->set_text_store( diff --git a/applications/irda/scene/irda-app-scene-learn-enter-name.cpp b/applications/irda/scene/irda-app-scene-learn-enter-name.cpp index 45cd5ebf..be0b8d63 100644 --- a/applications/irda/scene/irda-app-scene-learn-enter-name.cpp +++ b/applications/irda/scene/irda-app-scene-learn-enter-name.cpp @@ -5,15 +5,20 @@ void IrdaAppSceneLearnEnterName::on_enter(IrdaApp* app) { IrdaAppViewManager* view_manager = app->get_view_manager(); TextInput* text_input = view_manager->get_text_input(); - auto transceiver = app->get_transceiver(); - auto message = transceiver->get_last_message(); - - app->set_text_store( - 0, - "%.4s_%0*lX", - irda_get_protocol_name(message->protocol), - irda_get_protocol_command_length(message->protocol), - message->command); + auto signal = app->get_received_signal(); + + if(!signal.is_raw()) { + auto message = &signal.get_message(); + app->set_text_store( + 0, + "%.4s_%0*lX", + irda_get_protocol_name(message->protocol), + irda_get_protocol_command_length(message->protocol), + message->command); + } else { + auto raw_signal = signal.get_raw_signal(); + app->set_text_store(0, "RAW_%d", raw_signal.timings_cnt); + } text_input_set_header_text(text_input, "Name the key"); text_input_set_result_callback( @@ -31,14 +36,13 @@ bool IrdaAppSceneLearnEnterName::on_event(IrdaApp* app, IrdaAppEvent* event) { if(event->type == IrdaAppEvent::Type::TextEditDone) { auto remote_manager = app->get_remote_manager(); - auto transceiver = app->get_transceiver(); bool result = false; if(app->get_learn_new_remote()) { result = remote_manager->add_remote_with_button( - app->get_text_store(0), transceiver->get_last_message()); + app->get_text_store(0), app->get_received_signal()); } else { - result = remote_manager->add_button( - app->get_text_store(0), transceiver->get_last_message()); + result = + remote_manager->add_button(app->get_text_store(0), app->get_received_signal()); } if(!result) { diff --git a/applications/irda/scene/irda-app-scene-learn-success.cpp b/applications/irda/scene/irda-app-scene-learn-success.cpp index 8b20f065..74e8db74 100644 --- a/applications/irda/scene/irda-app-scene-learn-success.cpp +++ b/applications/irda/scene/irda-app-scene-learn-success.cpp @@ -17,19 +17,26 @@ void IrdaAppSceneLearnSuccess::on_enter(IrdaApp* app) { app->notify_green_on(); - auto transceiver = app->get_transceiver(); - auto message = transceiver->get_last_message(); + auto signal = app->get_received_signal(); + + if(!signal.is_raw()) { + auto message = &signal.get_message(); + app->set_text_store(0, "%s", irda_get_protocol_name(message->protocol)); + app->set_text_store( + 1, + "A: 0x%0*lX\nC: 0x%0*lX\n", + irda_get_protocol_address_length(message->protocol), + message->address, + irda_get_protocol_command_length(message->protocol), + message->command); + dialog_ex_set_header(dialog_ex, app->get_text_store(0), 95, 10, AlignCenter, AlignCenter); + dialog_ex_set_text(dialog_ex, app->get_text_store(1), 75, 23, AlignLeft, AlignTop); + } else { + dialog_ex_set_header(dialog_ex, "Unknown", 95, 10, AlignCenter, AlignCenter); + app->set_text_store(0, "%d samples", signal.get_raw_signal().timings_cnt); + dialog_ex_set_text(dialog_ex, app->get_text_store(0), 75, 23, AlignLeft, AlignTop); + } - app->set_text_store(0, "%s", irda_get_protocol_name(message->protocol)); - app->set_text_store( - 1, - "A: 0x%0*lX\nC: 0x%0*lX\n", - irda_get_protocol_address_length(message->protocol), - message->address, - irda_get_protocol_command_length(message->protocol), - message->command); - dialog_ex_set_header(dialog_ex, app->get_text_store(0), 95, 10, AlignCenter, AlignCenter); - dialog_ex_set_text(dialog_ex, app->get_text_store(1), 75, 23, AlignLeft, AlignTop); dialog_ex_set_left_button_text(dialog_ex, "Retry"); dialog_ex_set_right_button_text(dialog_ex, "Save"); dialog_ex_set_center_button_text(dialog_ex, "Send"); @@ -50,9 +57,8 @@ bool IrdaAppSceneLearnSuccess::on_event(IrdaApp* app, IrdaAppEvent* event) { break; case DialogExResultCenter: { app->notify_space_blink(); - auto transceiver = app->get_transceiver(); - auto message = transceiver->get_last_message(); - irda_send(message, 1); + auto signal = app->get_received_signal(); + signal.transmit(); break; } case DialogExResultRight: diff --git a/applications/irda/scene/irda-app-scene-learn.cpp b/applications/irda/scene/irda-app-scene-learn.cpp index 890a523f..7fdd8bf7 100644 --- a/applications/irda/scene/irda-app-scene-learn.cpp +++ b/applications/irda/scene/irda-app-scene-learn.cpp @@ -1,14 +1,40 @@ #include "../irda-app.hpp" +#include "../irda-app-event.hpp" +#include <irda_worker.h> -void IrdaAppSceneLearn::on_enter(IrdaApp* app) { - auto view_manager = app->get_view_manager(); - auto transceiver = app->get_transceiver(); - auto event_queue = view_manager->get_event_queue(); +static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) { + furi_assert(context); + furi_assert(received_signal); + + IrdaApp* app = static_cast<IrdaApp*>(context); - transceiver->capture_once_start(event_queue); + if(irda_worker_signal_is_decoded(received_signal)) { + IrdaAppSignal signal(irda_worker_get_decoded_message(received_signal)); + app->set_received_signal(signal); + } else { + const uint32_t* timings; + size_t timings_cnt; + irda_worker_get_raw_signal(received_signal, &timings, &timings_cnt); + IrdaAppSignal signal(timings, timings_cnt); + app->set_received_signal(signal); + } + + irda_worker_set_received_signal_callback(app->get_irda_worker(), NULL); + IrdaAppEvent event; + event.type = IrdaAppEvent::Type::IrdaMessageReceived; + auto view_manager = app->get_view_manager(); + view_manager->send_event(&event); +} +void IrdaAppSceneLearn::on_enter(IrdaApp* app) { + auto view_manager = app->get_view_manager(); auto popup = view_manager->get_popup(); + auto worker = app->get_irda_worker(); + irda_worker_set_context(worker, app); + irda_worker_set_received_signal_callback(worker, signal_received_callback); + irda_worker_start(worker); + popup_set_icon(popup, 0, 32, &I_IrdaLearnShort_128x31); popup_set_text( popup, "Point the remote at IR port\nand push the button", 5, 10, AlignLeft, AlignCenter); @@ -24,19 +50,27 @@ void IrdaAppSceneLearn::on_enter(IrdaApp* app) { bool IrdaAppSceneLearn::on_event(IrdaApp* app, IrdaAppEvent* event) { bool consumed = false; - if(event->type == IrdaAppEvent::Type::Tick) { + switch(event->type) { + case IrdaAppEvent::Type::Tick: consumed = true; app->notify_red_blink(); - } - if(event->type == IrdaAppEvent::Type::IrdaMessageReceived) { + break; + case IrdaAppEvent::Type::IrdaMessageReceived: app->notify_success(); app->switch_to_next_scene_without_saving(IrdaApp::Scene::LearnSuccess); + irda_worker_stop(app->get_irda_worker()); + break; + case IrdaAppEvent::Type::Back: + consumed = true; + irda_worker_stop(app->get_irda_worker()); + app->switch_to_previous_scene(); + break; + default: + furi_assert(0); } return consumed; } void IrdaAppSceneLearn::on_exit(IrdaApp* app) { - auto transceiver = app->get_transceiver(); - transceiver->capture_stop(); } diff --git a/applications/irda/scene/irda-app-scene-remote.cpp b/applications/irda/scene/irda-app-scene-remote.cpp index dd1036f6..9260babe 100644 --- a/applications/irda/scene/irda-app-scene-remote.cpp +++ b/applications/irda/scene/irda-app-scene-remote.cpp @@ -64,8 +64,8 @@ bool IrdaAppSceneRemote::on_event(IrdaApp* app, IrdaAppEvent* event) { default: app->notify_click_and_blink(); auto remote_manager = app->get_remote_manager(); - auto message = remote_manager->get_button_data(event->payload.menu_index); - app->get_transceiver()->send_message(message); + auto signal = remote_manager->get_button_data(event->payload.menu_index); + signal.transmit(); break; } } else if(event->type == IrdaAppEvent::Type::Back) { diff --git a/applications/irda/scene/irda-app-scene-universal-common.cpp b/applications/irda/scene/irda-app-scene-universal-common.cpp index 2eebe64f..53c8a246 100644 --- a/applications/irda/scene/irda-app-scene-universal-common.cpp +++ b/applications/irda/scene/irda-app-scene-universal-common.cpp @@ -63,7 +63,7 @@ bool IrdaAppSceneUniversalCommon::on_event(IrdaApp* app, IrdaAppEvent* event) { auto view_manager = app->get_view_manager(); IrdaAppEvent tick_event = {.type = IrdaAppEvent::Type::Tick}; view_manager->send_event(&tick_event); - if(brute_force.send_next_bruteforce(*app->get_transceiver())) { + if(brute_force.send_next_bruteforce()) { progress_popup(app); } else { brute_force.stop_bruteforce(); |