+ Started implementation of MSI Mystic Light USB controllers.

master
Nagy Tam?s (T-bond) 6 years ago committed by Adam Honse
parent 1f91dd227f
commit 37241ee6f2

@ -0,0 +1,156 @@
/*-----------------------------------------*\
| MSIMysticLightController.cpp |
| |
| Driver for MSI Mystic Light USB |
| lighting controller |
| |
| T-bond 3/4/2020 |
\*-----------------------------------------*/
#include "MSIMysticLightController.h"
#include <algorithm>
#include <array>
#include <bitset>
MSIMysticLightController::MSIMysticLightController(hid_device* handle, const char *path)
{
dev = handle;
if( dev )
{
loc = path;
}
}
MSIMysticLightController::~MSIMysticLightController()
{
if( dev )
{
hid_close(dev);
}
}
unsigned int MSIMysticLightController::GetZoneMinLedCount(ZONE zone)
{
return 1;
}
unsigned int MSIMysticLightController::GetZoneMaxLedCount(ZONE zone)
{
switch (zone)
{
case ZONE::J_RAINBOW_1:
case ZONE::J_RAINBOW_2:
case ZONE::J_CORSAIR:
return 1; // TODO: Handle multiple leds
break;
default:
return 1;
}
}
unsigned int MSIMysticLightController::GetZoneLedCount(ZONE zone)
{
return GetZoneMaxLedCount(zone); // TODO: Handle multiple leds
}
void MSIMysticLightController::SetMode(ZONE zone, EFFECT mode, SPEED speed, BRIGHTNESS brightness, bool rainbow_color)
{
ZoneData* zoneData = GetZoneData(zone);
if(!zoneData)
{
return;
}
zoneData->effect = mode;
zoneData->speedAndBrightnessFlags = (zoneData->speedAndBrightnessFlags & 128) | brightness << 2 | speed;
zoneData->colorFlags = static_cast<unsigned char>(std::bitset<8>(zoneData->colorFlags).set(7, !rainbow_color).to_ulong());
}
std::string MSIMysticLightController::GetDeviceName()
{
return(name);
}
std::string MSIMysticLightController::GetFWVersion()
{
return(version);
}
std::string MSIMysticLightController::GetDeviceLocation()
{
return(loc);
}
std::string MSIMysticLightController::GetSerial()
{
return(chip_id);
}
bool MSIMysticLightController::Update()
{
return hid_send_feature_report(dev, reinterpret_cast<unsigned char *>(&data), sizeof data) == sizeof data;
}
void MSIMysticLightController::SetSendLedSettings(bool send)
{
data.send_led_data = send;
}
void MSIMysticLightController::SetZoneColor(ZONE zone, unsigned char r1, unsigned char g1, unsigned char b1, unsigned char r2, unsigned char g2, unsigned char b2)
{
ZoneData* zoneData = GetZoneData(zone);
if(!zoneData)
{
return;
}
zoneData->color.R = r1;
zoneData->color.G = g1;
zoneData->color.B = b1;
zoneData->color2.R = r2;
zoneData->color2.G = g2;
zoneData->color2.B = b2;
}
ZoneData *MSIMysticLightController::GetZoneData(ZONE zone)
{
switch (zone)
{
case ZONE::J_RGB_1:
return &data.j_rgb_1;
case ZONE::J_RGB_2:
return &data.j_rgb_2;
case ZONE::J_RAINBOW_1:
return &data.j_rainbow_1;
case ZONE::J_RAINBOW_2:
return &data.j_rainbow_2;
case ZONE::J_PIPE_1:
return &data.j_pipe_1;
case ZONE::J_PIPE_2:
return &data.j_pipe_2;
case ZONE::ON_BOARD_LED:
return &data.on_board_led;
case ZONE::ON_BOARD_LED_1:
return &data.on_board_led_1;
case ZONE::ON_BOARD_LED_2:
return &data.on_board_led_2;
case ZONE::ON_BOARD_LED_3:
return &data.on_board_led_3;
case ZONE::ON_BOARD_LED_4:
return &data.on_board_led_4;
case ZONE::ON_BOARD_LED_5:
return &data.on_board_led_5;
case ZONE::ON_BOARD_LED_6:
return &data.on_board_led_6;
case ZONE::ON_BOARD_LED_7:
return &data.on_board_led_7;
case ZONE::ON_BOARD_LED_8:
return &data.on_board_led_8;
case ZONE::ON_BOARD_LED_9:
return &data.on_board_led_9;
}
return nullptr;
}

