2 using System.Collections.Generic;
4 using System.Runtime.InteropServices;
32 private object NumberUpdateLocker =
new object();
33 private int _Number = -1;
48 get {
return _Number; }
51 if (!value.IsBetween(1, 16))
53 throw new Exception(
"LedWiz Numbers must be between 1-16. The supplied number {0} is out of range.".Build(value));
55 lock (NumberUpdateLocker)
60 if (Name.IsNullOrWhiteSpace() || Name ==
"LedWiz {0:00}".Build(_Number))
62 Name =
"LedWiz {0:00}".Build(value);
75 private int _MinCommandIntervalMs = 1;
76 private bool MinCommandIntervalMsSet =
false;
89 public int MinCommandIntervalMs
91 get {
return _MinCommandIntervalMs; }
94 _MinCommandIntervalMs = value.Limit(0, 1000);
95 MinCommandIntervalMsSet =
true;
102 #region IOutputcontroller implementation
103 public override void Update()
109 LedWizUnits[Number].TriggerLedWizUpdaterThread();
121 Log.
Debug(
"Initializing LedWiz Nr. {0:00}".Build(Number));
128 LedWizUnits[Number].Init(Cabinet, MinCommandIntervalMs);
130 Log.
Write(
"LedWiz Nr. {0:00} initialized and updater thread initialized.".Build(Number));
140 Log.
Debug(
"Finishing LedWiz Nr. {0:00}".Build(Number));
141 LedWizUnits[Number].Finish();
142 LedWizUnits[Number].ShutdownLighting();
143 Log.
Write(
"LedWiz Nr. {0:00} finished and updater thread stopped.".Build(Number));
158 private void AddOutputs()
160 for (
int i = 1; i <= 32; i++)
162 if (!Outputs.Any(x => ((
LedWizOutput)x).LedWizOutputNumber == i))
164 Outputs.Add(
new LedWizOutput(i) { Name =
"{0}.{1:00}".Build(Name, i) });
184 throw new Exception(
"The OutputValueChanged event handler for LedWiz {0:00} has been called by a sender which is not a LedWizOutput.".Build(Number));
186 LedWizOutput LWO = (LedWizOutput)Output;
190 throw new Exception(
"LedWiz output numbers must be in the range of 1-32. The supplied output number {0} is out of range.".Build(LWO.
LedWizOutputNumber));
193 LedWizUnit S = LedWizUnits[this.Number];
227 #region LEDWIZ Static Private Methods & Properties
228 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
229 private struct LWZDEVICELIST
231 [MarshalAs(UnmanagedType.ByValArray, SizeConst = LWZ_MAX_DEVICES)]
232 public uint[] handles;
233 public int numdevices;
236 [DllImport(
"LEDWiz", CallingConvention = CallingConvention.Cdecl)]
237 private extern static void LWZ_SBA(uint device, uint bank0, uint bank1, uint bank2, uint bank3, uint globalPulseSpeed);
239 [DllImport(
"LEDWiz", CallingConvention = CallingConvention.Cdecl)]
240 private extern static void LWZ_PBA(uint device, uint brightness);
242 [DllImport(
"LEDWiz", CallingConvention = CallingConvention.Cdecl)]
243 private extern static void LWZ_REGISTER(uint h, uint hwnd);
245 [DllImport(
"LEDWiz", CallingConvention = CallingConvention.Cdecl)]
246 private extern static void LWZ_SET_NOTIFY(MulticastDelegate notifyProc, uint list);
248 private delegate
void NotifyDelegate(
int reason, uint newDevice);
250 private static IntPtr MainWindow = IntPtr.Zero;
252 private static LWZDEVICELIST deviceList;
254 private const int LWZ_MAX_DEVICES = 16;
255 private const int LWZ_ADD = 1;
256 private const int LWZ_DELETE = 2;
258 private enum AutoPulseMode :
int
260 RampUpRampDown = 129,
268 private static void Notify(
int reason, uint newDevice)
271 if (reason == LWZ_ADD)
273 LWZ_REGISTER(newDevice, (uint)MainWindow.ToInt32());
275 if (reason == LWZ_DELETE)
282 private static int NumDevices
284 get {
return deviceList.numdevices; }
287 private static uint[] DeviceHandles
289 get {
return deviceList.handles; }
292 private static int StartedUp = 0;
293 private static object StartupLocker =
new object();
294 private static void StartupLedWiz()
300 MainWindow = IntPtr.Zero;
301 deviceList.handles =
new uint[LWZ_MAX_DEVICES] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
302 deviceList.numdevices = 0;
305 NotifyDelegate del =
new NotifyDelegate(Notify);
307 IntPtr ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(LWZDEVICELIST)));
308 Marshal.StructureToPtr(deviceList, ptr,
true);
309 LWZ_SET_NOTIFY(del, (uint)ptr.ToInt32());
310 deviceList = (LWZDEVICELIST)Marshal.PtrToStructure(ptr, typeof(LWZDEVICELIST));
311 Marshal.FreeCoTaskMem(ptr);
312 Log.Debug(
"Ledwiz devicelist content. Handles: {0}, Num devices: {1}".Build(
string.Join(
", ", deviceList.handles.Select(H => H.ToString())), deviceList.numdevices));
316 Log.Exception(
"Could not init LedWiz", ex);
317 throw new Exception(
"Could not init LedWiz", ex);
325 private static void TerminateLedWiz()
335 foreach (LedWizUnit S
in LedWizUnits.Values)
337 S.ShutdownLighting();
339 LWZ_SET_NOTIFY((
System.MulticastDelegate)null, 0);
353 List<int> L =
new List<int>();
356 for (
int i = 0; i <
LedWiz.NumDevices; i++)
358 L.Add((
int)
LedWiz.DeviceHandles[i]);
386 GC.SuppressFinalize(
this);
392 protected virtual void Dispose(
bool disposing)
399 Log.
Debug(
"Disposing LedWiz instance {0:00}.".Build(Number));
425 private bool disposed =
false;
439 LedWizUnits =
new Dictionary<int, LedWizUnit>();
440 for (
int i = 1; i <= 16; i++)
442 LedWizUnits.Add(i,
new LedWizUnit(i));
467 this.Number = Number;
477 #region Internal class for LedWiz output states and update methods
479 private static Dictionary<int, LedWizUnit> LedWizUnits =
new Dictionary<int, LedWizUnit>();
481 private class LedWizUnit
489 private static readonly byte[] ByteToLedWizValue = { 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, 49 };
490 private const int MaxUpdateFailCount = 5;
493 public int Number {
get;
private set; }
495 public byte[] NewOutputValues =
new byte[32] { 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49 };
496 public byte[] CurrentOuputValues =
new byte[32];
497 public byte[] NewAfterValueSwitches =
new byte[4];
498 public byte[] NewBeforeValueSwitches =
new byte[4];
499 public byte[] CurrentAfterValueSwitches =
new byte[4];
500 public byte[] CurrentBeforeValueSwitches =
new byte[4];
501 public bool NewValueUpdateRequired =
true;
502 public bool NewSwitchUpdateBeforeValueUpdateRequired =
true;
503 public bool NewSwitchUpdateAfterValueUpdateRequired =
true;
505 public bool CurrentValueUpdateRequired =
true;
506 public bool CurrentSwitchUpdateBeforeValueUpdateRequired =
true;
507 public bool CurrentSwitchUpdateAfterValueUpdateRequired =
true;
508 public bool UpdateRequired =
true;
510 public object LedWizUpdateLocker =
new object();
511 public object ValueChangeLocker =
new object();
513 public Thread LedWizUpdater;
514 public bool KeepLedWizUpdaterAlive =
false;
515 public object LedWizUpdaterThreadLocker =
new object();
518 public void Init(Cabinet Cabinet,
int MinCommandIntervalMs)
548 this.MinCommandIntervalMs = MinCommandIntervalMs;
549 StartLedWizUpdaterThread();
555 TerminateLedWizUpdaterThread();
561 public void UpdateValue(LedWizOutput LedWizOutput)
563 byte V = ByteToLedWizValue[LedWizOutput.Value];
566 int ZeroBasedOutputNumber = LedWizOutput.LedWizOutputNumber - 1;
568 int ByteNr = ZeroBasedOutputNumber >> 3;
569 int BitNr = ZeroBasedOutputNumber & 7;
571 byte Mask = (byte)(1 << BitNr);
573 lock (ValueChangeLocker)
575 if (S != ((NewAfterValueSwitches[ByteNr] & Mask) != 0))
582 NewAfterValueSwitches[ByteNr] &= Mask;
583 NewBeforeValueSwitches[ByteNr] &= Mask;
584 NewSwitchUpdateBeforeValueUpdateRequired =
true;
585 UpdateRequired =
true;
590 if (V != NewOutputValues[ZeroBasedOutputNumber])
593 NewOutputValues[ZeroBasedOutputNumber] = V;
594 NewAfterValueSwitches[ByteNr] |= Mask;
595 NewValueUpdateRequired =
true;
596 NewSwitchUpdateAfterValueUpdateRequired =
true;
597 UpdateRequired =
true;
602 NewAfterValueSwitches[ByteNr] |= Mask;
603 NewBeforeValueSwitches[ByteNr] |= Mask;
604 NewSwitchUpdateBeforeValueUpdateRequired =
true;
605 UpdateRequired =
true;
611 if (S ==
true && V != NewOutputValues[ZeroBasedOutputNumber])
614 NewOutputValues[ZeroBasedOutputNumber] = V;
615 NewValueUpdateRequired =
true;
616 UpdateRequired =
true;
622 public void CopyNewToCurrent()
624 lock (ValueChangeLocker)
627 CurrentValueUpdateRequired = NewValueUpdateRequired;
628 CurrentSwitchUpdateBeforeValueUpdateRequired = NewSwitchUpdateBeforeValueUpdateRequired;
629 CurrentSwitchUpdateAfterValueUpdateRequired = NewSwitchUpdateAfterValueUpdateRequired;
632 if (NewValueUpdateRequired)
634 Array.Copy(NewOutputValues, CurrentOuputValues, NewOutputValues.Length);
635 NewValueUpdateRequired =
false;
637 if (NewSwitchUpdateAfterValueUpdateRequired || NewSwitchUpdateBeforeValueUpdateRequired)
639 Array.Copy(NewAfterValueSwitches, CurrentAfterValueSwitches, NewAfterValueSwitches.Length);
640 Array.Copy(NewBeforeValueSwitches, CurrentBeforeValueSwitches, NewBeforeValueSwitches.Length);
641 Array.Copy(CurrentAfterValueSwitches, NewBeforeValueSwitches, NewAfterValueSwitches.Length);
642 NewSwitchUpdateAfterValueUpdateRequired =
false;
643 NewSwitchUpdateBeforeValueUpdateRequired =
false;
651 public bool IsUpdaterThreadAlive
655 if (LedWizUpdater != null)
657 return LedWizUpdater.IsAlive;
663 public void StartLedWizUpdaterThread()
665 lock (LedWizUpdaterThreadLocker)
667 if (!IsUpdaterThreadAlive)
669 KeepLedWizUpdaterAlive =
true;
670 LedWizUpdater =
new Thread(LedWizUpdaterDoIt);
671 LedWizUpdater.Name =
"LedWiz {0:00} updater thread".Build(Number);
672 LedWizUpdater.Start();
676 public void TerminateLedWizUpdaterThread()
680 if (LedWizUpdater != null)
684 KeepLedWizUpdaterAlive =
false;
685 TriggerLedWizUpdaterThread();
686 if (!LedWizUpdater.Join(1000))
688 LedWizUpdater.Abort();
694 Log.Exception(
"A error occurd during termination of {0}.".Build(LedWizUpdater.Name), E);
695 throw new Exception(
"A error occurd during termination of {0}.".Build(LedWizUpdater.Name), E);
697 LedWizUpdater = null;
702 bool TriggerUpdate =
false;
703 public void TriggerLedWizUpdaterThread()
705 TriggerUpdate =
true;
706 lock (LedWizUpdaterThreadLocker)
708 Monitor.Pulse(LedWizUpdaterThreadLocker);
714 private void LedWizUpdaterDoIt()
716 Log.Write(
"Updater thread for LedWiz {0:00} started.".Build(Number));
721 while (KeepLedWizUpdaterAlive)
735 Log.Exception(
"A error occured when updating LedWiz Nr. {0}".Build(Number), E);
739 if (FailCnt > MaxUpdateFailCount)
741 Log.Exception(
"More than {0} consecutive updates failed for LedWiz Nr. {1}. Updater thread will terminate.".Build(MaxUpdateFailCount, Number));
742 KeepLedWizUpdaterAlive =
false;
746 if (KeepLedWizUpdaterAlive)
748 lock (LedWizUpdaterThreadLocker)
750 while (!TriggerUpdate && KeepLedWizUpdaterAlive)
752 Monitor.Wait(LedWizUpdaterThreadLocker, 50);
759 TriggerUpdate =
false;
762 Log.Write(
"Updater thread for LedWiz {0:00} terminated.".Build(Number));
767 private DateTime LastUpdate = DateTime.Now;
768 public int MinCommandIntervalMs = 1;
769 private void UpdateDelay()
771 int Ms = (int)DateTime.Now.Subtract(LastUpdate).TotalMilliseconds;
772 if (Ms < MinCommandIntervalMs)
774 Thread.Sleep((MinCommandIntervalMs - Ms).Limit(0, MinCommandIntervalMs));
776 LastUpdate = DateTime.Now;
779 private void SendLedWizUpdate()
781 if (Number.IsBetween(1, 16))
784 lock (LedWizUpdateLocker)
786 lock (ValueChangeLocker)
788 if (!UpdateRequired)
return;
793 UpdateRequired =
false;
797 if (CurrentValueUpdateRequired)
799 if (CurrentSwitchUpdateBeforeValueUpdateRequired)
803 SBA(CurrentBeforeValueSwitches[0], CurrentBeforeValueSwitches[1], CurrentBeforeValueSwitches[2], CurrentBeforeValueSwitches[3], 2);
809 PBA(CurrentOuputValues);
812 if (CurrentSwitchUpdateAfterValueUpdateRequired || (CurrentSwitchUpdateBeforeValueUpdateRequired && !NewValueUpdateRequired))
816 SBA(CurrentAfterValueSwitches[0], CurrentAfterValueSwitches[1], CurrentAfterValueSwitches[2], CurrentAfterValueSwitches[3], 2);
825 public void ShutdownLighting()
831 private void SBA(uint bank1, uint bank2, uint bank3, uint bank4, uint globalPulseSpeed)
835 LWZ_SBA((uint)Number, bank1, bank2, bank3, bank4, globalPulseSpeed);
839 private void PBA(byte[] val)
843 IntPtr ptr = Marshal.AllocCoTaskMem(val.Length);
844 Marshal.Copy(val, 0, ptr, val.Length);
845 LWZ_PBA((uint)Number, (uint)ptr.ToInt32());
846 Marshal.FreeCoTaskMem(ptr);
850 private bool IsPresent
854 if (!Number.IsBetween(1, 16))
return false;
855 return DeviceHandles.Any(x => x == Number);
860 public LedWizUnit(
int Number)
862 this.Number = Number;
override void Init(Cabinet Cabinet)
Initializes the LedWiz object. This method does also start the workerthread which does the actual up...
The Cabinet object describes the parts of a pinball cabinet (toys, outputcontrollers, outputs and more).
int LedWizOutputNumber
Number of the Output of the LedWiz.
virtual void Dispose(bool disposing)
Releases unmanaged and - optionally - managed resources.
override void OnOutputValueChanged(IOutput Output)
This method is called whenever the value of a output in the Outputs property changes its value...
void Dispose()
Disposes the LedWiz object.
ICabinetOwner Owner
Gets or sets the owner or the cabinet.
LedWiz(int Number)
Initializes a new instance of the LedWiz class.
static void Write(string Message)
Writes the specified message to the logfile.
A simple logger used to record important events and exceptions.
static void Debug(string Message="")
Writes the specified debug message to the log file.
Common interface for outputs of any output controller. The Output class implements this interface and...
Abstract OutputController base class to be used for IOutputController implementations. Implements IOutputController.
Common interface for all outputcontrollers. Only classes implementing this interface can be used as o...
Dictionary< string, object > ConfigurationSettings
Gets the configuration settings. This dict can contain settings which are used by the output controll...
LedWiz()
Initializes a new instance of the LedWiz class.
Output class for LedWiz output controllers.
The LedWiz is a easy to use outputcontroller with 32 outputs which all support 49 pwm levels with a P...
override void Finish()
Finishes the LedWiz object. Finish does also terminate the workerthread for updates.
static List< int > GetLedwizNumbers()
Gets the numbers of the LedWiz controllers which are connected to the system.
Basic IOutput implementation.