blob: 21f3d879013e66015d2594ff05550955f1bb1cf0 [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 {
Patrick Venture043d3232018-08-31 10:10:53 -0700121 statusIface =
122 std::experimental::any_cast<std::shared_ptr<StatusObject>>(
123 it->second);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500124 }
125
126 // If there's no fault file or the sensor has a fault file and
127 // its status is functional, read the input value.
128 if (!statusIface || (statusIface && statusIface->functional()))
129 {
Patrick Ventureb28f4322018-09-14 10:19:14 -0700130 unlockGpio();
131
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500132 // Retry for up to a second if device is busy
133 // or has a transient error.
Patrick Venture043d3232018-08-31 10:10:53 -0700134 val = ioAccess.read(sensor.first, sensor.second, hwmon::entry::cinput,
135 std::get<size_t>(retryIO),
136 std::get<std::chrono::milliseconds>(retryIO));
Patrick Ventureb28f4322018-09-14 10:19:14 -0700137
138 lockGpio();
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500139 val = adjustValue(val);
140 }
141
Patrick Venture043d3232018-08-31 10:10:53 -0700142 auto iface =
143 std::make_shared<ValueObject>(bus, objPath.c_str(), deferSignals);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500144 iface->value(val);
145
146 hwmon::Attributes attrs;
147 if (hwmon::getAttributes(sensor.first, attrs))
148 {
149 iface->unit(hwmon::getUnit(attrs));
150 iface->scale(hwmon::getScale(attrs));
151 }
152
153 auto maxValue = env::getEnv("MAXVALUE", sensor);
Patrick Venture043d3232018-08-31 10:10:53 -0700154 if (!maxValue.empty())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500155 {
156 iface->maxValue(std::stoll(maxValue));
157 }
158 auto minValue = env::getEnv("MINVALUE", sensor);
Patrick Venture043d3232018-08-31 10:10:53 -0700159 if (!minValue.empty())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500160 {
161 iface->minValue(std::stoll(minValue));
162 }
163
164 obj[InterfaceType::VALUE] = iface;
165 return iface;
166}
167
Matthew Barth2e41b132018-05-07 14:15:45 -0500168std::shared_ptr<StatusObject> Sensor::addStatus(ObjectInfo& info)
Matthew Barth35819382018-04-18 14:53:01 -0500169{
170 namespace fs = std::experimental::filesystem;
171
172 std::shared_ptr<StatusObject> iface = nullptr;
Matthew Barth35819382018-04-18 14:53:01 -0500173 auto& objPath = std::get<std::string>(info);
174 auto& obj = std::get<Object>(info);
175
176 // Check if fault sysfs file exists
177 std::string faultName = sensor.first;
178 std::string faultID = sensor.second;
179 std::string entry = hwmon::entry::fault;
180
Patrick Venture043d3232018-08-31 10:10:53 -0700181 auto sysfsFullPath =
182 sysfs::make_sysfs_path(ioAccess.path(), faultName, faultID, entry);
Matthew Barth35819382018-04-18 14:53:01 -0500183 if (fs::exists(sysfsFullPath))
184 {
185 bool functional = true;
Matthew Barth35819382018-04-18 14:53:01 -0500186 try
187 {
Patrick Venture685efa12018-10-12 18:00:13 -0700188 uint32_t fault = ioAccess.read(faultName, faultID, entry,
189 hwmonio::retries, hwmonio::delay);
Matthew Barth35819382018-04-18 14:53:01 -0500190 if (fault != 0)
191 {
192 functional = false;
193 }
194 }
195 catch (const std::system_error& e)
196 {
Patrick Venture043d3232018-08-31 10:10:53 -0700197 using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::
198 Error;
199 using metadata = xyz::openbmc_project::Sensor::Device::ReadFailure;
Matthew Barth35819382018-04-18 14:53:01 -0500200
Patrick Venture043d3232018-08-31 10:10:53 -0700201 report<ReadFailure>(metadata::CALLOUT_ERRNO(e.code().value()),
202 metadata::CALLOUT_DEVICE_PATH(devPath.c_str()));
Matthew Barth35819382018-04-18 14:53:01 -0500203
Patrick Venture043d3232018-08-31 10:10:53 -0700204 log<level::INFO>(
205 "Logging failing sysfs file",
206 phosphor::logging::entry("FILE=%s", sysfsFullPath.c_str()));
Matthew Barth35819382018-04-18 14:53:01 -0500207 }
208
Patrick Venture685efa12018-10-12 18:00:13 -0700209 static constexpr bool deferSignals = true;
210 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
211
Patrick Venture043d3232018-08-31 10:10:53 -0700212 iface =
213 std::make_shared<StatusObject>(bus, objPath.c_str(), deferSignals);
Matthew Barth35819382018-04-18 14:53:01 -0500214 // Set functional property
215 iface->functional(functional);
216
217 obj[InterfaceType::STATUS] = iface;
218 }
219
220 return iface;
221}
222
Patrick Ventureb28f4322018-09-14 10:19:14 -0700223void Sensor::unlockGpio()
224{
225 if (handle)
226 {
227 handle->setValues({1});
228 std::this_thread::sleep_for(pause);
229 }
230}
231
232void Sensor::lockGpio()
233{
234 if (handle)
235 {
236 handle->setValues({0});
237 }
238}
239
Matthew Barth35819382018-04-18 14:53:01 -0500240} // namespace sensor