blob: bd334a0cf4dc5e54a6d210e341959c8d409f4efc [file] [log] [blame]
Brad Bishope55ef3d2016-12-19 09:12:40 -05001/**
2 * Copyright © 2016 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matt Spinlerf9c83c42017-08-10 08:51:45 -050016#include "config.h"
Patrick Venture043d3232018-08-31 10:10:53 -070017
18#include "mainloop.hpp"
19
Patrick Venture09791852018-04-17 17:40:00 -070020#include "env.hpp"
21#include "fan_pwm.hpp"
22#include "fan_speed.hpp"
Brad Bishope55ef3d2016-12-19 09:12:40 -050023#include "hwmon.hpp"
Patrick Venture75e56c62018-04-20 18:10:15 -070024#include "hwmonio.hpp"
Patrick Venture043d3232018-08-31 10:10:53 -070025#include "sensor.hpp"
Patrick Venture09791852018-04-17 17:40:00 -070026#include "sensorset.hpp"
Brad Bishope55ef3d2016-12-19 09:12:40 -050027#include "sysfs.hpp"
Matthew Barthbf7b7b12017-03-07 15:46:59 -060028#include "targets.hpp"
Patrick Venture09791852018-04-17 17:40:00 -070029#include "thresholds.hpp"
Carol Wang9bbe6022019-08-01 17:31:30 +080030#include "util.hpp"
Brad Bishope55ef3d2016-12-19 09:12:40 -050031
William A. Kennington III0e749752018-11-06 15:25:41 -080032#include <cassert>
Patrick Venture043d3232018-08-31 10:10:53 -070033#include <cstdlib>
34#include <functional>
35#include <iostream>
36#include <memory>
37#include <phosphor-logging/elog-errors.hpp>
38#include <sstream>
39#include <string>
40#include <unordered_set>
Patrick Venture1e6324f2017-06-01 14:07:05 -070041#include <xyz/openbmc_project/Sensor/Device/error.hpp>
42
43using namespace phosphor::logging;
44
Saqib Khan973886d2017-03-15 14:01:16 -050045// Initialization for Warning Objects
46decltype(Thresholds<WarningObject>::setLo) Thresholds<WarningObject>::setLo =
47 &WarningObject::warningLow;
48decltype(Thresholds<WarningObject>::setHi) Thresholds<WarningObject>::setHi =
49 &WarningObject::warningHigh;
50decltype(Thresholds<WarningObject>::getLo) Thresholds<WarningObject>::getLo =
51 &WarningObject::warningLow;
52decltype(Thresholds<WarningObject>::getHi) Thresholds<WarningObject>::getHi =
53 &WarningObject::warningHigh;
Patrick Venture043d3232018-08-31 10:10:53 -070054decltype(
55 Thresholds<WarningObject>::alarmLo) Thresholds<WarningObject>::alarmLo =
Saqib Khan973886d2017-03-15 14:01:16 -050056 &WarningObject::warningAlarmLow;
Patrick Venture043d3232018-08-31 10:10:53 -070057decltype(
58 Thresholds<WarningObject>::alarmHi) Thresholds<WarningObject>::alarmHi =
Saqib Khan973886d2017-03-15 14:01:16 -050059 &WarningObject::warningAlarmHigh;
60
61// Initialization for Critical Objects
62decltype(Thresholds<CriticalObject>::setLo) Thresholds<CriticalObject>::setLo =
63 &CriticalObject::criticalLow;
64decltype(Thresholds<CriticalObject>::setHi) Thresholds<CriticalObject>::setHi =
65 &CriticalObject::criticalHigh;
66decltype(Thresholds<CriticalObject>::getLo) Thresholds<CriticalObject>::getLo =
67 &CriticalObject::criticalLow;
68decltype(Thresholds<CriticalObject>::getHi) Thresholds<CriticalObject>::getHi =
69 &CriticalObject::criticalHigh;
Patrick Venture043d3232018-08-31 10:10:53 -070070decltype(
71 Thresholds<CriticalObject>::alarmLo) Thresholds<CriticalObject>::alarmLo =
Saqib Khan973886d2017-03-15 14:01:16 -050072 &CriticalObject::criticalAlarmLow;
Patrick Venture043d3232018-08-31 10:10:53 -070073decltype(
74 Thresholds<CriticalObject>::alarmHi) Thresholds<CriticalObject>::alarmHi =
Saqib Khan973886d2017-03-15 14:01:16 -050075 &CriticalObject::criticalAlarmHigh;
76
Patrick Venturefeb744a2019-06-26 19:07:48 -070077void updateSensorInterfaces(InterfaceMap& ifaces, int64_t value)
78{
79 for (auto& iface : ifaces)
80 {
81 switch (iface.first)
82 {
Kun Yi94a04c42019-08-21 09:43:20 -070083 // clang-format off
Patrick Venturefeb744a2019-06-26 19:07:48 -070084 case InterfaceType::VALUE:
85 {
86 auto& valueIface =
87 std::any_cast<std::shared_ptr<ValueObject>&>(iface.second);
88 valueIface->value(value);
89 }
90 break;
Kun Yi94a04c42019-08-21 09:43:20 -070091 // clang-format on
Patrick Venturefeb744a2019-06-26 19:07:48 -070092 case InterfaceType::WARN:
93 checkThresholds<WarningObject>(iface.second, value);
94 break;
95 case InterfaceType::CRIT:
96 checkThresholds<CriticalObject>(iface.second, value);
97 break;
98 default:
99 break;
100 }
101 }
102}
103
Matthew Barth979c8062018-04-17 11:37:15 -0500104std::string MainLoop::getID(SensorSet::container_t::const_reference sensor)
Matthew Barth31d214c2018-03-26 09:54:27 -0500105{
Matthew Barth31d214c2018-03-26 09:54:27 -0500106 std::string id;
107
108 /*
109 * Check if the value of the MODE_<item><X> env variable for the sensor
Matt Spinler7c424802018-05-04 10:52:40 -0500110 * is set. If it is, then read the from the <item><X>_<mode>
Matthew Barth31d214c2018-03-26 09:54:27 -0500111 * file. The name of the DBUS object would be the value of the env
Matt Spinler7c424802018-05-04 10:52:40 -0500112 * variable LABEL_<item><mode value>. If the MODE_<item><X> env variable
Matthew Barth31d214c2018-03-26 09:54:27 -0500113 * doesn't exist, then the name of DBUS object is the value of the env
114 * variable LABEL_<item><X>.
Matt Spinler7c424802018-05-04 10:52:40 -0500115 *
116 * For example, if MODE_temp1 = "label", then code reads the temp1_label
117 * file. If it has a 5 in it, then it will use the following entry to
118 * name the object: LABEL_temp5 = "My DBus object name".
119 *
Matthew Barth31d214c2018-03-26 09:54:27 -0500120 */
Patrick Venture7a5285d2018-04-17 19:15:05 -0700121 auto mode = env::getEnv("MODE", sensor.first);
Matt Spinler7c424802018-05-04 10:52:40 -0500122 if (!mode.empty())
Matthew Barth31d214c2018-03-26 09:54:27 -0500123 {
Patrick Venture043d3232018-08-31 10:10:53 -0700124 id = env::getIndirectID(_hwmonRoot + '/' + _instance + '/', mode,
125 sensor.first);
Matthew Barth31d214c2018-03-26 09:54:27 -0500126
127 if (id.empty())
128 {
Matthew Barth979c8062018-04-17 11:37:15 -0500129 return id;
Matthew Barth31d214c2018-03-26 09:54:27 -0500130 }
131 }
132
133 // Use the ID we looked up above if there was one,
134 // otherwise use the standard one.
135 id = (id.empty()) ? sensor.first.second : id;
136
Matthew Barth979c8062018-04-17 11:37:15 -0500137 return id;
138}
139
Patrick Venture043d3232018-08-31 10:10:53 -0700140SensorIdentifiers
141 MainLoop::getIdentifiers(SensorSet::container_t::const_reference sensor)
Matthew Barth979c8062018-04-17 11:37:15 -0500142{
143 std::string id = getID(sensor);
144 std::string label;
145
146 if (!id.empty())
147 {
148 // Ignore inputs without a label.
149 label = env::getEnv("LABEL", sensor.first.first, id);
150 }
151
Patrick Venture043d3232018-08-31 10:10:53 -0700152 return std::make_tuple(std::move(id), std::move(label));
Matthew Barth979c8062018-04-17 11:37:15 -0500153}
154
155/**
156 * Reads the environment parameters of a sensor and creates an object with
157 * atleast the `Value` interface, otherwise returns without creating the object.
158 * If the `Value` interface is successfully created, by reading the sensor's
159 * corresponding sysfs file's value, the additional interfaces for the sensor
Matthew Barthd238e232018-04-17 12:01:50 -0500160 * are created and the InterfacesAdded signal is emitted. The object's state
161 * data is then returned for sensor state monitoring within the main loop.
Matthew Barth979c8062018-04-17 11:37:15 -0500162 */
William A. Kennington III4cbdfef2018-10-18 19:19:51 -0700163std::optional<ObjectStateData>
Patrick Venture043d3232018-08-31 10:10:53 -0700164 MainLoop::getObject(SensorSet::container_t::const_reference sensor)
Matthew Barth979c8062018-04-17 11:37:15 -0500165{
166 auto properties = getIdentifiers(sensor);
167 if (std::get<sensorID>(properties).empty() ||
168 std::get<sensorLabel>(properties).empty())
Matthew Barth31d214c2018-03-26 09:54:27 -0500169 {
Matthew Barthd238e232018-04-17 12:01:50 -0500170 return {};
Matthew Barth31d214c2018-03-26 09:54:27 -0500171 }
172
Patrick Venture09791852018-04-17 17:40:00 -0700173 hwmon::Attributes attrs;
174 if (!hwmon::getAttributes(sensor.first.first, attrs))
Matthew Barth31d214c2018-03-26 09:54:27 -0500175 {
Matthew Barthd238e232018-04-17 12:01:50 -0500176 return {};
Matthew Barth31d214c2018-03-26 09:54:27 -0500177 }
178
Kun Yi501ade22019-07-15 15:00:32 -0700179 const auto& [sensorSetKey, sensorAttrs] = sensor;
180 const auto& [sensorSysfsType, sensorSysfsNum] = sensorSetKey;
181
Patrick Venture2864b062018-12-19 08:13:41 -0800182 /* Note: The sensor objects all share the same ioAccess object. */
Patrick Venture043d3232018-08-31 10:10:53 -0700183 auto sensorObj =
Kun Yi501ade22019-07-15 15:00:32 -0700184 std::make_unique<sensor::Sensor>(sensorSetKey, _ioAccess, _devPath);
Matthew Barth9c431062018-05-07 13:55:29 -0500185
Matthew Barthb7985272018-04-17 10:50:36 -0500186 // Get list of return codes for removing sensors on device
187 auto devRmRCs = env::getEnv("REMOVERCS");
188 // Add sensor removal return codes defined at the device level
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500189 sensorObj->addRemoveRCs(devRmRCs);
Matthew Barth31d214c2018-03-26 09:54:27 -0500190
191 std::string objectPath{_root};
192 objectPath.append(1, '/');
Patrick Venture09791852018-04-17 17:40:00 -0700193 objectPath.append(hwmon::getNamespace(attrs));
Matthew Barth31d214c2018-03-26 09:54:27 -0500194 objectPath.append(1, '/');
Matthew Barth979c8062018-04-17 11:37:15 -0500195 objectPath.append(std::get<sensorLabel>(properties));
Matthew Barth31d214c2018-03-26 09:54:27 -0500196
Patrick Venture62067232019-06-19 17:39:33 -0700197 ObjectInfo info(&_bus, std::move(objectPath), InterfaceMap());
Patrick Venture75e56c62018-04-20 18:10:15 -0700198 RetryIO retryIO(hwmonio::retries, hwmonio::delay);
Kun Yi501ade22019-07-15 15:00:32 -0700199 if (_rmSensors.find(sensorSetKey) != _rmSensors.end())
Matthew Barthd4beecf2018-04-03 15:50:22 -0500200 {
201 // When adding a sensor that was purposely removed,
202 // don't retry on errors when reading its value
203 std::get<size_t>(retryIO) = 0;
204 }
Patrick Venture043d3232018-08-31 10:10:53 -0700205 auto valueInterface = static_cast<std::shared_ptr<ValueObject>>(nullptr);
Matthew Barth31d214c2018-03-26 09:54:27 -0500206 try
207 {
Matthew Barthca44c2e2018-04-24 15:33:25 -0500208 // Add status interface based on _fault file being present
Matthew Barth2e41b132018-05-07 14:15:45 -0500209 sensorObj->addStatus(info);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500210 valueInterface = sensorObj->addValue(retryIO, info);
Matthew Barth31d214c2018-03-26 09:54:27 -0500211 }
212 catch (const std::system_error& e)
213 {
Patrick Venture043d3232018-08-31 10:10:53 -0700214 auto file =
Kun Yi501ade22019-07-15 15:00:32 -0700215 sysfs::make_sysfs_path(_ioAccess->path(), sensorSysfsType,
216 sensorSysfsNum, hwmon::entry::cinput);
Patrick Venture0892c3f2019-06-27 14:24:03 -0700217
Matthew Barth31d214c2018-03-26 09:54:27 -0500218 // Check sensorAdjusts for sensor removal RCs
Matthew Barthac473092018-05-07 14:41:46 -0500219 auto& sAdjusts = sensorObj->getAdjusts();
220 if (sAdjusts.rmRCs.count(e.code().value()) > 0)
Matthew Barth31d214c2018-03-26 09:54:27 -0500221 {
Matthew Barthac473092018-05-07 14:41:46 -0500222 // Return code found in sensor return code removal list
Kun Yi501ade22019-07-15 15:00:32 -0700223 if (_rmSensors.find(sensorSetKey) == _rmSensors.end())
Matthew Barth31d214c2018-03-26 09:54:27 -0500224 {
Matthew Barthac473092018-05-07 14:41:46 -0500225 // Trace for sensor not already removed from dbus
226 log<level::INFO>("Sensor not added to dbus for read fail",
Patrick Venture043d3232018-08-31 10:10:53 -0700227 entry("FILE=%s", file.c_str()),
228 entry("RC=%d", e.code().value()));
Kun Yi501ade22019-07-15 15:00:32 -0700229 _rmSensors[std::move(sensorSetKey)] = std::move(sensorAttrs);
Matthew Barth31d214c2018-03-26 09:54:27 -0500230 }
Matthew Barthac473092018-05-07 14:41:46 -0500231 return {};
Matthew Barth31d214c2018-03-26 09:54:27 -0500232 }
Patrick Venture0892c3f2019-06-27 14:24:03 -0700233
Patrick Venture043d3232018-08-31 10:10:53 -0700234 using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::Error;
Matthew Barth31d214c2018-03-26 09:54:27 -0500235 report<ReadFailure>(
Patrick Venture043d3232018-08-31 10:10:53 -0700236 xyz::openbmc_project::Sensor::Device::ReadFailure::CALLOUT_ERRNO(
237 e.code().value()),
238 xyz::openbmc_project::Sensor::Device::ReadFailure::
239 CALLOUT_DEVICE_PATH(_devPath.c_str()));
Matthew Barth31d214c2018-03-26 09:54:27 -0500240
Matthew Barth31d214c2018-03-26 09:54:27 -0500241 log<level::INFO>("Logging failing sysfs file",
Patrick Venture043d3232018-08-31 10:10:53 -0700242 entry("FILE=%s", file.c_str()));
Matthew Barth31d214c2018-03-26 09:54:27 -0500243 exit(EXIT_FAILURE);
Matthew Barth31d214c2018-03-26 09:54:27 -0500244 }
245 auto sensorValue = valueInterface->value();
James Feistee73f5b2018-08-01 16:31:42 -0700246 int64_t scale = 0;
247 // scale the thresholds only if we're using doubles
248 if constexpr (std::is_same<SensorValueType, double>::value)
249 {
250 scale = sensorObj->getScale();
251 }
Kun Yi501ade22019-07-15 15:00:32 -0700252 addThreshold<WarningObject>(sensorSysfsType, std::get<sensorID>(properties),
253 sensorValue, info, scale);
254 addThreshold<CriticalObject>(sensorSysfsType,
James Feistee73f5b2018-08-01 16:31:42 -0700255 std::get<sensorID>(properties), sensorValue,
256 info, scale);
Matthew Barth31d214c2018-03-26 09:54:27 -0500257
Patrick Venture043d3232018-08-31 10:10:53 -0700258 auto target =
Kun Yi501ade22019-07-15 15:00:32 -0700259 addTarget<hwmon::FanSpeed>(sensorSetKey, _ioAccess, _devPath, info);
Matthew Barth28f8e662018-03-26 16:57:36 -0500260 if (target)
Matthew Barth31d214c2018-03-26 09:54:27 -0500261 {
Matthew Barth28f8e662018-03-26 16:57:36 -0500262 target->enable();
Matthew Barth31d214c2018-03-26 09:54:27 -0500263 }
Kun Yi501ade22019-07-15 15:00:32 -0700264 addTarget<hwmon::FanPwm>(sensorSetKey, _ioAccess, _devPath, info);
Matthew Barth31d214c2018-03-26 09:54:27 -0500265
266 // All the interfaces have been created. Go ahead
267 // and emit InterfacesAdded.
268 valueInterface->emit_object_added();
269
Matthew Barth9c431062018-05-07 13:55:29 -0500270 // Save sensor object specifications
Kun Yi501ade22019-07-15 15:00:32 -0700271 _sensorObjects[sensorSetKey] = std::move(sensorObj);
Matthew Barth9c431062018-05-07 13:55:29 -0500272
Matthew Barthd238e232018-04-17 12:01:50 -0500273 return std::make_pair(std::move(std::get<sensorLabel>(properties)),
274 std::move(info));
Matthew Barth31d214c2018-03-26 09:54:27 -0500275}
276
Patrick Venture043d3232018-08-31 10:10:53 -0700277MainLoop::MainLoop(sdbusplus::bus::bus&& bus, const std::string& param,
278 const std::string& path, const std::string& devPath,
Patrick Venture16805a62019-06-21 14:19:33 -0700279 const char* prefix, const char* root,
280 const hwmonio::HwmonIOInterface* ioIntf) :
Patrick Venture043d3232018-08-31 10:10:53 -0700281 _bus(std::move(bus)),
282 _manager(_bus, root), _pathParam(param), _hwmonRoot(), _instance(),
Patrick Venture16805a62019-06-21 14:19:33 -0700283 _devPath(devPath), _prefix(prefix), _root(root), _state(),
284 _ioAccess(ioIntf), _event(sdeventplus::Event::get_default()),
Patrick Venture52b40612018-12-19 13:36:41 -0800285 _timer(_event, std::bind(&MainLoop::read, this))
Brad Bishopd499ca62016-12-19 09:24:50 -0500286{
Patrick Venture73a50c72018-04-17 15:19:03 -0700287 // Strip off any trailing slashes.
Brad Bishopb8740fc2017-02-24 23:38:37 -0500288 std::string p = path;
289 while (!p.empty() && p.back() == '/')
Brad Bishop9c7b6e02016-12-19 12:43:36 -0500290 {
Brad Bishopb8740fc2017-02-24 23:38:37 -0500291 p.pop_back();
Brad Bishop9c7b6e02016-12-19 12:43:36 -0500292 }
Brad Bishopb8740fc2017-02-24 23:38:37 -0500293
Patrick Venture73a50c72018-04-17 15:19:03 -0700294 // Given the furthest right /, set instance to
295 // the basename, and hwmonRoot to the leading path.
Brad Bishopb8740fc2017-02-24 23:38:37 -0500296 auto n = p.rfind('/');
297 if (n != std::string::npos)
298 {
299 _instance.assign(p.substr(n + 1));
300 _hwmonRoot.assign(p.substr(0, n));
301 }
302
303 assert(!_instance.empty());
304 assert(!_hwmonRoot.empty());
Brad Bishopd499ca62016-12-19 09:24:50 -0500305}
306
307void MainLoop::shutdown() noexcept
308{
Patrick Venture52b40612018-12-19 13:36:41 -0800309 _event.exit(0);
Brad Bishopd499ca62016-12-19 09:24:50 -0500310}
311
312void MainLoop::run()
Brad Bishope55ef3d2016-12-19 09:12:40 -0500313{
Deepak Kodihalli2a51a9c2018-03-07 02:39:40 -0600314 init();
315
Patrick Venture043d3232018-08-31 10:10:53 -0700316 std::function<void()> callback(std::bind(&MainLoop::read, this));
Deepak Kodihalli2a51a9c2018-03-07 02:39:40 -0600317 try
318 {
Patrick Venture52b40612018-12-19 13:36:41 -0800319 _timer.restart(std::chrono::microseconds(_interval));
Deepak Kodihalli2a51a9c2018-03-07 02:39:40 -0600320
321 // TODO: Issue#6 - Optionally look at polling interval sysfs entry.
322
323 // TODO: Issue#7 - Should probably periodically check the SensorSet
324 // for new entries.
325
Patrick Venture52b40612018-12-19 13:36:41 -0800326 _bus.attach_event(_event.get(), SD_EVENT_PRIORITY_IMPORTANT);
327 _event.loop();
Deepak Kodihalli2a51a9c2018-03-07 02:39:40 -0600328 }
William A. Kennington III0fe4cb32018-10-18 19:19:58 -0700329 catch (const std::exception& e)
Deepak Kodihalli2a51a9c2018-03-07 02:39:40 -0600330 {
331 log<level::ERR>("Error in sysfs polling loop",
332 entry("ERROR=%s", e.what()));
333 throw;
334 }
335}
336
337void MainLoop::init()
338{
Brad Bishope55ef3d2016-12-19 09:12:40 -0500339 // Check sysfs for available sensors.
Brad Bishop4db64422017-02-16 11:33:32 -0500340 auto sensors = std::make_unique<SensorSet>(_hwmonRoot + '/' + _instance);
Brad Bishope55ef3d2016-12-19 09:12:40 -0500341
Patrick Venturedb7ecb62018-10-23 19:42:23 -0700342 for (const auto& i : *sensors)
Brad Bishop75b4ab82017-01-06 09:33:50 -0500343 {
Matthew Barthd238e232018-04-17 12:01:50 -0500344 auto object = getObject(i);
345 if (object)
346 {
347 // Construct the SensorSet value
348 // std::tuple<SensorSet::mapped_type,
349 // std::string(Sensor Label),
350 // ObjectInfo>
Patrick Venture043d3232018-08-31 10:10:53 -0700351 auto value =
352 std::make_tuple(std::move(i.second), std::move((*object).first),
353 std::move((*object).second));
Matthew Barthd238e232018-04-17 12:01:50 -0500354
Patrick Venture52b40612018-12-19 13:36:41 -0800355 _state[std::move(i.first)] = std::move(value);
Matthew Barthd238e232018-04-17 12:01:50 -0500356 }
Carol Wang9bbe6022019-08-01 17:31:30 +0800357
358 // Initialize _averageMap of sensor. e.g. <<power, 1>, <0, 0>>
359 if ((i.first.first == hwmon::type::power) &&
360 (phosphor::utility::isAverageEnvSet(i.first)))
361 {
362 _average.setAverageValue(i.first, std::make_pair(0, 0));
363 }
Brad Bishop75b4ab82017-01-06 09:33:50 -0500364 }
365
Patrick Venture62503a42017-05-23 07:30:29 -0700366 /* If there are no sensors specified by labels, exit. */
Patrick Venture52b40612018-12-19 13:36:41 -0800367 if (0 == _state.size())
Patrick Venture62503a42017-05-23 07:30:29 -0700368 {
Deepak Kodihalli2a51a9c2018-03-07 02:39:40 -0600369 exit(0);
Patrick Venture62503a42017-05-23 07:30:29 -0700370 }
371
Brad Bishop9c7b6e02016-12-19 12:43:36 -0500372 {
Patrick Venturec897d8b2018-04-23 19:01:56 -0700373 std::stringstream ss;
Patrick Venture043d3232018-08-31 10:10:53 -0700374 ss << _prefix << "-"
Patrick Venturec897d8b2018-04-23 19:01:56 -0700375 << std::to_string(std::hash<std::string>{}(_devPath + _pathParam))
376 << ".Hwmon1";
377
378 _bus.request_name(ss.str().c_str());
Brad Bishop9c7b6e02016-12-19 12:43:36 -0500379 }
380
Patrick Ventureab10f162017-05-22 09:44:50 -0700381 {
Patrick Venturea24c8802018-04-17 19:38:06 -0700382 auto interval = env::getEnv("INTERVAL");
383 if (!interval.empty())
Patrick Ventureab10f162017-05-22 09:44:50 -0700384 {
Patrick Venture50cf1c52018-04-18 09:21:41 -0700385 _interval = std::strtoull(interval.c_str(), NULL, 10);
Patrick Ventureab10f162017-05-22 09:44:50 -0700386 }
387 }
Deepak Kodihalli2a51a9c2018-03-07 02:39:40 -0600388}
Patrick Ventureab10f162017-05-22 09:44:50 -0700389
Deepak Kodihalli2a51a9c2018-03-07 02:39:40 -0600390void MainLoop::read()
391{
Brad Bishope55ef3d2016-12-19 09:12:40 -0500392 // TODO: Issue#3 - Need to make calls to the dbus sensor cache here to
393 // ensure the objects all exist?
394
Deepak Kodihalli2a51a9c2018-03-07 02:39:40 -0600395 // Iterate through all the sensors.
Kun Yi501ade22019-07-15 15:00:32 -0700396 for (auto& [sensorSetKey, sensorStateTuple] : _state)
Deepak Kodihalli2a51a9c2018-03-07 02:39:40 -0600397 {
Kun Yi501ade22019-07-15 15:00:32 -0700398 const auto& [sensorSysfsType, sensorSysfsNum] = sensorSetKey;
399 auto& [attrs, unused, objInfo] = sensorStateTuple;
400
Kun Yi553552c2019-07-15 22:14:21 -0700401 if (attrs.find(hwmon::entry::input) == attrs.end())
Brad Bishope55ef3d2016-12-19 09:12:40 -0500402 {
Kun Yi553552c2019-07-15 22:14:21 -0700403 continue;
404 }
Kun Yi501ade22019-07-15 15:00:32 -0700405
Kun Yi553552c2019-07-15 22:14:21 -0700406 // Read value from sensor.
Carol Wang9bbe6022019-08-01 17:31:30 +0800407 std::string input = hwmon::entry::input;
408 if (sensorSysfsType == hwmon::type::pwm)
Kun Yi553552c2019-07-15 22:14:21 -0700409 {
410 input = "";
411 }
Carol Wang9bbe6022019-08-01 17:31:30 +0800412 // If type is power and AVERAGE_power* is true in env, use average
413 // instead of input
414 else if ((sensorSysfsType == hwmon::type::power) &&
415 (phosphor::utility::isAverageEnvSet(sensorSetKey)))
416 {
417 input = hwmon::entry::average;
418 }
Kun Yi553552c2019-07-15 22:14:21 -0700419
420 int64_t value;
Kun Yi553552c2019-07-15 22:14:21 -0700421 auto& obj = std::get<InterfaceMap>(objInfo);
Kun Yi501ade22019-07-15 15:00:32 -0700422 std::unique_ptr<sensor::Sensor>& sensor = _sensorObjects[sensorSetKey];
Kun Yi553552c2019-07-15 22:14:21 -0700423
424 auto& statusIface = std::any_cast<std::shared_ptr<StatusObject>&>(
425 obj[InterfaceType::STATUS]);
426 // As long as addStatus is called before addValue, statusIface
427 // should never be nullptr.
428 assert(statusIface);
429
430 try
431 {
432 if (sensor->hasFaultFile())
Patrick Venture043d3232018-08-31 10:10:53 -0700433 {
Kun Yi501ade22019-07-15 15:00:32 -0700434 auto fault = _ioAccess->read(sensorSysfsType, sensorSysfsNum,
Kun Yi553552c2019-07-15 22:14:21 -0700435 hwmon::entry::fault,
436 hwmonio::retries, hwmonio::delay);
437 // Skip reading from a sensor with a valid fault file
438 // and set the functional property accordingly
439 if (!statusIface->functional((fault == 0) ? true : false))
Matthew Barth27c4a392018-04-25 14:38:51 -0500440 {
Matthew Barthac473092018-05-07 14:41:46 -0500441 continue;
Matthew Barth8772ce32018-03-22 16:03:06 -0500442 }
Brad Bishope55ef3d2016-12-19 09:12:40 -0500443 }
Kun Yi553552c2019-07-15 22:14:21 -0700444
445 {
446 // RAII object for GPIO unlock / lock
William A. Kennington III2227bd52019-06-19 11:32:22 -0700447 auto locker = sensor::gpioUnlock(sensor->getGpio());
Kun Yi553552c2019-07-15 22:14:21 -0700448
449 // Retry for up to a second if device is busy
450 // or has a transient error.
Kun Yi501ade22019-07-15 15:00:32 -0700451 value = _ioAccess->read(sensorSysfsType, sensorSysfsNum, input,
Kun Yi553552c2019-07-15 22:14:21 -0700452 hwmonio::retries, hwmonio::delay);
453 // Set functional property to true if we could read sensor
454 statusIface->functional(true);
455
456 value = sensor->adjustValue(value);
Carol Wang9bbe6022019-08-01 17:31:30 +0800457
458 if (input == hwmon::entry::average)
459 {
460 // Calculate the values of averageMap based on current
461 // average value, current average_interval value, previous
462 // average value, previous average_interval value
463 int64_t interval =
464 _ioAccess->read(sensorSysfsType, sensorSysfsNum,
465 hwmon::entry::caverage_interval,
466 hwmonio::retries, hwmonio::delay);
467 auto ret = _average.getAverageValue(sensorSetKey);
468 assert(ret);
469
470 const auto& [preAverage, preInterval] = *ret;
471
472 auto calValue = Average::calcAverage(
473 preAverage, preInterval, value, interval);
474 if (calValue)
475 {
476 // Update previous values in averageMap before the
477 // variable value is changed next
478 _average.setAverageValue(
479 sensorSetKey, std::make_pair(value, interval));
480 // Update value to be calculated average
481 value = calValue.value();
482 }
483 else
484 {
485 // the value of
486 // power*_average_interval is not changed yet, use the
487 // previous calculated average instead. So skip dbus
488 // update.
489 continue;
490 }
491 }
Kun Yi553552c2019-07-15 22:14:21 -0700492 }
493
494 updateSensorInterfaces(obj, value);
495 }
496 catch (const std::system_error& e)
497 {
498#ifdef UPDATE_FUNCTIONAL_ON_FAIL
499 // If UPDATE_FUNCTIONAL_ON_FAIL is defined and an exception was
500 // thrown, set the functional property to false.
501 // We cannot set this with the 'continue' in the lower block
502 // as the code may exit before reaching it.
503 statusIface->functional(false);
504#endif
Carol Wang9bbe6022019-08-01 17:31:30 +0800505 auto file = sysfs::make_sysfs_path(
506 _ioAccess->path(), sensorSysfsType, sensorSysfsNum, input);
Kun Yi553552c2019-07-15 22:14:21 -0700507
508 // Check sensorAdjusts for sensor removal RCs
Kun Yi501ade22019-07-15 15:00:32 -0700509 auto& sAdjusts = _sensorObjects[sensorSetKey]->getAdjusts();
Kun Yi553552c2019-07-15 22:14:21 -0700510 if (sAdjusts.rmRCs.count(e.code().value()) > 0)
511 {
512 // Return code found in sensor return code removal list
Kun Yi501ade22019-07-15 15:00:32 -0700513 if (_rmSensors.find(sensorSetKey) == _rmSensors.end())
Kun Yi553552c2019-07-15 22:14:21 -0700514 {
515 // Trace for sensor not already removed from dbus
516 log<level::INFO>("Remove sensor from dbus for read fail",
517 entry("FILE=%s", file.c_str()),
518 entry("RC=%d", e.code().value()));
519 // Mark this sensor to be removed from dbus
Kun Yi501ade22019-07-15 15:00:32 -0700520 _rmSensors[sensorSetKey] = attrs;
Kun Yi553552c2019-07-15 22:14:21 -0700521 }
522 continue;
523 }
524#ifdef UPDATE_FUNCTIONAL_ON_FAIL
525 // Do not exit with failure if UPDATE_FUNCTIONAL_ON_FAIL is set
526 continue;
527#endif
528 using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::
529 Error;
530 report<ReadFailure>(
531 xyz::openbmc_project::Sensor::Device::ReadFailure::
532 CALLOUT_ERRNO(e.code().value()),
533 xyz::openbmc_project::Sensor::Device::ReadFailure::
534 CALLOUT_DEVICE_PATH(_devPath.c_str()));
535
536 log<level::INFO>("Logging failing sysfs file",
537 entry("FILE=%s", file.c_str()));
538
539 exit(EXIT_FAILURE);
Brad Bishope55ef3d2016-12-19 09:12:40 -0500540 }
Deepak Kodihalli2a51a9c2018-03-07 02:39:40 -0600541 }
Brad Bishope55ef3d2016-12-19 09:12:40 -0500542
Patrick Venture0cd4f692019-06-21 13:39:40 -0700543 removeSensors();
544
Patrick Venture0cd4f692019-06-21 13:39:40 -0700545 addDroppedSensors();
Patrick Venture0cd4f692019-06-21 13:39:40 -0700546}
547
548void MainLoop::removeSensors()
549{
Matthew Barth8772ce32018-03-22 16:03:06 -0500550 // Remove any sensors marked for removal
Patrick Venture52b40612018-12-19 13:36:41 -0800551 for (const auto& i : _rmSensors)
Deepak Kodihalli2a51a9c2018-03-07 02:39:40 -0600552 {
Matthew Barthd0ce7922019-06-06 09:23:37 -0500553 // Remove sensor object from dbus using emit_object_removed()
554 auto& objInfo = std::get<ObjectInfo>(_state[i.first]);
555 auto& objPath = std::get<std::string>(objInfo);
Patrick Venture0cd4f692019-06-21 13:39:40 -0700556
Matthew Barthd0ce7922019-06-06 09:23:37 -0500557 _bus.emit_object_removed(objPath.c_str());
Patrick Venture0cd4f692019-06-21 13:39:40 -0700558
Matthew Barthd0ce7922019-06-06 09:23:37 -0500559 // Erase sensor object info
Patrick Venture52b40612018-12-19 13:36:41 -0800560 _state.erase(i.first);
Brad Bishope55ef3d2016-12-19 09:12:40 -0500561 }
Patrick Venture0cd4f692019-06-21 13:39:40 -0700562}
Matthew Barth31d214c2018-03-26 09:54:27 -0500563
Patrick Venture0cd4f692019-06-21 13:39:40 -0700564void MainLoop::addDroppedSensors()
565{
Matthew Barth31d214c2018-03-26 09:54:27 -0500566 // Attempt to add any sensors that were removed
Patrick Venture52b40612018-12-19 13:36:41 -0800567 auto it = _rmSensors.begin();
568 while (it != _rmSensors.end())
Matthew Barth31d214c2018-03-26 09:54:27 -0500569 {
Patrick Venture52b40612018-12-19 13:36:41 -0800570 if (_state.find(it->first) == _state.end())
Matthew Barth31d214c2018-03-26 09:54:27 -0500571 {
572 SensorSet::container_t::value_type ssValueType =
Patrick Venture043d3232018-08-31 10:10:53 -0700573 std::make_pair(it->first, it->second);
Patrick Venture0cd4f692019-06-21 13:39:40 -0700574
Matthew Barthd238e232018-04-17 12:01:50 -0500575 auto object = getObject(ssValueType);
576 if (object)
Matthew Barth31d214c2018-03-26 09:54:27 -0500577 {
Matthew Barthd238e232018-04-17 12:01:50 -0500578 // Construct the SensorSet value
579 // std::tuple<SensorSet::mapped_type,
580 // std::string(Sensor Label),
581 // ObjectInfo>
582 auto value = std::make_tuple(std::move(ssValueType.second),
583 std::move((*object).first),
584 std::move((*object).second));
585
Patrick Venture52b40612018-12-19 13:36:41 -0800586 _state[std::move(ssValueType.first)] = std::move(value);
Matthew Barthd238e232018-04-17 12:01:50 -0500587
Carol Wang9bbe6022019-08-01 17:31:30 +0800588 std::string input = hwmon::entry::input;
589 // If type is power and AVERAGE_power* is true in env, use
590 // average instead of input
591 if ((it->first.first == hwmon::type::power) &&
592 (phosphor::utility::isAverageEnvSet(it->first)))
593 {
594 input = hwmon::entry::average;
595 }
Matthew Barth31d214c2018-03-26 09:54:27 -0500596 // Sensor object added, erase entry from removal list
Carol Wang9bbe6022019-08-01 17:31:30 +0800597 auto file =
598 sysfs::make_sysfs_path(_ioAccess->path(), it->first.first,
599 it->first.second, input);
Patrick Venture0cd4f692019-06-21 13:39:40 -0700600
Patrick Venture043d3232018-08-31 10:10:53 -0700601 log<level::INFO>("Added sensor to dbus after successful read",
602 entry("FILE=%s", file.c_str()));
Patrick Venture0cd4f692019-06-21 13:39:40 -0700603
Patrick Venture52b40612018-12-19 13:36:41 -0800604 it = _rmSensors.erase(it);
Matthew Barth31d214c2018-03-26 09:54:27 -0500605 }
606 else
607 {
608 ++it;
609 }
610 }
611 else
612 {
613 // Sanity check to remove sensors that were re-added
Patrick Venture52b40612018-12-19 13:36:41 -0800614 it = _rmSensors.erase(it);
Matthew Barth31d214c2018-03-26 09:54:27 -0500615 }
616 }
Brad Bishope55ef3d2016-12-19 09:12:40 -0500617}
618
619// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4