blob: 8cd97af95c8d894745a66dfc83ac0da8171e7b22 [file] [log] [blame]
#pragma once
#include "config.h"
#include "occ_events.hpp"
#include <unistd.h>
#include <filesystem>
#include <functional>
namespace open_power
{
namespace occ
{
namespace fs = std::filesystem;
constexpr auto PRESENCE_ERROR_PATH =
"org.open_power.OCC.Firmware.Error.PresenceMismatch";
constexpr auto SAFE_ERROR_PATH = "org.open_power.OCC.Device.Error.SafeState";
constexpr auto MISSING_OCC_SENSORS_PATH =
"org.open_power.OCC.Firmware.Error.MissingOCCSensors";
/** @class Error
* @brief Monitors for OCC device error condition
*/
class Error
{
public:
Error() = delete;
Error(const Error&) = delete;
Error& operator=(const Error&) = delete;
Error(Error&&) = default;
Error& operator=(Error&&) = default;
/** @brief Constructs the Error object
*
* @param[in] event - reference to sd_event unique_ptr
* @param[in] file - File used by driver to communicate errors
* @param[in] callBack - Optional function callback on error condition
*/
Error(EventPtr& event, const fs::path& file,
std::function<void(int)> callBack = nullptr) :
event(event), file(file), callBack(callBack)
{
// Nothing to do here.
}
virtual ~Error()
{
if (fd >= 0)
{
close(fd);
}
}
/** @class Descriptor
* @brief Contains data relevant to an error that occurred.
*/
class Descriptor
{
public:
Descriptor(const Descriptor&) = default;
Descriptor& operator=(const Descriptor&) = default;
Descriptor(Descriptor&&) = default;
Descriptor& operator=(Descriptor&&) = default;
Descriptor() : log(false), err(0), callout(nullptr), path(nullptr) {}
/** @brief Constructs the Descriptor object
*
* @param[in] path - the DBus error path
* @param[in] err - Optional error return code
* @param[in] callout - Optional PEL callout path
*/
Descriptor(const char* path, int err = 0,
const char* callout = nullptr) :
log(true), err(err), callout(callout), path(path)
{}
bool log;
int err;
const char* callout;
const char* path;
};
/** @brief Starts to monitor for error conditions
*
* @param[in] poll - Indicates whether or not the error file should
* actually be polled for changes. Disabling polling is
* necessary for error files that don't support the poll
* file operation.
*/
void addWatch(bool poll = true);
/** @brief Removes error watch */
void removeWatch();
inline void setFile(const fs::path& f)
{
file = f;
}
private:
/** @brief sd_event wrapped in unique_ptr */
EventPtr& event;
/** @brief event source wrapped in unique_ptr */
EventSourcePtr eventSource;
/** @brief Current state of error watching */
bool watching = false;
/** @brief attaches FD to events and sets up callback handler */
void registerCallBack();
/** @brief Opens the file and populates fd */
void openFile();
/** @brief Callback handler when the FD has some activity on it
*
* @param[in] es - Populated event source
* @param[in] fd - Associated File descriptor
* @param[in] revents - Type of event
* @param[in] userData - User data that was passed during registration
*
* @return - 0 or positive number on success and negative
* errno otherwise
*/
static int processEvents(sd_event_source* es, int fd, uint32_t revents,
void* userData);
/** @brief When the error event is received, analyzes it
* and makes a callback to error handler if the
* content denotes an error condition
*/
virtual void analyzeEvent();
protected:
/** @brief File descriptor to watch for errors */
int fd = -1;
/** Error file */
fs::path file;
/** @brief Optional function to call on error scenario */
std::function<void(int)> callBack;
/** @brief Reads file data
*
* @return data read. Since its a /sysfs entry,
* it would be a string
*/
std::string readFile(int) const;
};
} // namespace occ
} // namespace open_power