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