blob: 5aa729eeef3652feb9943d005e037d978dde5778 [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>
Patrick Venture96e97db2019-10-31 13:44:38 -070023#include <stdexcept>
24#include <string>
James Feist6714a252018-09-10 15:26:18 -070025
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070026static constexpr size_t pwmMax = 255;
James Feist3a07f552019-08-27 13:34:54 -070027static constexpr double defaultPwm = 30.0;
James Feist6714a252018-09-10 15:26:18 -070028
Cheng C Yang916360b2019-05-07 18:47:16 +080029PwmSensor::PwmSensor(const std::string& name, const std::string& sysPath,
James Feist82bac4c2019-03-11 11:16:53 -070030 sdbusplus::asio::object_server& objectServer,
31 const std::string& sensorConfiguration) :
Brad Bishopfbb44ad2019-11-08 09:42:37 -050032 sysPath(sysPath),
33 objectServer(objectServer), name(name)
James Feist6714a252018-09-10 15:26:18 -070034{
James Feist6714a252018-09-10 15:26:18 -070035 // add interface under sensor and Control.FanPwm as Control is used
36 // in obmc project, also add sensor so it can be viewed as a sensor
37 sensorInterface = objectServer.add_interface(
38 "/xyz/openbmc_project/sensors/fan_pwm/" + name,
39 "xyz.openbmc_project.Sensor.Value");
40 uint32_t pwmValue = getValue(false);
James Feist3a07f552019-08-27 13:34:54 -070041 if (!pwmValue)
42 {
43 // default pwm to non 0
44 pwmValue = static_cast<uint32_t>(pwmMax * (defaultPwm / 100));
45 setValue(pwmValue);
46 }
James Feistb6c0b912019-07-09 12:21:44 -070047 double fValue = 100.0 * (static_cast<double>(pwmValue) / pwmMax);
James Feist6714a252018-09-10 15:26:18 -070048 sensorInterface->register_property(
49 "Value", fValue,
50 [this](const double& req, double& resp) {
51 if (req > 100 || req < 0)
52 {
53 throw std::runtime_error("Value out of range");
54 return -1;
55 }
James Feist46c5c1d2018-11-30 12:04:07 -080056 if (req == resp)
57 {
58 return 1;
59 }
James Feist6714a252018-09-10 15:26:18 -070060 double value = (req / 100) * pwmMax;
61 setValue(static_cast<int>(value));
62 resp = req;
James Feist46c5c1d2018-11-30 12:04:07 -080063
64 controlInterface->signal_property("Target");
65
James Feist6714a252018-09-10 15:26:18 -070066 return 1;
67 },
68 [this](double& curVal) {
James Feistb6c0b912019-07-09 12:21:44 -070069 double value = 100.0 * (static_cast<double>(getValue()) / pwmMax);
James Feist46c5c1d2018-11-30 12:04:07 -080070 if (curVal != value)
71 {
72 curVal = value;
73 controlInterface->signal_property("Target");
74 sensorInterface->signal_property("Value");
75 }
76
James Feist6714a252018-09-10 15:26:18 -070077 return curVal;
78 });
79 // pwm sensor interface is in percent
80 sensorInterface->register_property("MaxValue", static_cast<int64_t>(100));
81 sensorInterface->register_property("MinValue", static_cast<int64_t>(0));
82
83 controlInterface = objectServer.add_interface(
84 "/xyz/openbmc_project/control/fanpwm/" + name,
85 "xyz.openbmc_project.Control.FanPwm");
86 controlInterface->register_property(
87 "Target", static_cast<uint64_t>(pwmValue),
88 [this](const uint64_t& req, uint64_t& resp) {
James Feistb6c0b912019-07-09 12:21:44 -070089 if (req > pwmMax)
James Feist6714a252018-09-10 15:26:18 -070090 {
91 throw std::runtime_error("Value out of range");
92 return -1;
93 }
James Feist46c5c1d2018-11-30 12:04:07 -080094 if (req == resp)
95 {
96 return 1;
97 }
James Feist6714a252018-09-10 15:26:18 -070098 setValue(req);
99 resp = req;
James Feist46c5c1d2018-11-30 12:04:07 -0800100
101 sensorInterface->signal_property("Value");
102
James Feist6714a252018-09-10 15:26:18 -0700103 return 1;
104 },
105 [this](uint64_t& curVal) {
James Feist46c5c1d2018-11-30 12:04:07 -0800106 uint64_t value = getValue();
107 if (curVal != value)
108 {
109 curVal = value;
110 controlInterface->signal_property("Target");
111 sensorInterface->signal_property("Value");
112 }
113
James Feist6714a252018-09-10 15:26:18 -0700114 return curVal;
115 });
116 sensorInterface->initialize();
117 controlInterface->initialize();
James Feist82bac4c2019-03-11 11:16:53 -0700118
119 association = objectServer.add_interface(
James Feist2adc95c2019-09-30 14:55:28 -0700120 "/xyz/openbmc_project/sensors/fan_pwm/" + name, association::interface);
James Feist82bac4c2019-03-11 11:16:53 -0700121 createAssociation(association, sensorConfiguration);
James Feist6714a252018-09-10 15:26:18 -0700122}
123PwmSensor::~PwmSensor()
124{
125 objectServer.remove_interface(sensorInterface);
126 objectServer.remove_interface(controlInterface);
127}
128
129void PwmSensor::setValue(uint32_t value)
130{
131 std::ofstream ref(sysPath);
132 if (!ref.good())
133 {
134 throw std::runtime_error("Bad Write File");
James Feist6714a252018-09-10 15:26:18 -0700135 }
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}