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