blob: e519fa5a44751fd50483dd447e7e361383e9e6c0 [file] [log] [blame]
Shawn McCarneyc69a2752019-10-30 17:37:30 -05001/**
2 * Copyright © 2019 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 "device.hpp"
19#include "id_map.hpp"
20#include "rule.hpp"
21
22#include <cstddef> // for size_t
23#include <stdexcept>
24#include <string>
25
Shawn McCarneyea7385b2019-11-07 12:19:32 -060026namespace phosphor::power::regulators
Shawn McCarneyc69a2752019-10-30 17:37:30 -050027{
28
29/**
30 * @class ActionEnvironment
31 *
32 * The current environment when executing actions.
33 *
34 * The ActionEnvironment contains the following information:
35 * - current device ID
36 * - current volts value (if any)
37 * - mapping from device and rule IDs to the corresponding objects
38 * - rule call stack depth (to detect infinite recursion)
39 */
40class ActionEnvironment
41{
42 public:
43 // Specify which compiler-generated methods we want
44 ActionEnvironment() = delete;
45 ActionEnvironment(const ActionEnvironment&) = delete;
46 ActionEnvironment(ActionEnvironment&&) = delete;
47 ActionEnvironment& operator=(const ActionEnvironment&) = delete;
48 ActionEnvironment& operator=(ActionEnvironment&&) = delete;
49 ~ActionEnvironment() = default;
50
51 /**
52 * Maximum rule call stack depth. Used to detect infinite recursion.
53 */
54 static constexpr size_t maxRuleDepth{30};
55
56 /**
57 * Constructor.
58 *
59 * @param idMap mapping from IDs to the associated Device/Rule objects
60 * @param deviceID current device ID
61 */
62 explicit ActionEnvironment(const IDMap& idMap,
63 const std::string& deviceID) :
64 idMap{idMap},
65 deviceID{deviceID}
66 {
67 }
68
69 /**
70 * Decrements the rule call stack depth by one.
71 *
72 * Should be used when a call to a rule returns. Does nothing if depth is
73 * already 0.
74 */
75 void decrementRuleDepth()
76 {
77 if (ruleDepth > 0)
78 {
79 --ruleDepth;
80 }
81 }
82
83 /**
84 * Returns the device with the current device ID.
85 *
86 * Throws invalid_argument if no device is found with current ID.
87 *
88 * @return device with current device ID
89 */
90 Device& getDevice() const
91 {
92 return idMap.getDevice(deviceID);
93 }
94
95 /**
96 * Returns the current device ID.
97 *
98 * @return current device ID
99 */
100 const std::string& getDeviceID() const
101 {
102 return deviceID;
103 }
104
105 /**
106 * Returns the rule with the specified ID.
107 *
108 * Throws invalid_argument if no rule is found with specified ID.
109 *
110 * @param id rule ID
111 * @return rule with specified ID
112 */
113 Rule& getRule(const std::string& id) const
114 {
115 return idMap.getRule(id);
116 }
117
118 /**
119 * Returns the current rule call stack depth.
120 *
121 * The depth is 0 if no rules have been called.
122 *
123 * @return rule call stack depth
124 */
125 size_t getRuleDepth() const
126 {
127 return ruleDepth;
128 }
129
130 /**
131 * Returns the current volts value.
132 *
133 * Call hasVolts() first to check whether a volts value has been set.
134 *
135 * Throws logic_error if no volts value has been set.
136 *
137 * @return current volts value
138 */
139 double getVolts() const
140 {
141 if (!hasVoltsValue)
142 {
143 throw std::logic_error{"No volts value has been set."};
144 }
145 return volts;
146 }
147
148 /**
149 * Returns whether a volts value has been set.
150 *
151 * @return true if a volts value has been set, false otherwise
152 */
153 bool hasVolts() const
154 {
155 return hasVoltsValue;
156 }
157
158 /**
159 * Increments the rule call stack depth by one.
160 *
161 * Should be used when a rule is called.
162 *
163 * Throws runtime_error if the new depth exceeds maxRuleDepth. This
164 * indicates that infinite recursion has probably occurred (rule A -> rule B
165 * -> rule A).
166 */
167 void incrementRuleDepth()
168 {
169 if (ruleDepth >= maxRuleDepth)
170 {
171 throw std::runtime_error("Maximum rule depth exceeded.");
172 }
173 ++ruleDepth;
174 }
175
176 /**
177 * Sets the current device ID.
178 *
179 * @param id device ID
180 */
181 void setDeviceID(const std::string& id)
182 {
183 deviceID = id;
184 }
185
186 /**
187 * Sets the current volts value.
188 *
189 * @param volts new volts value.
190 */
191 void setVolts(double volts)
192 {
193 this->volts = volts;
194 hasVoltsValue = true;
195 }
196
197 private:
198 /**
199 * Mapping from string IDs to the associated Device and Rule objects.
200 */
201 const IDMap& idMap{};
202
203 /**
204 * Current device ID.
205 */
206 std::string deviceID{};
207
208 /**
209 * Indicates whether a volts value has been set.
210 */
211 bool hasVoltsValue{false};
212
213 /**
214 * Current volts value (if set).
215 */
216 double volts{0};
217
218 /**
219 * Rule call stack depth.
220 */
221 size_t ruleDepth{0};
222};
223
Shawn McCarneyea7385b2019-11-07 12:19:32 -0600224} // namespace phosphor::power::regulators