99
1010#include < iomanip>
1111#include < sstream>
12+ #include " LenovoDevices.h"
1213#include " LenovoUSBController_Gen7_8.h"
1314#include " StringUtils.h"
1415
1516using namespace std ;
1617
18+ static void SetGen10PayloadLength (uint16_t pid, uint8_t * buffer, uint16_t payload_length)
19+ {
20+ if (pid != LEGION_7GEN10)
21+ {
22+ return ;
23+ }
24+
25+ buffer[2 ] = payload_length & 0xFF ;
26+ buffer[3 ] = (payload_length >> 8 ) & 0xFF ;
27+ }
28+
1729LenovoGen7And8USBController::LenovoGen7And8USBController (hid_device* dev_handle, const char * path, uint16_t in_pid, std::string dev_name)
1830{
1931 dev = dev_handle;
@@ -44,54 +56,74 @@ string LenovoGen7And8USBController::getLocation()
4456
4557void LenovoGen7And8USBController::setLedsByGroup (uint8_t profile_id, vector<led_group> led_groups)
4658{
47- uint8_t buffer[PACKET_SIZE];
48- memset (buffer, 0x00 , PACKET_SIZE);
49-
50- size_t i = 0 ;
51- buffer[i++] = REPORT_ID;
52- buffer[i++] = SAVE_PROFILE;
53- buffer[i++] = 0xC0 ;
54- buffer[i++] = 0x03 ;
55- buffer[i++] = profile_id;
56- buffer[i++] = 0x01 ;
57- buffer[i++] = 0x01 ;
59+ if (led_groups.empty ())
60+ {
61+ return ;
62+ }
5863
59- for (size_t group = 0 ; group < led_groups.size () && i < PACKET_SIZE - 21 ; group++)
64+ /* ---------------------------------------------------------*\
65+ | Some devices require many groups for per-key updates. |
66+ | Send as many groups as fit in one report, then continue |
67+ | in additional reports. |
68+ \*---------------------------------------------------------*/
69+ size_t group = 0 ;
70+ while (group < led_groups.size ())
6071 {
61- buffer[i++] = (uint8_t )group + 1 ; // Group index
62- buffer[i++] = 0x06 ;
63- buffer[i++] = 0x01 ;
64- buffer[i++] = led_groups[group].mode ;
65- buffer[i++] = 0x02 ;
66- buffer[i++] = led_groups[group].speed ;
72+ uint8_t buffer[PACKET_SIZE];
73+ memset (buffer, 0x00 , PACKET_SIZE);
74+
75+ size_t i = 0 ;
76+ buffer[i++] = REPORT_ID;
77+ buffer[i++] = SAVE_PROFILE;
78+ buffer[i++] = 0xC0 ;
6779 buffer[i++] = 0x03 ;
68- buffer[i++] = led_groups[group].spin ;
69- buffer[i++] = 0x04 ;
70- buffer[i++] = led_groups[group].direction ;
71- buffer[i++] = 0x05 ;
72- buffer[i++] = led_groups[group].color_mode ;
73- buffer[i++] = 0x06 ;
74- buffer[i++] = 0x00 ;
80+ buffer[i++] = profile_id;
81+ buffer[i++] = 0x01 ;
82+ buffer[i++] = 0x01 ;
7583
76- buffer[i++] = (uint8_t )led_groups[group].colors .size ();
77- for (RGBColor c : led_groups[group].colors )
84+ for (; group < led_groups.size () && i < PACKET_SIZE - 21 ; group++)
7885 {
79- buffer[i++] = RGBGetRValue (c);
80- buffer[i++] = RGBGetGValue (c);
81- buffer[i++] = RGBGetBValue (c);
86+ buffer[i++] = (uint8_t )group + 1 ; // Group index
87+ buffer[i++] = 0x06 ;
88+ buffer[i++] = 0x01 ;
89+ buffer[i++] = led_groups[group].mode ;
90+ buffer[i++] = 0x02 ;
91+ buffer[i++] = led_groups[group].speed ;
92+ buffer[i++] = 0x03 ;
93+ buffer[i++] = led_groups[group].spin ;
94+ buffer[i++] = 0x04 ;
95+ buffer[i++] = led_groups[group].direction ;
96+ buffer[i++] = 0x05 ;
97+ buffer[i++] = led_groups[group].color_mode ;
98+ buffer[i++] = 0x06 ;
99+ buffer[i++] = 0x00 ;
100+
101+ buffer[i++] = (uint8_t )led_groups[group].colors .size ();
102+ for (RGBColor c : led_groups[group].colors )
103+ {
104+ buffer[i++] = RGBGetRValue (c);
105+ buffer[i++] = RGBGetGValue (c);
106+ buffer[i++] = RGBGetBValue (c);
107+ }
108+
109+ vector<uint16_t > leds = led_groups[group].leds ;
110+ size_t led_count = min (leds.size (), (PACKET_SIZE - i)/2 );
111+ buffer[i++] = (uint8_t )led_count;
112+ uint8_t * byte_ptr = reinterpret_cast <uint8_t *>(leds.data ());
113+ std::copy (byte_ptr, byte_ptr + led_count * sizeof (uint16_t ), buffer + i);
114+ i+= led_count * sizeof (uint16_t );
82115 }
83116
84- vector<uint16_t > leds = led_groups[group].leds ;
85- size_t led_count = min (leds.size (), (PACKET_SIZE - i)/2 );
86- buffer[i++] = (uint8_t )led_count;
87- uint8_t * byte_ptr = reinterpret_cast <uint8_t *>(leds.data ());
88- std::copy (byte_ptr, byte_ptr + led_count * sizeof (uint16_t ), buffer + i);
89- i+= led_count * sizeof (uint16_t );
117+ if (pid == LEGION_7GEN10)
118+ {
119+ SetGen10PayloadLength (pid, buffer, static_cast <uint16_t >(i - 4 ));
120+ }
121+ else
122+ {
123+ buffer[2 ] = (uint8_t )i;
124+ }
125+ sendFeatureReport (buffer, PACKET_SIZE);
90126 }
91-
92- buffer[2 ] = (uint8_t )i;
93-
94- sendFeatureReport (buffer, PACKET_SIZE);
95127}
96128
97129void LenovoGen7And8USBController::setLedsDirectOn (uint8_t profile_id)
@@ -107,6 +139,7 @@ void LenovoGen7And8USBController::setLedsDirectOn(uint8_t profile_id)
107139 buffer[i++] = 0x01 ;
108140 buffer[i++] = profile_id;
109141
142+ SetGen10PayloadLength (pid, buffer, 2 );
110143 sendFeatureReport (buffer, PACKET_SIZE);
111144}
112145
@@ -123,11 +156,43 @@ void LenovoGen7And8USBController::setLedsDirectOff(uint8_t profile_id)
123156 buffer[i++] = 0x02 ;
124157 buffer[i++] = profile_id;
125158
159+ SetGen10PayloadLength (pid, buffer, 2 );
126160 sendFeatureReport (buffer, PACKET_SIZE);
127161}
128162
129163void LenovoGen7And8USBController::setLedsDirect (std::vector<led> &leds, std::vector<RGBColor> &colors)
130164{
165+ if (pid == LEGION_7GEN10)
166+ {
167+ /* ---------------------------------------------------------*\
168+ | Gen10 uses 0x07/A1 direct updates, with payload length |
169+ | stored in bytes 2-3. |
170+ \*---------------------------------------------------------*/
171+ uint8_t buffer[PACKET_SIZE];
172+ memset (buffer, 0x00 , PACKET_SIZE);
173+
174+ size_t i = 0 ;
175+ buffer[i++] = REPORT_ID;
176+ buffer[i++] = DIRECT_MODE;
177+ buffer[i++] = 0x00 ;
178+ buffer[i++] = 0x00 ;
179+
180+ size_t count = 0 ;
181+ for (size_t index = 0 ; index < leds.size () && index < colors.size () && i + 5 <= PACKET_SIZE; index++)
182+ {
183+ buffer[i++] = leds[index].value & 0xFF ;
184+ buffer[i++] = leds[index].value >> 8 & 0xFF ;
185+ buffer[i++] = RGBGetRValue (colors[index]);
186+ buffer[i++] = RGBGetGValue (colors[index]);
187+ buffer[i++] = RGBGetBValue (colors[index]);
188+ count++;
189+ }
190+
191+ SetGen10PayloadLength (pid, buffer, static_cast <uint16_t >(count * 5 ));
192+ sendFeatureReport (buffer, PACKET_SIZE);
193+ return ;
194+ }
195+
131196 uint8_t buffer[PACKET_SIZE];
132197 memset (buffer, 0x00 , PACKET_SIZE);
133198
@@ -153,13 +218,15 @@ void LenovoGen7And8USBController::setLedsAllOff(uint8_t profile_id)
153218{
154219 uint8_t buffer[PACKET_SIZE] = {REPORT_ID, SAVE_PROFILE, 0xC0 , 0x03 , profile_id, 0x01 , 0x01 };
155220
221+ SetGen10PayloadLength (pid, buffer, 3 );
156222 sendFeatureReport (buffer, PACKET_SIZE);
157223}
158224
159225uint8_t LenovoGen7And8USBController::getCurrentProfileId ()
160226{
161227 uint8_t buffer[PACKET_SIZE] = {REPORT_ID, GET_ACTIVE_PROFILE, 0xC0 , 0x03 };
162228
229+ SetGen10PayloadLength (pid, buffer, 1 );
163230 vector<uint8_t > response = getFeatureReport (buffer, PACKET_SIZE);
164231
165232 return response.size ()>4 ?response[4 ]:0x01 ;
@@ -169,6 +236,7 @@ uint8_t LenovoGen7And8USBController::getCurrentBrightness()
169236{
170237 uint8_t buffer[PACKET_SIZE] = {REPORT_ID, GET_BRIGHTNESS, 0xC0 , 0x03 };
171238
239+ SetGen10PayloadLength (pid, buffer, 1 );
172240 vector<uint8_t > response = getFeatureReport (buffer, PACKET_SIZE);
173241
174242 return response.size ()>4 ?response[4 ]:0x00 ;
@@ -179,20 +247,23 @@ void LenovoGen7And8USBController::setBrightness(uint8_t brightness)
179247{
180248 uint8_t buffer[PACKET_SIZE] = {REPORT_ID, SET_BRIGHTNESS, 0xC0 , 0x03 , brightness};
181249
250+ SetGen10PayloadLength (pid, buffer, 1 );
182251 sendFeatureReport (buffer, PACKET_SIZE);
183252}
184253
185254void LenovoGen7And8USBController::switchProfileTo (uint8_t profile_id)
186255{
187256 uint8_t buffer[PACKET_SIZE] = {REPORT_ID, SWITCH_PROFILE, 0xC0 , 0x03 , profile_id};
188257
258+ SetGen10PayloadLength (pid, buffer, 1 );
189259 sendFeatureReport (buffer, PACKET_SIZE);
190260}
191261
192262std::vector<led_group> LenovoGen7And8USBController::getProfileSettings (uint8_t profile_id)
193263{
194264 uint8_t buffer[PACKET_SIZE] = {REPORT_ID, GET_PROFILE, 0xC0 , 0x03 , profile_id};
195265
266+ SetGen10PayloadLength (pid, buffer, PACKET_SIZE - 4 );
196267 vector<uint8_t > response = getFeatureReport (buffer, PACKET_SIZE);
197268
198269 vector<led_group> groups;
0 commit comments