@ -0,0 +1,191 @@
/*-----------------------------------------*\
| MSIMysticLightController.h |
| |
| Definitions and types for MSI Mystic |
| Light USB lighting controllers |
| |
| T-bond 3/4/2020 |
\*-----------------------------------------*/
#include "RGBController.h"
#include <cstring>
#include <hidapi/hidapi.h>
#include <limits>
#pragma once
enum ZONE
{
J_RGB_1 = 1,
J_RGB_2 = 174,
J_PIPE_1 = 11,
J_PIPE_2 = 21,
J_RAINBOW_1 = 31,
J_RAINBOW_2 = 42,
J_CORSAIR = 53,
J_CORSAIR_OUTERLL120 = 64,
ON_BOARD_LED = 74,
ON_BOARD_LED_1 = 84,
ON_BOARD_LED_2 = 94,
ON_BOARD_LED_3 = 104,
ON_BOARD_LED_4 = 114,
ON_BOARD_LED_5 = 124,
ON_BOARD_LED_6 = 134,
ON_BOARD_LED_7 = 144,
ON_BOARD_LED_8 = 154,
ON_BOARD_LED_9 = 164
};
struct ZoneDescription
{
std::string name;
ZONE value;
};
enum EFFECT
{
DISABLE,
STATIC,
BREATHING,
Flashing,
DoubleFlashing,
Lighting,
MSIMarquee,
Meteor,
WaterDrop,
MSIRainbow,
POP,
RAP,
JAZZ,
Play,
Movie,
ColorRing,
Planetary,
DoubleMeteor,
Energy,
Blink,
Clock,
ColorPulse,
ColorShift,
ColorWave,
Marquee,
Rainbow,
RainbowWave,
Visor,
JRainbow,
RainbowFlahing,
RainbowDoubleFlashing,
Random,
FANControl,
Disable2,
ColorRingFlashing,
ColorRingDoubleFlashing,
Stack,
CorsairiQUE,
Fire,
Lava
};
enum SPEED
{
LOW,
MEDIUM,
HIGH
};
enum BRIGHTNESS
{
OFF,
LEVEL_10,
LEVEL_20,
LEVEL_30,
LEVEL_40,
LEVEL_50,
LEVEL_60,
LEVEL_70,
LEVEL_80,
LEVEL_90,
LEVEL_100
};
struct Color
{
unsigned char R;
unsigned char G;
unsigned char B;
};
struct ZoneData
{
unsigned char effect = EFFECT::STATIC;
Color color { std::numeric_limits<unsigned char>::max(), 0, 0 };
unsigned char speedAndBrightnessFlags = 40;
Color color2 { 0, std::numeric_limits<unsigned char>::max(), 0 };
unsigned char colorFlags = 128;
const unsigned char padding = 0;
};
struct RainbowZoneData : ZoneData
{
unsigned char cycleNum = 20;
};
struct FeaturePacket
{
const unsigned char report_id = 82; // Report ID
ZoneData j_rgb_1; // 1
ZoneData j_pipe_1; // 11
ZoneData j_pipe_2; // 21
RainbowZoneData j_rainbow_1; // 31
RainbowZoneData j_rainbow_2; // 42
RainbowZoneData j_corsair; // 53
ZoneData j_corsair_outerll120; // 64
ZoneData on_board_led; // 74
ZoneData on_board_led_1; // 84
ZoneData on_board_led_2; // 94
ZoneData on_board_led_3; // 104
ZoneData on_board_led_4; // 114
ZoneData on_board_led_5; // 124
ZoneData on_board_led_6; // 134
ZoneData on_board_led_7; // 144
ZoneData on_board_led_8; // 154
ZoneData on_board_led_9; // 164
ZoneData j_rgb_2; // 174
unsigned char send_led_data = 0; // 184
};
class MSIMysticLightController
{
public:
MSIMysticLightController(hid_device* handle, const char *path);
~MSIMysticLightController();
unsigned int GetZoneMinLedCount(ZONE zone);
unsigned int GetZoneMaxLedCount(ZONE zone);
unsigned int GetZoneLedCount(ZONE zone);
void SetMode(ZONE zone, EFFECT mode, SPEED speed, BRIGHTNESS brightness, bool rainbow_color);
void SetZoneColor(ZONE zone, unsigned char r1, unsigned char g1, unsigned char b1, unsigned char r2, unsigned char g2, unsigned char b2);
bool Update();
std::string GetDeviceName();
std::string GetDeviceLocation();
std::string GetFWVersion();
std::string GetSerial();
private:
bool UpdateController();
void SetSendLedSettings(bool send);
ZoneData* GetZoneData(ZONE zone);
hid_device* dev;
std::string name;
std::string loc;
std::string version;
std::string chip_id;
FeaturePacket data;
};

