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 1764f072a7SJames Feist #include <chrono> 187136a5aeSJames Feist #include <conf.hpp> 197136a5aeSJames Feist #include <dbus/util.hpp> 2064f072a7SJames Feist #include <functional> 217136a5aeSJames Feist #include <iostream> 227136a5aeSJames Feist #include <sdbusplus/bus.hpp> 2364f072a7SJames Feist #include <sdbusplus/bus/match.hpp> 2422c257abSJames Feist #include <sdbusplus/exception.hpp> 257136a5aeSJames Feist #include <set> 2664f072a7SJames Feist #include <thread> 277136a5aeSJames Feist #include <unordered_map> 287136a5aeSJames Feist 297136a5aeSJames Feist static constexpr bool DEBUG = false; // enable to print found configuration 307136a5aeSJames Feist 317136a5aeSJames Feist std::map<std::string, struct sensor> SensorConfig = {}; 327136a5aeSJames Feist std::map<int64_t, PIDConf> ZoneConfig = {}; 337136a5aeSJames Feist std::map<int64_t, struct zone> ZoneDetailsConfig = {}; 347136a5aeSJames Feist 357136a5aeSJames Feist constexpr const char* pidConfigurationInterface = 367136a5aeSJames Feist "xyz.openbmc_project.Configuration.Pid"; 377136a5aeSJames Feist constexpr const char* objectManagerInterface = 387136a5aeSJames Feist "org.freedesktop.DBus.ObjectManager"; 397136a5aeSJames Feist constexpr const char* pidZoneConfigurationInterface = 407136a5aeSJames Feist "xyz.openbmc_project.Configuration.Pid.Zone"; 4122c257abSJames Feist constexpr const char* stepwiseConfigurationInterface = 4222c257abSJames Feist "xyz.openbmc_project.Configuration.Stepwise"; 437136a5aeSJames Feist constexpr const char* sensorInterface = "xyz.openbmc_project.Sensor.Value"; 447136a5aeSJames Feist constexpr const char* pwmInterface = "xyz.openbmc_project.Control.FanPwm"; 457136a5aeSJames Feist 467136a5aeSJames Feist namespace dbus_configuration 477136a5aeSJames Feist { 487136a5aeSJames Feist 4950fdfe39SJames Feist namespace variant_ns = sdbusplus::message::variant_ns; 5050fdfe39SJames Feist 517136a5aeSJames Feist bool findSensor(const std::unordered_map<std::string, std::string>& sensors, 527136a5aeSJames Feist const std::string& search, 537136a5aeSJames Feist std::pair<std::string, std::string>& sensor) 547136a5aeSJames Feist { 557136a5aeSJames Feist for (const auto& s : sensors) 567136a5aeSJames Feist { 577136a5aeSJames Feist if (s.first.find(search) != std::string::npos) 587136a5aeSJames Feist { 597136a5aeSJames Feist sensor = s; 607136a5aeSJames Feist return true; 617136a5aeSJames Feist } 627136a5aeSJames Feist } 637136a5aeSJames Feist return false; 647136a5aeSJames Feist } 657136a5aeSJames Feist 667136a5aeSJames Feist // this function prints the configuration into a form similar to the cpp 677136a5aeSJames Feist // generated code to help in verification, should be turned off during normal 687136a5aeSJames Feist // use 697136a5aeSJames Feist void debugPrint(void) 707136a5aeSJames Feist { 717136a5aeSJames Feist // print sensor config 727136a5aeSJames Feist std::cout << "sensor config:\n"; 737136a5aeSJames Feist std::cout << "{\n"; 747136a5aeSJames Feist for (auto& pair : SensorConfig) 757136a5aeSJames Feist { 767136a5aeSJames Feist 777136a5aeSJames Feist std::cout << "\t{" << pair.first << ",\n\t\t{"; 787136a5aeSJames Feist std::cout << pair.second.type << ", "; 797136a5aeSJames Feist std::cout << pair.second.readpath << ", "; 807136a5aeSJames Feist std::cout << pair.second.writepath << ", "; 817136a5aeSJames Feist std::cout << pair.second.min << ", "; 827136a5aeSJames Feist std::cout << pair.second.max << ", "; 837136a5aeSJames Feist std::cout << pair.second.timeout << "},\n\t},\n"; 847136a5aeSJames Feist } 857136a5aeSJames Feist std::cout << "}\n\n"; 867136a5aeSJames Feist std::cout << "ZoneDetailsConfig\n"; 877136a5aeSJames Feist std::cout << "{\n"; 887136a5aeSJames Feist for (auto& zone : ZoneDetailsConfig) 897136a5aeSJames Feist { 907136a5aeSJames Feist std::cout << "\t{" << zone.first << ",\n"; 917136a5aeSJames Feist std::cout << "\t\t{" << zone.second.minthermalrpm << ", "; 927136a5aeSJames Feist std::cout << zone.second.failsafepercent << "}\n\t},\n"; 937136a5aeSJames Feist } 947136a5aeSJames Feist std::cout << "}\n\n"; 957136a5aeSJames Feist std::cout << "ZoneConfig\n"; 967136a5aeSJames Feist std::cout << "{\n"; 977136a5aeSJames Feist for (auto& zone : ZoneConfig) 987136a5aeSJames Feist { 997136a5aeSJames Feist std::cout << "\t{" << zone.first << "\n"; 1007136a5aeSJames Feist for (auto& pidconf : zone.second) 1017136a5aeSJames Feist { 1027136a5aeSJames Feist std::cout << "\t\t{" << pidconf.first << ",\n"; 1037136a5aeSJames Feist std::cout << "\t\t\t{" << pidconf.second.type << ",\n"; 1047136a5aeSJames Feist std::cout << "\t\t\t{"; 1057136a5aeSJames Feist for (auto& input : pidconf.second.inputs) 1067136a5aeSJames Feist { 1077136a5aeSJames Feist std::cout << "\n\t\t\t" << input << ",\n"; 1087136a5aeSJames Feist } 1097136a5aeSJames Feist std::cout << "\t\t\t}\n"; 1107136a5aeSJames Feist std::cout << "\t\t\t" << pidconf.second.setpoint << ",\n"; 11122c257abSJames Feist std::cout << "\t\t\t{" << pidconf.second.pidInfo.ts << ",\n"; 11222c257abSJames Feist std::cout << "\t\t\t" << pidconf.second.pidInfo.p_c << ",\n"; 11322c257abSJames Feist std::cout << "\t\t\t" << pidconf.second.pidInfo.i_c << ",\n"; 11422c257abSJames Feist std::cout << "\t\t\t" << pidconf.second.pidInfo.ff_off << ",\n"; 11522c257abSJames Feist std::cout << "\t\t\t" << pidconf.second.pidInfo.ff_gain << ",\n"; 11622c257abSJames Feist std::cout << "\t\t\t{" << pidconf.second.pidInfo.i_lim.min << "," 11722c257abSJames Feist << pidconf.second.pidInfo.i_lim.max << "},\n"; 11822c257abSJames Feist std::cout << "\t\t\t{" << pidconf.second.pidInfo.out_lim.min << "," 11922c257abSJames Feist << pidconf.second.pidInfo.out_lim.max << "},\n"; 12022c257abSJames Feist std::cout << "\t\t\t" << pidconf.second.pidInfo.slew_neg << ",\n"; 12122c257abSJames Feist std::cout << "\t\t\t" << pidconf.second.pidInfo.slew_pos << ",\n"; 1227136a5aeSJames Feist std::cout << "\t\t\t}\n\t\t}\n"; 1237136a5aeSJames Feist } 1247136a5aeSJames Feist std::cout << "\t},\n"; 1257136a5aeSJames Feist } 1267136a5aeSJames Feist std::cout << "}\n\n"; 1277136a5aeSJames Feist } 1287136a5aeSJames Feist 12950fdfe39SJames Feist int eventHandler(sd_bus_message*, void*, sd_bus_error*) 13050fdfe39SJames Feist { 13150fdfe39SJames Feist // do a brief sleep as we tend to get a bunch of these events at 13250fdfe39SJames Feist // once 13350fdfe39SJames Feist std::this_thread::sleep_for(std::chrono::seconds(5)); 13450fdfe39SJames Feist std::cout << "New configuration detected, restarting\n."; 13550fdfe39SJames Feist std::exit(EXIT_SUCCESS); // service file should make us restart 13650fdfe39SJames Feist return 1; 13750fdfe39SJames Feist } 13850fdfe39SJames Feist 1397136a5aeSJames Feist void init(sdbusplus::bus::bus& bus) 1407136a5aeSJames Feist { 14122c257abSJames Feist using DbusVariantType = 14222c257abSJames Feist sdbusplus::message::variant<uint64_t, int64_t, double, std::string, 14322c257abSJames Feist std::vector<std::string>, 14422c257abSJames Feist std::vector<double>>; 14522c257abSJames Feist 1467136a5aeSJames Feist using ManagedObjectType = std::unordered_map< 1477136a5aeSJames Feist sdbusplus::message::object_path, 1487136a5aeSJames Feist std::unordered_map<std::string, 14922c257abSJames Feist std::unordered_map<std::string, DbusVariantType>>>; 15064f072a7SJames Feist 15150fdfe39SJames Feist // restart on configuration properties changed 15250fdfe39SJames Feist static sdbusplus::bus::match::match configMatch( 15364f072a7SJames Feist bus, 15464f072a7SJames Feist "type='signal',member='PropertiesChanged',arg0namespace='" + 15564f072a7SJames Feist std::string(pidConfigurationInterface) + "'", 15664f072a7SJames Feist eventHandler); 15764f072a7SJames Feist 15850fdfe39SJames Feist // restart on sensors changed 15950fdfe39SJames Feist static sdbusplus::bus::match::match sensorAdded( 16050fdfe39SJames Feist bus, 16150fdfe39SJames Feist "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/" 16250fdfe39SJames Feist "sensors/'", 16350fdfe39SJames Feist eventHandler); 16450fdfe39SJames Feist 1657136a5aeSJames Feist auto mapper = 1667136a5aeSJames Feist bus.new_method_call("xyz.openbmc_project.ObjectMapper", 1677136a5aeSJames Feist "/xyz/openbmc_project/object_mapper", 1687136a5aeSJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree"); 1697136a5aeSJames Feist mapper.append("", 0, 17022c257abSJames Feist std::array<const char*, 6>{objectManagerInterface, 1717136a5aeSJames Feist pidConfigurationInterface, 1727136a5aeSJames Feist pidZoneConfigurationInterface, 17322c257abSJames Feist stepwiseConfigurationInterface, 1747136a5aeSJames Feist sensorInterface, pwmInterface}); 17522c257abSJames Feist std::unordered_map< 17622c257abSJames Feist std::string, std::unordered_map<std::string, std::vector<std::string>>> 17722c257abSJames Feist respData; 17822c257abSJames Feist try 17922c257abSJames Feist { 1807136a5aeSJames Feist auto resp = bus.call(mapper); 1817136a5aeSJames Feist if (resp.is_method_error()) 1827136a5aeSJames Feist { 1837136a5aeSJames Feist throw std::runtime_error("ObjectMapper Call Failure"); 1847136a5aeSJames Feist } 1857136a5aeSJames Feist resp.read(respData); 18622c257abSJames Feist } 18722c257abSJames Feist catch (sdbusplus::exception_t&) 18822c257abSJames Feist { 18922c257abSJames Feist // can't do anything without mapper call data 19022c257abSJames Feist throw std::runtime_error("ObjectMapper Call Failure"); 19122c257abSJames Feist } 19222c257abSJames Feist 1937136a5aeSJames Feist if (respData.empty()) 1947136a5aeSJames Feist { 19522c257abSJames Feist // can't do anything without mapper call data 1967136a5aeSJames Feist throw std::runtime_error("No configuration data available from Mapper"); 1977136a5aeSJames Feist } 1987136a5aeSJames Feist // create a map of pair of <has pid configuration, ObjectManager path> 1997136a5aeSJames Feist std::unordered_map<std::string, std::pair<bool, std::string>> owners; 2007136a5aeSJames Feist // and a map of <path, interface> for sensors 2017136a5aeSJames Feist std::unordered_map<std::string, std::string> sensors; 2027136a5aeSJames Feist for (const auto& objectPair : respData) 2037136a5aeSJames Feist { 2047136a5aeSJames Feist for (const auto& ownerPair : objectPair.second) 2057136a5aeSJames Feist { 2067136a5aeSJames Feist auto& owner = owners[ownerPair.first]; 2077136a5aeSJames Feist for (const std::string& interface : ownerPair.second) 2087136a5aeSJames Feist { 2097136a5aeSJames Feist 2107136a5aeSJames Feist if (interface == objectManagerInterface) 2117136a5aeSJames Feist { 2127136a5aeSJames Feist owner.second = objectPair.first; 2137136a5aeSJames Feist } 2147136a5aeSJames Feist if (interface == pidConfigurationInterface || 21522c257abSJames Feist interface == pidZoneConfigurationInterface || 21622c257abSJames Feist interface == stepwiseConfigurationInterface) 2177136a5aeSJames Feist { 2187136a5aeSJames Feist owner.first = true; 2197136a5aeSJames Feist } 2207136a5aeSJames Feist if (interface == sensorInterface || interface == pwmInterface) 2217136a5aeSJames Feist { 2227136a5aeSJames Feist // we're not interested in pwm sensors, just pwm control 2237136a5aeSJames Feist if (interface == sensorInterface && 2247136a5aeSJames Feist objectPair.first.find("pwm") != std::string::npos) 2257136a5aeSJames Feist { 2267136a5aeSJames Feist continue; 2277136a5aeSJames Feist } 2287136a5aeSJames Feist sensors[objectPair.first] = interface; 2297136a5aeSJames Feist } 2307136a5aeSJames Feist } 2317136a5aeSJames Feist } 2327136a5aeSJames Feist } 2337136a5aeSJames Feist ManagedObjectType configurations; 2347136a5aeSJames Feist for (const auto& owner : owners) 2357136a5aeSJames Feist { 2367136a5aeSJames Feist // skip if no pid configuration (means probably a sensor) 2377136a5aeSJames Feist if (!owner.second.first) 2387136a5aeSJames Feist { 2397136a5aeSJames Feist continue; 2407136a5aeSJames Feist } 2417136a5aeSJames Feist auto endpoint = bus.new_method_call( 2427136a5aeSJames Feist owner.first.c_str(), owner.second.second.c_str(), 2437136a5aeSJames Feist "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 24422c257abSJames Feist ManagedObjectType configuration; 24522c257abSJames Feist try 24622c257abSJames Feist { 2477136a5aeSJames Feist auto responce = bus.call(endpoint); 2487136a5aeSJames Feist if (responce.is_method_error()) 2497136a5aeSJames Feist { 2507136a5aeSJames Feist throw std::runtime_error("Error getting managed objects from " + 2517136a5aeSJames Feist owner.first); 2527136a5aeSJames Feist } 2537136a5aeSJames Feist responce.read(configuration); 25422c257abSJames Feist } 25522c257abSJames Feist catch (sdbusplus::exception_t&) 25622c257abSJames Feist { 25722c257abSJames Feist // this shouldn't happen, probably means daemon crashed 25822c257abSJames Feist throw std::runtime_error("Error getting managed objects from " + 25922c257abSJames Feist owner.first); 26022c257abSJames Feist } 26122c257abSJames Feist 2627136a5aeSJames Feist for (auto& pathPair : configuration) 2637136a5aeSJames Feist { 2647136a5aeSJames Feist if (pathPair.second.find(pidConfigurationInterface) != 2657136a5aeSJames Feist pathPair.second.end() || 2667136a5aeSJames Feist pathPair.second.find(pidZoneConfigurationInterface) != 26722c257abSJames Feist pathPair.second.end() || 26822c257abSJames Feist pathPair.second.find(stepwiseConfigurationInterface) != 2697136a5aeSJames Feist pathPair.second.end()) 2707136a5aeSJames Feist { 2717136a5aeSJames Feist configurations.emplace(pathPair); 2727136a5aeSJames Feist } 2737136a5aeSJames Feist } 2747136a5aeSJames Feist } 2758c3c51eeSJames Feist 2768c3c51eeSJames Feist // on dbus having an index field is a bit strange, so randomly 2778c3c51eeSJames Feist // assign index based on name property 2788c3c51eeSJames Feist std::vector<std::string> zoneIndex; 2797136a5aeSJames Feist for (const auto& configuration : configurations) 2807136a5aeSJames Feist { 2817136a5aeSJames Feist auto findZone = 2827136a5aeSJames Feist configuration.second.find(pidZoneConfigurationInterface); 2837136a5aeSJames Feist if (findZone != configuration.second.end()) 2847136a5aeSJames Feist { 2857136a5aeSJames Feist const auto& zone = findZone->second; 2868c3c51eeSJames Feist size_t index = 1; 2878c3c51eeSJames Feist const std::string& name = 28850fdfe39SJames Feist variant_ns::get<std::string>(zone.at("Name")); 2898c3c51eeSJames Feist auto it = std::find(zoneIndex.begin(), zoneIndex.end(), name); 2908c3c51eeSJames Feist if (it == zoneIndex.end()) 2918c3c51eeSJames Feist { 2928c3c51eeSJames Feist zoneIndex.emplace_back(name); 2938c3c51eeSJames Feist index = zoneIndex.size(); 2948c3c51eeSJames Feist } 2958c3c51eeSJames Feist else 2968c3c51eeSJames Feist { 2978c3c51eeSJames Feist index = zoneIndex.end() - it; 2988c3c51eeSJames Feist } 2998c3c51eeSJames Feist 3008c3c51eeSJames Feist auto& details = ZoneDetailsConfig[index]; 301*d7a55bfdSJames Feist details.minthermalrpm = variant_ns::apply_visitor( 3027136a5aeSJames Feist VariantToFloatVisitor(), zone.at("MinThermalRpm")); 303*d7a55bfdSJames Feist details.failsafepercent = variant_ns::apply_visitor( 3047136a5aeSJames Feist VariantToFloatVisitor(), zone.at("FailSafePercent")); 3057136a5aeSJames Feist } 3067136a5aeSJames Feist auto findBase = configuration.second.find(pidConfigurationInterface); 30722c257abSJames Feist if (findBase != configuration.second.end()) 3087136a5aeSJames Feist { 3098c3c51eeSJames Feist 31022c257abSJames Feist const auto& base = 31122c257abSJames Feist configuration.second.at(pidConfigurationInterface); 3128c3c51eeSJames Feist const std::vector<std::string>& zones = 31350fdfe39SJames Feist variant_ns::get<std::vector<std::string>>(base.at("Zones")); 3148c3c51eeSJames Feist for (const std::string& zone : zones) 3158c3c51eeSJames Feist { 3168c3c51eeSJames Feist auto it = std::find(zoneIndex.begin(), zoneIndex.end(), zone); 3178c3c51eeSJames Feist size_t index = 1; 3188c3c51eeSJames Feist if (it == zoneIndex.end()) 3198c3c51eeSJames Feist { 3208c3c51eeSJames Feist zoneIndex.emplace_back(zone); 3218c3c51eeSJames Feist index = zoneIndex.size(); 3228c3c51eeSJames Feist } 3238c3c51eeSJames Feist else 3248c3c51eeSJames Feist { 3258c3c51eeSJames Feist index = zoneIndex.end() - it; 3268c3c51eeSJames Feist } 3278c3c51eeSJames Feist PIDConf& conf = ZoneConfig[index]; 32850fdfe39SJames Feist 32950fdfe39SJames Feist std::vector<std::string> sensorNames = 33050fdfe39SJames Feist variant_ns::get<std::vector<std::string>>( 33150fdfe39SJames Feist base.at("Inputs")); 33250fdfe39SJames Feist auto findOutputs = 33350fdfe39SJames Feist base.find("Outputs"); // currently only fans have outputs 33450fdfe39SJames Feist if (findOutputs != base.end()) 33550fdfe39SJames Feist { 33650fdfe39SJames Feist std::vector<std::string> outputs = 33750fdfe39SJames Feist variant_ns::get<std::vector<std::string>>( 33850fdfe39SJames Feist findOutputs->second); 33950fdfe39SJames Feist sensorNames.insert(sensorNames.end(), outputs.begin(), 34050fdfe39SJames Feist outputs.end()); 34150fdfe39SJames Feist } 34250fdfe39SJames Feist bool sensorsAvailable = sensorNames.size(); 34350fdfe39SJames Feist std::vector<std::string> inputs; 34450fdfe39SJames Feist for (const std::string& sensorName : sensorNames) 34550fdfe39SJames Feist { 34650fdfe39SJames Feist std::string name = sensorName; 34750fdfe39SJames Feist // replace spaces with underscores to be legal on dbus 34850fdfe39SJames Feist std::replace(name.begin(), name.end(), ' ', '_'); 34950fdfe39SJames Feist std::pair<std::string, std::string> sensorPathIfacePair; 35050fdfe39SJames Feist 35150fdfe39SJames Feist if (!findSensor(sensors, name, sensorPathIfacePair)) 35250fdfe39SJames Feist { 35350fdfe39SJames Feist sensorsAvailable = false; 35450fdfe39SJames Feist break; 35550fdfe39SJames Feist } 35650fdfe39SJames Feist if (sensorPathIfacePair.second == sensorInterface) 35750fdfe39SJames Feist { 35850fdfe39SJames Feist inputs.push_back(name); 35950fdfe39SJames Feist auto& config = SensorConfig[name]; 36050fdfe39SJames Feist config.type = 36150fdfe39SJames Feist variant_ns::get<std::string>(base.at("Class")); 36250fdfe39SJames Feist 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 { 36750fdfe39SJames Feist config.timeout = 500; 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 { 37550fdfe39SJames Feist if (otherSensor == sensorName) 37650fdfe39SJames Feist { 37750fdfe39SJames Feist continue; 37850fdfe39SJames Feist } 37950fdfe39SJames Feist std::replace(otherSensor.begin(), otherSensor.end(), 38050fdfe39SJames Feist ' ', '_'); 38150fdfe39SJames Feist auto& config = SensorConfig[otherSensor]; 38250fdfe39SJames Feist config.writepath = sensorPathIfacePair.first; 38350fdfe39SJames Feist // todo: un-hardcode this if there are fans with 38450fdfe39SJames Feist // different ranges 38550fdfe39SJames Feist config.max = 255; 38650fdfe39SJames Feist config.min = 0; 38750fdfe39SJames Feist } 38850fdfe39SJames Feist } 38950fdfe39SJames Feist } 39050fdfe39SJames Feist // if the sensors aren't available in the current state, don't 39150fdfe39SJames Feist // add them to the configuration. 39250fdfe39SJames Feist if (!sensorsAvailable) 39350fdfe39SJames Feist { 39450fdfe39SJames Feist continue; 39550fdfe39SJames Feist } 3967136a5aeSJames Feist struct controller_info& info = 39750fdfe39SJames Feist conf[variant_ns::get<std::string>(base.at("Name"))]; 39850fdfe39SJames Feist info.inputs = std::move(inputs); 39950fdfe39SJames Feist 40050fdfe39SJames Feist info.type = variant_ns::get<std::string>(base.at("Class")); 4018c3c51eeSJames Feist // todo: auto generation yaml -> c script seems to discard this 4028c3c51eeSJames Feist // value for fans, verify this is okay 4037136a5aeSJames Feist if (info.type == "fan") 4047136a5aeSJames Feist { 4057136a5aeSJames Feist info.setpoint = 0; 4067136a5aeSJames Feist } 4077136a5aeSJames Feist else 4087136a5aeSJames Feist { 409*d7a55bfdSJames Feist info.setpoint = variant_ns::apply_visitor( 4108c3c51eeSJames Feist VariantToFloatVisitor(), base.at("SetPoint")); 4117136a5aeSJames Feist } 41222c257abSJames Feist info.pidInfo.ts = 1.0; // currently unused 413*d7a55bfdSJames Feist info.pidInfo.p_c = variant_ns::apply_visitor( 4148c3c51eeSJames Feist VariantToFloatVisitor(), base.at("PCoefficient")); 415*d7a55bfdSJames Feist info.pidInfo.i_c = variant_ns::apply_visitor( 4168c3c51eeSJames Feist VariantToFloatVisitor(), base.at("ICoefficient")); 417*d7a55bfdSJames Feist info.pidInfo.ff_off = variant_ns::apply_visitor( 4187136a5aeSJames Feist VariantToFloatVisitor(), base.at("FFOffCoefficient")); 419*d7a55bfdSJames Feist info.pidInfo.ff_gain = variant_ns::apply_visitor( 4207136a5aeSJames Feist VariantToFloatVisitor(), base.at("FFGainCoefficient")); 421*d7a55bfdSJames Feist info.pidInfo.i_lim.max = variant_ns::apply_visitor( 4228c3c51eeSJames Feist VariantToFloatVisitor(), base.at("ILimitMax")); 423*d7a55bfdSJames Feist info.pidInfo.i_lim.min = variant_ns::apply_visitor( 4248c3c51eeSJames Feist VariantToFloatVisitor(), base.at("ILimitMin")); 425*d7a55bfdSJames Feist info.pidInfo.out_lim.max = variant_ns::apply_visitor( 4268c3c51eeSJames Feist VariantToFloatVisitor(), base.at("OutLimitMax")); 427*d7a55bfdSJames Feist info.pidInfo.out_lim.min = variant_ns::apply_visitor( 4288c3c51eeSJames Feist VariantToFloatVisitor(), base.at("OutLimitMin")); 429*d7a55bfdSJames Feist info.pidInfo.slew_neg = variant_ns::apply_visitor( 4307136a5aeSJames Feist VariantToFloatVisitor(), base.at("SlewNeg")); 431*d7a55bfdSJames Feist info.pidInfo.slew_pos = variant_ns::apply_visitor( 4327136a5aeSJames Feist VariantToFloatVisitor(), base.at("SlewPos")); 4337136a5aeSJames Feist } 4348c3c51eeSJames Feist } 43522c257abSJames Feist auto findStepwise = 43622c257abSJames Feist configuration.second.find(stepwiseConfigurationInterface); 43722c257abSJames Feist if (findStepwise != configuration.second.end()) 43822c257abSJames Feist { 43922c257abSJames Feist const auto& base = findStepwise->second; 44022c257abSJames Feist const std::vector<std::string>& zones = 44150fdfe39SJames Feist variant_ns::get<std::vector<std::string>>(base.at("Zones")); 44222c257abSJames Feist for (const std::string& zone : zones) 44322c257abSJames Feist { 44422c257abSJames Feist auto it = std::find(zoneIndex.begin(), zoneIndex.end(), zone); 44522c257abSJames Feist size_t index = 1; 44622c257abSJames Feist if (it == zoneIndex.end()) 44722c257abSJames Feist { 44822c257abSJames Feist zoneIndex.emplace_back(zone); 44922c257abSJames Feist index = zoneIndex.size(); 45022c257abSJames Feist } 45122c257abSJames Feist else 45222c257abSJames Feist { 45322c257abSJames Feist index = zoneIndex.end() - it; 45422c257abSJames Feist } 45522c257abSJames Feist PIDConf& conf = ZoneConfig[index]; 45650fdfe39SJames Feist 45750fdfe39SJames Feist std::vector<std::string> inputs; 45850fdfe39SJames Feist std::vector<std::string> sensorNames = 45950fdfe39SJames Feist variant_ns::get<std::vector<std::string>>( 46050fdfe39SJames Feist base.at("Inputs")); 46150fdfe39SJames Feist 46250fdfe39SJames Feist bool sensorFound = sensorNames.size(); 46350fdfe39SJames Feist for (const std::string& sensorName : sensorNames) 46450fdfe39SJames Feist { 46550fdfe39SJames Feist std::string name = sensorName; 46650fdfe39SJames Feist // replace spaces with underscores to be legal on dbus 46750fdfe39SJames Feist std::replace(name.begin(), name.end(), ' ', '_'); 46850fdfe39SJames Feist std::pair<std::string, std::string> sensorPathIfacePair; 46950fdfe39SJames Feist 47050fdfe39SJames Feist if (!findSensor(sensors, name, sensorPathIfacePair)) 47150fdfe39SJames Feist { 47250fdfe39SJames Feist sensorFound = false; 47350fdfe39SJames Feist break; 47450fdfe39SJames Feist } 47550fdfe39SJames Feist 47650fdfe39SJames Feist inputs.push_back(name); 47750fdfe39SJames Feist auto& config = SensorConfig[name]; 47850fdfe39SJames Feist config.readpath = sensorPathIfacePair.first; 47950fdfe39SJames Feist config.type = "temp"; 48050fdfe39SJames Feist // todo: maybe un-hardcode this if we run into slower 48150fdfe39SJames Feist // timeouts with sensors 48250fdfe39SJames Feist 48350fdfe39SJames Feist config.timeout = 500; 48450fdfe39SJames Feist } 48550fdfe39SJames Feist if (!sensorFound) 48650fdfe39SJames Feist { 48750fdfe39SJames Feist continue; 48850fdfe39SJames Feist } 48922c257abSJames Feist struct controller_info& info = 49050fdfe39SJames Feist conf[variant_ns::get<std::string>(base.at("Name"))]; 49150fdfe39SJames Feist info.inputs = std::move(inputs); 49250fdfe39SJames Feist 49322c257abSJames Feist info.type = "stepwise"; 49422c257abSJames Feist info.stepwiseInfo.ts = 1.0; // currently unused 4953dfaafdaSJames Feist info.stepwiseInfo.positiveHysteresis = 0.0; 4963dfaafdaSJames Feist info.stepwiseInfo.negativeHysteresis = 0.0; 4973dfaafdaSJames Feist auto findPosHyst = base.find("PositiveHysteresis"); 4983dfaafdaSJames Feist auto findNegHyst = base.find("NegativeHysteresis"); 4993dfaafdaSJames Feist if (findPosHyst != base.end()) 5003dfaafdaSJames Feist { 5013dfaafdaSJames Feist info.stepwiseInfo.positiveHysteresis = 502*d7a55bfdSJames Feist variant_ns::apply_visitor(VariantToFloatVisitor(), 5033dfaafdaSJames Feist findPosHyst->second); 5043dfaafdaSJames Feist } 5053dfaafdaSJames Feist if (findNegHyst != base.end()) 5063dfaafdaSJames Feist { 5073dfaafdaSJames Feist info.stepwiseInfo.positiveHysteresis = 508*d7a55bfdSJames Feist variant_ns::apply_visitor(VariantToFloatVisitor(), 5093dfaafdaSJames Feist findNegHyst->second); 5103dfaafdaSJames Feist } 51122c257abSJames Feist std::vector<double> readings = 51250fdfe39SJames Feist variant_ns::get<std::vector<double>>(base.at("Reading")); 51322c257abSJames Feist if (readings.size() > ec::maxStepwisePoints) 51422c257abSJames Feist { 51522c257abSJames Feist throw std::invalid_argument("Too many stepwise points."); 51622c257abSJames Feist } 51722c257abSJames Feist if (readings.empty()) 51822c257abSJames Feist { 51922c257abSJames Feist throw std::invalid_argument( 52022c257abSJames Feist "Must have one stepwise point."); 52122c257abSJames Feist } 52222c257abSJames Feist std::copy(readings.begin(), readings.end(), 52322c257abSJames Feist info.stepwiseInfo.reading); 52422c257abSJames Feist if (readings.size() < ec::maxStepwisePoints) 52522c257abSJames Feist { 52622c257abSJames Feist info.stepwiseInfo.reading[readings.size()] = 52722c257abSJames Feist std::numeric_limits<float>::quiet_NaN(); 52822c257abSJames Feist } 52922c257abSJames Feist std::vector<double> outputs = 53050fdfe39SJames Feist variant_ns::get<std::vector<double>>(base.at("Output")); 53122c257abSJames Feist if (readings.size() != outputs.size()) 53222c257abSJames Feist { 53322c257abSJames Feist throw std::invalid_argument( 53422c257abSJames Feist "Outputs size must match readings"); 53522c257abSJames Feist } 53622c257abSJames Feist std::copy(outputs.begin(), outputs.end(), 53722c257abSJames Feist info.stepwiseInfo.output); 53822c257abSJames Feist if (outputs.size() < ec::maxStepwisePoints) 53922c257abSJames Feist { 54022c257abSJames Feist info.stepwiseInfo.output[outputs.size()] = 54122c257abSJames Feist std::numeric_limits<float>::quiet_NaN(); 54222c257abSJames Feist } 54322c257abSJames Feist } 54422c257abSJames Feist } 54522c257abSJames Feist } 5467136a5aeSJames Feist if (DEBUG) 5477136a5aeSJames Feist { 5487136a5aeSJames Feist debugPrint(); 5497136a5aeSJames Feist } 55050fdfe39SJames Feist if (ZoneConfig.empty()) 55150fdfe39SJames Feist { 55250fdfe39SJames Feist std::cerr << "No fan zones, application pausing until reboot\n"; 55350fdfe39SJames Feist while (1) 55450fdfe39SJames Feist { 55550fdfe39SJames Feist bus.process_discard(); 55650fdfe39SJames Feist } 55750fdfe39SJames Feist } 5587136a5aeSJames Feist } 5597136a5aeSJames Feist } // namespace dbus_configuration 560