public EnumStateMachine <T> ForFromSubroutine(T state, Subroutine sub) { var seq = new Sequence(name: $"ForFromSubroutine({sub.Name})"); seq.WhenExecuted.Execute(i => { System.Threading.CancellationTokenSource cts; var evt = new System.Threading.ManualResetEvent(false); var runTask = sub.Run(out cts); runTask.ContinueWith(t => { evt.Set(); }); System.Threading.WaitHandle.WaitAny(new System.Threading.WaitHandle[] { evt, i.CancelToken.WaitHandle }); log.Debug("Cancel 1"); cts?.Cancel(); if (!runTask.Wait(10000)) { this.log.Information("Sequence {0} failed to cancel in time", seq.Name); } }); var seqJob = (seq.WhenExecuted as Sequence.SequenceJob); this.stateConfigs[state] = seqJob; return(this); }
private void WireupLifeCycle(Controller.Subroutine sub) { sub.Lifecycle.Subscribe(lc => { switch (lc) { case Controller.Subroutine.LifeCycles.Running: case Controller.Subroutine.LifeCycles.RunningLoop: // Check if we shouldn't run if (this.requestedSub != this.currentSub) { this.currentSub?.RequestCancel(); } break; case Controller.Subroutine.LifeCycles.Setup: if (this.reportMasterStatus) { Executor.Current.LogMasterStatus(Name, true); } break; case Controller.Subroutine.LifeCycles.Stopped: if (this.reportMasterStatus) { Executor.Current.LogMasterStatus(Name, false); } QueueCheckState(); break; } }); }
public TriggeredSubBaseModule([System.Runtime.CompilerServices.CallerMemberName] string name = "", bool reportMasterStatus = true) : base(name) { this.reportMasterStatus = reportMasterStatus; this.stateChecker = Observer.NotifyOn(Observer.Create <bool>(_ => { if (this.transition) { if (this.currentSub != null) { this.currentSub.RequestCancel(); Executor.Current.Cancel(this.currentSub); } // Transition done, let's exit and check again this.transition = false; this.currentSub = null; QueueCheckState(); return; } if (this.currentSub != this.requestedSub) { if (this.requestedSub == null) { // Request to turn off this.transition = true; QueueCheckState(); return; } else { var sub = this.requestedSub; this.currentSub = sub; Executor.Current.Execute(sub); QueueCheckState(); } } }), this.scheduler); WireupLifeCycle(this.powerOffSub); WireupLifeCycle(this.powerOnSub); OutputTrigger.Subscribe(x => { if (x.Trigger) { this.requestedSub = (x.Power || AlwaysUsePowerOnSub) ? this.powerOnSub : this.powerOffSub; } else { this.requestedSub = null; } QueueCheckState(); }); }
public DmxPlayback([System.Runtime.CompilerServices.CallerMemberName] string name = "") { this.name = name; this.sub = new Subroutine("SUB_" + this.name); this.watch = new Stopwatch(); this.pixelMapping = new Dictionary<int, int[]>(); long timestampOffset = 0; this.sub.RunAction(ins => { var bitmap = (Bitmap)this.device.GetFrameBuffer(this.sub.Token, this.device)[DataElements.PixelBitmap]; if (bitmap.Width != this.pixelWidth || bitmap.Height != this.pixelHeight) throw new ArgumentException("Invalid bitmap size"); var bitmapRect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); int bytesPerPixel = Bitmap.GetPixelFormatSize(bitmap.PixelFormat) / 8; int stride = 4 * ((bitmap.Width * bytesPerPixel + 3) / 4); int byteCount = stride * bitmap.Height; this.rgbValues = new byte[byteCount]; do { // See if we should restart if (this.file.Position >= this.file.Length) { // Restart this.file.Position = 0; this.dmxFrame = null; this.watch.Reset(); } if (this.dmxFrame == null) { this.dmxFrame = ReadFrame(this.binRead); timestampOffset = this.dmxFrame.TimestampMS; } this.watch.Start(); while (!ins.IsCancellationRequested && this.file.Position < this.file.Length) { // Calculate when the next stop is this.nextStop = this.dmxFrame.TimestampMS - timestampOffset; long msLeft = this.nextStop - this.watch.ElapsedMilliseconds; if (msLeft <= 0) { // Output OutputData(this.dmxFrame, bitmap, bitmapRect, stride); // Read next frame this.dmxFrame = ReadFrame(this.binRead); continue; } else if (msLeft < 16) { SpinWait.SpinUntil(() => this.watch.ElapsedMilliseconds >= this.nextStop); continue; } Thread.Sleep(1); } } while (!ins.IsCancellationRequested && this.loop); this.watch.Stop(); }); }