1 #pragma once 2 3 #include "logging.hpp" 4 #include "power_interface.hpp" 5 6 #include <fmt/format.h> 7 8 #include <sdeventplus/clock.hpp> 9 #include <sdeventplus/event.hpp> 10 #include <sdeventplus/utility/timer.hpp> 11 12 #include <chrono> 13 14 namespace phosphor::fan::monitor 15 { 16 17 /** 18 * @class PowerOffAction 19 * 20 * This is the base class for a power off action, which is 21 * used by the PowerOffRule class to do different types of 22 * power offs based on fan failures. 23 * 24 * The power off is started with the start() method, and the 25 * derived class may or may not allow it to be stopped with 26 * the cancel() method, which is really only useful when 27 * there is a delay before the power off. 28 * 29 * It uses the PowerInterfaceBase object pointer to perform 30 * the D-Bus call to do the power off, so it can be mocked 31 * for testing. 32 */ 33 class PowerOffAction 34 { 35 public: 36 using PrePowerOffFunc = std::function<void()>; 37 38 PowerOffAction() = delete; 39 virtual ~PowerOffAction() = default; 40 PowerOffAction(const PowerOffAction&) = delete; 41 PowerOffAction& operator=(const PowerOffAction&) = delete; 42 PowerOffAction(PowerOffAction&&) = delete; 43 PowerOffAction& operator=(PowerOffAction&&) = delete; 44 45 /** 46 * @brief Constructor 47 * 48 * @param[in] name - The action name. Used for tracing. 49 * @param[in] powerInterface - The object used to invoke the power off. 50 * @param[in] powerOffFunc - A function to call right before the power 51 * off occurs (after any delays). May be 52 * empty if no function is necessary. 53 */ 54 PowerOffAction(const std::string& name, 55 std::shared_ptr<PowerInterfaceBase> powerInterface, 56 PrePowerOffFunc& powerOffFunc) : 57 _name(name), 58 _powerIface(std::move(powerInterface)), 59 _event(sdeventplus::Event::get_default()), 60 _prePowerOffFunc(powerOffFunc) 61 {} 62 63 /** 64 * @brief Starts the power off. 65 * 66 * Though this occurs in the child class, usually this 67 * involves starting a timer and then powering off when it 68 * times out. 69 */ 70 virtual void start() = 0; 71 72 /** 73 * @brief Attempts to cancel the power off, if the derived 74 * class allows it, and assuming the power off hasn't 75 * already happened. 76 * 77 * The 'force' parameter is mainly for use when something else 78 * powered off the system so this action doesn't need to run 79 * anymore even if it isn't usually cancelable. 80 * 81 * @param[in] force - If the cancel should be forced 82 * 83 * @return bool - If the cancel was allowed/successful 84 */ 85 virtual bool cancel(bool force) = 0; 86 87 /** 88 * @brief If the power off action is currently in progress, which 89 * usually means it's still in the delay time before the 90 * power off D-Bus command is executed. 91 * 92 * @return bool - If the action is active 93 */ 94 bool active() const 95 { 96 return _active; 97 } 98 99 /** 100 * @brief Returns the name of the action 101 * 102 * @return const std::string& - The name 103 */ 104 const std::string& name() const 105 { 106 return _name; 107 } 108 109 protected: 110 /** 111 * @brief The name of the action, which is set by the 112 * derived class. 113 */ 114 const std::string _name; 115 116 /** 117 * @brief If the action is currently active or not. 118 */ 119 bool _active = false; 120 121 /** 122 * @brief The object used to invoke the power off with. 123 */ 124 std::shared_ptr<PowerInterfaceBase> _powerIface; 125 126 /** 127 * @brief The event loop object. Needed by timers. 128 */ 129 sdeventplus::Event _event; 130 131 /** 132 * @brief A function that will be called right before 133 * the power off. 134 */ 135 PrePowerOffFunc _prePowerOffFunc; 136 }; 137 138 /** 139 * @class HardPowerOff 140 * 141 * This class is derived from the PowerOffAction class 142 * and will execute a hard power off after some delay. 143 */ 144 class HardPowerOff : public PowerOffAction 145 { 146 public: 147 HardPowerOff() = delete; 148 ~HardPowerOff() = default; 149 HardPowerOff(const HardPowerOff&) = delete; 150 HardPowerOff& operator=(const HardPowerOff&) = delete; 151 HardPowerOff(HardPowerOff&&) = delete; 152 HardPowerOff& operator=(HardPowerOff&&) = delete; 153 154 /** 155 * @brief Constructor 156 * 157 * @param[in] delay - The amount of time in seconds to wait before 158 * doing the power off 159 * @param[in] powerInterface - The object to use to do the power off 160 * @param[in] func - A function to call right before the power 161 * off occurs (after the delay). May be 162 * empty if no function is necessary. 163 */ 164 HardPowerOff(uint32_t delay, 165 std::shared_ptr<PowerInterfaceBase> powerInterface, 166 PrePowerOffFunc func) : 167 PowerOffAction("Hard Power Off: " + std::to_string(delay) + "s", 168 powerInterface, func), 169 _delay(delay), 170 _timer(_event, std::bind(std::mem_fn(&HardPowerOff::powerOff), this)) 171 {} 172 173 /** 174 * @brief Starts a timer upon the expiration of which the 175 * hard power off will be done. 176 */ 177 void start() override 178 { 179 _timer.restartOnce(_delay); 180 } 181 182 /** 183 * @brief Cancels the timer. This is always allowed. 184 * 185 * @param[in] force - If the cancel should be forced or not 186 * (not checked in this case) 187 * @return bool - Always returns true 188 */ 189 bool cancel(bool) override 190 { 191 if (_timer.isEnabled()) 192 { 193 _timer.setEnabled(false); 194 } 195 196 // Can always be canceled 197 return true; 198 } 199 200 /** 201 * @brief Performs the hard power off. 202 */ 203 void powerOff() 204 { 205 206 if (_prePowerOffFunc) 207 { 208 _prePowerOffFunc(); 209 } 210 211 getLogger().log( 212 fmt::format("Action '{}' executing hard power off", name())); 213 _powerIface->hardPowerOff(); 214 } 215 216 private: 217 /** 218 * @brief The number of seconds to wait between starting the 219 * action and doing the power off. 220 */ 221 std::chrono::seconds _delay; 222 223 /** 224 * @brief The Timer object used to handle the delay. 225 */ 226 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer; 227 }; 228 229 /** 230 * @class SoftPowerOff 231 * 232 * This class is derived from the PowerOffAction class 233 * and will execute a soft power off after some delay. 234 */ 235 class SoftPowerOff : public PowerOffAction 236 { 237 public: 238 SoftPowerOff() = delete; 239 ~SoftPowerOff() = default; 240 SoftPowerOff(const SoftPowerOff&) = delete; 241 SoftPowerOff& operator=(const SoftPowerOff&) = delete; 242 SoftPowerOff(SoftPowerOff&&) = delete; 243 SoftPowerOff& operator=(SoftPowerOff&&) = delete; 244 245 /** 246 * @brief Constructor 247 * 248 * @param[in] delay - The amount of time in seconds to wait before 249 * doing the power off 250 * @param[in] powerInterface - The object to use to do the power off 251 * @param[in] func - A function to call right before the power 252 * off occurs (after the delay). May be 253 * empty if no function is necessary. 254 */ 255 SoftPowerOff(uint32_t delay, 256 std::shared_ptr<PowerInterfaceBase> powerInterface, 257 PrePowerOffFunc func) : 258 PowerOffAction("Soft Power Off: " + std::to_string(delay) + "s", 259 powerInterface, func), 260 _delay(delay), 261 _timer(_event, std::bind(std::mem_fn(&SoftPowerOff::powerOff), this)) 262 {} 263 264 /** 265 * @brief Starts a timer upon the expiration of which the 266 * soft power off will be done. 267 */ 268 void start() override 269 { 270 _timer.restartOnce(_delay); 271 } 272 273 /** 274 * @brief Cancels the timer. This is always allowed. 275 * 276 * @param[in] force - If the cancel should be forced or not 277 * (not checked in this case) 278 * @return bool - Always returns true 279 */ 280 bool cancel(bool) override 281 { 282 if (_timer.isEnabled()) 283 { 284 _timer.setEnabled(false); 285 } 286 287 // Can always be canceled 288 return true; 289 } 290 291 /** 292 * @brief Performs the soft power off. 293 */ 294 void powerOff() 295 { 296 if (_prePowerOffFunc) 297 { 298 _prePowerOffFunc(); 299 } 300 301 getLogger().log( 302 fmt::format("Action '{}' executing soft power off", name())); 303 _powerIface->softPowerOff(); 304 } 305 306 private: 307 /** 308 * @brief The number of seconds to wait between starting the 309 * action and doing the power off. 310 */ 311 std::chrono::seconds _delay; 312 313 /** 314 * @brief The Timer object used to handle the delay. 315 */ 316 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer; 317 }; 318 319 /** 320 * @class EpowPowerOff 321 * 322 * Still TODO, but has a cancelable service mode delay followed 323 * by an uncancelable meltdown delay followed by a hard power off, with 324 * some sort of EPOW alert in there as well. 325 */ 326 class EpowPowerOff : public PowerOffAction 327 { 328 public: 329 EpowPowerOff() = delete; 330 ~EpowPowerOff() = default; 331 EpowPowerOff(const EpowPowerOff&) = delete; 332 EpowPowerOff& operator=(const EpowPowerOff&) = delete; 333 EpowPowerOff(EpowPowerOff&&) = delete; 334 EpowPowerOff& operator=(EpowPowerOff&&) = delete; 335 336 EpowPowerOff(uint32_t serviceModeDelay, uint32_t meltdownDelay, 337 std::shared_ptr<PowerInterfaceBase> powerInterface, 338 PrePowerOffFunc func) : 339 PowerOffAction("EPOW Power Off: " + std::to_string(serviceModeDelay) + 340 "s/" + std::to_string(meltdownDelay) + "s", 341 powerInterface, func), 342 _serviceModeDelay(serviceModeDelay), _meltdownDelay(meltdownDelay) 343 {} 344 345 void start() override 346 { 347 // TODO 348 } 349 350 bool cancel(bool) override 351 { 352 // TODO 353 return true; 354 } 355 356 private: 357 std::chrono::seconds _serviceModeDelay; 358 std::chrono::seconds _meltdownDelay; 359 }; 360 } // namespace phosphor::fan::monitor 361