diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index acb7e9c39a..4c6c745df2 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -236,6 +236,10 @@ #include "feature/stepper_driver_safety.h" #endif +#if ENABLED(PSU_CONTROL) + #include "feature/power.h" +#endif + PGMSTR(M112_KILL_STR, "M112 Shutdown"); MarlinState marlin_state = MF_INITIALIZING; @@ -932,7 +936,7 @@ void minkill(const bool steppers_off/*=false*/) { // Power off all steppers (for M112) or just the E steppers steppers_off ? disable_all_steppers() : disable_e_steppers(); - TERN_(PSU_CONTROL, PSU_OFF()); + TERN_(PSU_CONTROL, powerManager.power_off()); TERN_(HAS_SUICIDE, suicide()); @@ -1235,8 +1239,7 @@ void setup() { #if ENABLED(PSU_CONTROL) SETUP_LOG("PSU_CONTROL"); - powersupply_on = ENABLED(PSU_DEFAULT_OFF); - if (ENABLED(PSU_DEFAULT_OFF)) PSU_OFF(); else PSU_ON(); + powerManager.init(); #endif #if ENABLED(POWER_LOSS_RECOVERY) diff --git a/Marlin/src/MarlinCore.h b/Marlin/src/MarlinCore.h index 243811d7fb..d7ab11d046 100644 --- a/Marlin/src/MarlinCore.h +++ b/Marlin/src/MarlinCore.h @@ -81,25 +81,6 @@ extern bool wait_for_heatup; void wait_for_user_response(millis_t ms=0, const bool no_sleep=false); #endif -#if ENABLED(PSU_CONTROL) - extern bool powersupply_on; - #define PSU_PIN_ON() do{ OUT_WRITE(PS_ON_PIN, PSU_ACTIVE_STATE); powersupply_on = true; }while(0) - #define PSU_PIN_OFF() do{ OUT_WRITE(PS_ON_PIN, !PSU_ACTIVE_STATE); powersupply_on = false; }while(0) - #if ENABLED(AUTO_POWER_CONTROL) - #define PSU_ON() powerManager.power_on() - #define PSU_OFF() powerManager.power_off() - #define PSU_OFF_SOON() powerManager.power_off_soon() - #else - #define PSU_ON() PSU_PIN_ON() - #if ENABLED(PS_OFF_SOUND) - #define PSU_OFF() do{ BUZZ(1000, 659); PSU_PIN_OFF(); }while(0) - #else - #define PSU_OFF() PSU_PIN_OFF() - #endif - #define PSU_OFF_SOON PSU_OFF - #endif -#endif - bool pin_is_protected(const pin_t pin); #if HAS_SUICIDE diff --git a/Marlin/src/feature/power.cpp b/Marlin/src/feature/power.cpp index 9b173d6ee7..30bf0d764d 100644 --- a/Marlin/src/feature/power.cpp +++ b/Marlin/src/feature/power.cpp @@ -26,10 +26,7 @@ #include "../inc/MarlinConfig.h" -#if ENABLED(AUTO_POWER_CONTROL) - #include "power.h" -#include "../module/temperature.h" #include "../module/stepper/indirection.h" #include "../MarlinCore.h" @@ -41,133 +38,183 @@ #include "../gcode/gcode.h" #endif -#if BOTH(USE_CONTROLLER_FAN, AUTO_POWER_CONTROLLERFAN) - #include "controllerfan.h" -#endif +#if EITHER(PSU_CONTROL, AUTO_POWER_CONTROL) Power powerManager; +bool Power::psu_on; -millis_t Power::lastPowerOn; - -bool Power::is_power_needed() { - - if (printJobOngoing() || printingIsPaused()) return true; - - #if ENABLED(AUTO_POWER_FANS) - FANS_LOOP(i) if (thermalManager.fan_speed[i]) return true; - #endif - - #if ENABLED(AUTO_POWER_E_FANS) - HOTEND_LOOP() if (thermalManager.autofan_speed[e]) return true; - #endif +#if ENABLED(AUTO_POWER_CONTROL) + #include "../module/temperature.h" #if BOTH(USE_CONTROLLER_FAN, AUTO_POWER_CONTROLLERFAN) - if (controllerFan.state()) return true; + #include "controllerfan.h" #endif - if (TERN0(AUTO_POWER_CHAMBER_FAN, thermalManager.chamberfan_speed)) - return true; - - if (TERN0(AUTO_POWER_COOLER_FAN, thermalManager.coolerfan_speed)) - return true; - - // If any of the drivers or the bed are enabled... - if (X_ENABLE_READ() == X_ENABLE_ON || Y_ENABLE_READ() == Y_ENABLE_ON || Z_ENABLE_READ() == Z_ENABLE_ON - #if HAS_X2_ENABLE - || X2_ENABLE_READ() == X_ENABLE_ON - #endif - #if HAS_Y2_ENABLE - || Y2_ENABLE_READ() == Y_ENABLE_ON - #endif - #if HAS_Z2_ENABLE - || Z2_ENABLE_READ() == Z_ENABLE_ON - #endif - #if E_STEPPERS - #define _OR_ENABLED_E(N) || E##N##_ENABLE_READ() == E_ENABLE_ON - REPEAT(E_STEPPERS, _OR_ENABLED_E) - #endif - ) return true; - - #if HAS_HOTEND - HOTEND_LOOP() if (thermalManager.degTargetHotend(e) > 0 || thermalManager.temp_hotend[e].soft_pwm_amount > 0) return true; - #endif - - if (TERN0(HAS_HEATED_BED, thermalManager.degTargetBed() > 0 || thermalManager.temp_bed.soft_pwm_amount > 0)) return true; - - #if HAS_HOTEND && AUTO_POWER_E_TEMP - HOTEND_LOOP() if (thermalManager.degHotend(e) >= (AUTO_POWER_E_TEMP)) return true; - #endif - - #if HAS_HEATED_CHAMBER && AUTO_POWER_CHAMBER_TEMP - if (thermalManager.degChamber() >= (AUTO_POWER_CHAMBER_TEMP)) return true; - #endif - - #if HAS_COOLER && AUTO_POWER_COOLER_TEMP - if (thermalManager.degCooler() >= (AUTO_POWER_COOLER_TEMP)) return true; - #endif - - return false; -} - -#ifndef POWER_TIMEOUT - #define POWER_TIMEOUT 0 + millis_t Power::lastPowerOn; #endif -void Power::check(const bool pause) { - static bool _pause = false; - static millis_t nextPowerCheck = 0; - const millis_t now = millis(); - #if POWER_TIMEOUT > 0 - if (pause != _pause) { - lastPowerOn = now + !now; - _pause = pause; - } - if (pause) return; - #endif - if (ELAPSED(now, nextPowerCheck)) { - nextPowerCheck = now + 2500UL; - if (is_power_needed()) - power_on(); - else if (!lastPowerOn || (POWER_TIMEOUT > 0 && ELAPSED(now, lastPowerOn + SEC_TO_MS(POWER_TIMEOUT)))) - power_off(); - } +/** + * Initialize pins & state for the power manager. + * + */ +void Power::init(){ + psu_on = ENABLED(PSU_DEFAULT_OFF); // Set opposite state to get full power_off/on + TERN(PSU_DEFAULT_OFF, power_off(), power_on()); } +/** + * Power on if the power is currently off. + * Restores stepper drivers and processes any PSU_POWERUP_GCODE. + * + */ void Power::power_on() { - const millis_t now = millis(); - lastPowerOn = now + !now; - if (!powersupply_on) { - PSU_PIN_ON(); - safe_delay(PSU_POWERUP_DELAY); - restore_stepper_drivers(); - TERN_(HAS_TRINAMIC_CONFIG, safe_delay(PSU_POWERUP_DELAY)); - #ifdef PSU_POWERUP_GCODE - GcodeSuite::process_subcommands_now_P(PSTR(PSU_POWERUP_GCODE)); - #endif - } -} + #if ENABLED(AUTO_POWER_CONTROL) + const millis_t now = millis(); + lastPowerOn = now + !now; + #endif -void Power::power_off() { - if (powersupply_on) { - #ifdef PSU_POWEROFF_GCODE - GcodeSuite::process_subcommands_now_P(PSTR(PSU_POWEROFF_GCODE)); - #endif + if (psu_on) return; - #if ENABLED(PS_OFF_SOUND) - BUZZ(1000, 659); - #endif + OUT_WRITE(PS_ON_PIN, PSU_ACTIVE_STATE); + psu_on = true; + safe_delay(PSU_POWERUP_DELAY); + restore_stepper_drivers(); + TERN_(HAS_TRINAMIC_CONFIG, safe_delay(PSU_POWERUP_DELAY)); - PSU_PIN_OFF(); - } -} - -void Power::power_off_soon() { - #if POWER_OFF_DELAY - lastPowerOn = millis() - SEC_TO_MS(POWER_TIMEOUT) + SEC_TO_MS(POWER_OFF_DELAY); - //if (!lastPowerOn) ++lastPowerOn; - #else - power_off(); + #ifdef PSU_POWERUP_GCODE + GcodeSuite::process_subcommands_now_P(PSTR(PSU_POWERUP_GCODE)); #endif } +/** + * Power off if the power is currently on. + * Processes any PSU_POWEROFF_GCODE and makes a PS_OFF_SOUND if enabled. + * + */ +void Power::power_off() { + if (!psu_on) return; + + #ifdef PSU_POWEROFF_GCODE + GcodeSuite::process_subcommands_now_P(PSTR(PSU_POWEROFF_GCODE)); + #endif + + #if ENABLED(PS_OFF_SOUND) + BUZZ(1000, 659); + #endif + + OUT_WRITE(PS_ON_PIN, !PSU_ACTIVE_STATE); + psu_on = false; +} + + +#if ENABLED(AUTO_POWER_CONTROL) + + #ifndef POWER_TIMEOUT + #define POWER_TIMEOUT 0 + #endif + + /** + * Check all conditions that would signal power needing to be on. + * + * @returns bool if power is needed + */ + bool Power::is_power_needed() { + + if (printJobOngoing() || printingIsPaused()) return true; + + #if ENABLED(AUTO_POWER_FANS) + FANS_LOOP(i) if (thermalManager.fan_speed[i]) return true; + #endif + + #if ENABLED(AUTO_POWER_E_FANS) + HOTEND_LOOP() if (thermalManager.autofan_speed[e]) return true; + #endif + + #if BOTH(USE_CONTROLLER_FAN, AUTO_POWER_CONTROLLERFAN) + if (controllerFan.state()) return true; + #endif + + if (TERN0(AUTO_POWER_CHAMBER_FAN, thermalManager.chamberfan_speed)) + return true; + + if (TERN0(AUTO_POWER_COOLER_FAN, thermalManager.coolerfan_speed)) + return true; + + // If any of the drivers or the bed are enabled... + if (X_ENABLE_READ() == X_ENABLE_ON || Y_ENABLE_READ() == Y_ENABLE_ON || Z_ENABLE_READ() == Z_ENABLE_ON + #if HAS_X2_ENABLE + || X2_ENABLE_READ() == X_ENABLE_ON + #endif + #if HAS_Y2_ENABLE + || Y2_ENABLE_READ() == Y_ENABLE_ON + #endif + #if HAS_Z2_ENABLE + || Z2_ENABLE_READ() == Z_ENABLE_ON + #endif + #if E_STEPPERS + #define _OR_ENABLED_E(N) || E##N##_ENABLE_READ() == E_ENABLE_ON + REPEAT(E_STEPPERS, _OR_ENABLED_E) + #endif + ) return true; + + #if HAS_HOTEND + HOTEND_LOOP() if (thermalManager.degTargetHotend(e) > 0 || thermalManager.temp_hotend[e].soft_pwm_amount > 0) return true; + #endif + + if (TERN0(HAS_HEATED_BED, thermalManager.degTargetBed() > 0 || thermalManager.temp_bed.soft_pwm_amount > 0)) return true; + + #if HAS_HOTEND && AUTO_POWER_E_TEMP + HOTEND_LOOP() if (thermalManager.degHotend(e) >= (AUTO_POWER_E_TEMP)) return true; + #endif + + #if HAS_HEATED_CHAMBER && AUTO_POWER_CHAMBER_TEMP + if (thermalManager.degChamber() >= (AUTO_POWER_CHAMBER_TEMP)) return true; + #endif + + #if HAS_COOLER && AUTO_POWER_COOLER_TEMP + if (thermalManager.degCooler() >= (AUTO_POWER_COOLER_TEMP)) return true; + #endif + + return false; + } + + /** + * Check if we should power off automatically (POWER_TIMEOUT elapsed, !is_power_needed). + * + * @param pause pause the 'timer' + */ + void Power::check(const bool pause) { + static millis_t nextPowerCheck = 0; + const millis_t now = millis(); + #if POWER_TIMEOUT > 0 + static bool _pause = false; + if (pause != _pause) { + lastPowerOn = now + !now; + _pause = pause; + } + if (pause) return; + #endif + if (ELAPSED(now, nextPowerCheck)) { + nextPowerCheck = now + 2500UL; + if (is_power_needed()) + power_on(); + else if (!lastPowerOn || (POWER_TIMEOUT > 0 && ELAPSED(now, lastPowerOn + SEC_TO_MS(POWER_TIMEOUT)))) + power_off(); + } + } + + #if POWER_OFF_DELAY > 0 + + /** + * Power off with a delay. Power off is triggered by check() after the delay. + * + */ + void Power::power_off_soon() { + lastPowerOn = millis() - SEC_TO_MS(POWER_TIMEOUT) + SEC_TO_MS(POWER_OFF_DELAY); + } + + #endif + #endif // AUTO_POWER_CONTROL + +#endif // PSU_CONTROL || AUTO_POWER_CONTROL diff --git a/Marlin/src/feature/power.h b/Marlin/src/feature/power.h index bca5432946..7f5a97e6df 100644 --- a/Marlin/src/feature/power.h +++ b/Marlin/src/feature/power.h @@ -25,17 +25,32 @@ * power.h - power control */ -#include "../core/millis_t.h" +#if ENABLED(AUTO_POWER_CONTROL) + #include "../core/millis_t.h" +#endif class Power { public: - static void check(const bool pause); + static bool psu_on; + + static void init(); static void power_on(); static void power_off(); + + #if ENABLED(AUTO_POWER_CONTROL) && POWER_OFF_DELAY > 0 static void power_off_soon(); - private: - static millis_t lastPowerOn; - static bool is_power_needed(); + #else + static inline void power_off_soon() { power_off(); } + #endif + + #if ENABLED(AUTO_POWER_CONTROL) + static void check(const bool pause); + + private: + static millis_t lastPowerOn; + static bool is_power_needed(); + + #endif }; extern Power powerManager; diff --git a/Marlin/src/gcode/control/M80_M81.cpp b/Marlin/src/gcode/control/M80_M81.cpp index 00a0a31026..f6ce9a9c87 100644 --- a/Marlin/src/gcode/control/M80_M81.cpp +++ b/Marlin/src/gcode/control/M80_M81.cpp @@ -29,25 +29,17 @@ #include "../../inc/MarlinConfig.h" +#if ENABLED(PSU_CONTROL) + #include "../queue.h" + #include "../../feature/power.h" +#endif + #if HAS_SUICIDE #include "../../MarlinCore.h" #endif #if ENABLED(PSU_CONTROL) - #if ENABLED(AUTO_POWER_CONTROL) - #include "../../feature/power.h" - #else - void restore_stepper_drivers(); - #endif - - // Could be moved to a feature, but this is all the data - bool powersupply_on; - - #if HAS_TRINAMIC_CONFIG - #include "../../feature/tmc_util.h" - #endif - /** * M80 : Turn on the Power Supply * M80 S : Report the current state and exit @@ -56,11 +48,11 @@ // S: Report the current power supply state and exit if (parser.seen('S')) { - SERIAL_ECHOPGM_P(powersupply_on ? PSTR("PS:1\n") : PSTR("PS:0\n")); + SERIAL_ECHOPGM_P(powerManager.psu_on ? PSTR("PS:1\n") : PSTR("PS:0\n")); return; } - PSU_ON(); + powerManager.power_on(); /** * If you have a switch on suicide pin, this is useful @@ -71,12 +63,6 @@ OUT_WRITE(SUICIDE_PIN, !SUICIDE_PIN_INVERTING); #endif - #if DISABLED(AUTO_POWER_CONTROL) - safe_delay(PSU_POWERUP_DELAY); - restore_stepper_drivers(); - TERN_(HAS_TRINAMIC_CONFIG, safe_delay(PSU_POWERUP_DELAY)); - #endif - TERN_(HAS_LCD_MENU, ui.reset_status()); } @@ -110,7 +96,7 @@ void GcodeSuite::M81() { #if HAS_SUICIDE suicide(); #elif ENABLED(PSU_CONTROL) - PSU_OFF_SOON(); + powerManager.power_off_soon(); #endif LCD_MESSAGEPGM_P(PSTR(MACHINE_NAME " " STR_OFF ".")); diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index d7a9d3d94e..f4938722e3 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -170,6 +170,10 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP; #include "../feature/power_monitor.h" #endif + #if ENABLED(PSU_CONTROL) && defined(LED_BACKLIGHT_TIMEOUT) + #include "../feature/power.h" + #endif + #if HAS_ENCODER_ACTION volatile uint8_t MarlinUI::buttons; #if HAS_SLOW_BUTTONS @@ -838,8 +842,8 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP; static uint16_t max_display_update_time = 0; millis_t ms = millis(); - #ifdef LED_BACKLIGHT_TIMEOUT - leds.update_timeout(powersupply_on); + #if ENABLED(PSU_CONTROL) && defined(LED_BACKLIGHT_TIMEOUT) + leds.update_timeout(powerManager.psu_on); #endif #if HAS_LCD_MENU @@ -988,8 +992,8 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP; refresh(LCDVIEW_REDRAW_NOW); - #ifdef LED_BACKLIGHT_TIMEOUT - if (!powersupply_on) leds.reset_timeout(ms); + #if ENABLED(PSU_CONTROL) && defined(LED_BACKLIGHT_TIMEOUT) + if (!powerManager.psu_on) leds.reset_timeout(ms); #endif } diff --git a/Marlin/src/lcd/menu/menu_led.cpp b/Marlin/src/lcd/menu/menu_led.cpp index 284e80c931..3261ecc658 100644 --- a/Marlin/src/lcd/menu/menu_led.cpp +++ b/Marlin/src/lcd/menu/menu_led.cpp @@ -30,6 +30,10 @@ #include "menu_item.h" +#if ENABLED(PSU_CONTROL) + #include "../../feature/power.h" +#endif + #if ENABLED(LED_CONTROL_MENU) #include "../../feature/leds/leds.h" @@ -125,12 +129,7 @@ void menu_led() { BACK_ITEM(MSG_MAIN); #if ENABLED(LED_CONTROL_MENU) - #if ENABLED(PSU_CONTROL) - extern bool powersupply_on; - #else - constexpr bool powersupply_on = true; - #endif - if (powersupply_on) { + if (TERN1(PSU_CONTROL, powerManager.psu_on)) { editable.state = leds.lights_on; EDIT_ITEM(bool, MSG_LEDS, &editable.state, leds.toggle); } diff --git a/Marlin/src/lcd/menu/menu_main.cpp b/Marlin/src/lcd/menu/menu_main.cpp index 6f32ef1d60..8fce2038a3 100644 --- a/Marlin/src/lcd/menu/menu_main.cpp +++ b/Marlin/src/lcd/menu/menu_main.cpp @@ -35,6 +35,10 @@ #include "../../module/stepper.h" #include "../../sd/cardreader.h" +#if ENABLED(PSU_CONTROL) + #include "../../feature/power.h" +#endif + #if HAS_GAMES && DISABLED(LCD_INFO_MENU) #include "game/game.h" #endif @@ -385,7 +389,7 @@ void menu_main() { // Switch power on/off // #if ENABLED(PSU_CONTROL) - if (powersupply_on) + if (powerManager.psu_on) #if ENABLED(PS_OFF_CONFIRM) CONFIRM_ITEM(MSG_SWITCH_PS_OFF, MSG_YES, MSG_NO, diff --git a/Marlin/src/module/stepper/indirection.h b/Marlin/src/module/stepper/indirection.h index 08d0be0b31..beba03699e 100644 --- a/Marlin/src/module/stepper/indirection.h +++ b/Marlin/src/module/stepper/indirection.h @@ -44,7 +44,7 @@ #include "trinamic.h" #endif -void restore_stepper_drivers(); // Called by PSU_ON +void restore_stepper_drivers(); // Called by powerManager.power_on() void reset_stepper_drivers(); // Called by settings.load / settings.reset // X Stepper diff --git a/ini/features.ini b/ini/features.ini index 28da75ef42..b94c3fb9bc 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -128,7 +128,7 @@ HAS_PRUSA_MMU1 = src_filter=+ HAS_PRUSA_MMU2 = src_filter=+ + PASSWORD_FEATURE = src_filter=+ + ADVANCED_PAUSE_FEATURE = src_filter=+ + + -AUTO_POWER_CONTROL = src_filter=+ +PSU_CONTROL = src_filter=+ HAS_POWER_MONITOR = src_filter=+ + POWER_LOSS_RECOVERY = src_filter=+ + PROBE_TEMP_COMPENSATION = src_filter=+ +