Files
bar/include/services/hidppBattery.hpp
T
2026-08-04 21:01:38 +02:00

65 lines
2.0 KiB
C++

#pragma once
#include <cstdint>
#include <optional>
#include <string>
namespace hidpp {
/// Battery state of a wireless Logitech device.
struct BatteryStatus {
enum class Level : uint8_t { UNKNOWN,
CRITICAL,
LOW,
GOOD,
FULL };
bool connected = false;
int percentage = -1; // 0..100, or -1 when the device only reports a level
Level level = Level::UNKNOWN;
bool charging = false;
bool externalPower = false;
};
/// Reads the battery level of a Logitech HID++ 2.0 device.
///
/// Prefers the power_supply entry that hid-logitech-hidpp exports, and falls
/// back to speaking HID++ 2.0 over /dev/hidraw* when that driver is not bound
/// (the receiver then sits on hid-generic and exports no battery at all).
///
/// read() blocks on wireless round-trips that can take seconds when the device
/// is asleep, so it must be called off the GTK main thread.
class BatteryReader {
public:
explicit BatteryReader(std::string deviceName);
~BatteryReader();
BatteryReader(const BatteryReader &) = delete;
BatteryReader &operator=(const BatteryReader &) = delete;
BatteryStatus read();
private:
/// A resolved HID++ endpoint: which hidraw node, which device slot on it,
/// and the feature index the battery lives behind.
struct Endpoint {
int fd = -1;
uint8_t deviceIndex = 0;
uint8_t featureIdx = 0;
uint16_t featureId = 0; // kFeatureUnifiedBattery or kFeatureBatteryStatus
};
std::string deviceName;
Endpoint endpoint{};
std::optional<BatteryStatus> readFromSysfs() const;
std::optional<BatteryStatus> readFromHidpp();
/// Finds the hidraw node and device slot our device answers on. Expensive:
/// only called on first use and after the cached endpoint stops replying.
bool resolveEndpoint();
void closeEndpoint();
};
} // namespace hidpp