xref: /openbmc/phosphor-fan-presence/control/json/actions/set_parameter_from_group_max.cpp (revision 61b7329603e737b76b04b98746d69c1f410761b8)
1  /**
2   * Copyright © 2021 IBM Corporation
3   *
4   * Licensed under the Apache License, Version 2.0 (the "License");
5   * you may not use this file except in compliance with the License.
6   * You may obtain a copy of the License at
7   *
8   *     http://www.apache.org/licenses/LICENSE-2.0
9   *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  #include "set_parameter_from_group_max.hpp"
17  
18  #include "../manager.hpp"
19  
20  #include <fmt/format.h>
21  
22  namespace phosphor::fan::control::json
23  {
24  
25  using json = nlohmann::json;
26  using namespace phosphor::logging;
27  
28  SetParameterFromGroupMax::SetParameterFromGroupMax(
29      const json& jsonObj, const std::vector<Group>& groups) :
30      ActionBase(jsonObj, groups)
31  {
32      setParameterName(jsonObj);
33      setModifier(jsonObj);
34  }
35  
36  void SetParameterFromGroupMax::run(Zone& /*zone*/)
37  {
38      std::optional<PropertyVariantType> max;
39  
40      // Find the maximum value of all group member properties, possibly modify
41      // it, and then write it to the Manager as a parameter.
42  
43      for (const auto& group : _groups)
44      {
45          const auto& members = group.getMembers();
46          for (const auto& member : members)
47          {
48              PropertyVariantType value;
49              try
50              {
51                  value = Manager::getObjValueVariant(
52                      member, group.getInterface(), group.getProperty());
53              }
54              catch (const std::out_of_range&)
55              {
56                  continue;
57              }
58  
59              // Only allow a group to have multiple members if it's
60              // numeric. Unlike with std::is_arithmetic, bools are not
61              // considered numeric here.
62              if (members.size() > 1)
63              {
64                  bool invalid = false;
65                  std::visit(
66                      [&group, &invalid, this](auto&& val) {
67                      using V = std::decay_t<decltype(val)>;
68                      if constexpr (!std::is_same_v<double, V> &&
69                                    !std::is_same_v<int32_t, V> &&
70                                    !std::is_same_v<int64_t, V>)
71                      {
72                          log<level::ERR>(fmt::format("{}: Group {} has more "
73                                                      "than one member but "
74                                                      "isn't numeric",
75                                                      ActionBase::getName(),
76                                                      group.getName())
77                                              .c_str());
78                          invalid = true;
79                      }
80                      },
81                      value);
82                  if (invalid)
83                  {
84                      continue;
85                  }
86              }
87  
88              if (max && (value > max))
89              {
90                  max = value;
91              }
92              else if (!max)
93              {
94                  max = value;
95              }
96          }
97      }
98  
99      if (_modifier && max)
100      {
101          try
102          {
103              *max = _modifier->doOp(*max);
104          }
105          catch (const std::exception& e)
106          {
107              log<level::ERR>(
108                  fmt::format("{}: Could not perform modifier operation: {}",
109                              ActionBase::getName(), e.what())
110                      .c_str());
111              return;
112          }
113      }
114  
115      Manager::setParameter(_name, max);
116  }
117  
118  void SetParameterFromGroupMax::setParameterName(const json& jsonObj)
119  {
120      if (!jsonObj.contains("parameter_name"))
121      {
122          throw ActionParseError{ActionBase::getName(),
123                                 "Missing required parameter_name value"};
124      }
125  
126      _name = jsonObj["parameter_name"].get<std::string>();
127  }
128  
129  void SetParameterFromGroupMax::setModifier(const json& jsonObj)
130  {
131      if (jsonObj.contains("modifier"))
132      {
133          try
134          {
135              _modifier = std::make_unique<Modifier>(jsonObj.at("modifier"));
136          }
137          catch (const std::invalid_argument& e)
138          {
139              throw ActionParseError{ActionBase::getName(), e.what()};
140          }
141      }
142  }
143  
144  }; // namespace phosphor::fan::control::json
145