1
0
mirror of https://github.com/DarthAffe/RGB.NET.git synced 2025-12-12 17:48:31 +00:00

Changed all existing device-providers to use update-queues to decouple the physical update from the internal update-loop (first draft, code-documention is missing)

This commit is contained in:
Darth Affe 2018-03-25 15:53:13 +02:00
parent 3965bfb9a0
commit 66d03cdf4f
61 changed files with 1125 additions and 440 deletions

View File

@ -0,0 +1,12 @@
using System;
namespace RGB.NET.Core
{
public interface IUpdateTrigger
{
event EventHandler Starting;
event EventHandler Update;
void TriggerHasData();
}
}

View File

@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace RGB.NET.Core
{
public abstract class UpdateQueue<TIdentifier, TData>
{
#region Properties & Fields
private readonly object _dataLock = new object();
private readonly IUpdateTrigger _updateTrigger;
private Dictionary<TIdentifier, TData> _currentDataSet;
#endregion
#region Constructors
public UpdateQueue(IUpdateTrigger updateTrigger)
{
this._updateTrigger = updateTrigger;
_updateTrigger.Starting += (sender, args) => OnStartup();
_updateTrigger.Update += OnUpdate;
}
#endregion
#region Methods
protected virtual void OnUpdate(object sender, EventArgs e)
{
Dictionary<TIdentifier, TData> dataSet;
lock (_dataLock)
{
dataSet = _currentDataSet;
_currentDataSet = null;
}
if ((dataSet != null) && (dataSet.Count != 0))
Update(dataSet);
}
protected virtual void OnStartup() { }
protected abstract void Update(Dictionary<TIdentifier, TData> dataSet);
public virtual void SetData(Dictionary<TIdentifier, TData> dataSet)
{
if ((dataSet == null) || (dataSet.Count == 0)) return;
lock (_dataLock)
{
if (_currentDataSet == null)
_currentDataSet = dataSet;
else
{
foreach (KeyValuePair<TIdentifier, TData> command in dataSet)
_currentDataSet[command.Key] = command.Value;
}
}
_updateTrigger.TriggerHasData();
}
public virtual void Reset()
{
lock (_dataLock)
_currentDataSet = null;
}
#endregion
}
public abstract class UpdateQueue : UpdateQueue<object, Color>
{
#region Constructors
/// <inheritdoc />
protected UpdateQueue(IUpdateTrigger updateTrigger)
: base(updateTrigger)
{ }
#endregion
#region Methods
public void SetData(IEnumerable<Led> leds) => SetData(leds?.ToDictionary(x => x.CustomData ?? x.Id, x => x.Color));
#endregion
}
}

View File

@ -0,0 +1,128 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace RGB.NET.Core
{
public class UpdateTrigger : IUpdateTrigger
{
#region Properties & Fields
public int Timeout { get; set; } = 100;
public double UpdateFrequency { get; private set; }
private double _maxUpdateRate;
public double MaxUpdateRate
{
get => _maxUpdateRate;
set
{
_maxUpdateRate = value;
UpdateUpdateFrequency();
}
}
private double _updateRateHardLimit;
public double UpdateRateHardLimit
{
get => _updateRateHardLimit;
protected set
{
_updateRateHardLimit = value;
UpdateUpdateFrequency();
}
}
private AutoResetEvent _hasDataEvent = new AutoResetEvent(false);
private bool _isRunning;
private Task _updateTask;
private CancellationTokenSource _updateTokenSource;
private CancellationToken _updateToken;
#endregion
#region Events
/// <inheritdoc />
public event EventHandler Starting;
/// <inheritdoc />
public event EventHandler Update;
#endregion
#region Constructors
public UpdateTrigger()
{ }
public UpdateTrigger(double updateRateHardLimit)
{
this._updateRateHardLimit = updateRateHardLimit;
}
#endregion
#region Methods
public void Start()
{
if (_isRunning) return;
_isRunning = true;
_updateTokenSource?.Dispose();
_updateTokenSource = new CancellationTokenSource();
_updateTask = Task.Factory.StartNew(UpdateLoop, (_updateToken = _updateTokenSource.Token), TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
public async void Stop()
{
if (!_isRunning) return;
_isRunning = false;
_updateTokenSource.Cancel();
await _updateTask;
_updateTask.Dispose();
_updateTask = null;
}
private void UpdateLoop()
{
Starting?.Invoke(this, null);
while (!_updateToken.IsCancellationRequested)
{
if (_hasDataEvent.WaitOne(Timeout))
{
long preUpdateTicks = Stopwatch.GetTimestamp();
Update?.Invoke(this, null);
if (UpdateFrequency > 0)
{
double lastUpdateTime = ((Stopwatch.GetTimestamp() - preUpdateTicks) / 10000.0);
int sleep = (int)((UpdateFrequency * 1000.0) - lastUpdateTime);
if (sleep > 0)
Thread.Sleep(sleep);
}
}
}
}
/// <inheritdoc />
public void TriggerHasData() => _hasDataEvent.Set();
private void UpdateUpdateFrequency()
{
UpdateFrequency = MaxUpdateRate;
if ((UpdateFrequency <= 0) || ((UpdateRateHardLimit > 0) && (UpdateRateHardLimit < UpdateFrequency)))
UpdateFrequency = UpdateRateHardLimit;
}
#endregion
}
}

View File

@ -64,6 +64,9 @@
<Compile Include="Devices\Layout\LedImage.cs" />
<Compile Include="Devices\Layout\LedImageLayout.cs" />
<Compile Include="Devices\RGBDeviceLighting.cs" />
<Compile Include="Devices\Update\IUpdateTrigger.cs" />
<Compile Include="Devices\Update\UpdateQueue.cs" />
<Compile Include="Devices\Update\UpdateTrigger.cs" />
<Compile Include="Helper\ConversionHelper.cs" />
<Compile Include="Helper\CultureHelper.cs" />
<Compile Include="Helper\PathHelper.cs" />

View File

@ -3,6 +3,7 @@
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=colorcorrection/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=decorators/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=devices/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=devices_005Cupdate/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=effects/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=events/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=exceptions/@EntryIndexedValue">True</s:Boolean>

View File

@ -63,6 +63,8 @@ namespace RGB.NET.Devices.Asus
// ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global
public Func<CultureInfo> GetCulture { get; set; } = CultureHelper.GetCurrentCulture;
public UpdateTrigger UpdateTrigger { get; private set; }
#endregion
#region Constructors
@ -75,6 +77,8 @@ namespace RGB.NET.Devices.Asus
{
if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(AsusDeviceProvider)}");
_instance = this;
UpdateTrigger = new UpdateTrigger();
}
#endregion
@ -88,6 +92,8 @@ namespace RGB.NET.Devices.Asus
try
{
UpdateTrigger?.Stop();
_AsusSDK.Reload();
IList<IRGBDevice> devices = new List<IRGBDevice>();
@ -112,7 +118,7 @@ namespace RGB.NET.Devices.Asus
IntPtr handle = Marshal.ReadIntPtr(mainboardHandles, i);
_AsusSDK.SetMbMode(handle, 1);
AsusMainboardRGBDevice device = new AsusMainboardRGBDevice(new AsusMainboardRGBDeviceInfo(RGBDeviceType.Mainboard, handle));
device.Initialize();
device.Initialize(UpdateTrigger);
devices.Add(device);
}
catch { if (throwExceptions) throw; }
@ -143,7 +149,7 @@ namespace RGB.NET.Devices.Asus
IntPtr handle = Marshal.ReadIntPtr(grapicsCardHandles, i);
_AsusSDK.SetGPUMode(handle, 1);
AsusGraphicsCardRGBDevice device = new AsusGraphicsCardRGBDevice(new AsusGraphicsCardRGBDeviceInfo(RGBDeviceType.GraphicsCard, handle));
device.Initialize();
device.Initialize(UpdateTrigger);
devices.Add(device);
}
catch { if (throwExceptions) throw; }
@ -172,7 +178,7 @@ namespace RGB.NET.Devices.Asus
// IntPtr handle = Marshal.ReadIntPtr(dramHandles, i);
// _AsusSDK.SetDramMode(handle, 1);
// AsusDramRGBDevice device = new AsusDramRGBDevice(new AsusDramRGBDeviceInfo(RGBDeviceType.DRAM, handle));
// device.Initialize();
// device.Initialize(UpdateTrigger);
// devices.Add(device);
// }
//catch { if (throwExceptions) throw; }
@ -193,7 +199,7 @@ namespace RGB.NET.Devices.Asus
{
_AsusSDK.SetClaymoreKeyboardMode(keyboardHandle, 1);
AsusKeyboardRGBDevice device = new AsusKeyboardRGBDevice(new AsusKeyboardRGBDeviceInfo(RGBDeviceType.Keyboard, keyboardHandle, GetCulture()));
device.Initialize();
device.Initialize(UpdateTrigger);
devices.Add(device);
}
}
@ -211,13 +217,15 @@ namespace RGB.NET.Devices.Asus
{
_AsusSDK.SetRogMouseMode(mouseHandle, 1);
AsusMouseRGBDevice device = new AsusMouseRGBDevice(new AsusMouseRGBDeviceInfo(RGBDeviceType.Mouse, mouseHandle));
device.Initialize();
device.Initialize(UpdateTrigger);
devices.Add(device);
}
}
catch { if (throwExceptions) throw; }
#endregion
UpdateTrigger?.Start();
Devices = new ReadOnlyCollection<IRGBDevice>(devices);
IsInitialized = true;

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using RGB.NET.Core;
using RGB.NET.Devices.Asus.Generic;
namespace RGB.NET.Devices.Asus
{
@ -16,17 +17,14 @@ namespace RGB.NET.Devices.Asus
{
#region Properties & Fields
/// <summary>
/// Gets or sets the internal color-data cache.
/// </summary>
protected byte[] ColorData { get; private set; }
/// <inheritdoc />
/// <summary>
/// Gets information about the <see cref="T:RGB.NET.Devices.Asus.AsusRGBDevice" />.
/// </summary>
public override TDeviceInfo DeviceInfo { get; }
protected AsusUpdateQueue UpdateQueue { get; set; }
#endregion
#region Constructors
@ -47,7 +45,7 @@ namespace RGB.NET.Devices.Asus
/// <summary>
/// Initializes the device.
/// </summary>
public void Initialize()
public void Initialize(IUpdateTrigger updateTrigger)
{
InitializeLayout();
@ -57,7 +55,8 @@ namespace RGB.NET.Devices.Asus
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
ColorData = new byte[LedMapping.Count * 3];
UpdateQueue = new AsusUpdateQueue(updateTrigger);
UpdateQueue.Initialize(GetUpdateColorAction(), DeviceInfo.Handle, LedMapping.Count);
}
/// <summary>
@ -66,28 +65,13 @@ namespace RGB.NET.Devices.Asus
protected abstract void InitializeLayout();
/// <inheritdoc />
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate)
{
List<Led> leds = ledsToUpdate.Where(x => x.Color.A > 0).ToList();
if (leds.Count > 0)
{
foreach (Led led in leds)
{
int index = ((int)led.CustomData) * 3;
ColorData[index] = led.Color.R;
ColorData[index + 1] = led.Color.B;
ColorData[index + 2] = led.Color.G;
}
ApplyColorData();
}
}
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate) => UpdateQueue.SetData(ledsToUpdate.Where(x => x.Color.A > 0));
/// <summary>
/// Sends the color-data-cache to the device.
/// Gets a action to update the physical device.
/// </summary>
protected abstract void ApplyColorData();
/// <returns></returns>
protected abstract Action<IntPtr, byte[]> GetUpdateColorAction();
/// <inheritdoc cref="IDisposable.Dispose" />
/// <inheritdoc cref="AbstractRGBDevice{TDeviceInfo}.Dispose" />
@ -96,8 +80,6 @@ namespace RGB.NET.Devices.Asus
if ((DeviceInfo is AsusRGBDeviceInfo deviceInfo) && (deviceInfo.Handle != IntPtr.Zero))
Marshal.FreeHGlobal(deviceInfo.Handle);
ColorData = null;
base.Dispose();
}

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using RGB.NET.Core;
namespace RGB.NET.Devices.Asus.Generic
{
public class AsusUpdateQueue : UpdateQueue
{
#region Properties & Fields
/// <summary>
/// Gets or sets the internal color-data cache.
/// </summary>
protected byte[] ColorData { get; private set; }
private Action<IntPtr, byte[]> _updateAction;
private IntPtr _handle;
#endregion
#region Constructors
public AsusUpdateQueue(IUpdateTrigger updateTrigger)
: base(updateTrigger)
{ }
#endregion
#region Methods
public void Initialize(Action<IntPtr, byte[]> updateAction, IntPtr handle, int ledCount)
{
_updateAction = updateAction;
_handle = handle;
ColorData = new byte[ledCount * 3];
}
protected override void Update(Dictionary<object, Color> dataSet)
{
foreach (KeyValuePair<object, Color> data in dataSet)
{
int index = ((int)data.Key) * 3;
ColorData[index] = data.Value.R;
ColorData[index + 1] = data.Value.B;
ColorData[index + 2] = data.Value.G;
}
_updateAction(_handle, ColorData);
}
#endregion
}
}

