mirror of
https://github.com/ICDSystems/ICD.Common.Utils.git
synced 2026-02-16 05:05:05 +00:00
Removing Utils directory to better match namespaces
This commit is contained in:
67
ICD.Common.Utils/Timers/IcdStopwatch.cs
Normal file
67
ICD.Common.Utils/Timers/IcdStopwatch.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
#else
|
||||
using System.Diagnostics;
|
||||
#endif
|
||||
|
||||
namespace ICD.Common.Utils.Timers
|
||||
{
|
||||
public sealed class IcdStopwatch
|
||||
{
|
||||
private readonly Stopwatch m_Stopwatch;
|
||||
|
||||
#region Properties
|
||||
|
||||
public long ElapsedMilliseconds { get { return m_Stopwatch.ElapsedMilliseconds; } }
|
||||
|
||||
public bool IsRunning { get { return m_Stopwatch.IsRunning; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public IcdStopwatch()
|
||||
: this(new Stopwatch())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="stopwatch"></param>
|
||||
public IcdStopwatch(Stopwatch stopwatch)
|
||||
{
|
||||
m_Stopwatch = stopwatch;
|
||||
}
|
||||
|
||||
public static IcdStopwatch StartNew()
|
||||
{
|
||||
return new IcdStopwatch(Stopwatch.StartNew());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
m_Stopwatch.Stop();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
m_Stopwatch.Start();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
m_Stopwatch.Reset();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
166
ICD.Common.Utils/Timers/IcdTimer.cs
Normal file
166
ICD.Common.Utils/Timers/IcdTimer.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using ICD.Common.EventArguments;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
|
||||
namespace ICD.Common.Utils.Timers
|
||||
{
|
||||
/// <summary>
|
||||
/// IcdTimer provides events for time increments as well as timer elapsed.
|
||||
/// </summary>
|
||||
public sealed class IcdTimer : IDisposable
|
||||
{
|
||||
private const long DEFAULT_HEARTBEAT_INTERVAL = 500;
|
||||
|
||||
/// <summary>
|
||||
/// Called when the timer is restarted/stopped.
|
||||
/// </summary>
|
||||
public event EventHandler<BoolEventArgs> OnIsRunningChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Called when the timer has elapsed.
|
||||
/// </summary>
|
||||
public event EventHandler OnElapsed;
|
||||
|
||||
/// <summary>
|
||||
/// Called when the milliseconds count changes. Useful for updating UIs.
|
||||
/// </summary>
|
||||
public event EventHandler OnMillisecondsChanged;
|
||||
|
||||
private readonly IcdStopwatch m_Stopwatch;
|
||||
|
||||
private readonly SafeTimer m_Heartbeat;
|
||||
private long m_LastHeartbeatMilliseconds;
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the timer is stopped.
|
||||
/// </summary>
|
||||
public bool IsStopped { get { return !m_Stopwatch.IsRunning; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the timer is running.
|
||||
/// </summary>
|
||||
public bool IsRunning { get { return m_Stopwatch.IsRunning; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the timer has elapsed.
|
||||
/// </summary>
|
||||
public bool IsElapsed { get { return Milliseconds > Length; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of milliseconds that have passed since the timer started.
|
||||
/// </summary>
|
||||
public long Milliseconds { get { return m_Stopwatch.ElapsedMilliseconds; } }
|
||||
|
||||
/// <summary>
|
||||
/// The number of milliseconds before the timer is elapsed.
|
||||
/// </summary>
|
||||
public long Length { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the remaining number of milliseconds until the timer is elapsed. Returns 0 if the timer has elapsed.
|
||||
/// </summary>
|
||||
public long Remaining { get { return Math.Max(Length - Milliseconds, 0); } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the remaining number of seconds until the timer is elapsed. Returns 0 if the timer has elapsed.
|
||||
/// </summary>
|
||||
public long RemainingSeconds { get { return (long)Math.Ceiling(Remaining / 1000.0f); } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public IcdTimer()
|
||||
: this(DEFAULT_HEARTBEAT_INTERVAL)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an IcdTimer with the specified heartbeat interval for the internal timer.
|
||||
/// This allows a finer resolution for timing than the default 500ms.
|
||||
/// </summary>
|
||||
/// <param name="heartbeatInterval"></param>
|
||||
public IcdTimer(long heartbeatInterval)
|
||||
{
|
||||
m_Heartbeat = new SafeTimer(HeartbeatCallback, heartbeatInterval, heartbeatInterval);
|
||||
m_Stopwatch = new IcdStopwatch();
|
||||
|
||||
Stop();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Release resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
OnIsRunningChanged = null;
|
||||
OnElapsed = null;
|
||||
OnMillisecondsChanged = null;
|
||||
|
||||
m_Stopwatch.Stop();
|
||||
m_Heartbeat.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restarts the timer.
|
||||
/// </summary>
|
||||
public void Restart(long length)
|
||||
{
|
||||
Length = length;
|
||||
|
||||
m_Stopwatch.Reset();
|
||||
m_Stopwatch.Start();
|
||||
|
||||
RaiseOnIsRunningChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the timer.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
m_Stopwatch.Stop();
|
||||
|
||||
RaiseOnIsRunningChanged();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Called when the heartbeat timer elapses.
|
||||
/// </summary>
|
||||
private void HeartbeatCallback()
|
||||
{
|
||||
if (Milliseconds == m_LastHeartbeatMilliseconds)
|
||||
return;
|
||||
|
||||
OnMillisecondsChanged.Raise(this);
|
||||
|
||||
if (m_LastHeartbeatMilliseconds <= Length && IsElapsed)
|
||||
OnElapsed.Raise(this);
|
||||
|
||||
m_LastHeartbeatMilliseconds = Milliseconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the OnIsRunningChanged event.
|
||||
/// </summary>
|
||||
private void RaiseOnIsRunningChanged()
|
||||
{
|
||||
OnIsRunningChanged.Raise(this, new BoolEventArgs(IsRunning));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
100
ICD.Common.Utils/Timers/Repeater.cs
Normal file
100
ICD.Common.Utils/Timers/Repeater.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
|
||||
namespace ICD.Common.Utils.Timers
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple class for implementing things like volume ramps, where a button has an
|
||||
/// immediate effect, and then begins ramping after a brief delay.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public sealed class Repeater : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Raised on the initial repeat.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public event EventHandler OnInitialRepeat;
|
||||
|
||||
/// <summary>
|
||||
/// Raised on each subsequent repeat.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public event EventHandler OnRepeat;
|
||||
|
||||
private readonly SafeTimer m_RepeatTimer;
|
||||
|
||||
private readonly long m_BeforeRepeat;
|
||||
private readonly long m_BetweenRepeat;
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="beforeRepeat">The delay before the second increment</param>
|
||||
/// <param name="betweenRepeat">The delay between each subsequent repeat</param>
|
||||
public Repeater(long beforeRepeat, long betweenRepeat)
|
||||
{
|
||||
m_RepeatTimer = SafeTimer.Stopped(RepeatCallback);
|
||||
|
||||
m_BeforeRepeat = beforeRepeat;
|
||||
m_BetweenRepeat = betweenRepeat;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destructor.
|
||||
/// </summary>
|
||||
~Repeater()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Release resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
m_RepeatTimer.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begin repeating.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public void Start()
|
||||
{
|
||||
OnInitialRepeat.Raise(this);
|
||||
|
||||
m_RepeatTimer.Reset(m_BeforeRepeat, m_BetweenRepeat);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop repeating volume.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public void Stop()
|
||||
{
|
||||
m_RepeatTimer.Stop();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Called for every repeat.
|
||||
/// </summary>
|
||||
private void RepeatCallback()
|
||||
{
|
||||
OnRepeat.Raise(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
180
ICD.Common.Utils/Timers/SafeTimer.cs
Normal file
180
ICD.Common.Utils/Timers/SafeTimer.cs
Normal file
@@ -0,0 +1,180 @@
|
||||
using System;
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp;
|
||||
#else
|
||||
using System.Threading;
|
||||
#endif
|
||||
using ICD.Common.Services;
|
||||
using ICD.Common.Services.Logging;
|
||||
|
||||
namespace ICD.Common.Utils.Timers
|
||||
{
|
||||
/// <summary>
|
||||
/// SafeTimer wraps CTimer to hide some of the jank.
|
||||
/// </summary>
|
||||
public sealed class SafeTimer : IStateDisposable
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
private readonly CTimer m_Timer;
|
||||
#else
|
||||
private readonly Timer m_Timer;
|
||||
private int m_DueTime, m_RepeatPeriod;
|
||||
#endif
|
||||
private readonly Action m_Callback;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this instance has been disposed.
|
||||
/// </summary>
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Creates a timer that is called every repeatPeriod in milliseconds.
|
||||
/// </summary>
|
||||
/// <param name="callback"></param>
|
||||
/// <param name="repeatPeriod"></param>
|
||||
public SafeTimer(Action callback, long repeatPeriod)
|
||||
: this(callback, 0, repeatPeriod)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a timer that is called in dueTime milliseconds and then every
|
||||
/// repeatPeriod milliseconds afterwards.
|
||||
/// </summary>
|
||||
/// <param name="callback"></param>
|
||||
/// <param name="dueTime"></param>
|
||||
/// <param name="repeatPeriod"></param>
|
||||
public SafeTimer(Action callback, long dueTime, long repeatPeriod)
|
||||
{
|
||||
m_Callback = callback;
|
||||
#if SIMPLSHARP
|
||||
m_Timer = new CTimer(SafeCallback, null, dueTime, repeatPeriod);
|
||||
#else
|
||||
m_DueTime = (int)dueTime;
|
||||
m_RepeatPeriod = (int)repeatPeriod;
|
||||
m_Timer = new Timer(SafeCallback, null, m_DueTime, m_RepeatPeriod);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a timer that is initially stopped.
|
||||
/// </summary>
|
||||
/// <param name="callback"></param>
|
||||
/// <returns></returns>
|
||||
public static SafeTimer Stopped(Action callback)
|
||||
{
|
||||
SafeTimer output = new SafeTimer(callback, 0);
|
||||
output.Stop();
|
||||
return output;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Release resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Stop();
|
||||
m_Timer.Dispose();
|
||||
IsDisposed = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the timer.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
m_Timer.Stop();
|
||||
#else
|
||||
m_Timer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Immediately calls the callback and resets the timer
|
||||
/// </summary>
|
||||
public void Trigger()
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
m_Timer.Reset();
|
||||
#else
|
||||
m_Timer.Change(0, m_RepeatPeriod);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback is called after the dueTime milliseconds.
|
||||
/// </summary>
|
||||
/// <param name="dueTime"></param>
|
||||
public void Reset(long dueTime)
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
m_Timer.Reset(dueTime);
|
||||
#else
|
||||
m_DueTime = (int)dueTime;
|
||||
m_Timer.Change(m_DueTime, m_RepeatPeriod);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback is called after the dueTime milliseconds and every repeatPeriod milliseconds.
|
||||
/// </summary>
|
||||
/// <param name="dueTime"></param>
|
||||
/// <param name="repeatPeriod"></param>
|
||||
public void Reset(long dueTime, long repeatPeriod)
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
m_Timer.Reset(dueTime, repeatPeriod);
|
||||
#else
|
||||
m_DueTime = (int)dueTime;
|
||||
m_RepeatPeriod = (int)repeatPeriod;
|
||||
m_Timer.Change(m_DueTime, m_RepeatPeriod);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Only executes the callback if the timer has not been disposed.
|
||||
/// Catches any exceptions and logs them.
|
||||
/// </summary>
|
||||
/// <param name="unused"></param>
|
||||
private void SafeCallback(object unused)
|
||||
{
|
||||
// Essentially the meat of this class. There's some weirdness with the garbage collector where
|
||||
// the reference to the timer will be cleared, and eventually the CTimer will call the callback
|
||||
// despite being stopped/disposed.
|
||||
if (m_Timer == null
|
||||
#if SIMPLSHARP
|
||||
|| m_Timer.Disposed
|
||||
#endif
|
||||
)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
m_Callback();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void LogException(Exception e)
|
||||
{
|
||||
string message = string.Format("{0} failed to execute callback - {1}", GetType().Name, e.Message);
|
||||
ServiceProvider.TryGetService<ILoggerService>().AddEntry(eSeverity.Error, e, message);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user