1 /** 2 * Copyright © 2020 IBM 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 "fan.hpp" 17 18 #include "sdbusplus.hpp" 19 20 #include <fmt/format.h> 21 22 #include <nlohmann/json.hpp> 23 #include <phosphor-logging/log.hpp> 24 #include <sdbusplus/bus.hpp> 25 26 namespace phosphor::fan::control::json 27 { 28 29 using json = nlohmann::json; 30 using namespace phosphor::logging; 31 32 constexpr auto FAN_SENSOR_PATH = "/xyz/openbmc_project/sensors/fan_tach/"; 33 constexpr auto FAN_TARGET_PROPERTY = "Target"; 34 35 Fan::Fan(const json& jsonObj) : 36 ConfigBase(jsonObj), _bus(util::SDBusPlus::getBus()) 37 { 38 setInterface(jsonObj); 39 setSensors(jsonObj); 40 setZone(jsonObj); 41 } 42 43 void Fan::setInterface(const json& jsonObj) 44 { 45 if (!jsonObj.contains("target_interface")) 46 { 47 log<level::ERR>("Missing required fan sensor target interface", 48 entry("JSON=%s", jsonObj.dump().c_str())); 49 throw std::runtime_error( 50 "Missing required fan sensor target interface"); 51 } 52 _interface = jsonObj["target_interface"].get<std::string>(); 53 } 54 55 void Fan::setSensors(const json& jsonObj) 56 { 57 if (!jsonObj.contains("sensors")) 58 { 59 log<level::ERR>("Missing required fan sensors list", 60 entry("JSON=%s", jsonObj.dump().c_str())); 61 throw std::runtime_error("Missing required fan sensors list"); 62 } 63 std::string path; 64 for (const auto& sensor : jsonObj["sensors"]) 65 { 66 path = FAN_SENSOR_PATH + sensor.get<std::string>(); 67 auto service = util::SDBusPlus::getService(_bus, path, _interface); 68 _sensors[path] = service; 69 } 70 // All sensors associated with this fan are set to the same target, 71 // so only need to read target property from one of them 72 if (!path.empty()) 73 { 74 _target = util::SDBusPlus::getProperty<uint64_t>( 75 _bus, _sensors.at(path), path, _interface, FAN_TARGET_PROPERTY); 76 } 77 } 78 79 void Fan::setZone(const json& jsonObj) 80 { 81 if (!jsonObj.contains("zone")) 82 { 83 log<level::ERR>("Missing required fan zone", 84 entry("JSON=%s", jsonObj.dump().c_str())); 85 throw std::runtime_error("Missing required fan zone"); 86 } 87 _zone = jsonObj["zone"].get<std::string>(); 88 } 89 90 void Fan::setTarget(uint64_t target) 91 { 92 if (_target == target) 93 { 94 return; 95 } 96 97 for (const auto& sensor : _sensors) 98 { 99 auto value = target; 100 try 101 { 102 util::SDBusPlus::setProperty<uint64_t>( 103 _bus, sensor.second, sensor.first, _interface, 104 FAN_TARGET_PROPERTY, std::move(value)); 105 } 106 catch (const sdbusplus::exception::exception&) 107 { 108 throw util::DBusPropertyError{ 109 fmt::format("Failed to set target for fan {}", _name).c_str(), 110 sensor.second, sensor.first, _interface, FAN_TARGET_PROPERTY}; 111 } 112 } 113 _target = target; 114 } 115 116 } // namespace phosphor::fan::control::json 117