1 /**
2  * Copyright © 2022 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 #pragma once
17 
18 #include "../zone.hpp"
19 #include "action.hpp"
20 #include "group.hpp"
21 
22 #include <nlohmann/json.hpp>
23 
24 namespace phosphor::fan::control::json
25 {
26 
27 using json = nlohmann::json;
28 
29 /**
30  * @class OverrideFanTarget - Action to override fan targets
31  *
32  * This action locks fans at configured targets when the configured `count`
33  * amount of fans meet criterion for the particular condition. A locked fan
34  * maintains its override target until unlocked (or locked at a higher target).
35  * Upon unlocking, it will either revert to temperature control or activate the
36  * the next-highest target remaining in its list of locks.
37  *
38  * The following config will set all fans in the zone to a target of 9999 if
39  * either fan has a properties_changed event where the Functional property goes
40  * false. The count value of 1 means it only requires one fan, the state value
41  * of false means Functional should go to false to be counted. The signal is
42  * declared under the "triggers" section.
43 
44 [
45   {
46     "name": "test",
47     "groups": [
48       { "name": "fan0 sensor inventory", "interface":
49 "xyz.openbmc_project.State.Decorator.OperationalStatus", "property": { "name":
50 "Functional" } }
51     ],
52     "triggers": [
53       { "class": "init", "method": "get_properties" },
54       { "class": "signal", "signal": "properties_changed" }
55     ],
56     "actions": [ {
57       "name": "override_fan_target",
58       "count": 1,
59       "state": false,
60       "fans": [ "fan0", "fan1", "fan2", "fan3" ],
61       "target": 9999
62     } ]
63   }
64 ]
65  */
66 
67 class OverrideFanTarget :
68     public ActionBase,
69     public ActionRegister<OverrideFanTarget>
70 {
71   public:
72     /* Name of this action */
73     static constexpr auto name = "override_fan_target";
74 
75     OverrideFanTarget() = delete;
76     OverrideFanTarget(const OverrideFanTarget&) = delete;
77     OverrideFanTarget(OverrideFanTarget&&) = delete;
78     OverrideFanTarget& operator=(const OverrideFanTarget&) = delete;
79     OverrideFanTarget& operator=(OverrideFanTarget&&) = delete;
80     ~OverrideFanTarget() = default;
81 
82     /**
83      * @brief Set target when a number of members are at a given state
84      *
85      * @param[in] jsonObj - JSON configuration of this action
86      * @param[in] groups - Groups of dbus objects the action uses
87      */
88     OverrideFanTarget(const json& jsonObj, const std::vector<Group>& groups);
89 
90     /**
91      * @brief Run the action
92      *
93      * Counts the number of members within a group are at or above
94      * the given state. The fans are held at the configured target
95      * until the number of members equal to the given state falls
96      * below the provided count.
97      *
98      * @param[in] zone - Zone to run the action on
99      */
100     void run(Zone& zone) override;
101 
102   private:
103     /* action will be triggered when enough group members equal this state*/
104     PropertyVariantType _state;
105 
106     /* how many group members required to be at _state to trigger action*/
107     size_t _count;
108 
109     /* target for this action */
110     uint64_t _target;
111 
112     /* store locked state to know when to unlock */
113     bool _locked = false;
114 
115     /* which fans this action applies to */
116     std::vector<std::string> _fans;
117 
118     /**
119      * @brief lock all fans in this action
120      *
121      * @param[in] Zone - zone in which _fans are found
122      *
123      */
124     void lockFans(Zone& zone);
125 
126     /**
127      * @brief unlock all fans in this action
128      *
129      * @param[in] Zone - zone which _fans are found
130      *
131      */
132     void unlockFans(Zone& zone);
133 
134     /**
135      * @brief Parse and set the count
136      *
137      * @param[in] jsonObj - JSON object for the action
138      *
139      * Sets the number of members that must equal the state
140      */
141     void setCount(const json& jsonObj);
142 
143     /**
144      * @brief Parse and set the state
145      *
146      * @param[in] jsonObj - JSON object for the action
147      *
148      * Sets the state for each member to equal to set the target
149      */
150     void setState(const json& jsonObj);
151 
152     /**
153      * @brief Parse and set the target
154      *
155      * @param[in] jsonObj - JSON object for the action
156      *
157      * Sets the target to use when running the action
158      */
159     void setTarget(const json& jsonObj);
160 
161     /**
162      * @brief Parse and set the fans
163      *
164      * @param[in] jsonObj - JSON object for the action
165      *
166      * Sets the fan list the action applies to
167      */
168     void setFans(const json& jsonObj);
169 };
170 
171 } // namespace phosphor::fan::control::json
172