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 
41544e7dc5SBruce Mitchell static constexpr double maxValuePressure = 120000; // Pascals
42544e7dc5SBruce Mitchell static constexpr double minValuePressure = 30000;  // Pascals
43544e7dc5SBruce Mitchell 
44544e7dc5SBruce Mitchell static constexpr double maxValueTemperature = 127;  // DegreesC
45544e7dc5SBruce Mitchell static constexpr double minValueTemperature = -128; // DegreesC
46544e7dc5SBruce Mitchell 
47cf3bce6eSJames Feist namespace fs = std::filesystem;
4866558235SBrandon Kim static auto sensorTypes{
49*4786334fSPotin Lai     std::to_array<const char*>({"xyz.openbmc_project.Configuration.DPS310",
50*4786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.EMC1412",
518b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.EMC1413",
52381636e2SGilbert Chen                                 "xyz.openbmc_project.Configuration.EMC1414",
53*4786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.HDC1080",
54*4786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.JC42",
55*4786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.LM75A",
56*4786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.LM95234",
578b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.MAX31725",
588b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.MAX31730",
5916e7af1dSJason Ling                                 "xyz.openbmc_project.Configuration.MAX6581",
603840d0adSJosh Lehan                                 "xyz.openbmc_project.Configuration.MAX6654",
615770a6fdSOskar Senft                                 "xyz.openbmc_project.Configuration.NCT7802",
628fb0a013SJosh Lehan                                 "xyz.openbmc_project.Configuration.SBTSI",
63*4786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.SI7020",
6455ab2afbSJohn Wang                                 "xyz.openbmc_project.Configuration.TMP112",
653546adb9SPatrick Venture                                 "xyz.openbmc_project.Configuration.TMP175",
668b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.TMP421",
678b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.TMP441",
687ea918f2SZev Weiss                                 "xyz.openbmc_project.Configuration.TMP75",
69*4786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.W83773G"})};
706714a25aSJames Feist 
71544e7dc5SBruce Mitchell static struct SensorParams
72544e7dc5SBruce Mitchell     getSensorParameters(const std::filesystem::path& path)
73544e7dc5SBruce Mitchell {
74544e7dc5SBruce Mitchell     // offset is to default to 0 and scale to 1, see lore
75544e7dc5SBruce Mitchell     // https://lore.kernel.org/linux-iio/5c79425f-6e88-36b6-cdfe-4080738d039f@metafoo.de/
76544e7dc5SBruce Mitchell     struct SensorParams tmpSensorParameters = {.minValue = minValueTemperature,
77544e7dc5SBruce Mitchell                                                .maxValue = maxValueTemperature,
78544e7dc5SBruce Mitchell                                                .offsetValue = 0.0,
79544e7dc5SBruce Mitchell                                                .scaleValue = 1.0,
805a86e562SBruce Mitchell                                                .units =
815a86e562SBruce Mitchell                                                    sensor_paths::unitDegreesC,
82544e7dc5SBruce Mitchell                                                .typeName = "temperature"};
83544e7dc5SBruce Mitchell 
84544e7dc5SBruce Mitchell     // For IIO RAW sensors we get a raw_value, an offset, and scale
85544e7dc5SBruce Mitchell     // to compute the value = (raw_value + offset) * scale
86544e7dc5SBruce Mitchell     // with a _raw IIO device we need to get the
87544e7dc5SBruce Mitchell     // offsetValue and scaleValue from the driver
88544e7dc5SBruce Mitchell     // these are used to compute the reading in
89544e7dc5SBruce Mitchell     // units that have yet to be scaled for D-Bus.
90544e7dc5SBruce Mitchell     const std::string pathStr = path.string();
91544e7dc5SBruce Mitchell     if (pathStr.ends_with("_raw"))
92544e7dc5SBruce Mitchell     {
93544e7dc5SBruce Mitchell         std::string pathOffsetStr =
94544e7dc5SBruce Mitchell             pathStr.substr(0, pathStr.size() - 4) + "_offset";
95544e7dc5SBruce Mitchell         std::optional<double> tmpOffsetValue = readFile(pathOffsetStr, 1.0);
96544e7dc5SBruce Mitchell         // In case there is nothing to read skip this device
97544e7dc5SBruce Mitchell         // This is not an error condition see lore
98544e7dc5SBruce Mitchell         // https://lore.kernel.org/linux-iio/5c79425f-6e88-36b6-cdfe-4080738d039f@metafoo.de/
99544e7dc5SBruce Mitchell         if (tmpOffsetValue)
100544e7dc5SBruce Mitchell         {
101544e7dc5SBruce Mitchell             tmpSensorParameters.offsetValue = *tmpOffsetValue;
102544e7dc5SBruce Mitchell         }
103544e7dc5SBruce Mitchell 
104544e7dc5SBruce Mitchell         std::string pathScaleStr =
105544e7dc5SBruce Mitchell             pathStr.substr(0, pathStr.size() - 4) + "_scale";
106544e7dc5SBruce Mitchell         std::optional<double> tmpScaleValue = readFile(pathScaleStr, 1.0);
107544e7dc5SBruce Mitchell         // In case there is nothing to read skip this device
108544e7dc5SBruce Mitchell         // This is not an error condition see lore
109544e7dc5SBruce Mitchell         // https://lore.kernel.org/linux-iio/5c79425f-6e88-36b6-cdfe-4080738d039f@metafoo.de/
110544e7dc5SBruce Mitchell         if (tmpScaleValue)
111544e7dc5SBruce Mitchell         {
112544e7dc5SBruce Mitchell             tmpSensorParameters.scaleValue = *tmpScaleValue;
113544e7dc5SBruce Mitchell         }
114544e7dc5SBruce Mitchell     }
115544e7dc5SBruce Mitchell 
116544e7dc5SBruce Mitchell     // Temperatures are read in milli degrees Celsius, we need
117544e7dc5SBruce Mitchell     // degrees Celsius. Pressures are read in kilopascal, we need
118544e7dc5SBruce Mitchell     // Pascals.  On D-Bus for Open BMC we use the International
119544e7dc5SBruce Mitchell     // System of Units without prefixes. Links to the kernel
120544e7dc5SBruce Mitchell     // documentation:
121544e7dc5SBruce Mitchell     // https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
122544e7dc5SBruce Mitchell     // https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-bus-iio
123544e7dc5SBruce Mitchell     if (path.filename() == "in_pressure_input" ||
124544e7dc5SBruce Mitchell         path.filename() == "in_pressure_raw")
125544e7dc5SBruce Mitchell     {
126544e7dc5SBruce Mitchell         tmpSensorParameters.minValue = minValuePressure;
127544e7dc5SBruce Mitchell         tmpSensorParameters.maxValue = maxValuePressure;
128544e7dc5SBruce Mitchell         // Pressures are read in kilopascal, we need Pascals.
129544e7dc5SBruce Mitchell         tmpSensorParameters.scaleValue *= 1000.0;
130544e7dc5SBruce Mitchell         tmpSensorParameters.typeName = "pressure";
1315a86e562SBruce Mitchell         tmpSensorParameters.units = sensor_paths::unitPascals;
132544e7dc5SBruce Mitchell     }
133544e7dc5SBruce Mitchell     else
134544e7dc5SBruce Mitchell     {
135544e7dc5SBruce Mitchell         // Temperatures are read in milli degrees Celsius,
136544e7dc5SBruce Mitchell         // we need degrees Celsius.
137544e7dc5SBruce Mitchell         tmpSensorParameters.scaleValue *= 0.001;
138544e7dc5SBruce Mitchell     }
139544e7dc5SBruce Mitchell 
140544e7dc5SBruce Mitchell     return tmpSensorParameters;
141544e7dc5SBruce Mitchell }
142544e7dc5SBruce Mitchell 
1436714a25aSJames Feist void createSensors(
1446714a25aSJames Feist     boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
145f3fd1915SYong Li     boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>>&
1466714a25aSJames Feist         sensors,
1476714a25aSJames Feist     std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
1485591cf08SJames Feist     const std::shared_ptr<boost::container::flat_set<std::string>>&
1496714a25aSJames Feist         sensorsChanged)
1506714a25aSJames Feist {
151df515159SJames Feist     auto getter = std::make_shared<GetSensorConfiguration>(
152df515159SJames Feist         dbusConnection,
1538a17c303SEd Tanous         [&io, &objectServer, &sensors, &dbusConnection,
1548a17c303SEd Tanous          sensorsChanged](const ManagedObjectType& sensorConfigurations) {
1556714a25aSJames Feist             bool firstScan = sensorsChanged == nullptr;
156df515159SJames Feist 
157544e7dc5SBruce Mitchell             // IIO _raw devices look like this on sysfs:
158544e7dc5SBruce Mitchell             //     /sys/bus/iio/devices/iio:device0/in_temp_raw
159544e7dc5SBruce Mitchell             //     /sys/bus/iio/devices/iio:device0/in_temp_offset
160544e7dc5SBruce Mitchell             //     /sys/bus/iio/devices/iio:device0/in_temp_scale
161544e7dc5SBruce Mitchell             //
162544e7dc5SBruce Mitchell             // Other IIO devices look like this on sysfs:
163544e7dc5SBruce Mitchell             //     /sys/bus/iio/devices/iio:device1/in_temp_input
164544e7dc5SBruce Mitchell             //     /sys/bus/iio/devices/iio:device1/in_pressure_input
1656714a25aSJames Feist             std::vector<fs::path> paths;
166544e7dc5SBruce Mitchell             fs::path root("/sys/bus/iio/devices");
167544e7dc5SBruce Mitchell             findFiles(root, R"(in_temp\d*_(input|raw))", paths);
168544e7dc5SBruce Mitchell             findFiles(root, R"(in_pressure\d*_(input|raw))", paths);
169544e7dc5SBruce Mitchell             findFiles(fs::path("/sys/class/hwmon"), R"(temp\d+_input)", paths);
170544e7dc5SBruce Mitchell 
171544e7dc5SBruce Mitchell             if (paths.empty())
1726714a25aSJames Feist             {
1736714a25aSJames Feist                 return;
1746714a25aSJames Feist             }
1756714a25aSJames Feist 
176544e7dc5SBruce Mitchell             // iterate through all found temp and pressure sensors,
177544e7dc5SBruce Mitchell             // and try to match them with configuration
1786714a25aSJames Feist             for (auto& path : paths)
1796714a25aSJames Feist             {
1806714a25aSJames Feist                 std::smatch match;
181544e7dc5SBruce Mitchell                 const std::string pathStr = path.string();
1826714a25aSJames Feist                 auto directory = path.parent_path();
183544e7dc5SBruce Mitchell                 fs::path device;
1846714a25aSJames Feist 
185544e7dc5SBruce Mitchell                 std::string deviceName;
186544e7dc5SBruce Mitchell                 if (pathStr.starts_with("/sys/bus/iio/devices"))
1876714a25aSJames Feist                 {
188544e7dc5SBruce Mitchell                     device = fs::canonical(directory);
189544e7dc5SBruce Mitchell                     deviceName = device.parent_path().stem();
19037266ca9SJames Feist                 }
191544e7dc5SBruce Mitchell                 else
192544e7dc5SBruce Mitchell                 {
193544e7dc5SBruce Mitchell                     device = directory / "device";
194544e7dc5SBruce Mitchell                     deviceName = fs::canonical(device).stem();
195544e7dc5SBruce Mitchell                 }
1968a57ec09SEd Tanous                 auto findHyphen = deviceName.find('-');
19737266ca9SJames Feist                 if (findHyphen == std::string::npos)
19837266ca9SJames Feist                 {
19937266ca9SJames Feist                     std::cerr << "found bad device " << deviceName << "\n";
2006714a25aSJames Feist                     continue;
2016714a25aSJames Feist                 }
20237266ca9SJames Feist                 std::string busStr = deviceName.substr(0, findHyphen);
20337266ca9SJames Feist                 std::string addrStr = deviceName.substr(findHyphen + 1);
20437266ca9SJames Feist 
20537266ca9SJames Feist                 size_t bus = 0;
20637266ca9SJames Feist                 size_t addr = 0;
20737266ca9SJames Feist                 try
2086714a25aSJames Feist                 {
20937266ca9SJames Feist                     bus = std::stoi(busStr);
2108a57ec09SEd Tanous                     addr = std::stoi(addrStr, nullptr, 16);
21137266ca9SJames Feist                 }
21226601e89SPatrick Williams                 catch (const std::invalid_argument&)
21337266ca9SJames Feist                 {
2146714a25aSJames Feist                     continue;
2156714a25aSJames Feist                 }
2166714a25aSJames Feist                 const SensorData* sensorData = nullptr;
2176714a25aSJames Feist                 const std::string* interfacePath = nullptr;
21837266ca9SJames Feist                 const char* sensorType = nullptr;
2198b3f7d40SAlex Qiu                 const SensorBaseConfiguration* baseConfiguration = nullptr;
2208b3f7d40SAlex Qiu                 const SensorBaseConfigMap* baseConfigMap = nullptr;
22137266ca9SJames Feist 
222544e7dc5SBruce Mitchell                 auto thisSensorParameters = getSensorParameters(path);
223544e7dc5SBruce Mitchell 
224df515159SJames Feist                 for (const std::pair<sdbusplus::message::object_path,
225df515159SJames Feist                                      SensorData>& sensor : sensorConfigurations)
22637266ca9SJames Feist                 {
22737266ca9SJames Feist                     sensorData = &(sensor.second);
2289ced0a38SJae Hyun Yoo                     for (const char* type : sensorTypes)
2296714a25aSJames Feist                     {
2306714a25aSJames Feist                         auto sensorBase = sensorData->find(type);
2316714a25aSJames Feist                         if (sensorBase != sensorData->end())
2326714a25aSJames Feist                         {
2336714a25aSJames Feist                             baseConfiguration = &(*sensorBase);
2346714a25aSJames Feist                             sensorType = type;
2356714a25aSJames Feist                             break;
2366714a25aSJames Feist                         }
2376714a25aSJames Feist                     }
2386714a25aSJames Feist                     if (baseConfiguration == nullptr)
2396714a25aSJames Feist                     {
24037266ca9SJames Feist                         std::cerr << "error finding base configuration for "
24137266ca9SJames Feist                                   << deviceName << "\n";
24237266ca9SJames Feist                         continue;
24337266ca9SJames Feist                     }
2448b3f7d40SAlex Qiu                     baseConfigMap = &baseConfiguration->second;
2458b3f7d40SAlex Qiu                     auto configurationBus = baseConfigMap->find("Bus");
2468b3f7d40SAlex Qiu                     auto configurationAddress = baseConfigMap->find("Address");
24737266ca9SJames Feist 
2488b3f7d40SAlex Qiu                     if (configurationBus == baseConfigMap->end() ||
2498b3f7d40SAlex Qiu                         configurationAddress == baseConfigMap->end())
25037266ca9SJames Feist                     {
2518b3f7d40SAlex Qiu                         std::cerr << "error finding bus or address in "
2528b3f7d40SAlex Qiu                                      "configuration\n";
25337266ca9SJames Feist                         continue;
25437266ca9SJames Feist                     }
25537266ca9SJames Feist 
2563eb82629SJames Feist                     if (std::get<uint64_t>(configurationBus->second) != bus ||
257df515159SJames Feist                         std::get<uint64_t>(configurationAddress->second) !=
258df515159SJames Feist                             addr)
25937266ca9SJames Feist                     {
26037266ca9SJames Feist                         continue;
26137266ca9SJames Feist                     }
26237266ca9SJames Feist 
26337266ca9SJames Feist                     interfacePath = &(sensor.first.str);
26437266ca9SJames Feist                     break;
26537266ca9SJames Feist                 }
26637266ca9SJames Feist                 if (interfacePath == nullptr)
26737266ca9SJames Feist                 {
2686714a25aSJames Feist                     continue;
2696714a25aSJames Feist                 }
2706714a25aSJames Feist 
271544e7dc5SBruce Mitchell                 // Temperature has "Name", pressure has "Name1"
2728b3f7d40SAlex Qiu                 auto findSensorName = baseConfigMap->find("Name");
273544e7dc5SBruce Mitchell                 if (thisSensorParameters.typeName == "pressure")
274544e7dc5SBruce Mitchell                 {
275544e7dc5SBruce Mitchell                     findSensorName = baseConfigMap->find("Name1");
276544e7dc5SBruce Mitchell                 }
277544e7dc5SBruce Mitchell 
2788b3f7d40SAlex Qiu                 if (findSensorName == baseConfigMap->end())
2796714a25aSJames Feist                 {
2806714a25aSJames Feist                     std::cerr << "could not determine configuration name for "
28137266ca9SJames Feist                               << deviceName << "\n";
2826714a25aSJames Feist                     continue;
2836714a25aSJames Feist                 }
284df515159SJames Feist                 std::string sensorName =
285df515159SJames Feist                     std::get<std::string>(findSensorName->second);
2866714a25aSJames Feist                 // on rescans, only update sensors we were signaled by
2876714a25aSJames Feist                 auto findSensor = sensors.find(sensorName);
2886714a25aSJames Feist                 if (!firstScan && findSensor != sensors.end())
2896714a25aSJames Feist                 {
2906714a25aSJames Feist                     bool found = false;
291d653b75cSBruce Mitchell                     auto it = sensorsChanged->begin();
292d653b75cSBruce Mitchell                     while (it != sensorsChanged->end())
2936714a25aSJames Feist                     {
2946714a25aSJames Feist                         if (boost::ends_with(*it, findSensor->second->name))
2956714a25aSJames Feist                         {
296d653b75cSBruce Mitchell                             it = sensorsChanged->erase(it);
2976714a25aSJames Feist                             findSensor->second = nullptr;
2986714a25aSJames Feist                             found = true;
2996714a25aSJames Feist                             break;
3006714a25aSJames Feist                         }
301d653b75cSBruce Mitchell                         ++it;
3026714a25aSJames Feist                     }
3036714a25aSJames Feist                     if (!found)
3046714a25aSJames Feist                     {
3056714a25aSJames Feist                         continue;
3066714a25aSJames Feist                     }
3076714a25aSJames Feist                 }
3085636d52bSMatt Spinler 
3096714a25aSJames Feist                 std::vector<thresholds::Threshold> sensorThresholds;
3105636d52bSMatt Spinler                 int index = 1;
3115636d52bSMatt Spinler 
3125636d52bSMatt Spinler                 if (!parseThresholdsFromConfig(*sensorData, sensorThresholds,
3135636d52bSMatt Spinler                                                nullptr, &index))
3146714a25aSJames Feist                 {
315df515159SJames Feist                     std::cerr << "error populating thresholds for "
3165636d52bSMatt Spinler                               << sensorName << " index 1\n";
3176714a25aSJames Feist                 }
31887bc67f7SJeff Lin 
31987bc67f7SJeff Lin                 auto findPollRate = baseConfiguration->second.find("PollRate");
32087bc67f7SJeff Lin                 float pollRate = pollRateDefault;
32187bc67f7SJeff Lin                 if (findPollRate != baseConfiguration->second.end())
32287bc67f7SJeff Lin                 {
32387bc67f7SJeff Lin                     pollRate = std::visit(VariantToFloatVisitor(),
32487bc67f7SJeff Lin                                           findPollRate->second);
32587bc67f7SJeff Lin                     if (pollRate <= 0.0f)
32687bc67f7SJeff Lin                     {
32787bc67f7SJeff Lin                         pollRate = pollRateDefault; // polling time too short
32887bc67f7SJeff Lin                     }
32987bc67f7SJeff Lin                 }
33087bc67f7SJeff Lin 
331f9b01b6dSJames Feist                 auto findPowerOn = baseConfiguration->second.find("PowerState");
332f9b01b6dSJames Feist                 PowerState readState = PowerState::always;
333f9b01b6dSJames Feist                 if (findPowerOn != baseConfiguration->second.end())
334f9b01b6dSJames Feist                 {
335f9b01b6dSJames Feist                     std::string powerState = std::visit(
336f9b01b6dSJames Feist                         VariantToStringVisitor(), findPowerOn->second);
337f9b01b6dSJames Feist                     setReadState(powerState, readState);
338f9b01b6dSJames Feist                 }
339100c20bfSJason Ling 
340100c20bfSJason Ling                 auto permitSet = getPermitSet(*baseConfigMap);
3418b3f7d40SAlex Qiu                 auto& sensor = sensors[sensorName];
3428b3f7d40SAlex Qiu                 sensor = nullptr;
343100c20bfSJason Ling                 auto hwmonFile = getFullHwmonFilePath(directory.string(),
344100c20bfSJason Ling                                                       "temp1", permitSet);
345544e7dc5SBruce Mitchell                 if (pathStr.starts_with("/sys/bus/iio/devices"))
346544e7dc5SBruce Mitchell                 {
347544e7dc5SBruce Mitchell                     hwmonFile = pathStr;
348544e7dc5SBruce Mitchell                 }
349100c20bfSJason Ling                 if (hwmonFile)
350100c20bfSJason Ling                 {
351f3fd1915SYong Li                     sensor = std::make_shared<HwmonTempSensor>(
352100c20bfSJason Ling                         *hwmonFile, sensorType, objectServer, dbusConnection,
353544e7dc5SBruce Mitchell                         io, sensorName, std::move(sensorThresholds),
354544e7dc5SBruce Mitchell                         thisSensorParameters, pollRate, *interfacePath,
355544e7dc5SBruce Mitchell                         readState);
356f3fd1915SYong Li                     sensor->setupRead();
357100c20bfSJason Ling                 }
3588b3f7d40SAlex Qiu                 // Looking for keys like "Name1" for temp2_input,
3598b3f7d40SAlex Qiu                 // "Name2" for temp3_input, etc.
3608b3f7d40SAlex Qiu                 int i = 0;
3618b3f7d40SAlex Qiu                 while (true)
36237266ca9SJames Feist                 {
3638b3f7d40SAlex Qiu                     ++i;
3648b3f7d40SAlex Qiu                     auto findKey =
3658b8bcc87SJason Ling                         baseConfigMap->find("Name" + std::to_string(i));
3668b3f7d40SAlex Qiu                     if (findKey == baseConfigMap->end())
3678b3f7d40SAlex Qiu                     {
3688b3f7d40SAlex Qiu                         break;
36937266ca9SJames Feist                     }
3708b3f7d40SAlex Qiu                     std::string sensorName =
3718b3f7d40SAlex Qiu                         std::get<std::string>(findKey->second);
372100c20bfSJason Ling                     hwmonFile = getFullHwmonFilePath(
373100c20bfSJason Ling                         directory.string(), "temp" + std::to_string(i + 1),
374100c20bfSJason Ling                         permitSet);
375544e7dc5SBruce Mitchell                     if (pathStr.starts_with("/sys/bus/iio/devices"))
376544e7dc5SBruce Mitchell                     {
377544e7dc5SBruce Mitchell                         continue;
378544e7dc5SBruce Mitchell                     }
379100c20bfSJason Ling                     if (hwmonFile)
380100c20bfSJason Ling                     {
3815636d52bSMatt Spinler                         // To look up thresholds for these additional sensors,
3825636d52bSMatt Spinler                         // match on the Index property in the threshold data
3835636d52bSMatt Spinler                         // where the index comes from the sysfs file we're on,
3845636d52bSMatt Spinler                         // i.e. index = 2 for temp2_input.
3855636d52bSMatt Spinler                         int index = i + 1;
3865636d52bSMatt Spinler                         std::vector<thresholds::Threshold> thresholds;
3875636d52bSMatt Spinler 
3885636d52bSMatt Spinler                         if (!parseThresholdsFromConfig(*sensorData, thresholds,
3895636d52bSMatt Spinler                                                        nullptr, &index))
3905636d52bSMatt Spinler                         {
3915636d52bSMatt Spinler                             std::cerr << "error populating thresholds for "
3925636d52bSMatt Spinler                                       << sensorName << " index " << index
3935636d52bSMatt Spinler                                       << "\n";
3945636d52bSMatt Spinler                         }
3955636d52bSMatt Spinler 
3968b3f7d40SAlex Qiu                         auto& sensor = sensors[sensorName];
3978b3f7d40SAlex Qiu                         sensor = nullptr;
398f3fd1915SYong Li                         sensor = std::make_shared<HwmonTempSensor>(
399100c20bfSJason Ling                             *hwmonFile, sensorType, objectServer,
400100c20bfSJason Ling                             dbusConnection, io, sensorName,
401544e7dc5SBruce Mitchell                             std::move(thresholds), thisSensorParameters,
402544e7dc5SBruce Mitchell                             pollRate, *interfacePath, readState);
403f3fd1915SYong Li                         sensor->setupRead();
4048b3f7d40SAlex Qiu                     }
4056714a25aSJames Feist                 }
406100c20bfSJason Ling             }
4078a17c303SEd Tanous         });
408df515159SJames Feist     getter->getConfiguration(
409df515159SJames Feist         std::vector<std::string>(sensorTypes.begin(), sensorTypes.end()));
4106714a25aSJames Feist }
4116714a25aSJames Feist 
41220bf2c1cSMatt Spinler void interfaceRemoved(
41320bf2c1cSMatt Spinler     sdbusplus::message::message& message,
41420bf2c1cSMatt Spinler     boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>>&
41520bf2c1cSMatt Spinler         sensors)
41620bf2c1cSMatt Spinler {
41720bf2c1cSMatt Spinler     if (message.is_method_error())
41820bf2c1cSMatt Spinler     {
41920bf2c1cSMatt Spinler         std::cerr << "interfacesRemoved callback method error\n";
42020bf2c1cSMatt Spinler         return;
42120bf2c1cSMatt Spinler     }
42220bf2c1cSMatt Spinler 
42320bf2c1cSMatt Spinler     sdbusplus::message::object_path path;
42420bf2c1cSMatt Spinler     std::vector<std::string> interfaces;
42520bf2c1cSMatt Spinler 
42620bf2c1cSMatt Spinler     message.read(path, interfaces);
42720bf2c1cSMatt Spinler 
42820bf2c1cSMatt Spinler     // If the xyz.openbmc_project.Confguration.X interface was removed
42920bf2c1cSMatt Spinler     // for one or more sensors, delete those sensor objects.
43020bf2c1cSMatt Spinler     auto sensorIt = sensors.begin();
43120bf2c1cSMatt Spinler     while (sensorIt != sensors.end())
43220bf2c1cSMatt Spinler     {
43320bf2c1cSMatt Spinler         if ((sensorIt->second->configurationPath == path) &&
43420bf2c1cSMatt Spinler             (std::find(interfaces.begin(), interfaces.end(),
43520bf2c1cSMatt Spinler                        sensorIt->second->objectType) != interfaces.end()))
43620bf2c1cSMatt Spinler         {
43720bf2c1cSMatt Spinler             sensorIt = sensors.erase(sensorIt);
43820bf2c1cSMatt Spinler         }
43920bf2c1cSMatt Spinler         else
44020bf2c1cSMatt Spinler         {
44120bf2c1cSMatt Spinler             sensorIt++;
44220bf2c1cSMatt Spinler         }
44320bf2c1cSMatt Spinler     }
44420bf2c1cSMatt Spinler }
44520bf2c1cSMatt Spinler 
446b6c0b914SJames Feist int main()
4476714a25aSJames Feist {
4486714a25aSJames Feist     boost::asio::io_service io;
4496714a25aSJames Feist     auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
4506714a25aSJames Feist     systemBus->request_name("xyz.openbmc_project.HwmonTempSensor");
4516714a25aSJames Feist     sdbusplus::asio::object_server objectServer(systemBus);
452f3fd1915SYong Li     boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>>
4536714a25aSJames Feist         sensors;
4546714a25aSJames Feist     std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches;
4555591cf08SJames Feist     auto sensorsChanged =
4565591cf08SJames Feist         std::make_shared<boost::container::flat_set<std::string>>();
4576714a25aSJames Feist 
4586714a25aSJames Feist     io.post([&]() {
4596714a25aSJames Feist         createSensors(io, objectServer, sensors, systemBus, nullptr);
4606714a25aSJames Feist     });
4616714a25aSJames Feist 
4626714a25aSJames Feist     boost::asio::deadline_timer filterTimer(io);
4636714a25aSJames Feist     std::function<void(sdbusplus::message::message&)> eventHandler =
4646714a25aSJames Feist         [&](sdbusplus::message::message& message) {
4656714a25aSJames Feist             if (message.is_method_error())
4666714a25aSJames Feist             {
4676714a25aSJames Feist                 std::cerr << "callback method error\n";
4686714a25aSJames Feist                 return;
4696714a25aSJames Feist             }
4706714a25aSJames Feist             sensorsChanged->insert(message.get_path());
4716714a25aSJames Feist             // this implicitly cancels the timer
4726714a25aSJames Feist             filterTimer.expires_from_now(boost::posix_time::seconds(1));
4736714a25aSJames Feist 
4746714a25aSJames Feist             filterTimer.async_wait([&](const boost::system::error_code& ec) {
4756714a25aSJames Feist                 if (ec == boost::asio::error::operation_aborted)
4766714a25aSJames Feist                 {
4776714a25aSJames Feist                     /* we were canceled*/
4786714a25aSJames Feist                     return;
4796714a25aSJames Feist                 }
4808a57ec09SEd Tanous                 if (ec)
4816714a25aSJames Feist                 {
4826714a25aSJames Feist                     std::cerr << "timer error\n";
4836714a25aSJames Feist                     return;
4846714a25aSJames Feist                 }
4856714a25aSJames Feist                 createSensors(io, objectServer, sensors, systemBus,
4866714a25aSJames Feist                               sensorsChanged);
4876714a25aSJames Feist             });
4886714a25aSJames Feist         };
4896714a25aSJames Feist 
4909ced0a38SJae Hyun Yoo     for (const char* type : sensorTypes)
4916714a25aSJames Feist     {
4926714a25aSJames Feist         auto match = std::make_unique<sdbusplus::bus::match::match>(
4936714a25aSJames Feist             static_cast<sdbusplus::bus::bus&>(*systemBus),
4946714a25aSJames Feist             "type='signal',member='PropertiesChanged',path_namespace='" +
4959ced0a38SJae Hyun Yoo                 std::string(inventoryPath) + "',arg0namespace='" + type + "'",
4966714a25aSJames Feist             eventHandler);
4976714a25aSJames Feist         matches.emplace_back(std::move(match));
4986714a25aSJames Feist     }
4996714a25aSJames Feist 
5001263c3daSBruce Lee     setupManufacturingModeMatch(*systemBus);
50120bf2c1cSMatt Spinler 
50220bf2c1cSMatt Spinler     // Watch for entity-manager to remove configuration interfaces
50320bf2c1cSMatt Spinler     // so the corresponding sensors can be removed.
50420bf2c1cSMatt Spinler     auto ifaceRemovedMatch = std::make_unique<sdbusplus::bus::match::match>(
50520bf2c1cSMatt Spinler         static_cast<sdbusplus::bus::bus&>(*systemBus),
50620bf2c1cSMatt Spinler         "type='signal',member='InterfacesRemoved',arg0path='" +
50720bf2c1cSMatt Spinler             std::string(inventoryPath) + "/'",
50820bf2c1cSMatt Spinler         [&sensors](sdbusplus::message::message& msg) {
50920bf2c1cSMatt Spinler             interfaceRemoved(msg, sensors);
51020bf2c1cSMatt Spinler         });
51120bf2c1cSMatt Spinler 
51220bf2c1cSMatt Spinler     matches.emplace_back(std::move(ifaceRemovedMatch));
51320bf2c1cSMatt Spinler 
5146714a25aSJames Feist     io.run();
5156714a25aSJames Feist }
516