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 17*0771659eSPatrick Venture #include "conf.hpp" 18*0771659eSPatrick Venture #include "dbus/util.hpp" 19*0771659eSPatrick Venture 20107a25daSPatrick Venture #include <algorithm> 2164f072a7SJames Feist #include <chrono> 2264f072a7SJames Feist #include <functional> 237136a5aeSJames Feist #include <iostream> 247136a5aeSJames Feist #include <sdbusplus/bus.hpp> 2564f072a7SJames Feist #include <sdbusplus/bus/match.hpp> 2622c257abSJames Feist #include <sdbusplus/exception.hpp> 277136a5aeSJames Feist #include <set> 2864f072a7SJames Feist #include <thread> 297136a5aeSJames Feist #include <unordered_map> 307136a5aeSJames Feist 317136a5aeSJames Feist static constexpr bool DEBUG = false; // enable to print found configuration 327136a5aeSJames Feist 337136a5aeSJames Feist std::map<std::string, struct sensor> SensorConfig = {}; 347136a5aeSJames Feist std::map<int64_t, PIDConf> ZoneConfig = {}; 357136a5aeSJames Feist std::map<int64_t, struct zone> ZoneDetailsConfig = {}; 367136a5aeSJames Feist 377136a5aeSJames Feist constexpr const char* pidConfigurationInterface = 387136a5aeSJames Feist "xyz.openbmc_project.Configuration.Pid"; 397136a5aeSJames Feist constexpr const char* objectManagerInterface = 407136a5aeSJames Feist "org.freedesktop.DBus.ObjectManager"; 417136a5aeSJames Feist constexpr const char* pidZoneConfigurationInterface = 427136a5aeSJames Feist "xyz.openbmc_project.Configuration.Pid.Zone"; 4322c257abSJames Feist constexpr const char* stepwiseConfigurationInterface = 4422c257abSJames Feist "xyz.openbmc_project.Configuration.Stepwise"; 457136a5aeSJames Feist constexpr const char* sensorInterface = "xyz.openbmc_project.Sensor.Value"; 467136a5aeSJames Feist constexpr const char* pwmInterface = "xyz.openbmc_project.Control.FanPwm"; 477136a5aeSJames Feist 487136a5aeSJames Feist namespace dbus_configuration 497136a5aeSJames Feist { 507136a5aeSJames Feist 5150fdfe39SJames Feist namespace variant_ns = sdbusplus::message::variant_ns; 5250fdfe39SJames Feist 537136a5aeSJames Feist bool findSensor(const std::unordered_map<std::string, std::string>& sensors, 547136a5aeSJames Feist const std::string& search, 557136a5aeSJames Feist std::pair<std::string, std::string>& sensor) 567136a5aeSJames Feist { 57107a25daSPatrick Venture auto found = 58107a25daSPatrick Venture std::find_if(sensors.begin(), sensors.end(), [&search](const auto& s) { 59107a25daSPatrick Venture return (s.first.find(search) != std::string::npos); 60107a25daSPatrick Venture }); 61107a25daSPatrick Venture if (found != sensors.end()) 627136a5aeSJames Feist { 63107a25daSPatrick Venture sensor = *found; 647136a5aeSJames Feist return true; 657136a5aeSJames Feist } 66107a25daSPatrick Venture 677136a5aeSJames Feist return false; 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"; 787136a5aeSJames Feist for (auto& pair : SensorConfig) 797136a5aeSJames Feist { 807136a5aeSJames Feist 817136a5aeSJames Feist std::cout << "\t{" << pair.first << ",\n\t\t{"; 827136a5aeSJames Feist std::cout << pair.second.type << ", "; 837136a5aeSJames Feist std::cout << pair.second.readpath << ", "; 847136a5aeSJames Feist 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"; 927136a5aeSJames Feist for (auto& zone : ZoneDetailsConfig) 937136a5aeSJames Feist { 947136a5aeSJames Feist std::cout << "\t{" << zone.first << ",\n"; 957136a5aeSJames Feist std::cout << "\t\t{" << zone.second.minthermalrpm << ", "; 967136a5aeSJames Feist 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"; 1017136a5aeSJames Feist for (auto& zone : ZoneConfig) 1027136a5aeSJames Feist { 1037136a5aeSJames Feist std::cout << "\t{" << zone.first << "\n"; 1047136a5aeSJames Feist for (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{"; 1097136a5aeSJames Feist for (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"; 11622c257abSJames Feist std::cout << "\t\t\t" << pidconf.second.pidInfo.p_c << ",\n"; 11722c257abSJames Feist std::cout << "\t\t\t" << pidconf.second.pidInfo.i_c << ",\n"; 11822c257abSJames Feist std::cout << "\t\t\t" << pidconf.second.pidInfo.ff_off << ",\n"; 11922c257abSJames Feist std::cout << "\t\t\t" << pidconf.second.pidInfo.ff_gain << ",\n"; 12022c257abSJames Feist std::cout << "\t\t\t{" << pidconf.second.pidInfo.i_lim.min << "," 12122c257abSJames Feist << pidconf.second.pidInfo.i_lim.max << "},\n"; 12222c257abSJames Feist std::cout << "\t\t\t{" << pidconf.second.pidInfo.out_lim.min << "," 12322c257abSJames Feist << pidconf.second.pidInfo.out_lim.max << "},\n"; 12422c257abSJames Feist std::cout << "\t\t\t" << pidconf.second.pidInfo.slew_neg << ",\n"; 12522c257abSJames Feist std::cout << "\t\t\t" << pidconf.second.pidInfo.slew_pos << ",\n"; 1267136a5aeSJames Feist std::cout << "\t\t\t}\n\t\t}\n"; 1277136a5aeSJames Feist } 1287136a5aeSJames Feist std::cout << "\t},\n"; 1297136a5aeSJames Feist } 1307136a5aeSJames Feist std::cout << "}\n\n"; 1317136a5aeSJames Feist } 1327136a5aeSJames Feist 13350fdfe39SJames Feist int eventHandler(sd_bus_message*, void*, sd_bus_error*) 13450fdfe39SJames Feist { 13550fdfe39SJames Feist // do a brief sleep as we tend to get a bunch of these events at 13650fdfe39SJames Feist // once 13750fdfe39SJames Feist std::this_thread::sleep_for(std::chrono::seconds(5)); 13850fdfe39SJames Feist std::cout << "New configuration detected, restarting\n."; 13950fdfe39SJames Feist std::exit(EXIT_SUCCESS); // service file should make us restart 14050fdfe39SJames Feist return 1; 14150fdfe39SJames Feist } 14250fdfe39SJames Feist 1437136a5aeSJames Feist void init(sdbusplus::bus::bus& bus) 1447136a5aeSJames Feist { 14522c257abSJames Feist using DbusVariantType = 14622c257abSJames Feist sdbusplus::message::variant<uint64_t, int64_t, double, std::string, 14722c257abSJames Feist std::vector<std::string>, 14822c257abSJames Feist std::vector<double>>; 14922c257abSJames Feist 1507136a5aeSJames Feist using ManagedObjectType = std::unordered_map< 1517136a5aeSJames Feist sdbusplus::message::object_path, 1527136a5aeSJames Feist std::unordered_map<std::string, 15322c257abSJames Feist std::unordered_map<std::string, DbusVariantType>>>; 15464f072a7SJames Feist 15550fdfe39SJames Feist // restart on configuration properties changed 15650fdfe39SJames Feist static sdbusplus::bus::match::match configMatch( 15764f072a7SJames Feist bus, 15864f072a7SJames Feist "type='signal',member='PropertiesChanged',arg0namespace='" + 15964f072a7SJames Feist std::string(pidConfigurationInterface) + "'", 16064f072a7SJames Feist eventHandler); 16164f072a7SJames Feist 16250fdfe39SJames Feist // restart on sensors changed 16350fdfe39SJames Feist static sdbusplus::bus::match::match sensorAdded( 16450fdfe39SJames Feist bus, 16550fdfe39SJames Feist "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/" 16650fdfe39SJames Feist "sensors/'", 16750fdfe39SJames Feist eventHandler); 16850fdfe39SJames Feist 1697136a5aeSJames Feist auto mapper = 1707136a5aeSJames Feist bus.new_method_call("xyz.openbmc_project.ObjectMapper", 1717136a5aeSJames Feist "/xyz/openbmc_project/object_mapper", 1727136a5aeSJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree"); 1737136a5aeSJames Feist mapper.append("", 0, 17422c257abSJames Feist std::array<const char*, 6>{objectManagerInterface, 1757136a5aeSJames Feist pidConfigurationInterface, 1767136a5aeSJames Feist pidZoneConfigurationInterface, 17722c257abSJames Feist stepwiseConfigurationInterface, 1787136a5aeSJames Feist sensorInterface, pwmInterface}); 17922c257abSJames Feist std::unordered_map< 18022c257abSJames Feist std::string, std::unordered_map<std::string, std::vector<std::string>>> 18122c257abSJames Feist respData; 18222c257abSJames Feist try 18322c257abSJames Feist { 1847136a5aeSJames Feist auto resp = bus.call(mapper); 1857136a5aeSJames Feist if (resp.is_method_error()) 1867136a5aeSJames Feist { 1877136a5aeSJames Feist throw std::runtime_error("ObjectMapper Call Failure"); 1887136a5aeSJames Feist } 1897136a5aeSJames Feist resp.read(respData); 19022c257abSJames Feist } 19122c257abSJames Feist catch (sdbusplus::exception_t&) 19222c257abSJames Feist { 19322c257abSJames Feist // can't do anything without mapper call data 19422c257abSJames Feist throw std::runtime_error("ObjectMapper Call Failure"); 19522c257abSJames Feist } 19622c257abSJames Feist 1977136a5aeSJames Feist if (respData.empty()) 1987136a5aeSJames Feist { 19922c257abSJames Feist // can't do anything without mapper call data 2007136a5aeSJames Feist throw std::runtime_error("No configuration data available from Mapper"); 2017136a5aeSJames Feist } 2027136a5aeSJames Feist // create a map of pair of <has pid configuration, ObjectManager path> 2037136a5aeSJames Feist std::unordered_map<std::string, std::pair<bool, std::string>> owners; 2047136a5aeSJames Feist // and a map of <path, interface> for sensors 2057136a5aeSJames Feist std::unordered_map<std::string, std::string> sensors; 2067136a5aeSJames Feist for (const auto& objectPair : respData) 2077136a5aeSJames Feist { 2087136a5aeSJames Feist for (const auto& ownerPair : objectPair.second) 2097136a5aeSJames Feist { 2107136a5aeSJames Feist auto& owner = owners[ownerPair.first]; 2117136a5aeSJames Feist for (const std::string& interface : ownerPair.second) 2127136a5aeSJames Feist { 2137136a5aeSJames Feist 2147136a5aeSJames Feist if (interface == objectManagerInterface) 2157136a5aeSJames Feist { 2167136a5aeSJames Feist owner.second = objectPair.first; 2177136a5aeSJames Feist } 2187136a5aeSJames Feist if (interface == pidConfigurationInterface || 21922c257abSJames Feist interface == pidZoneConfigurationInterface || 22022c257abSJames Feist interface == stepwiseConfigurationInterface) 2217136a5aeSJames Feist { 2227136a5aeSJames Feist owner.first = true; 2237136a5aeSJames Feist } 2247136a5aeSJames Feist if (interface == sensorInterface || interface == pwmInterface) 2257136a5aeSJames Feist { 2267136a5aeSJames Feist // we're not interested in pwm sensors, just pwm control 2277136a5aeSJames Feist if (interface == sensorInterface && 2287136a5aeSJames Feist objectPair.first.find("pwm") != std::string::npos) 2297136a5aeSJames Feist { 2307136a5aeSJames Feist continue; 2317136a5aeSJames Feist } 2327136a5aeSJames Feist sensors[objectPair.first] = interface; 2337136a5aeSJames Feist } 2347136a5aeSJames Feist } 2357136a5aeSJames Feist } 2367136a5aeSJames Feist } 2377136a5aeSJames Feist ManagedObjectType configurations; 2387136a5aeSJames Feist for (const auto& owner : owners) 2397136a5aeSJames Feist { 2407136a5aeSJames Feist // skip if no pid configuration (means probably a sensor) 2417136a5aeSJames Feist if (!owner.second.first) 2427136a5aeSJames Feist { 2437136a5aeSJames Feist continue; 2447136a5aeSJames Feist } 2457136a5aeSJames Feist auto endpoint = bus.new_method_call( 2467136a5aeSJames Feist owner.first.c_str(), owner.second.second.c_str(), 2477136a5aeSJames Feist "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 24822c257abSJames Feist ManagedObjectType configuration; 24922c257abSJames Feist try 25022c257abSJames Feist { 2517136a5aeSJames Feist auto responce = bus.call(endpoint); 2527136a5aeSJames Feist if (responce.is_method_error()) 2537136a5aeSJames Feist { 2547136a5aeSJames Feist throw std::runtime_error("Error getting managed objects from " + 2557136a5aeSJames Feist owner.first); 2567136a5aeSJames Feist } 2577136a5aeSJames Feist responce.read(configuration); 25822c257abSJames Feist } 25922c257abSJames Feist catch (sdbusplus::exception_t&) 26022c257abSJames Feist { 26122c257abSJames Feist // this shouldn't happen, probably means daemon crashed 26222c257abSJames Feist throw std::runtime_error("Error getting managed objects from " + 26322c257abSJames Feist owner.first); 26422c257abSJames Feist } 26522c257abSJames Feist 2667136a5aeSJames Feist for (auto& pathPair : configuration) 2677136a5aeSJames Feist { 2687136a5aeSJames Feist if (pathPair.second.find(pidConfigurationInterface) != 2697136a5aeSJames Feist pathPair.second.end() || 2707136a5aeSJames Feist pathPair.second.find(pidZoneConfigurationInterface) != 27122c257abSJames Feist pathPair.second.end() || 27222c257abSJames Feist pathPair.second.find(stepwiseConfigurationInterface) != 2737136a5aeSJames Feist pathPair.second.end()) 2747136a5aeSJames Feist { 2757136a5aeSJames Feist configurations.emplace(pathPair); 2767136a5aeSJames Feist } 2777136a5aeSJames Feist } 2787136a5aeSJames Feist } 2798c3c51eeSJames Feist 2808c3c51eeSJames Feist // on dbus having an index field is a bit strange, so randomly 2818c3c51eeSJames Feist // assign index based on name property 2828c3c51eeSJames Feist std::vector<std::string> zoneIndex; 2837136a5aeSJames Feist for (const auto& configuration : configurations) 2847136a5aeSJames Feist { 2857136a5aeSJames Feist auto findZone = 2867136a5aeSJames Feist configuration.second.find(pidZoneConfigurationInterface); 2877136a5aeSJames Feist if (findZone != configuration.second.end()) 2887136a5aeSJames Feist { 2897136a5aeSJames Feist const auto& zone = findZone->second; 2908c3c51eeSJames Feist size_t index = 1; 2918c3c51eeSJames Feist const std::string& name = 29250fdfe39SJames Feist variant_ns::get<std::string>(zone.at("Name")); 2938c3c51eeSJames Feist auto it = std::find(zoneIndex.begin(), zoneIndex.end(), name); 2948c3c51eeSJames Feist if (it == zoneIndex.end()) 2958c3c51eeSJames Feist { 2968c3c51eeSJames Feist zoneIndex.emplace_back(name); 2978c3c51eeSJames Feist index = zoneIndex.size(); 2988c3c51eeSJames Feist } 2998c3c51eeSJames Feist else 3008c3c51eeSJames Feist { 3018c3c51eeSJames Feist index = zoneIndex.end() - it; 3028c3c51eeSJames Feist } 3038c3c51eeSJames Feist 3048c3c51eeSJames Feist auto& details = ZoneDetailsConfig[index]; 305d7a55bfdSJames Feist details.minthermalrpm = variant_ns::apply_visitor( 3067136a5aeSJames Feist VariantToFloatVisitor(), zone.at("MinThermalRpm")); 307d7a55bfdSJames Feist details.failsafepercent = variant_ns::apply_visitor( 3087136a5aeSJames Feist VariantToFloatVisitor(), zone.at("FailSafePercent")); 3097136a5aeSJames Feist } 3107136a5aeSJames Feist auto findBase = configuration.second.find(pidConfigurationInterface); 31122c257abSJames Feist if (findBase != configuration.second.end()) 3127136a5aeSJames Feist { 3138c3c51eeSJames Feist 31422c257abSJames Feist const auto& base = 31522c257abSJames Feist configuration.second.at(pidConfigurationInterface); 3168c3c51eeSJames Feist const std::vector<std::string>& zones = 31750fdfe39SJames Feist variant_ns::get<std::vector<std::string>>(base.at("Zones")); 3188c3c51eeSJames Feist for (const std::string& zone : zones) 3198c3c51eeSJames Feist { 3208c3c51eeSJames Feist auto it = std::find(zoneIndex.begin(), zoneIndex.end(), zone); 3218c3c51eeSJames Feist size_t index = 1; 3228c3c51eeSJames Feist if (it == zoneIndex.end()) 3238c3c51eeSJames Feist { 3248c3c51eeSJames Feist zoneIndex.emplace_back(zone); 3258c3c51eeSJames Feist index = zoneIndex.size(); 3268c3c51eeSJames Feist } 3278c3c51eeSJames Feist else 3288c3c51eeSJames Feist { 3298c3c51eeSJames Feist index = zoneIndex.end() - it; 3308c3c51eeSJames Feist } 3318c3c51eeSJames Feist PIDConf& conf = ZoneConfig[index]; 33250fdfe39SJames Feist 33350fdfe39SJames Feist std::vector<std::string> sensorNames = 33450fdfe39SJames Feist variant_ns::get<std::vector<std::string>>( 33550fdfe39SJames Feist base.at("Inputs")); 33650fdfe39SJames Feist auto findOutputs = 33750fdfe39SJames Feist base.find("Outputs"); // currently only fans have outputs 33850fdfe39SJames Feist if (findOutputs != base.end()) 33950fdfe39SJames Feist { 34050fdfe39SJames Feist std::vector<std::string> outputs = 34150fdfe39SJames Feist variant_ns::get<std::vector<std::string>>( 34250fdfe39SJames Feist findOutputs->second); 34350fdfe39SJames Feist sensorNames.insert(sensorNames.end(), outputs.begin(), 34450fdfe39SJames Feist outputs.end()); 34550fdfe39SJames Feist } 34650fdfe39SJames Feist bool sensorsAvailable = sensorNames.size(); 34750fdfe39SJames Feist std::vector<std::string> inputs; 34850fdfe39SJames Feist for (const std::string& sensorName : sensorNames) 34950fdfe39SJames Feist { 35050fdfe39SJames Feist std::string name = sensorName; 35150fdfe39SJames Feist // replace spaces with underscores to be legal on dbus 35250fdfe39SJames Feist std::replace(name.begin(), name.end(), ' ', '_'); 35350fdfe39SJames Feist std::pair<std::string, std::string> sensorPathIfacePair; 35450fdfe39SJames Feist 35550fdfe39SJames Feist if (!findSensor(sensors, name, sensorPathIfacePair)) 35650fdfe39SJames Feist { 35750fdfe39SJames Feist sensorsAvailable = false; 35850fdfe39SJames Feist break; 35950fdfe39SJames Feist } 36050fdfe39SJames Feist if (sensorPathIfacePair.second == sensorInterface) 36150fdfe39SJames Feist { 36250fdfe39SJames Feist inputs.push_back(name); 36350fdfe39SJames Feist auto& config = SensorConfig[name]; 36450fdfe39SJames Feist config.type = 36550fdfe39SJames Feist variant_ns::get<std::string>(base.at("Class")); 36650fdfe39SJames Feist config.readpath = sensorPathIfacePair.first; 36750fdfe39SJames Feist // todo: maybe un-hardcode this if we run into slower 36850fdfe39SJames Feist // timeouts with sensors 36950fdfe39SJames Feist if (config.type == "temp") 37050fdfe39SJames Feist { 37150fdfe39SJames Feist config.timeout = 500; 37250fdfe39SJames Feist } 37350fdfe39SJames Feist } 37450fdfe39SJames Feist else if (sensorPathIfacePair.second == pwmInterface) 37550fdfe39SJames Feist { 37650fdfe39SJames Feist // copy so we can modify it 37750fdfe39SJames Feist for (std::string otherSensor : sensorNames) 37850fdfe39SJames Feist { 37950fdfe39SJames Feist if (otherSensor == sensorName) 38050fdfe39SJames Feist { 38150fdfe39SJames Feist continue; 38250fdfe39SJames Feist } 38350fdfe39SJames Feist std::replace(otherSensor.begin(), otherSensor.end(), 38450fdfe39SJames Feist ' ', '_'); 38550fdfe39SJames Feist auto& config = SensorConfig[otherSensor]; 38650fdfe39SJames Feist config.writepath = sensorPathIfacePair.first; 38750fdfe39SJames Feist // todo: un-hardcode this if there are fans with 38850fdfe39SJames Feist // different ranges 38950fdfe39SJames Feist config.max = 255; 39050fdfe39SJames Feist config.min = 0; 39150fdfe39SJames Feist } 39250fdfe39SJames Feist } 39350fdfe39SJames Feist } 39450fdfe39SJames Feist // if the sensors aren't available in the current state, don't 39550fdfe39SJames Feist // add them to the configuration. 39650fdfe39SJames Feist if (!sensorsAvailable) 39750fdfe39SJames Feist { 39850fdfe39SJames Feist continue; 39950fdfe39SJames Feist } 4007136a5aeSJames Feist struct controller_info& info = 40150fdfe39SJames Feist conf[variant_ns::get<std::string>(base.at("Name"))]; 40250fdfe39SJames Feist info.inputs = std::move(inputs); 40350fdfe39SJames Feist 40450fdfe39SJames Feist info.type = variant_ns::get<std::string>(base.at("Class")); 4058c3c51eeSJames Feist // todo: auto generation yaml -> c script seems to discard this 4068c3c51eeSJames Feist // value for fans, verify this is okay 4077136a5aeSJames Feist if (info.type == "fan") 4087136a5aeSJames Feist { 4097136a5aeSJames Feist info.setpoint = 0; 4107136a5aeSJames Feist } 4117136a5aeSJames Feist else 4127136a5aeSJames Feist { 413d7a55bfdSJames Feist info.setpoint = variant_ns::apply_visitor( 4148c3c51eeSJames Feist VariantToFloatVisitor(), base.at("SetPoint")); 4157136a5aeSJames Feist } 41622c257abSJames Feist info.pidInfo.ts = 1.0; // currently unused 417d7a55bfdSJames Feist info.pidInfo.p_c = variant_ns::apply_visitor( 4188c3c51eeSJames Feist VariantToFloatVisitor(), base.at("PCoefficient")); 419d7a55bfdSJames Feist info.pidInfo.i_c = variant_ns::apply_visitor( 4208c3c51eeSJames Feist VariantToFloatVisitor(), base.at("ICoefficient")); 421d7a55bfdSJames Feist info.pidInfo.ff_off = variant_ns::apply_visitor( 4227136a5aeSJames Feist VariantToFloatVisitor(), base.at("FFOffCoefficient")); 423d7a55bfdSJames Feist info.pidInfo.ff_gain = variant_ns::apply_visitor( 4247136a5aeSJames Feist VariantToFloatVisitor(), base.at("FFGainCoefficient")); 425d7a55bfdSJames Feist info.pidInfo.i_lim.max = variant_ns::apply_visitor( 4268c3c51eeSJames Feist VariantToFloatVisitor(), base.at("ILimitMax")); 427d7a55bfdSJames Feist info.pidInfo.i_lim.min = variant_ns::apply_visitor( 4288c3c51eeSJames Feist VariantToFloatVisitor(), base.at("ILimitMin")); 429d7a55bfdSJames Feist info.pidInfo.out_lim.max = variant_ns::apply_visitor( 4308c3c51eeSJames Feist VariantToFloatVisitor(), base.at("OutLimitMax")); 431d7a55bfdSJames Feist info.pidInfo.out_lim.min = variant_ns::apply_visitor( 4328c3c51eeSJames Feist VariantToFloatVisitor(), base.at("OutLimitMin")); 433d7a55bfdSJames Feist info.pidInfo.slew_neg = variant_ns::apply_visitor( 4347136a5aeSJames Feist VariantToFloatVisitor(), base.at("SlewNeg")); 435d7a55bfdSJames Feist info.pidInfo.slew_pos = variant_ns::apply_visitor( 4367136a5aeSJames Feist VariantToFloatVisitor(), base.at("SlewPos")); 4377136a5aeSJames Feist } 4388c3c51eeSJames Feist } 43922c257abSJames Feist auto findStepwise = 44022c257abSJames Feist configuration.second.find(stepwiseConfigurationInterface); 44122c257abSJames Feist if (findStepwise != configuration.second.end()) 44222c257abSJames Feist { 44322c257abSJames Feist const auto& base = findStepwise->second; 44422c257abSJames Feist const std::vector<std::string>& zones = 44550fdfe39SJames Feist variant_ns::get<std::vector<std::string>>(base.at("Zones")); 44622c257abSJames Feist for (const std::string& zone : zones) 44722c257abSJames Feist { 44822c257abSJames Feist auto it = std::find(zoneIndex.begin(), zoneIndex.end(), zone); 44922c257abSJames Feist size_t index = 1; 45022c257abSJames Feist if (it == zoneIndex.end()) 45122c257abSJames Feist { 45222c257abSJames Feist zoneIndex.emplace_back(zone); 45322c257abSJames Feist index = zoneIndex.size(); 45422c257abSJames Feist } 45522c257abSJames Feist else 45622c257abSJames Feist { 45722c257abSJames Feist index = zoneIndex.end() - it; 45822c257abSJames Feist } 45922c257abSJames Feist PIDConf& conf = ZoneConfig[index]; 46050fdfe39SJames Feist 46150fdfe39SJames Feist std::vector<std::string> inputs; 46250fdfe39SJames Feist std::vector<std::string> sensorNames = 46350fdfe39SJames Feist variant_ns::get<std::vector<std::string>>( 46450fdfe39SJames Feist base.at("Inputs")); 46550fdfe39SJames Feist 46650fdfe39SJames Feist bool sensorFound = sensorNames.size(); 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(), ' ', '_'); 47250fdfe39SJames Feist std::pair<std::string, std::string> sensorPathIfacePair; 47350fdfe39SJames Feist 47450fdfe39SJames Feist if (!findSensor(sensors, name, sensorPathIfacePair)) 47550fdfe39SJames Feist { 47650fdfe39SJames Feist sensorFound = false; 47750fdfe39SJames Feist break; 47850fdfe39SJames Feist } 47950fdfe39SJames Feist 48050fdfe39SJames Feist inputs.push_back(name); 48150fdfe39SJames Feist auto& config = SensorConfig[name]; 48250fdfe39SJames Feist config.readpath = sensorPathIfacePair.first; 48350fdfe39SJames Feist config.type = "temp"; 48450fdfe39SJames Feist // todo: maybe un-hardcode this if we run into slower 48550fdfe39SJames Feist // timeouts with sensors 48650fdfe39SJames Feist 48750fdfe39SJames Feist config.timeout = 500; 48850fdfe39SJames Feist } 48950fdfe39SJames Feist if (!sensorFound) 49050fdfe39SJames Feist { 49150fdfe39SJames Feist continue; 49250fdfe39SJames Feist } 49322c257abSJames Feist struct controller_info& info = 49450fdfe39SJames Feist conf[variant_ns::get<std::string>(base.at("Name"))]; 49550fdfe39SJames Feist info.inputs = std::move(inputs); 49650fdfe39SJames Feist 49722c257abSJames Feist info.type = "stepwise"; 49822c257abSJames Feist info.stepwiseInfo.ts = 1.0; // currently unused 4993dfaafdaSJames Feist info.stepwiseInfo.positiveHysteresis = 0.0; 5003dfaafdaSJames Feist info.stepwiseInfo.negativeHysteresis = 0.0; 5013dfaafdaSJames Feist auto findPosHyst = base.find("PositiveHysteresis"); 5023dfaafdaSJames Feist auto findNegHyst = base.find("NegativeHysteresis"); 5033dfaafdaSJames Feist if (findPosHyst != base.end()) 5043dfaafdaSJames Feist { 5053dfaafdaSJames Feist info.stepwiseInfo.positiveHysteresis = 506d7a55bfdSJames Feist variant_ns::apply_visitor(VariantToFloatVisitor(), 5073dfaafdaSJames Feist findPosHyst->second); 5083dfaafdaSJames Feist } 5093dfaafdaSJames Feist if (findNegHyst != base.end()) 5103dfaafdaSJames Feist { 5113dfaafdaSJames Feist info.stepwiseInfo.positiveHysteresis = 512d7a55bfdSJames Feist variant_ns::apply_visitor(VariantToFloatVisitor(), 5133dfaafdaSJames Feist findNegHyst->second); 5143dfaafdaSJames Feist } 51522c257abSJames Feist std::vector<double> readings = 51650fdfe39SJames Feist variant_ns::get<std::vector<double>>(base.at("Reading")); 51722c257abSJames Feist if (readings.size() > ec::maxStepwisePoints) 51822c257abSJames Feist { 51922c257abSJames Feist throw std::invalid_argument("Too many stepwise points."); 52022c257abSJames Feist } 52122c257abSJames Feist if (readings.empty()) 52222c257abSJames Feist { 52322c257abSJames Feist throw std::invalid_argument( 52422c257abSJames Feist "Must have one stepwise point."); 52522c257abSJames Feist } 52622c257abSJames Feist std::copy(readings.begin(), readings.end(), 52722c257abSJames Feist info.stepwiseInfo.reading); 52822c257abSJames Feist if (readings.size() < ec::maxStepwisePoints) 52922c257abSJames Feist { 53022c257abSJames Feist info.stepwiseInfo.reading[readings.size()] = 53122c257abSJames Feist std::numeric_limits<float>::quiet_NaN(); 53222c257abSJames Feist } 53322c257abSJames Feist std::vector<double> outputs = 53450fdfe39SJames Feist variant_ns::get<std::vector<double>>(base.at("Output")); 53522c257abSJames Feist if (readings.size() != outputs.size()) 53622c257abSJames Feist { 53722c257abSJames Feist throw std::invalid_argument( 53822c257abSJames Feist "Outputs size must match readings"); 53922c257abSJames Feist } 54022c257abSJames Feist std::copy(outputs.begin(), outputs.end(), 54122c257abSJames Feist info.stepwiseInfo.output); 54222c257abSJames Feist if (outputs.size() < ec::maxStepwisePoints) 54322c257abSJames Feist { 54422c257abSJames Feist info.stepwiseInfo.output[outputs.size()] = 54522c257abSJames Feist std::numeric_limits<float>::quiet_NaN(); 54622c257abSJames Feist } 54722c257abSJames Feist } 54822c257abSJames Feist } 54922c257abSJames Feist } 5507136a5aeSJames Feist if (DEBUG) 5517136a5aeSJames Feist { 5527136a5aeSJames Feist debugPrint(); 5537136a5aeSJames Feist } 55450fdfe39SJames Feist if (ZoneConfig.empty()) 55550fdfe39SJames Feist { 55650fdfe39SJames Feist std::cerr << "No fan zones, application pausing until reboot\n"; 55750fdfe39SJames Feist while (1) 55850fdfe39SJames Feist { 55950fdfe39SJames Feist bus.process_discard(); 56050fdfe39SJames Feist } 56150fdfe39SJames Feist } 5627136a5aeSJames Feist } 5637136a5aeSJames Feist } // namespace dbus_configuration 564