2 using System.Collections.Generic;
5 using System.Runtime.InteropServices;
6 using System.Threading;
7 using System.Xml.Serialization;
8 using DirectOutput.General;
9 using DirectOutput.General.Statistics;
11 namespace DirectOutput.Cab.Out.Pac
27 #region IOutputcontroller implementation
31 public override void Update()
33 PacDriveInstance.TriggerPacDriveUpdaterThread();
46 PacDriveInstance.Init(Cabinet);
47 Log.
Write(
"PacDrive initialized and updater thread started.");
55 public override void Finish()
57 PacDriveInstance.Finish();
58 PacDriveInstance.ShutdownLighting();
59 Log.
Write(
"PacDrive finished and updater thread stopped.");
73 private void AddOutputs()
75 for (
int i = 1; i <= 16; i++)
79 Outputs.Add(
new OutputNumbered() { Name =
"{0}.{1:00}".Build(Name, i), Number = i });
102 throw new Exception(
"The OutputValueChanged event handler for the PacDrive uni has been called by a sender which is not a OutputNumbered.");
104 OutputNumbered ON = (OutputNumbered)Output;
106 if (!ON.
Number.IsBetween(1, 64))
108 throw new Exception(
"PacDrive output numbers must be in the range of 1-16. The supplied output number {0} is out of range.".Build(ON.
Number));
111 PacDriveInstance.UpdateValue(ON);
181 PacDriveInstance =
new PacDriveUnit();
203 #region Internal class for PacDrive output states and update methods
205 private static PacDriveUnit PacDriveInstance=null;
207 private class PacDriveUnit
213 private const int MaxUpdateFailCount = 5;
217 private ushort NewValue;
218 private ushort CurrentValue;
219 private bool UpdateRequired =
true;
221 private int Index = -1;
223 public object PacDriveUpdateLocker =
new object();
224 public object ValueChangeLocker =
new object();
226 public Thread PacDriveUpdater;
227 public bool KeepPacDriveUpdaterAlive =
false;
228 public object PacDriveUpdaterThreadLocker =
new object();
236 UpdateTimeStatistics =
new TimeSpanStatisticsItem() { Name =
"PacDrive update calls", GroupName =
"OutputControllers - PacDrive" };
244 StartPacDriveUpdaterThread();
250 TerminatePacDriveUpdaterThread();
253 UpdateTimeStatistics = null;
256 public void UpdateValue(OutputNumbered OutputNumbered)
259 if (!OutputNumbered.Number.IsBetween(1, 16))
return;
261 int ZeroBasedOutputNumber = OutputNumbered.Number - 1;
262 ushort Mask = (ushort)(1 << ZeroBasedOutputNumber);
263 lock (ValueChangeLocker)
265 if (OutputNumbered.Value != 0)
271 NewValue &= (ushort)~Mask;
273 UpdateRequired =
true;
277 private void CopyNewToCurrent()
279 lock (ValueChangeLocker)
281 CurrentValue = NewValue;
286 public bool IsUpdaterThreadAlive
290 if (PacDriveUpdater != null)
292 return PacDriveUpdater.IsAlive;
298 public void StartPacDriveUpdaterThread()
300 lock (PacDriveUpdaterThreadLocker)
302 if (!IsUpdaterThreadAlive)
304 KeepPacDriveUpdaterAlive =
true;
305 PacDriveUpdater =
new Thread(PacDriveUpdaterDoIt);
306 PacDriveUpdater.Name =
"PacDrive updater thread";
307 PacDriveUpdater.Start();
311 public void TerminatePacDriveUpdaterThread()
313 lock (PacDriveUpdaterThreadLocker)
315 if (PacDriveUpdater != null)
319 KeepPacDriveUpdaterAlive =
false;
320 lock (PacDriveUpdater)
322 Monitor.Pulse(PacDriveUpdater);
324 if (!PacDriveUpdater.Join(1000))
326 PacDriveUpdater.Abort();
332 Log.Exception(
"A error occurd during termination of {0}.".Build(PacDriveUpdater.Name), E);
333 throw new Exception(
"A error occurd during termination of {0}.".Build(PacDriveUpdater.Name), E);
335 PacDriveUpdater = null;
340 bool TriggerUpdate =
false;
341 public void TriggerPacDriveUpdaterThread()
343 if (!UpdateRequired)
return;
344 TriggerUpdate =
true;
345 UpdateRequired =
false;
346 lock (PacDriveUpdaterThreadLocker)
348 Monitor.Pulse(PacDriveUpdaterThreadLocker);
354 private void PacDriveUpdaterDoIt()
360 while (KeepPacDriveUpdaterAlive)
366 UpdateTimeStatistics.MeasurementStart();
367 SendPacDriveUpdate();
368 UpdateTimeStatistics.MeasurementStop();
374 Log.Exception(
"A error occured when updating PacDrive", E);
378 if (FailCnt > MaxUpdateFailCount)
380 Log.Exception(
"More than {0} consecutive updates failed for PacDrive. Updater thread will terminate.".Build(MaxUpdateFailCount));
381 KeepPacDriveUpdaterAlive =
false;
385 if (KeepPacDriveUpdaterAlive)
387 lock (PacDriveUpdaterThreadLocker)
389 while (!TriggerUpdate && KeepPacDriveUpdaterAlive)
391 Monitor.Wait(PacDriveUpdaterThreadLocker, 50);
398 TriggerUpdate =
false;
408 private bool ForceFullUpdate =
true;
409 private void SendPacDriveUpdate()
414 lock (PacDriveUpdateLocker)
416 lock (ValueChangeLocker)
418 if (NewValue == CurrentValue && !ForceFullUpdate)
return;
425 PDSingleton.PacDriveUHIDSetLEDStates(Index, CurrentValue);
428 ForceFullUpdate =
false;
432 ForceFullUpdate =
true;
437 public void ShutdownLighting()
439 lock (PacDriveUpdateLocker)
441 lock (ValueChangeLocker)
446 PDSingleton.PacDriveUHIDSetLEDStates(Index, 0);
453 private bool IsPresent
462 void Instance_OnPacRemoved(
int Index)
464 this.Index = PDSingleton.PacDriveGetIndex();
467 void Instance_OnPacAttached(
int Index)
469 this.Index = PDSingleton.PacDriveGetIndex();
471 TriggerPacDriveUpdaterThread();
474 private void InitUnit()
476 lock (ValueChangeLocker)
479 CurrentValue = 65535;
481 SendPacDriveUpdate();
485 public PacDriveUnit()
487 PDSingleton = PacDriveSingleton.Instance;
488 PDSingleton.OnPacAttached +=
new PacDriveSingleton.PacAttachedDelegate(Instance_OnPacAttached);
489 PDSingleton.OnPacRemoved +=
new PacDriveSingleton.PacRemovedDelegate(Instance_OnPacRemoved);
490 this.Index = PacDriveSingleton.Instance.PacDriveGetIndex();