From b2ec9524f2351f8e1f013a190f37ad96b4be02eb Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Sat, 2 Aug 2025 22:03:48 +0800 Subject: [PATCH 1/6] WIP: Customize LED config by registry settings Signed-off-by: Daniel Schaefer --- FrameworkArgb/Device.c | 250 ++++++++++++++++++++++++++++++++---- FrameworkArgb/Device.h | 26 +++- FrameworkArgb/LampArray.cpp | 10 +- README.md | 37 ++++++ 4 files changed, 290 insertions(+), 33 deletions(-) diff --git a/FrameworkArgb/Device.c b/FrameworkArgb/Device.c index eb55608..1ca4341 100644 --- a/FrameworkArgb/Device.c +++ b/FrameworkArgb/Device.c @@ -17,6 +17,8 @@ Module Name: #include "driver.h" #include "EcCommunication.h" #include "device.tmh" +#define _USE_MATH_DEFINES +#include // // This is the default report descriptor for the virtual Hid device returned @@ -200,6 +202,81 @@ HID_DESCRIPTOR G_DefaultHidDescriptor = { } }; +NTSTATUS +CalculateLampPositions( + PDEVICE_CONTEXT DeviceContext, + UINT16 LampCount, + UINT8 LedArrangement +) +{ + UINT8 Layers = 0; + double centerX = 40000.0; + double centerY = 40000.0; + double radius = 40000.0; + + TraceInformation("%!FUNC! LampCount: %d, LedArrangement: %d", LampCount, LedArrangement); + + if (LampCount == 0) { + TraceError("LampCount is 0"); + return STATUS_INVALID_PARAMETER; + } + if (LampCount > MAX_LAMPARRAY_LAMP_COUNT) { + TraceError("LampCount %d over %d", LampCount, MAX_LAMPARRAY_LAMP_COUNT); + return STATUS_INVALID_PARAMETER; + } + + switch (LedArrangement) { + // Circular, layers of 8 + case 0: + DeviceContext->Width = 80000; + DeviceContext->Height = 80000; + DeviceContext->Depth = 2000 * (LampCount / 8); + // Place LampCount LEDs evenly spaced around a circle of radius 40000 (centered at 40000,40000) in layers of 8 + for (UINT8 i = 0; i < LampCount; i++) { + double angle = (2.0 * M_PI * (i % 8)) / 8; + DeviceContext->LampPositions[i].x = (UINT32)(centerX + radius * cos(angle)); + DeviceContext->LampPositions[i].y = (UINT32)(centerY + radius * sin(angle)); + DeviceContext->LampPositions[i].z = 2000 * i; + } + break; + // LEDs arranged in a circle single layer, even distance from each other + case 1: + DeviceContext->Width = 80000; + DeviceContext->Height = 80000; + // Place LampCount LEDs evenly spaced around a circle of radius 40000 (centered at 40000,40000) + for (UINT8 i = 0; i < LampCount; i++) { + double angle = (2.0 * M_PI * i) / LampCount; + DeviceContext->LampPositions[i].x = (UINT32)(centerX + radius * cos(angle)); + DeviceContext->LampPositions[i].y = (UINT32)(centerY + radius * sin(angle)); + } + break; + // Linear, LED strip with 5mm distance + case 2: + DeviceContext->Width = LampCount * 5000; + DeviceContext->Height = 0; + for (UINT8 i = 0; i <= LampCount; i++) { + DeviceContext->LampPositions[i].x = i * 5000; + DeviceContext->LampPositions[i].y = 0; + } + break; + // Square Matrix with 5mm distance + case 3: + Layers = (UINT8) sqrt((double) LampCount); + DeviceContext->Width = Layers * 5000; + DeviceContext->Height = Layers * 5000; + for (UINT8 i = 0; i <= LampCount; i++) { + DeviceContext->LampPositions[i].x = (i % Layers) * 5000; + DeviceContext->LampPositions[i].y = (i / Layers) * 5000; + } + break; + default: + TraceError("LedArrangement %d invalid.", LedArrangement); + return STATUS_INVALID_PARAMETER; + } + + return STATUS_SUCCESS; +} + NTSTATUS FrameworkArgbCreateDevice( _Inout_ PWDFDEVICE_INIT DeviceInit @@ -227,6 +304,7 @@ Return Value: PHID_DEVICE_ATTRIBUTES hidAttributes; WDFDEVICE device; NTSTATUS status; + UINT8 LedArrangement; TraceInformation("%!FUNC! Entry"); @@ -261,28 +339,35 @@ Return Value: deviceContext->Device = device; deviceContext->CurrentLampId = 0; deviceContext->AutonomousMode = TRUE; - // 8 LEDs in a circle - // z is 0 for all LEDs, they're all in the same plane - // Bottom LED - deviceContext->LampPositions[0].x = 40000; - deviceContext->LampPositions[0].y = 0; - deviceContext->LampPositions[1].x = 60000; - deviceContext->LampPositions[1].y = 20000; - // Right LED - deviceContext->LampPositions[2].x = 80000; - deviceContext->LampPositions[2].y = 40000; - deviceContext->LampPositions[3].x = 60000; - deviceContext->LampPositions[3].y = 60000; - // Top LED - deviceContext->LampPositions[4].x = 40000; - deviceContext->LampPositions[4].y = 80000; - deviceContext->LampPositions[5].x = 20000; - deviceContext->LampPositions[5].y = 60000; - // Left LED - deviceContext->LampPositions[6].x = 0; - deviceContext->LampPositions[6].y = 40000; - deviceContext->LampPositions[7].x = 20000; - deviceContext->LampPositions[7].y = 20000; + + deviceContext->LampCount = 0; + deviceContext->Width = 0; + deviceContext->Height = 0; + deviceContext->Depth = 2000; + LedArrangement = 0; + status = CheckRegistryForLedConfig(device); + if (NT_SUCCESS(status)) { + // + // We need to read read descriptor from registry + // + status = ReadLedConfigFromRegistry(device, &deviceContext->LampCount, &LedArrangement); + if (!NT_SUCCESS(status)) { + TraceError("Failed to read LED config from registry\n"); + } + } + + // Default 8 LED fan + if (deviceContext->LampCount == 0) { + TraceError("No lamps set, falling back to default"); + deviceContext->LampCount = 8; + LedArrangement = 0; + } + + status = CalculateLampPositions(deviceContext, deviceContext->LampCount, LedArrangement); + if (!NT_SUCCESS(status)) { + TraceError("Failed to calulcate lamp positions\n"); + deviceContext->LampCount = 0; + } hidAttributes = &deviceContext->HidDeviceAttributes; RtlZeroMemory(hidAttributes, sizeof(HID_DEVICE_ATTRIBUTES)); @@ -526,3 +611,124 @@ Return Value: status = RequestCopyFromBuffer(Request, string, stringSizeCb); return status; } + +NTSTATUS +CheckRegistryForLedConfig( + WDFDEVICE Device +) +/*++ + +Routine Description: + + Read "ReadFromRegistry" key value from device parameters in the registry. + +Arguments: + + device - pointer to a device object. + +Return Value: + + NT status code. + +--*/ + +{ + WDFKEY hKey = NULL; + NTSTATUS status; + UNICODE_STRING valueName; + ULONG value; + + TraceInformation("%!FUNC! Entry"); + status = WdfDeviceOpenRegistryKey(Device, + PLUGPLAY_REGKEY_DEVICE, + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + &hKey); + if (NT_SUCCESS(status)) { + TraceInformation("%!FUNC! Found driver Registry key"); + RtlInitUnicodeString(&valueName, L"ReadFromRegistry"); + + status = WdfRegistryQueryULong(hKey, + &valueName, + &value); + + if (NT_SUCCESS(status)) { + TraceInformation("%!FUNC! ReadFromRegistry has value: %d", value); + if (value == 0) { + status = STATUS_UNSUCCESSFUL; + } + } + + WdfRegistryClose(hKey); + } + + TraceInformation("%!FUNC! Exiting with %!STATUS!", status); + return status; +} + +NTSTATUS +ReadLedConfigFromRegistry( + WDFDEVICE Device, + UINT16 *LampCount, + UINT8 *LedArrangement +) +/*++ + +Routine Description: + + Read LED config report descriptor from registry + +Arguments: + + device - pointer to a device object. + +Return Value: + + NT status code. + +--*/ +{ + WDFKEY hKey = NULL; + NTSTATUS status; + UNICODE_STRING valueName; + PDEVICE_CONTEXT deviceContext; + ULONG value; + + TraceInformation("%!FUNC! Entry"); + deviceContext = GetDeviceContext(Device); + + status = WdfDeviceOpenRegistryKey(Device, + PLUGPLAY_REGKEY_DEVICE, + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + &hKey); + + if (!NT_SUCCESS(status)) { + TraceError("%!FUNC! Failed to find driver registry key"); + return status; + } + + RtlInitUnicodeString(&valueName, L"LedCount"); + status = WdfRegistryQueryULong(hKey, &valueName, &value); + if (!NT_SUCCESS(status)) { + TraceError("%!FUNC! Failed to WdfRegistryQueryULong LedCount: %!STATUS!", status); + WdfRegistryClose(hKey); + return status; + } + TraceInformation("%!FUNC! LedCount has value: %d", value); + *LampCount = (UINT8) value; + + RtlInitUnicodeString(&valueName, L"LedArrangement"); + status = WdfRegistryQueryULong(hKey, &valueName, &value); + if (!NT_SUCCESS(status)) { + TraceError("%!FUNC! Failed to WdfRegistryQueryULong LedArrangement: %!STATUS!", status); + WdfRegistryClose(hKey); + return status; + } + TraceInformation("%!FUNC! LedArrangement has value: %d", value); + *LedArrangement = (UINT8) value; + + WdfRegistryClose(hKey); + + return status; +} diff --git a/FrameworkArgb/Device.h b/FrameworkArgb/Device.h index 2f3a212..2a7f594 100644 --- a/FrameworkArgb/Device.h +++ b/FrameworkArgb/Device.h @@ -28,10 +28,10 @@ DRIVER_INITIALIZE DriverEntry; EVT_WDF_DRIVER_DEVICE_ADD EvtDeviceAdd; EVT_WDF_TIMER EvtTimerFunc; -#define LAMPARRAY_LAMP_COUNT 8 -#define LAMPARRAY_WIDTH 80000 // 80mm -#define LAMPARRAY_HEIGHT 80000 // 80mm -#define LAMPARRAY_DEPTH 20000 // 20mm +#define MAX_LAMPARRAY_LAMP_COUNT 256 +//#define LAMPARRAY_WIDTH 80000 // 80mm +//#define LAMPARRAY_HEIGHT 80000 // 80mm +//#define LAMPARRAY_DEPTH 20000 // 20mm #define LAMPARRAY_KIND 0x07 // LampArrayKindChassis #define LAMPARRAY_UPDATE_INTERVAL 100000 // 10ms @@ -48,10 +48,13 @@ typedef struct _DEVICE_CONTEXT HANDLE CrosEcHandle; UINT16 CurrentLampId; BOOLEAN AutonomousMode; - Position LampPositions[LAMPARRAY_LAMP_COUNT]; + UINT16 LampCount; + UINT32 Width; + UINT32 Height; + UINT32 Depth; + Position LampPositions[MAX_LAMPARRAY_LAMP_COUNT]; HID_DESCRIPTOR HidDescriptor; PHID_REPORT_DESCRIPTOR ReportDescriptor; - BOOLEAN ReadReportDescFromRegistry; } DEVICE_CONTEXT, * PDEVICE_CONTEXT; // @@ -168,6 +171,17 @@ RequestGetHidXferPacket_ToWriteToDevice( _Out_ HID_XFER_PACKET* Packet ); +NTSTATUS +CheckRegistryForLedConfig( + _In_ WDFDEVICE Device +); + +NTSTATUS +ReadLedConfigFromRegistry( + _In_ WDFDEVICE Device, + _Out_ UINT16 *LampCount, + _Out_ UINT8 *LedArrangement +); // // Misc definitions diff --git a/FrameworkArgb/LampArray.cpp b/FrameworkArgb/LampArray.cpp index 64194ec..31715fc 100644 --- a/FrameworkArgb/LampArray.cpp +++ b/FrameworkArgb/LampArray.cpp @@ -86,10 +86,10 @@ GetLampArrayAttributesReport( DeviceContext = DeviceContext; LampArrayAttributesReport report = { - LAMPARRAY_LAMP_COUNT, - LAMPARRAY_WIDTH, - LAMPARRAY_HEIGHT, - LAMPARRAY_DEPTH, + DeviceContext->LampCount, + DeviceContext->Width, + DeviceContext->Height, + DeviceContext->Depth, LAMPARRAY_KIND, LAMPARRAY_UPDATE_INTERVAL }; @@ -128,7 +128,7 @@ GetLampAttributesResponseReport( }; RtlCopyMemory(ReportBuffer, &report, sizeof(LampAttributesResponseReport)); - DeviceContext->CurrentLampId = CurrentLampId + 1 >= LAMPARRAY_LAMP_COUNT ? CurrentLampId : CurrentLampId + 1; + DeviceContext->CurrentLampId = CurrentLampId + 1 >= DeviceContext->LampCount ? CurrentLampId : CurrentLampId + 1; return Size; diff --git a/README.md b/README.md index b751616..8998e89 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,43 @@ References: - [Windows.Devices.Enumeration](https://learn.microsoft.com/en-us/uwp/api/windows.devices.enumeration.devicewatcher?view=winrt-26100) - [Game Dev Documentation](https://learn.microsoft.com/en-us/gaming/gdk/docs/features/common/lighting/gc-lighting-toc) +## Configuration + +When the driver loads, the Windows Dynamic Lighting interface (or any HID +application) asks it about the LED configuration - how many and where in 3D +space. +This is so that they can know how to apply 2D or 3D animations to them. + +By default the driver loads with an 8 LED configuration arranged in a circle of +20mm diameter. This matches the ARGB fan that Framework offers for the +Framework Desktop. + +To customize the configuration, set/edit the following registry entries. +They are all under: `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\ROOT\HIDCLASS\0000\Device Parameters` (0000 might be 0001 or higher, edit the highest one) + +After adding/changing the registry entries, you need to reboot the system to make sure the driver and the windows LampArray subsystem gets properly reinitialized. + +| Name | Type | Explanation | +|------------------|-------|---------------------------------| +| ReadFromRegistry | DWORD | If 1, the other values are read | +| LedCount | DWORD | How many LEDs in total | +| LedArrangement | DWORD | How the LEDs are arranged | + +LedArrangement can have the following values: + +- 0: Circular, layers of 8 (e.g. when 16 LEDs in total, two layers of 8 LEDs) +- 1: Circular, single layer +- 2: Linear (e.g. LED strip) +- 3: Square Matrix (works best with a square number of LEDs) + +For example to control just 4 LEDs on the fan: + +``` +sudo reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\ROOT\HIDCLASS\0000\Device Parameters" /v ReadFromRegistry /t REG_DWORD /d 1 +sudo reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\ROOT\HIDCLASS\0000\Device Parameters" /v LedCount /t REG_DWORD /d 8 +sudo reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\ROOT\HIDCLASS\0000\Device Parameters" /v LedArrangement /t REG_DWORD /d 0 +``` + ## Development ### Build From 5ae7413d5a22487addc26c4371a43d8efe6ad70e Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 4 Aug 2025 11:23:47 +0800 Subject: [PATCH 2/6] Remove more sample code Signed-off-by: Daniel Schaefer --- FrameworkArgb/Device.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/FrameworkArgb/Device.h b/FrameworkArgb/Device.h index 2a7f594..302346c 100644 --- a/FrameworkArgb/Device.h +++ b/FrameworkArgb/Device.h @@ -196,16 +196,6 @@ ReadLedConfigFromRegistry( #define FWK_ARGB_HID_PID 0x0033 #define FWK_ARGB_HID_VERSION 0x0100 -// -// Custom control codes are defined here. They are to be used for sideband -// communication with the hid minidriver. These control codes are sent to -// the hid minidriver using Hid_SetFeature() API to a custom collection -// defined especially to handle such requests. -// -#define FWK_ARGB_CONTROL_CODE_SET_ATTRIBUTES 0x00 -#define FWK_ARGB_CONTROL_CODE_DUMMY1 0x01 -#define FWK_ARGB_CONTROL_CODE_DUMMY2 0x02 - #define LAMP_ARRAY_ATTRIBUTES_REPORT_ID 0x01 #define LAMP_ATTRIBUTES_REQUEST_REPORT_ID 0x02 #define LAMP_ATTRIBUTES_RESPONSE_REPORT_ID 0x03 From 84dfa023403aa4085785f0bbd76e37477ff71117 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 4 Aug 2025 11:43:30 +0800 Subject: [PATCH 3/6] python: Add script to get info about lamp array It also shows a plot of the lamp locations Signed-off-by: Daniel Schaefer --- python/README.md | 7 ++ python/lamp_array.py | 137 ++++++++++++++++++++++++++++++++++++++++ python/requirements.txt | Bin 0 -> 486 bytes 3 files changed, 144 insertions(+) create mode 100644 python/README.md create mode 100644 python/lamp_array.py create mode 100644 python/requirements.txt diff --git a/python/README.md b/python/README.md new file mode 100644 index 0000000..0e678f4 --- /dev/null +++ b/python/README.md @@ -0,0 +1,7 @@ +# Python + +Get lamp array and invidual lamp configs from HID device. + +This only works on windows when the lamp array subsystem doesn't interfere. +So you have to go to device manager to "disable" the device. +It doesn't actually disable and it'll ask you to reboot - don't do that. diff --git a/python/lamp_array.py b/python/lamp_array.py new file mode 100644 index 0000000..c0a5dec --- /dev/null +++ b/python/lamp_array.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 +import os +import struct + +# pip install hidapi +import hid + +LIGHTING_USAGE_PAGE = 0x59 + +LAMP_ARRAY_ATTRIBUTES_REPORT_ID = 0x01 +LAMP_ATTRIBUTES_REQUEST_REPORT_ID = 0x02 +LAMP_ATTRIBUTES_RESPONSE_REPORT_ID = 0x03 +LAMP_MULTI_UPDATE_REPORT_ID = 0x04 +LAMP_RANGE_UPDATE_REPORT_ID = 0x05 +LAMP_ARRAY_CONTROL_REPORT_ID = 0x06 +CONTROL_COLLECTION_REPORT_ID = 0x07 + +LAMP_ARRAY_ATTRIBUTES_FORMAT = '=HIIIIi' +LAMP_ATTRIBUTES_FORMAT = '=HIIIIIBBBBBB' + +FWK_VID = 0x32AC +ARGB_PID = 0x0033 + +def print_lamp_details(device): + positions_x = [] + positions_y = [] + + h = hid.device() + h.open_path(device['path']) + + array_attributes = h.get_feature_report(LAMP_ARRAY_ATTRIBUTES_REPORT_ID, 0x100) + # Cut off report ID in first byte and convert to bytearray + array_attributes = bytes(array_attributes[1:]) + print(array_attributes.hex()) + print(len(array_attributes)) + + (cnt, width, height, depth, kind, interval) = \ + struct.unpack(LAMP_ARRAY_ATTRIBUTES_FORMAT, array_attributes) + + print(interval) + + print("Lamp Array") + print(f" Count: {cnt}") + print(f" Width: {width}um") + print(f" Height: {height}um") + print(f" Depth: {depth}um") + if kind == 1: + print(f" Kind: Keyboard") + elif kind == 2: + print(f" Kind: Mouse") + elif kind == 7: + print(f" Kind: Chassis") + else: + print(f" Kind: {kind}") + print(f" Min Update Interval: {interval}ms") + + h.send_feature_report([LAMP_ATTRIBUTES_REQUEST_REPORT_ID, 0x00, 0x00]) + for _ in range(cnt): + lamp_attributes = h.get_feature_report(LAMP_ATTRIBUTES_RESPONSE_REPORT_ID, 0x100) + # Cut off report ID in first byte and convert to bytearray + lamp_attributes = bytes(lamp_attributes[1:]) + # print(lamp_attributes.hex()) + # print(len(lamp_attributes)) + (lamp_id, pos_x, pos_y, pos_z, latency, purpose, red, green, blue, intensity, programmable, input_binding) = \ + struct.unpack(LAMP_ATTRIBUTES_FORMAT, lamp_attributes) + print(" Lamp") + print(f" ID: {lamp_id}") + print(f" Position: ({pos_x},{pos_y},{pos_z})") + print(f" Latency: {latency}ms") + print(f" Purpose: {depth}") + print(f" Red Count: {red}") + print(f" Green Count: {green}") + print(f" Blue Count: {blue}") + print(f" Intensity Count: {intensity}") + print(f" Programmable: {programmable}") + print(f" Input Binding: {input_binding}") + positions_x.append(pos_x) + positions_y.append(pos_y) + + return (positions_x, positions_y) + + +def main(): + devices = find_devs(show=False, verbose=False) + for device in devices: + positions = print_lamp_details(device) + import matplotlib.pyplot as plt + plt.scatter(x=positions[0], y=positions[1]) + plt.show() + +def format_bcd(fw_ver): + fw_ver_major = (fw_ver & 0xFF00) >> 8 + fw_ver_minor = (fw_ver & 0x00F0) >> 4 + fw_ver_patch = (fw_ver & 0x000F) + return f"{fw_ver_major}.{fw_ver_minor}.{fw_ver_patch}" + + +def find_devs(show, verbose): + if verbose: + show = True + + devices = [] + for device_dict in hid.enumerate(): + vid = device_dict["vendor_id"] + pid = device_dict["product_id"] + product = device_dict["product_string"] + manufacturer = device_dict["manufacturer_string"] + sn = device_dict['serial_number'] + interface = device_dict['interface_number'] + path = device_dict['path'] + usage_page = device_dict['usage_page'] + fw_ver = device_dict["release_number"] + + # For some reason on Linux it'll always show usage_page==0 + if (os.name == 'nt' and usage_page == LIGHTING_USAGE_PAGE) or verbose: + if show: + print(f"Manufacturer: {manufacturer}") + print(f"Product: {product}") + print("FW Version: {}".format(format_bcd(fw_ver))) + print(f"Serial No: {sn}") + + if verbose: + print(f"VID/PID: {vid:04X}:{pid:04X}") + print(f"Interface: {interface}") + print(f"Usage Page: {usage_page:04X}") + # TODO: print Usage Page + print("") + + + if (vid == FWK_VID and pid == ARGB_PID) or usage_page == LIGHTING_USAGE_PAGE: + devices.append(device_dict) + + return devices + + +if __name__ == "__main__": + main() diff --git a/python/requirements.txt b/python/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..c10f8e663900b54ff1aa5b574fe7614bb09146cd GIT binary patch literal 486 zcmYjNNe+TQ5UjI_PmusZ#DkAf+z4x65dFMb)gTx`AEv8o`@B=ssNgtzv}o|cfnNX* zTl?2oA?0g|0v95*^|=WU+SL9!afqcRt}|4`eT+S)525bJaK@1u*&mBg;%j)>(MM$1 zoS1=sXMB%YS-y0U7^)Ax7Wf#V=0d>8x792D6d=vMm=uKTMU5xx4k&f7g U^S|H35-$Bp{W&>Q{@tA53-3or!vFvP literal 0 HcmV?d00001 From 1a74606de7a845f622632df23c80dfabac5d3863 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 4 Aug 2025 18:19:09 +0800 Subject: [PATCH 4/6] Add comments about AppVerifier Signed-off-by: Daniel Schaefer --- FrameworkArgb/Device.c | 3 +++ FrameworkArgb/Driver.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/FrameworkArgb/Device.c b/FrameworkArgb/Device.c index 1ca4341..3f24c0a 100644 --- a/FrameworkArgb/Device.c +++ b/FrameworkArgb/Device.c @@ -639,6 +639,9 @@ Return Value: ULONG value; TraceInformation("%!FUNC! Entry"); + // + // If this fails, AppVerifier shows an error + // RegOpenKeyExW: Key (\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\Services\WUDFx02000) is denied 'READ_CONTROL KEY_QUERY_VALUE KEY_ENUMERATE_SUB_KEYS KEY_NOTIFY' access with error 0x2 status = WdfDeviceOpenRegistryKey(Device, PLUGPLAY_REGKEY_DEVICE, KEY_READ, diff --git a/FrameworkArgb/Driver.c b/FrameworkArgb/Driver.c index 13e98f4..b78e86b 100644 --- a/FrameworkArgb/Driver.c +++ b/FrameworkArgb/Driver.c @@ -62,6 +62,7 @@ Return Value: #endif TraceInformation("%!FUNC! Entry"); + // TODO: Print Registry path // // Register a cleanup callback so that we can call WPP_CLEANUP when @@ -74,6 +75,9 @@ Return Value: FrameworkArgbEvtDeviceAdd ); + // AppVerifier shows the following errors + // Could not convert Key security descriptor '\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\Services\FrameworkArgb' to text due to error 0x8 + // RegOpenKeyExW: Key (\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\Services\FrameworkArgb\Parameters\Wdf) is denied 'READ_CONTROL KEY_QUERY_VALUE KEY_ENUMERATE_SUB_KEYS KEY_NOTIFY' access with error 0x2 status = WdfDriverCreate(DriverObject, RegistryPath, &attributes, From f14a75dbdf3ff13a77b3c0caff28463a495066a9 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 6 Aug 2025 09:07:14 +0800 Subject: [PATCH 5/6] python: Make it work on linux linux doesn't include the usage page id Signed-off-by: Daniel Schaefer --- python/lamp_array.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/python/lamp_array.py b/python/lamp_array.py index c0a5dec..3908d93 100644 --- a/python/lamp_array.py +++ b/python/lamp_array.py @@ -31,14 +31,10 @@ def print_lamp_details(device): array_attributes = h.get_feature_report(LAMP_ARRAY_ATTRIBUTES_REPORT_ID, 0x100) # Cut off report ID in first byte and convert to bytearray array_attributes = bytes(array_attributes[1:]) - print(array_attributes.hex()) - print(len(array_attributes)) (cnt, width, height, depth, kind, interval) = \ struct.unpack(LAMP_ARRAY_ATTRIBUTES_FORMAT, array_attributes) - print(interval) - print("Lamp Array") print(f" Count: {cnt}") print(f" Width: {width}um") @@ -81,12 +77,22 @@ def print_lamp_details(device): def main(): - devices = find_devs(show=False, verbose=False) + verbose = False + devices = find_devs(show=False, verbose=verbose) for device in devices: - positions = print_lamp_details(device) - import matplotlib.pyplot as plt - plt.scatter(x=positions[0], y=positions[1]) - plt.show() + try: + positions = print_lamp_details(device) + import matplotlib.pyplot as plt + plt.scatter(x=positions[0], y=positions[1]) + plt.show() + except struct.error as e: + if verbose: + print(e) + continue + except OSError as e: + if verbose: + print(e) + continue def format_bcd(fw_ver): fw_ver_major = (fw_ver & 0xFF00) >> 8 From 844cf56300c1e5eacbf1191afe40e4716ae2ce2f Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 6 Aug 2025 16:23:08 +0800 Subject: [PATCH 6/6] Bump version to 0.0.0.2 Signed-off-by: Daniel Schaefer --- FrameworkArgb/FrameworkArgb.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FrameworkArgb/FrameworkArgb.vcxproj b/FrameworkArgb/FrameworkArgb.vcxproj index 2e22b3b..042de86 100644 --- a/FrameworkArgb/FrameworkArgb.vcxproj +++ b/FrameworkArgb/FrameworkArgb.vcxproj @@ -125,7 +125,7 @@ sha256 - 0.0.0.1 + 0.0.0.2