blob: 28f1479eba852c49662979f901390a0de125b2fc [file] [log] [blame]
Patrick Venture043d3232018-08-31 10:10:53 -07001#include "config.h"
2
3#include "sensor.hpp"
4
5#include "env.hpp"
Patrick Ventureb28f4322018-09-14 10:19:14 -07006#include "gpio_handle.hpp"
Patrick Venture043d3232018-08-31 10:10:53 -07007#include "hwmon.hpp"
8#include "sensorset.hpp"
9#include "sysfs.hpp"
10
James Feistee73f5b2018-08-01 16:31:42 -070011#include <cmath>
Matthew Barthcb3daaf2018-05-07 15:03:16 -050012#include <cstring>
Matthew Barth35819382018-04-18 14:53:01 -050013#include <experimental/filesystem>
Matthew Barth35819382018-04-18 14:53:01 -050014#include <phosphor-logging/elog-errors.hpp>
Patrick Ventureb28f4322018-09-14 10:19:14 -070015#include <thread>
16#include <xyz/openbmc_project/Common/error.hpp>
Matthew Barth35819382018-04-18 14:53:01 -050017#include <xyz/openbmc_project/Sensor/Device/error.hpp>
18
Matthew Barth35819382018-04-18 14:53:01 -050019namespace sensor
20{
21
Matthew Barthcb3daaf2018-05-07 15:03:16 -050022using namespace phosphor::logging;
Patrick Ventureb28f4322018-09-14 10:19:14 -070023using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Matthew Barthcb3daaf2018-05-07 15:03:16 -050024
James Feistee73f5b2018-08-01 16:31:42 -070025// todo: this can be deleted once we move to double
26// helper class to set the scale on the value iface only when it's available
27template <typename T>
28void setScale(T& iface, int64_t value, double)
29{
30}
31template <typename T>
32void setScale(T& iface, int64_t value, int64_t)
33{
34 iface->scale(value);
35}
36
37// todo: this can be simplified once we move to the double interface
Matthew Barth2e41b132018-05-07 14:15:45 -050038Sensor::Sensor(const SensorSet::key_type& sensor,
Patrick Venture2864b062018-12-19 08:13:41 -080039 const hwmonio::HwmonIOInterface* ioAccess,
40 const std::string& devPath) :
Patrick Venture12659aa2018-12-19 13:58:43 -080041 _sensor(sensor),
Patrick Venturee9764ff2019-01-24 14:11:45 -080042 _ioAccess(ioAccess), _devPath(devPath), _scale(0)
Matthew Barth9c431062018-05-07 13:55:29 -050043{
Patrick Ventureb28f4322018-09-14 10:19:14 -070044 auto chip = env::getEnv("GPIOCHIP", sensor);
45 auto access = env::getEnv("GPIO", sensor);
46 if (!access.empty() && !chip.empty())
47 {
Patrick Venture12659aa2018-12-19 13:58:43 -080048 _handle = gpio::BuildGpioHandle(chip, access);
Patrick Ventureb28f4322018-09-14 10:19:14 -070049
Patrick Venture12659aa2018-12-19 13:58:43 -080050 if (!_handle)
Patrick Ventureb28f4322018-09-14 10:19:14 -070051 {
52 log<level::ERR>("Unable to set up gpio locking");
53 elog<InternalFailure>();
54 }
55 }
56
Matthew Barthac473092018-05-07 14:41:46 -050057 auto gain = env::getEnv("GAIN", sensor);
58 if (!gain.empty())
59 {
Patrick Venture12659aa2018-12-19 13:58:43 -080060 _sensorAdjusts.gain = std::stod(gain);
Matthew Barthac473092018-05-07 14:41:46 -050061 }
62
63 auto offset = env::getEnv("OFFSET", sensor);
64 if (!offset.empty())
65 {
Patrick Venture12659aa2018-12-19 13:58:43 -080066 _sensorAdjusts.offset = std::stoi(offset);
Matthew Barthac473092018-05-07 14:41:46 -050067 }
68 auto senRmRCs = env::getEnv("REMOVERCS", sensor);
69 // Add sensor removal return codes defined per sensor
70 addRemoveRCs(senRmRCs);
Matthew Barth9c431062018-05-07 13:55:29 -050071}
72
Matthew Barthcb3daaf2018-05-07 15:03:16 -050073void Sensor::addRemoveRCs(const std::string& rcList)
74{
75 if (rcList.empty())
76 {
77 return;
78 }
79
80 // Convert to a char* for strtok
Patrick Venture043d3232018-08-31 10:10:53 -070081 std::vector<char> rmRCs(rcList.c_str(), rcList.c_str() + rcList.size() + 1);
Matthew Barthcb3daaf2018-05-07 15:03:16 -050082 auto rmRC = std::strtok(&rmRCs[0], ", ");
83 while (rmRC != nullptr)
84 {
85 try
86 {
Patrick Venture12659aa2018-12-19 13:58:43 -080087 _sensorAdjusts.rmRCs.insert(std::stoi(rmRC));
Matthew Barthcb3daaf2018-05-07 15:03:16 -050088 }
89 catch (const std::logic_error& le)
90 {
91 // Unable to convert to int, continue to next token
Patrick Venture12659aa2018-12-19 13:58:43 -080092 std::string name = _sensor.first + "_" + _sensor.second;
Matthew Barthcb3daaf2018-05-07 15:03:16 -050093 log<level::INFO>("Unable to convert sensor removal return code",
94 entry("SENSOR=%s", name.c_str()),
95 entry("RC=%s", rmRC),
96 entry("EXCEPTION=%s", le.what()));
97 }
98 rmRC = std::strtok(nullptr, ", ");
99 }
100}
101
James Feistee73f5b2018-08-01 16:31:42 -0700102SensorValueType Sensor::adjustValue(SensorValueType value)
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500103{
104// Because read doesn't have an out pointer to store errors.
105// let's assume negative values are errors if they have this
106// set.
107#ifdef NEGATIVE_ERRNO_ON_FAIL
108 if (value < 0)
109 {
110 return value;
111 }
112#endif
113
114 // Adjust based on gain and offset
Patrick Venture12659aa2018-12-19 13:58:43 -0800115 value = static_cast<decltype(value)>(static_cast<double>(value) *
116 _sensorAdjusts.gain +
117 _sensorAdjusts.offset);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500118
James Feistee73f5b2018-08-01 16:31:42 -0700119 if constexpr (std::is_same<SensorValueType, double>::value)
120 {
Patrick Venture12659aa2018-12-19 13:58:43 -0800121 value *= std::pow(10, _scale);
James Feistee73f5b2018-08-01 16:31:42 -0700122 }
123
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500124 return value;
125}
126
Patrick Venture043d3232018-08-31 10:10:53 -0700127std::shared_ptr<ValueObject> Sensor::addValue(const RetryIO& retryIO,
128 ObjectInfo& info)
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500129{
130 static constexpr bool deferSignals = true;
131
132 // Get the initial value for the value interface.
133 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
134 auto& obj = std::get<Object>(info);
135 auto& objPath = std::get<std::string>(info);
136
James Feistee73f5b2018-08-01 16:31:42 -0700137 SensorValueType val = 0;
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500138 std::shared_ptr<StatusObject> statusIface = nullptr;
139 auto it = obj.find(InterfaceType::STATUS);
140 if (it != obj.end())
141 {
William A. Kennington III4cbdfef2018-10-18 19:19:51 -0700142 statusIface = std::any_cast<std::shared_ptr<StatusObject>>(it->second);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500143 }
144
145 // If there's no fault file or the sensor has a fault file and
146 // its status is functional, read the input value.
147 if (!statusIface || (statusIface && statusIface->functional()))
148 {
Patrick Ventureb28f4322018-09-14 10:19:14 -0700149 unlockGpio();
150
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500151 // Retry for up to a second if device is busy
152 // or has a transient error.
Patrick Venture12659aa2018-12-19 13:58:43 -0800153 val = _ioAccess->read(_sensor.first, _sensor.second,
154 hwmon::entry::cinput, std::get<size_t>(retryIO),
155 std::get<std::chrono::milliseconds>(retryIO));
Patrick Ventureb28f4322018-09-14 10:19:14 -0700156
157 lockGpio();
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500158 val = adjustValue(val);
159 }
160
Patrick Venture043d3232018-08-31 10:10:53 -0700161 auto iface =
162 std::make_shared<ValueObject>(bus, objPath.c_str(), deferSignals);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500163 iface->value(val);
164
165 hwmon::Attributes attrs;
Patrick Venture12659aa2018-12-19 13:58:43 -0800166 if (hwmon::getAttributes(_sensor.first, attrs))
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500167 {
168 iface->unit(hwmon::getUnit(attrs));
James Feistee73f5b2018-08-01 16:31:42 -0700169
170 setScale(iface, hwmon::getScale(attrs), val);
171
Patrick Venture12659aa2018-12-19 13:58:43 -0800172 _scale = hwmon::getScale(attrs);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500173 }
174
Patrick Venture12659aa2018-12-19 13:58:43 -0800175 auto maxValue = env::getEnv("MAXVALUE", _sensor);
Patrick Venture043d3232018-08-31 10:10:53 -0700176 if (!maxValue.empty())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500177 {
178 iface->maxValue(std::stoll(maxValue));
179 }
Patrick Venture12659aa2018-12-19 13:58:43 -0800180 auto minValue = env::getEnv("MINVALUE", _sensor);
Patrick Venture043d3232018-08-31 10:10:53 -0700181 if (!minValue.empty())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500182 {
183 iface->minValue(std::stoll(minValue));
184 }
185
186 obj[InterfaceType::VALUE] = iface;
187 return iface;
188}
189
Matthew Barth2e41b132018-05-07 14:15:45 -0500190std::shared_ptr<StatusObject> Sensor::addStatus(ObjectInfo& info)
Matthew Barth35819382018-04-18 14:53:01 -0500191{
192 namespace fs = std::experimental::filesystem;
193
194 std::shared_ptr<StatusObject> iface = nullptr;
Matthew Barth35819382018-04-18 14:53:01 -0500195 auto& objPath = std::get<std::string>(info);
196 auto& obj = std::get<Object>(info);
197
198 // Check if fault sysfs file exists
Patrick Venture12659aa2018-12-19 13:58:43 -0800199 std::string faultName = _sensor.first;
200 std::string faultID = _sensor.second;
Matthew Barth35819382018-04-18 14:53:01 -0500201 std::string entry = hwmon::entry::fault;
202
Patrick Venture043d3232018-08-31 10:10:53 -0700203 auto sysfsFullPath =
Patrick Venture12659aa2018-12-19 13:58:43 -0800204 sysfs::make_sysfs_path(_ioAccess->path(), faultName, faultID, entry);
Matthew Barth35819382018-04-18 14:53:01 -0500205 if (fs::exists(sysfsFullPath))
206 {
207 bool functional = true;
Matthew Barth35819382018-04-18 14:53:01 -0500208 try
209 {
Patrick Venture12659aa2018-12-19 13:58:43 -0800210 uint32_t fault = _ioAccess->read(faultName, faultID, entry,
211 hwmonio::retries, hwmonio::delay);
Matthew Barth35819382018-04-18 14:53:01 -0500212 if (fault != 0)
213 {
214 functional = false;
215 }
216 }
217 catch (const std::system_error& e)
218 {
Patrick Venture043d3232018-08-31 10:10:53 -0700219 using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::
220 Error;
221 using metadata = xyz::openbmc_project::Sensor::Device::ReadFailure;
Matthew Barth35819382018-04-18 14:53:01 -0500222
Patrick Venture12659aa2018-12-19 13:58:43 -0800223 report<ReadFailure>(
224 metadata::CALLOUT_ERRNO(e.code().value()),
225 metadata::CALLOUT_DEVICE_PATH(_devPath.c_str()));
Matthew Barth35819382018-04-18 14:53:01 -0500226
Patrick Venture043d3232018-08-31 10:10:53 -0700227 log<level::INFO>(
228 "Logging failing sysfs file",
229 phosphor::logging::entry("FILE=%s", sysfsFullPath.c_str()));
Matthew Barth35819382018-04-18 14:53:01 -0500230 }
231
Patrick Venture685efa12018-10-12 18:00:13 -0700232 static constexpr bool deferSignals = true;
233 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
234
Patrick Venture043d3232018-08-31 10:10:53 -0700235 iface =
236 std::make_shared<StatusObject>(bus, objPath.c_str(), deferSignals);
Matthew Barth35819382018-04-18 14:53:01 -0500237 // Set functional property
238 iface->functional(functional);
239
240 obj[InterfaceType::STATUS] = iface;
241 }
242
243 return iface;
244}
245
Patrick Ventureb28f4322018-09-14 10:19:14 -0700246void Sensor::unlockGpio()
247{
Patrick Venture12659aa2018-12-19 13:58:43 -0800248 if (_handle)
Patrick Ventureb28f4322018-09-14 10:19:14 -0700249 {
Patrick Venture12659aa2018-12-19 13:58:43 -0800250 _handle->setValues({1});
251 std::this_thread::sleep_for(_pause);
Patrick Ventureb28f4322018-09-14 10:19:14 -0700252 }
253}
254
255void Sensor::lockGpio()
256{
Patrick Venture12659aa2018-12-19 13:58:43 -0800257 if (_handle)
Patrick Ventureb28f4322018-09-14 10:19:14 -0700258 {
Patrick Venture12659aa2018-12-19 13:58:43 -0800259 _handle->setValues({0});
Patrick Ventureb28f4322018-09-14 10:19:14 -0700260 }
261}
262
Matthew Barth35819382018-04-18 14:53:01 -0500263} // namespace sensor