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