diff --git a/headers/addons/i2cdisplay.h b/headers/addons/i2cdisplay.h index c7d5c6b02..9708bb17c 100644 --- a/headers/addons/i2cdisplay.h +++ b/headers/addons/i2cdisplay.h @@ -62,6 +62,10 @@ #define SPLASH_DURATION 7500 // Duration in milliseconds #endif +#ifndef DISPLAY_TURN_OFF_WHEN_SUSPENDED +#define DISPLAY_TURN_OFF_WHEN_SUSPENDED 0 +#endif + #ifndef DEFAULT_SPLASH #define DEFAULT_SPLASH \ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \ @@ -211,6 +215,7 @@ class I2CDisplayAddon : public GPAddon uint16_t prevButtonState; bool isFocusModeEnabled; bool focusModePrevState; + bool turnOffWhenSuspended; }; #endif diff --git a/headers/addons/neopicoleds.h b/headers/addons/neopicoleds.h index 6a7b94c71..e01b0cb31 100644 --- a/headers/addons/neopicoleds.h +++ b/headers/addons/neopicoleds.h @@ -146,6 +146,10 @@ #define LEDS_BUTTON_A2 -1 #endif +#ifndef LEDS_TURN_OFF_WHEN_SUSPENDED +#define LEDS_TURN_OFF_WHEN_SUSPENDED 0 +#endif + void configureAnimations(AnimationStation *as); AnimationHotkey animationHotkeys(Gamepad *gamepad); PixelMatrix createLedButtonLayout(ButtonLayout layout, int ledsPerPixel); @@ -192,6 +196,7 @@ class NeoPicoLEDAddon : public GPAddon { std::map buttonPositions; bool isFocusModeEnabled; bool focusModePrevState; + bool turnOffWhenSuspended; }; #endif diff --git a/headers/addons/pleds.h b/headers/addons/pleds.h index f44aa387a..679876e5b 100644 --- a/headers/addons/pleds.h +++ b/headers/addons/pleds.h @@ -48,6 +48,9 @@ class PlayerLEDAddon : public GPAddon PLEDType type; PWMPlayerLEDs *pwmLEDs = nullptr; PLEDAnimationState animationState; + +private: + bool turnOffWhenSuspended; }; #endif diff --git a/lib/TinyUSB_Gamepad/src/tusb_driver.cpp b/lib/TinyUSB_Gamepad/src/tusb_driver.cpp index 45c9be20b..395c19cb9 100644 --- a/lib/TinyUSB_Gamepad/src/tusb_driver.cpp +++ b/lib/TinyUSB_Gamepad/src/tusb_driver.cpp @@ -20,7 +20,8 @@ UsbMode usb_mode = USB_MODE_HID; InputMode input_mode = INPUT_MODE_XINPUT; -bool usb_mounted = false; +static bool usb_mounted = false; +static bool usb_suspended = false; InputMode get_input_mode(void) { @@ -32,6 +33,11 @@ bool get_usb_mounted(void) return usb_mounted; } +bool get_usb_suspended(void) +{ + return usb_suspended; +} + void initialize_driver(InputMode mode) { input_mode = mode; @@ -191,9 +197,11 @@ void tud_umount_cb(void) void tud_suspend_cb(bool remote_wakeup_en) { (void)remote_wakeup_en; + usb_suspended = true; } // Invoked when usb bus is resumed void tud_resume_cb(void) { + usb_suspended = false; } diff --git a/lib/TinyUSB_Gamepad/src/usb_driver.h b/lib/TinyUSB_Gamepad/src/usb_driver.h index 91e4bd98f..accbd0819 100644 --- a/lib/TinyUSB_Gamepad/src/usb_driver.h +++ b/lib/TinyUSB_Gamepad/src/usb_driver.h @@ -16,6 +16,7 @@ typedef enum InputMode get_input_mode(void); bool get_usb_mounted(void); +bool get_usb_suspended(void); void initialize_driver(InputMode mode); void receive_report(uint8_t *buffer); bool send_report(void *report, uint16_t report_size); diff --git a/proto/config.proto b/proto/config.proto index 3f5ed50c5..c68716a47 100644 --- a/proto/config.proto +++ b/proto/config.proto @@ -164,6 +164,7 @@ message DisplayOptions optional bool invert = 16; optional int32 displaySaverTimeout = 17; + optional bool turnOffWhenSuspended = 18; } message LEDOptions @@ -200,6 +201,8 @@ message LEDOptions optional int32 pledPin3 = 28; optional int32 pledPin4 = 29; optional uint32 pledColor = 30; + + optional bool turnOffWhenSuspended = 31; }; // This has to be kept in sync with AnimationOptions in AnimationStation.hpp diff --git a/src/addons/i2cdisplay.cpp b/src/addons/i2cdisplay.cpp index bdd6fc22f..3fc8d04fc 100644 --- a/src/addons/i2cdisplay.cpp +++ b/src/addons/i2cdisplay.cpp @@ -13,6 +13,7 @@ #include "ps4_driver.h" #include "helper.h" #include "config.pb.h" +#include "usb_driver.h" bool I2CDisplayAddon::available() { const DisplayOptions& options = Storage::getInstance().getDisplayOptions(); @@ -56,10 +57,18 @@ void I2CDisplayAddon::setup() { displaySaverTimer = options.displaySaverTimeout; displaySaverTimeout = displaySaverTimer; configMode = Storage::getInstance().GetConfigMode(); + turnOffWhenSuspended = options.turnOffWhenSuspended; } bool I2CDisplayAddon::isDisplayPowerOff() { + if (turnOffWhenSuspended && get_usb_suspended()) { + if (displayIsPowerOn) setDisplayPower(0); + return true; + } else { + if (!displayIsPowerOn) setDisplayPower(1); + } + if (!displaySaverTimeout && !isFocusModeEnabled) return false; float diffTime = getMillis() - prevMillis; diff --git a/src/addons/neopicoleds.cpp b/src/addons/neopicoleds.cpp index 912b0ae1d..c3c81efb5 100644 --- a/src/addons/neopicoleds.cpp +++ b/src/addons/neopicoleds.cpp @@ -12,6 +12,7 @@ #include "addons/neopicoleds.h" #include "addons/pleds.h" #include "themes.h" +#include "usb_driver.h" #include "enums.h" #include "helper.h" @@ -110,6 +111,7 @@ void NeoPicoLEDAddon::setup() { // Set Default LED Options const LEDOptions& ledOptions = Storage::getInstance().getLedOptions(); + turnOffWhenSuspended = ledOptions.turnOffWhenSuspended; if ( ledOptions.pledType == PLED_TYPE_RGB ) { neoPLEDs = new NeoPicoPlayerLEDs(); @@ -178,6 +180,13 @@ void NeoPicoLEDAddon::process() } } } + + if (turnOffWhenSuspended && get_usb_suspended()) { + as.DimBrightnessTo0(); + } else { + as.SetBrightness(AnimationStation::GetBrightness()); + } + as.ApplyBrightness(frame); // Apply the player LEDs to our first 4 leds if we're in NEOPIXEL mode diff --git a/src/addons/playerleds.cpp b/src/addons/playerleds.cpp index d24c94ecc..852c535fa 100644 --- a/src/addons/playerleds.cpp +++ b/src/addons/playerleds.cpp @@ -9,6 +9,7 @@ #include "hardware/pwm.h" #include "GamepadEnums.h" #include "xinput_driver.h" +#include "usb_driver.h" // GP2040 Includes #include "addons/pleds.h" @@ -83,6 +84,8 @@ bool PlayerLEDAddon::available() { void PlayerLEDAddon::setup() { const LEDOptions& ledOptions = Storage::getInstance().getLedOptions(); + turnOffWhenSuspended = ledOptions.turnOffWhenSuspended; + switch (ledOptions.pledType) { case PLED_TYPE_PWM: @@ -99,6 +102,8 @@ void PlayerLEDAddon::setup() { void PlayerLEDAddon::process() { + if (turnOffWhenSuspended && get_usb_suspended()) return; + Gamepad * gamepad = Storage::getInstance().GetProcessedGamepad(); const LEDOptions& ledOptions = Storage::getInstance().getLedOptions(); diff --git a/src/config_utils.cpp b/src/config_utils.cpp index c252affe7..25effcea7 100644 --- a/src/config_utils.cpp +++ b/src/config_utils.cpp @@ -206,6 +206,7 @@ void ConfigUtils::initUnsetPropertiesWithDefaults(Config& config) INIT_UNSET_PROPERTY(config.displayOptions, i2cSpeed, I2C_SPEED); INIT_UNSET_PROPERTY(config.displayOptions, buttonLayout, BUTTON_LAYOUT); INIT_UNSET_PROPERTY(config.displayOptions, buttonLayoutRight, BUTTON_LAYOUT_RIGHT); + INIT_UNSET_PROPERTY(config.displayOptions, turnOffWhenSuspended, DISPLAY_TURN_OFF_WHEN_SUSPENDED); ButtonLayoutParamsLeft& paramsLeft = config.displayOptions.buttonLayoutCustomOptions.paramsLeft; INIT_UNSET_PROPERTY(paramsLeft, layout, BUTTON_LAYOUT); @@ -277,6 +278,7 @@ void ConfigUtils::initUnsetPropertiesWithDefaults(Config& config) INIT_UNSET_PROPERTY(config.ledOptions, ledsPerButton, LEDS_PER_PIXEL); INIT_UNSET_PROPERTY(config.ledOptions, brightnessMaximum, LED_BRIGHTNESS_MAXIMUM); INIT_UNSET_PROPERTY(config.ledOptions, brightnessSteps, LED_BRIGHTNESS_STEPS); + INIT_UNSET_PROPERTY(config.ledOptions, turnOffWhenSuspended, LEDS_TURN_OFF_WHEN_SUSPENDED); INIT_UNSET_PROPERTY(config.ledOptions, indexUp, LEDS_DPAD_UP); INIT_UNSET_PROPERTY(config.ledOptions, indexDown, LEDS_DPAD_DOWN); diff --git a/src/configs/webconfig.cpp b/src/configs/webconfig.cpp index 49ae3dc63..34c741e47 100644 --- a/src/configs/webconfig.cpp +++ b/src/configs/webconfig.cpp @@ -415,6 +415,7 @@ std::string setDisplayOptions(DisplayOptions& displayOptions) readDoc(displayOptions.splashChoice, doc, "splashChoice"); readDoc(displayOptions.splashDuration, doc, "splashDuration"); readDoc(displayOptions.displaySaverTimeout, doc, "displaySaverTimeout"); + readDoc(displayOptions.turnOffWhenSuspended, doc, "turnOffWhenSuspended"); readDoc(displayOptions.buttonLayoutCustomOptions.paramsLeft.layout, doc, "buttonLayoutCustomOptions", "params", "layout"); readDoc(displayOptions.buttonLayoutCustomOptions.paramsLeft.common.startX, doc, "buttonLayoutCustomOptions", "params", "startX"); @@ -461,6 +462,7 @@ std::string getDisplayOptions() // Manually set Document Attributes for the disp writeDoc(doc, "splashChoice", displayOptions.splashChoice); writeDoc(doc, "splashDuration", displayOptions.splashDuration); writeDoc(doc, "displaySaverTimeout", displayOptions.displaySaverTimeout); + writeDoc(doc, "turnOffWhenSuspended", displayOptions.turnOffWhenSuspended); writeDoc(doc, "buttonLayoutCustomOptions", "params", "layout", displayOptions.buttonLayoutCustomOptions.paramsLeft.layout); writeDoc(doc, "buttonLayoutCustomOptions", "params", "startX", displayOptions.buttonLayoutCustomOptions.paramsLeft.common.startX); @@ -655,6 +657,7 @@ std::string setLedOptions() readDoc(ledOptions.ledsPerButton, doc, "ledsPerButton"); readDoc(ledOptions.brightnessMaximum, doc, "brightnessMaximum"); readDoc(ledOptions.brightnessSteps, doc, "brightnessSteps"); + readDoc(ledOptions.turnOffWhenSuspended, doc, "turnOffWhenSuspended"); readIndex(ledOptions.indexUp, "ledButtonMap", "Up"); readIndex(ledOptions.indexDown, "ledButtonMap", "Down"); readIndex(ledOptions.indexLeft, "ledButtonMap", "Left"); @@ -694,6 +697,7 @@ std::string getLedOptions() writeDoc(doc, "ledsPerButton", ledOptions.ledsPerButton); writeDoc(doc, "brightnessMaximum", ledOptions.brightnessMaximum); writeDoc(doc, "brightnessSteps", ledOptions.brightnessSteps); + writeDoc(doc, "turnOffWhenSuspended", ledOptions.turnOffWhenSuspended); const auto writeIndex = [&](const char* key0, const char* key1, int var) { diff --git a/www/server/app.js b/www/server/app.js index b214339cf..e00a2aa1f 100644 --- a/www/server/app.js +++ b/www/server/app.js @@ -69,6 +69,7 @@ app.get('/api/getDisplayOptions', (req, res) => { }, displaySaverTimeout: 0, + turnOffWhenSuspended: 0, }; console.log('data', data); return res.send(data); @@ -192,6 +193,7 @@ app.get('/api/getLedOptions', (req, res) => { pledPin3: 14, pledPin4: 15, pledColor: 65280, + turnOffWhenSuspended: 0, }); }); diff --git a/www/src/Locales/en/DisplayConfig.jsx b/www/src/Locales/en/DisplayConfig.jsx index 9e9125dd0..ec0e8bcd0 100644 --- a/www/src/Locales/en/DisplayConfig.jsx +++ b/www/src/Locales/en/DisplayConfig.jsx @@ -31,5 +31,6 @@ export default { 'splash-duration-label': 'Splash Duration (seconds, 0 for Always On)', 'display-saver-timeout-label': 'Display Saver Timeout (minutes)', 'inverted-label': 'Inverted', + 'turn-off-when-suspended': 'Turn Off When Suspended' }, }; diff --git a/www/src/Locales/en/LedConfig.jsx b/www/src/Locales/en/LedConfig.jsx index eabcdca3d..7c79226c2 100644 --- a/www/src/Locales/en/LedConfig.jsx +++ b/www/src/Locales/en/LedConfig.jsx @@ -31,4 +31,5 @@ export default { 'available-header-text': 'Available Buttons', 'assigned-header-text': 'Assigned Buttons', }, + 'turn-off-when-suspended': 'Turn Off When Suspended' }; diff --git a/www/src/Pages/DisplayConfig.jsx b/www/src/Pages/DisplayConfig.jsx index 0eec9a0ac..5f792cf75 100644 --- a/www/src/Pages/DisplayConfig.jsx +++ b/www/src/Pages/DisplayConfig.jsx @@ -149,6 +149,7 @@ const schema = yup.object().shape({ .oneOf(DISPLAY_FLIP_MODES.map((o) => o.value)) .label('Flip Display'), invertDisplay: yup.number().label('Invert Display'), + turnOffWhenSuspended: yup.number().label('Turn Off When Suspended'), buttonLayout: buttonLayoutSchema, buttonLayoutRight: buttonLayoutRightSchema, splashMode: yup @@ -226,6 +227,8 @@ const FormContext = () => { values.splashChoice = parseInt(values.splashChoice); if (!!values.splashDuration) values.splashDuration = parseInt(values.splashDuration); + if (!!values.turnOffWhenSuspended) + values.turnOffWhenSuspended = parseInt(values.turnOffWhenSuspended); await WebApi.setDisplayOptions(values, true); } @@ -241,6 +244,8 @@ const FormContext = () => { values.flipDisplay = parseInt(values.flipDisplay); if (!!values.invertDisplay) values.invertDisplay = parseInt(values.invertDisplay); + if (!!values.turnOffWhenSuspended) + values.turnOffWhenSuspended = parseInt(values.turnOffWhenSuspended); if (!!values.buttonLayout) values.buttonLayout = parseInt(values.buttonLayout); if (!!values.buttonLayoutRight) @@ -291,7 +296,7 @@ export default function DisplayConfigPage() { onSubmit={onSuccess} initialValues={defaultValues} > - {({ handleSubmit, handleChange, handleBlur, values, touched, errors }) => + {({ handleSubmit, handleChange, handleBlur, values, touched, errors, setFieldValue }) => console.log('errors', errors) || console.log('values', values) || (
@@ -511,6 +516,21 @@ export default function DisplayConfigPage() { ))} +
+ { + setFieldValue( + 'turnOffWhenSuspended', + e.target.checked ? 1 : 0, + ); + }} + /> +
{ @@ -314,6 +315,8 @@ export default function LEDConfigPage() { const data = { ...values }; data.pledType = parseInt(values.pledType); if (data.pledColor) data.pledColor = hexToInt(values.pledColor); + if (!!data.turnOffWhenSuspended) + data.turnOffWhenSuspended = parseInt(values.turnOffWhenSuspended); const success = await WebApi.setLedOptions(data); if (success) updateUsedPins(); @@ -369,6 +372,7 @@ export default function LEDConfigPage() { setValues, values, errors, + setFieldValue, }) => (
+
+ { + setFieldValue( + 'turnOffWhenSuspended', + e.target.checked ? 1 : 0, + ); + }} + /> +
@@ -619,6 +638,21 @@ export default function LEDConfigPage() { show={showPicker} target={colorPickerTarget} > +
+ { + setFieldValue( + 'turnOffWhenSuspended', + e.target.checked ? 1 : 0, + ); + }} + /> +