1 #pragma once
2 
3 #include "config.h"
4 
5 #include "xyz/openbmc_project/State/Chassis/server.hpp"
6 #include "xyz/openbmc_project/State/PowerOnHours/server.hpp"
7 
8 #include <cereal/cereal.hpp>
9 #include <sdbusplus/bus.hpp>
10 #include <sdeventplus/clock.hpp>
11 #include <sdeventplus/event.hpp>
12 #include <sdeventplus/utility/timer.hpp>
13 
14 #include <chrono>
15 #include <experimental/filesystem>
16 #include <functional>
17 
18 namespace phosphor
19 {
20 namespace state
21 {
22 namespace manager
23 {
24 
25 using ChassisInherit = sdbusplus::server::object::object<
26     sdbusplus::xyz::openbmc_project::State::server::Chassis,
27     sdbusplus::xyz::openbmc_project::State::server::PowerOnHours>;
28 namespace sdbusRule = sdbusplus::bus::match::rules;
29 namespace fs = std::experimental::filesystem;
30 
31 /** @class Chassis
32  *  @brief OpenBMC chassis state management implementation.
33  *  @details A concrete implementation for xyz.openbmc_project.State.Chassis
34  *  DBus API.
35  */
36 class Chassis : public ChassisInherit
37 {
38   public:
39     /** @brief Constructs Chassis State Manager
40      *
41      * @note This constructor passes 'true' to the base class in order to
42      *       defer dbus object registration until we can run
43      *       determineInitialState() and set our properties
44      *
45      * @param[in] bus       - The Dbus bus object
46      * @param[in] objPath   - The Dbus object path
47      */
48     Chassis(sdbusplus::bus::bus& bus, const char* objPath) :
49         ChassisInherit(bus, objPath, true), bus(bus),
50         systemdSignals(
51             bus,
52             sdbusRule::type::signal() + sdbusRule::member("JobRemoved") +
53                 sdbusRule::path("/org/freedesktop/systemd1") +
54                 sdbusRule::interface("org.freedesktop.systemd1.Manager"),
55             std::bind(std::mem_fn(&Chassis::sysStateChange), this,
56                       std::placeholders::_1)),
57         pohTimer(sdeventplus::Event::get_default(),
58                  std::bind(&Chassis::pohCallback, this), std::chrono::hours{1},
59                  std::chrono::minutes{1})
60     {
61         subscribeToSystemdSignals();
62 
63         restoreChassisStateChangeTime();
64 
65         determineInitialState();
66 
67         restorePOHCounter(); // restore POHCounter from persisted file
68 
69         // We deferred this until we could get our property correct
70         this->emit_object_added();
71     }
72 
73     /** @brief Set value of RequestedPowerTransition */
74     Transition requestedPowerTransition(Transition value) override;
75 
76     /** @brief Set value of CurrentPowerState */
77     PowerState currentPowerState(PowerState value) override;
78 
79     /** @brief Get value of POHCounter */
80     using ChassisInherit::pohCounter;
81 
82     /** @brief Increment POHCounter if Chassis Power state is ON */
83     void startPOHCounter();
84 
85   private:
86     /** @brief Determine initial chassis state and set internally */
87     void determineInitialState();
88 
89     /** @brief Determine status of power into system */
90     void determineStatusOfPower();
91 
92     /**
93      * @brief subscribe to the systemd signals
94      *
95      * This object needs to capture when it's systemd targets complete
96      * so it can keep it's state updated
97      *
98      **/
99     void subscribeToSystemdSignals();
100 
101     /** @brief Execute the transition request
102      *
103      * This function calls the appropriate systemd target for the input
104      * transition.
105      *
106      * @param[in] tranReq    - Transition requested
107      */
108     void executeTransition(Transition tranReq);
109 
110     /**
111      * @brief Determine if target is active
112      *
113      * This function determines if the target is active and
114      * helps prevent misleading log recorded states.
115      *
116      * @param[in] target - Target string to check on
117      *
118      * @return boolean corresponding to state active
119      **/
120     bool stateActive(const std::string& target);
121 
122     /** @brief Check if systemd state change is relevant to this object
123      *
124      * Instance specific interface to handle the detected systemd state
125      * change
126      *
127      * @param[in]  msg       - Data associated with subscribed signal
128      *
129      */
130     int sysStateChange(sdbusplus::message::message& msg);
131 
132     /** @brief Persistent sdbusplus DBus connection. */
133     sdbusplus::bus::bus& bus;
134 
135     /** @brief Used to subscribe to dbus systemd signals **/
136     sdbusplus::bus::match_t systemdSignals;
137 
138     /** @brief Watch for any changes to UPS properties  **/
139     std::unique_ptr<sdbusplus::bus::match_t> uPowerPropChangeSignal;
140 
141     /** @brief Used to Set value of POHCounter */
142     uint32_t pohCounter(uint32_t value) override;
143 
144     /** @brief Used by the timer to update the POHCounter */
145     void pohCallback();
146 
147     /** @brief Used to restore POHCounter value from persisted file */
148     void restorePOHCounter();
149 
150     /** @brief Serialize and persist requested POH counter.
151      *
152      *  @param[in] dir - pathname of file where the serialized POH counter will
153      *                   be placed.
154      *
155      *  @return fs::path - pathname of persisted requested POH counter.
156      */
157     fs::path
158         serializePOH(const fs::path& dir = fs::path(POH_COUNTER_PERSIST_PATH));
159 
160     /** @brief Deserialize a persisted requested POH counter.
161      *
162      *  @param[in] path - pathname of persisted POH counter file
163      *  @param[in] retCounter - deserialized POH counter value
164      *
165      *  @return bool - true if the deserialization was successful, false
166      *                 otherwise.
167      */
168     bool deserializePOH(const fs::path& path, uint32_t& retCounter);
169 
170     /** @brief Sets the LastStateChangeTime property and persists it. */
171     void setStateChangeTime();
172 
173     /** @brief Serialize the last power state change time.
174      *
175      *  Save the time the state changed and the state itself.
176      *  The state needs to be saved as well so that during rediscovery
177      *  on reboots there's a way to know not to update the time again.
178      */
179     void serializeStateChangeTime();
180 
181     /** @brief Deserialize the last power state change time.
182      *
183      *  @param[out] time - Deserialized time
184      *  @param[out] state - Deserialized power state
185      *
186      *  @return bool - true if successful, false otherwise.
187      */
188     bool deserializeStateChangeTime(uint64_t& time, PowerState& state);
189 
190     /** @brief Restores the power state change time.
191      *
192      *  The time is loaded into the LastStateChangeTime D-Bus property.
193      *  On the very first start after this code has been applied but
194      *  before the state has changed, the LastStateChangeTime value
195      *  will be zero.
196      */
197     void restoreChassisStateChangeTime();
198 
199     /** @brief Timer used for tracking power on hours */
200     sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> pohTimer;
201 
202     /** @brief Function to check for a standby voltage regulator fault
203      *
204      *  Determine if a standby voltage regulator fault was detected and
205      *  return true or false accordingly.
206      *
207      *  @return true if fault detected, else false
208      */
209     bool standbyVoltageRegulatorFault();
210 
211     /** @brief Process UPS property changes
212      *
213      * Instance specific interface to monitor for changes to the UPS
214      * properties which may impact CurrentPowerStatus
215      *
216      * @param[in]  msg              - Data associated with subscribed signal
217      *
218      */
219     void uPowerChangeEvent(sdbusplus::message::message& msg);
220 };
221 
222 } // namespace manager
223 } // namespace state
224 } // namespace phosphor
225