11/* ---------------------------------------------------------*\
22| SteelSeriesApexController.cpp |
33| |
4- | Driver for SteelSeries Apex 7 |
4+ | Driver for SteelSeries Apex Keyboards |
5+ | |
6+ | New driver based on SignalRGB Plugins |
7+ | https://gitlab.com/signalrgb/signal-plugins/ |
58| |
69| Eric Samuelson (edbgon) 05 Jul 2020 |
10+ | Filipe S. (filipesn) 5 Jan 2026 |
711| |
812| This file is part of the OpenRGB project |
913| SPDX-License-Identifier: GPL-2.0-or-later |
1014\*---------------------------------------------------------*/
1115
1216#include < cstring>
17+ #include < cstdio>
1318#include " SteelSeriesApexController.h"
19+ #include " LogManager.h"
1420
1521using namespace std ::chrono_literals;
1622
23+ #define FIRMWARE_REQ_LEN 645
24+
1725static unsigned int keys[] = {0x04 , 0x05 , 0x06 , 0x07 , 0x08 , 0x09 , 0x0A , 0x0B , 0x0C , 0x0D ,
1826 0x0E , 0x0F , 0x10 , 0x11 , 0x12 , 0x13 , 0x14 , 0x15 , 0x16 , 0x17 , // 20
1927 0x18 , 0x19 , 0x1A , 0x1B , 0x1C , 0x1D , 0x1E , 0x1F , 0x20 , 0x21 ,
@@ -29,7 +37,10 @@ static unsigned int keys[] = {0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x
2937
3038SteelSeriesApexController::SteelSeriesApexController (hid_device* dev_handle, steelseries_type type, const char * path, std::string dev_name) : SteelSeriesApexBaseController(dev_handle, path, dev_name)
3139{
32- proto_type = type;
40+ proto_type = type;
41+ use_new_protocol = false ;
42+
43+ SendInitialization ();
3344}
3445
3546SteelSeriesApexController::~SteelSeriesApexController ()
@@ -55,8 +66,23 @@ void SteelSeriesApexController::SetLEDsDirect(std::vector<RGBColor> colors)
5566 unsigned char buf[643 ];
5667 int num_keys = 0 ;
5768
69+ unsigned char packet_id = APEX_PACKET_ID_DIRECT;
70+
5871 num_keys = sizeof (keys) / sizeof (*keys);
5972
73+ if (use_new_protocol)
74+ {
75+ struct hid_device_info * info = hid_get_device_info (dev);
76+ if (info && (info->product_id == 0x162C || info->product_id == 0x162D )) // Aparently Gen 3 wireless models reuse this protocol, make sure to place their PID here and further below when developing.
77+ {
78+ packet_id = APEX_2023_PACKET_ID_DIRECT_WIRELESS;
79+ }
80+ else
81+ {
82+ packet_id = APEX_2023_PACKET_ID_DIRECT;
83+ }
84+ }
85+
6086 /* -----------------------------------------------------*\
6187 | Zero out buffer |
6288 \*-----------------------------------------------------*/
@@ -66,8 +92,8 @@ void SteelSeriesApexController::SetLEDsDirect(std::vector<RGBColor> colors)
6692 | Set up Direct packet |
6793 \*-----------------------------------------------------*/
6894 buf[0x00 ] = 0 ;
69- buf[0x01 ] = APEX_PACKET_ID_DIRECT ;
70- buf[0x02 ] = num_keys;
95+ buf[0x01 ] = packet_id ;
96+ buf[0x02 ] = (use_new_protocol) ? ( unsigned char )colors. size () : num_keys;
7197
7298 /* -----------------------------------------------------*\
7399 | Fill in color data |
@@ -106,3 +132,96 @@ void SteelSeriesApexController::SelectProfile
106132 buf[0x02 ] = profile;
107133 hid_send_feature_report (dev, buf, 65 );
108134}
135+
136+ void SteelSeriesApexController::SendInitialization ()
137+ {
138+ unsigned char buf[FIRMWARE_REQ_LEN];
139+ unsigned char read_buf[65 ];
140+ int res = 0 ;
141+ char version_str[32 ] = " Unknown" ;
142+
143+ struct hid_device_info * info = hid_get_device_info (dev);
144+ unsigned short pid = (info) ? info->product_id : 0 ;
145+
146+ // Firmware check
147+ if (pid == 0x1628 )
148+ {
149+ /* -----------------------------------------------------*\
150+ | Zero out buffer |
151+ \*-----------------------------------------------------*/
152+ memset (buf, 0x00 , sizeof (buf));
153+ buf[0x00 ] = 0x00 ;
154+ buf[0x01 ] = 0x90 ;
155+
156+ /* -----------------------------------------------------*\
157+ | Send packet |
158+ \*-----------------------------------------------------*/
159+ hid_write (dev, buf, 65 );
160+
161+ /* -----------------------------------------------------*\
162+ | Read Response |
163+ \*-----------------------------------------------------*/
164+ memset (read_buf, 0x00 , sizeof (read_buf));
165+ res = hid_read_timeout (dev, read_buf, sizeof (read_buf), 200 );
166+
167+ /* -----------------------------------------------------*\
168+ | Firmware Check |
169+ \*-----------------------------------------------------*/
170+ if (res > 2 && read_buf[0 ] == 0x90 )
171+ {
172+ int major = 0 , minor = 0 , patch = 0 ;
173+ char * fw_ptr = (char *)&read_buf[2 ];
174+
175+ snprintf (version_str, sizeof (version_str), " %s" , fw_ptr);
176+
177+ int count = sscanf (version_str, " %d.%d.%d" , &major, &minor, &patch);
178+
179+ if (count == 3 )
180+ {
181+ // Currently set to 1.19.7 or newer.
182+ if (major > 1 )
183+ {
184+ use_new_protocol = true ;
185+ }
186+ else if (major == 1 )
187+ {
188+ if (minor > 19 )
189+ {
190+ use_new_protocol = true ;
191+ }
192+ else if (minor == 19 && patch >= 7 )
193+ {
194+ use_new_protocol = true ;
195+ }
196+ }
197+ }
198+ }
199+ }
200+ // // Aparently Gen 3 models reuse this protocol, make sure to place their PID here and further above for wireless when developing.
201+ else if (pid == 0x162C || pid == 0x162D )
202+ {
203+ use_new_protocol = true ;
204+ }
205+
206+ /* -----------------------------------------------------*\
207+ | Send Initialization packet on new protocol. |
208+ \*-----------------------------------------------------*/
209+ if (use_new_protocol)
210+ {
211+ memset (buf, 0x00 , sizeof (buf));
212+ buf[0x00 ] = 0x00 ;
213+ buf[0x01 ] = APEX_2023_PACKET_ID_INIT;
214+ hid_send_feature_report (dev, buf, APEX_2023_PACKET_LENGTH);
215+
216+ LOG_DEBUG (" [%s] Using Apex 2023 protocol. FW: %s" , name.c_str (), version_str);
217+ }
218+ else
219+ {
220+ LOG_DEBUG (" [%s] Using Apex Legacy protocol. FW: %s" , name.c_str (), version_str);
221+ }
222+ }
223+
224+ std::string SteelSeriesApexController::GetSerial ()
225+ {
226+ return " 64865" ;
227+ }
0 commit comments