Files
ReLibreHardwareMonitor/LibreHardwareMonitorLib/Interop/PowerMonitor/Stm32PortFinder.cs
T
BlacktempelandPhyxionNL df9e0a5131 Add support for Thermal Grizzly WireView Pro 2. (#2171)
* Add support for Thermal Grizzly WireView Pro 2.

* Process PR comments.

* PR comments.

* Add private keyword.

* PR comments.

* Replace WMI with SetupAPI.

Some first updates according to Thermal Grizzly code.

* Add report.

* Further improve implementation according to code of Thermal Grizzly (thanks !).

* No connection check for welcome message.

* Rename class + change SerialPort to SharedSerialPort for guard - fixing mutex issues.

* PR comments.

* Remove SP_DEVINFO_DATA from NativeMethods.txt

* Update WireViewPro2.cs

* Rename hasMutex to _hasMutex for consistency

* Formatting

* Fix build

---------

Co-authored-by: PhyxionNL <7643972+PhyxionNL@users.noreply.github.com>
2026-01-27 13:20:07 +01:00

132 lines
4.4 KiB
C#

// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Copyright (C) LibreHardwareMonitor and Contributors.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using Windows.Win32;
using Windows.Win32.Devices.DeviceAndDriverInstallation;
using Windows.Win32.Foundation;
namespace LibreHardwareMonitor.Interop.PowerMonitor;
/// <summary>
/// Helper class to find STM32 COM ports based on VID and PID.
/// </summary>
public static class Stm32PortFinder
{
private const int BufferSize = 1024;
/// <summary>
/// Finds the names of all available COM ports that match the specified USB vendor ID (VID) and product ID (PID).
/// </summary>
/// <param name="vid">The USB vendor ID to match.</param>
/// <param name="pid">The USB product ID to match.</param>
/// <returns>
/// A list of strings containing the names of matching COM ports.<br />
/// The list is empty if no matching ports are found.
/// </returns>
public static List<string> FindMatchingComPorts(uint vid, uint pid)
{
return FindMatchingComPorts($"{vid:X4}", $"{pid:X4}");
}
/// <summary>
/// <inheritdoc cref="FindMatchingComPorts(uint, uint)" />
/// </summary>
/// <param name="vid">
/// <inheritdoc cref="FindMatchingComPorts(uint, uint)" />
/// </param>
/// <param name="pid">
/// <inheritdoc cref="FindMatchingComPorts(uint, uint)" />
/// </param>
/// <returns>
/// <inheritdoc cref="FindMatchingComPorts(uint, uint)" />
/// </returns>
public static List<string> FindMatchingComPorts(string vid, string pid)
{
var result = new List<string>();
//Setup
SetupDiDestroyDeviceInfoListSafeHandle devInfo = PInvoke.SetupDiGetClassDevs(PInvoke.GUID_DEVCLASS_PORTS, null, HWND.Null, SETUP_DI_GET_CLASS_DEVS_FLAGS.DIGCF_PRESENT);
//Check handle
if (devInfo.IsInvalid)
{
return result;
}
try
{
SP_DEVINFO_DATA devInfoData = new() { cbSize = (uint)Marshal.SizeOf<SP_DEVINFO_DATA>() };
uint index = 0;
while (PInvoke.SetupDiEnumDeviceInfo(devInfo, index++, ref devInfoData))
{
//Get hardware ID
string hwId = GetProperty(devInfo, SETUP_DI_REGISTRY_PROPERTY.SPDRP_HARDWAREID, devInfoData);
if (string.IsNullOrWhiteSpace(hwId))
{
continue;
}
//Check if hardware ID contains VID and PID
if (!hwId.Contains($"VID_{vid}", StringComparison.OrdinalIgnoreCase) ||
!hwId.Contains($"PID_{pid}", StringComparison.OrdinalIgnoreCase))
{
continue;
}
//Get friendly name
string friendlyName = GetProperty(devInfo, SETUP_DI_REGISTRY_PROPERTY.SPDRP_FRIENDLYNAME, devInfoData);
//Extract COM port from friendly name
int start = friendlyName.LastIndexOf("(COM", StringComparison.OrdinalIgnoreCase);
int end = friendlyName.LastIndexOf(')');
//Check if valid and add to result
if (start >= 0 && end > start)
{
string com = friendlyName.Substring(start + 1, end - start - 1);
result.Add(com);
}
}
}
finally
{
//Cleanup
devInfo.Dispose();
}
return result;
static string GetProperty(SafeHandle hDevInfo, SETUP_DI_REGISTRY_PROPERTY property, SP_DEVINFO_DATA devInfoData)
{
byte[] buffer = new byte[BufferSize];
if (PInvoke.SetupDiGetDeviceRegistryProperty(hDevInfo, devInfoData, property, buffer))
{
//Take first string only, no need for the rest
return NormalizeString(Encoding.Unicode.GetString(buffer));
}
return null;
}
}
private static string NormalizeString(string str)
{
int end = str.IndexOf('\0');
if (end == -1)
{
end = 0;
}
return str.Substring(0, end);
}
}