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 3518b1311eSPatrick Venture extern std::map<std::string, struct SensorConfig> sensorConfig; 3618b1311eSPatrick Venture extern std::map<int64_t, PIDConf> zoneConfig; 3718b1311eSPatrick Venture extern std::map<int64_t, struct 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"; 958e2fdb34SPatrick Venture std::cout << "\t\t{" << zone.second.minThermalRpm << ", "; 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]; 3028e2fdb34SPatrick Venture details.minThermalRpm = 3031f802f5eSJames Feist std::visit(VariantToDoubleVisitor(), zone.at("MinThermalRpm")); 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); 318c54fbd88SPatrick Venture 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 { 367*2642cb54SJames Feist config.timeout = 0; 36850fdfe39SJames Feist } 36950fdfe39SJames Feist } 37050fdfe39SJames Feist else if (sensorPathIfacePair.second == pwmInterface) 37150fdfe39SJames Feist { 37250fdfe39SJames Feist // copy so we can modify it 37350fdfe39SJames Feist for (std::string otherSensor : sensorNames) 37450fdfe39SJames Feist { 3751738e2a2SJames Feist std::replace(otherSensor.begin(), otherSensor.end(), 3761738e2a2SJames Feist ' ', '_'); 3771738e2a2SJames Feist if (sensorPathIfacePair.first.find(otherSensor) != 3781738e2a2SJames Feist std::string::npos) 37950fdfe39SJames Feist { 38050fdfe39SJames Feist continue; 38150fdfe39SJames Feist } 3821738e2a2SJames Feist 383c54fbd88SPatrick Venture auto& config = sensorConfig[otherSensor]; 38469c51061SPatrick Venture config.writePath = sensorPathIfacePair.first; 38550fdfe39SJames Feist // todo: un-hardcode this if there are fans with 38650fdfe39SJames Feist // different ranges 38750fdfe39SJames Feist config.max = 255; 38850fdfe39SJames Feist config.min = 0; 38950fdfe39SJames Feist } 39050fdfe39SJames Feist } 39150fdfe39SJames Feist } 3921738e2a2SJames Feist 393f3252315SPatrick Venture struct ControllerInfo& info = 3941f802f5eSJames Feist conf[std::get<std::string>(base.at("Name"))]; 39550fdfe39SJames Feist info.inputs = std::move(inputs); 39650fdfe39SJames Feist 3971f802f5eSJames Feist info.type = std::get<std::string>(base.at("Class")); 3988c3c51eeSJames Feist // todo: auto generation yaml -> c script seems to discard this 3998c3c51eeSJames Feist // value for fans, verify this is okay 4007136a5aeSJames Feist if (info.type == "fan") 4017136a5aeSJames Feist { 4027136a5aeSJames Feist info.setpoint = 0; 4037136a5aeSJames Feist } 4047136a5aeSJames Feist else 4057136a5aeSJames Feist { 4061f802f5eSJames Feist info.setpoint = std::visit(VariantToDoubleVisitor(), 407208abce8SJames Feist base.at("SetPoint")); 4087136a5aeSJames Feist } 40922c257abSJames Feist info.pidInfo.ts = 1.0; // currently unused 4107442c37aSPatrick Venture info.pidInfo.proportionalCoeff = std::visit( 4117442c37aSPatrick Venture VariantToDoubleVisitor(), base.at("PCoefficient")); 4127442c37aSPatrick Venture info.pidInfo.integralCoeff = std::visit( 4137442c37aSPatrick Venture VariantToDoubleVisitor(), base.at("ICoefficient")); 4147442c37aSPatrick Venture info.pidInfo.feedFwdOffset = std::visit( 4157442c37aSPatrick Venture VariantToDoubleVisitor(), base.at("FFOffCoefficient")); 4167442c37aSPatrick Venture info.pidInfo.feedFwdGain = std::visit( 4177442c37aSPatrick Venture VariantToDoubleVisitor(), base.at("FFGainCoefficient")); 4187442c37aSPatrick Venture info.pidInfo.integralLimit.max = 4191f802f5eSJames Feist std::visit(VariantToDoubleVisitor(), base.at("ILimitMax")); 4207442c37aSPatrick Venture info.pidInfo.integralLimit.min = 4211f802f5eSJames Feist std::visit(VariantToDoubleVisitor(), base.at("ILimitMin")); 4227442c37aSPatrick Venture info.pidInfo.outLim.max = std::visit(VariantToDoubleVisitor(), 4231f802f5eSJames Feist base.at("OutLimitMax")); 4247442c37aSPatrick Venture info.pidInfo.outLim.min = std::visit(VariantToDoubleVisitor(), 4251f802f5eSJames Feist base.at("OutLimitMin")); 4267442c37aSPatrick Venture info.pidInfo.slewNeg = 4271f802f5eSJames Feist std::visit(VariantToDoubleVisitor(), base.at("SlewNeg")); 4287442c37aSPatrick Venture info.pidInfo.slewPos = 4291f802f5eSJames Feist std::visit(VariantToDoubleVisitor(), base.at("SlewPos")); 430572c43daSJames Feist double negativeHysteresis = 0; 431572c43daSJames Feist double positiveHysteresis = 0; 432572c43daSJames Feist 433572c43daSJames Feist auto findNeg = base.find("NegativeHysteresis"); 434572c43daSJames Feist auto findPos = base.find("PositiveHysteresis"); 435572c43daSJames Feist if (findNeg != base.end()) 436572c43daSJames Feist { 4371f802f5eSJames Feist negativeHysteresis = 4381f802f5eSJames Feist std::visit(VariantToDoubleVisitor(), findNeg->second); 439572c43daSJames Feist } 440572c43daSJames Feist 441572c43daSJames Feist if (findPos != base.end()) 442572c43daSJames Feist { 4431f802f5eSJames Feist positiveHysteresis = 4441f802f5eSJames Feist std::visit(VariantToDoubleVisitor(), findPos->second); 445572c43daSJames Feist } 446572c43daSJames Feist info.pidInfo.negativeHysteresis = negativeHysteresis; 447572c43daSJames Feist info.pidInfo.positiveHysteresis = positiveHysteresis; 4487136a5aeSJames Feist } 4498c3c51eeSJames Feist } 45022c257abSJames Feist auto findStepwise = 45122c257abSJames Feist configuration.second.find(stepwiseConfigurationInterface); 45222c257abSJames Feist if (findStepwise != configuration.second.end()) 45322c257abSJames Feist { 45422c257abSJames Feist const auto& base = findStepwise->second; 45522c257abSJames Feist const std::vector<std::string>& zones = 4561f802f5eSJames Feist std::get<std::vector<std::string>>(base.at("Zones")); 45722c257abSJames Feist for (const std::string& zone : zones) 45822c257abSJames Feist { 459ffd418bbSJames Feist size_t index = getZoneIndex(zone, foundZones); 460c54fbd88SPatrick Venture PIDConf& conf = zoneConfig[index]; 46150fdfe39SJames Feist 46250fdfe39SJames Feist std::vector<std::string> inputs; 46350fdfe39SJames Feist std::vector<std::string> sensorNames = 4641f802f5eSJames Feist std::get<std::vector<std::string>>(base.at("Inputs")); 46550fdfe39SJames Feist 4661738e2a2SJames Feist bool sensorFound = false; 46750fdfe39SJames Feist for (const std::string& sensorName : sensorNames) 46850fdfe39SJames Feist { 46950fdfe39SJames Feist std::string name = sensorName; 47050fdfe39SJames Feist // replace spaces with underscores to be legal on dbus 47150fdfe39SJames Feist std::replace(name.begin(), name.end(), ' ', '_'); 4721738e2a2SJames Feist std::vector<std::pair<std::string, std::string>> 4731738e2a2SJames Feist sensorPathIfacePairs; 47450fdfe39SJames Feist 4751738e2a2SJames Feist if (!findSensors(sensors, name, sensorPathIfacePairs)) 47650fdfe39SJames Feist { 47750fdfe39SJames Feist break; 47850fdfe39SJames Feist } 47950fdfe39SJames Feist 4801738e2a2SJames Feist for (const auto& sensorPathIfacePair : sensorPathIfacePairs) 4811738e2a2SJames Feist { 4821738e2a2SJames Feist size_t idx = 4831738e2a2SJames Feist sensorPathIfacePair.first.find_last_of("/") + 1; 4841738e2a2SJames Feist std::string shortName = 4851738e2a2SJames Feist sensorPathIfacePair.first.substr(idx); 4861738e2a2SJames Feist 4871738e2a2SJames Feist inputs.push_back(shortName); 4881738e2a2SJames Feist auto& config = sensorConfig[shortName]; 48969c51061SPatrick Venture config.readPath = sensorPathIfacePair.first; 49050fdfe39SJames Feist config.type = "temp"; 49150fdfe39SJames Feist // todo: maybe un-hardcode this if we run into slower 49250fdfe39SJames Feist // timeouts with sensors 49350fdfe39SJames Feist 494*2642cb54SJames Feist config.timeout = 0; 4951738e2a2SJames Feist sensorFound = true; 4961738e2a2SJames Feist } 49750fdfe39SJames Feist } 49850fdfe39SJames Feist if (!sensorFound) 49950fdfe39SJames Feist { 50050fdfe39SJames Feist continue; 50150fdfe39SJames Feist } 502f3252315SPatrick Venture struct ControllerInfo& info = 5031f802f5eSJames Feist conf[std::get<std::string>(base.at("Name"))]; 50450fdfe39SJames Feist info.inputs = std::move(inputs); 50550fdfe39SJames Feist 50622c257abSJames Feist info.type = "stepwise"; 50722c257abSJames Feist info.stepwiseInfo.ts = 1.0; // currently unused 5083dfaafdaSJames Feist info.stepwiseInfo.positiveHysteresis = 0.0; 5093dfaafdaSJames Feist info.stepwiseInfo.negativeHysteresis = 0.0; 5103dfaafdaSJames Feist auto findPosHyst = base.find("PositiveHysteresis"); 5113dfaafdaSJames Feist auto findNegHyst = base.find("NegativeHysteresis"); 5123dfaafdaSJames Feist if (findPosHyst != base.end()) 5133dfaafdaSJames Feist { 5141f802f5eSJames Feist info.stepwiseInfo.positiveHysteresis = std::visit( 515208abce8SJames Feist VariantToDoubleVisitor(), findPosHyst->second); 5163dfaafdaSJames Feist } 5173dfaafdaSJames Feist if (findNegHyst != base.end()) 5183dfaafdaSJames Feist { 5191f802f5eSJames Feist info.stepwiseInfo.positiveHysteresis = std::visit( 520208abce8SJames Feist VariantToDoubleVisitor(), findNegHyst->second); 5213dfaafdaSJames Feist } 52222c257abSJames Feist std::vector<double> readings = 5231f802f5eSJames Feist std::get<std::vector<double>>(base.at("Reading")); 52422c257abSJames Feist if (readings.size() > ec::maxStepwisePoints) 52522c257abSJames Feist { 52622c257abSJames Feist throw std::invalid_argument("Too many stepwise points."); 52722c257abSJames Feist } 52822c257abSJames Feist if (readings.empty()) 52922c257abSJames Feist { 53022c257abSJames Feist throw std::invalid_argument( 53122c257abSJames Feist "Must have one stepwise point."); 53222c257abSJames Feist } 53322c257abSJames Feist std::copy(readings.begin(), readings.end(), 53422c257abSJames Feist info.stepwiseInfo.reading); 53522c257abSJames Feist if (readings.size() < ec::maxStepwisePoints) 53622c257abSJames Feist { 53722c257abSJames Feist info.stepwiseInfo.reading[readings.size()] = 5385f59c0fdSPatrick Venture std::numeric_limits<double>::quiet_NaN(); 53922c257abSJames Feist } 54022c257abSJames Feist std::vector<double> outputs = 5411f802f5eSJames Feist std::get<std::vector<double>>(base.at("Output")); 54222c257abSJames Feist if (readings.size() != outputs.size()) 54322c257abSJames Feist { 54422c257abSJames Feist throw std::invalid_argument( 54522c257abSJames Feist "Outputs size must match readings"); 54622c257abSJames Feist } 54722c257abSJames Feist std::copy(outputs.begin(), outputs.end(), 54822c257abSJames Feist info.stepwiseInfo.output); 54922c257abSJames Feist if (outputs.size() < ec::maxStepwisePoints) 55022c257abSJames Feist { 55122c257abSJames Feist info.stepwiseInfo.output[outputs.size()] = 5525f59c0fdSPatrick Venture std::numeric_limits<double>::quiet_NaN(); 55322c257abSJames Feist } 55422c257abSJames Feist } 55522c257abSJames Feist } 55622c257abSJames Feist } 5577136a5aeSJames Feist if (DEBUG) 5587136a5aeSJames Feist { 5597136a5aeSJames Feist debugPrint(); 5607136a5aeSJames Feist } 561c959c429SJames Feist if (zoneConfig.empty() || zoneDetailsConfig.empty()) 56250fdfe39SJames Feist { 56350fdfe39SJames Feist std::cerr << "No fan zones, application pausing until reboot\n"; 56450fdfe39SJames Feist while (1) 56550fdfe39SJames Feist { 56650fdfe39SJames Feist bus.process_discard(); 56765ea92e7SJames Feist bus.wait(); 56850fdfe39SJames Feist } 56950fdfe39SJames Feist } 5707136a5aeSJames Feist } 5717136a5aeSJames Feist } // namespace dbus_configuration 572