blob: 6402ad03d1a1a7b294abab01990a71d9ce4cfd9f [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*/
James Feist82bac4c2019-03-11 11:16:53 -070016#include "PwmSensor.hpp"
17
18#include "Utils.hpp"
19
James Feist6714a252018-09-10 15:26:18 -070020#include <fstream>
21#include <iostream>
22#include <sdbusplus/asio/object_server.hpp>
23
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070024static constexpr size_t pwmMax = 255;
25static constexpr size_t pwmMin = 0;
James Feist6714a252018-09-10 15:26:18 -070026
Cheng C Yang916360b2019-05-07 18:47:16 +080027PwmSensor::PwmSensor(const std::string& name, const std::string& sysPath,
James Feist82bac4c2019-03-11 11:16:53 -070028 sdbusplus::asio::object_server& objectServer,
29 const std::string& sensorConfiguration) :
Cheng C Yang916360b2019-05-07 18:47:16 +080030 name(name),
31 sysPath(sysPath), objectServer(objectServer)
James Feist6714a252018-09-10 15:26:18 -070032{
James Feist6714a252018-09-10 15:26:18 -070033 // 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 }
James Feist46c5c1d2018-11-30 12:04:07 -080048 if (req == resp)
49 {
50 return 1;
51 }
James Feist6714a252018-09-10 15:26:18 -070052 double value = (req / 100) * pwmMax;
53 setValue(static_cast<int>(value));
54 resp = req;
James Feist46c5c1d2018-11-30 12:04:07 -080055
56 controlInterface->signal_property("Target");
57
James Feist6714a252018-09-10 15:26:18 -070058 return 1;
59 },
60 [this](double& curVal) {
61 float value = 100.0 * (static_cast<float>(getValue()) / pwmMax);
James Feist46c5c1d2018-11-30 12:04:07 -080062 if (curVal != value)
63 {
64 curVal = value;
65 controlInterface->signal_property("Target");
66 sensorInterface->signal_property("Value");
67 }
68
James Feist6714a252018-09-10 15:26:18 -070069 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 }
James Feist46c5c1d2018-11-30 12:04:07 -080086 if (req == resp)
87 {
88 return 1;
89 }
James Feist6714a252018-09-10 15:26:18 -070090 setValue(req);
91 resp = req;
James Feist46c5c1d2018-11-30 12:04:07 -080092
93 sensorInterface->signal_property("Value");
94
James Feist6714a252018-09-10 15:26:18 -070095 return 1;
96 },
97 [this](uint64_t& curVal) {
James Feist46c5c1d2018-11-30 12:04:07 -080098 uint64_t value = getValue();
99 if (curVal != value)
100 {
101 curVal = value;
102 controlInterface->signal_property("Target");
103 sensorInterface->signal_property("Value");
104 }
105
James Feist6714a252018-09-10 15:26:18 -0700106 return curVal;
107 });
108 sensorInterface->initialize();
109 controlInterface->initialize();
James Feist82bac4c2019-03-11 11:16:53 -0700110
111 association = objectServer.add_interface(
112 "/xyz/openbmc_project/sensors/fan_pwm/" + name,
113 "org.openbmc.Associations");
114 createAssociation(association, sensorConfiguration);
James Feist6714a252018-09-10 15:26:18 -0700115}
116PwmSensor::~PwmSensor()
117{
118 objectServer.remove_interface(sensorInterface);
119 objectServer.remove_interface(controlInterface);
120}
121
122void 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
135uint32_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}