Skip to content

Commit

Permalink
enhancement: Device and Control attributes now support raw IDs (#5)
Browse files Browse the repository at this point in the history
Added test for Control attribute to confirm acceptance of Enums and integers.
Updated HID tables.
Addressed some null reference compile warnings.

Note, this is technically a breaking change as non enum/integer values passed to the Control/Device attributes may throw exceptions.
  • Loading branch information
thargy committed Aug 9, 2022
1 parent c2c8f20 commit c256897
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 23 deletions.
2 changes: 1 addition & 1 deletion HIDDevices.Sample/Samples/DependencyInjectionSample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public override async Task ExecuteAsync(CancellationToken token = default)
await using var serviceProvider = serviceCollection.BuildServiceProvider();

// Get the logger
var logger = serviceProvider.GetService<ILogger<DependencyInjectionSample>>();
var logger = serviceProvider.GetService<ILogger<DependencyInjectionSample>>()!;

// Grab the controllers service
var controllers = serviceProvider.GetService<Devices>()!;
Expand Down
4 changes: 2 additions & 2 deletions HIDDevices.Sample/SimpleConsoleLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ public SimpleConsoleLogger(LogLevel logLevel, string? name = null)
public LogLevel LogLevel { get; set; }

/// <inheritdoc />
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception,
Func<TState, Exception, string> formatter)
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception,
Func<TState, Exception?, string> formatter)
{
if (!IsEnabled(logLevel))
{
Expand Down
21 changes: 21 additions & 0 deletions HIDDevices.Test/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using System.Threading;
using System.Threading.Tasks;
using DevDecoder.HIDDevices;
using DevDecoder.HIDDevices.Pages;
using DevDecoder.HIDDevices.Usages;
using Microsoft.Extensions.Logging;
using Xunit;
using Xunit.Abstractions;
Expand Down Expand Up @@ -69,5 +71,24 @@ public void TestUndefinedUsage()
var usage = Usage.Get(0xffff);
Assert.Equal("Reserved (0x00) - Undefined (0xFFFF)", usage.ToString());
}

[Fact]
public void TestControlAttribute()
{
// Confirm that the enum and raw value are identical.
var attr1 = new ControlAttribute(ButtonPage.Button15);
var attr2 = new ControlAttribute(0x00090010);
Assert.Equal(1, attr1.Usages.Count);
Assert.Equal(1, attr2.Usages.Count);
Assert.Equal(attr1.Usages[0], attr2.Usages[0]);

// Confirm that a user defined ID is accepted.
var attr3 = new ControlAttribute(0x00090011);
var usage = attr3.Usages[0];
Assert.Equal(UsagePage.Button, usage.Page);
Assert.Equal(17, usage.Id);

Logger.LogInformation($"User defined usage: {usage}");
}
}
}
9 changes: 8 additions & 1 deletion HIDDevices/Attributes/ControlAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ namespace DevDecoder.HIDDevices
/// Attribute that should be added to properties on a <seealso cref="Controller" /> to indicate
/// that they should be bound to a <seealso cref="Control" />.
/// </summary>
/// <remarks>
/// Note that multiple usages can be supplied, any value that can be converted to a <see langref="uint"/>
/// is supported, which includes the Usage enums. Further, the value must be the full ID, and encode
/// the page and ID of the usage.
/// </remarks>
/// <seealso cref="Controller" />
/// <seealso cref="Control" />
/// <seealso cref="Attribute" />
Expand All @@ -23,7 +28,9 @@ public sealed class ControlAttribute : Attribute
/// Initializes a new instance of the <see cref="ControlAttribute" /> class.
/// </summary>
/// <param name="usages">The usages.</param>
public ControlAttribute(params object[] usages) => Usages = usages.OfType<Enum>().Select(Usage.Get).ToArray();
public ControlAttribute(params object[] usages) => Usages = usages
.Select(o => Usage.Get(Convert.ToUInt32(o)))
.ToArray();

/// <summary>
/// Gets or sets the weight, a higher weight will increase the scoring of controls matching this attribute,
Expand Down
9 changes: 8 additions & 1 deletion HIDDevices/Attributes/DeviceAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ namespace DevDecoder.HIDDevices
/// <seealso cref="Device">Devices</seealso>
/// that can be matched by the controller.
/// </summary>
/// <remarks>
/// Note that multiple usages can be supplied, any value that can be converted to a <see langref="uint"/>
/// is supported, which includes the Usage enums. Further, the value must be the full ID, and encode
/// the page and ID of the usage.
/// </remarks>
/// <seealso cref="Controller" />
/// <seealso cref="Device" />
/// <seealso cref="Attribute" />
Expand All @@ -27,7 +32,9 @@ public sealed class DeviceAttribute : Attribute
/// Initializes a new instance of the <see cref="DeviceAttribute" /> class.
/// </summary>
/// <param name="usages">The usages, all of which must match.</param>
public DeviceAttribute(params object[] usages) => Usages = usages.OfType<Enum>().Select(Usage.Get).ToArray();
public DeviceAttribute(params object[] usages) => Usages = Usages = usages
.Select(o => Usage.Get(Convert.ToUInt32(o)))
.ToArray();

