From 568da43bb6d9aec94fac577a7f44126d7ba57197 Mon Sep 17 00:00:00 2001 From: Wayne Riordan Date: Tue, 9 Jan 2024 21:41:53 +0000 Subject: [PATCH] Initial commit to add Lenovo Legion M300 RGB Mouse Added support for Lenovo Legion M300 RGB Mouse. Added all supported modes Static, Rainbow, Breathing and Off Also Tested all modes to verify its working --- .../LenovoM300Controller.cpp | 86 +++++++++++++ .../LenovoControllers/LenovoM300Controller.h | 44 +++++++ .../LenovoControllers/LenovoMouseDetect.cpp | 36 ++++++ .../RGBController_LenovoM300.cpp | 116 ++++++++++++++++++ .../RGBController_LenovoM300.h | 32 +++++ 5 files changed, 314 insertions(+) create mode 100644 Controllers/LenovoControllers/LenovoM300Controller.cpp create mode 100644 Controllers/LenovoControllers/LenovoM300Controller.h create mode 100644 Controllers/LenovoControllers/LenovoMouseDetect.cpp create mode 100644 Controllers/LenovoControllers/RGBController_LenovoM300.cpp create mode 100644 Controllers/LenovoControllers/RGBController_LenovoM300.h diff --git a/Controllers/LenovoControllers/LenovoM300Controller.cpp b/Controllers/LenovoControllers/LenovoM300Controller.cpp new file mode 100644 index 00000000..a344982a --- /dev/null +++ b/Controllers/LenovoControllers/LenovoM300Controller.cpp @@ -0,0 +1,86 @@ +/*-----------------------------------*\ +| LenovoM300Controller.cpp | +| | +| Controller For Lenovo Legion M300 | +| Mouse | +| | +| Wayne Riordan 9 Jan 2024 | +\*-----------------------------------*/ + +#include "LenovoM300Controller.h" +#include + +using namespace std; + +LenovoM300Controller::LenovoM300Controller(hid_device* dev_handle, const hid_device_info& info) +{ + device = dev_handle; + location = info.path; +} + +LenovoM300Controller::~LenovoM300Controller() +{ + hid_close(device); +} + +std::string LenovoM300Controller::GetDeviceLocation() +{ + return("HID: " + location); +} + +void LenovoM300Controller::SetMode(std::vector colors, unsigned char mode_value, unsigned int brigthness) +{ + unsigned char usb_buf[M300_DATA_SIZE]; + memset(usb_buf, 0x00, M300_DATA_SIZE); + + usb_buf[0x01] = 0x25; + usb_buf[0x03] = 0x01; + usb_buf[0x04] = 0x01; + usb_buf[0x05] = 0x0C; + + switch(mode_value) + { + case M300_MODE_RAINBOW: + usb_buf[0x06] = 0x01; + usb_buf[0x07] = 0x64; + usb_buf[0x09] = 0x0A; + usb_buf[0x40] = CalculateFinalByte(usb_buf, 0x0A); + break; + case M300_MODE_BREATHING: + usb_buf[0x06] = 0x02; + usb_buf[0x07] = 0x64; + usb_buf[0x09] = 0x02; + usb_buf[0x0A] = 0x03; + usb_buf[0x0C] = RGBGetRValue(colors[0]); + usb_buf[0x0D] = RGBGetGValue(colors[0]); + usb_buf[0x0E] = RGBGetBValue(colors[0]); + usb_buf[0x0F] = RGBGetRValue(colors[1]); + usb_buf[0x10] = RGBGetGValue(colors[1]); + usb_buf[0x11] = RGBGetBValue(colors[1]); + usb_buf[0x40] = CalculateFinalByte(usb_buf, 0x12); + break; + case M300_MODE_STATIC: + usb_buf[0x06] = 0x03; + usb_buf[0x07] = brigthness; + usb_buf[0x09] = RGBGetRValue(colors[0]); + usb_buf[0x0A] = RGBGetGValue(colors[0]); + usb_buf[0x0B] = RGBGetBValue(colors[0]); + usb_buf[0x40] = CalculateFinalByte(usb_buf, 0x0C); + break; + case M300_MODE_OFF: + default: + usb_buf[0x06] = 0x03; + usb_buf[0x40] = 0x36; + } + hid_write(device, usb_buf, M300_DATA_SIZE); +} + +unsigned char LenovoM300Controller::CalculateFinalByte(unsigned char* ptr, int count) +{ + unsigned char final_byte = 0; + for(int i = 0; i < count; i++) + { + final_byte += ptr[i]; + } + return final_byte; +} diff --git a/Controllers/LenovoControllers/LenovoM300Controller.h b/Controllers/LenovoControllers/LenovoM300Controller.h new file mode 100644 index 00000000..f14ced2d --- /dev/null +++ b/Controllers/LenovoControllers/LenovoM300Controller.h @@ -0,0 +1,44 @@ +/*-----------------------------------*\ +| LenovoM300Controller.h | +| | +| Header file for Lenovo M300 Mouse | +| controller | +| | +| Wayne Riordan 9 Jan 2024 | +\*-----------------------------------*/ +#pragma once + +#include "RGBController.h" +#include +#include + +#define M300_DATA_SIZE 0x41 +#define M300_MAX_BRIGTH 0x64 +#define M300_MIN_BRIGHT 0x01 + +enum +{ + M300_MODE_OFF = 0x00, + M300_MODE_RAINBOW = 0x01, + M300_MODE_BREATHING = 0x02, + M300_MODE_STATIC = 0X03 +}; + +class LenovoM300Controller +{ +public: + LenovoM300Controller(hid_device* dev_handle, const hid_device_info& info); + ~LenovoM300Controller(); + + std::string GetDeviceLocation(); + + void SetMode(std::vector colors, unsigned char mode_value, unsigned int brightness); + +protected: + hid_device* device; + +private: + std::string location; + + unsigned char CalculateFinalByte(unsigned char* ptr, int count); +}; diff --git a/Controllers/LenovoControllers/LenovoMouseDetect.cpp b/Controllers/LenovoControllers/LenovoMouseDetect.cpp new file mode 100644 index 00000000..9e4775fb --- /dev/null +++ b/Controllers/LenovoControllers/LenovoMouseDetect.cpp @@ -0,0 +1,36 @@ +/*-----------------------------------*\ +| LenovoMouseDetect.h | +| | +| Detect Lenovo Mouse | +| | +| Wayne Riordan 9 Jan 2024 | +\*-----------------------------------*/ + +#include "Detector.h" +#include "RGBController_LenovoM300.h" +#include "LenovoM300Controller.h" + +/*---------------------------------------------------------*\ +| Lenovo vendor, product, usage and page IDs | +\*---------------------------------------------------------*/ +#define LENOVO_VID 0x17EF +#define LEGION_M300_PID 0x60E4 +#define LENOVO_USAGE 0X01 +#define LENOVO_PAGE 0XFF01 + +void DetectLenovoLegionM300Controllers(hid_device_info* info, const std::string& name) +{ + hid_device* dev = hid_open_path(info->path); + + if(dev) + { + LenovoM300Controller* controller = new LenovoM300Controller(dev, *info); + RGBController_LenovoM300* rgb_controller = new RGBController_LenovoM300(controller); + rgb_controller->name = name; + + ResourceManager::get()->RegisterRGBController(rgb_controller); + + } +} + +REGISTER_HID_DETECTOR_PU("Lenovo Legion M300", DetectLenovoLegionM300Controllers, LENOVO_VID, LEGION_M300_PID, LENOVO_PAGE, LENOVO_USAGE); diff --git a/Controllers/LenovoControllers/RGBController_LenovoM300.cpp b/Controllers/LenovoControllers/RGBController_LenovoM300.cpp new file mode 100644 index 00000000..133c4cab --- /dev/null +++ b/Controllers/LenovoControllers/RGBController_LenovoM300.cpp @@ -0,0 +1,116 @@ +/*-----------------------------------*\ +| RGBController_LenovoM300.cpp | +| | +| RGB Controller For Lenovo M300 | +| Mouse | +| | +| Wayne Riordan 9 Jan 2024 | +\*-----------------------------------*/ +#include "RGBController_LenovoM300.h" + +/**------------------------------------------------------------------*\ + @name Lenovo Legion M300 + @category Mouse + @type USB + @save :robot: + @direct :x: + @effects :white_check_mark: + @detectors DetectLenovoLegionM300Controllers + @comment +\*-------------------------------------------------------------------*/ + +RGBController_LenovoM300::RGBController_LenovoM300(LenovoM300Controller* controller_ptr) +{ + controller = controller_ptr; + name = "Lenovo Legion M300"; + vendor = "Lenovo"; + type = DEVICE_TYPE_MOUSE; + description = name; + location = controller->GetDeviceLocation(); + + mode Static; + Static.name = "Static"; + Static.value = M300_MODE_STATIC; + Static.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE; + Static.brightness_max = M300_MAX_BRIGTH; + Static.brightness_min = M300_MIN_BRIGHT; + Static.brightness = M300_MAX_BRIGTH; + Static.color_mode = MODE_COLORS_MODE_SPECIFIC; + Static.colors.resize(1); + modes.push_back(Static); + + mode Off; + Off.name = "Off"; + Off.value = M300_MODE_OFF; + Off.flags = MODE_FLAG_AUTOMATIC_SAVE; + Off.color_mode = MODE_COLORS_NONE; + modes.push_back(Off); + + mode Breathing; + Breathing.name = "Breathing"; + Breathing.value = M300_MODE_BREATHING; + Breathing.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE; + Breathing.brightness_max = M300_MAX_BRIGTH; + Breathing.brightness_min = M300_MIN_BRIGHT; + Breathing.brightness = M300_MAX_BRIGTH; + Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC; + Breathing.colors.resize(2); + modes.push_back(Breathing); + + mode Spectrum; + Spectrum.name = "Spectrum Cycle"; + Spectrum.value = M300_MODE_RAINBOW; + Spectrum.flags = MODE_FLAG_AUTOMATIC_SAVE; + Spectrum.color_mode = MODE_COLORS_NONE; + modes.push_back(Spectrum); + + SetupZones(); +} + +RGBController_LenovoM300::~RGBController_LenovoM300() +{ + delete controller; +} + +void RGBController_LenovoM300::SetupZones() +{ + zone default_zone; + default_zone.name = "Mouse"; + default_zone.type = ZONE_TYPE_SINGLE; + default_zone.leds_min = 1; + default_zone.leds_max = 1; + default_zone.leds_count = 1; + default_zone.matrix_map = nullptr; + zones.emplace_back(default_zone); + + leds.resize(1); + leds[0].name = "LED 1"; + + SetupColors(); +} + +void RGBController_LenovoM300::ResizeZone(int zone, int new_size) +{ + // Not Supported +} + +void RGBController_LenovoM300::DeviceUpdateLEDs() +{ + const mode& active = modes[active_mode]; + controller->SetMode(active.colors, active.value, active.brightness); +} + +void RGBController_LenovoM300::UpdateZoneLEDs(int zone) +{ + DeviceUpdateLEDs(); +} + +void RGBController_LenovoM300::UpdateSingleLED(int led) +{ + DeviceUpdateLEDs(); +} + +void RGBController_LenovoM300::DeviceUpdateMode() +{ + DeviceUpdateLEDs(); +} diff --git a/Controllers/LenovoControllers/RGBController_LenovoM300.h b/Controllers/LenovoControllers/RGBController_LenovoM300.h new file mode 100644 index 00000000..c853b63e --- /dev/null +++ b/Controllers/LenovoControllers/RGBController_LenovoM300.h @@ -0,0 +1,32 @@ +/*-----------------------------------*\ +| RGBController_LenovoM300.h | +| | +| Header file for Lenovo M300 Mouse | +| RGB Controller | +| | +| Wayne Riordan 9 Jan 2024 | +\*-----------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "LenovoM300Controller.h" + +class RGBController_LenovoM300 : public RGBController +{ +public: + RGBController_LenovoM300(LenovoM300Controller* controller_ptr); + ~RGBController_LenovoM300(); + + void SetupZones(); + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void DeviceUpdateMode(); + +private: + LenovoM300Controller* controller; +};