View File

@ -7,6 +7,6 @@ namespace RGB.NET.Devices.Asus
/// </summary>
internal interface IAsusRGBDevice : IRGBDevice
{
void Initialize();
void Initialize(IUpdateTrigger updateTrigger);
}
}

View File

@ -1,4 +1,5 @@
using RGB.NET.Core;
using System;
using RGB.NET.Core;
using RGB.NET.Devices.Asus.Native;
namespace RGB.NET.Devices.Asus
@ -40,7 +41,7 @@ namespace RGB.NET.Devices.Asus
protected override object CreateLedCustomData(LedId ledId) => (int)ledId - (int)LedId.GraphicsCard1;
/// <inheritdoc />
protected override void ApplyColorData() => _AsusSDK.SetGPUColor(DeviceInfo.Handle, ColorData);
protected override Action<IntPtr, byte[]> GetUpdateColorAction() => _AsusSDK.SetGPUColor;
#endregion
}

View File

@ -1,4 +1,5 @@
using RGB.NET.Core;
using System;
using RGB.NET.Core;
using RGB.NET.Devices.Asus.Native;
namespace RGB.NET.Devices.Asus
@ -38,9 +39,9 @@ namespace RGB.NET.Devices.Asus
/// <inheritdoc />
protected override object CreateLedCustomData(LedId ledId) => (int)ledId - (int)LedId.Keyboard_Escape;
/// <inheritdoc />
protected override void ApplyColorData() => _AsusSDK.SetClaymoreKeyboardColor(DeviceInfo.Handle, ColorData);
protected override Action<IntPtr, byte[]> GetUpdateColorAction() => _AsusSDK.SetClaymoreKeyboardColor;
#endregion
}

View File

@ -1,4 +1,5 @@
using RGB.NET.Core;
using System;
using RGB.NET.Core;
using RGB.NET.Devices.Asus.Native;
namespace RGB.NET.Devices.Asus
@ -48,7 +49,7 @@ namespace RGB.NET.Devices.Asus
}
/// <inheritdoc />
protected override void ApplyColorData() => _AsusSDK.SetMbColor(DeviceInfo.Handle, ColorData);
protected override Action<IntPtr, byte[]> GetUpdateColorAction() => _AsusSDK.SetMbColor;
#endregion
}

View File

@ -1,4 +1,5 @@
using RGB.NET.Core;
using System;
using RGB.NET.Core;
using RGB.NET.Devices.Asus.Native;
namespace RGB.NET.Devices.Asus
@ -39,7 +40,7 @@ namespace RGB.NET.Devices.Asus
protected override object CreateLedCustomData(LedId ledId) => (int)ledId - (int)LedId.Mouse1;
/// <inheritdoc />
protected override void ApplyColorData() => _AsusSDK.SetRogMouseColor(DeviceInfo.Handle, ColorData);
protected override Action<IntPtr, byte[]> GetUpdateColorAction() => _AsusSDK.SetRogMouseColor;
#endregion
}

View File

@ -54,6 +54,7 @@
<Compile Include="Enum\AsusPhysicalKeyboardLayout.cs" />
<Compile Include="Generic\AsusRGBDevice.cs" />
<Compile Include="Generic\AsusRGBDeviceInfo.cs" />
<Compile Include="Generic\AsusUpdateQueue.cs" />
<Compile Include="Generic\IAsusRGBDevice.cs" />
<Compile Include="GraphicsCard\AsusGraphicsCardRGBDevice.cs" />
<Compile Include="GraphicsCard\AsusGraphicsCardRGBDeviceInfo.cs" />

View File

@ -63,6 +63,8 @@ namespace RGB.NET.Devices.CoolerMaster
// ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global
public Func<CultureInfo> GetCulture { get; set; } = CultureHelper.GetCurrentCulture;
public UpdateTrigger UpdateTrigger { get; private set; }
#endregion
#region Constructors
@ -75,6 +77,8 @@ namespace RGB.NET.Devices.CoolerMaster
{
if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(CoolerMasterDeviceProvider)}");
_instance = this;
UpdateTrigger = new UpdateTrigger();
}
#endregion
@ -88,6 +92,8 @@ namespace RGB.NET.Devices.CoolerMaster
try
{
UpdateTrigger?.Stop();
_CoolerMasterSDK.Reload();
if (_CoolerMasterSDK.GetSDKVersion() <= 0) return false;
@ -120,13 +126,15 @@ namespace RGB.NET.Devices.CoolerMaster
_CoolerMasterSDK.EnableLedControl(true);
device.Initialize();
device.Initialize(UpdateTrigger);
devices.Add(device);
}
}
catch { if (throwExceptions) throw; }
}
UpdateTrigger?.Start();
Devices = new ReadOnlyCollection<IRGBDevice>(devices);
IsInitialized = true;
}

View File

@ -15,12 +15,15 @@ namespace RGB.NET.Devices.CoolerMaster
where TDeviceInfo : CoolerMasterRGBDeviceInfo
{
#region Properties & Fields
/// <inheritdoc />
/// <summary>
/// Gets information about the <see cref="T:RGB.NET.Devices.CoolerMaster.CoolerMasterRGBDevice" />.
/// </summary>
public override TDeviceInfo DeviceInfo { get; }
protected CoolerMasterUpdateQueue UpdateQueue { get; set; }
#endregion
#region Constructors
@ -42,7 +45,7 @@ namespace RGB.NET.Devices.CoolerMaster
/// <summary>
/// Initializes the device.
/// </summary>
public void Initialize()
public void Initialize(IUpdateTrigger updateTrigger)
{
InitializeLayout();
@ -51,6 +54,8 @@ namespace RGB.NET.Devices.CoolerMaster
Rectangle ledRectangle = new Rectangle(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
UpdateQueue = new CoolerMasterUpdateQueue(updateTrigger, DeviceInfo.DeviceIndex);
}
/// <summary>
@ -59,23 +64,7 @@ namespace RGB.NET.Devices.CoolerMaster
protected abstract void InitializeLayout();
/// <inheritdoc />
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate)
{
List<Led> leds = ledsToUpdate.Where(x => x.Color.A > 0).ToList();
if (leds.Count > 0)
{
_CoolerMasterSDK.SetControlDevice(DeviceInfo.DeviceIndex);
foreach (Led led in leds)
{
(int row, int column) = ((int, int))led.CustomData;
_CoolerMasterSDK.SetLedColor(row, column, led.Color.R, led.Color.G, led.Color.B);
}
_CoolerMasterSDK.RefreshLed(false);
}
}
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate) => UpdateQueue.SetData(ledsToUpdate.Where(x => x.Color.A > 0));
/// <inheritdoc cref="IDisposable.Dispose" />
/// <inheritdoc cref="AbstractRGBDevice{TDeviceInfo}.Dispose" />

