65 lines
2.0 KiB
C++
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
|