@@ -71,6 +71,10 @@ class LogitechGProX2Lightspeed : public protocols::LogitechCenturionProtocol {
7171
7272 std::optional<EqualizerInfo> getEqualizerInfo () const override
7373 {
74+ if (!has_cached_equalizer_info_) {
75+ return std::nullopt ;
76+ }
77+
7478 return EqualizerInfo {
7579 .bands_count = cached_band_count_,
7680 .bands_baseline = 0 ,
@@ -82,6 +86,10 @@ class LogitechGProX2Lightspeed : public protocols::LogitechCenturionProtocol {
8286
8387 std::optional<ParametricEqualizerInfo> getParametricEqualizerInfo () const override
8488 {
89+ if (!has_cached_equalizer_info_) {
90+ return std::nullopt ;
91+ }
92+
8593 return ParametricEqualizerInfo {
8694 .bands_count = cached_band_count_,
8795 .gain_base = 0 .0f ,
@@ -113,6 +121,7 @@ class LogitechGProX2Lightspeed : public protocols::LogitechCenturionProtocol {
113121
114122 Result<BatteryResult> getBattery (hid_device* device_handle) override
115123 {
124+ auto centurion_start_time = std::chrono::steady_clock::now ();
116125 if (auto centurion_battery = sendCenturionFeatureRequest (
117126 device_handle,
118127 static_cast <uint16_t >(protocols::CenturionFeature::CenturionBatterySoc),
@@ -124,7 +133,9 @@ class LogitechGProX2Lightspeed : public protocols::LogitechCenturionProtocol {
124133 }
125134
126135 battery_result->raw_data = *centurion_battery;
127- battery_result->query_duration = std::chrono::milliseconds { 0 };
136+ auto centurion_end_time = std::chrono::steady_clock::now ();
137+ battery_result->query_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
138+ centurion_end_time - centurion_start_time);
128139 return *battery_result;
129140 }
130141
@@ -252,26 +263,14 @@ class LogitechGProX2Lightspeed : public protocols::LogitechCenturionProtocol {
252263 return DeviceError::invalidParameter (" Device only supports presets 0-4" );
253264 }
254265
255- const std::array<float , 5 >* preset_values = nullptr ;
256- switch (preset) {
257- case 0 :
258- preset_values = &PRESET_FLAT ;
259- break ;
260- case 1 :
261- preset_values = &PRESET_BASS_BOOST ;
262- break ;
263- case 2 :
264- preset_values = &PRESET_TEAM_CHAT ;
265- break ;
266- case 3 :
267- preset_values = &PRESET_SHOOTER ;
268- break ;
269- case 4 :
270- preset_values = &PRESET_MOBA ;
271- break ;
272- default :
273- return DeviceError::invalidParameter (" Device only supports presets 0-4" );
274- }
266+ static constexpr std::array<const std::array<float , 5 >*, EQUALIZER_PRESETS_COUNT > PRESET_VALUES {
267+ &PRESET_FLAT ,
268+ &PRESET_BASS_BOOST ,
269+ &PRESET_TEAM_CHAT ,
270+ &PRESET_SHOOTER ,
271+ &PRESET_MOBA ,
272+ };
273+ const auto * preset_values = PRESET_VALUES [preset];
275274
276275 EqualizerSettings settings;
277276 settings.bands .assign (preset_values->begin (), preset_values->end ());
@@ -404,6 +403,7 @@ class LogitechGProX2Lightspeed : public protocols::LogitechCenturionProtocol {
404403 }
405404
406405 auto charging_state = packet.size () >= 3 ? packet[2 ] : 0 ;
406+ // Centurion battery replies use states 1 and 2 for charging; the legacy packet parser only treats 0x02 as charging.
407407 auto status = (charging_state == 1 || charging_state == 2 )
408408 ? BATTERY_CHARGING
409409 : BATTERY_AVAILABLE ;
@@ -472,8 +472,21 @@ class LogitechGProX2Lightspeed : public protocols::LogitechCenturionProtocol {
472472 return buildOnboardEqPayload (slot, converted);
473473 }
474474
475+ static std::vector<uint16_t > quantizeOnboardEqCoefficientsForTest (const std::array<double , 5 >& coeffs)
476+ {
477+ return quantizeOnboardEqCoefficients (coeffs);
478+ }
479+
475480private:
476481
482+ void cacheEqualizerInfo (const AdvancedEqDescriptor& descriptor) const
483+ {
484+ cached_band_count_ = static_cast <int >(descriptor.bands .size ());
485+ cached_gain_min_ = static_cast <int >(descriptor.gain_min );
486+ cached_gain_max_ = static_cast <int >(descriptor.gain_max );
487+ has_cached_equalizer_info_ = true ;
488+ }
489+
477490 static constexpr std::array<uint8_t , 2 > buildPlaybackEqSelector (uint8_t slot)
478491 {
479492 return { PLAYBACK_DIRECTION , slot };
@@ -523,7 +536,7 @@ class LogitechGProX2Lightspeed : public protocols::LogitechCenturionProtocol {
523536 for (size_t i = 0 ; i < coeffs.size (); ++i) {
524537 auto q_value = static_cast <int64_t >(std::llround (coeffs[i] * scales[i]));
525538 q_value = std::clamp<int64_t >(q_value, -(1LL << 31 ), (1LL << 31 ) - 1 );
526- q_value &= 0xFFFFFF00 ;
539+ q_value &= ~INT64_C ( 0xFF ) ;
527540 words.push_back (static_cast <uint16_t >((q_value >> 16 ) & 0xFFFF ));
528541 words.push_back (static_cast <uint16_t >(q_value & 0xFFFF ));
529542 }
@@ -677,9 +690,7 @@ class LogitechGProX2Lightspeed : public protocols::LogitechCenturionProtocol {
677690 return DeviceError::protocolError (" Advanced EQ band response was empty" );
678691 }
679692
680- cached_band_count_ = static_cast <int >(descriptor.bands .size ());
681- cached_gain_min_ = static_cast <int >(descriptor.gain_min );
682- cached_gain_max_ = static_cast <int >(descriptor.gain_max );
693+ cacheEqualizerInfo (descriptor);
683694 return descriptor;
684695 }
685696
@@ -732,9 +743,7 @@ class LogitechGProX2Lightspeed : public protocols::LogitechCenturionProtocol {
732743 return DeviceError::protocolError (" Onboard EQ band response was empty" );
733744 }
734745
735- cached_band_count_ = static_cast <int >(descriptor.bands .size ());
736- cached_gain_min_ = static_cast <int >(descriptor.gain_min );
737- cached_gain_max_ = static_cast <int >(descriptor.gain_max );
746+ cacheEqualizerInfo (descriptor);
738747 return descriptor;
739748 }
740749
@@ -789,9 +798,10 @@ class LogitechGProX2Lightspeed : public protocols::LogitechCenturionProtocol {
789798 return {};
790799 }
791800
792- mutable int cached_band_count_ = 5 ;
793- mutable int cached_gain_min_ = -12 ;
794- mutable int cached_gain_max_ = 12 ;
801+ mutable bool has_cached_equalizer_info_ = false ;
802+ mutable int cached_band_count_ = 0 ;
803+ mutable int cached_gain_min_ = 0 ;
804+ mutable int cached_gain_max_ = 0 ;
795805};
796806
797807} // namespace headsetcontrol
0 commit comments