OSDP.Net 5.2.1
A .NET library for implementing the Open Supervised Device Protocol (OSDP)
Loading...
Searching...
No Matches
LineTiming.cs
1using System;
2using System.Diagnostics;
3using System.Threading;
4using System.Threading.Tasks;
5
6namespace OSDP.Net.Utilities
7{
19 internal static class LineTiming
20 {
25 private const int BitsPerCharacter = 10;
26
30 private const int IdleCharacters = 2;
31
38 private const double SpinThresholdMilliseconds = 16;
39
48 public static TimeSpan ForCharacters(int baudRate, int characterCount) =>
49 baudRate <= 0 || characterCount <= 0
50 ? TimeSpan.Zero
51 : TimeSpan.FromSeconds((double)(characterCount * BitsPerCharacter) / baudRate);
52
62 public static TimeSpan IdleLine(int baudRate) => ForCharacters(baudRate, IdleCharacters);
63
72 public static async Task WaitAsync(TimeSpan delay, long sinceTimestamp)
73 {
74 if (delay <= TimeSpan.Zero) return;
75
76 long target = sinceTimestamp + (long)(delay.TotalSeconds * Stopwatch.Frequency);
77
78 // A delay long enough to sleep through is slept off first, leaving only the imprecise
79 // tail to spin. In practice the whole wait is spun: two characters is 2.08 ms at 9600
80 // baud and less at every higher rate.
81 double remaining = RemainingMilliseconds(target);
82 if (remaining > SpinThresholdMilliseconds)
83 {
84 await Task.Delay((int)(remaining - SpinThresholdMilliseconds)).ConfigureAwait(false);
85 }
86
87 while (Stopwatch.GetTimestamp() < target)
88 {
89 Thread.SpinWait(50);
90 }
91 }
92
93 private static double RemainingMilliseconds(long target) =>
94 (target - Stopwatch.GetTimestamp()) * 1000.0 / Stopwatch.Frequency;
95 }
96}