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 <fmt/format.h>
22 
23 #include <phosphor-logging/log.hpp>
24 #include <sdbusplus/exception.hpp>
25 #include <sdbusplus/sdbus.hpp>
26 #include <sdbusplus/server.hpp>
27 
28 #include <string>
29 #include <tuple>
30 
31 using namespace phosphor::logging;
32 
33 namespace phosphor::power::sequencer
34 {
35 
36 PowerInterface::PowerInterface(sdbusplus::bus_t& bus, const char* path) :
37     serverInterface(bus, path, POWER_IFACE, vtable, this)
38 {}
39 
40 int PowerInterface::callbackGetPgood(sd_bus* /*bus*/, const char* /*path*/,
41                                      const char* /*interface*/,
42                                      const char* /*property*/,
43                                      sd_bus_message* msg, void* context,
44                                      sd_bus_error* error)
45 {
46     if (msg != nullptr && context != nullptr)
47     {
48         try
49         {
50             auto pwrObj = static_cast<PowerInterface*>(context);
51             int pgood = pwrObj->getPgood();
52             log<level::INFO>(
53                 fmt::format("callbackGetPgood: {}", pgood).c_str());
54 
55             sdbusplus::message_t(msg).append(pgood);
56         }
57         catch (const sdbusplus::exception_t& e)
58         {
59             return sd_bus_error_set(error, e.name(), e.description());
60         }
61     }
62     else
63     {
64         // The message or context were null
65         log<level::ERR>("Unable to service get pgood property callback");
66         return -1;
67     }
68 
69     return 1;
70 }
71 
72 int PowerInterface::callbackGetPgoodTimeout(sd_bus* /*bus*/,
73                                             const char* /*path*/,
74                                             const char* /*interface*/,
75                                             const char* /*property*/,
76                                             sd_bus_message* msg, void* context,
77                                             sd_bus_error* error)
78 {
79     if (msg != nullptr && context != nullptr)
80     {
81         try
82         {
83             auto pwrObj = static_cast<PowerInterface*>(context);
84             int timeout = pwrObj->getPgoodTimeout();
85             log<level::INFO>(
86                 fmt::format("callbackGetPgoodTimeout: {}", timeout).c_str());
87 
88             sdbusplus::message_t(msg).append(timeout);
89         }
90         catch (const sdbusplus::exception_t& e)
91         {
92             return sd_bus_error_set(error, e.name(), e.description());
93         }
94     }
95     else
96     {
97         // The message or context were null
98         log<level::ERR>(
99             "Unable to service get pgood timeout property callback");
100         return -1;
101     }
102 
103     return 1;
104 }
105 
106 int PowerInterface::callbackGetPowerState(sd_bus_message* msg, void* context,
107                                           sd_bus_error* error)
108 {
109     if (msg != nullptr && context != nullptr)
110     {
111         try
112         {
113             auto pwrObj = static_cast<PowerInterface*>(context);
114             // Return the current power state of the GPIO, rather than the last
115             // requested power state change
116             int pgood = pwrObj->getPgood();
117             log<level::INFO>(
118                 fmt::format("callbackGetPowerState: {}", pgood).c_str());
119 
120             auto reply = sdbusplus::message_t(msg).new_method_return();
121             reply.append(pgood);
122             reply.method_return();
123         }
124         catch (const sdbusplus::exception_t& e)
125         {
126             return sd_bus_error_set(error, e.name(), e.description());
127         }
128     }
129     else
130     {
131         // The message or context were null
132         log<level::ERR>("Unable to service getPowerState method callback");
133         return -1;
134     }
135 
136     return 1;
137 }
138 
139 int PowerInterface::callbackSetPgoodTimeout(sd_bus* /*bus*/,
140                                             const char* /*path*/,
141                                             const char* /*interface*/,
142                                             const char* /*property*/,
143                                             sd_bus_message* msg, void* context,
144                                             sd_bus_error* error)
145 {
146     if (msg != nullptr && context != nullptr)
147     {
148         try
149         {
150             auto m = sdbusplus::message_t(msg);
151 
152             int timeout{};
153             m.read(timeout);
154             log<level::INFO>(
155                 fmt::format("callbackSetPgoodTimeout: {}", timeout).c_str());
156 
157             auto pwrObj = static_cast<PowerInterface*>(context);
158             pwrObj->setPgoodTimeout(timeout);
159         }
160         catch (const sdbusplus::exception_t& e)
161         {
162             return sd_bus_error_set(error, e.name(), e.description());
163         }
164     }
165     else
166     {
167         // The message or context were null
168         log<level::ERR>(
169             "Unable to service set pgood timeout property callback");
170         return -1;
171     }
172 
173     return 1;
174 }
175 
176 int PowerInterface::callbackGetState(sd_bus* /*bus*/, const char* /*path*/,
177                                      const char* /*interface*/,
178                                      const char* /*property*/,
179                                      sd_bus_message* msg, void* context,
180                                      sd_bus_error* error)
181 {
182     if (msg != nullptr && context != nullptr)
183     {
184         try
185         {
186             auto pwrObj = static_cast<PowerInterface*>(context);
187             int state = pwrObj->getState();
188             log<level::INFO>(
189                 fmt::format("callbackGetState: {}", state).c_str());
190 
191             sdbusplus::message_t(msg).append(state);
192         }
193         catch (const sdbusplus::exception_t& e)
194         {
195             return sd_bus_error_set(error, e.name(), e.description());
196         }
197     }
198     else
199     {
200         // The message or context were null
201         log<level::ERR>("Unable to service get state property callback");
202         return -1;
203     }
204 
205     return 1;
206 }
207 
208 int PowerInterface::callbackSetPowerState(sd_bus_message* msg, void* context,
209                                           sd_bus_error* error)
210 {
211     if (msg != nullptr && context != nullptr)
212     {
213         try
214         {
215             auto m = sdbusplus::message_t(msg);
216 
217             int state{};
218             m.read(state);
219 
220             if (state != 1 && state != 0)
221             {
222                 return sd_bus_error_set(error,
223                                         "org.openbmc.ControlPower.Error.Failed",
224                                         "Invalid power state");
225             }
226             log<level::INFO>(
227                 fmt::format("callbackSetPowerState: {}", state).c_str());
228 
229             auto pwrObj = static_cast<PowerInterface*>(context);
230             pwrObj->setState(state);
231 
232             m.new_method_return().method_return();
233         }
234         catch (const sdbusplus::exception_t& e)
235         {
236             return sd_bus_error_set(error, e.name(), e.description());
237         }
238     }
239     else
240     {
241         // The message or context were null
242         log<level::ERR>("Unable to service setPowerState method callback");
243         return -1;
244     }
245 
246     return 1;
247 }
248 
249 int PowerInterface::callbackSetPowerSupplyError(sd_bus_message* msg,
250                                                 void* context,
251                                                 sd_bus_error* error)
252 {
253     if (msg != nullptr && context != nullptr)
254     {
255         try
256         {
257             auto m = sdbusplus::message_t(msg);
258 
259             std::string psError{};
260             m.read(psError);
261             log<level::INFO>(
262                 fmt::format("callbackSetPowerSupplyError: {}", psError)
263                     .c_str());
264 
265             auto pwrObj = static_cast<PowerInterface*>(context);
266             pwrObj->setPowerSupplyError(psError);
267 
268             m.new_method_return().method_return();
269         }
270         catch (const sdbusplus::exception_t& e)
271         {
272             return sd_bus_error_set(error, e.name(), e.description());
273         }
274     }
275     else
276     {
277         // The message or context were null
278         log<level::ERR>(
279             "Unable to service setPowerSupplyError method callback");
280         return -1;
281     }
282 
283     return 1;
284 }
285 
286 void PowerInterface::emitPowerGoodSignal()
287 {
288     log<level::INFO>("emitPowerGoodSignal");
289     serverInterface.new_signal("PowerGood").signal_send();
290 }
291 
292 void PowerInterface::emitPowerLostSignal()
293 {
294     log<level::INFO>("emitPowerLostSignal");
295     serverInterface.new_signal("PowerLost").signal_send();
296 }
297 
298 void PowerInterface::emitPropertyChangedSignal(const char* property)
299 {
300     log<level::INFO>(
301         fmt::format("emitPropertyChangedSignal: {}", property).c_str());
302     serverInterface.property_changed(property);
303 }
304 
305 const sdbusplus::vtable::vtable_t PowerInterface::vtable[] = {
306     sdbusplus::vtable::start(),
307     // Method setPowerState takes an int parameter and returns void
308     sdbusplus::vtable::method("setPowerState", "i", "", callbackSetPowerState),
309     // Method getPowerState takes no parameters and returns int
310     sdbusplus::vtable::method("getPowerState", "", "i", callbackGetPowerState),
311     // Signal PowerGood
312     sdbusplus::vtable::signal("PowerGood", ""),
313     // Signal PowerLost
314     sdbusplus::vtable::signal("PowerLost", ""),
315     // Property pgood is type int, read only, and uses the emits_change flag
316     sdbusplus::vtable::property("pgood", "i", callbackGetPgood,
317                                 sdbusplus::vtable::property_::emits_change),
318     // Property state is type int, read only, and uses the emits_change flag
319     sdbusplus::vtable::property("state", "i", callbackGetState,
320                                 sdbusplus::vtable::property_::emits_change),
321     // Property pgood_timeout is type int, read write, and uses the emits_change
322     // flag
323     sdbusplus::vtable::property("pgood_timeout", "i", callbackGetPgoodTimeout,
324                                 callbackSetPgoodTimeout,
325                                 sdbusplus::vtable::property_::emits_change),
326     // Method setPowerSupplyError takes a string parameter and returns void
327     sdbusplus::vtable::method("setPowerSupplyError", "s", "",
328                               callbackSetPowerSupplyError),
329     sdbusplus::vtable::end()};
330 
331 } // namespace phosphor::power::sequencer
332