View File

@ -0,0 +1,43 @@
using System.Collections.Generic;
using RGB.NET.Core;
using RGB.NET.Devices.CoolerMaster.Native;
namespace RGB.NET.Devices.CoolerMaster
{
public class CoolerMasterUpdateQueue : UpdateQueue
{
#region Properties & Fields
private CoolerMasterDevicesIndexes _deviceIndex;
#endregion
#region Constructors
public CoolerMasterUpdateQueue(IUpdateTrigger updateTrigger, CoolerMasterDevicesIndexes deviceIndex)
: base(updateTrigger)
{
this._deviceIndex = deviceIndex;
}
#endregion
#region Methods
/// <inheritdoc />
protected override void Update(Dictionary<object, Color> dataSet)
{
_CoolerMasterSDK.SetControlDevice(_deviceIndex);
foreach (KeyValuePair<object, Color> data in dataSet)
{
(int row, int column) = ((int, int))data.Key;
_CoolerMasterSDK.SetLedColor(row, column, data.Value.R, data.Value.G, data.Value.B);
}
_CoolerMasterSDK.RefreshLed(false);
}
#endregion
}
}

View File

@ -7,6 +7,6 @@ namespace RGB.NET.Devices.CoolerMaster
/// </summary>
internal interface ICoolerMasterRGBDevice : IRGBDevice
{
void Initialize();
void Initialize(IUpdateTrigger updateTrigger);
}
}

View File

@ -55,6 +55,7 @@
<Compile Include="Enum\CoolerMasterLogicalKeyboardLayout.cs" />
<Compile Include="Generic\CoolerMasterRGBDevice.cs" />
<Compile Include="Generic\CoolerMasterRGBDeviceInfo.cs" />
<Compile Include="Generic\CoolerMasterUpdateQueue.cs" />
<Compile Include="Generic\ICoolerMasterRGBDevice.cs" />
<Compile Include="Helper\EnumExtension.cs" />
<Compile Include="Keyboard\CoolerMasterKeyboardRGBDevice.cs" />

View File

@ -66,6 +66,9 @@ namespace RGB.NET.Devices.Corsair
/// <inheritdoc />
public IEnumerable<IRGBDevice> Devices { get; private set; }
public UpdateTrigger UpdateTrigger { get; private set; }
private CorsairUpdateQueue _updateQueue;
#endregion
#region Constructors
@ -78,6 +81,9 @@ namespace RGB.NET.Devices.Corsair
{
if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(CorsairDeviceProvider)}");
_instance = this;
UpdateTrigger = new UpdateTrigger();
_updateQueue = new CorsairUpdateQueue(UpdateTrigger);
}
#endregion
@ -93,6 +99,8 @@ namespace RGB.NET.Devices.Corsair
try
{
UpdateTrigger?.Stop();
_CUESDK.Reload();
ProtocolDetails = new CorsairProtocolDetails(_CUESDK.CorsairPerformProtocolHandshake());
@ -130,7 +138,7 @@ namespace RGB.NET.Devices.Corsair
ICorsairRGBDevice device = GetRGBDevice(info, i, nativeDeviceInfo);
if ((device == null) || !loadFilter.HasFlag(device.DeviceInfo.DeviceType)) continue;
device.Initialize();
device.Initialize(_updateQueue);
AddSpecialParts(device);
error = LastError;
@ -142,6 +150,8 @@ namespace RGB.NET.Devices.Corsair
catch { if (throwExceptions) throw; }
}
UpdateTrigger?.Start();
Devices = new ReadOnlyCollection<IRGBDevice>(devices);
IsInitialized = true;
}

View File

@ -29,6 +29,8 @@ namespace RGB.NET.Devices.Corsair
// ReSharper disable once MemberCanBePrivate.Global
protected Dictionary<CorsairLedId, Led> InternalLedMapping { get; } = new Dictionary<CorsairLedId, Led>();
protected CorsairUpdateQueue UpdateQueue { get; set; }
#endregion
#region Indexer
@ -61,8 +63,10 @@ namespace RGB.NET.Devices.Corsair
/// <summary>
/// Initializes the device.
/// </summary>
public void Initialize()
public void Initialize(CorsairUpdateQueue updateQueue)
{
UpdateQueue = updateQueue;
InitializeLayout();
foreach (Led led in LedMapping.Values)
@ -86,31 +90,7 @@ namespace RGB.NET.Devices.Corsair
/// <inheritdoc />
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate)
{
List<Led> leds = ledsToUpdate.Where(x => (x.Color.A > 0) && (x.CustomData is CorsairLedId ledId && (ledId != CorsairLedId.Invalid))).ToList();
if (leds.Count > 0) // CUE seems to crash if 'CorsairSetLedsColors' is called with a zero length array
{
int structSize = Marshal.SizeOf(typeof(_CorsairLedColor));
IntPtr ptr = Marshal.AllocHGlobal(structSize * leds.Count);
IntPtr addPtr = new IntPtr(ptr.ToInt64());
foreach (Led led in leds)
{
_CorsairLedColor color = new _CorsairLedColor
{
ledId = (int)led.CustomData,
r = led.Color.R,
g = led.Color.G,
b = led.Color.B
};
Marshal.StructureToPtr(color, addPtr, false);
addPtr = new IntPtr(addPtr.ToInt64() + structSize);
}
_CUESDK.CorsairSetLedsColors(leds.Count, ptr);
Marshal.FreeHGlobal(ptr);
}
}
=> UpdateQueue.SetData(ledsToUpdate.Where(x => (x.Color.A > 0) && (x.CustomData is CorsairLedId ledId && (ledId != CorsairLedId.Invalid))));
/// <inheritdoc cref="IRGBDevice.SyncBack" />
public override void SyncBack()

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using RGB.NET.Core;
using RGB.NET.Devices.Corsair.Native;
namespace RGB.NET.Devices.Corsair
{
public class CorsairUpdateQueue : UpdateQueue
{
#region Constructors
public CorsairUpdateQueue(IUpdateTrigger updateTrigger)
: base(updateTrigger)
{ }
#endregion
#region Methods
/// <inheritdoc />
protected override void Update(Dictionary<object, Color> dataSet)
{
int structSize = Marshal.SizeOf(typeof(_CorsairLedColor));
IntPtr ptr = Marshal.AllocHGlobal(structSize * dataSet.Count);
IntPtr addPtr = new IntPtr(ptr.ToInt64());
foreach (KeyValuePair<object, Color> data in dataSet)
{
_CorsairLedColor color = new _CorsairLedColor
{
ledId = (int)data.Key,
r = data.Value.R,
g = data.Value.G,
b = data.Value.B
};
Marshal.StructureToPtr(color, addPtr, false);
addPtr = new IntPtr(addPtr.ToInt64() + structSize);
}
_CUESDK.CorsairSetLedsColors(dataSet.Count, ptr);
Marshal.FreeHGlobal(ptr);
}
#endregion
}
}

View File

@ -7,6 +7,6 @@ namespace RGB.NET.Devices.Corsair
/// </summary>
internal interface ICorsairRGBDevice : IRGBDevice
{
void Initialize();
void Initialize(CorsairUpdateQueue updateQueue);
}
}

View File

@ -59,6 +59,7 @@
<Compile Include="Generic\CorsairProtocolDetails.cs" />
<Compile Include="Generic\CorsairRGBDeviceInfo.cs" />
<Compile Include="Generic\CorsairRGBDevice.cs" />
<Compile Include="Generic\CorsairUpdateQueue.cs" />
<Compile Include="Generic\ICorsairRGBDevice.cs" />
<Compile Include="HeadsetStand\CorsairHeadsetStandRGBDevice.cs" />
<Compile Include="HeadsetStand\CorsairHeadsetStandRGBDeviceInfo.cs" />

View File

@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generic_005Cupdate/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=headsetstand/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=helper/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=libs/@EntryIndexedValue">True</s:Boolean>

View File

@ -37,6 +37,8 @@ namespace RGB.NET.Devices.DMX
/// </summary>
public List<IDMXDeviceDefinition> DeviceDefinitions { get; } = new List<IDMXDeviceDefinition>();
public UpdateTrigger UpdateTrigger { get; private set; }
#endregion
#region Constructors
@ -49,6 +51,8 @@ namespace RGB.NET.Devices.DMX
{
if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(DMXDeviceProvider)}");
_instance = this;
UpdateTrigger = new UpdateTrigger();
}
#endregion
@ -68,6 +72,8 @@ namespace RGB.NET.Devices.DMX
try
{
UpdateTrigger.Stop();
IList<IRGBDevice> devices = new List<IRGBDevice>();
foreach (IDMXDeviceDefinition dmxDeviceDefinition in DeviceDefinitions)
@ -79,7 +85,7 @@ namespace RGB.NET.Devices.DMX
if (e131DMXDeviceDefinition.Leds.Count > 0)
{
E131Device device = new E131Device(new E131DeviceInfo(e131DMXDeviceDefinition), e131DMXDeviceDefinition.Leds);
device.Initialize();
device.Initialize(UpdateTrigger);
devices.Add(device);
}
}
@ -87,6 +93,8 @@ namespace RGB.NET.Devices.DMX
catch { if (throwExceptions) throw; }
}
UpdateTrigger.Start();
Devices = new ReadOnlyCollection<IRGBDevice>(devices);
IsInitialized = true;
}

