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