33#define AIRPODS_PACKETS_H
44
55#include < QByteArray>
6+ #include < optional>
7+
68#include " enums.h"
9+ #include " BasicControlCommand.hpp"
710
811namespace AirPodsPackets
912{
1013 // Noise Control Mode Packets
1114 namespace NoiseControl
1215 {
13- static const QByteArray HEADER = QByteArray::fromHex( " 0400040009000D " ); // Added for parsing
14- static const QByteArray OFF = HEADER + QByteArray::fromHex( " 01000000 " );
15- static const QByteArray NOISE_CANCELLATION = HEADER + QByteArray::fromHex( " 02000000 " );
16- static const QByteArray TRANSPARENCY = HEADER + QByteArray::fromHex( " 03000000 " );
17- static const QByteArray ADAPTIVE = HEADER + QByteArray::fromHex( " 04000000 " );
16+ static const QByteArray HEADER = ControlCommand::HEADER + 0x0D ;
17+ static const QByteArray OFF = ControlCommand::createCommand( 0x0D , 0x01 );
18+ static const QByteArray NOISE_CANCELLATION = ControlCommand::createCommand( 0x0D , 0x02 );
19+ static const QByteArray TRANSPARENCY = ControlCommand::createCommand( 0x0D , 0x03 );
20+ static const QByteArray ADAPTIVE = ControlCommand::createCommand( 0x0D , 0x04 );
1821
1922 static const QByteArray getPacketForMode (AirpodsTrayApp::Enums::NoiseControlMode mode)
2023 {
@@ -35,32 +38,73 @@ namespace AirPodsPackets
3538 }
3639 }
3740
38- // Conversational Awareness Packets
39- namespace ConversationalAwareness
41+ // One Bud ANC Mode
42+ namespace OneBudANCMode
4043 {
41- static const QByteArray HEADER = QByteArray::fromHex(" 04000400090028" ); // For command/status
42- static const QByteArray ENABLED = HEADER + QByteArray::fromHex(" 01000000" ); // Command to enable
43- static const QByteArray DISABLED = HEADER + QByteArray::fromHex(" 02000000" ); // Command to disable
44- static const QByteArray DATA_HEADER = QByteArray::fromHex(" 040004004B00020001" ); // For received speech level data
44+ using Type = BasicControlCommand<0x1B >;
45+ static const QByteArray ENABLED = Type::ENABLED;
46+ static const QByteArray DISABLED = Type::DISABLED;
47+ static const QByteArray HEADER = Type::HEADER;
48+ inline std::optional<bool > parseState (const QByteArray &data) { return Type::parseState (data); }
49+ }
4550
46- static std::optional<bool > parseCAState (const QByteArray &data)
51+ // Volume Swipe (partial - still needs custom interval function)
52+ namespace VolumeSwipe
53+ {
54+ using Type = BasicControlCommand<0x25 >;
55+ static const QByteArray ENABLED = Type::ENABLED;
56+ static const QByteArray DISABLED = Type::DISABLED;
57+ static const QByteArray HEADER = Type::HEADER;
58+ inline std::optional<bool > parseState (const QByteArray &data) { return Type::parseState (data); }
59+
60+ // Keep custom interval function
61+ static QByteArray getIntervalPacket (quint8 interval)
4762 {
48- // Extract the status byte (index 7)
49- quint8 statusByte = static_cast <quint8>(data.at (HEADER.size ())); // HEADER.size() is 7
50-
51- // Interpret the status byte
52- switch (statusByte)
53- {
54- case 0x01 : // Enabled
55- return true ;
56- case 0x02 : // Disabled
57- return false ;
58- default :
59- return std::nullopt ;
60- }
63+ return ControlCommand::createCommand (0x23 , interval);
6164 }
6265 }
6366
67+ // Adaptive Volume Config
68+ namespace AdaptiveVolume
69+ {
70+ using Type = BasicControlCommand<0x26 >;
71+ static const QByteArray ENABLED = Type::ENABLED;
72+ static const QByteArray DISABLED = Type::DISABLED;
73+ static const QByteArray HEADER = Type::HEADER;
74+ inline std::optional<bool > parseState (const QByteArray &data) { return Type::parseState (data); }
75+ }
76+
77+ // Conversational Awareness
78+ namespace ConversationalAwareness
79+ {
80+ using Type = BasicControlCommand<0x28 >;
81+ static const QByteArray ENABLED = Type::ENABLED;
82+ static const QByteArray DISABLED = Type::DISABLED;
83+ static const QByteArray HEADER = Type::HEADER;
84+ static const QByteArray DATA_HEADER = QByteArray::fromHex(" 040004004B00020001" );
85+ inline std::optional<bool > parseState (const QByteArray &data) { return Type::parseState (data); }
86+ }
87+
88+ // Hearing Assist
89+ namespace HearingAssist
90+ {
91+ using Type = BasicControlCommand<0x33 >;
92+ static const QByteArray ENABLED = Type::ENABLED;
93+ static const QByteArray DISABLED = Type::DISABLED;
94+ static const QByteArray HEADER = Type::HEADER;
95+ inline std::optional<bool > parseState (const QByteArray &data) { return Type::parseState (data); }
96+ }
97+
98+ // Allow Off Option
99+ namespace AllowOffOption
100+ {
101+ using Type = BasicControlCommand<0x34 >;
102+ static const QByteArray ENABLED = Type::ENABLED;
103+ static const QByteArray DISABLED = Type::DISABLED;
104+ static const QByteArray HEADER = Type::HEADER;
105+ inline std::optional<bool > parseState (const QByteArray &data) { return Type::parseState (data); }
106+ }
107+
64108 // Connection Packets
65109 namespace Connection
66110 {
@@ -118,65 +162,37 @@ namespace AirPodsPackets
118162 {
119163 MagicCloudKeys keys;
120164
121- // Expected size: header (7 bytes) + (1 (tag) + 2 (length) + 1 (reserved) + 16 (value)) * 2 = 47 bytes.
122- if (data.size () < 47 )
123- {
124- return keys; // or handle error as needed
125- }
126-
127- // Check header
128- if (!data.startsWith (MAGIC_CLOUD_KEYS_HEADER))
165+ if (data.size () < 47 || !data.startsWith (MAGIC_CLOUD_KEYS_HEADER))
129166 {
130- return keys; // header mismatch
167+ return keys;
131168 }
132169
133- int index = MAGIC_CLOUD_KEYS_HEADER.size (); // Start after header (index 7)
170+ int index = MAGIC_CLOUD_KEYS_HEADER.size ();
134171
135- // --- TLV Block 1 (MagicAccIRK) ---
136- // Tag should be 0x01
172+ // First TLV block (MagicAccIRK)
137173 if (static_cast <quint8>(data.at (index)) != 0x01 )
138- {
139- return keys; // unexpected tag
140- }
174+ return keys;
141175 index += 1 ;
142176
143- // Read length (2 bytes, big-endian)
144177 quint16 len1 = (static_cast <quint8>(data.at (index)) << 8 ) | static_cast <quint8>(data.at (index + 1 ));
145178 if (len1 != 16 )
146- {
147- return keys; // invalid length
148- }
149- index += 2 ;
179+ return keys;
180+ index += 3 ; // Skip length (2 bytes) and reserved byte (1 byte)
150181
151- // Skip reserved byte
152- index += 1 ;
153-
154- // Extract MagicAccIRK (16 bytes)
155182 keys.magicAccIRK = data.mid (index, 16 );
156183 index += 16 ;
157184
158- // --- TLV Block 2 (MagicAccEncKey) ---
159- // Tag should be 0x04
185+ // Second TLV block (MagicAccEncKey)
160186 if (static_cast <quint8>(data.at (index)) != 0x04 )
161- {
162- return keys; // unexpected tag
163- }
187+ return keys;
164188 index += 1 ;
165189
166- // Read length (2 bytes, big-endian)
167190 quint16 len2 = (static_cast <quint8>(data.at (index)) << 8 ) | static_cast <quint8>(data.at (index + 1 ));
168191 if (len2 != 16 )
169- {
170- return keys; // invalid length
171- }
172- index += 2 ;
173-
174- // Skip reserved byte
175- index += 1 ;
192+ return keys;
193+ index += 3 ; // Skip length (2 bytes) and reserved byte (1 byte)
176194
177- // Extract MagicAccEncKey (16 bytes)
178195 keys.magicAccEncKey = data.mid (index, 16 );
179- index += 16 ;
180196
181197 return keys;
182198 }
0 commit comments