Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better debugging with MSI Mystic Light #54

Open
ayufan opened this issue Feb 14, 2019 · 3 comments
Open

Better debugging with MSI Mystic Light #54

ayufan opened this issue Feb 14, 2019 · 3 comments

Comments

@ayufan
Copy link

ayufan commented Feb 14, 2019

Some easier workflow to debug the function calls:

  1. Install Api Monitor http://www.rohitab.com/apimonitor,
  2. Install MSI Mystic Light,
  3. Start MSI Mystic Light,
  4. After starting, stop MSI_MysticLight2_service (Services Manager),
  5. Run API Monitor v2 32-bit in Admin mode,
  6. In API Monitor terminate LED Keeper.exe process,
  7. In API Monitor add External DLLs from MSI Mystic Light directory: LEDControl.dll, MBAPI_x86.dll, SMBUS_Engine.dll,
  8. Enable monitoring of all functions for these DLLs,
  9. Start a new process: LED Keeper.exe from API Monitor, attach using Remote Thread (Extended),
  10. Tinker with MSI Mystic Light and see a method calls executed, like: ControlCorsairProDRAMLED, RenesasLEDControlV3, SMB_ByteWrite,
  11. Install .NET Reflector,
  12. Open in .NET Reflector the LEDKeeper.exe to see all annotated enums and method calls to LEDControl.dll,
  13. Cross-check enums with method calls and SMBUS calls.

It seems to work. I have very nice stream of SMB_ByteWrites.

It seems that MSI Mystic Light supports a majority of RGB-controlled devices (RAMs (G.SKILL, Corsair PRO, etc.), GFX, etc.).

@ayufan
Copy link
Author

ayufan commented Feb 14, 2019

To aid the debugging of method calls. This is the interface of MBAPI_x86.dll:
https://gist.github.com/ayufan/dca808e3927ddc3a204043348b43f140

@ayufan
Copy link
Author

ayufan commented Feb 14, 2019

OK. I came-up with this: https://github.com/ayufan/control-msi-rgb.

It seems that recent MSI boards use SMBus and slightly different protocol.

@dumbasPL
Copy link

dumbasPL commented Nov 2, 2019

open LEDKeeper.exe in dnSpy find MIS_LED.CControl and you just got documentation on how to control every msi motherboard in existence that has RGB
just ctrl+f for your model. for example mine is MS-7B12
and i find a function like this:

