17136a5aeSJames Feist /* 27136a5aeSJames Feist // Copyright (c) 2018 Intel Corporation 37136a5aeSJames Feist // 47136a5aeSJames Feist // Licensed under the Apache License, Version 2.0 (the "License"); 57136a5aeSJames Feist // you may not use this file except in compliance with the License. 67136a5aeSJames Feist // You may obtain a copy of the License at 77136a5aeSJames Feist // 87136a5aeSJames Feist // http://www.apache.org/licenses/LICENSE-2.0 97136a5aeSJames Feist // 107136a5aeSJames Feist // Unless required by applicable law or agreed to in writing, software 117136a5aeSJames Feist // distributed under the License is distributed on an "AS IS" BASIS, 127136a5aeSJames Feist // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137136a5aeSJames Feist // See the License for the specific language governing permissions and 147136a5aeSJames Feist // limitations under the License. 157136a5aeSJames Feist */ 167e952d9fSPatrick Venture #include "dbusconfiguration.hpp" 177136a5aeSJames Feist 180771659eSPatrick Venture #include "conf.hpp" 19ef1f8864SPatrick Venture #include "dbushelper.hpp" 20ef1f8864SPatrick Venture #include "dbusutil.hpp" 210c8223b5SJames Feist #include "util.hpp" 220771659eSPatrick Venture 231fe08952SJames Feist #include <boost/asio/steady_timer.hpp> 24a83a3eccSPatrick Venture #include <sdbusplus/bus.hpp> 25a83a3eccSPatrick Venture #include <sdbusplus/bus/match.hpp> 26a83a3eccSPatrick Venture #include <sdbusplus/exception.hpp> 27a83a3eccSPatrick Venture 28a83a3eccSPatrick Venture #include <algorithm> 2964f072a7SJames Feist #include <chrono> 3064f072a7SJames Feist #include <functional> 317136a5aeSJames Feist #include <iostream> 321fe08952SJames Feist #include <list> 337136a5aeSJames Feist #include <set> 347136a5aeSJames Feist #include <unordered_map> 351f802f5eSJames Feist #include <variant> 367136a5aeSJames Feist 37a076487aSPatrick Venture namespace pid_control 38a076487aSPatrick Venture { 39a076487aSPatrick Venture 407136a5aeSJames Feist constexpr const char* pidConfigurationInterface = 417136a5aeSJames Feist "xyz.openbmc_project.Configuration.Pid"; 427136a5aeSJames Feist constexpr const char* objectManagerInterface = 437136a5aeSJames Feist "org.freedesktop.DBus.ObjectManager"; 447136a5aeSJames Feist constexpr const char* pidZoneConfigurationInterface = 457136a5aeSJames Feist "xyz.openbmc_project.Configuration.Pid.Zone"; 4622c257abSJames Feist constexpr const char* stepwiseConfigurationInterface = 4722c257abSJames Feist "xyz.openbmc_project.Configuration.Stepwise"; 48f0096a0cSJames Feist constexpr const char* thermalControlIface = 49f0096a0cSJames Feist "xyz.openbmc_project.Control.ThermalMode"; 507136a5aeSJames Feist constexpr const char* sensorInterface = "xyz.openbmc_project.Sensor.Value"; 510911bfe7SPatrick Venture constexpr const char* defaultPwmInterface = 520911bfe7SPatrick Venture "xyz.openbmc_project.Control.FanPwm"; 537136a5aeSJames Feist 54991ebd80SJames Feist using Association = std::tuple<std::string, std::string, std::string>; 55991ebd80SJames Feist using Associations = std::vector<Association>; 56991ebd80SJames Feist 575ec20270SJames Feist namespace thresholds 585ec20270SJames Feist { 595ec20270SJames Feist constexpr const char* warningInterface = 605ec20270SJames Feist "xyz.openbmc_project.Sensor.Threshold.Warning"; 615ec20270SJames Feist constexpr const char* criticalInterface = 625ec20270SJames Feist "xyz.openbmc_project.Sensor.Threshold.Critical"; 635ec20270SJames Feist const std::array<const char*, 4> types = {"CriticalLow", "CriticalHigh", 645ec20270SJames Feist "WarningLow", "WarningHigh"}; 655ec20270SJames Feist 665ec20270SJames Feist } // namespace thresholds 675ec20270SJames Feist 687136a5aeSJames Feist namespace dbus_configuration 697136a5aeSJames Feist { 70f3b04fd3SJason Ling using SensorInterfaceType = std::pair<std::string, std::string>; 71f3b04fd3SJason Ling 72f3b04fd3SJason Ling inline std::string getSensorNameFromPath(const std::string& dbusPath) 73f3b04fd3SJason Ling { 74f3b04fd3SJason Ling return dbusPath.substr(dbusPath.find_last_of("/") + 1); 75f3b04fd3SJason Ling } 76f3b04fd3SJason Ling 77f3b04fd3SJason Ling inline std::string sensorNameToDbusName(const std::string& sensorName) 78f3b04fd3SJason Ling { 79f3b04fd3SJason Ling std::string retString = sensorName; 80f3b04fd3SJason Ling std::replace(retString.begin(), retString.end(), ' ', '_'); 81f3b04fd3SJason Ling return retString; 82f3b04fd3SJason Ling } 835ec20270SJames Feist 84b228bc30SPatrick Williams std::vector<std::string> getSelectedProfiles(sdbusplus::bus_t& bus) 85f0096a0cSJames Feist { 86f0096a0cSJames Feist std::vector<std::string> ret; 87f0096a0cSJames Feist auto mapper = 88f0096a0cSJames Feist bus.new_method_call("xyz.openbmc_project.ObjectMapper", 89f0096a0cSJames Feist "/xyz/openbmc_project/object_mapper", 90f0096a0cSJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree"); 91f0096a0cSJames Feist mapper.append("/", 0, std::array<const char*, 1>{thermalControlIface}); 92f0096a0cSJames Feist std::unordered_map< 93f0096a0cSJames Feist std::string, std::unordered_map<std::string, std::vector<std::string>>> 94f0096a0cSJames Feist respData; 95f0096a0cSJames Feist 96f0096a0cSJames Feist try 97f0096a0cSJames Feist { 98f0096a0cSJames Feist auto resp = bus.call(mapper); 99f0096a0cSJames Feist resp.read(respData); 100f0096a0cSJames Feist } 1010001ee02SPatrick Williams catch (const sdbusplus::exception_t&) 102f0096a0cSJames Feist { 103f0096a0cSJames Feist // can't do anything without mapper call data 104f0096a0cSJames Feist throw std::runtime_error("ObjectMapper Call Failure"); 105f0096a0cSJames Feist } 106f0096a0cSJames Feist if (respData.empty()) 107f0096a0cSJames Feist { 108f0096a0cSJames Feist // if the user has profiles but doesn't expose the interface to select 109f0096a0cSJames Feist // one, just go ahead without using profiles 110f0096a0cSJames Feist return ret; 111f0096a0cSJames Feist } 112f0096a0cSJames Feist 113f0096a0cSJames Feist // assumption is that we should only have a small handful of selected 114f0096a0cSJames Feist // profiles at a time (probably only 1), so calling each individually should 115f0096a0cSJames Feist // not incur a large cost 116f0096a0cSJames Feist for (const auto& objectPair : respData) 117f0096a0cSJames Feist { 118f0096a0cSJames Feist const std::string& path = objectPair.first; 119f0096a0cSJames Feist for (const auto& ownerPair : objectPair.second) 120f0096a0cSJames Feist { 121f0096a0cSJames Feist const std::string& busName = ownerPair.first; 122f0096a0cSJames Feist auto getProfile = 123f0096a0cSJames Feist bus.new_method_call(busName.c_str(), path.c_str(), 124f0096a0cSJames Feist "org.freedesktop.DBus.Properties", "Get"); 125f0096a0cSJames Feist getProfile.append(thermalControlIface, "Current"); 126f0096a0cSJames Feist std::variant<std::string> variantResp; 127f0096a0cSJames Feist try 128f0096a0cSJames Feist { 129f0096a0cSJames Feist auto resp = bus.call(getProfile); 130f0096a0cSJames Feist resp.read(variantResp); 131f0096a0cSJames Feist } 1320001ee02SPatrick Williams catch (const sdbusplus::exception_t&) 133f0096a0cSJames Feist { 134f0096a0cSJames Feist throw std::runtime_error("Failure getting profile"); 135f0096a0cSJames Feist } 136f0096a0cSJames Feist std::string mode = std::get<std::string>(variantResp); 137f0096a0cSJames Feist ret.emplace_back(std::move(mode)); 138f0096a0cSJames Feist } 139f0096a0cSJames Feist } 14039199b4dSPatrick Venture if constexpr (pid_control::conf::DEBUG) 141f0096a0cSJames Feist { 142f0096a0cSJames Feist std::cout << "Profiles selected: "; 143f0096a0cSJames Feist for (const auto& profile : ret) 144f0096a0cSJames Feist { 145f0096a0cSJames Feist std::cout << profile << " "; 146f0096a0cSJames Feist } 147f0096a0cSJames Feist std::cout << "\n"; 148f0096a0cSJames Feist } 149f0096a0cSJames Feist return ret; 150f0096a0cSJames Feist } 151f0096a0cSJames Feist 152991ebd80SJames Feist int eventHandler(sd_bus_message* m, void* context, sd_bus_error*) 1537136a5aeSJames Feist { 1541fe08952SJames Feist 155991ebd80SJames Feist if (context == nullptr || m == nullptr) 1561fe08952SJames Feist { 1571fe08952SJames Feist throw std::runtime_error("Invalid match"); 1581fe08952SJames Feist } 159991ebd80SJames Feist 160991ebd80SJames Feist // we skip associations because the mapper populates these, not the sensors 161991ebd80SJames Feist const std::array<const char*, 1> skipList = { 162991ebd80SJames Feist "xyz.openbmc_project.Association"}; 163991ebd80SJames Feist 164b228bc30SPatrick Williams sdbusplus::message_t message(m); 165991ebd80SJames Feist if (std::string(message.get_member()) == "InterfacesAdded") 166991ebd80SJames Feist { 167991ebd80SJames Feist sdbusplus::message::object_path path; 168991ebd80SJames Feist std::unordered_map< 169991ebd80SJames Feist std::string, 170991ebd80SJames Feist std::unordered_map<std::string, std::variant<Associations, bool>>> 171991ebd80SJames Feist data; 172991ebd80SJames Feist 173991ebd80SJames Feist message.read(path, data); 174991ebd80SJames Feist 175991ebd80SJames Feist for (const char* skip : skipList) 176991ebd80SJames Feist { 177991ebd80SJames Feist auto find = data.find(skip); 178991ebd80SJames Feist if (find != data.end()) 179991ebd80SJames Feist { 180991ebd80SJames Feist data.erase(find); 181991ebd80SJames Feist if (data.empty()) 182991ebd80SJames Feist { 183991ebd80SJames Feist return 1; 184991ebd80SJames Feist } 185991ebd80SJames Feist } 186991ebd80SJames Feist } 187991ebd80SJames Feist } 188991ebd80SJames Feist 1891fe08952SJames Feist boost::asio::steady_timer* timer = 1901fe08952SJames Feist static_cast<boost::asio::steady_timer*>(context); 1911fe08952SJames Feist 1921fe08952SJames Feist // do a brief sleep as we tend to get a bunch of these events at 1931fe08952SJames Feist // once 1941fe08952SJames Feist timer->expires_after(std::chrono::seconds(2)); 1951fe08952SJames Feist timer->async_wait([](const boost::system::error_code ec) { 1961fe08952SJames Feist if (ec == boost::asio::error::operation_aborted) 1971fe08952SJames Feist { 1981fe08952SJames Feist /* another timer started*/ 1991fe08952SJames Feist return; 2001fe08952SJames Feist } 2011fe08952SJames Feist 2021fe08952SJames Feist std::cout << "New configuration detected, reloading\n."; 203298a95cbSYong Li tryRestartControlLoops(); 2041fe08952SJames Feist }); 2051fe08952SJames Feist 2061fe08952SJames Feist return 1; 2071fe08952SJames Feist } 2081fe08952SJames Feist 209b228bc30SPatrick Williams void createMatches(sdbusplus::bus_t& bus, boost::asio::steady_timer& timer) 2101fe08952SJames Feist { 2111fe08952SJames Feist // this is a list because the matches can't be moved 212b228bc30SPatrick Williams static std::list<sdbusplus::bus::match_t> matches; 2131fe08952SJames Feist 2143987c8b4SJames Feist const std::array<std::string, 4> interfaces = { 2153987c8b4SJames Feist thermalControlIface, pidConfigurationInterface, 2163987c8b4SJames Feist pidZoneConfigurationInterface, stepwiseConfigurationInterface}; 2171fe08952SJames Feist 2181fe08952SJames Feist // this list only needs to be created once 2191fe08952SJames Feist if (!matches.empty()) 2201fe08952SJames Feist { 2211fe08952SJames Feist return; 2221fe08952SJames Feist } 2231fe08952SJames Feist 2241fe08952SJames Feist // we restart when the configuration changes or there are new sensors 2251fe08952SJames Feist for (const auto& interface : interfaces) 2261fe08952SJames Feist { 2271fe08952SJames Feist matches.emplace_back( 2281fe08952SJames Feist bus, 2291fe08952SJames Feist "type='signal',member='PropertiesChanged',arg0namespace='" + 2301fe08952SJames Feist interface + "'", 2311fe08952SJames Feist eventHandler, &timer); 2321fe08952SJames Feist } 2331fe08952SJames Feist matches.emplace_back( 2341fe08952SJames Feist bus, 2351fe08952SJames Feist "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/" 2361fe08952SJames Feist "sensors/'", 2371fe08952SJames Feist eventHandler, &timer); 2381fe08952SJames Feist } 2391fe08952SJames Feist 2406fc301fbSJason Ling /** 2416fc301fbSJason Ling * retrieve an attribute from the pid configuration map 2426fc301fbSJason Ling * @param[in] base - the PID configuration map, keys are the attributes and 2436fc301fbSJason Ling * value is the variant associated with that attribute. 2446fc301fbSJason Ling * @param attributeName - the name of the attribute 2456fc301fbSJason Ling * @return a variant holding the value associated with a key 2466fc301fbSJason Ling * @throw runtime_error : attributeName is not in base 2476fc301fbSJason Ling */ 2486fc301fbSJason Ling inline DbusVariantType getPIDAttribute( 2496fc301fbSJason Ling const std::unordered_map<std::string, DbusVariantType>& base, 2506fc301fbSJason Ling const std::string& attributeName) 2516fc301fbSJason Ling { 2526fc301fbSJason Ling auto search = base.find(attributeName); 2536fc301fbSJason Ling if (search == base.end()) 2546fc301fbSJason Ling { 2556fc301fbSJason Ling throw std::runtime_error("missing attribute " + attributeName); 2566fc301fbSJason Ling } 2576fc301fbSJason Ling return search->second; 2586fc301fbSJason Ling } 2596fc301fbSJason Ling 2605ec20270SJames Feist void populatePidInfo( 261*a1ae4fa1SHarvey.Wu [[maybe_unused]] sdbusplus::bus_t& bus, 2625ec20270SJames Feist const std::unordered_map<std::string, DbusVariantType>& base, 2631df9e879SPatrick Venture conf::ControllerInfo& info, const std::string* thresholdProperty, 2647382318fSPatrick Venture const std::map<std::string, conf::SensorConfig>& sensorConfig) 2655ec20270SJames Feist { 2666fc301fbSJason Ling info.type = std::get<std::string>(getPIDAttribute(base, "Class")); 2675ec20270SJames Feist if (info.type == "fan") 2685ec20270SJames Feist { 2695ec20270SJames Feist info.setpoint = 0; 2705ec20270SJames Feist } 2715ec20270SJames Feist else 2725ec20270SJames Feist { 2736fc301fbSJason Ling info.setpoint = std::visit(VariantToDoubleVisitor(), 2746fc301fbSJason Ling getPIDAttribute(base, "SetPoint")); 2755ec20270SJames Feist } 2765ec20270SJames Feist 2775ec20270SJames Feist if (thresholdProperty != nullptr) 2785ec20270SJames Feist { 2795ec20270SJames Feist std::string interface; 2805ec20270SJames Feist if (*thresholdProperty == "WarningHigh" || 2815ec20270SJames Feist *thresholdProperty == "WarningLow") 2825ec20270SJames Feist { 2835ec20270SJames Feist interface = thresholds::warningInterface; 2845ec20270SJames Feist } 2855ec20270SJames Feist else 2865ec20270SJames Feist { 2875ec20270SJames Feist interface = thresholds::criticalInterface; 2885ec20270SJames Feist } 2897382318fSPatrick Venture const std::string& path = sensorConfig.at(info.inputs.front()).readPath; 2905ec20270SJames Feist 2918729eb98SPatrick Venture DbusHelper helper(sdbusplus::bus::new_system()); 2929b93692dSPatrick Venture std::string service = helper.getService(interface, path); 2935ec20270SJames Feist double reading = 0; 2945ec20270SJames Feist try 2955ec20270SJames Feist { 2969b93692dSPatrick Venture helper.getProperty(service, path, interface, *thresholdProperty, 2979b93692dSPatrick Venture reading); 2985ec20270SJames Feist } 299b228bc30SPatrick Williams catch (const sdbusplus::exception_t& ex) 3005ec20270SJames Feist { 3015ec20270SJames Feist // unsupported threshold, leaving reading at 0 3025ec20270SJames Feist } 3035ec20270SJames Feist 3045ec20270SJames Feist info.setpoint += reading; 3055ec20270SJames Feist } 3065ec20270SJames Feist 3075ec20270SJames Feist info.pidInfo.ts = 1.0; // currently unused 3086fc301fbSJason Ling info.pidInfo.proportionalCoeff = std::visit( 3096fc301fbSJason Ling VariantToDoubleVisitor(), getPIDAttribute(base, "PCoefficient")); 3106fc301fbSJason Ling info.pidInfo.integralCoeff = std::visit( 3116fc301fbSJason Ling VariantToDoubleVisitor(), getPIDAttribute(base, "ICoefficient")); 3126fc301fbSJason Ling info.pidInfo.feedFwdOffset = std::visit( 3136fc301fbSJason Ling VariantToDoubleVisitor(), getPIDAttribute(base, "FFOffCoefficient")); 3146fc301fbSJason Ling info.pidInfo.feedFwdGain = std::visit( 3156fc301fbSJason Ling VariantToDoubleVisitor(), getPIDAttribute(base, "FFGainCoefficient")); 3166fc301fbSJason Ling info.pidInfo.integralLimit.max = std::visit( 3176fc301fbSJason Ling VariantToDoubleVisitor(), getPIDAttribute(base, "ILimitMax")); 3186fc301fbSJason Ling info.pidInfo.integralLimit.min = std::visit( 3196fc301fbSJason Ling VariantToDoubleVisitor(), getPIDAttribute(base, "ILimitMin")); 3206fc301fbSJason Ling info.pidInfo.outLim.max = std::visit(VariantToDoubleVisitor(), 3216fc301fbSJason Ling getPIDAttribute(base, "OutLimitMax")); 3226fc301fbSJason Ling info.pidInfo.outLim.min = std::visit(VariantToDoubleVisitor(), 3236fc301fbSJason Ling getPIDAttribute(base, "OutLimitMin")); 3245ec20270SJames Feist info.pidInfo.slewNeg = 3256fc301fbSJason Ling std::visit(VariantToDoubleVisitor(), getPIDAttribute(base, "SlewNeg")); 3265ec20270SJames Feist info.pidInfo.slewPos = 3276fc301fbSJason Ling std::visit(VariantToDoubleVisitor(), getPIDAttribute(base, "SlewPos")); 3285ec20270SJames Feist double negativeHysteresis = 0; 3295ec20270SJames Feist double positiveHysteresis = 0; 3305ec20270SJames Feist 3315ec20270SJames Feist auto findNeg = base.find("NegativeHysteresis"); 3325ec20270SJames Feist auto findPos = base.find("PositiveHysteresis"); 3335ec20270SJames Feist 3345ec20270SJames Feist if (findNeg != base.end()) 3355ec20270SJames Feist { 3365ec20270SJames Feist negativeHysteresis = 3375ec20270SJames Feist std::visit(VariantToDoubleVisitor(), findNeg->second); 3385ec20270SJames Feist } 3395ec20270SJames Feist 3405ec20270SJames Feist if (findPos != base.end()) 3415ec20270SJames Feist { 3425ec20270SJames Feist positiveHysteresis = 3435ec20270SJames Feist std::visit(VariantToDoubleVisitor(), findPos->second); 3445ec20270SJames Feist } 3455ec20270SJames Feist info.pidInfo.negativeHysteresis = negativeHysteresis; 3465ec20270SJames Feist info.pidInfo.positiveHysteresis = positiveHysteresis; 3475ec20270SJames Feist } 3485ec20270SJames Feist 349b228bc30SPatrick Williams bool init(sdbusplus::bus_t& bus, boost::asio::steady_timer& timer, 3507382318fSPatrick Venture std::map<std::string, conf::SensorConfig>& sensorConfig, 3517382318fSPatrick Venture std::map<int64_t, conf::PIDConf>& zoneConfig, 3527382318fSPatrick Venture std::map<int64_t, conf::ZoneConfig>& zoneDetailsConfig) 3531fe08952SJames Feist { 3541fe08952SJames Feist 3551fe08952SJames Feist sensorConfig.clear(); 3561fe08952SJames Feist zoneConfig.clear(); 3571fe08952SJames Feist zoneDetailsConfig.clear(); 3581fe08952SJames Feist 3591fe08952SJames Feist createMatches(bus, timer); 3601fe08952SJames Feist 3617136a5aeSJames Feist auto mapper = 3627136a5aeSJames Feist bus.new_method_call("xyz.openbmc_project.ObjectMapper", 3637136a5aeSJames Feist "/xyz/openbmc_project/object_mapper", 3647136a5aeSJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree"); 36526e8c6a9SJames Feist mapper.append("/", 0, 3660911bfe7SPatrick Venture std::array<const char*, 6>{ 3670911bfe7SPatrick Venture objectManagerInterface, pidConfigurationInterface, 3687136a5aeSJames Feist pidZoneConfigurationInterface, 3690911bfe7SPatrick Venture stepwiseConfigurationInterface, sensorInterface, 3700911bfe7SPatrick Venture defaultPwmInterface}); 37122c257abSJames Feist std::unordered_map< 37222c257abSJames Feist std::string, std::unordered_map<std::string, std::vector<std::string>>> 37322c257abSJames Feist respData; 37422c257abSJames Feist try 37522c257abSJames Feist { 3767136a5aeSJames Feist auto resp = bus.call(mapper); 3777136a5aeSJames Feist resp.read(respData); 37822c257abSJames Feist } 3790001ee02SPatrick Williams catch (const sdbusplus::exception_t&) 38022c257abSJames Feist { 38122c257abSJames Feist // can't do anything without mapper call data 38222c257abSJames Feist throw std::runtime_error("ObjectMapper Call Failure"); 38322c257abSJames Feist } 38422c257abSJames Feist 3857136a5aeSJames Feist if (respData.empty()) 3867136a5aeSJames Feist { 38722c257abSJames Feist // can't do anything without mapper call data 3887136a5aeSJames Feist throw std::runtime_error("No configuration data available from Mapper"); 3897136a5aeSJames Feist } 3907136a5aeSJames Feist // create a map of pair of <has pid configuration, ObjectManager path> 3917136a5aeSJames Feist std::unordered_map<std::string, std::pair<bool, std::string>> owners; 3927136a5aeSJames Feist // and a map of <path, interface> for sensors 3937136a5aeSJames Feist std::unordered_map<std::string, std::string> sensors; 3947136a5aeSJames Feist for (const auto& objectPair : respData) 3957136a5aeSJames Feist { 3967136a5aeSJames Feist for (const auto& ownerPair : objectPair.second) 3977136a5aeSJames Feist { 3987136a5aeSJames Feist auto& owner = owners[ownerPair.first]; 3997136a5aeSJames Feist for (const std::string& interface : ownerPair.second) 4007136a5aeSJames Feist { 4017136a5aeSJames Feist 4027136a5aeSJames Feist if (interface == objectManagerInterface) 4037136a5aeSJames Feist { 4047136a5aeSJames Feist owner.second = objectPair.first; 4057136a5aeSJames Feist } 4067136a5aeSJames Feist if (interface == pidConfigurationInterface || 40722c257abSJames Feist interface == pidZoneConfigurationInterface || 40822c257abSJames Feist interface == stepwiseConfigurationInterface) 4097136a5aeSJames Feist { 4107136a5aeSJames Feist owner.first = true; 4117136a5aeSJames Feist } 4120911bfe7SPatrick Venture if (interface == sensorInterface || 4130911bfe7SPatrick Venture interface == defaultPwmInterface) 4147136a5aeSJames Feist { 4157136a5aeSJames Feist // we're not interested in pwm sensors, just pwm control 4167136a5aeSJames Feist if (interface == sensorInterface && 4177136a5aeSJames Feist objectPair.first.find("pwm") != std::string::npos) 4187136a5aeSJames Feist { 4197136a5aeSJames Feist continue; 4207136a5aeSJames Feist } 4217136a5aeSJames Feist sensors[objectPair.first] = interface; 4227136a5aeSJames Feist } 4237136a5aeSJames Feist } 4247136a5aeSJames Feist } 4257136a5aeSJames Feist } 4267136a5aeSJames Feist ManagedObjectType configurations; 4277136a5aeSJames Feist for (const auto& owner : owners) 4287136a5aeSJames Feist { 4297136a5aeSJames Feist // skip if no pid configuration (means probably a sensor) 4307136a5aeSJames Feist if (!owner.second.first) 4317136a5aeSJames Feist { 4327136a5aeSJames Feist continue; 4337136a5aeSJames Feist } 4347136a5aeSJames Feist auto endpoint = bus.new_method_call( 4357136a5aeSJames Feist owner.first.c_str(), owner.second.second.c_str(), 4367136a5aeSJames Feist "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 43722c257abSJames Feist ManagedObjectType configuration; 43822c257abSJames Feist try 43922c257abSJames Feist { 4407136a5aeSJames Feist auto responce = bus.call(endpoint); 4417136a5aeSJames Feist responce.read(configuration); 44222c257abSJames Feist } 4430001ee02SPatrick Williams catch (const sdbusplus::exception_t&) 44422c257abSJames Feist { 44522c257abSJames Feist // this shouldn't happen, probably means daemon crashed 44622c257abSJames Feist throw std::runtime_error("Error getting managed objects from " + 44722c257abSJames Feist owner.first); 44822c257abSJames Feist } 44922c257abSJames Feist 4507136a5aeSJames Feist for (auto& pathPair : configuration) 4517136a5aeSJames Feist { 4527136a5aeSJames Feist if (pathPair.second.find(pidConfigurationInterface) != 4537136a5aeSJames Feist pathPair.second.end() || 4547136a5aeSJames Feist pathPair.second.find(pidZoneConfigurationInterface) != 45522c257abSJames Feist pathPair.second.end() || 45622c257abSJames Feist pathPair.second.find(stepwiseConfigurationInterface) != 4577136a5aeSJames Feist pathPair.second.end()) 4587136a5aeSJames Feist { 4597136a5aeSJames Feist configurations.emplace(pathPair); 4607136a5aeSJames Feist } 461f0096a0cSJames Feist } 462f0096a0cSJames Feist } 463f0096a0cSJames Feist 464f0096a0cSJames Feist // remove controllers from config that aren't in the current profile(s) 465f0096a0cSJames Feist std::vector<std::string> selectedProfiles = getSelectedProfiles(bus); 466f0096a0cSJames Feist if (selectedProfiles.size()) 467f0096a0cSJames Feist { 4683987c8b4SJames Feist for (auto pathIt = configurations.begin(); 4693987c8b4SJames Feist pathIt != configurations.end();) 470f0096a0cSJames Feist { 4713987c8b4SJames Feist for (auto confIt = pathIt->second.begin(); 4723987c8b4SJames Feist confIt != pathIt->second.end();) 4733987c8b4SJames Feist { 4743987c8b4SJames Feist auto profilesFind = confIt->second.find("Profiles"); 4753987c8b4SJames Feist if (profilesFind == confIt->second.end()) 4763987c8b4SJames Feist { 4773987c8b4SJames Feist confIt++; 4783987c8b4SJames Feist continue; // if no profiles selected, apply always 4793987c8b4SJames Feist } 4803987c8b4SJames Feist auto profiles = 4813987c8b4SJames Feist std::get<std::vector<std::string>>(profilesFind->second); 4823987c8b4SJames Feist if (profiles.empty()) 4833987c8b4SJames Feist { 4843987c8b4SJames Feist confIt++; 4853987c8b4SJames Feist continue; 486f0096a0cSJames Feist } 487f0096a0cSJames Feist 4883987c8b4SJames Feist bool found = false; 4893987c8b4SJames Feist for (const std::string& profile : profiles) 490f0096a0cSJames Feist { 4913987c8b4SJames Feist if (std::find(selectedProfiles.begin(), 4923987c8b4SJames Feist selectedProfiles.end(), 4933987c8b4SJames Feist profile) != selectedProfiles.end()) 494f0096a0cSJames Feist { 4953987c8b4SJames Feist found = true; 4963987c8b4SJames Feist break; 4973987c8b4SJames Feist } 4983987c8b4SJames Feist } 4993987c8b4SJames Feist if (found) 5003987c8b4SJames Feist { 5013987c8b4SJames Feist confIt++; 502f0096a0cSJames Feist } 503f0096a0cSJames Feist else 504f0096a0cSJames Feist { 5053987c8b4SJames Feist confIt = pathIt->second.erase(confIt); 506f0096a0cSJames Feist } 507f0096a0cSJames Feist } 5083987c8b4SJames Feist if (pathIt->second.empty()) 509f0096a0cSJames Feist { 5103987c8b4SJames Feist pathIt = configurations.erase(pathIt); 511f0096a0cSJames Feist } 512f0096a0cSJames Feist else 513f0096a0cSJames Feist { 5143987c8b4SJames Feist pathIt++; 515f0096a0cSJames Feist } 5167136a5aeSJames Feist } 5177136a5aeSJames Feist } 5188c3c51eeSJames Feist 519998fbe67SJosh Lehan // On D-Bus, although not necessary, 520998fbe67SJosh Lehan // having the "zoneID" field can still be useful, 521998fbe67SJosh Lehan // as it is used for diagnostic messages, 522998fbe67SJosh Lehan // logging file names, and so on. 523998fbe67SJosh Lehan // Accept optional "ZoneIndex" parameter to explicitly specify. 524998fbe67SJosh Lehan // If not present, or not unique, auto-assign index, 525998fbe67SJosh Lehan // using 0-based numbering, ensuring uniqueness. 526998fbe67SJosh Lehan std::map<std::string, int64_t> foundZones; 5277136a5aeSJames Feist for (const auto& configuration : configurations) 5287136a5aeSJames Feist { 5297136a5aeSJames Feist auto findZone = 5307136a5aeSJames Feist configuration.second.find(pidZoneConfigurationInterface); 5317136a5aeSJames Feist if (findZone != configuration.second.end()) 5327136a5aeSJames Feist { 5337136a5aeSJames Feist const auto& zone = findZone->second; 534ffd418bbSJames Feist 5351f802f5eSJames Feist const std::string& name = std::get<std::string>(zone.at("Name")); 536998fbe67SJosh Lehan 537998fbe67SJosh Lehan auto findZoneIndex = zone.find("ZoneIndex"); 538998fbe67SJosh Lehan if (findZoneIndex == zone.end()) 539998fbe67SJosh Lehan { 540998fbe67SJosh Lehan continue; 541998fbe67SJosh Lehan } 542998fbe67SJosh Lehan 543998fbe67SJosh Lehan auto ptrZoneIndex = std::get_if<double>(&(findZoneIndex->second)); 544998fbe67SJosh Lehan if (!ptrZoneIndex) 545998fbe67SJosh Lehan { 546998fbe67SJosh Lehan continue; 547998fbe67SJosh Lehan } 548998fbe67SJosh Lehan 549998fbe67SJosh Lehan auto desiredIndex = static_cast<int64_t>(*ptrZoneIndex); 550998fbe67SJosh Lehan auto grantedIndex = setZoneIndex(name, foundZones, desiredIndex); 551998fbe67SJosh Lehan std::cout << "Zone " << name << " is at ZoneIndex " << grantedIndex 552998fbe67SJosh Lehan << "\n"; 553998fbe67SJosh Lehan } 554998fbe67SJosh Lehan } 555998fbe67SJosh Lehan 556998fbe67SJosh Lehan for (const auto& configuration : configurations) 557998fbe67SJosh Lehan { 558998fbe67SJosh Lehan auto findZone = 559998fbe67SJosh Lehan configuration.second.find(pidZoneConfigurationInterface); 560998fbe67SJosh Lehan if (findZone != configuration.second.end()) 561998fbe67SJosh Lehan { 562998fbe67SJosh Lehan const auto& zone = findZone->second; 563998fbe67SJosh Lehan 564998fbe67SJosh Lehan const std::string& name = std::get<std::string>(zone.at("Name")); 565998fbe67SJosh Lehan 566998fbe67SJosh Lehan auto index = getZoneIndex(name, foundZones); 5678c3c51eeSJames Feist 568c54fbd88SPatrick Venture auto& details = zoneDetailsConfig[index]; 569998fbe67SJosh Lehan 5703484bedaSJames Feist details.minThermalOutput = std::visit(VariantToDoubleVisitor(), 5713484bedaSJames Feist zone.at("MinThermalOutput")); 5728e2fdb34SPatrick Venture details.failsafePercent = std::visit(VariantToDoubleVisitor(), 5731f802f5eSJames Feist zone.at("FailSafePercent")); 5747136a5aeSJames Feist } 5757136a5aeSJames Feist auto findBase = configuration.second.find(pidConfigurationInterface); 576f3b04fd3SJason Ling // loop through all the PID configurations and fill out a sensor config 57722c257abSJames Feist if (findBase != configuration.second.end()) 5787136a5aeSJames Feist { 57922c257abSJames Feist const auto& base = 58022c257abSJames Feist configuration.second.at(pidConfigurationInterface); 581f3b04fd3SJason Ling const std::string pidName = std::get<std::string>(base.at("Name")); 582f3b04fd3SJason Ling const std::string pidClass = 583f3b04fd3SJason Ling std::get<std::string>(base.at("Class")); 5848c3c51eeSJames Feist const std::vector<std::string>& zones = 5851f802f5eSJames Feist std::get<std::vector<std::string>>(base.at("Zones")); 5868c3c51eeSJames Feist for (const std::string& zone : zones) 5878c3c51eeSJames Feist { 588998fbe67SJosh Lehan auto index = getZoneIndex(zone, foundZones); 589998fbe67SJosh Lehan 590f81f2886SJames Feist conf::PIDConf& conf = zoneConfig[index]; 591f3b04fd3SJason Ling std::vector<std::string> inputSensorNames( 592f3b04fd3SJason Ling std::get<std::vector<std::string>>(base.at("Inputs"))); 593f3b04fd3SJason Ling std::vector<std::string> outputSensorNames; 59450fdfe39SJames Feist 595f3b04fd3SJason Ling // assumption: all fan pids must have at least one output 596f3b04fd3SJason Ling if (pidClass == "fan") 59750fdfe39SJames Feist { 598f3b04fd3SJason Ling outputSensorNames = std::get<std::vector<std::string>>( 599f3b04fd3SJason Ling getPIDAttribute(base, "Outputs")); 60050fdfe39SJames Feist } 6011738e2a2SJames Feist 6028f73ad76SAlex.Song bool unavailableAsFailed = true; 6038f73ad76SAlex.Song auto findUnavailableAsFailed = 6048f73ad76SAlex.Song base.find("InputUnavailableAsFailed"); 6058f73ad76SAlex.Song if (findUnavailableAsFailed != base.end()) 6068f73ad76SAlex.Song { 6078f73ad76SAlex.Song unavailableAsFailed = 6088f73ad76SAlex.Song std::get<bool>(findUnavailableAsFailed->second); 6098f73ad76SAlex.Song } 6108f73ad76SAlex.Song 611f3b04fd3SJason Ling std::vector<SensorInterfaceType> inputSensorInterfaces; 612f3b04fd3SJason Ling std::vector<SensorInterfaceType> outputSensorInterfaces; 613f3b04fd3SJason Ling /* populate an interface list for different sensor direction 614f3b04fd3SJason Ling * types (input,output) 615f3b04fd3SJason Ling */ 616f3b04fd3SJason Ling /* take the Inputs from the configuration and generate 617f3b04fd3SJason Ling * a list of dbus descriptors (path, interface). 618f3b04fd3SJason Ling * Mapping can be many-to-one since an element of Inputs can be 619f3b04fd3SJason Ling * a regex 620f3b04fd3SJason Ling */ 621f3b04fd3SJason Ling for (const std::string& sensorName : inputSensorNames) 62250fdfe39SJames Feist { 623f3b04fd3SJason Ling findSensors(sensors, sensorNameToDbusName(sensorName), 624f3b04fd3SJason Ling inputSensorInterfaces); 625f3b04fd3SJason Ling } 626f3b04fd3SJason Ling for (const std::string& sensorName : outputSensorNames) 627f3b04fd3SJason Ling { 628f3b04fd3SJason Ling findSensors(sensors, sensorNameToDbusName(sensorName), 629f3b04fd3SJason Ling outputSensorInterfaces); 63050fdfe39SJames Feist } 6311738e2a2SJames Feist 632f3b04fd3SJason Ling inputSensorNames.clear(); 633f3b04fd3SJason Ling for (const SensorInterfaceType& inputSensorInterface : 634f3b04fd3SJason Ling inputSensorInterfaces) 6351738e2a2SJames Feist { 636f3b04fd3SJason Ling const std::string& dbusInterface = 637f3b04fd3SJason Ling inputSensorInterface.second; 638f3b04fd3SJason Ling const std::string& inputSensorPath = 639f3b04fd3SJason Ling inputSensorInterface.first; 640ed1dafdfSHarvey.Wu // todo: maybe un-hardcode this if we run into slower 641ed1dafdfSHarvey.Wu // timeouts with sensors 642ed1dafdfSHarvey.Wu if (pidClass == "temp") 643ed1dafdfSHarvey.Wu { 644f3b04fd3SJason Ling std::string inputSensorName = 645f3b04fd3SJason Ling getSensorNameFromPath(inputSensorPath); 646f3b04fd3SJason Ling auto& config = sensorConfig[inputSensorName]; 647f3b04fd3SJason Ling inputSensorNames.push_back(inputSensorName); 648f3b04fd3SJason Ling config.type = pidClass; 649f3b04fd3SJason Ling config.readPath = inputSensorInterface.first; 6502642cb54SJames Feist config.timeout = 0; 6513433cb60SJames Feist config.ignoreDbusMinMax = true; 6528f73ad76SAlex.Song config.unavailableAsFailed = unavailableAsFailed; 65350fdfe39SJames Feist } 654f3b04fd3SJason Ling if (dbusInterface != sensorInterface) 655f3b04fd3SJason Ling { 656f3b04fd3SJason Ling /* all expected inputs in the configuration are expected 657f3b04fd3SJason Ling * to be sensor interfaces 658f3b04fd3SJason Ling */ 659f3b04fd3SJason Ling throw std::runtime_error( 660f3b04fd3SJason Ling "sensor at dbus path [" + inputSensorPath + 661f3b04fd3SJason Ling "] has an interface [" + dbusInterface + 662f3b04fd3SJason Ling "] that does not match the expected interface of " + 663f3b04fd3SJason Ling sensorInterface); 66450fdfe39SJames Feist } 66550fdfe39SJames Feist } 6661738e2a2SJames Feist 667f3b04fd3SJason Ling /* fan pids need to pair up tach sensors with their pwm 668f3b04fd3SJason Ling * counterparts 669f3b04fd3SJason Ling */ 670f3b04fd3SJason Ling if (pidClass == "fan") 671f3b04fd3SJason Ling { 672f3b04fd3SJason Ling /* If a PID is a fan there should be either 673f3b04fd3SJason Ling * (1) one output(pwm) per input(tach) 674f3b04fd3SJason Ling * OR 675f3b04fd3SJason Ling * (2) one putput(pwm) for all inputs(tach) 676f3b04fd3SJason Ling * everything else indicates a bad configuration. 677f3b04fd3SJason Ling */ 678f3b04fd3SJason Ling bool singlePwm = false; 679f3b04fd3SJason Ling if (outputSensorInterfaces.size() == 1) 680f3b04fd3SJason Ling { 681f3b04fd3SJason Ling /* one pwm, set write paths for all fan sensors to it */ 682f3b04fd3SJason Ling singlePwm = true; 683f3b04fd3SJason Ling } 684f3b04fd3SJason Ling else if (inputSensorInterfaces.size() == 685f3b04fd3SJason Ling outputSensorInterfaces.size()) 686f3b04fd3SJason Ling { 687f3b04fd3SJason Ling /* one to one mapping, each fan sensor gets its own pwm 688f3b04fd3SJason Ling * control */ 689f3b04fd3SJason Ling singlePwm = false; 690f3b04fd3SJason Ling } 691f3b04fd3SJason Ling else 692f3b04fd3SJason Ling { 693f3b04fd3SJason Ling throw std::runtime_error( 694f3b04fd3SJason Ling "fan PID has invalid number of Outputs"); 695f3b04fd3SJason Ling } 696f3b04fd3SJason Ling std::string fanSensorName; 697f3b04fd3SJason Ling std::string pwmPath; 698f3b04fd3SJason Ling std::string pwmInterface; 699ed1dafdfSHarvey.Wu std::string pwmSensorName; 700f3b04fd3SJason Ling if (singlePwm) 701f3b04fd3SJason Ling { 702f3b04fd3SJason Ling /* if just a single output(pwm) is provided then use 703f3b04fd3SJason Ling * that pwm control path for all the fan sensor write 704f3b04fd3SJason Ling * path configs 705f3b04fd3SJason Ling */ 706f3b04fd3SJason Ling pwmPath = outputSensorInterfaces.at(0).first; 707f3b04fd3SJason Ling pwmInterface = outputSensorInterfaces.at(0).second; 708f3b04fd3SJason Ling } 709f3b04fd3SJason Ling for (uint32_t idx = 0; idx < inputSensorInterfaces.size(); 710f3b04fd3SJason Ling idx++) 711f3b04fd3SJason Ling { 712f3b04fd3SJason Ling if (!singlePwm) 713f3b04fd3SJason Ling { 714f3b04fd3SJason Ling pwmPath = outputSensorInterfaces.at(idx).first; 715f3b04fd3SJason Ling pwmInterface = 716f3b04fd3SJason Ling outputSensorInterfaces.at(idx).second; 717f3b04fd3SJason Ling } 7180911bfe7SPatrick Venture if (defaultPwmInterface != pwmInterface) 719f3b04fd3SJason Ling { 720f3b04fd3SJason Ling throw std::runtime_error( 721f3b04fd3SJason Ling "fan pwm control at dbus path [" + pwmPath + 722f3b04fd3SJason Ling "] has an interface [" + pwmInterface + 723f3b04fd3SJason Ling "] that does not match the expected interface " 724f3b04fd3SJason Ling "of " + 7250911bfe7SPatrick Venture defaultPwmInterface); 726f3b04fd3SJason Ling } 727f3b04fd3SJason Ling const std::string& fanPath = 728f3b04fd3SJason Ling inputSensorInterfaces.at(idx).first; 729f3b04fd3SJason Ling fanSensorName = getSensorNameFromPath(fanPath); 730ed1dafdfSHarvey.Wu pwmSensorName = getSensorNameFromPath(pwmPath); 731ed1dafdfSHarvey.Wu std::string fanPwmIndex = fanSensorName + pwmSensorName; 732ed1dafdfSHarvey.Wu inputSensorNames.push_back(fanPwmIndex); 733ed1dafdfSHarvey.Wu auto& fanConfig = sensorConfig[fanPwmIndex]; 734ed1dafdfSHarvey.Wu fanConfig.type = pidClass; 735ed1dafdfSHarvey.Wu fanConfig.readPath = fanPath; 736f3b04fd3SJason Ling fanConfig.writePath = pwmPath; 73750fdfe39SJames Feist // todo: un-hardcode this if there are fans with 73850fdfe39SJames Feist // different ranges 739f3b04fd3SJason Ling fanConfig.max = 255; 740f3b04fd3SJason Ling fanConfig.min = 0; 74150fdfe39SJames Feist } 74250fdfe39SJames Feist } 74311d243dfSJames Feist // if the sensors aren't available in the current state, don't 74411d243dfSJames Feist // add them to the configuration. 745f3b04fd3SJason Ling if (inputSensorNames.empty()) 74611d243dfSJames Feist { 74711d243dfSJames Feist continue; 74811d243dfSJames Feist } 74911d243dfSJames Feist 7505ec20270SJames Feist std::string offsetType; 7515ec20270SJames Feist 7525ec20270SJames Feist // SetPointOffset is a threshold value to pull from the sensor 7535ec20270SJames Feist // to apply an offset. For upper thresholds this means the 7545ec20270SJames Feist // setpoint is usually negative. 7555ec20270SJames Feist auto findSetpointOffset = base.find("SetPointOffset"); 7565ec20270SJames Feist if (findSetpointOffset != base.end()) 7575ec20270SJames Feist { 7585ec20270SJames Feist offsetType = 7595ec20270SJames Feist std::get<std::string>(findSetpointOffset->second); 7605ec20270SJames Feist if (std::find(thresholds::types.begin(), 7615ec20270SJames Feist thresholds::types.end(), 7625ec20270SJames Feist offsetType) == thresholds::types.end()) 7635ec20270SJames Feist { 7645ec20270SJames Feist throw std::runtime_error("Unsupported type: " + 7655ec20270SJames Feist offsetType); 7665ec20270SJames Feist } 7675ec20270SJames Feist } 7685ec20270SJames Feist 7695ec20270SJames Feist if (offsetType.empty()) 7705ec20270SJames Feist { 7711df9e879SPatrick Venture conf::ControllerInfo& info = 7721f802f5eSJames Feist conf[std::get<std::string>(base.at("Name"))]; 773f3b04fd3SJason Ling info.inputs = std::move(inputSensorNames); 7747382318fSPatrick Venture populatePidInfo(bus, base, info, nullptr, sensorConfig); 7757136a5aeSJames Feist } 7767136a5aeSJames Feist else 7777136a5aeSJames Feist { 7785ec20270SJames Feist // we have to split up the inputs, as in practice t-control 7795ec20270SJames Feist // values will differ, making setpoints differ 780f3b04fd3SJason Ling for (const std::string& input : inputSensorNames) 781572c43daSJames Feist { 7821df9e879SPatrick Venture conf::ControllerInfo& info = conf[input]; 7835ec20270SJames Feist info.inputs.emplace_back(input); 7847382318fSPatrick Venture populatePidInfo(bus, base, info, &offsetType, 7857382318fSPatrick Venture sensorConfig); 786572c43daSJames Feist } 787572c43daSJames Feist } 7887136a5aeSJames Feist } 7898c3c51eeSJames Feist } 79022c257abSJames Feist auto findStepwise = 79122c257abSJames Feist configuration.second.find(stepwiseConfigurationInterface); 79222c257abSJames Feist if (findStepwise != configuration.second.end()) 79322c257abSJames Feist { 79422c257abSJames Feist const auto& base = findStepwise->second; 79522c257abSJames Feist const std::vector<std::string>& zones = 7961f802f5eSJames Feist std::get<std::vector<std::string>>(base.at("Zones")); 79722c257abSJames Feist for (const std::string& zone : zones) 79822c257abSJames Feist { 799998fbe67SJosh Lehan auto index = getZoneIndex(zone, foundZones); 800998fbe67SJosh Lehan 801f81f2886SJames Feist conf::PIDConf& conf = zoneConfig[index]; 80250fdfe39SJames Feist 80350fdfe39SJames Feist std::vector<std::string> inputs; 80450fdfe39SJames Feist std::vector<std::string> sensorNames = 8051f802f5eSJames Feist std::get<std::vector<std::string>>(base.at("Inputs")); 80650fdfe39SJames Feist 8078f73ad76SAlex.Song bool unavailableAsFailed = true; 8088f73ad76SAlex.Song auto findUnavailableAsFailed = 8098f73ad76SAlex.Song base.find("InputUnavailableAsFailed"); 8108f73ad76SAlex.Song if (findUnavailableAsFailed != base.end()) 8118f73ad76SAlex.Song { 8128f73ad76SAlex.Song unavailableAsFailed = 8138f73ad76SAlex.Song std::get<bool>(findUnavailableAsFailed->second); 8148f73ad76SAlex.Song } 8158f73ad76SAlex.Song 8161738e2a2SJames Feist bool sensorFound = false; 81750fdfe39SJames Feist for (const std::string& sensorName : sensorNames) 81850fdfe39SJames Feist { 8191738e2a2SJames Feist std::vector<std::pair<std::string, std::string>> 8201738e2a2SJames Feist sensorPathIfacePairs; 821f3b04fd3SJason Ling if (!findSensors(sensors, sensorNameToDbusName(sensorName), 822f3b04fd3SJason Ling sensorPathIfacePairs)) 82350fdfe39SJames Feist { 82450fdfe39SJames Feist break; 82550fdfe39SJames Feist } 82650fdfe39SJames Feist 8271738e2a2SJames Feist for (const auto& sensorPathIfacePair : sensorPathIfacePairs) 8281738e2a2SJames Feist { 8291738e2a2SJames Feist size_t idx = 8301738e2a2SJames Feist sensorPathIfacePair.first.find_last_of("/") + 1; 8311738e2a2SJames Feist std::string shortName = 8321738e2a2SJames Feist sensorPathIfacePair.first.substr(idx); 8331738e2a2SJames Feist 8341738e2a2SJames Feist inputs.push_back(shortName); 8351738e2a2SJames Feist auto& config = sensorConfig[shortName]; 83669c51061SPatrick Venture config.readPath = sensorPathIfacePair.first; 83750fdfe39SJames Feist config.type = "temp"; 8383660b388SJames Feist config.ignoreDbusMinMax = true; 8398f73ad76SAlex.Song config.unavailableAsFailed = unavailableAsFailed; 84050fdfe39SJames Feist // todo: maybe un-hardcode this if we run into slower 84150fdfe39SJames Feist // timeouts with sensors 84250fdfe39SJames Feist 8432642cb54SJames Feist config.timeout = 0; 8441738e2a2SJames Feist sensorFound = true; 8451738e2a2SJames Feist } 84650fdfe39SJames Feist } 84750fdfe39SJames Feist if (!sensorFound) 84850fdfe39SJames Feist { 84950fdfe39SJames Feist continue; 85050fdfe39SJames Feist } 8511df9e879SPatrick Venture conf::ControllerInfo& info = 8521f802f5eSJames Feist conf[std::get<std::string>(base.at("Name"))]; 85350fdfe39SJames Feist info.inputs = std::move(inputs); 85450fdfe39SJames Feist 85522c257abSJames Feist info.type = "stepwise"; 85622c257abSJames Feist info.stepwiseInfo.ts = 1.0; // currently unused 8573dfaafdaSJames Feist info.stepwiseInfo.positiveHysteresis = 0.0; 8583dfaafdaSJames Feist info.stepwiseInfo.negativeHysteresis = 0.0; 859608304daSJames Feist std::string subtype = std::get<std::string>(base.at("Class")); 860608304daSJames Feist 861608304daSJames Feist info.stepwiseInfo.isCeiling = (subtype == "Ceiling"); 8623dfaafdaSJames Feist auto findPosHyst = base.find("PositiveHysteresis"); 8633dfaafdaSJames Feist auto findNegHyst = base.find("NegativeHysteresis"); 8643dfaafdaSJames Feist if (findPosHyst != base.end()) 8653dfaafdaSJames Feist { 8661f802f5eSJames Feist info.stepwiseInfo.positiveHysteresis = std::visit( 867208abce8SJames Feist VariantToDoubleVisitor(), findPosHyst->second); 8683dfaafdaSJames Feist } 8693dfaafdaSJames Feist if (findNegHyst != base.end()) 8703dfaafdaSJames Feist { 8715782ab81SJames Feist info.stepwiseInfo.negativeHysteresis = std::visit( 872208abce8SJames Feist VariantToDoubleVisitor(), findNegHyst->second); 8733dfaafdaSJames Feist } 87422c257abSJames Feist std::vector<double> readings = 8751f802f5eSJames Feist std::get<std::vector<double>>(base.at("Reading")); 87622c257abSJames Feist if (readings.size() > ec::maxStepwisePoints) 87722c257abSJames Feist { 87822c257abSJames Feist throw std::invalid_argument("Too many stepwise points."); 87922c257abSJames Feist } 88022c257abSJames Feist if (readings.empty()) 88122c257abSJames Feist { 88222c257abSJames Feist throw std::invalid_argument( 88322c257abSJames Feist "Must have one stepwise point."); 88422c257abSJames Feist } 88522c257abSJames Feist std::copy(readings.begin(), readings.end(), 88622c257abSJames Feist info.stepwiseInfo.reading); 88722c257abSJames Feist if (readings.size() < ec::maxStepwisePoints) 88822c257abSJames Feist { 88922c257abSJames Feist info.stepwiseInfo.reading[readings.size()] = 8905f59c0fdSPatrick Venture std::numeric_limits<double>::quiet_NaN(); 89122c257abSJames Feist } 89222c257abSJames Feist std::vector<double> outputs = 8931f802f5eSJames Feist std::get<std::vector<double>>(base.at("Output")); 89422c257abSJames Feist if (readings.size() != outputs.size()) 89522c257abSJames Feist { 89622c257abSJames Feist throw std::invalid_argument( 89722c257abSJames Feist "Outputs size must match readings"); 89822c257abSJames Feist } 89922c257abSJames Feist std::copy(outputs.begin(), outputs.end(), 90022c257abSJames Feist info.stepwiseInfo.output); 90122c257abSJames Feist if (outputs.size() < ec::maxStepwisePoints) 90222c257abSJames Feist { 90322c257abSJames Feist info.stepwiseInfo.output[outputs.size()] = 9045f59c0fdSPatrick Venture std::numeric_limits<double>::quiet_NaN(); 90522c257abSJames Feist } 90622c257abSJames Feist } 90722c257abSJames Feist } 90822c257abSJames Feist } 90939199b4dSPatrick Venture if constexpr (pid_control::conf::DEBUG) 9107136a5aeSJames Feist { 91139199b4dSPatrick Venture debugPrint(sensorConfig, zoneConfig, zoneDetailsConfig); 9127136a5aeSJames Feist } 913c959c429SJames Feist if (zoneConfig.empty() || zoneDetailsConfig.empty()) 91450fdfe39SJames Feist { 9151fe08952SJames Feist std::cerr 9161fe08952SJames Feist << "No fan zones, application pausing until new configuration\n"; 9171fe08952SJames Feist return false; 91850fdfe39SJames Feist } 9191fe08952SJames Feist return true; 9207136a5aeSJames Feist } 921a076487aSPatrick Venture 9227136a5aeSJames Feist } // namespace dbus_configuration 923a076487aSPatrick Venture } // namespace pid_control 924