From 1c51264fe8d3337ea520d4ab20054117659aca71 Mon Sep 17 00:00:00 2001 From: Denis Arnst Date: Tue, 13 Jan 2026 13:24:25 +0100 Subject: [PATCH 1/4] Steelseries Gen2 uses absolute battery --- lib/devices/steelseries_arctis_nova_7.hpp | 55 ++++++++++++++++++----- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/lib/devices/steelseries_arctis_nova_7.hpp b/lib/devices/steelseries_arctis_nova_7.hpp index 713135c..73a7678 100644 --- a/lib/devices/steelseries_arctis_nova_7.hpp +++ b/lib/devices/steelseries_arctis_nova_7.hpp @@ -29,15 +29,16 @@ namespace headsetcontrol { */ class SteelSeriesArctisNova7 : public protocols::SteelSeriesNovaDevice { public: - static constexpr std::array SUPPORTED_PRODUCT_IDS { - 0x2202, // Arctis Nova 7 - 0x227e, // Arctis Nova 7 Wireless - 0x2206, // Arctis Nova 7x - 0x2258, // Arctis Nova 7x v2 - 0x229e, // Arctis Nova 7x v2 - 0x223a, // Arctis Nova 7 Diablo IV (before Jan Update) - 0x22a9, // Arctis Nova 7 Diablo IV (after Jan Update) - 0x227a // Arctis Nova 7 WoW Edition + static constexpr std::array SUPPORTED_PRODUCT_IDS { + 0x2202, // Arctis Nova 7 (discrete battery: 0-4) + 0x22A1, // Arctis Nova 7 (percentage battery: 0-100, Jan 2026 update) + 0x227e, // Arctis Nova 7 Wireless Gen 2 (percentage battery: 0-100) + 0x2206, // Arctis Nova 7x (discrete battery: 0-4) + 0x2258, // Arctis Nova 7x v2 (percentage battery: 0-100) + 0x229e, // Arctis Nova 7x v2 (percentage battery: 0-100) + 0x223a, // Arctis Nova 7 Diablo IV (discrete battery: 0-4, before Jan 2026 update) + 0x22a9, // Arctis Nova 7 Diablo IV (percentage battery: 0-100, after Jan 2026 update) + 0x227a // Arctis Nova 7 WoW Edition (discrete battery: 0-4) }; static constexpr int EQUALIZER_BANDS = 10; @@ -122,12 +123,44 @@ class SteelSeriesArctisNova7 : public protocols::SteelSeriesNovaDevice 4 → Gen 2 protocol (wouldn't be valid in discrete mode) + // + // TODO: Known edge case - Gen 2 at 1-4% battery while actively charging (status=0x01) + // will be misdetected as original protocol and show inflated percentage + // (1%→25%, 2%→50%, 3%→75%, 4%→100%). This is extremely rare because: + // - Requires plugging in exactly at 1-4% battery + // - At low battery, devices typically show status=0x03 (on battery) + // - Self-corrects once battery charges past 4% + // - Only lasts a few seconds/minutes + // Proper fix would require passing product_id to getBattery() method. + bool is_gen2_protocol = (data[3] == 0x02 || data[3] == 0x03) || (data[2] > 4); + enum battery_status status = BATTERY_AVAILABLE; - if (data[3] == 0x01) { + if (data[3] == 0x01 || data[3] == 0x02) { status = BATTERY_CHARGING; } - int level = map(data[2], 0, 4, 0, 100); + int level; + if (is_gen2_protocol) { + // Gen 2: Direct percentage reporting (0-100) in data[2] + level = data[2]; + } else { + // Original models: Discrete levels (0-4) that need mapping + level = map(data[2], 0, 4, 0, 100); + } + if (level > 100) level = 100; From 9afe103c67394fed6747ef4f5c69ad4a2f19c5cf Mon Sep 17 00:00:00 2001 From: Denis Arnst Date: Thu, 22 Jan 2026 15:24:19 +0100 Subject: [PATCH 2/4] Fix mingw --- cli/main.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cli/main.cpp b/cli/main.cpp index 397f234..2b8e570 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -1101,6 +1102,12 @@ bool checkDeviceConnected(DiscoveredDevice& selected, const Options& opts) int main(int argc, char* argv[]) { +#if defined(_WIN32) && defined(__GNUC__) + // Fix MinGW stdout buffering issue - without this, console output may not appear + setvbuf(stdout, nullptr, _IONBF, 0); + setvbuf(stderr, nullptr, _IONBF, 0); +#endif + Options opts; cli::ArgumentParser parser(argv[0]); configureParser(parser, opts); From 3c73a0a04ddc12ce57a57630974c526940753831 Mon Sep 17 00:00:00 2001 From: Denis Arnst Date: Thu, 22 Jan 2026 15:46:35 +0100 Subject: [PATCH 3/4] Fix static linking --- CMakeLists.txt | 9 +++++---- cli/main.cpp | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 932e951..2e9d6f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,10 +65,11 @@ if(WIN32) # Use static runtime to avoid VC++ Redistributable dependency set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") else() - # MinGW/GCC flags - set(CMAKE_C_STANDARD_LIBRARIES "-lsetupapi -static-libgcc -static-libstdc++ -lwsock32 -lws2_32 ${CMAKE_CXX_STANDARD_LIBRARIES}") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") + # MinGW/GCC flags - statically link runtime to avoid DLL dependencies + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++ -Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive") + set(CMAKE_C_STANDARD_LIBRARIES "-lsetupapi -lwsock32 -lws2_32 ${CMAKE_C_STANDARD_LIBRARIES}") + set(CMAKE_CXX_STANDARD_LIBRARIES "-lsetupapi -lwsock32 -lws2_32 ${CMAKE_CXX_STANDARD_LIBRARIES}") + add_compile_options(-Wall) endif() else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") diff --git a/cli/main.cpp b/cli/main.cpp index 2b8e570..0011ec6 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -1103,7 +1103,7 @@ bool checkDeviceConnected(DiscoveredDevice& selected, const Options& opts) int main(int argc, char* argv[]) { #if defined(_WIN32) && defined(__GNUC__) - // Fix MinGW stdout buffering issue - without this, console output may not appear + // Disable stdout/stderr buffering for MinGW builds setvbuf(stdout, nullptr, _IONBF, 0); setvbuf(stderr, nullptr, _IONBF, 0); #endif From 3e915b01ee12551aaa59f2cbb6c3c4c999e67633 Mon Sep 17 00:00:00 2001 From: Denis Arnst Date: Thu, 29 Jan 2026 16:08:33 +0100 Subject: [PATCH 4/4] Update lib/devices/steelseries_arctis_nova_7.hpp Co-authored-by: Aaro Luomanen <71641519+aarol@users.noreply.github.com> --- lib/devices/steelseries_arctis_nova_7.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/devices/steelseries_arctis_nova_7.hpp b/lib/devices/steelseries_arctis_nova_7.hpp index 73a7678..88bdfc8 100644 --- a/lib/devices/steelseries_arctis_nova_7.hpp +++ b/lib/devices/steelseries_arctis_nova_7.hpp @@ -31,14 +31,14 @@ class SteelSeriesArctisNova7 : public protocols::SteelSeriesNovaDevice SUPPORTED_PRODUCT_IDS { 0x2202, // Arctis Nova 7 (discrete battery: 0-4) - 0x22A1, // Arctis Nova 7 (percentage battery: 0-100, Jan 2026 update) + 0x22A1, // Arctis Nova 7 (percentage battery: 0-100, Jan. 2026 update) 0x227e, // Arctis Nova 7 Wireless Gen 2 (percentage battery: 0-100) 0x2206, // Arctis Nova 7x (discrete battery: 0-4) 0x2258, // Arctis Nova 7x v2 (percentage battery: 0-100) 0x229e, // Arctis Nova 7x v2 (percentage battery: 0-100) 0x223a, // Arctis Nova 7 Diablo IV (discrete battery: 0-4, before Jan 2026 update) 0x22a9, // Arctis Nova 7 Diablo IV (percentage battery: 0-100, after Jan 2026 update) - 0x227a // Arctis Nova 7 WoW Edition (discrete battery: 0-4) + 0x227a // Arctis Nova 7 WoW Edition (discrete battery: 0-4) }; static constexpr int EQUALIZER_BANDS = 10;