[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 "button_menu.h" | ||||||
| #include "gui/canvas.h" | #include "gui/canvas.h" | ||||||
| #include "gui/elements.h" | #include "gui/elements.h" | ||||||
|  | #include "input/input.h" | ||||||
| #include <m-array.h> | #include <m-array.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| @ -23,6 +24,7 @@ ARRAY_DEF(ButtonMenuItemArray, ButtonMenuItem, M_POD_OPLIST); | |||||||
| 
 | 
 | ||||||
| struct ButtonMenu { | struct ButtonMenu { | ||||||
|     View* view; |     View* view; | ||||||
|  |     bool freeze_input; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef struct { | 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); |     furi_assert(button_menu); | ||||||
| 
 | 
 | ||||||
|     ButtonMenuItem* item = NULL; |     ButtonMenuItem* item = NULL; | ||||||
| @ -168,11 +170,22 @@ static void button_menu_process_ok(ButtonMenu* button_menu) { | |||||||
|             if(model->position < (ButtonMenuItemArray_size(model->items))) { |             if(model->position < (ButtonMenuItemArray_size(model->items))) { | ||||||
|                 item = ButtonMenuItemArray_get(model->items, model->position); |                 item = ButtonMenuItemArray_get(model->items, model->position); | ||||||
|             } |             } | ||||||
|             return true; |             return false; | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|  |     if(item->type == ButtonMenuItemTypeControl) { | ||||||
|  |         if(type == InputTypeShort) { | ||||||
|             if(item && item->callback) { |             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; |     ButtonMenu* button_menu = context; | ||||||
|     bool consumed = false; |     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) { |         switch(event->key) { | ||||||
|         case InputKeyUp: |         case InputKeyUp: | ||||||
|             consumed = true; |             consumed = true; | ||||||
| @ -192,10 +217,6 @@ static bool button_menu_view_input_callback(InputEvent* event, void* context) { | |||||||
|             consumed = true; |             consumed = true; | ||||||
|             button_menu_process_down(button_menu); |             button_menu_process_down(button_menu); | ||||||
|             break; |             break; | ||||||
|         case InputKeyOk: |  | ||||||
|             consumed = true; |  | ||||||
|             button_menu_process_ok(button_menu); |  | ||||||
|             break; |  | ||||||
|         default: |         default: | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @ -272,6 +293,7 @@ ButtonMenu* button_menu_alloc(void) { | |||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|  |     button_menu->freeze_input = false; | ||||||
|     return button_menu; |     return button_menu; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ typedef struct ButtonMenu ButtonMenu; | |||||||
| typedef struct ButtonMenuItem ButtonMenuItem; | typedef struct ButtonMenuItem ButtonMenuItem; | ||||||
| 
 | 
 | ||||||
| /* Callback for any button menu actions */ | /* 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. */ | /* Type of button. Difference in drawing buttons. */ | ||||||
| typedef enum { | typedef enum { | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ static void signal_received_callback(void* context, IrdaWorkerSignal* received_s | |||||||
|     Cli* cli = (Cli*)context; |     Cli* cli = (Cli*)context; | ||||||
| 
 | 
 | ||||||
|     if(irda_worker_signal_is_decoded(received_signal)) { |     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_cnt = sniprintf( | ||||||
|             buf, |             buf, | ||||||
|             sizeof(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(); |     IrdaWorker* worker = irda_worker_alloc(); | ||||||
|     irda_worker_set_context(worker, cli); |     irda_worker_rx_start(worker); | ||||||
|     irda_worker_start(worker); |     irda_worker_rx_set_received_signal_callback(worker, signal_received_callback, cli); | ||||||
|     irda_worker_set_received_signal_callback(worker, signal_received_callback); |  | ||||||
| 
 | 
 | ||||||
|     printf("Receiving IRDA...\r\nPress Ctrl+C to abort\r\n"); |     printf("Receiving IRDA...\r\nPress Ctrl+C to abort\r\n"); | ||||||
|     while(!cli_cmd_interrupt_received(cli)) { |     while(!cli_cmd_interrupt_received(cli)) { | ||||||
|         delay(50); |         delay(50); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     irda_worker_stop(worker); |     irda_worker_rx_stop(worker); | ||||||
|     irda_worker_free(worker); |     irda_worker_free(worker); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| #include "irda-app-brute-force.hpp" | #include "irda-app-brute-force.h" | ||||||
| #include "irda/irda-app-file-parser.hpp" | #include "irda/irda-app-file-parser.h" | ||||||
| #include "m-string.h" | #include "m-string.h" | ||||||
| #include <file-worker-cpp.h> | #include <file-worker-cpp.h> | ||||||
| #include <memory> | #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) { | bool IrdaAppBruteForce::send_next_bruteforce(void) { | ||||||
|     furi_assert(current_record.size()); |     furi_assert(current_record.size()); | ||||||
|     furi_assert(file_parser); |     furi_assert(file_parser); | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "furi/check.h" | #include "furi/check.h" | ||||||
| #include <unordered_map> | #include <unordered_map> | ||||||
| #include "irda-app-file-parser.hpp" | #include "irda-app-file-parser.h" | ||||||
| #include <memory> | #include <memory> | ||||||
| 
 | 
 | ||||||
| class IrdaAppBruteForce { | class IrdaAppBruteForce { | ||||||
| @ -28,7 +28,9 @@ public: | |||||||
|     bool start_bruteforce(int index, int& record_amount); |     bool start_bruteforce(int index, int& record_amount); | ||||||
|     void add_record(int index, const char* name); |     void add_record(int index, const char* name); | ||||||
| 
 | 
 | ||||||
|     IrdaAppBruteForce(const char* filename) : universal_db_filename (filename) {} |     IrdaAppBruteForce(const char* filename) | ||||||
|     ~IrdaAppBruteForce() {} |         : universal_db_filename(filename) { | ||||||
|  |     } | ||||||
|  |     ~IrdaAppBruteForce() { | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| 
 |  | ||||||
| @ -9,6 +9,8 @@ public: | |||||||
|         Exit, |         Exit, | ||||||
|         Back, |         Back, | ||||||
|         MenuSelected, |         MenuSelected, | ||||||
|  |         MenuSelectedPress, | ||||||
|  |         MenuSelectedRelease, | ||||||
|         DialogExSelected, |         DialogExSelected, | ||||||
|         NextScene, |         NextScene, | ||||||
|         IrdaMessageReceived, |         IrdaMessageReceived, | ||||||
| @ -24,4 +26,3 @@ public: | |||||||
| 
 | 
 | ||||||
|     Type type; |     Type type; | ||||||
| }; | }; | ||||||
| 
 |  | ||||||
| @ -1,6 +1,6 @@ | |||||||
| #include "irda-app-file-parser.hpp" | #include "irda-app-file-parser.h" | ||||||
| #include "furi/check.h" | #include "furi/check.h" | ||||||
| #include "irda-app-remote-manager.hpp" | #include "irda-app-remote-manager.h" | ||||||
| #include "irda-app-signal.h" | #include "irda-app-signal.h" | ||||||
| #include "m-string.h" | #include "m-string.h" | ||||||
| #include <text-store.h> | #include <text-store.h> | ||||||
|  | |||||||
| @ -26,8 +26,16 @@ public: | |||||||
|     std::string make_name(const std::string& full_name) const; |     std::string make_name(const std::string& full_name) const; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     size_t stringify_message(const IrdaAppSignal& signal, const char* name, char* content, size_t content_len); |     size_t stringify_message( | ||||||
|     size_t stringify_raw_signal(const IrdaAppSignal& signal, const char* name, char* content, size_t content_len); |         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(const std::string& str) const; | ||||||
|     std::unique_ptr<IrdaFileSignal> parse_signal_raw(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; |     std::string make_full_name(const std::string& name) const; | ||||||
| @ -41,4 +49,3 @@ private: | |||||||
|     char file_buf[128]; |     char file_buf[128]; | ||||||
|     size_t file_buf_cnt = 0; |     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 <storage/storage.h> | ||||||
| #include "furi.h" | #include "furi.h" | ||||||
| #include "furi/check.h" | #include "furi/check.h" | ||||||
| @ -8,7 +8,7 @@ | |||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <string> | #include <string> | ||||||
| #include <utility> | #include <utility> | ||||||
| #include "irda-app-file-parser.hpp" | #include "irda-app-file-parser.h" | ||||||
| 
 | 
 | ||||||
| static const std::string default_remote_name = "remote"; | static const std::string default_remote_name = "remote"; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -12,21 +12,27 @@ class IrdaAppRemoteButton { | |||||||
|     friend class IrdaAppRemoteManager; |     friend class IrdaAppRemoteManager; | ||||||
|     std::string name; |     std::string name; | ||||||
|     IrdaAppSignal signal; |     IrdaAppSignal signal; | ||||||
|  | 
 | ||||||
| public: | public: | ||||||
|     IrdaAppRemoteButton(const char* name, const IrdaAppSignal& signal) |     IrdaAppRemoteButton(const char* name, const IrdaAppSignal& signal) | ||||||
|         : name(name), signal (signal) {} |         : name(name) | ||||||
|     ~IrdaAppRemoteButton() {} |         , signal(signal) { | ||||||
|  |     } | ||||||
|  |     ~IrdaAppRemoteButton() { | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class IrdaAppRemote { | class IrdaAppRemote { | ||||||
|     friend class IrdaAppRemoteManager; |     friend class IrdaAppRemoteManager; | ||||||
|     std::vector<IrdaAppRemoteButton> buttons; |     std::vector<IrdaAppRemoteButton> buttons; | ||||||
|     std::string name; |     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; |         name = new_name; | ||||||
|         buttons.clear(); |         buttons.clear(); | ||||||
|         return *this; |         return *this; | ||||||
| @ -61,4 +67,3 @@ public: | |||||||
|     bool store(); |     bool store(); | ||||||
|     bool load(const std::string& name); |     bool load(const std::string& name); | ||||||
| }; | }; | ||||||
| 
 |  | ||||||
| @ -1,7 +1,7 @@ | |||||||
| #include "furi.h" | #include "furi.h" | ||||||
| #include "gui/modules/button_panel.h" | #include "gui/modules/button_panel.h" | ||||||
| #include "irda-app.hpp" | #include "irda-app.h" | ||||||
| #include "irda/irda-app-event.hpp" | #include "irda/irda-app-event.h" | ||||||
| #include <callback-connector.h> | #include <callback-connector.h> | ||||||
| 
 | 
 | ||||||
| IrdaAppViewManager::IrdaAppViewManager() { | IrdaAppViewManager::IrdaAppViewManager() { | ||||||
| @ -112,8 +112,14 @@ void IrdaAppViewManager::receive_event(IrdaAppEvent* event) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IrdaAppViewManager::send_event(IrdaAppEvent* event) { | void IrdaAppViewManager::send_event(IrdaAppEvent* event) { | ||||||
|     osStatus_t result = osMessageQueuePut(event_queue, event, 0, 0); |     uint32_t timeout = 0; | ||||||
|     furi_check(result == osOK); |     /* 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) { | uint32_t IrdaAppViewManager::previous_view_callback(void* context) { | ||||||
|  | |||||||
| @ -6,7 +6,7 @@ | |||||||
| #include <gui/modules/dialog_ex.h> | #include <gui/modules/dialog_ex.h> | ||||||
| #include <gui/modules/submenu.h> | #include <gui/modules/submenu.h> | ||||||
| #include <gui/modules/popup.h> | #include <gui/modules/popup.h> | ||||||
| #include "irda-app.hpp" | #include "irda-app.h" | ||||||
| #include "view/irda-app-brut-view.h" | #include "view/irda-app-brut-view.h" | ||||||
| #include "gui/modules/button_panel.h" | #include "gui/modules/button_panel.h" | ||||||
| 
 | 
 | ||||||
| @ -57,4 +57,3 @@ private: | |||||||
| 
 | 
 | ||||||
|     void add_view(ViewType view_type, View* view); |     void add_view(ViewType view_type, View* view); | ||||||
| }; | }; | ||||||
| 
 |  | ||||||
| @ -1,5 +1,5 @@ | |||||||
| #include "irda-app.hpp" | #include "irda-app.h" | ||||||
| #include "irda/irda-app-file-parser.hpp" | #include "irda/irda-app-file-parser.h" | ||||||
| #include <irda_worker.h> | #include <irda_worker.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| @ -222,22 +222,33 @@ void IrdaApp::notify_click() { | |||||||
|     notification_message_block(notification, &sequence); |     notification_message_block(notification, &sequence); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IrdaApp::notify_click_and_blink() { | void IrdaApp::notify_click_and_green_blink() { | ||||||
|     static const NotificationSequence sequence = { |     static const NotificationSequence sequence = { | ||||||
|         &message_click, |         &message_click, | ||||||
|         &message_delay_1, |         &message_delay_1, | ||||||
|         &message_sound_off, |         &message_sound_off, | ||||||
|         &message_red_0, |  | ||||||
|         &message_green_255, |         &message_green_255, | ||||||
|         &message_blue_0, |  | ||||||
|         &message_delay_10, |         &message_delay_10, | ||||||
|         &message_green_0, |         &message_green_0, | ||||||
|  |         &message_do_not_reset, | ||||||
|         NULL, |         NULL, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     notification_message_block(notification, &sequence); |     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() { | void IrdaApp::notify_double_vibro() { | ||||||
|     notification_message(notification, &sequence_double_vibro); |     notification_message(notification, &sequence_double_vibro); | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,17 +2,16 @@ | |||||||
| #include <map> | #include <map> | ||||||
| #include <irda.h> | #include <irda.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include "scene/irda-app-scene.hpp" | #include "scene/irda-app-scene.h" | ||||||
| #include "irda-app-event.hpp" | #include "irda-app-event.h" | ||||||
| #include "scene/irda-app-scene.hpp" | #include "scene/irda-app-scene.h" | ||||||
| #include "irda-app-view-manager.hpp" | #include "irda-app-view-manager.h" | ||||||
| #include "irda-app-remote-manager.hpp" | #include "irda-app-remote-manager.h" | ||||||
| #include <forward_list> | #include <forward_list> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <notification/notification-messages.h> | #include <notification/notification-messages.h> | ||||||
| #include <irda_worker.h> | #include <irda_worker.h> | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| class IrdaApp { | class IrdaApp { | ||||||
| public: | public: | ||||||
|     enum class EditElement : uint8_t { |     enum class EditElement : uint8_t { | ||||||
| @ -83,7 +82,8 @@ public: | |||||||
|     void notify_green_on(); |     void notify_green_on(); | ||||||
|     void notify_green_off(); |     void notify_green_off(); | ||||||
|     void notify_click(); |     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 text_input_callback(void* context); | ||||||
|     static void popup_callback(void* context); |     static void popup_callback(void* context); | ||||||
| @ -95,9 +95,9 @@ public: | |||||||
|     ~IrdaApp() { |     ~IrdaApp() { | ||||||
|         irda_worker_free(irda_worker); |         irda_worker_free(irda_worker); | ||||||
|         furi_record_close("notification"); |         furi_record_close("notification"); | ||||||
|         for (auto &it : scenes) |         for(auto& it : scenes) delete it.second; | ||||||
|             delete it.second; |  | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     static const uint8_t text_store_size = 128; |     static const uint8_t text_store_size = 128; | ||||||
|     static const uint8_t text_store_max = 2; |     static const uint8_t text_store_max = 2; | ||||||
| @ -120,7 +120,7 @@ private: | |||||||
|         {Scene::Start, new IrdaAppSceneStart()}, |         {Scene::Start, new IrdaAppSceneStart()}, | ||||||
|         {Scene::Universal, new IrdaAppSceneUniversal()}, |         {Scene::Universal, new IrdaAppSceneUniversal()}, | ||||||
|         {Scene::UniversalTV, new IrdaAppSceneUniversalTV()}, |         {Scene::UniversalTV, new IrdaAppSceneUniversalTV()}, | ||||||
| //        {Scene::UniversalAudio, new IrdaAppSceneUniversalAudio()},
 |         //        {Scene::UniversalAudio, new IrdaAppSceneUniversalAudio()},
 | ||||||
|         {Scene::Learn, new IrdaAppSceneLearn()}, |         {Scene::Learn, new IrdaAppSceneLearn()}, | ||||||
|         {Scene::LearnSuccess, new IrdaAppSceneLearnSuccess()}, |         {Scene::LearnSuccess, new IrdaAppSceneLearnSuccess()}, | ||||||
|         {Scene::LearnEnterName, new IrdaAppSceneLearnEnterName()}, |         {Scene::LearnEnterName, new IrdaAppSceneLearnEnterName()}, | ||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "irda-app.hpp" | #include "irda-app.h" | ||||||
| 
 | 
 | ||||||
| extern "C" int32_t irda_app(void* p) { | extern "C" int32_t irda_app(void* p) { | ||||||
|     IrdaApp* app = new IrdaApp(); |     IrdaApp* app = new IrdaApp(); | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "../irda-app.hpp" | #include "../irda-app.h" | ||||||
| 
 | 
 | ||||||
| void IrdaAppSceneEditDeleteDone::on_enter(IrdaApp* app) { | void IrdaAppSceneEditDeleteDone::on_enter(IrdaApp* app) { | ||||||
|     IrdaAppViewManager* view_manager = app->get_view_manager(); |     IrdaAppViewManager* view_manager = app->get_view_manager(); | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| #include "../irda-app.hpp" | #include "../irda-app.h" | ||||||
| #include "irda.h" | #include "irda.h" | ||||||
| #include "irda/scene/irda-app-scene.hpp" | #include "irda/scene/irda-app-scene.h" | ||||||
| #include <string> | #include <string> | ||||||
| 
 | 
 | ||||||
| static void dialog_result_callback(DialogExResult result, void* context) { | 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" | #include "gui/modules/submenu.h" | ||||||
| 
 | 
 | ||||||
| static void submenu_callback(void* context, uint32_t index) { | 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) { | void IrdaAppSceneEditRenameDone::on_enter(IrdaApp* app) { | ||||||
|     IrdaAppViewManager* view_manager = app->get_view_manager(); |     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) { | void IrdaAppSceneEditRename::on_enter(IrdaApp* app) { | ||||||
|     IrdaAppViewManager* view_manager = app->get_view_manager(); |     IrdaAppViewManager* view_manager = app->get_view_manager(); | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "../irda-app.hpp" | #include "../irda-app.h" | ||||||
| #include "gui/modules/submenu.h" | #include "gui/modules/submenu.h" | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "../irda-app.hpp" | #include "../irda-app.h" | ||||||
| 
 | 
 | ||||||
| void IrdaAppSceneLearnDone::on_enter(IrdaApp* app) { | void IrdaAppSceneLearnDone::on_enter(IrdaApp* app) { | ||||||
|     IrdaAppViewManager* view_manager = app->get_view_manager(); |     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" | #include "gui/modules/text_input.h" | ||||||
| 
 | 
 | ||||||
| void IrdaAppSceneLearnEnterName::on_enter(IrdaApp* app) { | void IrdaAppSceneLearnEnterName::on_enter(IrdaApp* app) { | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| #include "../irda-app.hpp" | #include "../irda-app.h" | ||||||
| #include "irda.h" | #include "irda.h" | ||||||
| #include "../irda-app-file-parser.hpp" | #include "../irda-app-file-parser.h" | ||||||
| #include <memory> | #include <memory> | ||||||
| 
 | 
 | ||||||
| static void dialog_result_callback(DialogExResult result, void* context) { | static void dialog_result_callback(DialogExResult result, void* context) { | ||||||
| @ -51,6 +51,10 @@ void IrdaAppSceneLearnSuccess::on_enter(IrdaApp* app) { | |||||||
| 
 | 
 | ||||||
| bool IrdaAppSceneLearnSuccess::on_event(IrdaApp* app, IrdaAppEvent* event) { | bool IrdaAppSceneLearnSuccess::on_event(IrdaApp* app, IrdaAppEvent* event) { | ||||||
|     bool consumed = false; |     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) { |     if(event->type == IrdaAppEvent::Type::DialogExSelected) { | ||||||
|         switch(event->payload.dialog_ex_result) { |         switch(event->payload.dialog_ex_result) { | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| #include "../irda-app.hpp" | #include "../irda-app.h" | ||||||
| #include "../irda-app-event.hpp" | #include "../irda-app-event.h" | ||||||
| #include <irda_worker.h> | #include <irda_worker.h> | ||||||
| 
 | 
 | ||||||
| static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) { | static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) { | ||||||
| @ -9,7 +9,7 @@ static void signal_received_callback(void* context, IrdaWorkerSignal* received_s | |||||||
|     IrdaApp* app = static_cast<IrdaApp*>(context); |     IrdaApp* app = static_cast<IrdaApp*>(context); | ||||||
| 
 | 
 | ||||||
|     if(irda_worker_signal_is_decoded(received_signal)) { |     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); |         app->set_received_signal(signal); | ||||||
|     } else { |     } else { | ||||||
|         const uint32_t* timings; |         const uint32_t* timings; | ||||||
| @ -19,7 +19,7 @@ static void signal_received_callback(void* context, IrdaWorkerSignal* received_s | |||||||
|         app->set_received_signal(signal); |         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; |     IrdaAppEvent event; | ||||||
|     event.type = IrdaAppEvent::Type::IrdaMessageReceived; |     event.type = IrdaAppEvent::Type::IrdaMessageReceived; | ||||||
|     auto view_manager = app->get_view_manager(); |     auto view_manager = app->get_view_manager(); | ||||||
| @ -31,9 +31,8 @@ void IrdaAppSceneLearn::on_enter(IrdaApp* app) { | |||||||
|     auto popup = view_manager->get_popup(); |     auto popup = view_manager->get_popup(); | ||||||
| 
 | 
 | ||||||
|     auto worker = app->get_irda_worker(); |     auto worker = app->get_irda_worker(); | ||||||
|     irda_worker_set_context(worker, app); |     irda_worker_rx_set_received_signal_callback(worker, signal_received_callback, app); | ||||||
|     irda_worker_set_received_signal_callback(worker, signal_received_callback); |     irda_worker_rx_start(worker); | ||||||
|     irda_worker_start(worker); |  | ||||||
| 
 | 
 | ||||||
|     popup_set_icon(popup, 0, 32, &I_IrdaLearnShort_128x31); |     popup_set_icon(popup, 0, 32, &I_IrdaLearnShort_128x31); | ||||||
|     popup_set_text( |     popup_set_text( | ||||||
| @ -58,11 +57,9 @@ bool IrdaAppSceneLearn::on_event(IrdaApp* app, IrdaAppEvent* event) { | |||||||
|     case IrdaAppEvent::Type::IrdaMessageReceived: |     case IrdaAppEvent::Type::IrdaMessageReceived: | ||||||
|         app->notify_success(); |         app->notify_success(); | ||||||
|         app->switch_to_next_scene_without_saving(IrdaApp::Scene::LearnSuccess); |         app->switch_to_next_scene_without_saving(IrdaApp::Scene::LearnSuccess); | ||||||
|         irda_worker_stop(app->get_irda_worker()); |  | ||||||
|         break; |         break; | ||||||
|     case IrdaAppEvent::Type::Back: |     case IrdaAppEvent::Type::Back: | ||||||
|         consumed = true; |         consumed = true; | ||||||
|         irda_worker_stop(app->get_irda_worker()); |  | ||||||
|         app->switch_to_previous_scene(); |         app->switch_to_previous_scene(); | ||||||
|         break; |         break; | ||||||
|     default: |     default: | ||||||
| @ -73,4 +70,5 @@ bool IrdaAppSceneLearn::on_event(IrdaApp* app, IrdaAppEvent* event) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IrdaAppSceneLearn::on_exit(IrdaApp* app) { | void IrdaAppSceneLearn::on_exit(IrdaApp* app) { | ||||||
|  |     irda_worker_rx_stop(app->get_irda_worker()); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| #include "../irda-app.hpp" | #include "../irda-app.h" | ||||||
| #include "irda/irda-app-event.hpp" | #include "irda/irda-app-event.h" | ||||||
| 
 | 
 | ||||||
| void IrdaAppSceneRemoteList::on_enter(IrdaApp* app) { | void IrdaAppSceneRemoteList::on_enter(IrdaApp* app) { | ||||||
|     IrdaAppFileParser file_parser; |     IrdaAppFileParser file_parser; | ||||||
|  | |||||||
| @ -1,5 +1,7 @@ | |||||||
| #include "../irda-app.hpp" | #include "../irda-app.h" | ||||||
| #include "gui/modules/button_menu.h" | #include "gui/modules/button_menu.h" | ||||||
|  | #include "input/input.h" | ||||||
|  | #include "irda_worker.h" | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     ButtonIndexPlus = -2, |     ButtonIndexPlus = -2, | ||||||
| @ -7,22 +9,41 @@ typedef enum { | |||||||
|     ButtonIndexNA = 0, |     ButtonIndexNA = 0, | ||||||
| } ButtonIndex; | } 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); |     IrdaApp* app = static_cast<IrdaApp*>(context); | ||||||
|     IrdaAppEvent event; |     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; |         event.type = IrdaAppEvent::Type::MenuSelected; | ||||||
|  |     } else { | ||||||
|  |         furi_assert(0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     event.payload.menu_index = index; |     event.payload.menu_index = index; | ||||||
| 
 | 
 | ||||||
|     app->get_view_manager()->send_event(&event); |     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) { | void IrdaAppSceneRemote::on_enter(IrdaApp* app) { | ||||||
|     IrdaAppViewManager* view_manager = app->get_view_manager(); |     IrdaAppViewManager* view_manager = app->get_view_manager(); | ||||||
|     ButtonMenu* button_menu = view_manager->get_button_menu(); |     ButtonMenu* button_menu = view_manager->get_button_menu(); | ||||||
|     auto remote_manager = app->get_remote_manager(); |     auto remote_manager = app->get_remote_manager(); | ||||||
|     int i = 0; |     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(); |     buttons_names = remote_manager->get_button_list(); | ||||||
| 
 | 
 | ||||||
|     i = 0; |     i = 0; | ||||||
| @ -48,24 +69,49 @@ void IrdaAppSceneRemote::on_enter(IrdaApp* app) { | |||||||
| bool IrdaAppSceneRemote::on_event(IrdaApp* app, IrdaAppEvent* event) { | bool IrdaAppSceneRemote::on_event(IrdaApp* app, IrdaAppEvent* event) { | ||||||
|     bool consumed = true; |     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) { |         switch(event->payload.menu_index) { | ||||||
|         case ButtonIndexPlus: |         case ButtonIndexPlus: | ||||||
|  |             furi_assert(event->type == IrdaAppEvent::Type::MenuSelected); | ||||||
|             app->notify_click(); |             app->notify_click(); | ||||||
|             buttonmenu_item_selected = event->payload.menu_index; |             buttonmenu_item_selected = event->payload.menu_index; | ||||||
|             app->set_learn_new_remote(false); |             app->set_learn_new_remote(false); | ||||||
|             app->switch_to_next_scene(IrdaApp::Scene::Learn); |             app->switch_to_next_scene(IrdaApp::Scene::Learn); | ||||||
|             break; |             break; | ||||||
|         case ButtonIndexEdit: |         case ButtonIndexEdit: | ||||||
|  |             furi_assert(event->type == IrdaAppEvent::Type::MenuSelected); | ||||||
|             app->notify_click(); |             app->notify_click(); | ||||||
|             buttonmenu_item_selected = event->payload.menu_index; |             buttonmenu_item_selected = event->payload.menu_index; | ||||||
|             app->switch_to_next_scene(IrdaApp::Scene::Edit); |             app->switch_to_next_scene(IrdaApp::Scene::Edit); | ||||||
|             break; |             break; | ||||||
|         default: |         default: | ||||||
|             app->notify_click_and_blink(); |             furi_assert(event->type != IrdaAppEvent::Type::MenuSelected); | ||||||
|             auto remote_manager = app->get_remote_manager(); |             bool pressed = (event->type == IrdaAppEvent::Type::MenuSelectedPress); | ||||||
|             auto signal = remote_manager->get_button_data(event->payload.menu_index); | 
 | ||||||
|             signal.transmit(); |             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; |             break; | ||||||
|         } |         } | ||||||
|     } else if(event->type == IrdaAppEvent::Type::Back) { |     } 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) { | 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(); |     IrdaAppViewManager* view_manager = app->get_view_manager(); | ||||||
|     ButtonMenu* button_menu = view_manager->get_button_menu(); |     ButtonMenu* button_menu = view_manager->get_button_menu(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "../irda-app.hpp" | #include "../irda-app.h" | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubmenuIndexUniversalLibrary, |     SubmenuIndexUniversalLibrary, | ||||||
|  | |||||||
| @ -1,12 +1,12 @@ | |||||||
| #include "../irda-app.hpp" | #include "../irda-app.h" | ||||||
| #include "assets_icons.h" | #include "assets_icons.h" | ||||||
| #include "gui/modules/button_menu.h" | #include "gui/modules/button_menu.h" | ||||||
| #include "gui/modules/button_panel.h" | #include "gui/modules/button_panel.h" | ||||||
| #include "../view/irda-app-brut-view.h" | #include "../view/irda-app-brut-view.h" | ||||||
| #include "gui/view.h" | #include "gui/view.h" | ||||||
| #include "irda/irda-app-event.hpp" | #include "irda/irda-app-event.h" | ||||||
| #include "irda/irda-app-view-manager.hpp" | #include "irda/irda-app-view-manager.h" | ||||||
| #include "irda/scene/irda-app-scene.hpp" | #include "irda/scene/irda-app-scene.h" | ||||||
| 
 | 
 | ||||||
| void IrdaAppSceneUniversalCommon::irda_app_item_callback(void* context, uint32_t index) { | void IrdaAppSceneUniversalCommon::irda_app_item_callback(void* context, uint32_t index) { | ||||||
|     IrdaApp* app = static_cast<IrdaApp*>(context); |     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); |     button_panel_set_popup_input_callback(button_panel, irda_popup_brut_input_callback, app); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IrdaAppSceneUniversalCommon::progress_popup(IrdaApp* app) { | bool IrdaAppSceneUniversalCommon::progress_popup(IrdaApp* app) { | ||||||
|     popup_brut_increase_progress(app->get_view_manager()->get_popup_brut()); |     bool result = popup_brut_increase_progress(app->get_view_manager()->get_popup_brut()); | ||||||
|     auto button_panel = app->get_view_manager()->get_button_panel(); |     auto button_panel = app->get_view_manager()->get_button_panel(); | ||||||
|     with_view_model_cpp(button_panel_get_view(button_panel), void*, model, { return true; }); |     with_view_model_cpp(button_panel_get_view(button_panel), void*, model, { return true; }); | ||||||
|  |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool IrdaAppSceneUniversalCommon::on_event(IrdaApp* app, IrdaAppEvent* event) { | 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(); |             auto view_manager = app->get_view_manager(); | ||||||
|             IrdaAppEvent tick_event = {.type = IrdaAppEvent::Type::Tick}; |             IrdaAppEvent tick_event = {.type = IrdaAppEvent::Type::Tick}; | ||||||
|             view_manager->send_event(&tick_event); |             view_manager->send_event(&tick_event); | ||||||
|             if(brute_force.send_next_bruteforce()) { |             bool result = brute_force.send_next_bruteforce(); | ||||||
|                 progress_popup(app); |             if(result) { | ||||||
|             } else { |                 result = progress_popup(app); | ||||||
|  |             } | ||||||
|  |             if(!result) { | ||||||
|                 brute_force.stop_bruteforce(); |                 brute_force.stop_bruteforce(); | ||||||
|                 brute_force_started = false; |                 brute_force_started = false; | ||||||
|                 remove_popup(app); |                 remove_popup(app); | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| #include "irda/scene/irda-app-scene.hpp" | #include "irda/scene/irda-app-scene.h" | ||||||
| #include "irda/irda-app.hpp" | #include "irda/irda-app.h" | ||||||
| 
 | 
 | ||||||
| void IrdaAppSceneUniversalTV::on_enter(IrdaApp* app) { | void IrdaAppSceneUniversalTV::on_enter(IrdaApp* app) { | ||||||
|     IrdaAppViewManager* view_manager = app->get_view_manager(); |     IrdaAppViewManager* view_manager = app->get_view_manager(); | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "../irda-app.hpp" | #include "../irda-app.h" | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubmenuIndexUniversalTV, |     SubmenuIndexUniversalTV, | ||||||
|  | |||||||
| @ -1,11 +1,10 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "../irda-app-event.hpp" | #include "../irda-app-event.h" | ||||||
| #include <furi-hal-irda.h> | #include <furi-hal-irda.h> | ||||||
| #include "irda.h" | #include "irda.h" | ||||||
| #include <vector> | #include <vector> | ||||||
| #include <string> | #include <string> | ||||||
| #include "../irda-app-brute-force.hpp" | #include "../irda-app-brute-force.h" | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| class IrdaApp; | class IrdaApp; | ||||||
| 
 | 
 | ||||||
| @ -24,6 +23,7 @@ public: | |||||||
|     void on_enter(IrdaApp* app) final; |     void on_enter(IrdaApp* app) final; | ||||||
|     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; |     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; | ||||||
|     void on_exit(IrdaApp* app) final; |     void on_exit(IrdaApp* app) final; | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     uint32_t submenu_item_selected = 0; |     uint32_t submenu_item_selected = 0; | ||||||
| }; | }; | ||||||
| @ -33,6 +33,7 @@ public: | |||||||
|     void on_enter(IrdaApp* app) final; |     void on_enter(IrdaApp* app) final; | ||||||
|     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; |     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; | ||||||
|     void on_exit(IrdaApp* app) final; |     void on_exit(IrdaApp* app) final; | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     uint32_t submenu_item_selected = 0; |     uint32_t submenu_item_selected = 0; | ||||||
| }; | }; | ||||||
| @ -70,9 +71,11 @@ public: | |||||||
|     void on_enter(IrdaApp* app) final; |     void on_enter(IrdaApp* app) final; | ||||||
|     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; |     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; | ||||||
|     void on_exit(IrdaApp* app) final; |     void on_exit(IrdaApp* app) final; | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     std::vector<std::string> buttons_names; |     std::vector<std::string> buttons_names; | ||||||
|     uint32_t buttonmenu_item_selected = 0; |     uint32_t buttonmenu_item_selected = 0; | ||||||
|  |     bool button_pressed = false; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class IrdaAppSceneRemoteList : public IrdaAppScene { | class IrdaAppSceneRemoteList : public IrdaAppScene { | ||||||
| @ -80,6 +83,7 @@ public: | |||||||
|     void on_enter(IrdaApp* app) final; |     void on_enter(IrdaApp* app) final; | ||||||
|     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; |     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; | ||||||
|     void on_exit(IrdaApp* app) final; |     void on_exit(IrdaApp* app) final; | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     uint32_t submenu_item_selected = 0; |     uint32_t submenu_item_selected = 0; | ||||||
|     std::vector<std::string> remote_names; |     std::vector<std::string> remote_names; | ||||||
| @ -90,6 +94,7 @@ public: | |||||||
|     void on_enter(IrdaApp* app) final; |     void on_enter(IrdaApp* app) final; | ||||||
|     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; |     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; | ||||||
|     void on_exit(IrdaApp* app) final; |     void on_exit(IrdaApp* app) final; | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     uint32_t submenu_item_selected = 0; |     uint32_t submenu_item_selected = 0; | ||||||
| }; | }; | ||||||
| @ -99,6 +104,7 @@ public: | |||||||
|     void on_enter(IrdaApp* app) final; |     void on_enter(IrdaApp* app) final; | ||||||
|     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; |     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; | ||||||
|     void on_exit(IrdaApp* app) final; |     void on_exit(IrdaApp* app) final; | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     std::vector<std::string> buttons_names; |     std::vector<std::string> buttons_names; | ||||||
| }; | }; | ||||||
| @ -133,16 +139,20 @@ public: | |||||||
| 
 | 
 | ||||||
| class IrdaAppSceneUniversalCommon : public IrdaAppScene { | class IrdaAppSceneUniversalCommon : public IrdaAppScene { | ||||||
|     bool brute_force_started = false; |     bool brute_force_started = false; | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
|     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; |     bool on_event(IrdaApp* app, IrdaAppEvent* event) final; | ||||||
|     void on_exit(IrdaApp* app) final; |     void on_exit(IrdaApp* app) final; | ||||||
|     IrdaAppBruteForce brute_force; |     IrdaAppBruteForce brute_force; | ||||||
|     void remove_popup(IrdaApp* app); |     void remove_popup(IrdaApp* app); | ||||||
|     void show_popup(IrdaApp* app, int record_amount); |     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); |     static void irda_app_item_callback(void* context, uint32_t index); | ||||||
|     IrdaAppSceneUniversalCommon(const char* filename) : brute_force(filename) {} |     IrdaAppSceneUniversalCommon(const char* filename) | ||||||
|     ~IrdaAppSceneUniversalCommon() {} |         : brute_force(filename) { | ||||||
|  |     } | ||||||
|  |     ~IrdaAppSceneUniversalCommon() { | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class IrdaAppSceneUniversalTV : public IrdaAppSceneUniversalCommon { | class IrdaAppSceneUniversalTV : public IrdaAppSceneUniversalCommon { | ||||||
| @ -151,13 +161,16 @@ public: | |||||||
|     IrdaAppSceneUniversalTV() |     IrdaAppSceneUniversalTV() | ||||||
|         : IrdaAppSceneUniversalCommon("/ext/irda/universal/tv.ir") { |         : IrdaAppSceneUniversalCommon("/ext/irda/universal/tv.ir") { | ||||||
|     } |     } | ||||||
|     ~IrdaAppSceneUniversalTV() {} |     ~IrdaAppSceneUniversalTV() { | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class IrdaAppSceneUniversalAudio : public IrdaAppSceneUniversalCommon { | class IrdaAppSceneUniversalAudio : public IrdaAppSceneUniversalCommon { | ||||||
| public: | public: | ||||||
|     void on_enter(IrdaApp* app) final; |     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]; |     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); |     furi_assert(popup_brut); | ||||||
| 
 | 
 | ||||||
|     if(popup_brut->progress < popup_brut->progress_max) |     if(popup_brut->progress < popup_brut->progress_max) | ||||||
|         ++popup_brut->progress; |         ++popup_brut->progress; | ||||||
|     else |     else | ||||||
|         furi_assert(0); |         furi_assert(0); | ||||||
|  | 
 | ||||||
|  |     return popup_brut->progress < popup_brut->progress_max; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void popup_brut_draw_callback(Canvas* canvas, void* context) { | void popup_brut_draw_callback(Canvas* canvas, void* context) { | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ extern "C" { | |||||||
| 
 | 
 | ||||||
| typedef struct IrdaAppPopupBrut IrdaAppPopupBrut; | typedef struct IrdaAppPopupBrut IrdaAppPopupBrut; | ||||||
| 
 | 
 | ||||||
| void popup_brut_increase_progress(IrdaAppPopupBrut* popup_brut); | bool popup_brut_increase_progress(IrdaAppPopupBrut* popup_brut); | ||||||
| IrdaAppPopupBrut* popup_brut_alloc(); | IrdaAppPopupBrut* popup_brut_alloc(); | ||||||
| void popup_brut_free(IrdaAppPopupBrut* popup_brut); | void popup_brut_free(IrdaAppPopupBrut* popup_brut); | ||||||
| void popup_brut_draw_callback(Canvas* canvas, void* model); | 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; |     IrdaMonitor* irda_monitor = context; | ||||||
| 
 | 
 | ||||||
|     if(irda_worker_signal_is_decoded(received_signal)) { |     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( |         snprintf( | ||||||
|             irda_monitor->display_text, |             irda_monitor->display_text, | ||||||
|             sizeof(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); |     gui_add_view_port(gui, irda_monitor->view_port, GuiLayerFullscreen); | ||||||
| 
 | 
 | ||||||
|     irda_monitor->worker = irda_worker_alloc(); |     irda_monitor->worker = irda_worker_alloc(); | ||||||
|     irda_worker_set_context(irda_monitor->worker, irda_monitor); |     irda_worker_rx_start(irda_monitor->worker); | ||||||
|     irda_worker_start(irda_monitor->worker); |     irda_worker_rx_set_received_signal_callback( | ||||||
|     irda_worker_set_received_signal_callback(irda_monitor->worker, signal_received_callback); |         irda_monitor->worker, signal_received_callback, irda_monitor); | ||||||
|     irda_worker_enable_blink_on_receiving(irda_monitor->worker, true); |     irda_worker_rx_enable_blink_on_receiving(irda_monitor->worker, true); | ||||||
| 
 | 
 | ||||||
|     while(1) { |     while(1) { | ||||||
|         InputEvent event; |         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); |     irda_worker_free(irda_monitor->worker); | ||||||
|     osMessageQueueDelete(irda_monitor->event_queue); |     osMessageQueueDelete(irda_monitor->event_queue); | ||||||
|     view_port_enabled_set(irda_monitor->view_port, false); |     view_port_enabled_set(irda_monitor->view_port, false); | ||||||
|  | |||||||
| @ -40,8 +40,10 @@ typedef struct{ | |||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     float cycle_duration; |     float cycle_duration; | ||||||
|     FuriHalIrdaTxGetDataCallback data_callback; |     FuriHalIrdaTxGetDataISRCallback data_callback; | ||||||
|  |     FuriHalIrdaTxSignalSentISRCallback signal_sent_callback; | ||||||
|     void* data_context; |     void* data_context; | ||||||
|  |     void* signal_sent_context; | ||||||
|     IrdaTxBuf buffer[2]; |     IrdaTxBuf buffer[2]; | ||||||
|     osSemaphoreId_t stop_semaphore; |     osSemaphoreId_t stop_semaphore; | ||||||
| } IrdaTimTx; | } IrdaTimTx; | ||||||
| @ -175,8 +177,10 @@ void furi_hal_irda_async_rx_stop(void) { | |||||||
|     furi_hal_irda_state = IrdaStateIdle; |     furi_hal_irda_state = IrdaStateIdle; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_irda_async_rx_set_timeout(uint32_t timeout_ms) { | void furi_hal_irda_async_rx_set_timeout(uint32_t timeout_us) { | ||||||
|     LL_TIM_OC_SetCompareCH3(TIM2, timeout_ms * 1000); |     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_OC_SetMode(TIM2, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_ACTIVE); | ||||||
|     LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH3); |     LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH3); | ||||||
|     LL_TIM_EnableIT_CC3(TIM2); |     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 */ |             /* if it's not end of the packet - continue receiving */ | ||||||
|             furi_hal_irda_tx_dma_set_buffer(next_buf_num); |             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(); |     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); |     furi_assert(furi_hal_irda_state == IrdaStateIdle); | ||||||
|     irda_tim_tx.data_callback = callback; |     irda_tim_tx.data_callback = callback; | ||||||
|     irda_tim_tx.data_context = context; |     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 */ |     FuriHalIrdaTxGetDataStateLastDone,   /* New data obtained, and this is end of package and no more data available */ | ||||||
| } FuriHalIrdaTxGetDataState; | } 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. |  * 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); | 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()'. |  * 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. |  *                           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]   callback - callback to call when RX signal edge changing occurs | ||||||
|  * @param[in]   ctx - context for callback |  * @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. |  * 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]   callback - callback for silence timeout | ||||||
|  * @param[in]   ctx - context to pass to callback |  * @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]   callback - function to provide new data | ||||||
|  * @param[in]   context - context for callback |  * @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: |  * 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); | 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 | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -34,6 +34,8 @@ typedef struct { | |||||||
|     IrdaEncoders encoder; |     IrdaEncoders encoder; | ||||||
|     uint8_t address_length; |     uint8_t address_length; | ||||||
|     uint8_t command_length; |     uint8_t command_length; | ||||||
|  |     uint32_t frequency; | ||||||
|  |     float duty_cycle; | ||||||
| } IrdaProtocolImplementation; | } IrdaProtocolImplementation; | ||||||
| 
 | 
 | ||||||
| struct IrdaEncoderHandler { | struct IrdaEncoderHandler { | ||||||
| @ -58,6 +60,8 @@ static const IrdaProtocolImplementation irda_protocols[] = { | |||||||
|           .free = irda_encoder_nec_free}, |           .free = irda_encoder_nec_free}, | ||||||
|       .address_length = 2, |       .address_length = 2, | ||||||
|       .command_length = 2, |       .command_length = 2, | ||||||
|  |       .frequency = IRDA_COMMON_CARRIER_FREQUENCY, | ||||||
|  |       .duty_cycle = IRDA_COMMON_DUTY_CYCLE, | ||||||
|     }, |     }, | ||||||
|     // #1 - have to be after NEC
 |     // #1 - have to be after NEC
 | ||||||
|     { .protocol = IrdaProtocolNECext, |     { .protocol = IrdaProtocolNECext, | ||||||
| @ -74,6 +78,8 @@ static const IrdaProtocolImplementation irda_protocols[] = { | |||||||
|           .free = irda_encoder_nec_free}, |           .free = irda_encoder_nec_free}, | ||||||
|       .address_length = 4, |       .address_length = 4, | ||||||
|       .command_length = 2, |       .command_length = 2, | ||||||
|  |       .frequency = IRDA_COMMON_CARRIER_FREQUENCY, | ||||||
|  |       .duty_cycle = IRDA_COMMON_DUTY_CYCLE, | ||||||
|     }, |     }, | ||||||
|     // #2
 |     // #2
 | ||||||
|     { .protocol = IrdaProtocolSamsung32, |     { .protocol = IrdaProtocolSamsung32, | ||||||
| @ -90,6 +96,8 @@ static const IrdaProtocolImplementation irda_protocols[] = { | |||||||
|           .free = irda_encoder_samsung32_free}, |           .free = irda_encoder_samsung32_free}, | ||||||
|       .address_length = 2, |       .address_length = 2, | ||||||
|       .command_length = 2, |       .command_length = 2, | ||||||
|  |       .frequency = IRDA_COMMON_CARRIER_FREQUENCY, | ||||||
|  |       .duty_cycle = IRDA_COMMON_DUTY_CYCLE, | ||||||
|     }, |     }, | ||||||
|     // #3
 |     // #3
 | ||||||
|     { .protocol = IrdaProtocolRC6, |     { .protocol = IrdaProtocolRC6, | ||||||
| @ -106,6 +114,8 @@ static const IrdaProtocolImplementation irda_protocols[] = { | |||||||
|           .free = irda_encoder_rc6_free}, |           .free = irda_encoder_rc6_free}, | ||||||
|       .address_length = 2, |       .address_length = 2, | ||||||
|       .command_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)) |         if (!strcmp(irda_protocols[i].name, protocol_name)) | ||||||
|             return i; |             return i; | ||||||
|     } |     } | ||||||
|  |     furi_assert(0); | ||||||
|     return IrdaProtocolUnknown; |     return IrdaProtocolUnknown; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const char* irda_get_protocol_name(IrdaProtocol protocol) { | const char* irda_get_protocol_name(IrdaProtocol protocol) { | ||||||
|  |     furi_assert(irda_is_protocol_valid(protocol)); | ||||||
|     if (irda_is_protocol_valid(protocol)) |     if (irda_is_protocol_valid(protocol)) | ||||||
|         return irda_protocols[protocol].name; |         return irda_protocols[protocol].name; | ||||||
|     else |     else | ||||||
| @ -233,6 +245,7 @@ const char* irda_get_protocol_name(IrdaProtocol protocol) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint8_t irda_get_protocol_address_length(IrdaProtocol protocol) { | uint8_t irda_get_protocol_address_length(IrdaProtocol protocol) { | ||||||
|  |     furi_assert(irda_is_protocol_valid(protocol)); | ||||||
|     if (irda_is_protocol_valid(protocol)) |     if (irda_is_protocol_valid(protocol)) | ||||||
|         return irda_protocols[protocol].address_length; |         return irda_protocols[protocol].address_length; | ||||||
|     else |     else | ||||||
| @ -240,9 +253,26 @@ uint8_t irda_get_protocol_address_length(IrdaProtocol protocol) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint8_t irda_get_protocol_command_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)) |     if (irda_is_protocol_valid(protocol)) | ||||||
|         return irda_protocols[protocol].command_length; |         return irda_protocols[protocol].command_length; | ||||||
|     else |     else | ||||||
|         return 0; |         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_CARRIER_FREQUENCY      38000 | ||||||
| #define IRDA_COMMON_DUTY_CYCLE             0.33 | #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 IrdaDecoderHandler IrdaDecoderHandler; | ||||||
| typedef struct IrdaEncoderHandler IrdaEncoderHandler; | 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); | 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 | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #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_BIT                        444     // half of time-quant for 1 bit
 | ||||||
| #define IRDA_RC6_PREAMBLE_TOLERANCE         0.07    // percents
 | #define IRDA_RC6_PREAMBLE_TOLERANCE         0.07    // percents
 | ||||||
| #define IRDA_RC6_BIT_TOLERANCE              120     // us
 | #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_alloc(void); | ||||||
| void irda_decoder_rc6_reset(void* decoder); | 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)) { |     if (irda_tx_raw_add_silence && (irda_tx_raw_timings_index == 0)) { | ||||||
|         irda_tx_raw_add_silence = false; |         irda_tx_raw_add_silence = false; | ||||||
|         *level = false; |         *level = false; | ||||||
|         *duration = 180000;     // 180 ms delay between raw packets
 |         *duration = IRDA_RAW_TX_TIMING_DELAY_US; | ||||||
|     } else { |     } else { | ||||||
|         *level = irda_tx_raw_start_from_mark ^ (irda_tx_raw_timings_index % 2); |         *level = irda_tx_raw_start_from_mark ^ (irda_tx_raw_timings_index % 2); | ||||||
|         *duration = timings[irda_tx_raw_timings_index++]; |         *duration = timings[irda_tx_raw_timings_index++]; | ||||||
|  | |||||||
| @ -1,20 +1,45 @@ | |||||||
|  | #include "furi/check.h" | ||||||
|  | #include "furi/common_defines.h" | ||||||
|  | #include "sys/_stdint.h" | ||||||
| #include "irda_worker.h" | #include "irda_worker.h" | ||||||
| #include <irda.h> | #include <irda.h> | ||||||
| #include <furi-hal-irda.h> | #include <furi-hal-irda.h> | ||||||
| #include <limits.h> | #include <limits.h> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stream_buffer.h> |  | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <notification/notification-messages.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_RECEIVED             0x01 | ||||||
| #define IRDA_WORKER_RX_TIMEOUT_RECEIVED     0x02 | #define IRDA_WORKER_RX_TIMEOUT_RECEIVED     0x02 | ||||||
| #define IRDA_WORKER_OVERRUN                 0x04 | #define IRDA_WORKER_OVERRUN                 0x04 | ||||||
| #define IRDA_WORKER_EXIT                    0x08 | #define IRDA_WORKER_EXIT                    0x08 | ||||||
|  | #define IRDA_WORKER_TX_FILL_BUFFER          0x10 | ||||||
|  | #define IRDA_WORKER_TX_MESSAGE_SENT         0x20 | ||||||
| 
 | 
 | ||||||
| struct IrdaWorkerSignal { | #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; |     bool decoded; | ||||||
|     size_t timings_cnt; |     size_t timings_cnt; | ||||||
|     union { |     union { | ||||||
| @ -25,37 +50,67 @@ struct IrdaWorkerSignal { | |||||||
| 
 | 
 | ||||||
| struct IrdaWorker { | struct IrdaWorker { | ||||||
|     FuriThread* thread; |     FuriThread* thread; | ||||||
|     IrdaDecoderHandler* irda_decoder; |  | ||||||
|     StreamBufferHandle_t stream; |     StreamBufferHandle_t stream; | ||||||
|  |     osEventFlagsId_t events; | ||||||
| 
 | 
 | ||||||
|     TaskHandle_t worker_handle; |  | ||||||
|     IrdaWorkerSignal signal; |     IrdaWorkerSignal signal; | ||||||
| 
 |     IrdaWorkerState state; | ||||||
|     IrdaWorkerReceivedSignalCallback received_signal_callback; |     IrdaEncoderHandler* irda_encoder; | ||||||
|     void* context; |     IrdaDecoderHandler* irda_decoder; | ||||||
|     bool blink_enable; |  | ||||||
|     bool overrun; |  | ||||||
|     NotificationApp* notification; |     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) { | static void irda_worker_rx_timeout_callback(void* context) { | ||||||
|     IrdaWorker* instance = context; |     IrdaWorker* instance = context; | ||||||
|     BaseType_t xHigherPriorityTaskWoken = pdFALSE; |     uint32_t flags_set = osEventFlagsSet(instance->events, IRDA_WORKER_RX_TIMEOUT_RECEIVED); | ||||||
|     xTaskNotifyFromISR(instance->worker_handle, IRDA_WORKER_RX_TIMEOUT_RECEIVED, eSetBits,  &xHigherPriorityTaskWoken); |     furi_check(flags_set & IRDA_WORKER_RX_TIMEOUT_RECEIVED); | ||||||
|     portYIELD_FROM_ISR(xHigherPriorityTaskWoken); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void irda_worker_rx_callback(void* context, bool level, uint32_t duration) { | static void irda_worker_rx_callback(void* context, bool level, uint32_t duration) { | ||||||
|     IrdaWorker* instance = context; |     IrdaWorker* instance = context; | ||||||
| 
 | 
 | ||||||
|     BaseType_t xHigherPriorityTaskWoken = pdFALSE; |     BaseType_t xHigherPriorityTaskWoken = pdFALSE; | ||||||
|  |     furi_assert(duration != 0); | ||||||
|     LevelDuration level_duration = level_duration_make(level, duration); |     LevelDuration level_duration = level_duration_make(level, duration); | ||||||
| 
 | 
 | ||||||
|     size_t ret = |     size_t ret = | ||||||
|         xStreamBufferSendFromISR(instance->stream, &level_duration, sizeof(LevelDuration), &xHigherPriorityTaskWoken); |         xStreamBufferSendFromISR(instance->stream, &level_duration, sizeof(LevelDuration), &xHigherPriorityTaskWoken); | ||||||
|     uint32_t notify_value = (ret == sizeof(LevelDuration)) ? IRDA_WORKER_RX_RECEIVED : IRDA_WORKER_OVERRUN; |     uint32_t events = (ret == sizeof(LevelDuration)) ? IRDA_WORKER_RX_RECEIVED : IRDA_WORKER_OVERRUN; | ||||||
|     xTaskNotifyFromISR(instance->worker_handle, notify_value, eSetBits,  &xHigherPriorityTaskWoken); |  | ||||||
|     portYIELD_FROM_ISR(xHigherPriorityTaskWoken); |     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) { | static void irda_worker_process_timeout(IrdaWorker* instance) { | ||||||
| @ -63,8 +118,8 @@ static void irda_worker_process_timeout(IrdaWorker* instance) { | |||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     instance->signal.decoded = false; |     instance->signal.decoded = false; | ||||||
|     if (instance->received_signal_callback) |     if (instance->rx.received_signal_callback) | ||||||
|         instance->received_signal_callback(instance->context, &instance->signal); |         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) { | 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.data.message = *message_decoded; | ||||||
|         instance->signal.timings_cnt = 0; |         instance->signal.timings_cnt = 0; | ||||||
|         instance->signal.decoded = true; |         instance->signal.decoded = true; | ||||||
|         if (instance->received_signal_callback) |         if (instance->rx.received_signal_callback) | ||||||
|             instance->received_signal_callback(instance->context, &instance->signal); |             instance->rx.received_signal_callback(instance->rx.received_signal_context, &instance->signal); | ||||||
|     } else { |     } else { | ||||||
|         /* Skip first timing if it's starts from Space */ |         /* Skip first timing if it's starts from Space */ | ||||||
|         if ((instance->signal.timings_cnt == 0) && !level) { |         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.data.timings[instance->signal.timings_cnt] = duration; | ||||||
|             ++instance->signal.timings_cnt; |             ++instance->signal.timings_cnt; | ||||||
|         } else { |         } else { | ||||||
|             xTaskNotify(instance->worker_handle, IRDA_WORKER_OVERRUN, eSetBits); |             uint32_t flags_set = osEventFlagsSet(instance->events, IRDA_WORKER_OVERRUN); | ||||||
|             instance->overrun = true; |             furi_check(flags_set & IRDA_WORKER_OVERRUN); | ||||||
|  |             instance->rx.overrun = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int32_t irda_worker_thread_callback(void* context) { | static int32_t irda_worker_rx_thread(void* thread_context) { | ||||||
|     IrdaWorker* instance = context; |     IrdaWorker* instance = thread_context; | ||||||
|     uint32_t notify_value = 0; |     uint32_t events = 0; | ||||||
|     LevelDuration level_duration; |     LevelDuration level_duration; | ||||||
|     TickType_t last_blink_time = 0; |     TickType_t last_blink_time = 0; | ||||||
| 
 | 
 | ||||||
|     while(1) { |     while(1) { | ||||||
|         BaseType_t result; |         events = osEventFlagsWait(instance->events, IRDA_WORKER_ALL_RX_EVENTS, 0, osWaitForever); | ||||||
|         result = xTaskNotifyWait(pdFALSE, ULONG_MAX, ¬ify_value, 1000); |         furi_check(events & IRDA_WORKER_ALL_RX_EVENTS); /* at least one caught */ | ||||||
|         if (result != pdPASS) |  | ||||||
|             continue; |  | ||||||
| 
 | 
 | ||||||
|         if (notify_value & IRDA_WORKER_RX_RECEIVED) { |         if (events & IRDA_WORKER_RX_RECEIVED) { | ||||||
|             if (!instance->overrun && instance->blink_enable && ((xTaskGetTickCount() - last_blink_time) > 80)) { |             if (!instance->rx.overrun && instance->blink_enable && ((xTaskGetTickCount() - last_blink_time) > 80)) { | ||||||
|                 last_blink_time = xTaskGetTickCount(); |                 last_blink_time = xTaskGetTickCount(); | ||||||
|                 notification_message(instance->notification, &sequence_blink_blue_10); |                 notification_message(instance->notification, &sequence_blink_blue_10); | ||||||
|             } |             } | ||||||
|             if (instance->signal.timings_cnt == 0) |             if (instance->signal.timings_cnt == 0) | ||||||
|                 notification_message(instance->notification, &sequence_display_on); |                 notification_message(instance->notification, &sequence_display_on); | ||||||
|             while (sizeof(LevelDuration) == xStreamBufferReceive(instance->stream, &level_duration, sizeof(LevelDuration), 0)) { |             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); |                     bool level = level_duration_get_level(level_duration); | ||||||
|                     uint32_t duration = level_duration_get_duration(level_duration); |                     uint32_t duration = level_duration_get_duration(level_duration); | ||||||
|                     irda_worker_process_timings(instance, duration, level); |                     irda_worker_process_timings(instance, duration, level); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if (notify_value & IRDA_WORKER_OVERRUN) { |         if (events & IRDA_WORKER_OVERRUN) { | ||||||
|             printf("#"); |             printf("#"); | ||||||
|             irda_reset_decoder(instance->irda_decoder); |             irda_reset_decoder(instance->irda_decoder); | ||||||
|             instance->signal.timings_cnt = 0; |             instance->signal.timings_cnt = 0; | ||||||
|             if (instance->blink_enable) |             if (instance->blink_enable) | ||||||
|                 notification_message(instance->notification, &sequence_set_red_255); |                 notification_message(instance->notification, &sequence_set_red_255); | ||||||
|         } |         } | ||||||
|         if (notify_value & IRDA_WORKER_RX_TIMEOUT_RECEIVED) { |         if (events & IRDA_WORKER_RX_TIMEOUT_RECEIVED) { | ||||||
|             if (instance->overrun) { |             if (instance->rx.overrun) { | ||||||
|                 printf("\nOVERRUN, max samples: %d\n", MAX_TIMINGS_AMOUNT); |                 printf("\nOVERRUN, max samples: %d\n", MAX_TIMINGS_AMOUNT); | ||||||
|                 instance->overrun = false; |                 instance->rx.overrun = false; | ||||||
|                 if (instance->blink_enable) |                 if (instance->blink_enable) | ||||||
|                     notification_message(instance->notification, &sequence_reset_red); |                     notification_message(instance->notification, &sequence_reset_red); | ||||||
|             } else { |             } else { | ||||||
| @ -136,16 +190,17 @@ static int32_t irda_worker_thread_callback(void* context) { | |||||||
|             } |             } | ||||||
|             instance->signal.timings_cnt = 0; |             instance->signal.timings_cnt = 0; | ||||||
|         } |         } | ||||||
|         if (notify_value & IRDA_WORKER_EXIT) |         if (events & IRDA_WORKER_EXIT) | ||||||
|             break; |             break; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return 0; |     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); |     furi_assert(instance); | ||||||
|     instance->received_signal_callback = callback; |     instance->rx.received_signal_callback = callback; | ||||||
|  |     instance->rx.received_signal_context = context; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| IrdaWorker* irda_worker_alloc() { | IrdaWorker* irda_worker_alloc() { | ||||||
| @ -155,60 +210,67 @@ IrdaWorker* irda_worker_alloc() { | |||||||
|     furi_thread_set_name(instance->thread, "irda_worker"); |     furi_thread_set_name(instance->thread, "irda_worker"); | ||||||
|     furi_thread_set_stack_size(instance->thread, 2048); |     furi_thread_set_stack_size(instance->thread, 2048); | ||||||
|     furi_thread_set_context(instance->thread, instance); |     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_decoder = irda_alloc_decoder(); | ||||||
|  |     instance->irda_encoder = irda_alloc_encoder(); | ||||||
|     instance->blink_enable = false; |     instance->blink_enable = false; | ||||||
|     instance->notification = furi_record_open("notification"); |     instance->notification = furi_record_open("notification"); | ||||||
|  |     instance->state = IrdaWorkerStateIdle; | ||||||
|  |     instance->events = osEventFlagsNew(NULL); | ||||||
| 
 | 
 | ||||||
|     return instance; |     return instance; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void irda_worker_free(IrdaWorker* instance) { | void irda_worker_free(IrdaWorker* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     furi_assert(!instance->worker_handle); |     furi_assert(instance->state == IrdaWorkerStateIdle); | ||||||
| 
 | 
 | ||||||
|     furi_record_close("notification"); |     furi_record_close("notification"); | ||||||
|     irda_free_decoder(instance->irda_decoder); |     irda_free_decoder(instance->irda_decoder); | ||||||
|  |     irda_free_encoder(instance->irda_encoder); | ||||||
|     vStreamBufferDelete(instance->stream); |     vStreamBufferDelete(instance->stream); | ||||||
|     furi_thread_free(instance->thread); |     furi_thread_free(instance->thread); | ||||||
|  |     osEventFlagsDelete(instance->events); | ||||||
| 
 | 
 | ||||||
|     free(instance); |     free(instance); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void irda_worker_set_context(IrdaWorker* instance, void* context) { | void irda_worker_rx_start(IrdaWorker* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     instance->context = context; |     furi_assert(instance->state == IrdaWorkerStateIdle); | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| void irda_worker_start(IrdaWorker* instance) { |     xStreamBufferSetTriggerLevel(instance->stream, sizeof(LevelDuration)); | ||||||
|     furi_assert(instance); |  | ||||||
|     furi_assert(!instance->worker_handle); |  | ||||||
| 
 | 
 | ||||||
|  |     osEventFlagsClear(instance->events, IRDA_WORKER_ALL_EVENTS); | ||||||
|  |     furi_thread_set_callback(instance->thread, irda_worker_rx_thread); | ||||||
|     furi_thread_start(instance->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_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_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); | ||||||
|     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_timeout_isr_callback(NULL, NULL); | ||||||
|     furi_hal_irda_async_rx_set_capture_isr_callback(NULL, NULL); |     furi_hal_irda_async_rx_set_capture_isr_callback(NULL, NULL); | ||||||
|     furi_hal_irda_async_rx_stop(); |     furi_hal_irda_async_rx_stop(); | ||||||
| 
 | 
 | ||||||
|     xTaskNotify(instance->worker_handle, IRDA_WORKER_EXIT, eSetBits); |     osEventFlagsSet(instance->events, IRDA_WORKER_EXIT); | ||||||
| 
 |  | ||||||
|     instance->worker_handle = NULL; |  | ||||||
| 
 |  | ||||||
|     furi_thread_join(instance->thread); |     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) { | 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; |     *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); |     furi_assert(signal); | ||||||
|     return &signal->data.message; |     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); |     furi_assert(instance); | ||||||
|     instance->blink_enable = enable; |     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" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #define MAX_TIMINGS_AMOUNT                  512 | ||||||
|  | 
 | ||||||
| /** Interface struct of irda worker */ | /** Interface struct of irda worker */ | ||||||
| typedef struct IrdaWorker IrdaWorker; | typedef struct IrdaWorker IrdaWorker; | ||||||
| /** Interface struct of received signal */ | /** Interface struct of received signal */ | ||||||
| typedef struct IrdaWorkerSignal IrdaWorkerSignal; | 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 */ | /** Callback type to call by IrdaWorker thread when new signal is received */ | ||||||
| typedef void (*IrdaWorkerReceivedSignalCallback)(void* context, IrdaWorkerSignal* received_signal); | typedef void (*IrdaWorkerReceivedSignalCallback)(void* context, IrdaWorkerSignal* received_signal); | ||||||
| 
 | 
 | ||||||
| @ -27,31 +44,33 @@ IrdaWorker* irda_worker_alloc(); | |||||||
|  */ |  */ | ||||||
| void irda_worker_free(IrdaWorker* instance); | 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.
 | /** Start IrdaWorker thread, initialise furi-hal, prepare all work.
 | ||||||
|  * |  * | ||||||
|  * @param[in]   instance - IrdaWorker instance |  * @param[in]   instance - IrdaWorker instance | ||||||
|  */ |  */ | ||||||
| void irda_worker_start(IrdaWorker* instance); | void irda_worker_rx_start(IrdaWorker* instance); | ||||||
| 
 | 
 | ||||||
| /** Stop IrdaWorker thread, deinitialize furi-hal.
 | /** Stop IrdaWorker thread, deinitialize furi-hal.
 | ||||||
|  * |  * | ||||||
|  * @param[in]   instance - IrdaWorker instance |  * @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
 | /** 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); | 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'.
 | /** Acquire raw signal from interface struct 'IrdaWorkerSignal'.
 | ||||||
|  * First, you have to ensure that signal is raw. |  * 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. |  * First, you have to ensure that signal is decoded. | ||||||
|  * |  * | ||||||
|  * @param[in]   signal - received signal |  * @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[out]  instance - IrdaWorker instance | ||||||
|  * @param[in]   enable - true if you want to enable blinking |  * @param[in]   message - decoded signal | ||||||
|  *                       false otherwise |  | ||||||
|  */ |  */ | ||||||
| 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 | #ifdef __cplusplus | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Albert Kharisov
						Albert Kharisov