Preliminary support for Logitech FP8071

* Updated detection for differences in FP8071
This commit is contained in:
Chris M 2023-12-27 10:02:58 +11:00
parent 366adce39e
commit 7b454ce5f4
3 changed files with 180 additions and 12 deletions

View file

@ -168,6 +168,7 @@ void RGBController_LogitechLightspeed::SetupZones()
const std::string led_string = "LED";
uint8_t led_count = controller->lightspeed->getLED_count();
LOG_DEBUG("[%s] Setting up %d LEDs", name.c_str(), led_count);
if(led_count > 0)
{
for(size_t i = 0; i < led_count; i++)

View file

@ -17,7 +17,14 @@ const char* logitech_led_locations[] =
"Primary",
"Logo",
"Left",
"Right"
"Right",
"Combined",
"Group One",
"Group Two",
"Group Three",
"Group Four",
"Group Five",
"Group Six"
};
const int NUM_LOGITECH_LED_LOCATIONS = sizeof(logitech_led_locations);
@ -589,11 +596,11 @@ void logitech_device::getRGBconfig()
result = hid_write(dev_use2, get_count.buffer, get_count.size());
result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT);
LOG_DEBUG("[%s] FP8071 - LED Count - %02X : %02X %02X %04X %04X %04X %02X %02X %02X %02X %02X %02X %02X", device_name.c_str(),
response.data[2], response.data[0], response.data[1], (response.data[3] << 8 | response.data[4]), (response.data[5] << 8 | response.data[6]),
LOG_DEBUG("[%s] FP8071 - LED Count - %04X : %02X %04X %04X %04X %04X %02X %02X %02X %02X %02X %02X %02X", device_name.c_str(),
(response.data[1] << 8 | response.data[2]), response.data[0], (response.data[1] << 8 | response.data[2]), (response.data[3] << 8 | response.data[4]), (response.data[5] << 8 | response.data[6]),
(response.data[7] << 8 | response.data[8]), response.data[9], response.data[10], response.data[11], response.data[12], response.data[13], response.data[14], response.data[15]);
led_response = response.data[2];
led_response = (response.data[1] << 8 | response.data[2]);
for(size_t i = 0; i < led_response; i++)
{
get_count.data[0] = (uint8_t)i;
@ -602,7 +609,7 @@ void logitech_device::getRGBconfig()
result = hid_write(dev_use2, get_count.buffer, get_count.size());
result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT);
LOG_DEBUG("[%s] FP8071 - LED %02i - %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", device_name.c_str(), led_counter,
LOG_DEBUG("[%s] FP8071 - LED %02i - %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", device_name.c_str(), i,
response.data[0], response.data[1], response.data[2], response.data[3], response.data[4], response.data[5], response.data[6], response.data[7],
response.data[8], response.data[9], response.data[10], response.data[11], response.data[12], response.data[13], response.data[14], response.data[15]);
@ -617,7 +624,7 @@ void logitech_device::getRGBconfig()
fx_response.init();
longFAPrequest get_effect;
get_effect.init(device_index, RGB_feature_index, LOGITECH_CMD_RGB_EFFECTS_GET_INFO);
get_effect.init(device_index, RGB_feature_index, LOGITECH_CMD_RGB_EFFECTS_GET_COUNT);
get_effect.data[0] = get_count.data[0];
get_effect.data[1] = i;
@ -638,6 +645,10 @@ void logitech_device::getRGBconfig()
leds.emplace(response.data[0], new_led);
}
/*-----------------------------------------------------------------*\
| Set the config to SW control mode |
\*-----------------------------------------------------------------*/
set8071Effects(5);
}
/*get_count.feature_command = LOGITECH_CMD_RGB_EFFECTS_GET_STATE;
@ -682,7 +693,7 @@ uint8_t logitech_device::setDirectMode(bool direct)
| Turn the direct mode on or off via the RGB_feature_index |
\*-----------------------------------------------------------------*/
longFAPrequest set_direct;
set_direct.init(device_index, RGB_feature_index, LOGITECH_CMD_RGB_EFFECTS_UNKNOWN);
set_direct.init(device_index, RGB_feature_index, LOGITECH_FP8070_SET_SW_CTL);
set_direct.data[0] = (direct) ? 1 : 0;
set_direct.data[1] = set_direct.data[0];
@ -733,7 +744,13 @@ uint8_t logitech_device::setMode(uint8_t mode, uint16_t speed, uint8_t zone, uin
| Set the mode via the RGB_feature_index |
\*-----------------------------------------------------------------*/
longFAPrequest set_mode;
set_mode.init(device_index, RGB_feature_index, ((feature_page == LOGITECH_HIDPP_PAGE_RGB_EFFECTS1) ? LOGITECH_CMD_RGB_EFFECTS_SET_CONTROL : LOGITECH_CMD_RGB_EFFECTS_GET_INFO));
bool fp8070 = (feature_page == LOGITECH_HIDPP_PAGE_RGB_EFFECTS1);
set_mode.init(
device_index,
RGB_feature_index,
(fp8070 ? LOGITECH_FP8070_SET_EFFECT : LOGITECH_FP8071_SET_LED_EFFECT)
);
set_mode.data[0] = zone;
set_mode.data[1] = mode;
@ -741,12 +758,13 @@ uint8_t logitech_device::setMode(uint8_t mode, uint16_t speed, uint8_t zone, uin
set_mode.data[3] = green;
set_mode.data[4] = blue;
set_mode.data[12] = fp8070 ? 0x00 : 0x01; //Bit 2-3 Power Mode : Bit 1-0 Persistence
speed *= 100;
switch(fx)
{
case LOGITECH_DEVICE_LED_ON:
set_mode.data[5] = 0x02; //zone;
//set_mode.data[12] = 0x01; //Save to flash testing
//set_mode.data[5] = 0x02; //zone;
break;
case LOGITECH_DEVICE_LED_SPECTRUM:
@ -795,5 +813,108 @@ uint8_t logitech_device::setMode(uint8_t mode, uint16_t speed, uint8_t zone, uin
}
}
return result;
}
uint8_t logitech_device::set8071Effects(uint8_t control)
{
int result = 0;
/*-----------------------------------------------------------------*\
| Check the usage map for usage2 (0x11 Long FAP Message) |
| then set the device into direct mode via register 0x80 |
\*-----------------------------------------------------------------*/
hid_device* dev_use2 = getDevice(2);
if(dev_use2)
{
/*-----------------------------------------------------------------*\
| Create a buffer for reads |
\*-----------------------------------------------------------------*/
blankFAPmessage response;
response.init();
/*-----------------------------------------------------------------*\
| Turn the direct mode on or off via the RGB_feature_index |
\*-----------------------------------------------------------------*/
shortFAPrequest set_effects;
set_effects.init(device_index, RGB_feature_index);
set_effects.feature_command = LOGITECH_FP8071_CONTROL;
set_effects.data[0] = 1;
set_effects.data[1] = 3; //Disables all FW control for PWR (0x02) and RGB (0x01)
set_effects.data[2] = control;
/*-----------------------------------------------------*\
| Send packet |
| This code has to be protected to avoid crashes when |
| this is called at the same time to change a powerplay |
| mat and its paired wireless mouse leds. It will |
| happen when using effects engines with high framerate |
\*-----------------------------------------------------*/
if(mutex)
{
std::lock_guard<std::mutex> guard(*mutex);
result = hid_write(dev_use2, set_effects.buffer, set_effects.size());
result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT);
}
else
{
result = hid_write(dev_use2, set_effects.buffer, set_effects.size());
result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT);
}
}
return result;
}
uint8_t logitech_device::set8071TimeoutControl(uint8_t control)
{
int result = 0;
/*-----------------------------------------------------------------*\
| Check the usage map for usage2 (0x11 Long FAP Message) |
| then set the device into direct mode via register 0x80 |
\*-----------------------------------------------------------------*/
hid_device* dev_use2 = getDevice(2);
if(dev_use2)
{
/*-----------------------------------------------------------------*\
| Create a buffer for reads |
\*-----------------------------------------------------------------*/
blankFAPmessage response;
response.init();
/*-----------------------------------------------------------------*\
| Turn the direct mode on or off via the RGB_feature_index |
\*-----------------------------------------------------------------*/
longFAPrequest set_control;
set_control.init(device_index, RGB_feature_index, LOGITECH_FP8071_PWR_CFG);
set_control.data[0] = 1; //1;
set_control.data[3] = 0; //0x3C; //Inactive Lighting timeout MSB
set_control.data[4] = 5; //0x3C; //Inactive Lighting timeout LSB
set_control.data[5] = 0; //1; //Lights off timeout MSB
set_control.data[6] = 20; //0x2C; //Lights off timeout LSB
/*-----------------------------------------------------*\
| Send packet |
| This code has to be protected to avoid crashes when |
| this is called at the same time to change a powerplay |
| mat and its paired wireless mouse leds. It will |
| happen when using effects engines with high framerate |
\*-----------------------------------------------------*/
if(mutex)
{
std::lock_guard<std::mutex> guard(*mutex);
result = hid_write(dev_use2, set_control.buffer, set_control.size());
result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT);
}
else
{
result = hid_write(dev_use2, set_control.buffer, set_control.size());
result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT);
}
}
return(result);
}

