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