View File

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using RGB.NET.Core;
namespace RGB.NET.Devices.DMX.E131
@ -13,27 +12,13 @@ namespace RGB.NET.Devices.DMX.E131
{
#region Properties & Fields
/// <summary>
/// Gets the UDP-Connection used to send data.
/// </summary>
private UdpClient _socket;
/// <summary>
/// Gets the byte-representation of a E1.31 packet as described in http://tsp.esta.org/tsp/documents/docs/E1-31-2016.pdf.
/// CID, SequenceNumber, Universe and PropertyValues needs to be updated before use!
/// </summary>
private byte[] _dataPacket = { 0x00, 0x10, 0x00, 0x00, 0x41, 0x53, 0x43, 0x2D, 0x45, 0x31, 0x2E, 0x31, 0x37, 0x00, 0x00, 0x00, 0x72, 0x6E, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x72, 0x0B, 0x02, 0xA1, 0x00, 0x00, 0x00, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
/// <summary>
/// Gets or sets the Sequence number used to detect the order in which packages where sent.
/// </summary>
private byte _sequenceNumber = 0;
/// <inheritdoc />
public override E131DeviceInfo DeviceInfo { get; }
private readonly Dictionary<LedId, List<(int channel, Func<Color, byte> getValueFunc)>> _ledMappings;
private E131UpdateQueue _updateQueue;
#endregion
#region Constructors
@ -49,18 +34,12 @@ namespace RGB.NET.Devices.DMX.E131
#region Methods
internal void Initialize()
internal void Initialize(IUpdateTrigger updateTrigger)
{
int count = 0;
foreach (LedId id in _ledMappings.Keys)
InitializeLed(id, new Rectangle((count++) * 10, 0, 10, 10));
_socket = new UdpClient();
_socket.Connect(DeviceInfo.Hostname, DeviceInfo.Port);
_dataPacket.SetCID(DeviceInfo.CID);
_dataPacket.SetUniverse(DeviceInfo.Universe);
//TODO DarthAffe 18.02.2018: Allow to load a layout.
if (Size == Size.Invalid)
@ -68,44 +47,17 @@ namespace RGB.NET.Devices.DMX.E131
Rectangle ledRectangle = new Rectangle(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
_updateQueue = new E131UpdateQueue(updateTrigger, DeviceInfo.Hostname, DeviceInfo.Port);
_updateQueue.DataPacket.SetCID(DeviceInfo.CID);
_updateQueue.DataPacket.SetUniverse(DeviceInfo.Universe);
}
/// <inheritdoc />
protected override object CreateLedCustomData(LedId ledId) => new LedChannelMapping(_ledMappings[ledId]);
/// <inheritdoc />
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate)
{
List<Led> leds = ledsToUpdate.Where(x => x.Color.A > 0).ToList();
if (leds.Count > 0)
{
_dataPacket.SetSequenceNumber(GetNextSequenceNumber());
foreach (Led led in leds)
{
LedChannelMapping mapping = (LedChannelMapping)led.CustomData;
foreach ((int channel, Func<Color, byte> getValue) in mapping)
_dataPacket.SetChannel(channel, getValue(led.Color));
}
_socket.Send(_dataPacket, _dataPacket.Length);
}
}
/// <summary>
/// Increments the sequence number and wraps it if neded.
/// </summary>
/// <returns>The next usable sequence number.</returns>
private byte GetNextSequenceNumber()
{
if (_sequenceNumber == byte.MaxValue)
{
_sequenceNumber = byte.MinValue;
return byte.MaxValue;
}
return _sequenceNumber++;
}
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate) => _updateQueue.SetData(ledsToUpdate.Where(x => x.Color.A > 0));
#endregion
}

View File

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using RGB.NET.Core;
namespace RGB.NET.Devices.DMX.E131
{
public class E131UpdateQueue : UpdateQueue
{
#region Properties & Fields
/// <summary>
/// The UDP-Connection used to send data.
/// </summary>
private UdpClient _socket;
/// <summary>
/// Gets the byte-representation of a E1.31 packet as described in http://tsp.esta.org/tsp/documents/docs/E1-31-2016.pdf.
/// CID, SequenceNumber, Universe and PropertyValues needs to be updated before use!
/// </summary>
internal byte[] DataPacket { get; } = { 0x00, 0x10, 0x00, 0x00, 0x41, 0x53, 0x43, 0x2D, 0x45, 0x31, 0x2E, 0x31, 0x37, 0x00, 0x00, 0x00, 0x72, 0x6E, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x72, 0x0B, 0x02, 0xA1, 0x00, 0x00, 0x00, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
/// <summary>
/// The sequence-number used to detect the order in which packages where sent.
/// </summary>
private byte _sequenceNumber = 0;
#endregion
#region Constructors
public E131UpdateQueue(IUpdateTrigger updateTrigger, string hostname, int port)
: base(updateTrigger)
{
_socket = new UdpClient();
_socket.Connect(hostname, port);
}
#endregion
#region Methods
protected override void Update(Dictionary<object, Color> dataSet)
{
DataPacket.SetSequenceNumber(GetNextSequenceNumber());
foreach (KeyValuePair<object, Color> data in dataSet)
{
LedChannelMapping mapping = (LedChannelMapping)data.Key;
foreach ((int channel, Func<Color, byte> getValue) in mapping)
DataPacket.SetChannel(channel, getValue(data.Value));
}
_socket.Send(DataPacket, DataPacket.Length);
}
/// <summary>
/// Increments the sequence number and wraps it if neded.
/// </summary>
/// <returns>The next usable sequence number.</returns>
private byte GetNextSequenceNumber()
{
if (_sequenceNumber == byte.MaxValue)
{
_sequenceNumber = byte.MinValue;
return byte.MaxValue;
}
return _sequenceNumber++;
}
#endregion
}
}

View File

@ -51,6 +51,7 @@
<Compile Include="E131\E131Device.cs" />
<Compile Include="E131\E131DeviceInfo.cs" />
<Compile Include="E131\E131DMXDeviceDefinition.cs" />
<Compile Include="E131\E131UpdateQueue.cs" />
<Compile Include="Generic\IDMXDeviceDefinition.cs" />
<Compile Include="Generic\LedChannelMapping.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

View File

@ -7,6 +7,6 @@ namespace RGB.NET.Devices.Logitech
/// </summary>
internal interface ILogitechRGBDevice : IRGBDevice
{
void Initialize();
void Initialize(UpdateQueue updateQueue);
}
}

View File

@ -19,6 +19,8 @@ namespace RGB.NET.Devices.Logitech
/// </summary>
public override TDeviceInfo DeviceInfo { get; }
protected UpdateQueue UpdateQueue { get; set; }
#endregion
#region Constructors
@ -39,7 +41,7 @@ namespace RGB.NET.Devices.Logitech
/// <summary>
/// Initializes the device.
/// </summary>
public void Initialize()
public void Initialize(UpdateQueue updateQueue)
{
InitializeLayout();
@ -48,6 +50,8 @@ namespace RGB.NET.Devices.Logitech
Rectangle ledRectangle = new Rectangle(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
UpdateQueue = updateQueue;
}
/// <summary>

View File

@ -56,6 +56,10 @@ namespace RGB.NET.Devices.Logitech
/// </summary>
public Func<CultureInfo> GetCulture { get; set; } = CultureHelper.GetCurrentCulture;
public UpdateTrigger UpdateTrigger { get; private set; }
private LogitechPerDeviceUpdateQueue _perDeviceUpdateQueue;
private LogitechPerKeyUpdateQueue _perKeyUpdateQueue;
#endregion
#region Constructors
@ -68,6 +72,10 @@ namespace RGB.NET.Devices.Logitech
{
if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(LogitechDeviceProvider)}");
_instance = this;
UpdateTrigger = new UpdateTrigger();
_perDeviceUpdateQueue = new LogitechPerDeviceUpdateQueue(UpdateTrigger);
_perKeyUpdateQueue = new LogitechPerKeyUpdateQueue(UpdateTrigger);
}
#endregion
@ -88,6 +96,8 @@ namespace RGB.NET.Devices.Logitech
try
{
UpdateTrigger?.Stop();
_LogitechGSDK.Reload();
if (!_LogitechGSDK.LogiLedInit()) return false;
@ -104,7 +114,7 @@ namespace RGB.NET.Devices.Logitech
if (loadFilter.HasFlag(deviceType)) //TODO DarthAffe 07.12.2017: Check if it's worth to try another device if the one returned doesn't match the filter
{
ILogitechRGBDevice device = new LogitechPerKeyRGBDevice(new LogitechRGBDeviceInfo(deviceType, model, LogitechDeviceCaps.PerKeyRGB, imageLayout, layoutPath));
device.Initialize();
device.Initialize(_perKeyUpdateQueue);
devices.Add(device);
}
}
@ -119,13 +129,15 @@ namespace RGB.NET.Devices.Logitech
if (loadFilter.HasFlag(deviceType)) //TODO DarthAffe 07.12.2017: Check if it's worth to try another device if the one returned doesn't match the filter
{
ILogitechRGBDevice device = new LogitechPerDeviceRGBDevice(new LogitechRGBDeviceInfo(deviceType, model, LogitechDeviceCaps.DeviceRGB, imageLayout, layoutPath));
device.Initialize();
device.Initialize(_perDeviceUpdateQueue);
devices.Add(device);
}
}
}
catch { if (throwExceptions) throw; }
UpdateTrigger?.Start();
Devices = new ReadOnlyCollection<IRGBDevice>(devices);
IsInitialized = true;
}

View File

