Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Build/Build.csproj.DotSettings
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=HeapView_002EDelegateAllocation/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=VariableHidesOuterVariable/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ClassNeverInstantiated_002EGlobal/@EntryIndexedValue">DO_NOT_SHOW</s:String>
Expand All @@ -20,6 +20,7 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net48</TargetFramework>
<AssemblyTitle>TTController.Plugin.ToughfanController</AssemblyTitle>
<Product>TTController.Plugin.ToughfanController</Product>
<Copyright>Copyright © 2023</Copyright>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Source\TTController.Common\TTController.Common.csproj" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using TTController.Common.Plugin;

namespace TTController.Plugin.ToughfanController
{
public class ToughfanControllerDefinition : IControllerDefinition
{
public string Name => "Toughfan";

public int VendorId => 0x264a;

public IEnumerable<int> ProductIds => Enumerable.Range(0, 16).Select(x => 0x232b + x);
public int PortCount => 5;
public Type ControllerProxyType => typeof(ToughfanControllerProxy);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
using System;
using System.Collections.Generic;
using System.Linq;
using TTController.Common;
using TTController.Common.Plugin;

namespace TTController.Plugin.ToughfanController
{
public class ToughfanControllerProxy : AbstractControllerProxy
{
private readonly IReadOnlyDictionary<string, byte> _availableEffects;

public ToughfanControllerProxy(IHidDeviceProxy device, IControllerDefinition definition)
: base(device, definition)
{
var effectModes = new Dictionary<string, byte>()
{
["Flow"] = 0x00,
["Spectrum"] = 0x04,
["Ripple"] = 0x08,
["Blink"] = 0x0c,
["Pulse"] = 0x10,
["Wave"] = 0x14,
};

var effectSpeeds = new Dictionary<string, byte>()
{
["Extreme"] = 0x00,
["Fast"] = 0x01,
["Normal"] = 0x02,
["Slow"] = 0x03
};

var result = new Dictionary<string, byte>();
foreach (var mkv in effectModes)
foreach (var skv in effectSpeeds)
result.Add($"{mkv.Key}_{skv.Key}", (byte)(mkv.Value + skv.Value));

result.Add("PerLed", 0x18);
result.Add("Full", 0x19);

_availableEffects = result;
}

public override Version Version
{
get
{
var bytes = Device.WriteReadBytes(0x33, 0x50);
if (bytes == null)
return new Version();

return new Version(bytes[3], bytes[4], bytes[5]);
}
}

public override IEnumerable<PortIdentifier> Ports => Enumerable.Range(1, Definition.PortCount)
.Select(x => new PortIdentifier(Device.VendorId, Device.ProductId, (byte)x));

public override IEnumerable<string> EffectTypes => _availableEffects.Keys;

public override bool SetRgb(byte port, string effectType, IEnumerable<LedColor> colors)
{
if (!_availableEffects.TryGetValue(effectType, out var mode))
return false;

var bytes = new List<byte> { 0x32, 0x52, port, 0x24 };
var color = colors.First();
for (int i = 0; i < 24; i++)
{
bytes.Add(color.G);
bytes.Add(color.R);
bytes.Add(color.B);
}

// var bytes = new byte[]
// {
// 0x32, 0x52, port, 0x24,
// 0x00, 0x00, 0xff, // 1
// 0x00, 0x00, 0xff, // 2
// 0x00, 0x00, 0xff, // 3
// 0x00, 0x00, 0xff, // 4
// 0x00, 0x00, 0xff, // 5
// 0x00, 0x00, 0xff, // 6
// 0x00, 0x00, 0xff, // 7
// 0x00, 0x00, 0xff, // 8
// 0x00, 0x00, 0xff, // 9
// 0x00, 0x00, 0xff, // 10
// 0x00, 0x00, 0xff, // 11
// 0x00, 0x00, 0xff, // 12
// 0x00, 0x00, 0xff, // 13
// 0x00, 0x00, 0xff, // 14
// 0x00, 0x00, 0xff, // 15
// 0x00, 0x00, 0xff, // 16
// 0x00, 0x00, 0xff, // 17
// 0x00, 0x00, 0xff, // 18
// 0x00, 0x00, 0xff, // 19
// 0x00, 0x00, 0xff, // 20
// 0x00, 0x00, 0xff, // 21
// 0x00, 0x00, 0xff, // 22
// 0x00, 0x00, 0xff, // 23
// 0x00, 0x00, 0xff, // 24
var endBytes = new byte[]
{
0x7f, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x7f, 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00, 0xff, 0xff,
0x00, 0x7f, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00, 0xff, 0xff, 0x00, 0x7f, 0xff, 0x00,
0x00, 0xff, 0x7f, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x7f, 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00,
0xff, 0xff, 0x00, 0x7f, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00, 0xff, 0xff, 0x00, 0x7f,
0xff, 0x00, 0x00, 0xff, 0x7f, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x7f, 0xff, 0x00, 0x00, 0xff,
0x7f, 0x00, 0xff, 0xff, 0x00, 0x7f, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00, 0xff, 0xff,
0x00, 0x7f, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
bytes.AddRange(endBytes);
var result = Device.WriteReadBytes(bytes);
return result?[3] == 0xfc;
}

public override bool SetSpeed(byte port, byte speed) =>
Device.WriteReadBytes(0x32, 0x51, port, 0x01, speed)?[3] == 0xfc;

public override PortData GetPortData(byte port)
{
var result = Device.WriteReadBytes(0x33, 0x51, port);
if (result == null)
return null;

if (result[3] == 0xfe)
return null;

var data = new PortData
{
PortId = result[3],
Speed = result[5],
Rpm = (result[7] << 8) + result[6],
["Unknown"] = result[4]
};

return data;
}

public override void SaveProfile() =>
Device.WriteReadBytes(0x32, 0x53);

public override bool Init() =>
Device.WriteReadBytes(0xfe, 0x33)?[3] == 0xfc;

public override bool IsValidPort(PortIdentifier port) =>
port.ControllerProductId == Device.ProductId
&& port.ControllerVendorId == Device.VendorId
&& port.Id >= 1
&& port.Id <= Definition.PortCount;
}
}
5 changes: 5 additions & 0 deletions Plugins/Devices/Toughfan.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"Name": "Toughfan",
"LedCount": 24,
"Zones": [ 24 ]
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ public override IDictionary<PortIdentifier, List<LedColor>> GenerateColors(List<
colors.AddRange(GenerateColors(12, portStart, portEnd));
colors.AddRange(GenerateColors(6, portStart, portEnd, radius: 0.33, oddDivide: false));
break;
case "Toughfan":
colors.AddRange(GenerateColors(12, portStart, portEnd));
colors.AddRange(colors.ToList());
colors.AddRange(GenerateColors(6, portStart, portEnd, radius: 0.33, oddDivide: false));
break;
case "PurePlus":
colors.AddRange(GenerateColors(9, portStart, portEnd, radius: 0.33));
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Drawing;

namespace TTController.Plugin.StaticColorEffect2
{
public struct CurvePoint
{
public int Value { get; }
public byte Red { get; }
public byte Green { get; }
public byte Blue { get; }

public CurvePoint(int value, byte red, byte green, byte blue)
{
Value = value;
Red = red;
Green = green;
Blue = blue;
}

public override string ToString() => $"[Value: {Value}, Color: ({Red}, {Green}, {Blue})]";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace TTController.Plugin.StaticColorEffect2
{
public class CurvePointConverter : JsonConverter<CurvePoint>
{
public override void WriteJson(JsonWriter writer, CurvePoint value, JsonSerializer serializer)
{
var array = new JArray { value.Value, value.Red, value.Green, value.Blue };
writer.WriteRawValue(JsonConvert.SerializeObject(array, Formatting.None));
}

public override CurvePoint ReadJson(JsonReader reader, Type objectType, CurvePoint existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var array = JArray.Load(reader);
return new CurvePoint(array[0].Value<int>(), array[1].Value<byte>(), array[2].Value<byte>(), array[3].Value<byte>());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using LibreHardwareMonitor.Hardware;
using TTController.Common;
using TTController.Common.Plugin;

namespace TTController.Plugin.StaticColorEffect2
{
public class StaticColorEffect2Config : EffectConfigBase
{
public List<CurvePoint> CurvePoints { get; internal set; } = new List<CurvePoint>();
public List<Identifier> Sensors { get; internal set; } = new List<Identifier>();

[DefaultValue(SensorMixFunction.Maximum)]
public SensorMixFunction SensorMixFunction { get; internal set; } = SensorMixFunction.Maximum;

[DefaultValue(4)] public int MinimumChange { get; internal set; } = 4;
[DefaultValue(8)] public int MaximumChange { get; internal set; } = 8;
}

public class StaticColorEffect2 : EffectBase<StaticColorEffect2Config>
{
public StaticColorEffect2(StaticColorEffect2Config config) : base(config)
{
}

public override string EffectType => "PerLed";

private Color InterpolateColor(double temperature)
{
var curvePoints = Config.CurvePoints.OrderBy(p => p.Value).ToArray();
var n = curvePoints.Length;

if (temperature <= curvePoints[0].Value)
{
return CreateColorFromCurvePoint(curvePoints[0]);
}

if (temperature >= curvePoints[n - 1].Value)
{
return CreateColorFromCurvePoint(curvePoints[n - 1]);
}

for (var i = 0; i < n - 1; i++)
{
if (IsInRange(temperature, curvePoints[i].Value, curvePoints[i + 1].Value))
{
var t = CalculateInterpolationParameter(temperature, curvePoints[i].Value,
curvePoints[i + 1].Value);

var r = InterpolateLinear(curvePoints[i].Red, curvePoints[i + 1].Red, t);
var g = InterpolateLinear(curvePoints[i].Green, curvePoints[i + 1].Green, t);
var b = InterpolateLinear(curvePoints[i].Blue, curvePoints[i + 1].Blue, t);

return CreateColorFromRgbValues(r, g, b);
}
}

return Color.White; // Handle cases outside the defined range
}

private Color CreateColorFromCurvePoint(CurvePoint curvePoint)
{
return Color.FromArgb(curvePoint.Red, curvePoint.Green, curvePoint.Blue);
}

private bool IsInRange(double value, int minValue, int maxValue)
{
return value >= minValue && value <= maxValue;
}

private double CalculateInterpolationParameter(double value, int minValue, int maxValue)
{
return (double)(value - minValue) / (maxValue - minValue);
}

private double InterpolateLinear(int startValue, int endValue, double t)
{
return startValue + t * (endValue - startValue);
}

private Color CreateColorFromRgbValues(double r, double g, double b)
{
return Color.FromArgb(Clamp((int)r, 0, 255), Clamp((int)g, 0, 255), Clamp((int)b, 0, 255));
}

private int Clamp(int value, int min, int max)
{
if (value < min)
return min;
if (value > max)
return max;
return value;
}

public override IDictionary<PortIdentifier, List<LedColor>> GenerateColors(List<PortIdentifier> ports,
ICacheProvider cache)
{
var values = Config.Sensors.Select(cache.GetSensorValue);
var value = float.NaN;
if (Config.SensorMixFunction == SensorMixFunction.Average)
value = values.Average();
else if (Config.SensorMixFunction == SensorMixFunction.Minimum)
value = values.Min();
else if (Config.SensorMixFunction == SensorMixFunction.Maximum)
value = values.Max();

if (float.IsNaN(value))
return ports.ToDictionary(p => p, _ => new List<LedColor> { new LedColor(255, 255, 255) });

var curveTargetColor = InterpolateColor(value);

return ports.ToDictionary(p => p, _ => new List<LedColor>
{ new LedColor(curveTargetColor.R, curveTargetColor.G, curveTargetColor.B) }
);
}


public override List<LedColor> GenerateColors(int count, ICacheProvider cache)
{
return null;
}
}
}
Loading