@@ -19,6 +19,9 @@ class Battery : public QObject
1919 Q_PROPERTY (quint8 rightPodLevel READ getRightPodLevel NOTIFY batteryStatusChanged)
2020 Q_PROPERTY (bool rightPodCharging READ isRightPodCharging NOTIFY batteryStatusChanged)
2121 Q_PROPERTY (bool rightPodAvailable READ isRightPodAvailable NOTIFY batteryStatusChanged)
22+ Q_PROPERTY (quint8 headsetLevel READ getHeadsetLevel NOTIFY batteryStatusChanged)
23+ Q_PROPERTY (bool headsetCharging READ isHeadsetCharging NOTIFY batteryStatusChanged)
24+ Q_PROPERTY (bool headsetAvailable READ isHeadsetAvailable NOTIFY batteryStatusChanged)
2225 Q_PROPERTY (quint8 caseLevel READ getCaseLevel NOTIFY batteryStatusChanged)
2326 Q_PROPERTY (bool caseCharging READ isCaseCharging NOTIFY batteryStatusChanged)
2427 Q_PROPERTY (bool caseAvailable READ isCaseAvailable NOTIFY batteryStatusChanged)
@@ -32,6 +35,7 @@ class Battery : public QObject
3235 void reset ()
3336 {
3437 // Initialize all components to unknown state
38+ states[Component::Headset] = {};
3539 states[Component::Left] = {};
3640 states[Component::Right] = {};
3741 states[Component::Case] = {};
@@ -41,6 +45,7 @@ class Battery : public QObject
4145 // Enum for AirPods components
4246 enum class Component
4347 {
48+ Headset = 0x01 , // AirPods Max
4449 Right = 0x02 ,
4550 Left = 0x04 ,
4651 Case = 0x08 ,
@@ -105,7 +110,7 @@ class Battery : public QObject
105110 }
106111
107112 // If this is a pod (Left or Right), add it to the list
108- if (comp == Component::Left || comp == Component::Right)
113+ if (comp == Component::Left || comp == Component::Right || comp == Component::Headset )
109114 {
110115 podsInPacket.append (comp);
111116 }
@@ -117,11 +122,17 @@ class Battery : public QObject
117122 // Set primary and secondary pods based on order
118123 if (!podsInPacket.isEmpty ())
119124 {
120- Component newPrimaryPod = podsInPacket[0 ]; // First pod is primary
121- if (newPrimaryPod != primaryPod)
122- {
123- primaryPod = newPrimaryPod;
125+ if (podsInPacket.count () == 1 && podsInPacket[0 ] == Component::Headset) {
126+ // AirPods Max
127+ primaryPod = podsInPacket[0 ];
124128 emit primaryChanged ();
129+ } else {
130+ Component newPrimaryPod = podsInPacket[0 ]; // First pod is primary
131+ if (newPrimaryPod != primaryPod)
132+ {
133+ primaryPod = newPrimaryPod;
134+ emit primaryChanged ();
135+ }
125136 }
126137 }
127138 if (podsInPacket.size () >= 2 )
@@ -132,14 +143,18 @@ class Battery : public QObject
132143 // Emit signal to notify about battery status change
133144 emit batteryStatusChanged ();
134145
135- // Log which is left and right pod
136- LOG_INFO (" Primary Pod:" << primaryPod);
137- LOG_INFO (" Secondary Pod:" << secondaryPod);
146+ if (primaryPod == Component::Headset) {
147+ LOG_INFO (" Primary Pod:" << primaryPod);
148+ } else {
149+ // Log which is left and right pod
150+ LOG_INFO (" Primary Pod:" << primaryPod);
151+ LOG_INFO (" Secondary Pod:" << secondaryPod);
152+ }
138153
139154 return true ;
140155 }
141156
142- bool parseEncryptedPacket (const QByteArray &packet, bool isLeftPodPrimary, bool podInCase)
157+ bool parseEncryptedPacket (const QByteArray &packet, bool isLeftPodPrimary, bool podInCase, bool isHeadset )
143158 {
144159 // Validate packet size (expect 16 bytes based on provided payloads)
145160 if (packet.size () != 16 )
@@ -160,30 +175,42 @@ class Battery : public QObject
160175 auto [isLeftCharging, rawLeftBattery] = formatBattery (rawLeftBatteryByte);
161176 auto [isRightCharging, rawRightBattery] = formatBattery (rawRightBatteryByte);
162177 auto [isCaseCharging, rawCaseBattery] = formatBattery (rawCaseBatteryByte);
178+ if (isHeadset) {
179+ int batteries[] = {rawLeftBattery, rawRightBattery, rawCaseBattery};
180+ bool statuses[] = {isLeftCharging, isRightCharging, isCaseCharging};
181+ // Find the first battery that isn't CHAR_MAX
182+ auto it = std::find_if (std::begin (batteries), std::end (batteries), [](int i) { return i != CHAR_MAX; });
183+ if (it != std::end (batteries)) {
184+ std::size_t idx = it - std::begin (batteries);
185+ int battery = *it;
186+ primaryPod = Component::Headset;
187+ states[Component::Headset] = {static_cast <quint8>(battery), statuses[idx] ? BatteryStatus::Charging : BatteryStatus::Discharging};
188+ }
189+ } else {
190+ if (rawLeftBattery == CHAR_MAX) {
191+ rawLeftBattery = states.value (Component::Left).level ; // Use last valid level
192+ isLeftCharging = states.value (Component::Left).status == BatteryStatus::Charging;
193+ }
163194
164- if (rawLeftBattery == CHAR_MAX) {
165- rawLeftBattery = states.value (Component::Left).level ; // Use last valid level
166- isLeftCharging = states.value (Component::Left).status == BatteryStatus::Charging;
167- }
168-
169- if (rawRightBattery == CHAR_MAX) {
170- rawRightBattery = states.value (Component::Right).level ; // Use last valid level
171- isRightCharging = states.value (Component::Right).status == BatteryStatus::Charging;
172- }
195+ if (rawRightBattery == CHAR_MAX) {
196+ rawRightBattery = states.value (Component::Right).level ; // Use last valid level
197+ isRightCharging = states.value (Component::Right).status == BatteryStatus::Charging;
198+ }
173199
174- if (rawCaseBattery == CHAR_MAX) {
175- rawCaseBattery = states.value (Component::Case).level ; // Use last valid level
176- isCaseCharging = states.value (Component::Case).status == BatteryStatus::Charging;
177- }
200+ if (rawCaseBattery == CHAR_MAX) {
201+ rawCaseBattery = states.value (Component::Case).level ; // Use last valid level
202+ isCaseCharging = states.value (Component::Case).status == BatteryStatus::Charging;
203+ }
178204
179- // Update states
180- states[Component::Left] = {static_cast <quint8>(rawLeftBattery), isLeftCharging ? BatteryStatus::Charging : BatteryStatus::Discharging};
181- states[Component::Right] = {static_cast <quint8>(rawRightBattery), isRightCharging ? BatteryStatus::Charging : BatteryStatus::Discharging};
182- if (podInCase) {
183- states[Component::Case] = {static_cast <quint8>(rawCaseBattery), isCaseCharging ? BatteryStatus::Charging : BatteryStatus::Discharging};
205+ // Update states
206+ states[Component::Left] = {static_cast <quint8>(rawLeftBattery), isLeftCharging ? BatteryStatus::Charging : BatteryStatus::Discharging};
207+ states[Component::Right] = {static_cast <quint8>(rawRightBattery), isRightCharging ? BatteryStatus::Charging : BatteryStatus::Discharging};
208+ if (podInCase) {
209+ states[Component::Case] = {static_cast <quint8>(rawCaseBattery), isCaseCharging ? BatteryStatus::Charging : BatteryStatus::Discharging};
210+ }
211+ primaryPod = isLeftPodPrimary ? Component::Left : Component::Right;
212+ secondaryPod = isLeftPodPrimary ? Component::Right : Component::Left;
184213 }
185- primaryPod = isLeftPodPrimary ? Component::Left : Component::Right;
186- secondaryPod = isLeftPodPrimary ? Component::Right : Component::Left;
187214 emit batteryStatusChanged ();
188215 emit primaryChanged ();
189216
@@ -236,6 +263,9 @@ class Battery : public QObject
236263 quint8 getCaseLevel () const { return states.value (Component::Case).level ; }
237264 bool isCaseCharging () const { return isStatus (Component::Case, BatteryStatus::Charging); }
238265 bool isCaseAvailable () const { return !isStatus (Component::Case, BatteryStatus::Disconnected); }
266+ quint8 getHeadsetLevel () const { return states.value (Component::Headset).level ; }
267+ bool isHeadsetCharging () const { return isStatus (Component::Headset, BatteryStatus::Charging); }
268+ bool isHeadsetAvailable () const { return !isStatus (Component::Headset, BatteryStatus::Disconnected); }
239269
240270signals:
241271 void batteryStatusChanged ();
@@ -257,4 +287,4 @@ class Battery : public QObject
257287 QMap<Component, BatteryState> states;
258288 Component primaryPod;
259289 Component secondaryPod;
260- };
290+ };
0 commit comments