blob: 619168873286a49e3a2f93f14a524c9ef355cdcc [file] [log] [blame]
Matthew Barthcb3daaf2018-05-07 15:03:16 -05001#include <cstring>
Matthew Barth35819382018-04-18 14:53:01 -05002#include <experimental/filesystem>
3
4#include <phosphor-logging/elog-errors.hpp>
5#include <xyz/openbmc_project/Sensor/Device/error.hpp>
6
Matthew Barthcb3daaf2018-05-07 15:03:16 -05007#include "config.h"
Matthew Barth35819382018-04-18 14:53:01 -05008#include "sensor.hpp"
9#include "sensorset.hpp"
10#include "hwmon.hpp"
Matthew Barthcb3daaf2018-05-07 15:03:16 -050011#include "env.hpp"
Matthew Barth35819382018-04-18 14:53:01 -050012#include "sysfs.hpp"
13
14namespace sensor
15{
16
Matthew Barthcb3daaf2018-05-07 15:03:16 -050017using namespace phosphor::logging;
18
Matthew Barth2e41b132018-05-07 14:15:45 -050019Sensor::Sensor(const SensorSet::key_type& sensor,
20 const hwmonio::HwmonIO& ioAccess,
21 const std::string& devPath) :
22 sensor(sensor),
23 ioAccess(ioAccess),
24 devPath(devPath)
Matthew Barth9c431062018-05-07 13:55:29 -050025{
Matthew Barthac473092018-05-07 14:41:46 -050026 auto gain = env::getEnv("GAIN", sensor);
27 if (!gain.empty())
28 {
29 sensorAdjusts.gain = std::stod(gain);
30 }
31
32 auto offset = env::getEnv("OFFSET", sensor);
33 if (!offset.empty())
34 {
35 sensorAdjusts.offset = std::stoi(offset);
36 }
37 auto senRmRCs = env::getEnv("REMOVERCS", sensor);
38 // Add sensor removal return codes defined per sensor
39 addRemoveRCs(senRmRCs);
Matthew Barth9c431062018-05-07 13:55:29 -050040}
41
Matthew Barthcb3daaf2018-05-07 15:03:16 -050042void Sensor::addRemoveRCs(const std::string& rcList)
43{
44 if (rcList.empty())
45 {
46 return;
47 }
48
49 // Convert to a char* for strtok
50 std::vector<char> rmRCs(rcList.c_str(),
51 rcList.c_str() + rcList.size() + 1);
52 auto rmRC = std::strtok(&rmRCs[0], ", ");
53 while (rmRC != nullptr)
54 {
55 try
56 {
57 sensorAdjusts.rmRCs.insert(std::stoi(rmRC));
58 }
59 catch (const std::logic_error& le)
60 {
61 // Unable to convert to int, continue to next token
62 std::string name = sensor.first + "_" + sensor.second;
63 log<level::INFO>("Unable to convert sensor removal return code",
64 entry("SENSOR=%s", name.c_str()),
65 entry("RC=%s", rmRC),
66 entry("EXCEPTION=%s", le.what()));
67 }
68 rmRC = std::strtok(nullptr, ", ");
69 }
70}
71
72int64_t Sensor::adjustValue(int64_t value)
73{
74// Because read doesn't have an out pointer to store errors.
75// let's assume negative values are errors if they have this
76// set.
77#ifdef NEGATIVE_ERRNO_ON_FAIL
78 if (value < 0)
79 {
80 return value;
81 }
82#endif
83
84 // Adjust based on gain and offset
85 value = static_cast<decltype(value)>(
86 static_cast<double>(value) * sensorAdjusts.gain
87 + sensorAdjusts.offset);
88
89 return value;
90}
91
92std::shared_ptr<ValueObject> Sensor::addValue(
93 const RetryIO& retryIO,
94 ObjectInfo& info)
95{
96 static constexpr bool deferSignals = true;
97
98 // Get the initial value for the value interface.
99 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
100 auto& obj = std::get<Object>(info);
101 auto& objPath = std::get<std::string>(info);
102
103 int64_t val = 0;
104 std::shared_ptr<StatusObject> statusIface = nullptr;
105 auto it = obj.find(InterfaceType::STATUS);
106 if (it != obj.end())
107 {
108 statusIface = std::experimental::any_cast<
109 std::shared_ptr<StatusObject>>(it->second);
110 }
111
112 // If there's no fault file or the sensor has a fault file and
113 // its status is functional, read the input value.
114 if (!statusIface || (statusIface && statusIface->functional()))
115 {
116 // Retry for up to a second if device is busy
117 // or has a transient error.
118 val = ioAccess.read(
119 sensor.first,
120 sensor.second,
121 hwmon::entry::cinput,
122 std::get<size_t>(retryIO),
123 std::get<std::chrono::milliseconds>(retryIO));
124 val = adjustValue(val);
125 }
126
127 auto iface = std::make_shared<ValueObject>(bus, objPath.c_str(), deferSignals);
128 iface->value(val);
129
130 hwmon::Attributes attrs;
131 if (hwmon::getAttributes(sensor.first, attrs))
132 {
133 iface->unit(hwmon::getUnit(attrs));
134 iface->scale(hwmon::getScale(attrs));
135 }
136
137 auto maxValue = env::getEnv("MAXVALUE", sensor);
138 if(!maxValue.empty())
139 {
140 iface->maxValue(std::stoll(maxValue));
141 }
142 auto minValue = env::getEnv("MINVALUE", sensor);
143 if(!minValue.empty())
144 {
145 iface->minValue(std::stoll(minValue));
146 }
147
148 obj[InterfaceType::VALUE] = iface;
149 return iface;
150}
151
Matthew Barth2e41b132018-05-07 14:15:45 -0500152std::shared_ptr<StatusObject> Sensor::addStatus(ObjectInfo& info)
Matthew Barth35819382018-04-18 14:53:01 -0500153{
154 namespace fs = std::experimental::filesystem;
155
156 std::shared_ptr<StatusObject> iface = nullptr;
157 static constexpr bool deferSignals = true;
158 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
159 auto& objPath = std::get<std::string>(info);
160 auto& obj = std::get<Object>(info);
161
162 // Check if fault sysfs file exists
163 std::string faultName = sensor.first;
164 std::string faultID = sensor.second;
165 std::string entry = hwmon::entry::fault;
166
167 auto sysfsFullPath = sysfs::make_sysfs_path(ioAccess.path(),
168 faultName,
169 faultID,
170 entry);
171 if (fs::exists(sysfsFullPath))
172 {
173 bool functional = true;
174 uint32_t fault = 0;
175 try
176 {
177 fault = ioAccess.read(faultName,
178 faultID,
179 entry,
180 hwmonio::retries,
181 hwmonio::delay);
182 if (fault != 0)
183 {
184 functional = false;
185 }
186 }
187 catch (const std::system_error& e)
188 {
Matthew Barth35819382018-04-18 14:53:01 -0500189 using namespace sdbusplus::xyz::openbmc_project::
190 Sensor::Device::Error;
191 using metadata = xyz::openbmc_project::Sensor::
192 Device::ReadFailure;
193
194 report<ReadFailure>(
195 metadata::CALLOUT_ERRNO(e.code().value()),
196 metadata::CALLOUT_DEVICE_PATH(devPath.c_str()));
197
198 log<level::INFO>("Logging failing sysfs file",
199 phosphor::logging::entry(
200 "FILE=%s", sysfsFullPath.c_str()));
201 }
202
203 iface = std::make_shared<StatusObject>(
204 bus,
205 objPath.c_str(),
206 deferSignals);
207 // Set functional property
208 iface->functional(functional);
209
210 obj[InterfaceType::STATUS] = iface;
211 }
212
213 return iface;
214}
215
216} // namespace sensor