From 830c5cd5d09ed3639040b0034f3c031498bc78a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Bartoletti?= Date: Fri, 30 Sep 2022 21:59:27 +0200 Subject: [PATCH] FreeBSD: Add support to battery This commit aims to propose a FreeBSD to gain battery support using sysctl on hw.acpi.battery.* --- include/factory.hpp | 2 +- meson.build | 5 +++ src/factory.cpp | 2 +- src/modules/battery.cpp | 79 +++++++++++++++++++++++++++++++++++++++-- 4 files changed, 84 insertions(+), 4 deletions(-) diff --git a/include/factory.hpp b/include/factory.hpp index 55031b83..ca707a3c 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -27,7 +27,7 @@ #include "modules/hyprland/language.hpp" #include "modules/hyprland/window.hpp" #endif -#if defined(__linux__) && !defined(NO_FILESYSTEM) +#if defined(__FreeBSD__) || (defined(__linux__) && !defined(NO_FILESYSTEM)) #include "modules/battery.hpp" #endif #if defined(HAVE_CPU_LINUX) || defined(HAVE_CPU_BSD) diff --git a/meson.build b/meson.build index aab5a492..e537bcca 100644 --- a/meson.build +++ b/meson.build @@ -179,6 +179,11 @@ elif is_dragonfly or is_freebsd or is_netbsd or is_openbsd 'src/modules/memory/bsd.cpp', 'src/modules/memory/common.cpp', ) + if is_freebsd + src_files += files( + 'src/modules/battery.cpp', + ) + endif endif add_project_arguments('-DHAVE_SWAY', language: 'cpp') diff --git a/src/factory.cpp b/src/factory.cpp index 9b9dde89..d00a7d47 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -7,7 +7,7 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { auto hash_pos = name.find('#'); auto ref = name.substr(0, hash_pos); auto id = hash_pos != std::string::npos ? name.substr(hash_pos + 1) : ""; -#if defined(__linux__) && !defined(NO_FILESYSTEM) +#if defined(__FreeBSD__) || (defined(__linux__) && !defined(NO_FILESYSTEM)) if (ref == "battery") { return new waybar::modules::Battery(id, config_[name]); } diff --git a/src/modules/battery.cpp b/src/modules/battery.cpp index e25ad9e5..1fbdcb58 100644 --- a/src/modules/battery.cpp +++ b/src/modules/battery.cpp @@ -1,9 +1,16 @@ #include "modules/battery.hpp" - +#if defined(__FreeBSD__) +// clang-format off +#include +#include +// clang-format on +#endif #include +#include waybar::modules::Battery::Battery(const std::string& id, const Json::Value& config) : AButton(config, "battery", id, "{capacity}%", 60) { +#if defined(__Linux__) battery_watch_fd_ = inotify_init1(IN_CLOEXEC); if (battery_watch_fd_ == -1) { throw std::runtime_error("Unable to listen batteries."); @@ -19,11 +26,12 @@ waybar::modules::Battery::Battery(const std::string& id, const Json::Value& conf if (global_watch < 0) { throw std::runtime_error("Could not watch for battery plug/unplug"); } - +#endif worker(); } waybar::modules::Battery::~Battery() { +#if (__Linux__) std::lock_guard guard(battery_list_mutex_); if (global_watch >= 0) { @@ -39,9 +47,16 @@ waybar::modules::Battery::~Battery() { batteries_.erase(it); } close(battery_watch_fd_); +#endif } void waybar::modules::Battery::worker() { +#if defined(__FreeBSD__) + thread_timer_ = [this] { + dp.emit(); + thread_timer_.sleep_for(interval_); + }; +#else thread_timer_ = [this] { // Make sure we eventually update the list of batteries even if we miss an // inotify event for some reason @@ -68,9 +83,11 @@ void waybar::modules::Battery::worker() { refreshBatteries(); dp.emit(); }; +#endif } void waybar::modules::Battery::refreshBatteries() { +#if (__Linux__) std::lock_guard guard(battery_list_mutex_); // Mark existing list of batteries as not necessarily found std::map check_map; @@ -135,6 +152,7 @@ void waybar::modules::Battery::refreshBatteries() { batteries_.erase(check.first); } } +#endif } // Unknown > Full > Not charging > Discharging > Charging @@ -158,6 +176,49 @@ const std::tuple waybar::modules::Battery::g try { uint32_t total_power = 0; // μW bool total_power_exists = false; +#if defined(__FreeBSD__) + int capacity; + size_t size_capacity = sizeof capacity; + if (sysctlbyname("hw.acpi.battery.life", &capacity, &size_capacity, NULL,0) != 0) { + throw std::runtime_error("sysctl hw.acpi.battery.life failed"); + } + int time; + size_t size_time = sizeof time; + if (sysctlbyname("hw.acpi.battery.time", &time, &size_time, NULL,0) != 0) { + throw std::runtime_error("sysctl hw.acpi.battery.time failed"); + } + int rate; + size_t size_rate = sizeof rate; + if (sysctlbyname("hw.acpi.battery.rate", &rate, &size_rate, NULL,0) != 0) { + throw std::runtime_error("sysctl hw.acpi.battery.rate failed"); + } + + auto status = getAdapterStatus(capacity); + // Handle full-at + if (config_["full-at"].isUInt()) { + auto full_at = config_["full-at"].asUInt(); + if (full_at < 100) { + capacity = 100.f * capacity / full_at; + } + } + if (capacity > 100.f) { + // This can happen when the battery is calibrating and goes above 100% + // Handle it gracefully by clamping at 100% + capacity = 100.f; + } + uint8_t cap = round(capacity); + if (cap == 100 && status=="Plugged") { + // If we've reached 100% just mark as full as some batteries can stay + // stuck reporting they're still charging but not yet done + status = "Full"; + } + + //spdlog::info("{} {} {} {}", capacity,time,status,rate); + return {capacity, time, status, rate}; + +#else + uint32_t total_power = 0; // μW +>>>>>>> 246e377 (FreeBSD: Add support to battery) uint32_t total_energy = 0; // μWh bool total_energy_exists = false; uint32_t total_energy_full = 0; @@ -456,6 +517,7 @@ const std::tuple waybar::modules::Battery::g if (cap == 100 && status == "Charging") status = "Full"; return {cap, time_remaining, status, total_power / 1e6}; +#endif } catch (const std::exception& e) { spdlog::error("Battery: {}", e.what()); return {0, 0, "Unknown", 0}; @@ -463,11 +525,20 @@ const std::tuple waybar::modules::Battery::g } const std::string waybar::modules::Battery::getAdapterStatus(uint8_t capacity) const { +#if defined(__Linux__) if (!adapter_.empty()) { bool online; std::string status; std::ifstream(adapter_ / "online") >> online; std::getline(std::ifstream(adapter_ / "status"), status); +#else + int state; + size_t size_state = sizeof state; + if (sysctlbyname("hw.acpi.battery.state", &state, &size_state, NULL,0) != 0) { + throw std::runtime_error("sysctl hw.acpi.battery.state failed"); + } + bool online = state == 2; +#endif if (capacity == 100) { return "Full"; } @@ -475,7 +546,9 @@ const std::string waybar::modules::Battery::getAdapterStatus(uint8_t capacity) c return "Plugged"; } return "Discharging"; +#if defined(__Linux__) } +#endif return "Unknown"; } @@ -497,10 +570,12 @@ const std::string waybar::modules::Battery::formatTimeRemaining(float hoursRemai } auto waybar::modules::Battery::update() -> void { +#if __Linux__ if (batteries_.empty()) { event_box_.hide(); return; } +#endif auto [capacity, time_remaining, status, power] = getInfos(); if (status == "Unknown") { status = getAdapterStatus(capacity);