/// <summary>
/// Gets a list of valid usages, of which the device must match all.
Expand Down
154 changes: 138 additions & 16 deletions HIDDevices/Usages/GenerateUsagePages.generated.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Licensed under the Apache License, Version 2.0 (the "License").
// See the LICENSE file in the project root for more information.
//
// Auto Generated 2651 usages in 35 pages on 20/01/2022 13:01:03.
// Auto Generated 2663 usages in 36 pages on 09/08/2022 14:11:21.

#pragma warning disable CS0108 // Member hides inherited member; missing new keyword

Expand Down Expand Up @@ -7690,7 +7690,13 @@ public enum DigitizerPage : uint
/// Transducer Switches Usage.
/// </summary>
[Description("Transducer Switches")]
TransducerSwitches = 0x000d00a5
TransducerSwitches = 0x000d00a5,

/// <summary>
/// Transducer Index Selector Usage.
/// </summary>
[Description("Transducer Index Selector")]
TransducerIndexSelector = 0x000d00a6
}

/// <summary>
Expand Down Expand Up @@ -7881,10 +7887,10 @@ public enum HapticsPage : uint
}

/// <summary>
/// Physical Interface Device Usage Page.
/// Physical Interput Device Usage Page.
/// </summary>
[Description("Physical Interface Device Usage Page")]
public enum PhysicalInterfaceDevicePage : uint
[Description("Physical Interput Device Usage Page")]
public enum PhysicalInterputDevicePage : uint
{
/// <summary>
/// Undefined Usage.
Expand All @@ -7893,10 +7899,10 @@ public enum PhysicalInterfaceDevicePage : uint
Undefined = 0x000f0000,

/// <summary>
/// Physical Interface Device Usage.
/// Physical Input Device Usage.
/// </summary>
[Description("Physical Interface Device")]
PhysicalInterfaceDevice = 0x000f0001,
[Description("Physical Input Device")]
PhysicalInputDevice = 0x000f0001,

/// <summary>
/// Normal Usage.
Expand Down Expand Up @@ -8536,6 +8542,79 @@ public enum UnicodePage : uint
Undefined = 0x00100000
}

/// <summary>
/// SoC Usage Page.
/// </summary>
[Description("SoC Usage Page")]
public enum SoCPage : uint
{
/// <summary>
/// Undefined Usage.
/// </summary>
[Description("Undefined")]
Undefined = 0x00110000,

/// <summary>
/// SoC Control Usage.
/// </summary>
[Description("SoC Control")]
SoCControl = 0x00110001,

/// <summary>
/// Firmware Transfer Usage.
/// </summary>
[Description("Firmware Transfer")]
FirmwareTransfer = 0x00110002,

/// <summary>
/// Firmware File Id Usage.
/// </summary>
[Description("Firmware File Id")]
FirmwareFileId = 0x00110003,

/// <summary>
/// File Offset In Bytes Usage.
/// </summary>
[Description("File Offset In Bytes")]
FileOffsetInBytes = 0x00110004,

/// <summary>
/// File Transfer Size Max In Bytes Usage.
/// </summary>
[Description("File Transfer Size Max In Bytes")]
FileTransferSizeMaxInBytes = 0x00110005,

/// <summary>
/// File Payload Usage.
/// </summary>
[Description("File Payload")]
FilePayload = 0x00110006,

/// <summary>
/// File Payload Size In Bytes Usage.
/// </summary>
[Description("File Payload Size In Bytes")]
FilePayloadSizeInBytes = 0x00110007,

/// <summary>
/// File Payload Contains Last Bytes Usage.
/// </summary>
[Description("File Payload Contains Last Bytes")]
FilePayloadContainsLastBytes = 0x00110008,

/// <summary>
/// File Transfer Stop Usage.
/// </summary>
[Description("File Transfer Stop")]
FileTransferStop = 0x00110009,

/// <summary>
/// File Transfer Till End Usage.
/// </summary>
[Description("File Transfer Till End")]
FileTransferTillEnd = 0x0011000a
}

/// <summary>
/// Eye and Head Trackers Usage Page.
/// </summary>
Expand Down Expand Up @@ -18621,8 +18700,9 @@ public partial class UsagePage
[0x000c] = ConsumerUsagePage.Instance,
[0x000d] = DigitizerUsagePage.Instance,
[0x000e] = HapticsUsagePage.Instance,
[0x000f] = PhysicalInterfaceDeviceUsagePage.Instance,
[0x000f] = PhysicalInterputDeviceUsagePage.Instance,
[0x0010] = UnicodeUsagePage.Instance,
[0x0011] = SoCUsagePage.Instance,
[0x0012] = EyeAndHeadTrackersUsagePage.Instance,
[0x0014] = AuxiliaryDisplayUsagePage.Instance,
[0x0020] = SensorUsagePage.Instance,
Expand Down Expand Up @@ -18715,15 +18795,20 @@ public partial class UsagePage
public static readonly HapticsUsagePage Haptics = HapticsUsagePage.Instance;

