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