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