blob: d2ab5ca6a19f35ab524ad144a8410ff4d85bb656 [file] [log] [blame]
James Feist6714a252018-09-10 15:26:18 -07001#pragma once
Ed Tanous8a57ec02020-10-09 12:46:52 -07002#include <VariantVisitors.hpp>
James Feistc71c1192019-09-18 14:31:33 -07003#include <boost/algorithm/string/predicate.hpp>
James Feist8086aba2020-08-25 16:00:59 -07004#include <boost/asio/steady_timer.hpp>
James Feist6714a252018-09-10 15:26:18 -07005#include <boost/container/flat_map.hpp>
James Feist38fb5982020-05-28 10:09:54 -07006#include <sdbusplus/asio/connection.hpp>
7#include <sdbusplus/asio/object_server.hpp>
8#include <sdbusplus/message/types.hpp>
9
James Feist24f02f22019-04-15 11:05:39 -070010#include <filesystem>
Patrick Venturefd6ba732019-10-31 14:27:39 -070011#include <functional>
James Feist6714a252018-09-10 15:26:18 -070012#include <iostream>
Patrick Venturefd6ba732019-10-31 14:27:39 -070013#include <memory>
James Feist6714a252018-09-10 15:26:18 -070014#include <regex>
Patrick Venturefd6ba732019-10-31 14:27:39 -070015#include <string>
16#include <tuple>
17#include <utility>
18#include <variant>
19#include <vector>
James Feist6714a252018-09-10 15:26:18 -070020
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070021const constexpr char* jsonStore = "/var/configuration/flattened.json";
22const constexpr char* inventoryPath = "/xyz/openbmc_project/inventory";
23const constexpr char* entityManagerName = "xyz.openbmc_project.EntityManager";
James Feist58295ad2019-05-30 15:01:41 -070024
25constexpr const char* cpuInventoryPath =
26 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070027const std::regex illegalDbusRegex("[^A-Za-z0-9_]");
James Feist6714a252018-09-10 15:26:18 -070028
29using BasicVariantType =
James Feist3eb82622019-02-08 13:10:22 -080030 std::variant<std::vector<std::string>, std::string, int64_t, uint64_t,
31 double, int32_t, uint32_t, int16_t, uint16_t, uint8_t, bool>;
Alex Qiu8b3f7d42020-01-06 13:54:42 -080032using SensorBaseConfigMap =
33 boost::container::flat_map<std::string, BasicVariantType>;
34using SensorBaseConfiguration = std::pair<std::string, SensorBaseConfigMap>;
35using SensorData = boost::container::flat_map<std::string, SensorBaseConfigMap>;
36using ManagedObjectType =
37 boost::container::flat_map<sdbusplus::message::object_path, SensorData>;
James Feist6714a252018-09-10 15:26:18 -070038
James Feista5e58722019-04-22 14:43:11 -070039using GetSubTreeType = std::vector<
40 std::pair<std::string,
41 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
James Feistd8bd5622019-06-26 12:09:05 -070042using Association = std::tuple<std::string, std::string, std::string>;
43
Jason Ling100c20b2020-08-11 14:50:33 -070044std::optional<std::string> openAndRead(const std::string& hwmonFile);
45std::optional<std::string>
46 getFullHwmonFilePath(const std::string& directory,
47 const std::string& hwmonBaseName,
48 const std::set<std::string>& permitSet);
49std::set<std::string> getPermitSet(const SensorBaseConfigMap& config);
Ed Tanous8a57ec02020-10-09 12:46:52 -070050bool findFiles(const std::filesystem::path& dirPath,
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070051 const std::string& matchString,
James Feistcf3bce62019-01-08 10:07:19 -080052 std::vector<std::filesystem::path>& foundPaths,
Ed Tanous8a57ec02020-10-09 12:46:52 -070053 int symlinkDepth = 1);
James Feist71d31b22019-01-02 16:57:54 -080054bool isPowerOn(void);
James Feistfc94b212019-02-06 16:14:51 -080055bool hasBiosPost(void);
James Feist71d31b22019-01-02 16:57:54 -080056void setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection>& conn);
James Feist6714a252018-09-10 15:26:18 -070057bool getSensorConfiguration(
58 const std::string& type,
59 const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
Ed Tanous8a57ec02020-10-09 12:46:52 -070060 ManagedObjectType& resp, bool useCache);
61
62bool getSensorConfiguration(
63 const std::string& type,
64 const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
65 ManagedObjectType& resp);
James Feist87d713a2018-12-06 16:06:24 -080066
James Feist82bac4c2019-03-11 11:16:53 -070067void createAssociation(
68 std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
69 const std::string& path);
70
James Feist87d713a2018-12-06 16:06:24 -080071// replaces limits if MinReading and MaxReading are found.
72void findLimits(std::pair<double, double>& limits,
James Feist40a72142018-12-21 10:09:53 -080073 const SensorBaseConfiguration* data);
74
James Feistfc94b212019-02-06 16:14:51 -080075enum class PowerState
James Feist6ef20402019-01-07 16:45:08 -080076{
77 on,
James Feistfc94b212019-02-06 16:14:51 -080078 biosPost,
James Feist6ef20402019-01-07 16:45:08 -080079 always
80};
81
James Feista5e58722019-04-22 14:43:11 -070082namespace mapper
83{
84constexpr const char* busName = "xyz.openbmc_project.ObjectMapper";
85constexpr const char* path = "/xyz/openbmc_project/object_mapper";
86constexpr const char* interface = "xyz.openbmc_project.ObjectMapper";
87constexpr const char* subtree = "GetSubTree";
88} // namespace mapper
89
90namespace properties
91{
92constexpr const char* interface = "org.freedesktop.DBus.Properties";
93constexpr const char* get = "Get";
James Feist49a8ccd2020-09-16 16:09:52 -070094constexpr const char* set = "Set";
James Feista5e58722019-04-22 14:43:11 -070095} // namespace properties
96
James Feist52497fd2019-06-07 13:01:33 -070097namespace power
98{
99const static constexpr char* busname = "xyz.openbmc_project.State.Host";
100const static constexpr char* interface = "xyz.openbmc_project.State.Host";
101const static constexpr char* path = "/xyz/openbmc_project/state/host0";
102const static constexpr char* property = "CurrentHostState";
103} // namespace power
104namespace post
105{
106const static constexpr char* busname =
107 "xyz.openbmc_project.State.OperatingSystem";
108const static constexpr char* interface =
109 "xyz.openbmc_project.State.OperatingSystem.Status";
110const static constexpr char* path = "/xyz/openbmc_project/state/os";
111const static constexpr char* property = "OperatingSystemState";
112} // namespace post
113
James Feist2adc95c2019-09-30 14:55:28 -0700114namespace association
115{
116const static constexpr char* interface =
117 "xyz.openbmc_project.Association.Definitions";
118} // namespace association
119
James Feist40a72142018-12-21 10:09:53 -0800120template <typename T>
121inline T loadVariant(
122 const boost::container::flat_map<std::string, BasicVariantType>& data,
123 const std::string& key)
124{
125 auto it = data.find(key);
126 if (it == data.end())
127 {
128 std::cerr << "Configuration missing " << key << "\n";
129 throw std::invalid_argument("Key Missing");
130 }
131 if constexpr (std::is_same_v<T, double>)
132 {
James Feist3eb82622019-02-08 13:10:22 -0800133 return std::visit(VariantToDoubleVisitor(), it->second);
James Feist40a72142018-12-21 10:09:53 -0800134 }
James Feist6ef20402019-01-07 16:45:08 -0800135 else if constexpr (std::is_unsigned_v<T>)
136 {
James Feist3eb82622019-02-08 13:10:22 -0800137 return std::visit(VariantToUnsignedIntVisitor(), it->second);
James Feist6ef20402019-01-07 16:45:08 -0800138 }
James Feist40a72142018-12-21 10:09:53 -0800139 else if constexpr (std::is_same_v<T, std::string>)
140 {
James Feist3eb82622019-02-08 13:10:22 -0800141 return std::visit(VariantToStringVisitor(), it->second);
James Feist40a72142018-12-21 10:09:53 -0800142 }
143 else
144 {
James Feist52497fd2019-06-07 13:01:33 -0700145 static_assert(!std::is_same_v<T, T>, "Type Not Implemented");
James Feist40a72142018-12-21 10:09:53 -0800146 }
147}
James Feistfc94b212019-02-06 16:14:51 -0800148
149inline void setReadState(const std::string& str, PowerState& val)
150{
151
152 if (str == "On")
153 {
154 val = PowerState::on;
155 }
156 else if (str == "BiosPost")
157 {
158 val = PowerState::biosPost;
159 }
160 else if (str == "Always")
161 {
162 val = PowerState::always;
163 }
164}
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800165
Ed Tanous8a57ec02020-10-09 12:46:52 -0700166inline void setLed(const std::shared_ptr<sdbusplus::asio::connection>& conn,
James Feist49a8ccd2020-09-16 16:09:52 -0700167 const std::string& name, bool on)
168{
169 conn->async_method_call(
170 [name](const boost::system::error_code ec) {
171 if (ec)
172 {
173 std::cerr << "Failed to set LED " << name << "\n";
174 }
175 },
176 "xyz.openbmc_project.LED.GroupManager",
177 "/xyz/openbmc_project/led/groups/" + name, properties::interface,
178 properties::set, "xyz.openbmc_project.Led.Group", "Asserted",
179 std::variant<bool>(on));
180}
181
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800182void createInventoryAssoc(
Ed Tanous8a57ec02020-10-09 12:46:52 -0700183 const std::shared_ptr<sdbusplus::asio::connection>& conn,
184 const std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800185 const std::string& path);
James Feistc71c1192019-09-18 14:31:33 -0700186
James Feist38fb5982020-05-28 10:09:54 -0700187struct GetSensorConfiguration :
188 std::enable_shared_from_this<GetSensorConfiguration>
James Feistc71c1192019-09-18 14:31:33 -0700189{
190 GetSensorConfiguration(
191 std::shared_ptr<sdbusplus::asio::connection> connection,
192 std::function<void(ManagedObjectType& resp)>&& callbackFunc) :
Ed Tanous8a57ec02020-10-09 12:46:52 -0700193 dbusConnection(std::move(connection)),
James Feistc71c1192019-09-18 14:31:33 -0700194 callback(std::move(callbackFunc))
James Feist38fb5982020-05-28 10:09:54 -0700195 {}
James Feistf27a55c2020-08-04 14:27:30 -0700196
197 void getPath(const std::string& path, const std::string& interface,
198 const std::string& owner, size_t retries = 5)
James Feistc71c1192019-09-18 14:31:33 -0700199 {
James Feistf27a55c2020-08-04 14:27:30 -0700200 if (retries > 5)
201 {
202 retries = 5;
203 }
204 std::shared_ptr<GetSensorConfiguration> self = shared_from_this();
205
206 self->dbusConnection->async_method_call(
207 [self, path, interface, owner,
208 retries](const boost::system::error_code ec,
209 boost::container::flat_map<std::string, BasicVariantType>&
210 data) {
211 if (ec)
212 {
213 std::cerr << "Error getting " << path << ": retries left"
214 << retries - 1 << "\n";
215 if (!retries)
216 {
217 return;
218 }
219 auto timer = std::make_shared<boost::asio::steady_timer>(
220 self->dbusConnection->get_io_context());
221 timer->expires_after(std::chrono::seconds(10));
222 timer->async_wait([self, timer, path, interface, owner,
223 retries](boost::system::error_code ec) {
224 if (ec)
225 {
226 std::cerr << "Timer error!\n";
227 return;
228 }
229 self->getPath(path, interface, owner, retries - 1);
230 });
231 return;
232 }
233
234 self->respData[path][interface] = std::move(data);
235 },
236 owner, path, "org.freedesktop.DBus.Properties", "GetAll",
237 interface);
238 }
239
240 void getConfiguration(const std::vector<std::string>& interfaces,
241 size_t retries = 0)
242 {
243 if (retries > 5)
244 {
245 retries = 5;
246 }
247
James Feistc71c1192019-09-18 14:31:33 -0700248 std::shared_ptr<GetSensorConfiguration> self = shared_from_this();
249 dbusConnection->async_method_call(
James Feistf27a55c2020-08-04 14:27:30 -0700250 [self, interfaces, retries](const boost::system::error_code ec,
251 const GetSubTreeType& ret) {
James Feistc71c1192019-09-18 14:31:33 -0700252 if (ec)
253 {
254 std::cerr << "Error calling mapper\n";
James Feistf27a55c2020-08-04 14:27:30 -0700255 if (!retries)
256 {
257 return;
258 }
259 auto timer = std::make_shared<boost::asio::steady_timer>(
260 self->dbusConnection->get_io_context());
261 timer->expires_after(std::chrono::seconds(10));
262 timer->async_wait([self, timer, interfaces,
263 retries](boost::system::error_code ec) {
264 if (ec)
265 {
266 std::cerr << "Timer error!\n";
267 return;
268 }
269 self->getConfiguration(interfaces, retries - 1);
270 });
271
James Feistc71c1192019-09-18 14:31:33 -0700272 return;
273 }
274 for (const auto& [path, objDict] : ret)
275 {
276 if (objDict.empty())
277 {
278 return;
279 }
280 const std::string& owner = objDict.begin()->first;
281
282 for (const std::string& interface : objDict.begin()->second)
283 {
284 // anything that starts with a requested configuration
285 // is good
286 if (std::find_if(
287 interfaces.begin(), interfaces.end(),
288 [interface](const std::string& possible) {
289 return boost::starts_with(interface,
290 possible);
291 }) == interfaces.end())
292 {
293 continue;
294 }
James Feistf27a55c2020-08-04 14:27:30 -0700295 self->getPath(path, interface, owner);
James Feistc71c1192019-09-18 14:31:33 -0700296 }
297 }
298 },
299 mapper::busName, mapper::path, mapper::interface, mapper::subtree,
300 "/", 0, interfaces);
301 }
302
303 ~GetSensorConfiguration()
304 {
305 callback(respData);
306 }
307
308 std::shared_ptr<sdbusplus::asio::connection> dbusConnection;
309 std::function<void(ManagedObjectType& resp)> callback;
310 ManagedObjectType respData;
311};
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200312
313// The common scheme for sysfs files naming is: <type><number>_<item>.
314// This function returns optionally these 3 elements as a tuple.
315std::optional<std::tuple<std::string, std::string, std::string>>
316 splitFileName(const std::filesystem::path& filePath);
317std::optional<double> readFile(const std::string& thresholdFile,
James Feist8086aba2020-08-25 16:00:59 -0700318 const double& scaleFactor);