blob: b157d52f6676b7056a6854f689341c1d5147ec87 [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;
25static constexpr size_t pwmMin = 0;
James Feist6714a252018-09-10 15:26:18 -070026
27PwmSensor::PwmSensor(const std::string& sysPath,
James Feist82bac4c2019-03-11 11:16:53 -070028 sdbusplus::asio::object_server& objectServer,
29 const std::string& sensorConfiguration) :
James Feist6714a252018-09-10 15:26:18 -070030 sysPath(sysPath),
31 objectServer(objectServer)
32{
33 // strip off index from path
34 name = "Pwm_" + sysPath.substr(sysPath.find_last_of("pwm") + 1);
35
36 // add interface under sensor and Control.FanPwm as Control is used
37 // in obmc project, also add sensor so it can be viewed as a sensor
38 sensorInterface = objectServer.add_interface(
39 "/xyz/openbmc_project/sensors/fan_pwm/" + name,
40 "xyz.openbmc_project.Sensor.Value");
41 uint32_t pwmValue = getValue(false);
42 double fValue = 100.0 * (static_cast<float>(pwmValue) / pwmMax);
43 sensorInterface->register_property(
44 "Value", fValue,
45 [this](const double& req, double& resp) {
46 if (req > 100 || req < 0)
47 {
48 throw std::runtime_error("Value out of range");
49 return -1;
50 }
James Feist46c5c1d2018-11-30 12:04:07 -080051 if (req == resp)
52 {
53 return 1;
54 }
James Feist6714a252018-09-10 15:26:18 -070055 double value = (req / 100) * pwmMax;
56 setValue(static_cast<int>(value));
57 resp = req;
James Feist46c5c1d2018-11-30 12:04:07 -080058
59 controlInterface->signal_property("Target");
60
James Feist6714a252018-09-10 15:26:18 -070061 return 1;
62 },
63 [this](double& curVal) {
64 float value = 100.0 * (static_cast<float>(getValue()) / pwmMax);
James Feist46c5c1d2018-11-30 12:04:07 -080065 if (curVal != value)
66 {
67 curVal = value;
68 controlInterface->signal_property("Target");
69 sensorInterface->signal_property("Value");
70 }
71
James Feist6714a252018-09-10 15:26:18 -070072 return curVal;
73 });
74 // pwm sensor interface is in percent
75 sensorInterface->register_property("MaxValue", static_cast<int64_t>(100));
76 sensorInterface->register_property("MinValue", static_cast<int64_t>(0));
77
78 controlInterface = objectServer.add_interface(
79 "/xyz/openbmc_project/control/fanpwm/" + name,
80 "xyz.openbmc_project.Control.FanPwm");
81 controlInterface->register_property(
82 "Target", static_cast<uint64_t>(pwmValue),
83 [this](const uint64_t& req, uint64_t& resp) {
84 if (req > pwmMax || req < pwmMin)
85 {
86 throw std::runtime_error("Value out of range");
87 return -1;
88 }
James Feist46c5c1d2018-11-30 12:04:07 -080089 if (req == resp)
90 {
91 return 1;
92 }
James Feist6714a252018-09-10 15:26:18 -070093 setValue(req);
94 resp = req;
James Feist46c5c1d2018-11-30 12:04:07 -080095
96 sensorInterface->signal_property("Value");
97
James Feist6714a252018-09-10 15:26:18 -070098 return 1;
99 },
100 [this](uint64_t& curVal) {
James Feist46c5c1d2018-11-30 12:04:07 -0800101 uint64_t value = getValue();
102 if (curVal != value)
103 {
104 curVal = value;
105 controlInterface->signal_property("Target");
106 sensorInterface->signal_property("Value");
107 }
108
James Feist6714a252018-09-10 15:26:18 -0700109 return curVal;
110 });
111 sensorInterface->initialize();
112 controlInterface->initialize();
James Feist82bac4c2019-03-11 11:16:53 -0700113
114 association = objectServer.add_interface(
115 "/xyz/openbmc_project/sensors/fan_pwm/" + name,
116 "org.openbmc.Associations");
117 createAssociation(association, sensorConfiguration);
James Feist6714a252018-09-10 15:26:18 -0700118}
119PwmSensor::~PwmSensor()
120{
121 objectServer.remove_interface(sensorInterface);
122 objectServer.remove_interface(controlInterface);
123}
124
125void PwmSensor::setValue(uint32_t value)
126{
127 std::ofstream ref(sysPath);
128 if (!ref.good())
129 {
130 throw std::runtime_error("Bad Write File");
131 return;
132 }
133 ref << value;
134}
135
136// on success returns pwm, on failure throws except on initialization, where it
137// prints an error and returns 0
138uint32_t PwmSensor::getValue(bool errThrow)
139{
140 std::ifstream ref(sysPath);
141 if (!ref.good())
142 {
143 return -1;
144 }
145 std::string line;
146 if (!std::getline(ref, line))
147 {
148 return -1;
149 }
150 try
151 {
152 uint32_t value = std::stoi(line);
153 return value;
154 }
155 catch (std::invalid_argument)
156 {
157 std::cerr << "Error reading pwm at " << sysPath << "\n";
158 // throw if not initial read to be caught by dbus bindings
159 if (errThrow)
160 {
161 throw std::runtime_error("Bad Read");
162 }
163 }
164 return 0;
165}