1 /**
2 * Copyright © 2021 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "power_interface.hpp"
18
19 #include "types.hpp"
20
21 #include <phosphor-logging/lg2.hpp>
22 #include <sdbusplus/exception.hpp>
23 #include <sdbusplus/sdbus.hpp>
24 #include <sdbusplus/server.hpp>
25
26 #include <string>
27 #include <tuple>
28
29 namespace phosphor::power::sequencer
30 {
31
PowerInterface(sdbusplus::bus_t & bus,const char * path)32 PowerInterface::PowerInterface(sdbusplus::bus_t& bus, const char* path) :
33 serverInterface(bus, path, POWER_IFACE, vtable, this)
34 {}
35
callbackGetPgood(sd_bus *,const char *,const char *,const char *,sd_bus_message * msg,void * context,sd_bus_error * error)36 int PowerInterface::callbackGetPgood(
37 sd_bus* /*bus*/, const char* /*path*/, const char* /*interface*/,
38 const char* /*property*/, sd_bus_message* msg, void* context,
39 sd_bus_error* error)
40 {
41 if (msg != nullptr && context != nullptr)
42 {
43 try
44 {
45 auto pwrObj = static_cast<PowerInterface*>(context);
46 int pgood = pwrObj->getPgood();
47 lg2::debug("callbackGetPgood: {PGOOD}", "PGOOD", pgood);
48
49 sdbusplus::message_t(msg).append(pgood);
50 }
51 catch (const sdbusplus::exception_t& e)
52 {
53 return sd_bus_error_set(error, e.name(), e.description());
54 }
55 }
56 else
57 {
58 // The message or context were null
59 lg2::error("Unable to service get pgood property callback");
60 return -1;
61 }
62
63 return 1;
64 }
65
callbackGetPgoodTimeout(sd_bus *,const char *,const char *,const char *,sd_bus_message * msg,void * context,sd_bus_error * error)66 int PowerInterface::callbackGetPgoodTimeout(
67 sd_bus* /*bus*/, const char* /*path*/, const char* /*interface*/,
68 const char* /*property*/, sd_bus_message* msg, void* context,
69 sd_bus_error* error)
70 {
71 if (msg != nullptr && context != nullptr)
72 {
73 try
74 {
75 auto pwrObj = static_cast<PowerInterface*>(context);
76 int timeout = pwrObj->getPgoodTimeout();
77 lg2::debug("callbackGetPgoodTimeout: {TIMEOUT}", "TIMEOUT",
78 timeout);
79
80 sdbusplus::message_t(msg).append(timeout);
81 }
82 catch (const sdbusplus::exception_t& e)
83 {
84 return sd_bus_error_set(error, e.name(), e.description());
85 }
86 }
87 else
88 {
89 // The message or context were null
90 lg2::error("Unable to service get pgood timeout property callback");
91 return -1;
92 }
93
94 return 1;
95 }
96
callbackGetPowerState(sd_bus_message * msg,void * context,sd_bus_error * error)97 int PowerInterface::callbackGetPowerState(sd_bus_message* msg, void* context,
98 sd_bus_error* error)
99 {
100 if (msg != nullptr && context != nullptr)
101 {
102 try
103 {
104 auto pwrObj = static_cast<PowerInterface*>(context);
105 // Return the current power state of the GPIO, rather than the last
106 // requested power state change
107 int pgood = pwrObj->getPgood();
108 lg2::debug("callbackGetPowerState: {PGOOD}", "PGOOD", pgood);
109
110 auto reply = sdbusplus::message_t(msg).new_method_return();
111 reply.append(pgood);
112 reply.method_return();
113 }
114 catch (const sdbusplus::exception_t& e)
115 {
116 return sd_bus_error_set(error, e.name(), e.description());
117 }
118 }
119 else
120 {
121 // The message or context were null
122 lg2::error("Unable to service getPowerState method callback");
123 return -1;
124 }
125
126 return 1;
127 }
128
callbackSetPgoodTimeout(sd_bus *,const char *,const char *,const char *,sd_bus_message * msg,void * context,sd_bus_error * error)129 int PowerInterface::callbackSetPgoodTimeout(
130 sd_bus* /*bus*/, const char* /*path*/, const char* /*interface*/,
131 const char* /*property*/, sd_bus_message* msg, void* context,
132 sd_bus_error* error)
133 {
134 if (msg != nullptr && context != nullptr)
135 {
136 try
137 {
138 auto m = sdbusplus::message_t(msg);
139
140 int timeout{};
141 m.read(timeout);
142 lg2::info("callbackSetPgoodTimeout: {TIMEOUT}", "TIMEOUT", timeout);
143
144 auto pwrObj = static_cast<PowerInterface*>(context);
145 pwrObj->setPgoodTimeout(timeout);
146 }
147 catch (const sdbusplus::exception_t& e)
148 {
149 return sd_bus_error_set(error, e.name(), e.description());
150 }
151 }
152 else
153 {
154 // The message or context were null
155 lg2::error("Unable to service set pgood timeout property callback");
156 return -1;
157 }
158
159 return 1;
160 }
161
callbackGetState(sd_bus *,const char *,const char *,const char *,sd_bus_message * msg,void * context,sd_bus_error * error)162 int PowerInterface::callbackGetState(
163 sd_bus* /*bus*/, const char* /*path*/, const char* /*interface*/,
164 const char* /*property*/, sd_bus_message* msg, void* context,
165 sd_bus_error* error)
166 {
167 if (msg != nullptr && context != nullptr)
168 {
169 try
170 {
171 auto pwrObj = static_cast<PowerInterface*>(context);
172 int state = pwrObj->getState();
173 lg2::debug("callbackGetState: {STATE}", "STATE", state);
174
175 sdbusplus::message_t(msg).append(state);
176 }
177 catch (const sdbusplus::exception_t& e)
178 {
179 return sd_bus_error_set(error, e.name(), e.description());
180 }
181 }
182 else
183 {
184 // The message or context were null
185 lg2::error("Unable to service get state property callback");
186 return -1;
187 }
188
189 return 1;
190 }
191
callbackSetPowerState(sd_bus_message * msg,void * context,sd_bus_error * error)192 int PowerInterface::callbackSetPowerState(sd_bus_message* msg, void* context,
193 sd_bus_error* error)
194 {
195 if (msg != nullptr && context != nullptr)
196 {
197 try
198 {
199 auto m = sdbusplus::message_t(msg);
200
201 int state{};
202 m.read(state);
203
204 if (state != 1 && state != 0)
205 {
206 return sd_bus_error_set(error,
207 "org.openbmc.ControlPower.Error.Failed",
208 "Invalid power state");
209 }
210 lg2::info("callbackSetPowerState: {STATE}", "STATE", state);
211
212 auto pwrObj = static_cast<PowerInterface*>(context);
213 pwrObj->setState(state);
214
215 m.new_method_return().method_return();
216 }
217 catch (const sdbusplus::exception_t& e)
218 {
219 return sd_bus_error_set(error, e.name(), e.description());
220 }
221 }
222 else
223 {
224 // The message or context were null
225 lg2::error("Unable to service setPowerState method callback");
226 return -1;
227 }
228
229 return 1;
230 }
231
callbackSetPowerSupplyError(sd_bus_message * msg,void * context,sd_bus_error * error)232 int PowerInterface::callbackSetPowerSupplyError(
233 sd_bus_message* msg, void* context, sd_bus_error* error)
234 {
235 if (msg != nullptr && context != nullptr)
236 {
237 try
238 {
239 auto m = sdbusplus::message_t(msg);
240
241 std::string psError{};
242 m.read(psError);
243 lg2::info("callbackSetPowerSupplyError: {PSERROR}", "PSERROR",
244 psError);
245
246 auto pwrObj = static_cast<PowerInterface*>(context);
247 pwrObj->setPowerSupplyError(psError);
248
249 m.new_method_return().method_return();
250 }
251 catch (const sdbusplus::exception_t& e)
252 {
253 return sd_bus_error_set(error, e.name(), e.description());
254 }
255 }
256 else
257 {
258 // The message or context were null
259 lg2::error("Unable to service setPowerSupplyError method callback");
260 return -1;
261 }
262
263 return 1;
264 }
265
emitPowerGoodSignal()266 void PowerInterface::emitPowerGoodSignal()
267 {
268 lg2::info("emitPowerGoodSignal");
269 serverInterface.new_signal("PowerGood").signal_send();
270 }
271
emitPowerLostSignal()272 void PowerInterface::emitPowerLostSignal()
273 {
274 lg2::info("emitPowerLostSignal");
275 serverInterface.new_signal("PowerLost").signal_send();
276 }
277
emitPropertyChangedSignal(const char * property)278 void PowerInterface::emitPropertyChangedSignal(const char* property)
279 {
280 lg2::info("emitPropertyChangedSignal: {PROPERTY}", "PROPERTY", property);
281 serverInterface.property_changed(property);
282 }
283
284 const sdbusplus::vtable::vtable_t PowerInterface::vtable[] = {
285 sdbusplus::vtable::start(),
286 // Method setPowerState takes an int parameter and returns void
287 sdbusplus::vtable::method("setPowerState", "i", "", callbackSetPowerState),
288 // Method getPowerState takes no parameters and returns int
289 sdbusplus::vtable::method("getPowerState", "", "i", callbackGetPowerState),
290 // Signal PowerGood
291 sdbusplus::vtable::signal("PowerGood", ""),
292 // Signal PowerLost
293 sdbusplus::vtable::signal("PowerLost", ""),
294 // Property pgood is type int, read only, and uses the emits_change flag
295 sdbusplus::vtable::property("pgood", "i", callbackGetPgood,
296 sdbusplus::vtable::property_::emits_change),
297 // Property state is type int, read only, and uses the emits_change flag
298 sdbusplus::vtable::property("state", "i", callbackGetState,
299 sdbusplus::vtable::property_::emits_change),
300 // Property pgood_timeout is type int, read write, and uses the emits_change
301 // flag
302 sdbusplus::vtable::property("pgood_timeout", "i", callbackGetPgoodTimeout,
303 callbackSetPgoodTimeout,
304 sdbusplus::vtable::property_::emits_change),
305 // Method setPowerSupplyError takes a string parameter and returns void
306 sdbusplus::vtable::method("setPowerSupplyError", "s", "",
307 callbackSetPowerSupplyError),
308 sdbusplus::vtable::end()};
309
310 } // namespace phosphor::power::sequencer
311