blob: 0c5d439d32c98719b622847285ada2ab2fffb706 [file] [log] [blame]
James Feist6714a252018-09-10 15:26:18 -07001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
James Feist82bac4c2019-03-11 11:16:53 -070016#include "PwmSensor.hpp"
17
18#include "Utils.hpp"
19
James Feist38fb5982020-05-28 10:09:54 -070020#include <sdbusplus/asio/object_server.hpp>
21
James Feist6714a252018-09-10 15:26:18 -070022#include <fstream>
23#include <iostream>
Patrick Venture96e97db2019-10-31 13:44:38 -070024#include <stdexcept>
25#include <string>
James Feist6714a252018-09-10 15:26:18 -070026
Kuiying Wang105a1972020-08-28 19:07:53 +080027static constexpr size_t sysPwmMax = 255;
28static constexpr size_t psuPwmMax = 100;
James Feist3a07f552019-08-27 13:34:54 -070029static constexpr double defaultPwm = 30.0;
James Feist6714a252018-09-10 15:26:18 -070030
Cheng C Yang916360b2019-05-07 18:47:16 +080031PwmSensor::PwmSensor(const std::string& name, const std::string& sysPath,
AppaRao Pulid9d8caf2020-02-27 20:56:59 +053032 std::shared_ptr<sdbusplus::asio::connection>& conn,
James Feist82bac4c2019-03-11 11:16:53 -070033 sdbusplus::asio::object_server& objectServer,
AppaRao Pulid9d8caf2020-02-27 20:56:59 +053034 const std::string& sensorConfiguration,
35 const std::string& sensorType) :
Brad Bishopfbb44ad2019-11-08 09:42:37 -050036 sysPath(sysPath),
37 objectServer(objectServer), name(name)
James Feist6714a252018-09-10 15:26:18 -070038{
James Feist6714a252018-09-10 15:26:18 -070039 // add interface under sensor and Control.FanPwm as Control is used
40 // in obmc project, also add sensor so it can be viewed as a sensor
41 sensorInterface = objectServer.add_interface(
42 "/xyz/openbmc_project/sensors/fan_pwm/" + name,
43 "xyz.openbmc_project.Sensor.Value");
44 uint32_t pwmValue = getValue(false);
Kuiying Wang105a1972020-08-28 19:07:53 +080045 if (sensorType == "PSU")
46 {
47 pwmMax = psuPwmMax;
48 }
49 else
50 {
51 pwmMax = sysPwmMax;
52 }
53
James Feist3a07f552019-08-27 13:34:54 -070054 if (!pwmValue)
55 {
56 // default pwm to non 0
57 pwmValue = static_cast<uint32_t>(pwmMax * (defaultPwm / 100));
58 setValue(pwmValue);
59 }
James Feistb6c0b912019-07-09 12:21:44 -070060 double fValue = 100.0 * (static_cast<double>(pwmValue) / pwmMax);
James Feist6714a252018-09-10 15:26:18 -070061 sensorInterface->register_property(
62 "Value", fValue,
63 [this](const double& req, double& resp) {
64 if (req > 100 || req < 0)
65 {
66 throw std::runtime_error("Value out of range");
67 return -1;
68 }
James Feist46c5c1d2018-11-30 12:04:07 -080069 if (req == resp)
70 {
71 return 1;
72 }
James Feist6714a252018-09-10 15:26:18 -070073 double value = (req / 100) * pwmMax;
74 setValue(static_cast<int>(value));
75 resp = req;
James Feist46c5c1d2018-11-30 12:04:07 -080076
77 controlInterface->signal_property("Target");
78
James Feist6714a252018-09-10 15:26:18 -070079 return 1;
80 },
81 [this](double& curVal) {
James Feistb6c0b912019-07-09 12:21:44 -070082 double value = 100.0 * (static_cast<double>(getValue()) / pwmMax);
James Feist46c5c1d2018-11-30 12:04:07 -080083 if (curVal != value)
84 {
85 curVal = value;
86 controlInterface->signal_property("Target");
87 sensorInterface->signal_property("Value");
88 }
89
James Feist6714a252018-09-10 15:26:18 -070090 return curVal;
91 });
92 // pwm sensor interface is in percent
93 sensorInterface->register_property("MaxValue", static_cast<int64_t>(100));
94 sensorInterface->register_property("MinValue", static_cast<int64_t>(0));
95
96 controlInterface = objectServer.add_interface(
97 "/xyz/openbmc_project/control/fanpwm/" + name,
98 "xyz.openbmc_project.Control.FanPwm");
99 controlInterface->register_property(
100 "Target", static_cast<uint64_t>(pwmValue),
101 [this](const uint64_t& req, uint64_t& resp) {
James Feistb6c0b912019-07-09 12:21:44 -0700102 if (req > pwmMax)
James Feist6714a252018-09-10 15:26:18 -0700103 {
104 throw std::runtime_error("Value out of range");
105 return -1;
106 }
James Feist46c5c1d2018-11-30 12:04:07 -0800107 if (req == resp)
108 {
109 return 1;
110 }
James Feist6714a252018-09-10 15:26:18 -0700111 setValue(req);
112 resp = req;
James Feist46c5c1d2018-11-30 12:04:07 -0800113
114 sensorInterface->signal_property("Value");
115
James Feist6714a252018-09-10 15:26:18 -0700116 return 1;
117 },
118 [this](uint64_t& curVal) {
James Feist46c5c1d2018-11-30 12:04:07 -0800119 uint64_t value = getValue();
120 if (curVal != value)
121 {
122 curVal = value;
123 controlInterface->signal_property("Target");
124 sensorInterface->signal_property("Value");
125 }
126
James Feist6714a252018-09-10 15:26:18 -0700127 return curVal;
128 });
129 sensorInterface->initialize();
130 controlInterface->initialize();
James Feist82bac4c2019-03-11 11:16:53 -0700131
132 association = objectServer.add_interface(
James Feist2adc95c2019-09-30 14:55:28 -0700133 "/xyz/openbmc_project/sensors/fan_pwm/" + name, association::interface);
AppaRao Pulid9d8caf2020-02-27 20:56:59 +0530134
135 // PowerSupply sensors should be associated with chassis board path
136 // and inventory along with psu object.
137 if (sensorType == "PSU")
138 {
139 createInventoryAssoc(conn, association, sensorConfiguration);
140 }
141 else
142 {
143 createAssociation(association, sensorConfiguration);
144 }
James Feist6714a252018-09-10 15:26:18 -0700145}
146PwmSensor::~PwmSensor()
147{
148 objectServer.remove_interface(sensorInterface);
149 objectServer.remove_interface(controlInterface);
AppaRao Pulid9d8caf2020-02-27 20:56:59 +0530150 objectServer.remove_interface(association);
James Feist6714a252018-09-10 15:26:18 -0700151}
152
153void PwmSensor::setValue(uint32_t value)
154{
155 std::ofstream ref(sysPath);
156 if (!ref.good())
157 {
158 throw std::runtime_error("Bad Write File");
James Feist6714a252018-09-10 15:26:18 -0700159 }
160 ref << value;
161}
162
163// on success returns pwm, on failure throws except on initialization, where it
164// prints an error and returns 0
165uint32_t PwmSensor::getValue(bool errThrow)
166{
167 std::ifstream ref(sysPath);
168 if (!ref.good())
169 {
170 return -1;
171 }
172 std::string line;
173 if (!std::getline(ref, line))
174 {
175 return -1;
176 }
177 try
178 {
179 uint32_t value = std::stoi(line);
180 return value;
181 }
James Feistb6c0b912019-07-09 12:21:44 -0700182 catch (std::invalid_argument&)
James Feist6714a252018-09-10 15:26:18 -0700183 {
184 std::cerr << "Error reading pwm at " << sysPath << "\n";
185 // throw if not initial read to be caught by dbus bindings
186 if (errThrow)
187 {
188 throw std::runtime_error("Bad Read");
189 }
190 }
191 return 0;
192}