blob: 6cb0be06b1276e4219f507abff183007cfbee0bd [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 "tlbmc/central_config/config.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/
absl::StatusOr<boost::filesystem::path> hwmon_path =
I2cHwmonBasedSensor::CreateDeviceAndReturnsHwmonPath(
i2c_common_config, driver_name, i2c_sysfs);
if (!hwmon_path.ok()) {
if (!GetTlbmcConfig()
.sensor_collector_module()
.allow_sensor_creation_failure()) {
return hwmon_path.status();
}
LOG(ERROR) << "Failed to create FanController (NONFATAL): "
<< hwmon_path.status();
return std::make_shared<FanController>(
Token(), config, std::unordered_map<uint32_t, Tachometers>(),
std::unordered_map<uint32_t, Pwm>());
}
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