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