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 #include "phase_fault.hpp" 20 #include "services.hpp" 21 22 #include <cstddef> // for size_t 23 #include <map> 24 #include <optional> 25 #include <set> 26 #include <stdexcept> 27 #include <string> 28 29 namespace phosphor::power::regulators 30 { 31 32 // Forward declarations to avoid circular dependencies 33 class Device; 34 class Rule; 35 36 /** 37 * @class ActionEnvironment 38 * 39 * The current environment when executing actions. 40 * 41 * The ActionEnvironment contains the following information: 42 * - current device ID 43 * - current volts value (if any) 44 * - mapping from device and rule IDs to the corresponding objects 45 * - rule call stack depth (to detect infinite recursion) 46 * - reference to system services 47 * - faults detected by actions (if any) 48 * - additional error data captured by actions (if any) 49 */ 50 class ActionEnvironment 51 { 52 public: 53 // Specify which compiler-generated methods we want 54 ActionEnvironment() = delete; 55 ActionEnvironment(const ActionEnvironment&) = delete; 56 ActionEnvironment(ActionEnvironment&&) = delete; 57 ActionEnvironment& operator=(const ActionEnvironment&) = delete; 58 ActionEnvironment& operator=(ActionEnvironment&&) = delete; 59 ~ActionEnvironment() = default; 60 61 /** 62 * Maximum rule call stack depth. Used to detect infinite recursion. 63 */ 64 static constexpr size_t maxRuleDepth{30}; 65 66 /** 67 * Constructor. 68 * 69 * @param idMap mapping from IDs to the associated Device/Rule objects 70 * @param deviceID current device ID 71 * @param services system services like error logging and the journal 72 */ 73 explicit ActionEnvironment(const IDMap& idMap, const std::string& deviceID, 74 Services& services) : 75 idMap{idMap}, 76 deviceID{deviceID}, services{services} 77 {} 78 79 /** 80 * Adds the specified key/value pair to the map of additional error data 81 * that has been captured. 82 * 83 * This data provides more information about an error and will be stored in 84 * the error log. 85 * 86 * @param key key name 87 * @param value value expressed as a string 88 */ 89 void addAdditionalErrorData(const std::string& key, 90 const std::string& value) 91 { 92 additionalErrorData.emplace(key, value); 93 } 94 95 /** 96 * Adds the specified phase fault to the set of faults that have been 97 * detected. 98 * 99 * @param type phase fault type 100 */ 101 void addPhaseFault(PhaseFaultType type) 102 { 103 phaseFaults.emplace(type); 104 } 105 106 /** 107 * Decrements the rule call stack depth by one. 108 * 109 * Should be used when a call to a rule returns. Does nothing if depth is 110 * already 0. 111 */ 112 void decrementRuleDepth() 113 { 114 if (ruleDepth > 0) 115 { 116 --ruleDepth; 117 } 118 } 119 120 /** 121 * Returns the additional error data that has been captured (if any). 122 * 123 * @return additional error data 124 */ 125 const std::map<std::string, std::string>& getAdditionalErrorData() const 126 { 127 return additionalErrorData; 128 } 129 130 /** 131 * Returns the device with the current device ID. 132 * 133 * Throws invalid_argument if no device is found with current ID. 134 * 135 * @return device with current device ID 136 */ 137 Device& getDevice() const 138 { 139 return idMap.getDevice(deviceID); 140 } 141 142 /** 143 * Returns the current device ID. 144 * 145 * @return current device ID 146 */ 147 const std::string& getDeviceID() const 148 { 149 return deviceID; 150 } 151 152 /** 153 * Returns the set of phase faults that have been detected (if any). 154 * 155 * @return phase faults detected 156 */ 157 const std::set<PhaseFaultType>& getPhaseFaults() const 158 { 159 return phaseFaults; 160 } 161 162 /** 163 * Returns the rule with the specified ID. 164 * 165 * Throws invalid_argument if no rule is found with specified ID. 166 * 167 * @param id rule ID 168 * @return rule with specified ID 169 */ 170 Rule& getRule(const std::string& id) const 171 { 172 return idMap.getRule(id); 173 } 174 175 /** 176 * Returns the current rule call stack depth. 177 * 178 * The depth is 0 if no rules have been called. 179 * 180 * @return rule call stack depth 181 */ 182 size_t getRuleDepth() const 183 { 184 return ruleDepth; 185 } 186 187 /** 188 * Returns the services in this action environment. 189 * 190 * @return system services 191 */ 192 Services& getServices() const 193 { 194 return services; 195 } 196 197 /** 198 * Returns the current volts value, if set. 199 * 200 * @return current volts value 201 */ 202 std::optional<double> getVolts() const 203 { 204 return volts; 205 } 206 207 /** 208 * Increments the rule call stack depth by one. 209 * 210 * Should be used when a rule is called. 211 * 212 * Throws runtime_error if the new depth exceeds maxRuleDepth. This 213 * indicates that infinite recursion has probably occurred (rule A -> rule B 214 * -> rule A). 215 * 216 * @param ruleID ID of the rule that is being called 217 */ 218 void incrementRuleDepth(const std::string& ruleID) 219 { 220 if (ruleDepth >= maxRuleDepth) 221 { 222 throw std::runtime_error("Maximum rule depth exceeded by rule " + 223 ruleID + '.'); 224 } 225 ++ruleDepth; 226 } 227 228 /** 229 * Sets the current device ID. 230 * 231 * @param id device ID 232 */ 233 void setDeviceID(const std::string& id) 234 { 235 deviceID = id; 236 } 237 238 /** 239 * Sets the current volts value. 240 * 241 * @param volts new volts value. 242 */ 243 void setVolts(double volts) 244 { 245 this->volts = volts; 246 } 247 248 private: 249 /** 250 * Mapping from string IDs to the associated Device and Rule objects. 251 */ 252 const IDMap& idMap; 253 254 /** 255 * Current device ID. 256 */ 257 std::string deviceID{}; 258 259 /** 260 * System services like error logging and the journal. 261 */ 262 Services& services; 263 264 /** 265 * Current volts value (if set). 266 */ 267 std::optional<double> volts{}; 268 269 /** 270 * Rule call stack depth. 271 */ 272 size_t ruleDepth{0}; 273 274 /** 275 * Redundant phase faults that have been detected. 276 */ 277 std::set<PhaseFaultType> phaseFaults{}; 278 279 /** 280 * Additional error data that has been captured. 281 */ 282 std::map<std::string, std::string> additionalErrorData{}; 283 }; 284 285 } // namespace phosphor::power::regulators 286