Explorar el Código

Merge cross_remote from https://github.com/leedave/flipper-zero-cross-remote

Willy-JL hace 10 meses
padre
commit
2557a85b98

+ 9 - 1
cross_remote/README.md

@@ -30,12 +30,15 @@ Wouldn't it be nicer to simply click one button and let everything happen? This
 - Add pauses, becaue target systems are not always fast enough for multiple commands<br>
 - Run file containing chained IR & SubGhz commands<br>
 - Loop Transmissions until quit
+- Pin to Favorites menu (if supported by firmware)
 
 ### Settings
 - LED FX, allow the LED to blink
 - Save settings, stores a file with your settings in it on exit
 - IR time ms, the default duration of an IR signal transmission. Individual times can be set
 - SubG. time ms, the default duration of a SubGhz signal. Only needed for Encoded signals, RAW files play until finished
+- Loop transmip, repeats the command chain until cancelled
+- External IR & 5V on GPIO, settings for external IR boards
 
 ### Limitations
 SubGhz commands will stop working if you move/rename/delete the original files on your Flipper. This is because of how the Flippers SubGhz worker expects data. 
@@ -53,8 +56,13 @@ Then run the command:
  ```
 The application will be compiled and copied onto your device. 
 
+## Pin to Favorites feature
+This feature is only available in custom firmwares that support it or if you modify the owf to support the .xr file types.
+
+From the start screen on flipper press down to enter the favorites menu. Navigate left and right until you hit the tab "browser". From there navigate into the folder apps_data/xremote and select the command chain you want to add to your favorites. Select "Pin" from the context menu and your command chain will be available in the favorites menu. 
+
 ## Thank you notes
-- [Willy-JL](https://github.com/Willy-JL) for distributing in Momentum Firmware
+- [Willy-JL](https://github.com/Willy-JL) for code contributions and distributing in Momentum Firmware
 - [Roguemaster](https://github.com/RogueMaster/flipperzero-firmware-wPlugins) for distributing in Roguemaster Firmware
 - [Miccayo](https://github.com/miccayo) for contributing the loop transmit feature
 

+ 1 - 1
cross_remote/application.fam

@@ -6,7 +6,7 @@ App(
     stack_size=3 * 1024,
     fap_icon="icons/xremote_10px.png",
     fap_icon_assets="icons",
-    fap_version="3.0",
+    fap_version="3.3",
     fap_category="Infrared",
     fap_author="Leedave",
     fap_description="One-Click, sends multiple commands",

+ 2 - 0
cross_remote/docs/README.md

@@ -4,6 +4,7 @@ This app combines your IR and SubGhz commands into a playlist that can be run wi
 
 ## Features
 - Read out commands you recorded in the IR app
+- Supports external GPIO Boards like IR Blaster or Masta-Blasta
 - Read out commands you saved as .sub files
 - Combine commands to a chain/playlist 
 - Add pauses inbetween commands 
@@ -12,6 +13,7 @@ This app combines your IR and SubGhz commands into a playlist that can be run wi
 - Configure duration of IR Signals
 - Configure default duration of Encoded SubGhz Signals
 - Loop Transmissions until quit
+- Pin to Favorites menu (if supported by Firmware)
 
 ## What good is this?
 

+ 10 - 0
cross_remote/docs/changelog.md

@@ -1,3 +1,13 @@
+## 3.3
+- Added support for Favorites menu. 
+
+## 3.2
+- Added support for external IR GPIO boards, tested on IR Blaster & Masta-Blasta. 
+
+## 3.1
+- Bugfix to enable save on first use (thanks to WillyJL)
+- Bugfix for loop transmit when using RAW SubGHz transmissions
+
 ## 3.0
 - Added loop transmit feature (thanks to miccayo)
 - Replaced transmission counter with animations

+ 0 - 7
cross_remote/helpers/subghz/subghz.c

@@ -28,13 +28,6 @@ void subghz_scene_transmit_callback_end_tx(void* context) {
     furi_assert(context);
     FURI_LOG_D(TAG, "callback end");
     XRemote* app = context;
-    view_dispatcher_send_custom_event(
-        app->view_dispatcher, XRemoteCustomEventViewTransmitterSendStop);
-
-    //app->state_notifications = SubGhzNotificationStateIDLE;
-    //subghz_txrx_stop(app->subghz->txrx);
-    //app->transmitting = false;
-    //xremote_scene_ir_notification_message(app, SubGhzNotificationMessageBlinkStop);
     xremote_cross_remote_set_transmitting(app->cross_remote, XRemoteTransmittingStopSubghz);
 }
 

+ 5 - 1
cross_remote/helpers/subghz/subghz_txrx.c

@@ -3,6 +3,7 @@
 #include <lib/subghz/subghz_protocol_registry.h>
 #include <applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h>
 #include <lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h>
+#include <infrared_transmit.h>
 
 #define TAG "SubGhz"
 
@@ -24,7 +25,10 @@ static void subghz_txrx_radio_device_power_on(SubGhzTxRx* instance) {
 
 static void subghz_txrx_radio_device_power_off(SubGhzTxRx* instance) {
     UNUSED(instance);
-    if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg();
+    FuriHalInfraredTxPin tx_pin_detected = furi_hal_infrared_detect_tx_output();
+    if(furi_hal_power_is_otg_enabled() && tx_pin_detected == FuriHalInfraredTxPinInternal) {
+        furi_hal_power_disable_otg();
+    }
 }
 
 SubGhzTxRx* subghz_txrx_alloc(void) {

+ 3 - 0
cross_remote/helpers/xremote_custom_event.h

@@ -52,6 +52,9 @@ typedef enum {
     XRemoteCustomEventPauseSetOk,
 
     XRemoteCustomEventViewTransmitterSendStop,
+
+    XRemoteCustomEventTypeIrGpioPinChanged,
+    XRemoteCustomEventTypeIrGpioOtgChanged,
 } XRemoteCustomEvent;
 
 static inline uint32_t xremote_custom_menu_event_pack(uint16_t type, int16_t value) {

+ 9 - 1
cross_remote/helpers/xremote_storage.c

@@ -30,7 +30,7 @@ void xremote_save_settings(void* context) {
     }
 
     // Open File, create if not exists
-    if(!storage_common_stat(storage, XREMOTE_SETTINGS_SAVE_PATH, NULL) == FSE_OK) {
+    if(storage_common_stat(storage, XREMOTE_SETTINGS_SAVE_PATH, NULL) != FSE_OK) {
         FURI_LOG_D(
             TAG, "Config file %s is not found. Will create new.", XREMOTE_SETTINGS_SAVE_PATH);
         if(storage_common_stat(storage, CONFIG_FILE_DIRECTORY_PATH, NULL) == FSE_NOT_EXIST) {
@@ -62,6 +62,10 @@ void xremote_save_settings(void* context) {
     flipper_format_write_uint32(
         fff_file, XREMOTE_SETTINGS_KEY_LOOP_TRANSMIT, &app->loop_transmit, 1);
 
+    //IR GPIO Settings
+    flipper_format_write_uint32(fff_file, XREMOTE_SETTINGS_KEY_IR_TX_PIN, &app->ir_tx_pin, 1);
+    flipper_format_write_bool(fff_file, XREMOTE_SETTINGS_KEY_IR_USE_OTP, &app->ir_is_otg_enabled, 1);
+
     if(!flipper_format_rewind(fff_file)) {
         xremote_close_config_file(fff_file);
         FURI_LOG_E(TAG, "Rewind error");
@@ -117,6 +121,10 @@ void xremote_read_settings(void* context) {
     flipper_format_read_uint32(
         fff_file, XREMOTE_SETTINGS_KEY_LOOP_TRANSMIT, &app->loop_transmit, 1);
 
+    // IR GPIO Settings
+    flipper_format_read_uint32(fff_file, XREMOTE_SETTINGS_KEY_IR_TX_PIN, &app->ir_tx_pin, 1);
+    flipper_format_read_bool(fff_file, XREMOTE_SETTINGS_KEY_IR_USE_OTP, &app->ir_is_otg_enabled, 1);
+
     flipper_format_rewind(fff_file);
 
     furi_string_free(temp_str);

+ 2 - 0
cross_remote/helpers/xremote_storage.h

@@ -12,6 +12,8 @@
 #define XREMOTE_SETTINGS_KEY_SPEAKER "Speaker"
 #define XREMOTE_SETTINGS_KEY_SAVE_SETTINGS "SaveSettings"
 #define XREMOTE_SETTINGS_KEY_IR_TIMING "IRTiming"
+#define XREMOTE_SETTINGS_KEY_IR_TX_PIN "IRTXPin"
+#define XREMOTE_SETTINGS_KEY_IR_USE_OTP "IRUSEOTP"
 #define XREMOTE_SETTINGS_KEY_SG_TIMING "SGTiming"
 #define XREMOTE_SETTINGS_KEY_LOOP_TRANSMIT "LoopTransmit"
 

+ 68 - 45
cross_remote/scenes/xremote_scene_settings.c

@@ -1,29 +1,16 @@
 #include "../xremote.h"
 #include <lib/toolbox/value_index.h>
-/*
-enum SettingsIndex {
-    SettingsIndexHaptic = 10,
-    SettingsIndexValue1,
-    SettingsIndexValue2,
-};*/
-
-/*const char* const haptic_text[2] = {
-    "OFF",
-    "ON",
+
+static const char* infrared_pin_text[] = {
+    "Flipper",
+    "2 (A7)",
+    "Detect",
 };
-const uint32_t haptic_value[2] = {
-    XRemoteHapticOff,
-    XRemoteHapticOn,
-};*/
 
-/*const char* const speaker_text[2] = {
+static const char* infrared_otg_text[] = {
     "OFF",
     "ON",
 };
-const uint32_t speaker_value[2] = {
-    XRemoteSpeakerOff,
-    XRemoteSpeakerOn,
-};*/
 
 const char* const led_text[2] = {
     "OFF",
@@ -33,6 +20,7 @@ const uint32_t led_value[2] = {
     XRemoteLedOff,
     XRemoteLedOn,
 };
+
 const char* const loop_text[2] = {
     "OFF",
     "ON",
@@ -41,6 +29,7 @@ const uint32_t loop_value[2] = {
     XRemoteLoopOff,
     XRemoteLoopOn,
 };
+
 const char* const settings_text[2] = {
     "OFF",
     "ON",
@@ -50,20 +39,27 @@ const uint32_t settings_value[2] = {
     XRemoteSettingsOn,
 };
 
-/*static void xremote_scene_settings_set_haptic(VariableItem* item) {
+static void xremote_scene_settings_set_ir_pin(VariableItem* item) {
     XRemote* app = variable_item_get_context(item);
     uint8_t index = variable_item_get_current_value_index(item);
 
-    variable_item_set_current_value_text(item, haptic_text[index]);
-    app->haptic = haptic_value[index];
-}*/
+    variable_item_set_current_value_text(item, infrared_pin_text[index]);
+    app->ir_tx_pin = index;
+    view_dispatcher_send_custom_event(
+        app->view_dispatcher,
+        xremote_custom_menu_event_pack(XRemoteCustomEventTypeIrGpioPinChanged, index));
+}
 
-/*static void xremote_scene_settings_set_speaker(VariableItem* item) {
+static void xremote_scene_settings_set_ir_is_otg_enabled(VariableItem* item) {
     XRemote* app = variable_item_get_context(item);
     uint8_t index = variable_item_get_current_value_index(item);
-    variable_item_set_current_value_text(item, speaker_text[index]);
-    app->speaker = speaker_value[index];
-}*/
+
+    variable_item_set_current_value_text(item, infrared_otg_text[index]);
+    app->ir_is_otg_enabled = index;
+    view_dispatcher_send_custom_event(
+        app->view_dispatcher,
+        xremote_custom_menu_event_pack(XRemoteCustomEventTypeIrGpioOtgChanged, index));
+}
 
 static void xremote_scene_settings_set_led(VariableItem* item) {
     XRemote* app = variable_item_get_context(item);
@@ -109,25 +105,11 @@ void xremote_scene_settings_submenu_callback(void* context, uint32_t index) {
     view_dispatcher_send_custom_event(app->view_dispatcher, index);
 }
 
-void xremote_scene_settings_on_enter(void* context) {
-    XRemote* app = context;
+void xremote_scene_settings_init(void* context) {
+    XRemote* app = context;    
     VariableItem* item;
     uint8_t value_index;
 
-    // Vibro on/off
-    /*    item = variable_item_list_add(
-        app->variable_item_list, "Vibro/Haptic:", 2, xremote_scene_settings_set_haptic, app);
-    value_index = value_index_uint32(app->haptic, haptic_value, 2);
-    variable_item_set_current_value_index(item, value_index);
-    variable_item_set_current_value_text(item, haptic_text[value_index]);*/
-
-    // Sound on/off
-    /*   item = variable_item_list_add(
-        app->variable_item_list, "Sound:", 2, xremote_scene_settings_set_speaker, app);
-    value_index = value_index_uint32(app->speaker, speaker_value, 2);
-    variable_item_set_current_value_index(item, value_index);
-    variable_item_set_current_value_text(item, speaker_text[value_index]);*/
-
     // LED Effects on/off
     item = variable_item_list_add(
         app->variable_item_list, "LED FX", 2, xremote_scene_settings_set_led, app);
@@ -149,6 +131,35 @@ void xremote_scene_settings_on_enter(void* context) {
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_text(item, settings_text[value_index]);
 
+    // Infrared GPIO Board
+    item = variable_item_list_add(
+        app->variable_item_list, 
+        "External IR", 
+        COUNT_OF(infrared_pin_text), 
+        xremote_scene_settings_set_ir_pin, 
+        app);
+    value_index = app->ir_tx_pin;
+    variable_item_set_current_value_index(item, value_index);
+    variable_item_set_current_value_text(item, infrared_pin_text[value_index]);
+    
+    // Infrared GPIO 5V
+    item = variable_item_list_add(
+        app->variable_item_list,
+        "5V on IR GPIO",
+        COUNT_OF(infrared_otg_text),
+        xremote_scene_settings_set_ir_is_otg_enabled,
+        app);
+    
+    if(app->ir_tx_pin < FuriHalInfraredTxPinMax) {
+        value_index = app->ir_is_otg_enabled;
+        variable_item_set_current_value_index(item, value_index);
+        variable_item_set_current_value_text(item, infrared_otg_text[value_index]);
+    } else {
+        variable_item_set_values_count(item, 1);
+        variable_item_set_current_value_index(item, 0);
+        variable_item_set_current_value_text(item, "Auto");
+    }
+
     // Set Infrared Timer
     item = variable_item_list_add(
         app->variable_item_list, "IR Time ms", 30, xremote_scene_settings_set_ir_timing, app);
@@ -163,16 +174,28 @@ void xremote_scene_settings_on_enter(void* context) {
 
     variable_item_set_current_value_index(item, (uint8_t)(app->sg_timing / 100));
     snprintf(app->sg_timing_char, 20, "%lu", app->sg_timing);
-    variable_item_set_current_value_text(item, app->sg_timing_char);
+    variable_item_set_current_value_text(item, app->sg_timing_char);    
+}
 
+void xremote_scene_settings_on_enter(void* context) {
+    XRemote* app = context;
+    xremote_scene_settings_init(app);
     view_dispatcher_switch_to_view(app->view_dispatcher, XRemoteViewIdSettings);
 }
 
 bool xremote_scene_settings_on_event(void* context, SceneManagerEvent event) {
     XRemote* app = context;
-    UNUSED(app);
     bool consumed = false;
     if(event.type == SceneManagerEventTypeCustom) {
+        const uint16_t custom_event_type = xremote_custom_menu_event_get_type(event.event);
+        
+        if (custom_event_type == XRemoteCustomEventTypeIrGpioPinChanged) {
+            variable_item_list_reset(app->variable_item_list);
+            xremote_scene_settings_init(app);
+            xremote_ir_set_tx_pin(app);
+        } else if(custom_event_type == XRemoteCustomEventTypeIrGpioOtgChanged) {
+            xremote_ir_enable_otg(app, app->ir_is_otg_enabled);
+        }
     }
     return consumed;
 }

+ 6 - 1
cross_remote/scenes/xremote_scene_transmit.c

@@ -117,7 +117,12 @@ void xremote_scene_transmit_send_signal(void* context, CrossRemoteItem* item) {
 
 static void xremote_scene_transmit_end_scene(XRemote* app) {
     xremote_scene_ir_notification_message(app, InfraredNotificationMessageBlinkStop);
-    scene_manager_previous_scene(app->scene_manager);
+    if (app->loadFavorite) {
+        scene_manager_stop(app->scene_manager);
+        view_dispatcher_stop(app->view_dispatcher);
+    } else {
+        scene_manager_previous_scene(app->scene_manager);
+    }
 }
 
 static void xremote_scene_transmit_run_single_transmit(XRemote* app) {

+ 0 - 1
cross_remote/scenes/xremote_scene_xr_list.c

@@ -12,7 +12,6 @@ void xremote_scene_xr_list_on_enter(void* context) {
     furi_string_set(path, XREMOTE_APP_FOLDER);
 
     bool success = dialog_file_browser_show(
-        //app->dialogs, app->file_path, app->file_path, &browser_options);
         app->dialogs,
         app->file_path,
         path,

+ 50 - 7
cross_remote/xremote.c

@@ -53,6 +53,7 @@ XRemote* xremote_app_alloc() {
     app->stop_transmit = false;
     app->loop_transmit = 0;
     app->transmit_item = 0;
+    app->loadFavorite = false;
 
     // Load configs
     xremote_read_settings(app);
@@ -191,23 +192,65 @@ void xremote_text_input_callback(void* context) {
     view_dispatcher_send_custom_event(app->view_dispatcher, XRemoteCustomEventTextInput);
 }
 
+void xremote_ir_enable_otg(XRemote* app, bool enable) {
+    if(enable) {
+        furi_hal_power_enable_otg();
+    } else {
+        furi_hal_power_disable_otg();
+    }
+    app->ir_is_otg_enabled = enable;
+}
+
+void xremote_ir_set_tx_pin(XRemote* app) {
+    if(app->ir_tx_pin < FuriHalInfraredTxPinMax) {
+        furi_hal_infrared_set_tx_output(app->ir_tx_pin);
+    } else {
+        FuriHalInfraredTxPin tx_pin_detected = furi_hal_infrared_detect_tx_output();
+        furi_hal_infrared_set_tx_output(tx_pin_detected);
+        if(tx_pin_detected != FuriHalInfraredTxPinInternal) {
+            xremote_ir_enable_otg(app, true);
+        }
+    }
+}
+
+static void xremote_ir_load_settings(XRemote* app) {
+    xremote_ir_set_tx_pin(app);
+    if(app->ir_tx_pin < FuriHalInfraredTxPinMax) {
+        xremote_ir_enable_otg(app, app->ir_is_otg_enabled);
+    }
+}
+
 int32_t xremote_app(void* p) {
-    UNUSED(p);
     XRemote* app = xremote_app_alloc();
-
+    
     view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
 
-    //scene_manager_next_scene(app->scene_manager, XRemoteSceneInfoscreen); //Start with start screen
-    scene_manager_next_scene(
-        app->scene_manager, XRemoteSceneMenu); //if you want to directly start with Menu
-
     furi_hal_power_suppress_charge_enter();
+    xremote_ir_load_settings(app);
+
+
+    Storage* storage = furi_record_open(RECORD_STORAGE);
+    storage_common_mkdir(storage, XREMOTE_APP_FOLDER);
+    furi_record_close(RECORD_STORAGE);
+
+    //bool loadFavorite = false;
+    if(p && strlen(p)) {
+        furi_string_set_str(app->file_path, p);
+        app->loadFavorite = xremote_cross_remote_load(app->cross_remote, app->file_path);
+    }
+    if (app->loadFavorite) {
+        scene_manager_next_scene(
+            app->scene_manager, XRemoteSceneTransmit); //if you loaded from Favorites
+    } else {
+        scene_manager_next_scene(
+            app->scene_manager, XRemoteSceneMenu); //if you want to directly start with Menu
+    }
 
     view_dispatcher_run(app->view_dispatcher);
 
     xremote_save_settings(app);
-
     furi_hal_power_suppress_charge_exit();
+    xremote_ir_enable_otg(app, false);
     xremote_app_free(app);
 
     return 0;

+ 6 - 1
cross_remote/xremote.h

@@ -36,6 +36,8 @@ typedef struct {
     XRemotePauseSet* xremote_pause_set;
     InfraredRemote* ir_remote_buffer;
     InfraredWorker* ir_worker;
+    bool ir_is_otg_enabled; /**< Whether OTG power (external 5V) is enabled for IR. */
+    uint32_t ir_tx_pin; 
     SubGhzRemote* sg_remote_buffer;
     CrossRemote* cross_remote;
     uint32_t haptic;
@@ -54,6 +56,7 @@ typedef struct {
     char text_store[XREMOTE_TEXT_STORE_NUM][XREMOTE_TEXT_STORE_SIZE + 1];
     SubGhz* subghz;
     NumberInput* number_input;
+    bool loadFavorite;
 } XRemote;
 
 typedef enum {
@@ -98,4 +101,6 @@ typedef enum {
 } XRemoteSettingsStoreState;
 
 void xremote_popup_closed_callback(void* context);
-void xremote_text_input_callback(void* context);
+void xremote_text_input_callback(void* context);
+void xremote_ir_enable_otg(XRemote* app, bool enable);
+void xremote_ir_set_tx_pin(XRemote* app);

+ 1 - 1
cross_remote/xremote_i.h

@@ -51,7 +51,7 @@
 #define XREMOTE_TEXT_STORE_SIZE 128
 #define XREMOTE_MAX_ITEM_NAME_LENGTH 22
 #define XREMOTE_MAX_REMOTE_NAME_LENGTH 22
-#define XREMOTE_VERSION "3.0"
+#define XREMOTE_VERSION FAP_VERSION
 
 #define INFRARED_APP_EXTENSION ".ir"
 #define INFRARED_APP_FOLDER EXT_PATH("infrared")