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