Improve support for NZXT Kraken V3 devices and merge KrakenX and KrakenZ hardware support (#1078)
* Improve support for NZXT Kraken V3 devices and merge KrakenX and KrakenZ hardware support * add support for new kraken elite 2023 * Add support for kraken 2023 (non-elite) * removed ContinuousRead as it's too eager and conflicted with other application connecting to the device (to manage lcd or leds for example) * handle ObjectDisposedException and cleanup code * Update KrakenV3.cs --------- Co-authored-by: PhyxionNL <7643972+PhyxionNL@users.noreply.github.com>
This commit is contained in:
co-authored by
PhyxionNL
parent
6066b1a797
commit
132d83ed22
@@ -0,0 +1,248 @@
|
||||
using System;
|
||||
using HidSharp;
|
||||
|
||||
namespace LibreHardwareMonitor.Hardware.Controller.Nzxt;
|
||||
|
||||
/**
|
||||
* Support for the KrakenZ devices from NZXT
|
||||
*/
|
||||
internal sealed class KrakenV3 : Hardware
|
||||
{
|
||||
private static readonly byte[] _getFirmwareInfo = { 0x10, 0x01 };
|
||||
private static readonly byte[] _setPumpSpeedHeader = { 0x72, 0x01, 0x00, 0x00 };
|
||||
private static readonly byte[] _setFanSpeedHeader = { 0x72, 0x02, 0x00, 0x00 };
|
||||
private static readonly byte[] _status_req = { 0x74, 0x01 };
|
||||
private static readonly byte[] _setPumpTarget = new byte[64];
|
||||
private static readonly byte[] _setFanTarget = new byte[64];
|
||||
|
||||
private readonly Sensor _pump;
|
||||
private readonly Sensor _pumpRpm;
|
||||
private readonly Sensor _fan;
|
||||
private readonly Sensor _fanRpm;
|
||||
private readonly byte[] _rawData = new byte[64];
|
||||
private readonly HidStream _stream;
|
||||
private readonly Sensor _temperature;
|
||||
private readonly bool _fanControl;
|
||||
private readonly string _supportedFirmware;
|
||||
private volatile bool _controllingFans;
|
||||
private volatile bool _controllingPump;
|
||||
|
||||
private static void FillTargetArray(byte[] targetArray, byte value)
|
||||
{
|
||||
for (byte i = 4; i < targetArray.Length; i++)
|
||||
targetArray[i] = value;
|
||||
}
|
||||
|
||||
static KrakenV3()
|
||||
{
|
||||
// Init pump control target array
|
||||
Array.Copy(_setPumpSpeedHeader, 0, _setPumpTarget, 0, 4);
|
||||
// Fill target array with a pump duty of 60%
|
||||
FillTargetArray(_setPumpTarget, 60);
|
||||
|
||||
// Init fan control target array
|
||||
Array.Copy(_setFanSpeedHeader, 0, _setFanTarget, 0, 4);
|
||||
// Fill target array with a fan duty of 40%
|
||||
FillTargetArray(_setFanTarget, 40);
|
||||
}
|
||||
|
||||
public KrakenV3(HidDevice dev, ISettings settings) : base("Nzxt Kraken Z", new Identifier("nzxt", "krakenz", dev.GetSerialNumber().TrimStart('0')), settings)
|
||||
{
|
||||
if (dev.ProductID == 0x3008)
|
||||
{
|
||||
Name = "NZXT Kraken Z3";
|
||||
_fanControl = true;
|
||||
_supportedFirmware = "5.7.0";
|
||||
|
||||
}
|
||||
else if (dev.ProductID == 0x300C)
|
||||
{
|
||||
Name = "NZXT Kraken Elite";
|
||||
_fanControl = true;
|
||||
_supportedFirmware = "1.2.4";
|
||||
}
|
||||
else if (dev.ProductID == 0x300E)
|
||||
{
|
||||
Name = "NZXT Kraken";
|
||||
_fanControl = true;
|
||||
_supportedFirmware = "1.2.4"; // Firmware version to be confirmed
|
||||
}
|
||||
else
|
||||
{
|
||||
Name = "NZXT Kraken X3";
|
||||
_fanControl = false;
|
||||
_supportedFirmware = "2.1.0";
|
||||
}
|
||||
|
||||
if (dev.TryOpen(out _stream))
|
||||
{
|
||||
_stream.ReadTimeout = 5000;
|
||||
|
||||
_stream.Write(_getFirmwareInfo);
|
||||
do
|
||||
{
|
||||
_stream.Read(_rawData);
|
||||
if (_rawData[0] == 0x11 && _rawData[1] == 0x01)
|
||||
{
|
||||
FirmwareVersion = $"{_rawData[0x11]}.{_rawData[0x12]}.{_rawData[0x13]}";
|
||||
}
|
||||
}
|
||||
while (FirmwareVersion == null);
|
||||
|
||||
// Liquid temperature
|
||||
_temperature = new Sensor("Liquid", 0, SensorType.Temperature, this, Array.Empty<ParameterDescription>(), settings);
|
||||
ActivateSensor(_temperature);
|
||||
|
||||
// Pump Control
|
||||
_pump = new Sensor("Pump Control", 0, SensorType.Control, this, Array.Empty<ParameterDescription>(), settings);
|
||||
Control pumpControl = new(_pump, settings, 20, 100);
|
||||
_pump.Control = pumpControl;
|
||||
pumpControl.ControlModeChanged += PumpSoftwareControlValueChanged;
|
||||
pumpControl.SoftwareControlValueChanged += PumpSoftwareControlValueChanged;
|
||||
PumpSoftwareControlValueChanged(pumpControl);
|
||||
ActivateSensor(_pump);
|
||||
|
||||
// Pump RPM
|
||||
_pumpRpm = new Sensor("Pump", 0, SensorType.Fan, this, Array.Empty<ParameterDescription>(), settings);
|
||||
ActivateSensor(_pumpRpm);
|
||||
|
||||
if (_fanControl)
|
||||
{
|
||||
// Fan Control
|
||||
_fan = new Sensor("Fans Control", 1, SensorType.Control, this, Array.Empty<ParameterDescription>(), settings);
|
||||
Control fanControl = new(_fan, settings, 20, 100);
|
||||
_fan.Control = fanControl;
|
||||
fanControl.ControlModeChanged += FanSoftwareControlValueChanged;
|
||||
fanControl.SoftwareControlValueChanged += FanSoftwareControlValueChanged;
|
||||
FanSoftwareControlValueChanged(fanControl);
|
||||
ActivateSensor(_fan);
|
||||
|
||||
// Fan RPM
|
||||
_fanRpm = new Sensor("Fans", 1, SensorType.Fan, this, Array.Empty<ParameterDescription>(), settings);
|
||||
ActivateSensor(_fanRpm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string FirmwareVersion { get; }
|
||||
|
||||
public override HardwareType HardwareType => HardwareType.Cooler;
|
||||
|
||||
public string Status => FirmwareVersion != _supportedFirmware ? $"Status: Untested Firmware Version {FirmwareVersion}! Please consider Updating to Version {_supportedFirmware}" : "Status: OK";
|
||||
|
||||
private void PumpSoftwareControlValueChanged(Control control)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (control.ControlMode == ControlMode.Software)
|
||||
{
|
||||
float value = control.SoftwareValue;
|
||||
|
||||
FillTargetArray(_setPumpTarget, (byte)(value > 100 ? 100 : value < 0 ? 0 : value));
|
||||
|
||||
_controllingPump = true;
|
||||
_stream.Write(_setPumpTarget);
|
||||
_pump.Value = value;
|
||||
}
|
||||
else if (control.ControlMode == ControlMode.Default)
|
||||
{
|
||||
// There isn't a "default" mode with this pump, but a safe setting is 60%
|
||||
FillTargetArray(_setPumpTarget, 60);
|
||||
_stream.Write(_setPumpTarget);
|
||||
}
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// Could be unplugged, or the app is stopping...
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void FanSoftwareControlValueChanged(Control control)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (control.ControlMode == ControlMode.Software)
|
||||
{
|
||||
float value = control.SoftwareValue;
|
||||
FillTargetArray(_setFanTarget, (byte)(value > 100 ? 100 : value < 0 ? 0 : value));
|
||||
|
||||
_controllingFans = true;
|
||||
_stream.Write(_setFanTarget);
|
||||
_fan.Value = value;
|
||||
}
|
||||
else if (control.ControlMode == ControlMode.Default)
|
||||
{
|
||||
// There isn't a "default" mode with this fan, but a safe setting is 40%
|
||||
FillTargetArray(_setFanTarget, 40);
|
||||
_stream.Write(_setFanTarget);
|
||||
}
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// Could be unplugged, or the app is stopping...
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
base.Close();
|
||||
_stream?.Close();
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
try
|
||||
{
|
||||
_stream.Write(_status_req);
|
||||
do
|
||||
{
|
||||
_stream.Read(_rawData);
|
||||
} while (_rawData[0] != 0x75 || _rawData[1] != 0x1);
|
||||
|
||||
_temperature.Value = _rawData[15] + (_rawData[16] / 10.0f);
|
||||
_pumpRpm.Value = (_rawData[18] << 8) | _rawData[17];
|
||||
|
||||
// The following logic makes sure the pump is set to the controlling value. This pump sometimes sets itself to 0% when instructed to a value.
|
||||
if (!_controllingPump)
|
||||
{
|
||||
_pump.Value = _rawData[19];
|
||||
}
|
||||
else if (_pump.Value != _rawData[19])
|
||||
{
|
||||
float value = _pump.Value.GetValueOrDefault();
|
||||
FillTargetArray(_setPumpTarget, (byte)value);
|
||||
_stream.Write(_setPumpTarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
_controllingPump = false;
|
||||
}
|
||||
|
||||
if (_fanControl)
|
||||
{
|
||||
_fanRpm.Value = (_rawData[24] << 8) | _rawData[23];
|
||||
if (!_controllingFans)
|
||||
{
|
||||
_fan.Value = _rawData[25];
|
||||
}
|
||||
else if (_fan.Value != _rawData[25])
|
||||
{
|
||||
float value = _fan.Value.GetValueOrDefault();
|
||||
FillTargetArray(_setFanTarget, (byte)value);
|
||||
_stream.Write(_setFanTarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
_controllingFans = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// Could be unplugged, or the app is stopping...
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
// 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.
|
||||
// All Rights Reserved.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using HidSharp;
|
||||
|
||||
namespace LibreHardwareMonitor.Hardware.Controller.Nzxt;
|
||||
|
||||
/**
|
||||
* Support for the Kraken X3 devices from NZXT
|
||||
*/
|
||||
internal sealed class KrakenX3 : Hardware
|
||||
{
|
||||
// Some fixed messages to send to the pump for basic monitoring and control
|
||||
private static readonly byte[] _getFirmwareInfo = { 0x10, 0x01 };
|
||||
private static readonly byte[] _initialize1 = { 0x70, 0x02, 0x01, 0xb8, 0x0b };
|
||||
private static readonly byte[] _initialize2 = { 0x70, 0x01 };
|
||||
private static readonly byte[][] _setPumpTargetMap = new byte[101][]; // Sacrifice memory to speed this up with a lookup instead of a copy operation
|
||||
|
||||
private readonly Sensor _pump;
|
||||
private readonly Sensor _pumpRpm;
|
||||
private readonly byte[] _rawData = new byte[64];
|
||||
private readonly HidStream _stream;
|
||||
private readonly Sensor _temperature;
|
||||
|
||||
private volatile bool _controlling;
|
||||
|
||||
static KrakenX3()
|
||||
{
|
||||
byte[] setPumpSpeedHeader = { 0x72, 0x01, 0x00, 0x00 };
|
||||
|
||||
for (byte speed = 0; speed < _setPumpTargetMap.Length; speed++)
|
||||
_setPumpTargetMap[speed] = setPumpSpeedHeader.Concat(Enumerable.Repeat(speed, 40).Concat(new byte[20])).ToArray();
|
||||
}
|
||||
|
||||
public KrakenX3(HidDevice dev, ISettings settings) : base("Nzxt Kraken X3", new Identifier("nzxt", "krakenx3", dev.GetSerialNumber().TrimStart('0')), settings)
|
||||
{
|
||||
if (dev.TryOpen(out _stream))
|
||||
{
|
||||
_stream.ReadTimeout = 5000; // The NZXT device returns with data that we need periodically without writing...
|
||||
_stream.Write(_initialize1);
|
||||
_stream.Write(_initialize2);
|
||||
|
||||
_stream.Write(_getFirmwareInfo);
|
||||
do
|
||||
{
|
||||
_stream.Read(_rawData);
|
||||
if (_rawData[0] == 0x11 && _rawData[1] == 0x01)
|
||||
{
|
||||
FirmwareVersion = $"{_rawData[0x11]}.{_rawData[0x12]}.{_rawData[0x13]}";
|
||||
}
|
||||
}
|
||||
while (FirmwareVersion == null);
|
||||
|
||||
Name = "Nzxt Kraken X3";
|
||||
|
||||
_pump = new Sensor("Pump Control", 0, SensorType.Control, this, Array.Empty<ParameterDescription>(), settings);
|
||||
Control pumpControl = new(_pump, settings, 0, 100);
|
||||
_pump.Control = pumpControl;
|
||||
pumpControl.ControlModeChanged += SoftwareControlValueChanged;
|
||||
pumpControl.SoftwareControlValueChanged += SoftwareControlValueChanged;
|
||||
SoftwareControlValueChanged(pumpControl);
|
||||
ActivateSensor(_pump);
|
||||
|
||||
_pumpRpm = new Sensor("Pump", 0, SensorType.Fan, this, Array.Empty<ParameterDescription>(), settings);
|
||||
ActivateSensor(_pumpRpm);
|
||||
|
||||
_temperature = new Sensor("Internal Water", 0, SensorType.Temperature, this, Array.Empty<ParameterDescription>(), settings);
|
||||
ActivateSensor(_temperature);
|
||||
|
||||
ThreadPool.UnsafeQueueUserWorkItem(ContinuousRead, _rawData);
|
||||
}
|
||||
}
|
||||
|
||||
public string FirmwareVersion { get; }
|
||||
|
||||
public override HardwareType HardwareType => HardwareType.Cooler;
|
||||
|
||||
public string Status => FirmwareVersion != "2.1.0" ? $"Status: Untested Firmware Version {FirmwareVersion}! Please consider Updating to Version 2.1.0" : "Status: OK";
|
||||
|
||||
private void SoftwareControlValueChanged(Control control)
|
||||
{
|
||||
if (control.ControlMode == ControlMode.Software)
|
||||
{
|
||||
float value = control.SoftwareValue;
|
||||
byte pumpSpeedIndex = (byte)(value > 100 ? 100 : value < 0 ? 0 : value); // Clamp the value, anything out of range will fail
|
||||
|
||||
_controlling = true;
|
||||
_stream.Write(_setPumpTargetMap[pumpSpeedIndex]);
|
||||
_pump.Value = value;
|
||||
}
|
||||
else if (control.ControlMode == ControlMode.Default)
|
||||
{
|
||||
// There isn't a "default" mode with this pump, but a safe setting is 40%
|
||||
_stream.Write(_setPumpTargetMap[40]);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
base.Close();
|
||||
_stream?.Close();
|
||||
}
|
||||
|
||||
private void ContinuousRead(object state)
|
||||
{
|
||||
byte[] buffer = new byte[_rawData.Length];
|
||||
while (_stream.CanRead)
|
||||
{
|
||||
try
|
||||
{
|
||||
_stream.Read(buffer); // This is a blocking call, will wait for bytes to become available
|
||||
|
||||
lock (_rawData)
|
||||
{
|
||||
Array.Copy(buffer, _rawData, buffer.Length);
|
||||
}
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
// Don't care, just make sure the stream is still open
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// Could be unplugged, or the app is stopping...
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
// The NZXT Kraken X3 series sends updates periodically. We have to read it in a seperate thread, this call just reads that data.
|
||||
lock (_rawData)
|
||||
{
|
||||
if (_rawData[0] == 0x75 && _rawData[1] == 0x02)
|
||||
{
|
||||
_temperature.Value = _rawData[15] + (_rawData[16] / 10.0f);
|
||||
_pumpRpm.Value = (_rawData[18] << 8) | _rawData[17];
|
||||
|
||||
// The following logic makes sure the pump is set to the controlling value. This pump sometimes sets itself to 0% when instructed to a value.
|
||||
if (!_controlling)
|
||||
{
|
||||
_pump.Value = _rawData[19];
|
||||
}
|
||||
else if (_pump.Value != _rawData[19])
|
||||
{
|
||||
float value = _pump.Value.GetValueOrDefault();
|
||||
byte pumpSpeedIndex = (byte)(value > 100 ? 100 : value < 0 ? 0 : value); // Clamp the value, anything out of range will fail
|
||||
_stream.Write(_setPumpTargetMap[pumpSpeedIndex]);
|
||||
}
|
||||
else
|
||||
{
|
||||
_controlling = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,218 +0,0 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using HidSharp;
|
||||
|
||||
namespace LibreHardwareMonitor.Hardware.Controller.Nzxt;
|
||||
|
||||
/**
|
||||
* Support for the KrakenZ devices from NZXT
|
||||
*/
|
||||
internal sealed class KrakenZ : Hardware
|
||||
{
|
||||
private static readonly byte[] _getFirmwareInfo = { 0x10, 0x01 };
|
||||
private static readonly byte[] _setPumpSpeedHeader = { 0x72, 0x01, 0x00, 0x00 };
|
||||
private static readonly byte[] _setFanSpeedHeader = { 0x72, 0x02, 0x00, 0x00 };
|
||||
private static readonly byte[] _status_req = { 0x74, 0x01 };
|
||||
private static readonly byte[] _setPumpTarget = new byte[64];
|
||||
private static readonly byte[] _setFanTarget = new byte[64];
|
||||
|
||||
private readonly Sensor _pump;
|
||||
private readonly Sensor _pumpRpm;
|
||||
private readonly Sensor _fan;
|
||||
private readonly Sensor _fanRpm;
|
||||
private readonly byte[] _rawData = new byte[64];
|
||||
private readonly HidStream _stream;
|
||||
private readonly Sensor _temperature;
|
||||
|
||||
private volatile bool _controlling;
|
||||
|
||||
private static void FillTargetArray(byte[] targetArray, byte value)
|
||||
{
|
||||
for (byte i = 4; i < targetArray.Length; i++)
|
||||
targetArray[i] = value;
|
||||
}
|
||||
|
||||
static KrakenZ()
|
||||
{
|
||||
// Init pump control target array
|
||||
Array.Copy(_setPumpSpeedHeader, 0, _setPumpTarget, 0, 4);
|
||||
// Fill target array with a pump duty of 60%
|
||||
FillTargetArray(_setPumpTarget, 60);
|
||||
|
||||
// Init fan control target array
|
||||
Array.Copy(_setFanSpeedHeader, 0, _setFanTarget, 0, 4);
|
||||
// Fill target array with a fan duty of 40%
|
||||
FillTargetArray(_setFanTarget, 40);
|
||||
}
|
||||
|
||||
public KrakenZ(HidDevice dev, ISettings settings) : base("Nzxt Kraken Z", new Identifier("nzxt", "krakenz", dev.GetSerialNumber().TrimStart('0')), settings)
|
||||
{
|
||||
if (dev.TryOpen(out _stream))
|
||||
{
|
||||
_stream.ReadTimeout = 5000;
|
||||
|
||||
_stream.Write(_getFirmwareInfo);
|
||||
do
|
||||
{
|
||||
_stream.Read(_rawData);
|
||||
if (_rawData[0] == 0x11 && _rawData[1] == 0x01)
|
||||
{
|
||||
FirmwareVersion = $"{_rawData[0x11]}.{_rawData[0x12]}.{_rawData[0x13]}";
|
||||
}
|
||||
}
|
||||
while (FirmwareVersion == null);
|
||||
|
||||
Name = "NZXT KrakenZ";
|
||||
|
||||
// Pump Control
|
||||
_pump = new Sensor("Pump Control", 0, SensorType.Control, this, Array.Empty<ParameterDescription>(), settings);
|
||||
Control pumpControl = new(_pump, settings, 20, 100);
|
||||
_pump.Control = pumpControl;
|
||||
pumpControl.ControlModeChanged += PumpSoftwareControlValueChanged;
|
||||
pumpControl.SoftwareControlValueChanged += PumpSoftwareControlValueChanged;
|
||||
PumpSoftwareControlValueChanged(pumpControl);
|
||||
ActivateSensor(_pump);
|
||||
|
||||
// Pump RPM
|
||||
_pumpRpm = new Sensor("Pump", 0, SensorType.Fan, this, Array.Empty<ParameterDescription>(), settings);
|
||||
ActivateSensor(_pumpRpm);
|
||||
|
||||
// Fan Control
|
||||
_fan = new Sensor("Fans Control", 1, SensorType.Control, this, Array.Empty<ParameterDescription>(), settings);
|
||||
Control fanControl = new(_fan, settings, 20, 100);
|
||||
_fan.Control = fanControl;
|
||||
fanControl.ControlModeChanged += FanSoftwareControlValueChanged;
|
||||
fanControl.SoftwareControlValueChanged += FanSoftwareControlValueChanged;
|
||||
FanSoftwareControlValueChanged(fanControl);
|
||||
ActivateSensor(_fan);
|
||||
|
||||
// Fan RPM
|
||||
_fanRpm = new Sensor("Fans", 1, SensorType.Fan, this, Array.Empty<ParameterDescription>(), settings);
|
||||
ActivateSensor(_fanRpm);
|
||||
|
||||
// Liquid temperature
|
||||
_temperature = new Sensor("Liquid", 0, SensorType.Temperature, this, Array.Empty<ParameterDescription>(), settings);
|
||||
ActivateSensor(_temperature);
|
||||
|
||||
ThreadPool.UnsafeQueueUserWorkItem(ContinuousRead, _rawData);
|
||||
}
|
||||
}
|
||||
|
||||
public string FirmwareVersion { get; }
|
||||
|
||||
public override HardwareType HardwareType => HardwareType.Cooler;
|
||||
|
||||
public string Status => FirmwareVersion != "5.7.0" ? $"Status: Untested Firmware Version {FirmwareVersion}! Please consider Updating to Version 5.7.0" : "Status: OK";
|
||||
|
||||
private void PumpSoftwareControlValueChanged(Control control)
|
||||
{
|
||||
if (control.ControlMode == ControlMode.Software)
|
||||
{
|
||||
float value = control.SoftwareValue;
|
||||
FillTargetArray(_setPumpTarget, (byte)value);
|
||||
|
||||
_controlling = true;
|
||||
_stream.Write(_setPumpTarget);
|
||||
_pump.Value = value;
|
||||
}
|
||||
else if (control.ControlMode == ControlMode.Default)
|
||||
{
|
||||
// There isn't a "default" mode with this pump, but a safe setting is 60%
|
||||
FillTargetArray(_setPumpTarget, 60);
|
||||
_stream.Write(_setPumpTarget);
|
||||
}
|
||||
}
|
||||
|
||||
private void FanSoftwareControlValueChanged(Control control)
|
||||
{
|
||||
if (control.ControlMode == ControlMode.Software)
|
||||
{
|
||||
float value = control.SoftwareValue;
|
||||
FillTargetArray(_setFanTarget, (byte)value);
|
||||
|
||||
_controlling = true;
|
||||
_stream.Write(_setFanTarget);
|
||||
_fan.Value = value;
|
||||
}
|
||||
else if (control.ControlMode == ControlMode.Default)
|
||||
{
|
||||
// There isn't a "default" mode with this fan, but a safe setting is 40%
|
||||
FillTargetArray(_setFanTarget, 40);
|
||||
_stream.Write(_setFanTarget);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
base.Close();
|
||||
_stream?.Close();
|
||||
}
|
||||
|
||||
private void ContinuousRead(object state)
|
||||
{
|
||||
byte[] buffer = new byte[_rawData.Length];
|
||||
while (_stream.CanRead)
|
||||
{
|
||||
try
|
||||
{
|
||||
_stream.Write(_status_req); // Request status
|
||||
_stream.Read(buffer); // This is a blocking call, will wait for bytes to become available
|
||||
|
||||
lock (_rawData)
|
||||
{
|
||||
Array.Copy(buffer, _rawData, buffer.Length);
|
||||
}
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
// Don't care, just make sure the stream is still open
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// Could be unplugged, or the app is stopping...
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
lock (_rawData)
|
||||
{
|
||||
if (_rawData[0] == 0x75 /*status response*/ && _rawData.Length >= 30)
|
||||
{
|
||||
_temperature.Value = _rawData[15] + (_rawData[16] / 10.0f);
|
||||
_pumpRpm.Value = (_rawData[18] << 8) | _rawData[17];
|
||||
_fanRpm.Value = (_rawData[24] << 8) | _rawData[23];
|
||||
|
||||
// The following logic makes sure the pump is set to the controlling value. This pump sometimes sets itself to 0% when instructed to a value.
|
||||
if (!_controlling)
|
||||
{
|
||||
_pump.Value = _rawData[19];
|
||||
_fan.Value = _rawData[25];
|
||||
}
|
||||
else if (_pump.Value != _rawData[19] || _fan.Value != _rawData[25])
|
||||
{
|
||||
if (_pump.Value != _rawData[19])
|
||||
{
|
||||
float value = _pump.Value.GetValueOrDefault();
|
||||
FillTargetArray(_setPumpTarget, (byte)value);
|
||||
_stream.Write(_setPumpTarget);
|
||||
}
|
||||
|
||||
if (_fan.Value != _rawData[25])
|
||||
{
|
||||
float value = _fan.Value.GetValueOrDefault();
|
||||
FillTargetArray(_setFanTarget, (byte)value);
|
||||
_stream.Write(_setFanTarget);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_controlling = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,14 +25,20 @@ internal class NzxtGroup : IGroup
|
||||
|
||||
switch (dev.ProductID)
|
||||
{
|
||||
case 0x2007:
|
||||
var device = new KrakenX3(dev, settings);
|
||||
case 0x2007: // Kraken X3 original pid
|
||||
case 0x2014: // Kraken X3 new pid
|
||||
case 0x3008: // Kraken Z3
|
||||
case 0x300C: // Kraken 2023 elite
|
||||
case 0x300E: // Kraken 2023 standard
|
||||
// NZXT KrakenV3 Devices
|
||||
var krakenV3 = new KrakenV3(dev, settings);
|
||||
_report.AppendLine($"Device name: {productName}");
|
||||
_report.AppendLine($"Firmware version: {device.FirmwareVersion}");
|
||||
_report.AppendLine($"{device.Status}");
|
||||
_report.AppendLine($"Firmware version: {krakenV3.FirmwareVersion}");
|
||||
_report.AppendLine($"{krakenV3.Status}");
|
||||
_report.AppendLine();
|
||||
_hardware.Add(device);
|
||||
_hardware.Add(krakenV3);
|
||||
break;
|
||||
|
||||
case 0x1711:
|
||||
var gridv3 = new GridV3(dev, settings);
|
||||
_report.AppendLine($"Device name: {productName}");
|
||||
@@ -40,14 +46,7 @@ internal class NzxtGroup : IGroup
|
||||
_report.AppendLine();
|
||||
_hardware.Add(gridv3);
|
||||
break;
|
||||
case 0x3008: // NZXT KrakenZ Device
|
||||
var krakenZ = new KrakenZ(dev, settings);
|
||||
_report.AppendLine($"Device name: {productName}");
|
||||
_report.AppendLine($"Firmware version: {krakenZ.FirmwareVersion}");
|
||||
_report.AppendLine($"{krakenZ.Status}");
|
||||
_report.AppendLine();
|
||||
_hardware.Add(krakenZ);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
_report.AppendLine($"Unknown Hardware PID: {dev.ProductID} Name: {productName}");
|
||||
|
||||
Reference in New Issue
Block a user