@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using RGB.NET.Core;
using RGB.NET.Devices.Logitech.Native;
namespace RGB.NET.Devices.Logitech
{
@ -37,19 +35,10 @@ namespace RGB.NET.Devices.Logitech
}
/// <inheritdoc />
protected override object CreateLedCustomData(LedId ledId) => LogitechLedId.DEVICE;
protected override object CreateLedCustomData(LedId ledId) => (ledId, LogitechLedId.DEVICE);
/// <inheritdoc />
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate)
{
Led led = ledsToUpdate.FirstOrDefault(x => x.Color.A > 0);
if (led == null) return;
_LogitechGSDK.LogiLedSetTargetDevice(LogitechDeviceCaps.DeviceRGB);
_LogitechGSDK.LogiLedSetLighting((int)Math.Round(led.Color.RPercent * 100),
(int)Math.Round(led.Color.GPercent * 100),
(int)Math.Round(led.Color.BPercent * 100));
}
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate) => UpdateQueue.SetData(ledsToUpdate.Where(x => x.Color.A > 0).Take(1));
#endregion
}

View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using RGB.NET.Core;
using RGB.NET.Devices.Logitech.Native;
namespace RGB.NET.Devices.Logitech
{
public class LogitechPerDeviceUpdateQueue : UpdateQueue
{
#region Constructors
public LogitechPerDeviceUpdateQueue(IUpdateTrigger updateTrigger)
: base(updateTrigger)
{ }
#endregion
#region Methods
/// <inheritdoc />
protected override void Update(Dictionary<object, Color> dataSet)
{
Color color = dataSet.Values.First();
_LogitechGSDK.LogiLedSetTargetDevice(LogitechDeviceCaps.DeviceRGB);
_LogitechGSDK.LogiLedSetLighting((int)Math.Round(color.RPercent * 100),
(int)Math.Round(color.GPercent * 100),
(int)Math.Round(color.BPercent * 100));
}
#endregion
}
}

View File

@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using RGB.NET.Core;
using RGB.NET.Devices.Logitech.Native;
namespace RGB.NET.Devices.Logitech
{
@ -28,37 +26,10 @@ namespace RGB.NET.Devices.Logitech
#region Methods
/// <inheritdoc />
protected override object CreateLedCustomData(LedId ledId) => PerKeyIdMapping.DEFAULT.TryGetValue(ledId, out LogitechLedId logitechLedId) ? logitechLedId : LogitechLedId.Invalid;
protected override object CreateLedCustomData(LedId ledId) => (ledId, PerKeyIdMapping.DEFAULT.TryGetValue(ledId, out LogitechLedId logitechLedId) ? logitechLedId : LogitechLedId.Invalid);
/// <inheritdoc />
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate)
{
List<Led> leds = ledsToUpdate.Where(x => x.Color.A > 0).ToList();
if (leds.Count <= 0) return;
_LogitechGSDK.LogiLedSetTargetDevice(LogitechDeviceCaps.PerKeyRGB);
byte[] bitmap = null;
foreach (Led led in leds)
{
// DarthAffe 26.03.2017: This is only needed since update by name doesn't work as expected for all keys ...
if (BitmapMapping.BitmapOffset.TryGetValue(led.Id, out int bitmapOffset))
{
if (bitmap == null)
bitmap = BitmapMapping.CreateBitmap();
BitmapMapping.SetColor(ref bitmap, bitmapOffset, led.Color);
}
else
_LogitechGSDK.LogiLedSetLightingForKeyWithKeyName((int)led.CustomData,
(int)Math.Round(led.Color.RPercent * 100),
(int)Math.Round(led.Color.GPercent * 100),
(int)Math.Round(led.Color.BPercent * 100));
}
if (bitmap != null)
_LogitechGSDK.LogiLedSetLightingFromBitmap(bitmap);
}
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate) => UpdateQueue.SetData(ledsToUpdate.Where(x => x.Color.A > 0));
#endregion
}

View File

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using RGB.NET.Core;
using RGB.NET.Devices.Logitech.Native;
namespace RGB.NET.Devices.Logitech
{
public class LogitechPerKeyUpdateQueue : UpdateQueue
{
#region Constructors
public LogitechPerKeyUpdateQueue(IUpdateTrigger updateTrigger)
: base(updateTrigger)
{ }
#endregion
#region Methods
/// <inheritdoc />
protected override void Update(Dictionary<object, Color> dataSet)
{
_LogitechGSDK.LogiLedSetTargetDevice(LogitechDeviceCaps.PerKeyRGB);
byte[] bitmap = null;
foreach (KeyValuePair<object, Color> data in dataSet)
{
(LedId id, int customData) = ((LedId, int))data.Key;
// DarthAffe 26.03.2017: This is only needed since update by name doesn't work as expected for all keys ...
if (BitmapMapping.BitmapOffset.TryGetValue(id, out int bitmapOffset))
{
if (bitmap == null)
bitmap = BitmapMapping.CreateBitmap();
BitmapMapping.SetColor(ref bitmap, bitmapOffset, data.Value);
}
else
_LogitechGSDK.LogiLedSetLightingForKeyWithKeyName(customData,
(int)Math.Round(data.Value.RPercent * 100),
(int)Math.Round(data.Value.GPercent * 100),
(int)Math.Round(data.Value.BPercent * 100));
}
if (bitmap != null)
_LogitechGSDK.LogiLedSetLightingFromBitmap(bitmap);
}
#endregion
}
}

View File

@ -57,11 +57,13 @@
<Compile Include="Generic\LogitechRGBDevice.cs" />
<Compile Include="Generic\LogitechRGBDeviceInfo.cs" />
<Compile Include="LogitechDeviceProviderLoader.cs" />
<Compile Include="PerDevice\LogitechPerDeviceUpdateQueue.cs" />
<Compile Include="PerKey\BitmapMapping.cs" />
<Compile Include="HID\DeviceChecker.cs" />
<Compile Include="LogitechDeviceProvider.cs" />
<Compile Include="Native\_LogitechGSDK.cs" />
<Compile Include="PerDevice\LogitechPerDeviceRGBDevice.cs" />
<Compile Include="PerKey\LogitechPerKeyUpdateQueue.cs" />
<Compile Include="PerKey\PerKeyIdMapping.cs" />
<Compile Include="PerKey\LogitechPerKeyRGBDevice.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

View File

@ -7,6 +7,6 @@ namespace RGB.NET.Devices.Novation
/// </summary>
internal interface INovationRGBDevice : IRGBDevice
{
void Initialize();
void Initialize(IUpdateTrigger updateTrigger);
}
}

View File

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using RGB.NET.Core;
using Sanford.Multimedia.Midi;
namespace RGB.NET.Devices.Novation
{
public class LimitedColorUpdateQueue : MidiUpdateQueue
{
#region Constructors
public LimitedColorUpdateQueue(IUpdateTrigger updateTrigger, int deviceId)
: base(updateTrigger, deviceId)
{ }
#endregion
#region Methods
/// <inheritdoc />
protected override ShortMessage CreateMessage(KeyValuePair<object, Color> data)
{
NovationLedId ledId = (NovationLedId)data.Key;
return new ShortMessage(Convert.ToByte(ledId.GetStatus()), Convert.ToByte(ledId.GetId()), Convert.ToByte(ConvertColor(data.Value)));
}
/// <summary>
/// Convert a <see cref="Color"/> to its novation-representation depending on the <see cref="NovationColorCapabilities"/> of the <see cref="NovationRGBDevice{TDeviceInfo}"/>.
/// The conversion uses only a limited amount of colors (3 red, 3 yellow, 3 green).
/// </summary>
/// <param name="color">The <see cref="Color"/> to convert.</param>
/// <returns>The novation-representation of the <see cref="Color"/>.</returns>
protected virtual int ConvertColor(Color color)
{
if ((color.Hue >= 330) || (color.Hue < 30))
return (int)Math.Ceiling(color.Value * 3); // red with brightness 1, 2 or 3
if ((color.Hue >= 30) && (color.Hue < 90)) // yellow with brightness 17, 34 or 51
return (int)Math.Ceiling(color.Value * 3) * 17;
if ((color.Hue >= 90) && (color.Hue < 150)) // green with brightness 16, 32 or 48
return (int)Math.Ceiling(color.Value * 3) * 16;
return 0;
}
/// <inheritdoc />
public override void Reset()
{
base.Reset();
SendMessage(new ShortMessage(Convert.ToByte(0xB0), Convert.ToByte(0), Convert.ToByte(0)));
}
#endregion
}
}

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using RGB.NET.Core;
using Sanford.Multimedia.Midi;
namespace RGB.NET.Devices.Novation
{
public abstract class MidiUpdateQueue : UpdateQueue, IDisposable
{
#region Properties & Fields
private readonly OutputDevice _outputDevice;
#endregion
#region Constructors
public MidiUpdateQueue(IUpdateTrigger updateTrigger, int deviceId)
: base(updateTrigger)
{
_outputDevice = new OutputDevice(deviceId);
}
#endregion
#region Methods
/// <inheritdoc />
protected override void Update(Dictionary<object, Color> dataSet)
{
foreach (KeyValuePair<object, Color> data in dataSet)
SendMessage(CreateMessage(data));
}
protected virtual void SendMessage(ShortMessage message) => _outputDevice.SendShort(message.Message);
protected abstract ShortMessage CreateMessage(KeyValuePair<object, Color> data);
public void Dispose()
{
_outputDevice.Dispose();
}
#endregion
}
}

View File

