33#include " ../result_types.hpp"
44#include " device_utils.hpp"
55#include " protocols/steelseries_protocol.hpp"
6+ #include < algorithm>
67#include < array>
78#include < string_view>
89
@@ -29,7 +30,7 @@ namespace headsetcontrol {
2930 */
3031class SteelSeriesArctisNova7 : public protocols ::SteelSeriesNovaDevice<SteelSeriesArctisNova7> {
3132public:
32- static constexpr std::array<uint16_t ,12 > SUPPORTED_PRODUCT_IDS {
33+ static constexpr std::array<uint16_t , 12 > SUPPORTED_PRODUCT_IDS {
3334 0x2202 , // Arctis Nova 7 (discrete battery: 0-4)
3435 0x22A1 , // Arctis Nova 7 (percentage battery: 0-100, Jan. 2026 update)
3536 0x227e , // Arctis Nova 7 Wireless Gen 2 (percentage battery: 0-100)
@@ -41,7 +42,7 @@ class SteelSeriesArctisNova7 : public protocols::SteelSeriesNovaDevice<SteelSeri
4142 0x22a9 , // Arctis Nova 7 Diablo IV (percentage battery: 0-100, after Jan 2026 update)
4243 0x227a , // Arctis Nova 7 WoW Edition (discrete battery: 0-4)
4344 0x22a4 , // Arctis Nova 7X (discrete battery: 0-4)
44- 0x22a5 // Arctis Nova 7X (percentage battery: 0-100)
45+ 0x22a5 // Arctis Nova 7X (percentage battery: 0-100)
4546 };
4647
4748 static constexpr int EQUALIZER_BANDS = 10 ;
@@ -126,29 +127,21 @@ class SteelSeriesArctisNova7 : public protocols::SteelSeriesNovaDevice<SteelSeri
126127 return DeviceError::deviceOffline (" Headset not connected" );
127128 }
128129
129- // Auto-detect battery protocol (Gen 2 vs original models):
130+ // Determine battery protocol based on matched product ID.
130131 //
131- // Original models (0x2202, 0x2206, 0x220a, 0x223a, 0x227a):
132- // - Battery: data[2] in discrete levels 0-4 (0%/25%/50%/75%/100%)
133- // - Status: data[3] = 0x01 when charging, other non-zero when on battery
132+ // Original models (discrete battery: 0-4 levels → 0%/25%/50%/75%/100%):
133+ // 0x2202, 0x2206, 0x220a, 0x223a, 0x227a, 0x22a4
134134 //
135- // Gen 2 models (0x227e, possibly 0x2258):
136- // - Battery: data[2] as direct percentage 0-100
137- // - Status: data[3] = 0x01 charging, 0x02 fully charged, 0x03 on battery
138- //
139- // Detection heuristics (since we don't have product_id here):
140- // 1. Status byte 0x02 or 0x03 → Gen 2 protocol
141- // 2. Battery value > 4 → Gen 2 protocol (wouldn't be valid in discrete mode)
142- //
143- // TODO: Known edge case - Gen 2 at 1-4% battery while actively charging (status=0x01)
144- // will be misdetected as original protocol and show inflated percentage
145- // (1%→25%, 2%→50%, 3%→75%, 4%→100%). This is extremely rare because:
146- // - Requires plugging in exactly at 1-4% battery
147- // - At low battery, devices typically show status=0x03 (on battery)
148- // - Self-corrects once battery charges past 4%
149- // - Only lasts a few seconds/minutes
150- // Proper fix would require passing product_id to getBattery() method.
151- bool is_gen2_protocol = (data[3 ] == 0x02 || data[3 ] == 0x03 ) || (data[2 ] > 4 );
135+ // Gen 2 / updated firmware models (percentage battery: 0-100 direct):
136+ // 0x22A1, 0x227e, 0x2258, 0x229e, 0x22ad, 0x22a9, 0x22a5, 0x22a7
137+ static constexpr std::array<uint16_t , 6 > DISCRETE_BATTERY_PIDS {
138+ 0x2202 , 0x2206 , 0x220a , 0x223a , 0x227a , 0x22a4
139+ };
140+ uint16_t pid = getMatchedProductId ();
141+ bool is_discrete = std::find (DISCRETE_BATTERY_PIDS.begin (),
142+ DISCRETE_BATTERY_PIDS.end (), pid)
143+ != DISCRETE_BATTERY_PIDS.end ();
144+ bool is_gen2_protocol = !is_discrete;
152145
153146 enum battery_status status = BATTERY_AVAILABLE;
154147 if (data[3 ] == 0x01 || data[3 ] == 0x02 ) {
0 commit comments