xref: /openbmc/dbus-sensors/src/PwmSensor.cpp (revision 6714a25a)
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 #include <fstream>
18 #include <iostream>
19 #include <sdbusplus/asio/object_server.hpp>
20 
21 constexpr size_t pwmMax = 255;
22 constexpr size_t pwmMin = 0;
23 
24 PwmSensor::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             }
47             double value = (req / 100) * pwmMax;
48             setValue(static_cast<int>(value));
49             resp = req;
50             return 1;
51         },
52         [this](double& curVal) {
53             float value = 100.0 * (static_cast<float>(getValue()) / pwmMax);
54             curVal = value;
55             return curVal;
56         });
57     // pwm sensor interface is in percent
58     sensorInterface->register_property("MaxValue", static_cast<int64_t>(100));
59     sensorInterface->register_property("MinValue", static_cast<int64_t>(0));
60 
61     controlInterface = objectServer.add_interface(
62         "/xyz/openbmc_project/control/fanpwm/" + name,
63         "xyz.openbmc_project.Control.FanPwm");
64     controlInterface->register_property(
65         "Target", static_cast<uint64_t>(pwmValue),
66         [this](const uint64_t& req, uint64_t& resp) {
67             if (req > pwmMax || req < pwmMin)
68             {
69                 throw std::runtime_error("Value out of range");
70                 return -1;
71             }
72             setValue(req);
73             resp = req;
74             return 1;
75         },
76         [this](uint64_t& curVal) {
77             curVal = getValue();
78             return curVal;
79         });
80     sensorInterface->initialize();
81     controlInterface->initialize();
82 }
83 PwmSensor::~PwmSensor()
84 {
85     objectServer.remove_interface(sensorInterface);
86     objectServer.remove_interface(controlInterface);
87 }
88 
89 void PwmSensor::setValue(uint32_t value)
90 {
91     std::ofstream ref(sysPath);
92     if (!ref.good())
93     {
94         throw std::runtime_error("Bad Write File");
95         return;
96     }
97     ref << value;
98 }
99 
100 // on success returns pwm, on failure throws except on initialization, where it
101 // prints an error and returns 0
102 uint32_t PwmSensor::getValue(bool errThrow)
103 {
104     std::ifstream ref(sysPath);
105     if (!ref.good())
106     {
107         return -1;
108     }
109     std::string line;
110     if (!std::getline(ref, line))
111     {
112         return -1;
113     }
114     try
115     {
116         uint32_t value = std::stoi(line);
117         return value;
118     }
119     catch (std::invalid_argument)
120     {
121         std::cerr << "Error reading pwm at " << sysPath << "\n";
122         // throw if not initial read to be caught by dbus bindings
123         if (errThrow)
124         {
125             throw std::runtime_error("Bad Read");
126         }
127     }
128     return 0;
129 }
130