From c2568972cc1529dec6de07b335d9d30b03387941 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Tue, 9 Aug 2022 14:19:58 +0100 Subject: [PATCH] enhancement: Device and Control attributes now support raw IDs (#5) 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. --- .../Samples/DependencyInjectionSample.cs | 2 +- HIDDevices.Sample/SimpleConsoleLogger.cs | 4 +- HIDDevices.Test/Tests.cs | 21 +++ HIDDevices/Attributes/ControlAttribute.cs | 9 +- HIDDevices/Attributes/DeviceAttribute.cs | 9 +- .../Usages/GenerateUsagePages.generated.cs | 154 ++++++++++++++++-- HIDDevices/Usages/hid-usage-tables | 2 +- version.json | 2 +- 8 files changed, 180 insertions(+), 23 deletions(-) diff --git a/HIDDevices.Sample/Samples/DependencyInjectionSample.cs b/HIDDevices.Sample/Samples/DependencyInjectionSample.cs index 497c75e..d66f318 100644 --- a/HIDDevices.Sample/Samples/DependencyInjectionSample.cs +++ b/HIDDevices.Sample/Samples/DependencyInjectionSample.cs @@ -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>(); + var logger = serviceProvider.GetService>()!; // Grab the controllers service var controllers = serviceProvider.GetService()!; diff --git a/HIDDevices.Sample/SimpleConsoleLogger.cs b/HIDDevices.Sample/SimpleConsoleLogger.cs index 154f8fd..7317e1e 100644 --- a/HIDDevices.Sample/SimpleConsoleLogger.cs +++ b/HIDDevices.Sample/SimpleConsoleLogger.cs @@ -20,8 +20,8 @@ public SimpleConsoleLogger(LogLevel logLevel, string? name = null) public LogLevel LogLevel { get; set; } /// - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, - Func formatter) + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, + Func formatter) { if (!IsEnabled(logLevel)) { diff --git a/HIDDevices.Test/Tests.cs b/HIDDevices.Test/Tests.cs index 84bd0e3..2b2f77a 100644 --- a/HIDDevices.Test/Tests.cs +++ b/HIDDevices.Test/Tests.cs @@ -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; @@ -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}"); + } } } diff --git a/HIDDevices/Attributes/ControlAttribute.cs b/HIDDevices/Attributes/ControlAttribute.cs index 116a1c7..614cabc 100644 --- a/HIDDevices/Attributes/ControlAttribute.cs +++ b/HIDDevices/Attributes/ControlAttribute.cs @@ -13,6 +13,11 @@ namespace DevDecoder.HIDDevices /// Attribute that should be added to properties on a to indicate /// that they should be bound to a . /// + /// + /// Note that multiple usages can be supplied, any value that can be converted to a + /// is supported, which includes the Usage enums. Further, the value must be the full ID, and encode + /// the page and ID of the usage. + /// /// /// /// @@ -23,7 +28,9 @@ public sealed class ControlAttribute : Attribute /// Initializes a new instance of the class. /// /// The usages. - public ControlAttribute(params object[] usages) => Usages = usages.OfType().Select(Usage.Get).ToArray(); + public ControlAttribute(params object[] usages) => Usages = usages + .Select(o => Usage.Get(Convert.ToUInt32(o))) + .ToArray(); /// /// Gets or sets the weight, a higher weight will increase the scoring of controls matching this attribute, diff --git a/HIDDevices/Attributes/DeviceAttribute.cs b/HIDDevices/Attributes/DeviceAttribute.cs index 82f24a4..1f73c1b 100644 --- a/HIDDevices/Attributes/DeviceAttribute.cs +++ b/HIDDevices/Attributes/DeviceAttribute.cs @@ -15,6 +15,11 @@ namespace DevDecoder.HIDDevices /// Devices /// that can be matched by the controller. /// + /// + /// Note that multiple usages can be supplied, any value that can be converted to a + /// is supported, which includes the Usage enums. Further, the value must be the full ID, and encode + /// the page and ID of the usage. + /// /// /// /// @@ -27,7 +32,9 @@ public sealed class DeviceAttribute : Attribute /// Initializes a new instance of the class. /// /// The usages, all of which must match. - public DeviceAttribute(params object[] usages) => Usages = usages.OfType().Select(Usage.Get).ToArray(); + public DeviceAttribute(params object[] usages) => Usages = Usages = usages + .Select(o => Usage.Get(Convert.ToUInt32(o))) + .ToArray(); /// /// Gets a list of valid usages, of which the device must match all. diff --git a/HIDDevices/Usages/GenerateUsagePages.generated.cs b/HIDDevices/Usages/GenerateUsagePages.generated.cs index 5d1939b..ad8aaf0 100644 --- a/HIDDevices/Usages/GenerateUsagePages.generated.cs +++ b/HIDDevices/Usages/GenerateUsagePages.generated.cs @@ -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 @@ -7690,7 +7690,13 @@ public enum DigitizerPage : uint /// Transducer Switches Usage. /// [Description("Transducer Switches")] - TransducerSwitches = 0x000d00a5 + TransducerSwitches = 0x000d00a5, + + /// + /// Transducer Index Selector Usage. + /// + [Description("Transducer Index Selector")] + TransducerIndexSelector = 0x000d00a6 } /// @@ -7881,10 +7887,10 @@ public enum HapticsPage : uint } /// - /// Physical Interface Device Usage Page. + /// Physical Interput Device Usage Page. /// - [Description("Physical Interface Device Usage Page")] - public enum PhysicalInterfaceDevicePage : uint + [Description("Physical Interput Device Usage Page")] + public enum PhysicalInterputDevicePage : uint { /// /// Undefined Usage. @@ -7893,10 +7899,10 @@ public enum PhysicalInterfaceDevicePage : uint Undefined = 0x000f0000, /// - /// Physical Interface Device Usage. + /// Physical Input Device Usage. /// - [Description("Physical Interface Device")] - PhysicalInterfaceDevice = 0x000f0001, + [Description("Physical Input Device")] + PhysicalInputDevice = 0x000f0001, /// /// Normal Usage. @@ -8536,6 +8542,79 @@ public enum UnicodePage : uint Undefined = 0x00100000 } + /// + /// SoC Usage Page. + /// + [Description("SoC Usage Page")] + public enum SoCPage : uint + { + /// + /// Undefined Usage. + /// + [Description("Undefined")] + Undefined = 0x00110000, + + /// + /// SoC Control Usage. + /// + [Description("SoC Control")] + SoCControl = 0x00110001, + + /// + /// Firmware Transfer Usage. + /// + [Description("Firmware Transfer")] + FirmwareTransfer = 0x00110002, + + /// + /// Firmware File Id Usage. + /// + [Description("Firmware File Id")] + FirmwareFileId = 0x00110003, + + /// + /// File Offset In Bytes Usage. + /// + [Description("File Offset In Bytes")] + FileOffsetInBytes = 0x00110004, + + /// + /// File Transfer Size Max In Bytes Usage. + /// + [Description("File Transfer Size Max In Bytes")] + FileTransferSizeMaxInBytes = 0x00110005, + + /// + /// File Payload Usage. + /// + [Description("File Payload")] + FilePayload = 0x00110006, + + /// + /// File Payload Size In Bytes Usage. + /// + [Description("File Payload Size In Bytes")] + FilePayloadSizeInBytes = 0x00110007, + + /// + /// File Payload Contains Last Bytes Usage. + /// + [Description("File Payload Contains Last Bytes")] + FilePayloadContainsLastBytes = 0x00110008, + + /// + /// File Transfer Stop Usage. + /// + [Description("File Transfer Stop")] + FileTransferStop = 0x00110009, + + /// + /// File Transfer Till End Usage. + /// + [Description("File Transfer Till End")] + FileTransferTillEnd = 0x0011000a + } + /// /// Eye and Head Trackers Usage Page. /// @@ -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, @@ -18715,15 +18795,20 @@ public partial class UsagePage public static readonly HapticsUsagePage Haptics = HapticsUsagePage.Instance; /// - /// Physical Interface Device Usage Page. + /// Physical Interput Device Usage Page. /// - public static readonly PhysicalInterfaceDeviceUsagePage PhysicalInterfaceDevice = PhysicalInterfaceDeviceUsagePage.Instance; + public static readonly PhysicalInterputDeviceUsagePage PhysicalInterputDevice = PhysicalInterputDeviceUsagePage.Instance; /// /// Unicode Usage Page. /// public static readonly UnicodeUsagePage Unicode = UnicodeUsagePage.Instance; + /// + /// SoC Usage Page. + /// + public static readonly SoCUsagePage SoC = SoCUsagePage.Instance; + /// /// Eye and Head Trackers Usage Page. /// @@ -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); @@ -20475,14 +20561,14 @@ protected override Usage CreateUsage(ushort id) /// /// Base class for all usage pages. /// - public sealed class PhysicalInterfaceDeviceUsagePage : UsagePage + public sealed class PhysicalInterputDeviceUsagePage : UsagePage { /// - /// Singleton instance of PhysicalInterfaceDevice Usage Page. + /// Singleton instance of PhysicalInterputDevice Usage Page. /// - public static readonly PhysicalInterfaceDeviceUsagePage Instance = new PhysicalInterfaceDeviceUsagePage(); + public static readonly PhysicalInterputDeviceUsagePage Instance = new PhysicalInterputDeviceUsagePage(); - private PhysicalInterfaceDeviceUsagePage() : base(0x000f, "PhysicalInterfaceDevice") + private PhysicalInterputDeviceUsagePage() : base(0x000f, "PhysicalInterputDevice") { } @@ -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); @@ -20629,6 +20715,42 @@ protected override Usage CreateUsage(ushort id) } } + /// + /// Base class for all usage pages. + /// + public sealed class SoCUsagePage : UsagePage + { + /// + /// Singleton instance of SoC Usage Page. + /// + public static readonly SoCUsagePage Instance = new SoCUsagePage(); + + private SoCUsagePage() : base(0x0011, "SoC") + { + } + + /// + 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); + } + } + /// /// Base class for all usage pages. /// diff --git a/HIDDevices/Usages/hid-usage-tables b/HIDDevices/Usages/hid-usage-tables index a08345f..34c6340 160000 --- a/HIDDevices/Usages/hid-usage-tables +++ b/HIDDevices/Usages/hid-usage-tables @@ -1 +1 @@ -Subproject commit a08345f330fce7c9da486aea44f3d21b8bf5af89 +Subproject commit 34c63400176fa6d6118897ef4103a14fd3a5f124 diff --git a/version.json b/version.json index 6b29fd1..f962a7c 100644 --- a/version.json +++ b/version.json @@ -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+)?$"