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] instance  - The instance of this object
44      * @param[in] objPath   - The Dbus object path
45      */
46     Chassis(sdbusplus::bus::bus& bus, const char* busName,
47             const char* objPath) :
48         ChassisInherit(bus, objPath, true),
49         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     /**
90      * @brief subscribe to the systemd signals
91      *
92      * This object needs to capture when it's systemd targets complete
93      * so it can keep it's state updated
94      *
95      **/
96     void subscribeToSystemdSignals();
97 
98     /** @brief Execute the transition request
99      *
100      * This function calls the appropriate systemd target for the input
101      * transition.
102      *
103      * @param[in] tranReq    - Transition requested
104      */
105     void executeTransition(Transition tranReq);
106 
107     /**
108      * @brief Determine if target is active
109      *
110      * This function determines if the target is active and
111      * helps prevent misleading log recorded states.
112      *
113      * @param[in] target - Target string to check on
114      *
115      * @return boolean corresponding to state active
116      **/
117     bool stateActive(const std::string& target);
118 
119     /** @brief Check if systemd state change is relevant to this object
120      *
121      * Instance specific interface to handle the detected systemd state
122      * change
123      *
124      * @param[in]  msg       - Data associated with subscribed signal
125      *
126      */
127     int sysStateChange(sdbusplus::message::message& msg);
128 
129     /** @brief Persistent sdbusplus DBus connection. */
130     sdbusplus::bus::bus& bus;
131 
132     /** @brief Used to subscribe to dbus systemd signals **/
133     sdbusplus::bus::match_t systemdSignals;
134 
135     /** @brief Used to Set value of POHCounter */
136     uint32_t pOHCounter(uint32_t value) override;
137 
138     /** @brief Used by the timer to update the POHCounter */
139     void pOHCallback();
140 
141     /** @brief Used to restore POHCounter value from persisted file */
142     void restorePOHCounter();
143 
144     /** @brief Serialize and persist requested POH counter.
145      *
146      *  @param[in] dir - pathname of file where the serialized POH counter will
147      *                   be placed.
148      *
149      *  @return fs::path - pathname of persisted requested POH counter.
150      */
151     fs::path
152         serializePOH(const fs::path& dir = fs::path(POH_COUNTER_PERSIST_PATH));
153 
154     /** @brief Deserialize a persisted requested POH counter.
155      *
156      *  @param[in] path - pathname of persisted POH counter file
157      *  @param[in] retCounter - deserialized POH counter value
158      *
159      *  @return bool - true if the deserialization was successful, false
160      *                 otherwise.
161      */
162     bool deserializePOH(const fs::path& path, uint32_t& retCounter);
163 
164     /** @brief Sets the LastStateChangeTime property and persists it. */
165     void setStateChangeTime();
166 
167     /** @brief Serialize the last power state change time.
168      *
169      *  Save the time the state changed and the state itself.
170      *  The state needs to be saved as well so that during rediscovery
171      *  on reboots there's a way to know not to update the time again.
172      */
173     void serializeStateChangeTime();
174 
175     /** @brief Deserialize the last power state change time.
176      *
177      *  @param[out] time - Deserialized time
178      *  @param[out] state - Deserialized power state
179      *
180      *  @return bool - true if successful, false otherwise.
181      */
182     bool deserializeStateChangeTime(uint64_t& time, PowerState& state);
183 
184     /** @brief Restores the power state change time.
185      *
186      *  The time is loaded into the LastStateChangeTime D-Bus property.
187      *  On the very first start after this code has been applied but
188      *  before the state has changed, the LastStateChangeTime value
189      *  will be zero.
190      */
191     void restoreChassisStateChangeTime();
192 
193     /** @brief Timer used for tracking power on hours */
194     sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> pOHTimer;
195 };
196 
197 } // namespace manager
198 } // namespace state
199 } // namespace phosphor
200