@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using RGB.NET.Core;
using Sanford.Multimedia.Midi;
namespace RGB.NET.Devices.Novation
{
@ -16,14 +15,13 @@ namespace RGB.NET.Devices.Novation
{
#region Properties & Fields
private readonly OutputDevice _outputDevice;
private readonly TDeviceInfo _deviceInfo;
/// <inheritdoc />
/// <summary>
/// Gets information about the <see cref="T:RGB.NET.Devices.Novation.NovationRGBDevice" />.
/// </summary>
public override TDeviceInfo DeviceInfo => _deviceInfo;
public override TDeviceInfo DeviceInfo { get; }
protected MidiUpdateQueue UpdateQueue { get; set; }
#endregion
@ -35,20 +33,17 @@ namespace RGB.NET.Devices.Novation
/// <param name="info">The generic information provided by Novation for the device.</param>
protected NovationRGBDevice(TDeviceInfo info)
{
this._deviceInfo = info;
_outputDevice = new OutputDevice(info.DeviceId);
this.DeviceInfo = info;
}
#endregion
#region Methods
/// <summary>
/// Initializes the device.
/// </summary>
public void Initialize()
public void Initialize(IUpdateTrigger updateTrigger)
{
InitializeLayout();
@ -57,6 +52,9 @@ namespace RGB.NET.Devices.Novation
Rectangle ledRectangle = new Rectangle(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
if (DeviceInfo.ColorCapabilities == NovationColorCapabilities.LimitedRG)
UpdateQueue = new LimitedColorUpdateQueue(updateTrigger, DeviceInfo.DeviceId);
}
/// <summary>
@ -65,96 +63,19 @@ namespace RGB.NET.Devices.Novation
protected abstract void InitializeLayout();
/// <inheritdoc />
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate)
{
List<Led> leds = ledsToUpdate.Where(x => x.Color.A > 0).ToList();
if (leds.Count > 0)
{
foreach (Led led in leds)
{
NovationLedId ledId = (NovationLedId)led.CustomData;
int color = ConvertColor(led.Color);
SendMessage(ledId.GetStatus(), ledId.GetId(), color);
}
}
}
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate) => UpdateQueue.SetData(ledsToUpdate.Where(x => x.Color.A > 0));
/// <summary>
/// Resets the <see cref="NovationRGBDevice{TDeviceInfo}"/> back top default.
/// Resets the <see cref="NovationRGBDevice{TDeviceInfo}"/> back to default.
/// </summary>
public virtual void Reset() => SendMessage(0xB0, 0, 0);
/// <summary>
/// Convert a <see cref="Color"/> to its novation-representation depending on the <see cref="NovationColorCapabilities"/> of the <see cref="NovationRGBDevice{TDeviceInfo}"/>.
/// </summary>
/// <param name="color">The <see cref="Color"/> to convert.</param>
/// <returns>The novation-representation of the <see cref="Color"/>.</returns>
protected virtual int ConvertColor(Color color)
{
switch (_deviceInfo.ColorCapabilities)
{
case NovationColorCapabilities.RGB:
return ConvertColorFull(color);
case NovationColorCapabilities.LimitedRG:
return ConvertColorLimited(color);
default:
return 0;
}
}
/// <summary>
/// Convert a <see cref="Color"/> to its novation-representation depending on the <see cref="NovationColorCapabilities"/> of the <see cref="NovationRGBDevice{TDeviceInfo}"/>.
/// The conversion uses the full rgb-range.
/// </summary>
/// <param name="color">The <see cref="Color"/> to convert.</param>
/// <returns>The novation-representation of the <see cref="Color"/>.</returns>
protected virtual int ConvertColorFull(Color color)
{
//TODO DarthAffe 16.08.2017: How are colors for full rgb devices encoded?
return 0;
}
/// <summary>
/// Convert a <see cref="Color"/> to its novation-representation depending on the <see cref="NovationColorCapabilities"/> of the <see cref="NovationRGBDevice{TDeviceInfo}"/>.
/// The conversion uses only a limited amount of colors (3 red, 3 yellow, 3 green).
/// </summary>
/// <param name="color">The <see cref="Color"/> to convert.</param>
/// <returns>The novation-representation of the <see cref="Color"/>.</returns>
protected virtual int ConvertColorLimited(Color color)
{
if ((color.Hue >= 330) || (color.Hue < 30))
return (int)Math.Ceiling(color.Value * 3); // red with brightness 1, 2 or 3
if ((color.Hue >= 30) && (color.Hue < 90)) // yellow with brightness 17, 34 or 51
return (int)Math.Ceiling(color.Value * 3) * 17;
if ((color.Hue >= 90) && (color.Hue < 150)) // green with brightness 16, 32 or 48
return (int)Math.Ceiling(color.Value * 3) * 16;
return 0;
}
/// <summary>
/// Sends a message to the <see cref="NovationRGBDevice{TDeviceInfo}"/>.
/// </summary>
/// <param name="status">The status-code of the message.</param>
/// <param name="data1">The first data-package of the message.</param>
/// <param name="data2">The second data-package of the message.</param>
protected virtual void SendMessage(int status, int data1, int data2)
{
ShortMessage shortMessage = new ShortMessage(Convert.ToByte(status), Convert.ToByte(data1), Convert.ToByte(data2));
_outputDevice.SendShort(shortMessage.Message);
}
public virtual void Reset() => UpdateQueue.Reset();
/// <inheritdoc cref="IDisposable.Dispose" />
/// <inheritdoc cref="AbstractRGBDevice{TDeviceInfo}.Dispose" />
public override void Dispose()
{
Reset();
_outputDevice.Dispose();
UpdateQueue.Dispose();
base.Dispose();
}

View File

@ -39,6 +39,8 @@ namespace RGB.NET.Devices.Novation
/// <inheritdoc />
public IEnumerable<IRGBDevice> Devices { get; private set; }
public UpdateTrigger UpdateTrigger { get; private set; }
#endregion
#region Constructors
@ -51,6 +53,8 @@ namespace RGB.NET.Devices.Novation
{
if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(NovationDeviceProvider)}");
_instance = this;
UpdateTrigger = new UpdateTrigger();
}
#endregion
@ -64,6 +68,8 @@ namespace RGB.NET.Devices.Novation
try
{
UpdateTrigger?.Stop();
IList<IRGBDevice> devices = new List<IRGBDevice>();
if (loadFilter.HasFlag(RGBDeviceType.LedMatrix))
@ -81,12 +87,13 @@ namespace RGB.NET.Devices.Novation
if (deviceId == null) continue;
INovationRGBDevice device = new NovationLaunchpadRGBDevice(new NovationLaunchpadRGBDeviceInfo(outCaps.name, index, deviceId.GetColorCapability()));
device.Initialize();
device.Initialize(UpdateTrigger);
devices.Add(device);
}
catch { if (throwExceptions) throw; }
}
UpdateTrigger?.Start();
Devices = new ReadOnlyCollection<IRGBDevice>(devices);
IsInitialized = true;
}

View File

@ -54,6 +54,8 @@
<Compile Include="Enum\NovationColorCapabilities.cs" />
<Compile Include="Enum\NovationDevices.cs" />
<Compile Include="Enum\NovationLedId.cs" />
<Compile Include="Generic\LimitedColorUpdateQueue.cs" />
<Compile Include="Generic\MidiUpdateQueue.cs" />
<Compile Include="Generic\NovationRGBDevice.cs" />
<Compile Include="Generic\NovationRGBDeviceInfo.cs" />
<Compile Include="Helper\DictionaryExtension.cs" />

View File

@ -1,9 +1,6 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using RGB.NET.Core;
using RGB.NET.Devices.Razer.Native;
@ -45,20 +42,7 @@ namespace RGB.NET.Devices.Razer
protected override object CreateLedCustomData(LedId ledId) => (int)ledId - (int)LedId.Custom1;
/// <inheritdoc />
protected override IntPtr CreateEffectParams(IEnumerable<Led> leds)
{
_Color[] colors = new _Color[_Defines.CHROMALINK_MAX_LEDS];
foreach (Led led in leds)
colors[(int)led.CustomData] = new _Color(led.Color.R, led.Color.G, led.Color.B);
_ChromaLinkCustomEffect effectParams = new _ChromaLinkCustomEffect { Color = colors };
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(effectParams));
Marshal.StructureToPtr(effectParams, ptr, false);
return ptr;
}
protected override RazerUpdateQueue CreateUpdateQueue(IUpdateTrigger updateTrigger) => new RazerChromaLinkUpdateQueue(updateTrigger, DeviceInfo.DeviceId);
#endregion
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using RGB.NET.Core;
using RGB.NET.Devices.Razer.Native;
namespace RGB.NET.Devices.Razer
{
public class RazerChromaLinkUpdateQueue : RazerUpdateQueue
{
#region Constructors
public RazerChromaLinkUpdateQueue(IUpdateTrigger updateTrigger, Guid deviceId)
: base(updateTrigger, deviceId)
{ }
#endregion
#region Methods
/// <inheritdoc />
protected override IntPtr CreateEffectParams(Dictionary<object, Color> dataSet)
{
_Color[] colors = new _Color[_Defines.CHROMALINK_MAX_LEDS];
foreach (KeyValuePair<object, Color> data in dataSet)
colors[(int)data.Key] = new _Color(data.Value);
_ChromaLinkCustomEffect effectParams = new _ChromaLinkCustomEffect { Color = colors };
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(effectParams));
Marshal.StructureToPtr(effectParams, ptr, false);
return ptr;
}
#endregion
}
}

View File

@ -7,7 +7,7 @@ namespace RGB.NET.Devices.Razer
/// </summary>
internal interface IRazerRGBDevice : IRGBDevice
{
void Initialize();
void Initialize(IUpdateTrigger updateTrigger);
void Reset();
}
}

View File

