[FL-1652, FL-1554] IRDA: Continuous transmitting (#636)
* [FL-1652] IRDA: Continuous transmitting * continuous encoding and sending signals by pressing button on menu * fast buttons scrolling in remote menu * bruteforce: stop reading file if progress == 100% * IRDA: .hpp -> .h * [FL-1554] IRDA: xTaskNotify -> osEventsFlagSet * IRDA: some stability fixes * Irda: minor cleanup, api-hal to furi-hal rename. Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									8696355556
								
							
						
					
					
						commit
						5ed9bdbc37
					
				| @ -1,6 +1,7 @@ | ||||
| #include "button_menu.h" | ||||
| #include "gui/canvas.h" | ||||
| #include "gui/elements.h" | ||||
| #include "input/input.h" | ||||
| #include <m-array.h> | ||||
| #include <furi.h> | ||||
| #include <stdint.h> | ||||
| @ -23,6 +24,7 @@ ARRAY_DEF(ButtonMenuItemArray, ButtonMenuItem, M_POD_OPLIST); | ||||
| 
 | ||||
| struct ButtonMenu { | ||||
|     View* view; | ||||
|     bool freeze_input; | ||||
| }; | ||||
| 
 | ||||
| typedef struct { | ||||
| @ -158,7 +160,7 @@ static void button_menu_process_down(ButtonMenu* button_menu) { | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| static void button_menu_process_ok(ButtonMenu* button_menu) { | ||||
| static void button_menu_process_ok(ButtonMenu* button_menu, InputType type) { | ||||
|     furi_assert(button_menu); | ||||
| 
 | ||||
|     ButtonMenuItem* item = NULL; | ||||
| @ -168,11 +170,22 @@ static void button_menu_process_ok(ButtonMenu* button_menu) { | ||||
|             if(model->position < (ButtonMenuItemArray_size(model->items))) { | ||||
|                 item = ButtonMenuItemArray_get(model->items, model->position); | ||||
|             } | ||||
|             return true; | ||||
|             return false; | ||||
|         }); | ||||
| 
 | ||||
|     if(item->type == ButtonMenuItemTypeControl) { | ||||
|         if(type == InputTypeShort) { | ||||
|             if(item && item->callback) { | ||||
|         item->callback(item->callback_context, item->index); | ||||
|                 item->callback(item->callback_context, item->index, type); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     if(item->type == ButtonMenuItemTypeCommon) { | ||||
|         if((type == InputTypePress) || (type == InputTypeRelease)) { | ||||
|             if(item && item->callback) { | ||||
|                 item->callback(item->callback_context, item->index, type); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -182,7 +195,19 @@ static bool button_menu_view_input_callback(InputEvent* event, void* context) { | ||||
|     ButtonMenu* button_menu = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event->type == InputTypeShort) { | ||||
|     if(event->key == InputKeyOk) { | ||||
|         if((event->type == InputTypeRelease) || (event->type == InputTypePress)) { | ||||
|             consumed = true; | ||||
|             button_menu->freeze_input = (event->type == InputTypePress); | ||||
|             button_menu_process_ok(button_menu, event->type); | ||||
|         } else if(event->type == InputTypeShort) { | ||||
|             consumed = true; | ||||
|             button_menu_process_ok(button_menu, event->type); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if(!button_menu->freeze_input && | ||||
|        ((event->type == InputTypeRepeat) || (event->type == InputTypeShort))) { | ||||
|         switch(event->key) { | ||||
|         case InputKeyUp: | ||||
|             consumed = true; | ||||
| @ -192,10 +217,6 @@ static bool button_menu_view_input_callback(InputEvent* event, void* context) { | ||||
|             consumed = true; | ||||
|             button_menu_process_down(button_menu); | ||||
|             break; | ||||
|         case InputKeyOk: | ||||
|             consumed = true; | ||||
|             button_menu_process_ok(button_menu); | ||||
|             break; | ||||
|         default: | ||||
|             break; | ||||
|         } | ||||
| @ -272,6 +293,7 @@ ButtonMenu* button_menu_alloc(void) { | ||||
|             return true; | ||||
|         }); | ||||
| 
 | ||||
|     button_menu->freeze_input = false; | ||||
|     return button_menu; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -11,7 +11,7 @@ typedef struct ButtonMenu ButtonMenu; | ||||
| typedef struct ButtonMenuItem ButtonMenuItem; | ||||
| 
 | ||||
| /* Callback for any button menu actions */ | ||||
| typedef void (*ButtonMenuItemCallback)(void* context, int32_t index); | ||||
| typedef void (*ButtonMenuItemCallback)(void* context, int32_t index, InputType type); | ||||
| 
 | ||||
| /* Type of button. Difference in drawing buttons. */ | ||||
| typedef enum { | ||||
|  | ||||
| @ -19,7 +19,7 @@ static void signal_received_callback(void* context, IrdaWorkerSignal* received_s | ||||
|     Cli* cli = (Cli*)context; | ||||
| 
 | ||||
|     if(irda_worker_signal_is_decoded(received_signal)) { | ||||
|         const IrdaMessage* message = irda_worker_get_decoded_message(received_signal); | ||||
|         const IrdaMessage* message = irda_worker_get_decoded_signal(received_signal); | ||||
|         buf_cnt = sniprintf( | ||||
|             buf, | ||||
|             sizeof(buf), | ||||
| @ -54,16 +54,15 @@ static void irda_cli_start_ir_rx(Cli* cli, string_t args, void* context) { | ||||
|     } | ||||
| 
 | ||||
|     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); | ||||
|     irda_worker_rx_start(worker); | ||||
|     irda_worker_rx_set_received_signal_callback(worker, signal_received_callback, cli); | ||||
| 
 | ||||
|     printf("Receiving IRDA...\r\nPress Ctrl+C to abort\r\n"); | ||||
|     while(!cli_cmd_interrupt_received(cli)) { | ||||
|         delay(50); | ||||
|     } | ||||
| 
 | ||||
|     irda_worker_stop(worker); | ||||
|     irda_worker_rx_stop(worker); | ||||
|     irda_worker_free(worker); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| #include "irda-app-brute-force.hpp" | ||||
| #include "irda/irda-app-file-parser.hpp" | ||||
| #include "irda-app-brute-force.h" | ||||
| #include "irda/irda-app-file-parser.h" | ||||
| #include "m-string.h" | ||||
| #include <file-worker-cpp.h> | ||||
| #include <memory> | ||||
| @ -47,7 +47,6 @@ void IrdaAppBruteForce::stop_bruteforce() { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // TODO: [FL-1418] replace with timer-chained consequence of messages.
 | ||||
| bool IrdaAppBruteForce::send_next_bruteforce(void) { | ||||
|     furi_assert(current_record.size()); | ||||
|     furi_assert(file_parser); | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| #pragma once | ||||
| #include "furi/check.h" | ||||
| #include <unordered_map> | ||||
| #include "irda-app-file-parser.hpp" | ||||
| #include "irda-app-file-parser.h" | ||||
| #include <memory> | ||||
| 
 | ||||
| class IrdaAppBruteForce { | ||||
| @ -28,7 +28,9 @@ public: | ||||
|     bool start_bruteforce(int index, int& record_amount); | ||||
|     void add_record(int index, const char* name); | ||||
| 
 | ||||
|     IrdaAppBruteForce(const char* filename) : universal_db_filename (filename) {} | ||||
|     ~IrdaAppBruteForce() {} | ||||
|     IrdaAppBruteForce(const char* filename) | ||||
|         : universal_db_filename(filename) { | ||||
|     } | ||||
|     ~IrdaAppBruteForce() { | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| @ -9,6 +9,8 @@ public: | ||||
|         Exit, | ||||
|         Back, | ||||
|         MenuSelected, | ||||
|         MenuSelectedPress, | ||||
|         MenuSelectedRelease, | ||||
|         DialogExSelected, | ||||
|         NextScene, | ||||
|         IrdaMessageReceived, | ||||
| @ -24,4 +26,3 @@ public: | ||||
| 
 | ||||
|     Type type; | ||||
| }; | ||||
| 
 | ||||
| @ -1,6 +1,6 @@ | ||||
| #include "irda-app-file-parser.hpp" | ||||
| #include "irda-app-file-parser.h" | ||||
| #include "furi/check.h" | ||||
| #include "irda-app-remote-manager.hpp" | ||||
| #include "irda-app-remote-manager.h" | ||||
| #include "irda-app-signal.h" | ||||
| #include "m-string.h" | ||||
| #include <text-store.h> | ||||
|  | ||||
| @ -26,8 +26,16 @@ public: | ||||
|     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); | ||||
|     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; | ||||
| @ -41,4 +49,3 @@ private: | ||||
|     char file_buf[128]; | ||||
|     size_t file_buf_cnt = 0; | ||||
| }; | ||||
| 
 | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "irda-app-remote-manager.hpp" | ||||
| #include "irda-app-remote-manager.h" | ||||
| #include <storage/storage.h> | ||||
| #include "furi.h" | ||||
| #include "furi/check.h" | ||||
| @ -8,7 +8,7 @@ | ||||
| #include <stdint.h> | ||||
| #include <string> | ||||
| #include <utility> | ||||
| #include "irda-app-file-parser.hpp" | ||||
| #include "irda-app-file-parser.h" | ||||
| 
 | ||||
| static const std::string default_remote_name = "remote"; | ||||
| 
 | ||||
|  | ||||
| @ -12,21 +12,27 @@ class IrdaAppRemoteButton { | ||||
|     friend class IrdaAppRemoteManager; | ||||
|     std::string name; | ||||
|     IrdaAppSignal signal; | ||||
| 
 | ||||
| public: | ||||
|     IrdaAppRemoteButton(const char* name, const IrdaAppSignal& signal) | ||||
|         : name(name), signal (signal) {} | ||||
|     ~IrdaAppRemoteButton() {} | ||||
|         : name(name) | ||||
|         , signal(signal) { | ||||
|     } | ||||
|     ~IrdaAppRemoteButton() { | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| class IrdaAppRemote { | ||||
|     friend class IrdaAppRemoteManager; | ||||
|     std::vector<IrdaAppRemoteButton> buttons; | ||||
|     std::string name; | ||||
| public: | ||||
|     IrdaAppRemote(const std::string& name) : name(name) {} | ||||
| 
 | ||||
|     IrdaAppRemote& operator=(std::string& new_name) noexcept | ||||
|     { | ||||
| public: | ||||
|     IrdaAppRemote(const std::string& name) | ||||
|         : name(name) { | ||||
|     } | ||||
| 
 | ||||
|     IrdaAppRemote& operator=(std::string& new_name) noexcept { | ||||
|         name = new_name; | ||||
|         buttons.clear(); | ||||
|         return *this; | ||||
| @ -61,4 +67,3 @@ public: | ||||
|     bool store(); | ||||
|     bool load(const std::string& name); | ||||
| }; | ||||
| 
 | ||||
| @ -1,7 +1,7 @@ | ||||
| #include "furi.h" | ||||
| #include "gui/modules/button_panel.h" | ||||
| #include "irda-app.hpp" | ||||
| #include "irda/irda-app-event.hpp" | ||||
| #include "irda-app.h" | ||||
| #include "irda/irda-app-event.h" | ||||
| #include <callback-connector.h> | ||||
| 
 | ||||
| IrdaAppViewManager::IrdaAppViewManager() { | ||||
| @ -112,8 +112,14 @@ void IrdaAppViewManager::receive_event(IrdaAppEvent* event) { | ||||
| } | ||||
| 
 | ||||
| void IrdaAppViewManager::send_event(IrdaAppEvent* event) { | ||||
|     osStatus_t result = osMessageQueuePut(event_queue, event, 0, 0); | ||||
|     furi_check(result == osOK); | ||||
|     uint32_t timeout = 0; | ||||
|     /* Rapid button hammering on Remote Scene causes queue overflow - ignore it,
 | ||||
|      * but try to keep button release event - it switches off IRDA DMA sending. */ | ||||
|     if(event->type == IrdaAppEvent::Type::MenuSelectedRelease) { | ||||
|         timeout = 200; | ||||
|     } | ||||
|     osMessageQueuePut(event_queue, event, 0, timeout); | ||||
|     /* furi_check(result == osOK); */ | ||||
| } | ||||
| 
 | ||||
| uint32_t IrdaAppViewManager::previous_view_callback(void* context) { | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
| #include <gui/modules/dialog_ex.h> | ||||
| #include <gui/modules/submenu.h> | ||||
| #include <gui/modules/popup.h> | ||||
| #include "irda-app.hpp" | ||||
| #include "irda-app.h" | ||||
| #include "view/irda-app-brut-view.h" | ||||
| #include "gui/modules/button_panel.h" | ||||
| 
 | ||||
| @ -57,4 +57,3 @@ private: | ||||
| 
 | ||||
|     void add_view(ViewType view_type, View* view); | ||||
| }; | ||||
| 
 | ||||
| @ -1,5 +1,5 @@ | ||||
| #include "irda-app.hpp" | ||||
| #include "irda/irda-app-file-parser.hpp" | ||||
| #include "irda-app.h" | ||||
| #include "irda/irda-app-file-parser.h" | ||||
| #include <irda_worker.h> | ||||
| #include <furi.h> | ||||
| #include <gui/gui.h> | ||||
| @ -222,22 +222,33 @@ void IrdaApp::notify_click() { | ||||
|     notification_message_block(notification, &sequence); | ||||
| } | ||||
| 
 | ||||
| void IrdaApp::notify_click_and_blink() { | ||||
| void IrdaApp::notify_click_and_green_blink() { | ||||
|     static const NotificationSequence sequence = { | ||||
|         &message_click, | ||||
|         &message_delay_1, | ||||
|         &message_sound_off, | ||||
|         &message_red_0, | ||||
|         &message_green_255, | ||||
|         &message_blue_0, | ||||
|         &message_delay_10, | ||||
|         &message_green_0, | ||||
|         &message_do_not_reset, | ||||
|         NULL, | ||||
|     }; | ||||
| 
 | ||||
|     notification_message_block(notification, &sequence); | ||||
| } | ||||
| 
 | ||||
| void IrdaApp::notify_blink_green() { | ||||
|     static const NotificationSequence sequence = { | ||||
|         &message_green_255, | ||||
|         &message_delay_10, | ||||
|         &message_green_0, | ||||
|         &message_do_not_reset, | ||||
|         NULL, | ||||
|     }; | ||||
| 
 | ||||
|     notification_message(notification, &sequence); | ||||
| } | ||||
| 
 | ||||
| void IrdaApp::notify_double_vibro() { | ||||
|     notification_message(notification, &sequence_double_vibro); | ||||
| } | ||||
|  | ||||
| @ -2,17 +2,16 @@ | ||||
| #include <map> | ||||
| #include <irda.h> | ||||
| #include <furi.h> | ||||
| #include "scene/irda-app-scene.hpp" | ||||
| #include "irda-app-event.hpp" | ||||
| #include "scene/irda-app-scene.hpp" | ||||
| #include "irda-app-view-manager.hpp" | ||||
| #include "irda-app-remote-manager.hpp" | ||||
| #include "scene/irda-app-scene.h" | ||||
| #include "irda-app-event.h" | ||||
| #include "scene/irda-app-scene.h" | ||||
| #include "irda-app-view-manager.h" | ||||
| #include "irda-app-remote-manager.h" | ||||
| #include <forward_list> | ||||
| #include <stdint.h> | ||||
| #include <notification/notification-messages.h> | ||||
| #include <irda_worker.h> | ||||
| 
 | ||||
| 
 | ||||
| class IrdaApp { | ||||
| public: | ||||
|     enum class EditElement : uint8_t { | ||||
| @ -83,7 +82,8 @@ public: | ||||
|     void notify_green_on(); | ||||
|     void notify_green_off(); | ||||
|     void notify_click(); | ||||
|     void notify_click_and_blink(); | ||||
|     void notify_click_and_green_blink(); | ||||
|     void notify_blink_green(); | ||||
| 
 | ||||
|     static void text_input_callback(void* context); | ||||
|     static void popup_callback(void* context); | ||||
| @ -95,9 +95,9 @@ public: | ||||
|     ~IrdaApp() { | ||||
|         irda_worker_free(irda_worker); | ||||
|         furi_record_close("notification"); | ||||
|         for (auto &it : scenes) | ||||
|             delete it.second; | ||||
|         for(auto& it : scenes) delete it.second; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     static const uint8_t text_store_size = 128; | ||||
|     static const uint8_t text_store_max = 2; | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "irda-app.hpp" | ||||
| #include "irda-app.h" | ||||
| 
 | ||||
| extern "C" int32_t irda_app(void* p) { | ||||
|     IrdaApp* app = new IrdaApp(); | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "../irda-app.hpp" | ||||
| #include "../irda-app.h" | ||||
| 
 | ||||
| void IrdaAppSceneEditDeleteDone::on_enter(IrdaApp* app) { | ||||
|     IrdaAppViewManager* view_manager = app->get_view_manager(); | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| #include "../irda-app.hpp" | ||||
| #include "../irda-app.h" | ||||
| #include "irda.h" | ||||
| #include "irda/scene/irda-app-scene.hpp" | ||||
| #include "irda/scene/irda-app-scene.h" | ||||
| #include <string> | ||||
| 
 | ||||
| static void dialog_result_callback(DialogExResult result, void* context) { | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "../irda-app.hpp" | ||||
| #include "../irda-app.h" | ||||
| #include "gui/modules/submenu.h" | ||||
| 
 | ||||
| static void submenu_callback(void* context, uint32_t index) { | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "../irda-app.hpp" | ||||
| #include "../irda-app.h" | ||||
| 
 | ||||
| void IrdaAppSceneEditRenameDone::on_enter(IrdaApp* app) { | ||||
|     IrdaAppViewManager* view_manager = app->get_view_manager(); | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "../irda-app.hpp" | ||||
| #include "../irda-app.h" | ||||
| 
 | ||||
| void IrdaAppSceneEditRename::on_enter(IrdaApp* app) { | ||||
|     IrdaAppViewManager* view_manager = app->get_view_manager(); | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "../irda-app.hpp" | ||||
| #include "../irda-app.h" | ||||
| #include "gui/modules/submenu.h" | ||||
| 
 | ||||
| typedef enum { | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "../irda-app.hpp" | ||||
| #include "../irda-app.h" | ||||
| 
 | ||||
| void IrdaAppSceneLearnDone::on_enter(IrdaApp* app) { | ||||
|     IrdaAppViewManager* view_manager = app->get_view_manager(); | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "../irda-app.hpp" | ||||
| #include "../irda-app.h" | ||||
| #include "gui/modules/text_input.h" | ||||
| 
 | ||||
| void IrdaAppSceneLearnEnterName::on_enter(IrdaApp* app) { | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| #include "../irda-app.hpp" | ||||
| #include "../irda-app.h" | ||||
| #include "irda.h" | ||||
| #include "../irda-app-file-parser.hpp" | ||||
| #include "../irda-app-file-parser.h" | ||||
| #include <memory> | ||||
| 
 | ||||
| static void dialog_result_callback(DialogExResult result, void* context) { | ||||
| @ -51,6 +51,10 @@ void IrdaAppSceneLearnSuccess::on_enter(IrdaApp* app) { | ||||
| 
 | ||||
| bool IrdaAppSceneLearnSuccess::on_event(IrdaApp* app, IrdaAppEvent* event) { | ||||
|     bool consumed = false; | ||||
|     if(event->type == IrdaAppEvent::Type::Tick) { | ||||
|         /* Send event every tick to suppress any switching off green light */ | ||||
|         app->notify_green_on(); | ||||
|     } | ||||
| 
 | ||||
|     if(event->type == IrdaAppEvent::Type::DialogExSelected) { | ||||
|         switch(event->payload.dialog_ex_result) { | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| #include "../irda-app.hpp" | ||||
| #include "../irda-app-event.hpp" | ||||
| #include "../irda-app.h" | ||||
| #include "../irda-app-event.h" | ||||
| #include <irda_worker.h> | ||||
| 
 | ||||
| static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) { | ||||
| @ -9,7 +9,7 @@ static void signal_received_callback(void* context, IrdaWorkerSignal* received_s | ||||
|     IrdaApp* app = static_cast<IrdaApp*>(context); | ||||
| 
 | ||||
|     if(irda_worker_signal_is_decoded(received_signal)) { | ||||
|         IrdaAppSignal signal(irda_worker_get_decoded_message(received_signal)); | ||||
|         IrdaAppSignal signal(irda_worker_get_decoded_signal(received_signal)); | ||||
|         app->set_received_signal(signal); | ||||
|     } else { | ||||
|         const uint32_t* timings; | ||||
| @ -19,7 +19,7 @@ static void signal_received_callback(void* context, IrdaWorkerSignal* received_s | ||||
|         app->set_received_signal(signal); | ||||
|     } | ||||
| 
 | ||||
|     irda_worker_set_received_signal_callback(app->get_irda_worker(), NULL); | ||||
|     irda_worker_rx_set_received_signal_callback(app->get_irda_worker(), NULL, NULL); | ||||
|     IrdaAppEvent event; | ||||
|     event.type = IrdaAppEvent::Type::IrdaMessageReceived; | ||||
|     auto view_manager = app->get_view_manager(); | ||||
| @ -31,9 +31,8 @@ void IrdaAppSceneLearn::on_enter(IrdaApp* app) { | ||||
|     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); | ||||
|     irda_worker_rx_set_received_signal_callback(worker, signal_received_callback, app); | ||||
|     irda_worker_rx_start(worker); | ||||
| 
 | ||||
|     popup_set_icon(popup, 0, 32, &I_IrdaLearnShort_128x31); | ||||
|     popup_set_text( | ||||
| @ -58,11 +57,9 @@ bool IrdaAppSceneLearn::on_event(IrdaApp* app, IrdaAppEvent* event) { | ||||
|     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: | ||||
| @ -73,4 +70,5 @@ bool IrdaAppSceneLearn::on_event(IrdaApp* app, IrdaAppEvent* event) { | ||||
| } | ||||
| 
 | ||||
| void IrdaAppSceneLearn::on_exit(IrdaApp* app) { | ||||
|     irda_worker_rx_stop(app->get_irda_worker()); | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| #include "../irda-app.hpp" | ||||
| #include "irda/irda-app-event.hpp" | ||||
| #include "../irda-app.h" | ||||
| #include "irda/irda-app-event.h" | ||||
| 
 | ||||
| void IrdaAppSceneRemoteList::on_enter(IrdaApp* app) { | ||||
|     IrdaAppFileParser file_parser; | ||||
|  | ||||
| @ -1,5 +1,7 @@ | ||||
| #include "../irda-app.hpp" | ||||
| #include "../irda-app.h" | ||||
| #include "gui/modules/button_menu.h" | ||||
| #include "input/input.h" | ||||
| #include "irda_worker.h" | ||||
| 
 | ||||
| typedef enum { | ||||
|     ButtonIndexPlus = -2, | ||||
| @ -7,22 +9,41 @@ typedef enum { | ||||
|     ButtonIndexNA = 0, | ||||
| } ButtonIndex; | ||||
| 
 | ||||
| static void button_menu_callback(void* context, int32_t index) { | ||||
| static void button_menu_callback(void* context, int32_t index, InputType type) { | ||||
|     IrdaApp* app = static_cast<IrdaApp*>(context); | ||||
|     IrdaAppEvent event; | ||||
| 
 | ||||
|     if(type == InputTypePress) { | ||||
|         event.type = IrdaAppEvent::Type::MenuSelectedPress; | ||||
|     } else if(type == InputTypeRelease) { | ||||
|         event.type = IrdaAppEvent::Type::MenuSelectedRelease; | ||||
|     } else if(type == InputTypeShort) { | ||||
|         event.type = IrdaAppEvent::Type::MenuSelected; | ||||
|     } else { | ||||
|         furi_assert(0); | ||||
|     } | ||||
| 
 | ||||
|     event.payload.menu_index = index; | ||||
| 
 | ||||
|     app->get_view_manager()->send_event(&event); | ||||
| } | ||||
| 
 | ||||
| static void irda_app_message_sent_callback(void* context) { | ||||
|     IrdaApp* app = static_cast<IrdaApp*>(context); | ||||
|     app->notify_blink_green(); | ||||
| } | ||||
| 
 | ||||
| void IrdaAppSceneRemote::on_enter(IrdaApp* app) { | ||||
|     IrdaAppViewManager* view_manager = app->get_view_manager(); | ||||
|     ButtonMenu* button_menu = view_manager->get_button_menu(); | ||||
|     auto remote_manager = app->get_remote_manager(); | ||||
|     int i = 0; | ||||
|     button_pressed = false; | ||||
| 
 | ||||
|     irda_worker_tx_set_get_signal_callback( | ||||
|         app->get_irda_worker(), irda_worker_tx_get_signal_steady_callback, app); | ||||
|     irda_worker_tx_set_signal_sent_callback( | ||||
|         app->get_irda_worker(), irda_app_message_sent_callback, app); | ||||
|     buttons_names = remote_manager->get_button_list(); | ||||
| 
 | ||||
|     i = 0; | ||||
| @ -48,24 +69,49 @@ void IrdaAppSceneRemote::on_enter(IrdaApp* app) { | ||||
| bool IrdaAppSceneRemote::on_event(IrdaApp* app, IrdaAppEvent* event) { | ||||
|     bool consumed = true; | ||||
| 
 | ||||
|     if(event->type == IrdaAppEvent::Type::MenuSelected) { | ||||
|     if((event->type == IrdaAppEvent::Type::MenuSelected) || | ||||
|        (event->type == IrdaAppEvent::Type::MenuSelectedPress) || | ||||
|        (event->type == IrdaAppEvent::Type::MenuSelectedRelease)) { | ||||
|         switch(event->payload.menu_index) { | ||||
|         case ButtonIndexPlus: | ||||
|             furi_assert(event->type == IrdaAppEvent::Type::MenuSelected); | ||||
|             app->notify_click(); | ||||
|             buttonmenu_item_selected = event->payload.menu_index; | ||||
|             app->set_learn_new_remote(false); | ||||
|             app->switch_to_next_scene(IrdaApp::Scene::Learn); | ||||
|             break; | ||||
|         case ButtonIndexEdit: | ||||
|             furi_assert(event->type == IrdaAppEvent::Type::MenuSelected); | ||||
|             app->notify_click(); | ||||
|             buttonmenu_item_selected = event->payload.menu_index; | ||||
|             app->switch_to_next_scene(IrdaApp::Scene::Edit); | ||||
|             break; | ||||
|         default: | ||||
|             app->notify_click_and_blink(); | ||||
|             auto remote_manager = app->get_remote_manager(); | ||||
|             auto signal = remote_manager->get_button_data(event->payload.menu_index); | ||||
|             signal.transmit(); | ||||
|             furi_assert(event->type != IrdaAppEvent::Type::MenuSelected); | ||||
|             bool pressed = (event->type == IrdaAppEvent::Type::MenuSelectedPress); | ||||
| 
 | ||||
|             if(pressed && !button_pressed) { | ||||
|                 button_pressed = true; | ||||
|                 app->notify_click_and_green_blink(); | ||||
| 
 | ||||
|                 auto button_signal = | ||||
|                     app->get_remote_manager()->get_button_data(event->payload.menu_index); | ||||
|                 if(button_signal.is_raw()) { | ||||
|                     irda_worker_set_raw_signal( | ||||
|                         app->get_irda_worker(), | ||||
|                         button_signal.get_raw_signal().timings, | ||||
|                         button_signal.get_raw_signal().timings_cnt); | ||||
|                 } else { | ||||
|                     irda_worker_set_decoded_signal( | ||||
|                         app->get_irda_worker(), &button_signal.get_message()); | ||||
|                 } | ||||
| 
 | ||||
|                 irda_worker_tx_start(app->get_irda_worker()); | ||||
|             } else if(!pressed && button_pressed) { | ||||
|                 button_pressed = false; | ||||
|                 irda_worker_tx_stop(app->get_irda_worker()); | ||||
|                 app->notify_green_off(); | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
|     } else if(event->type == IrdaAppEvent::Type::Back) { | ||||
| @ -79,6 +125,8 @@ bool IrdaAppSceneRemote::on_event(IrdaApp* app, IrdaAppEvent* event) { | ||||
| } | ||||
| 
 | ||||
| void IrdaAppSceneRemote::on_exit(IrdaApp* app) { | ||||
|     irda_worker_tx_set_get_signal_callback(app->get_irda_worker(), nullptr, nullptr); | ||||
|     irda_worker_tx_set_signal_sent_callback(app->get_irda_worker(), nullptr, nullptr); | ||||
|     IrdaAppViewManager* view_manager = app->get_view_manager(); | ||||
|     ButtonMenu* button_menu = view_manager->get_button_menu(); | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "../irda-app.hpp" | ||||
| #include "../irda-app.h" | ||||
| 
 | ||||
| typedef enum { | ||||
|     SubmenuIndexUniversalLibrary, | ||||
|  | ||||
| @ -1,12 +1,12 @@ | ||||
| #include "../irda-app.hpp" | ||||
| #include "../irda-app.h" | ||||
| #include "assets_icons.h" | ||||
| #include "gui/modules/button_menu.h" | ||||
| #include "gui/modules/button_panel.h" | ||||
| #include "../view/irda-app-brut-view.h" | ||||
| #include "gui/view.h" | ||||
| #include "irda/irda-app-event.hpp" | ||||
| #include "irda/irda-app-view-manager.hpp" | ||||
| #include "irda/scene/irda-app-scene.hpp" | ||||
| #include "irda/irda-app-event.h" | ||||
| #include "irda/irda-app-view-manager.h" | ||||
| #include "irda/scene/irda-app-scene.h" | ||||
| 
 | ||||
| void IrdaAppSceneUniversalCommon::irda_app_item_callback(void* context, uint32_t index) { | ||||
|     IrdaApp* app = static_cast<IrdaApp*>(context); | ||||
| @ -49,10 +49,11 @@ void IrdaAppSceneUniversalCommon::show_popup(IrdaApp* app, int record_amount) { | ||||
|     button_panel_set_popup_input_callback(button_panel, irda_popup_brut_input_callback, app); | ||||
| } | ||||
| 
 | ||||
| void IrdaAppSceneUniversalCommon::progress_popup(IrdaApp* app) { | ||||
|     popup_brut_increase_progress(app->get_view_manager()->get_popup_brut()); | ||||
| bool IrdaAppSceneUniversalCommon::progress_popup(IrdaApp* app) { | ||||
|     bool result = popup_brut_increase_progress(app->get_view_manager()->get_popup_brut()); | ||||
|     auto button_panel = app->get_view_manager()->get_button_panel(); | ||||
|     with_view_model_cpp(button_panel_get_view(button_panel), void*, model, { return true; }); | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| bool IrdaAppSceneUniversalCommon::on_event(IrdaApp* app, IrdaAppEvent* event) { | ||||
| @ -63,9 +64,11 @@ 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()) { | ||||
|                 progress_popup(app); | ||||
|             } else { | ||||
|             bool result = brute_force.send_next_bruteforce(); | ||||
|             if(result) { | ||||
|                 result = progress_popup(app); | ||||
|             } | ||||
|             if(!result) { | ||||
|                 brute_force.stop_bruteforce(); | ||||
|                 brute_force_started = false; | ||||
|                 remove_popup(app); | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| #include "irda/scene/irda-app-scene.hpp" | ||||
| #include "irda/irda-app.hpp" | ||||
| #include "irda/scene/irda-app-scene.h" | ||||
| #include "irda/irda-app.h" | ||||
| 
 | ||||
| void IrdaAppSceneUniversalTV::on_enter(IrdaApp* app) { | ||||
|     IrdaAppViewManager* view_manager = app->get_view_manager(); | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "../irda-app.hpp" | ||||
| #include "../irda-app.h" | ||||
| 
 | ||||
| typedef enum { | ||||
|     SubmenuIndexUniversalTV, | ||||
|  | ||||
| @ -1,11 +1,10 @@ | ||||
| #pragma once | ||||
| #include "../irda-app-event.hpp" | ||||
| #include "../irda-app-event.h" | ||||
| #include <furi-hal-irda.h> | ||||
| #include "irda.h" | ||||
| #include <vector> | ||||
| #include <string> | ||||
| #include "../irda-app-brute-force.hpp" | ||||
| 
 | ||||
| #include "../irda-app-brute-force.h" | ||||
| 
 | ||||
| class IrdaApp; | ||||
| 
 | ||||
| @ -24,6 +23,7 @@ public: | ||||
|     void on_enter(IrdaApp* app) final; | ||||
|     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; | ||||
|     void on_exit(IrdaApp* app) final; | ||||
| 
 | ||||
| private: | ||||
|     uint32_t submenu_item_selected = 0; | ||||
| }; | ||||
| @ -33,6 +33,7 @@ public: | ||||
|     void on_enter(IrdaApp* app) final; | ||||
|     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; | ||||
|     void on_exit(IrdaApp* app) final; | ||||
| 
 | ||||
| private: | ||||
|     uint32_t submenu_item_selected = 0; | ||||
| }; | ||||
| @ -70,9 +71,11 @@ public: | ||||
|     void on_enter(IrdaApp* app) final; | ||||
|     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; | ||||
|     void on_exit(IrdaApp* app) final; | ||||
| 
 | ||||
| private: | ||||
|     std::vector<std::string> buttons_names; | ||||
|     uint32_t buttonmenu_item_selected = 0; | ||||
|     bool button_pressed = false; | ||||
| }; | ||||
| 
 | ||||
| class IrdaAppSceneRemoteList : public IrdaAppScene { | ||||
| @ -80,6 +83,7 @@ public: | ||||
|     void on_enter(IrdaApp* app) final; | ||||
|     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; | ||||
|     void on_exit(IrdaApp* app) final; | ||||
| 
 | ||||
| private: | ||||
|     uint32_t submenu_item_selected = 0; | ||||
|     std::vector<std::string> remote_names; | ||||
| @ -90,6 +94,7 @@ public: | ||||
|     void on_enter(IrdaApp* app) final; | ||||
|     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; | ||||
|     void on_exit(IrdaApp* app) final; | ||||
| 
 | ||||
| private: | ||||
|     uint32_t submenu_item_selected = 0; | ||||
| }; | ||||
| @ -99,6 +104,7 @@ public: | ||||
|     void on_enter(IrdaApp* app) final; | ||||
|     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; | ||||
|     void on_exit(IrdaApp* app) final; | ||||
| 
 | ||||
| private: | ||||
|     std::vector<std::string> buttons_names; | ||||
| }; | ||||
| @ -133,16 +139,20 @@ public: | ||||
| 
 | ||||
| class IrdaAppSceneUniversalCommon : public IrdaAppScene { | ||||
|     bool brute_force_started = false; | ||||
| 
 | ||||
| protected: | ||||
|     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; | ||||
|     void on_exit(IrdaApp* app) final; | ||||
|     IrdaAppBruteForce brute_force; | ||||
|     void remove_popup(IrdaApp* app); | ||||
|     void show_popup(IrdaApp* app, int record_amount); | ||||
|     void progress_popup(IrdaApp* app); | ||||
|     bool progress_popup(IrdaApp* app); | ||||
|     static void irda_app_item_callback(void* context, uint32_t index); | ||||
|     IrdaAppSceneUniversalCommon(const char* filename) : brute_force(filename) {} | ||||
|     ~IrdaAppSceneUniversalCommon() {} | ||||
|     IrdaAppSceneUniversalCommon(const char* filename) | ||||
|         : brute_force(filename) { | ||||
|     } | ||||
|     ~IrdaAppSceneUniversalCommon() { | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| class IrdaAppSceneUniversalTV : public IrdaAppSceneUniversalCommon { | ||||
| @ -151,13 +161,16 @@ public: | ||||
|     IrdaAppSceneUniversalTV() | ||||
|         : IrdaAppSceneUniversalCommon("/ext/irda/universal/tv.ir") { | ||||
|     } | ||||
|     ~IrdaAppSceneUniversalTV() {} | ||||
|     ~IrdaAppSceneUniversalTV() { | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| class IrdaAppSceneUniversalAudio : public IrdaAppSceneUniversalCommon { | ||||
| public: | ||||
|     void on_enter(IrdaApp* app) final; | ||||
|     IrdaAppSceneUniversalAudio() : IrdaAppSceneUniversalCommon("/ext/irda/universal/audio.ir") {} | ||||
|     ~IrdaAppSceneUniversalAudio() {} | ||||
|     IrdaAppSceneUniversalAudio() | ||||
|         : IrdaAppSceneUniversalCommon("/ext/irda/universal/audio.ir") { | ||||
|     } | ||||
|     ~IrdaAppSceneUniversalAudio() { | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| @ -15,13 +15,15 @@ struct IrdaAppPopupBrut { | ||||
|     char percents_string_storage[8]; | ||||
| }; | ||||
| 
 | ||||
| void popup_brut_increase_progress(IrdaAppPopupBrut* popup_brut) { | ||||
| bool popup_brut_increase_progress(IrdaAppPopupBrut* popup_brut) { | ||||
|     furi_assert(popup_brut); | ||||
| 
 | ||||
|     if(popup_brut->progress < popup_brut->progress_max) | ||||
|         ++popup_brut->progress; | ||||
|     else | ||||
|         furi_assert(0); | ||||
| 
 | ||||
|     return popup_brut->progress < popup_brut->progress_max; | ||||
| } | ||||
| 
 | ||||
| void popup_brut_draw_callback(Canvas* canvas, void* context) { | ||||
|  | ||||
| @ -7,7 +7,7 @@ extern "C" { | ||||
| 
 | ||||
| typedef struct IrdaAppPopupBrut IrdaAppPopupBrut; | ||||
| 
 | ||||
| void popup_brut_increase_progress(IrdaAppPopupBrut* popup_brut); | ||||
| bool popup_brut_increase_progress(IrdaAppPopupBrut* popup_brut); | ||||
| IrdaAppPopupBrut* popup_brut_alloc(); | ||||
| void popup_brut_free(IrdaAppPopupBrut* popup_brut); | ||||
| void popup_brut_draw_callback(Canvas* canvas, void* model); | ||||
|  | ||||
| @ -58,7 +58,7 @@ static void signal_received_callback(void* context, IrdaWorkerSignal* received_s | ||||
|     IrdaMonitor* irda_monitor = context; | ||||
| 
 | ||||
|     if(irda_worker_signal_is_decoded(received_signal)) { | ||||
|         const IrdaMessage* message = irda_worker_get_decoded_message(received_signal); | ||||
|         const IrdaMessage* message = irda_worker_get_decoded_signal(received_signal); | ||||
|         snprintf( | ||||
|             irda_monitor->display_text, | ||||
|             sizeof(irda_monitor->display_text), | ||||
| @ -112,10 +112,10 @@ int32_t irda_monitor_app(void* p) { | ||||
|     gui_add_view_port(gui, irda_monitor->view_port, GuiLayerFullscreen); | ||||
| 
 | ||||
|     irda_monitor->worker = irda_worker_alloc(); | ||||
|     irda_worker_set_context(irda_monitor->worker, irda_monitor); | ||||
|     irda_worker_start(irda_monitor->worker); | ||||
|     irda_worker_set_received_signal_callback(irda_monitor->worker, signal_received_callback); | ||||
|     irda_worker_enable_blink_on_receiving(irda_monitor->worker, true); | ||||
|     irda_worker_rx_start(irda_monitor->worker); | ||||
|     irda_worker_rx_set_received_signal_callback( | ||||
|         irda_monitor->worker, signal_received_callback, irda_monitor); | ||||
|     irda_worker_rx_enable_blink_on_receiving(irda_monitor->worker, true); | ||||
| 
 | ||||
|     while(1) { | ||||
|         InputEvent event; | ||||
| @ -126,7 +126,7 @@ int32_t irda_monitor_app(void* p) { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     irda_worker_stop(irda_monitor->worker); | ||||
|     irda_worker_rx_stop(irda_monitor->worker); | ||||
|     irda_worker_free(irda_monitor->worker); | ||||
|     osMessageQueueDelete(irda_monitor->event_queue); | ||||
|     view_port_enabled_set(irda_monitor->view_port, false); | ||||
|  | ||||
| @ -40,8 +40,10 @@ typedef struct{ | ||||
| 
 | ||||
| typedef struct { | ||||
|     float cycle_duration; | ||||
|     FuriHalIrdaTxGetDataCallback data_callback; | ||||
|     FuriHalIrdaTxGetDataISRCallback data_callback; | ||||
|     FuriHalIrdaTxSignalSentISRCallback signal_sent_callback; | ||||
|     void* data_context; | ||||
|     void* signal_sent_context; | ||||
|     IrdaTxBuf buffer[2]; | ||||
|     osSemaphoreId_t stop_semaphore; | ||||
| } IrdaTimTx; | ||||
| @ -175,8 +177,10 @@ void furi_hal_irda_async_rx_stop(void) { | ||||
|     furi_hal_irda_state = IrdaStateIdle; | ||||
| } | ||||
| 
 | ||||
| void furi_hal_irda_async_rx_set_timeout(uint32_t timeout_ms) { | ||||
|     LL_TIM_OC_SetCompareCH3(TIM2, timeout_ms * 1000); | ||||
| void furi_hal_irda_async_rx_set_timeout(uint32_t timeout_us) { | ||||
|     furi_assert(LL_APB1_GRP1_IsEnabledClock(LL_APB1_GRP1_PERIPH_TIM2)); | ||||
| 
 | ||||
|     LL_TIM_OC_SetCompareCH3(TIM2, timeout_us); | ||||
|     LL_TIM_OC_SetMode(TIM2, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_ACTIVE); | ||||
|     LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH3); | ||||
|     LL_TIM_EnableIT_CC3(TIM2); | ||||
| @ -287,6 +291,9 @@ static void furi_hal_irda_tx_dma_isr() { | ||||
|             /* if it's not end of the packet - continue receiving */ | ||||
|             furi_hal_irda_tx_dma_set_buffer(next_buf_num); | ||||
|         } | ||||
|         if (irda_tim_tx.signal_sent_callback) { | ||||
|             irda_tim_tx.signal_sent_callback(irda_tim_tx.signal_sent_context); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -576,9 +583,14 @@ void furi_hal_irda_async_tx_stop(void) { | ||||
|     furi_hal_irda_async_tx_wait_termination(); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_irda_async_tx_set_data_isr_callback(FuriHalIrdaTxGetDataCallback callback, void* context) { | ||||
| void furi_hal_irda_async_tx_set_data_isr_callback(FuriHalIrdaTxGetDataISRCallback callback, void* context) { | ||||
|     furi_assert(furi_hal_irda_state == IrdaStateIdle); | ||||
|     irda_tim_tx.data_callback = callback; | ||||
|     irda_tim_tx.data_context = context; | ||||
| } | ||||
| 
 | ||||
| void furi_hal_irda_async_tx_set_signal_sent_isr_callback(FuriHalIrdaTxSignalSentISRCallback callback, void* context) { | ||||
|     irda_tim_tx.signal_sent_callback = callback; | ||||
|     irda_tim_tx.signal_sent_context = context; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -14,7 +14,15 @@ typedef enum { | ||||
|     FuriHalIrdaTxGetDataStateLastDone,   /* New data obtained, and this is end of package and no more data available */ | ||||
| } FuriHalIrdaTxGetDataState; | ||||
| 
 | ||||
| typedef FuriHalIrdaTxGetDataState (*FuriHalIrdaTxGetDataCallback) (void* context, uint32_t* duration, bool* level); | ||||
| /* Callback type for providing data to IRDA DMA TX system. It is called every tim */ | ||||
| typedef FuriHalIrdaTxGetDataState (*FuriHalIrdaTxGetDataISRCallback) (void* context, uint32_t* duration, bool* level); | ||||
| 
 | ||||
| /* Callback type called every time signal is sent by DMA to Timer.
 | ||||
|  * Actually, it means there are 2 timings left to send for this signal, which is almost end. | ||||
|  * Don't use this callback to stop transmission, as far as there are next signal is | ||||
|  * charged for transmission by DMA. | ||||
|  */ | ||||
| typedef void (*FuriHalIrdaTxSignalSentISRCallback) (void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Signature of callback function for receiving continuous IRDA rx signal. | ||||
| @ -44,16 +52,15 @@ void furi_hal_irda_async_rx_start(void); | ||||
|  */ | ||||
| void furi_hal_irda_async_rx_stop(void); | ||||
| 
 | ||||
| /** Setup api hal for receiving silence timeout.
 | ||||
| /** Setup hal for receiving silence timeout.
 | ||||
|  * Should be used with 'furi_hal_irda_timeout_irq_set_callback()'. | ||||
|  * | ||||
|  * @param[in]   timeout_ms - time to wait for silence on IRDA port | ||||
|  * @param[in]   timeout_us - time to wait for silence on IRDA port | ||||
|  *                           before generating IRQ. | ||||
|  */ | ||||
| void furi_hal_irda_async_rx_set_timeout(uint32_t timeout_ms); | ||||
| void furi_hal_irda_async_rx_set_timeout(uint32_t timeout_us); | ||||
| 
 | ||||
| /**
 | ||||
|  * Setup callback for previously initialized IRDA RX interrupt. | ||||
| /** Setup callback for previously initialized IRDA RX interrupt.
 | ||||
|  * | ||||
|  * @param[in]   callback - callback to call when RX signal edge changing occurs | ||||
|  * @param[in]   ctx - context for callback | ||||
| @ -62,7 +69,7 @@ void furi_hal_irda_async_rx_set_capture_isr_callback(FuriHalIrdaRxCaptureCallbac | ||||
| 
 | ||||
| /**
 | ||||
|  * Setup callback for reaching silence timeout on IRDA port. | ||||
|  * Should setup api hal with 'furi_hal_irda_setup_rx_timeout_irq()' first. | ||||
|  * Should setup hal with 'furi_hal_irda_setup_rx_timeout_irq()' first. | ||||
|  * | ||||
|  * @param[in]   callback - callback for silence timeout | ||||
|  * @param[in]   ctx - context to pass to callback | ||||
| @ -82,7 +89,7 @@ bool furi_hal_irda_is_busy(void); | ||||
|  * @param[in]   callback - function to provide new data | ||||
|  * @param[in]   context - context for callback | ||||
|  */ | ||||
| void furi_hal_irda_async_tx_set_data_isr_callback(FuriHalIrdaTxGetDataCallback callback, void* context); | ||||
| void furi_hal_irda_async_tx_set_data_isr_callback(FuriHalIrdaTxGetDataISRCallback callback, void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Start IR asynchronous transmission. It can be stopped by 2 reasons: | ||||
| @ -115,6 +122,14 @@ void furi_hal_irda_async_tx_stop(void); | ||||
|  */ | ||||
| void furi_hal_irda_async_tx_wait_termination(void); | ||||
| 
 | ||||
| /**
 | ||||
|  * Set callback for end of signal transmission | ||||
|  * | ||||
|  * @param[in]   callback - function to call when signal is sent | ||||
|  * @param[in]   context - context for callback | ||||
|  */ | ||||
| void furi_hal_irda_async_tx_set_signal_sent_isr_callback(FuriHalIrdaTxSignalSentISRCallback callback, void* context); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -34,6 +34,8 @@ typedef struct { | ||||
|     IrdaEncoders encoder; | ||||
|     uint8_t address_length; | ||||
|     uint8_t command_length; | ||||
|     uint32_t frequency; | ||||
|     float duty_cycle; | ||||
| } IrdaProtocolImplementation; | ||||
| 
 | ||||
| struct IrdaEncoderHandler { | ||||
| @ -58,6 +60,8 @@ static const IrdaProtocolImplementation irda_protocols[] = { | ||||
|           .free = irda_encoder_nec_free}, | ||||
|       .address_length = 2, | ||||
|       .command_length = 2, | ||||
|       .frequency = IRDA_COMMON_CARRIER_FREQUENCY, | ||||
|       .duty_cycle = IRDA_COMMON_DUTY_CYCLE, | ||||
|     }, | ||||
|     // #1 - have to be after NEC
 | ||||
|     { .protocol = IrdaProtocolNECext, | ||||
| @ -74,6 +78,8 @@ static const IrdaProtocolImplementation irda_protocols[] = { | ||||
|           .free = irda_encoder_nec_free}, | ||||
|       .address_length = 4, | ||||
|       .command_length = 2, | ||||
|       .frequency = IRDA_COMMON_CARRIER_FREQUENCY, | ||||
|       .duty_cycle = IRDA_COMMON_DUTY_CYCLE, | ||||
|     }, | ||||
|     // #2
 | ||||
|     { .protocol = IrdaProtocolSamsung32, | ||||
| @ -90,6 +96,8 @@ static const IrdaProtocolImplementation irda_protocols[] = { | ||||
|           .free = irda_encoder_samsung32_free}, | ||||
|       .address_length = 2, | ||||
|       .command_length = 2, | ||||
|       .frequency = IRDA_COMMON_CARRIER_FREQUENCY, | ||||
|       .duty_cycle = IRDA_COMMON_DUTY_CYCLE, | ||||
|     }, | ||||
|     // #3
 | ||||
|     { .protocol = IrdaProtocolRC6, | ||||
| @ -106,6 +114,8 @@ static const IrdaProtocolImplementation irda_protocols[] = { | ||||
|           .free = irda_encoder_rc6_free}, | ||||
|       .address_length = 2, | ||||
|       .command_length = 2, | ||||
|       .frequency = IRDA_COMMON_CARRIER_FREQUENCY, | ||||
|       .duty_cycle = IRDA_COMMON_DUTY_CYCLE, | ||||
|     }, | ||||
| }; | ||||
| 
 | ||||
| @ -222,10 +232,12 @@ IrdaProtocol irda_get_protocol_by_name(const char* protocol_name) { | ||||
|         if (!strcmp(irda_protocols[i].name, protocol_name)) | ||||
|             return i; | ||||
|     } | ||||
|     furi_assert(0); | ||||
|     return IrdaProtocolUnknown; | ||||
| } | ||||
| 
 | ||||
| const char* irda_get_protocol_name(IrdaProtocol protocol) { | ||||
|     furi_assert(irda_is_protocol_valid(protocol)); | ||||
|     if (irda_is_protocol_valid(protocol)) | ||||
|         return irda_protocols[protocol].name; | ||||
|     else | ||||
| @ -233,6 +245,7 @@ const char* irda_get_protocol_name(IrdaProtocol protocol) { | ||||
| } | ||||
| 
 | ||||
| uint8_t irda_get_protocol_address_length(IrdaProtocol protocol) { | ||||
|     furi_assert(irda_is_protocol_valid(protocol)); | ||||
|     if (irda_is_protocol_valid(protocol)) | ||||
|         return irda_protocols[protocol].address_length; | ||||
|     else | ||||
| @ -240,9 +253,26 @@ uint8_t irda_get_protocol_address_length(IrdaProtocol protocol) { | ||||
| } | ||||
| 
 | ||||
| uint8_t irda_get_protocol_command_length(IrdaProtocol protocol) { | ||||
|     furi_assert(irda_is_protocol_valid(protocol)); | ||||
|     if (irda_is_protocol_valid(protocol)) | ||||
|         return irda_protocols[protocol].command_length; | ||||
|     else | ||||
|         return 0; | ||||
| } | ||||
| 
 | ||||
| uint32_t irda_get_protocol_frequency(IrdaProtocol protocol) { | ||||
|     furi_assert(irda_is_protocol_valid(protocol)); | ||||
|     if (irda_is_protocol_valid(protocol)) | ||||
|         return irda_protocols[protocol].frequency; | ||||
|     else | ||||
|         return 0; | ||||
| } | ||||
| 
 | ||||
| float irda_get_protocol_duty_cycle(IrdaProtocol protocol) { | ||||
|     furi_assert(irda_is_protocol_valid(protocol)); | ||||
|     if (irda_is_protocol_valid(protocol)) | ||||
|         return irda_protocols[protocol].duty_cycle; | ||||
|     else | ||||
|         return 0; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -10,6 +10,12 @@ extern "C" { | ||||
| #define IRDA_COMMON_CARRIER_FREQUENCY      38000 | ||||
| #define IRDA_COMMON_DUTY_CYCLE             0.33 | ||||
| 
 | ||||
| /* if we want to see splitted raw signals during brutforce,
 | ||||
|  * we have to have RX raw timing delay less than TX */ | ||||
| #define IRDA_RAW_RX_TIMING_DELAY_US        150000 | ||||
| #define IRDA_RAW_TX_TIMING_DELAY_US        180000 | ||||
| 
 | ||||
| 
 | ||||
| typedef struct IrdaDecoderHandler IrdaDecoderHandler; | ||||
| typedef struct IrdaEncoderHandler IrdaEncoderHandler; | ||||
| 
 | ||||
| @ -150,6 +156,24 @@ IrdaStatus irda_encode(IrdaEncoderHandler* handler, uint32_t* duration, bool* le | ||||
|  */ | ||||
| void irda_reset_encoder(IrdaEncoderHandler* handler, const IrdaMessage* message); | ||||
| 
 | ||||
| /**
 | ||||
|  * Get PWM frequency value for selected protocol | ||||
|  * | ||||
|  * \param[in]   protocol    - protocol to get from PWM frequency | ||||
|  * | ||||
|  * \return      frequency | ||||
|  */ | ||||
| uint32_t irda_get_protocol_frequency(IrdaProtocol protocol); | ||||
| 
 | ||||
| /**
 | ||||
|  * Get PWM duty cycle value for selected protocol | ||||
|  * | ||||
|  * \param[in]   protocol    - protocol to get from PWM duty cycle | ||||
|  * | ||||
|  * \return      duty cycle | ||||
|  */ | ||||
| float irda_get_protocol_duty_cycle(IrdaProtocol protocol); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -137,7 +137,8 @@ extern const IrdaCommonProtocolSpec protocol_samsung32; | ||||
| #define IRDA_RC6_BIT                        444     // half of time-quant for 1 bit
 | ||||
| #define IRDA_RC6_PREAMBLE_TOLERANCE         0.07    // percents
 | ||||
| #define IRDA_RC6_BIT_TOLERANCE              120     // us
 | ||||
| #define IRDA_RC6_SILENCE                    2700 | ||||
| /* protocol allows 2700 silence, but it is hard to send 1 message without repeat */ | ||||
| #define IRDA_RC6_SILENCE                    (2700 * 10) | ||||
| 
 | ||||
| void* irda_decoder_rc6_alloc(void); | ||||
| void irda_decoder_rc6_reset(void* decoder); | ||||
|  | ||||
| @ -23,7 +23,7 @@ FuriHalIrdaTxGetDataState irda_get_raw_data_callback (void* context, uint32_t* d | ||||
|     if (irda_tx_raw_add_silence && (irda_tx_raw_timings_index == 0)) { | ||||
|         irda_tx_raw_add_silence = false; | ||||
|         *level = false; | ||||
|         *duration = 180000;     // 180 ms delay between raw packets
 | ||||
|         *duration = IRDA_RAW_TX_TIMING_DELAY_US; | ||||
|     } else { | ||||
|         *level = irda_tx_raw_start_from_mark ^ (irda_tx_raw_timings_index % 2); | ||||
|         *duration = timings[irda_tx_raw_timings_index++]; | ||||
|  | ||||
| @ -1,18 +1,43 @@ | ||||
| #include "furi/check.h" | ||||
| #include "furi/common_defines.h" | ||||
| #include "sys/_stdint.h" | ||||
| #include "irda_worker.h" | ||||
| #include <irda.h> | ||||
| #include <furi-hal-irda.h> | ||||
| #include <limits.h> | ||||
| #include <stdint.h> | ||||
| #include <stream_buffer.h> | ||||
| #include <furi.h> | ||||
| #include <notification/notification-messages.h> | ||||
| #include <stream_buffer.h> | ||||
| 
 | ||||
| #define IRDA_WORKER_RX_TIMEOUT              IRDA_RAW_RX_TIMING_DELAY_US | ||||
| 
 | ||||
| #define MAX_TIMINGS_AMOUNT                  500 | ||||
| #define IRDA_WORKER_RX_TIMEOUT              150 // ms
 | ||||
| #define IRDA_WORKER_RX_RECEIVED             0x01 | ||||
| #define IRDA_WORKER_RX_TIMEOUT_RECEIVED     0x02 | ||||
| #define IRDA_WORKER_OVERRUN                 0x04 | ||||
| #define IRDA_WORKER_EXIT                    0x08 | ||||
| #define IRDA_WORKER_TX_FILL_BUFFER          0x10 | ||||
| #define IRDA_WORKER_TX_MESSAGE_SENT         0x20 | ||||
| 
 | ||||
| #define IRDA_WORKER_ALL_RX_EVENTS       (IRDA_WORKER_RX_RECEIVED \ | ||||
|                                         | IRDA_WORKER_RX_TIMEOUT_RECEIVED \ | ||||
|                                         | IRDA_WORKER_OVERRUN \ | ||||
|                                         | IRDA_WORKER_EXIT) | ||||
| 
 | ||||
| #define IRDA_WORKER_ALL_TX_EVENTS       (IRDA_WORKER_TX_FILL_BUFFER \ | ||||
|                                         | IRDA_WORKER_TX_MESSAGE_SENT \ | ||||
|                                         | IRDA_WORKER_EXIT) | ||||
| 
 | ||||
| #define IRDA_WORKER_ALL_EVENTS          (IRDA_WORKER_ALL_RX_EVENTS | IRDA_WORKER_ALL_TX_EVENTS) | ||||
| 
 | ||||
| typedef enum { | ||||
|     IrdaWorkerStateIdle, | ||||
|     IrdaWorkerStateRunRx, | ||||
|     IrdaWorkerStateRunTx, | ||||
|     IrdaWorkerStateWaitTxEnd, | ||||
|     IrdaWorkerStateStopTx, | ||||
|     IrdaWorkerStateStartTx, | ||||
| } IrdaWorkerState; | ||||
| 
 | ||||
| struct IrdaWorkerSignal{ | ||||
|     bool decoded; | ||||
| @ -25,37 +50,67 @@ struct IrdaWorkerSignal { | ||||
| 
 | ||||
| struct IrdaWorker { | ||||
|     FuriThread* thread; | ||||
|     IrdaDecoderHandler* irda_decoder; | ||||
|     StreamBufferHandle_t stream; | ||||
|     osEventFlagsId_t events; | ||||
| 
 | ||||
|     TaskHandle_t worker_handle; | ||||
|     IrdaWorkerSignal signal; | ||||
| 
 | ||||
|     IrdaWorkerReceivedSignalCallback received_signal_callback; | ||||
|     void* context; | ||||
|     bool blink_enable; | ||||
|     bool overrun; | ||||
|     IrdaWorkerState state; | ||||
|     IrdaEncoderHandler* irda_encoder; | ||||
|     IrdaDecoderHandler* irda_decoder; | ||||
|     NotificationApp* notification; | ||||
|     bool blink_enable; | ||||
| 
 | ||||
|     union { | ||||
|         struct { | ||||
|             IrdaWorkerGetSignalCallback get_signal_callback; | ||||
|             IrdaWorkerMessageSentCallback message_sent_callback; | ||||
|             void* get_signal_context; | ||||
|             void* message_sent_context; | ||||
|             uint32_t frequency; | ||||
|             float duty_cycle; | ||||
|             uint32_t tx_raw_cnt; | ||||
|             bool need_reinitialization; | ||||
|             bool steady_signal_sent; | ||||
|         } tx; | ||||
|         struct { | ||||
|             IrdaWorkerReceivedSignalCallback received_signal_callback; | ||||
|             void* received_signal_context; | ||||
|             bool overrun; | ||||
|         } rx; | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint32_t duration; | ||||
|     bool level; | ||||
|     FuriHalIrdaTxGetDataState state; | ||||
| } IrdaWorkerTiming; | ||||
| 
 | ||||
| static int32_t irda_worker_tx_thread(void* context); | ||||
| static FuriHalIrdaTxGetDataState irda_worker_furi_hal_data_isr_callback(void* context, uint32_t* duration, bool* level); | ||||
| static void irda_worker_furi_hal_message_sent_isr_callback(void* context); | ||||
| 
 | ||||
| 
 | ||||
| static void irda_worker_rx_timeout_callback(void* context) { | ||||
|     IrdaWorker* instance = context; | ||||
|     BaseType_t xHigherPriorityTaskWoken = pdFALSE; | ||||
|     xTaskNotifyFromISR(instance->worker_handle, IRDA_WORKER_RX_TIMEOUT_RECEIVED, eSetBits,  &xHigherPriorityTaskWoken); | ||||
|     portYIELD_FROM_ISR(xHigherPriorityTaskWoken); | ||||
|     uint32_t flags_set = osEventFlagsSet(instance->events, IRDA_WORKER_RX_TIMEOUT_RECEIVED); | ||||
|     furi_check(flags_set & IRDA_WORKER_RX_TIMEOUT_RECEIVED); | ||||
| } | ||||
| 
 | ||||
| static void irda_worker_rx_callback(void* context, bool level, uint32_t duration) { | ||||
|     IrdaWorker* instance = context; | ||||
| 
 | ||||
|     BaseType_t xHigherPriorityTaskWoken = pdFALSE; | ||||
|     furi_assert(duration != 0); | ||||
|     LevelDuration level_duration = level_duration_make(level, duration); | ||||
| 
 | ||||
|     size_t ret = | ||||
|         xStreamBufferSendFromISR(instance->stream, &level_duration, sizeof(LevelDuration), &xHigherPriorityTaskWoken); | ||||
|     uint32_t notify_value = (ret == sizeof(LevelDuration)) ? IRDA_WORKER_RX_RECEIVED : IRDA_WORKER_OVERRUN; | ||||
|     xTaskNotifyFromISR(instance->worker_handle, notify_value, eSetBits,  &xHigherPriorityTaskWoken); | ||||
|     uint32_t events = (ret == sizeof(LevelDuration)) ? IRDA_WORKER_RX_RECEIVED : IRDA_WORKER_OVERRUN; | ||||
|     portYIELD_FROM_ISR(xHigherPriorityTaskWoken); | ||||
| 
 | ||||
|     uint32_t flags_set = osEventFlagsSet(instance->events, events); | ||||
|     furi_check(flags_set & events); | ||||
| } | ||||
| 
 | ||||
| static void irda_worker_process_timeout(IrdaWorker* instance) { | ||||
| @ -63,8 +118,8 @@ static void irda_worker_process_timeout(IrdaWorker* instance) { | ||||
|         return; | ||||
| 
 | ||||
|     instance->signal.decoded = false; | ||||
|     if (instance->received_signal_callback) | ||||
|         instance->received_signal_callback(instance->context, &instance->signal); | ||||
|     if (instance->rx.received_signal_callback) | ||||
|         instance->rx.received_signal_callback(instance->rx.received_signal_context, &instance->signal); | ||||
| } | ||||
| 
 | ||||
| static void irda_worker_process_timings(IrdaWorker* instance, uint32_t duration, bool level) { | ||||
| @ -73,8 +128,8 @@ static void irda_worker_process_timings(IrdaWorker* instance, uint32_t duration, | ||||
|         instance->signal.data.message = *message_decoded; | ||||
|         instance->signal.timings_cnt = 0; | ||||
|         instance->signal.decoded = true; | ||||
|         if (instance->received_signal_callback) | ||||
|             instance->received_signal_callback(instance->context, &instance->signal); | ||||
|         if (instance->rx.received_signal_callback) | ||||
|             instance->rx.received_signal_callback(instance->rx.received_signal_context, &instance->signal); | ||||
|     } else { | ||||
|         /* Skip first timing if it's starts from Space */ | ||||
|         if ((instance->signal.timings_cnt == 0) && !level) { | ||||
| @ -85,50 +140,49 @@ static void irda_worker_process_timings(IrdaWorker* instance, uint32_t duration, | ||||
|             instance->signal.data.timings[instance->signal.timings_cnt] = duration; | ||||
|             ++instance->signal.timings_cnt; | ||||
|         } else { | ||||
|             xTaskNotify(instance->worker_handle, IRDA_WORKER_OVERRUN, eSetBits); | ||||
|             instance->overrun = true; | ||||
|             uint32_t flags_set = osEventFlagsSet(instance->events, IRDA_WORKER_OVERRUN); | ||||
|             furi_check(flags_set & IRDA_WORKER_OVERRUN); | ||||
|             instance->rx.overrun = true; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static int32_t irda_worker_thread_callback(void* context) { | ||||
|     IrdaWorker* instance = context; | ||||
|     uint32_t notify_value = 0; | ||||
| static int32_t irda_worker_rx_thread(void* thread_context) { | ||||
|     IrdaWorker* instance = thread_context; | ||||
|     uint32_t events = 0; | ||||
|     LevelDuration level_duration; | ||||
|     TickType_t last_blink_time = 0; | ||||
| 
 | ||||
|     while(1) { | ||||
|         BaseType_t result; | ||||
|         result = xTaskNotifyWait(pdFALSE, ULONG_MAX, ¬ify_value, 1000); | ||||
|         if (result != pdPASS) | ||||
|             continue; | ||||
|         events = osEventFlagsWait(instance->events, IRDA_WORKER_ALL_RX_EVENTS, 0, osWaitForever); | ||||
|         furi_check(events & IRDA_WORKER_ALL_RX_EVENTS); /* at least one caught */ | ||||
| 
 | ||||
|         if (notify_value & IRDA_WORKER_RX_RECEIVED) { | ||||
|             if (!instance->overrun && instance->blink_enable && ((xTaskGetTickCount() - last_blink_time) > 80)) { | ||||
|         if (events & IRDA_WORKER_RX_RECEIVED) { | ||||
|             if (!instance->rx.overrun && instance->blink_enable && ((xTaskGetTickCount() - last_blink_time) > 80)) { | ||||
|                 last_blink_time = xTaskGetTickCount(); | ||||
|                 notification_message(instance->notification, &sequence_blink_blue_10); | ||||
|             } | ||||
|             if (instance->signal.timings_cnt == 0) | ||||
|                 notification_message(instance->notification, &sequence_display_on); | ||||
|             while (sizeof(LevelDuration) == xStreamBufferReceive(instance->stream, &level_duration, sizeof(LevelDuration), 0)) { | ||||
|                 if (!instance->overrun) { | ||||
|                 if (!instance->rx.overrun) { | ||||
|                     bool level = level_duration_get_level(level_duration); | ||||
|                     uint32_t duration = level_duration_get_duration(level_duration); | ||||
|                     irda_worker_process_timings(instance, duration, level); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         if (notify_value & IRDA_WORKER_OVERRUN) { | ||||
|         if (events & IRDA_WORKER_OVERRUN) { | ||||
|             printf("#"); | ||||
|             irda_reset_decoder(instance->irda_decoder); | ||||
|             instance->signal.timings_cnt = 0; | ||||
|             if (instance->blink_enable) | ||||
|                 notification_message(instance->notification, &sequence_set_red_255); | ||||
|         } | ||||
|         if (notify_value & IRDA_WORKER_RX_TIMEOUT_RECEIVED) { | ||||
|             if (instance->overrun) { | ||||
|         if (events & IRDA_WORKER_RX_TIMEOUT_RECEIVED) { | ||||
|             if (instance->rx.overrun) { | ||||
|                 printf("\nOVERRUN, max samples: %d\n", MAX_TIMINGS_AMOUNT); | ||||
|                 instance->overrun = false; | ||||
|                 instance->rx.overrun = false; | ||||
|                 if (instance->blink_enable) | ||||
|                     notification_message(instance->notification, &sequence_reset_red); | ||||
|             } else { | ||||
| @ -136,16 +190,17 @@ static int32_t irda_worker_thread_callback(void* context) { | ||||
|             } | ||||
|             instance->signal.timings_cnt = 0; | ||||
|         } | ||||
|         if (notify_value & IRDA_WORKER_EXIT) | ||||
|         if (events & IRDA_WORKER_EXIT) | ||||
|             break; | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| void irda_worker_set_received_signal_callback(IrdaWorker* instance, IrdaWorkerReceivedSignalCallback callback) { | ||||
| void irda_worker_rx_set_received_signal_callback(IrdaWorker* instance, IrdaWorkerReceivedSignalCallback callback, void* context) { | ||||
|     furi_assert(instance); | ||||
|     instance->received_signal_callback = callback; | ||||
|     instance->rx.received_signal_callback = callback; | ||||
|     instance->rx.received_signal_context = context; | ||||
| } | ||||
| 
 | ||||
| IrdaWorker* irda_worker_alloc() { | ||||
| @ -155,60 +210,67 @@ IrdaWorker* irda_worker_alloc() { | ||||
|     furi_thread_set_name(instance->thread, "irda_worker"); | ||||
|     furi_thread_set_stack_size(instance->thread, 2048); | ||||
|     furi_thread_set_context(instance->thread, instance); | ||||
|     furi_thread_set_callback(instance->thread, irda_worker_thread_callback); | ||||
| 
 | ||||
|     instance->stream = xStreamBufferCreate(sizeof(LevelDuration) * 512, sizeof(LevelDuration)); | ||||
| 
 | ||||
|     size_t buffer_size = MAX(sizeof(IrdaWorkerTiming) * MAX_TIMINGS_AMOUNT, sizeof(LevelDuration) * MAX_TIMINGS_AMOUNT); | ||||
|     instance->stream = xStreamBufferCreate(buffer_size, sizeof(IrdaWorkerTiming)); | ||||
|     instance->irda_decoder = irda_alloc_decoder(); | ||||
|     instance->irda_encoder = irda_alloc_encoder(); | ||||
|     instance->blink_enable = false; | ||||
|     instance->notification = furi_record_open("notification"); | ||||
|     instance->state = IrdaWorkerStateIdle; | ||||
|     instance->events = osEventFlagsNew(NULL); | ||||
| 
 | ||||
|     return instance; | ||||
| } | ||||
| 
 | ||||
| void irda_worker_free(IrdaWorker* instance) { | ||||
|     furi_assert(instance); | ||||
|     furi_assert(!instance->worker_handle); | ||||
|     furi_assert(instance->state == IrdaWorkerStateIdle); | ||||
| 
 | ||||
|     furi_record_close("notification"); | ||||
|     irda_free_decoder(instance->irda_decoder); | ||||
|     irda_free_encoder(instance->irda_encoder); | ||||
|     vStreamBufferDelete(instance->stream); | ||||
|     furi_thread_free(instance->thread); | ||||
|     osEventFlagsDelete(instance->events); | ||||
| 
 | ||||
|     free(instance); | ||||
| } | ||||
| 
 | ||||
| void irda_worker_set_context(IrdaWorker* instance, void* context) { | ||||
| void irda_worker_rx_start(IrdaWorker* instance) { | ||||
|     furi_assert(instance); | ||||
|     instance->context = context; | ||||
| } | ||||
|     furi_assert(instance->state == IrdaWorkerStateIdle); | ||||
| 
 | ||||
| void irda_worker_start(IrdaWorker* instance) { | ||||
|     furi_assert(instance); | ||||
|     furi_assert(!instance->worker_handle); | ||||
|     xStreamBufferSetTriggerLevel(instance->stream, sizeof(LevelDuration)); | ||||
| 
 | ||||
|     osEventFlagsClear(instance->events, IRDA_WORKER_ALL_EVENTS); | ||||
|     furi_thread_set_callback(instance->thread, irda_worker_rx_thread); | ||||
|     furi_thread_start(instance->thread); | ||||
| 
 | ||||
|     instance->worker_handle = furi_thread_get_thread_id(instance->thread); | ||||
|     furi_hal_irda_async_rx_start(); | ||||
|     furi_hal_irda_async_rx_set_timeout(IRDA_WORKER_RX_TIMEOUT); | ||||
|     furi_hal_irda_async_rx_set_capture_isr_callback(irda_worker_rx_callback, instance); | ||||
|     furi_hal_irda_async_rx_set_timeout_isr_callback(irda_worker_rx_timeout_callback, instance); | ||||
|     furi_hal_irda_async_rx_start(); | ||||
|     furi_hal_irda_async_rx_set_timeout(IRDA_WORKER_RX_TIMEOUT); | ||||
| 
 | ||||
|     instance->state = IrdaWorkerStateRunRx; | ||||
| } | ||||
| 
 | ||||
| void irda_worker_stop(IrdaWorker* instance) { | ||||
| void irda_worker_rx_stop(IrdaWorker* instance) { | ||||
|     furi_assert(instance); | ||||
|     furi_assert(instance->worker_handle); | ||||
|     furi_assert(instance->state == IrdaWorkerStateRunRx); | ||||
| 
 | ||||
|     furi_hal_irda_async_rx_set_timeout_isr_callback(NULL, NULL); | ||||
|     furi_hal_irda_async_rx_set_capture_isr_callback(NULL, NULL); | ||||
|     furi_hal_irda_async_rx_stop(); | ||||
| 
 | ||||
|     xTaskNotify(instance->worker_handle, IRDA_WORKER_EXIT, eSetBits); | ||||
| 
 | ||||
|     instance->worker_handle = NULL; | ||||
| 
 | ||||
|     osEventFlagsSet(instance->events, IRDA_WORKER_EXIT); | ||||
|     furi_thread_join(instance->thread); | ||||
| 
 | ||||
|     BaseType_t xReturn = pdFAIL; | ||||
|     xReturn = xStreamBufferReset(instance->stream); | ||||
|     furi_assert(xReturn == pdPASS); | ||||
|     instance->state = IrdaWorkerStateIdle; | ||||
|     instance->state = IrdaWorkerStateIdle; | ||||
| } | ||||
| 
 | ||||
| bool irda_worker_signal_is_decoded(const IrdaWorkerSignal* signal) { | ||||
| @ -225,13 +287,268 @@ void irda_worker_get_raw_signal(const IrdaWorkerSignal* signal, const uint32_t** | ||||
|     *timings_cnt = signal->timings_cnt; | ||||
| } | ||||
| 
 | ||||
| const IrdaMessage* irda_worker_get_decoded_message(const IrdaWorkerSignal* signal) { | ||||
| const IrdaMessage* irda_worker_get_decoded_signal(const IrdaWorkerSignal* signal) { | ||||
|     furi_assert(signal); | ||||
|     return &signal->data.message; | ||||
| } | ||||
| 
 | ||||
| void irda_worker_enable_blink_on_receiving(IrdaWorker* instance, bool enable) { | ||||
| void irda_worker_rx_enable_blink_on_receiving(IrdaWorker* instance, bool enable) { | ||||
|     furi_assert(instance); | ||||
|     instance->blink_enable = enable; | ||||
| } | ||||
| 
 | ||||
| void irda_worker_tx_start(IrdaWorker* instance) { | ||||
|     furi_assert(instance); | ||||
|     furi_assert(instance->state == IrdaWorkerStateIdle); | ||||
| 
 | ||||
|     // size have to be greater than api hal irda async tx buffer size
 | ||||
|     xStreamBufferSetTriggerLevel(instance->stream, sizeof(IrdaWorkerTiming)); | ||||
| 
 | ||||
|     osEventFlagsClear(instance->events, IRDA_WORKER_ALL_EVENTS); | ||||
|     furi_thread_set_callback(instance->thread, irda_worker_tx_thread); | ||||
|     furi_thread_start(instance->thread); | ||||
| 
 | ||||
|     instance->tx.steady_signal_sent = false; | ||||
|     instance->tx.need_reinitialization = false; | ||||
|     furi_hal_irda_async_tx_set_data_isr_callback(irda_worker_furi_hal_data_isr_callback, instance); | ||||
|     furi_hal_irda_async_tx_set_signal_sent_isr_callback(irda_worker_furi_hal_message_sent_isr_callback, instance); | ||||
| 
 | ||||
|     instance->state = IrdaWorkerStateStartTx; | ||||
| } | ||||
| 
 | ||||
| static void irda_worker_furi_hal_message_sent_isr_callback(void* context) { | ||||
|     IrdaWorker* instance = context; | ||||
|     uint32_t flags_set = osEventFlagsSet(instance->events, IRDA_WORKER_TX_MESSAGE_SENT); | ||||
|     furi_check(flags_set & IRDA_WORKER_TX_MESSAGE_SENT); | ||||
| } | ||||
| 
 | ||||
| static FuriHalIrdaTxGetDataState irda_worker_furi_hal_data_isr_callback(void* context, uint32_t* duration, bool* level) { | ||||
|     furi_assert(context); | ||||
|     furi_assert(duration); | ||||
|     furi_assert(level); | ||||
| 
 | ||||
|     IrdaWorker* instance = context; | ||||
|     IrdaWorkerTiming timing = {.state = FuriHalIrdaTxGetDataStateError} ; | ||||
| 
 | ||||
|     if (sizeof(IrdaWorkerTiming) == xStreamBufferReceiveFromISR(instance->stream, &timing, sizeof(IrdaWorkerTiming), 0)) { | ||||
|         *level = timing.level; | ||||
|         *duration = timing.duration; | ||||
|         furi_assert(timing.state != FuriHalIrdaTxGetDataStateError); | ||||
|     } else { | ||||
|         furi_assert(0); | ||||
|         timing.state = FuriHalIrdaTxGetDataStateError; | ||||
|     } | ||||
| 
 | ||||
|     uint32_t flags_set = osEventFlagsSet(instance->events, IRDA_WORKER_TX_FILL_BUFFER); | ||||
|     furi_check(flags_set & IRDA_WORKER_TX_FILL_BUFFER); | ||||
| 
 | ||||
|     return timing.state; | ||||
| } | ||||
| 
 | ||||
| static bool irda_get_new_signal(IrdaWorker* instance) { | ||||
|     bool new_signal_obtained = false; | ||||
| 
 | ||||
|     IrdaWorkerGetSignalResponse response = instance->tx.get_signal_callback(instance->tx.get_signal_context, instance); | ||||
|     if (response == IrdaWorkerGetSignalResponseNew) { | ||||
|         uint32_t new_tx_frequency = 0; | ||||
|         float new_tx_duty_cycle = 0; | ||||
|         if (instance->signal.decoded) { | ||||
|             new_tx_frequency = irda_get_protocol_frequency(instance->signal.data.message.protocol); | ||||
|             new_tx_duty_cycle = irda_get_protocol_duty_cycle(instance->signal.data.message.protocol); | ||||
|         } else { | ||||
|             furi_assert(instance->signal.timings_cnt > 1); | ||||
|             new_tx_frequency = IRDA_COMMON_CARRIER_FREQUENCY; | ||||
|             new_tx_duty_cycle = IRDA_COMMON_DUTY_CYCLE; | ||||
|         } | ||||
| 
 | ||||
|         instance->tx.tx_raw_cnt = 0; | ||||
|         instance->tx.need_reinitialization = (new_tx_frequency != instance->tx.frequency) || (new_tx_duty_cycle != instance->tx.duty_cycle); | ||||
|         instance->tx.frequency = new_tx_frequency; | ||||
|         instance->tx.duty_cycle = new_tx_duty_cycle; | ||||
|         if (instance->signal.decoded) { | ||||
|             irda_reset_encoder(instance->irda_encoder, &instance->signal.data.message); | ||||
|         } | ||||
|         new_signal_obtained = true; | ||||
|     } else if (response == IrdaWorkerGetSignalResponseSame) { | ||||
|         new_signal_obtained = true; | ||||
|         /* no need to reinit */ | ||||
|     } else if (response == IrdaWorkerGetSignalResponseStop) { | ||||
|         new_signal_obtained = false; | ||||
|     } else { | ||||
|         furi_assert(0); | ||||
|     } | ||||
| 
 | ||||
|     return new_signal_obtained; | ||||
| } | ||||
| 
 | ||||
| static bool irda_worker_tx_fill_buffer(IrdaWorker* instance) { | ||||
|     bool new_data_available = true; | ||||
|     IrdaWorkerTiming timing; | ||||
|     IrdaStatus status = IrdaStatusError; | ||||
| 
 | ||||
|     while(!xStreamBufferIsFull(instance->stream) && !instance->tx.need_reinitialization && new_data_available) { | ||||
|         if (instance->signal.decoded) { | ||||
|             status = irda_encode(instance->irda_encoder, &timing.duration, &timing.level); | ||||
|         } else { | ||||
|             timing.duration = instance->signal.data.timings[instance->tx.tx_raw_cnt]; | ||||
| /* raw always starts from Mark, but we fulfill it with space delay at start */ | ||||
|             timing.level = (instance->tx.tx_raw_cnt % 2); | ||||
|             ++instance->tx.tx_raw_cnt; | ||||
|             if (instance->tx.tx_raw_cnt >= instance->signal.timings_cnt) { | ||||
|                 instance->tx.tx_raw_cnt = 0; | ||||
|                 status = IrdaStatusDone; | ||||
|             } else { | ||||
|                 status = IrdaStatusOk; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (status == IrdaStatusError) { | ||||
|             furi_assert(0); | ||||
|             new_data_available = false; | ||||
|             break; | ||||
|         } else if (status == IrdaStatusOk) { | ||||
|             timing.state = FuriHalIrdaTxGetDataStateOk; | ||||
|         } else if (status == IrdaStatusDone) { | ||||
|             timing.state = FuriHalIrdaTxGetDataStateDone; | ||||
| 
 | ||||
|             new_data_available = irda_get_new_signal(instance); | ||||
|             if (instance->tx.need_reinitialization || !new_data_available) { | ||||
|                 timing.state = FuriHalIrdaTxGetDataStateLastDone; | ||||
|             } | ||||
|         } else { | ||||
|             furi_assert(0); | ||||
|         } | ||||
|         uint32_t written_size = xStreamBufferSend(instance->stream, &timing, sizeof(IrdaWorkerTiming), 0); | ||||
|         furi_assert(sizeof(IrdaWorkerTiming) == written_size); | ||||
|     } | ||||
| 
 | ||||
|     return new_data_available; | ||||
| } | ||||
| 
 | ||||
| static int32_t irda_worker_tx_thread(void* thread_context) { | ||||
|     IrdaWorker* instance = thread_context; | ||||
|     furi_assert(instance->state == IrdaWorkerStateStartTx); | ||||
|     furi_assert(thread_context); | ||||
| 
 | ||||
|     uint32_t events = 0; | ||||
|     bool new_data_available = true; | ||||
|     bool exit = false; | ||||
| 
 | ||||
|     exit = !irda_get_new_signal(instance); | ||||
|     furi_assert(!exit); | ||||
| 
 | ||||
|     while(!exit) { | ||||
|         switch (instance->state) { | ||||
|         case IrdaWorkerStateStartTx: | ||||
|             instance->tx.need_reinitialization = false; | ||||
|             new_data_available = irda_worker_tx_fill_buffer(instance); | ||||
|             furi_hal_irda_async_tx_start(instance->tx.frequency, instance->tx.duty_cycle); | ||||
| 
 | ||||
|             if (!new_data_available) { | ||||
|                 instance->state = IrdaWorkerStateStopTx; | ||||
|             } else if (instance->tx.need_reinitialization) { | ||||
|                 instance->state = IrdaWorkerStateWaitTxEnd; | ||||
|             } else { | ||||
|                 instance->state = IrdaWorkerStateRunTx; | ||||
|             } | ||||
| 
 | ||||
|             break; | ||||
|         case IrdaWorkerStateStopTx: | ||||
|             furi_hal_irda_async_tx_stop(); | ||||
|             exit = true; | ||||
|             break; | ||||
|         case IrdaWorkerStateWaitTxEnd: | ||||
|             furi_hal_irda_async_tx_wait_termination(); | ||||
|             instance->state = IrdaWorkerStateStartTx; | ||||
| 
 | ||||
|             events = osEventFlagsGet(instance->events); | ||||
|             if(events & IRDA_WORKER_EXIT) { | ||||
|                 exit = true; | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             break; | ||||
|         case IrdaWorkerStateRunTx: | ||||
|             events = osEventFlagsWait(instance->events, IRDA_WORKER_ALL_TX_EVENTS, 0, osWaitForever); | ||||
|             furi_check(events & IRDA_WORKER_ALL_TX_EVENTS); /* at least one caught */ | ||||
| 
 | ||||
|             if (events & IRDA_WORKER_EXIT) { | ||||
|                 instance->state = IrdaWorkerStateStopTx; | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             if (events & IRDA_WORKER_TX_FILL_BUFFER) { | ||||
|                 irda_worker_tx_fill_buffer(instance); | ||||
| 
 | ||||
|                 if (instance->tx.need_reinitialization) { | ||||
|                     instance->state = IrdaWorkerStateWaitTxEnd; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (events & IRDA_WORKER_TX_MESSAGE_SENT) { | ||||
|                 if (instance->tx.message_sent_callback) | ||||
|                     instance->tx.message_sent_callback(instance->tx.message_sent_context); | ||||
|             } | ||||
|             break; | ||||
|         default: | ||||
|             furi_assert(0); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| void irda_worker_tx_set_get_signal_callback(IrdaWorker* instance, IrdaWorkerGetSignalCallback callback, void* context) { | ||||
|     furi_assert(instance); | ||||
|     instance->tx.get_signal_callback = callback; | ||||
|     instance->tx.get_signal_context = context; | ||||
| } | ||||
| 
 | ||||
| void irda_worker_tx_set_signal_sent_callback(IrdaWorker* instance, IrdaWorkerMessageSentCallback callback, void* context) { | ||||
|     furi_assert(instance); | ||||
|     instance->tx.message_sent_callback = callback; | ||||
|     instance->tx.message_sent_context = context; | ||||
| } | ||||
| 
 | ||||
| void irda_worker_tx_stop(IrdaWorker* instance) { | ||||
|     furi_assert(instance); | ||||
|     furi_assert(instance->state != IrdaWorkerStateRunRx); | ||||
| 
 | ||||
|     osEventFlagsSet(instance->events, IRDA_WORKER_EXIT); | ||||
|     furi_thread_join(instance->thread); | ||||
|     furi_hal_irda_async_tx_set_data_isr_callback(NULL, NULL); | ||||
|     furi_hal_irda_async_tx_set_signal_sent_isr_callback(NULL, NULL); | ||||
| 
 | ||||
|     instance->signal.timings_cnt = 0; | ||||
|     BaseType_t xReturn = pdFAIL; | ||||
|     xReturn = xStreamBufferReset(instance->stream); | ||||
|     furi_assert(xReturn == pdPASS); | ||||
|     instance->state = IrdaWorkerStateIdle; | ||||
| } | ||||
| 
 | ||||
| void irda_worker_set_decoded_signal(IrdaWorker* instance, const IrdaMessage* message) { | ||||
|     furi_assert(instance); | ||||
|     furi_assert(message); | ||||
| 
 | ||||
|     instance->signal.decoded = true; | ||||
|     instance->signal.data.message = *message; | ||||
| } | ||||
| 
 | ||||
| void irda_worker_set_raw_signal(IrdaWorker* instance, const uint32_t* timings, size_t timings_cnt) { | ||||
|     furi_assert(instance); | ||||
|     furi_assert(timings); | ||||
|     furi_assert(timings_cnt > 2); | ||||
| 
 | ||||
|     instance->signal.data.timings[0] = IRDA_RAW_TX_TIMING_DELAY_US; | ||||
|     memcpy(&instance->signal.data.timings[1], timings, timings_cnt * sizeof(uint32_t)); | ||||
|     instance->signal.decoded = false; | ||||
|     instance->signal.timings_cnt = timings_cnt + 1; | ||||
| } | ||||
| 
 | ||||
| IrdaWorkerGetSignalResponse irda_worker_tx_get_signal_steady_callback(void* context, IrdaWorker* instance) { | ||||
|     IrdaWorkerGetSignalResponse response = instance->tx.steady_signal_sent ? IrdaWorkerGetSignalResponseSame : IrdaWorkerGetSignalResponseNew; | ||||
|     instance->tx.steady_signal_sent = true; | ||||
|     return response; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -7,11 +7,28 @@ | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| #define MAX_TIMINGS_AMOUNT                  512 | ||||
| 
 | ||||
| /** Interface struct of irda worker */ | ||||
| typedef struct IrdaWorker IrdaWorker; | ||||
| /** Interface struct of received signal */ | ||||
| typedef struct IrdaWorkerSignal IrdaWorkerSignal; | ||||
| 
 | ||||
| typedef enum { | ||||
|     IrdaWorkerGetSignalResponseNew,     /** Signal, provided by callback is new and encoder should be reseted */ | ||||
|     IrdaWorkerGetSignalResponseSame,    /** Signal, provided by callback is same. No encoder resetting. */ | ||||
|     IrdaWorkerGetSignalResponseStop,    /** No more signals available. */ | ||||
| } IrdaWorkerGetSignalResponse; | ||||
| 
 | ||||
| /** Callback type for providing next signal to send. Should be used with
 | ||||
|  * irda_worker_make_decoded_signal() or irda_worker_make_raw_signal() | ||||
|  */ | ||||
| typedef IrdaWorkerGetSignalResponse (*IrdaWorkerGetSignalCallback)(void* context, IrdaWorker* instance); | ||||
| 
 | ||||
| /** Callback type for 'message is sent' event */ | ||||
| typedef void (*IrdaWorkerMessageSentCallback)(void* context); | ||||
| 
 | ||||
| 
 | ||||
| /** Callback type to call by IrdaWorker thread when new signal is received */ | ||||
| typedef void (*IrdaWorkerReceivedSignalCallback)(void* context, IrdaWorkerSignal* received_signal); | ||||
| 
 | ||||
| @ -27,31 +44,33 @@ IrdaWorker* irda_worker_alloc(); | ||||
|  */ | ||||
| void irda_worker_free(IrdaWorker* instance); | ||||
| 
 | ||||
| /** Received data callback IrdaWorker
 | ||||
|  * | ||||
|  * @param[in]   instance - IrdaWorker instance | ||||
|  * @param[in]   callback - IrdaWorkerReceivedSignalCallback callback | ||||
|  */ | ||||
| void irda_worker_set_received_signal_callback(IrdaWorker* instance, IrdaWorkerReceivedSignalCallback callback); | ||||
| 
 | ||||
| /** Context callback IrdaWorker
 | ||||
|  * | ||||
|  * @param[in]   instance - IrdaWorker instance | ||||
|  * @param[in]   context - context to pass to callbacks | ||||
|  */ | ||||
| void irda_worker_set_context(IrdaWorker* instance, void* context); | ||||
| 
 | ||||
| /** Start IrdaWorker thread, initialise furi-hal, prepare all work.
 | ||||
|  * | ||||
|  * @param[in]   instance - IrdaWorker instance | ||||
|  */ | ||||
| void irda_worker_start(IrdaWorker* instance); | ||||
| void irda_worker_rx_start(IrdaWorker* instance); | ||||
| 
 | ||||
| /** Stop IrdaWorker thread, deinitialize furi-hal.
 | ||||
|  * | ||||
|  * @param[in]   instance - IrdaWorker instance | ||||
|  */ | ||||
| void irda_worker_stop(IrdaWorker* instance); | ||||
| void irda_worker_rx_stop(IrdaWorker* instance); | ||||
| 
 | ||||
| /** Set received data callback IrdaWorker
 | ||||
|  * | ||||
|  * @param[in]   instance - IrdaWorker instance | ||||
|  * @param[in]   context - context to pass to callbacks | ||||
|  * @param[in]   callback - IrdaWorkerReceivedSignalCallback callback | ||||
|  */ | ||||
| void irda_worker_rx_set_received_signal_callback(IrdaWorker* instance, IrdaWorkerReceivedSignalCallback callback, void* context); | ||||
| 
 | ||||
| /** Enable blinking on receiving any signal on IR port.
 | ||||
|  * | ||||
|  * @param[in]   instance - instance of IrdaWorker | ||||
|  * @param[in]   enable - true if you want to enable blinking | ||||
|  *                       false otherwise | ||||
|  */ | ||||
| void irda_worker_rx_enable_blink_on_receiving(IrdaWorker* instance, bool enable); | ||||
| 
 | ||||
| /** Clarify is received signal either decoded or raw
 | ||||
|  * | ||||
| @ -60,6 +79,48 @@ void irda_worker_stop(IrdaWorker* instance); | ||||
|  */ | ||||
| bool irda_worker_signal_is_decoded(const IrdaWorkerSignal* signal); | ||||
| 
 | ||||
| /** Start transmitting signal. Callback IrdaWorkerGetSignalCallback should be
 | ||||
|  * set before this function is called, as it calls for it to fill buffer before | ||||
|  * starting transmission. | ||||
|  * | ||||
|  * @param[in]   instance - IrdaWorker instance | ||||
|  */ | ||||
| void irda_worker_tx_start(IrdaWorker* instance); | ||||
| 
 | ||||
| /** Stop transmitting signal. Waits for end of current signal and stops transmission.
 | ||||
|  * | ||||
|  * @param[in]   instance - IrdaWorker instance | ||||
|  */ | ||||
| void irda_worker_tx_stop(IrdaWorker* instance); | ||||
| 
 | ||||
| /** Set callback for providing next signal to send
 | ||||
|  * | ||||
|  * @param[in]   instance - IrdaWorker instance | ||||
|  * @param[in]   context - context to pass to callbacks | ||||
|  * @param[in]   callback - IrdaWorkerGetSignalCallback callback | ||||
|  */ | ||||
| void irda_worker_tx_set_get_signal_callback(IrdaWorker* instance, IrdaWorkerGetSignalCallback callback, void* context); | ||||
| 
 | ||||
| /** Set callback for end of signal transmitting
 | ||||
|  * | ||||
|  * @param[in]   instance - IrdaWorker instance | ||||
|  * @param[in]   context - context to pass to callbacks | ||||
|  * @param[in]   callback - IrdaWorkerMessageSentCallback callback | ||||
|  */ | ||||
| void irda_worker_tx_set_signal_sent_callback(IrdaWorker* instance, IrdaWorkerMessageSentCallback callback, void* context); | ||||
| 
 | ||||
| /** Callback to pass to irda_worker_tx_set_get_signal_callback() if signal
 | ||||
|  * is steady and will not be changed between irda_worker start and stop. | ||||
|  * Before starting transmission, desired steady signal must be set with | ||||
|  * irda_worker_make_decoded_signal() or irda_worker_make_raw_signal(). | ||||
|  * | ||||
|  * This function should not be implicitly called. | ||||
|  * | ||||
|  * @param[in]   context - context | ||||
|  * @param[out]  instance - IrdaWorker instance | ||||
|  */ | ||||
| IrdaWorkerGetSignalResponse irda_worker_tx_get_signal_steady_callback(void* context, IrdaWorker* instance); | ||||
| 
 | ||||
| /** Acquire raw signal from interface struct 'IrdaWorkerSignal'.
 | ||||
|  * First, you have to ensure that signal is raw. | ||||
|  * | ||||
| @ -73,17 +134,24 @@ void irda_worker_get_raw_signal(const IrdaWorkerSignal* signal, const uint32_t** | ||||
|  * First, you have to ensure that signal is decoded. | ||||
|  * | ||||
|  * @param[in]   signal - received signal | ||||
|  * @return      decoded irda message | ||||
|  * @return      decoded IRDA message | ||||
|  */ | ||||
| const IrdaMessage* irda_worker_get_decoded_message(const IrdaWorkerSignal* signal); | ||||
| const IrdaMessage* irda_worker_get_decoded_signal(const IrdaWorkerSignal* signal); | ||||
| 
 | ||||
| /** Enable blinking on receiving any signal on IR port.
 | ||||
| /** Set current decoded signal for IrdaWorker instance
 | ||||
|  * | ||||
|  * @param[in]   instance - instance of IrdaWorker | ||||
|  * @param[in]   enable - true if you want to enable blinking | ||||
|  *                       false otherwise | ||||
|  * @param[out]  instance - IrdaWorker instance | ||||
|  * @param[in]   message - decoded signal | ||||
|  */ | ||||
| void irda_worker_enable_blink_on_receiving(IrdaWorker* instance, bool enable); | ||||
| void irda_worker_set_decoded_signal(IrdaWorker* instance, const IrdaMessage* message); | ||||
| 
 | ||||
| /** Set current raw signal for IrdaWorker instance
 | ||||
|  * | ||||
|  * @param[out]  instance - IrdaWorker instance | ||||
|  * @param[in]   timings - array of raw timings | ||||
|  * @param[in]   timings_cnt - size of array of raw timings | ||||
|  */ | ||||
| void irda_worker_set_raw_signal(IrdaWorker* instance, const uint32_t* timings, size_t timings_cnt); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Albert Kharisov
						Albert Kharisov