Improvements to battery monitoring (#1158)
* Check whether battery values are available * Rename _degradationPercentage to _degradationLevel * Add support for temperature monitoring * Include the battery device name and tag in the hardware identifier * Set sensor index value properly * Fix temperature conversion The returned temperature value must be divided, not multiplied. * Disable sensors that have a "null" value * Fix random symbols in battery device name and manufacturer
This commit is contained in:
@@ -19,11 +19,12 @@ internal sealed class Battery : Hardware
|
||||
private readonly Sensor _chargeDischargeCurrent;
|
||||
private readonly Sensor _chargeDischargeRate;
|
||||
private readonly Sensor _chargeLevel;
|
||||
private readonly Sensor _degradationPercentage;
|
||||
private readonly Sensor _degradationLevel;
|
||||
private readonly Sensor _designedCapacity;
|
||||
private readonly Sensor _fullChargedCapacity;
|
||||
private readonly Sensor _remainingCapacity;
|
||||
private readonly Sensor _remainingTime;
|
||||
private readonly Sensor _temperature;
|
||||
private readonly Sensor _voltage;
|
||||
|
||||
public Battery
|
||||
@@ -34,7 +35,7 @@ internal sealed class Battery : Hardware
|
||||
Kernel32.BATTERY_INFORMATION batteryInfo,
|
||||
uint batteryTag,
|
||||
ISettings settings) :
|
||||
base(name, new Identifier("battery"), settings)
|
||||
base(name, new Identifier("battery", $"{name.Replace(' ', '-')}_{batteryTag}"), settings)
|
||||
{
|
||||
Name = name;
|
||||
Manufacturer = manufacturer;
|
||||
@@ -72,61 +73,65 @@ internal sealed class Battery : Hardware
|
||||
Chemistry = BatteryChemistry.Unknown;
|
||||
}
|
||||
|
||||
DegradationLevel = 100f - (batteryInfo.FullChargedCapacity * 100f / batteryInfo.DesignedCapacity);
|
||||
DesignedCapacity = batteryInfo.DesignedCapacity;
|
||||
FullChargedCapacity = batteryInfo.FullChargedCapacity;
|
||||
|
||||
_designedCapacity = new Sensor("Designed Capacity", 0, SensorType.Energy, this, settings);
|
||||
_fullChargedCapacity = new Sensor("Fully-Charged Capacity", 1, SensorType.Energy, this, settings);
|
||||
_degradationLevel = new Sensor("Degradation Level", 1, SensorType.Level, this, settings);
|
||||
_chargeLevel = new Sensor("Charge Level", 0, SensorType.Level, this, settings);
|
||||
ActivateSensor(_chargeLevel);
|
||||
|
||||
_voltage = new Sensor("Voltage", 1, SensorType.Voltage, this, settings);
|
||||
ActivateSensor(_voltage);
|
||||
|
||||
_chargeDischargeCurrent = new Sensor("Current", 2, SensorType.Current, this, settings);
|
||||
ActivateSensor(_chargeDischargeCurrent);
|
||||
|
||||
_designedCapacity = new Sensor("Designed Capacity", 3, SensorType.Energy, this, settings);
|
||||
ActivateSensor(_designedCapacity);
|
||||
|
||||
_fullChargedCapacity = new Sensor("Full Charged Capacity", 4, SensorType.Energy, this, settings);
|
||||
ActivateSensor(_fullChargedCapacity);
|
||||
|
||||
_remainingCapacity = new Sensor("Remaining Capacity", 5, SensorType.Energy, this, settings);
|
||||
ActivateSensor(_remainingCapacity);
|
||||
|
||||
_voltage = new Sensor("Voltage", 0, SensorType.Voltage, this, settings);
|
||||
_remainingCapacity = new Sensor("Remaining Capacity", 2, SensorType.Energy, this, settings);
|
||||
_chargeDischargeCurrent = new Sensor("Charge/Discharge Current", 0, SensorType.Current, this, settings);
|
||||
_chargeDischargeRate = new Sensor("Charge/Discharge Rate", 0, SensorType.Power, this, settings);
|
||||
ActivateSensor(_chargeDischargeRate);
|
||||
|
||||
_degradationPercentage = new Sensor("Degradation Level", 0, SensorType.Level, this, settings);
|
||||
ActivateSensor(_degradationPercentage);
|
||||
|
||||
_remainingTime = new Sensor("Remaining Time (Estimated)", 0, SensorType.TimeSpan, this, settings);
|
||||
ActivateSensor(_remainingTime);
|
||||
_temperature = new Sensor("Battery Temperature", 0, SensorType.Temperature, this, settings);
|
||||
|
||||
if (batteryInfo.FullChargedCapacity is not Kernel32.BATTERY_UNKNOWN_CAPACITY &&
|
||||
batteryInfo.DesignedCapacity is not Kernel32.BATTERY_UNKNOWN_CAPACITY)
|
||||
{
|
||||
_designedCapacity.Value = batteryInfo.DesignedCapacity;
|
||||
_fullChargedCapacity.Value = batteryInfo.FullChargedCapacity;
|
||||
_degradationLevel.Value = 100f - (batteryInfo.FullChargedCapacity * 100f / batteryInfo.DesignedCapacity);
|
||||
DesignedCapacity = batteryInfo.DesignedCapacity;
|
||||
FullChargedCapacity = batteryInfo.FullChargedCapacity;
|
||||
|
||||
ActivateSensor(_designedCapacity);
|
||||
ActivateSensor(_fullChargedCapacity);
|
||||
ActivateSensor(_degradationLevel);
|
||||
}
|
||||
}
|
||||
|
||||
public float ChargeDischargeCurrent { get; private set; }
|
||||
public float? ChargeDischargeCurrent { get; private set; }
|
||||
|
||||
public float ChargeDischargeRate { get; private set; }
|
||||
public float? ChargeDischargeRate { get; private set; }
|
||||
|
||||
public float ChargeLevel { get; private set; }
|
||||
public float? ChargeLevel => _chargeLevel.Value;
|
||||
|
||||
public BatteryChemistry Chemistry { get; }
|
||||
|
||||
public float DegradationLevel { get; }
|
||||
public float? DegradationLevel => _degradationLevel.Value;
|
||||
|
||||
public float DesignedCapacity { get; }
|
||||
public float? DesignedCapacity { get; }
|
||||
|
||||
public float FullChargedCapacity { get; }
|
||||
public float? FullChargedCapacity { get; }
|
||||
|
||||
public override HardwareType HardwareType => HardwareType.Battery;
|
||||
|
||||
public string Manufacturer { get; }
|
||||
|
||||
public float RemainingCapacity { get; private set; }
|
||||
public float? RemainingCapacity => _remainingCapacity.Value;
|
||||
|
||||
public uint RemainingTime { get; private set; }
|
||||
public float? RemainingTime => _remainingTime.Value;
|
||||
|
||||
public float Voltage { get; private set; }
|
||||
public float? Temperature => _temperature.Value;
|
||||
|
||||
public float? Voltage => _voltage.Value;
|
||||
|
||||
private void ActivateSensorIfValueNotNull(ISensor sensor)
|
||||
{
|
||||
if (sensor.Value != null)
|
||||
ActivateSensor(sensor);
|
||||
else
|
||||
DeactivateSensor(sensor);
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
@@ -142,53 +147,55 @@ internal sealed class Battery : Hardware
|
||||
out _,
|
||||
IntPtr.Zero))
|
||||
{
|
||||
_designedCapacity.Value = Convert.ToSingle(_batteryInformation.DesignedCapacity);
|
||||
_fullChargedCapacity.Value = Convert.ToSingle(_batteryInformation.FullChargedCapacity);
|
||||
|
||||
_remainingCapacity.Value = Convert.ToSingle(batteryStatus.Capacity);
|
||||
RemainingCapacity = Convert.ToSingle(batteryStatus.Capacity);
|
||||
|
||||
_voltage.Value = Convert.ToSingle(batteryStatus.Voltage) / 1000f;
|
||||
Voltage = Convert.ToSingle(batteryStatus.Voltage) / 1000f;
|
||||
if (batteryStatus.Capacity != Kernel32.BATTERY_UNKNOWN_CAPACITY)
|
||||
_remainingCapacity.Value = batteryStatus.Capacity;
|
||||
else
|
||||
_remainingCapacity.Value = null;
|
||||
|
||||
_chargeLevel.Value = _remainingCapacity.Value * 100f / _fullChargedCapacity.Value;
|
||||
ChargeLevel = (_remainingCapacity.Value * 100f / _fullChargedCapacity.Value).GetValueOrDefault();
|
||||
|
||||
ChargeDischargeRate = batteryStatus.Rate / 1000f;
|
||||
if (batteryStatus.Voltage is not Kernel32.BATTERY_UNKNOWN_VOLTAGE)
|
||||
_voltage.Value = batteryStatus.Voltage / 1000f;
|
||||
else
|
||||
_voltage.Value = null;
|
||||
|
||||
switch (batteryStatus.Rate)
|
||||
if (batteryStatus.Rate is Kernel32.BATTERY_UNKNOWN_RATE)
|
||||
{
|
||||
case > 0:
|
||||
_chargeDischargeRate.Name = "Charge Rate";
|
||||
_chargeDischargeRate.Value = batteryStatus.Rate / 1000f;
|
||||
ChargeDischargeCurrent = null;
|
||||
_chargeDischargeCurrent.Value = null;
|
||||
|
||||
_chargeDischargeCurrent.Name = "Charge Current";
|
||||
_chargeDischargeCurrent.Value = _chargeDischargeRate.Value / _voltage.Value;
|
||||
ChargeDischargeCurrent = (_chargeDischargeRate.Value / _voltage.Value).GetValueOrDefault();
|
||||
|
||||
break;
|
||||
case < 0:
|
||||
_chargeDischargeRate.Name = "Discharge Rate";
|
||||
_chargeDischargeRate.Value = Math.Abs(batteryStatus.Rate / 1000f);
|
||||
|
||||
_chargeDischargeCurrent.Name = "Discharge Current";
|
||||
_chargeDischargeCurrent.Value = _chargeDischargeRate.Value / _voltage.Value;
|
||||
ChargeDischargeCurrent = (_chargeDischargeRate.Value / _voltage.Value).GetValueOrDefault();
|
||||
|
||||
break;
|
||||
default:
|
||||
_chargeDischargeRate.Name = "Charge/Discharge Rate";
|
||||
_chargeDischargeRate.Value = 0f;
|
||||
ChargeDischargeRate = 0f;
|
||||
|
||||
_chargeDischargeCurrent.Name = "Charge/Discharge Current";
|
||||
_chargeDischargeCurrent.Value = 0f;
|
||||
ChargeDischargeCurrent = 0f;
|
||||
|
||||
break;
|
||||
ChargeDischargeRate = null;
|
||||
_chargeDischargeRate.Value = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
float rateWatts = batteryStatus.Rate / 1000f;
|
||||
ChargeDischargeRate = rateWatts;
|
||||
_chargeDischargeRate.Value = Math.Abs(rateWatts);
|
||||
|
||||
_degradationPercentage.Value = 100f - (_fullChargedCapacity.Value * 100f / _designedCapacity.Value);
|
||||
float? current = rateWatts / _voltage.Value;
|
||||
ChargeDischargeCurrent = current;
|
||||
if (current is not null)
|
||||
_chargeDischargeCurrent.Value = Math.Abs(current.Value);
|
||||
else
|
||||
_chargeDischargeCurrent.Value = null;
|
||||
|
||||
if (rateWatts > 0)
|
||||
{
|
||||
_chargeDischargeRate.Name = "Charge Rate";
|
||||
_chargeDischargeCurrent.Name = "Charge Current";
|
||||
}
|
||||
else if (rateWatts < 0)
|
||||
{
|
||||
_chargeDischargeRate.Name = "Discharge Rate";
|
||||
_chargeDischargeCurrent.Name = "Discharge Current";
|
||||
}
|
||||
else
|
||||
{
|
||||
_chargeDischargeRate.Name = "Charge/Discharge Rate";
|
||||
_chargeDischargeCurrent.Name = "Charge/Discharge Current";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint estimatedRunTime = 0;
|
||||
@@ -204,17 +211,41 @@ internal sealed class Battery : Hardware
|
||||
out _,
|
||||
IntPtr.Zero))
|
||||
{
|
||||
RemainingTime = estimatedRunTime;
|
||||
if (estimatedRunTime != Kernel32.BATTERY_UNKNOWN_TIME)
|
||||
{
|
||||
ActivateSensor(_remainingTime);
|
||||
_remainingTime.Value = estimatedRunTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
DeactivateSensor(_remainingTime);
|
||||
}
|
||||
_remainingTime.Value = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_remainingTime.Value = null;
|
||||
}
|
||||
|
||||
uint temperature = 0;
|
||||
bqi.InformationLevel = Kernel32.BATTERY_QUERY_INFORMATION_LEVEL.BatteryTemperature;
|
||||
if (Kernel32.DeviceIoControl(_batteryHandle,
|
||||
Kernel32.IOCTL.IOCTL_BATTERY_QUERY_INFORMATION,
|
||||
ref bqi,
|
||||
Marshal.SizeOf(bqi),
|
||||
ref temperature,
|
||||
Marshal.SizeOf<uint>(),
|
||||
out _,
|
||||
IntPtr.Zero))
|
||||
{
|
||||
_temperature.Value = (temperature / 10f) - 273.15f;
|
||||
}
|
||||
else
|
||||
{
|
||||
_temperature.Value = null;
|
||||
}
|
||||
|
||||
ActivateSensorIfValueNotNull(_remainingCapacity);
|
||||
ActivateSensorIfValueNotNull(_chargeLevel);
|
||||
ActivateSensorIfValueNotNull(_voltage);
|
||||
ActivateSensorIfValueNotNull(_chargeDischargeCurrent);
|
||||
ActivateSensorIfValueNotNull(_chargeDischargeRate);
|
||||
ActivateSensorIfValueNotNull(_remainingTime);
|
||||
ActivateSensorIfValueNotNull(_temperature);
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
|
||||
@@ -17,6 +17,35 @@ internal class BatteryGroup : IGroup
|
||||
{
|
||||
private readonly List<Battery> _hardware = new();
|
||||
|
||||
static bool QueryStringFromBatteryInfo(SafeFileHandle battery, Kernel32.BATTERY_QUERY_INFORMATION bqi, out string value)
|
||||
{
|
||||
const int maxLoadString = 100;
|
||||
|
||||
value = null;
|
||||
|
||||
bool result = false;
|
||||
IntPtr ptrString = Marshal.AllocHGlobal(maxLoadString);
|
||||
if (Kernel32.DeviceIoControl(battery,
|
||||
Kernel32.IOCTL.IOCTL_BATTERY_QUERY_INFORMATION,
|
||||
ref bqi,
|
||||
Marshal.SizeOf(bqi),
|
||||
ptrString,
|
||||
maxLoadString,
|
||||
out uint stringSizeBytes,
|
||||
IntPtr.Zero))
|
||||
{
|
||||
// Use the value stored in stringSizeBytes to avoid relying on a
|
||||
// terminator char.
|
||||
// See https://github.com/LibreHardwareMonitor/LibreHardwareMonitor/pull/1158#issuecomment-1979559929
|
||||
int stringSizeChars = (int)stringSizeBytes / 2;
|
||||
value = Marshal.PtrToStringUni(ptrString, stringSizeChars);
|
||||
result = true;
|
||||
}
|
||||
|
||||
Marshal.FreeHGlobal(ptrString);
|
||||
return result;
|
||||
}
|
||||
|
||||
public unsafe BatteryGroup(ISettings settings)
|
||||
{
|
||||
// No implementation for battery information on Unix systems
|
||||
@@ -93,42 +122,12 @@ internal class BatteryGroup : IGroup
|
||||
// Only batteries count.
|
||||
if (bi.Capabilities.HasFlag(Kernel32.BatteryCapabilities.BATTERY_SYSTEM_BATTERY))
|
||||
{
|
||||
const int maxLoadString = 100;
|
||||
|
||||
IntPtr ptrDevName = Marshal.AllocCoTaskMem(maxLoadString);
|
||||
bqi.InformationLevel = Kernel32.BATTERY_QUERY_INFORMATION_LEVEL.BatteryDeviceName;
|
||||
QueryStringFromBatteryInfo(battery, bqi, out string batteryName);
|
||||
bqi.InformationLevel = Kernel32.BATTERY_QUERY_INFORMATION_LEVEL.BatteryManufactureName;
|
||||
QueryStringFromBatteryInfo(battery, bqi, out string manufacturer);
|
||||
|
||||
if (Kernel32.DeviceIoControl(battery,
|
||||
Kernel32.IOCTL.IOCTL_BATTERY_QUERY_INFORMATION,
|
||||
ref bqi,
|
||||
Marshal.SizeOf(bqi),
|
||||
ptrDevName,
|
||||
maxLoadString,
|
||||
out _,
|
||||
IntPtr.Zero))
|
||||
{
|
||||
IntPtr ptrManName = Marshal.AllocCoTaskMem(maxLoadString);
|
||||
bqi.InformationLevel = Kernel32.BATTERY_QUERY_INFORMATION_LEVEL.BatteryManufactureName;
|
||||
|
||||
if (Kernel32.DeviceIoControl(battery,
|
||||
Kernel32.IOCTL.IOCTL_BATTERY_QUERY_INFORMATION,
|
||||
ref bqi,
|
||||
Marshal.SizeOf(bqi),
|
||||
ptrManName,
|
||||
maxLoadString,
|
||||
out _,
|
||||
IntPtr.Zero))
|
||||
{
|
||||
string name = Marshal.PtrToStringUni(ptrDevName);
|
||||
string manufacturer = Marshal.PtrToStringUni(ptrManName);
|
||||
|
||||
_hardware.Add(new Battery(name, manufacturer, battery, bi, bqi.BatteryTag, settings));
|
||||
}
|
||||
|
||||
Marshal.FreeCoTaskMem(ptrManName);
|
||||
}
|
||||
|
||||
Marshal.FreeCoTaskMem(ptrDevName);
|
||||
_hardware.Add(new Battery(batteryName, manufacturer, battery, bi, bqi.BatteryTag, settings));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -177,37 +176,55 @@ internal class BatteryGroup : IGroup
|
||||
reportBuilder.Append("Battery #").Append(count).AppendLine(":")
|
||||
.Append(" Name: ").AppendLine(bat.Name)
|
||||
.Append(" Manufacturer: ").AppendLine(bat.Manufacturer)
|
||||
.Append(" Chemistry: ").AppendLine(chemistry)
|
||||
.Append(" Degradation Level: ").AppendFormat("{0:F2}", bat.DegradationLevel).AppendLine(" %")
|
||||
.Append(" Designed Capacity: ").Append(bat.DesignedCapacity).AppendLine(" mWh")
|
||||
.Append(" Full Charged Capacity: ").Append(bat.FullChargedCapacity).AppendLine(" mWh")
|
||||
.Append(" Remaining Capacity: ").Append(bat.RemainingCapacity).AppendLine(" mWh")
|
||||
.Append(" Charge Level: ").AppendFormat("{0:F2}", bat.RemainingCapacity * 100f / bat.FullChargedCapacity).AppendLine(" %")
|
||||
.Append(" Voltage: ").AppendFormat("{0:F3}", bat.Voltage).AppendLine(" V");
|
||||
.Append(" Chemistry: ").AppendLine(chemistry);
|
||||
|
||||
if (bat.RemainingTime != Kernel32.BATTERY_UNKNOWN_TIME)
|
||||
if (bat.DegradationLevel.HasValue)
|
||||
reportBuilder.Append(" Degradation Level: ").AppendFormat("{0:F2}", bat.DegradationLevel).AppendLine(" %");
|
||||
|
||||
if (bat.DesignedCapacity.HasValue)
|
||||
reportBuilder.Append(" Designed Capacity: ").Append(bat.DesignedCapacity).AppendLine(" mWh");
|
||||
|
||||
if (bat.FullChargedCapacity.HasValue)
|
||||
reportBuilder.Append(" Fully-Charged Capacity: ").Append(bat.FullChargedCapacity).AppendLine(" mWh");
|
||||
|
||||
if (bat.RemainingCapacity.HasValue)
|
||||
reportBuilder.Append(" Remaining Capacity: ").Append(bat.RemainingCapacity).AppendLine(" mWh");
|
||||
|
||||
if (bat.ChargeLevel.HasValue)
|
||||
reportBuilder.Append(" Charge Level: ").AppendFormat("{0:F2}", bat.ChargeLevel).AppendLine(" %");
|
||||
|
||||
if (bat.Voltage.HasValue)
|
||||
reportBuilder.Append(" Voltage: ").AppendFormat("{0:F3}", bat.Voltage).AppendLine(" V");
|
||||
|
||||
if (bat.Temperature.HasValue)
|
||||
reportBuilder.Append(" Temperature: ").AppendFormat("{0:F3}", bat.Temperature).AppendLine(" ºC");
|
||||
|
||||
if (bat.RemainingTime.HasValue)
|
||||
reportBuilder.Append(" Remaining Time (Estimated): ").AppendFormat("{0:g}", TimeSpan.FromSeconds(bat.RemainingTime.Value)).AppendLine();
|
||||
|
||||
string cdRateSensorName;
|
||||
string cdCurrentSensorName;
|
||||
if (bat.ChargeDischargeRate > 0)
|
||||
{
|
||||
reportBuilder.Append(" Remaining Time (Estimated): ").AppendFormat("{0:g}", TimeSpan.FromSeconds(bat.RemainingTime)).AppendLine();
|
||||
cdRateSensorName = " Charge Rate: ";
|
||||
cdCurrentSensorName = " Charge Current: ";
|
||||
}
|
||||
else if (bat.ChargeDischargeRate < 0)
|
||||
{
|
||||
cdRateSensorName = " Discharge Rate: ";
|
||||
cdCurrentSensorName = " Discharge Current: ";
|
||||
}
|
||||
else
|
||||
{
|
||||
cdRateSensorName = " Charge/Discharge Rate: ";
|
||||
cdCurrentSensorName = " Charge/Discharge Current: ";
|
||||
}
|
||||
|
||||
switch (bat.ChargeDischargeRate)
|
||||
{
|
||||
case > 0:
|
||||
reportBuilder.Append(" Charge Rate: ").AppendFormat("{0:F1}", bat.ChargeDischargeRate).AppendLine(" W")
|
||||
.Append(" Charge Current: ").AppendFormat("{0:F3}", bat.ChargeDischargeRate / bat.Voltage).AppendLine(" A");
|
||||
if (bat.ChargeDischargeRate.HasValue)
|
||||
reportBuilder.Append(cdRateSensorName).AppendFormat("{0:F1}", Math.Abs(bat.ChargeDischargeRate.Value)).AppendLine(" W");
|
||||
|
||||
break;
|
||||
case < 0:
|
||||
reportBuilder.Append(" Discharge Rate: ").AppendFormat("{0:F1}", Math.Abs(bat.ChargeDischargeRate)).AppendLine(" W")
|
||||
.Append(" Discharge Current: ").AppendFormat("{0:F3}", Math.Abs(bat.ChargeDischargeRate) / bat.Voltage).AppendLine(" A");
|
||||
|
||||
break;
|
||||
default:
|
||||
reportBuilder.AppendLine(" Charge/Discharge Rate: 0 W")
|
||||
.AppendLine(" Charge/Discharge Current: 0 A");
|
||||
|
||||
break;
|
||||
}
|
||||
if (bat.ChargeDischargeCurrent.HasValue)
|
||||
reportBuilder.Append(cdCurrentSensorName).AppendFormat("{0:F3}", Math.Abs(bat.ChargeDischargeCurrent.Value)).AppendLine(" A");
|
||||
|
||||
reportBuilder.AppendLine();
|
||||
count++;
|
||||
|
||||
@@ -18,7 +18,11 @@ public class Kernel32
|
||||
|
||||
public const int ERROR_SERVICE_EXISTS = unchecked((int)0x80070431);
|
||||
|
||||
internal const uint BATTERY_UNKNOWN_CAPACITY = 0xFFFFFFFF;
|
||||
internal const uint BATTERY_UNKNOWN_VOLTAGE = 0xFFFFFFFF;
|
||||
internal const int BATTERY_UNKNOWN_RATE = unchecked((int)0x80000000);
|
||||
internal const uint BATTERY_UNKNOWN_TIME = 0xFFFFFFFF;
|
||||
|
||||
internal const string IntelNVMeMiniPortSignature1 = "NvmeMini";
|
||||
internal const string IntelNVMeMiniPortSignature2 = "IntelNvm";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user