1d7be555eSGeorge Liu /*
2d7be555eSGeorge Liu // Copyright (c) 2017 Intel Corporation
3d7be555eSGeorge Liu //
4d7be555eSGeorge Liu // Licensed under the Apache License, Version 2.0 (the "License");
5d7be555eSGeorge Liu // you may not use this file except in compliance with the License.
6d7be555eSGeorge Liu // You may obtain a copy of the License at
7d7be555eSGeorge Liu //
8d7be555eSGeorge Liu // http://www.apache.org/licenses/LICENSE-2.0
9d7be555eSGeorge Liu //
10d7be555eSGeorge Liu // Unless required by applicable law or agreed to in writing, software
11d7be555eSGeorge Liu // distributed under the License is distributed on an "AS IS" BASIS,
12d7be555eSGeorge Liu // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d7be555eSGeorge Liu // See the License for the specific language governing permissions and
14d7be555eSGeorge Liu // limitations under the License.
15d7be555eSGeorge Liu */
16d7be555eSGeorge Liu
17d7be555eSGeorge Liu #include "ADCSensor.hpp"
18d7be555eSGeorge Liu #include "Thresholds.hpp"
19d7be555eSGeorge Liu #include "Utils.hpp"
20d7be555eSGeorge Liu #include "VariantVisitors.hpp"
21d7be555eSGeorge Liu
22d7be555eSGeorge Liu #include <boost/algorithm/string/case_conv.hpp>
23d7be555eSGeorge Liu #include <boost/asio/error.hpp>
24d7be555eSGeorge Liu #include <boost/asio/io_context.hpp>
25d7be555eSGeorge Liu #include <boost/asio/post.hpp>
26d7be555eSGeorge Liu #include <boost/asio/steady_timer.hpp>
27d7be555eSGeorge Liu #include <boost/container/flat_map.hpp>
28d7be555eSGeorge Liu #include <boost/container/flat_set.hpp>
29d7be555eSGeorge Liu #include <gpiod.hpp>
30*d4bc41f2SGeorge Liu #include <phosphor-logging/lg2.hpp>
31d7be555eSGeorge Liu #include <sdbusplus/asio/connection.hpp>
32d7be555eSGeorge Liu #include <sdbusplus/asio/object_server.hpp>
33d7be555eSGeorge Liu #include <sdbusplus/bus.hpp>
34d7be555eSGeorge Liu #include <sdbusplus/bus/match.hpp>
35d7be555eSGeorge Liu #include <sdbusplus/message.hpp>
36d7be555eSGeorge Liu #include <sdbusplus/message/native_types.hpp>
37d7be555eSGeorge Liu
38d7be555eSGeorge Liu #include <array>
39d7be555eSGeorge Liu #include <chrono>
40d7be555eSGeorge Liu #include <cstddef>
41d7be555eSGeorge Liu #include <filesystem>
42d7be555eSGeorge Liu #include <fstream>
43d7be555eSGeorge Liu #include <functional>
44d7be555eSGeorge Liu #include <memory>
45d7be555eSGeorge Liu #include <optional>
46d7be555eSGeorge Liu #include <regex>
47d7be555eSGeorge Liu #include <stdexcept>
48d7be555eSGeorge Liu #include <string>
49d7be555eSGeorge Liu #include <utility>
50d7be555eSGeorge Liu #include <variant>
51d7be555eSGeorge Liu #include <vector>
52d7be555eSGeorge Liu
53d7be555eSGeorge Liu static constexpr bool debug = false;
54d7be555eSGeorge Liu static constexpr float pollRateDefault = 0.5;
55d7be555eSGeorge Liu static constexpr float gpioBridgeSetupTimeDefault = 0.02;
56d7be555eSGeorge Liu
57d7be555eSGeorge Liu static constexpr auto sensorTypes{std::to_array<const char*>({"ADC"})};
58d7be555eSGeorge Liu static std::regex inputRegex(R"(in(\d+)_input)");
59d7be555eSGeorge Liu
60d7be555eSGeorge Liu static boost::container::flat_map<size_t, bool> cpuPresence;
61d7be555eSGeorge Liu
62d7be555eSGeorge Liu enum class UpdateType
63d7be555eSGeorge Liu {
64d7be555eSGeorge Liu init,
65d7be555eSGeorge Liu cpuPresenceChange
66d7be555eSGeorge Liu };
67d7be555eSGeorge Liu
68d7be555eSGeorge Liu // filter out adc from any other voltage sensor
isAdc(const std::filesystem::path & parentPath)692e466967SEd Tanous bool isAdc(const std::filesystem::path& parentPath)
70d7be555eSGeorge Liu {
712e466967SEd Tanous std::filesystem::path namePath = parentPath / "name";
72d7be555eSGeorge Liu
73d7be555eSGeorge Liu std::ifstream nameFile(namePath);
74d7be555eSGeorge Liu if (!nameFile.good())
75d7be555eSGeorge Liu {
76*d4bc41f2SGeorge Liu lg2::error("Failure reading '{PATH}'", "PATH", namePath.string());
77d7be555eSGeorge Liu return false;
78d7be555eSGeorge Liu }
79d7be555eSGeorge Liu
80d7be555eSGeorge Liu std::string name;
81d7be555eSGeorge Liu std::getline(nameFile, name);
82d7be555eSGeorge Liu
83d7be555eSGeorge Liu return name == "iio_hwmon";
84d7be555eSGeorge Liu }
85d7be555eSGeorge Liu
createSensors(boost::asio::io_context & io,sdbusplus::asio::object_server & objectServer,boost::container::flat_map<std::string,std::shared_ptr<ADCSensor>> & sensors,std::shared_ptr<sdbusplus::asio::connection> & dbusConnection,const std::shared_ptr<boost::container::flat_set<std::string>> & sensorsChanged,UpdateType updateType)86d7be555eSGeorge Liu void createSensors(
87d7be555eSGeorge Liu boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
88d7be555eSGeorge Liu boost::container::flat_map<std::string, std::shared_ptr<ADCSensor>>&
89d7be555eSGeorge Liu sensors,
90d7be555eSGeorge Liu std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
91d7be555eSGeorge Liu const std::shared_ptr<boost::container::flat_set<std::string>>&
92d7be555eSGeorge Liu sensorsChanged,
93d7be555eSGeorge Liu UpdateType updateType)
94d7be555eSGeorge Liu {
95d7be555eSGeorge Liu auto getter = std::make_shared<GetSensorConfiguration>(
96d7be555eSGeorge Liu dbusConnection,
97d7be555eSGeorge Liu [&io, &objectServer, &sensors, &dbusConnection, sensorsChanged,
98d7be555eSGeorge Liu updateType](const ManagedObjectType& sensorConfigurations) {
99d7be555eSGeorge Liu bool firstScan = sensorsChanged == nullptr;
1002e466967SEd Tanous std::vector<std::filesystem::path> paths;
1012e466967SEd Tanous if (!findFiles(std::filesystem::path("/sys/class/hwmon"),
1022e466967SEd Tanous R"(in\d+_input)", paths))
103d7be555eSGeorge Liu {
104*d4bc41f2SGeorge Liu lg2::error("No adc sensors in system");
105d7be555eSGeorge Liu return;
106d7be555eSGeorge Liu }
107d7be555eSGeorge Liu
108d7be555eSGeorge Liu // iterate through all found adc sensors, and try to match them with
109d7be555eSGeorge Liu // configuration
110d7be555eSGeorge Liu for (auto& path : paths)
111d7be555eSGeorge Liu {
112d7be555eSGeorge Liu if (!isAdc(path.parent_path()))
113d7be555eSGeorge Liu {
114d7be555eSGeorge Liu continue;
115d7be555eSGeorge Liu }
116d7be555eSGeorge Liu std::smatch match;
117d7be555eSGeorge Liu std::string pathStr = path.string();
118d7be555eSGeorge Liu
119d7be555eSGeorge Liu std::regex_search(pathStr, match, inputRegex);
120d7be555eSGeorge Liu std::string indexStr = *(match.begin() + 1);
121d7be555eSGeorge Liu
122d7be555eSGeorge Liu // convert to 0 based
123d7be555eSGeorge Liu size_t index = std::stoul(indexStr) - 1;
124d7be555eSGeorge Liu
125d7be555eSGeorge Liu const SensorData* sensorData = nullptr;
126d7be555eSGeorge Liu const std::string* interfacePath = nullptr;
127d7be555eSGeorge Liu const std::pair<std::string, SensorBaseConfigMap>*
128d7be555eSGeorge Liu baseConfiguration = nullptr;
129d7be555eSGeorge Liu for (const auto& [path, cfgData] : sensorConfigurations)
130d7be555eSGeorge Liu {
131d7be555eSGeorge Liu // clear it out each loop
132d7be555eSGeorge Liu baseConfiguration = nullptr;
133d7be555eSGeorge Liu
134d7be555eSGeorge Liu // find base configuration
135d7be555eSGeorge Liu for (const char* type : sensorTypes)
136d7be555eSGeorge Liu {
137d7be555eSGeorge Liu auto sensorBase =
138d7be555eSGeorge Liu cfgData.find(configInterfaceName(type));
139d7be555eSGeorge Liu if (sensorBase != cfgData.end())
140d7be555eSGeorge Liu {
141d7be555eSGeorge Liu baseConfiguration = &(*sensorBase);
142d7be555eSGeorge Liu break;
143d7be555eSGeorge Liu }
144d7be555eSGeorge Liu }
145d7be555eSGeorge Liu if (baseConfiguration == nullptr)
146d7be555eSGeorge Liu {
147d7be555eSGeorge Liu continue;
148d7be555eSGeorge Liu }
149d7be555eSGeorge Liu auto findIndex = baseConfiguration->second.find("Index");
150d7be555eSGeorge Liu if (findIndex == baseConfiguration->second.end())
151d7be555eSGeorge Liu {
152*d4bc41f2SGeorge Liu lg2::error(
153*d4bc41f2SGeorge Liu "Base configuration missing Index: '{INTERFACE}'",
154*d4bc41f2SGeorge Liu "INTERFACE", baseConfiguration->first);
155d7be555eSGeorge Liu continue;
156d7be555eSGeorge Liu }
157d7be555eSGeorge Liu
158d7be555eSGeorge Liu unsigned int number = std::visit(
159d7be555eSGeorge Liu VariantToUnsignedIntVisitor(), findIndex->second);
160d7be555eSGeorge Liu
161d7be555eSGeorge Liu if (number != index)
162d7be555eSGeorge Liu {
163d7be555eSGeorge Liu continue;
164d7be555eSGeorge Liu }
165d7be555eSGeorge Liu
166d7be555eSGeorge Liu sensorData = &cfgData;
167d7be555eSGeorge Liu interfacePath = &path.str;
168d7be555eSGeorge Liu break;
169d7be555eSGeorge Liu }
170d7be555eSGeorge Liu if (sensorData == nullptr)
171d7be555eSGeorge Liu {
172d7be555eSGeorge Liu if constexpr (debug)
173d7be555eSGeorge Liu {
174*d4bc41f2SGeorge Liu lg2::error("failed to find match for '{PATH}'", "PATH",
175*d4bc41f2SGeorge Liu path.string());
176d7be555eSGeorge Liu }
177d7be555eSGeorge Liu continue;
178d7be555eSGeorge Liu }
179d7be555eSGeorge Liu
180d7be555eSGeorge Liu if (baseConfiguration == nullptr)
181d7be555eSGeorge Liu {
182*d4bc41f2SGeorge Liu lg2::error("error finding base configuration for '{PATH}'",
183*d4bc41f2SGeorge Liu "PATH", path.string());
184d7be555eSGeorge Liu continue;
185d7be555eSGeorge Liu }
186d7be555eSGeorge Liu
187d7be555eSGeorge Liu auto findSensorName = baseConfiguration->second.find("Name");
188d7be555eSGeorge Liu if (findSensorName == baseConfiguration->second.end())
189d7be555eSGeorge Liu {
190*d4bc41f2SGeorge Liu lg2::error(
191*d4bc41f2SGeorge Liu "could not determine configuration name for '{PATH}'",
192*d4bc41f2SGeorge Liu "PATH", path.string());
193d7be555eSGeorge Liu continue;
194d7be555eSGeorge Liu }
195d7be555eSGeorge Liu std::string sensorName =
196d7be555eSGeorge Liu std::get<std::string>(findSensorName->second);
197d7be555eSGeorge Liu
198d7be555eSGeorge Liu // on rescans, only update sensors we were signaled by
199d7be555eSGeorge Liu auto findSensor = sensors.find(sensorName);
200d7be555eSGeorge Liu if (!firstScan && findSensor != sensors.end())
201d7be555eSGeorge Liu {
202d7be555eSGeorge Liu bool found = false;
203d7be555eSGeorge Liu for (auto it = sensorsChanged->begin();
204d7be555eSGeorge Liu it != sensorsChanged->end(); it++)
205d7be555eSGeorge Liu {
206d7be555eSGeorge Liu if (findSensor->second &&
207d7be555eSGeorge Liu it->ends_with(findSensor->second->name))
208d7be555eSGeorge Liu {
209d7be555eSGeorge Liu sensorsChanged->erase(it);
210d7be555eSGeorge Liu findSensor->second = nullptr;
211d7be555eSGeorge Liu found = true;
212d7be555eSGeorge Liu break;
213d7be555eSGeorge Liu }
214d7be555eSGeorge Liu }
215d7be555eSGeorge Liu if (!found)
216d7be555eSGeorge Liu {
217d7be555eSGeorge Liu continue;
218d7be555eSGeorge Liu }
219d7be555eSGeorge Liu }
220d7be555eSGeorge Liu
221d7be555eSGeorge Liu auto findCPU = baseConfiguration->second.find("CPURequired");
222d7be555eSGeorge Liu if (findCPU != baseConfiguration->second.end())
223d7be555eSGeorge Liu {
224d7be555eSGeorge Liu size_t index =
225d7be555eSGeorge Liu std::visit(VariantToIntVisitor(), findCPU->second);
226d7be555eSGeorge Liu auto presenceFind = cpuPresence.find(index);
227d7be555eSGeorge Liu if (presenceFind == cpuPresence.end())
228d7be555eSGeorge Liu {
229d7be555eSGeorge Liu continue; // no such cpu
230d7be555eSGeorge Liu }
231d7be555eSGeorge Liu if (!presenceFind->second)
232d7be555eSGeorge Liu {
233d7be555eSGeorge Liu continue; // cpu not installed
234d7be555eSGeorge Liu }
235d7be555eSGeorge Liu }
236d7be555eSGeorge Liu else if (updateType == UpdateType::cpuPresenceChange)
237d7be555eSGeorge Liu {
238d7be555eSGeorge Liu continue;
239d7be555eSGeorge Liu }
240d7be555eSGeorge Liu
241d7be555eSGeorge Liu std::vector<thresholds::Threshold> sensorThresholds;
242d7be555eSGeorge Liu if (!parseThresholdsFromConfig(*sensorData, sensorThresholds))
243d7be555eSGeorge Liu {
244*d4bc41f2SGeorge Liu lg2::error("error populating thresholds for '{NAME}'",
245*d4bc41f2SGeorge Liu "NAME", sensorName);
246d7be555eSGeorge Liu }
247d7be555eSGeorge Liu
248d7be555eSGeorge Liu auto findScaleFactor =
249d7be555eSGeorge Liu baseConfiguration->second.find("ScaleFactor");
250d7be555eSGeorge Liu float scaleFactor = 1.0;
251d7be555eSGeorge Liu if (findScaleFactor != baseConfiguration->second.end())
252d7be555eSGeorge Liu {
253d7be555eSGeorge Liu scaleFactor = std::visit(VariantToFloatVisitor(),
254d7be555eSGeorge Liu findScaleFactor->second);
255d7be555eSGeorge Liu // scaleFactor is used in division
256d7be555eSGeorge Liu if (scaleFactor == 0.0F)
257d7be555eSGeorge Liu {
258d7be555eSGeorge Liu scaleFactor = 1.0;
259d7be555eSGeorge Liu }
260d7be555eSGeorge Liu }
261d7be555eSGeorge Liu
262d7be555eSGeorge Liu float pollRate =
263d7be555eSGeorge Liu getPollRate(baseConfiguration->second, pollRateDefault);
264d7be555eSGeorge Liu PowerState readState = getPowerState(baseConfiguration->second);
265d7be555eSGeorge Liu
266d7be555eSGeorge Liu auto& sensor = sensors[sensorName];
267d7be555eSGeorge Liu sensor = nullptr;
268d7be555eSGeorge Liu
269d7be555eSGeorge Liu std::optional<BridgeGpio> bridgeGpio;
270d7be555eSGeorge Liu for (const auto& [key, cfgMap] : *sensorData)
271d7be555eSGeorge Liu {
272d7be555eSGeorge Liu if (key.find("BridgeGpio") != std::string::npos)
273d7be555eSGeorge Liu {
274d7be555eSGeorge Liu auto findName = cfgMap.find("Name");
275d7be555eSGeorge Liu if (findName != cfgMap.end())
276d7be555eSGeorge Liu {
277d7be555eSGeorge Liu std::string gpioName = std::visit(
278d7be555eSGeorge Liu VariantToStringVisitor(), findName->second);
279d7be555eSGeorge Liu
280d7be555eSGeorge Liu int polarity = gpiod::line::ACTIVE_HIGH;
281d7be555eSGeorge Liu auto findPolarity = cfgMap.find("Polarity");
282d7be555eSGeorge Liu if (findPolarity != cfgMap.end())
283d7be555eSGeorge Liu {
284d7be555eSGeorge Liu if (std::string("Low") ==
285d7be555eSGeorge Liu std::visit(VariantToStringVisitor(),
286d7be555eSGeorge Liu findPolarity->second))
287d7be555eSGeorge Liu {
288d7be555eSGeorge Liu polarity = gpiod::line::ACTIVE_LOW;
289d7be555eSGeorge Liu }
290d7be555eSGeorge Liu }
291d7be555eSGeorge Liu
292d7be555eSGeorge Liu float setupTime = gpioBridgeSetupTimeDefault;
293d7be555eSGeorge Liu auto findSetupTime = cfgMap.find("SetupTime");
294d7be555eSGeorge Liu if (findSetupTime != cfgMap.end())
295d7be555eSGeorge Liu {
296d7be555eSGeorge Liu setupTime = std::visit(VariantToFloatVisitor(),
297d7be555eSGeorge Liu findSetupTime->second);
298d7be555eSGeorge Liu }
299d7be555eSGeorge Liu
300d7be555eSGeorge Liu bridgeGpio =
301d7be555eSGeorge Liu BridgeGpio(gpioName, polarity, setupTime);
302d7be555eSGeorge Liu }
303d7be555eSGeorge Liu
304d7be555eSGeorge Liu break;
305d7be555eSGeorge Liu }
306d7be555eSGeorge Liu }
307d7be555eSGeorge Liu
308d7be555eSGeorge Liu sensor = std::make_shared<ADCSensor>(
309d7be555eSGeorge Liu path.string(), objectServer, dbusConnection, io, sensorName,
310d7be555eSGeorge Liu std::move(sensorThresholds), scaleFactor, pollRate,
311d7be555eSGeorge Liu readState, *interfacePath, std::move(bridgeGpio));
312d7be555eSGeorge Liu sensor->setupRead();
313d7be555eSGeorge Liu }
314d7be555eSGeorge Liu });
315d7be555eSGeorge Liu
316d7be555eSGeorge Liu getter->getConfiguration(
317d7be555eSGeorge Liu std::vector<std::string>{sensorTypes.begin(), sensorTypes.end()});
318d7be555eSGeorge Liu }
319d7be555eSGeorge Liu
main()320d7be555eSGeorge Liu int main()
321d7be555eSGeorge Liu {
322d7be555eSGeorge Liu boost::asio::io_context io;
323d7be555eSGeorge Liu auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
324d7be555eSGeorge Liu sdbusplus::asio::object_server objectServer(systemBus, true);
325d7be555eSGeorge Liu objectServer.add_manager("/xyz/openbmc_project/sensors");
326d7be555eSGeorge Liu
327d7be555eSGeorge Liu systemBus->request_name("xyz.openbmc_project.ADCSensor");
328d7be555eSGeorge Liu boost::container::flat_map<std::string, std::shared_ptr<ADCSensor>> sensors;
329d7be555eSGeorge Liu auto sensorsChanged =
330d7be555eSGeorge Liu std::make_shared<boost::container::flat_set<std::string>>();
331d7be555eSGeorge Liu
332d7be555eSGeorge Liu boost::asio::post(io, [&]() {
333d7be555eSGeorge Liu createSensors(io, objectServer, sensors, systemBus, nullptr,
334d7be555eSGeorge Liu UpdateType::init);
335d7be555eSGeorge Liu });
336d7be555eSGeorge Liu
337d7be555eSGeorge Liu boost::asio::steady_timer filterTimer(io);
338d7be555eSGeorge Liu std::function<void(sdbusplus::message_t&)> eventHandler =
339d7be555eSGeorge Liu [&](sdbusplus::message_t& message) {
340d7be555eSGeorge Liu if (message.is_method_error())
341d7be555eSGeorge Liu {
342*d4bc41f2SGeorge Liu lg2::error("callback method error");
343d7be555eSGeorge Liu return;
344d7be555eSGeorge Liu }
345d7be555eSGeorge Liu sensorsChanged->insert(message.get_path());
346d7be555eSGeorge Liu // this implicitly cancels the timer
347d7be555eSGeorge Liu filterTimer.expires_after(std::chrono::seconds(1));
348d7be555eSGeorge Liu
349d7be555eSGeorge Liu filterTimer.async_wait([&](const boost::system::error_code& ec) {
350d7be555eSGeorge Liu if (ec == boost::asio::error::operation_aborted)
351d7be555eSGeorge Liu {
352d7be555eSGeorge Liu /* we were canceled*/
353d7be555eSGeorge Liu return;
354d7be555eSGeorge Liu }
355d7be555eSGeorge Liu if (ec)
356d7be555eSGeorge Liu {
357*d4bc41f2SGeorge Liu lg2::error("timer error");
358d7be555eSGeorge Liu return;
359d7be555eSGeorge Liu }
360d7be555eSGeorge Liu createSensors(io, objectServer, sensors, systemBus,
361d7be555eSGeorge Liu sensorsChanged, UpdateType::init);
362d7be555eSGeorge Liu });
363d7be555eSGeorge Liu };
364d7be555eSGeorge Liu
365d7be555eSGeorge Liu boost::asio::steady_timer cpuFilterTimer(io);
366d7be555eSGeorge Liu std::function<void(sdbusplus::message_t&)> cpuPresenceHandler =
367d7be555eSGeorge Liu [&](sdbusplus::message_t& message) {
368d7be555eSGeorge Liu std::string path = message.get_path();
369d7be555eSGeorge Liu boost::to_lower(path);
370d7be555eSGeorge Liu
371d7be555eSGeorge Liu sdbusplus::message::object_path cpuPath(path);
372d7be555eSGeorge Liu std::string cpuName = cpuPath.filename();
373d7be555eSGeorge Liu if (!cpuName.starts_with("cpu"))
374d7be555eSGeorge Liu {
375d7be555eSGeorge Liu return; // not interested
376d7be555eSGeorge Liu }
377d7be555eSGeorge Liu size_t index = 0;
378d7be555eSGeorge Liu try
379d7be555eSGeorge Liu {
380d7be555eSGeorge Liu index = std::stoi(path.substr(path.size() - 1));
381d7be555eSGeorge Liu }
382d7be555eSGeorge Liu catch (const std::invalid_argument&)
383d7be555eSGeorge Liu {
384*d4bc41f2SGeorge Liu lg2::error("Found invalid path: '{PATH}'", "PATH", path);
385d7be555eSGeorge Liu return;
386d7be555eSGeorge Liu }
387d7be555eSGeorge Liu
388d7be555eSGeorge Liu std::string objectName;
389d7be555eSGeorge Liu boost::container::flat_map<std::string, std::variant<bool>> values;
390d7be555eSGeorge Liu message.read(objectName, values);
391d7be555eSGeorge Liu auto findPresence = values.find("Present");
392d7be555eSGeorge Liu if (findPresence != values.end())
393d7be555eSGeorge Liu {
394d7be555eSGeorge Liu cpuPresence[index] = std::get<bool>(findPresence->second);
395d7be555eSGeorge Liu }
396d7be555eSGeorge Liu
397d7be555eSGeorge Liu // this implicitly cancels the timer
398d7be555eSGeorge Liu cpuFilterTimer.expires_after(std::chrono::seconds(1));
399d7be555eSGeorge Liu
400d7be555eSGeorge Liu cpuFilterTimer.async_wait([&](const boost::system::error_code& ec) {
401d7be555eSGeorge Liu if (ec == boost::asio::error::operation_aborted)
402d7be555eSGeorge Liu {
403d7be555eSGeorge Liu /* we were canceled*/
404d7be555eSGeorge Liu return;
405d7be555eSGeorge Liu }
406d7be555eSGeorge Liu if (ec)
407d7be555eSGeorge Liu {
408*d4bc41f2SGeorge Liu lg2::error("timer error");
409d7be555eSGeorge Liu return;
410d7be555eSGeorge Liu }
411d7be555eSGeorge Liu createSensors(io, objectServer, sensors, systemBus, nullptr,
412d7be555eSGeorge Liu UpdateType::cpuPresenceChange);
413d7be555eSGeorge Liu });
414d7be555eSGeorge Liu };
415d7be555eSGeorge Liu
416d7be555eSGeorge Liu std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
417d7be555eSGeorge Liu setupPropertiesChangedMatches(*systemBus, sensorTypes, eventHandler);
418d7be555eSGeorge Liu matches.emplace_back(std::make_unique<sdbusplus::bus::match_t>(
419d7be555eSGeorge Liu static_cast<sdbusplus::bus_t&>(*systemBus),
420d7be555eSGeorge Liu "type='signal',member='PropertiesChanged',path_namespace='" +
421d7be555eSGeorge Liu std::string(cpuInventoryPath) +
422d7be555eSGeorge Liu "',arg0namespace='xyz.openbmc_project.Inventory.Item'",
423d7be555eSGeorge Liu cpuPresenceHandler));
424d7be555eSGeorge Liu
425d7be555eSGeorge Liu setupManufacturingModeMatch(*systemBus);
426d7be555eSGeorge Liu io.run();
427d7be555eSGeorge Liu }
428