FreeBSD: Add support to battery

This commit aims to propose a FreeBSD to gain battery support using sysctl on hw.acpi.battery.*
This commit is contained in:
Loïc Bartoletti 2022-09-30 21:59:27 +02:00
parent a7e6330078
commit 830c5cd5d0
4 changed files with 84 additions and 4 deletions

View File

@ -27,7 +27,7 @@
#include "modules/hyprland/language.hpp" #include "modules/hyprland/language.hpp"
#include "modules/hyprland/window.hpp" #include "modules/hyprland/window.hpp"
#endif #endif
#if defined(__linux__) && !defined(NO_FILESYSTEM) #if defined(__FreeBSD__) || (defined(__linux__) && !defined(NO_FILESYSTEM))
#include "modules/battery.hpp" #include "modules/battery.hpp"
#endif #endif
#if defined(HAVE_CPU_LINUX) || defined(HAVE_CPU_BSD) #if defined(HAVE_CPU_LINUX) || defined(HAVE_CPU_BSD)

View File

@ -179,6 +179,11 @@ elif is_dragonfly or is_freebsd or is_netbsd or is_openbsd
'src/modules/memory/bsd.cpp', 'src/modules/memory/bsd.cpp',
'src/modules/memory/common.cpp', 'src/modules/memory/common.cpp',
) )
if is_freebsd
src_files += files(
'src/modules/battery.cpp',
)
endif
endif endif
add_project_arguments('-DHAVE_SWAY', language: 'cpp') add_project_arguments('-DHAVE_SWAY', language: 'cpp')

View File

@ -7,7 +7,7 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
auto hash_pos = name.find('#'); auto hash_pos = name.find('#');
auto ref = name.substr(0, hash_pos); auto ref = name.substr(0, hash_pos);
auto id = hash_pos != std::string::npos ? name.substr(hash_pos + 1) : ""; 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") { if (ref == "battery") {
return new waybar::modules::Battery(id, config_[name]); return new waybar::modules::Battery(id, config_[name]);
} }

View File

