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 
443ec41c53SBruce Mitchell static constexpr double maxValueRelativeHumidity = 100; // PercentRH
453ec41c53SBruce Mitchell static constexpr double minValueRelativeHumidity = 0;   // PercentRH
463ec41c53SBruce Mitchell 
47544e7dc5SBruce Mitchell static constexpr double maxValueTemperature = 127;  // DegreesC
48544e7dc5SBruce Mitchell static constexpr double minValueTemperature = -128; // DegreesC
49544e7dc5SBruce Mitchell 
50cf3bce6eSJames Feist namespace fs = std::filesystem;
5166558235SBrandon Kim static auto sensorTypes{
524786334fSPotin Lai     std::to_array<const char*>({"xyz.openbmc_project.Configuration.DPS310",
534786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.EMC1412",
548b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.EMC1413",
55381636e2SGilbert Chen                                 "xyz.openbmc_project.Configuration.EMC1414",
564786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.HDC1080",
574786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.JC42",
584786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.LM75A",
594786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.LM95234",
608b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.MAX31725",
618b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.MAX31730",
6216e7af1dSJason Ling                                 "xyz.openbmc_project.Configuration.MAX6581",
633840d0adSJosh Lehan                                 "xyz.openbmc_project.Configuration.MAX6654",
645770a6fdSOskar Senft                                 "xyz.openbmc_project.Configuration.NCT7802",
658fb0a013SJosh Lehan                                 "xyz.openbmc_project.Configuration.SBTSI",
664786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.SI7020",
6755ab2afbSJohn Wang                                 "xyz.openbmc_project.Configuration.TMP112",
683546adb9SPatrick Venture                                 "xyz.openbmc_project.Configuration.TMP175",
698b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.TMP421",
708b3f7d40SAlex Qiu                                 "xyz.openbmc_project.Configuration.TMP441",
717ea918f2SZev Weiss                                 "xyz.openbmc_project.Configuration.TMP75",
724786334fSPotin Lai                                 "xyz.openbmc_project.Configuration.W83773G"})};
736714a25aSJames Feist 
74544e7dc5SBruce Mitchell static struct SensorParams
75544e7dc5SBruce Mitchell     getSensorParameters(const std::filesystem::path& path)
76544e7dc5SBruce Mitchell {
77544e7dc5SBruce Mitchell     // offset is to default to 0 and scale to 1, see lore
78544e7dc5SBruce Mitchell     // https://lore.kernel.org/linux-iio/5c79425f-6e88-36b6-cdfe-4080738d039f@metafoo.de/
79544e7dc5SBruce Mitchell     struct SensorParams tmpSensorParameters = {.minValue = minValueTemperature,
80544e7dc5SBruce Mitchell                                                .maxValue = maxValueTemperature,
81544e7dc5SBruce Mitchell                                                .offsetValue = 0.0,
82544e7dc5SBruce Mitchell                                                .scaleValue = 1.0,
835a86e562SBruce Mitchell                                                .units =
845a86e562SBruce Mitchell                                                    sensor_paths::unitDegreesC,
85544e7dc5SBruce Mitchell                                                .typeName = "temperature"};
86544e7dc5SBruce Mitchell 
87544e7dc5SBruce Mitchell     // For IIO RAW sensors we get a raw_value, an offset, and scale
88544e7dc5SBruce Mitchell     // to compute the value = (raw_value + offset) * scale
89544e7dc5SBruce Mitchell     // with a _raw IIO device we need to get the
90544e7dc5SBruce Mitchell     // offsetValue and scaleValue from the driver
91544e7dc5SBruce Mitchell     // these are used to compute the reading in
92544e7dc5SBruce Mitchell     // units that have yet to be scaled for D-Bus.
93544e7dc5SBruce Mitchell     const std::string pathStr = path.string();
94544e7dc5SBruce Mitchell     if (pathStr.ends_with("_raw"))
95544e7dc5SBruce Mitchell     {
96544e7dc5SBruce Mitchell         std::string pathOffsetStr =
97544e7dc5SBruce Mitchell             pathStr.substr(0, pathStr.size() - 4) + "_offset";
98544e7dc5SBruce Mitchell         std::optional<double> tmpOffsetValue = readFile(pathOffsetStr, 1.0);
99544e7dc5SBruce Mitchell         // In case there is nothing to read skip this device
100544e7dc5SBruce Mitchell         // This is not an error condition see lore
101544e7dc5SBruce Mitchell         // https://lore.kernel.org/linux-iio/5c79425f-6e88-36b6-cdfe-4080738d039f@metafoo.de/
102544e7dc5SBruce Mitchell         if (tmpOffsetValue)
103544e7dc5SBruce Mitchell         {
104544e7dc5SBruce Mitchell             tmpSensorParameters.offsetValue = *tmpOffsetValue;
105544e7dc5SBruce Mitchell         }
106544e7dc5SBruce Mitchell 
107544e7dc5SBruce Mitchell         std::string pathScaleStr =
108544e7dc5SBruce Mitchell             pathStr.substr(0, pathStr.size() - 4) + "_scale";
109544e7dc5SBruce Mitchell         std::optional<double> tmpScaleValue = readFile(pathScaleStr, 1.0);
110544e7dc5SBruce Mitchell         // In case there is nothing to read skip this device
111544e7dc5SBruce Mitchell         // This is not an error condition see lore
112544e7dc5SBruce Mitchell         // https://lore.kernel.org/linux-iio/5c79425f-6e88-36b6-cdfe-4080738d039f@metafoo.de/
113544e7dc5SBruce Mitchell         if (tmpScaleValue)
114544e7dc5SBruce Mitchell         {
115544e7dc5SBruce Mitchell             tmpSensorParameters.scaleValue = *tmpScaleValue;
116544e7dc5SBruce Mitchell         }
117544e7dc5SBruce Mitchell     }
118544e7dc5SBruce Mitchell 
119544e7dc5SBruce Mitchell     // Temperatures are read in milli degrees Celsius, we need
120544e7dc5SBruce Mitchell     // degrees Celsius. Pressures are read in kilopascal, we need
121544e7dc5SBruce Mitchell     // Pascals.  On D-Bus for Open BMC we use the International
122544e7dc5SBruce Mitchell     // System of Units without prefixes. Links to the kernel
123544e7dc5SBruce Mitchell     // documentation:
124544e7dc5SBruce Mitchell     // https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
125544e7dc5SBruce Mitchell     // https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-bus-iio
126544e7dc5SBruce Mitchell     if (path.filename() == "in_pressure_input" ||
127544e7dc5SBruce Mitchell         path.filename() == "in_pressure_raw")
128544e7dc5SBruce Mitchell     {
129544e7dc5SBruce Mitchell         tmpSensorParameters.minValue = minValuePressure;
130544e7dc5SBruce Mitchell         tmpSensorParameters.maxValue = maxValuePressure;
131544e7dc5SBruce Mitchell         // Pressures are read in kilopascal, we need Pascals.
132544e7dc5SBruce Mitchell         tmpSensorParameters.scaleValue *= 1000.0;
133544e7dc5SBruce Mitchell         tmpSensorParameters.typeName = "pressure";
1345a86e562SBruce Mitchell         tmpSensorParameters.units = sensor_paths::unitPascals;
135544e7dc5SBruce Mitchell     }
1363ec41c53SBruce Mitchell     else if (path.filename() == "in_humidityrelative_input" ||
1373ec41c53SBruce Mitchell              path.filename() == "in_humidityrelative_raw")
1383ec41c53SBruce Mitchell     {
1393ec41c53SBruce Mitchell         tmpSensorParameters.minValue = minValueRelativeHumidity;
1403ec41c53SBruce Mitchell         tmpSensorParameters.maxValue = maxValueRelativeHumidity;
1413ec41c53SBruce Mitchell         // Relative Humidity are read in milli-percent, we need percent.
1423ec41c53SBruce Mitchell         tmpSensorParameters.scaleValue *= 0.001;
1433ec41c53SBruce Mitchell         tmpSensorParameters.typeName = "humidity";
1443ec41c53SBruce Mitchell         tmpSensorParameters.units = "PercentRH";
1453ec41c53SBruce Mitchell     }
146544e7dc5SBruce Mitchell     else
147544e7dc5SBruce Mitchell     {
148544e7dc5SBruce Mitchell         // Temperatures are read in milli degrees Celsius,
149544e7dc5SBruce Mitchell         // we need degrees Celsius.
150544e7dc5SBruce Mitchell         tmpSensorParameters.scaleValue *= 0.001;
151544e7dc5SBruce Mitchell     }
152544e7dc5SBruce Mitchell 
153544e7dc5SBruce Mitchell     return tmpSensorParameters;
154544e7dc5SBruce Mitchell }
155544e7dc5SBruce Mitchell 
156*9f3a74edSJayashree Dhanapal struct SensorConfigKey
157*9f3a74edSJayashree Dhanapal {
158*9f3a74edSJayashree Dhanapal     uint64_t bus;
159*9f3a74edSJayashree Dhanapal     uint64_t addr;
160*9f3a74edSJayashree Dhanapal     bool operator<(const SensorConfigKey& other) const
161*9f3a74edSJayashree Dhanapal     {
162*9f3a74edSJayashree Dhanapal         if (bus != other.bus)
163*9f3a74edSJayashree Dhanapal         {
164*9f3a74edSJayashree Dhanapal             return bus < other.bus;
165*9f3a74edSJayashree Dhanapal         }
166*9f3a74edSJayashree Dhanapal         return addr < other.addr;
167*9f3a74edSJayashree Dhanapal     }
168*9f3a74edSJayashree Dhanapal };
169*9f3a74edSJayashree Dhanapal 
170*9f3a74edSJayashree Dhanapal struct SensorConfig
171*9f3a74edSJayashree Dhanapal {
172*9f3a74edSJayashree Dhanapal     std::string sensorPath;
173*9f3a74edSJayashree Dhanapal     SensorData sensorData;
174*9f3a74edSJayashree Dhanapal     std::string interface;
175*9f3a74edSJayashree Dhanapal     SensorBaseConfigMap config;
176*9f3a74edSJayashree Dhanapal     std::vector<std::string> name;
177*9f3a74edSJayashree Dhanapal };
178*9f3a74edSJayashree Dhanapal 
179*9f3a74edSJayashree Dhanapal using SensorConfigMap =
180*9f3a74edSJayashree Dhanapal     boost::container::flat_map<SensorConfigKey, SensorConfig>;
181*9f3a74edSJayashree Dhanapal 
182*9f3a74edSJayashree Dhanapal static SensorConfigMap
183*9f3a74edSJayashree Dhanapal     buildSensorConfigMap(const ManagedObjectType& sensorConfigs)
184*9f3a74edSJayashree Dhanapal {
185*9f3a74edSJayashree Dhanapal     SensorConfigMap configMap;
186*9f3a74edSJayashree Dhanapal     for (const std::pair<sdbusplus::message::object_path, SensorData>& sensor :
187*9f3a74edSJayashree Dhanapal          sensorConfigs)
188*9f3a74edSJayashree Dhanapal     {
189*9f3a74edSJayashree Dhanapal         for (const std::pair<std::string, SensorBaseConfigMap>& cfgmap :
190*9f3a74edSJayashree Dhanapal              sensor.second)
191*9f3a74edSJayashree Dhanapal         {
192*9f3a74edSJayashree Dhanapal             const SensorBaseConfigMap& cfg = cfgmap.second;
193*9f3a74edSJayashree Dhanapal             auto busCfg = cfg.find("Bus");
194*9f3a74edSJayashree Dhanapal             auto addrCfg = cfg.find("Address");
195*9f3a74edSJayashree Dhanapal             if ((busCfg == cfg.end()) || (addrCfg == cfg.end()))
196*9f3a74edSJayashree Dhanapal             {
197*9f3a74edSJayashree Dhanapal                 std::cerr << sensor.first.str << " missing Bus or Address\n";
198*9f3a74edSJayashree Dhanapal                 continue;
199*9f3a74edSJayashree Dhanapal             }
200*9f3a74edSJayashree Dhanapal 
201*9f3a74edSJayashree Dhanapal             if ((!std::get_if<uint64_t>(&busCfg->second)) ||
202*9f3a74edSJayashree Dhanapal                 (!std::get_if<uint64_t>(&addrCfg->second)))
203*9f3a74edSJayashree Dhanapal             {
204*9f3a74edSJayashree Dhanapal                 std::cerr << sensor.first.str << " Bus or Address invalid\n";
205*9f3a74edSJayashree Dhanapal                 continue;
206*9f3a74edSJayashree Dhanapal             }
207*9f3a74edSJayashree Dhanapal 
208*9f3a74edSJayashree Dhanapal             std::vector<std::string> hwmonNames;
209*9f3a74edSJayashree Dhanapal             auto nameCfg = cfg.find("Name");
210*9f3a74edSJayashree Dhanapal             if (nameCfg != cfg.end())
211*9f3a74edSJayashree Dhanapal             {
212*9f3a74edSJayashree Dhanapal                 hwmonNames.push_back(std::get<std::string>(nameCfg->second));
213*9f3a74edSJayashree Dhanapal                 size_t i = 1;
214*9f3a74edSJayashree Dhanapal                 while (true)
215*9f3a74edSJayashree Dhanapal                 {
216*9f3a74edSJayashree Dhanapal                     auto sensorNameCfg = cfg.find("Name" + std::to_string(i));
217*9f3a74edSJayashree Dhanapal                     if (sensorNameCfg == cfg.end())
218*9f3a74edSJayashree Dhanapal                     {
219*9f3a74edSJayashree Dhanapal                         break;
220*9f3a74edSJayashree Dhanapal                     }
221*9f3a74edSJayashree Dhanapal                     hwmonNames.push_back(
222*9f3a74edSJayashree Dhanapal                         std::get<std::string>(sensorNameCfg->second));
223*9f3a74edSJayashree Dhanapal                     i++;
224*9f3a74edSJayashree Dhanapal                 }
225*9f3a74edSJayashree Dhanapal             }
226*9f3a74edSJayashree Dhanapal 
227*9f3a74edSJayashree Dhanapal             SensorConfigKey key = {std::get<uint64_t>(busCfg->second),
228*9f3a74edSJayashree Dhanapal                                    std::get<uint64_t>(addrCfg->second)};
229*9f3a74edSJayashree Dhanapal             SensorConfig val = {sensor.first.str, sensor.second, cfgmap.first,
230*9f3a74edSJayashree Dhanapal                                 cfg, hwmonNames};
231*9f3a74edSJayashree Dhanapal 
232*9f3a74edSJayashree Dhanapal             auto [it, inserted] = configMap.emplace(key, std::move(val));
233*9f3a74edSJayashree Dhanapal             if (!inserted)
234*9f3a74edSJayashree Dhanapal             {
235*9f3a74edSJayashree Dhanapal                 std::cerr << sensor.first.str
236*9f3a74edSJayashree Dhanapal                           << ": ignoring duplicate entry for {" << key.bus
237*9f3a74edSJayashree Dhanapal                           << ", 0x" << std::hex << key.addr << std::dec
238*9f3a74edSJayashree Dhanapal                           << "}\n";
239*9f3a74edSJayashree Dhanapal             }
240*9f3a74edSJayashree Dhanapal         }
241*9f3a74edSJayashree Dhanapal     }
242*9f3a74edSJayashree Dhanapal     return configMap;
243*9f3a74edSJayashree Dhanapal }
244*9f3a74edSJayashree Dhanapal 
2456714a25aSJames Feist void createSensors(
2466714a25aSJames Feist     boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
247f3fd1915SYong Li     boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>>&
2486714a25aSJames Feist         sensors,
2496714a25aSJames Feist     std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
2505591cf08SJames Feist     const std::shared_ptr<boost::container::flat_set<std::string>>&
2516714a25aSJames Feist         sensorsChanged)
2526714a25aSJames Feist {
253df515159SJames Feist     auto getter = std::make_shared<GetSensorConfiguration>(
254df515159SJames Feist         dbusConnection,
2558a17c303SEd Tanous         [&io, &objectServer, &sensors, &dbusConnection,
2568a17c303SEd Tanous          sensorsChanged](const ManagedObjectType& sensorConfigurations) {
2576714a25aSJames Feist             bool firstScan = sensorsChanged == nullptr;
258df515159SJames Feist 
259*9f3a74edSJayashree Dhanapal             SensorConfigMap configMap =
260*9f3a74edSJayashree Dhanapal                 buildSensorConfigMap(sensorConfigurations);
261*9f3a74edSJayashree 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 
31137266ca9SJames Feist                 size_t bus = 0;
31237266ca9SJames Feist                 size_t addr = 0;
31337266ca9SJames Feist                 try
3146714a25aSJames Feist                 {
31537266ca9SJames Feist                     bus = std::stoi(busStr);
3168a57ec09SEd Tanous                     addr = std::stoi(addrStr, nullptr, 16);
31737266ca9SJames Feist                 }
31826601e89SPatrick Williams                 catch (const std::invalid_argument&)
31937266ca9SJames Feist                 {
3206714a25aSJames Feist                     continue;
3216714a25aSJames Feist                 }
32237266ca9SJames Feist 
323544e7dc5SBruce Mitchell                 auto thisSensorParameters = getSensorParameters(path);
324*9f3a74edSJayashree Dhanapal                 auto findSensorCfg = configMap.find({bus, addr});
325*9f3a74edSJayashree Dhanapal                 if (findSensorCfg == configMap.end())
32637266ca9SJames Feist                 {
32737266ca9SJames Feist                     continue;
32837266ca9SJames Feist                 }
32937266ca9SJames Feist 
330*9f3a74edSJayashree Dhanapal                 const std::string& interfacePath =
331*9f3a74edSJayashree Dhanapal                     findSensorCfg->second.sensorPath;
332*9f3a74edSJayashree Dhanapal                 const SensorData& sensorData = findSensorCfg->second.sensorData;
333*9f3a74edSJayashree Dhanapal                 const std::string& sensorType = findSensorCfg->second.interface;
334*9f3a74edSJayashree Dhanapal                 const SensorBaseConfigMap& baseConfigMap =
335*9f3a74edSJayashree Dhanapal                     findSensorCfg->second.config;
336*9f3a74edSJayashree Dhanapal                 std::vector<std::string>& hwmonName =
337*9f3a74edSJayashree Dhanapal                     findSensorCfg->second.name;
3386714a25aSJames Feist 
339544e7dc5SBruce Mitchell                 // Temperature has "Name", pressure has "Name1"
340*9f3a74edSJayashree Dhanapal                 auto findSensorName = baseConfigMap.find("Name");
3413ec41c53SBruce Mitchell                 if (thisSensorParameters.typeName == "pressure" ||
3423ec41c53SBruce Mitchell                     thisSensorParameters.typeName == "humidity")
343544e7dc5SBruce Mitchell                 {
344*9f3a74edSJayashree Dhanapal                     findSensorName = baseConfigMap.find("Name1");
345544e7dc5SBruce Mitchell                 }
346544e7dc5SBruce Mitchell 
347*9f3a74edSJayashree Dhanapal                 if (findSensorName == baseConfigMap.end())
3486714a25aSJames Feist                 {
3496714a25aSJames Feist                     std::cerr << "could not determine configuration name for "
35037266ca9SJames Feist                               << deviceName << "\n";
3516714a25aSJames Feist                     continue;
3526714a25aSJames Feist                 }
353df515159SJames Feist                 std::string sensorName =
354df515159SJames Feist                     std::get<std::string>(findSensorName->second);
3556714a25aSJames Feist                 // on rescans, only update sensors we were signaled by
3566714a25aSJames Feist                 auto findSensor = sensors.find(sensorName);
3576714a25aSJames Feist                 if (!firstScan && findSensor != sensors.end())
3586714a25aSJames Feist                 {
3596714a25aSJames Feist                     bool found = false;
360d653b75cSBruce Mitchell                     auto it = sensorsChanged->begin();
361d653b75cSBruce Mitchell                     while (it != sensorsChanged->end())
3626714a25aSJames Feist                     {
3636714a25aSJames Feist                         if (boost::ends_with(*it, findSensor->second->name))
3646714a25aSJames Feist                         {
365d653b75cSBruce Mitchell                             it = sensorsChanged->erase(it);
3666714a25aSJames Feist                             findSensor->second = nullptr;
3676714a25aSJames Feist                             found = true;
3686714a25aSJames Feist                             break;
3696714a25aSJames Feist                         }
370d653b75cSBruce Mitchell                         ++it;
3716714a25aSJames Feist                     }
3726714a25aSJames Feist                     if (!found)
3736714a25aSJames Feist                     {
3746714a25aSJames Feist                         continue;
3756714a25aSJames Feist                     }
3766714a25aSJames Feist                 }
3775636d52bSMatt Spinler 
3786714a25aSJames Feist                 std::vector<thresholds::Threshold> sensorThresholds;
3795636d52bSMatt Spinler                 int index = 1;
3805636d52bSMatt Spinler 
381*9f3a74edSJayashree Dhanapal                 if (!parseThresholdsFromConfig(sensorData, sensorThresholds,
3825636d52bSMatt Spinler                                                nullptr, &index))
3836714a25aSJames Feist                 {
384df515159SJames Feist                     std::cerr << "error populating thresholds for "
3855636d52bSMatt Spinler                               << sensorName << " index 1\n";
3866714a25aSJames Feist                 }
38787bc67f7SJeff Lin 
388*9f3a74edSJayashree Dhanapal                 auto findPollRate = baseConfigMap.find("PollRate");
38987bc67f7SJeff Lin                 float pollRate = pollRateDefault;
390*9f3a74edSJayashree Dhanapal                 if (findPollRate != baseConfigMap.end())
39187bc67f7SJeff Lin                 {
39287bc67f7SJeff Lin                     pollRate = std::visit(VariantToFloatVisitor(),
39387bc67f7SJeff Lin                                           findPollRate->second);
39487bc67f7SJeff Lin                     if (pollRate <= 0.0f)
39587bc67f7SJeff Lin                     {
39687bc67f7SJeff Lin                         pollRate = pollRateDefault; // polling time too short
39787bc67f7SJeff Lin                     }
39887bc67f7SJeff Lin                 }
39987bc67f7SJeff Lin 
400*9f3a74edSJayashree Dhanapal                 auto findPowerOn = baseConfigMap.find("PowerState");
401f9b01b6dSJames Feist                 PowerState readState = PowerState::always;
402*9f3a74edSJayashree Dhanapal                 if (findPowerOn != baseConfigMap.end())
403f9b01b6dSJames Feist                 {
404f9b01b6dSJames Feist                     std::string powerState = std::visit(
405f9b01b6dSJames Feist                         VariantToStringVisitor(), findPowerOn->second);
406f9b01b6dSJames Feist                     setReadState(powerState, readState);
407f9b01b6dSJames Feist                 }
408100c20bfSJason Ling 
409*9f3a74edSJayashree Dhanapal                 auto permitSet = getPermitSet(baseConfigMap);
4108b3f7d40SAlex Qiu                 auto& sensor = sensors[sensorName];
4118b3f7d40SAlex Qiu                 sensor = nullptr;
412100c20bfSJason Ling                 auto hwmonFile = getFullHwmonFilePath(directory.string(),
413100c20bfSJason Ling                                                       "temp1", permitSet);
414544e7dc5SBruce Mitchell                 if (pathStr.starts_with("/sys/bus/iio/devices"))
415544e7dc5SBruce Mitchell                 {
416544e7dc5SBruce Mitchell                     hwmonFile = pathStr;
417544e7dc5SBruce Mitchell                 }
418100c20bfSJason Ling                 if (hwmonFile)
419100c20bfSJason Ling                 {
420f3fd1915SYong Li                     sensor = std::make_shared<HwmonTempSensor>(
421100c20bfSJason Ling                         *hwmonFile, sensorType, objectServer, dbusConnection,
422544e7dc5SBruce Mitchell                         io, sensorName, std::move(sensorThresholds),
423*9f3a74edSJayashree Dhanapal                         thisSensorParameters, pollRate, interfacePath,
424544e7dc5SBruce Mitchell                         readState);
425f3fd1915SYong Li                     sensor->setupRead();
426*9f3a74edSJayashree Dhanapal                     hwmonName.erase(
427*9f3a74edSJayashree Dhanapal                         remove(hwmonName.begin(), hwmonName.end(), sensorName),
428*9f3a74edSJayashree Dhanapal                         hwmonName.end());
429100c20bfSJason Ling                 }
4308b3f7d40SAlex Qiu                 // Looking for keys like "Name1" for temp2_input,
4318b3f7d40SAlex Qiu                 // "Name2" for temp3_input, etc.
4328b3f7d40SAlex Qiu                 int i = 0;
4338b3f7d40SAlex Qiu                 while (true)
43437266ca9SJames Feist                 {
4358b3f7d40SAlex Qiu                     ++i;
4368b3f7d40SAlex Qiu                     auto findKey =
437*9f3a74edSJayashree Dhanapal                         baseConfigMap.find("Name" + std::to_string(i));
438*9f3a74edSJayashree Dhanapal                     if (findKey == baseConfigMap.end())
4398b3f7d40SAlex Qiu                     {
4408b3f7d40SAlex Qiu                         break;
44137266ca9SJames Feist                     }
4428b3f7d40SAlex Qiu                     std::string sensorName =
4438b3f7d40SAlex Qiu                         std::get<std::string>(findKey->second);
444100c20bfSJason Ling                     hwmonFile = getFullHwmonFilePath(
445100c20bfSJason Ling                         directory.string(), "temp" + std::to_string(i + 1),
446100c20bfSJason Ling                         permitSet);
447544e7dc5SBruce Mitchell                     if (pathStr.starts_with("/sys/bus/iio/devices"))
448544e7dc5SBruce Mitchell                     {
449544e7dc5SBruce Mitchell                         continue;
450544e7dc5SBruce Mitchell                     }
451100c20bfSJason Ling                     if (hwmonFile)
452100c20bfSJason Ling                     {
4535636d52bSMatt Spinler                         // To look up thresholds for these additional sensors,
4545636d52bSMatt Spinler                         // match on the Index property in the threshold data
4555636d52bSMatt Spinler                         // where the index comes from the sysfs file we're on,
4565636d52bSMatt Spinler                         // i.e. index = 2 for temp2_input.
4575636d52bSMatt Spinler                         int index = i + 1;
4585636d52bSMatt Spinler                         std::vector<thresholds::Threshold> thresholds;
4595636d52bSMatt Spinler 
460*9f3a74edSJayashree Dhanapal                         if (!parseThresholdsFromConfig(sensorData, thresholds,
4615636d52bSMatt Spinler                                                        nullptr, &index))
4625636d52bSMatt Spinler                         {
4635636d52bSMatt Spinler                             std::cerr << "error populating thresholds for "
4645636d52bSMatt Spinler                                       << sensorName << " index " << index
4655636d52bSMatt Spinler                                       << "\n";
4665636d52bSMatt Spinler                         }
4675636d52bSMatt Spinler 
4688b3f7d40SAlex Qiu                         auto& sensor = sensors[sensorName];
4698b3f7d40SAlex Qiu                         sensor = nullptr;
470f3fd1915SYong Li                         sensor = std::make_shared<HwmonTempSensor>(
471100c20bfSJason Ling                             *hwmonFile, sensorType, objectServer,
472100c20bfSJason Ling                             dbusConnection, io, sensorName,
473544e7dc5SBruce Mitchell                             std::move(thresholds), thisSensorParameters,
474*9f3a74edSJayashree Dhanapal                             pollRate, interfacePath, readState);
475f3fd1915SYong Li                         sensor->setupRead();
476*9f3a74edSJayashree Dhanapal                         hwmonName.erase(remove(hwmonName.begin(),
477*9f3a74edSJayashree Dhanapal                                                hwmonName.end(), sensorName),
478*9f3a74edSJayashree Dhanapal                                         hwmonName.end());
4798b3f7d40SAlex Qiu                     }
4806714a25aSJames Feist                 }
481*9f3a74edSJayashree Dhanapal                 if (hwmonName.empty())
482*9f3a74edSJayashree Dhanapal                 {
483*9f3a74edSJayashree Dhanapal                     configMap.erase(findSensorCfg);
484*9f3a74edSJayashree Dhanapal                 }
485100c20bfSJason Ling             }
4868a17c303SEd Tanous         });
487df515159SJames Feist     getter->getConfiguration(
488df515159SJames Feist         std::vector<std::string>(sensorTypes.begin(), sensorTypes.end()));
4896714a25aSJames Feist }
4906714a25aSJames Feist 
49120bf2c1cSMatt Spinler void interfaceRemoved(
49220bf2c1cSMatt Spinler     sdbusplus::message::message& message,
49320bf2c1cSMatt Spinler     boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>>&
49420bf2c1cSMatt Spinler         sensors)
49520bf2c1cSMatt Spinler {
49620bf2c1cSMatt Spinler     if (message.is_method_error())
49720bf2c1cSMatt Spinler     {
49820bf2c1cSMatt Spinler         std::cerr << "interfacesRemoved callback method error\n";
49920bf2c1cSMatt Spinler         return;
50020bf2c1cSMatt Spinler     }
50120bf2c1cSMatt Spinler 
50220bf2c1cSMatt Spinler     sdbusplus::message::object_path path;
50320bf2c1cSMatt Spinler     std::vector<std::string> interfaces;
50420bf2c1cSMatt Spinler 
50520bf2c1cSMatt Spinler     message.read(path, interfaces);
50620bf2c1cSMatt Spinler 
50720bf2c1cSMatt Spinler     // If the xyz.openbmc_project.Confguration.X interface was removed
50820bf2c1cSMatt Spinler     // for one or more sensors, delete those sensor objects.
50920bf2c1cSMatt Spinler     auto sensorIt = sensors.begin();
51020bf2c1cSMatt Spinler     while (sensorIt != sensors.end())
51120bf2c1cSMatt Spinler     {
51220bf2c1cSMatt Spinler         if ((sensorIt->second->configurationPath == path) &&
51320bf2c1cSMatt Spinler             (std::find(interfaces.begin(), interfaces.end(),
51420bf2c1cSMatt Spinler                        sensorIt->second->objectType) != interfaces.end()))
51520bf2c1cSMatt Spinler         {
51620bf2c1cSMatt Spinler             sensorIt = sensors.erase(sensorIt);
51720bf2c1cSMatt Spinler         }
51820bf2c1cSMatt Spinler         else
51920bf2c1cSMatt Spinler         {
52020bf2c1cSMatt Spinler             sensorIt++;
52120bf2c1cSMatt Spinler         }
52220bf2c1cSMatt Spinler     }
52320bf2c1cSMatt Spinler }
52420bf2c1cSMatt Spinler 
525b6c0b914SJames Feist int main()
5266714a25aSJames Feist {
5276714a25aSJames Feist     boost::asio::io_service io;
5286714a25aSJames Feist     auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
5296714a25aSJames Feist     systemBus->request_name("xyz.openbmc_project.HwmonTempSensor");
5306714a25aSJames Feist     sdbusplus::asio::object_server objectServer(systemBus);
531f3fd1915SYong Li     boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>>
5326714a25aSJames Feist         sensors;
5336714a25aSJames Feist     std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches;
5345591cf08SJames Feist     auto sensorsChanged =
5355591cf08SJames Feist         std::make_shared<boost::container::flat_set<std::string>>();
5366714a25aSJames Feist 
5376714a25aSJames Feist     io.post([&]() {
5386714a25aSJames Feist         createSensors(io, objectServer, sensors, systemBus, nullptr);
5396714a25aSJames Feist     });
5406714a25aSJames Feist 
5416714a25aSJames Feist     boost::asio::deadline_timer filterTimer(io);
5426714a25aSJames Feist     std::function<void(sdbusplus::message::message&)> eventHandler =
5436714a25aSJames Feist         [&](sdbusplus::message::message& message) {
5446714a25aSJames Feist             if (message.is_method_error())
5456714a25aSJames Feist             {
5466714a25aSJames Feist                 std::cerr << "callback method error\n";
5476714a25aSJames Feist                 return;
5486714a25aSJames Feist             }
5496714a25aSJames Feist             sensorsChanged->insert(message.get_path());
5506714a25aSJames Feist             // this implicitly cancels the timer
5516714a25aSJames Feist             filterTimer.expires_from_now(boost::posix_time::seconds(1));
5526714a25aSJames Feist 
5536714a25aSJames Feist             filterTimer.async_wait([&](const boost::system::error_code& ec) {
5546714a25aSJames Feist                 if (ec == boost::asio::error::operation_aborted)
5556714a25aSJames Feist                 {
5566714a25aSJames Feist                     /* we were canceled*/
5576714a25aSJames Feist                     return;
5586714a25aSJames Feist                 }
5598a57ec09SEd Tanous                 if (ec)
5606714a25aSJames Feist                 {
5616714a25aSJames Feist                     std::cerr << "timer error\n";
5626714a25aSJames Feist                     return;
5636714a25aSJames Feist                 }
5646714a25aSJames Feist                 createSensors(io, objectServer, sensors, systemBus,
5656714a25aSJames Feist                               sensorsChanged);
5666714a25aSJames Feist             });
5676714a25aSJames Feist         };
5686714a25aSJames Feist 
5699ced0a38SJae Hyun Yoo     for (const char* type : sensorTypes)
5706714a25aSJames Feist     {
5716714a25aSJames Feist         auto match = std::make_unique<sdbusplus::bus::match::match>(
5726714a25aSJames Feist             static_cast<sdbusplus::bus::bus&>(*systemBus),
5736714a25aSJames Feist             "type='signal',member='PropertiesChanged',path_namespace='" +
5749ced0a38SJae Hyun Yoo                 std::string(inventoryPath) + "',arg0namespace='" + type + "'",
5756714a25aSJames Feist             eventHandler);
5766714a25aSJames Feist         matches.emplace_back(std::move(match));
5776714a25aSJames Feist     }
5786714a25aSJames Feist 
5791263c3daSBruce Lee     setupManufacturingModeMatch(*systemBus);
58020bf2c1cSMatt Spinler 
58120bf2c1cSMatt Spinler     // Watch for entity-manager to remove configuration interfaces
58220bf2c1cSMatt Spinler     // so the corresponding sensors can be removed.
58320bf2c1cSMatt Spinler     auto ifaceRemovedMatch = std::make_unique<sdbusplus::bus::match::match>(
58420bf2c1cSMatt Spinler         static_cast<sdbusplus::bus::bus&>(*systemBus),
58520bf2c1cSMatt Spinler         "type='signal',member='InterfacesRemoved',arg0path='" +
58620bf2c1cSMatt Spinler             std::string(inventoryPath) + "/'",
58720bf2c1cSMatt Spinler         [&sensors](sdbusplus::message::message& msg) {
58820bf2c1cSMatt Spinler             interfaceRemoved(msg, sensors);
58920bf2c1cSMatt Spinler         });
59020bf2c1cSMatt Spinler 
59120bf2c1cSMatt Spinler     matches.emplace_back(std::move(ifaceRemovedMatch));
59220bf2c1cSMatt Spinler 
5936714a25aSJames Feist     io.run();
5946714a25aSJames Feist }
595