181bc880dSMatt Spinler /**
281bc880dSMatt Spinler  * Copyright © 2021 IBM Corporation
381bc880dSMatt Spinler  *
481bc880dSMatt Spinler  * Licensed under the Apache License, Version 2.0 (the "License");
581bc880dSMatt Spinler  * you may not use this file except in compliance with the License.
681bc880dSMatt Spinler  * You may obtain a copy of the License at
781bc880dSMatt Spinler  *
881bc880dSMatt Spinler  *     http://www.apache.org/licenses/LICENSE-2.0
981bc880dSMatt Spinler  *
1081bc880dSMatt Spinler  * Unless required by applicable law or agreed to in writing, software
1181bc880dSMatt Spinler  * distributed under the License is distributed on an "AS IS" BASIS,
1281bc880dSMatt Spinler  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1381bc880dSMatt Spinler  * See the License for the specific language governing permissions and
1481bc880dSMatt Spinler  * limitations under the License.
1581bc880dSMatt Spinler  */
1681bc880dSMatt Spinler #include "set_parameter_from_group_max.hpp"
1781bc880dSMatt Spinler 
1881bc880dSMatt Spinler #include "../manager.hpp"
1981bc880dSMatt Spinler 
20*fbf4703fSPatrick Williams #include <format>
2181bc880dSMatt Spinler 
2281bc880dSMatt Spinler namespace phosphor::fan::control::json
2381bc880dSMatt Spinler {
2481bc880dSMatt Spinler 
2581bc880dSMatt Spinler using json = nlohmann::json;
2681bc880dSMatt Spinler using namespace phosphor::logging;
2781bc880dSMatt Spinler 
SetParameterFromGroupMax(const json & jsonObj,const std::vector<Group> & groups)2881bc880dSMatt Spinler SetParameterFromGroupMax::SetParameterFromGroupMax(
2981bc880dSMatt Spinler     const json& jsonObj, const std::vector<Group>& groups) :
3081bc880dSMatt Spinler     ActionBase(jsonObj, groups)
3181bc880dSMatt Spinler {
3281bc880dSMatt Spinler     setParameterName(jsonObj);
3381bc880dSMatt Spinler     setModifier(jsonObj);
3481bc880dSMatt Spinler }
3581bc880dSMatt Spinler 
run(Zone &)36b2e9a4fcSMike Capps void SetParameterFromGroupMax::run(Zone& /*zone*/)
3781bc880dSMatt Spinler {
3881bc880dSMatt Spinler     std::optional<PropertyVariantType> max;
3981bc880dSMatt Spinler 
4081bc880dSMatt Spinler     // Find the maximum value of all group member properties, possibly modify
4181bc880dSMatt Spinler     // it, and then write it to the Manager as a parameter.
4281bc880dSMatt Spinler 
4381bc880dSMatt Spinler     for (const auto& group : _groups)
4481bc880dSMatt Spinler     {
4581bc880dSMatt Spinler         const auto& members = group.getMembers();
4681bc880dSMatt Spinler         for (const auto& member : members)
4781bc880dSMatt Spinler         {
4881bc880dSMatt Spinler             PropertyVariantType value;
4981bc880dSMatt Spinler             try
5081bc880dSMatt Spinler             {
5181bc880dSMatt Spinler                 value = Manager::getObjValueVariant(
5281bc880dSMatt Spinler                     member, group.getInterface(), group.getProperty());
5381bc880dSMatt Spinler             }
5481bc880dSMatt Spinler             catch (const std::out_of_range&)
5581bc880dSMatt Spinler             {
5681bc880dSMatt Spinler                 continue;
5781bc880dSMatt Spinler             }
5881bc880dSMatt Spinler 
5981bc880dSMatt Spinler             // Only allow a group to have multiple members if it's
6081bc880dSMatt Spinler             // numeric. Unlike with std::is_arithmetic, bools are not
6181bc880dSMatt Spinler             // considered numeric here.
6281bc880dSMatt Spinler             if (members.size() > 1)
6381bc880dSMatt Spinler             {
6481bc880dSMatt Spinler                 bool invalid = false;
6581bc880dSMatt Spinler                 std::visit(
6681bc880dSMatt Spinler                     [&group, &invalid, this](auto&& val) {
6781bc880dSMatt Spinler                         using V = std::decay_t<decltype(val)>;
6881bc880dSMatt Spinler                         if constexpr (!std::is_same_v<double, V> &&
6981bc880dSMatt Spinler                                       !std::is_same_v<int32_t, V> &&
7081bc880dSMatt Spinler                                       !std::is_same_v<int64_t, V>)
7181bc880dSMatt Spinler                         {
72*fbf4703fSPatrick Williams                             log<level::ERR>(std::format("{}: Group {} has more "
7381bc880dSMatt Spinler                                                         "than one member but "
7481bc880dSMatt Spinler                                                         "isn't numeric",
7581bc880dSMatt Spinler                                                         ActionBase::getName(),
7681bc880dSMatt Spinler                                                         group.getName())
7781bc880dSMatt Spinler                                                 .c_str());
7881bc880dSMatt Spinler                             invalid = true;
7981bc880dSMatt Spinler                         }
8081bc880dSMatt Spinler                     },
8181bc880dSMatt Spinler                     value);
8281bc880dSMatt Spinler                 if (invalid)
8381bc880dSMatt Spinler                 {
8481bc880dSMatt Spinler                     continue;
8581bc880dSMatt Spinler                 }
8681bc880dSMatt Spinler             }
8781bc880dSMatt Spinler 
8881bc880dSMatt Spinler             if (max && (value > max))
8981bc880dSMatt Spinler             {
9081bc880dSMatt Spinler                 max = value;
9181bc880dSMatt Spinler             }
9281bc880dSMatt Spinler             else if (!max)
9381bc880dSMatt Spinler             {
9481bc880dSMatt Spinler                 max = value;
9581bc880dSMatt Spinler             }
9681bc880dSMatt Spinler         }
9781bc880dSMatt Spinler     }
9881bc880dSMatt Spinler 
9968a025f8SMatt Spinler     if (_modifier && max)
10081bc880dSMatt Spinler     {
10181bc880dSMatt Spinler         try
10281bc880dSMatt Spinler         {
10381bc880dSMatt Spinler             *max = _modifier->doOp(*max);
10481bc880dSMatt Spinler         }
10581bc880dSMatt Spinler         catch (const std::exception& e)
10681bc880dSMatt Spinler         {
10781bc880dSMatt Spinler             log<level::ERR>(
108*fbf4703fSPatrick Williams                 std::format("{}: Could not perform modifier operation: {}",
10981bc880dSMatt Spinler                             ActionBase::getName(), e.what())
11081bc880dSMatt Spinler                     .c_str());
11181bc880dSMatt Spinler             return;
11281bc880dSMatt Spinler         }
11381bc880dSMatt Spinler     }
11481bc880dSMatt Spinler 
11572c4af43SMatt Spinler     Manager::setParameter(_name, max);
11668a025f8SMatt Spinler }
11781bc880dSMatt Spinler 
setParameterName(const json & jsonObj)11881bc880dSMatt Spinler void SetParameterFromGroupMax::setParameterName(const json& jsonObj)
11981bc880dSMatt Spinler {
12081bc880dSMatt Spinler     if (!jsonObj.contains("parameter_name"))
12181bc880dSMatt Spinler     {
12281bc880dSMatt Spinler         throw ActionParseError{ActionBase::getName(),
12381bc880dSMatt Spinler                                "Missing required parameter_name value"};
12481bc880dSMatt Spinler     }
12581bc880dSMatt Spinler 
12681bc880dSMatt Spinler     _name = jsonObj["parameter_name"].get<std::string>();
12781bc880dSMatt Spinler }
12881bc880dSMatt Spinler 
setModifier(const json & jsonObj)12981bc880dSMatt Spinler void SetParameterFromGroupMax::setModifier(const json& jsonObj)
13081bc880dSMatt Spinler {
13181bc880dSMatt Spinler     if (jsonObj.contains("modifier"))
13281bc880dSMatt Spinler     {
13381bc880dSMatt Spinler         try
13481bc880dSMatt Spinler         {
13581bc880dSMatt Spinler             _modifier = std::make_unique<Modifier>(jsonObj.at("modifier"));
13681bc880dSMatt Spinler         }
13781bc880dSMatt Spinler         catch (const std::invalid_argument& e)
13881bc880dSMatt Spinler         {
13981bc880dSMatt Spinler             throw ActionParseError{ActionBase::getName(), e.what()};
14081bc880dSMatt Spinler         }
14181bc880dSMatt Spinler     }
14281bc880dSMatt Spinler }
14381bc880dSMatt Spinler 
14481bc880dSMatt Spinler }; // namespace phosphor::fan::control::json
145