blob: bc5f34dd3298fa1169dbe688da97d3bcf10aa131 [file] [log] [blame]
Patrick Venture043d3232018-08-31 10:10:53 -07001#include "config.h"
2
3#include "sensor.hpp"
4
5#include "env.hpp"
6#include "hwmon.hpp"
7#include "sensorset.hpp"
8#include "sysfs.hpp"
9
Matthew Barthcb3daaf2018-05-07 15:03:16 -050010#include <cstring>
Matthew Barth35819382018-04-18 14:53:01 -050011#include <experimental/filesystem>
Matthew Barth35819382018-04-18 14:53:01 -050012#include <phosphor-logging/elog-errors.hpp>
13#include <xyz/openbmc_project/Sensor/Device/error.hpp>
14
Matthew Barth35819382018-04-18 14:53:01 -050015namespace sensor
16{
17
Matthew Barthcb3daaf2018-05-07 15:03:16 -050018using namespace phosphor::logging;
19
Matthew Barth2e41b132018-05-07 14:15:45 -050020Sensor::Sensor(const SensorSet::key_type& sensor,
Patrick Venture043d3232018-08-31 10:10:53 -070021 const hwmonio::HwmonIO& ioAccess, const std::string& devPath) :
Matthew Barth2e41b132018-05-07 14:15:45 -050022 sensor(sensor),
Patrick Venture043d3232018-08-31 10:10:53 -070023 ioAccess(ioAccess), devPath(devPath)
Matthew Barth9c431062018-05-07 13:55:29 -050024{
Matthew Barthac473092018-05-07 14:41:46 -050025 auto gain = env::getEnv("GAIN", sensor);
26 if (!gain.empty())
27 {
28 sensorAdjusts.gain = std::stod(gain);
29 }
30
31 auto offset = env::getEnv("OFFSET", sensor);
32 if (!offset.empty())
33 {
34 sensorAdjusts.offset = std::stoi(offset);
35 }
36 auto senRmRCs = env::getEnv("REMOVERCS", sensor);
37 // Add sensor removal return codes defined per sensor
38 addRemoveRCs(senRmRCs);
Matthew Barth9c431062018-05-07 13:55:29 -050039}
40
Matthew Barthcb3daaf2018-05-07 15:03:16 -050041void Sensor::addRemoveRCs(const std::string& rcList)
42{
43 if (rcList.empty())
44 {
45 return;
46 }
47
48 // Convert to a char* for strtok
Patrick Venture043d3232018-08-31 10:10:53 -070049 std::vector<char> rmRCs(rcList.c_str(), rcList.c_str() + rcList.size() + 1);
Matthew Barthcb3daaf2018-05-07 15:03:16 -050050 auto rmRC = std::strtok(&rmRCs[0], ", ");
51 while (rmRC != nullptr)
52 {
53 try
54 {
55 sensorAdjusts.rmRCs.insert(std::stoi(rmRC));
56 }
57 catch (const std::logic_error& le)
58 {
59 // Unable to convert to int, continue to next token
60 std::string name = sensor.first + "_" + sensor.second;
61 log<level::INFO>("Unable to convert sensor removal return code",
62 entry("SENSOR=%s", name.c_str()),
63 entry("RC=%s", rmRC),
64 entry("EXCEPTION=%s", le.what()));
65 }
66 rmRC = std::strtok(nullptr, ", ");
67 }
68}
69
70int64_t Sensor::adjustValue(int64_t value)
71{
72// Because read doesn't have an out pointer to store errors.
73// let's assume negative values are errors if they have this
74// set.
75#ifdef NEGATIVE_ERRNO_ON_FAIL
76 if (value < 0)
77 {
78 return value;
79 }
80#endif
81
82 // Adjust based on gain and offset
83 value = static_cast<decltype(value)>(
Patrick Venture043d3232018-08-31 10:10:53 -070084 static_cast<double>(value) * sensorAdjusts.gain + sensorAdjusts.offset);
Matthew Barthcb3daaf2018-05-07 15:03:16 -050085
86 return value;
87}
88
Patrick Venture043d3232018-08-31 10:10:53 -070089std::shared_ptr<ValueObject> Sensor::addValue(const RetryIO& retryIO,
90 ObjectInfo& info)
Matthew Barthcb3daaf2018-05-07 15:03:16 -050091{
92 static constexpr bool deferSignals = true;
93
94 // Get the initial value for the value interface.
95 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
96 auto& obj = std::get<Object>(info);
97 auto& objPath = std::get<std::string>(info);
98
99 int64_t val = 0;
100 std::shared_ptr<StatusObject> statusIface = nullptr;
101 auto it = obj.find(InterfaceType::STATUS);
102 if (it != obj.end())
103 {
Patrick Venture043d3232018-08-31 10:10:53 -0700104 statusIface =
105 std::experimental::any_cast<std::shared_ptr<StatusObject>>(
106 it->second);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500107 }
108
109 // If there's no fault file or the sensor has a fault file and
110 // its status is functional, read the input value.
111 if (!statusIface || (statusIface && statusIface->functional()))
112 {
113 // Retry for up to a second if device is busy
114 // or has a transient error.
Patrick Venture043d3232018-08-31 10:10:53 -0700115 val = ioAccess.read(sensor.first, sensor.second, hwmon::entry::cinput,
116 std::get<size_t>(retryIO),
117 std::get<std::chrono::milliseconds>(retryIO));
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500118 val = adjustValue(val);
119 }
120
Patrick Venture043d3232018-08-31 10:10:53 -0700121 auto iface =
122 std::make_shared<ValueObject>(bus, objPath.c_str(), deferSignals);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500123 iface->value(val);
124
125 hwmon::Attributes attrs;
126 if (hwmon::getAttributes(sensor.first, attrs))
127 {
128 iface->unit(hwmon::getUnit(attrs));
129 iface->scale(hwmon::getScale(attrs));
130 }
131
132 auto maxValue = env::getEnv("MAXVALUE", sensor);
Patrick Venture043d3232018-08-31 10:10:53 -0700133 if (!maxValue.empty())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500134 {
135 iface->maxValue(std::stoll(maxValue));
136 }
137 auto minValue = env::getEnv("MINVALUE", sensor);
Patrick Venture043d3232018-08-31 10:10:53 -0700138 if (!minValue.empty())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500139 {
140 iface->minValue(std::stoll(minValue));
141 }
142
143 obj[InterfaceType::VALUE] = iface;
144 return iface;
145}
146
Matthew Barth2e41b132018-05-07 14:15:45 -0500147std::shared_ptr<StatusObject> Sensor::addStatus(ObjectInfo& info)
Matthew Barth35819382018-04-18 14:53:01 -0500148{
149 namespace fs = std::experimental::filesystem;
150
151 std::shared_ptr<StatusObject> iface = nullptr;
152 static constexpr bool deferSignals = true;
153 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
154 auto& objPath = std::get<std::string>(info);
155 auto& obj = std::get<Object>(info);
156
157 // Check if fault sysfs file exists
158 std::string faultName = sensor.first;
159 std::string faultID = sensor.second;
160 std::string entry = hwmon::entry::fault;
161
Patrick Venture043d3232018-08-31 10:10:53 -0700162 auto sysfsFullPath =
163 sysfs::make_sysfs_path(ioAccess.path(), faultName, faultID, entry);
Matthew Barth35819382018-04-18 14:53:01 -0500164 if (fs::exists(sysfsFullPath))
165 {
166 bool functional = true;
167 uint32_t fault = 0;
168 try
169 {
Patrick Venture043d3232018-08-31 10:10:53 -0700170 fault = ioAccess.read(faultName, faultID, entry, hwmonio::retries,
Matthew Barth35819382018-04-18 14:53:01 -0500171 hwmonio::delay);
172 if (fault != 0)
173 {
174 functional = false;
175 }
176 }
177 catch (const std::system_error& e)
178 {
Patrick Venture043d3232018-08-31 10:10:53 -0700179 using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::
180 Error;
181 using metadata = xyz::openbmc_project::Sensor::Device::ReadFailure;
Matthew Barth35819382018-04-18 14:53:01 -0500182
Patrick Venture043d3232018-08-31 10:10:53 -0700183 report<ReadFailure>(metadata::CALLOUT_ERRNO(e.code().value()),
184 metadata::CALLOUT_DEVICE_PATH(devPath.c_str()));
Matthew Barth35819382018-04-18 14:53:01 -0500185
Patrick Venture043d3232018-08-31 10:10:53 -0700186 log<level::INFO>(
187 "Logging failing sysfs file",
188 phosphor::logging::entry("FILE=%s", sysfsFullPath.c_str()));
Matthew Barth35819382018-04-18 14:53:01 -0500189 }
190
Patrick Venture043d3232018-08-31 10:10:53 -0700191 iface =
192 std::make_shared<StatusObject>(bus, objPath.c_str(), deferSignals);
Matthew Barth35819382018-04-18 14:53:01 -0500193 // Set functional property
194 iface->functional(functional);
195
196 obj[InterfaceType::STATUS] = iface;
197 }
198
199 return iface;
200}
201
202} // namespace sensor