diff --git a/RGB.NET.Core/Devices/AbstractRGBDeviceProvider.cs b/RGB.NET.Core/Devices/AbstractRGBDeviceProvider.cs
index 7843edd..ae66ca0 100644
--- a/RGB.NET.Core/Devices/AbstractRGBDeviceProvider.cs
+++ b/RGB.NET.Core/Devices/AbstractRGBDeviceProvider.cs
@@ -42,7 +42,7 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
#endregion
#region Constructors
-
+
///
/// Initializes a new instance of the class.
///
@@ -157,7 +157,6 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
/// The newly created update trigger.
protected virtual IDeviceUpdateTrigger CreateUpdateTrigger(int id, double updateRateHardLimit) => new DeviceUpdateTrigger(updateRateHardLimit);
-
///
/// Resets the device provider and disposes all devices and update triggers.
///
diff --git a/RGB.NET.Core/Extensions/CustomUpdateDataExtension.cs b/RGB.NET.Core/Extensions/CustomUpdateDataExtension.cs
index 4c73e84..ff014a9 100644
--- a/RGB.NET.Core/Extensions/CustomUpdateDataExtension.cs
+++ b/RGB.NET.Core/Extensions/CustomUpdateDataExtension.cs
@@ -40,4 +40,16 @@ public static class CustomUpdateDataExtension
customUpdateData[CustomUpdateDataIndex.UPDATE_DEVICES] = value;
return customUpdateData;
}
+
+ ///
+ /// Sets the -Parameter to the given value.
+ ///
+ /// The update-data to modify.
+ /// The value to set.
+ /// The modified update-data.
+ public static CustomUpdateData Heartbeat(this CustomUpdateData customUpdateData, bool value = true)
+ {
+ customUpdateData[CustomUpdateDataIndex.HEARTBEAT] = value;
+ return customUpdateData;
+ }
}
\ No newline at end of file
diff --git a/RGB.NET.Core/Update/CustomUpdateData.cs b/RGB.NET.Core/Update/CustomUpdateData.cs
index a16011f..88f734a 100644
--- a/RGB.NET.Core/Update/CustomUpdateData.cs
+++ b/RGB.NET.Core/Update/CustomUpdateData.cs
@@ -24,6 +24,11 @@ public static class CustomUpdateDataIndex
/// default: true
///
public const string UPDATE_DEVICES = "updateDevices";
+
+ ///
+ /// Used by to indicate heatbeat updates.
+ ///
+ public const string HEARTBEAT = "heartbeat";
}
///
diff --git a/RGB.NET.Core/Update/Devices/DeviceUpdateTrigger.cs b/RGB.NET.Core/Update/Devices/DeviceUpdateTrigger.cs
index 6868a87..5d357b6 100644
--- a/RGB.NET.Core/Update/Devices/DeviceUpdateTrigger.cs
+++ b/RGB.NET.Core/Update/Devices/DeviceUpdateTrigger.cs
@@ -1,5 +1,6 @@
// ReSharper disable MemberCanBePrivate.Global
+using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
@@ -52,9 +53,20 @@ public class DeviceUpdateTrigger : AbstractUpdateTrigger, IDeviceUpdateTrigger
}
}
+ ///
+ /// Gets or sets the time in ms after which a refresh-request is sent even if no changes are made in the meantime to prevent the target from timing out or similar problems.
+ /// To disable heartbeats leave it at 0.
+ ///
+ public int HeartbeatTimer { get; set; }
+
///
public override double LastUpdateTime { get; protected set; }
+ ///
+ /// Gets or sets the timestamp of the last update.
+ ///
+ protected long LastUpdateTimestamp { get; set; }
+
///
/// Gets or sets the event to trigger when new data is available ().
///
@@ -145,6 +157,14 @@ public class DeviceUpdateTrigger : AbstractUpdateTrigger, IDeviceUpdateTrigger
while (!UpdateToken.IsCancellationRequested)
if (HasDataEvent.WaitOne(Timeout))
LastUpdateTime = TimerHelper.Execute(() => OnUpdate(), UpdateFrequency * 1000);
+ else if ((HeartbeatTimer > 0) && (LastUpdateTimestamp > 0) && (TimerHelper.GetElapsedTime(LastUpdateTimestamp) > HeartbeatTimer))
+ OnUpdate(new CustomUpdateData().Heartbeat());
+ }
+
+ protected override void OnUpdate(CustomUpdateData? updateData = null)
+ {
+ base.OnUpdate(updateData);
+ LastUpdateTimestamp = Stopwatch.GetTimestamp();
}
///
diff --git a/RGB.NET.Devices.DMX/DMXDeviceProvider.cs b/RGB.NET.Devices.DMX/DMXDeviceProvider.cs
index ee12196..55e8e3f 100644
--- a/RGB.NET.Devices.DMX/DMXDeviceProvider.cs
+++ b/RGB.NET.Devices.DMX/DMXDeviceProvider.cs
@@ -57,14 +57,15 @@ public class DMXDeviceProvider : AbstractRGBDeviceProvider
///
protected override IEnumerable LoadDevices()
{
- foreach (IDMXDeviceDefinition dmxDeviceDefinition in DeviceDefinitions)
+ for (int i = 0; i < DeviceDefinitions.Count; i++)
{
+ IDMXDeviceDefinition dmxDeviceDefinition = DeviceDefinitions[i];
IRGBDevice? device = null;
try
{
if (dmxDeviceDefinition is E131DMXDeviceDefinition e131DMXDeviceDefinition)
if (e131DMXDeviceDefinition.Leds.Count > 0)
- device = new E131Device(new E131DeviceInfo(e131DMXDeviceDefinition), e131DMXDeviceDefinition.Leds, GetUpdateTrigger(0));
+ device = new E131Device(new E131DeviceInfo(e131DMXDeviceDefinition), e131DMXDeviceDefinition.Leds, GetUpdateTrigger(i));
}
catch (Exception ex)
{
@@ -76,5 +77,14 @@ public class DMXDeviceProvider : AbstractRGBDeviceProvider
}
}
+ protected override IDeviceUpdateTrigger CreateUpdateTrigger(int id, double updateRateHardLimit)
+ {
+ DeviceUpdateTrigger updateTrigger = new(updateRateHardLimit);
+ if ((DeviceDefinitions[id] is E131DMXDeviceDefinition e131DMXDeviceDefinition))
+ updateTrigger.HeartbeatTimer = e131DMXDeviceDefinition.HeartbeatTimer;
+
+ return updateTrigger;
+ }
+
#endregion
}
\ No newline at end of file
diff --git a/RGB.NET.Devices.DMX/E131/E131DMXDeviceDefinition.cs b/RGB.NET.Devices.DMX/E131/E131DMXDeviceDefinition.cs
index 12f0cb1..37db5ea 100644
--- a/RGB.NET.Devices.DMX/E131/E131DMXDeviceDefinition.cs
+++ b/RGB.NET.Devices.DMX/E131/E131DMXDeviceDefinition.cs
@@ -57,6 +57,12 @@ public class E131DMXDeviceDefinition : IDMXDeviceDefinition
///
public Dictionary getValueFunc)>> Leds { get; } = new();
+ ///
+ /// The time in ms after which the device is updated even if no changes are made in the meantime to prevent the target from timing out or similar problems.
+ /// To disable heartbeats leave it at 0.
+ ///
+ public int HeartbeatTimer { get; set; } = 0;
+
#endregion
#region Constructors
diff --git a/RGB.NET.Devices.DMX/E131/E131UpdateQueue.cs b/RGB.NET.Devices.DMX/E131/E131UpdateQueue.cs
index e6c108f..b1bffdb 100644
--- a/RGB.NET.Devices.DMX/E131/E131UpdateQueue.cs
+++ b/RGB.NET.Devices.DMX/E131/E131UpdateQueue.cs
@@ -50,6 +50,14 @@ public class E131UpdateQueue : UpdateQueue
#region Methods
+ protected override void OnUpdate(object? sender, CustomUpdateData customData)
+ {
+ if (customData[CustomUpdateDataIndex.HEARTBEAT] as bool? ?? false)
+ Update(Array.Empty<(object key, Color color)>());
+ else
+ base.OnUpdate(sender, customData);
+ }
+
///
protected override void Update(in ReadOnlySpan<(object key, Color color)> dataSet)
{
diff --git a/RGB.NET.Devices.SteelSeries/Generic/SteelSeriesDeviceUpdateQueue.cs b/RGB.NET.Devices.SteelSeries/Generic/SteelSeriesDeviceUpdateQueue.cs
index 3ccc664..67c39a4 100644
--- a/RGB.NET.Devices.SteelSeries/Generic/SteelSeriesDeviceUpdateQueue.cs
+++ b/RGB.NET.Devices.SteelSeries/Generic/SteelSeriesDeviceUpdateQueue.cs
@@ -14,7 +14,7 @@ internal class SteelSeriesDeviceUpdateQueue : UpdateQueue
{
#region Properties & Fields
- private string _deviceType;
+ private readonly string _deviceType;
#endregion
@@ -37,7 +37,7 @@ internal class SteelSeriesDeviceUpdateQueue : UpdateQueue
protected override void OnUpdate(object? sender, CustomUpdateData customData)
{
- if (customData["refresh"] as bool? ?? false)
+ if (customData[CustomUpdateDataIndex.HEARTBEAT] as bool? ?? false)
SteelSeriesSDK.SendHeartbeat();
else
base.OnUpdate(sender, customData);
diff --git a/RGB.NET.Devices.SteelSeries/Generic/SteelSeriesDeviceUpdateTrigger.cs b/RGB.NET.Devices.SteelSeries/Generic/SteelSeriesDeviceUpdateTrigger.cs
deleted file mode 100644
index ddc644b..0000000
--- a/RGB.NET.Devices.SteelSeries/Generic/SteelSeriesDeviceUpdateTrigger.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-// ReSharper disable MemberCanBePrivate.Global
-
-using System.Diagnostics;
-using System.Threading;
-using RGB.NET.Core;
-
-namespace RGB.NET.Devices.SteelSeries;
-
-///
-/// Represents an update-trigger used to update SteelSeries devices
-///
-public class SteelSeriesDeviceUpdateTrigger : DeviceUpdateTrigger
-{
- #region Constants
-
- private static readonly long FLUSH_TIMER = 5 * 1000 * (long)(Stopwatch.Frequency / 1000.0); // flush the device every 5 seconds to prevent timeouts
-
- #endregion
-
- #region Properties & Fields
-
- private long _lastUpdateTimestamp;
-
- #endregion
-
- #region Constructors
-
- ///
- /// Initializes a new instance of the class.
- ///
- public SteelSeriesDeviceUpdateTrigger()
- { }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The hard limit of the update rate of this trigger.
- public SteelSeriesDeviceUpdateTrigger(double updateRateHardLimit)
- : base(updateRateHardLimit)
- { }
-
- #endregion
-
- #region Methods
-
- ///
- protected override void UpdateLoop()
- {
- OnStartup();
-
- while (!UpdateToken.IsCancellationRequested)
- {
- if (HasDataEvent.WaitOne(Timeout))
- {
- long preUpdateTicks = Stopwatch.GetTimestamp();
-
- OnUpdate();
-
- if (UpdateFrequency > 0)
- {
- double lastUpdateTime = ((_lastUpdateTimestamp - preUpdateTicks) / (Stopwatch.Frequency / 1000.0));
- int sleep = (int)((UpdateFrequency * 1000.0) - lastUpdateTime);
- if (sleep > 0)
- Thread.Sleep(sleep);
- }
- }
- else if ((_lastUpdateTimestamp > 0) && ((Stopwatch.GetTimestamp() - _lastUpdateTimestamp) > FLUSH_TIMER))
- OnUpdate(new CustomUpdateData(("refresh", true)));
- }
- }
-
- ///
- protected override void OnUpdate(CustomUpdateData? updateData = null)
- {
- base.OnUpdate(updateData);
- _lastUpdateTimestamp = Stopwatch.GetTimestamp();
- }
-
- #endregion
-}
\ No newline at end of file
diff --git a/RGB.NET.Devices.SteelSeries/SteelSeriesDeviceProvider.cs b/RGB.NET.Devices.SteelSeries/SteelSeriesDeviceProvider.cs
index 3deb842..8b04c34 100644
--- a/RGB.NET.Devices.SteelSeries/SteelSeriesDeviceProvider.cs
+++ b/RGB.NET.Devices.SteelSeries/SteelSeriesDeviceProvider.cs
@@ -12,6 +12,12 @@ namespace RGB.NET.Devices.SteelSeries;
///
public class SteelSeriesDeviceProvider : AbstractRGBDeviceProvider
{
+ #region Constants
+
+ private static readonly int HEARTBEAT_TIMER = 5000; // flush the device every 5 seconds to prevent timeouts
+
+ #endregion
+
#region Properties & Fields
private static SteelSeriesDeviceProvider? _instance;
@@ -121,7 +127,7 @@ public class SteelSeriesDeviceProvider : AbstractRGBDeviceProvider
}
///
- protected override IDeviceUpdateTrigger CreateUpdateTrigger(int id, double updateRateHardLimit) => new SteelSeriesDeviceUpdateTrigger(updateRateHardLimit);
+ protected override IDeviceUpdateTrigger CreateUpdateTrigger(int id, double updateRateHardLimit) => new DeviceUpdateTrigger(updateRateHardLimit) { HeartbeatTimer = HEARTBEAT_TIMER };
///
public override void Dispose()