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