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 */ 167136a5aeSJames Feist 170771659eSPatrick Venture #include "conf.hpp" 180771659eSPatrick Venture #include "dbus/util.hpp" 190771659eSPatrick Venture 20107a25daSPatrick Venture #include <algorithm> 2164f072a7SJames Feist #include <chrono> 2264f072a7SJames Feist #include <functional> 237136a5aeSJames Feist #include <iostream> 241738e2a2SJames Feist #include <regex> 257136a5aeSJames Feist #include <sdbusplus/bus.hpp> 2664f072a7SJames Feist #include <sdbusplus/bus/match.hpp> 2722c257abSJames Feist #include <sdbusplus/exception.hpp> 287136a5aeSJames Feist #include <set> 2964f072a7SJames Feist #include <thread> 307136a5aeSJames Feist #include <unordered_map> 311f802f5eSJames Feist #include <variant> 327136a5aeSJames Feist 337136a5aeSJames Feist static constexpr bool DEBUG = false; // enable to print found configuration 347136a5aeSJames Feist 35*f81f2886SJames Feist extern std::map<std::string, struct conf::SensorConfig> sensorConfig; 36*f81f2886SJames Feist extern std::map<int64_t, conf::PIDConf> zoneConfig; 37*f81f2886SJames Feist extern std::map<int64_t, struct conf::ZoneConfig> zoneDetailsConfig; 387136a5aeSJames Feist 397136a5aeSJames Feist constexpr const char* pidConfigurationInterface = 407136a5aeSJames Feist "xyz.openbmc_project.Configuration.Pid"; 417136a5aeSJames Feist constexpr const char* objectManagerInterface = 427136a5aeSJames Feist "org.freedesktop.DBus.ObjectManager"; 437136a5aeSJames Feist constexpr const char* pidZoneConfigurationInterface = 447136a5aeSJames Feist "xyz.openbmc_project.Configuration.Pid.Zone"; 4522c257abSJames Feist constexpr const char* stepwiseConfigurationInterface = 4622c257abSJames Feist "xyz.openbmc_project.Configuration.Stepwise"; 477136a5aeSJames Feist constexpr const char* sensorInterface = "xyz.openbmc_project.Sensor.Value"; 487136a5aeSJames Feist constexpr const char* pwmInterface = "xyz.openbmc_project.Control.FanPwm"; 497136a5aeSJames Feist 507136a5aeSJames Feist namespace dbus_configuration 517136a5aeSJames Feist { 527136a5aeSJames Feist 531738e2a2SJames Feist bool findSensors(const std::unordered_map<std::string, std::string>& sensors, 547136a5aeSJames Feist const std::string& search, 551738e2a2SJames Feist std::vector<std::pair<std::string, std::string>>& matches) 567136a5aeSJames Feist { 571738e2a2SJames Feist std::smatch match; 581738e2a2SJames Feist std::regex reg(search); 591738e2a2SJames Feist for (const auto& sensor : sensors) 607136a5aeSJames Feist { 611738e2a2SJames Feist if (std::regex_search(sensor.first, match, reg)) 621738e2a2SJames Feist { 631738e2a2SJames Feist matches.push_back(sensor); 641738e2a2SJames Feist } 657136a5aeSJames Feist } 66107a25daSPatrick Venture 671738e2a2SJames Feist return matches.size() > 0; 687136a5aeSJames Feist } 697136a5aeSJames Feist 707136a5aeSJames Feist // this function prints the configuration into a form similar to the cpp 717136a5aeSJames Feist // generated code to help in verification, should be turned off during normal 727136a5aeSJames Feist // use 737136a5aeSJames Feist void debugPrint(void) 747136a5aeSJames Feist { 757136a5aeSJames Feist // print sensor config 767136a5aeSJames Feist std::cout << "sensor config:\n"; 777136a5aeSJames Feist std::cout << "{\n"; 78c54fbd88SPatrick Venture for (const auto& pair : sensorConfig) 797136a5aeSJames Feist { 807136a5aeSJames Feist 817136a5aeSJames Feist std::cout << "\t{" << pair.first << ",\n\t\t{"; 827136a5aeSJames Feist std::cout << pair.second.type << ", "; 8369c51061SPatrick Venture std::cout << pair.second.readPath << ", "; 8469c51061SPatrick Venture std::cout << pair.second.writePath << ", "; 857136a5aeSJames Feist std::cout << pair.second.min << ", "; 867136a5aeSJames Feist std::cout << pair.second.max << ", "; 877136a5aeSJames Feist std::cout << pair.second.timeout << "},\n\t},\n"; 887136a5aeSJames Feist } 897136a5aeSJames Feist std::cout << "}\n\n"; 907136a5aeSJames Feist std::cout << "ZoneDetailsConfig\n"; 917136a5aeSJames Feist std::cout << "{\n"; 92c54fbd88SPatrick Venture for (const auto& zone : zoneDetailsConfig) 937136a5aeSJames Feist { 947136a5aeSJames Feist std::cout << "\t{" << zone.first << ",\n"; 953484bedaSJames Feist std::cout << "\t\t{" << zone.second.minThermalOutput << ", "; 968e2fdb34SPatrick Venture std::cout << zone.second.failsafePercent << "}\n\t},\n"; 977136a5aeSJames Feist } 987136a5aeSJames Feist std::cout << "}\n\n"; 997136a5aeSJames Feist std::cout << "ZoneConfig\n"; 1007136a5aeSJames Feist std::cout << "{\n"; 101c54fbd88SPatrick Venture for (const auto& zone : zoneConfig) 1027136a5aeSJames Feist { 1037136a5aeSJames Feist std::cout << "\t{" << zone.first << "\n"; 1044a2dc4d8SPatrick Venture for (const auto& pidconf : zone.second) 1057136a5aeSJames Feist { 1067136a5aeSJames Feist std::cout << "\t\t{" << pidconf.first << ",\n"; 1077136a5aeSJames Feist std::cout << "\t\t\t{" << pidconf.second.type << ",\n"; 1087136a5aeSJames Feist std::cout << "\t\t\t{"; 1094a2dc4d8SPatrick Venture for (const auto& input : pidconf.second.inputs) 1107136a5aeSJames Feist { 1117136a5aeSJames Feist std::cout << "\n\t\t\t" << input << ",\n"; 1127136a5aeSJames Feist } 1137136a5aeSJames Feist std::cout << "\t\t\t}\n"; 1147136a5aeSJames Feist std::cout << "\t\t\t" << pidconf.second.setpoint << ",\n"; 11522c257abSJames Feist std::cout << "\t\t\t{" << pidconf.second.pidInfo.ts << ",\n"; 1167442c37aSPatrick Venture std::cout << "\t\t\t" << pidconf.second.pidInfo.proportionalCoeff 1177442c37aSPatrick Venture << ",\n"; 1187442c37aSPatrick Venture std::cout << "\t\t\t" << pidconf.second.pidInfo.integralCoeff 1197442c37aSPatrick Venture << ",\n"; 1207442c37aSPatrick Venture std::cout << "\t\t\t" << pidconf.second.pidInfo.feedFwdOffset 1217442c37aSPatrick Venture << ",\n"; 1227442c37aSPatrick Venture std::cout << "\t\t\t" << pidconf.second.pidInfo.feedFwdGain 1237442c37aSPatrick Venture << ",\n"; 1247442c37aSPatrick Venture std::cout << "\t\t\t{" << pidconf.second.pidInfo.integralLimit.min 1257442c37aSPatrick Venture << "," << pidconf.second.pidInfo.integralLimit.max 1267442c37aSPatrick Venture << "},\n"; 1277442c37aSPatrick Venture std::cout << "\t\t\t{" << pidconf.second.pidInfo.outLim.min << "," 1287442c37aSPatrick Venture << pidconf.second.pidInfo.outLim.max << "},\n"; 1297442c37aSPatrick Venture std::cout << "\t\t\t" << pidconf.second.pidInfo.slewNeg << ",\n"; 1307442c37aSPatrick Venture std::cout << "\t\t\t" << pidconf.second.pidInfo.slewPos << ",\n"; 1317136a5aeSJames Feist std::cout << "\t\t\t}\n\t\t}\n"; 1327136a5aeSJames Feist } 1337136a5aeSJames Feist std::cout << "\t},\n"; 1347136a5aeSJames Feist } 1357136a5aeSJames Feist std::cout << "}\n\n"; 1367136a5aeSJames Feist } 1377136a5aeSJames Feist 13850fdfe39SJames Feist int eventHandler(sd_bus_message*, void*, sd_bus_error*) 13950fdfe39SJames Feist { 14050fdfe39SJames Feist // do a brief sleep as we tend to get a bunch of these events at 14150fdfe39SJames Feist // once 14250fdfe39SJames Feist std::this_thread::sleep_for(std::chrono::seconds(5)); 14350fdfe39SJames Feist std::cout << "New configuration detected, restarting\n."; 14450fdfe39SJames Feist std::exit(EXIT_SUCCESS); // service file should make us restart 14550fdfe39SJames Feist return 1; 14650fdfe39SJames Feist } 14750fdfe39SJames Feist 148ffd418bbSJames Feist size_t getZoneIndex(const std::string& name, std::vector<std::string>& zones) 149ffd418bbSJames Feist { 150ffd418bbSJames Feist auto it = std::find(zones.begin(), zones.end(), name); 151ffd418bbSJames Feist if (it == zones.end()) 152ffd418bbSJames Feist { 153ffd418bbSJames Feist zones.emplace_back(name); 154ffd418bbSJames Feist it = zones.end() - 1; 155ffd418bbSJames Feist } 156ffd418bbSJames Feist 157ffd418bbSJames Feist return it - zones.begin(); 158ffd418bbSJames Feist } 159ffd418bbSJames Feist 1607136a5aeSJames Feist void init(sdbusplus::bus::bus& bus) 1617136a5aeSJames Feist { 16222c257abSJames Feist using DbusVariantType = 1631f802f5eSJames Feist std::variant<uint64_t, int64_t, double, std::string, 1641f802f5eSJames Feist std::vector<std::string>, std::vector<double>>; 16522c257abSJames Feist 1667136a5aeSJames Feist using ManagedObjectType = std::unordered_map< 1677136a5aeSJames Feist sdbusplus::message::object_path, 1687136a5aeSJames Feist std::unordered_map<std::string, 16922c257abSJames Feist std::unordered_map<std::string, DbusVariantType>>>; 17064f072a7SJames Feist 17150fdfe39SJames Feist // restart on configuration properties changed 17250fdfe39SJames Feist static sdbusplus::bus::match::match configMatch( 17364f072a7SJames Feist bus, 17464f072a7SJames Feist "type='signal',member='PropertiesChanged',arg0namespace='" + 17564f072a7SJames Feist std::string(pidConfigurationInterface) + "'", 17664f072a7SJames Feist eventHandler); 17764f072a7SJames Feist 17850fdfe39SJames Feist // restart on sensors changed 17950fdfe39SJames Feist static sdbusplus::bus::match::match sensorAdded( 18050fdfe39SJames Feist bus, 18150fdfe39SJames Feist "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/" 18250fdfe39SJames Feist "sensors/'", 18350fdfe39SJames Feist eventHandler); 18450fdfe39SJames Feist 1857136a5aeSJames Feist auto mapper = 1867136a5aeSJames Feist bus.new_method_call("xyz.openbmc_project.ObjectMapper", 1877136a5aeSJames Feist "/xyz/openbmc_project/object_mapper", 1887136a5aeSJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree"); 18926e8c6a9SJames Feist mapper.append("/", 0, 19022c257abSJames Feist std::array<const char*, 6>{objectManagerInterface, 1917136a5aeSJames Feist pidConfigurationInterface, 1927136a5aeSJames Feist pidZoneConfigurationInterface, 19322c257abSJames Feist stepwiseConfigurationInterface, 1947136a5aeSJames Feist sensorInterface, pwmInterface}); 19522c257abSJames Feist std::unordered_map< 19622c257abSJames Feist std::string, std::unordered_map<std::string, std::vector<std::string>>> 19722c257abSJames Feist respData; 19822c257abSJames Feist try 19922c257abSJames Feist { 2007136a5aeSJames Feist auto resp = bus.call(mapper); 2017136a5aeSJames Feist resp.read(respData); 20222c257abSJames Feist } 20322c257abSJames Feist catch (sdbusplus::exception_t&) 20422c257abSJames Feist { 20522c257abSJames Feist // can't do anything without mapper call data 20622c257abSJames Feist throw std::runtime_error("ObjectMapper Call Failure"); 20722c257abSJames Feist } 20822c257abSJames Feist 2097136a5aeSJames Feist if (respData.empty()) 2107136a5aeSJames Feist { 21122c257abSJames Feist // can't do anything without mapper call data 2127136a5aeSJames Feist throw std::runtime_error("No configuration data available from Mapper"); 2137136a5aeSJames Feist } 2147136a5aeSJames Feist // create a map of pair of <has pid configuration, ObjectManager path> 2157136a5aeSJames Feist std::unordered_map<std::string, std::pair<bool, std::string>> owners; 2167136a5aeSJames Feist // and a map of <path, interface> for sensors 2177136a5aeSJames Feist std::unordered_map<std::string, std::string> sensors; 2187136a5aeSJames Feist for (const auto& objectPair : respData) 2197136a5aeSJames Feist { 2207136a5aeSJames Feist for (const auto& ownerPair : objectPair.second) 2217136a5aeSJames Feist { 2227136a5aeSJames Feist auto& owner = owners[ownerPair.first]; 2237136a5aeSJames Feist for (const std::string& interface : ownerPair.second) 2247136a5aeSJames Feist { 2257136a5aeSJames Feist 2267136a5aeSJames Feist if (interface == objectManagerInterface) 2277136a5aeSJames Feist { 2287136a5aeSJames Feist owner.second = objectPair.first; 2297136a5aeSJames Feist } 2307136a5aeSJames Feist if (interface == pidConfigurationInterface || 23122c257abSJames Feist interface == pidZoneConfigurationInterface || 23222c257abSJames Feist interface == stepwiseConfigurationInterface) 2337136a5aeSJames Feist { 2347136a5aeSJames Feist owner.first = true; 2357136a5aeSJames Feist } 2367136a5aeSJames Feist if (interface == sensorInterface || interface == pwmInterface) 2377136a5aeSJames Feist { 2387136a5aeSJames Feist // we're not interested in pwm sensors, just pwm control 2397136a5aeSJames Feist if (interface == sensorInterface && 2407136a5aeSJames Feist objectPair.first.find("pwm") != std::string::npos) 2417136a5aeSJames Feist { 2427136a5aeSJames Feist continue; 2437136a5aeSJames Feist } 2447136a5aeSJames Feist sensors[objectPair.first] = interface; 2457136a5aeSJames Feist } 2467136a5aeSJames Feist } 2477136a5aeSJames Feist } 2487136a5aeSJames Feist } 2497136a5aeSJames Feist ManagedObjectType configurations; 2507136a5aeSJames Feist for (const auto& owner : owners) 2517136a5aeSJames Feist { 2527136a5aeSJames Feist // skip if no pid configuration (means probably a sensor) 2537136a5aeSJames Feist if (!owner.second.first) 2547136a5aeSJames Feist { 2557136a5aeSJames Feist continue; 2567136a5aeSJames Feist } 2577136a5aeSJames Feist auto endpoint = bus.new_method_call( 2587136a5aeSJames Feist owner.first.c_str(), owner.second.second.c_str(), 2597136a5aeSJames Feist "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 26022c257abSJames Feist ManagedObjectType configuration; 26122c257abSJames Feist try 26222c257abSJames Feist { 2637136a5aeSJames Feist auto responce = bus.call(endpoint); 2647136a5aeSJames Feist responce.read(configuration); 26522c257abSJames Feist } 26622c257abSJames Feist catch (sdbusplus::exception_t&) 26722c257abSJames Feist { 26822c257abSJames Feist // this shouldn't happen, probably means daemon crashed 26922c257abSJames Feist throw std::runtime_error("Error getting managed objects from " + 27022c257abSJames Feist owner.first); 27122c257abSJames Feist } 27222c257abSJames Feist 2737136a5aeSJames Feist for (auto& pathPair : configuration) 2747136a5aeSJames Feist { 2757136a5aeSJames Feist if (pathPair.second.find(pidConfigurationInterface) != 2767136a5aeSJames Feist pathPair.second.end() || 2777136a5aeSJames Feist pathPair.second.find(pidZoneConfigurationInterface) != 27822c257abSJames Feist pathPair.second.end() || 27922c257abSJames Feist pathPair.second.find(stepwiseConfigurationInterface) != 2807136a5aeSJames Feist pathPair.second.end()) 2817136a5aeSJames Feist { 2827136a5aeSJames Feist configurations.emplace(pathPair); 2837136a5aeSJames Feist } 2847136a5aeSJames Feist } 2857136a5aeSJames Feist } 2868c3c51eeSJames Feist 2878c3c51eeSJames Feist // on dbus having an index field is a bit strange, so randomly 2888c3c51eeSJames Feist // assign index based on name property 289ffd418bbSJames Feist std::vector<std::string> foundZones; 2907136a5aeSJames Feist for (const auto& configuration : configurations) 2917136a5aeSJames Feist { 2927136a5aeSJames Feist auto findZone = 2937136a5aeSJames Feist configuration.second.find(pidZoneConfigurationInterface); 2947136a5aeSJames Feist if (findZone != configuration.second.end()) 2957136a5aeSJames Feist { 2967136a5aeSJames Feist const auto& zone = findZone->second; 297ffd418bbSJames Feist 2981f802f5eSJames Feist const std::string& name = std::get<std::string>(zone.at("Name")); 299ffd418bbSJames Feist size_t index = getZoneIndex(name, foundZones); 3008c3c51eeSJames Feist 301c54fbd88SPatrick Venture auto& details = zoneDetailsConfig[index]; 3023484bedaSJames Feist details.minThermalOutput = std::visit(VariantToDoubleVisitor(), 3033484bedaSJames Feist zone.at("MinThermalOutput")); 3048e2fdb34SPatrick Venture details.failsafePercent = std::visit(VariantToDoubleVisitor(), 3051f802f5eSJames Feist zone.at("FailSafePercent")); 3067136a5aeSJames Feist } 3077136a5aeSJames Feist auto findBase = configuration.second.find(pidConfigurationInterface); 30822c257abSJames Feist if (findBase != configuration.second.end()) 3097136a5aeSJames Feist { 3108c3c51eeSJames Feist 31122c257abSJames Feist const auto& base = 31222c257abSJames Feist configuration.second.at(pidConfigurationInterface); 3138c3c51eeSJames Feist const std::vector<std::string>& zones = 3141f802f5eSJames Feist std::get<std::vector<std::string>>(base.at("Zones")); 3158c3c51eeSJames Feist for (const std::string& zone : zones) 3168c3c51eeSJames Feist { 317ffd418bbSJames Feist size_t index = getZoneIndex(zone, foundZones); 318*f81f2886SJames Feist conf::PIDConf& conf = zoneConfig[index]; 31950fdfe39SJames Feist 32050fdfe39SJames Feist std::vector<std::string> sensorNames = 3211f802f5eSJames Feist std::get<std::vector<std::string>>(base.at("Inputs")); 32250fdfe39SJames Feist auto findOutputs = 32350fdfe39SJames Feist base.find("Outputs"); // currently only fans have outputs 32450fdfe39SJames Feist if (findOutputs != base.end()) 32550fdfe39SJames Feist { 32650fdfe39SJames Feist std::vector<std::string> outputs = 3271f802f5eSJames Feist std::get<std::vector<std::string>>(findOutputs->second); 32850fdfe39SJames Feist sensorNames.insert(sensorNames.end(), outputs.begin(), 32950fdfe39SJames Feist outputs.end()); 33050fdfe39SJames Feist } 3311738e2a2SJames Feist 33250fdfe39SJames Feist std::vector<std::string> inputs; 3331738e2a2SJames Feist std::vector<std::pair<std::string, std::string>> 3341738e2a2SJames Feist sensorInterfaces; 33550fdfe39SJames Feist for (const std::string& sensorName : sensorNames) 33650fdfe39SJames Feist { 33750fdfe39SJames Feist std::string name = sensorName; 33850fdfe39SJames Feist // replace spaces with underscores to be legal on dbus 33950fdfe39SJames Feist std::replace(name.begin(), name.end(), ' ', '_'); 3401738e2a2SJames Feist findSensors(sensors, name, sensorInterfaces); 34150fdfe39SJames Feist } 3421738e2a2SJames Feist 3431738e2a2SJames Feist // if the sensors aren't available in the current state, don't 3441738e2a2SJames Feist // add them to the configuration. 3451738e2a2SJames Feist if (sensorInterfaces.empty()) 3461738e2a2SJames Feist { 3471738e2a2SJames Feist continue; 3481738e2a2SJames Feist } 3491738e2a2SJames Feist for (const auto& sensorPathIfacePair : sensorInterfaces) 3501738e2a2SJames Feist { 3511738e2a2SJames Feist 35250fdfe39SJames Feist if (sensorPathIfacePair.second == sensorInterface) 35350fdfe39SJames Feist { 3541738e2a2SJames Feist size_t idx = 3551738e2a2SJames Feist sensorPathIfacePair.first.find_last_of("/") + 1; 3561738e2a2SJames Feist std::string shortName = 3571738e2a2SJames Feist sensorPathIfacePair.first.substr(idx); 3581738e2a2SJames Feist 3591738e2a2SJames Feist inputs.push_back(shortName); 3601738e2a2SJames Feist auto& config = sensorConfig[shortName]; 3611f802f5eSJames Feist config.type = std::get<std::string>(base.at("Class")); 36269c51061SPatrick Venture config.readPath = sensorPathIfacePair.first; 36350fdfe39SJames Feist // todo: maybe un-hardcode this if we run into slower 36450fdfe39SJames Feist // timeouts with sensors 36550fdfe39SJames Feist if (config.type == "temp") 36650fdfe39SJames Feist { 3672642cb54SJames Feist config.timeout = 0; 36850fdfe39SJames Feist } 36975eb769dSJames Feist else if (config.type == "fan") 37075eb769dSJames Feist { 37175eb769dSJames Feist config.max = conf::inheritValueFromDbus; 37275eb769dSJames Feist config.min = conf::inheritValueFromDbus; 37375eb769dSJames Feist } 37450fdfe39SJames Feist } 37550fdfe39SJames Feist else if (sensorPathIfacePair.second == pwmInterface) 37650fdfe39SJames Feist { 37750fdfe39SJames Feist // copy so we can modify it 37850fdfe39SJames Feist for (std::string otherSensor : sensorNames) 37950fdfe39SJames Feist { 3801738e2a2SJames Feist std::replace(otherSensor.begin(), otherSensor.end(), 3811738e2a2SJames Feist ' ', '_'); 3821738e2a2SJames Feist if (sensorPathIfacePair.first.find(otherSensor) != 3831738e2a2SJames Feist std::string::npos) 38450fdfe39SJames Feist { 38550fdfe39SJames Feist continue; 38650fdfe39SJames Feist } 3871738e2a2SJames Feist 388c54fbd88SPatrick Venture auto& config = sensorConfig[otherSensor]; 38969c51061SPatrick Venture config.writePath = sensorPathIfacePair.first; 39050fdfe39SJames Feist // todo: un-hardcode this if there are fans with 39150fdfe39SJames Feist // different ranges 39250fdfe39SJames Feist config.max = 255; 39350fdfe39SJames Feist config.min = 0; 39450fdfe39SJames Feist } 39550fdfe39SJames Feist } 39650fdfe39SJames Feist } 3971738e2a2SJames Feist 398*f81f2886SJames Feist struct conf::ControllerInfo& info = 3991f802f5eSJames Feist conf[std::get<std::string>(base.at("Name"))]; 40050fdfe39SJames Feist info.inputs = std::move(inputs); 40150fdfe39SJames Feist 4021f802f5eSJames Feist info.type = std::get<std::string>(base.at("Class")); 4038c3c51eeSJames Feist // todo: auto generation yaml -> c script seems to discard this 4048c3c51eeSJames Feist // value for fans, verify this is okay 4057136a5aeSJames Feist if (info.type == "fan") 4067136a5aeSJames Feist { 4077136a5aeSJames Feist info.setpoint = 0; 4087136a5aeSJames Feist } 4097136a5aeSJames Feist else 4107136a5aeSJames Feist { 4111f802f5eSJames Feist info.setpoint = std::visit(VariantToDoubleVisitor(), 412208abce8SJames Feist base.at("SetPoint")); 4137136a5aeSJames Feist } 41422c257abSJames Feist info.pidInfo.ts = 1.0; // currently unused 4157442c37aSPatrick Venture info.pidInfo.proportionalCoeff = std::visit( 4167442c37aSPatrick Venture VariantToDoubleVisitor(), base.at("PCoefficient")); 4177442c37aSPatrick Venture info.pidInfo.integralCoeff = std::visit( 4187442c37aSPatrick Venture VariantToDoubleVisitor(), base.at("ICoefficient")); 4197442c37aSPatrick Venture info.pidInfo.feedFwdOffset = std::visit( 4207442c37aSPatrick Venture VariantToDoubleVisitor(), base.at("FFOffCoefficient")); 4217442c37aSPatrick Venture info.pidInfo.feedFwdGain = std::visit( 4227442c37aSPatrick Venture VariantToDoubleVisitor(), base.at("FFGainCoefficient")); 4237442c37aSPatrick Venture info.pidInfo.integralLimit.max = 4241f802f5eSJames Feist std::visit(VariantToDoubleVisitor(), base.at("ILimitMax")); 4257442c37aSPatrick Venture info.pidInfo.integralLimit.min = 4261f802f5eSJames Feist std::visit(VariantToDoubleVisitor(), base.at("ILimitMin")); 4277442c37aSPatrick Venture info.pidInfo.outLim.max = std::visit(VariantToDoubleVisitor(), 4281f802f5eSJames Feist base.at("OutLimitMax")); 4297442c37aSPatrick Venture info.pidInfo.outLim.min = std::visit(VariantToDoubleVisitor(), 4301f802f5eSJames Feist base.at("OutLimitMin")); 4317442c37aSPatrick Venture info.pidInfo.slewNeg = 4321f802f5eSJames Feist std::visit(VariantToDoubleVisitor(), base.at("SlewNeg")); 4337442c37aSPatrick Venture info.pidInfo.slewPos = 4341f802f5eSJames Feist std::visit(VariantToDoubleVisitor(), base.at("SlewPos")); 435572c43daSJames Feist double negativeHysteresis = 0; 436572c43daSJames Feist double positiveHysteresis = 0; 437572c43daSJames Feist 438572c43daSJames Feist auto findNeg = base.find("NegativeHysteresis"); 439572c43daSJames Feist auto findPos = base.find("PositiveHysteresis"); 440572c43daSJames Feist if (findNeg != base.end()) 441572c43daSJames Feist { 4421f802f5eSJames Feist negativeHysteresis = 4431f802f5eSJames Feist std::visit(VariantToDoubleVisitor(), findNeg->second); 444572c43daSJames Feist } 445572c43daSJames Feist 446572c43daSJames Feist if (findPos != base.end()) 447572c43daSJames Feist { 4481f802f5eSJames Feist positiveHysteresis = 4491f802f5eSJames Feist std::visit(VariantToDoubleVisitor(), findPos->second); 450572c43daSJames Feist } 451572c43daSJames Feist info.pidInfo.negativeHysteresis = negativeHysteresis; 452572c43daSJames Feist info.pidInfo.positiveHysteresis = positiveHysteresis; 4537136a5aeSJames Feist } 4548c3c51eeSJames Feist } 45522c257abSJames Feist auto findStepwise = 45622c257abSJames Feist configuration.second.find(stepwiseConfigurationInterface); 45722c257abSJames Feist if (findStepwise != configuration.second.end()) 45822c257abSJames Feist { 45922c257abSJames Feist const auto& base = findStepwise->second; 46022c257abSJames Feist const std::vector<std::string>& zones = 4611f802f5eSJames Feist std::get<std::vector<std::string>>(base.at("Zones")); 46222c257abSJames Feist for (const std::string& zone : zones) 46322c257abSJames Feist { 464ffd418bbSJames Feist size_t index = getZoneIndex(zone, foundZones); 465*f81f2886SJames Feist conf::PIDConf& conf = zoneConfig[index]; 46650fdfe39SJames Feist 46750fdfe39SJames Feist std::vector<std::string> inputs; 46850fdfe39SJames Feist std::vector<std::string> sensorNames = 4691f802f5eSJames Feist std::get<std::vector<std::string>>(base.at("Inputs")); 47050fdfe39SJames Feist 4711738e2a2SJames Feist bool sensorFound = false; 47250fdfe39SJames Feist for (const std::string& sensorName : sensorNames) 47350fdfe39SJames Feist { 47450fdfe39SJames Feist std::string name = sensorName; 47550fdfe39SJames Feist // replace spaces with underscores to be legal on dbus 47650fdfe39SJames Feist std::replace(name.begin(), name.end(), ' ', '_'); 4771738e2a2SJames Feist std::vector<std::pair<std::string, std::string>> 4781738e2a2SJames Feist sensorPathIfacePairs; 47950fdfe39SJames Feist 4801738e2a2SJames Feist if (!findSensors(sensors, name, sensorPathIfacePairs)) 48150fdfe39SJames Feist { 48250fdfe39SJames Feist break; 48350fdfe39SJames Feist } 48450fdfe39SJames Feist 4851738e2a2SJames Feist for (const auto& sensorPathIfacePair : sensorPathIfacePairs) 4861738e2a2SJames Feist { 4871738e2a2SJames Feist size_t idx = 4881738e2a2SJames Feist sensorPathIfacePair.first.find_last_of("/") + 1; 4891738e2a2SJames Feist std::string shortName = 4901738e2a2SJames Feist sensorPathIfacePair.first.substr(idx); 4911738e2a2SJames Feist 4921738e2a2SJames Feist inputs.push_back(shortName); 4931738e2a2SJames Feist auto& config = sensorConfig[shortName]; 49469c51061SPatrick Venture config.readPath = sensorPathIfacePair.first; 49550fdfe39SJames Feist config.type = "temp"; 49650fdfe39SJames Feist // todo: maybe un-hardcode this if we run into slower 49750fdfe39SJames Feist // timeouts with sensors 49850fdfe39SJames Feist 4992642cb54SJames Feist config.timeout = 0; 5001738e2a2SJames Feist sensorFound = true; 5011738e2a2SJames Feist } 50250fdfe39SJames Feist } 50350fdfe39SJames Feist if (!sensorFound) 50450fdfe39SJames Feist { 50550fdfe39SJames Feist continue; 50650fdfe39SJames Feist } 507*f81f2886SJames Feist struct conf::ControllerInfo& info = 5081f802f5eSJames Feist conf[std::get<std::string>(base.at("Name"))]; 50950fdfe39SJames Feist info.inputs = std::move(inputs); 51050fdfe39SJames Feist 51122c257abSJames Feist info.type = "stepwise"; 51222c257abSJames Feist info.stepwiseInfo.ts = 1.0; // currently unused 5133dfaafdaSJames Feist info.stepwiseInfo.positiveHysteresis = 0.0; 5143dfaafdaSJames Feist info.stepwiseInfo.negativeHysteresis = 0.0; 515608304daSJames Feist std::string subtype = std::get<std::string>(base.at("Class")); 516608304daSJames Feist 517608304daSJames Feist info.stepwiseInfo.isCeiling = (subtype == "Ceiling"); 5183dfaafdaSJames Feist auto findPosHyst = base.find("PositiveHysteresis"); 5193dfaafdaSJames Feist auto findNegHyst = base.find("NegativeHysteresis"); 5203dfaafdaSJames Feist if (findPosHyst != base.end()) 5213dfaafdaSJames Feist { 5221f802f5eSJames Feist info.stepwiseInfo.positiveHysteresis = std::visit( 523208abce8SJames Feist VariantToDoubleVisitor(), findPosHyst->second); 5243dfaafdaSJames Feist } 5253dfaafdaSJames Feist if (findNegHyst != base.end()) 5263dfaafdaSJames Feist { 5271f802f5eSJames Feist info.stepwiseInfo.positiveHysteresis = std::visit( 528208abce8SJames Feist VariantToDoubleVisitor(), findNegHyst->second); 5293dfaafdaSJames Feist } 53022c257abSJames Feist std::vector<double> readings = 5311f802f5eSJames Feist std::get<std::vector<double>>(base.at("Reading")); 53222c257abSJames Feist if (readings.size() > ec::maxStepwisePoints) 53322c257abSJames Feist { 53422c257abSJames Feist throw std::invalid_argument("Too many stepwise points."); 53522c257abSJames Feist } 53622c257abSJames Feist if (readings.empty()) 53722c257abSJames Feist { 53822c257abSJames Feist throw std::invalid_argument( 53922c257abSJames Feist "Must have one stepwise point."); 54022c257abSJames Feist } 54122c257abSJames Feist std::copy(readings.begin(), readings.end(), 54222c257abSJames Feist info.stepwiseInfo.reading); 54322c257abSJames Feist if (readings.size() < ec::maxStepwisePoints) 54422c257abSJames Feist { 54522c257abSJames Feist info.stepwiseInfo.reading[readings.size()] = 5465f59c0fdSPatrick Venture std::numeric_limits<double>::quiet_NaN(); 54722c257abSJames Feist } 54822c257abSJames Feist std::vector<double> outputs = 5491f802f5eSJames Feist std::get<std::vector<double>>(base.at("Output")); 55022c257abSJames Feist if (readings.size() != outputs.size()) 55122c257abSJames Feist { 55222c257abSJames Feist throw std::invalid_argument( 55322c257abSJames Feist "Outputs size must match readings"); 55422c257abSJames Feist } 55522c257abSJames Feist std::copy(outputs.begin(), outputs.end(), 55622c257abSJames Feist info.stepwiseInfo.output); 55722c257abSJames Feist if (outputs.size() < ec::maxStepwisePoints) 55822c257abSJames Feist { 55922c257abSJames Feist info.stepwiseInfo.output[outputs.size()] = 5605f59c0fdSPatrick Venture std::numeric_limits<double>::quiet_NaN(); 56122c257abSJames Feist } 56222c257abSJames Feist } 56322c257abSJames Feist } 56422c257abSJames Feist } 5657136a5aeSJames Feist if (DEBUG) 5667136a5aeSJames Feist { 5677136a5aeSJames Feist debugPrint(); 5687136a5aeSJames Feist } 569c959c429SJames Feist if (zoneConfig.empty() || zoneDetailsConfig.empty()) 57050fdfe39SJames Feist { 57150fdfe39SJames Feist std::cerr << "No fan zones, application pausing until reboot\n"; 57250fdfe39SJames Feist while (1) 57350fdfe39SJames Feist { 57450fdfe39SJames Feist bus.process_discard(); 57565ea92e7SJames Feist bus.wait(); 57650fdfe39SJames Feist } 57750fdfe39SJames Feist } 5787136a5aeSJames Feist } 5797136a5aeSJames Feist } // namespace dbus_configuration 580