xref: /openbmc/dbus-sensors/src/PwmSensor.cpp (revision 8a7e291c)
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 size_t pwmMin = 0;
26 
27 PwmSensor::PwmSensor(const std::string& sysPath,
28                      sdbusplus::asio::object_server& objectServer,
29                      const std::string& sensorConfiguration) :
30     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             }
51             if (req == resp)
52             {
53                 return 1;
54             }
55             double value = (req / 100) * pwmMax;
56             setValue(static_cast<int>(value));
57             resp = req;
58 
59             controlInterface->signal_property("Target");
60 
61             return 1;
62         },
63         [this](double& curVal) {
64             float value = 100.0 * (static_cast<float>(getValue()) / pwmMax);
65             if (curVal != value)
66             {
67                 curVal = value;
68                 controlInterface->signal_property("Target");
69                 sensorInterface->signal_property("Value");
70             }
71 
72             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             }
89             if (req == resp)
90             {
91                 return 1;
92             }
93             setValue(req);
94             resp = req;
95 
96             sensorInterface->signal_property("Value");
97 
98             return 1;
99         },
100         [this](uint64_t& curVal) {
101             uint64_t value = getValue();
102             if (curVal != value)
103             {
104                 curVal = value;
105                 controlInterface->signal_property("Target");
106                 sensorInterface->signal_property("Value");
107             }
108 
109             return curVal;
110         });
111     sensorInterface->initialize();
112     controlInterface->initialize();
113 
114     association = objectServer.add_interface(
115         "/xyz/openbmc_project/sensors/fan_pwm/" + name,
116         "org.openbmc.Associations");
117     createAssociation(association, sensorConfiguration);
118 }
119 PwmSensor::~PwmSensor()
120 {
121     objectServer.remove_interface(sensorInterface);
122     objectServer.remove_interface(controlInterface);
123 }
124 
125 void 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
138 uint32_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 }
166