1 /*
2 // Copyright (c) 2018 Intel 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 "dbus/dbuswrite.hpp"
18 
19 #include <iostream>
20 #include <memory>
21 #include <phosphor-logging/log.hpp>
22 #include <sdbusplus/bus.hpp>
23 #include <string>
24 
25 constexpr const char* pwmInterface = "xyz.openbmc_project.Control.FanPwm";
26 
27 using namespace phosphor::logging;
28 
29 // this bus object is treated as a singleton because the class is constructed in
30 // a different thread than it is used, and as bus objects are relatively
31 // expensive we'd prefer to only have one
32 std::unique_ptr<sdbusplus::bus::bus> writeBus = nullptr;
33 
34 std::unique_ptr<WriteInterface>
35     DbusWritePercent::createDbusWrite(const std::string& path, int64_t min,
36                                       int64_t max, DbusHelperInterface& helper)
37 {
38     auto tempBus = sdbusplus::bus::new_default();
39     std::string connectionName;
40 
41     try
42     {
43         connectionName = helper.getService(tempBus, pwmInterface, path);
44     }
45     catch (const std::exception& e)
46     {
47         return nullptr;
48     }
49 
50     return std::make_unique<DbusWritePercent>(path, min, max, connectionName);
51 }
52 
53 void initBus()
54 {
55     if (writeBus == nullptr)
56     {
57         writeBus = std::make_unique<sdbusplus::bus::bus>(
58             sdbusplus::bus::new_default());
59     }
60 }
61 
62 void DbusWritePercent::write(double value)
63 {
64     float minimum = getMin();
65     float maximum = getMax();
66 
67     float range = maximum - minimum;
68     float offset = range * value;
69     float ovalue = offset + minimum;
70 
71     if (oldValue == static_cast<int64_t>(ovalue))
72     {
73         return;
74     }
75     initBus();
76     auto mesg =
77         writeBus->new_method_call(connectionName.c_str(), path.c_str(),
78                                   "org.freedesktop.DBus.Properties", "Set");
79     mesg.append(pwmInterface, "Target",
80                 sdbusplus::message::variant<uint64_t>(ovalue));
81 
82     try
83     {
84         // TODO: if we don't use the reply, call_noreply()
85         auto resp = writeBus->call(mesg);
86     }
87     catch (const sdbusplus::exception::SdBusError& ex)
88     {
89         log<level::ERR>("Dbus Call Failure", entry("PATH=%s", path.c_str()),
90                         entry("WHAT=%s", ex.what()));
91     }
92 
93     oldValue = static_cast<int64_t>(ovalue);
94     return;
95 }
96 
97 std::unique_ptr<WriteInterface>
98     DbusWrite::createDbusWrite(const std::string& path, int64_t min,
99                                int64_t max, DbusHelperInterface& helper)
100 {
101     auto tempBus = sdbusplus::bus::new_default();
102     std::string connectionName;
103 
104     try
105     {
106         connectionName = helper.getService(tempBus, pwmInterface, path);
107     }
108     catch (const std::exception& e)
109     {
110         return nullptr;
111     }
112 
113     return std::make_unique<DbusWrite>(path, min, max, connectionName);
114 }
115 
116 void DbusWrite::write(double value)
117 {
118     if (oldValue == static_cast<int64_t>(value))
119     {
120         return;
121     }
122     initBus();
123     auto mesg =
124         writeBus->new_method_call(connectionName.c_str(), path.c_str(),
125                                   "org.freedesktop.DBus.Properties", "Set");
126     mesg.append(pwmInterface, "Target",
127                 sdbusplus::message::variant<uint64_t>(value));
128 
129     try
130     {
131         // TODO: consider call_noreplly
132         auto resp = writeBus->call(mesg);
133     }
134     catch (const sdbusplus::exception::SdBusError& ex)
135     {
136         log<level::ERR>("Dbus Call Failure", entry("PATH=%s", path.c_str()),
137                         entry("WHAT=%s", ex.what()));
138     }
139 
140     oldValue = static_cast<int64_t>(value);
141     return;
142 }
143