Added animatrix control thanks to https://github.com/vddCore/Starlight

This commit is contained in:
seerge
2023-03-04 00:11:59 +01:00
parent e9fa181d4e
commit 43d2ed656a
14 changed files with 742 additions and 73 deletions

33
Communication/Device.cs Normal file
View File

@@ -0,0 +1,33 @@
// Source thanks to https://github.com/vddCore/Starlight :)
using Starlight.Communication.Platform;
namespace Starlight.Communication
{
public abstract class Device : IDisposable
{
private static UsbProvider _usbProvider;
protected Device(ushort vendorId, ushort productId, int maxFeatureReportLength)
{
_usbProvider = new WindowsUsbProvider(vendorId, productId, maxFeatureReportLength);
}
protected T Packet<T>(params byte[] command) where T : Packet
{
return (T)Activator.CreateInstance(typeof(T), command)!;
}
public void Set(Packet packet)
=> _usbProvider?.Set(packet.Data);
public byte[] Get(Packet packet)
=> _usbProvider?.Get(packet.Data);
public void Dispose()
{
_usbProvider?.Dispose();
}
}
}

61
Communication/Packet.cs Normal file
View File

@@ -0,0 +1,61 @@
// Source thanks to https://github.com/vddCore/Starlight :)
using System.ComponentModel;
using HidSharp;
namespace Starlight.Communication
{
public abstract class Packet
{
private int _currentDataIndex = 1;
public byte[] Data { get; }
internal Packet(byte reportId, int packetLength, params byte[] data)
{
if (packetLength < 1)
{
throw new ArgumentOutOfRangeException(
nameof(packetLength),
"Packet length must be at least 1."
);
}
Data = new byte[packetLength];
Data[0] = reportId;
if (data.Length > 0)
{
if (_currentDataIndex >= Data.Length)
{
throw new ArgumentOutOfRangeException(
nameof(data),
"Your packet length does not allow for initial data to be appended."
);
}
AppendData(data);
}
}
public Packet AppendData(params byte[] data)
=> AppendData(out _, data);
public Packet AppendData(out int bytesWritten, params byte[] data)
{
bytesWritten = 0;
for (var i = 0;
i < data.Length && _currentDataIndex < Data.Length - 1;
i++, bytesWritten++, _currentDataIndex++)
{
if (_currentDataIndex > Data.Length - 1)
break;
Data[_currentDataIndex] = data[i];
}
return this;
}
}
}

View File

@@ -0,0 +1,19 @@
namespace Starlight.Communication.Platform
{
internal abstract class UsbProvider : IDisposable
{
protected ushort VendorID { get; }
protected ushort ProductID { get; }
protected UsbProvider(ushort vendorId, ushort productId)
{
VendorID = vendorId;
ProductID = productId;
}
public abstract void Set(byte[] data);
public abstract byte[] Get(byte[] data);
public abstract void Dispose();
}
}

View File

@@ -0,0 +1,79 @@
using System.ComponentModel;
using HidSharp;
namespace Starlight.Communication.Platform
{
internal class WindowsUsbProvider : UsbProvider
{
protected HidDevice HidDevice { get; }
protected HidStream HidStream { get; }
public WindowsUsbProvider(ushort vendorId, ushort productId, int maxFeatureReportLength)
: base(vendorId, productId)
{
try
{
HidDevice = DeviceList.Local
.GetHidDevices(vendorId, productId)
.First(x => x.GetMaxFeatureReportLength() == maxFeatureReportLength);
}
catch
{
throw new IOException("AniMe Matrix control device was not found on your machine.");
}
var config = new OpenConfiguration();
config.SetOption(OpenOption.Interruptible, true);
config.SetOption(OpenOption.Exclusive, false);
config.SetOption(OpenOption.Priority, 10);
HidStream = HidDevice.Open(config);
}
public override void Set(byte[] data)
{
WrapException(() =>
{
HidStream.SetFeature(data);
HidStream.Flush();
});
}
public override byte[] Get(byte[] data)
{
var outData = new byte[data.Length];
Array.Copy(data, outData, data.Length);
WrapException(() =>
{
HidStream.GetFeature(outData);
HidStream.Flush();
});
return data;
}
public override void Dispose()
{
HidStream.Dispose();
}
private void WrapException(Action action)
{
try
{
action();
}
catch (IOException e)
{
if (e.InnerException is Win32Exception w32e)
{
if (w32e.NativeErrorCode != 0)
{
throw;
}
}
}
}
}
}