Просмотр исходного кода

Merge pull request #32 from leedave/feature/gpio_ir

Feature/gpio ir
David Lee 11 месяцев назад
Родитель
Сommit
0a312ff149
11 измененных файлов с 126 добавлено и 50 удалено
  1. 2 0
      README.md
  2. 1 1
      application.fam
  3. 1 0
      docs/README.md
  4. 3 0
      docs/changelog.md
  5. 3 0
      helpers/xremote_custom_event.h
  6. 8 0
      helpers/xremote_storage.c
  7. 2 0
      helpers/xremote_storage.h
  8. 68 45
      scenes/xremote_scene_settings.c
  9. 32 2
      xremote.c
  10. 5 1
      xremote.h
  11. 1 1
      xremote_i.h

+ 2 - 0
README.md

@@ -36,6 +36,8 @@ Wouldn't it be nicer to simply click one button and let everything happen? This
 - 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. 

+ 1 - 1
application.fam

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

+ 1 - 0
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 

+ 3 - 0
docs/changelog.md

@@ -1,3 +1,6 @@
+## 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
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) {

+ 8 - 0
helpers/xremote_storage.c

@@ -61,6 +61,10 @@ void xremote_save_settings(void* context) {
     flipper_format_write_uint32(fff_file, XREMOTE_SETTINGS_KEY_SG_TIMING, &app->sg_timing, 1);
     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");
@@ -115,6 +119,10 @@ void xremote_read_settings(void* context) {
     flipper_format_read_uint32(fff_file, XREMOTE_SETTINGS_KEY_SG_TIMING, &app->sg_timing, 1);
     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
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
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;
 }

+ 32 - 2
xremote.c

@@ -191,10 +191,38 @@ 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
@@ -202,6 +230,8 @@ int32_t xremote_app(void* p) {
         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);
@@ -210,8 +240,8 @@ int32_t xremote_app(void* p) {
     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;

+ 5 - 1
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;
@@ -98,4 +100,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
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.1"
+#define XREMOTE_VERSION "3.2"
 
 #define INFRARED_APP_EXTENSION ".ir"
 #define INFRARED_APP_FOLDER EXT_PATH("infrared")