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

Merge quac from https://github.com/rdefeo/quac

# Conflicts:
#	quac/actions/action_ir.c
Willy-JL 1 год назад
Родитель
Сommit
c9a8993ed2
6 измененных файлов с 64 добавлено и 25 удалено
  1. 8 6
      quac/README.md
  2. 15 0
      quac/actions/action_ir.c
  3. 2 0
      quac/actions/action_ir_utils.h
  4. 1 0
      quac/quac.h
  5. 13 1
      quac/quac_settings.c
  6. 25 18
      quac/scenes/scene_settings.c

+ 8 - 6
quac/README.md

@@ -31,20 +31,20 @@ The app does not provide any recording functionality - you must use the existing
 ## Navigation / Controls
 
 * Pressing `OK` on a folder label will open/navigate to that folder and display it's contents
-* Pressing `OK` on a signal will transmit that signal
+* Pressing `OK` on a signal will transmit that signal / playlist
 * Pressing `Back` will take you up one folder
 * Pressing `Up` and `Down` will, you know, select things up and down...
 * Long pressing `Right` will open that item's settings: Rename, Delete, Import Here, Create Group
 
 ## Signal playback
 
-The signal files are played back as recorded. During playback/transmit, the LED light will flash blue until the action is complete. For RFID signals, they are continuously played back for 2.5 seconds, by default. This can be changed in [application Settings](README.md#application-settings).
+The signal files are played back as recorded. During playback/transmit, the LED light will flash blue until the action is complete. For RFID and NFC signals, they are continuously played back for their defined durations: RFID - 2.5 seconds and NFC - 1 second. These defaults can be changed in [application Settings](README.md#application-settings).
 
 ## Signal Organization
 
 The key to organizing your Quac! interface is to organize your `/ext/apps_data/quac` folder structure. The UI is derived directly from the filesystem structure. Every individual file/signal is given a label on screen. And every folder/directory is a logical group of more files/folders. Selecting a group in the UI will show you the contents of that folder. There is no limit on the number of actions or folders - nest as deep as you want!
 
-You can organize your files by device type, or by function. For example, you may have a folder of "TV" actions, which correspond to Channel Up, Channel Down, Volume Up, Volume Down, etc. Or you may have a "Work Access" folder, which contains files/actions that correspond to Parking Gate, Garage Door, Lobby Entrance.
+You can organize your files by device type, or by function. For example, you may have a folder of "TV" actions, which correspond to Channel Up, Channel Down, Volume Up, Volume Down, etc. Or you may have a "Work" folder, which contains files/actions that correspond to Parking Gate, Garage Door, Lobby Entrance.
 
 The files in a folder can be of mixed types. **This is Quac!'s main strength!** So continuing with the "Work Access" example, the Parking Gate can be Sub-Ghz and the Garage Door can be RFID.
 
@@ -80,7 +80,7 @@ You can chain multiple signal playback actions together by creating a playlist.
 * Comments: lines that start with a `#` are ignored
 * `pause <ms>` on a line will pause the playback by the specified millisecond duration
 * Signal file names can be absolute (full path) or relative to the current directory
-* RFID files can have an optional duration specified. Simply add a space, followed by a millisecond duration. This duration will override the Quac! Settings value, just for this one signal.
+* RFID and NFC files can have an optional duration specified. Simply add a space after the signal's file name, followed by a millisecond duration. This duration will override the Quac! Settings value, just for this one signal.
 
 Errors found in the playlist will halt playback and vibrate the Flipper. Blank lines are ignored.
 
@@ -98,13 +98,14 @@ pause 2500
 /ext/apps_data/quac/06_Lights/Disco_Ball.sub
 
 Lava_Lamp.rfid 4000
+Neon_Strobe.nfc
 ```
 
-The first two `.sub` files live in the `/ext/apps_data/quac` folder, which is where `arrive_home.qpl` is located, and will not show up in any UI screen since they are hidden (start with a `.`). Next, we pause the playlist for 2.5 sec. The next two files live elsewhere, but can still be referenced by the playlist. Lastly, the RFID signal is transmitted for 4000ms, instead of the duration listed in Quac! Settings.
+The first two `.sub` files live in the `/ext/apps_data/quac` folder, which is where `arrive_home.qpl` is located, and they will not show up in any UI screen since they are hidden (they start with a `.`). Next, we pause the playlist for 2.5 sec. The next two files live elsewhere, but can still be referenced by the playlist since they are specified via absolute path. For the last two signals: the RFID signal is transmitted for 4000ms, instead of the duration listed in Quac! Settings, followed by an NFC signal which is transmitted for the default duration.
 
 ## Sorting and Naming
 
-The list view UI is based on the sorted file and folder order. This is enforced by sorting the actual filenames. When there are cases where you need to force a specific order, you can prepend the file and folder names with `XX_` where `X` is a digit between 0-9. This will let you place an action called `On` before `Off`, even though when sorted alphabeticaly, `Off` would come before `On`. Therefore, you would name your files `00_On.rfid` and `01_Off.rfid`. But that looks ugly! When the files and folders are rendered for display, any `XX_` prefix will be stripped. All underscores will be replaced with spaces. Extensions will be stripped. Casing is preserved. Additionally, all files and folders that begin with a `.` will be ignored when drawing the UI - these are "hidden" files. However, they can still be referenced in playlists. This keeps the UI uncluttered.
+The list view UI is based on the sorted file and folder order. This is enforced by sorting the actual filenames. When there are cases where you need to create a specific order, you can prepend the file and folder names with `XX_` where `X` is a digit between 0-9. This will let you place an action called `On` before `Off`, even though when sorted alphabeticaly, `Off` would come before `On`. Therefore, you would name your files `00_On.rfid` and `01_Off.rfid`. But that looks ugly! When the files and folders are rendered for display, any `XX_` prefix will be stripped. All underscores will be replaced with spaces. Extensions will be stripped. Casing is preserved. Additionally, all files and folders that begin with a `.` will be ignored when drawing the UI - these are "hidden" files. However, they can still be referenced in playlists. This keeps the UI uncluttered.
 
 ## Application Settings
 
@@ -118,6 +119,7 @@ The settings menu will appear as the last item when you are viewing the "root" d
 * RFID Duration: Changes the length of time a RFID signal is transmitted. Within playlists, this can be overridden per `.rfid` file.
 * NFC Duration: Changes the length of time a NFC signal is transmitted. Within playlists, this can be overridden per `.nfc` file.
 * SubGhz Ext Ant: Whether to try using the external antenna for sub-ghz signals. If this is "Enabled" but no external antenna is attached, or the external antenna can't be accessed, Quac! will fall back to using the internal antenna.
+* IR Ext Ant: Whether to use the external device for IR signals. If enabled, but no external IR device is attached to TX, then the internal IR device will be used.
 * Show Hidden: Will display files and folders that start with a period (`.`)
 * About: Application info
 

+ 15 - 0
quac/actions/action_ir.c

@@ -29,6 +29,8 @@ void action_ir_tx(void* context, const FuriString* action_path, FuriString* erro
             break;
         }
 
+        if(app->settings.ir_use_ext_module) action_ir_power_otg(true);
+
         if(signal->is_raw) {
             // raw
             FURI_LOG_I(
@@ -62,9 +64,22 @@ void action_ir_tx(void* context, const FuriString* action_path, FuriString* erro
             FURI_LOG_I(TAG, "IR: Send complete");
         }
 
+        if(app->settings.ir_use_ext_module) action_ir_power_otg(false);
     } while(false);
 
     furi_string_free(temp_str);
     flipper_format_free(fff_data_file);
     infrared_utils_signal_free(signal);
 }
+
+void action_ir_power_otg(bool enable) {
+    FuriHalInfraredTxPin tx_pin_detected = furi_hal_infrared_detect_tx_output();
+    furi_hal_infrared_set_tx_output(tx_pin_detected);
+
+    if(tx_pin_detected == FuriHalInfraredTxPinInternal) return;
+
+    if(enable)
+        furi_hal_power_enable_otg();
+    else
+        furi_hal_power_disable_otg();
+}

+ 2 - 0
quac/actions/action_ir_utils.h

@@ -36,3 +36,5 @@ bool infrared_utils_read_signal_at_index(
     FuriString* name);
 
 bool infrared_utils_write_signal(FlipperFormat* fffile, InfraredSignal* signal, FuriString* name);
+
+void action_ir_power_otg(bool enable);

+ 1 - 0
quac/quac.h

@@ -61,6 +61,7 @@ typedef struct App {
         uint32_t nfc_duration; // Defaults to 1000 ms
         uint32_t subghz_repeat; // Defaults to 10, just like the CLI
         bool subghz_use_ext_antenna; // Defaults to False
+        bool ir_use_ext_module; // Defaults to False
         bool show_hidden; // Defaults to False
     } settings;
 

+ 13 - 1
quac/quac_settings.c

@@ -14,6 +14,7 @@ void quac_set_default_settings(App* app) {
     app->settings.nfc_duration = 1000;
     app->settings.subghz_repeat = 10;
     app->settings.subghz_use_ext_antenna = false;
+    app->settings.ir_use_ext_module = false;
     app->settings.show_hidden = false;
 }
 
@@ -91,7 +92,13 @@ void quac_load_settings(App* app) {
         if(!flipper_format_read_uint32(fff_settings, "SubGHz Ext Antenna", &temp_data32, 1)) {
             FURI_LOG_W(TAG, "SETTINGS: Missing 'SubGHz Ext Antenna'");
         } else {
-            app->settings.subghz_use_ext_antenna = (temp_data32 == 1) ? true : false;
+            app->settings.subghz_use_ext_antenna = temp_data32 == 1;
+        }
+
+        if(!flipper_format_read_uint32(fff_settings, "IR Ext Module", &temp_data32, 1)) {
+            FURI_LOG_W(TAG, "SETTINGS: Missing 'IR Ext Module'");
+        } else {
+            app->settings.ir_use_ext_module = temp_data32 == 1;
         }
 
         if(!flipper_format_read_uint32(fff_settings, "Show Hidden", &temp_data32, 1)) {
@@ -161,6 +168,11 @@ void quac_save_settings(App* app) {
             FURI_LOG_E(TAG, "SETTINGS: Failed to write 'SubGHz Ext Antenna'");
             break;
         }
+        temp_data32 = app->settings.ir_use_ext_module ? 1 : 0;
+        if(!flipper_format_write_uint32(fff_settings, "IR Ext Module", &temp_data32, 1)) {
+            FURI_LOG_E(TAG, "SETTINGS: Failed to write 'IR Ext Module'");
+            break;
+        }
         temp_data32 = app->settings.show_hidden ? 1 : 0;
         if(!flipper_format_write_uint32(fff_settings, "Show Hidden", &temp_data32, 1)) {
             FURI_LOG_E(TAG, "SETTINGS: Failed to write 'Show Hidden'");

+ 25 - 18
quac/scenes/scene_settings.c

@@ -14,17 +14,11 @@
 
 #include <lib/toolbox/path.h>
 
-typedef enum {
-    SceneSettingsLayout,
-    SceneSettingsIcons,
-    SceneSettingsHeaders,
-    SceneSettingsRFIDDuration,
-    SceneSettingsNFCDuration,
-    SceneSettingsSubGHzRepeat,
-    SceneSettingsSubGHzExtAnt,
-    SceneSettingsHidden,
-    SceneSettingsAbout
-} SceneSettingsIndex;
+// Unfortunately, the VariableItemList does not provide a method to query the length
+// of the list. Since we intend to place "About" last, it would be convenient to
+// dynamically know it's list index for our on_event method. However, we'll need to
+// hardcode the value..
+#define SCENE_SETTINGS_ABOUT 9 // 10 items in our Settings list, so last index is 9
 
 static const char* const layout_text[2] = {"Vert", "Horiz"};
 static const uint32_t layout_value[2] = {QUAC_APP_PORTRAIT, QUAC_APP_LANDSCAPE};
@@ -67,8 +61,8 @@ static const char* const repeat_text[V_REPEAT_COUNT] = {
     "50"};
 static const uint32_t repeat_value[V_REPEAT_COUNT] = {1, 2, 3, 5, 8, 10, 15, 20, 50};
 
-static const char* const subghz_ext_text[2] = {"Disabled", "Enabled"};
-static const uint32_t subghz_ext_value[2] = {false, true};
+static const char* const disabled_enabled_text[2] = {"Disabled", "Enabled"};
+static const uint32_t disabled_enabled_value[2] = {false, true};
 
 static void scene_settings_layout_changed(VariableItem* item) {
     App* app = variable_item_get_context(item);
@@ -115,8 +109,15 @@ static void scene_settings_subghz_repeat_changed(VariableItem* item) {
 static void scene_settings_subghz_ext_changed(VariableItem* item) {
     App* app = variable_item_get_context(item);
     uint8_t index = variable_item_get_current_value_index(item);
-    variable_item_set_current_value_text(item, subghz_ext_text[index]);
-    app->settings.subghz_use_ext_antenna = subghz_ext_value[index];
+    variable_item_set_current_value_text(item, disabled_enabled_text[index]);
+    app->settings.subghz_use_ext_antenna = disabled_enabled_value[index];
+}
+
+static void scene_settings_ir_ext_changed(VariableItem* item) {
+    App* app = variable_item_get_context(item);
+    uint8_t index = variable_item_get_current_value_index(item);
+    variable_item_set_current_value_text(item, disabled_enabled_text[index]);
+    app->settings.ir_use_ext_module = disabled_enabled_value[index];
 }
 
 static void scene_settings_show_hidden_changed(VariableItem* item) {
@@ -178,9 +179,15 @@ void scene_settings_on_enter(void* context) {
 
     item =
         variable_item_list_add(vil, "SubGHz Ext Ant", 2, scene_settings_subghz_ext_changed, app);
-    value_index = value_index_uint32(app->settings.subghz_use_ext_antenna, subghz_ext_value, 2);
+    value_index =
+        value_index_uint32(app->settings.subghz_use_ext_antenna, disabled_enabled_value, 2);
+    variable_item_set_current_value_index(item, value_index);
+    variable_item_set_current_value_text(item, disabled_enabled_text[value_index]);
+
+    item = variable_item_list_add(vil, "IR Ext Module", 2, scene_settings_ir_ext_changed, app);
+    value_index = value_index_uint32(app->settings.ir_use_ext_module, disabled_enabled_value, 2);
     variable_item_set_current_value_index(item, value_index);
-    variable_item_set_current_value_text(item, subghz_ext_text[value_index]);
+    variable_item_set_current_value_text(item, disabled_enabled_text[value_index]);
 
     item = variable_item_list_add(vil, "Show Hidden", 2, scene_settings_show_hidden_changed, app);
     value_index = value_index_uint32(app->settings.show_hidden, show_offon_value, 2);
@@ -200,7 +207,7 @@ bool scene_settings_on_event(void* context, SceneManagerEvent event) {
 
     if(event.type == SceneManagerEventTypeCustom) {
         switch(event.event) {
-        case SceneSettingsAbout:
+        case SCENE_SETTINGS_ABOUT:
             consumed = true;
             scene_manager_next_scene(app->scene_manager, QScene_About);
             break;