@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using RGB.NET.Core;
using RGB.NET.Devices.Razer.Native;
namespace RGB.NET.Devices.Razer
{
@ -16,14 +14,14 @@ namespace RGB.NET.Devices.Razer
{
#region Properties & Fields
private Guid? _lastEffect;
/// <inheritdoc />
/// <summary>
/// Gets information about the <see cref="T:RGB.NET.Devices.Razer.RazerRGBDevice" />.
/// </summary>
public override TDeviceInfo DeviceInfo { get; }
protected RazerUpdateQueue UpdateQueue { get; set; }
#endregion
#region Constructors
@ -46,7 +44,7 @@ namespace RGB.NET.Devices.Razer
/// <summary>
/// Initializes the device.
/// </summary>
public void Initialize()
public void Initialize(IUpdateTrigger updateTrigger)
{
InitializeLayout();
@ -55,50 +53,24 @@ namespace RGB.NET.Devices.Razer
Rectangle ledRectangle = new Rectangle(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
UpdateQueue = CreateUpdateQueue(updateTrigger);
}
protected abstract RazerUpdateQueue CreateUpdateQueue(IUpdateTrigger updateTrigger);
/// <summary>
/// Initializes the <see cref="Led"/> and <see cref="Size"/> of the device.
/// </summary>
protected abstract void InitializeLayout();
/// <inheritdoc />
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate)
{
List<Led> leds = ledsToUpdate.Where(x => x.Color.A > 0).ToList();
if (leds.Count <= 0) return;
IntPtr effectParams = CreateEffectParams(leds);
Guid effectId = Guid.NewGuid();
_RazerSDK.CreateEffect(DeviceInfo.DeviceId, _Defines.EFFECT_ID, effectParams, ref effectId);
_RazerSDK.SetEffect(effectId);
if (_lastEffect.HasValue)
_RazerSDK.DeleteEffect(_lastEffect.Value);
_lastEffect = effectId;
}
/// <summary>
/// Creates the device-specific effect parameters for the led-update.
/// </summary>
/// <param name="leds">The leds to be updated.</param>
/// <returns>An <see cref="IntPtr"/> pointing to the effect parameter struct.</returns>
protected abstract IntPtr CreateEffectParams(IEnumerable<Led> leds);
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate) => UpdateQueue.SetData(ledsToUpdate.Where(x => x.Color.A > 0));
/// <summary>
/// Resets the device.
/// </summary>
public void Reset()
{
if (_lastEffect.HasValue)
{
_RazerSDK.DeleteEffect(_lastEffect.Value);
_lastEffect = null;
}
}
public void Reset() => UpdateQueue.Reset();
#endregion
}

View File

@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using RGB.NET.Core;
using RGB.NET.Devices.Razer.Native;
namespace RGB.NET.Devices.Razer
{
public abstract class RazerUpdateQueue : UpdateQueue
{
#region Properties & Fields
private readonly Guid _deviceId;
private Guid? _lastEffect;
#endregion
#region Constructors
protected RazerUpdateQueue(IUpdateTrigger updateTrigger, Guid deviceId)
: base(updateTrigger)
{
this._deviceId = deviceId;
}
#endregion
#region Methods
/// <inheritdoc />
protected override void Update(Dictionary<object, Color> dataSet)
{
IntPtr effectParams = CreateEffectParams(dataSet);
Guid effectId = Guid.NewGuid();
_RazerSDK.CreateEffect(_deviceId, _Defines.EFFECT_ID, effectParams, ref effectId);
_RazerSDK.SetEffect(effectId);
if (_lastEffect.HasValue)
_RazerSDK.DeleteEffect(_lastEffect.Value);
_lastEffect = effectId;
}
/// <inheritdoc />
public override void Reset()
{
if (_lastEffect.HasValue)
{
_RazerSDK.DeleteEffect(_lastEffect.Value);
_lastEffect = null;
}
}
/// <summary>
/// Creates the device-specific effect parameters for the led-update.
/// </summary>
/// <param name="dataSet">The data to be updated.</param>
/// <returns>An <see cref="IntPtr"/> pointing to the effect parameter struct.</returns>
protected abstract IntPtr CreateEffectParams(Dictionary<object, Color> dataSet);
#endregion
}
}

View File

@ -1,9 +1,6 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using RGB.NET.Core;
using RGB.NET.Devices.Razer.Native;
@ -45,20 +42,7 @@ namespace RGB.NET.Devices.Razer
protected override object CreateLedCustomData(LedId ledId) => (int)ledId - (int)LedId.Headset1;
/// <inheritdoc />
protected override IntPtr CreateEffectParams(IEnumerable<Led> leds)
{
_Color[] colors = new _Color[_Defines.HEADSET_MAX_LEDS];
foreach (Led led in leds)
colors[(int)led.CustomData] = new _Color(led.Color.R, led.Color.G, led.Color.B);
_HeadsetCustomEffect effectParams = new _HeadsetCustomEffect { Color = colors };
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(effectParams));
Marshal.StructureToPtr(effectParams, ptr, false);
return ptr;
}
protected override RazerUpdateQueue CreateUpdateQueue(IUpdateTrigger updateTrigger) => new RazerHeadsetUpdateQueue(updateTrigger, DeviceInfo.DeviceId);
#endregion
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using RGB.NET.Core;
using RGB.NET.Devices.Razer.Native;
namespace RGB.NET.Devices.Razer
{
public class RazerHeadsetUpdateQueue : RazerUpdateQueue
{
#region Constructors
public RazerHeadsetUpdateQueue(IUpdateTrigger updateTrigger, Guid deviceId)
: base(updateTrigger, deviceId)
{ }
#endregion
#region Methods
/// <inheritdoc />
protected override IntPtr CreateEffectParams(Dictionary<object, Color> dataSet)
{
_Color[] colors = new _Color[_Defines.HEADSET_MAX_LEDS];
foreach (KeyValuePair<object, Color> data in dataSet)
colors[(int)data.Key] = new _Color(data.Value);
_HeadsetCustomEffect effectParams = new _HeadsetCustomEffect { Color = colors };
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(effectParams));
Marshal.StructureToPtr(effectParams, ptr, false);
return ptr;
}
#endregion
}
}

View File

@ -1,9 +1,6 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using RGB.NET.Core;
using RGB.NET.Devices.Razer.Native;
@ -51,20 +48,7 @@ namespace RGB.NET.Devices.Razer
protected override object CreateLedCustomData(LedId ledId) => (int)ledId - (int)LedId.Keyboard_Escape;
/// <inheritdoc />
protected override IntPtr CreateEffectParams(IEnumerable<Led> leds)
{
_Color[] colors = new _Color[_Defines.KEYBOARD_MAX_LEDS];
foreach (Led led in leds)
colors[(int)led.CustomData] = new _Color(led.Color.R, led.Color.G, led.Color.B);
_KeyboardCustomEffect effectParams = new _KeyboardCustomEffect { Color = colors };
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(effectParams));
Marshal.StructureToPtr(effectParams, ptr, false);
return ptr;
}
protected override RazerUpdateQueue CreateUpdateQueue(IUpdateTrigger updateTrigger) => new RazerKeyboardUpdateQueue(updateTrigger, DeviceInfo.DeviceId);
#endregion
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using RGB.NET.Core;
using RGB.NET.Devices.Razer.Native;
namespace RGB.NET.Devices.Razer
{
public class RazerKeyboardUpdateQueue : RazerUpdateQueue
{
#region Constructors
public RazerKeyboardUpdateQueue(IUpdateTrigger updateTrigger, Guid deviceId)
: base(updateTrigger, deviceId)
{ }
#endregion
#region Methods
/// <inheritdoc />
protected override IntPtr CreateEffectParams(Dictionary<object, Color> dataSet)
{
_Color[] colors = new _Color[_Defines.KEYBOARD_MAX_LEDS];
foreach (KeyValuePair<object, Color> data in dataSet)
colors[(int)data.Key] = new _Color(data.Value);
_KeyboardCustomEffect effectParams = new _KeyboardCustomEffect { Color = colors };
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(effectParams));
Marshal.StructureToPtr(effectParams, ptr, false);
return ptr;
}
#endregion
}
}

View File

@ -1,9 +1,6 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using RGB.NET.Core;
using RGB.NET.Devices.Razer.Native;
@ -48,20 +45,7 @@ namespace RGB.NET.Devices.Razer
protected override object CreateLedCustomData(LedId ledId) => (int)ledId - (int)LedId.Keypad1;
/// <inheritdoc />
protected override IntPtr CreateEffectParams(IEnumerable<Led> leds)
{
_Color[] colors = new _Color[_Defines.KEYPAD_MAX_LEDS];
foreach (Led led in leds)
colors[(int)led.CustomData] = new _Color(led.Color.R, led.Color.G, led.Color.B);
_KeypadCustomEffect effectParams = new _KeypadCustomEffect { Color = colors };
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(effectParams));
Marshal.StructureToPtr(effectParams, ptr, false);
return ptr;
}
protected override RazerUpdateQueue CreateUpdateQueue(IUpdateTrigger updateTrigger) => new RazerKeypadUpdateQueue(updateTrigger, DeviceInfo.DeviceId);
#endregion
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using RGB.NET.Core;
using RGB.NET.Devices.Razer.Native;
namespace RGB.NET.Devices.Razer
{
public class RazerKeypadUpdateQueue : RazerUpdateQueue
{
#region Constructors
public RazerKeypadUpdateQueue(IUpdateTrigger updateTrigger, Guid deviceId)
: base(updateTrigger, deviceId)
{ }
#endregion
#region Methods
/// <inheritdoc />
protected override IntPtr CreateEffectParams(Dictionary<object, Color> dataSet)
{
_Color[] colors = new _Color[_Defines.KEYPAD_MAX_LEDS];
foreach (KeyValuePair<object, Color> data in dataSet)
colors[(int)data.Key] = new _Color(data.Value);
_KeypadCustomEffect effectParams = new _KeypadCustomEffect { Color = colors };
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(effectParams));
Marshal.StructureToPtr(effectParams, ptr, false);
return ptr;
}
#endregion
}
}

View File

