Skip to content

Commit

Permalink
✨ Start adding the embededd monitor service.
Browse files Browse the repository at this point in the history
  • Loading branch information
hexawyz committed Jan 29, 2025
1 parent ca4d6b1 commit c5d8aba
Show file tree
Hide file tree
Showing 11 changed files with 1,154 additions and 458 deletions.
6 changes: 2 additions & 4 deletions src/Exo/Core/Exo.Core/Features/EmbeddedMonitorFeatures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@

namespace Exo.Features.EmbeddedMonitors;

public interface IEmbeddedMonitorFeature : IEmbeddedMonitor, IEmbeddedMonitorDeviceFeature
{
}
/// <summary>To be used for a device exposing multiple embedded monitors.</summary>
/// <remarks>
/// <para>This feature is necessary to support devices such as the various Elgato StreamDecks.</para>
Expand Down Expand Up @@ -163,7 +160,8 @@ public readonly struct EmbeddedMonitorGraphicsDescription

/// <summary>Gets a definition to represent a graphics off mode.</summary>
/// <remarks>Embedded monitors supporting a built-in "graphics off" mode can add this to the list of modes.</remarks>
public static EmbeddedMonitorGraphicsDescription Off => new(OffId);
// NB: References the shared "off" string, to avoid useless duplication. may be changed later.
public static EmbeddedMonitorGraphicsDescription Off => new(OffId, new Guid(0xA9F9A2E6, 0x2091, 0x4BD9, 0xB1, 0x35, 0xA4, 0xA5, 0xD6, 0xD4, 0x00, 0x9E));

/// <summary>Gets the ID used to describe these graphics.</summary>
/// <remarks>
Expand Down
38 changes: 38 additions & 0 deletions src/Exo/Core/Exo.Core/Images/PixelFormat.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Exo.Images;

[JsonConverter(typeof(PixelFormatJsonConverter))]
public readonly struct PixelFormat : IEquatable<PixelFormat>
{
// As enumerating all possible color formats is a lost fight, we will instead use a compact system to describe pixel formats.
Expand Down Expand Up @@ -82,3 +85,38 @@ namespace Exo.Images;
public static bool operator ==(PixelFormat left, PixelFormat right) => left.Equals(right);
public static bool operator !=(PixelFormat left, PixelFormat right) => !(left == right);
}

