xref: /openbmc/dbus-sensors/src/PwmSensor.cpp (revision b83bb2be)
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& 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     double fValue = 100.0 * (static_cast<float>(pwmValue) / pwmMax);
40     sensorInterface->register_property(
41         "Value", fValue,
42         [this](const double& req, double& resp) {
43             if (req > 100 || req < 0)
44             {
45                 throw std::runtime_error("Value out of range");
46                 return -1;
47             }
48             if (req == resp)
49             {
50                 return 1;
51             }
52             double value = (req / 100) * pwmMax;
53             setValue(static_cast<int>(value));
54             resp = req;
55 
56             controlInterface->signal_property("Target");
57 
58             return 1;
59         },
60         [this](double& curVal) {
61             float value = 100.0 * (static_cast<float>(getValue()) / pwmMax);
62             if (curVal != value)
63             {
64                 curVal = value;
65                 controlInterface->signal_property("Target");
66                 sensorInterface->signal_property("Value");
67             }
68 
69             return curVal;
70         });
71     // pwm sensor interface is in percent
72     sensorInterface->register_property("MaxValue", static_cast<int64_t>(100));
73     sensorInterface->register_property("MinValue", static_cast<int64_t>(0));
74 
75     controlInterface = objectServer.add_interface(
76         "/xyz/openbmc_project/control/fanpwm/" + name,
77         "xyz.openbmc_project.Control.FanPwm");
78     controlInterface->register_property(
79         "Target", static_cast<uint64_t>(pwmValue),
80         [this](const uint64_t& req, uint64_t& resp) {
81             if (req > pwmMax || req < pwmMin)
82             {
83                 throw std::runtime_error("Value out of range");
84                 return -1;
85             }
86             if (req == resp)
87             {
88                 return 1;
89             }
90             setValue(req);
91             resp = req;
92 
93             sensorInterface->signal_property("Value");
94 
95             return 1;
96         },
97         [this](uint64_t& curVal) {
98             uint64_t value = getValue();
99             if (curVal != value)
100             {
101                 curVal = value;
102                 controlInterface->signal_property("Target");
103                 sensorInterface->signal_property("Value");
104             }
105 
106             return curVal;
107         });
108     sensorInterface->initialize();
109     controlInterface->initialize();
110 
111     association = objectServer.add_interface(
112         "/xyz/openbmc_project/sensors/fan_pwm/" + name,
113         "org.openbmc.Associations");
114     createAssociation(association, sensorConfiguration);
115 }
116 PwmSensor::~PwmSensor()
117 {
118     objectServer.remove_interface(sensorInterface);
119     objectServer.remove_interface(controlInterface);
120 }
121 
122 void PwmSensor::setValue(uint32_t value)
123 {
124     std::ofstream ref(sysPath);
125     if (!ref.good())
126     {
127         throw std::runtime_error("Bad Write File");
128         return;
129     }
130     ref << value;
131 }
132 
133 // on success returns pwm, on failure throws except on initialization, where it
134 // prints an error and returns 0
135 uint32_t PwmSensor::getValue(bool errThrow)
136 {
137     std::ifstream ref(sysPath);
138     if (!ref.good())
139     {
140         return -1;
141     }
142     std::string line;
143     if (!std::getline(ref, line))
144     {
145         return -1;
146     }
147     try
148     {
149         uint32_t value = std::stoi(line);
150         return value;
151     }
152     catch (std::invalid_argument)
153     {
154         std::cerr << "Error reading pwm at " << sysPath << "\n";
155         // throw if not initial read to be caught by dbus bindings
156         if (errThrow)
157         {
158             throw std::runtime_error("Bad Read");
159         }
160     }
161     return 0;
162 }
163