16714a25aSJames Feist /* 26714a25aSJames Feist // Copyright (c) 2017 Intel Corporation 36714a25aSJames Feist // 46714a25aSJames Feist // Licensed under the Apache License, Version 2.0 (the "License"); 56714a25aSJames Feist // you may not use this file except in compliance with the License. 66714a25aSJames Feist // You may obtain a copy of the License at 76714a25aSJames Feist // 86714a25aSJames Feist // http://www.apache.org/licenses/LICENSE-2.0 96714a25aSJames Feist // 106714a25aSJames Feist // Unless required by applicable law or agreed to in writing, software 116714a25aSJames Feist // distributed under the License is distributed on an "AS IS" BASIS, 126714a25aSJames Feist // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136714a25aSJames Feist // See the License for the specific language governing permissions and 146714a25aSJames Feist // limitations under the License. 156714a25aSJames Feist */ 166714a25aSJames Feist 17e73bd0a1SAndrew Jeffery #include "PwmSensor.hpp" 18e73bd0a1SAndrew Jeffery #include "TachSensor.hpp" 19e73bd0a1SAndrew Jeffery #include "Utils.hpp" 20e73bd0a1SAndrew Jeffery #include "VariantVisitors.hpp" 21e73bd0a1SAndrew Jeffery 226714a25aSJames Feist #include <boost/algorithm/string/replace.hpp> 2396e97db7SPatrick Venture #include <boost/container/flat_map.hpp> 246714a25aSJames Feist #include <boost/container/flat_set.hpp> 2538fb5983SJames Feist #include <sdbusplus/asio/connection.hpp> 2638fb5983SJames Feist #include <sdbusplus/asio/object_server.hpp> 2738fb5983SJames Feist #include <sdbusplus/bus/match.hpp> 2838fb5983SJames Feist 2938fb5983SJames Feist #include <array> 3024f02f24SJames Feist #include <filesystem> 316714a25aSJames Feist #include <fstream> 3296e97db7SPatrick Venture #include <functional> 3396e97db7SPatrick Venture #include <memory> 3496e97db7SPatrick Venture #include <optional> 356714a25aSJames Feist #include <regex> 3696e97db7SPatrick Venture #include <string> 3796e97db7SPatrick Venture #include <utility> 3896e97db7SPatrick Venture #include <variant> 3996e97db7SPatrick Venture #include <vector> 406714a25aSJames Feist 41cf3bce6eSJames Feist namespace fs = std::filesystem; 423eb82629SJames Feist 43a3e8f2a3SYong Zhao // The following two structures need to be consistent 44c361e222SChris Sides static auto sensorTypes{std::to_array<const char*>( 45c361e222SChris Sides {"AspeedFan", "I2CFan", "NuvotonFan", "HPEFan"})}; 46a3e8f2a3SYong Zhao 47a3e8f2a3SYong Zhao enum FanTypes 48a3e8f2a3SYong Zhao { 49a3e8f2a3SYong Zhao aspeed = 0, 50a3e8f2a3SYong Zhao i2c, 51a3e8f2a3SYong Zhao nuvoton, 52c361e222SChris Sides hpe, 53a3e8f2a3SYong Zhao max, 54a3e8f2a3SYong Zhao }; 55a3e8f2a3SYong Zhao 56a3e8f2a3SYong Zhao static_assert(std::tuple_size<decltype(sensorTypes)>::value == FanTypes::max, 57a3e8f2a3SYong Zhao "sensorTypes element number is not equal to FanTypes number"); 58a3e8f2a3SYong Zhao 59dc6c55f3SJames Feist constexpr const char* redundancyConfiguration = 60dc6c55f3SJames Feist "xyz.openbmc_project.Configuration.FanRedundancy"; 619ced0a38SJae Hyun Yoo static std::regex inputRegex(R"(fan(\d+)_input)"); 626714a25aSJames Feist 63dc6c55f3SJames Feist // todo: power supply fan redundancy 647b18b1e0SJames Feist std::optional<RedundancySensor> systemRedundancy; 6595b079b7SJames Feist 663d5260dcSChris Sides static const std::map<std::string, FanTypes> compatibleFanTypes = { 673d5260dcSChris Sides {"aspeed,ast2400-pwm-tacho", FanTypes::aspeed}, 683d5260dcSChris Sides {"aspeed,ast2500-pwm-tacho", FanTypes::aspeed}, 69c361e222SChris Sides {"nuvoton,npcm750-pwm-fan", FanTypes::nuvoton}, 70*d37e1db5SBrian Ma {"nuvoton,npcm845-pwm-fan", FanTypes::nuvoton}, 71c361e222SChris Sides {"hpe,gxp-fan-ctrl", FanTypes::hpe} 723d5260dcSChris Sides // add compatible string here for new fan type 733d5260dcSChris Sides }; 743d5260dcSChris Sides 7595b079b7SJames Feist FanTypes getFanType(const fs::path& parentPath) 7695b079b7SJames Feist { 779a472e8eSChris Sides fs::path linkPath = parentPath / "of_node"; 7839963226SZhikui Ren if (!fs::exists(linkPath)) 7939963226SZhikui Ren { 8039963226SZhikui Ren return FanTypes::i2c; 8139963226SZhikui Ren } 829a472e8eSChris Sides 8339963226SZhikui Ren std::string canonical = fs::canonical(linkPath); 849a472e8eSChris Sides std::string compatiblePath = canonical + "/compatible"; 859a472e8eSChris Sides std::ifstream compatibleStream(compatiblePath); 869a472e8eSChris Sides 873d5260dcSChris Sides if (!compatibleStream) 889a472e8eSChris Sides { 899a472e8eSChris Sides std::cerr << "Error opening " << compatiblePath << "\n"; 903d5260dcSChris Sides return FanTypes::i2c; 919a472e8eSChris Sides } 929a472e8eSChris Sides 939a472e8eSChris Sides std::string compatibleString; 943d5260dcSChris Sides while (std::getline(compatibleStream, compatibleString)) 959a472e8eSChris Sides { 969a472e8eSChris Sides compatibleString.pop_back(); // trim EOL before comparisons 979a472e8eSChris Sides 983d5260dcSChris Sides std::map<std::string, FanTypes>::const_iterator compatibleIterator = 993d5260dcSChris Sides compatibleFanTypes.find(compatibleString); 1003d5260dcSChris Sides 1013d5260dcSChris Sides if (compatibleIterator != compatibleFanTypes.end()) 10295b079b7SJames Feist { 1033d5260dcSChris Sides return compatibleIterator->second; 1048843b627SPeter Lundgren } 1059a472e8eSChris Sides } 1069a472e8eSChris Sides 10795b079b7SJames Feist return FanTypes::i2c; 10895b079b7SJames Feist } 109abf91de1SJeff Lin void enablePwm(const fs::path& filePath) 110abf91de1SJeff Lin { 111abf91de1SJeff Lin std::fstream enableFile(filePath, std::ios::in | std::ios::out); 112abf91de1SJeff Lin if (!enableFile.good()) 113abf91de1SJeff Lin { 114abf91de1SJeff Lin std::cerr << "Error read/write " << filePath << "\n"; 115abf91de1SJeff Lin return; 116abf91de1SJeff Lin } 117dc6c55f3SJames Feist 118abf91de1SJeff Lin std::string regulateMode; 119abf91de1SJeff Lin std::getline(enableFile, regulateMode); 120abf91de1SJeff Lin if (regulateMode == "0") 121abf91de1SJeff Lin { 122abf91de1SJeff Lin enableFile << 1; 123abf91de1SJeff Lin } 124abf91de1SJeff Lin } 125ddf25d17SHoward Chiu bool findPwmfanPath(unsigned int configPwmfanIndex, fs::path& pwmPath) 126ddf25d17SHoward Chiu { 127ddf25d17SHoward Chiu /* Search PWM since pwm-fan had separated 128ddf25d17SHoward Chiu * PWM from tach directory and 1 channel only*/ 129ddf25d17SHoward Chiu std::vector<fs::path> pwmfanPaths; 130ddf25d17SHoward Chiu std::string pwnfanDevName("pwm-fan"); 131ddf25d17SHoward Chiu 132ddf25d17SHoward Chiu pwnfanDevName += std::to_string(configPwmfanIndex); 133ddf25d17SHoward Chiu 134ddf25d17SHoward Chiu if (!findFiles(fs::path("/sys/class/hwmon"), R"(pwm\d+)", pwmfanPaths)) 135ddf25d17SHoward Chiu { 136ddf25d17SHoward Chiu std::cerr << "No PWMs are found!\n"; 137ddf25d17SHoward Chiu return false; 138ddf25d17SHoward Chiu } 139ddf25d17SHoward Chiu for (const auto& path : pwmfanPaths) 140ddf25d17SHoward Chiu { 141ddf25d17SHoward Chiu std::error_code ec; 142ddf25d17SHoward Chiu fs::path link = fs::read_symlink(path.parent_path() / "device", ec); 143ddf25d17SHoward Chiu 144ddf25d17SHoward Chiu if (ec) 145ddf25d17SHoward Chiu { 146ddf25d17SHoward Chiu std::cerr << "read_symlink() failed: " << ec.message() << " (" 147ddf25d17SHoward Chiu << ec.value() << ")\n"; 148ddf25d17SHoward Chiu continue; 149ddf25d17SHoward Chiu } 150ddf25d17SHoward Chiu 151ddf25d17SHoward Chiu if (link.filename().string() == pwnfanDevName) 152ddf25d17SHoward Chiu { 153ddf25d17SHoward Chiu pwmPath = path; 154ddf25d17SHoward Chiu return true; 155ddf25d17SHoward Chiu } 156ddf25d17SHoward Chiu } 157ddf25d17SHoward Chiu return false; 158ddf25d17SHoward Chiu } 159ddf25d17SHoward Chiu bool findPwmPath(const fs::path& directory, unsigned int pwm, fs::path& pwmPath) 160ddf25d17SHoward Chiu { 161ddf25d17SHoward Chiu std::error_code ec; 162ddf25d17SHoward Chiu 163ddf25d17SHoward Chiu /* Assuming PWM file is appeared in the same directory as fanX_input */ 164ddf25d17SHoward Chiu auto path = directory / ("pwm" + std::to_string(pwm + 1)); 165ddf25d17SHoward Chiu bool exists = fs::exists(path, ec); 166ddf25d17SHoward Chiu 167ddf25d17SHoward Chiu if (ec || !exists) 168ddf25d17SHoward Chiu { 169ddf25d17SHoward Chiu /* PWM file not exist or error happened */ 170ddf25d17SHoward Chiu if (ec) 171ddf25d17SHoward Chiu { 172ddf25d17SHoward Chiu std::cerr << "exists() failed: " << ec.message() << " (" 173ddf25d17SHoward Chiu << ec.value() << ")\n"; 174ddf25d17SHoward Chiu } 175ddf25d17SHoward Chiu /* try search form pwm-fanX directory */ 176ddf25d17SHoward Chiu return findPwmfanPath(pwm, pwmPath); 177ddf25d17SHoward Chiu } 178ddf25d17SHoward Chiu 179ddf25d17SHoward Chiu pwmPath = path; 180ddf25d17SHoward Chiu return true; 181ddf25d17SHoward Chiu } 1829c47bd7eSJustin Ledford 1839c47bd7eSJustin Ledford // The argument to this function should be the fanN_input file that we want to 1849c47bd7eSJustin Ledford // enable. The function will locate the corresponding fanN_enable file if it 1859c47bd7eSJustin Ledford // exists. Note that some drivers don't provide this file if the sensors are 1869c47bd7eSJustin Ledford // always enabled. 1879c47bd7eSJustin Ledford void enableFanInput(const fs::path& fanInputPath) 1889c47bd7eSJustin Ledford { 1899c47bd7eSJustin Ledford std::error_code ec; 1909c47bd7eSJustin Ledford std::string path(fanInputPath.string()); 1919c47bd7eSJustin Ledford boost::replace_last(path, "input", "enable"); 1929c47bd7eSJustin Ledford 1939c47bd7eSJustin Ledford bool exists = fs::exists(path, ec); 1949c47bd7eSJustin Ledford if (ec || !exists) 1959c47bd7eSJustin Ledford { 1969c47bd7eSJustin Ledford return; 1979c47bd7eSJustin Ledford } 1989c47bd7eSJustin Ledford 1999c47bd7eSJustin Ledford std::fstream enableFile(path, std::ios::out); 2009c47bd7eSJustin Ledford if (!enableFile.good()) 2019c47bd7eSJustin Ledford { 2029c47bd7eSJustin Ledford return; 2039c47bd7eSJustin Ledford } 2049c47bd7eSJustin Ledford enableFile << 1; 2059c47bd7eSJustin Ledford } 2069c47bd7eSJustin Ledford 207d540741eSKuiying Wang void createRedundancySensor( 2085170fe63SJosh Lehan const boost::container::flat_map<std::string, std::shared_ptr<TachSensor>>& 209d540741eSKuiying Wang sensors, 2108a57ec09SEd Tanous const std::shared_ptr<sdbusplus::asio::connection>& conn, 211d540741eSKuiying Wang sdbusplus::asio::object_server& objectServer) 212d540741eSKuiying Wang { 213d540741eSKuiying Wang conn->async_method_call( 214d540741eSKuiying Wang [&objectServer, &sensors](boost::system::error_code& ec, 2158a57ec09SEd Tanous const ManagedObjectType& managedObj) { 216d540741eSKuiying Wang if (ec) 217d540741eSKuiying Wang { 218d540741eSKuiying Wang std::cerr << "Error calling entity manager \n"; 219d540741eSKuiying Wang return; 220d540741eSKuiying Wang } 22177636ecbSZev Weiss for (const auto& [path, interfaces] : managedObj) 222d540741eSKuiying Wang { 22377636ecbSZev Weiss for (const auto& [intf, cfg] : interfaces) 224d540741eSKuiying Wang { 22577636ecbSZev Weiss if (intf == redundancyConfiguration) 226d540741eSKuiying Wang { 227d540741eSKuiying Wang // currently only support one 22877636ecbSZev Weiss auto findCount = cfg.find("AllowedFailures"); 22977636ecbSZev Weiss if (findCount == cfg.end()) 230d540741eSKuiying Wang { 231d540741eSKuiying Wang std::cerr << "Malformed redundancy record \n"; 232d540741eSKuiying Wang return; 233d540741eSKuiying Wang } 234d540741eSKuiying Wang std::vector<std::string> sensorList; 235d540741eSKuiying Wang 23677636ecbSZev Weiss for (const auto& [name, sensor] : sensors) 237d540741eSKuiying Wang { 238d540741eSKuiying Wang sensorList.push_back( 239d540741eSKuiying Wang "/xyz/openbmc_project/sensors/fan_tach/" + 24077636ecbSZev Weiss sensor->name); 241d540741eSKuiying Wang } 242d540741eSKuiying Wang systemRedundancy.reset(); 24377636ecbSZev Weiss systemRedundancy.emplace( 24477636ecbSZev Weiss RedundancySensor(std::get<uint64_t>(findCount->second), 24577636ecbSZev Weiss sensorList, objectServer, path)); 246d540741eSKuiying Wang 247d540741eSKuiying Wang return; 248d540741eSKuiying Wang } 249d540741eSKuiying Wang } 250d540741eSKuiying Wang } 251d540741eSKuiying Wang }, 2523e620af1SNan Zhou "xyz.openbmc_project.EntityManager", "/xyz/openbmc_project/inventory", 253d540741eSKuiying Wang "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 254d540741eSKuiying Wang } 255d540741eSKuiying Wang 2566714a25aSJames Feist void createSensors( 2571f978631SEd Tanous boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer, 2585170fe63SJosh Lehan boost::container::flat_map<std::string, std::shared_ptr<TachSensor>>& 2596714a25aSJames Feist tachSensors, 2606714a25aSJames Feist boost::container::flat_map<std::string, std::unique_ptr<PwmSensor>>& 2616714a25aSJames Feist pwmSensors, 2626714a25aSJames Feist std::shared_ptr<sdbusplus::asio::connection>& dbusConnection, 2635591cf08SJames Feist const std::shared_ptr<boost::container::flat_set<std::string>>& 264f27a55c7SJames Feist sensorsChanged, 265f27a55c7SJames Feist size_t retries = 0) 2666714a25aSJames Feist { 267de5e9705SJames Feist auto getter = std::make_shared<GetSensorConfiguration>( 268de5e9705SJames Feist dbusConnection, 2698a17c303SEd Tanous [&io, &objectServer, &tachSensors, &pwmSensors, &dbusConnection, 2708a17c303SEd Tanous sensorsChanged](const ManagedObjectType& sensorConfigurations) { 2716714a25aSJames Feist bool firstScan = sensorsChanged == nullptr; 2726714a25aSJames Feist std::vector<fs::path> paths; 273bb67932aSEd Tanous if (!findFiles(fs::path("/sys/class/hwmon"), R"(fan\d+_input)", paths)) 2746714a25aSJames Feist { 27577b3add2SYong Zhao std::cerr << "No fan sensors in system\n"; 2766714a25aSJames Feist return; 2776714a25aSJames Feist } 2786714a25aSJames Feist 2796714a25aSJames Feist // iterate through all found fan sensors, and try to match them with 2806714a25aSJames Feist // configuration 28195b079b7SJames Feist for (const auto& path : paths) 2826714a25aSJames Feist { 2836714a25aSJames Feist std::smatch match; 2846714a25aSJames Feist std::string pathStr = path.string(); 2856714a25aSJames Feist 2869ced0a38SJae Hyun Yoo std::regex_search(pathStr, match, inputRegex); 2876714a25aSJames Feist std::string indexStr = *(match.begin() + 1); 2886714a25aSJames Feist 28977b3add2SYong Zhao fs::path directory = path.parent_path(); 29095b079b7SJames Feist FanTypes fanType = getFanType(directory); 291054aad8fSZev Weiss std::string cfgIntf = configInterfaceName(sensorTypes[fanType]); 29277b3add2SYong Zhao 2936714a25aSJames Feist // convert to 0 based 2946714a25aSJames Feist size_t index = std::stoul(indexStr) - 1; 2956714a25aSJames Feist 296a771f6a7SEd Tanous const char* baseType = nullptr; 2976714a25aSJames Feist const SensorData* sensorData = nullptr; 2986714a25aSJames Feist const std::string* interfacePath = nullptr; 29987d713abSJames Feist const SensorBaseConfiguration* baseConfiguration = nullptr; 30077636ecbSZev Weiss for (const auto& [path, cfgData] : sensorConfigurations) 3016714a25aSJames Feist { 302de5e9705SJames Feist // find the base of the configuration to see if indexes 303de5e9705SJames Feist // match 304054aad8fSZev Weiss auto sensorBaseFind = cfgData.find(cfgIntf); 30577636ecbSZev Weiss if (sensorBaseFind == cfgData.end()) 3066714a25aSJames Feist { 3076714a25aSJames Feist continue; 3086714a25aSJames Feist } 309347dd4e7SZhikui Ren 310a3e8f2a3SYong Zhao baseConfiguration = &(*sensorBaseFind); 31177636ecbSZev Weiss interfacePath = &path.str; 312a3e8f2a3SYong Zhao baseType = sensorTypes[fanType]; 313a3e8f2a3SYong Zhao 3146714a25aSJames Feist auto findIndex = baseConfiguration->second.find("Index"); 3156714a25aSJames Feist if (findIndex == baseConfiguration->second.end()) 3166714a25aSJames Feist { 317bb67932aSEd Tanous std::cerr << baseConfiguration->first << " missing index\n"; 3186714a25aSJames Feist continue; 3196714a25aSJames Feist } 320de5e9705SJames Feist unsigned int configIndex = std::visit( 321de5e9705SJames Feist VariantToUnsignedIntVisitor(), findIndex->second); 3226714a25aSJames Feist if (configIndex != index) 3236714a25aSJames Feist { 3246714a25aSJames Feist continue; 3256714a25aSJames Feist } 326c361e222SChris Sides if (fanType == FanTypes::aspeed || 327c361e222SChris Sides fanType == FanTypes::nuvoton || fanType == FanTypes::hpe) 3286714a25aSJames Feist { 329c361e222SChris Sides // there will be only 1 aspeed or nuvoton or hpe sensor 3303d5260dcSChris Sides // object in sysfs, we found the fan 33177636ecbSZev Weiss sensorData = &cfgData; 33295b079b7SJames Feist break; 33395b079b7SJames Feist } 3348a57ec09SEd Tanous if (fanType == FanTypes::i2c) 33595b079b7SJames Feist { 33603d333e0SAkshit Shah std::string deviceName = 337add46820SYong Zhao fs::read_symlink(directory / "device").filename(); 338add46820SYong Zhao 33903d333e0SAkshit Shah size_t bus = 0; 34003d333e0SAkshit Shah size_t addr = 0; 34103d333e0SAkshit Shah if (!getDeviceBusAddr(deviceName, bus, addr)) 342add46820SYong Zhao { 34303d333e0SAkshit Shah continue; 344add46820SYong Zhao } 345add46820SYong Zhao 34695b079b7SJames Feist auto findBus = baseConfiguration->second.find("Bus"); 347de5e9705SJames Feist auto findAddress = 348de5e9705SJames Feist baseConfiguration->second.find("Address"); 34995b079b7SJames Feist if (findBus == baseConfiguration->second.end() || 35095b079b7SJames Feist findAddress == baseConfiguration->second.end()) 35195b079b7SJames Feist { 35295b079b7SJames Feist std::cerr << baseConfiguration->first 35395b079b7SJames Feist << " missing bus or address\n"; 3546714a25aSJames Feist continue; 3556714a25aSJames Feist } 356de5e9705SJames Feist unsigned int configBus = std::visit( 357de5e9705SJames Feist VariantToUnsignedIntVisitor(), findBus->second); 3583eb82629SJames Feist unsigned int configAddress = std::visit( 35995b079b7SJames Feist VariantToUnsignedIntVisitor(), findAddress->second); 36095b079b7SJames Feist 36103d333e0SAkshit Shah if (configBus == bus && configAddress == addr) 3626714a25aSJames Feist { 36377636ecbSZev Weiss sensorData = &cfgData; 3646714a25aSJames Feist break; 3656714a25aSJames Feist } 3666714a25aSJames Feist } 36795b079b7SJames Feist } 3686714a25aSJames Feist if (sensorData == nullptr) 3696714a25aSJames Feist { 370de5e9705SJames Feist std::cerr << "failed to find match for " << path.string() 371de5e9705SJames Feist << "\n"; 3726714a25aSJames Feist continue; 3736714a25aSJames Feist } 3746714a25aSJames Feist 3756714a25aSJames Feist auto findSensorName = baseConfiguration->second.find("Name"); 376347dd4e7SZhikui Ren 3776714a25aSJames Feist if (findSensorName == baseConfiguration->second.end()) 3786714a25aSJames Feist { 3796714a25aSJames Feist std::cerr << "could not determine configuration name for " 3806714a25aSJames Feist << path.string() << "\n"; 3816714a25aSJames Feist continue; 3826714a25aSJames Feist } 383de5e9705SJames Feist std::string sensorName = 384de5e9705SJames Feist std::get<std::string>(findSensorName->second); 385347dd4e7SZhikui Ren 3866714a25aSJames Feist // on rescans, only update sensors we were signaled by 3876714a25aSJames Feist auto findSensor = tachSensors.find(sensorName); 3886714a25aSJames Feist if (!firstScan && findSensor != tachSensors.end()) 3896714a25aSJames Feist { 3906714a25aSJames Feist bool found = false; 391de5e9705SJames Feist for (auto it = sensorsChanged->begin(); 392de5e9705SJames Feist it != sensorsChanged->end(); it++) 3936714a25aSJames Feist { 3946c106d66SZev Weiss if (it->ends_with(findSensor->second->name)) 3956714a25aSJames Feist { 3966714a25aSJames Feist sensorsChanged->erase(it); 3976714a25aSJames Feist findSensor->second = nullptr; 3986714a25aSJames Feist found = true; 3996714a25aSJames Feist break; 4006714a25aSJames Feist } 4016714a25aSJames Feist } 4026714a25aSJames Feist if (!found) 4036714a25aSJames Feist { 4046714a25aSJames Feist continue; 4056714a25aSJames Feist } 4066714a25aSJames Feist } 4076714a25aSJames Feist std::vector<thresholds::Threshold> sensorThresholds; 4089ced0a38SJae Hyun Yoo if (!parseThresholdsFromConfig(*sensorData, sensorThresholds)) 4096714a25aSJames Feist { 410bb67932aSEd Tanous std::cerr << "error populating thresholds for " << sensorName 411bb67932aSEd Tanous << "\n"; 4126714a25aSJames Feist } 4136714a25aSJames Feist 4147bc2bab2SJames Feist auto presenceConfig = 415054aad8fSZev Weiss sensorData->find(cfgIntf + std::string(".Presence")); 4167bc2bab2SJames Feist 4177bc2bab2SJames Feist std::unique_ptr<PresenceSensor> presenceSensor(nullptr); 4187bc2bab2SJames Feist 4197bc2bab2SJames Feist // presence sensors are optional 4207bc2bab2SJames Feist if (presenceConfig != sensorData->end()) 4217bc2bab2SJames Feist { 4227bc2bab2SJames Feist auto findPolarity = presenceConfig->second.find("Polarity"); 423347dd4e7SZhikui Ren auto findPinName = presenceConfig->second.find("PinName"); 4247bc2bab2SJames Feist 425347dd4e7SZhikui Ren if (findPinName == presenceConfig->second.end() || 4267bc2bab2SJames Feist findPolarity == presenceConfig->second.end()) 4277bc2bab2SJames Feist { 4287bc2bab2SJames Feist std::cerr << "Malformed Presence Configuration\n"; 4297bc2bab2SJames Feist } 4307bc2bab2SJames Feist else 4317bc2bab2SJames Feist { 432bb67932aSEd Tanous bool inverted = 433bb67932aSEd Tanous std::get<std::string>(findPolarity->second) == "Low"; 4342049bd26SEd Tanous if (const auto* pinName = 435347dd4e7SZhikui Ren std::get_if<std::string>(&findPinName->second)) 436347dd4e7SZhikui Ren { 4377b18b1e0SJames Feist presenceSensor = std::make_unique<PresenceSensor>( 438347dd4e7SZhikui Ren *pinName, inverted, io, sensorName); 439347dd4e7SZhikui Ren } 440347dd4e7SZhikui Ren else 441347dd4e7SZhikui Ren { 442bb67932aSEd Tanous std::cerr << "Malformed Presence pinName for sensor " 443347dd4e7SZhikui Ren << sensorName << " \n"; 444347dd4e7SZhikui Ren } 4457bc2bab2SJames Feist } 4467bc2bab2SJames Feist } 4477b18b1e0SJames Feist std::optional<RedundancySensor>* redundancy = nullptr; 44895b079b7SJames Feist if (fanType == FanTypes::aspeed) 44995b079b7SJames Feist { 4507b18b1e0SJames Feist redundancy = &systemRedundancy; 45195b079b7SJames Feist } 4527bc2bab2SJames Feist 453a4d2768cSZev Weiss PowerState powerState = getPowerState(baseConfiguration->second); 454f920e09cSJosh Lehan 45587d713abSJames Feist constexpr double defaultMaxReading = 25000; 45687d713abSJames Feist constexpr double defaultMinReading = 0; 457f69fbf99SEd Tanous std::pair<double, double> limits = 458de5e9705SJames Feist std::make_pair(defaultMinReading, defaultMaxReading); 45987d713abSJames Feist 460de5e9705SJames Feist auto connector = 461054aad8fSZev Weiss sensorData->find(cfgIntf + std::string(".Connector")); 46249a8ccd6SJames Feist 46349a8ccd6SJames Feist std::optional<std::string> led; 46477b3add2SYong Zhao std::string pwmName; 465d05867c0SZhikui Ren fs::path pwmPath; 46649a8ccd6SJames Feist 4673291b9c7SJie Yang // The Mutable parameter is optional, defaulting to false 4683291b9c7SJie Yang bool isValueMutable = false; 4698e94c204SJames Feist if (connector != sensorData->end()) 4708e94c204SJames Feist { 4718e94c204SJames Feist auto findPwm = connector->second.find("Pwm"); 47249a8ccd6SJames Feist if (findPwm != connector->second.end()) 4738e94c204SJames Feist { 474de5e9705SJames Feist size_t pwm = std::visit(VariantToUnsignedIntVisitor(), 475de5e9705SJames Feist findPwm->second); 476ddf25d17SHoward Chiu if (!findPwmPath(directory, pwm, pwmPath)) 477ddf25d17SHoward Chiu { 478ddf25d17SHoward Chiu std::cerr << "Connector for " << sensorName 479ddf25d17SHoward Chiu << " no pwm channel found!\n"; 480ddf25d17SHoward Chiu continue; 481ddf25d17SHoward Chiu } 482ddf25d17SHoward Chiu 483779c96a2SPatrick Williams fs::path pwmEnableFile = "pwm" + std::to_string(pwm + 1) + 484779c96a2SPatrick Williams "_enable"; 485bb67932aSEd Tanous fs::path enablePath = pwmPath.parent_path() / pwmEnableFile; 486ddf25d17SHoward Chiu enablePwm(enablePath); 487ddf25d17SHoward Chiu 48849a8ccd6SJames Feist /* use pwm name override if found in configuration else 48949a8ccd6SJames Feist * use default */ 490d320a2e1SJason Ling auto findOverride = connector->second.find("PwmName"); 491d320a2e1SJason Ling if (findOverride != connector->second.end()) 492d320a2e1SJason Ling { 493d320a2e1SJason Ling pwmName = std::visit(VariantToStringVisitor(), 494d320a2e1SJason Ling findOverride->second); 495d320a2e1SJason Ling } 496d320a2e1SJason Ling else 497d320a2e1SJason Ling { 498d320a2e1SJason Ling pwmName = "Pwm_" + std::to_string(pwm + 1); 499d320a2e1SJason Ling } 5003291b9c7SJie Yang 5013291b9c7SJie Yang // Check PWM sensor mutability 5023291b9c7SJie Yang auto findMutable = connector->second.find("Mutable"); 5033291b9c7SJie Yang if (findMutable != connector->second.end()) 5043291b9c7SJie Yang { 5052049bd26SEd Tanous const auto* ptrMutable = 5063291b9c7SJie Yang std::get_if<bool>(&(findMutable->second)); 5072049bd26SEd Tanous if (ptrMutable != nullptr) 5083291b9c7SJie Yang { 5093291b9c7SJie Yang isValueMutable = *ptrMutable; 5103291b9c7SJie Yang } 5113291b9c7SJie Yang } 5128e94c204SJames Feist } 51349a8ccd6SJames Feist else 51449a8ccd6SJames Feist { 51549a8ccd6SJames Feist std::cerr << "Connector for " << sensorName 51649a8ccd6SJames Feist << " missing pwm!\n"; 51749a8ccd6SJames Feist } 51849a8ccd6SJames Feist 51949a8ccd6SJames Feist auto findLED = connector->second.find("LED"); 52049a8ccd6SJames Feist if (findLED != connector->second.end()) 52149a8ccd6SJames Feist { 5222049bd26SEd Tanous const auto* ledName = 5232049bd26SEd Tanous std::get_if<std::string>(&(findLED->second)); 52449a8ccd6SJames Feist if (ledName == nullptr) 52549a8ccd6SJames Feist { 526bb67932aSEd Tanous std::cerr << "Wrong format for LED of " << sensorName 527bb67932aSEd Tanous << "\n"; 52849a8ccd6SJames Feist } 52949a8ccd6SJames Feist else 53049a8ccd6SJames Feist { 53149a8ccd6SJames Feist led = *ledName; 53249a8ccd6SJames Feist } 53349a8ccd6SJames Feist } 53449a8ccd6SJames Feist } 53549a8ccd6SJames Feist 53649a8ccd6SJames Feist findLimits(limits, baseConfiguration); 5375170fe63SJosh Lehan 5389c47bd7eSJustin Ledford enableFanInput(path); 5399c47bd7eSJustin Ledford 5405170fe63SJosh Lehan auto& tachSensor = tachSensors[sensorName]; 5415170fe63SJosh Lehan tachSensor = nullptr; 5425170fe63SJosh Lehan tachSensor = std::make_shared<TachSensor>( 54349a8ccd6SJames Feist path.string(), baseType, objectServer, dbusConnection, 54449a8ccd6SJames Feist std::move(presenceSensor), redundancy, io, sensorName, 545bb67932aSEd Tanous std::move(sensorThresholds), *interfacePath, limits, powerState, 546bb67932aSEd Tanous led); 5475170fe63SJosh Lehan tachSensor->setupRead(); 54877b3add2SYong Zhao 549d05867c0SZhikui Ren if (!pwmPath.empty() && fs::exists(pwmPath) && 5502049bd26SEd Tanous (pwmSensors.count(pwmPath) == 0U)) 55177b3add2SYong Zhao { 55277b3add2SYong Zhao pwmSensors[pwmPath] = std::make_unique<PwmSensor>( 55377b3add2SYong Zhao pwmName, pwmPath, dbusConnection, objectServer, 5543291b9c7SJie Yang *interfacePath, "Fan", isValueMutable); 5556714a25aSJames Feist } 55677b3add2SYong Zhao } 55777b3add2SYong Zhao 558d540741eSKuiying Wang createRedundancySensor(tachSensors, dbusConnection, objectServer); 5598a17c303SEd Tanous }); 560de5e9705SJames Feist getter->getConfiguration( 561f27a55c7SJames Feist std::vector<std::string>{sensorTypes.begin(), sensorTypes.end()}, 562f27a55c7SJames Feist retries); 5636714a25aSJames Feist } 5646714a25aSJames Feist 565b6c0b914SJames Feist int main() 5666714a25aSJames Feist { 5671f978631SEd Tanous boost::asio::io_context io; 5686714a25aSJames Feist auto systemBus = std::make_shared<sdbusplus::asio::connection>(io); 56914ed5e99SEd Tanous sdbusplus::asio::object_server objectServer(systemBus, true); 57014ed5e99SEd Tanous 57114ed5e99SEd Tanous objectServer.add_manager("/xyz/openbmc_project/sensors"); 572d9067251SEd Tanous objectServer.add_manager("/xyz/openbmc_project/control"); 573c2f83fedSLei YU objectServer.add_manager("/xyz/openbmc_project/inventory"); 5746714a25aSJames Feist systemBus->request_name("xyz.openbmc_project.FanSensor"); 5755170fe63SJosh Lehan boost::container::flat_map<std::string, std::shared_ptr<TachSensor>> 5766714a25aSJames Feist tachSensors; 5776714a25aSJames Feist boost::container::flat_map<std::string, std::unique_ptr<PwmSensor>> 5786714a25aSJames Feist pwmSensors; 5795591cf08SJames Feist auto sensorsChanged = 5805591cf08SJames Feist std::make_shared<boost::container::flat_set<std::string>>(); 5816714a25aSJames Feist 58283db50caSEd Tanous boost::asio::post(io, [&]() { 5836714a25aSJames Feist createSensors(io, objectServer, tachSensors, pwmSensors, systemBus, 5846714a25aSJames Feist nullptr); 5856714a25aSJames Feist }); 5866714a25aSJames Feist 5879b4a20e9SEd Tanous boost::asio::steady_timer filterTimer(io); 58892f8f515SPatrick Williams std::function<void(sdbusplus::message_t&)> eventHandler = 58992f8f515SPatrick Williams [&](sdbusplus::message_t& message) { 5906714a25aSJames Feist if (message.is_method_error()) 5916714a25aSJames Feist { 5926714a25aSJames Feist std::cerr << "callback method error\n"; 5936714a25aSJames Feist return; 5946714a25aSJames Feist } 5956714a25aSJames Feist sensorsChanged->insert(message.get_path()); 5966714a25aSJames Feist // this implicitly cancels the timer 59783db50caSEd Tanous filterTimer.expires_after(std::chrono::seconds(1)); 5986714a25aSJames Feist 5996714a25aSJames Feist filterTimer.async_wait([&](const boost::system::error_code& ec) { 6006714a25aSJames Feist if (ec == boost::asio::error::operation_aborted) 6016714a25aSJames Feist { 6026714a25aSJames Feist /* we were canceled*/ 6036714a25aSJames Feist return; 6046714a25aSJames Feist } 6058a57ec09SEd Tanous if (ec) 6066714a25aSJames Feist { 6076714a25aSJames Feist std::cerr << "timer error\n"; 6086714a25aSJames Feist return; 6096714a25aSJames Feist } 610bb67932aSEd Tanous createSensors(io, objectServer, tachSensors, pwmSensors, systemBus, 611bb67932aSEd Tanous sensorsChanged, 5); 6126714a25aSJames Feist }); 6136714a25aSJames Feist }; 6146714a25aSJames Feist 615214d9717SZev Weiss std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches = 616214d9717SZev Weiss setupPropertiesChangedMatches(*systemBus, sensorTypes, eventHandler); 6176714a25aSJames Feist 618dc6c55f3SJames Feist // redundancy sensor 61992f8f515SPatrick Williams std::function<void(sdbusplus::message_t&)> redundancyHandler = 62092f8f515SPatrick Williams [&tachSensors, &systemBus, &objectServer](sdbusplus::message_t&) { 621dc6c55f3SJames Feist createRedundancySensor(tachSensors, systemBus, objectServer); 622dc6c55f3SJames Feist }; 62392f8f515SPatrick Williams auto match = std::make_unique<sdbusplus::bus::match_t>( 62492f8f515SPatrick Williams static_cast<sdbusplus::bus_t&>(*systemBus), 625dc6c55f3SJames Feist "type='signal',member='PropertiesChanged',path_namespace='" + 626dc6c55f3SJames Feist std::string(inventoryPath) + "',arg0namespace='" + 627dc6c55f3SJames Feist redundancyConfiguration + "'", 628b6c0b914SJames Feist std::move(redundancyHandler)); 629dc6c55f3SJames Feist matches.emplace_back(std::move(match)); 630dc6c55f3SJames Feist 6311263c3daSBruce Lee setupManufacturingModeMatch(*systemBus); 6326714a25aSJames Feist io.run(); 6338685b17aSZhikui Ren return 0; 6346714a25aSJames Feist } 635