@ -0,0 +1,90 @@
#include "MSIMysticLightController.h"
#include "RGBController_MSIMysticLight.h"
#include <algorithm>
#define MSI_VID 0x1462
constexpr unsigned short SupportedPIDs[41] =
{
31847, // MS_7C67
31504, // MS_7B10
31879, // MS_7C87
31635, // MS_7B93
31796, // MS_7C34
31797, // MS_7C35
31798, // MS_7C36
31799, // MS_7C37
31810, // MS_7C42
31876, // MS_7C84
31636, // MS_7B94
31638, // MS_7B96
31833, // MS_7C59
31840, // MS_7C60
31856, // MS_7C70
31857, // MS_7C71
31859, // MS_7C73
31861, // MS_7C75
31862, // MS_7C76
31863, // MS_7C77
31865, // MS_7C79
31872, // MS_7C80
31896, // MS_7C98
31897, // MS_7C99
31873, // MS_7C81
31874, // MS_7C82
31875, // MS_7C83
31877, // MS_7C85
31878, // MS_7C86
31880, // MS_7C88
31881, // MS_7C89
17497, // MS_4459
16036, // MS_3EA4
36957, // MS_905D
31888, // MS_7C90
31889, // MS_7C91
31890, // MS_7C92
31892, // MS_7C94
31893, // MS_7C95
31894, // MS_7C96
31830 // MS_7C56
};
/******************************************************************************************\
* *
* DetectMSIMysticLightControllers *
* *
* Detect MSI Mystic Light devices that use NCT6775 RGB controllers *
* *
\******************************************************************************************/
void DetectMSIMysticLightControllers(std::vector<RGBController*> &rgb_controllers)
{
if(hid_init() < 0)
{
return;
}
hid_device_info * device_list = hid_enumerate(MSI_VID, 0);
if(!device_list)
{
return;
}
hid_device_info * device = device_list;
while(device)
{
if(std::find(std::begin(SupportedPIDs), std::end(SupportedPIDs), device->product_id) != std::end(SupportedPIDs))
{
hid_device * dev = hid_open_path(device->path);
if(dev)
{
MSIMysticLightController * controller = new MSIMysticLightController(dev, device_list->path);
RGBController_MSIMysticLight * rgb_controller = new RGBController_MSIMysticLight(controller);
rgb_controllers.push_back(rgb_controller);
}
}
device = device->next;
}
hid_free_enumeration(device_list);
}