View file

@ -52,7 +52,6 @@
#define LOGITECH_CMD_RGB_EFFECTS_SET_STATE 0x50
#define LOGITECH_CMD_RGB_EFFECTS_GET_CONFIG 0x60
#define LOGITECH_CMD_RGB_EFFECTS_SET_CONFIG 0x70
#define LOGITECH_CMD_RGB_EFFECTS_UNKNOWN 0x80 //Used to set "direct" mode
enum LOGITECH_DEVICE_TYPE
{
@ -79,6 +78,51 @@ enum LOGITECH_DEVICE_MODE
LOGITECH_DEVICE_LED_CUSTOM = 0x000C
};
enum LOGITECH_FP8070
{
LOGITECH_FP8070_INFO = 0x00,
LOGITECH_FP8070_ZONE_INFO = 0x10,
LOGITECH_FP8070_EFFECT_INFO = 0x20,
LOGITECH_FP8070_SET_EFFECT = 0x30,
LOGITECH_FP8070_SET_CFG = 0x40,
LOGITECH_FP8070_GET_CFG = 0x50,
LOGITECH_FP8070_GET_BIN_INFO = 0x60,
LOGITECH_FP8070_GET_SW_CTL = 0x70,
LOGITECH_FP8070_SET_SW_CTL = 0x80,
LOGITECH_FP8070_GET_STATUS = 0x90,
LOGITECH_FP8070_CLEAR_EFFECT = 0xA0,
LOGITECH_FP8070_SET_DIR = 0xB0,
LOGITECH_FP8070_GET_COLOUR = 0xC0,
LOGITECH_FP8070_SYNC_CFG = 0xD0,
LOGITECH_FP8070_GET_EFFECT = 0xE0,
LOGITECH_FP8070_SET_BIN_INFO = 0xF0,
};
enum LOGITECH_FP8071
{
LOGITECH_FP8071_INFO = 0x00,
LOGITECH_FP8071_SET_LED_EFFECT = 0x10,
LOGITECH_FP8071_ZONE_PATTERN = 0x20,
LOGITECH_FP8071_CONFIG = 0x30,
LOGITECH_FP8070_BIN_INFO = 0x40,
LOGITECH_FP8071_CONTROL = 0x50,
LOGITECH_FP8071_SYNC_CFG = 0x60,
LOGITECH_FP8071_PWR_CFG = 0x70,
LOGITECH_FP8071_PWR_MODE = 0x80,
LOGITECH_FP8071_SHUTDOWN = 0x90
};
enum LOGITECH_FP8071_FLAGS
{
FP8071_SUPPORTS_GET_STATUS = 0x01,
FP8071_RESERVED = 0x02,
FP8071_SUPPORTS_SET_BIN_INFO = 0x04,
FP8071_MONOCHROME_ONLY = 0x08,
FP8071_NO_SYNC_SUPPORT = 0x10,
FP8071_SUPPORTS_SHUTDOWN = 0x20,
FP8071_SUPPORTS_CLUSTER_CHANGED = 0x40,
};
extern const char* logitech_led_locations[];
extern const int NUM_LOGITECH_LED_LOCATIONS;
@ -122,7 +166,7 @@ union shortFAPrequest
this->report_id = LOGITECH_SHORT_MESSAGE;
this->device_index = device_index;
this->feature_index = feature_index;
this->feature_command = 0;
this->feature_command = feature_command;
for(size_t i = 0; i < sizeof(data); i++)
{
this->data[i] = 0;
@ -258,6 +302,8 @@ public:
logitech_led getLED_info(uint8_t LED_num);
uint8_t setDirectMode(bool direct);
uint8_t setMode(uint8_t mode, uint16_t speed, uint8_t zone, uint8_t red, uint8_t green, uint8_t blue, uint8_t brightness);
uint8_t set8071Effects(uint8_t control);
uint8_t set8071TimeoutControl(uint8_t control);
int getDeviceName();
private:
std::map<uint8_t, logitech_led> leds;