| #include "tlbmc/hal/sysfs/led.h" |
| |
| #include <cstdint> |
| #include <fstream> |
| #include <string> |
| #include <vector> |
| |
| #include "absl/log/log.h" |
| #include "absl/status/status.h" |
| #include "absl/status/statusor.h" |
| #include "absl/strings/numbers.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/strings/str_split.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/strings/strip.h" |
| #include "boost/filesystem.hpp" // NOLINT: boost::filesystem is commonly used in BMC |
| |
| namespace milotic_tlbmc { |
| namespace { |
| |
| std::string GetLedAttributePath(absl::string_view sysfs_path, |
| absl::string_view led_name, |
| absl::string_view attribute) { |
| return absl::StrCat(sysfs_path, led_name, "/", attribute); |
| } |
| |
| absl::StatusOr<uint32_t> ReadUint32FromFile(const std::string& path) { |
| std::ifstream file(path); |
| if (!file.good()) { |
| return absl::InternalError(absl::StrCat("Failed to open ", path)); |
| } |
| |
| std::string content; |
| std::getline(file, content); |
| if (!file.good() && !file.eof()) { |
| return absl::InternalError(absl::StrCat("Failed to read from ", path)); |
| } |
| |
| uint32_t value; |
| if (!absl::SimpleAtoi(content, &value)) { |
| return absl::InternalError( |
| absl::StrCat("Failed to parse integer from '", content, "' in ", path)); |
| } |
| |
| return value; |
| } |
| |
| absl::Status WriteUint32ToFile(const std::string& path, uint32_t value) { |
| std::ofstream file(path); |
| if (!file.good()) { |
| return absl::InternalError(absl::StrCat("Failed to open ", path)); |
| } |
| |
| file << value << "\n"; |
| file.flush(); |
| |
| if (!file.good()) { |
| return absl::InternalError(absl::StrCat("Failed to write to ", path)); |
| } |
| |
| return absl::OkStatus(); |
| } |
| |
| absl::Status WriteStringToFile(const std::string& path, |
| absl::string_view value) { |
| std::ofstream file(path); |
| if (!file.good()) { |
| return absl::InternalError(absl::StrCat("Failed to open ", path)); |
| } |
| |
| file << value << "\n"; |
| file.flush(); |
| |
| if (!file.good()) { |
| return absl::InternalError(absl::StrCat("Failed to write to ", path)); |
| } |
| |
| return absl::OkStatus(); |
| } |
| |
| } // namespace |
| |
| bool LedSysfs::IsLedPresent(absl::string_view led_name) const { |
| boost::filesystem::path path(absl::StrCat(config_.led_sysfs_path, led_name)); |
| boost::system::error_code ec; |
| bool exists = boost::filesystem::exists(path, ec); |
| if (ec) { |
| LOG(ERROR) << "Error checking exists for path '" << path |
| << "': " << ec.message(); |
| return false; |
| } |
| return exists; |
| } |
| |
| absl::StatusOr<uint32_t> LedSysfs::GetBrightness( |
| absl::string_view led_name) const { |
| return ReadUint32FromFile( |
| GetLedAttributePath(config_.led_sysfs_path, led_name, "brightness")); |
| } |
| |
| absl::Status LedSysfs::SetBrightness(absl::string_view led_name, |
| uint32_t brightness) const { |
| return WriteUint32ToFile( |
| GetLedAttributePath(config_.led_sysfs_path, led_name, "brightness"), |
| brightness); |
| } |
| |
| absl::StatusOr<uint32_t> LedSysfs::GetMaxBrightness( |
| absl::string_view led_name) const { |
| return ReadUint32FromFile( |
| GetLedAttributePath(config_.led_sysfs_path, led_name, "max_brightness")); |
| } |
| |
| absl::StatusOr<std::string> LedSysfs::GetTrigger( |
| absl::string_view led_name) const { |
| std::string path = |
| GetLedAttributePath(config_.led_sysfs_path, led_name, "trigger"); |
| std::ifstream file(path); |
| if (!file.good()) { |
| return absl::InternalError(absl::StrCat("Failed to open ", path)); |
| } |
| |
| std::string content; |
| std::getline(file, content); |
| if (!file.good() && !file.eof()) { |
| return absl::InternalError(absl::StrCat("Failed to read from ", path)); |
| } |
| |
| // The active trigger is enclosed in brackets: "none [timer] heartbeat" |
| // Find the bracketed trigger. |
| auto start = content.find('['); |
| auto end = content.find(']'); |
| if (start == std::string::npos || end == std::string::npos || end <= start) { |
| return absl::InternalError(absl::StrCat( |
| "Failed to parse active trigger from '", content, "' in ", path)); |
| } |
| |
| return content.substr(start + 1, end - start - 1); |
| } |
| |
| absl::StatusOr<std::vector<std::string>> LedSysfs::GetAvailableTriggers( |
| absl::string_view led_name) const { |
| std::string path = |
| GetLedAttributePath(config_.led_sysfs_path, led_name, "trigger"); |
| std::ifstream file(path); |
| if (!file.good()) { |
| return absl::InternalError(absl::StrCat("Failed to open ", path)); |
| } |
| |
| std::string content; |
| std::getline(file, content); |
| if (!file.good() && !file.eof()) { |
| return absl::InternalError(absl::StrCat("Failed to read from ", path)); |
| } |
| |
| // Split by whitespace, stripping brackets from the active trigger. |
| std::vector<std::string> triggers; |
| for (absl::string_view token : |
| absl::StrSplit(content, ' ', absl::SkipEmpty())) { |
| absl::string_view stripped = token; |
| absl::ConsumePrefix(&stripped, "["); |
| absl::ConsumeSuffix(&stripped, "]"); |
| triggers.emplace_back(stripped); |
| } |
| |
| return triggers; |
| } |
| |
| absl::Status LedSysfs::SetTrigger(absl::string_view led_name, |
| absl::string_view trigger) const { |
| return WriteStringToFile( |
| GetLedAttributePath(config_.led_sysfs_path, led_name, "trigger"), |
| trigger); |
| } |
| |
| absl::StatusOr<uint32_t> LedSysfs::GetDelayOn( |
| absl::string_view led_name) const { |
| return ReadUint32FromFile( |
| GetLedAttributePath(config_.led_sysfs_path, led_name, "delay_on")); |
| } |
| |
| absl::Status LedSysfs::SetDelayOn(absl::string_view led_name, |
| uint32_t delay_ms) const { |
| return WriteUint32ToFile( |
| GetLedAttributePath(config_.led_sysfs_path, led_name, "delay_on"), |
| delay_ms); |
| } |
| |
| absl::StatusOr<uint32_t> LedSysfs::GetDelayOff( |
| absl::string_view led_name) const { |
| return ReadUint32FromFile( |
| GetLedAttributePath(config_.led_sysfs_path, led_name, "delay_off")); |
| } |
| |
| absl::Status LedSysfs::SetDelayOff(absl::string_view led_name, |
| uint32_t delay_ms) const { |
| return WriteUint32ToFile( |
| GetLedAttributePath(config_.led_sysfs_path, led_name, "delay_off"), |
| delay_ms); |
| } |
| |
| } // namespace milotic_tlbmc |