@ -293,6 +293,7 @@ void DetectPatriotViperControllers(std::vector<i2c_smbus_interface*> &busses, st
void DetectPolychromeControllers(std::vector<i2c_smbus_interface*>& busses, std::vector<RGBController*>& rgb_controllers);
void DetectRGBFusionControllers(std::vector<i2c_smbus_interface*>& busses, std::vector<RGBController*>& rgb_controllers);
void DetectRGBFusionGPUControllers(std::vector<i2c_smbus_interface*>& busses, std::vector<RGBController*>& rgb_controllers);
void DetectMSIMysticLightControllers(std::vector<RGBController*> &rgb_controllers);
void DetectMSIRGBControllers(std::vector<RGBController*> &rgb_controllers);
void DetectAuraAddressableControllers(std::vector<RGBController*> &rgb_controllers);
void DetectLEDStripControllers(std::vector<RGBController*> &rgb_controllers);
@ -335,6 +336,7 @@ void DetectRGBControllers(void)
DetectRGBFusionGPUControllers(busses, rgb_controllers);
DetectRGBFusionControllers(busses, rgb_controllers);
DetectMSIMysticLightControllers(rgb_controllers);
DetectMSIRGBControllers(rgb_controllers);
DetectAuraAddressableControllers(rgb_controllers);

@ -45,6 +45,7 @@ INCLUDEPATH += \
Controllers/HyperXKeyboardController/ \
Controllers/LEDStripController/ \
Controllers/MSI3ZoneController/ \
Controllers/MSIMysticLightController/ \
Controllers/MSIRGBController/ \
Controllers/NZXTKrakenController/ \
Controllers/PatriotViperController/ \
@ -110,6 +111,8 @@ SOURCES += \
Controllers/LEDStripController/LEDStripControllerDetect.cpp \
Controllers/MSI3ZoneController/MSI3ZoneController.cpp \
Controllers/MSI3ZoneController/MSI3ZoneControllerDetect.cpp \
Controllers/MSIMysticLightController/MSIMysticLightController.cpp \
Controllers/MSIMysticLightController/MSIMysticLightControllerDetect.cpp \
Controllers/MSIRGBController/MSIRGBController.cpp \
Controllers/MSIRGBController/MSIRGBControllerDetect.cpp \
Controllers/NZXTKrakenController/NZXTKrakenController.cpp \
@ -150,6 +153,7 @@ SOURCES += \
RGBController/RGBController_E131.cpp \
RGBController/RGBController_LEDStrip.cpp \
RGBController/RGBController_MSI3Zone.cpp \
RGBController/RGBController_MSIMysticLight.cpp \
RGBController/RGBController_MSIRGB.cpp \
RGBController/RGBController_NZXTKraken.cpp \
RGBController/RGBController_PatriotViper.cpp \
@ -194,6 +198,7 @@ HEADERS += \
Controllers/HyperXKeyboardController/HyperXKeyboardController.h \
Controllers/LEDStripController/LEDStripController.h \
Controllers/MSI3ZoneController/MSI3ZoneController.h \
Controllers/MSIMysticLightController/MSIMysticLightController.h \
Controllers/MSIRGBController/MSIRGBController.h \
Controllers/PatriotViperController/PatriotViperController.h \
Controllers/PolychromeController/PolychromeController.h \
@ -222,6 +227,7 @@ HEADERS += \
RGBController/RGBController_HyperXKeyboard.h \
RGBController/RGBController_LEDStrip.h \
RGBController/RGBController_MSI3Zone.h \
RGBController/RGBController_MSIMysticLight.h \
RGBController/RGBController_MSIRGB.h \
RGBController/RGBController_PatriotViper.h \
RGBController/RGBController_Polychrome.h \

@ -0,0 +1,173 @@
/*-----------------------------------------*\
| RGBController_MSIMysticLight.cpp |
| |
| Generic RGB Interface for OpenRGB |
| MSI Mystic Light USB Driver |
| |
| T-bond 3/4/2020 |
\*-----------------------------------------*/
#include "RGBController_MSIMysticLight.h"
#include <array>
static const std::array<ZoneDescription, 18> led_zones
{
ZoneDescription{"JRGB1", J_RGB_1},
ZoneDescription{"JRGB2", J_RGB_2},
ZoneDescription{"JRAINBOW1", J_RAINBOW_1},
ZoneDescription{"JRAINBOW2", J_RAINBOW_2},
ZoneDescription{"JPIPE1", J_PIPE_1},
ZoneDescription{"JPIPE2", J_PIPE_2},
ZoneDescription{"JCORSAIR", J_CORSAIR},
ZoneDescription{"JCORSAIR Outer", J_CORSAIR_OUTERLL120},
ZoneDescription{"OnboardLED", ON_BOARD_LED},
ZoneDescription{"OnboardLED1", ON_BOARD_LED_1},
ZoneDescription{"OnboardLED2", ON_BOARD_LED_2},
ZoneDescription{"OnboardLED3", ON_BOARD_LED_3},
ZoneDescription{"OnboardLED4", ON_BOARD_LED_4},
ZoneDescription{"OnboardLED5", ON_BOARD_LED_5},
ZoneDescription{"OnboardLED6", ON_BOARD_LED_6},
ZoneDescription{"OnboardLED7", ON_BOARD_LED_7},
ZoneDescription{"OnboardLED8", ON_BOARD_LED_8},
ZoneDescription{"OnboardLED9", ON_BOARD_LED_9},
};
RGBController_MSIMysticLight::RGBController_MSIMysticLight(MSIMysticLightController* controller_ptr)
{
controller = controller_ptr;
name = "MSI Mystic Light Controller";
type = DEVICE_TYPE_MOTHERBOARD;
description = controller->GetDeviceName();
version = controller->GetFWVersion();
location = controller->GetDeviceLocation();
serial = controller->GetSerial();
SetupModes();
SetupZones();
SetupColors();
}
void RGBController_MSIMysticLight::SetupZones()
{
/*---------------------------------------------------------*\
| Set up zones |
\*---------------------------------------------------------*/
for(std::size_t zone_idx = 0; zone_idx < led_zones.size(); zone_idx++)
{
ZoneDescription zd = led_zones[zone_idx];
zone new_zone;
new_zone.name = zd.name;
new_zone.type = ZONE_TYPE_LINEAR;
new_zone.leds_min = controller->GetZoneMinLedCount(zd.value);
new_zone.leds_min = controller->GetZoneMaxLedCount(zd.value);
new_zone.leds_count = controller->GetZoneLedCount(zd.value);
zones.push_back(new_zone);
/*---------------------------------------------------------*\
| Set up LEDs |
\*---------------------------------------------------------*/
for(std::size_t led_idx = 0; led_idx < new_zone.leds_count; led_idx++)
{
led new_led;
new_led.name = new_zone.name + " LED ";
if(new_zone.leds_count > 1)
{
new_led.name.append(std::to_string(led_idx + 1));
}
new_led.value = zone_idx;
leds.push_back(new_led);
}
}
}
void RGBController_MSIMysticLight::ResizeZone(int zone, int new_size)
{
ZONE zon = ZoneFromPos(zone);
unsigned int max_count = controller->GetZoneMaxLedCount(zon),
min_count = controller->GetZoneMinLedCount(zon),
new_siz = new_size;
new_siz = std::min(std::max(new_siz, min_count), max_count); // std::clamp only from C++17
/// TODO: Update LED count
}
void RGBController_MSIMysticLight::SetCustomMode()
{
active_mode = 0;
}
void RGBController_MSIMysticLight::UpdateLEDs()
{
for(size_t zone_idx = 0; zone_idx < zones.size(); zone_idx++)
{
UpdateZoneLEDs(zone_idx);
}
}
void RGBController_MSIMysticLight::UpdateZoneLEDs(int zone)
{
for(int led_idx = zones[zone].leds_count - 1; led_idx >= 0; led_idx--)
{
UpdateLed(zone, led_idx);
}
controller->Update();
}
void RGBController_MSIMysticLight::UpdateSingleLED(int led)
{
UpdateLed(leds[led].value, led);
controller->Update();
}
void RGBController_MSIMysticLight::UpdateMode()
{
}
void RGBController_MSIMysticLight::SetupModes()
{
mode Off;
Off.name = "Off";
Off.value = EFFECT::DISABLE;
Off.color_mode = MODE_COLORS_PER_LED; // Only needed to show the Zones and Leds on the GUI
modes.push_back(Off);
mode Static;
Static.name = "Static";
Static.value = EFFECT::STATIC;
Static.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_PER_LED_COLOR;
Static.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Static);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = EFFECT::BREATHING;
Breathing.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_RANDOM_COLOR;
Breathing.color_mode = MODE_COLORS_PER_LED;
Breathing.speed = SPEED::MEDIUM;
Breathing.speed_max = SPEED::HIGH;
Breathing.speed_min = SPEED::LOW;
modes.push_back(Breathing);
}
void RGBController_MSIMysticLight::UpdateLed(int zone, int led)
{
bool random = modes[active_mode].color_mode == MODE_COLORS_RANDOM;
unsigned char red = RGBGetRValue(zones[zone].colors[led]);
unsigned char grn = RGBGetGValue(zones[zone].colors[led]);
unsigned char blu = RGBGetBValue(zones[zone].colors[led]);
EFFECT mode = static_cast<EFFECT>(modes[active_mode].value);
SPEED speed = static_cast<SPEED>(modes[active_mode].speed);
ZONE zon = ZoneFromPos(zone);
controller->SetMode(zon, mode, speed, BRIGHTNESS::LEVEL_100, random);
controller->SetZoneColor(zon, red, grn, blu, red, grn, blu);
}
ZONE RGBController_MSIMysticLight::ZoneFromPos(int zone)
{
return led_zones[zone].value;
}

@ -0,0 +1,46 @@
/*-----------------------------------------*\
| RGBController_MSIMysticLight.h |
| |
| Generic RGB Interface for OpenRGB |
| MSI Mystic Light USB Driver |
| |
| T-bond 3/4/2020 |
\*-----------------------------------------*/
#pragma once
#include "RGBController.h"
#include "MSIMysticLightController.h"
#include <map>
#include <vector>
struct LedPort
{
const char* name;
int header;
};
typedef std::vector< std::vector<LedPort> > ZoneLeds;
class RGBController_MSIMysticLight: public RGBController
{
public:
RGBController_MSIMysticLight(MSIMysticLightController* controller_ptr);
void SetupZones();
void ResizeZone(int zone, int new_size);
void UpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void SetCustomMode();
void UpdateMode();
private:
void SetupModes();
void UpdateLed(int zone, int led);
ZONE ZoneFromPos(int zone);
MSIMysticLightController* controller;
};
Loading…
Cancel
Save