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..02321f7 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) && ((Stopwatch.GetTimestamp() - LastUpdateTimestamp) > HeartbeatTimer))
+ OnUpdate(new CustomUpdateData().Heartbeat());
+ }
+
+ protected override void OnUpdate(CustomUpdateData? updateData = null)
+ {
+ base.OnUpdate(updateData);
+ LastUpdateTimestamp = Stopwatch.GetTimestamp();
}
///