[Linux] Read AirPods state from BLE broadcast when not connected (#138)

* Fix possible build error

* [Linux] Read AirPods state from BLE broadcast when not connected

* SImplify

* Remove old code

* Remove old code

* Maintain charging state when state is unknown

* Simplify

* Remove unused var
This commit is contained in:
Tim Gromeyer
2025-06-04 13:10:55 +02:00
committed by GitHub
parent 5dc7e512ae
commit c4633d6871
14 changed files with 416 additions and 617 deletions

View File

@@ -130,6 +130,58 @@ public:
return true;
}
bool parseEncryptedPacket(const QByteArray &packet, bool isLeftPodPrimary)
{
// Validate packet size (expect 16 bytes based on provided payloads)
if (packet.size() != 16)
{
return false;
}
// Determine byte indices based on isFlipped
int leftByteIndex = isLeftPodPrimary ? 1 : 2;
int rightByteIndex = isLeftPodPrimary ? 2 : 1;
// Extract raw battery bytes
unsigned char rawLeftBatteryByte = static_cast<unsigned char>(packet.at(leftByteIndex));
unsigned char rawRightBatteryByte = static_cast<unsigned char>(packet.at(rightByteIndex));
unsigned char rawCaseBatteryByte = static_cast<unsigned char>(packet.at(3));
// Extract battery data (charging status and raw level 0-127)
auto [isLeftCharging, rawLeftBattery] = formatBattery(rawLeftBatteryByte);
auto [isRightCharging, rawRightBattery] = formatBattery(rawRightBatteryByte);
auto [isCaseCharging, rawCaseBattery] = formatBattery(rawCaseBatteryByte);
// If raw byte is 0xFF or (0x7F and charging), use the last known level
if (rawLeftBatteryByte == 0xFF || (rawLeftBatteryByte == 0x7F && isLeftCharging)) {
rawLeftBatteryByte = states.value(Component::Left).level; // Use last valid level
isLeftCharging = states.value(Component::Left).status == BatteryStatus::Charging;
}
// If raw byte is 0xFF or (0x7F and charging), use the last known level
if (rawRightBatteryByte == 0xFF || (rawRightBatteryByte == 0x7F && isRightCharging)) {
rawRightBattery = states.value(Component::Right).level; // Use last valid level
isRightCharging = states.value(Component::Right).status == BatteryStatus::Charging;
}
// If raw byte is 0xFF or (0x7F and charging), use the last known level
if (rawCaseBatteryByte == 0xFF || (rawCaseBatteryByte == 0x7F && isCaseCharging)) {
rawCaseBattery = states.value(Component::Case).level; // Use last valid level
isCaseCharging = states.value(Component::Case).status == BatteryStatus::Charging;
}
// Update states
states[Component::Left] = {static_cast<quint8>(rawLeftBattery), isLeftCharging ? BatteryStatus::Charging : BatteryStatus::Discharging};
states[Component::Right] = {static_cast<quint8>(rawRightBattery), isRightCharging ? BatteryStatus::Charging : BatteryStatus::Discharging};
states[Component::Case] = {static_cast<quint8>(rawCaseBattery), isCaseCharging ? BatteryStatus::Charging : BatteryStatus::Discharging};
primaryPod = isLeftPodPrimary ? Component::Left : Component::Right;
secondaryPod = isLeftPodPrimary ? Component::Right : Component::Left;
emit batteryStatusChanged();
emit primaryChanged();
return true;
}
// Get the raw state for a component
BatteryState getState(Component comp) const
{
@@ -187,7 +239,14 @@ private:
return states.value(component).status == status;
}
std::pair<bool, int> formatBattery(unsigned char byteVal)
{
bool charging = (byteVal & 0x80) != 0;
int level = byteVal & 0x7F;
return std::make_pair(charging, level);
}
QMap<Component, BatteryState> states;
Component primaryPod;
Component secondaryPod;
};
};