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