public void NUC126_7B12_Set_LED_Data(Nuvoton_7B12_MCU.DeviceName Area, byte style, bool bAllBoard, byte r, byte g, byte b, byte speed, byte bright, byte ColorSel, byte JCType = 1, byte FanType = 1)
{
	byte b2 = bAllBoard ? 1 : 0;
	byte b3 = (byte)((int)bright << 2 | (int)speed);
	byte b4 = (byte)((int)b2 << 7 | (int)bright << 2 | (int)speed);
	byte b5 = (JCType == 0) ? 19 : 5;
	byte b6 = 0;
	byte b7 = bAllBoard ? 1 : 0;
	byte b8 = (byte)((int)ColorSel << 7 | (int)FanType << 1 | (int)JCType);
	byte b9 = (byte)((int)ColorSel << 7 | (int)b6);
	byte b10 = (byte)(b5 << 2);
	byte b11 = (byte)((int)ColorSel << 7 | (int)b7);
	if (bAllBoard)
	{
		App.Device_7B12.Nuvoton_7B12_Data[41] = style;
		App.Device_7B12.Nuvoton_7B12_Data[42] = r;
		App.Device_7B12.Nuvoton_7B12_Data[43] = g;
		App.Device_7B12.Nuvoton_7B12_Data[44] = b;
		App.Device_7B12.Nuvoton_7B12_Data[45] = b4;
		App.Device_7B12.Nuvoton_7B12_Data[49] = b11;
		App.Device_7B12.Nuvoton_7B12_Data[50] = 0;
	}
	else
	{
		switch (Area)
		{
		case Nuvoton_7B12_MCU.DeviceName.JRGB1:
		case Nuvoton_7B12_MCU.DeviceName.OnBoardLED1:
		case Nuvoton_7B12_MCU.DeviceName.OnBoardLED2:
		case Nuvoton_7B12_MCU.DeviceName.OnBoardLED3:
		case Nuvoton_7B12_MCU.DeviceName.OnBoardLED4:
		case Nuvoton_7B12_MCU.DeviceName.OnBoardLED5:
		case Nuvoton_7B12_MCU.DeviceName.OnBoardLED6:
		case Nuvoton_7B12_MCU.DeviceName.JPIPE1:
		case Nuvoton_7B12_MCU.DeviceName.JPIPE2:
		case Nuvoton_7B12_MCU.DeviceName.JPIPE3:
		case Nuvoton_7B12_MCU.DeviceName.JPIPE4:
		case Nuvoton_7B12_MCU.DeviceName.JRGB2:
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 1)] = style;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 2)] = r;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 3)] = g;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 4)] = b;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 5)] = b3;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 9)] = b8;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 10)] = 0;
			if (!this.b7B12_Special)
			{
				App.Device_7B12.Nuvoton_7B12_Data[45] = b4;
				App.Device_7B12.Nuvoton_7B12_Data[49] = b11;
			}
			break;
		case Nuvoton_7B12_MCU.DeviceName.JRAINBOW:
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 1)] = style;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 2)] = r;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 3)] = g;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 4)] = b;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 5)] = b3;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 9)] = b8;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 10)] = 0;
			break;
		case Nuvoton_7B12_MCU.DeviceName.JCORSAIR:
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 1)] = style;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 2)] = r;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 3)] = g;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 4)] = b;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 5)] = b3;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 9)] = b8;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 10)] = b10;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 11)] = style;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 12)] = r;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 13)] = g;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 14)] = b;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 15)] = b3;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 19)] = b9;
			App.Device_7B12.Nuvoton_7B12_Data[(int)(Area * Nuvoton_7B12_MCU.DeviceName.OnBoardLED6 + 20)] = b10;
			break;
		}
	}
}

Nuvoton_7B12_MCU.DeviceName gives me all the zones along with thier id's
but this function just sets some buffer but does not send anything.
so then we need to look where the function is used. a good place is MSI_LED.CControl.SetAllLEDOff() and we find something like this:

case EnumChipest.NUC126_1:
	this.NUC126_7B12_Set_LED_Data(Nuvoton_7B12_MCU.DeviceName.JPIPE4, 0, false, 0, 0, 0, 0, 10, 1, 1, 1);
	this.NUC126_7B12_Set_LED_Data(Nuvoton_7B12_MCU.DeviceName.JRGB1, 0, true, 0, 0, 0, 0, 10, 1, 1, 1);
	this.NUC126_7B12_Set_LED_Data(Nuvoton_7B12_MCU.DeviceName.JRAINBOW, 0, false, 0, 0, 0, 0, 10, 1, 1, 1);
	this.NUC126_7B12_Set_LED_Data(Nuvoton_7B12_MCU.DeviceName.JCORSAIR, 0, false, 0, 0, 0, 0, 10, 1, 1, 1);
	App.Device_7B12.Set_AllBoard(App.Device_7B12.Nuvoton_7B12_Data);

tn this case App.Device_7B12.Set_AllBoard tells us how the data is sent to the device

public bool Set_AllBoard(byte[] data)
{
	bool result;
	if (data.Length < 162)
	{
		result = false;
	}
	else if (data[0] != 82 || data.Length < 162)
	{
		result = false;
	}
	else
	{
		int num = HID_Basic.SetFeature(this.device, data, 162UL);
		Thread.Sleep(10);
		result = (num == 1);
	}
	return result;
}

in this case we can see that all it does it writes the buffer to usb
Now we can use USBPcap and wireshark to look at the packet
In this case it's a control transfer with
request_type = 0x21
bRequest = 9
wValue = 0x0352
wIndex = 0
and the body that we have seen in code
Now that we know all that we need to control it manually, we can use libusb to send the data.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants