1 /**
2  * Copyright © 2022 Ampere Computing
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 #pragma once
17 
18 #include "../utils/modifier.hpp"
19 #include "../zone.hpp"
20 #include "action.hpp"
21 #include "group.hpp"
22 
23 #include <nlohmann/json.hpp>
24 
25 namespace phosphor::fan::control::json
26 {
27 
28 using json = nlohmann::json;
29 
30 /**
31  * @class class TargetFromGroupMax : - Action to set target of Zone
32  * to a value corresponding to the maximum value from group's member
33  * properties. The mapping is according to the configurable map.
34  *
35  * If there are more than one group using this action, the maximum
36  * speed derived from the mapping of all groups will be set to target.
37  *
38  * For example:
39  *
40  *  {
41       "name": "target_from_group_max",
42       "groups": [
43             {
44               "name": "zone0_ambient",
45               "interface": "xyz.openbmc_project.Sensor.Value",
46               "property": { "name": "Value" }
47             }
48           ],
49       "neg_hysteresis": 1,
50       "pos_hysteresis": 0,
51       "map": [
52             { "value": 10.0, "target": 38.0 }
53       ]
54     }
55 
56  *
57  * The above JSON will cause the action to read the property specified
58  * in the group "zone0_ambient" from all members of the group, the change
59  * in the group's members value will be checked against "neg_hysteresis"
60  * and "pos_hysteresis" to decide if it is worth taking action.
61  * "neg_hysteresis" is for the increasing case and "pos_hysteresis" is
62  * for the decreasing case. The maximum property value in a group will be
63  * mapped to the "map" to get the output "target". The updated "target"
64  * value of each group will be stored in a static map with a key. The
65  * maximum value from the static map will be used to set to the Zone's target.
66  *
67  */
68 class TargetFromGroupMax :
69     public ActionBase,
70     public ActionRegister<TargetFromGroupMax>
71 {
72   public:
73     /* Name of this action */
74     static constexpr auto name = "target_from_group_max";
75 
76     TargetFromGroupMax() = delete;
77     TargetFromGroupMax(const TargetFromGroupMax&) = delete;
78     TargetFromGroupMax(TargetFromGroupMax&&) = delete;
79     TargetFromGroupMax& operator=(const TargetFromGroupMax&) = delete;
80     TargetFromGroupMax& operator=(TargetFromGroupMax&&) = delete;
81     ~TargetFromGroupMax() = default;
82 
83     /**
84      * @brief Constructor
85      *
86      * @param[in] jsonObj - JSON configuration of this action
87      * @param[in] groups - Groups of dbus objects the action uses
88      */
89     TargetFromGroupMax(const json& jsonObj, const std::vector<Group>& groups);
90 
91     /**
92      * @brief Reads a property value from the configured group,
93      *        get the max, do mapping and get the target.
94      *
95      * @param[in] zone - Zone to run the action on
96      */
97     void run(Zone& zone) override;
98 
99   private:
100     /*The previous maximum property value from group used for checking against
101      * hysteresis*/
102     uint64_t _prevGroupValue = 0;
103 
104     /*The table of maximum speed derived from each group using this action*/
105     static std::map<size_t, uint64_t> _speedFromGroupsMap;
106 
107     /*The group index counter*/
108     static size_t _groupIndexCounter;
109 
110     /*The Hysteresis parameters from config*/
111     uint64_t _negHysteresis = 0;
112     uint64_t _posHysteresis = 0;
113 
114     /*The group index from config*/
115     size_t _groupIndex = 0;
116 
117     /*The mapping table from config*/
118     std::map<uint64_t, uint64_t> _valueToSpeedMap;
119 
120     /**
121      * @brief Read the hysteresis parameters from the JSON
122      *
123      * @param[in] jsonObj - JSON configuration of this action
124      */
125     void setHysteresis(const json& jsonObj);
126 
127     /**
128      * @brief Set index for the group
129      *
130      * @param[in] jsonObj - JSON configuration of this action
131      */
132     void setIndex();
133 
134     /**
135      * @brief Read the map from the JSON
136      *
137      * @param[in] jsonObj - JSON configuration of this action
138      */
139     void setMap(const json& jsonObj);
140 
141     /**
142      * @brief Process through all groups of the event and return the maximum
143      * property value
144      *
145      * @param[in] jsonObj - JSON configuration of this action
146      */
147     std::optional<PropertyVariantType> processGroups();
148 };
149 
150 } // namespace phosphor::fan::control::json
151