diff --git a/RGB.NET.Devices.Msi/Exceptions/MysticLightException.cs b/RGB.NET.Devices.Msi/Exceptions/MysticLightException.cs index d36665b..0b12582 100644 --- a/RGB.NET.Devices.Msi/Exceptions/MysticLightException.cs +++ b/RGB.NET.Devices.Msi/Exceptions/MysticLightException.cs @@ -34,6 +34,7 @@ namespace RGB.NET.Devices.Msi.Exceptions /// The raw error code provided by the SDK. /// The text-description of the error. public MysticLightException(int errorCode, string description) + : base($"MSI error code {errorCode} ({description})") { this.ErrorCode = errorCode; this.Description = description; diff --git a/RGB.NET.Devices.Msi/Generic/IMsiRGBDevice.cs b/RGB.NET.Devices.Msi/Generic/IMsiRGBDevice.cs index f8b35a8..cd09af0 100644 --- a/RGB.NET.Devices.Msi/Generic/IMsiRGBDevice.cs +++ b/RGB.NET.Devices.Msi/Generic/IMsiRGBDevice.cs @@ -3,10 +3,10 @@ namespace RGB.NET.Devices.Msi { /// - /// Represents a msi RGB-device. + /// Represents a MSI RGB-device. /// internal interface IMsiRGBDevice : IRGBDevice { - void Initialize(); + void Initialize(MsiDeviceUpdateQueue updateQueue, int ledCount); } } diff --git a/RGB.NET.Devices.Msi/Generic/MsiDeviceUpdateQueue.cs b/RGB.NET.Devices.Msi/Generic/MsiDeviceUpdateQueue.cs new file mode 100644 index 0000000..b2dffc0 --- /dev/null +++ b/RGB.NET.Devices.Msi/Generic/MsiDeviceUpdateQueue.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using RGB.NET.Core; +using RGB.NET.Devices.Msi.Native; + +namespace RGB.NET.Devices.Msi +{ + /// + /// + /// Represents the update-queue performing updates for MSI devices. + /// + public class MsiDeviceUpdateQueue : UpdateQueue + { + #region Properties & Fields + + private string _deviceType; + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The update trigger used by this queue. + /// The device-type used to identify the device. + public MsiDeviceUpdateQueue(IDeviceUpdateTrigger updateTrigger, string deviceType) + : base(updateTrigger) + { + this._deviceType = deviceType; + } + + #endregion + + #region Methods + + /// + protected override void Update(Dictionary dataSet) + { + foreach (KeyValuePair data in dataSet) + _MsiSDK.SetLedColor(_deviceType, (int)data.Key, data.Value.GetR(), data.Value.GetG(), data.Value.GetB()); + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Msi/Generic/MsiRGBDevice.cs b/RGB.NET.Devices.Msi/Generic/MsiRGBDevice.cs index 5fe18ab..e6a5210 100644 --- a/RGB.NET.Devices.Msi/Generic/MsiRGBDevice.cs +++ b/RGB.NET.Devices.Msi/Generic/MsiRGBDevice.cs @@ -1,14 +1,13 @@ using System.Collections.Generic; using System.Linq; using RGB.NET.Core; -using RGB.NET.Devices.Msi.Native; namespace RGB.NET.Devices.Msi { /// /// /// - /// Represents a generic Msi-device. (keyboard, mouse, headset, mousepad). + /// Represents a generic MSI-device. (keyboard, mouse, headset, mousepad). /// public abstract class MsiRGBDevice : AbstractRGBDevice, IMsiRGBDevice where TDeviceInfo : MsiRGBDeviceInfo @@ -21,6 +20,12 @@ namespace RGB.NET.Devices.Msi /// public override TDeviceInfo DeviceInfo { get; } + /// + /// Gets or sets the update queue performing updates for this device. + /// + // ReSharper disable once MemberCanBePrivate.Global + protected MsiDeviceUpdateQueue DeviceUpdateQueue { get; set; } + #endregion #region Constructors @@ -28,7 +33,7 @@ namespace RGB.NET.Devices.Msi /// /// Initializes a new instance of the class. /// - /// The generic information provided by Msi for the device. + /// The generic information provided by MSI for the device. protected MsiRGBDevice(TDeviceInfo info) { this.DeviceInfo = info; @@ -41,9 +46,11 @@ namespace RGB.NET.Devices.Msi /// /// Initializes the device. /// - public void Initialize() + public void Initialize(MsiDeviceUpdateQueue updateQueue, int ledCount) { - InitializeLayout(); + DeviceUpdateQueue = updateQueue; + + InitializeLayout(ledCount); if (Size == Size.Invalid) { @@ -55,20 +62,11 @@ namespace RGB.NET.Devices.Msi /// /// Initializes the and of the device. /// - protected abstract void InitializeLayout(); + protected abstract void InitializeLayout(int ledCount); /// protected override void UpdateLeds(IEnumerable ledsToUpdate) - { - List leds = ledsToUpdate.Where(x => x.Color.A > 0).ToList(); - - if (leds.Count > 0) - { - string deviceType = DeviceInfo.MsiDeviceType; - foreach (Led led in leds) - _MsiSDK.SetLedColor(deviceType, (int)led.CustomData, led.Color.GetR(), led.Color.GetG(), led.Color.GetB()); - } - } + => DeviceUpdateQueue.SetData(ledsToUpdate.Where(x => (x.Color.A > 0) && (x.CustomData is int))); #endregion } diff --git a/RGB.NET.Devices.Msi/Generic/MsiRGBDeviceInfo.cs b/RGB.NET.Devices.Msi/Generic/MsiRGBDeviceInfo.cs index 1d8e942..d846266 100644 --- a/RGB.NET.Devices.Msi/Generic/MsiRGBDeviceInfo.cs +++ b/RGB.NET.Devices.Msi/Generic/MsiRGBDeviceInfo.cs @@ -5,7 +5,7 @@ namespace RGB.NET.Devices.Msi { /// /// - /// Represents a generic information for a Corsair-. + /// Represents a generic information for a MSI-. /// public class MsiRGBDeviceInfo : IRGBDeviceInfo { diff --git a/RGB.NET.Devices.Msi/GraphicsCard/MsiGraphicsCardRGBDevice.cs b/RGB.NET.Devices.Msi/GraphicsCard/MsiGraphicsCardRGBDevice.cs new file mode 100644 index 0000000..ee0800a --- /dev/null +++ b/RGB.NET.Devices.Msi/GraphicsCard/MsiGraphicsCardRGBDevice.cs @@ -0,0 +1,56 @@ +using RGB.NET.Core; +using RGB.NET.Devices.Msi.Native; + +namespace RGB.NET.Devices.Msi +{ + /// + /// + /// Represents MSI VGA adapters. + /// + public class MsiGraphicsCardRGBDevice : MsiRGBDevice + { + #region Constructors + + /// + /// + /// Initializes a new instance of the class. + /// + /// The specific information provided by MSI for graphics cards. + internal MsiGraphicsCardRGBDevice(MsiRGBDeviceInfo info) + : base(info) + { } + + #endregion + + #region Methods + + /// + protected override void InitializeLayout(int ledCount) + { + for (int i = 0; i < ledCount; i++) + { + //Hex3l: Should it be configurable in order to provide style access? + //Hex3l: Sets led style to "Steady" in order to have a solid color output therefore a controllable led color + //Hex3l: This is a string defined by the output of _MsiSDK.GetLedStyle, "Steady" should be always present + const string LED_STYLE = "Steady"; + + //Hex3l: Every led is a video card adapter. + + _MsiSDK.SetLedStyle(DeviceInfo.MsiDeviceType, i, LED_STYLE); + InitializeLed(LedId.GraphicsCard1 + i, new Rectangle(i * 10, 0, 10, 10)); + } + + //TODO DarthAffe 07.10.2017: We don't know the model, how to save layouts and images? + ApplyLayoutFromFile(PathHelper.GetAbsolutePath($@"Layouts\MSI\GraphicsCard\{DeviceInfo.Model.Replace(" ", string.Empty).ToUpper()}.xml"), null); + } + + /// + protected override object CreateLedCustomData(LedId ledId) => (int)ledId - (int)LedId.GraphicsCard1; + + /// + public override void SyncBack() + { } + + #endregion + } +} diff --git a/RGB.NET.Devices.Msi/Mainboard/MsiMainboardRGBDevice.cs b/RGB.NET.Devices.Msi/Mainboard/MsiMainboardRGBDevice.cs new file mode 100644 index 0000000..f80dab0 --- /dev/null +++ b/RGB.NET.Devices.Msi/Mainboard/MsiMainboardRGBDevice.cs @@ -0,0 +1,54 @@ +using RGB.NET.Core; +using RGB.NET.Devices.Msi.Native; + +namespace RGB.NET.Devices.Msi +{ + /// + /// + /// Represents a MSI mainboard. + /// + public class MsiMainboardRGBDevice : MsiRGBDevice + { + #region Constructors + + /// + /// + /// Initializes a new instance of the class. + /// + /// The specific information provided by MSI for the mainboard. + internal MsiMainboardRGBDevice(MsiRGBDeviceInfo info) + : base(info) + { } + + #endregion + + #region Methods + + /// + protected override void InitializeLayout(int ledCount) + { + for (int i = 0; i < ledCount; i++) + { + //Hex3l: Should it be configurable in order to provide style access? + //Hex3l: Sets led style to "Steady" in order to have a solid color output therefore a controllable led color + //Hex3l: This is a string defined by the output of _MsiSDK.GetLedStyle, "Steady" should be always present + const string LED_STYLE = "Steady"; + + _MsiSDK.SetLedStyle(DeviceInfo.MsiDeviceType, i, LED_STYLE); + InitializeLed(LedId.Mainboard1 + i, new Rectangle(i * 40, 0, 40, 8)); + } + + //TODO DarthAffe 07.10.2017: We don't know the model, how to save layouts and images? + ApplyLayoutFromFile(PathHelper.GetAbsolutePath($@"Layouts\MSI\Mainboards\{DeviceInfo.Model.Replace(" ", string.Empty).ToUpper()}.xml"), null); + } + + /// + protected override object CreateLedCustomData(LedId ledId) => (int)ledId - (int)LedId.Mainboard1; + + /// + public override void SyncBack() + { } + + #endregion + } +} diff --git a/RGB.NET.Devices.Msi/MsiDeviceProvider.cs b/RGB.NET.Devices.Msi/MsiDeviceProvider.cs index 2eba9a0..59a3980 100644 --- a/RGB.NET.Devices.Msi/MsiDeviceProvider.cs +++ b/RGB.NET.Devices.Msi/MsiDeviceProvider.cs @@ -13,7 +13,7 @@ namespace RGB.NET.Devices.Msi { /// /// - /// Represents a device provider responsible for Cooler Master devices. + /// Represents a device provider responsible for MSI devices. /// public class MsiDeviceProvider : IRGBDeviceProvider { @@ -62,6 +62,11 @@ namespace RGB.NET.Devices.Msi /// public Func GetCulture { get; set; } = CultureHelper.GetCurrentCulture; + /// + /// The used to trigger the updates for corsair devices. + /// + public DeviceUpdateTrigger UpdateTrigger { get; } + #endregion #region Constructors @@ -74,6 +79,8 @@ namespace RGB.NET.Devices.Msi { if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(MsiDeviceProvider)}"); _instance = this; + + UpdateTrigger = new DeviceUpdateTrigger(); } #endregion @@ -87,6 +94,8 @@ namespace RGB.NET.Devices.Msi try { + UpdateTrigger?.Stop(); + _MsiSDK.Reload(); IList devices = new List(); @@ -102,11 +111,35 @@ namespace RGB.NET.Devices.Msi { try { - //TODO DarthAffe 11.11.2017: What is this deviceType? Find someone to try that out + string deviceType = deviceTypes[i]; + int ledCount = ledCounts[i]; + + //Hex3l: MSI_MB provide access to the motherboard "leds" where a led must be intended as a led header (JRGB, JRAINBOW etc..) (Tested on MSI X570 Unify) + if (deviceType.Equals("MSI_MB")) + { + MsiDeviceUpdateQueue updateQueue = new MsiDeviceUpdateQueue(UpdateTrigger, deviceType); + IMsiRGBDevice motherboard = new MsiMainboardRGBDevice(new MsiRGBDeviceInfo(RGBDeviceType.Mainboard, deviceType, "Msi", "Motherboard")); + motherboard.Initialize(updateQueue, ledCount); + devices.Add(motherboard); + } + else if (deviceType.Equals("MSI_VGA")) + { + //Hex3l: Every led under MSI_VGA should be a different graphics card. Handling all the cards together seems a good way to avoid overlapping of leds + //Hex3l: The led name is the name of the card (e.g. NVIDIA GeForce RTX 2080 Ti) we could provide it in device info. + + MsiDeviceUpdateQueue updateQueue = new MsiDeviceUpdateQueue(UpdateTrigger, deviceType); + IMsiRGBDevice graphicscard = new MsiGraphicsCardRGBDevice(new MsiRGBDeviceInfo(RGBDeviceType.GraphicsCard, deviceType, "Msi", "GraphicsCard")); + graphicscard.Initialize(updateQueue, ledCount); + devices.Add(graphicscard); + } + + //TODO DarthAffe 22.02.2020: Add other devices } catch { if (throwExceptions) throw; } } + UpdateTrigger?.Start(); + Devices = new ReadOnlyCollection(devices); IsInitialized = true; } diff --git a/RGB.NET.Devices.Msi/MsiDeviceProviderLoader.cs b/RGB.NET.Devices.Msi/MsiDeviceProviderLoader.cs index 0aef5c4..b059f85 100644 --- a/RGB.NET.Devices.Msi/MsiDeviceProviderLoader.cs +++ b/RGB.NET.Devices.Msi/MsiDeviceProviderLoader.cs @@ -3,7 +3,7 @@ namespace RGB.NET.Devices.Msi { /// - /// Represents a device provider loaded used to dynamically load msi devices into an application. + /// Represents a device provider loaded used to dynamically load MSI devices into an application. /// public class MsiDeviceProviderLoader : IRGBDeviceProviderLoader { diff --git a/RGB.NET.Devices.Msi/Native/_MsiSDK.cs b/RGB.NET.Devices.Msi/Native/_MsiSDK.cs index 031918d..a67aa94 100644 --- a/RGB.NET.Devices.Msi/Native/_MsiSDK.cs +++ b/RGB.NET.Devices.Msi/Native/_MsiSDK.cs @@ -110,51 +110,104 @@ namespace RGB.NET.Devices.Msi.Native private delegate int InitializePointer(); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int GetDeviceInfoPointer(out string[] pDevType, out int[] pLedCount); + private delegate int GetDeviceInfoPointer( + [Out, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)] out string[] pDevType, + [Out, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)] out string[] pLedCount); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int GetLedInfoPointer(string type, int index, out string pName, out string[] pLedStyles); + private delegate int GetLedInfoPointer( + [In, MarshalAs(UnmanagedType.BStr)] string type, + [In, MarshalAs(UnmanagedType.I4)] int index, + [Out, MarshalAs(UnmanagedType.BStr)] out string pName, + [Out, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)] out string[] pLedStyles); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int GetLedColorPointer(string type, int index, out int r, out int g, out int b); + private delegate int GetLedColorPointer( + [In, MarshalAs(UnmanagedType.BStr)] string type, + [In, MarshalAs(UnmanagedType.I4)] int index, + [Out, MarshalAs(UnmanagedType.I4)] out int r, + [Out, MarshalAs(UnmanagedType.I4)] out int g, + [Out, MarshalAs(UnmanagedType.I4)] out int b); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int GetLedStylePointer(string type, int index, out int style); + private delegate int GetLedStylePointer( + [In, MarshalAs(UnmanagedType.BStr)] string type, + [In, MarshalAs(UnmanagedType.I4)] int index, + [Out, MarshalAs(UnmanagedType.BStr)] out string style); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int GetLedMaxBrightPointer(string type, int index, out int maxLevel); + private delegate int GetLedMaxBrightPointer( + [In, MarshalAs(UnmanagedType.BStr)] string type, + [In, MarshalAs(UnmanagedType.I4)] int index, + [Out, MarshalAs(UnmanagedType.I4)] out int maxLevel); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int GetLedBrightPointer(string type, int index, out int currentLevel); + private delegate int GetLedBrightPointer( + [In, MarshalAs(UnmanagedType.BStr)] string type, + [In, MarshalAs(UnmanagedType.I4)] int index, + [Out, MarshalAs(UnmanagedType.I4)] out int currentLevel); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int GetLedMaxSpeedPointer(string type, int index, out int maxSpeed); + private delegate int GetLedMaxSpeedPointer( + [In, MarshalAs(UnmanagedType.BStr)] string type, + [In, MarshalAs(UnmanagedType.I4)] int index, + [Out, MarshalAs(UnmanagedType.I4)] out int maxSpeed); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int GetLedSpeedPointer(string type, int index, out int currentSpeed); + private delegate int GetLedSpeedPointer( + [In, MarshalAs(UnmanagedType.BStr)] string type, + [In, MarshalAs(UnmanagedType.I4)] int index, + [Out, MarshalAs(UnmanagedType.I4)] out int currentSpeed); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int SetLedColorPointer(string type, int index, int r, int g, int b); + private delegate int SetLedColorPointer( + [In, MarshalAs(UnmanagedType.BStr)] string type, + [In, MarshalAs(UnmanagedType.I4)] int index, + [In, MarshalAs(UnmanagedType.I4)] int r, + [In, MarshalAs(UnmanagedType.I4)] int g, + [In, MarshalAs(UnmanagedType.I4)] int b); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int SetLedStylePointer(string type, int index, string style); + private delegate int SetLedStylePointer( + [In, MarshalAs(UnmanagedType.BStr)] string type, + [In, MarshalAs(UnmanagedType.I4)] int index, + [In, MarshalAs(UnmanagedType.BStr)] string style); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int SetLedBrightPointer(string type, int index, int level); + private delegate int SetLedBrightPointer( + [In, MarshalAs(UnmanagedType.BStr)] string type, + [In, MarshalAs(UnmanagedType.I4)] int index, + [In, MarshalAs(UnmanagedType.I4)] int level); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int SetLedSpeedPointer(string type, int index, int speed); + private delegate int SetLedSpeedPointer( + [In, MarshalAs(UnmanagedType.BStr)] string type, + [In, MarshalAs(UnmanagedType.I4)] int index, + [In, MarshalAs(UnmanagedType.I4)] int speed); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int GetErrorMessagePointer(int errorCode, out string pDesc); + private delegate int GetErrorMessagePointer( + [In, MarshalAs(UnmanagedType.I4)] int errorCode, + [Out, MarshalAs(UnmanagedType.BStr)] out string pDesc); #endregion internal static int Initialize() => _initializePointer(); - internal static int GetDeviceInfo(out string[] pDevType, out int[] pLedCount) => _getDeviceInfoPointer(out pDevType, out pLedCount); + internal static int GetDeviceInfo(out string[] pDevType, out int[] pLedCount) + { + // HACK - SDK GetDeviceInfo returns a string[] for ledCount, so we'll parse that to int. + int result = _getDeviceInfoPointer(out pDevType, out string[] ledCount); + pLedCount = new int[ledCount.Length]; + + for (int i = 0; i < ledCount.Length; i++) + pLedCount[i] = int.Parse(ledCount[i]); + + return result; + } + internal static int GetLedInfo(string type, int index, out string pName, out string[] pLedStyles) => _getLedInfoPointer(type, index, out pName, out pLedStyles); internal static int GetLedColor(string type, int index, out int r, out int g, out int b) => _getLedColorPointer(type, index, out r, out g, out b); - internal static int GetLedStyle(string type, int index, out int style) => _getLedStylePointer(type, index, out style); + internal static int GetLedStyle(string type, int index, out string style) => _getLedStylePointer(type, index, out style); internal static int GetLedMaxBright(string type, int index, out int maxLevel) => _getLedMaxBrightPointer(type, index, out maxLevel); internal static int GetLedBright(string type, int index, out int currentLevel) => _getLedBrightPointer(type, index, out currentLevel); internal static int GetLedMaxSpeed(string type, int index, out int maxSpeed) => _getLedMaxSpeedPointer(type, index, out maxSpeed); diff --git a/RGB.NET.Devices.Msi/RGB.NET.Devices.Msi.csproj.DotSettings b/RGB.NET.Devices.Msi/RGB.NET.Devices.Msi.csproj.DotSettings index bcc9d7d..5db6073 100644 --- a/RGB.NET.Devices.Msi/RGB.NET.Devices.Msi.csproj.DotSettings +++ b/RGB.NET.Devices.Msi/RGB.NET.Devices.Msi.csproj.DotSettings @@ -1,3 +1,5 @@  True - True \ No newline at end of file + True + True + True \ No newline at end of file