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