blob: 9373518f3a3c1d526d7ad802a42ffded74a8aa21 [file] [log] [blame]
#ifndef THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_SENSORS_PSU_SENSOR_H_
#define THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_SENSORS_PSU_SENSOR_H_
#include <array>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
#include <vector>
#include "absl/base/thread_annotations.h"
#include "absl/status/statusor.h"
#include "boost/asio.hpp" //NOLINT: boost::asio is commonly used in BMC
#include "boost/circular_buffer.hpp" //NOLINT: boost is commonly used in BMC
#include "entity_common_config.pb.h"
#include "i2c_common_config.pb.h"
#include "psu_sensor_config.pb.h"
#include "reading_range_config.pb.h"
#include "reading_transform_config.pb.h"
#include "threshold_config.pb.h"
#include "tlbmc/hal/sysfs/i2c.h"
#include "sensor.pb.h"
#include "tlbmc/sensors/i2c_hwmon_based_sensor.h"
#include "tlbmc/sensors/sensor.h"
namespace milotic_tlbmc {
constexpr std::string_view kLabelSuffix = "_label";
/*
The following is the framework for adding different types of PSU sensors.
To add a new sensor type please do the following:
1. Add the new sensor type to the PsuSensorType enum below
2. Add the new sensor type to the kDefaultPsuSensorProperties array in
psu_sensor.cc.
3. Add the new sensor file suffix to the kPsuSensorFileSuffixes array below
4. Add the new sensor label prefix to the kPsuSensorFilePrefixes array below
Example:
The peak power input file is found with a file that has the suffix
"_input_highest". In the EM config file, we attach the prefix "highest" to the
label to expose that sensor.
*/
enum class PsuSensorFileType : uint8_t {
kDefault = 0, // This is the default [sensor]_input file.
kHighestPower, // Power sensors have a special file for highest power:
// [power]_input_highest.
kUnknown, // Non-standard sensor file.
};
constexpr std::array<std::string_view,
static_cast<size_t>(PsuSensorFileType::kUnknown)>
kPsuSensorFileSuffixes = {"_input", "_input_highest"};
constexpr std::array<std::string_view,
static_cast<size_t>(PsuSensorFileType::kUnknown)>
kPsuSensorLabelPrefixes = {"", "highest"};
struct PsuSensorFileInfo {
std::string file_prefix;
PsuSensorFileType file_type;
};
class PsuSensor : public I2cHwmonBasedSensor {
private:
class Token;
public:
struct ReadingProperties {
std::string_view label_type_name;
double max_reading;
double min_reading;
double scale;
double offset;
SensorUnit sensor_unit;
bool operator==(const ReadingProperties& other) const {
return std::tie(max_reading, min_reading, scale, offset, sensor_unit) ==
std::tie(other.max_reading, other.min_reading, other.scale,
other.offset, sensor_unit);
}
};
// Load the device if not already loaded and returns a list of sensors that
// can be used to read the temperature from the device. Note:
// 1. The `io_context` must run only on a single thread.
static absl::StatusOr<std::vector<std::shared_ptr<Sensor>>> Create(
const PsuSensorConfig& config,
const std::shared_ptr<boost::asio::io_context>& io_context,
const I2cSysfs& i2c_sysfs,
std::optional<NotificationCb> on_batch_notify = std::nullopt);
PsuSensor(Token token, PsuSensorType sensor_type, SensorUnit sensor_unit,
const std::string& input_dev_path, const std::string& sensor_name,
const I2cCommonConfig& i2c_common_config,
const ThresholdConfigs& threshold_configs,
const ReadingRangeConfigs& reading_range_configs,
const ReadingTransformConfig& reading_transform_config,
const EntityCommonConfig& entity_common_config,
const std::shared_ptr<boost::asio::io_context>& io_context,
std::optional<NotificationCb> on_batch_notify);
~PsuSensor() override = default;
void HandleRefreshResult(const boost::system::error_code& error,
size_t bytes_read) override
ABSL_LOCKS_EXCLUDED(sensor_data_mutex_);
protected:
PsuSensor() = default;
// Returns the driver name for the given sensor type.
static absl::StatusOr<std::string_view> GetDriverName(
PsuSensorType sensor_type);
// Given the config and the properties of the sensor, returns the reading
// range configs.
static absl::StatusOr<ReadingRangeConfigs> GetReadingRangeConfigs(
const ReadingRangeConfigs& configs, const ReadingProperties& properties);
// Given a label with digits (e.g., "vout1"), returns the default reading
// properties of the sensor.
static absl::StatusOr<ReadingProperties> GetPsuSensorProperties(
std::string_view label);
// Given an label, returns the unit of the sensor.
static absl::StatusOr<SensorUnit> GetSensorUnit(std::string_view label);
static std::string ApplyLabelModifications(std::string_view label,
PsuSensorFileType file_type);
static absl::StatusOr<std::string> ParseLabelFile(
const boost::filesystem::path& hwmon_path, std::string_view file_prefix);
// Given a sensor name, performs the transformation to append sensor unit and
// create a unique name for the sensor.
static std::string GetPsuSensorKey(std::string_view name,
const PsuSensorConfig& config,
PsuSensor::ReadingProperties properties);
// Get the contents of the label of the sensor.
static std::string GetLabel(const boost::filesystem::path& hwmon_path,
std::string_view file_prefix,
PsuSensorFileType file_type);
static PsuSensorFileInfo GetPsuSensorFileInfo(std::string_view input_file);
private:
class Token {
private:
explicit Token() = default;
friend PsuSensor;
};
const PsuSensorType sensor_type_ = PSU_SENSOR_TYPE0_UNKNOWN;
const std::string sensor_name_;
const std::string board_config_name_;
};
} // namespace milotic_tlbmc
#endif // THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_SENSORS_PSU_SENSOR_H_