blob: 063c3595065853218aa86109f1ef10e6290c3cd3 [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(
James Feist2adc95c2019-09-30 14:55:28 -0700118 "/xyz/openbmc_project/sensors/fan_pwm/" + name, association::interface);
James Feist82bac4c2019-03-11 11:16:53 -0700119 createAssociation(association, sensorConfiguration);
James Feist6714a252018-09-10 15:26:18 -0700120}
121PwmSensor::~PwmSensor()
122{
123 objectServer.remove_interface(sensorInterface);
124 objectServer.remove_interface(controlInterface);
125}
126
127void PwmSensor::setValue(uint32_t value)
128{
129 std::ofstream ref(sysPath);
130 if (!ref.good())
131 {
132 throw std::runtime_error("Bad Write File");
133 return;
134 }
135 ref << value;
136}
137
138// on success returns pwm, on failure throws except on initialization, where it
139// prints an error and returns 0
140uint32_t PwmSensor::getValue(bool errThrow)
141{
142 std::ifstream ref(sysPath);
143 if (!ref.good())
144 {
145 return -1;
146 }
147 std::string line;
148 if (!std::getline(ref, line))
149 {
150 return -1;
151 }
152 try
153 {
154 uint32_t value = std::stoi(line);
155 return value;
156 }
James Feistb6c0b912019-07-09 12:21:44 -0700157 catch (std::invalid_argument&)
James Feist6714a252018-09-10 15:26:18 -0700158 {
159 std::cerr << "Error reading pwm at " << sysPath << "\n";
160 // throw if not initial read to be caught by dbus bindings
161 if (errThrow)
162 {
163 throw std::runtime_error("Bad Read");
164 }
165 }
166 return 0;
167}