@ -1,9 +1,16 @@
#include "modules/battery.hpp" #include "modules/battery.hpp"
#if defined(__FreeBSD__)
// clang-format off
#include <sys/types.h>
#include <sys/sysctl.h>
// clang-format on
#endif
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <iostream>
waybar::modules::Battery::Battery(const std::string& id, const Json::Value& config) waybar::modules::Battery::Battery(const std::string& id, const Json::Value& config)
: AButton(config, "battery", id, "{capacity}%", 60) { : AButton(config, "battery", id, "{capacity}%", 60) {
#if defined(__Linux__)
battery_watch_fd_ = inotify_init1(IN_CLOEXEC); battery_watch_fd_ = inotify_init1(IN_CLOEXEC);
if (battery_watch_fd_ == -1) { if (battery_watch_fd_ == -1) {
throw std::runtime_error("Unable to listen batteries."); 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) { if (global_watch < 0) {
throw std::runtime_error("Could not watch for battery plug/unplug"); throw std::runtime_error("Could not watch for battery plug/unplug");
} }
#endif
worker(); worker();
} }
waybar::modules::Battery::~Battery() { waybar::modules::Battery::~Battery() {
#if (__Linux__)
std::lock_guard<std::mutex> guard(battery_list_mutex_); std::lock_guard<std::mutex> guard(battery_list_mutex_);
if (global_watch >= 0) { if (global_watch >= 0) {
@ -39,9 +47,16 @@ waybar::modules::Battery::~Battery() {
batteries_.erase(it); batteries_.erase(it);
} }
close(battery_watch_fd_); close(battery_watch_fd_);
#endif
} }
void waybar::modules::Battery::worker() { void waybar::modules::Battery::worker() {
#if defined(__FreeBSD__)
thread_timer_ = [this] {
dp.emit();
thread_timer_.sleep_for(interval_);
};
#else
thread_timer_ = [this] { thread_timer_ = [this] {
// Make sure we eventually update the list of batteries even if we miss an // Make sure we eventually update the list of batteries even if we miss an
// inotify event for some reason // inotify event for some reason
@ -68,9 +83,11 @@ void waybar::modules::Battery::worker() {
refreshBatteries(); refreshBatteries();
dp.emit(); dp.emit();
}; };
#endif
} }
void waybar::modules::Battery::refreshBatteries() { void waybar::modules::Battery::refreshBatteries() {
#if (__Linux__)
std::lock_guard<std::mutex> guard(battery_list_mutex_); std::lock_guard<std::mutex> guard(battery_list_mutex_);
// Mark existing list of batteries as not necessarily found // Mark existing list of batteries as not necessarily found
std::map<fs::path, bool> check_map; std::map<fs::path, bool> check_map;
@ -135,6 +152,7 @@ void waybar::modules::Battery::refreshBatteries() {
batteries_.erase(check.first); batteries_.erase(check.first);
} }
} }
#endif
} }
// Unknown > Full > Not charging > Discharging > Charging // Unknown > Full > Not charging > Discharging > Charging
@ -158,6 +176,49 @@ const std::tuple<uint8_t, float, std::string, float> waybar::modules::Battery::g
try { try {
uint32_t total_power = 0; // μW uint32_t total_power = 0; // μW
bool total_power_exists = false; 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 uint32_t total_energy = 0; // μWh
bool total_energy_exists = false; bool total_energy_exists = false;
uint32_t total_energy_full = 0; uint32_t total_energy_full = 0;
@ -456,6 +517,7 @@ const std::tuple<uint8_t, float, std::string, float> waybar::modules::Battery::g
if (cap == 100 && status == "Charging") status = "Full"; if (cap == 100 && status == "Charging") status = "Full";
return {cap, time_remaining, status, total_power / 1e6}; return {cap, time_remaining, status, total_power / 1e6};
#endif
} catch (const std::exception& e) { } catch (const std::exception& e) {
spdlog::error("Battery: {}", e.what()); spdlog::error("Battery: {}", e.what());
return {0, 0, "Unknown", 0}; return {0, 0, "Unknown", 0};
@ -463,11 +525,20 @@ const std::tuple<uint8_t, float, std::string, float> waybar::modules::Battery::g
} }
const std::string waybar::modules::Battery::getAdapterStatus(uint8_t capacity) const { const std::string waybar::modules::Battery::getAdapterStatus(uint8_t capacity) const {
#if defined(__Linux__)
if (!adapter_.empty()) { if (!adapter_.empty()) {
bool online; bool online;
std::string status; std::string status;
std::ifstream(adapter_ / "online") >> online; std::ifstream(adapter_ / "online") >> online;
std::getline(std::ifstream(adapter_ / "status"), status); 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) { if (capacity == 100) {
return "Full"; return "Full";
} }
@ -475,7 +546,9 @@ const std::string waybar::modules::Battery::getAdapterStatus(uint8_t capacity) c
return "Plugged"; return "Plugged";
} }
return "Discharging"; return "Discharging";
#if defined(__Linux__)
} }
#endif
return "Unknown"; return "Unknown";
} }
@ -497,10 +570,12 @@ const std::string waybar::modules::Battery::formatTimeRemaining(float hoursRemai
} }
auto waybar::modules::Battery::update() -> void { auto waybar::modules::Battery::update() -> void {
#if __Linux__
if (batteries_.empty()) { if (batteries_.empty()) {
event_box_.hide(); event_box_.hide();
return; return;
} }
#endif
auto [capacity, time_remaining, status, power] = getInfos(); auto [capacity, time_remaining, status, power] = getInfos();
if (status == "Unknown") { if (status == "Unknown") {
status = getAdapterStatus(capacity); status = getAdapterStatus(capacity);