1 #include "occ_dbus.hpp"
2 
3 #include "utils.hpp"
4 
5 #include <phosphor-logging/log.hpp>
6 
7 #include <format>
8 #include <iostream>
9 
10 namespace open_power
11 {
12 namespace occ
13 {
14 namespace dbus
15 {
16 
17 using namespace phosphor::logging;
18 using namespace std::string_literals;
19 const auto defaultChassisPath =
20     "/xyz/openbmc_project/inventory/system/chassis"s;
21 const auto chassisInterface = "xyz.openbmc_project.Inventory.Item.Chassis"s;
22 
setMaxValue(const std::string & path,double value)23 bool OccDBusSensors::setMaxValue(const std::string& path, double value)
24 {
25     if (path.empty())
26     {
27         return false;
28     }
29 
30     if (!sensors.contains(path))
31     {
32         sensors.emplace(
33             path, std::make_unique<SensorIntf>(utils::getBus(), path.c_str()));
34     }
35 
36     sensors.at(path)->maxValue(value);
37     return true;
38 }
39 
getMaxValue(const std::string & path) const40 double OccDBusSensors::getMaxValue(const std::string& path) const
41 {
42     if (sensors.find(path) != sensors.end())
43     {
44         return sensors.at(path)->maxValue();
45     }
46 
47     throw std::invalid_argument("Failed to get MaxValue property.");
48 }
49 
setMinValue(const std::string & path,double value)50 bool OccDBusSensors::setMinValue(const std::string& path, double value)
51 {
52     if (path.empty())
53     {
54         return false;
55     }
56 
57     if (!sensors.contains(path))
58     {
59         sensors.emplace(
60             path, std::make_unique<SensorIntf>(utils::getBus(), path.c_str()));
61     }
62 
63     sensors.at(path)->minValue(value);
64     return true;
65 }
66 
getMinValue(const std::string & path) const67 double OccDBusSensors::getMinValue(const std::string& path) const
68 {
69     if (sensors.find(path) != sensors.end())
70     {
71         return sensors.at(path)->minValue();
72     }
73 
74     throw std::invalid_argument("Failed to get MinValue property.");
75 }
76 
setValue(const std::string & path,double value)77 bool OccDBusSensors::setValue(const std::string& path, double value)
78 {
79     if (path.empty())
80     {
81         return false;
82     }
83 
84     if (!sensors.contains(path))
85     {
86         sensors.emplace(
87             path, std::make_unique<SensorIntf>(utils::getBus(), path.c_str()));
88     }
89 
90     sensors.at(path)->value(value);
91     return true;
92 }
93 
getValue(const std::string & path) const94 double OccDBusSensors::getValue(const std::string& path) const
95 {
96     if (sensors.find(path) != sensors.end())
97     {
98         return sensors.at(path)->value();
99     }
100 
101     throw std::invalid_argument("Failed to get Value property.");
102 }
103 
setUnit(const std::string & path,const std::string & value)104 bool OccDBusSensors::setUnit(const std::string& path, const std::string& value)
105 {
106     if (path.empty())
107     {
108         return false;
109     }
110 
111     if (!sensors.contains(path))
112     {
113         sensors.emplace(
114             path, std::make_unique<SensorIntf>(utils::getBus(), path.c_str()));
115     }
116 
117     try
118     {
119         sensors.at(path)->unit(SensorIntf::convertUnitFromString(value));
120     }
121     catch (const std::exception& e)
122     {
123         log<level::ERR>("set Unit propety failed", entry("ERROR=%s", e.what()));
124         return false;
125     }
126 
127     return true;
128 }
129 
getUnit(const std::string & path) const130 std::string OccDBusSensors::getUnit(const std::string& path) const
131 {
132     if (sensors.find(path) != sensors.end())
133     {
134         try
135         {
136             return SensorIntf::convertUnitToString(sensors.at(path)->unit());
137         }
138         catch (const std::exception& e)
139         {
140             log<level::ERR>("get Unit propety failed",
141                             entry("ERROR=%s", e.what()));
142         }
143     }
144 
145     throw std::invalid_argument("Failed to get Unit property.");
146 }
147 
setOperationalStatus(const std::string & path,bool value)148 bool OccDBusSensors::setOperationalStatus(const std::string& path, bool value)
149 {
150     if (path.empty())
151     {
152         return false;
153     }
154 
155     if (!operationalStatus.contains(path))
156     {
157         operationalStatus.emplace(path, std::make_unique<OperationalStatusIntf>(
158                                             utils::getBus(), path.c_str()));
159     }
160 
161     operationalStatus.at(path)->functional(value);
162     return true;
163 }
164 
getOperationalStatus(const std::string & path) const165 bool OccDBusSensors::getOperationalStatus(const std::string& path) const
166 {
167     if (operationalStatus.find(path) != operationalStatus.end())
168     {
169         return operationalStatus.at(path)->functional();
170     }
171 
172     throw std::invalid_argument("Failed to get OperationalStatus property.");
173 }
174 
setChassisAssociation(const std::string & path)175 void OccDBusSensors::setChassisAssociation(const std::string& path)
176 {
177     using AssociationsEntry = std::tuple<std::string, std::string, std::string>;
178     using AssociationsProperty = std::vector<AssociationsEntry>;
179     using PropVariant = sdbusplus::xyz::openbmc_project::Association::server::
180         Definitions::PropertiesVariant;
181 
182     if (chassisPath.empty())
183     {
184         chassisPath = getChassisPath();
185     }
186 
187     AssociationsProperty associations{
188         AssociationsEntry{"chassis", "all_sensors", chassisPath}};
189     PropVariant value{std::move(associations)};
190 
191     std::map<std::string, PropVariant> properties;
192     properties.emplace("Associations", std::move(value));
193 
194     chassisAssociations.emplace(
195         path, std::make_unique<AssociationIntf>(utils::getBus(), path.c_str(),
196                                                 properties));
197 }
198 
getChassisPath()199 std::string OccDBusSensors::getChassisPath()
200 {
201     try
202     {
203         auto paths = utils::getSubtreePaths(std::vector{chassisInterface});
204 
205         // For now, support either 1 chassis, or multiple as long as one
206         // of them has the standard name, which we will use.  If this ever
207         // fails, then someone would have to figure out how to identify the
208         // chassis the OCCs are on.
209         if (paths.size() == 1)
210         {
211             return paths[0];
212         }
213         else if (std::find(paths.begin(), paths.end(), defaultChassisPath) ==
214                  paths.end())
215         {
216             log<level::ERR>(
217                 std::format(
218                     "Could not find a chassis out of {} chassis objects",
219                     paths.size())
220                     .c_str());
221             // Can't throw an exception here, the sdeventplus timer
222             // just catches it.
223             abort();
224         }
225     }
226     catch (const std::exception& e)
227     {
228         log<level::ERR>(
229             std::format("Error looking up chassis objects: {}", e.what())
230                 .c_str());
231         abort();
232     }
233 
234     return defaultChassisPath;
235 }
236 
hasDvfsTemp(const std::string & path) const237 bool OccDBusSensors::hasDvfsTemp(const std::string& path) const
238 {
239     return dvfsTemps.find(path) != dvfsTemps.end();
240 }
241 
setDvfsTemp(const std::string & path,double value)242 void OccDBusSensors::setDvfsTemp(const std::string& path, double value)
243 {
244     dvfsTemps[path] = std::make_unique<SensorIntf>(utils::getBus(),
245                                                    path.c_str());
246     dvfsTemps[path]->value(value);
247 }
248 
249 } // namespace dbus
250 } // namespace occ
251 } // namespace open_power
252