blob: 265a7bf33fdad42b15965592a85e5438aea404f0 [file] [log] [blame]
/**
* Copyright © 2019 IBM Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "id_map.hpp"
#include "phase_fault.hpp"
#include "services.hpp"
#include <cstddef> // for size_t
#include <map>
#include <optional>
#include <set>
#include <stdexcept>
#include <string>
namespace phosphor::power::regulators
{
// Forward declarations to avoid circular dependencies
class Device;
class Rule;
/**
* @class ActionEnvironment
*
* The current environment when executing actions.
*
* The ActionEnvironment contains the following information:
* - current device ID
* - current volts value (if any)
* - mapping from device and rule IDs to the corresponding objects
* - rule call stack depth (to detect infinite recursion)
* - reference to system services
* - faults detected by actions (if any)
* - additional error data captured by actions (if any)
*/
class ActionEnvironment
{
public:
// Specify which compiler-generated methods we want
ActionEnvironment() = delete;
ActionEnvironment(const ActionEnvironment&) = delete;
ActionEnvironment(ActionEnvironment&&) = delete;
ActionEnvironment& operator=(const ActionEnvironment&) = delete;
ActionEnvironment& operator=(ActionEnvironment&&) = delete;
~ActionEnvironment() = default;
/**
* Maximum rule call stack depth. Used to detect infinite recursion.
*/
static constexpr size_t maxRuleDepth{30};
/**
* Constructor.
*
* @param idMap mapping from IDs to the associated Device/Rule objects
* @param deviceID current device ID
* @param services system services like error logging and the journal
*/
explicit ActionEnvironment(const IDMap& idMap, const std::string& deviceID,
Services& services) :
idMap{idMap},
deviceID{deviceID}, services{services}
{}
/**
* Adds the specified key/value pair to the map of additional error data
* that has been captured.
*
* This data provides more information about an error and will be stored in
* the error log.
*
* @param key key name
* @param value value expressed as a string
*/
void addAdditionalErrorData(const std::string& key,
const std::string& value)
{
additionalErrorData.emplace(key, value);
}
/**
* Adds the specified phase fault to the set of faults that have been
* detected.
*
* @param type phase fault type
*/
void addPhaseFault(PhaseFaultType type)
{
phaseFaults.emplace(type);
}
/**
* Decrements the rule call stack depth by one.
*
* Should be used when a call to a rule returns. Does nothing if depth is
* already 0.
*/
void decrementRuleDepth()
{
if (ruleDepth > 0)
{
--ruleDepth;
}
}
/**
* Returns the additional error data that has been captured (if any).
*
* @return additional error data
*/
const std::map<std::string, std::string>& getAdditionalErrorData() const
{
return additionalErrorData;
}
/**
* Returns the device with the current device ID.
*
* Throws invalid_argument if no device is found with current ID.
*
* @return device with current device ID
*/
Device& getDevice() const
{
return idMap.getDevice(deviceID);
}
/**
* Returns the current device ID.
*
* @return current device ID
*/
const std::string& getDeviceID() const
{
return deviceID;
}
/**
* Returns the set of phase faults that have been detected (if any).
*
* @return phase faults detected
*/
const std::set<PhaseFaultType>& getPhaseFaults() const
{
return phaseFaults;
}
/**
* Returns the rule with the specified ID.
*
* Throws invalid_argument if no rule is found with specified ID.
*
* @param id rule ID
* @return rule with specified ID
*/
Rule& getRule(const std::string& id) const
{
return idMap.getRule(id);
}
/**
* Returns the current rule call stack depth.
*
* The depth is 0 if no rules have been called.
*
* @return rule call stack depth
*/
size_t getRuleDepth() const
{
return ruleDepth;
}
/**
* Returns the services in this action environment.
*
* @return system services
*/
Services& getServices() const
{
return services;
}
/**
* Returns the current volts value, if set.
*
* @return current volts value
*/
std::optional<double> getVolts() const
{
return volts;
}
/**
* Increments the rule call stack depth by one.
*
* Should be used when a rule is called.
*
* Throws runtime_error if the new depth exceeds maxRuleDepth. This
* indicates that infinite recursion has probably occurred (rule A -> rule B
* -> rule A).
*
* @param ruleID ID of the rule that is being called
*/
void incrementRuleDepth(const std::string& ruleID)
{
if (ruleDepth >= maxRuleDepth)
{
throw std::runtime_error("Maximum rule depth exceeded by rule " +
ruleID + '.');
}
++ruleDepth;
}
/**
* Sets the current device ID.
*
* @param id device ID
*/
void setDeviceID(const std::string& id)
{
deviceID = id;
}
/**
* Sets the current volts value.
*
* @param volts new volts value.
*/
void setVolts(double volts)
{
this->volts = volts;
}
private:
/**
* Mapping from string IDs to the associated Device and Rule objects.
*/
const IDMap& idMap;
/**
* Current device ID.
*/
std::string deviceID{};
/**
* System services like error logging and the journal.
*/
Services& services;
/**
* Current volts value (if set).
*/
std::optional<double> volts{};
/**
* Rule call stack depth.
*/
size_t ruleDepth{0};
/**
* Redundant phase faults that have been detected.
*/
std::set<PhaseFaultType> phaseFaults{};
/**
* Additional error data that has been captured.
*/
std::map<std::string, std::string> additionalErrorData{};
};
} // namespace phosphor::power::regulators