@ -1,9 +1,6 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using RGB.NET.Core;
using RGB.NET.Devices.Razer.Native;
@ -48,20 +45,7 @@ namespace RGB.NET.Devices.Razer
protected override object CreateLedCustomData(LedId ledId) => (int)ledId - (int)LedId.Mouse1;
/// <inheritdoc />
protected override IntPtr CreateEffectParams(IEnumerable<Led> leds)
{
_Color[] colors = new _Color[_Defines.MOUSE_MAX_LEDS];
foreach (Led led in leds)
colors[(int)led.CustomData] = new _Color(led.Color.R, led.Color.G, led.Color.B);
_MouseCustomEffect effectParams = new _MouseCustomEffect { Color = colors };
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(effectParams));
Marshal.StructureToPtr(effectParams, ptr, false);
return ptr;
}
protected override RazerUpdateQueue CreateUpdateQueue(IUpdateTrigger updateTrigger) => new RazerMouseUpdateQueue(updateTrigger, DeviceInfo.DeviceId);
#endregion
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using RGB.NET.Core;
using RGB.NET.Devices.Razer.Native;
namespace RGB.NET.Devices.Razer
{
public class RazerMouseUpdateQueue : RazerUpdateQueue
{
#region Constructors
public RazerMouseUpdateQueue(IUpdateTrigger updateTrigger, Guid deviceId)
: base(updateTrigger, deviceId)
{ }
#endregion
#region Methods
/// <inheritdoc />
protected override IntPtr CreateEffectParams(Dictionary<object, Color> dataSet)
{
_Color[] colors = new _Color[_Defines.MOUSE_MAX_LEDS];
foreach (KeyValuePair<object, Color> data in dataSet)
colors[(int)data.Key] = new _Color(data.Value);
_MouseCustomEffect effectParams = new _MouseCustomEffect { Color = colors };
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(effectParams));
Marshal.StructureToPtr(effectParams, ptr, false);
return ptr;
}
#endregion
}
}

View File

@ -1,9 +1,6 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using RGB.NET.Core;
using RGB.NET.Devices.Razer.Native;
@ -45,20 +42,7 @@ namespace RGB.NET.Devices.Razer
protected override object CreateLedCustomData(LedId ledId) => (int)ledId - (int)LedId.Mousepad1;
/// <inheritdoc />
protected override IntPtr CreateEffectParams(IEnumerable<Led> leds)
{
_Color[] colors = new _Color[_Defines.MOUSEPAD_MAX_LEDS];
foreach (Led led in leds)
colors[(int)led.CustomData] = new _Color(led.Color.R, led.Color.G, led.Color.B);
_MousepadCustomEffect effectParams = new _MousepadCustomEffect { Color = colors };
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(effectParams));
Marshal.StructureToPtr(effectParams, ptr, false);
return ptr;
}
protected override RazerUpdateQueue CreateUpdateQueue(IUpdateTrigger updateTrigger) => new RazerMousepadUpdateQueue(updateTrigger, DeviceInfo.DeviceId);
#endregion
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using RGB.NET.Core;
using RGB.NET.Devices.Razer.Native;
namespace RGB.NET.Devices.Razer
{
public class RazerMousepadUpdateQueue : RazerUpdateQueue
{
#region Constructors
public RazerMousepadUpdateQueue(IUpdateTrigger updateTrigger, Guid deviceId)
: base(updateTrigger, deviceId)
{ }
#endregion
#region Methods
/// <inheritdoc />
protected override IntPtr CreateEffectParams(Dictionary<object, Color> dataSet)
{
_Color[] colors = new _Color[_Defines.MOUSEPAD_MAX_LEDS];
foreach (KeyValuePair<object, Color> data in dataSet)
colors[(int)data.Key] = new _Color(data.Value);
_MousepadCustomEffect effectParams = new _MousepadCustomEffect { Color = colors };
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(effectParams));
Marshal.StructureToPtr(effectParams, ptr, false);
return ptr;
}
#endregion
}
}

View File

@ -4,6 +4,7 @@
// ReSharper disable MemberCanBePrivate.Global
using System.Runtime.InteropServices;
using RGB.NET.Core;
namespace RGB.NET.Devices.Razer.Native
{
@ -19,6 +20,9 @@ namespace RGB.NET.Devices.Razer.Native
#region Constructors
public _Color(Color color)
: this(color.R, color.G, color.B) { }
public _Color(byte red, byte green, byte blue)
: this()
{

View File

@ -45,6 +45,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ChromaLink\RazerChromaLinkUpdateQueue.cs" />
<Compile Include="Enum\RazerLogicalKeyboardLayout.cs" />
<Compile Include="Enum\RazerPhysicalKeyboardLayout.cs" />
<Compile Include="Enum\DeviceType.cs" />
@ -55,12 +56,18 @@
<Compile Include="Generic\IRazerRGBDevice.cs" />
<Compile Include="ChromaLink\RazerChromaLinkRGBDevice.cs" />
<Compile Include="ChromaLink\RazerChromaLinkRGBDeviceInfo.cs" />
<Compile Include="Generic\RazerUpdateQueue.cs" />
<Compile Include="Headset\RazerHeadsetUpdateQueue.cs" />
<Compile Include="Keyboard\RazerKeyboardUpdateQueue.cs" />
<Compile Include="Keypad\RazerKeypadUpdateQueue.cs" />
<Compile Include="Mousepad\RazerMousepadUpdateQueue.cs" />
<Compile Include="Mousepad\RazerMousepadRGBDevice.cs" />
<Compile Include="Mousepad\RazerMousepadRGBDeviceInfo.cs" />
<Compile Include="Keypad\RazerKeypadRGBDevice.cs" />
<Compile Include="Keypad\RazerKeypadRGBDeviceInfo.cs" />
<Compile Include="Headset\RazerHeadsetRGBDevice.cs" />
<Compile Include="Headset\RazerHeadsetRGBDeviceInfo.cs" />
<Compile Include="Mouse\RazerMouseUpdateQueue.cs" />
<Compile Include="Mouse\RazerMouseRGBDevice.cs" />
<Compile Include="Mouse\RazerMouseRGBDeviceInfo.cs" />
<Compile Include="Keyboard\RazerKeyboardRGBDevice.cs" />

View File

@ -68,6 +68,8 @@ namespace RGB.NET.Devices.Razer
/// </summary>
public bool LoadEmulatorDevices { get; set; } = false;
public UpdateTrigger UpdateTrigger { get; private set; }
#endregion
#region Constructors
@ -80,6 +82,8 @@ namespace RGB.NET.Devices.Razer
{
if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(RazerDeviceProvider)}");
_instance = this;
UpdateTrigger = new UpdateTrigger();
}
#endregion
@ -96,10 +100,12 @@ namespace RGB.NET.Devices.Razer
try
{
UpdateTrigger?.Stop();
_RazerSDK.Reload();
RazerError error;
if (((error = _RazerSDK.Init()) != RazerError.Success)
if (((error = _RazerSDK.Init()) != RazerError.Success)
&& Enum.IsDefined(typeof(RazerError), error)) //HACK DarthAffe 08.02.2018: The x86-SDK seems to have a problem here ...
ThrowRazerError(error);
@ -113,7 +119,7 @@ namespace RGB.NET.Devices.Razer
&& (!LoadEmulatorDevices || (Razer.Devices.KEYBOARDS.FirstOrDefault().guid != guid))) continue;
RazerKeyboardRGBDevice device = new RazerKeyboardRGBDevice(new RazerKeyboardRGBDeviceInfo(guid, model, GetCulture()));
device.Initialize();
device.Initialize(UpdateTrigger);
devices.Add(device);
}
catch { if (throwExceptions) throw; }
@ -126,7 +132,7 @@ namespace RGB.NET.Devices.Razer
&& (!LoadEmulatorDevices || (Razer.Devices.MICE.FirstOrDefault().guid != guid))) continue;
RazerMouseRGBDevice device = new RazerMouseRGBDevice(new RazerMouseRGBDeviceInfo(guid, model));
device.Initialize();
device.Initialize(UpdateTrigger);
devices.Add(device);
}
catch { if (throwExceptions) throw; }
@ -139,7 +145,7 @@ namespace RGB.NET.Devices.Razer
&& (!LoadEmulatorDevices || (Razer.Devices.HEADSETS.FirstOrDefault().guid != guid))) continue;
RazerHeadsetRGBDevice device = new RazerHeadsetRGBDevice(new RazerHeadsetRGBDeviceInfo(guid, model));
device.Initialize();
device.Initialize(UpdateTrigger);
devices.Add(device);
}
catch { if (throwExceptions) throw; }
@ -152,7 +158,7 @@ namespace RGB.NET.Devices.Razer
&& (!LoadEmulatorDevices || (Razer.Devices.MOUSEMATS.FirstOrDefault().guid != guid))) continue;
RazerMousepadRGBDevice device = new RazerMousepadRGBDevice(new RazerMousepadRGBDeviceInfo(guid, model));
device.Initialize();
device.Initialize(UpdateTrigger);
devices.Add(device);
}
catch { if (throwExceptions) throw; }
@ -165,7 +171,7 @@ namespace RGB.NET.Devices.Razer
&& (!LoadEmulatorDevices || (Razer.Devices.KEYPADS.FirstOrDefault().guid != guid))) continue;
RazerKeypadRGBDevice device = new RazerKeypadRGBDevice(new RazerKeypadRGBDeviceInfo(guid, model));
device.Initialize();
device.Initialize(UpdateTrigger);
devices.Add(device);
}
catch { if (throwExceptions) throw; }
@ -178,11 +184,12 @@ namespace RGB.NET.Devices.Razer
&& (!LoadEmulatorDevices || (Razer.Devices.CHROMALINKS.FirstOrDefault().guid != guid))) continue;
RazerChromaLinkRGBDevice device = new RazerChromaLinkRGBDevice(new RazerChromaLinkRGBDeviceInfo(guid, model));
device.Initialize();
device.Initialize(UpdateTrigger);
devices.Add(device);
}
catch { if (throwExceptions) throw; }
UpdateTrigger?.Start();
Devices = new ReadOnlyCollection<IRGBDevice>(devices);
IsInitialized = true;
}