blob: 047d5eadf5ac6266f0fe09171514e957977c205f [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*/
16#include <PwmSensor.hpp>
17#include <fstream>
18#include <iostream>
19#include <sdbusplus/asio/object_server.hpp>
20
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070021static constexpr size_t pwmMax = 255;
22static constexpr size_t pwmMin = 0;
James Feist6714a252018-09-10 15:26:18 -070023
24PwmSensor::PwmSensor(const std::string& sysPath,
25 sdbusplus::asio::object_server& objectServer) :
26 sysPath(sysPath),
27 objectServer(objectServer)
28{
29 // strip off index from path
30 name = "Pwm_" + sysPath.substr(sysPath.find_last_of("pwm") + 1);
31
32 // add interface under sensor and Control.FanPwm as Control is used
33 // in obmc project, also add sensor so it can be viewed as a sensor
34 sensorInterface = objectServer.add_interface(
35 "/xyz/openbmc_project/sensors/fan_pwm/" + name,
36 "xyz.openbmc_project.Sensor.Value");
37 uint32_t pwmValue = getValue(false);
38 double fValue = 100.0 * (static_cast<float>(pwmValue) / pwmMax);
39 sensorInterface->register_property(
40 "Value", fValue,
41 [this](const double& req, double& resp) {
42 if (req > 100 || req < 0)
43 {
44 throw std::runtime_error("Value out of range");
45 return -1;
46 }
James Feist46c5c1d2018-11-30 12:04:07 -080047 if (req == resp)
48 {
49 return 1;
50 }
James Feist6714a252018-09-10 15:26:18 -070051 double value = (req / 100) * pwmMax;
52 setValue(static_cast<int>(value));
53 resp = req;
James Feist46c5c1d2018-11-30 12:04:07 -080054
55 controlInterface->signal_property("Target");
56
James Feist6714a252018-09-10 15:26:18 -070057 return 1;
58 },
59 [this](double& curVal) {
60 float value = 100.0 * (static_cast<float>(getValue()) / pwmMax);
James Feist46c5c1d2018-11-30 12:04:07 -080061 if (curVal != value)
62 {
63 curVal = value;
64 controlInterface->signal_property("Target");
65 sensorInterface->signal_property("Value");
66 }
67
James Feist6714a252018-09-10 15:26:18 -070068 return curVal;
69 });
70 // pwm sensor interface is in percent
71 sensorInterface->register_property("MaxValue", static_cast<int64_t>(100));
72 sensorInterface->register_property("MinValue", static_cast<int64_t>(0));
73
74 controlInterface = objectServer.add_interface(
75 "/xyz/openbmc_project/control/fanpwm/" + name,
76 "xyz.openbmc_project.Control.FanPwm");
77 controlInterface->register_property(
78 "Target", static_cast<uint64_t>(pwmValue),
79 [this](const uint64_t& req, uint64_t& resp) {
80 if (req > pwmMax || req < pwmMin)
81 {
82 throw std::runtime_error("Value out of range");
83 return -1;
84 }
James Feist46c5c1d2018-11-30 12:04:07 -080085 if (req == resp)
86 {
87 return 1;
88 }
James Feist6714a252018-09-10 15:26:18 -070089 setValue(req);
90 resp = req;
James Feist46c5c1d2018-11-30 12:04:07 -080091
92 sensorInterface->signal_property("Value");
93
James Feist6714a252018-09-10 15:26:18 -070094 return 1;
95 },
96 [this](uint64_t& curVal) {
James Feist46c5c1d2018-11-30 12:04:07 -080097 uint64_t value = getValue();
98 if (curVal != value)
99 {
100 curVal = value;
101 controlInterface->signal_property("Target");
102 sensorInterface->signal_property("Value");
103 }
104
James Feist6714a252018-09-10 15:26:18 -0700105 return curVal;
106 });
107 sensorInterface->initialize();
108 controlInterface->initialize();
109}
110PwmSensor::~PwmSensor()
111{
112 objectServer.remove_interface(sensorInterface);
113 objectServer.remove_interface(controlInterface);
114}
115
116void PwmSensor::setValue(uint32_t value)
117{
118 std::ofstream ref(sysPath);
119 if (!ref.good())
120 {
121 throw std::runtime_error("Bad Write File");
122 return;
123 }
124 ref << value;
125}
126
127// on success returns pwm, on failure throws except on initialization, where it
128// prints an error and returns 0
129uint32_t PwmSensor::getValue(bool errThrow)
130{
131 std::ifstream ref(sysPath);
132 if (!ref.good())
133 {
134 return -1;
135 }
136 std::string line;
137 if (!std::getline(ref, line))
138 {
139 return -1;
140 }
141 try
142 {
143 uint32_t value = std::stoi(line);
144 return value;
145 }
146 catch (std::invalid_argument)
147 {
148 std::cerr << "Error reading pwm at " << sysPath << "\n";
149 // throw if not initial read to be caught by dbus bindings
150 if (errThrow)
151 {
152 throw std::runtime_error("Bad Read");
153 }
154 }
155 return 0;
156}