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 
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 
40 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 
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 
67 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 
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 
94 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 
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 
130 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 
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 
165 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 
175 void OccDBusSensors::setChassisAssociation(
176     const std::string& path, const std::vector<std::string>& fTypes)
177 {
178     using AssociationsEntry = std::tuple<std::string, std::string, std::string>;
179     using AssociationsProperty = std::vector<AssociationsEntry>;
180     using PropVariant = sdbusplus::xyz::openbmc_project::Association::server::
181         Definitions::PropertiesVariant;
182 
183     if (chassisPath.empty())
184     {
185         chassisPath = getChassisPath();
186     }
187 
188     AssociationsProperty associations;
189     for (const auto& fType : fTypes)
190     {
191         associations.emplace_back("chassis", fType, chassisPath);
192     }
193     PropVariant value{std::move(associations)};
194 
195     std::map<std::string, PropVariant> properties;
196     properties.emplace("Associations", std::move(value));
197 
198     chassisAssociations.emplace(
199         path, std::make_unique<AssociationIntf>(utils::getBus(), path.c_str(),
200                                                 properties));
201 }
202 
203 std::string OccDBusSensors::getChassisPath()
204 {
205     try
206     {
207         auto paths = utils::getSubtreePaths(std::vector{chassisInterface});
208 
209         // For now, support either 1 chassis, or multiple as long as one
210         // of them has the standard name, which we will use.  If this ever
211         // fails, then someone would have to figure out how to identify the
212         // chassis the OCCs are on.
213         if (paths.size() == 1)
214         {
215             return paths[0];
216         }
217         else if (std::find(paths.begin(), paths.end(), defaultChassisPath) ==
218                  paths.end())
219         {
220             log<level::ERR>(
221                 std::format(
222                     "Could not find a chassis out of {} chassis objects",
223                     paths.size())
224                     .c_str());
225             // Can't throw an exception here, the sdeventplus timer
226             // just catches it.
227             abort();
228         }
229     }
230     catch (const std::exception& e)
231     {
232         log<level::ERR>(
233             std::format("Error looking up chassis objects: {}", e.what())
234                 .c_str());
235         abort();
236     }
237 
238     return defaultChassisPath;
239 }
240 
241 bool OccDBusSensors::hasDvfsTemp(const std::string& path) const
242 {
243     return dvfsTemps.find(path) != dvfsTemps.end();
244 }
245 
246 void OccDBusSensors::setDvfsTemp(const std::string& path, double value)
247 {
248     dvfsTemps[path] =
249         std::make_unique<SensorIntf>(utils::getBus(), path.c_str());
250     dvfsTemps[path]->value(value);
251 }
252 
253 } // namespace dbus
254 } // namespace occ
255 } // namespace open_power
256