DirectOuput Framework R2
DirectOutput framework R2 for virtual pinball cabinets
Go to:
Overview 
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Properties Events Macros Pages
WS2811StripController.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using DirectOutput.General.Generic;
6 using System.Threading;
7 
8 namespace DirectOutput.Cab.Out.AdressableLedStrip
9 {
10 
25  {
26  #region ISupportsSetValues Member
27 
33  public void SetValues(int FirstOutput, byte[] Values)
34  {
35  if (FirstOutput >= LedData.Length) return;
36  if (FirstOutput < 0) return;
37  int CopyLength = (LedData.Length - FirstOutput).Limit(0, Values.Length);
38  if (CopyLength < 1) return;
39 
40  lock (UpdateLocker)
41  {
42  Buffer.BlockCopy(Values, 0, LedData, FirstOutput, CopyLength);
43  UpdateRequired = true;
44  }
45  }
46 
47  #endregion
48 
49 
50  private byte[] LedData = new byte[0];
51 
52  private byte[] OutputLedData = new byte[0];
53 
54 
55  private int _ControllerNumber = 1;
56 
63  public int ControllerNumber
64  {
65  get { return _ControllerNumber; }
66  set { _ControllerNumber = value; }
67  }
68 
69 
70  private int _NumberOfLeds = 1;
71 
78  public int NumberOfLeds
79  {
80  get { return _NumberOfLeds; }
81  set
82  {
83  _NumberOfLeds = value.Limit(0, 4006);
84  LedData = new byte[_NumberOfLeds * 3];
85  OutputLedData = new byte[_NumberOfLeds * 3];
86  }
87  }
88 
89 
90 
91 
92  private object UpdateLocker = new object();
93  private bool UpdateRequired = true;
94 
95 
96 
97 
98 
99 
100  private readonly int[] ColNrLookup = { 1, 0, 2 };
105  protected override void OnOutputValueChanged(IOutput Output)
106  {
107  if (Output is IOutputNumbered)
108  {
109  IOutputNumbered ON = (IOutputNumbered)Output;
110  int ByteNr = ON.Number - 1;
111  ByteNr = (ByteNr / 3) * 3 + ColNrLookup[ByteNr % 3];
112 
113 
114  try
115  {
116 
117  lock (UpdateLocker)
118  {
119  if (LedData[ByteNr] != ON.Value)
120  {
121  LedData[ByteNr] = ON.Value;
122  UpdateRequired = true;
123  }
124 
125  }
126  }
127  catch (Exception E)
128  {
129  Log.Exception("WS2811StripController {0} with number {1} has received a update with a illegal or to high output number ({2}).".Build(Name, ControllerNumber, ON.Number), E);
130  }
131  }
132 
133  }
134 
135 
136  private void AddOutputs()
137  {
138  for (int i = 1; i <= NumberOfLeds * 3; i++)
139  {
140  if (!Outputs.Any(x => ((LedStripOutput)x).Number == i))
141  {
142  Outputs.Add(new LedStripOutput() { Name = "{0}.{1}".Build(Name, i), Number = i });
143  }
144  }
145  }
146 
147 
148 
153  public override void Init(Cabinet Cabinet)
154  {
155  AddOutputs();
156 
157  InitUpdaterThread();
158  Log.Write("WS2811StripController {0} with number {1} initialized and updaterthread started.".Build(Name, ControllerNumber));
159 
160  }
161 
165  public override void Finish()
166  {
167  FinishUpdaterThread();
168  Log.Write("WS2811StripController {0} with number {1} finished and updaterthread stopped.".Build(Name, ControllerNumber));
169  }
170 
174  public override void Update()
175  {
176  if (UpdateRequired)
177  {
178  UpdaterThreadSignal();
179  }
180  }
181 
182 
183 
184  #region UpdaterThread
185 
186 
187 
188 
189  private void InitUpdaterThread()
190  {
191 
192  if (!UpdaterThreadIsActive)
193  {
194  KeepUpdaterThreadAlive = true;
195  try
196  {
197  UpdaterThread = new Thread(UpdaterThreadDoIt);
198  UpdaterThread.Name = "WS2811StripController {0} named {1} updater thread ".Build(ControllerNumber, Name);
199  UpdaterThread.Start();
200  }
201  catch (Exception E)
202  {
203  Log.Exception("WS2811StripController {0} named {1} updater thread could not start.".Build(ControllerNumber, Name), E);
204  throw new Exception("WS2811StripController {0} named {1} updater thread could not start.".Build(ControllerNumber, Name), E);
205  }
206  }
207  }
208 
213  private void FinishUpdaterThread()
214  {
215  if (UpdaterThread != null)
216  {
217  try
218  {
219  KeepUpdaterThreadAlive = false;
220  lock (UpdaterThreadLocker)
221  {
222  Monitor.Pulse(UpdaterThreadLocker);
223  }
224  if (!UpdaterThread.Join(1000))
225  {
226  UpdaterThread.Abort();
227  }
228  UpdaterThread = null;
229  }
230  catch (Exception E)
231  {
232  Log.Exception("A error occured during termination of WS2811StripController updater thread.", E);
233  throw new Exception("A error occured during termination of WS2811StripController updater thread.", E);
234  }
235  }
236  }
237 
238 
242  public bool UpdaterThreadIsActive
243  {
244  get
245  {
246  if (UpdaterThread != null)
247  {
248  if (UpdaterThread.IsAlive)
249  {
250  return true;
251  }
252  }
253  return false;
254  }
255  }
256 
260  private void UpdaterThreadSignal()
261  {
262 
263  lock (UpdaterThreadLocker)
264  {
265  Monitor.Pulse(UpdaterThreadLocker);
266  }
267  }
268 
269 
270  private Thread UpdaterThread { get; set; }
271  private object UpdaterThreadLocker = new object();
272  private bool KeepUpdaterThreadAlive = true;
273 
274 
275 
276 
277  private WS2811StripControllerApi Controller = null;
278 
282  private void UpdaterThreadDoIt()
283  {
284  if (Controller == null)
285  {
286  Controller = new WS2811StripControllerApi(ControllerNumber);
287  if (!Controller.DeviceIsPresent)
288  {
289  Log.Warning("WS2811 Strip Controller Nr. {0} is not present. Will not send updates.".Build(ControllerNumber));
290  Controller = null;
291  }
292  }
293 
294 
295  OutputLedData.Fill((byte)0);
296  if (Controller != null)
297  {
298  Controller.SetAndDisplayData(OutputLedData);
299  }
300  while (KeepUpdaterThreadAlive)
301  {
302 
303  if (UpdateRequired)
304  {
305  lock (UpdateLocker)
306  {
307  UpdateRequired = false;
308 
309  Buffer.BlockCopy(LedData, 0, OutputLedData, 0, LedData.Length);
310  }
311 
312  if (Controller != null)
313  {
314 
315  Controller.SetAndDisplayData(OutputLedData);
316  }
317  }
318 
319  if (KeepUpdaterThreadAlive)
320  {
321  lock (UpdaterThreadLocker)
322  {
323  while (UpdateRequired == false && KeepUpdaterThreadAlive)
324  {
325  Monitor.Wait(UpdaterThreadLocker, 50); // Lock is released while we’re waiting
326  }
327  }
328  }
329 
330  }
331 
332  OutputLedData.Fill((byte)0);
333  if (Controller != null)
334  {
335  Controller.SetAndDisplayData(OutputLedData);
336 
337  Controller.Close();
338  }
339  Controller = null;
340 
341  }
342  #endregion
343 
348  {
349  Outputs = new OutputList();
350  }
351 
352 
353  }
354 }