16714a25aSJames Feist /*
26714a25aSJames Feist // Copyright (c) 2017 Intel Corporation
36714a25aSJames Feist //
46714a25aSJames Feist // Licensed under the Apache License, Version 2.0 (the "License");
56714a25aSJames Feist // you may not use this file except in compliance with the License.
66714a25aSJames Feist // You may obtain a copy of the License at
76714a25aSJames Feist //
86714a25aSJames Feist //      http://www.apache.org/licenses/LICENSE-2.0
96714a25aSJames Feist //
106714a25aSJames Feist // Unless required by applicable law or agreed to in writing, software
116714a25aSJames Feist // distributed under the License is distributed on an "AS IS" BASIS,
126714a25aSJames Feist // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136714a25aSJames Feist // See the License for the specific language governing permissions and
146714a25aSJames Feist // limitations under the License.
156714a25aSJames Feist */
166714a25aSJames Feist 
178a57ec09SEd Tanous #include <HwmonTempSensor.hpp>
188a57ec09SEd Tanous #include <Utils.hpp>
196714a25aSJames Feist #include <boost/algorithm/string/predicate.hpp>
206714a25aSJames Feist #include <boost/algorithm/string/replace.hpp>
2196e97db7SPatrick Venture #include <boost/container/flat_map.hpp>
226714a25aSJames Feist #include <boost/container/flat_set.hpp>
2338fb5983SJames Feist #include <sdbusplus/asio/connection.hpp>
2438fb5983SJames Feist #include <sdbusplus/asio/object_server.hpp>
2538fb5983SJames Feist #include <sdbusplus/bus/match.hpp>
2638fb5983SJames Feist 
2738fb5983SJames Feist #include <array>
2824f02f24SJames Feist #include <filesystem>
296714a25aSJames Feist #include <fstream>
3096e97db7SPatrick Venture #include <functional>
3196e97db7SPatrick Venture #include <memory>
326714a25aSJames Feist #include <regex>
3396e97db7SPatrick Venture #include <stdexcept>
3496e97db7SPatrick Venture #include <string>
3596e97db7SPatrick Venture #include <utility>
3696e97db7SPatrick Venture #include <variant>
3796e97db7SPatrick Venture #include <vector>
386714a25aSJames Feist 
3987bc67f7SJeff Lin static constexpr float pollRateDefault = 0.5;
406714a25aSJames Feist 
41cf3bce6eSJames Feist namespace fs = std::filesystem;
42*66558235SBrandon Kim static auto sensorTypes{
43*66558235SBrandon Kim     std::to_array<const char*>({"xyz.openbmc_project.Configuration.EMC1412",
448b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.EMC1413",
45381636e2SGilbert Chen                                 "xyz.openbmc_project.Configuration.EMC1414",
468b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.MAX31725",
478b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.MAX31730",
4816e7af1dSJason Ling                                 "xyz.openbmc_project.Configuration.MAX6581",
493840d0adSJosh Lehan                                 "xyz.openbmc_project.Configuration.MAX6654",
505770a6fdSOskar Senft                                 "xyz.openbmc_project.Configuration.NCT7802",
518fb0a013SJosh Lehan                                 "xyz.openbmc_project.Configuration.SBTSI",
525a3b3f8aSKonstantin Aladyshev                                 "xyz.openbmc_project.Configuration.LM95234",
5355ab2afbSJohn Wang                                 "xyz.openbmc_project.Configuration.TMP112",
543546adb9SPatrick Venture                                 "xyz.openbmc_project.Configuration.TMP175",
558b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.TMP421",
568b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.TMP441",
5734fc75a7SKonstantin Aladyshev                                 "xyz.openbmc_project.Configuration.LM75A",
587ea918f2SZev Weiss                                 "xyz.openbmc_project.Configuration.TMP75",
59*66558235SBrandon Kim                                 "xyz.openbmc_project.Configuration.W83773G"})};
606714a25aSJames Feist 
616714a25aSJames Feist void createSensors(
626714a25aSJames Feist     boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
63f3fd1915SYong Li     boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>>&
646714a25aSJames Feist         sensors,
656714a25aSJames Feist     std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
665591cf08SJames Feist     const std::shared_ptr<boost::container::flat_set<std::string>>&
676714a25aSJames Feist         sensorsChanged)
686714a25aSJames Feist {
69df515159SJames Feist     auto getter = std::make_shared<GetSensorConfiguration>(
70df515159SJames Feist         dbusConnection,
718a17c303SEd Tanous         [&io, &objectServer, &sensors, &dbusConnection,
728a17c303SEd Tanous          sensorsChanged](const ManagedObjectType& sensorConfigurations) {
736714a25aSJames Feist             bool firstScan = sensorsChanged == nullptr;
74df515159SJames Feist 
756714a25aSJames Feist             std::vector<fs::path> paths;
76df515159SJames Feist             if (!findFiles(fs::path("/sys/class/hwmon"), R"(temp\d+_input)",
77df515159SJames Feist                            paths))
786714a25aSJames Feist             {
796714a25aSJames Feist                 std::cerr << "No temperature sensors in system\n";
806714a25aSJames Feist                 return;
816714a25aSJames Feist             }
826714a25aSJames Feist 
8337266ca9SJames Feist             boost::container::flat_set<std::string> directories;
8437266ca9SJames Feist 
85df515159SJames Feist             // iterate through all found temp sensors, and try to match them
86df515159SJames Feist             // with configuration
876714a25aSJames Feist             for (auto& path : paths)
886714a25aSJames Feist             {
896714a25aSJames Feist                 std::smatch match;
906714a25aSJames Feist                 auto directory = path.parent_path();
916714a25aSJames Feist 
9237266ca9SJames Feist                 auto ret = directories.insert(directory.string());
9337266ca9SJames Feist                 if (!ret.second)
946714a25aSJames Feist                 {
9537266ca9SJames Feist                     continue; // already searched this path
9637266ca9SJames Feist                 }
9737266ca9SJames Feist 
98b6c0b914SJames Feist                 fs::path device = directory / "device";
9937266ca9SJames Feist                 std::string deviceName = fs::canonical(device).stem();
1008a57ec09SEd Tanous                 auto findHyphen = deviceName.find('-');
10137266ca9SJames Feist                 if (findHyphen == std::string::npos)
10237266ca9SJames Feist                 {
10337266ca9SJames Feist                     std::cerr << "found bad device " << deviceName << "\n";
1046714a25aSJames Feist                     continue;
1056714a25aSJames Feist                 }
10637266ca9SJames Feist                 std::string busStr = deviceName.substr(0, findHyphen);
10737266ca9SJames Feist                 std::string addrStr = deviceName.substr(findHyphen + 1);
10837266ca9SJames Feist 
10937266ca9SJames Feist                 size_t bus = 0;
11037266ca9SJames Feist                 size_t addr = 0;
11137266ca9SJames Feist                 try
1126714a25aSJames Feist                 {
11337266ca9SJames Feist                     bus = std::stoi(busStr);
1148a57ec09SEd Tanous                     addr = std::stoi(addrStr, nullptr, 16);
11537266ca9SJames Feist                 }
11626601e89SPatrick Williams                 catch (const std::invalid_argument&)
11737266ca9SJames Feist                 {
1186714a25aSJames Feist                     continue;
1196714a25aSJames Feist                 }
1206714a25aSJames Feist                 const SensorData* sensorData = nullptr;
1216714a25aSJames Feist                 const std::string* interfacePath = nullptr;
12237266ca9SJames Feist                 const char* sensorType = nullptr;
1238b3f7d40SAlex Qiu                 const SensorBaseConfiguration* baseConfiguration = nullptr;
1248b3f7d40SAlex Qiu                 const SensorBaseConfigMap* baseConfigMap = nullptr;
12537266ca9SJames Feist 
126df515159SJames Feist                 for (const std::pair<sdbusplus::message::object_path,
127df515159SJames Feist                                      SensorData>& sensor : sensorConfigurations)
12837266ca9SJames Feist                 {
12937266ca9SJames Feist                     sensorData = &(sensor.second);
1309ced0a38SJae Hyun Yoo                     for (const char* type : sensorTypes)
1316714a25aSJames Feist                     {
1326714a25aSJames Feist                         auto sensorBase = sensorData->find(type);
1336714a25aSJames Feist                         if (sensorBase != sensorData->end())
1346714a25aSJames Feist                         {
1356714a25aSJames Feist                             baseConfiguration = &(*sensorBase);
1366714a25aSJames Feist                             sensorType = type;
1376714a25aSJames Feist                             break;
1386714a25aSJames Feist                         }
1396714a25aSJames Feist                     }
1406714a25aSJames Feist                     if (baseConfiguration == nullptr)
1416714a25aSJames Feist                     {
14237266ca9SJames Feist                         std::cerr << "error finding base configuration for "
14337266ca9SJames Feist                                   << deviceName << "\n";
14437266ca9SJames Feist                         continue;
14537266ca9SJames Feist                     }
1468b3f7d40SAlex Qiu                     baseConfigMap = &baseConfiguration->second;
1478b3f7d40SAlex Qiu                     auto configurationBus = baseConfigMap->find("Bus");
1488b3f7d40SAlex Qiu                     auto configurationAddress = baseConfigMap->find("Address");
14937266ca9SJames Feist 
1508b3f7d40SAlex Qiu                     if (configurationBus == baseConfigMap->end() ||
1518b3f7d40SAlex Qiu                         configurationAddress == baseConfigMap->end())
15237266ca9SJames Feist                     {
1538b3f7d40SAlex Qiu                         std::cerr << "error finding bus or address in "
1548b3f7d40SAlex Qiu                                      "configuration\n";
15537266ca9SJames Feist                         continue;
15637266ca9SJames Feist                     }
15737266ca9SJames Feist 
1583eb82629SJames Feist                     if (std::get<uint64_t>(configurationBus->second) != bus ||
159df515159SJames Feist                         std::get<uint64_t>(configurationAddress->second) !=
160df515159SJames Feist                             addr)
16137266ca9SJames Feist                     {
16237266ca9SJames Feist                         continue;
16337266ca9SJames Feist                     }
16437266ca9SJames Feist 
16537266ca9SJames Feist                     interfacePath = &(sensor.first.str);
16637266ca9SJames Feist                     break;
16737266ca9SJames Feist                 }
16837266ca9SJames Feist                 if (interfacePath == nullptr)
16937266ca9SJames Feist                 {
170df515159SJames Feist                     std::cerr << "failed to find match for " << deviceName
171df515159SJames Feist                               << "\n";
1726714a25aSJames Feist                     continue;
1736714a25aSJames Feist                 }
1746714a25aSJames Feist 
1758b3f7d40SAlex Qiu                 auto findSensorName = baseConfigMap->find("Name");
1768b3f7d40SAlex Qiu                 if (findSensorName == baseConfigMap->end())
1776714a25aSJames Feist                 {
1786714a25aSJames Feist                     std::cerr << "could not determine configuration name for "
17937266ca9SJames Feist                               << deviceName << "\n";
1806714a25aSJames Feist                     continue;
1816714a25aSJames Feist                 }
182df515159SJames Feist                 std::string sensorName =
183df515159SJames Feist                     std::get<std::string>(findSensorName->second);
1846714a25aSJames Feist                 // on rescans, only update sensors we were signaled by
1856714a25aSJames Feist                 auto findSensor = sensors.find(sensorName);
1866714a25aSJames Feist                 if (!firstScan && findSensor != sensors.end())
1876714a25aSJames Feist                 {
1886714a25aSJames Feist                     bool found = false;
189d653b75cSBruce Mitchell                     auto it = sensorsChanged->begin();
190d653b75cSBruce Mitchell                     while (it != sensorsChanged->end())
1916714a25aSJames Feist                     {
1926714a25aSJames Feist                         if (boost::ends_with(*it, findSensor->second->name))
1936714a25aSJames Feist                         {
194d653b75cSBruce Mitchell                             it = sensorsChanged->erase(it);
1956714a25aSJames Feist                             findSensor->second = nullptr;
1966714a25aSJames Feist                             found = true;
1976714a25aSJames Feist                             break;
1986714a25aSJames Feist                         }
199d653b75cSBruce Mitchell                         ++it;
2006714a25aSJames Feist                     }
2016714a25aSJames Feist                     if (!found)
2026714a25aSJames Feist                     {
2036714a25aSJames Feist                         continue;
2046714a25aSJames Feist                     }
2056714a25aSJames Feist                 }
2065636d52bSMatt Spinler 
2076714a25aSJames Feist                 std::vector<thresholds::Threshold> sensorThresholds;
2085636d52bSMatt Spinler                 int index = 1;
2095636d52bSMatt Spinler 
2105636d52bSMatt Spinler                 if (!parseThresholdsFromConfig(*sensorData, sensorThresholds,
2115636d52bSMatt Spinler                                                nullptr, &index))
2126714a25aSJames Feist                 {
213df515159SJames Feist                     std::cerr << "error populating thresholds for "
2145636d52bSMatt Spinler                               << sensorName << " index 1\n";
2156714a25aSJames Feist                 }
21687bc67f7SJeff Lin 
21787bc67f7SJeff Lin                 auto findPollRate = baseConfiguration->second.find("PollRate");
21887bc67f7SJeff Lin                 float pollRate = pollRateDefault;
21987bc67f7SJeff Lin                 if (findPollRate != baseConfiguration->second.end())
22087bc67f7SJeff Lin                 {
22187bc67f7SJeff Lin                     pollRate = std::visit(VariantToFloatVisitor(),
22287bc67f7SJeff Lin                                           findPollRate->second);
22387bc67f7SJeff Lin                     if (pollRate <= 0.0f)
22487bc67f7SJeff Lin                     {
22587bc67f7SJeff Lin                         pollRate = pollRateDefault; // polling time too short
22687bc67f7SJeff Lin                     }
22787bc67f7SJeff Lin                 }
22887bc67f7SJeff Lin 
229f9b01b6dSJames Feist                 auto findPowerOn = baseConfiguration->second.find("PowerState");
230f9b01b6dSJames Feist                 PowerState readState = PowerState::always;
231f9b01b6dSJames Feist                 if (findPowerOn != baseConfiguration->second.end())
232f9b01b6dSJames Feist                 {
233f9b01b6dSJames Feist                     std::string powerState = std::visit(
234f9b01b6dSJames Feist                         VariantToStringVisitor(), findPowerOn->second);
235f9b01b6dSJames Feist                     setReadState(powerState, readState);
236f9b01b6dSJames Feist                 }
237100c20bfSJason Ling 
238100c20bfSJason Ling                 auto permitSet = getPermitSet(*baseConfigMap);
2398b3f7d40SAlex Qiu                 auto& sensor = sensors[sensorName];
2408b3f7d40SAlex Qiu                 sensor = nullptr;
241100c20bfSJason Ling                 auto hwmonFile = getFullHwmonFilePath(directory.string(),
242100c20bfSJason Ling                                                       "temp1", permitSet);
243100c20bfSJason Ling                 if (hwmonFile)
244100c20bfSJason Ling                 {
245f3fd1915SYong Li                     sensor = std::make_shared<HwmonTempSensor>(
246100c20bfSJason Ling                         *hwmonFile, sensorType, objectServer, dbusConnection,
24787bc67f7SJeff Lin                         io, sensorName, std::move(sensorThresholds), pollRate,
248100c20bfSJason Ling                         *interfacePath, readState);
249f3fd1915SYong Li                     sensor->setupRead();
250100c20bfSJason Ling                 }
2518b3f7d40SAlex Qiu                 // Looking for keys like "Name1" for temp2_input,
2528b3f7d40SAlex Qiu                 // "Name2" for temp3_input, etc.
2538b3f7d40SAlex Qiu                 int i = 0;
2548b3f7d40SAlex Qiu                 while (true)
25537266ca9SJames Feist                 {
2568b3f7d40SAlex Qiu                     ++i;
2578b3f7d40SAlex Qiu                     auto findKey =
2588b8bcc87SJason Ling                         baseConfigMap->find("Name" + std::to_string(i));
2598b3f7d40SAlex Qiu                     if (findKey == baseConfigMap->end())
2608b3f7d40SAlex Qiu                     {
2618b3f7d40SAlex Qiu                         break;
26237266ca9SJames Feist                     }
2638b3f7d40SAlex Qiu                     std::string sensorName =
2648b3f7d40SAlex Qiu                         std::get<std::string>(findKey->second);
265100c20bfSJason Ling                     hwmonFile = getFullHwmonFilePath(
266100c20bfSJason Ling                         directory.string(), "temp" + std::to_string(i + 1),
267100c20bfSJason Ling                         permitSet);
268100c20bfSJason Ling                     if (hwmonFile)
269100c20bfSJason Ling                     {
2705636d52bSMatt Spinler                         // To look up thresholds for these additional sensors,
2715636d52bSMatt Spinler                         // match on the Index property in the threshold data
2725636d52bSMatt Spinler                         // where the index comes from the sysfs file we're on,
2735636d52bSMatt Spinler                         // i.e. index = 2 for temp2_input.
2745636d52bSMatt Spinler                         int index = i + 1;
2755636d52bSMatt Spinler                         std::vector<thresholds::Threshold> thresholds;
2765636d52bSMatt Spinler 
2775636d52bSMatt Spinler                         if (!parseThresholdsFromConfig(*sensorData, thresholds,
2785636d52bSMatt Spinler                                                        nullptr, &index))
2795636d52bSMatt Spinler                         {
2805636d52bSMatt Spinler                             std::cerr << "error populating thresholds for "
2815636d52bSMatt Spinler                                       << sensorName << " index " << index
2825636d52bSMatt Spinler                                       << "\n";
2835636d52bSMatt Spinler                         }
2845636d52bSMatt Spinler 
2858b3f7d40SAlex Qiu                         auto& sensor = sensors[sensorName];
2868b3f7d40SAlex Qiu                         sensor = nullptr;
287f3fd1915SYong Li                         sensor = std::make_shared<HwmonTempSensor>(
288100c20bfSJason Ling                             *hwmonFile, sensorType, objectServer,
289100c20bfSJason Ling                             dbusConnection, io, sensorName,
2905636d52bSMatt Spinler                             std::move(thresholds), pollRate, *interfacePath,
2915636d52bSMatt Spinler                             readState);
292f3fd1915SYong Li                         sensor->setupRead();
2938b3f7d40SAlex Qiu                     }
2946714a25aSJames Feist                 }
295100c20bfSJason Ling             }
2968a17c303SEd Tanous         });
297df515159SJames Feist     getter->getConfiguration(
298df515159SJames Feist         std::vector<std::string>(sensorTypes.begin(), sensorTypes.end()));
2996714a25aSJames Feist }
3006714a25aSJames Feist 
30120bf2c1cSMatt Spinler void interfaceRemoved(
30220bf2c1cSMatt Spinler     sdbusplus::message::message& message,
30320bf2c1cSMatt Spinler     boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>>&
30420bf2c1cSMatt Spinler         sensors)
30520bf2c1cSMatt Spinler {
30620bf2c1cSMatt Spinler     if (message.is_method_error())
30720bf2c1cSMatt Spinler     {
30820bf2c1cSMatt Spinler         std::cerr << "interfacesRemoved callback method error\n";
30920bf2c1cSMatt Spinler         return;
31020bf2c1cSMatt Spinler     }
31120bf2c1cSMatt Spinler 
31220bf2c1cSMatt Spinler     sdbusplus::message::object_path path;
31320bf2c1cSMatt Spinler     std::vector<std::string> interfaces;
31420bf2c1cSMatt Spinler 
31520bf2c1cSMatt Spinler     message.read(path, interfaces);
31620bf2c1cSMatt Spinler 
31720bf2c1cSMatt Spinler     // If the xyz.openbmc_project.Confguration.X interface was removed
31820bf2c1cSMatt Spinler     // for one or more sensors, delete those sensor objects.
31920bf2c1cSMatt Spinler     auto sensorIt = sensors.begin();
32020bf2c1cSMatt Spinler     while (sensorIt != sensors.end())
32120bf2c1cSMatt Spinler     {
32220bf2c1cSMatt Spinler         if ((sensorIt->second->configurationPath == path) &&
32320bf2c1cSMatt Spinler             (std::find(interfaces.begin(), interfaces.end(),
32420bf2c1cSMatt Spinler                        sensorIt->second->objectType) != interfaces.end()))
32520bf2c1cSMatt Spinler         {
32620bf2c1cSMatt Spinler             sensorIt = sensors.erase(sensorIt);
32720bf2c1cSMatt Spinler         }
32820bf2c1cSMatt Spinler         else
32920bf2c1cSMatt Spinler         {
33020bf2c1cSMatt Spinler             sensorIt++;
33120bf2c1cSMatt Spinler         }
33220bf2c1cSMatt Spinler     }
33320bf2c1cSMatt Spinler }
33420bf2c1cSMatt Spinler 
335b6c0b914SJames Feist int main()
3366714a25aSJames Feist {
3376714a25aSJames Feist     boost::asio::io_service io;
3386714a25aSJames Feist     auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
3396714a25aSJames Feist     systemBus->request_name("xyz.openbmc_project.HwmonTempSensor");
3406714a25aSJames Feist     sdbusplus::asio::object_server objectServer(systemBus);
341f3fd1915SYong Li     boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>>
3426714a25aSJames Feist         sensors;
3436714a25aSJames Feist     std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches;
3445591cf08SJames Feist     auto sensorsChanged =
3455591cf08SJames Feist         std::make_shared<boost::container::flat_set<std::string>>();
3466714a25aSJames Feist 
3476714a25aSJames Feist     io.post([&]() {
3486714a25aSJames Feist         createSensors(io, objectServer, sensors, systemBus, nullptr);
3496714a25aSJames Feist     });
3506714a25aSJames Feist 
3516714a25aSJames Feist     boost::asio::deadline_timer filterTimer(io);
3526714a25aSJames Feist     std::function<void(sdbusplus::message::message&)> eventHandler =
3536714a25aSJames Feist         [&](sdbusplus::message::message& message) {
3546714a25aSJames Feist             if (message.is_method_error())
3556714a25aSJames Feist             {
3566714a25aSJames Feist                 std::cerr << "callback method error\n";
3576714a25aSJames Feist                 return;
3586714a25aSJames Feist             }
3596714a25aSJames Feist             sensorsChanged->insert(message.get_path());
3606714a25aSJames Feist             // this implicitly cancels the timer
3616714a25aSJames Feist             filterTimer.expires_from_now(boost::posix_time::seconds(1));
3626714a25aSJames Feist 
3636714a25aSJames Feist             filterTimer.async_wait([&](const boost::system::error_code& ec) {
3646714a25aSJames Feist                 if (ec == boost::asio::error::operation_aborted)
3656714a25aSJames Feist                 {
3666714a25aSJames Feist                     /* we were canceled*/
3676714a25aSJames Feist                     return;
3686714a25aSJames Feist                 }
3698a57ec09SEd Tanous                 if (ec)
3706714a25aSJames Feist                 {
3716714a25aSJames Feist                     std::cerr << "timer error\n";
3726714a25aSJames Feist                     return;
3736714a25aSJames Feist                 }
3746714a25aSJames Feist                 createSensors(io, objectServer, sensors, systemBus,
3756714a25aSJames Feist                               sensorsChanged);
3766714a25aSJames Feist             });
3776714a25aSJames Feist         };
3786714a25aSJames Feist 
3799ced0a38SJae Hyun Yoo     for (const char* type : sensorTypes)
3806714a25aSJames Feist     {
3816714a25aSJames Feist         auto match = std::make_unique<sdbusplus::bus::match::match>(
3826714a25aSJames Feist             static_cast<sdbusplus::bus::bus&>(*systemBus),
3836714a25aSJames Feist             "type='signal',member='PropertiesChanged',path_namespace='" +
3849ced0a38SJae Hyun Yoo                 std::string(inventoryPath) + "',arg0namespace='" + type + "'",
3856714a25aSJames Feist             eventHandler);
3866714a25aSJames Feist         matches.emplace_back(std::move(match));
3876714a25aSJames Feist     }
3886714a25aSJames Feist 
3891263c3daSBruce Lee     setupManufacturingModeMatch(*systemBus);
39020bf2c1cSMatt Spinler 
39120bf2c1cSMatt Spinler     // Watch for entity-manager to remove configuration interfaces
39220bf2c1cSMatt Spinler     // so the corresponding sensors can be removed.
39320bf2c1cSMatt Spinler     auto ifaceRemovedMatch = std::make_unique<sdbusplus::bus::match::match>(
39420bf2c1cSMatt Spinler         static_cast<sdbusplus::bus::bus&>(*systemBus),
39520bf2c1cSMatt Spinler         "type='signal',member='InterfacesRemoved',arg0path='" +
39620bf2c1cSMatt Spinler             std::string(inventoryPath) + "/'",
39720bf2c1cSMatt Spinler         [&sensors](sdbusplus::message::message& msg) {
39820bf2c1cSMatt Spinler             interfaceRemoved(msg, sensors);
39920bf2c1cSMatt Spinler         });
40020bf2c1cSMatt Spinler 
40120bf2c1cSMatt Spinler     matches.emplace_back(std::move(ifaceRemovedMatch));
40220bf2c1cSMatt Spinler 
4036714a25aSJames Feist     io.run();
4046714a25aSJames Feist }
405