blob: 92e4eeb14b4648577e90451c88c50b4a5190e681 [file] [log] [blame]
Brandon Wyman3f1242f2020-01-28 13:11:25 -06001#pragma once
Brandon Wyman3f1242f2020-01-28 13:11:25 -06002#include "util_base.hpp"
3#include "utility.hpp"
B. J. Wyman681b2a32021-04-20 22:31:22 +00004#include "xyz/openbmc_project/Common/error.hpp"
5
6#include <fmt/format.h>
7
8#include <gpiod.hpp>
9#include <phosphor-logging/elog-errors.hpp>
10#include <phosphor-logging/elog.hpp>
11#include <phosphor-logging/log.hpp>
Brandon Wyman3f1242f2020-01-28 13:11:25 -060012
Adriana Kobylak52245b62021-09-13 15:46:21 +000013#include <bitset>
14
Brandon Wyman3f1242f2020-01-28 13:11:25 -060015namespace phosphor::power::psu
16{
17
Matt Spinler0975eaf2022-02-14 15:38:30 -060018using Property = std::string;
19using Value = std::variant<bool, std::string>;
20using PropertyMap = std::map<Property, Value>;
21using Interface = std::string;
22using InterfaceMap = std::map<Interface, PropertyMap>;
23using Object = sdbusplus::message::object_path;
24using ObjectMap = std::map<Object, InterfaceMap>;
25
Brandon Wyman3f1242f2020-01-28 13:11:25 -060026class Util : public UtilBase
27{
28 public:
Brandon Wyman3f1242f2020-01-28 13:11:25 -060029 bool getPresence(sdbusplus::bus::bus& bus,
30 const std::string& invpath) const override
31 {
32 bool present = false;
33
34 // Use getProperty utility function to get presence status.
35 util::getProperty(INVENTORY_IFACE, PRESENT_PROP, invpath,
36 INVENTORY_MGR_IFACE, bus, present);
37
38 return present;
39 }
B. J. Wyman681b2a32021-04-20 22:31:22 +000040
41 void setPresence(sdbusplus::bus::bus& bus, const std::string& invpath,
42 bool present, const std::string& name) const override
43 {
44 using InternalFailure =
45 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
B. J. Wyman681b2a32021-04-20 22:31:22 +000046 PropertyMap invProp;
47
48 invProp.emplace("Present", present);
49 invProp.emplace("PrettyName", name);
50
B. J. Wyman681b2a32021-04-20 22:31:22 +000051 InterfaceMap invIntf;
52 invIntf.emplace("xyz.openbmc_project.Inventory.Item",
53 std::move(invProp));
54
55 Interface extraIface = "xyz.openbmc_project.Inventory.Item.PowerSupply";
56
57 invIntf.emplace(extraIface, PropertyMap());
58
B. J. Wyman681b2a32021-04-20 22:31:22 +000059 ObjectMap invObj;
60 invObj.emplace(std::move(invpath), std::move(invIntf));
61
62 using namespace phosphor::logging;
63 log<level::INFO>(fmt::format("Updating inventory present property. "
64 "present:{} invpath:{} name:{}",
65 present, invpath, name)
66 .c_str());
67
68 try
69 {
70 auto invService = phosphor::power::util::getService(
71 INVENTORY_OBJ_PATH, INVENTORY_MGR_IFACE, bus);
72
73 // Update inventory
74 auto invMsg =
75 bus.new_method_call(invService.c_str(), INVENTORY_OBJ_PATH,
76 INVENTORY_MGR_IFACE, "Notify");
77 invMsg.append(std::move(invObj));
78 auto invMgrResponseMsg = bus.call(invMsg);
79 }
80 catch (const std::exception& e)
81 {
82 log<level::ERR>(
83 fmt::format(
84 "Error in inventory manager call to update inventory: {}",
85 e.what())
86 .c_str());
87 elog<InternalFailure>();
88 }
89 }
Matt Spinler0975eaf2022-02-14 15:38:30 -060090
91 void setAvailable(sdbusplus::bus::bus& bus, const std::string& invpath,
92 bool available) const override
93 {
94 PropertyMap invProp;
95 InterfaceMap invIntf;
96 ObjectMap invObj;
97
98 invProp.emplace(AVAILABLE_PROP, available);
99 invIntf.emplace(AVAILABILITY_IFACE, std::move(invProp));
100
101 invObj.emplace(std::move(invpath), std::move(invIntf));
102
103 try
104 {
105
106 auto invService = phosphor::power::util::getService(
107 INVENTORY_OBJ_PATH, INVENTORY_MGR_IFACE, bus);
108
109 auto invMsg =
110 bus.new_method_call(invService.c_str(), INVENTORY_OBJ_PATH,
111 INVENTORY_MGR_IFACE, "Notify");
112 invMsg.append(std::move(invObj));
113 auto invMgrResponseMsg = bus.call(invMsg);
114 }
115 catch (const sdbusplus::exception::exception& e)
116 {
117 using namespace phosphor::logging;
118 log<level::ERR>(
119 fmt::format("Error in inventory manager call to update "
120 "availability interface: {}",
121 e.what())
122 .c_str());
123 throw;
124 }
125 }
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600126
127 void handleChassisHealthRollup(sdbusplus::bus::bus& bus,
128 const std::string& invpath,
129 bool addRollup) const override
130 {
131 using AssociationTuple =
132 std::tuple<std::string, std::string, std::string>;
133 using AssociationsProperty = std::vector<AssociationTuple>;
134 try
135 {
136 auto chassisPath = getChassis(bus, invpath);
137
138 auto service = phosphor::power::util::getService(
139 invpath, ASSOC_DEF_IFACE, bus);
140
141 AssociationsProperty associations;
142 phosphor::power::util::getProperty<AssociationsProperty>(
143 ASSOC_DEF_IFACE, ASSOC_PROP, invpath, service, bus,
144 associations);
145
146 AssociationTuple critAssociation{"health_rollup", "critical",
147 chassisPath};
148
149 auto assocIt = std::find(associations.begin(), associations.end(),
150 critAssociation);
151 if (addRollup)
152 {
153 if (assocIt != associations.end())
154 {
155 // It's already there
156 return;
157 }
158
159 associations.push_back(critAssociation);
160 }
161 else
162 {
163 if (assocIt == associations.end())
164 {
165 // It's already been removed.
166 return;
167 }
168
169 // If the object still isn't functional, then don't clear
170 // the association.
171 bool functional = false;
172 phosphor::power::util::getProperty<bool>(
173 OPERATIONAL_STATE_IFACE, FUNCTIONAL_PROP, invpath, service,
174 bus, functional);
175
176 if (!functional)
177 {
178 return;
179 }
180
181 associations.erase(assocIt);
182 }
183
184 phosphor::power::util::setProperty(ASSOC_DEF_IFACE, ASSOC_PROP,
185 invpath, service, bus,
186 associations);
187 }
188 catch (const sdbusplus::exception::exception& e)
189 {
190 using namespace phosphor::logging;
191 log<level::INFO>(fmt::format("Error trying to handle health rollup "
192 "associations for {}: {}",
193 invpath, e.what())
194 .c_str());
195 }
196 }
197
198 std::string getChassis(sdbusplus::bus::bus& bus,
199 const std::string& invpath) const
200 {
201 // Use the 'chassis' association to find the parent chassis.
202 auto assocPath = invpath + "/chassis";
203 std::vector<std::string> endpoints;
204
205 phosphor::power::util::getProperty<decltype(endpoints)>(
206 ASSOCIATION_IFACE, ENDPOINTS_PROP, assocPath,
207 "xyz.openbmc_project.ObjectMapper", bus, endpoints);
208
209 if (endpoints.empty())
210 {
211 throw std::runtime_error(
212 fmt::format("Missing chassis association for {}", invpath));
213 }
214
215 return endpoints[0];
216 }
B. J. Wyman681b2a32021-04-20 22:31:22 +0000217};
218
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000219std::unique_ptr<GPIOInterfaceBase> createGPIO(const std::string& namedGpio);
B. J. Wyman681b2a32021-04-20 22:31:22 +0000220
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000221class GPIOInterface : public GPIOInterfaceBase
B. J. Wyman681b2a32021-04-20 22:31:22 +0000222{
223 public:
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000224 GPIOInterface() = delete;
225 virtual ~GPIOInterface() = default;
226 GPIOInterface(const GPIOInterface&) = default;
227 GPIOInterface& operator=(const GPIOInterface&) = default;
228 GPIOInterface(GPIOInterface&&) = default;
229 GPIOInterface& operator=(GPIOInterface&&) = default;
B. J. Wyman681b2a32021-04-20 22:31:22 +0000230
231 /**
232 * Constructor
233 *
234 * @param[in] namedGpio - The string for the gpio-line-name
235 */
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000236 GPIOInterface(const std::string& namedGpio);
B. J. Wyman681b2a32021-04-20 22:31:22 +0000237
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000238 static std::unique_ptr<GPIOInterfaceBase>
B. J. Wyman681b2a32021-04-20 22:31:22 +0000239 createGPIO(const std::string& namedGpio);
240
241 /**
242 * @brief Attempts to read the state of the GPIO line.
243 *
244 * Throws an exception if line not found, request line fails, or get_value
245 * from line fails.
246 *
247 * @return 1 for active (low/present), 0 for not active (high/not present).
248 */
249 int read() override;
250
B. J. Wymand8b8cb12021-07-15 22:03:34 +0000251 /**
Adriana Kobylak52245b62021-09-13 15:46:21 +0000252 * @brief Attempts to set the state of the GPIO line to the specified value.
253 *
254 * Throws an exception if line not found, request line fails, or set_value
255 * to line fails.
256 *
257 * @param[in] value - The value to set the state of the GPIO line, 1 or 0.
258 * @param[in] flags - Additional line request flags as defined in gpiod.hpp.
259 */
260 void write(int value, std::bitset<32> flags) override;
261
262 /**
B. J. Wymand8b8cb12021-07-15 22:03:34 +0000263 * @brief Returns the name of the GPIO, if not empty.
264 */
265 std::string getName() const override;
266
B. J. Wyman681b2a32021-04-20 22:31:22 +0000267 private:
268 gpiod::line line;
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600269};
270
271} // namespace phosphor::power::psu