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