// TODO: Build a generator for this?
public sealed class PixelFormatJsonConverter : JsonConverter<PixelFormat>
{
public override PixelFormat Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> reader.GetString() switch
{
nameof(PixelFormat.R8G8B8) => PixelFormat.R8G8B8,
nameof(PixelFormat.B8G8R8) => PixelFormat.B8G8R8,
nameof(PixelFormat.X8R8G8B8) => PixelFormat.X8R8G8B8,
nameof(PixelFormat.X8B8G8R8) => PixelFormat.X8B8G8R8,
nameof(PixelFormat.R8G8B8X8) => PixelFormat.R8G8B8X8,
nameof(PixelFormat.B8G8R8X8) => PixelFormat.B8G8R8X8,
nameof(PixelFormat.A8R8G8B8) => PixelFormat.A8R8G8B8,
nameof(PixelFormat.A8B8G8R8) => PixelFormat.A8B8G8R8,
nameof(PixelFormat.R8G8B8A8) => PixelFormat.R8G8B8A8,
nameof(PixelFormat.B8G8R8A8) => PixelFormat.B8G8R8A8,
_ => throw new InvalidOperationException(),
};

public override void Write(Utf8JsonWriter writer, PixelFormat value, JsonSerializerOptions options)
{
if (value == PixelFormat.R8G8B8) writer.WriteStringValue(nameof(PixelFormat.R8G8B8));
else if (value == PixelFormat.B8G8R8) writer.WriteStringValue(nameof(PixelFormat.B8G8R8));
else if (value == PixelFormat.X8R8G8B8) writer.WriteStringValue(nameof(PixelFormat.X8R8G8B8));
else if (value == PixelFormat.X8B8G8R8) writer.WriteStringValue(nameof(PixelFormat.X8B8G8R8));
else if (value == PixelFormat.R8G8B8X8) writer.WriteStringValue(nameof(PixelFormat.R8G8B8X8));
else if (value == PixelFormat.B8G8R8X8) writer.WriteStringValue(nameof(PixelFormat.B8G8R8X8));
else if (value == PixelFormat.A8R8G8B8) writer.WriteStringValue(nameof(PixelFormat.A8R8G8B8));
else if (value == PixelFormat.A8B8G8R8) writer.WriteStringValue(nameof(PixelFormat.A8B8G8R8));
else if (value == PixelFormat.R8G8B8A8) writer.WriteStringValue(nameof(PixelFormat.R8G8B8A8));
else if (value == PixelFormat.B8G8R8A8) writer.WriteStringValue(nameof(PixelFormat.B8G8R8A8));
else throw new InvalidOperationException();
}
}
18 changes: 10 additions & 8 deletions src/Exo/Devices/Exo.Devices.Nzxt.Kraken/KrakenDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class KrakenDriver :
ISensorsFeature,
ISensorsGroupedQueryFeature,
ICoolingControllerFeature,
IEmbeddedMonitorFeature,
IEmbeddedMonitorControllerFeature,
IEmbeddedMonitorBuiltInGraphics,
IMonitorBrightnessFeature
{
Expand All @@ -42,10 +42,10 @@ public class KrakenDriver :
private static readonly Guid FanCoolerId = new(0x5A0FE6F5, 0xB7D1, 0x46E4, 0xA5, 0x12, 0x82, 0x72, 0x6E, 0x95, 0x35, 0xC4);
private static readonly Guid PumpCoolerId = new(0x2A57C838, 0xCD58, 0x4D6C, 0xAF, 0x9E, 0xF5, 0xBD, 0xDD, 0x6F, 0xB9, 0x92);

private static readonly Guid MonitorId = new (0xAB1C8580, 0x9FC4, 0x4BB6, 0xB9, 0xC7, 0x02, 0xF1, 0x81, 0x81, 0x68, 0xB6);
private static readonly Guid MonitorId = new(0xAB1C8580, 0x9FC4, 0x4BB6, 0xB9, 0xC7, 0x02, 0xF1, 0x81, 0x81, 0x68, 0xB6);

private static readonly Guid BootAnimationGraphicsId = new (0xE4A8CC79, 0x1062, 0x4E85, 0x97, 0x72, 0xB4, 0xBF, 0xFF, 0x66, 0x74, 0xB3);
private static readonly Guid LiquidTemperatureGraphicsId = new (0x9AA7AF98, 0x19D2, 0x4F98, 0x96, 0x90, 0xAD, 0xF9, 0xA5, 0x90, 0x8B, 0xC3);
private static readonly Guid BootAnimationGraphicsId = new(0xE4A8CC79, 0x1062, 0x4E85, 0x97, 0x72, 0xB4, 0xBF, 0xFF, 0x66, 0x74, 0xB3);
private static readonly Guid LiquidTemperatureGraphicsId = new(0x9AA7AF98, 0x19D2, 0x4F98, 0x96, 0x90, 0xAD, 0xF9, 0xA5, 0x90, 0x8B, 0xC3);

// Both cooling curves taken out of NZXT CAM when creating a new cooling profile. No idea if they are the default HW curve.
// Points from CAM are the first column, others are interpolated.
Expand Down Expand Up @@ -79,7 +79,7 @@ public class KrakenDriver :
[DeviceInterfaceClass(DeviceInterfaceClass.Hid)]
[ProductId(VendorIdSource.Usb, NzxtVendorId, 0x3008)] // Kraken Z
[ProductId(VendorIdSource.Usb, NzxtVendorId, 0x300C)] // Kraken Elite (2023)
//[ProductId(VendorIdSource.Usb, NzxtVendorId, 0x300E)] // Kraken (2023)
//[ProductId(VendorIdSource.Usb, NzxtVendorId, 0x300E)] // Kraken (2023)
[ProductId(VendorIdSource.Usb, NzxtVendorId, 0x3012)] // Kraken Elite RGB (2024)
public static async ValueTask<DriverCreationResult<SystemDevicePath>?> CreateAsync
(
Expand Down Expand Up @@ -295,7 +295,7 @@ static uint GetColor(byte r, byte g, byte b)
Guid IEmbeddedMonitor.MonitorId => MonitorId;
EmbeddedMonitorInformation IEmbeddedMonitor.MonitorInformation => new(MonitorShape.Circle, new(_imageWidth, _imageHeight), PixelFormat.R8G8B8X8, ImageFormats.Raw | ImageFormats.Gif, true);

IDeviceFeatureSet <IGenericDeviceFeature> IDeviceDriver<IGenericDeviceFeature>.Features => _genericFeatures;
IDeviceFeatureSet<IGenericDeviceFeature> IDeviceDriver<IGenericDeviceFeature>.Features => _genericFeatures;
IDeviceFeatureSet<ISensorDeviceFeature> IDeviceDriver<ISensorDeviceFeature>.Features => _sensorFeatures;
IDeviceFeatureSet<ICoolingDeviceFeature> IDeviceDriver<ICoolingDeviceFeature>.Features => _coolingFeatures;
IDeviceFeatureSet<IMonitorDeviceFeature> IDeviceDriver<IMonitorDeviceFeature>.Features => _monitorFeatures;
Expand Down Expand Up @@ -332,7 +332,7 @@ DeviceConfigurationKey configurationKey
[
EmbeddedMonitorGraphicsDescription.Off,
new(BootAnimationGraphicsId),
new(LiquidTemperatureGraphicsId),
new(LiquidTemperatureGraphicsId, new Guid(0x5553C264, 0x35BF, 0x44BA, 0xBD, 0x23, 0x5A, 0x1B, 0xF6, 0x11, 0xF5, 0xE1)),
EmbeddedMonitorGraphicsDescription.CustomGraphics,
];
_genericFeatures = ConfigurationKey.UniqueId is not null ?
Expand All @@ -341,7 +341,7 @@ DeviceConfigurationKey configurationKey
_sensorFeatures = FeatureSet.Create<ISensorDeviceFeature, KrakenDriver, ISensorsFeature, ISensorsGroupedQueryFeature>(this);
_coolingFeatures = FeatureSet.Create<ICoolingDeviceFeature, KrakenDriver, ICoolingControllerFeature>(this);
_monitorFeatures = FeatureSet.Create<IMonitorDeviceFeature, KrakenDriver, IMonitorBrightnessFeature>(this);
_embeddedMonitorFeatures = FeatureSet.Create<IEmbeddedMonitorDeviceFeature, KrakenDriver, IEmbeddedMonitorFeature>(this);
_embeddedMonitorFeatures = FeatureSet.Create<IEmbeddedMonitorDeviceFeature, KrakenDriver, IEmbeddedMonitorControllerFeature>(this);
}

public override async ValueTask DisposeAsync()
Expand All @@ -362,6 +362,8 @@ async ValueTask IContinuousVcpFeature.SetValueAsync(ushort value, CancellationTo
await _hidTransport.SetBrightnessAsync((byte)value, cancellationToken).ConfigureAwait(false);
}

ImmutableArray<IEmbeddedMonitor> IEmbeddedMonitorControllerFeature.EmbeddedMonitors => [this];

ImmutableArray<EmbeddedMonitorGraphicsDescription> IEmbeddedMonitorBuiltInGraphics.SupportedGraphics => _embeddedMonitorGraphicsDescriptions;

Guid IEmbeddedMonitorBuiltInGraphics.CurrentGraphicsId
Expand Down
7 changes: 7 additions & 0 deletions src/Exo/Devices/Exo.Devices.Nzxt.Kraken/Strings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
// Built-in Graphics Names
"e4a8cc79-1062-4e85-9772-b4bfff6674b3": {
"en": "Default animation",
"fr": "Animation par défaut"
}
}
12 changes: 12 additions & 0 deletions src/Exo/Service/Exo.Service.Core/EmbeddedMonitorCapabilities.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Exo.Service;

[Flags]
public enum EmbeddedMonitorCapabilities : uint
{
None = 0b00000000,
StaticImages = 0b00000001,
AnimatedImages = 0b00000010,
PartialUpdates = 0b00000100,
BuiltInGraphics = 0b00001000,
ScreensaverImage = 0b00010000,
}
Loading

0 comments on commit c5d8aba

Please sign in to comment.