/// <summary>
/// Physical Interface Device Usage Page.
/// Physical Interput Device Usage Page.
/// </summary>
public static readonly PhysicalInterfaceDeviceUsagePage PhysicalInterfaceDevice = PhysicalInterfaceDeviceUsagePage.Instance;
public static readonly PhysicalInterputDeviceUsagePage PhysicalInterputDevice = PhysicalInterputDeviceUsagePage.Instance;

/// <summary>
/// Unicode Usage Page.
/// </summary>
public static readonly UnicodeUsagePage Unicode = UnicodeUsagePage.Instance;

/// <summary>
/// SoC Usage Page.
/// </summary>
public static readonly SoCUsagePage SoC = SoCUsagePage.Instance;

/// <summary>
/// Eye and Head Trackers Usage Page.
/// </summary>
Expand Down Expand Up @@ -20411,6 +20496,7 @@ protected override Usage CreateUsage(ushort id)
case 0x00a3: return new Usage(this, id, "Switch Disabled", UsageTypes.Sel);
case 0x00a4: return new Usage(this, id, "Switch Unimplemented", UsageTypes.Sel);
case 0x00a5: return new Usage(this, id, "Transducer Switches", UsageTypes.CL);
case 0x00a6: return new Usage(this, id, "Transducer Index Selector", UsageTypes.DV);
}

return base.CreateUsage(id);
Expand Down Expand Up @@ -20475,14 +20561,14 @@ protected override Usage CreateUsage(ushort id)
/// <summary>
/// Base class for all usage pages.
/// </summary>
public sealed class PhysicalInterfaceDeviceUsagePage : UsagePage
public sealed class PhysicalInterputDeviceUsagePage : UsagePage
{
/// <summary>
/// Singleton instance of PhysicalInterfaceDevice Usage Page.
/// Singleton instance of PhysicalInterputDevice Usage Page.
/// </summary>
public static readonly PhysicalInterfaceDeviceUsagePage Instance = new PhysicalInterfaceDeviceUsagePage();
public static readonly PhysicalInterputDeviceUsagePage Instance = new PhysicalInterputDeviceUsagePage();

private PhysicalInterfaceDeviceUsagePage() : base(0x000f, "PhysicalInterfaceDevice")
private PhysicalInterputDeviceUsagePage() : base(0x000f, "PhysicalInterputDevice")
{
}

Expand All @@ -20492,7 +20578,7 @@ protected override Usage CreateUsage(ushort id)
switch (id)
{
case 0x0000: return new Usage(this, id, "Undefined", UsageTypes.None);
case 0x0001: return new Usage(this, id, "Physical Interface Device", UsageTypes.CA);
case 0x0001: return new Usage(this, id, "Physical Input Device", UsageTypes.CA);
case 0x0020: return new Usage(this, id, "Normal", UsageTypes.DV);
case 0x0021: return new Usage(this, id, "Set Effect Report", UsageTypes.CL);
case 0x0022: return new Usage(this, id, "Effect Block Index", UsageTypes.DV);
Expand Down Expand Up @@ -20629,6 +20715,42 @@ protected override Usage CreateUsage(ushort id)
}
}

/// <summary>
/// Base class for all usage pages.
/// </summary>
public sealed class SoCUsagePage : UsagePage
{
/// <summary>
/// Singleton instance of SoC Usage Page.
/// </summary>
public static readonly SoCUsagePage Instance = new SoCUsagePage();

private SoCUsagePage() : base(0x0011, "SoC")
{
}

/// <inheritdoc />
protected override Usage CreateUsage(ushort id)
{
switch (id)
{
case 0x0000: return new Usage(this, id, "Undefined", UsageTypes.None);
case 0x0001: return new Usage(this, id, "SoC Control", UsageTypes.CA);
case 0x0002: return new Usage(this, id, "Firmware Transfer", UsageTypes.CL);
case 0x0003: return new Usage(this, id, "Firmware File Id", UsageTypes.DV);
case 0x0004: return new Usage(this, id, "File Offset In Bytes", UsageTypes.DV);
case 0x0005: return new Usage(this, id, "File Transfer Size Max In Bytes", UsageTypes.DV);
case 0x0006: return new Usage(this, id, "File Payload", UsageTypes.DV);
case 0x0007: return new Usage(this, id, "File Payload Size In Bytes", UsageTypes.DV);
case 0x0008: return new Usage(this, id, "File Payload Contains Last Bytes", UsageTypes.DF);
case 0x0009: return new Usage(this, id, "File Transfer Stop", UsageTypes.DF);
case 0x000a: return new Usage(this, id, "File Transfer Till End", UsageTypes.DF);
}

return base.CreateUsage(id);
}
}

/// <summary>
/// Base class for all usage pages.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion version.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema":
"https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
"version": "2.2",
"version": "2.3",
"publicReleaseRefSpec": [
"^refs/heads/master$",
"^refs/heads/v\\d+(?:\\.\\d+)?$"
Expand Down

0 comments on commit c256897

Please sign in to comment.