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>
287dd6443bSJae Hyun Yoo #include <charconv>
2924f02f24SJames Feist #include <filesystem>
306714a25aSJames Feist #include <fstream>
3196e97db7SPatrick Venture #include <functional>
3296e97db7SPatrick Venture #include <memory>
336714a25aSJames Feist #include <regex>
3496e97db7SPatrick Venture #include <stdexcept>
3596e97db7SPatrick Venture #include <string>
3696e97db7SPatrick Venture #include <utility>
3796e97db7SPatrick Venture #include <variant>
3896e97db7SPatrick Venture #include <vector>
396714a25aSJames Feist 
4087bc67f7SJeff Lin static constexpr float pollRateDefault = 0.5;
416714a25aSJames Feist 
42544e7dc5SBruce Mitchell static constexpr double maxValuePressure = 120000; // Pascals
43544e7dc5SBruce Mitchell static constexpr double minValuePressure = 30000;  // Pascals
44544e7dc5SBruce Mitchell 
453ec41c53SBruce Mitchell static constexpr double maxValueRelativeHumidity = 100; // PercentRH
463ec41c53SBruce Mitchell static constexpr double minValueRelativeHumidity = 0;   // PercentRH
473ec41c53SBruce Mitchell 
48544e7dc5SBruce Mitchell static constexpr double maxValueTemperature = 127;  // DegreesC
49544e7dc5SBruce Mitchell static constexpr double minValueTemperature = -128; // DegreesC
50544e7dc5SBruce Mitchell 
51cf3bce6eSJames Feist namespace fs = std::filesystem;
5266558235SBrandon Kim static auto sensorTypes{
534786334fSPotin Lai     std::to_array<const char*>({"xyz.openbmc_project.Configuration.DPS310",
544786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.EMC1412",
558b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.EMC1413",
56381636e2SGilbert Chen                                 "xyz.openbmc_project.Configuration.EMC1414",
574786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.HDC1080",
584786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.JC42",
594786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.LM75A",
604786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.LM95234",
618b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.MAX31725",
628b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.MAX31730",
6316e7af1dSJason Ling                                 "xyz.openbmc_project.Configuration.MAX6581",
643840d0adSJosh Lehan                                 "xyz.openbmc_project.Configuration.MAX6654",
655770a6fdSOskar Senft                                 "xyz.openbmc_project.Configuration.NCT7802",
667c97730bSZev Weiss                                 "xyz.openbmc_project.Configuration.NCT6779",
678fb0a013SJosh Lehan                                 "xyz.openbmc_project.Configuration.SBTSI",
684786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.SI7020",
6955ab2afbSJohn Wang                                 "xyz.openbmc_project.Configuration.TMP112",
703546adb9SPatrick Venture                                 "xyz.openbmc_project.Configuration.TMP175",
718b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.TMP421",
728b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.TMP441",
737ea918f2SZev Weiss                                 "xyz.openbmc_project.Configuration.TMP75",
744786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.W83773G"})};
756714a25aSJames Feist 
76544e7dc5SBruce Mitchell static struct SensorParams
77544e7dc5SBruce Mitchell     getSensorParameters(const std::filesystem::path& path)
78544e7dc5SBruce Mitchell {
79544e7dc5SBruce Mitchell     // offset is to default to 0 and scale to 1, see lore
80544e7dc5SBruce Mitchell     // https://lore.kernel.org/linux-iio/5c79425f-6e88-36b6-cdfe-4080738d039f@metafoo.de/
81544e7dc5SBruce Mitchell     struct SensorParams tmpSensorParameters = {.minValue = minValueTemperature,
82544e7dc5SBruce Mitchell                                                .maxValue = maxValueTemperature,
83544e7dc5SBruce Mitchell                                                .offsetValue = 0.0,
84544e7dc5SBruce Mitchell                                                .scaleValue = 1.0,
855a86e562SBruce Mitchell                                                .units =
865a86e562SBruce Mitchell                                                    sensor_paths::unitDegreesC,
87544e7dc5SBruce Mitchell                                                .typeName = "temperature"};
88544e7dc5SBruce Mitchell 
89544e7dc5SBruce Mitchell     // For IIO RAW sensors we get a raw_value, an offset, and scale
90544e7dc5SBruce Mitchell     // to compute the value = (raw_value + offset) * scale
91544e7dc5SBruce Mitchell     // with a _raw IIO device we need to get the
92544e7dc5SBruce Mitchell     // offsetValue and scaleValue from the driver
93544e7dc5SBruce Mitchell     // these are used to compute the reading in
94544e7dc5SBruce Mitchell     // units that have yet to be scaled for D-Bus.
95544e7dc5SBruce Mitchell     const std::string pathStr = path.string();
96544e7dc5SBruce Mitchell     if (pathStr.ends_with("_raw"))
97544e7dc5SBruce Mitchell     {
98544e7dc5SBruce Mitchell         std::string pathOffsetStr =
99544e7dc5SBruce Mitchell             pathStr.substr(0, pathStr.size() - 4) + "_offset";
100544e7dc5SBruce Mitchell         std::optional<double> tmpOffsetValue = readFile(pathOffsetStr, 1.0);
101544e7dc5SBruce Mitchell         // In case there is nothing to read skip this device
102544e7dc5SBruce Mitchell         // This is not an error condition see lore
103544e7dc5SBruce Mitchell         // https://lore.kernel.org/linux-iio/5c79425f-6e88-36b6-cdfe-4080738d039f@metafoo.de/
104544e7dc5SBruce Mitchell         if (tmpOffsetValue)
105544e7dc5SBruce Mitchell         {
106544e7dc5SBruce Mitchell             tmpSensorParameters.offsetValue = *tmpOffsetValue;
107544e7dc5SBruce Mitchell         }
108544e7dc5SBruce Mitchell 
109544e7dc5SBruce Mitchell         std::string pathScaleStr =
110544e7dc5SBruce Mitchell             pathStr.substr(0, pathStr.size() - 4) + "_scale";
111544e7dc5SBruce Mitchell         std::optional<double> tmpScaleValue = readFile(pathScaleStr, 1.0);
112544e7dc5SBruce Mitchell         // In case there is nothing to read skip this device
113544e7dc5SBruce Mitchell         // This is not an error condition see lore
114544e7dc5SBruce Mitchell         // https://lore.kernel.org/linux-iio/5c79425f-6e88-36b6-cdfe-4080738d039f@metafoo.de/
115544e7dc5SBruce Mitchell         if (tmpScaleValue)
116544e7dc5SBruce Mitchell         {
117544e7dc5SBruce Mitchell             tmpSensorParameters.scaleValue = *tmpScaleValue;
118544e7dc5SBruce Mitchell         }
119544e7dc5SBruce Mitchell     }
120544e7dc5SBruce Mitchell 
121544e7dc5SBruce Mitchell     // Temperatures are read in milli degrees Celsius, we need
122544e7dc5SBruce Mitchell     // degrees Celsius. Pressures are read in kilopascal, we need
123544e7dc5SBruce Mitchell     // Pascals.  On D-Bus for Open BMC we use the International
124544e7dc5SBruce Mitchell     // System of Units without prefixes. Links to the kernel
125544e7dc5SBruce Mitchell     // documentation:
126544e7dc5SBruce Mitchell     // https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
127544e7dc5SBruce Mitchell     // https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-bus-iio
128544e7dc5SBruce Mitchell     if (path.filename() == "in_pressure_input" ||
129544e7dc5SBruce Mitchell         path.filename() == "in_pressure_raw")
130544e7dc5SBruce Mitchell     {
131544e7dc5SBruce Mitchell         tmpSensorParameters.minValue = minValuePressure;
132544e7dc5SBruce Mitchell         tmpSensorParameters.maxValue = maxValuePressure;
133544e7dc5SBruce Mitchell         // Pressures are read in kilopascal, we need Pascals.
134544e7dc5SBruce Mitchell         tmpSensorParameters.scaleValue *= 1000.0;
135544e7dc5SBruce Mitchell         tmpSensorParameters.typeName = "pressure";
1365a86e562SBruce Mitchell         tmpSensorParameters.units = sensor_paths::unitPascals;
137544e7dc5SBruce Mitchell     }
1383ec41c53SBruce Mitchell     else if (path.filename() == "in_humidityrelative_input" ||
1393ec41c53SBruce Mitchell              path.filename() == "in_humidityrelative_raw")
1403ec41c53SBruce Mitchell     {
1413ec41c53SBruce Mitchell         tmpSensorParameters.minValue = minValueRelativeHumidity;
1423ec41c53SBruce Mitchell         tmpSensorParameters.maxValue = maxValueRelativeHumidity;
1433ec41c53SBruce Mitchell         // Relative Humidity are read in milli-percent, we need percent.
1443ec41c53SBruce Mitchell         tmpSensorParameters.scaleValue *= 0.001;
1453ec41c53SBruce Mitchell         tmpSensorParameters.typeName = "humidity";
1463ec41c53SBruce Mitchell         tmpSensorParameters.units = "PercentRH";
1473ec41c53SBruce Mitchell     }
148544e7dc5SBruce Mitchell     else
149544e7dc5SBruce Mitchell     {
150544e7dc5SBruce Mitchell         // Temperatures are read in milli degrees Celsius,
151544e7dc5SBruce Mitchell         // we need degrees Celsius.
152544e7dc5SBruce Mitchell         tmpSensorParameters.scaleValue *= 0.001;
153544e7dc5SBruce Mitchell     }
154544e7dc5SBruce Mitchell 
155544e7dc5SBruce Mitchell     return tmpSensorParameters;
156544e7dc5SBruce Mitchell }
157544e7dc5SBruce Mitchell 
1589f3a74edSJayashree Dhanapal struct SensorConfigKey
1599f3a74edSJayashree Dhanapal {
1609f3a74edSJayashree Dhanapal     uint64_t bus;
1619f3a74edSJayashree Dhanapal     uint64_t addr;
1629f3a74edSJayashree Dhanapal     bool operator<(const SensorConfigKey& other) const
1639f3a74edSJayashree Dhanapal     {
1649f3a74edSJayashree Dhanapal         if (bus != other.bus)
1659f3a74edSJayashree Dhanapal         {
1669f3a74edSJayashree Dhanapal             return bus < other.bus;
1679f3a74edSJayashree Dhanapal         }
1689f3a74edSJayashree Dhanapal         return addr < other.addr;
1699f3a74edSJayashree Dhanapal     }
1709f3a74edSJayashree Dhanapal };
1719f3a74edSJayashree Dhanapal 
1729f3a74edSJayashree Dhanapal struct SensorConfig
1739f3a74edSJayashree Dhanapal {
1749f3a74edSJayashree Dhanapal     std::string sensorPath;
1759f3a74edSJayashree Dhanapal     SensorData sensorData;
1769f3a74edSJayashree Dhanapal     std::string interface;
1779f3a74edSJayashree Dhanapal     SensorBaseConfigMap config;
1789f3a74edSJayashree Dhanapal     std::vector<std::string> name;
1799f3a74edSJayashree Dhanapal };
1809f3a74edSJayashree Dhanapal 
1819f3a74edSJayashree Dhanapal using SensorConfigMap =
1829f3a74edSJayashree Dhanapal     boost::container::flat_map<SensorConfigKey, SensorConfig>;
1839f3a74edSJayashree Dhanapal 
1849f3a74edSJayashree Dhanapal static SensorConfigMap
1859f3a74edSJayashree Dhanapal     buildSensorConfigMap(const ManagedObjectType& sensorConfigs)
1869f3a74edSJayashree Dhanapal {
1879f3a74edSJayashree Dhanapal     SensorConfigMap configMap;
1889f3a74edSJayashree Dhanapal     for (const std::pair<sdbusplus::message::object_path, SensorData>& sensor :
1899f3a74edSJayashree Dhanapal          sensorConfigs)
1909f3a74edSJayashree Dhanapal     {
1919f3a74edSJayashree Dhanapal         for (const std::pair<std::string, SensorBaseConfigMap>& cfgmap :
1929f3a74edSJayashree Dhanapal              sensor.second)
1939f3a74edSJayashree Dhanapal         {
1949f3a74edSJayashree Dhanapal             const SensorBaseConfigMap& cfg = cfgmap.second;
1959f3a74edSJayashree Dhanapal             auto busCfg = cfg.find("Bus");
1969f3a74edSJayashree Dhanapal             auto addrCfg = cfg.find("Address");
1979f3a74edSJayashree Dhanapal             if ((busCfg == cfg.end()) || (addrCfg == cfg.end()))
1989f3a74edSJayashree Dhanapal             {
1999f3a74edSJayashree Dhanapal                 continue;
2009f3a74edSJayashree Dhanapal             }
2019f3a74edSJayashree Dhanapal 
2022049bd26SEd Tanous             if ((std::get_if<uint64_t>(&busCfg->second) == nullptr) ||
2032049bd26SEd Tanous                 (std::get_if<uint64_t>(&addrCfg->second) == nullptr))
2049f3a74edSJayashree Dhanapal             {
2059f3a74edSJayashree Dhanapal                 std::cerr << sensor.first.str << " Bus or Address invalid\n";
2069f3a74edSJayashree Dhanapal                 continue;
2079f3a74edSJayashree Dhanapal             }
2089f3a74edSJayashree Dhanapal 
2099f3a74edSJayashree Dhanapal             std::vector<std::string> hwmonNames;
2109f3a74edSJayashree Dhanapal             auto nameCfg = cfg.find("Name");
2119f3a74edSJayashree Dhanapal             if (nameCfg != cfg.end())
2129f3a74edSJayashree Dhanapal             {
2139f3a74edSJayashree Dhanapal                 hwmonNames.push_back(std::get<std::string>(nameCfg->second));
2149f3a74edSJayashree Dhanapal                 size_t i = 1;
2159f3a74edSJayashree Dhanapal                 while (true)
2169f3a74edSJayashree Dhanapal                 {
2179f3a74edSJayashree Dhanapal                     auto sensorNameCfg = cfg.find("Name" + std::to_string(i));
2189f3a74edSJayashree Dhanapal                     if (sensorNameCfg == cfg.end())
2199f3a74edSJayashree Dhanapal                     {
2209f3a74edSJayashree Dhanapal                         break;
2219f3a74edSJayashree Dhanapal                     }
2229f3a74edSJayashree Dhanapal                     hwmonNames.push_back(
2239f3a74edSJayashree Dhanapal                         std::get<std::string>(sensorNameCfg->second));
2249f3a74edSJayashree Dhanapal                     i++;
2259f3a74edSJayashree Dhanapal                 }
2269f3a74edSJayashree Dhanapal             }
2279f3a74edSJayashree Dhanapal 
2289f3a74edSJayashree Dhanapal             SensorConfigKey key = {std::get<uint64_t>(busCfg->second),
2299f3a74edSJayashree Dhanapal                                    std::get<uint64_t>(addrCfg->second)};
2309f3a74edSJayashree Dhanapal             SensorConfig val = {sensor.first.str, sensor.second, cfgmap.first,
2319f3a74edSJayashree Dhanapal                                 cfg, hwmonNames};
2329f3a74edSJayashree Dhanapal 
2339f3a74edSJayashree Dhanapal             auto [it, inserted] = configMap.emplace(key, std::move(val));
2349f3a74edSJayashree Dhanapal             if (!inserted)
2359f3a74edSJayashree Dhanapal             {
2369f3a74edSJayashree Dhanapal                 std::cerr << sensor.first.str
2379f3a74edSJayashree Dhanapal                           << ": ignoring duplicate entry for {" << key.bus
2389f3a74edSJayashree Dhanapal                           << ", 0x" << std::hex << key.addr << std::dec
2399f3a74edSJayashree Dhanapal                           << "}\n";
2409f3a74edSJayashree Dhanapal             }
2419f3a74edSJayashree Dhanapal         }
2429f3a74edSJayashree Dhanapal     }
2439f3a74edSJayashree Dhanapal     return configMap;
2449f3a74edSJayashree Dhanapal }
2459f3a74edSJayashree Dhanapal 
2466714a25aSJames Feist void createSensors(
2476714a25aSJames Feist     boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
248f3fd1915SYong Li     boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>>&
2496714a25aSJames Feist         sensors,
2506714a25aSJames Feist     std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
2515591cf08SJames Feist     const std::shared_ptr<boost::container::flat_set<std::string>>&
2526714a25aSJames Feist         sensorsChanged)
2536714a25aSJames Feist {
254df515159SJames Feist     auto getter = std::make_shared<GetSensorConfiguration>(
255df515159SJames Feist         dbusConnection,
2568a17c303SEd Tanous         [&io, &objectServer, &sensors, &dbusConnection,
2578a17c303SEd Tanous          sensorsChanged](const ManagedObjectType& sensorConfigurations) {
2586714a25aSJames Feist         bool firstScan = sensorsChanged == nullptr;
259df515159SJames Feist 
260bb67932aSEd Tanous         SensorConfigMap configMap = buildSensorConfigMap(sensorConfigurations);
2619f3a74edSJayashree Dhanapal 
262544e7dc5SBruce Mitchell         // IIO _raw devices look like this on sysfs:
263544e7dc5SBruce Mitchell         //     /sys/bus/iio/devices/iio:device0/in_temp_raw
264544e7dc5SBruce Mitchell         //     /sys/bus/iio/devices/iio:device0/in_temp_offset
265544e7dc5SBruce Mitchell         //     /sys/bus/iio/devices/iio:device0/in_temp_scale
266544e7dc5SBruce Mitchell         //
267544e7dc5SBruce Mitchell         // Other IIO devices look like this on sysfs:
268544e7dc5SBruce Mitchell         //     /sys/bus/iio/devices/iio:device1/in_temp_input
269544e7dc5SBruce Mitchell         //     /sys/bus/iio/devices/iio:device1/in_pressure_input
2706714a25aSJames Feist         std::vector<fs::path> paths;
271544e7dc5SBruce Mitchell         fs::path root("/sys/bus/iio/devices");
272544e7dc5SBruce Mitchell         findFiles(root, R"(in_temp\d*_(input|raw))", paths);
273544e7dc5SBruce Mitchell         findFiles(root, R"(in_pressure\d*_(input|raw))", paths);
2743ec41c53SBruce Mitchell         findFiles(root, R"(in_humidityrelative\d*_(input|raw))", paths);
275544e7dc5SBruce Mitchell         findFiles(fs::path("/sys/class/hwmon"), R"(temp\d+_input)", paths);
276544e7dc5SBruce Mitchell 
277544e7dc5SBruce Mitchell         if (paths.empty())
2786714a25aSJames Feist         {
2796714a25aSJames Feist             return;
2806714a25aSJames Feist         }
2816714a25aSJames Feist 
282544e7dc5SBruce Mitchell         // iterate through all found temp and pressure sensors,
283544e7dc5SBruce Mitchell         // and try to match them with configuration
2846714a25aSJames Feist         for (auto& path : paths)
2856714a25aSJames Feist         {
2866714a25aSJames Feist             std::smatch match;
287544e7dc5SBruce Mitchell             const std::string pathStr = path.string();
2886714a25aSJames Feist             auto directory = path.parent_path();
289544e7dc5SBruce Mitchell             fs::path device;
2906714a25aSJames Feist 
291544e7dc5SBruce Mitchell             std::string deviceName;
292544e7dc5SBruce Mitchell             if (pathStr.starts_with("/sys/bus/iio/devices"))
2936714a25aSJames Feist             {
294544e7dc5SBruce Mitchell                 device = fs::canonical(directory);
295544e7dc5SBruce Mitchell                 deviceName = device.parent_path().stem();
29637266ca9SJames Feist             }
297544e7dc5SBruce Mitchell             else
298544e7dc5SBruce Mitchell             {
299544e7dc5SBruce Mitchell                 device = directory / "device";
300544e7dc5SBruce Mitchell                 deviceName = fs::canonical(device).stem();
301544e7dc5SBruce Mitchell             }
3028a57ec09SEd Tanous             auto findHyphen = deviceName.find('-');
30337266ca9SJames Feist             if (findHyphen == std::string::npos)
30437266ca9SJames Feist             {
30537266ca9SJames Feist                 std::cerr << "found bad device " << deviceName << "\n";
3066714a25aSJames Feist                 continue;
3076714a25aSJames Feist             }
30837266ca9SJames Feist             std::string busStr = deviceName.substr(0, findHyphen);
30937266ca9SJames Feist             std::string addrStr = deviceName.substr(findHyphen + 1);
31037266ca9SJames Feist 
3117dd6443bSJae Hyun Yoo             uint64_t bus = 0;
3127dd6443bSJae Hyun Yoo             uint64_t addr = 0;
3132049bd26SEd Tanous             std::from_chars_result res{};
314bb67932aSEd Tanous             res = std::from_chars(busStr.data(), busStr.data() + busStr.size(),
315bb67932aSEd Tanous                                   bus);
3167dd6443bSJae Hyun Yoo             if (res.ec != std::errc{})
3176714a25aSJames Feist             {
3187dd6443bSJae Hyun Yoo                 continue;
31937266ca9SJames Feist             }
320bb67932aSEd Tanous             res = std::from_chars(addrStr.data(),
321bb67932aSEd Tanous                                   addrStr.data() + addrStr.size(), addr, 16);
3227dd6443bSJae Hyun Yoo             if (res.ec != std::errc{})
32337266ca9SJames Feist             {
3246714a25aSJames Feist                 continue;
3256714a25aSJames Feist             }
32637266ca9SJames Feist 
327544e7dc5SBruce Mitchell             auto thisSensorParameters = getSensorParameters(path);
3289f3a74edSJayashree Dhanapal             auto findSensorCfg = configMap.find({bus, addr});
3299f3a74edSJayashree Dhanapal             if (findSensorCfg == configMap.end())
33037266ca9SJames Feist             {
33137266ca9SJames Feist                 continue;
33237266ca9SJames Feist             }
33337266ca9SJames Feist 
334bb67932aSEd Tanous             const std::string& interfacePath = findSensorCfg->second.sensorPath;
3359f3a74edSJayashree Dhanapal             const SensorData& sensorData = findSensorCfg->second.sensorData;
3369f3a74edSJayashree Dhanapal             const std::string& sensorType = findSensorCfg->second.interface;
3379f3a74edSJayashree Dhanapal             const SensorBaseConfigMap& baseConfigMap =
3389f3a74edSJayashree Dhanapal                 findSensorCfg->second.config;
339bb67932aSEd Tanous             std::vector<std::string>& hwmonName = findSensorCfg->second.name;
3406714a25aSJames Feist 
341544e7dc5SBruce Mitchell             // Temperature has "Name", pressure has "Name1"
3429f3a74edSJayashree Dhanapal             auto findSensorName = baseConfigMap.find("Name");
343fefdbe7fSPotin Lai             int index = 1;
3443ec41c53SBruce Mitchell             if (thisSensorParameters.typeName == "pressure" ||
3453ec41c53SBruce Mitchell                 thisSensorParameters.typeName == "humidity")
346544e7dc5SBruce Mitchell             {
3479f3a74edSJayashree Dhanapal                 findSensorName = baseConfigMap.find("Name1");
348fefdbe7fSPotin Lai                 index = 2;
349544e7dc5SBruce Mitchell             }
350544e7dc5SBruce Mitchell 
3519f3a74edSJayashree Dhanapal             if (findSensorName == baseConfigMap.end())
3526714a25aSJames Feist             {
3536714a25aSJames Feist                 std::cerr << "could not determine configuration name for "
35437266ca9SJames Feist                           << deviceName << "\n";
3556714a25aSJames Feist                 continue;
3566714a25aSJames Feist             }
357df515159SJames Feist             std::string sensorName =
358df515159SJames Feist                 std::get<std::string>(findSensorName->second);
3596714a25aSJames Feist             // on rescans, only update sensors we were signaled by
3606714a25aSJames Feist             auto findSensor = sensors.find(sensorName);
3616714a25aSJames Feist             if (!firstScan && findSensor != sensors.end())
3626714a25aSJames Feist             {
3636714a25aSJames Feist                 bool found = false;
364d653b75cSBruce Mitchell                 auto it = sensorsChanged->begin();
365d653b75cSBruce Mitchell                 while (it != sensorsChanged->end())
3666714a25aSJames Feist                 {
3676714a25aSJames Feist                     if (boost::ends_with(*it, findSensor->second->name))
3686714a25aSJames Feist                     {
369d653b75cSBruce Mitchell                         it = sensorsChanged->erase(it);
3706714a25aSJames Feist                         findSensor->second = nullptr;
3716714a25aSJames Feist                         found = true;
3726714a25aSJames Feist                         break;
3736714a25aSJames Feist                     }
374d653b75cSBruce Mitchell                     ++it;
3756714a25aSJames Feist                 }
3766714a25aSJames Feist                 if (!found)
3776714a25aSJames Feist                 {
3786714a25aSJames Feist                     continue;
3796714a25aSJames Feist                 }
3806714a25aSJames Feist             }
3815636d52bSMatt Spinler 
3826714a25aSJames Feist             std::vector<thresholds::Threshold> sensorThresholds;
3835636d52bSMatt Spinler 
3849f3a74edSJayashree Dhanapal             if (!parseThresholdsFromConfig(sensorData, sensorThresholds,
3855636d52bSMatt Spinler                                            nullptr, &index))
3866714a25aSJames Feist             {
387bb67932aSEd Tanous                 std::cerr << "error populating thresholds for " << sensorName
388bb67932aSEd Tanous                           << " index " << index << "\n";
3896714a25aSJames Feist             }
39087bc67f7SJeff Lin 
3919f3a74edSJayashree Dhanapal             auto findPollRate = baseConfigMap.find("PollRate");
39287bc67f7SJeff Lin             float pollRate = pollRateDefault;
3939f3a74edSJayashree Dhanapal             if (findPollRate != baseConfigMap.end())
39487bc67f7SJeff Lin             {
395bb67932aSEd Tanous                 pollRate =
396bb67932aSEd Tanous                     std::visit(VariantToFloatVisitor(), findPollRate->second);
3972049bd26SEd Tanous                 if (pollRate <= 0.0F)
39887bc67f7SJeff Lin                 {
39987bc67f7SJeff Lin                     pollRate = pollRateDefault; // polling time too short
40087bc67f7SJeff Lin                 }
40187bc67f7SJeff Lin             }
40287bc67f7SJeff Lin 
403a4d2768cSZev Weiss             PowerState readState = getPowerState(baseConfigMap);
404100c20bfSJason Ling 
4059f3a74edSJayashree Dhanapal             auto permitSet = getPermitSet(baseConfigMap);
4068b3f7d40SAlex Qiu             auto& sensor = sensors[sensorName];
4078b3f7d40SAlex Qiu             sensor = nullptr;
408bb67932aSEd Tanous             auto hwmonFile =
409bb67932aSEd Tanous                 getFullHwmonFilePath(directory.string(), "temp1", permitSet);
410544e7dc5SBruce Mitchell             if (pathStr.starts_with("/sys/bus/iio/devices"))
411544e7dc5SBruce Mitchell             {
412544e7dc5SBruce Mitchell                 hwmonFile = pathStr;
413544e7dc5SBruce Mitchell             }
414100c20bfSJason Ling             if (hwmonFile)
415100c20bfSJason Ling             {
416f3fd1915SYong Li                 sensor = std::make_shared<HwmonTempSensor>(
417bb67932aSEd Tanous                     *hwmonFile, sensorType, objectServer, dbusConnection, io,
418bb67932aSEd Tanous                     sensorName, std::move(sensorThresholds),
419bb67932aSEd Tanous                     thisSensorParameters, pollRate, interfacePath, readState);
420f3fd1915SYong Li                 sensor->setupRead();
4219eb0cc3dSWilly Tu             }
4229f3a74edSJayashree Dhanapal             hwmonName.erase(
4239f3a74edSJayashree Dhanapal                 remove(hwmonName.begin(), hwmonName.end(), sensorName),
4249f3a74edSJayashree Dhanapal                 hwmonName.end());
4259eb0cc3dSWilly Tu 
4268b3f7d40SAlex Qiu             // Looking for keys like "Name1" for temp2_input,
4278b3f7d40SAlex Qiu             // "Name2" for temp3_input, etc.
4288b3f7d40SAlex Qiu             int i = 0;
4298b3f7d40SAlex Qiu             while (true)
43037266ca9SJames Feist             {
4318b3f7d40SAlex Qiu                 ++i;
432bb67932aSEd Tanous                 auto findKey = baseConfigMap.find("Name" + std::to_string(i));
4339f3a74edSJayashree Dhanapal                 if (findKey == baseConfigMap.end())
4348b3f7d40SAlex Qiu                 {
4358b3f7d40SAlex Qiu                     break;
43637266ca9SJames Feist                 }
437bb67932aSEd Tanous                 std::string sensorName = std::get<std::string>(findKey->second);
438bb67932aSEd Tanous                 hwmonFile = getFullHwmonFilePath(directory.string(),
439bb67932aSEd Tanous                                                  "temp" + std::to_string(i + 1),
440100c20bfSJason Ling                                                  permitSet);
441544e7dc5SBruce Mitchell                 if (pathStr.starts_with("/sys/bus/iio/devices"))
442544e7dc5SBruce Mitchell                 {
443544e7dc5SBruce Mitchell                     continue;
444544e7dc5SBruce Mitchell                 }
445100c20bfSJason Ling                 if (hwmonFile)
446100c20bfSJason Ling                 {
4475636d52bSMatt Spinler                     // To look up thresholds for these additional sensors,
4485636d52bSMatt Spinler                     // match on the Index property in the threshold data
4495636d52bSMatt Spinler                     // where the index comes from the sysfs file we're on,
4505636d52bSMatt Spinler                     // i.e. index = 2 for temp2_input.
4515636d52bSMatt Spinler                     int index = i + 1;
4525636d52bSMatt Spinler                     std::vector<thresholds::Threshold> thresholds;
4535636d52bSMatt Spinler 
4549f3a74edSJayashree Dhanapal                     if (!parseThresholdsFromConfig(sensorData, thresholds,
4555636d52bSMatt Spinler                                                    nullptr, &index))
4565636d52bSMatt Spinler                     {
4575636d52bSMatt Spinler                         std::cerr << "error populating thresholds for "
458bb67932aSEd Tanous                                   << sensorName << " index " << index << "\n";
4595636d52bSMatt Spinler                     }
4605636d52bSMatt Spinler 
4618b3f7d40SAlex Qiu                     auto& sensor = sensors[sensorName];
4628b3f7d40SAlex Qiu                     sensor = nullptr;
463f3fd1915SYong Li                     sensor = std::make_shared<HwmonTempSensor>(
464bb67932aSEd Tanous                         *hwmonFile, sensorType, objectServer, dbusConnection,
465bb67932aSEd Tanous                         io, sensorName, std::move(thresholds),
466bb67932aSEd Tanous                         thisSensorParameters, pollRate, interfacePath,
467bb67932aSEd Tanous                         readState);
468f3fd1915SYong Li                     sensor->setupRead();
4698b3f7d40SAlex Qiu                 }
4709eb0cc3dSWilly Tu 
4719eb0cc3dSWilly Tu                 hwmonName.erase(
4729eb0cc3dSWilly Tu                     remove(hwmonName.begin(), hwmonName.end(), sensorName),
4739eb0cc3dSWilly Tu                     hwmonName.end());
4746714a25aSJames Feist             }
47531ec7dbbSMatt Spinler             if (hwmonName.empty())
47631ec7dbbSMatt Spinler             {
4779f3a74edSJayashree Dhanapal                 configMap.erase(findSensorCfg);
4789f3a74edSJayashree Dhanapal             }
47931ec7dbbSMatt Spinler         }
4808a17c303SEd Tanous         });
481df515159SJames Feist     getter->getConfiguration(
482df515159SJames Feist         std::vector<std::string>(sensorTypes.begin(), sensorTypes.end()));
4836714a25aSJames Feist }
4846714a25aSJames Feist 
48520bf2c1cSMatt Spinler void interfaceRemoved(
48692f8f515SPatrick Williams     sdbusplus::message_t& message,
48720bf2c1cSMatt Spinler     boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>>&
48820bf2c1cSMatt Spinler         sensors)
48920bf2c1cSMatt Spinler {
49020bf2c1cSMatt Spinler     if (message.is_method_error())
49120bf2c1cSMatt Spinler     {
49220bf2c1cSMatt Spinler         std::cerr << "interfacesRemoved callback method error\n";
49320bf2c1cSMatt Spinler         return;
49420bf2c1cSMatt Spinler     }
49520bf2c1cSMatt Spinler 
49620bf2c1cSMatt Spinler     sdbusplus::message::object_path path;
49720bf2c1cSMatt Spinler     std::vector<std::string> interfaces;
49820bf2c1cSMatt Spinler 
49920bf2c1cSMatt Spinler     message.read(path, interfaces);
50020bf2c1cSMatt Spinler 
50120bf2c1cSMatt Spinler     // If the xyz.openbmc_project.Confguration.X interface was removed
50220bf2c1cSMatt Spinler     // for one or more sensors, delete those sensor objects.
50320bf2c1cSMatt Spinler     auto sensorIt = sensors.begin();
50420bf2c1cSMatt Spinler     while (sensorIt != sensors.end())
50520bf2c1cSMatt Spinler     {
50620bf2c1cSMatt Spinler         if ((sensorIt->second->configurationPath == path) &&
50720bf2c1cSMatt Spinler             (std::find(interfaces.begin(), interfaces.end(),
50820bf2c1cSMatt Spinler                        sensorIt->second->objectType) != interfaces.end()))
50920bf2c1cSMatt Spinler         {
51020bf2c1cSMatt Spinler             sensorIt = sensors.erase(sensorIt);
51120bf2c1cSMatt Spinler         }
51220bf2c1cSMatt Spinler         else
51320bf2c1cSMatt Spinler         {
51420bf2c1cSMatt Spinler             sensorIt++;
51520bf2c1cSMatt Spinler         }
51620bf2c1cSMatt Spinler     }
51720bf2c1cSMatt Spinler }
51820bf2c1cSMatt Spinler 
519b6c0b914SJames Feist int main()
5206714a25aSJames Feist {
5216714a25aSJames Feist     boost::asio::io_service io;
5226714a25aSJames Feist     auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
5236714a25aSJames Feist     systemBus->request_name("xyz.openbmc_project.HwmonTempSensor");
5246714a25aSJames Feist     sdbusplus::asio::object_server objectServer(systemBus);
525f3fd1915SYong Li     boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>>
5266714a25aSJames Feist         sensors;
5275591cf08SJames Feist     auto sensorsChanged =
5285591cf08SJames Feist         std::make_shared<boost::container::flat_set<std::string>>();
5296714a25aSJames Feist 
5306714a25aSJames Feist     io.post([&]() {
5316714a25aSJames Feist         createSensors(io, objectServer, sensors, systemBus, nullptr);
5326714a25aSJames Feist     });
5336714a25aSJames Feist 
5346714a25aSJames Feist     boost::asio::deadline_timer filterTimer(io);
53592f8f515SPatrick Williams     std::function<void(sdbusplus::message_t&)> eventHandler =
53692f8f515SPatrick Williams         [&](sdbusplus::message_t& message) {
5376714a25aSJames Feist         if (message.is_method_error())
5386714a25aSJames Feist         {
5396714a25aSJames Feist             std::cerr << "callback method error\n";
5406714a25aSJames Feist             return;
5416714a25aSJames Feist         }
5426714a25aSJames Feist         sensorsChanged->insert(message.get_path());
5436714a25aSJames Feist         // this implicitly cancels the timer
5446714a25aSJames Feist         filterTimer.expires_from_now(boost::posix_time::seconds(1));
5456714a25aSJames Feist 
5466714a25aSJames Feist         filterTimer.async_wait([&](const boost::system::error_code& ec) {
5476714a25aSJames Feist             if (ec == boost::asio::error::operation_aborted)
5486714a25aSJames Feist             {
5496714a25aSJames Feist                 /* we were canceled*/
5506714a25aSJames Feist                 return;
5516714a25aSJames Feist             }
5528a57ec09SEd Tanous             if (ec)
5536714a25aSJames Feist             {
5546714a25aSJames Feist                 std::cerr << "timer error\n";
5556714a25aSJames Feist                 return;
5566714a25aSJames Feist             }
557bb67932aSEd Tanous             createSensors(io, objectServer, sensors, systemBus, sensorsChanged);
5586714a25aSJames Feist         });
5596714a25aSJames Feist     };
5606714a25aSJames Feist 
561*214d9717SZev Weiss     std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
562*214d9717SZev Weiss         setupPropertiesChangedMatches(*systemBus, sensorTypes, eventHandler);
5631263c3daSBruce Lee     setupManufacturingModeMatch(*systemBus);
56420bf2c1cSMatt Spinler 
56520bf2c1cSMatt Spinler     // Watch for entity-manager to remove configuration interfaces
56620bf2c1cSMatt Spinler     // so the corresponding sensors can be removed.
56792f8f515SPatrick Williams     auto ifaceRemovedMatch = std::make_unique<sdbusplus::bus::match_t>(
56892f8f515SPatrick Williams         static_cast<sdbusplus::bus_t&>(*systemBus),
56920bf2c1cSMatt Spinler         "type='signal',member='InterfacesRemoved',arg0path='" +
57020bf2c1cSMatt Spinler             std::string(inventoryPath) + "/'",
57192f8f515SPatrick Williams         [&sensors](sdbusplus::message_t& msg) {
57220bf2c1cSMatt Spinler         interfaceRemoved(msg, sensors);
57320bf2c1cSMatt Spinler         });
57420bf2c1cSMatt Spinler 
57520bf2c1cSMatt Spinler     matches.emplace_back(std::move(ifaceRemovedMatch));
57620bf2c1cSMatt Spinler 
5776714a25aSJames Feist     io.run();
5786714a25aSJames Feist }
579