blob: 3cf997a6766d9644b164445f8f52d28563dffcdf [file] [log] [blame]
#include "tlbmc/sensors/fan_controller.h"
#include <sys/types.h>
#include <algorithm>
#include <array>
#include <cstdint>
#include <memory>
#include <string>
#include <string_view>
#include <unordered_map>
#include <utility>
#include "absl/log/log.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/match.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/substitute.h"
#include "g3/macros.h"
#include "fan_controller_config.pb.h"
#include "tlbmc/hal/sysfs/i2c.h"
#include "tlbmc/sensors/i2c_hwmon_based_sensor.h"
#include "re2/re2.h"
namespace milotic_tlbmc {
template <class TypeName>
struct TypeComparator {
// Compared by the first element which is the type name.
bool operator()(const std::pair<FanControllerType, TypeName>& lhs,
const std::pair<FanControllerType, TypeName>& rhs) const {
return lhs.first < rhs.first;
}
};
constexpr std::array<std::pair<FanControllerType, std::string_view>, 1>
kSupportedFanControllerTypes = {
// go/keep-sorted start
{{FAN_CONTROLLER_TYPE_MAX31790, "max31790"}}
// go/keep-sorted end
};
FanController::FanController(
Token token, const FanControllerConfig& config,
const std::unordered_map<uint32_t, Tachometers>& tachs,
const std::unordered_map<uint32_t, Pwm>& pwms)
: config_(config), index_to_tachs_(tachs), index_to_pwms_(pwms) {}
absl::StatusOr<std::string_view> FanController::GetDriverName(
FanControllerType type) {
const auto* it = std::lower_bound(
kSupportedFanControllerTypes.begin(), kSupportedFanControllerTypes.end(),
std::pair<FanControllerType, std::string_view>{type, ""},
TypeComparator<std::string_view>());
if (it == kSupportedFanControllerTypes.end() || it->first != type) {
return absl::InvalidArgumentError(
absl::Substitute("Unsupported fan controller type: $0", type));
}
return it->second;
}
absl::StatusOr<std::shared_ptr<FanController>> FanController::Create(
const FanControllerConfig& config, const I2cSysfs& i2c_sysfs) {
DLOG(INFO) << "Creating FanController for device: " << absl::StrCat(config);
const I2cCommonConfig& i2c_common_config = config.i2c_common_config();
ECCLESIA_ASSIGN_OR_RETURN(std::string_view driver_name,
GetDriverName(config.type()));
// E.g., /sys/bus/i2c/devices/i2c-19/19-002c/hwmon/hwmon9/
ECCLESIA_ASSIGN_OR_RETURN(
boost::filesystem::path hwmon_path,
I2cHwmonBasedSensor::CreateDeviceAndReturnsHwmonPath(
i2c_common_config, driver_name, i2c_sysfs));
std::unordered_map<uint32_t, Tachometers> tachs;
std::unordered_map<uint32_t, Pwm> pwms;
for (const auto& entry : boost::filesystem::directory_iterator(hwmon_path)) {
std::string entry_path_str = entry.path().filename().string();
std::string_view entry_path = entry_path_str;
constexpr std::string_view kFanTachPrefix = "fan";
constexpr std::string_view kFanTachSuffix = "_input";
if (absl::StartsWith(entry_path, kFanTachPrefix) &&
absl::EndsWith(entry_path, kFanTachSuffix)) {
std::string_view index = entry_path.substr(
kFanTachPrefix.size(),
entry_path.size() - kFanTachPrefix.size() - kFanTachSuffix.size());
uint32_t index_int;
if (!absl::SimpleAtoi(index, &index_int)) {
return absl::InternalError(absl::Substitute(
"Failed to convert fan tach index to int: $0", index));
}
tachs[index_int].tach_input = entry;
}
constexpr std::string_view kPwmPrefix = "pwm";
constexpr std::string_view kPwmEnableSuffix = "_enable";
uint32_t index_int;
if (RE2::FullMatch(entry_path, absl::StrCat(kPwmPrefix, "(\\d+)"),
&index_int)) {
pwms[index_int].pwm = entry;
}
if (absl::StartsWith(entry_path, kPwmPrefix) &&
absl::EndsWith(entry_path, kPwmEnableSuffix)) {
std::string_view index = entry_path.substr(
kPwmPrefix.size(),
entry_path.size() - kPwmPrefix.size() - kPwmEnableSuffix.size());
if (!absl::SimpleAtoi(index, &index_int)) {
return absl::InternalError(absl::Substitute(
"Failed to convert pwm enable index to int: $0", index));
}
pwms[index_int].pwm_enable = entry;
}
}
return std::make_shared<FanController>(Token(), config, std::move(tachs),
std::move(pwms));
}
} // namespace milotic_tlbmc