Move source files into application-specific sub-directories
Currently, dbus-sensors implement multiple applications:
- psusensor
- adcsensor
- intelcpusensor
- hwmontempsensor
- ipmbsensor
- nvmesensor
- externalsensor
- mcutempsensor
- intrusionsensor
- fansensor
- exitairtempsensor
This commit is to create separate directories for each application so
that things can be separated more easily and the files are smaller,
instead of creating one huge file for the sensor implementation.
There was some discussion in discord on this. [1][2]
[1]: https://discord.com/channels/775381525260664832/1187158775438778408/1284106093756289067
[2]: https://discord.com/channels/775381525260664832/867820390406422538/1303217796821553214
Signed-off-by: George Liu <liuxiwei@ieisystem.com>
Change-Id: I258fc2ee7d8f939c7b83a07350395e78775b2b8d
diff --git a/src/adc/ADCSensor.cpp b/src/adc/ADCSensor.cpp
new file mode 100644
index 0000000..0b3fd28
--- /dev/null
+++ b/src/adc/ADCSensor.cpp
@@ -0,0 +1,244 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include "ADCSensor.hpp"
+
+#include "SensorPaths.hpp"
+#include "Thresholds.hpp"
+#include "Utils.hpp"
+#include "sensor.hpp"
+
+#include <fcntl.h>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_context.hpp>
+#include <boost/asio/read_until.hpp>
+#include <boost/asio/streambuf.hpp>
+#include <sdbusplus/asio/connection.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+
+#include <chrono>
+#include <cmath>
+#include <cstddef>
+#include <iostream>
+#include <memory>
+#include <optional>
+#include <stdexcept>
+#include <string>
+#include <utility>
+#include <vector>
+
+// scaling factor from hwmon
+static constexpr unsigned int sensorScaleFactor = 1000;
+
+static constexpr double roundFactor = 10000; // 3 decimal places
+static constexpr double maxVoltageReading = 1.8; // pre sensor scaling
+static constexpr double minVoltageReading = 0;
+
+ADCSensor::ADCSensor(
+ const std::string& path, sdbusplus::asio::object_server& objectServer,
+ std::shared_ptr<sdbusplus::asio::connection>& conn,
+ boost::asio::io_context& io, const std::string& sensorName,
+ std::vector<thresholds::Threshold>&& thresholdsIn, const double scaleFactor,
+ const float pollRate, PowerState readState,
+ const std::string& sensorConfiguration,
+ std::optional<BridgeGpio>&& bridgeGpio) :
+ Sensor(escapeName(sensorName), std::move(thresholdsIn), sensorConfiguration,
+ "ADC", false, false, maxVoltageReading / scaleFactor,
+ minVoltageReading / scaleFactor, conn, readState),
+ objServer(objectServer), inputDev(io), waitTimer(io), path(path),
+ scaleFactor(scaleFactor),
+ sensorPollMs(static_cast<unsigned int>(pollRate * 1000)),
+ bridgeGpio(std::move(bridgeGpio)), thresholdTimer(io)
+{
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
+ int fd = open(path.c_str(), O_RDONLY);
+ if (fd < 0)
+ {
+ std::cerr << "unable to open acd device \n";
+ }
+
+ inputDev.assign(fd);
+
+ sensorInterface = objectServer.add_interface(
+ "/xyz/openbmc_project/sensors/voltage/" + name,
+ "xyz.openbmc_project.Sensor.Value");
+ for (const auto& threshold : thresholds)
+ {
+ std::string interface = thresholds::getInterface(threshold.level);
+ thresholdInterfaces[static_cast<size_t>(threshold.level)] =
+ objectServer.add_interface(
+ "/xyz/openbmc_project/sensors/voltage/" + name, interface);
+ }
+ association = objectServer.add_interface(
+ "/xyz/openbmc_project/sensors/voltage/" + name, association::interface);
+ setInitialProperties(sensor_paths::unitVolts);
+}
+
+ADCSensor::~ADCSensor()
+{
+ // close the input dev to cancel async operations
+ inputDev.close();
+ waitTimer.cancel();
+
+ for (const auto& iface : thresholdInterfaces)
+ {
+ objServer.remove_interface(iface);
+ }
+ objServer.remove_interface(sensorInterface);
+ objServer.remove_interface(association);
+}
+
+void ADCSensor::setupRead()
+{
+ std::shared_ptr<boost::asio::streambuf> buffer =
+ std::make_shared<boost::asio::streambuf>();
+
+ std::weak_ptr<ADCSensor> weakRef = weak_from_this();
+
+ if (bridgeGpio.has_value())
+ {
+ (*bridgeGpio).set(1);
+ // In case a channel has a bridge circuit,we have to turn the bridge on
+ // prior to reading a value at least for one scan cycle to get a valid
+ // value. Guarantee that the HW signal can be stable, the HW signal
+ // could be instability.
+ waitTimer.expires_after(
+ std::chrono::milliseconds(bridgeGpio->setupTimeMs));
+ waitTimer.async_wait(
+ [weakRef, buffer](const boost::system::error_code& ec) {
+ std::shared_ptr<ADCSensor> self = weakRef.lock();
+ if (ec == boost::asio::error::operation_aborted)
+ {
+ return; // we're being canceled
+ }
+
+ if (self)
+ {
+ boost::asio::async_read_until(
+ self->inputDev, *buffer, '\n',
+ [weakRef, buffer](const boost::system::error_code& ec,
+ std::size_t /*bytes_transfered*/) {
+ std::shared_ptr<ADCSensor> self = weakRef.lock();
+ if (self)
+ {
+ self->readBuf = buffer;
+ self->handleResponse(ec);
+ }
+ });
+ }
+ });
+ }
+ else
+ {
+ boost::asio::async_read_until(
+ inputDev, *buffer, '\n',
+ [weakRef, buffer](const boost::system::error_code& ec,
+ std::size_t /*bytes_transfered*/) {
+ std::shared_ptr<ADCSensor> self = weakRef.lock();
+ if (self)
+ {
+ self->readBuf = buffer;
+ self->handleResponse(ec);
+ }
+ });
+ }
+}
+
+void ADCSensor::handleResponse(const boost::system::error_code& err)
+{
+ std::weak_ptr<ADCSensor> weakRef = weak_from_this();
+
+ if (err == boost::system::errc::bad_file_descriptor)
+ {
+ return; // we're being destroyed
+ }
+ std::istream responseStream(readBuf.get());
+
+ if (!err)
+ {
+ std::string response;
+ std::getline(responseStream, response);
+
+ // todo read scaling factors from configuration
+ try
+ {
+ rawValue = std::stod(response);
+ double nvalue = (rawValue / sensorScaleFactor) / scaleFactor;
+ nvalue = std::round(nvalue * roundFactor) / roundFactor;
+ updateValue(nvalue);
+ }
+ catch (const std::invalid_argument&)
+ {
+ incrementError();
+ }
+ }
+ else
+ {
+ incrementError();
+ }
+
+ responseStream.clear();
+ inputDev.close();
+ if (bridgeGpio.has_value())
+ {
+ (*bridgeGpio).set(0);
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
+ int fd = open(path.c_str(), O_RDONLY);
+ if (fd < 0)
+ {
+ std::cerr << "adcsensor " << name << " failed to open " << path << "\n";
+ return; // we're no longer valid
+ }
+ inputDev.assign(fd);
+ waitTimer.expires_after(std::chrono::milliseconds(sensorPollMs));
+ waitTimer.async_wait([weakRef](const boost::system::error_code& ec) {
+ std::shared_ptr<ADCSensor> self = weakRef.lock();
+ if (ec == boost::asio::error::operation_aborted)
+ {
+ if (self)
+ {
+ std::cerr << "adcsensor " << self->name << " read cancelled\n";
+ }
+ else
+ {
+ std::cerr << "adcsensor read cancelled no self\n";
+ }
+ return; // we're being canceled
+ }
+
+ if (self)
+ {
+ self->setupRead();
+ }
+ else
+ {
+ std::cerr << "adcsensor weakref no self\n";
+ }
+ });
+}
+
+void ADCSensor::checkThresholds()
+{
+ if (!readingStateGood())
+ {
+ return;
+ }
+
+ thresholds::checkThresholdsPowerDelay(weak_from_this(), thresholdTimer);
+}
diff --git a/src/adc/ADCSensor.hpp b/src/adc/ADCSensor.hpp
new file mode 100644
index 0000000..f562405
--- /dev/null
+++ b/src/adc/ADCSensor.hpp
@@ -0,0 +1,92 @@
+#pragma once
+
+#include "Thresholds.hpp"
+#include "sensor.hpp"
+
+#include <boost/asio/streambuf.hpp>
+#include <gpiod.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+
+#include <memory>
+#include <optional>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+class BridgeGpio
+{
+ public:
+ BridgeGpio(const std::string& name, const int polarity,
+ const float setupTime) :
+ setupTimeMs(static_cast<unsigned int>(setupTime * 1000))
+ {
+ line = gpiod::find_line(name);
+ if (!line)
+ {
+ std::cerr << "Error finding gpio: " << name << "\n";
+ }
+ else
+ {
+ try
+ {
+ line.request(
+ {"adcsensor", gpiod::line_request::DIRECTION_OUTPUT,
+ polarity == gpiod::line::ACTIVE_HIGH
+ ? 0
+ : gpiod::line_request::FLAG_ACTIVE_LOW});
+ }
+ catch (const std::system_error&)
+ {
+ std::cerr << "Error requesting gpio: " << name << "\n";
+ }
+ }
+ }
+
+ void set(int value)
+ {
+ if (line)
+ {
+ try
+ {
+ line.set_value(value);
+ }
+ catch (const std::system_error& exc)
+ {
+ std::cerr << "Error set_value: " << exc.what() << "\n";
+ }
+ }
+ }
+
+ unsigned int setupTimeMs;
+
+ private:
+ gpiod::line line;
+};
+
+class ADCSensor : public Sensor, public std::enable_shared_from_this<ADCSensor>
+{
+ public:
+ ADCSensor(const std::string& path,
+ sdbusplus::asio::object_server& objectServer,
+ std::shared_ptr<sdbusplus::asio::connection>& conn,
+ boost::asio::io_context& io, const std::string& sensorName,
+ std::vector<thresholds::Threshold>&& thresholds,
+ double scaleFactor, float pollRate, PowerState readState,
+ const std::string& sensorConfiguration,
+ std::optional<BridgeGpio>&& bridgeGpio);
+ ~ADCSensor() override;
+ void setupRead();
+
+ private:
+ sdbusplus::asio::object_server& objServer;
+ boost::asio::posix::stream_descriptor inputDev;
+ boost::asio::steady_timer waitTimer;
+ std::shared_ptr<boost::asio::streambuf> readBuf;
+ std::string path;
+ double scaleFactor;
+ unsigned int sensorPollMs;
+ std::optional<BridgeGpio> bridgeGpio;
+ thresholds::ThresholdTimer thresholdTimer;
+ void handleResponse(const boost::system::error_code& err);
+ void checkThresholds() override;
+};
diff --git a/src/adc/ADCSensorMain.cpp b/src/adc/ADCSensorMain.cpp
new file mode 100644
index 0000000..ec38908
--- /dev/null
+++ b/src/adc/ADCSensorMain.cpp
@@ -0,0 +1,427 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include "ADCSensor.hpp"
+#include "Thresholds.hpp"
+#include "Utils.hpp"
+#include "VariantVisitors.hpp"
+
+#include <boost/algorithm/string/case_conv.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_context.hpp>
+#include <boost/asio/post.hpp>
+#include <boost/asio/steady_timer.hpp>
+#include <boost/container/flat_map.hpp>
+#include <boost/container/flat_set.hpp>
+#include <gpiod.hpp>
+#include <sdbusplus/asio/connection.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/bus/match.hpp>
+#include <sdbusplus/message.hpp>
+#include <sdbusplus/message/native_types.hpp>
+
+#include <array>
+#include <chrono>
+#include <cstddef>
+#include <filesystem>
+#include <fstream>
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <optional>
+#include <regex>
+#include <stdexcept>
+#include <string>
+#include <utility>
+#include <variant>
+#include <vector>
+
+static constexpr bool debug = false;
+static constexpr float pollRateDefault = 0.5;
+static constexpr float gpioBridgeSetupTimeDefault = 0.02;
+
+namespace fs = std::filesystem;
+
+static constexpr auto sensorTypes{std::to_array<const char*>({"ADC"})};
+static std::regex inputRegex(R"(in(\d+)_input)");
+
+static boost::container::flat_map<size_t, bool> cpuPresence;
+
+enum class UpdateType
+{
+ init,
+ cpuPresenceChange
+};
+
+// filter out adc from any other voltage sensor
+bool isAdc(const fs::path& parentPath)
+{
+ fs::path namePath = parentPath / "name";
+
+ std::ifstream nameFile(namePath);
+ if (!nameFile.good())
+ {
+ std::cerr << "Failure reading " << namePath.string() << "\n";
+ return false;
+ }
+
+ std::string name;
+ std::getline(nameFile, name);
+
+ return name == "iio_hwmon";
+}
+
+void 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)
+{
+ auto getter = std::make_shared<GetSensorConfiguration>(
+ dbusConnection,
+ [&io, &objectServer, &sensors, &dbusConnection, sensorsChanged,
+ updateType](const ManagedObjectType& sensorConfigurations) {
+ bool firstScan = sensorsChanged == nullptr;
+ std::vector<fs::path> paths;
+ if (!findFiles(fs::path("/sys/class/hwmon"), R"(in\d+_input)",
+ paths))
+ {
+ std::cerr << "No adc sensors in system\n";
+ return;
+ }
+
+ // iterate through all found adc sensors, and try to match them with
+ // configuration
+ for (auto& path : paths)
+ {
+ if (!isAdc(path.parent_path()))
+ {
+ continue;
+ }
+ std::smatch match;
+ std::string pathStr = path.string();
+
+ std::regex_search(pathStr, match, inputRegex);
+ std::string indexStr = *(match.begin() + 1);
+
+ // convert to 0 based
+ size_t index = std::stoul(indexStr) - 1;
+
+ const SensorData* sensorData = nullptr;
+ const std::string* interfacePath = nullptr;
+ const std::pair<std::string, SensorBaseConfigMap>*
+ baseConfiguration = nullptr;
+ for (const auto& [path, cfgData] : sensorConfigurations)
+ {
+ // clear it out each loop
+ baseConfiguration = nullptr;
+
+ // find base configuration
+ for (const char* type : sensorTypes)
+ {
+ auto sensorBase =
+ cfgData.find(configInterfaceName(type));
+ if (sensorBase != cfgData.end())
+ {
+ baseConfiguration = &(*sensorBase);
+ break;
+ }
+ }
+ if (baseConfiguration == nullptr)
+ {
+ continue;
+ }
+ auto findIndex = baseConfiguration->second.find("Index");
+ if (findIndex == baseConfiguration->second.end())
+ {
+ std::cerr << "Base configuration missing Index"
+ << baseConfiguration->first << "\n";
+ continue;
+ }
+
+ unsigned int number = std::visit(
+ VariantToUnsignedIntVisitor(), findIndex->second);
+
+ if (number != index)
+ {
+ continue;
+ }
+
+ sensorData = &cfgData;
+ interfacePath = &path.str;
+ break;
+ }
+ if (sensorData == nullptr)
+ {
+ if constexpr (debug)
+ {
+ std::cerr << "failed to find match for "
+ << path.string() << "\n";
+ }
+ continue;
+ }
+
+ if (baseConfiguration == nullptr)
+ {
+ std::cerr << "error finding base configuration for"
+ << path.string() << "\n";
+ continue;
+ }
+
+ auto findSensorName = baseConfiguration->second.find("Name");
+ if (findSensorName == baseConfiguration->second.end())
+ {
+ std::cerr << "could not determine configuration name for "
+ << path.string() << "\n";
+ continue;
+ }
+ std::string sensorName =
+ std::get<std::string>(findSensorName->second);
+
+ // on rescans, only update sensors we were signaled by
+ auto findSensor = sensors.find(sensorName);
+ if (!firstScan && findSensor != sensors.end())
+ {
+ bool found = false;
+ for (auto it = sensorsChanged->begin();
+ it != sensorsChanged->end(); it++)
+ {
+ if (findSensor->second &&
+ it->ends_with(findSensor->second->name))
+ {
+ sensorsChanged->erase(it);
+ findSensor->second = nullptr;
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ continue;
+ }
+ }
+
+ auto findCPU = baseConfiguration->second.find("CPURequired");
+ if (findCPU != baseConfiguration->second.end())
+ {
+ size_t index =
+ std::visit(VariantToIntVisitor(), findCPU->second);
+ auto presenceFind = cpuPresence.find(index);
+ if (presenceFind == cpuPresence.end())
+ {
+ continue; // no such cpu
+ }
+ if (!presenceFind->second)
+ {
+ continue; // cpu not installed
+ }
+ }
+ else if (updateType == UpdateType::cpuPresenceChange)
+ {
+ continue;
+ }
+
+ std::vector<thresholds::Threshold> sensorThresholds;
+ if (!parseThresholdsFromConfig(*sensorData, sensorThresholds))
+ {
+ std::cerr << "error populating thresholds for "
+ << sensorName << "\n";
+ }
+
+ auto findScaleFactor =
+ baseConfiguration->second.find("ScaleFactor");
+ float scaleFactor = 1.0;
+ if (findScaleFactor != baseConfiguration->second.end())
+ {
+ scaleFactor = std::visit(VariantToFloatVisitor(),
+ findScaleFactor->second);
+ // scaleFactor is used in division
+ if (scaleFactor == 0.0F)
+ {
+ scaleFactor = 1.0;
+ }
+ }
+
+ float pollRate =
+ getPollRate(baseConfiguration->second, pollRateDefault);
+ PowerState readState = getPowerState(baseConfiguration->second);
+
+ auto& sensor = sensors[sensorName];
+ sensor = nullptr;
+
+ std::optional<BridgeGpio> bridgeGpio;
+ for (const auto& [key, cfgMap] : *sensorData)
+ {
+ if (key.find("BridgeGpio") != std::string::npos)
+ {
+ auto findName = cfgMap.find("Name");
+ if (findName != cfgMap.end())
+ {
+ std::string gpioName = std::visit(
+ VariantToStringVisitor(), findName->second);
+
+ int polarity = gpiod::line::ACTIVE_HIGH;
+ auto findPolarity = cfgMap.find("Polarity");
+ if (findPolarity != cfgMap.end())
+ {
+ if (std::string("Low") ==
+ std::visit(VariantToStringVisitor(),
+ findPolarity->second))
+ {
+ polarity = gpiod::line::ACTIVE_LOW;
+ }
+ }
+
+ float setupTime = gpioBridgeSetupTimeDefault;
+ auto findSetupTime = cfgMap.find("SetupTime");
+ if (findSetupTime != cfgMap.end())
+ {
+ setupTime = std::visit(VariantToFloatVisitor(),
+ findSetupTime->second);
+ }
+
+ bridgeGpio =
+ BridgeGpio(gpioName, polarity, setupTime);
+ }
+
+ break;
+ }
+ }
+
+ sensor = std::make_shared<ADCSensor>(
+ path.string(), objectServer, dbusConnection, io, sensorName,
+ std::move(sensorThresholds), scaleFactor, pollRate,
+ readState, *interfacePath, std::move(bridgeGpio));
+ sensor->setupRead();
+ }
+ });
+
+ getter->getConfiguration(
+ std::vector<std::string>{sensorTypes.begin(), sensorTypes.end()});
+}
+
+int main()
+{
+ boost::asio::io_context io;
+ auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
+ sdbusplus::asio::object_server objectServer(systemBus, true);
+ objectServer.add_manager("/xyz/openbmc_project/sensors");
+
+ systemBus->request_name("xyz.openbmc_project.ADCSensor");
+ boost::container::flat_map<std::string, std::shared_ptr<ADCSensor>> sensors;
+ auto sensorsChanged =
+ std::make_shared<boost::container::flat_set<std::string>>();
+
+ boost::asio::post(io, [&]() {
+ createSensors(io, objectServer, sensors, systemBus, nullptr,
+ UpdateType::init);
+ });
+
+ boost::asio::steady_timer filterTimer(io);
+ std::function<void(sdbusplus::message_t&)> eventHandler =
+ [&](sdbusplus::message_t& message) {
+ if (message.is_method_error())
+ {
+ std::cerr << "callback method error\n";
+ return;
+ }
+ sensorsChanged->insert(message.get_path());
+ // this implicitly cancels the timer
+ filterTimer.expires_after(std::chrono::seconds(1));
+
+ filterTimer.async_wait([&](const boost::system::error_code& ec) {
+ if (ec == boost::asio::error::operation_aborted)
+ {
+ /* we were canceled*/
+ return;
+ }
+ if (ec)
+ {
+ std::cerr << "timer error\n";
+ return;
+ }
+ createSensors(io, objectServer, sensors, systemBus,
+ sensorsChanged, UpdateType::init);
+ });
+ };
+
+ boost::asio::steady_timer cpuFilterTimer(io);
+ std::function<void(sdbusplus::message_t&)> cpuPresenceHandler =
+ [&](sdbusplus::message_t& message) {
+ std::string path = message.get_path();
+ boost::to_lower(path);
+
+ sdbusplus::message::object_path cpuPath(path);
+ std::string cpuName = cpuPath.filename();
+ if (!cpuName.starts_with("cpu"))
+ {
+ return; // not interested
+ }
+ size_t index = 0;
+ try
+ {
+ index = std::stoi(path.substr(path.size() - 1));
+ }
+ catch (const std::invalid_argument&)
+ {
+ std::cerr << "Found invalid path " << path << "\n";
+ return;
+ }
+
+ std::string objectName;
+ boost::container::flat_map<std::string, std::variant<bool>> values;
+ message.read(objectName, values);
+ auto findPresence = values.find("Present");
+ if (findPresence != values.end())
+ {
+ cpuPresence[index] = std::get<bool>(findPresence->second);
+ }
+
+ // this implicitly cancels the timer
+ cpuFilterTimer.expires_after(std::chrono::seconds(1));
+
+ cpuFilterTimer.async_wait([&](const boost::system::error_code& ec) {
+ if (ec == boost::asio::error::operation_aborted)
+ {
+ /* we were canceled*/
+ return;
+ }
+ if (ec)
+ {
+ std::cerr << "timer error\n";
+ return;
+ }
+ createSensors(io, objectServer, sensors, systemBus, nullptr,
+ UpdateType::cpuPresenceChange);
+ });
+ };
+
+ std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
+ setupPropertiesChangedMatches(*systemBus, sensorTypes, eventHandler);
+ matches.emplace_back(std::make_unique<sdbusplus::bus::match_t>(
+ static_cast<sdbusplus::bus_t&>(*systemBus),
+ "type='signal',member='PropertiesChanged',path_namespace='" +
+ std::string(cpuInventoryPath) +
+ "',arg0namespace='xyz.openbmc_project.Inventory.Item'",
+ cpuPresenceHandler));
+
+ setupManufacturingModeMatch(*systemBus);
+ io.run();
+}
diff --git a/src/adc/meson.build b/src/adc/meson.build
new file mode 100644
index 0000000..02c69c4
--- /dev/null
+++ b/src/adc/meson.build
@@ -0,0 +1,15 @@
+src_inc = include_directories('..')
+
+executable(
+ 'adcsensor',
+ 'ADCSensor.cpp',
+ 'ADCSensorMain.cpp',
+ dependencies: [
+ default_deps,
+ gpiodcxx,
+ thresholds_dep,
+ utils_dep,
+ ],
+ include_directories: src_inc,
+ install: true,
+)
\ No newline at end of file