1 #include "occ_dbus.hpp"
2 
3 #include "utils.hpp"
4 
5 #include <phosphor-logging/lg2.hpp>
6 
7 #include <iostream>
8 
9 namespace open_power
10 {
11 namespace occ
12 {
13 namespace dbus
14 {
15 
16 using namespace std::string_literals;
17 const auto defaultChassisPath =
18     "/xyz/openbmc_project/inventory/system/chassis"s;
19 const auto chassisInterface = "xyz.openbmc_project.Inventory.Item.Chassis"s;
20 
setMaxValue(const std::string & path,double value)21 bool OccDBusSensors::setMaxValue(const std::string& path, double value)
22 {
23     if (path.empty())
24     {
25         return false;
26     }
27 
28     if (!sensors.contains(path))
29     {
30         sensors.emplace(
31             path, std::make_unique<SensorIntf>(utils::getBus(), path.c_str()));
32     }
33 
34     sensors.at(path)->maxValue(value);
35     return true;
36 }
37 
getMaxValue(const std::string & path) const38 double OccDBusSensors::getMaxValue(const std::string& path) const
39 {
40     if (sensors.find(path) != sensors.end())
41     {
42         return sensors.at(path)->maxValue();
43     }
44 
45     throw std::invalid_argument("Failed to get MaxValue property.");
46 }
47 
setMinValue(const std::string & path,double value)48 bool OccDBusSensors::setMinValue(const std::string& path, double value)
49 {
50     if (path.empty())
51     {
52         return false;
53     }
54 
55     if (!sensors.contains(path))
56     {
57         sensors.emplace(
58             path, std::make_unique<SensorIntf>(utils::getBus(), path.c_str()));
59     }
60 
61     sensors.at(path)->minValue(value);
62     return true;
63 }
64 
getMinValue(const std::string & path) const65 double OccDBusSensors::getMinValue(const std::string& path) const
66 {
67     if (sensors.find(path) != sensors.end())
68     {
69         return sensors.at(path)->minValue();
70     }
71 
72     throw std::invalid_argument("Failed to get MinValue property.");
73 }
74 
setValue(const std::string & path,double value)75 bool OccDBusSensors::setValue(const std::string& path, double value)
76 {
77     if (path.empty())
78     {
79         return false;
80     }
81 
82     if (!sensors.contains(path))
83     {
84         sensors.emplace(
85             path, std::make_unique<SensorIntf>(utils::getBus(), path.c_str()));
86     }
87 
88     sensors.at(path)->value(value);
89     return true;
90 }
91 
getValue(const std::string & path) const92 double OccDBusSensors::getValue(const std::string& path) const
93 {
94     if (sensors.find(path) != sensors.end())
95     {
96         return sensors.at(path)->value();
97     }
98 
99     throw std::invalid_argument("Failed to get Value property.");
100 }
101 
setUnit(const std::string & path,const std::string & value)102 bool OccDBusSensors::setUnit(const std::string& path, const std::string& value)
103 {
104     if (path.empty())
105     {
106         return false;
107     }
108 
109     if (!sensors.contains(path))
110     {
111         sensors.emplace(
112             path, std::make_unique<SensorIntf>(utils::getBus(), path.c_str()));
113     }
114 
115     try
116     {
117         sensors.at(path)->unit(SensorIntf::convertUnitFromString(value));
118     }
119     catch (const std::exception& e)
120     {
121         lg2::error("set Unit propety failed: error={ERR}", "ERR", e.what());
122         return false;
123     }
124 
125     return true;
126 }
127 
getUnit(const std::string & path) const128 std::string OccDBusSensors::getUnit(const std::string& path) const
129 {
130     if (sensors.find(path) != sensors.end())
131     {
132         try
133         {
134             return SensorIntf::convertUnitToString(sensors.at(path)->unit());
135         }
136         catch (const std::exception& e)
137         {
138             lg2::error("get Unit propety failed: error={ERR}", "ERR", e.what());
139         }
140     }
141 
142     throw std::invalid_argument("Failed to get Unit property.");
143 }
144 
setOperationalStatus(const std::string & path,bool value)145 bool OccDBusSensors::setOperationalStatus(const std::string& path, bool value)
146 {
147     if (path.empty())
148     {
149         return false;
150     }
151 
152     if (!operationalStatus.contains(path))
153     {
154         operationalStatus.emplace(path, std::make_unique<OperationalStatusIntf>(
155                                             utils::getBus(), path.c_str()));
156     }
157 
158     operationalStatus.at(path)->functional(value);
159     return true;
160 }
161 
getOperationalStatus(const std::string & path) const162 bool OccDBusSensors::getOperationalStatus(const std::string& path) const
163 {
164     if (operationalStatus.find(path) != operationalStatus.end())
165     {
166         return operationalStatus.at(path)->functional();
167     }
168 
169     throw std::invalid_argument("Failed to get OperationalStatus property.");
170 }
171 
setChassisAssociation(const std::string & path,const std::vector<std::string> & fTypes)172 void OccDBusSensors::setChassisAssociation(
173     const std::string& path, const std::vector<std::string>& fTypes)
174 {
175     using AssociationsEntry = std::tuple<std::string, std::string, std::string>;
176     using AssociationsProperty = std::vector<AssociationsEntry>;
177     using PropVariant = sdbusplus::xyz::openbmc_project::Association::server::
178         Definitions::PropertiesVariant;
179 
180     if (chassisPath.empty())
181     {
182         chassisPath = getChassisPath();
183     }
184 
185     AssociationsProperty associations;
186     for (const auto& fType : fTypes)
187     {
188         associations.emplace_back("chassis", fType, chassisPath);
189     }
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 
getChassisPath()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             lg2::error("Could not find a chassis out of {NUM} chassis objects",
218                        "NUM", paths.size());
219             // Can't throw an exception here, the sdeventplus timer
220             // just catches it.
221             abort();
222         }
223     }
224     catch (const std::exception& e)
225     {
226         lg2::error("Error looking up chassis objects: {ERR}", "ERR", e.what());
227         abort();
228     }
229 
230     return defaultChassisPath;
231 }
232 
hasDvfsTemp(const std::string & path) const233 bool OccDBusSensors::hasDvfsTemp(const std::string& path) const
234 {
235     return dvfsTemps.find(path) != dvfsTemps.end();
236 }
237 
setDvfsTemp(const std::string & path,double value)238 void OccDBusSensors::setDvfsTemp(const std::string& path, double value)
239 {
240     dvfsTemps[path] =
241         std::make_unique<SensorIntf>(utils::getBus(), path.c_str());
242     dvfsTemps[path]->value(value);
243 }
244 
245 } // namespace dbus
246 } // namespace occ
247 } // namespace open_power
248