WIP
DirectOutput framework for virtual pinball cabinets WIP
Go to:
Overview 
DirectStripController.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
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  private bool _PackData = false;
91 
99  public bool PackData
100  {
101  get { return _PackData; }
102  set { _PackData = value; }
103  }
104 
105 
106  private object UpdateLocker = new object();
107  private bool UpdateRequired = true;
108 
109 
110 
111 
112 
113 
114  private readonly int[] ColNrLookup = { 1, 0, 2 };
119  protected override void OnOutputValueChanged(IOutput ChangedOutput)
120  {
121  if (ChangedOutput is IOutput)
122  {
123  IOutput ON = ChangedOutput;
124  int ByteNr = ON.Number - 1;
125  ByteNr = (ByteNr / 3) * 3 + ColNrLookup[ByteNr % 3];
126 
127 
128  try
129  {
130 
131  lock (UpdateLocker)
132  {
133  if (LedData[ByteNr] != ON.Value)
134  {
135  LedData[ByteNr] = ON.Value;
136  UpdateRequired = true;
137  }
138 
139  }
140  }
141  catch (Exception E)
142  {
143  Log.Exception("DirectStripController {0} with number {1} has received a update with a illegal or to high output number ({2}).".Build(Name, ControllerNumber, ON.Number), E);
144  }
145  }
146 
147  }
148 
149 
150  private void AddOutputs()
151  {
152  for (int i = 1; i <= NumberOfLeds * 3; i++)
153  {
154  if (!Outputs.Any(x => ((LedStripOutput)x).Number == i))
155  {
156  Outputs.Add(new LedStripOutput() { Name = "{0}.{1}".Build(Name, i), Number = i });
157  }
158  }
159  }
160 
161 
162 
167  public override void Init(Cabinet Cabinet)
168  {
169  AddOutputs();
170 
171  InitUpdaterThread();
172  Log.Write("DirectStripController {0} with number {1} initialized and updaterthread started.".Build(Name, ControllerNumber));
173 
174  }
175 
179  public override void Finish()
180  {
181  FinishUpdaterThread();
182  Log.Write("DirectStripController {0} with number {1} finished and updaterthread stopped.".Build(Name, ControllerNumber));
183  }
184 
188  public override void Update()
189  {
190  if (UpdateRequired)
191  {
192  UpdaterThreadSignal();
193  }
194  }
195 
196 
197 
198  #region UpdaterThread
199  private void InitUpdaterThread()
204  {
205 
206  if (!UpdaterThreadIsActive)
207  {
208  KeepUpdaterThreadAlive = true;
209  try
210  {
211  UpdaterThread = new Thread(UpdaterThreadDoIt);
212  UpdaterThread.Name = "DirectStripController {0} named {1} updater thread ".Build(ControllerNumber, Name);
213  UpdaterThread.Start();
214  }
215  catch (Exception E)
216  {
217  Log.Exception("DirectStripController {0} named {1} updater thread could not start.".Build(ControllerNumber, Name), E);
218  throw new Exception("DirectStripController {0} named {1} updater thread could not start.".Build(ControllerNumber, Name), E);
219  }
220  }
221  }
222 
227  private void FinishUpdaterThread()
228  {
229  if (UpdaterThread != null)
230  {
231  try
232  {
233  KeepUpdaterThreadAlive = false;
234  UpdaterThreadSignal();
235  if (!UpdaterThread.Join(1000))
236  {
237  UpdaterThread.Abort();
238  }
239  UpdaterThread = null;
240  }
241  catch (Exception E)
242  {
243  Log.Exception("A error occured during termination of DirectStripController updater thread.", E);
244  throw new Exception("A error occured during termination of DirectStripController updater thread.", E);
245  }
246  }
247  }
248 
249 
253  public bool UpdaterThreadIsActive
254  {
255  get
256  {
257  if (UpdaterThread != null)
258  {
259  if (UpdaterThread.IsAlive)
260  {
261  return true;
262  }
263  }
264  return false;
265  }
266  }
267 
271  private void UpdaterThreadSignal()
272  {
273 
274  lock (UpdaterThreadLocker)
275  {
276  Monitor.Pulse(UpdaterThreadLocker);
277  }
278  }
279 
280 
281  private Thread UpdaterThread { get; set; }
282  private object UpdaterThreadLocker = new object();
283  private bool KeepUpdaterThreadAlive = true;
284 
285 
286 
287 
288  private DirectStripControllerApi Controller = null;
289 
293  private void UpdaterThreadDoIt()
294  {
295  if (Controller == null)
296  {
297  Controller = new DirectStripControllerApi(ControllerNumber);
298  if (!Controller.DeviceIsPresent)
299  {
300  Log.Warning("WS2811 Strip Controller Nr. {0} is not present. Will not send updates.".Build(ControllerNumber));
301  Controller = null;
302  }
303  }
304 
305 
306  OutputLedData.Fill((byte)0);
307  if (Controller != null)
308  {
309  if (PackData)
310  {
311  Controller.SetAndDisplayPackedData(OutputLedData);
312  }
313  else
314  {
315  Controller.SetAndDisplayData(OutputLedData);
316  }
317  }
318  while (KeepUpdaterThreadAlive)
319  {
320 
321  if (UpdateRequired)
322  {
323  lock (UpdateLocker)
324  {
325  UpdateRequired = false;
326 
327  Buffer.BlockCopy(LedData, 0, OutputLedData, 0, LedData.Length);
328  }
329 
330  if (Controller != null)
331  {
332  if (PackData)
333  {
334  Controller.SetAndDisplayPackedData(OutputLedData);
335  }
336  else
337  {
338  Controller.SetAndDisplayData(OutputLedData);
339  }
340  }
341  }
342 
343  if (KeepUpdaterThreadAlive)
344  {
345  lock (UpdaterThreadLocker)
346  {
347  while (UpdateRequired == false && KeepUpdaterThreadAlive)
348  {
349  Monitor.Wait(UpdaterThreadLocker, 50); // Lock is released while we’re waiting
350  }
351  }
352  }
353 
354  }
355 
356  OutputLedData.Fill((byte)0);
357  if (Controller != null)
358  {
359  if (PackData)
360  {
361  Controller.SetAndDisplayPackedData(OutputLedData);
362  }
363  else
364  {
365  Controller.SetAndDisplayData(OutputLedData);
366  }
367  Controller.Close();
368  }
369  Controller = null;
370 
371  }
372  #endregion
373 
378  {
379  Outputs = new OutputList();
380  }
381 
382 
383  }
384 }
385 
The Cabinet object describes the parts of a pinball cabinet (toys, outputcontrollers, outputs and more).
Definition: Cabinet.cs:17
int Number
Gets or sets the number of the Output object.
Definition: IOutput.cs:27
override void OnOutputValueChanged(IOutput ChangedOutput)
This method is called whenever the value of a output in the Outputs property changes its value...
byte Value
Value of the output.
Definition: IOutput.cs:18
static void Warning(string Message)
Writes a warning message to the log.
Definition: Log.cs:134
This output controller class is used to control the direct strip controller by Swisslizard.
void SetValues(int FirstOutput, byte[] Values)
Sets the values for one or several outputs of the controller.
List of IOutput objects
Definition: OutputList.cs:13
static void Write(string Message)
Writes the specified message to the logfile.
Definition: Log.cs:99
A simple logger used to record important events and exceptions.
Definition: Log.cs:14
override void Update()
Notifies the updater thread to sdend data to the controller hardware.
A simple wrapper for the OutputNumbered class. This might be replaced with some more sophisticated so...
Common interface for outputs of any output controller. The Output class implements this interface and...
Definition: IOutput.cs:10
Abstract OutputController base class to be used for IOutputController implementations. Implements IOutputController.
This interface defines additional methods for output controllers which allow for direct modification ...
override void Finish()
Finishes the output controller.
DirectStripController()
Initializes a new instance of the DirectStripController class.
The namespace DirectOutput.General contains classes for general use.
override void Init(Cabinet Cabinet)
Initializes the output controller.
static void Exception(string Message, Exception E=null)
Writes a exception message to the log.
Definition: Log.cs:144