xref: /openbmc/phosphor-hwmon/mainloop.cpp (revision 94539af60991235bc921c848ab1aba47485265b3)
1e55ef3d8SBrad Bishop /**
2e55ef3d8SBrad Bishop  * Copyright © 2016 IBM Corporation
3e55ef3d8SBrad Bishop  *
4e55ef3d8SBrad Bishop  * Licensed under the Apache License, Version 2.0 (the "License");
5e55ef3d8SBrad Bishop  * you may not use this file except in compliance with the License.
6e55ef3d8SBrad Bishop  * You may obtain a copy of the License at
7e55ef3d8SBrad Bishop  *
8e55ef3d8SBrad Bishop  *     http://www.apache.org/licenses/LICENSE-2.0
9e55ef3d8SBrad Bishop  *
10e55ef3d8SBrad Bishop  * Unless required by applicable law or agreed to in writing, software
11e55ef3d8SBrad Bishop  * distributed under the License is distributed on an "AS IS" BASIS,
12e55ef3d8SBrad Bishop  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e55ef3d8SBrad Bishop  * See the License for the specific language governing permissions and
14e55ef3d8SBrad Bishop  * limitations under the License.
15e55ef3d8SBrad Bishop  */
16f9c83c48SMatt Spinler #include "config.h"
17043d3230SPatrick Venture 
18043d3230SPatrick Venture #include "mainloop.hpp"
19043d3230SPatrick Venture 
2009791857SPatrick Venture #include "env.hpp"
2109791857SPatrick Venture #include "fan_pwm.hpp"
2209791857SPatrick Venture #include "fan_speed.hpp"
23e55ef3d8SBrad Bishop #include "hwmon.hpp"
2475e56c67SPatrick Venture #include "hwmonio.hpp"
25043d3230SPatrick Venture #include "sensor.hpp"
2609791857SPatrick Venture #include "sensorset.hpp"
27e55ef3d8SBrad Bishop #include "sysfs.hpp"
28bf7b7b1dSMatthew Barth #include "targets.hpp"
2909791857SPatrick Venture #include "thresholds.hpp"
309bbe6026SCarol Wang #include "util.hpp"
31e55ef3d8SBrad Bishop 
32e8771fd4SPatrick Williams #include <phosphor-logging/elog-errors.hpp>
33e8771fd4SPatrick Williams #include <xyz/openbmc_project/Sensor/Device/error.hpp>
34e8771fd4SPatrick Williams 
350e749757SWilliam A. Kennington III #include <cassert>
36043d3230SPatrick Venture #include <cstdlib>
3764129937SPatrick Williams #include <format>
38043d3230SPatrick Venture #include <functional>
396d50c3e9SBrandon Kim #include <future>
40043d3230SPatrick Venture #include <iostream>
41043d3230SPatrick Venture #include <memory>
42043d3230SPatrick Venture #include <sstream>
43043d3230SPatrick Venture #include <string>
44043d3230SPatrick Venture #include <unordered_set>
451e6324faSPatrick Venture 
461e6324faSPatrick Venture using namespace phosphor::logging;
471e6324faSPatrick Venture 
48973886dbSSaqib Khan // Initialization for Warning Objects
49973886dbSSaqib Khan decltype(Thresholds<WarningObject>::setLo) Thresholds<WarningObject>::setLo =
50973886dbSSaqib Khan     &WarningObject::warningLow;
51973886dbSSaqib Khan decltype(Thresholds<WarningObject>::setHi) Thresholds<WarningObject>::setHi =
52973886dbSSaqib Khan     &WarningObject::warningHigh;
53973886dbSSaqib Khan decltype(Thresholds<WarningObject>::getLo) Thresholds<WarningObject>::getLo =
54973886dbSSaqib Khan     &WarningObject::warningLow;
55973886dbSSaqib Khan decltype(Thresholds<WarningObject>::getHi) Thresholds<WarningObject>::getHi =
56973886dbSSaqib Khan     &WarningObject::warningHigh;
573a816147SPatrick Williams decltype(Thresholds<WarningObject>::alarmLo)
583a816147SPatrick Williams     Thresholds<WarningObject>::alarmLo = &WarningObject::warningAlarmLow;
593a816147SPatrick Williams decltype(Thresholds<WarningObject>::alarmHi)
603a816147SPatrick Williams     Thresholds<WarningObject>::alarmHi = &WarningObject::warningAlarmHigh;
6173769099SDuke Du decltype(Thresholds<WarningObject>::getAlarmLow)
6273769099SDuke Du     Thresholds<WarningObject>::getAlarmLow = &WarningObject::warningAlarmLow;
6373769099SDuke Du decltype(Thresholds<WarningObject>::getAlarmHigh)
6473769099SDuke Du     Thresholds<WarningObject>::getAlarmHigh = &WarningObject::warningAlarmHigh;
6573769099SDuke Du decltype(Thresholds<WarningObject>::assertLowSignal)
6673769099SDuke Du     Thresholds<WarningObject>::assertLowSignal =
6773769099SDuke Du         &WarningObject::warningLowAlarmAsserted;
6873769099SDuke Du decltype(Thresholds<WarningObject>::assertHighSignal)
6973769099SDuke Du     Thresholds<WarningObject>::assertHighSignal =
7073769099SDuke Du         &WarningObject::warningHighAlarmAsserted;
7173769099SDuke Du decltype(Thresholds<WarningObject>::deassertLowSignal)
7273769099SDuke Du     Thresholds<WarningObject>::deassertLowSignal =
7373769099SDuke Du         &WarningObject::warningLowAlarmDeasserted;
7473769099SDuke Du decltype(Thresholds<WarningObject>::deassertHighSignal)
7573769099SDuke Du     Thresholds<WarningObject>::deassertHighSignal =
7673769099SDuke Du         &WarningObject::warningHighAlarmDeasserted;
77973886dbSSaqib Khan 
78973886dbSSaqib Khan // Initialization for Critical Objects
79973886dbSSaqib Khan decltype(Thresholds<CriticalObject>::setLo) Thresholds<CriticalObject>::setLo =
80973886dbSSaqib Khan     &CriticalObject::criticalLow;
81973886dbSSaqib Khan decltype(Thresholds<CriticalObject>::setHi) Thresholds<CriticalObject>::setHi =
82973886dbSSaqib Khan     &CriticalObject::criticalHigh;
83973886dbSSaqib Khan decltype(Thresholds<CriticalObject>::getLo) Thresholds<CriticalObject>::getLo =
84973886dbSSaqib Khan     &CriticalObject::criticalLow;
85973886dbSSaqib Khan decltype(Thresholds<CriticalObject>::getHi) Thresholds<CriticalObject>::getHi =
86973886dbSSaqib Khan     &CriticalObject::criticalHigh;
873a816147SPatrick Williams decltype(Thresholds<CriticalObject>::alarmLo)
883a816147SPatrick Williams     Thresholds<CriticalObject>::alarmLo = &CriticalObject::criticalAlarmLow;
893a816147SPatrick Williams decltype(Thresholds<CriticalObject>::alarmHi)
903a816147SPatrick Williams     Thresholds<CriticalObject>::alarmHi = &CriticalObject::criticalAlarmHigh;
9173769099SDuke Du decltype(Thresholds<CriticalObject>::getAlarmLow)
9273769099SDuke Du     Thresholds<CriticalObject>::getAlarmLow = &CriticalObject::criticalAlarmLow;
9373769099SDuke Du decltype(Thresholds<CriticalObject>::getAlarmHigh)
9473769099SDuke Du     Thresholds<CriticalObject>::getAlarmHigh =
9573769099SDuke Du         &CriticalObject::criticalAlarmHigh;
9673769099SDuke Du decltype(Thresholds<CriticalObject>::assertLowSignal)
9773769099SDuke Du     Thresholds<CriticalObject>::assertLowSignal =
9873769099SDuke Du         &CriticalObject::criticalLowAlarmAsserted;
9973769099SDuke Du decltype(Thresholds<CriticalObject>::assertHighSignal)
10073769099SDuke Du     Thresholds<CriticalObject>::assertHighSignal =
10173769099SDuke Du         &CriticalObject::criticalHighAlarmAsserted;
10273769099SDuke Du decltype(Thresholds<CriticalObject>::deassertLowSignal)
10373769099SDuke Du     Thresholds<CriticalObject>::deassertLowSignal =
10473769099SDuke Du         &CriticalObject::criticalLowAlarmDeasserted;
10573769099SDuke Du decltype(Thresholds<CriticalObject>::deassertHighSignal)
10673769099SDuke Du     Thresholds<CriticalObject>::deassertHighSignal =
10773769099SDuke Du         &CriticalObject::criticalHighAlarmDeasserted;
108973886dbSSaqib Khan 
updateSensorInterfaces(InterfaceMap & ifaces,SensorValueType value)109ecac0ae2SMatt Spinler void updateSensorInterfaces(InterfaceMap& ifaces, SensorValueType value)
110feb744a7SPatrick Venture {
111feb744a7SPatrick Venture     for (auto& iface : ifaces)
112feb744a7SPatrick Venture     {
113feb744a7SPatrick Venture         switch (iface.first)
114feb744a7SPatrick Venture         {
11594a04c4eSKun Yi                 // clang-format off
116feb744a7SPatrick Venture             case InterfaceType::VALUE:
117feb744a7SPatrick Venture             {
118feb744a7SPatrick Venture                 auto& valueIface =
119feb744a7SPatrick Venture                     std::any_cast<std::shared_ptr<ValueObject>&>(iface.second);
120feb744a7SPatrick Venture                 valueIface->value(value);
121feb744a7SPatrick Venture             }
122feb744a7SPatrick Venture             break;
12394a04c4eSKun Yi             // clang-format on
124feb744a7SPatrick Venture             case InterfaceType::WARN:
125feb744a7SPatrick Venture                 checkThresholds<WarningObject>(iface.second, value);
126feb744a7SPatrick Venture                 break;
127feb744a7SPatrick Venture             case InterfaceType::CRIT:
128feb744a7SPatrick Venture                 checkThresholds<CriticalObject>(iface.second, value);
129feb744a7SPatrick Venture                 break;
130feb744a7SPatrick Venture             default:
131feb744a7SPatrick Venture                 break;
132feb744a7SPatrick Venture         }
133feb744a7SPatrick Venture     }
134feb744a7SPatrick Venture }
135feb744a7SPatrick Venture 
getID(SensorSet::container_t::const_reference sensor)136979c806dSMatthew Barth std::string MainLoop::getID(SensorSet::container_t::const_reference sensor)
13731d214ccSMatthew Barth {
13831d214ccSMatthew Barth     std::string id;
13931d214ccSMatthew Barth 
14031d214ccSMatthew Barth     /*
14131d214ccSMatthew Barth      * Check if the value of the MODE_<item><X> env variable for the sensor
1427c424807SMatt Spinler      * is set. If it is, then read the from the <item><X>_<mode>
14331d214ccSMatthew Barth      * file. The name of the DBUS object would be the value of the env
1447c424807SMatt Spinler      * variable LABEL_<item><mode value>. If the MODE_<item><X> env variable
14531d214ccSMatthew Barth      * doesn't exist, then the name of DBUS object is the value of the env
14631d214ccSMatthew Barth      * variable LABEL_<item><X>.
1477c424807SMatt Spinler      *
1487c424807SMatt Spinler      * For example, if MODE_temp1 = "label", then code reads the temp1_label
1497c424807SMatt Spinler      * file.  If it has a 5 in it, then it will use the following entry to
1507c424807SMatt Spinler      * name the object: LABEL_temp5 = "My DBus object name".
1517c424807SMatt Spinler      *
15231d214ccSMatthew Barth      */
1537a5285deSPatrick Venture     auto mode = env::getEnv("MODE", sensor.first);
1547c424807SMatt Spinler     if (!mode.empty())
15531d214ccSMatthew Barth     {
156043d3230SPatrick Venture         id = env::getIndirectID(_hwmonRoot + '/' + _instance + '/', mode,
1577c424807SMatt Spinler                                 sensor.first);
15831d214ccSMatthew Barth 
15931d214ccSMatthew Barth         if (id.empty())
16031d214ccSMatthew Barth         {
161979c806dSMatthew Barth             return id;
16231d214ccSMatthew Barth         }
16331d214ccSMatthew Barth     }
16431d214ccSMatthew Barth 
16531d214ccSMatthew Barth     // Use the ID we looked up above if there was one,
16631d214ccSMatthew Barth     // otherwise use the standard one.
16731d214ccSMatthew Barth     id = (id.empty()) ? sensor.first.second : id;
16831d214ccSMatthew Barth 
169979c806dSMatthew Barth     return id;
170979c806dSMatthew Barth }
171979c806dSMatthew Barth 
getIdentifiers(SensorSet::container_t::const_reference sensor)172*94539af6SPatrick Williams SensorIdentifiers MainLoop::getIdentifiers(
173*94539af6SPatrick Williams     SensorSet::container_t::const_reference sensor)
174979c806dSMatthew Barth {
175979c806dSMatthew Barth     std::string id = getID(sensor);
176979c806dSMatthew Barth     std::string label;
177c9d61613SGeorge Liu     std::string accuracy;
17847fb49acSLakshmi Yadlapati     std::string priority;
179979c806dSMatthew Barth 
180979c806dSMatthew Barth     if (!id.empty())
181979c806dSMatthew Barth     {
18231d214ccSMatthew Barth         // Ignore inputs without a label.
1837a5285deSPatrick Venture         label = env::getEnv("LABEL", sensor.first.first, id);
184c9d61613SGeorge Liu         accuracy = env::getEnv("ACCURACY", sensor.first.first, id);
18547fb49acSLakshmi Yadlapati         priority = env::getEnv("PRIORITY", sensor.first.first, id);
186979c806dSMatthew Barth     }
187979c806dSMatthew Barth 
18847fb49acSLakshmi Yadlapati     return std::make_tuple(std::move(id), std::move(label), std::move(accuracy),
18947fb49acSLakshmi Yadlapati                            std::move(priority));
190979c806dSMatthew Barth }
191979c806dSMatthew Barth 
192979c806dSMatthew Barth /**
193979c806dSMatthew Barth  * Reads the environment parameters of a sensor and creates an object with
19430cab629SManojkiran Eda  * at least the `Value` interface, otherwise returns without creating the
19530cab629SManojkiran Eda  * object. If the `Value` interface is successfully created, by reading the
19630cab629SManojkiran Eda  * sensor's corresponding sysfs file's value, the additional interfaces for
19730cab629SManojkiran Eda  * the sensor are created and the InterfacesAdded signal is emitted. The
19830cab629SManojkiran Eda  * object's state data is then returned for sensor state monitoring within
19930cab629SManojkiran Eda  * the main loop.
200979c806dSMatthew Barth  */
getObject(SensorSet::container_t::const_reference sensor)201*94539af6SPatrick Williams std::optional<ObjectStateData> MainLoop::getObject(
202*94539af6SPatrick Williams     SensorSet::container_t::const_reference sensor)
203979c806dSMatthew Barth {
204979c806dSMatthew Barth     auto properties = getIdentifiers(sensor);
205979c806dSMatthew Barth     if (std::get<sensorID>(properties).empty() ||
206979c806dSMatthew Barth         std::get<sensorLabel>(properties).empty())
20731d214ccSMatthew Barth     {
208d238e232SMatthew Barth         return {};
20931d214ccSMatthew Barth     }
21031d214ccSMatthew Barth 
21109791857SPatrick Venture     hwmon::Attributes attrs;
21209791857SPatrick Venture     if (!hwmon::getAttributes(sensor.first.first, attrs))
21331d214ccSMatthew Barth     {
214d238e232SMatthew Barth         return {};
21531d214ccSMatthew Barth     }
21631d214ccSMatthew Barth 
217501ade24SKun Yi     const auto& [sensorSetKey, sensorAttrs] = sensor;
218501ade24SKun Yi     const auto& [sensorSysfsType, sensorSysfsNum] = sensorSetKey;
219501ade24SKun Yi 
2202864b063SPatrick Venture     /* Note: The sensor objects all share the same ioAccess object. */
22102e598abSPatrick Williams     auto sensorObj =
22202e598abSPatrick Williams         std::make_unique<sensor::Sensor>(sensorSetKey, _ioAccess, _devPath);
2239c43106cSMatthew Barth 
224b798527cSMatthew Barth     // Get list of return codes for removing sensors on device
225b798527cSMatthew Barth     auto devRmRCs = env::getEnv("REMOVERCS");
22631d214ccSMatthew Barth     // Add sensor removal return codes defined at the device level
227cb3daafbSMatthew Barth     sensorObj->addRemoveRCs(devRmRCs);
22831d214ccSMatthew Barth 
22931d214ccSMatthew Barth     std::string objectPath{_root};
23031d214ccSMatthew Barth     objectPath.append(1, '/');
23109791857SPatrick Venture     objectPath.append(hwmon::getNamespace(attrs));
23231d214ccSMatthew Barth     objectPath.append(1, '/');
233979c806dSMatthew Barth     objectPath.append(std::get<sensorLabel>(properties));
23431d214ccSMatthew Barth 
2356206723dSPatrick Venture     ObjectInfo info(&_bus, std::move(objectPath), InterfaceMap());
23675e56c67SPatrick Venture     RetryIO retryIO(hwmonio::retries, hwmonio::delay);
237501ade24SKun Yi     if (_rmSensors.find(sensorSetKey) != _rmSensors.end())
238d4beecfaSMatthew Barth     {
239d4beecfaSMatthew Barth         // When adding a sensor that was purposely removed,
240d4beecfaSMatthew Barth         // don't retry on errors when reading its value
241d4beecfaSMatthew Barth         std::get<size_t>(retryIO) = 0;
242d4beecfaSMatthew Barth     }
243043d3230SPatrick Venture     auto valueInterface = static_cast<std::shared_ptr<ValueObject>>(nullptr);
24431d214ccSMatthew Barth     try
24531d214ccSMatthew Barth     {
246c9d61613SGeorge Liu         // Add accuracy interface
247c9d61613SGeorge Liu         auto accuracyStr = std::get<sensorAccuracy>(properties);
248c9d61613SGeorge Liu         try
249c9d61613SGeorge Liu         {
250c9d61613SGeorge Liu             if (!accuracyStr.empty())
251c9d61613SGeorge Liu             {
252c9d61613SGeorge Liu                 auto accuracy = stod(accuracyStr);
253c9d61613SGeorge Liu                 sensorObj->addAccuracy(info, accuracy);
254c9d61613SGeorge Liu             }
255c9d61613SGeorge Liu         }
256c9d61613SGeorge Liu         catch (const std::invalid_argument&)
257e8771fd4SPatrick Williams         {}
258c9d61613SGeorge Liu 
25947fb49acSLakshmi Yadlapati         // Add priority interface
26047fb49acSLakshmi Yadlapati         auto priorityStr = std::get<sensorPriority>(properties);
26147fb49acSLakshmi Yadlapati         try
26247fb49acSLakshmi Yadlapati         {
26347fb49acSLakshmi Yadlapati             if (!priorityStr.empty())
26447fb49acSLakshmi Yadlapati             {
26547fb49acSLakshmi Yadlapati                 auto priority = std::stoul(priorityStr);
26647fb49acSLakshmi Yadlapati                 sensorObj->addPriority(info, priority);
26747fb49acSLakshmi Yadlapati             }
26847fb49acSLakshmi Yadlapati         }
26947fb49acSLakshmi Yadlapati         catch (const std::invalid_argument&)
27047fb49acSLakshmi Yadlapati         {}
27147fb49acSLakshmi Yadlapati 
272ca44c2e1SMatthew Barth         // Add status interface based on _fault file being present
2732e41b13fSMatthew Barth         sensorObj->addStatus(info);
2746d50c3e9SBrandon Kim         valueInterface = sensorObj->addValue(retryIO, info, _timedoutMap);
27531d214ccSMatthew Barth     }
27631d214ccSMatthew Barth     catch (const std::system_error& e)
27731d214ccSMatthew Barth     {
27802e598abSPatrick Williams         auto file =
27902e598abSPatrick Williams             sysfs::make_sysfs_path(_ioAccess->path(), sensorSysfsType,
28002e598abSPatrick Williams                                    sensorSysfsNum, hwmon::entry::cinput);
2810892c3fbSPatrick Venture 
28231d214ccSMatthew Barth         // Check sensorAdjusts for sensor removal RCs
283ac47309fSMatthew Barth         auto& sAdjusts = sensorObj->getAdjusts();
284ac47309fSMatthew Barth         if (sAdjusts.rmRCs.count(e.code().value()) > 0)
28531d214ccSMatthew Barth         {
28638c74e70SMatthew Barth             // Return code found in sensor return code removal list
287501ade24SKun Yi             if (_rmSensors.find(sensorSetKey) == _rmSensors.end())
28838c74e70SMatthew Barth             {
28938c74e70SMatthew Barth                 // Trace for sensor not already removed from dbus
29038c74e70SMatthew Barth                 log<level::INFO>("Sensor not added to dbus for read fail",
29138c74e70SMatthew Barth                                  entry("FILE=%s", file.c_str()),
29238c74e70SMatthew Barth                                  entry("RC=%d", e.code().value()));
293501ade24SKun Yi                 _rmSensors[std::move(sensorSetKey)] = std::move(sensorAttrs);
29438c74e70SMatthew Barth             }
295d238e232SMatthew Barth             return {};
29631d214ccSMatthew Barth         }
2970892c3fbSPatrick Venture 
298043d3230SPatrick Venture         using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::Error;
29931d214ccSMatthew Barth         report<ReadFailure>(
300043d3230SPatrick Venture             xyz::openbmc_project::Sensor::Device::ReadFailure::CALLOUT_ERRNO(
301043d3230SPatrick Venture                 e.code().value()),
302043d3230SPatrick Venture             xyz::openbmc_project::Sensor::Device::ReadFailure::
303043d3230SPatrick Venture                 CALLOUT_DEVICE_PATH(_devPath.c_str()));
30431d214ccSMatthew Barth 
30564129937SPatrick Williams         log<level::INFO>(std::format("Failing sysfs file: {} errno: {}", file,
3066a391de4SMatt Spinler                                      e.code().value())
3076a391de4SMatt Spinler                              .c_str());
30831d214ccSMatthew Barth         exit(EXIT_FAILURE);
30931d214ccSMatthew Barth     }
31031d214ccSMatthew Barth     auto sensorValue = valueInterface->value();
311ecac0ae2SMatt Spinler     int64_t scale = sensorObj->getScale();
312ecac0ae2SMatt Spinler 
313501ade24SKun Yi     addThreshold<WarningObject>(sensorSysfsType, std::get<sensorID>(properties),
314501ade24SKun Yi                                 sensorValue, info, scale);
315501ade24SKun Yi     addThreshold<CriticalObject>(sensorSysfsType,
316ee73f5bdSJames Feist                                  std::get<sensorID>(properties), sensorValue,
317ee73f5bdSJames Feist                                  info, scale);
31831d214ccSMatthew Barth 
31902e598abSPatrick Williams     auto target =
32002e598abSPatrick Williams         addTarget<hwmon::FanSpeed>(sensorSetKey, _ioAccess, _devPath, info);
32131d214ccSMatthew Barth     if (target)
32231d214ccSMatthew Barth     {
32331d214ccSMatthew Barth         target->enable();
32431d214ccSMatthew Barth     }
325501ade24SKun Yi     addTarget<hwmon::FanPwm>(sensorSetKey, _ioAccess, _devPath, info);
32631d214ccSMatthew Barth 
32731d214ccSMatthew Barth     // All the interfaces have been created.  Go ahead
32831d214ccSMatthew Barth     // and emit InterfacesAdded.
32931d214ccSMatthew Barth     valueInterface->emit_object_added();
33031d214ccSMatthew Barth 
3319c43106cSMatthew Barth     // Save sensor object specifications
332501ade24SKun Yi     _sensorObjects[sensorSetKey] = std::move(sensorObj);
3339c43106cSMatthew Barth 
334d238e232SMatthew Barth     return std::make_pair(std::move(std::get<sensorLabel>(properties)),
33531d214ccSMatthew Barth                           std::move(info));
33631d214ccSMatthew Barth }
33731d214ccSMatthew Barth 
MainLoop(sdbusplus::bus_t && bus,const std::string & param,const std::string & path,const std::string & devPath,const char * prefix,const char * root,const std::string & instanceId,const hwmonio::HwmonIOInterface * ioIntf)338ad6043f6SPatrick Williams MainLoop::MainLoop(sdbusplus::bus_t&& bus, const std::string& param,
339043d3230SPatrick Venture                    const std::string& path, const std::string& devPath,
34016805a6aSPatrick Venture                    const char* prefix, const char* root,
341d46d0818SAnton D. Kachalov                    const std::string& instanceId,
34216805a6aSPatrick Venture                    const hwmonio::HwmonIOInterface* ioIntf) :
34302e598abSPatrick Williams     _bus(std::move(bus)), _manager(_bus, root), _pathParam(param), _hwmonRoot(),
34402e598abSPatrick Williams     _instance(), _devPath(devPath), _prefix(prefix), _root(root), _state(),
345d46d0818SAnton D. Kachalov     _instanceId(instanceId), _ioAccess(ioIntf),
346d46d0818SAnton D. Kachalov     _event(sdeventplus::Event::get_default()),
34752b40613SPatrick Venture     _timer(_event, std::bind(&MainLoop::read, this))
348d499ca64SBrad Bishop {
34973a50c7fSPatrick Venture     // Strip off any trailing slashes.
350b8740fc7SBrad Bishop     std::string p = path;
351b8740fc7SBrad Bishop     while (!p.empty() && p.back() == '/')
3529c7b6e06SBrad Bishop     {
353b8740fc7SBrad Bishop         p.pop_back();
3549c7b6e06SBrad Bishop     }
355b8740fc7SBrad Bishop 
35673a50c7fSPatrick Venture     // Given the furthest right /, set instance to
35773a50c7fSPatrick Venture     // the basename, and hwmonRoot to the leading path.
358b8740fc7SBrad Bishop     auto n = p.rfind('/');
359b8740fc7SBrad Bishop     if (n != std::string::npos)
360b8740fc7SBrad Bishop     {
361b8740fc7SBrad Bishop         _instance.assign(p.substr(n + 1));
362b8740fc7SBrad Bishop         _hwmonRoot.assign(p.substr(0, n));
363b8740fc7SBrad Bishop     }
364b8740fc7SBrad Bishop 
365b8740fc7SBrad Bishop     assert(!_instance.empty());
366b8740fc7SBrad Bishop     assert(!_hwmonRoot.empty());
367d499ca64SBrad Bishop }
368d499ca64SBrad Bishop 
shutdown()369d499ca64SBrad Bishop void MainLoop::shutdown() noexcept
370d499ca64SBrad Bishop {
37152b40613SPatrick Venture     _event.exit(0);
372d499ca64SBrad Bishop }
373d499ca64SBrad Bishop 
run()374d499ca64SBrad Bishop void MainLoop::run()
375e55ef3d8SBrad Bishop {
3762a51a9c9SDeepak Kodihalli     init();
3772a51a9c9SDeepak Kodihalli 
378043d3230SPatrick Venture     std::function<void()> callback(std::bind(&MainLoop::read, this));
3792a51a9c9SDeepak Kodihalli     try
3802a51a9c9SDeepak Kodihalli     {
38152b40613SPatrick Venture         _timer.restart(std::chrono::microseconds(_interval));
3822a51a9c9SDeepak Kodihalli 
3832a51a9c9SDeepak Kodihalli         // TODO: Issue#6 - Optionally look at polling interval sysfs entry.
3842a51a9c9SDeepak Kodihalli 
3852a51a9c9SDeepak Kodihalli         // TODO: Issue#7 - Should probably periodically check the SensorSet
3862a51a9c9SDeepak Kodihalli         //       for new entries.
3872a51a9c9SDeepak Kodihalli 
38852b40613SPatrick Venture         _bus.attach_event(_event.get(), SD_EVENT_PRIORITY_IMPORTANT);
38952b40613SPatrick Venture         _event.loop();
3902a51a9c9SDeepak Kodihalli     }
3910fe4cb34SWilliam A. Kennington III     catch (const std::exception& e)
3922a51a9c9SDeepak Kodihalli     {
3932a51a9c9SDeepak Kodihalli         log<level::ERR>("Error in sysfs polling loop",
3942a51a9c9SDeepak Kodihalli                         entry("ERROR=%s", e.what()));
3952a51a9c9SDeepak Kodihalli         throw;
3962a51a9c9SDeepak Kodihalli     }
3972a51a9c9SDeepak Kodihalli }
3982a51a9c9SDeepak Kodihalli 
init()3992a51a9c9SDeepak Kodihalli void MainLoop::init()
4002a51a9c9SDeepak Kodihalli {
401e55ef3d8SBrad Bishop     // Check sysfs for available sensors.
4024db64422SBrad Bishop     auto sensors = std::make_unique<SensorSet>(_hwmonRoot + '/' + _instance);
403e55ef3d8SBrad Bishop 
404db7ecb6aSPatrick Venture     for (const auto& i : *sensors)
40575b4ab8dSBrad Bishop     {
406d238e232SMatthew Barth         auto object = getObject(i);
407d238e232SMatthew Barth         if (object)
408d238e232SMatthew Barth         {
409d238e232SMatthew Barth             // Construct the SensorSet value
410d238e232SMatthew Barth             // std::tuple<SensorSet::mapped_type,
411d238e232SMatthew Barth             //            std::string(Sensor Label),
412d238e232SMatthew Barth             //            ObjectInfo>
41302e598abSPatrick Williams             auto value =
41402e598abSPatrick Williams                 std::make_tuple(std::move(i.second), std::move((*object).first),
415d238e232SMatthew Barth                                 std::move((*object).second));
416d238e232SMatthew Barth 
41752b40613SPatrick Venture             _state[std::move(i.first)] = std::move(value);
418d238e232SMatthew Barth         }
4199bbe6026SCarol Wang 
4209bbe6026SCarol Wang         // Initialize _averageMap of sensor. e.g. <<power, 1>, <0, 0>>
4219bbe6026SCarol Wang         if ((i.first.first == hwmon::type::power) &&
4229bbe6026SCarol Wang             (phosphor::utility::isAverageEnvSet(i.first)))
4239bbe6026SCarol Wang         {
4249bbe6026SCarol Wang             _average.setAverageValue(i.first, std::make_pair(0, 0));
4259bbe6026SCarol Wang         }
42675b4ab8dSBrad Bishop     }
42775b4ab8dSBrad Bishop 
42862503a4eSPatrick Venture     /* If there are no sensors specified by labels, exit. */
42952b40613SPatrick Venture     if (0 == _state.size())
43062503a4eSPatrick Venture     {
4312a51a9c9SDeepak Kodihalli         exit(0);
43262503a4eSPatrick Venture     }
43362503a4eSPatrick Venture 
4349c7b6e06SBrad Bishop     {
435c897d8bbSPatrick Venture         std::stringstream ss;
436d46d0818SAnton D. Kachalov         std::string id = _instanceId;
437d46d0818SAnton D. Kachalov         if (id.empty())
438d46d0818SAnton D. Kachalov         {
439d46d0818SAnton D. Kachalov             id =
440d46d0818SAnton D. Kachalov                 std::to_string(std::hash<std::string>{}(_devPath + _pathParam));
441d46d0818SAnton D. Kachalov         }
442d46d0818SAnton D. Kachalov         ss << _prefix << "-" << id << ".Hwmon1";
443c897d8bbSPatrick Venture 
444c897d8bbSPatrick Venture         _bus.request_name(ss.str().c_str());
4459c7b6e06SBrad Bishop     }
4469c7b6e06SBrad Bishop 
447ab10f164SPatrick Venture     {
448a24c8808SPatrick Venture         auto interval = env::getEnv("INTERVAL");
449a24c8808SPatrick Venture         if (!interval.empty())
450ab10f164SPatrick Venture         {
45150cf1c57SPatrick Venture             _interval = std::strtoull(interval.c_str(), NULL, 10);
452ab10f164SPatrick Venture         }
453ab10f164SPatrick Venture     }
4542a51a9c9SDeepak Kodihalli }
455ab10f164SPatrick Venture 
read()4562a51a9c9SDeepak Kodihalli void MainLoop::read()
4572a51a9c9SDeepak Kodihalli {
458e55ef3d8SBrad Bishop     // TODO: Issue#3 - Need to make calls to the dbus sensor cache here to
459e55ef3d8SBrad Bishop     //       ensure the objects all exist?
460e55ef3d8SBrad Bishop 
461e55ef3d8SBrad Bishop     // Iterate through all the sensors.
462501ade24SKun Yi     for (auto& [sensorSetKey, sensorStateTuple] : _state)
463e55ef3d8SBrad Bishop     {
464501ade24SKun Yi         const auto& [sensorSysfsType, sensorSysfsNum] = sensorSetKey;
465501ade24SKun Yi         auto& [attrs, unused, objInfo] = sensorStateTuple;
466501ade24SKun Yi 
467553552c4SKun Yi         if (attrs.find(hwmon::entry::input) == attrs.end())
468e55ef3d8SBrad Bishop         {
469553552c4SKun Yi             continue;
470553552c4SKun Yi         }
471501ade24SKun Yi 
472e55ef3d8SBrad Bishop         // Read value from sensor.
4739bbe6026SCarol Wang         std::string input = hwmon::entry::input;
4749bbe6026SCarol Wang         if (sensorSysfsType == hwmon::type::pwm)
475043d3230SPatrick Venture         {
4769331ab78SPatrick Venture             input = "";
4779331ab78SPatrick Venture         }
4789bbe6026SCarol Wang         // If type is power and AVERAGE_power* is true in env, use average
4799bbe6026SCarol Wang         // instead of input
4809bbe6026SCarol Wang         else if ((sensorSysfsType == hwmon::type::power) &&
4819bbe6026SCarol Wang                  (phosphor::utility::isAverageEnvSet(sensorSetKey)))
4829bbe6026SCarol Wang         {
4839bbe6026SCarol Wang             input = hwmon::entry::average;
4849bbe6026SCarol Wang         }
4859331ab78SPatrick Venture 
486ecac0ae2SMatt Spinler         SensorValueType value;
4876206723dSPatrick Venture         auto& obj = std::get<InterfaceMap>(objInfo);
488501ade24SKun Yi         std::unique_ptr<sensor::Sensor>& sensor = _sensorObjects[sensorSetKey];
48927c4a394SMatthew Barth 
49079205b2cSBrandon Kim         auto& statusIface = std::any_cast<std::shared_ptr<StatusObject>&>(
49186dcac85SBrandon Kim             obj[InterfaceType::STATUS]);
49286dcac85SBrandon Kim         // As long as addStatus is called before addValue, statusIface
49386dcac85SBrandon Kim         // should never be nullptr.
49486dcac85SBrandon Kim         assert(statusIface);
49586dcac85SBrandon Kim 
49679205b2cSBrandon Kim         try
49779205b2cSBrandon Kim         {
49886dcac85SBrandon Kim             if (sensor->hasFaultFile())
49927c4a394SMatthew Barth             {
500501ade24SKun Yi                 auto fault = _ioAccess->read(sensorSysfsType, sensorSysfsNum,
501553552c4SKun Yi                                              hwmon::entry::fault,
502043d3230SPatrick Venture                                              hwmonio::retries, hwmonio::delay);
50386dcac85SBrandon Kim                 // Skip reading from a sensor with a valid fault file
50486dcac85SBrandon Kim                 // and set the functional property accordingly
505bfcaf3d8SMatthew Barth                 if (!statusIface->functional((fault == 0) ? true : false))
50627c4a394SMatthew Barth                 {
50727c4a394SMatthew Barth                     continue;
50827c4a394SMatthew Barth                 }
50927c4a394SMatthew Barth             }
51027c4a394SMatthew Barth 
511db76d49cSBrandon Kim             {
512db76d49cSBrandon Kim                 // RAII object for GPIO unlock / lock
5132227bd52SWilliam A. Kennington III                 auto locker = sensor::gpioUnlock(sensor->getGpio());
514754d38cfSBrad Bishop 
5156d50c3e9SBrandon Kim                 // For sensors with attribute ASYNC_READ_TIMEOUT,
5166d50c3e9SBrandon Kim                 // spawn a thread with timeout
51702e598abSPatrick Williams                 auto asyncReadTimeout =
51802e598abSPatrick Williams                     env::getEnv("ASYNC_READ_TIMEOUT", sensorSetKey);
5196d50c3e9SBrandon Kim                 if (!asyncReadTimeout.empty())
5206d50c3e9SBrandon Kim                 {
5216d50c3e9SBrandon Kim                     std::chrono::milliseconds asyncTimeout{
5226d50c3e9SBrandon Kim                         std::stoi(asyncReadTimeout)};
5236d50c3e9SBrandon Kim                     value = sensor::asyncRead(
5246d50c3e9SBrandon Kim                         sensorSetKey, _ioAccess, asyncTimeout, _timedoutMap,
5256d50c3e9SBrandon Kim                         sensorSysfsType, sensorSysfsNum, input,
5266d50c3e9SBrandon Kim                         hwmonio::retries, hwmonio::delay);
5276d50c3e9SBrandon Kim                 }
5286d50c3e9SBrandon Kim                 else
5296d50c3e9SBrandon Kim                 {
53086dcac85SBrandon Kim                     // Retry for up to a second if device is busy
53186dcac85SBrandon Kim                     // or has a transient error.
53202e598abSPatrick Williams                     value =
53302e598abSPatrick Williams                         _ioAccess->read(sensorSysfsType, sensorSysfsNum, input,
53402e598abSPatrick Williams                                         hwmonio::retries, hwmonio::delay);
5356d50c3e9SBrandon Kim                 }
5366d50c3e9SBrandon Kim 
53779205b2cSBrandon Kim                 // Set functional property to true if we could read sensor
53879205b2cSBrandon Kim                 statusIface->functional(true);
5391e6324faSPatrick Venture 
540b28f432aSPatrick Venture                 value = sensor->adjustValue(value);
5419bbe6026SCarol Wang 
5429bbe6026SCarol Wang                 if (input == hwmon::entry::average)
5439bbe6026SCarol Wang                 {
5449bbe6026SCarol Wang                     // Calculate the values of averageMap based on current
5459bbe6026SCarol Wang                     // average value, current average_interval value, previous
5469bbe6026SCarol Wang                     // average value, previous average_interval value
5479bbe6026SCarol Wang                     int64_t interval =
5489bbe6026SCarol Wang                         _ioAccess->read(sensorSysfsType, sensorSysfsNum,
5499bbe6026SCarol Wang                                         hwmon::entry::caverage_interval,
5509bbe6026SCarol Wang                                         hwmonio::retries, hwmonio::delay);
5519bbe6026SCarol Wang                     auto ret = _average.getAverageValue(sensorSetKey);
5529bbe6026SCarol Wang                     assert(ret);
5539bbe6026SCarol Wang 
5549bbe6026SCarol Wang                     const auto& [preAverage, preInterval] = *ret;
5559bbe6026SCarol Wang 
5569bbe6026SCarol Wang                     auto calValue = Average::calcAverage(
5579bbe6026SCarol Wang                         preAverage, preInterval, value, interval);
5589bbe6026SCarol Wang                     if (calValue)
5599bbe6026SCarol Wang                     {
5609bbe6026SCarol Wang                         // Update previous values in averageMap before the
5619bbe6026SCarol Wang                         // variable value is changed next
5629bbe6026SCarol Wang                         _average.setAverageValue(
5639bbe6026SCarol Wang                             sensorSetKey, std::make_pair(value, interval));
5649bbe6026SCarol Wang                         // Update value to be calculated average
5659bbe6026SCarol Wang                         value = calValue.value();
5669bbe6026SCarol Wang                     }
5679bbe6026SCarol Wang                     else
5689bbe6026SCarol Wang                     {
5699bbe6026SCarol Wang                         // the value of
5709bbe6026SCarol Wang                         // power*_average_interval is not changed yet, use the
5719bbe6026SCarol Wang                         // previous calculated average instead. So skip dbus
5729bbe6026SCarol Wang                         // update.
5739bbe6026SCarol Wang                         continue;
5749bbe6026SCarol Wang                     }
5759bbe6026SCarol Wang                 }
576db76d49cSBrandon Kim             }
577c923ce9dSChiabing Lee 
578feb744a7SPatrick Venture             updateSensorInterfaces(obj, value);
579e55ef3d8SBrad Bishop         }
580751043e9SBrad Bishop         catch (const std::system_error& e)
5811e6324faSPatrick Venture         {
582d8cacfd4SMatt Spinler #if UPDATE_FUNCTIONAL_ON_FAIL
58379205b2cSBrandon Kim             // If UPDATE_FUNCTIONAL_ON_FAIL is defined and an exception was
58479205b2cSBrandon Kim             // thrown, set the functional property to false.
58579205b2cSBrandon Kim             // We cannot set this with the 'continue' in the lower block
58679205b2cSBrandon Kim             // as the code may exit before reaching it.
58779205b2cSBrandon Kim             statusIface->functional(false);
58879205b2cSBrandon Kim #endif
5899bbe6026SCarol Wang             auto file = sysfs::make_sysfs_path(
5909bbe6026SCarol Wang                 _ioAccess->path(), sensorSysfsType, sensorSysfsNum, input);
5910892c3fbSPatrick Venture 
5928772ce3aSMatthew Barth             // Check sensorAdjusts for sensor removal RCs
593501ade24SKun Yi             auto& sAdjusts = _sensorObjects[sensorSetKey]->getAdjusts();
594ac47309fSMatthew Barth             if (sAdjusts.rmRCs.count(e.code().value()) > 0)
5958772ce3aSMatthew Barth             {
59638c74e70SMatthew Barth                 // Return code found in sensor return code removal list
597501ade24SKun Yi                 if (_rmSensors.find(sensorSetKey) == _rmSensors.end())
59838c74e70SMatthew Barth                 {
59938c74e70SMatthew Barth                     // Trace for sensor not already removed from dbus
600553552c4SKun Yi                     log<level::INFO>("Remove sensor from dbus for read fail",
60138c74e70SMatthew Barth                                      entry("FILE=%s", file.c_str()),
60238c74e70SMatthew Barth                                      entry("RC=%d", e.code().value()));
6038772ce3aSMatthew Barth                     // Mark this sensor to be removed from dbus
604501ade24SKun Yi                     _rmSensors[sensorSetKey] = attrs;
60538c74e70SMatthew Barth                 }
6068772ce3aSMatthew Barth                 continue;
6078772ce3aSMatthew Barth             }
608d8cacfd4SMatt Spinler #if UPDATE_FUNCTIONAL_ON_FAIL
60979205b2cSBrandon Kim             // Do not exit with failure if UPDATE_FUNCTIONAL_ON_FAIL is set
61079205b2cSBrandon Kim             continue;
61179205b2cSBrandon Kim #endif
612553552c4SKun Yi             using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::
613553552c4SKun Yi                 Error;
614751043e9SBrad Bishop             report<ReadFailure>(
615043d3230SPatrick Venture                 xyz::openbmc_project::Sensor::Device::ReadFailure::
616043d3230SPatrick Venture                     CALLOUT_ERRNO(e.code().value()),
617043d3230SPatrick Venture                 xyz::openbmc_project::Sensor::Device::ReadFailure::
618043d3230SPatrick Venture                     CALLOUT_DEVICE_PATH(_devPath.c_str()));
6199b65f76dSMatt Spinler 
62064129937SPatrick Williams             log<level::INFO>(std::format("Failing sysfs file: {} errno: {}",
6216a391de4SMatt Spinler                                          file, e.code().value())
6226a391de4SMatt Spinler                                  .c_str());
6239b65f76dSMatt Spinler 
624f9c83c48SMatt Spinler             exit(EXIT_FAILURE);
6251e6324faSPatrick Venture         }
6261e6324faSPatrick Venture     }
6271e6324faSPatrick Venture 
6280cd4f69fSPatrick Venture     removeSensors();
6290cd4f69fSPatrick Venture 
6300cd4f69fSPatrick Venture     addDroppedSensors();
6310cd4f69fSPatrick Venture }
6320cd4f69fSPatrick Venture 
removeSensors()6330cd4f69fSPatrick Venture void MainLoop::removeSensors()
6340cd4f69fSPatrick Venture {
6358772ce3aSMatthew Barth     // Remove any sensors marked for removal
63652b40613SPatrick Venture     for (const auto& i : _rmSensors)
6371e6324faSPatrick Venture     {
638d0ce7925SMatthew Barth         // Remove sensor object from dbus using emit_object_removed()
639d0ce7925SMatthew Barth         auto& objInfo = std::get<ObjectInfo>(_state[i.first]);
640d0ce7925SMatthew Barth         auto& objPath = std::get<std::string>(objInfo);
6410cd4f69fSPatrick Venture 
642d0ce7925SMatthew Barth         _bus.emit_object_removed(objPath.c_str());
6430cd4f69fSPatrick Venture 
644d0ce7925SMatthew Barth         // Erase sensor object info
64552b40613SPatrick Venture         _state.erase(i.first);
646e55ef3d8SBrad Bishop     }
6470cd4f69fSPatrick Venture }
64831d214ccSMatthew Barth 
addDroppedSensors()6490cd4f69fSPatrick Venture void MainLoop::addDroppedSensors()
6500cd4f69fSPatrick Venture {
65131d214ccSMatthew Barth     // Attempt to add any sensors that were removed
65252b40613SPatrick Venture     auto it = _rmSensors.begin();
65352b40613SPatrick Venture     while (it != _rmSensors.end())
65431d214ccSMatthew Barth     {
65552b40613SPatrick Venture         if (_state.find(it->first) == _state.end())
65631d214ccSMatthew Barth         {
65731d214ccSMatthew Barth             SensorSet::container_t::value_type ssValueType =
65831d214ccSMatthew Barth                 std::make_pair(it->first, it->second);
6590cd4f69fSPatrick Venture 
660d238e232SMatthew Barth             auto object = getObject(ssValueType);
661d238e232SMatthew Barth             if (object)
66231d214ccSMatthew Barth             {
663d238e232SMatthew Barth                 // Construct the SensorSet value
664d238e232SMatthew Barth                 // std::tuple<SensorSet::mapped_type,
665d238e232SMatthew Barth                 //            std::string(Sensor Label),
666d238e232SMatthew Barth                 //            ObjectInfo>
667d238e232SMatthew Barth                 auto value = std::make_tuple(std::move(ssValueType.second),
668d238e232SMatthew Barth                                              std::move((*object).first),
669d238e232SMatthew Barth                                              std::move((*object).second));
670d238e232SMatthew Barth 
67152b40613SPatrick Venture                 _state[std::move(ssValueType.first)] = std::move(value);
672d238e232SMatthew Barth 
6739bbe6026SCarol Wang                 std::string input = hwmon::entry::input;
6749bbe6026SCarol Wang                 // If type is power and AVERAGE_power* is true in env, use
6759bbe6026SCarol Wang                 // average instead of input
6769bbe6026SCarol Wang                 if ((it->first.first == hwmon::type::power) &&
6779bbe6026SCarol Wang                     (phosphor::utility::isAverageEnvSet(it->first)))
6789bbe6026SCarol Wang                 {
6799bbe6026SCarol Wang                     input = hwmon::entry::average;
6809bbe6026SCarol Wang                 }
68131d214ccSMatthew Barth                 // Sensor object added, erase entry from removal list
68202e598abSPatrick Williams                 auto file =
68302e598abSPatrick Williams                     sysfs::make_sysfs_path(_ioAccess->path(), it->first.first,
6849bbe6026SCarol Wang                                            it->first.second, input);
6850cd4f69fSPatrick Venture 
686043d3230SPatrick Venture                 log<level::INFO>("Added sensor to dbus after successful read",
68738c74e70SMatthew Barth                                  entry("FILE=%s", file.c_str()));
6880cd4f69fSPatrick Venture 
68952b40613SPatrick Venture                 it = _rmSensors.erase(it);
69031d214ccSMatthew Barth             }
69131d214ccSMatthew Barth             else
69231d214ccSMatthew Barth             {
69331d214ccSMatthew Barth                 ++it;
69431d214ccSMatthew Barth             }
69531d214ccSMatthew Barth         }
69631d214ccSMatthew Barth         else
69731d214ccSMatthew Barth         {
69831d214ccSMatthew Barth             // Sanity check to remove sensors that were re-added
69952b40613SPatrick Venture             it = _rmSensors.erase(it);
70031d214ccSMatthew Barth         }
70131d214ccSMatthew Barth     }
702e55ef3d8SBrad Bishop }
703