xref: /openbmc/dbus-sensors/src/PwmSensor.cpp (revision 49c17cbc)
1 /*
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 
18 #include "Utils.hpp"
19 
20 #include <fstream>
21 #include <iostream>
22 #include <sdbusplus/asio/object_server.hpp>
23 
24 static constexpr size_t pwmMax = 255;
25 static constexpr double defaultPwm = 30.0;
26 
27 PwmSensor::PwmSensor(const std::string& name, const std::string& sysPath,
28                      sdbusplus::asio::object_server& objectServer,
29                      const std::string& sensorConfiguration) :
30     name(name),
31     sysPath(sysPath), objectServer(objectServer)
32 {
33     // 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);
39     if (!pwmValue)
40     {
41         // default pwm to non 0
42         pwmValue = static_cast<uint32_t>(pwmMax * (defaultPwm / 100));
43         setValue(pwmValue);
44     }
45     double fValue = 100.0 * (static_cast<double>(pwmValue) / pwmMax);
46     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             }
54             if (req == resp)
55             {
56                 return 1;
57             }
58             double value = (req / 100) * pwmMax;
59             setValue(static_cast<int>(value));
60             resp = req;
61 
62             controlInterface->signal_property("Target");
63 
64             return 1;
65         },
66         [this](double& curVal) {
67             double value = 100.0 * (static_cast<double>(getValue()) / pwmMax);
68             if (curVal != value)
69             {
70                 curVal = value;
71                 controlInterface->signal_property("Target");
72                 sensorInterface->signal_property("Value");
73             }
74 
75             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) {
87             if (req > pwmMax)
88             {
89                 throw std::runtime_error("Value out of range");
90                 return -1;
91             }
92             if (req == resp)
93             {
94                 return 1;
95             }
96             setValue(req);
97             resp = req;
98 
99             sensorInterface->signal_property("Value");
100 
101             return 1;
102         },
103         [this](uint64_t& curVal) {
104             uint64_t value = getValue();
105             if (curVal != value)
106             {
107                 curVal = value;
108                 controlInterface->signal_property("Target");
109                 sensorInterface->signal_property("Value");
110             }
111 
112             return curVal;
113         });
114     sensorInterface->initialize();
115     controlInterface->initialize();
116 
117     association = objectServer.add_interface(
118         "/xyz/openbmc_project/sensors/fan_pwm/" + name, association::interface);
119     createAssociation(association, sensorConfiguration);
120 }
121 PwmSensor::~PwmSensor()
122 {
123     objectServer.remove_interface(sensorInterface);
124     objectServer.remove_interface(controlInterface);
125 }
126 
127 void 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
140 uint32_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     }
157     catch (std::invalid_argument&)
158     {
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 }
168