void patternAnimator_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker worker = (BackgroundWorker)sender; try { log.InfoFormat("[{0}] Starting pattern playback", this.Serial); List <TriggeredEvent> eventsPlaying = new List <TriggeredEvent>(); while (!worker.CancellationPending) { TriggeredEvent ev = null; lock (EventQueue) { for (int i = 0; i < EventQueue.Count; i++) { ev = EventQueue.Dequeue(); for (int j = eventsPlaying.Count - 1; j >= 0; j--) { if (ev.Notification == eventsPlaying[j].Notification && (eventsPlaying[j].Repeat < 0 || eventsPlaying[j].Duration > 0)) { log.DebugFormat("Removing infinite playback notifications as there is another pending"); TriggeredEvent evPlaying = eventsPlaying[j]; eventsPlaying.RemoveAt(j); AssignBusyLeds(evPlaying, false); } } if (CanPlayEvent(ev)) { break; } else { EventQueue.Enqueue(ev); ev = null; } } } if (ev != null) { if (ev.NotificationSnapshot is PatternNotification) { ev.EventStarted = DateTime.Now; ev.AnimationStarted = DateTime.Now; PatternNotification notification = ev.NotificationSnapshot as PatternNotification; foreach (Animation animation in notification.Pattern.Animations) { Animation copyAnimation = new Animation(); copyAnimation.Assign(animation); ev.Animations.Add(copyAnimation); } ev.Animations[0].ReferenceColor = GetColor(ev.NotificationSnapshot); AssignBusyLeds(ev, true); eventsPlaying.Add(ev); } else { ev.AnimationStarted = DateTime.Now; ev.EventStarted = DateTime.Now; foreach (Animation animation in ev.Pattern.Animations) { Animation copyAnimation = new Animation(); copyAnimation.Assign(animation); ev.Animations.Add(copyAnimation); } ev.Animations[0].ReferenceColor = GetColor(ev.NotificationSnapshot); AssignBusyLeds(ev, true); eventsPlaying.Add(ev); } } //Prepare next frame of data to send to LEDs for (int ii = eventsPlaying.Count - 1; ii >= 0; ii--) { TriggeredEvent evnt = eventsPlaying[ii]; RgbColor color = evnt.Animations[evnt.AnimationIndex].GetColor(evnt.AnimationStarted.Value, DateTime.Now, evnt.Animations[evnt.AnimationIndex].ReferenceColor); PatternNotification notification = evnt.NotificationSnapshot as PatternNotification; lock (this) { SetColor(evnt, color.R, color.G, color.B); } if (evnt.Animations[evnt.AnimationIndex].AnimationFinished) { evnt.AnimationIndex += 1; if (evnt.Duration > 0 && evnt.EventStarted.Value.AddMilliseconds(evnt.Duration) <= DateTime.Now) { eventsPlaying.RemoveAt(ii); AssignBusyLeds(evnt, false); } else if (evnt.AnimationIndex == evnt.Animations.Count) { evnt.RepeatCount += 1; if (evnt.Duration > 0 || evnt.Repeat < 0 || evnt.RepeatCount < evnt.Repeat) { evnt.AnimationStarted = DateTime.Now; evnt.AnimationIndex = 0; evnt.Animations.ForEach(delegate(Animation a) { a.Reset(); }); } else { eventsPlaying.RemoveAt(ii); AssignBusyLeds(evnt, false); } } else { evnt.Animations[evnt.AnimationIndex].ReferenceColor = GetColor(evnt.NotificationSnapshot); evnt.AnimationStarted = DateTime.Now; } } } if (Led != null && NeedsLedUpdate) { lock (this) { NeedsLedUpdate = false; } int retryCount = 5; if (Led.BlinkStickDevice == BlinkStickDeviceEnum.BlinkStick || Led.BlinkStickDevice == BlinkStickDeviceEnum.BlinkStickPro && Led.Mode < 2) { while (retryCount > 0) //Retry loop { try { Led.SetColor(LedFrame[0][1], LedFrame[0][0], LedFrame[0][2]); retryCount = 0; } catch (Exception ex) { retryCount--; log.ErrorFormat("Failed to set color: {0}", ex); if (retryCount > 0) { Thread.Sleep(20); log.InfoFormat("Retry set color #{0}", 5 - retryCount); } else { log.Warn("Failed to set color 5 times, giving up..."); } } } } else { byte[] frame = new byte[this.LedsR * 3]; Array.Copy(LedFrame[0], 0, frame, 0, frame.Length); while (retryCount > 0) //Retry loop { try { Led.SetColors(0, frame); retryCount = 0; } catch (Exception ex) { retryCount--; log.ErrorFormat("Failed to set color: {0}", ex); if (retryCount > 0) { Thread.Sleep(20); log.InfoFormat("Retry set color #{0}", 5 - retryCount); } else { log.Warn("Failed to set color 5 times, giving up..."); } } } int sleep = Math.Max(2, (int)(this.LedsR * 3 * 8f / 400f * 1.2)); //number of LEDs times 3 color elements times 8 bytes divided by speed Thread.Sleep(sleep); if (Led != null && Led.BlinkStickDevice == BlinkStickDeviceEnum.BlinkStickPro) { frame = new byte[this.LedsG * 3]; Array.Copy(LedFrame[1], 0, frame, 0, frame.Length); while (retryCount > 0) //Retry loop { try { Led.SetColors(1, frame); retryCount = 0; } catch (Exception ex) { retryCount--; log.ErrorFormat("Failed to set color: {0}", ex); if (retryCount > 0) { Thread.Sleep(20); log.InfoFormat("Retry set color #{0}", 5 - retryCount); } else { log.Warn("Failed to set color 5 times, giving up..."); } } } sleep = Math.Max(2, (int)(this.LedsG * 3 * 8f / 400f * 1.2)); Thread.Sleep(sleep); frame = new byte[this.LedsB * 3]; Array.Copy(LedFrame[2], 0, frame, 0, frame.Length); while (retryCount > 0) //Retry loop { try { Led.SetColors(2, frame); retryCount = 0; } catch (Exception ex) { retryCount--; log.ErrorFormat("Failed to set color: {0}", ex); if (retryCount > 0) { Thread.Sleep(20); log.InfoFormat("Retry set color #{0}", 5 - retryCount); } else { log.Warn("Failed to set color 5 times, giving up..."); } } } sleep = Math.Max(2, (int)(this.LedsB * 3 * 8f / 400f * 1.2)); Thread.Sleep(sleep); } } } else { Thread.Sleep(1); } } } catch (Exception ex) { log.ErrorFormat("Pattern playback crash {0}", ex); } log.InfoFormat("[{0}] Pattern playback stopped", this.Serial); Running = false; }