Created
March 9, 2018 12:22
-
-
Save enusbaum/eb40d1dcbf5d5630292ccf94b7daa45d to your computer and use it in GitHub Desktop.
Oscillator Class in C# to pulse an AutoResetEvent at a sub-millisecond rate
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Diagnostics; | |
| using System.Threading; | |
| using System.Threading.Tasks; | |
| namespace TimerTest | |
| { | |
| /// <summary> | |
| /// Oscillator class to pulse the specified AutoResetEvents at a higher frequency | |
| /// than the minimum resolution of most system timers of 1ms | |
| /// | |
| /// The Oscillator spins watching elapsed ticks from the Stopwatch object and pulses | |
| /// the specified AutoResetEvents at the specified frequency. | |
| /// | |
| /// On my i5 with a PulseRate of 50,000 it will come within 0.01%, not exactly within | |
| /// the tolerances of a commercial Oscillator, but it works. | |
| /// </summary> | |
| public class Oscillator | |
| { | |
| private readonly Stopwatch _masterClock = new Stopwatch(); | |
| private readonly AutoResetEvent[] _targets = new AutoResetEvent[10]; | |
| private int _targetCount; | |
| private readonly long _maxFrequency = Stopwatch.Frequency; | |
| private long _pulseRate; | |
| private long _ticksPerPulse; | |
| private long _lastPulseTicks; | |
| private bool _running; | |
| /// <summary> | |
| /// Number of Pulses-Per-Second | |
| /// </summary> | |
| public long PulseRate | |
| { | |
| get => _pulseRate; | |
| set | |
| { | |
| if(value > _maxFrequency) | |
| throw new Exception("Pulse Rate higher than maximum supported pulse rate"); | |
| _pulseRate = value; | |
| _ticksPerPulse =_maxFrequency / _pulseRate; | |
| Console.WriteLine($"{PulseRate} : {_ticksPerPulse} : {_maxFrequency}"); | |
| } | |
| } | |
| /// <summary> | |
| /// Default Constructor | |
| /// </summary> | |
| public Oscillator() | |
| { | |
| if(!Stopwatch.IsHighResolution) | |
| throw new Exception("Oscillator requres HPC be in use"); | |
| } | |
| /// <summary> | |
| /// Adds AutoResetEvent Target that will be Set during the Oscillator pulses | |
| /// </summary> | |
| /// <param name="target"></param> | |
| public void AddTarget(AutoResetEvent target) | |
| { | |
| if (_running) | |
| throw new Exception("Unable to add new targets while Oscillator is running"); | |
| if (_targetCount == _targets.Length) | |
| throw new Exception("Max targets already specified, high precision not possible with multiple targets"); | |
| _targets[_targetCount] = target; | |
| _targetCount++; | |
| } | |
| /// <summary> | |
| /// Starts the Oscillator | |
| /// </summary> | |
| public void Start() | |
| { | |
| if(_targetCount == 0) | |
| throw new Exception("At least one target must be specified before starting the Oscillator"); | |
| _running = true; | |
| _masterClock.Start(); | |
| Task.Factory.StartNew(Oscillate, TaskCreationOptions.LongRunning); | |
| } | |
| /// <summary> | |
| /// Stops the Oscillator | |
| /// </summary> | |
| public void Stop() | |
| { | |
| _running = false; | |
| } | |
| /// <summary> | |
| /// Oscillator Pulse routine that runs within the Task created in Start() | |
| /// </summary> | |
| private void Oscillate() | |
| { | |
| while (_running) | |
| { | |
| _lastPulseTicks = _masterClock.ElapsedTicks; | |
| for (int i = 0; i < _targetCount; i++) | |
| _targets[i].Set(); | |
| while (_masterClock.ElapsedTicks - _lastPulseTicks < _ticksPerPulse) { } | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment