xref: /openbmc/dbus-sensors/src/adc/ADCSensorMain.cpp (revision d4bc41f295c919c985366a4abe53db99f611c2b5)
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