blob: c33f05c0abdb76e3bf23c99678c55977c17a4c2e [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 Feist6714a252018-09-10 15:26:18 -070020#include <fstream>
21#include <iostream>
22#include <sdbusplus/asio/object_server.hpp>
23
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070024static constexpr size_t pwmMax = 255;
James Feist3a07f552019-08-27 13:34:54 -070025static constexpr double defaultPwm = 30.0;
James Feist6714a252018-09-10 15:26:18 -070026
Cheng C Yang916360b2019-05-07 18:47:16 +080027PwmSensor::PwmSensor(const std::string& name, const std::string& sysPath,
James Feist82bac4c2019-03-11 11:16:53 -070028 sdbusplus::asio::object_server& objectServer,
29 const std::string& sensorConfiguration) :
Cheng C Yang916360b2019-05-07 18:47:16 +080030 name(name),
31 sysPath(sysPath), objectServer(objectServer)
James Feist6714a252018-09-10 15:26:18 -070032{
James Feist6714a252018-09-10 15:26:18 -070033 // add interface under sensor and Control.FanPwm as Control is used
34 // in obmc project, also add sensor so it can be viewed as a sensor
35 sensorInterface = objectServer.add_interface(
36 "/xyz/openbmc_project/sensors/fan_pwm/" + name,
37 "xyz.openbmc_project.Sensor.Value");
38 uint32_t pwmValue = getValue(false);
James Feist3a07f552019-08-27 13:34:54 -070039 if (!pwmValue)
40 {
41 // default pwm to non 0
42 pwmValue = static_cast<uint32_t>(pwmMax * (defaultPwm / 100));
43 setValue(pwmValue);
44 }
James Feistb6c0b912019-07-09 12:21:44 -070045 double fValue = 100.0 * (static_cast<double>(pwmValue) / pwmMax);
James Feist6714a252018-09-10 15:26:18 -070046 sensorInterface->register_property(
47 "Value", fValue,
48 [this](const double& req, double& resp) {
49 if (req > 100 || req < 0)
50 {
51 throw std::runtime_error("Value out of range");
52 return -1;
53 }
James Feist46c5c1d2018-11-30 12:04:07 -080054 if (req == resp)
55 {
56 return 1;
57 }
James Feist6714a252018-09-10 15:26:18 -070058 double value = (req / 100) * pwmMax;
59 setValue(static_cast<int>(value));
60 resp = req;
James Feist46c5c1d2018-11-30 12:04:07 -080061
62 controlInterface->signal_property("Target");
63
James Feist6714a252018-09-10 15:26:18 -070064 return 1;
65 },
66 [this](double& curVal) {
James Feistb6c0b912019-07-09 12:21:44 -070067 double value = 100.0 * (static_cast<double>(getValue()) / pwmMax);
James Feist46c5c1d2018-11-30 12:04:07 -080068 if (curVal != value)
69 {
70 curVal = value;
71 controlInterface->signal_property("Target");
72 sensorInterface->signal_property("Value");
73 }
74
James Feist6714a252018-09-10 15:26:18 -070075 return curVal;
76 });
77 // pwm sensor interface is in percent
78 sensorInterface->register_property("MaxValue", static_cast<int64_t>(100));
79 sensorInterface->register_property("MinValue", static_cast<int64_t>(0));
80
81 controlInterface = objectServer.add_interface(
82 "/xyz/openbmc_project/control/fanpwm/" + name,
83 "xyz.openbmc_project.Control.FanPwm");
84 controlInterface->register_property(
85 "Target", static_cast<uint64_t>(pwmValue),
86 [this](const uint64_t& req, uint64_t& resp) {
James Feistb6c0b912019-07-09 12:21:44 -070087 if (req > pwmMax)
James Feist6714a252018-09-10 15:26:18 -070088 {
89 throw std::runtime_error("Value out of range");
90 return -1;
91 }
James Feist46c5c1d2018-11-30 12:04:07 -080092 if (req == resp)
93 {
94 return 1;
95 }
James Feist6714a252018-09-10 15:26:18 -070096 setValue(req);
97 resp = req;
James Feist46c5c1d2018-11-30 12:04:07 -080098
99 sensorInterface->signal_property("Value");
100
James Feist6714a252018-09-10 15:26:18 -0700101 return 1;
102 },
103 [this](uint64_t& curVal) {
James Feist46c5c1d2018-11-30 12:04:07 -0800104 uint64_t value = getValue();
105 if (curVal != value)
106 {
107 curVal = value;
108 controlInterface->signal_property("Target");
109 sensorInterface->signal_property("Value");
110 }
111
James Feist6714a252018-09-10 15:26:18 -0700112 return curVal;
113 });
114 sensorInterface->initialize();
115 controlInterface->initialize();
James Feist82bac4c2019-03-11 11:16:53 -0700116
117 association = objectServer.add_interface(
118 "/xyz/openbmc_project/sensors/fan_pwm/" + name,
119 "org.openbmc.Associations");
120 createAssociation(association, sensorConfiguration);
James Feist6714a252018-09-10 15:26:18 -0700121}
122PwmSensor::~PwmSensor()
123{
124 objectServer.remove_interface(sensorInterface);
125 objectServer.remove_interface(controlInterface);
126}
127
128void PwmSensor::setValue(uint32_t value)
129{
130 std::ofstream ref(sysPath);
131 if (!ref.good())
132 {
133 throw std::runtime_error("Bad Write File");
134 return;
135 }
136 ref << value;
137}
138
139// on success returns pwm, on failure throws except on initialization, where it
140// prints an error and returns 0
141uint32_t PwmSensor::getValue(bool errThrow)
142{
143 std::ifstream ref(sysPath);
144 if (!ref.good())
145 {
146 return -1;
147 }
148 std::string line;
149 if (!std::getline(ref, line))
150 {
151 return -1;
152 }
153 try
154 {
155 uint32_t value = std::stoi(line);
156 return value;
157 }
James Feistb6c0b912019-07-09 12:21:44 -0700158 catch (std::invalid_argument&)
James Feist6714a252018-09-10 15:26:18 -0700159 {
160 std::cerr << "Error reading pwm at " << sysPath << "\n";
161 // throw if not initial read to be caught by dbus bindings
162 if (errThrow)
163 {
164 throw std::runtime_error("Bad Read");
165 }
166 }
167 return 0;
168}