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
ArtNet.cs
Go to the documentation of this file.
1 using System;
2 using System.Threading;
3 using DirectOutput.Cab.Out.DMX.ArtnetEngine;
4 using System.Xml.Serialization;
5 using System.Linq;
6 
7 namespace DirectOutput.Cab.Out.DMX
8 {
21  {
22 
23  private Engine Engine = null;
24  private byte[] DMXData = new byte[512];
25  private int LastDMXChannel = 0;
26  private bool UpdateRequired = true;
27  private object UpdateLocker = new object();
28 
29  private short _Universe = 0;
30 
37  public short Universe
38  {
39  get { return _Universe; }
40  set { _Universe = value; }
41  }
42 
43  private string _BroadcastAddress="";
44 
53  public string BroadcastAddress
54  {
55  get { return _BroadcastAddress; }
56  set { _BroadcastAddress = value; }
57  }
58 
59 
60 
64  private void AddOutputs()
65  {
66  for (int i = 1; i <= 512; i++)
67  {
68  if (!Outputs.Any(x => ((DMXOutput)x).DmxChannel == i))
69  {
70  Outputs.Add(new DMXOutput() { Name = "{0}.{1:000}".Build(Name, i), DmxChannel=i });
71  }
72  }
73  }
74 
82  protected override void OnOutputValueChanged(IOutput Output)
83  {
84  if (!(Output is DMXOutput))
85  {
86  throw new Exception("The OutputValueChanged event handler for ArtNet node {0} (controlling Dmx universe {1}) has been called by a sender which is not a DmxOutput.".Build(Name, Universe));
87  }
88 
89  DMXOutput O = (DMXOutput)Output;
90 
91  if (!O.DmxChannel.IsBetween(1, 512))
92  {
93  Log.Exception("ArtNet node {0} has received a update for a illegal dmx channel number ({1}).".Build(Name, O.DmxChannel));
94  throw new ArgumentOutOfRangeException("ArtNet node {0} has received a update for a illegal dmx channel number ({1}).".Build(Name, O.DmxChannel));
95 
96  }
97 
98  lock (UpdateLocker)
99  {
100  if (DMXData[O.DmxChannel - 1] != O.Value)
101  {
102  DMXData[O.DmxChannel - 1] = O.Value;
103  if (O.DmxChannel > LastDMXChannel)
104  {
105  LastDMXChannel = O.DmxChannel;
106  }
107  UpdateRequired = true;
108  }
109  }
110  }
111 
112 
113 
118  public override void Update()
119  {
120  if (UpdateRequired)
121  {
122  UpdaterThreadSignal();
123  }
124  }
125 
131  public override void Init(Cabinet Cabinet)
132  {
133  AddOutputs();
134 
135 
136  InitUpdaterThread();
137 
138  Log.Write("ArtNet node {0} (controlling universe {1}) initialized and updater thread started.".Build(Name,Universe));
139  }
140 
144  public override void Finish()
145  {
146  FinishUpdaterThread();
147  Log.Write("ArtNet node {0} (controlling universe {1}) finished and updater thread stopped.".Build(Name, Universe));
148 
149  }
150 
151 
152 
153  #region UpdaterThread
154 
155 
156 
157 
158  private void InitUpdaterThread()
159  {
160 
161  if (!UpdaterThreadIsActive)
162  {
163  KeepUpdaterThreadAlive = true;
164  try
165  {
166  UpdaterThread = new Thread(UpdaterThreadDoIt);
167  UpdaterThread.Name = "ArtNet node {0} updater thread ".Build(Name);
168  UpdaterThread.Start();
169  }
170  catch (Exception E)
171  {
172  Log.Exception("Artnet node {0} updater thread could not start.".Build(Name), E);
173  throw new Exception("Artnet node {0} updater thread could not start.".Build(Name), E);
174  }
175  }
176  }
177 
182  private void FinishUpdaterThread()
183  {
184  if (UpdaterThread != null)
185  {
186  try
187  {
188  KeepUpdaterThreadAlive = false;
189  lock (UpdaterThreadLocker)
190  {
191  Monitor.Pulse(UpdaterThreadLocker);
192  }
193  if (!UpdaterThread.Join(1000))
194  {
195  UpdaterThread.Abort();
196  }
197  UpdaterThread = null;
198  }
199  catch (Exception E)
200  {
201  Log.Exception("A error occured during termination of ArtNet updater thread.", E);
202  throw new Exception("A error occured during termination of ArtNet updater thread.", E);
203  }
204  }
205  }
206 
207 
211  public bool UpdaterThreadIsActive
212  {
213  get
214  {
215  if (UpdaterThread != null)
216  {
217  if (UpdaterThread.IsAlive)
218  {
219  return true;
220  }
221  }
222  return false;
223  }
224  }
225 
229  private void UpdaterThreadSignal()
230  {
231 
232  lock (UpdaterThreadLocker)
233  {
234  Monitor.Pulse(UpdaterThreadLocker);
235  }
236  }
237 
238 
239  private Thread UpdaterThread { get; set; }
240  private object UpdaterThreadLocker = new object();
241  private bool KeepUpdaterThreadAlive = true;
242 
243 
244 
245 
249  private void UpdaterThreadDoIt()
250  {
251  if (Engine == null)
252  {
254 
255  }
256 
257  //Send all channels to ensure that there are defined values
258  Engine.SendDMX(BroadcastAddress,Universe, DMXData, 512);
259 
260  while (KeepUpdaterThreadAlive)
261  {
262 
263  if (UpdateRequired)
264  {
265  lock (UpdateLocker)
266  {
267  UpdateRequired = false;
268  Engine.SendDMX(BroadcastAddress, Universe, DMXData, 512);// ((LastDMXChannel | 1) + 1).Limit(2, 512));
269  }
270 
271  }
272 
273  if (KeepUpdaterThreadAlive)
274  {
275  lock (UpdaterThreadLocker)
276  {
277  while (UpdateRequired == false && KeepUpdaterThreadAlive)
278  {
279  Monitor.Wait(UpdaterThreadLocker, 50); // Lock is released while we’re waiting
280  }
281  }
282  }
283 
284  }
285  Engine.SendDMX(BroadcastAddress, Universe, new byte[512], 512);
286 
287 
288  if (Engine != null)
289  {
290 
291  Engine = null;
292  }
293 
294  }
295  #endregion
296 
297 
301  public ArtNet() {
302  Outputs = new OutputList();
303 
304  }
305 
306 
307 
308  }
309 }