xref: /openbmc/phosphor-fan-presence/monitor/json_parser.cpp (revision dfddd648cb81b27492afead4e2346f5fcd1397cb)
19ea8bee7SMatthew Barth /**
29ea8bee7SMatthew Barth  * Copyright © 2020 IBM Corporation
39ea8bee7SMatthew Barth  *
49ea8bee7SMatthew Barth  * Licensed under the Apache License, Version 2.0 (the "License");
59ea8bee7SMatthew Barth  * you may not use this file except in compliance with the License.
69ea8bee7SMatthew Barth  * You may obtain a copy of the License at
79ea8bee7SMatthew Barth  *
89ea8bee7SMatthew Barth  *     http://www.apache.org/licenses/LICENSE-2.0
99ea8bee7SMatthew Barth  *
109ea8bee7SMatthew Barth  * Unless required by applicable law or agreed to in writing, software
119ea8bee7SMatthew Barth  * distributed under the License is distributed on an "AS IS" BASIS,
129ea8bee7SMatthew Barth  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139ea8bee7SMatthew Barth  * See the License for the specific language governing permissions and
149ea8bee7SMatthew Barth  * limitations under the License.
159ea8bee7SMatthew Barth  */
169ea8bee7SMatthew Barth #include "json_parser.hpp"
179ea8bee7SMatthew Barth 
1822ab93b4SMatthew Barth #include "conditions.hpp"
199ea8bee7SMatthew Barth #include "json_config.hpp"
209ea8bee7SMatthew Barth #include "nonzero_speed_trust.hpp"
21f06ab07cSMatt Spinler #include "power_interface.hpp"
22f06ab07cSMatt Spinler #include "power_off_rule.hpp"
2369f2f48eSJolie Ku #include "tach_sensor.hpp"
249ea8bee7SMatthew Barth #include "types.hpp"
259ea8bee7SMatthew Barth 
269ea8bee7SMatthew Barth #include <nlohmann/json.hpp>
279ea8bee7SMatthew Barth #include <phosphor-logging/log.hpp>
289ea8bee7SMatthew Barth 
299ea8bee7SMatthew Barth #include <algorithm>
30fbf4703fSPatrick Williams #include <format>
319ea8bee7SMatthew Barth #include <map>
329ea8bee7SMatthew Barth #include <memory>
3322ab93b4SMatthew Barth #include <optional>
349ea8bee7SMatthew Barth #include <vector>
359ea8bee7SMatthew Barth 
369ea8bee7SMatthew Barth namespace phosphor::fan::monitor
379ea8bee7SMatthew Barth {
389ea8bee7SMatthew Barth 
399ea8bee7SMatthew Barth using json = nlohmann::json;
409ea8bee7SMatthew Barth using namespace phosphor::logging;
419ea8bee7SMatthew Barth 
429ea8bee7SMatthew Barth namespace tClass
439ea8bee7SMatthew Barth {
449ea8bee7SMatthew Barth 
459ea8bee7SMatthew Barth // Get a constructed trust group class for a non-zero speed group
469ea8bee7SMatthew Barth CreateGroupFunction
getNonZeroSpeed(const std::vector<trust::GroupDefinition> & group)479ea8bee7SMatthew Barth     getNonZeroSpeed(const std::vector<trust::GroupDefinition>& group)
489ea8bee7SMatthew Barth {
499ea8bee7SMatthew Barth     return [group]() {
509ea8bee7SMatthew Barth         return std::make_unique<trust::NonzeroSpeed>(std::move(group));
519ea8bee7SMatthew Barth     };
529ea8bee7SMatthew Barth }
539ea8bee7SMatthew Barth 
549ea8bee7SMatthew Barth } // namespace tClass
559ea8bee7SMatthew Barth 
569ea8bee7SMatthew Barth const std::map<std::string, trustHandler> trusts = {
579ea8bee7SMatthew Barth     {"nonzerospeed", tClass::getNonZeroSpeed}};
583ad14346SMatthew Barth const std::map<std::string, condHandler> conditions = {
593ad14346SMatthew Barth     {"propertiesmatch", condition::getPropertiesMatch}};
6069f2f48eSJolie Ku const std::map<std::string, size_t> methods = {
6169f2f48eSJolie Ku     {"timebased", MethodMode::timebased}, {"count", MethodMode::count}};
629ea8bee7SMatthew Barth 
getTrustGrps(const json & obj)639ea8bee7SMatthew Barth const std::vector<CreateGroupFunction> getTrustGrps(const json& obj)
649ea8bee7SMatthew Barth {
659ea8bee7SMatthew Barth     std::vector<CreateGroupFunction> grpFuncs;
669ea8bee7SMatthew Barth 
679ea8bee7SMatthew Barth     if (obj.contains("sensor_trust_groups"))
689ea8bee7SMatthew Barth     {
699ea8bee7SMatthew Barth         for (auto& stg : obj["sensor_trust_groups"])
709ea8bee7SMatthew Barth         {
719ea8bee7SMatthew Barth             if (!stg.contains("class") || !stg.contains("group"))
729ea8bee7SMatthew Barth             {
739ea8bee7SMatthew Barth                 // Log error on missing required parameters
749ea8bee7SMatthew Barth                 log<level::ERR>(
759ea8bee7SMatthew Barth                     "Missing required fan monitor trust group parameters",
769ea8bee7SMatthew Barth                     entry("REQUIRED_PARAMETERS=%s", "{class, group}"));
779ea8bee7SMatthew Barth                 throw std::runtime_error(
789ea8bee7SMatthew Barth                     "Missing required fan trust group parameters");
799ea8bee7SMatthew Barth             }
809ea8bee7SMatthew Barth             auto tgClass = stg["class"].get<std::string>();
819ea8bee7SMatthew Barth             std::vector<trust::GroupDefinition> group;
829ea8bee7SMatthew Barth             for (auto& member : stg["group"])
839ea8bee7SMatthew Barth             {
849ea8bee7SMatthew Barth                 // Construct list of group members
859ea8bee7SMatthew Barth                 if (!member.contains("name"))
869ea8bee7SMatthew Barth                 {
879ea8bee7SMatthew Barth                     // Log error on missing required parameter
889ea8bee7SMatthew Barth                     log<level::ERR>(
899ea8bee7SMatthew Barth                         "Missing required fan monitor trust group member name",
909ea8bee7SMatthew Barth                         entry("CLASS=%s", tgClass.c_str()));
919ea8bee7SMatthew Barth                     throw std::runtime_error(
929ea8bee7SMatthew Barth                         "Missing required fan monitor trust group member name");
939ea8bee7SMatthew Barth                 }
949ea8bee7SMatthew Barth                 auto in_trust = true;
959ea8bee7SMatthew Barth                 if (member.contains("in_trust"))
969ea8bee7SMatthew Barth                 {
979ea8bee7SMatthew Barth                     in_trust = member["in_trust"].get<bool>();
989ea8bee7SMatthew Barth                 }
999ea8bee7SMatthew Barth                 group.emplace_back(trust::GroupDefinition{
1009ea8bee7SMatthew Barth                     member["name"].get<std::string>(), in_trust});
1019ea8bee7SMatthew Barth             }
1029ea8bee7SMatthew Barth             // The class for fan sensor trust groups
1039ea8bee7SMatthew Barth             // (Must have a supported function within the tClass namespace)
1049ea8bee7SMatthew Barth             std::transform(tgClass.begin(), tgClass.end(), tgClass.begin(),
1059ea8bee7SMatthew Barth                            tolower);
1069ea8bee7SMatthew Barth             auto handler = trusts.find(tgClass);
1079ea8bee7SMatthew Barth             if (handler != trusts.end())
1089ea8bee7SMatthew Barth             {
1099ea8bee7SMatthew Barth                 // Call function for trust group class
1109ea8bee7SMatthew Barth                 grpFuncs.emplace_back(handler->second(group));
1119ea8bee7SMatthew Barth             }
1129ea8bee7SMatthew Barth             else
1139ea8bee7SMatthew Barth             {
1149ea8bee7SMatthew Barth                 // Log error on unsupported trust group class
1159ea8bee7SMatthew Barth                 log<level::ERR>("Invalid fan monitor trust group class",
1169ea8bee7SMatthew Barth                                 entry("CLASS=%s", tgClass.c_str()));
1179ea8bee7SMatthew Barth                 throw std::runtime_error(
1189ea8bee7SMatthew Barth                     "Invalid fan monitor trust group class");
1199ea8bee7SMatthew Barth             }
1209ea8bee7SMatthew Barth         }
1219ea8bee7SMatthew Barth     }
1229ea8bee7SMatthew Barth 
1239ea8bee7SMatthew Barth     return grpFuncs;
1249ea8bee7SMatthew Barth }
1259ea8bee7SMatthew Barth 
getSensorDefs(const json & sensors)12622ab93b4SMatthew Barth const std::vector<SensorDefinition> getSensorDefs(const json& sensors)
12722ab93b4SMatthew Barth {
12822ab93b4SMatthew Barth     std::vector<SensorDefinition> sensorDefs;
12922ab93b4SMatthew Barth 
13022ab93b4SMatthew Barth     for (const auto& sensor : sensors)
13122ab93b4SMatthew Barth     {
13222ab93b4SMatthew Barth         if (!sensor.contains("name") || !sensor.contains("has_target"))
13322ab93b4SMatthew Barth         {
13422ab93b4SMatthew Barth             // Log error on missing required parameters
13522ab93b4SMatthew Barth             log<level::ERR>(
13622ab93b4SMatthew Barth                 "Missing required fan sensor definition parameters",
13722ab93b4SMatthew Barth                 entry("REQUIRED_PARAMETERS=%s", "{name, has_target}"));
13822ab93b4SMatthew Barth             throw std::runtime_error(
13922ab93b4SMatthew Barth                 "Missing required fan sensor definition parameters");
14022ab93b4SMatthew Barth         }
14122ab93b4SMatthew Barth         // Target interface is optional and defaults to
14222ab93b4SMatthew Barth         // 'xyz.openbmc_project.Control.FanSpeed'
14322ab93b4SMatthew Barth         std::string targetIntf = "xyz.openbmc_project.Control.FanSpeed";
14422ab93b4SMatthew Barth         if (sensor.contains("target_interface"))
14522ab93b4SMatthew Barth         {
14622ab93b4SMatthew Barth             targetIntf = sensor["target_interface"].get<std::string>();
14722ab93b4SMatthew Barth         }
14827cc39f1SChau Ly         // Target path is optional
14927cc39f1SChau Ly         std::string targetPath;
15027cc39f1SChau Ly         if (sensor.contains("target_path"))
15127cc39f1SChau Ly         {
15227cc39f1SChau Ly             targetPath = sensor["target_path"].get<std::string>();
15327cc39f1SChau Ly         }
15422ab93b4SMatthew Barth         // Factor is optional and defaults to 1
15518fb12b8SMatt Spinler         double factor = 1.0;
15622ab93b4SMatthew Barth         if (sensor.contains("factor"))
15722ab93b4SMatthew Barth         {
15822ab93b4SMatthew Barth             factor = sensor["factor"].get<double>();
15922ab93b4SMatthew Barth         }
16022ab93b4SMatthew Barth         // Offset is optional and defaults to 0
16118fb12b8SMatt Spinler         int64_t offset = 0;
16222ab93b4SMatthew Barth         if (sensor.contains("offset"))
16322ab93b4SMatthew Barth         {
16422ab93b4SMatthew Barth             offset = sensor["offset"].get<int64_t>();
16522ab93b4SMatthew Barth         }
16669f2f48eSJolie Ku         // Threshold is optional and defaults to 1
16718fb12b8SMatt Spinler         size_t threshold = 1;
16869f2f48eSJolie Ku         if (sensor.contains("threshold"))
16969f2f48eSJolie Ku         {
17069f2f48eSJolie Ku             threshold = sensor["threshold"].get<size_t>();
17169f2f48eSJolie Ku         }
1728a8aa442SMatthew Barth         // Ignore being above the allowed max is optional, defaults to not
1738a8aa442SMatthew Barth         bool ignoreAboveMax = false;
1748a8aa442SMatthew Barth         if (sensor.contains("ignore_above_max"))
1758a8aa442SMatthew Barth         {
1768a8aa442SMatthew Barth             ignoreAboveMax = sensor["ignore_above_max"].get<bool>();
1778a8aa442SMatthew Barth         }
17822ab93b4SMatthew Barth 
179*dfddd648SPatrick Williams         SensorDefinition def{
180*dfddd648SPatrick Williams             .name = sensor["name"].get<std::string>(),
18118fb12b8SMatt Spinler             .hasTarget = sensor["has_target"].get<bool>(),
18218fb12b8SMatt Spinler             .targetInterface = targetIntf,
18318fb12b8SMatt Spinler             .targetPath = targetPath,
18418fb12b8SMatt Spinler             .factor = factor,
18518fb12b8SMatt Spinler             .offset = offset,
18618fb12b8SMatt Spinler             .threshold = threshold,
18718fb12b8SMatt Spinler             .ignoreAboveMax = ignoreAboveMax};
18818fb12b8SMatt Spinler 
18918fb12b8SMatt Spinler         sensorDefs.push_back(std::move(def));
19022ab93b4SMatthew Barth     }
19122ab93b4SMatthew Barth 
19222ab93b4SMatthew Barth     return sensorDefs;
19322ab93b4SMatthew Barth }
19422ab93b4SMatthew Barth 
getFanDefs(const json & obj)19522ab93b4SMatthew Barth const std::vector<FanDefinition> getFanDefs(const json& obj)
19622ab93b4SMatthew Barth {
19722ab93b4SMatthew Barth     std::vector<FanDefinition> fanDefs;
19822ab93b4SMatthew Barth 
19922ab93b4SMatthew Barth     for (const auto& fan : obj["fans"])
20022ab93b4SMatthew Barth     {
20169f2f48eSJolie Ku         if (!fan.contains("inventory") || !fan.contains("deviation") ||
20269f2f48eSJolie Ku             !fan.contains("sensors"))
20322ab93b4SMatthew Barth         {
20422ab93b4SMatthew Barth             // Log error on missing required parameters
20522ab93b4SMatthew Barth             log<level::ERR>(
20622ab93b4SMatthew Barth                 "Missing required fan monitor definition parameters",
20722ab93b4SMatthew Barth                 entry("REQUIRED_PARAMETERS=%s",
20869f2f48eSJolie Ku                       "{inventory, deviation, sensors}"));
20922ab93b4SMatthew Barth             throw std::runtime_error(
21022ab93b4SMatthew Barth                 "Missing required fan monitor definition parameters");
21122ab93b4SMatthew Barth         }
2124c4de263SMatthew Barth         // Valid deviation range is 0 - 100%
2134c4de263SMatthew Barth         auto deviation = fan["deviation"].get<size_t>();
214808d7fe8SMike Capps         if (100 < deviation)
2154c4de263SMatthew Barth         {
216fbf4703fSPatrick Williams             auto msg = std::format(
2174c4de263SMatthew Barth                 "Invalid deviation of {} found, must be between 0 and 100",
21878182482SMike Capps                 deviation);
21978182482SMike Capps 
22078182482SMike Capps             log<level::ERR>(msg.c_str());
22178182482SMike Capps             throw std::runtime_error(msg.c_str());
2224c4de263SMatthew Barth         }
2234c4de263SMatthew Barth 
224f724c16bSMatt Spinler         // Upper deviation defaults to the deviation value and
225f724c16bSMatt Spinler         // can also be separately specified.
226f724c16bSMatt Spinler         size_t upperDeviation = deviation;
227f724c16bSMatt Spinler         if (fan.contains("upper_deviation"))
228f724c16bSMatt Spinler         {
229f724c16bSMatt Spinler             upperDeviation = fan["upper_deviation"].get<size_t>();
230f724c16bSMatt Spinler             if (100 < upperDeviation)
231f724c16bSMatt Spinler             {
232f724c16bSMatt Spinler                 auto msg =
233fbf4703fSPatrick Williams                     std::format("Invalid upper_deviation of {} found, must "
234f724c16bSMatt Spinler                                 "be between 0 and 100",
235f724c16bSMatt Spinler                                 upperDeviation);
236f724c16bSMatt Spinler 
237f724c16bSMatt Spinler                 log<level::ERR>(msg.c_str());
238f724c16bSMatt Spinler                 throw std::runtime_error(msg.c_str());
239f724c16bSMatt Spinler             }
240f724c16bSMatt Spinler         }
241f724c16bSMatt Spinler 
24222ab93b4SMatthew Barth         // Construct the sensor definitions for this fan
24322ab93b4SMatthew Barth         auto sensorDefs = getSensorDefs(fan["sensors"]);
24422ab93b4SMatthew Barth 
24522ab93b4SMatthew Barth         // Functional delay is optional and defaults to 0
24622ab93b4SMatthew Barth         size_t funcDelay = 0;
24722ab93b4SMatthew Barth         if (fan.contains("functional_delay"))
24822ab93b4SMatthew Barth         {
24922ab93b4SMatthew Barth             funcDelay = fan["functional_delay"].get<size_t>();
25022ab93b4SMatthew Barth         }
25122ab93b4SMatthew Barth 
25269f2f48eSJolie Ku         // Method is optional and defaults to time based functional
25369f2f48eSJolie Ku         // determination
25469f2f48eSJolie Ku         size_t method = MethodMode::timebased;
255623635c6SMatt Spinler         size_t countInterval = 1;
25669f2f48eSJolie Ku         if (fan.contains("method"))
25769f2f48eSJolie Ku         {
25869f2f48eSJolie Ku             auto methodConf = fan["method"].get<std::string>();
25969f2f48eSJolie Ku             auto methodFunc = methods.find(methodConf);
26069f2f48eSJolie Ku             if (methodFunc != methods.end())
26169f2f48eSJolie Ku             {
26269f2f48eSJolie Ku                 method = methodFunc->second;
26369f2f48eSJolie Ku             }
26469f2f48eSJolie Ku             else
26569f2f48eSJolie Ku             {
26669f2f48eSJolie Ku                 // Log error on unsupported method parameter
26769f2f48eSJolie Ku                 log<level::ERR>("Invalid fan method");
26869f2f48eSJolie Ku                 throw std::runtime_error("Invalid fan method");
26969f2f48eSJolie Ku             }
270623635c6SMatt Spinler 
271623635c6SMatt Spinler             // Read the count interval value used with the count method.
272623635c6SMatt Spinler             if (method == MethodMode::count)
273623635c6SMatt Spinler             {
274623635c6SMatt Spinler                 if (fan.contains("count_interval"))
275623635c6SMatt Spinler                 {
276623635c6SMatt Spinler                     countInterval = fan["count_interval"].get<size_t>();
277623635c6SMatt Spinler                 }
278623635c6SMatt Spinler             }
27969f2f48eSJolie Ku         }
28069f2f48eSJolie Ku 
28169f2f48eSJolie Ku         // Timeout defaults to 0
28269f2f48eSJolie Ku         size_t timeout = 0;
28369f2f48eSJolie Ku         if (method == MethodMode::timebased)
28469f2f48eSJolie Ku         {
28569f2f48eSJolie Ku             if (!fan.contains("allowed_out_of_range_time"))
28669f2f48eSJolie Ku             {
28769f2f48eSJolie Ku                 // Log error on missing required parameter
28869f2f48eSJolie Ku                 log<level::ERR>(
28969f2f48eSJolie Ku                     "Missing required fan monitor definition parameters",
29069f2f48eSJolie Ku                     entry("REQUIRED_PARAMETER=%s",
29169f2f48eSJolie Ku                           "{allowed_out_of_range_time}"));
29269f2f48eSJolie Ku                 throw std::runtime_error(
29369f2f48eSJolie Ku                     "Missing required fan monitor definition parameters");
29469f2f48eSJolie Ku             }
29569f2f48eSJolie Ku             else
29669f2f48eSJolie Ku             {
29769f2f48eSJolie Ku                 timeout = fan["allowed_out_of_range_time"].get<size_t>();
29869f2f48eSJolie Ku             }
29969f2f48eSJolie Ku         }
30069f2f48eSJolie Ku 
301b0412d07SMatt Spinler         // Monitor start delay is optional and defaults to 0
302b0412d07SMatt Spinler         size_t monitorDelay = 0;
303b0412d07SMatt Spinler         if (fan.contains("monitor_start_delay"))
304b0412d07SMatt Spinler         {
305b0412d07SMatt Spinler             monitorDelay = fan["monitor_start_delay"].get<size_t>();
306b0412d07SMatt Spinler         }
307b0412d07SMatt Spinler 
308ae1f8efeSMatt Spinler         // num_sensors_nonfunc_for_fan_nonfunc is optional and defaults
309ae1f8efeSMatt Spinler         // to zero if not present, meaning the code will not set the
310ae1f8efeSMatt Spinler         // parent fan to nonfunctional based on sensors.
311ae1f8efeSMatt Spinler         size_t nonfuncSensorsCount = 0;
312ae1f8efeSMatt Spinler         if (fan.contains("num_sensors_nonfunc_for_fan_nonfunc"))
313ae1f8efeSMatt Spinler         {
314ae1f8efeSMatt Spinler             nonfuncSensorsCount =
315ae1f8efeSMatt Spinler                 fan["num_sensors_nonfunc_for_fan_nonfunc"].get<size_t>();
316ae1f8efeSMatt Spinler         }
317ae1f8efeSMatt Spinler 
318f13b42e2SMatt Spinler         // nonfunc_rotor_error_delay is optional, though it will
319f13b42e2SMatt Spinler         // default to zero if 'fault_handling' is present.
320f13b42e2SMatt Spinler         std::optional<size_t> nonfuncRotorErrorDelay;
321f13b42e2SMatt Spinler         if (fan.contains("nonfunc_rotor_error_delay"))
322f13b42e2SMatt Spinler         {
323f13b42e2SMatt Spinler             nonfuncRotorErrorDelay =
324f13b42e2SMatt Spinler                 fan["nonfunc_rotor_error_delay"].get<size_t>();
325f13b42e2SMatt Spinler         }
326f13b42e2SMatt Spinler         else if (obj.contains("fault_handling"))
327f13b42e2SMatt Spinler         {
328f13b42e2SMatt Spinler             nonfuncRotorErrorDelay = 0;
329f13b42e2SMatt Spinler         }
330f13b42e2SMatt Spinler 
33127f6b686SMatt Spinler         // fan_missing_error_delay is optional.
33227f6b686SMatt Spinler         std::optional<size_t> fanMissingErrorDelay;
33327f6b686SMatt Spinler         if (fan.contains("fan_missing_error_delay"))
33427f6b686SMatt Spinler         {
33527f6b686SMatt Spinler             fanMissingErrorDelay =
33627f6b686SMatt Spinler                 fan.at("fan_missing_error_delay").get<size_t>();
33727f6b686SMatt Spinler         }
33827f6b686SMatt Spinler 
3393ad14346SMatthew Barth         // Handle optional conditions
3408a0c2327SMatthew Barth         auto cond = std::optional<Condition>();
3413ad14346SMatthew Barth         if (fan.contains("condition"))
3423ad14346SMatthew Barth         {
3433ad14346SMatthew Barth             if (!fan["condition"].contains("name"))
3443ad14346SMatthew Barth             {
3453ad14346SMatthew Barth                 // Log error on missing required parameter
3463ad14346SMatthew Barth                 log<level::ERR>(
3473ad14346SMatthew Barth                     "Missing required fan monitor condition parameter",
3483ad14346SMatthew Barth                     entry("REQUIRED_PARAMETER=%s", "{name}"));
3493ad14346SMatthew Barth                 throw std::runtime_error(
3503ad14346SMatthew Barth                     "Missing required fan monitor condition parameter");
3513ad14346SMatthew Barth             }
3523ad14346SMatthew Barth             auto name = fan["condition"]["name"].get<std::string>();
3533ad14346SMatthew Barth             // The function for fan monitoring condition
3543ad14346SMatthew Barth             // (Must have a supported function within the condition namespace)
3553ad14346SMatthew Barth             std::transform(name.begin(), name.end(), name.begin(), tolower);
3563ad14346SMatthew Barth             auto handler = conditions.find(name);
3573ad14346SMatthew Barth             if (handler != conditions.end())
3583ad14346SMatthew Barth             {
3593ad14346SMatthew Barth                 cond = handler->second(fan["condition"]);
3603ad14346SMatthew Barth             }
3613ad14346SMatthew Barth             else
3623ad14346SMatthew Barth             {
3633ad14346SMatthew Barth                 log<level::INFO>(
3643ad14346SMatthew Barth                     "No handler found for configured condition",
3653ad14346SMatthew Barth                     entry("CONDITION_NAME=%s", name.c_str()),
3663ad14346SMatthew Barth                     entry("JSON_DUMP=%s", fan["condition"].dump().c_str()));
3673ad14346SMatthew Barth             }
3683ad14346SMatthew Barth         }
36969f2f48eSJolie Ku 
370a3584bd2SMatt Spinler         // if the fan should be set to functional when plugged in
371a3584bd2SMatt Spinler         bool setFuncOnPresent = false;
372a3584bd2SMatt Spinler         if (fan.contains("set_func_on_present"))
373a3584bd2SMatt Spinler         {
374a3584bd2SMatt Spinler             setFuncOnPresent = fan["set_func_on_present"].get<bool>();
375a3584bd2SMatt Spinler         }
376a3584bd2SMatt Spinler 
377*dfddd648SPatrick Williams         FanDefinition def{
378*dfddd648SPatrick Williams             .name = fan["inventory"].get<std::string>(),
37918fb12b8SMatt Spinler             .method = method,
38018fb12b8SMatt Spinler             .funcDelay = funcDelay,
38118fb12b8SMatt Spinler             .timeout = timeout,
38218fb12b8SMatt Spinler             .deviation = deviation,
383f724c16bSMatt Spinler             .upperDeviation = upperDeviation,
38418fb12b8SMatt Spinler             .numSensorFailsForNonfunc = nonfuncSensorsCount,
38518fb12b8SMatt Spinler             .monitorStartDelay = monitorDelay,
38618fb12b8SMatt Spinler             .countInterval = countInterval,
38718fb12b8SMatt Spinler             .nonfuncRotorErrDelay = nonfuncRotorErrorDelay,
38818fb12b8SMatt Spinler             .fanMissingErrDelay = fanMissingErrorDelay,
38918fb12b8SMatt Spinler             .sensorList = std::move(sensorDefs),
39018fb12b8SMatt Spinler             .condition = cond,
39118fb12b8SMatt Spinler             .funcOnPresent = setFuncOnPresent};
39218fb12b8SMatt Spinler 
39318fb12b8SMatt Spinler         fanDefs.push_back(std::move(def));
39422ab93b4SMatthew Barth     }
39522ab93b4SMatthew Barth 
39622ab93b4SMatthew Barth     return fanDefs;
39722ab93b4SMatthew Barth }
39822ab93b4SMatthew Barth 
getPowerOffPowerRuleState(const json & powerOffConfig)399f06ab07cSMatt Spinler PowerRuleState getPowerOffPowerRuleState(const json& powerOffConfig)
400f06ab07cSMatt Spinler {
401f06ab07cSMatt Spinler     // The state is optional and defaults to runtime
402f06ab07cSMatt Spinler     PowerRuleState ruleState{PowerRuleState::runtime};
403f06ab07cSMatt Spinler 
404f06ab07cSMatt Spinler     if (powerOffConfig.contains("state"))
405f06ab07cSMatt Spinler     {
406f06ab07cSMatt Spinler         auto state = powerOffConfig.at("state").get<std::string>();
407f06ab07cSMatt Spinler         if (state == "at_pgood")
408f06ab07cSMatt Spinler         {
409f06ab07cSMatt Spinler             ruleState = PowerRuleState::atPgood;
410f06ab07cSMatt Spinler         }
411f06ab07cSMatt Spinler         else if (state != "runtime")
412f06ab07cSMatt Spinler         {
413fbf4703fSPatrick Williams             auto msg = std::format("Invalid power off state entry {}", state);
414f06ab07cSMatt Spinler             log<level::ERR>(msg.c_str());
415f06ab07cSMatt Spinler             throw std::runtime_error(msg.c_str());
416f06ab07cSMatt Spinler         }
417f06ab07cSMatt Spinler     }
418f06ab07cSMatt Spinler 
419f06ab07cSMatt Spinler     return ruleState;
420f06ab07cSMatt Spinler }
421f06ab07cSMatt Spinler 
getPowerOffCause(const json & powerOffConfig)422f06ab07cSMatt Spinler std::unique_ptr<PowerOffCause> getPowerOffCause(const json& powerOffConfig)
423f06ab07cSMatt Spinler {
424f06ab07cSMatt Spinler     std::unique_ptr<PowerOffCause> cause;
425f06ab07cSMatt Spinler 
426f06ab07cSMatt Spinler     if (!powerOffConfig.contains("count") || !powerOffConfig.contains("cause"))
427f06ab07cSMatt Spinler     {
428f06ab07cSMatt Spinler         const auto msg =
429f06ab07cSMatt Spinler             "Missing 'count' or 'cause' entries in power off config";
430f06ab07cSMatt Spinler         log<level::ERR>(msg);
431f06ab07cSMatt Spinler         throw std::runtime_error(msg);
432f06ab07cSMatt Spinler     }
433f06ab07cSMatt Spinler 
434f06ab07cSMatt Spinler     auto count = powerOffConfig.at("count").get<size_t>();
435f06ab07cSMatt Spinler     auto powerOffCause = powerOffConfig.at("cause").get<std::string>();
436f06ab07cSMatt Spinler 
437f06ab07cSMatt Spinler     const std::map<std::string, std::function<std::unique_ptr<PowerOffCause>()>>
438f06ab07cSMatt Spinler         causes{
439f06ab07cSMatt Spinler             {"missing_fan_frus",
440f06ab07cSMatt Spinler              [count]() { return std::make_unique<MissingFanFRUCause>(count); }},
4414c62fc77SMatt Spinler             {"nonfunc_fan_rotors",
4424c62fc77SMatt Spinler              [count]() {
443f06ab07cSMatt Spinler                  return std::make_unique<NonfuncFanRotorCause>(count);
4444c62fc77SMatt Spinler              }},
4454c62fc77SMatt Spinler             {"fan_frus_with_nonfunc_rotors", [count]() {
4464c62fc77SMatt Spinler                  return std::make_unique<FanFRUsWithNonfuncRotorsCause>(count);
447f06ab07cSMatt Spinler              }}};
448f06ab07cSMatt Spinler 
449f06ab07cSMatt Spinler     auto it = causes.find(powerOffCause);
450f06ab07cSMatt Spinler     if (it != causes.end())
451f06ab07cSMatt Spinler     {
452f06ab07cSMatt Spinler         cause = it->second();
453f06ab07cSMatt Spinler     }
454f06ab07cSMatt Spinler     else
455f06ab07cSMatt Spinler     {
456f06ab07cSMatt Spinler         auto msg =
457fbf4703fSPatrick Williams             std::format("Invalid power off cause {} in power off config JSON",
458f06ab07cSMatt Spinler                         powerOffCause);
459f06ab07cSMatt Spinler         log<level::ERR>(msg.c_str());
460f06ab07cSMatt Spinler         throw std::runtime_error(msg.c_str());
461f06ab07cSMatt Spinler     }
462f06ab07cSMatt Spinler 
463f06ab07cSMatt Spinler     return cause;
464f06ab07cSMatt Spinler }
465f06ab07cSMatt Spinler 
466f06ab07cSMatt Spinler std::unique_ptr<PowerOffAction>
getPowerOffAction(const json & powerOffConfig,std::shared_ptr<PowerInterfaceBase> & powerInterface,PowerOffAction::PrePowerOffFunc & func)467f06ab07cSMatt Spinler     getPowerOffAction(const json& powerOffConfig,
468ac1efc11SMatt Spinler                       std::shared_ptr<PowerInterfaceBase>& powerInterface,
469ac1efc11SMatt Spinler                       PowerOffAction::PrePowerOffFunc& func)
470f06ab07cSMatt Spinler {
471f06ab07cSMatt Spinler     std::unique_ptr<PowerOffAction> action;
472f06ab07cSMatt Spinler     if (!powerOffConfig.contains("type"))
473f06ab07cSMatt Spinler     {
474f06ab07cSMatt Spinler         const auto msg = "Missing 'type' entry in power off config";
475f06ab07cSMatt Spinler         log<level::ERR>(msg);
476f06ab07cSMatt Spinler         throw std::runtime_error(msg);
477f06ab07cSMatt Spinler     }
478f06ab07cSMatt Spinler 
479f06ab07cSMatt Spinler     auto type = powerOffConfig.at("type").get<std::string>();
480f06ab07cSMatt Spinler 
481f06ab07cSMatt Spinler     if (((type == "hard") || (type == "soft")) &&
482f06ab07cSMatt Spinler         !powerOffConfig.contains("delay"))
483f06ab07cSMatt Spinler     {
484f06ab07cSMatt Spinler         const auto msg = "Missing 'delay' entry in power off config";
485f06ab07cSMatt Spinler         log<level::ERR>(msg);
486f06ab07cSMatt Spinler         throw std::runtime_error(msg);
487f06ab07cSMatt Spinler     }
488f06ab07cSMatt Spinler     else if ((type == "epow") &&
489f06ab07cSMatt Spinler              (!powerOffConfig.contains("service_mode_delay") ||
490f06ab07cSMatt Spinler               !powerOffConfig.contains("meltdown_delay")))
491f06ab07cSMatt Spinler     {
492f06ab07cSMatt Spinler         const auto msg = "Missing 'service_mode_delay' or 'meltdown_delay' "
493f06ab07cSMatt Spinler                          "entry in power off config";
494f06ab07cSMatt Spinler         log<level::ERR>(msg);
495f06ab07cSMatt Spinler         throw std::runtime_error(msg);
496f06ab07cSMatt Spinler     }
497f06ab07cSMatt Spinler 
498f06ab07cSMatt Spinler     if (type == "hard")
499f06ab07cSMatt Spinler     {
500f06ab07cSMatt Spinler         action = std::make_unique<HardPowerOff>(
501ac1efc11SMatt Spinler             powerOffConfig.at("delay").get<uint32_t>(), powerInterface, func);
502f06ab07cSMatt Spinler     }
503f06ab07cSMatt Spinler     else if (type == "soft")
504f06ab07cSMatt Spinler     {
505f06ab07cSMatt Spinler         action = std::make_unique<SoftPowerOff>(
506ac1efc11SMatt Spinler             powerOffConfig.at("delay").get<uint32_t>(), powerInterface, func);
507f06ab07cSMatt Spinler     }
508f06ab07cSMatt Spinler     else if (type == "epow")
509f06ab07cSMatt Spinler     {
510f06ab07cSMatt Spinler         action = std::make_unique<EpowPowerOff>(
511f06ab07cSMatt Spinler             powerOffConfig.at("service_mode_delay").get<uint32_t>(),
512ac1efc11SMatt Spinler             powerOffConfig.at("meltdown_delay").get<uint32_t>(), powerInterface,
513ac1efc11SMatt Spinler             func);
514f06ab07cSMatt Spinler     }
515f06ab07cSMatt Spinler     else
516f06ab07cSMatt Spinler     {
517*dfddd648SPatrick Williams         auto msg =
518*dfddd648SPatrick Williams             std::format("Invalid 'type' entry {} in power off config", type);
519f06ab07cSMatt Spinler         log<level::ERR>(msg.c_str());
520f06ab07cSMatt Spinler         throw std::runtime_error(msg.c_str());
521f06ab07cSMatt Spinler     }
522f06ab07cSMatt Spinler 
523f06ab07cSMatt Spinler     return action;
524f06ab07cSMatt Spinler }
525f06ab07cSMatt Spinler 
getPowerOffRules(const json & obj,std::shared_ptr<PowerInterfaceBase> & powerInterface,PowerOffAction::PrePowerOffFunc & func)526*dfddd648SPatrick Williams std::vector<std::unique_ptr<PowerOffRule>> getPowerOffRules(
527*dfddd648SPatrick Williams     const json& obj, std::shared_ptr<PowerInterfaceBase>& powerInterface,
528ac1efc11SMatt Spinler     PowerOffAction::PrePowerOffFunc& func)
529f06ab07cSMatt Spinler {
530f06ab07cSMatt Spinler     std::vector<std::unique_ptr<PowerOffRule>> rules;
531f06ab07cSMatt Spinler 
532f06ab07cSMatt Spinler     if (!(obj.contains("fault_handling") &&
533f06ab07cSMatt Spinler           obj.at("fault_handling").contains("power_off_config")))
534f06ab07cSMatt Spinler     {
535f06ab07cSMatt Spinler         return rules;
536f06ab07cSMatt Spinler     }
537f06ab07cSMatt Spinler 
538f06ab07cSMatt Spinler     for (const auto& config : obj.at("fault_handling").at("power_off_config"))
539f06ab07cSMatt Spinler     {
540f06ab07cSMatt Spinler         auto state = getPowerOffPowerRuleState(config);
541f06ab07cSMatt Spinler         auto cause = getPowerOffCause(config);
542ac1efc11SMatt Spinler         auto action = getPowerOffAction(config, powerInterface, func);
543f06ab07cSMatt Spinler 
544f06ab07cSMatt Spinler         auto rule = std::make_unique<PowerOffRule>(
545f06ab07cSMatt Spinler             std::move(state), std::move(cause), std::move(action));
546f06ab07cSMatt Spinler         rules.push_back(std::move(rule));
547f06ab07cSMatt Spinler     }
548f06ab07cSMatt Spinler 
549f06ab07cSMatt Spinler     return rules;
550f06ab07cSMatt Spinler }
551f06ab07cSMatt Spinler 
getNumNonfuncRotorsBeforeError(const json & obj)552f13b42e2SMatt Spinler std::optional<size_t> getNumNonfuncRotorsBeforeError(const json& obj)
553f13b42e2SMatt Spinler {
554f13b42e2SMatt Spinler     std::optional<size_t> num;
555f13b42e2SMatt Spinler 
556f13b42e2SMatt Spinler     if (obj.contains("fault_handling"))
557f13b42e2SMatt Spinler     {
558f13b42e2SMatt Spinler         // Defaults to 1 if not present inside of 'fault_handling'.
559f13b42e2SMatt Spinler         num = obj.at("fault_handling")
560f13b42e2SMatt Spinler                   .value("num_nonfunc_rotors_before_error", 1);
561f13b42e2SMatt Spinler     }
562f13b42e2SMatt Spinler 
563f13b42e2SMatt Spinler     return num;
564f13b42e2SMatt Spinler }
565f13b42e2SMatt Spinler 
5669ea8bee7SMatthew Barth } // namespace phosphor::fan::monitor
567