blob: 0a0971f262789f9ace3818940abf734fcd6d31fc [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
Matthew Barthcb3daaf2018-05-07 15:03:16 -050011#include <cstring>
Matthew Barth35819382018-04-18 14:53:01 -050012#include <experimental/filesystem>
Matthew Barth35819382018-04-18 14:53:01 -050013#include <phosphor-logging/elog-errors.hpp>
Patrick Ventureb28f4322018-09-14 10:19:14 -070014#include <thread>
15#include <xyz/openbmc_project/Common/error.hpp>
Matthew Barth35819382018-04-18 14:53:01 -050016#include <xyz/openbmc_project/Sensor/Device/error.hpp>
17
Matthew Barth35819382018-04-18 14:53:01 -050018namespace sensor
19{
20
Matthew Barthcb3daaf2018-05-07 15:03:16 -050021using namespace phosphor::logging;
Patrick Ventureb28f4322018-09-14 10:19:14 -070022using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Matthew Barthcb3daaf2018-05-07 15:03:16 -050023
Matthew Barth2e41b132018-05-07 14:15:45 -050024Sensor::Sensor(const SensorSet::key_type& sensor,
Patrick Venture043d3232018-08-31 10:10:53 -070025 const hwmonio::HwmonIO& ioAccess, const std::string& devPath) :
Matthew Barth2e41b132018-05-07 14:15:45 -050026 sensor(sensor),
Patrick Venture043d3232018-08-31 10:10:53 -070027 ioAccess(ioAccess), devPath(devPath)
Matthew Barth9c431062018-05-07 13:55:29 -050028{
Patrick Ventureb28f4322018-09-14 10:19:14 -070029 auto chip = env::getEnv("GPIOCHIP", sensor);
30 auto access = env::getEnv("GPIO", sensor);
31 if (!access.empty() && !chip.empty())
32 {
33 handle = gpio::BuildGpioHandle(chip, access);
34
35 if (!handle)
36 {
37 log<level::ERR>("Unable to set up gpio locking");
38 elog<InternalFailure>();
39 }
40 }
41
Matthew Barthac473092018-05-07 14:41:46 -050042 auto gain = env::getEnv("GAIN", sensor);
43 if (!gain.empty())
44 {
45 sensorAdjusts.gain = std::stod(gain);
46 }
47
48 auto offset = env::getEnv("OFFSET", sensor);
49 if (!offset.empty())
50 {
51 sensorAdjusts.offset = std::stoi(offset);
52 }
53 auto senRmRCs = env::getEnv("REMOVERCS", sensor);
54 // Add sensor removal return codes defined per sensor
55 addRemoveRCs(senRmRCs);
Matthew Barth9c431062018-05-07 13:55:29 -050056}
57
Matthew Barthcb3daaf2018-05-07 15:03:16 -050058void Sensor::addRemoveRCs(const std::string& rcList)
59{
60 if (rcList.empty())
61 {
62 return;
63 }
64
65 // Convert to a char* for strtok
Patrick Venture043d3232018-08-31 10:10:53 -070066 std::vector<char> rmRCs(rcList.c_str(), rcList.c_str() + rcList.size() + 1);
Matthew Barthcb3daaf2018-05-07 15:03:16 -050067 auto rmRC = std::strtok(&rmRCs[0], ", ");
68 while (rmRC != nullptr)
69 {
70 try
71 {
72 sensorAdjusts.rmRCs.insert(std::stoi(rmRC));
73 }
74 catch (const std::logic_error& le)
75 {
76 // Unable to convert to int, continue to next token
77 std::string name = sensor.first + "_" + sensor.second;
78 log<level::INFO>("Unable to convert sensor removal return code",
79 entry("SENSOR=%s", name.c_str()),
80 entry("RC=%s", rmRC),
81 entry("EXCEPTION=%s", le.what()));
82 }
83 rmRC = std::strtok(nullptr, ", ");
84 }
85}
86
87int64_t Sensor::adjustValue(int64_t value)
88{
89// Because read doesn't have an out pointer to store errors.
90// let's assume negative values are errors if they have this
91// set.
92#ifdef NEGATIVE_ERRNO_ON_FAIL
93 if (value < 0)
94 {
95 return value;
96 }
97#endif
98
99 // Adjust based on gain and offset
100 value = static_cast<decltype(value)>(
Patrick Venture043d3232018-08-31 10:10:53 -0700101 static_cast<double>(value) * sensorAdjusts.gain + sensorAdjusts.offset);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500102
103 return value;
104}
105
Patrick Venture043d3232018-08-31 10:10:53 -0700106std::shared_ptr<ValueObject> Sensor::addValue(const RetryIO& retryIO,
107 ObjectInfo& info)
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500108{
109 static constexpr bool deferSignals = true;
110
111 // Get the initial value for the value interface.
112 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
113 auto& obj = std::get<Object>(info);
114 auto& objPath = std::get<std::string>(info);
115
116 int64_t val = 0;
117 std::shared_ptr<StatusObject> statusIface = nullptr;
118 auto it = obj.find(InterfaceType::STATUS);
119 if (it != obj.end())
120 {
William A. Kennington III4cbdfef2018-10-18 19:19:51 -0700121 statusIface = std::any_cast<std::shared_ptr<StatusObject>>(it->second);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500122 }
123
124 // If there's no fault file or the sensor has a fault file and
125 // its status is functional, read the input value.
126 if (!statusIface || (statusIface && statusIface->functional()))
127 {
Patrick Ventureb28f4322018-09-14 10:19:14 -0700128 unlockGpio();
129
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500130 // Retry for up to a second if device is busy
131 // or has a transient error.
Patrick Venture043d3232018-08-31 10:10:53 -0700132 val = ioAccess.read(sensor.first, sensor.second, hwmon::entry::cinput,
133 std::get<size_t>(retryIO),
134 std::get<std::chrono::milliseconds>(retryIO));
Patrick Ventureb28f4322018-09-14 10:19:14 -0700135
136 lockGpio();
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500137 val = adjustValue(val);
138 }
139
Patrick Venture043d3232018-08-31 10:10:53 -0700140 auto iface =
141 std::make_shared<ValueObject>(bus, objPath.c_str(), deferSignals);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500142 iface->value(val);
143
144 hwmon::Attributes attrs;
145 if (hwmon::getAttributes(sensor.first, attrs))
146 {
147 iface->unit(hwmon::getUnit(attrs));
148 iface->scale(hwmon::getScale(attrs));
149 }
150
151 auto maxValue = env::getEnv("MAXVALUE", sensor);
Patrick Venture043d3232018-08-31 10:10:53 -0700152 if (!maxValue.empty())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500153 {
154 iface->maxValue(std::stoll(maxValue));
155 }
156 auto minValue = env::getEnv("MINVALUE", sensor);
Patrick Venture043d3232018-08-31 10:10:53 -0700157 if (!minValue.empty())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500158 {
159 iface->minValue(std::stoll(minValue));
160 }
161
162 obj[InterfaceType::VALUE] = iface;
163 return iface;
164}
165
Matthew Barth2e41b132018-05-07 14:15:45 -0500166std::shared_ptr<StatusObject> Sensor::addStatus(ObjectInfo& info)
Matthew Barth35819382018-04-18 14:53:01 -0500167{
168 namespace fs = std::experimental::filesystem;
169
170 std::shared_ptr<StatusObject> iface = nullptr;
Matthew Barth35819382018-04-18 14:53:01 -0500171 auto& objPath = std::get<std::string>(info);
172 auto& obj = std::get<Object>(info);
173
174 // Check if fault sysfs file exists
175 std::string faultName = sensor.first;
176 std::string faultID = sensor.second;
177 std::string entry = hwmon::entry::fault;
178
Patrick Venture043d3232018-08-31 10:10:53 -0700179 auto sysfsFullPath =
180 sysfs::make_sysfs_path(ioAccess.path(), faultName, faultID, entry);
Matthew Barth35819382018-04-18 14:53:01 -0500181 if (fs::exists(sysfsFullPath))
182 {
183 bool functional = true;
Matthew Barth35819382018-04-18 14:53:01 -0500184 try
185 {
Patrick Venture685efa12018-10-12 18:00:13 -0700186 uint32_t fault = ioAccess.read(faultName, faultID, entry,
187 hwmonio::retries, hwmonio::delay);
Matthew Barth35819382018-04-18 14:53:01 -0500188 if (fault != 0)
189 {
190 functional = false;
191 }
192 }
193 catch (const std::system_error& e)
194 {
Patrick Venture043d3232018-08-31 10:10:53 -0700195 using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::
196 Error;
197 using metadata = xyz::openbmc_project::Sensor::Device::ReadFailure;
Matthew Barth35819382018-04-18 14:53:01 -0500198
Patrick Venture043d3232018-08-31 10:10:53 -0700199 report<ReadFailure>(metadata::CALLOUT_ERRNO(e.code().value()),
200 metadata::CALLOUT_DEVICE_PATH(devPath.c_str()));
Matthew Barth35819382018-04-18 14:53:01 -0500201
Patrick Venture043d3232018-08-31 10:10:53 -0700202 log<level::INFO>(
203 "Logging failing sysfs file",
204 phosphor::logging::entry("FILE=%s", sysfsFullPath.c_str()));
Matthew Barth35819382018-04-18 14:53:01 -0500205 }
206
Patrick Venture685efa12018-10-12 18:00:13 -0700207 static constexpr bool deferSignals = true;
208 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
209
Patrick Venture043d3232018-08-31 10:10:53 -0700210 iface =
211 std::make_shared<StatusObject>(bus, objPath.c_str(), deferSignals);
Matthew Barth35819382018-04-18 14:53:01 -0500212 // Set functional property
213 iface->functional(functional);
214
215 obj[InterfaceType::STATUS] = iface;
216 }
217
218 return iface;
219}
220
Patrick Ventureb28f4322018-09-14 10:19:14 -0700221void Sensor::unlockGpio()
222{
223 if (handle)
224 {
225 handle->setValues({1});
226 std::this_thread::sleep_for(pause);
227 }
228}
229
230void Sensor::lockGpio()
231{
232 if (handle)
233 {
234 handle->setValues({0});
235 }
236}
237
Matthew Barth35819382018-04-18 14:53:01 -0500238} // namespace sensor