2 using System.Collections.Generic;
4 using System.Reflection;
5 using System.Threading;
6 using DirectOutput.Cab;
8 using DirectOutput.General;
9 using DirectOutput.GlobalConfiguration;
10 using DirectOutput.LedControl.Loader;
11 using DirectOutput.PinballSupport;
13 using DirectOutput.Table;
14 using DirectOutput.General.Statistics;
15 using System.Diagnostics;
17 namespace DirectOutput
44 get {
return _Table; }
45 set { _Table = value; }
57 get {
return _Cabinet; }
58 set { _Cabinet = value; }
73 get {
return _Alarms; }
74 private set { _Alarms = value; }
87 get {
return _GlobalConfig; }
88 private set { _GlobalConfig = value; }
105 public void Setup(
string GlobalConfigFilename =
"",
string TableFilename =
"",
string RomName =
"")
107 bool GlobalConfigLoaded =
true;
113 if (!GlobalConfigFilename.IsNullOrWhiteSpace())
115 FileInfo GlobalConfigFile =
new FileInfo(GlobalConfigFilename);
121 GlobalConfigLoaded =
false;
138 throw new Exception(
"DirectOutput framework could not initialize global config.\n Inner exception: {0}".Build(E.Message), E);
148 FileInfo LF =
new FileInfo(
GlobalConfig.
GetLogFilename((!TableFilename.IsNullOrWhiteSpace() ?
new FileInfo(TableFilename).FullName :
""), RomName));
166 throw new Exception(
"DirectOutput framework could initialize the log file.\n Inner exception: {0}".Build(E.Message), E);
173 if (GlobalConfigLoaded)
175 Log.
Write(
"Global config loaded from: {0}".Build(GlobalConfigFilename));
179 if (!GlobalConfigFilename.IsNullOrWhiteSpace())
181 Log.
Write(
"Could not find or load theGlobalConfig file {0}".Build(GlobalConfigFilename));
185 Log.
Write(
"No GlobalConfig file loaded. Using newly instanciated GlobalConfig object instead.");
203 Log.
Write(
"Will load cabinet config file: {0}".Build(CCF.FullName));
214 Log.
Write(
"Cabinet config file has AutoConfig feature enabled. Calling AutoConfig.");
221 Log.
Exception(
"A eception occured during cabinet auto configuration", E);
225 Log.
Write(
"Cabinet config loaded successfully from {0}".Build(CCF.FullName));
229 Log.
Exception(
"A exception occured when loading cabinet config file: {0}".Build(CCF.FullName), E);
236 Log.
Warning(
"Cabinet config file {0} does not exist.".Build(CCF.FullName));
241 Log.
Write(
"No cabinet config file loaded. Will use AutoConfig.");
256 if (!TableFilename.IsNullOrWhiteSpace())
258 FileInfo TableFile =
new FileInfo(TableFilename);
262 Log.
Write(
"Will load table config from {0}".Build(TCF.FullName));
267 Log.
Write(
"Table config loaded successfully from {0}".Build(TCF.FullName));
271 Log.
Exception(
"A exception occured when loading table config: {0}".Build(TCF.FullName), E);
275 Log.
Write(
"Table config allows mix with ledcontrol configs.");
280 Log.
Warning(
"No table config file found. Will try to load config from LedControl file(s).");
285 Log.
Write(
"No TableFilename specified, will use empty tableconfig");
289 if (!RomName.IsNullOrWhiteSpace())
291 Log.
Write(
"Will try to load configs from DirectOutput.ini or LedControl.ini file(s) for RomName {0}".Build(RomName));
298 if (LedControlIniFiles.Count > 0)
301 Log.
Write(
"{0} directoutputconfig.ini or ledcontrol.ini files loaded.".Build(LedControlIniFiles.Count));
305 Log.
Write(
"No directoutputconfig.ini or ledcontrol.ini files found.");
310 Log.
Write(
"No config for table found in LedControl data for RomName {0}.".Build(RomName));
314 Log.
Write(
"Config for RomName {0} exists in LedControl data. Updating cabinet and config.".Build(RomName));
316 DirectOutput.LedControl.Setup.Configurator C =
new DirectOutput.LedControl.Setup.Configurator();
324 Version DOFVersion = typeof(
Pinball).Assembly.GetName().Version;
326 if(L.Any(LC=>LC.MinDOFVersion!=null && LC.MinDOFVersion.CompareTo(DOFVersion)>0)) {
328 Version MaxVersion = null;
337 Log.
Warning(
"UPDATE DIRECT OUTPUT FRAMEWORK!");
338 if (MaxVersion != null)
340 Log.
Warning(
"Current DOF version is {0}, but DOF version {1} or later is required by one or several config files.".Build(DOFVersion, MaxVersion));
345 Process.Start(Path.Combine(Path.GetDirectoryName( System.Reflection.Assembly.GetExecutingAssembly().Location),
"UpdateNotification.exe"));
349 Log.
Exception(
"A exception occured when displaying the update notification", E);
362 Log.
Write(
"Cant load config from directoutput.ini or ledcontrol.ini file(s) since no RomName was supplied. No ledcontrol config will be loaded.");
368 if (!TableFilename.IsNullOrWhiteSpace())
370 Table.
TableName = Path.GetFileNameWithoutExtension(
new FileInfo(TableFilename).FullName);
372 else if (!RomName.IsNullOrWhiteSpace())
377 if (!TableFilename.IsNullOrWhiteSpace())
381 if (!RomName.IsNullOrWhiteSpace())
385 Log.
Write(
"Table config loading finished");
393 Log.
Exception(
"DirectOutput framework has encountered a exception during setup.", E);
394 throw new Exception(
"DirectOutput framework has encountered a exception during setup.\n Inner exception: {0}".Build(E.Message), E);
425 Log.
Write(
"Framework initialized.");
432 Log.
Exception(
"DirectOutput framework has encountered a exception during initialization.", E);
433 throw new Exception(
"DirectOutput framework has encountered a exception during initialization.\n Inner exception: {0}".Build(E.Message), E);
456 Log.
Write(
"DirectOutput framework finished.");
457 Log.
Write(
"Bye and thanks for using!");
462 Log.
Exception(
"A exception occured while finishing the DirectOutput framework.", E);
463 throw new Exception(
"DirectOutput framework has encountered while finishing.\n Inner exception: {0}".Build(E.Message), E);
476 private void InitMainThread()
481 KeepMainThreadAlive =
true;
484 MainThread =
new Thread(MainThreadDoIt);
485 MainThread.Name =
"DirectOutput MainThread ";
492 Log.Exception(
"DirectOutput MainThread could not start.", E);
493 throw new Exception(
"DirectOutput MainThread could not start.", E);
502 private void FinishMainThread()
504 if (MainThread != null)
508 KeepMainThreadAlive =
false;
509 lock (MainThreadLocker)
511 Monitor.Pulse(MainThreadLocker);
513 if (!MainThread.Join(1000))
521 Log.Exception(
"A error occured during termination of DirectOutput MainThread", E);
522 throw new Exception(
"A error occured during termination of DirectOutput MainThread", E);
535 if (MainThread != null)
537 if (MainThread.IsAlive)
551 lock (MainThreadLocker)
553 MainThreadDoWork =
true;
554 Monitor.Pulse(MainThreadLocker);
559 private Thread MainThread {
get;
set; }
560 private object MainThreadLocker =
new object();
561 private bool KeepMainThreadAlive =
true;
562 private bool MainThreadDoWork =
false;
564 const int MaxInputDataProcessingTimeMs = 10;
572 private void MainThreadDoIt()
578 while (KeepMainThreadAlive)
580 bool UpdateRequired =
false;
581 DateTime Start = DateTime.Now;
584 while (
InputQueue.
Count > 0 && (DateTime.Now - Start).Milliseconds <= MaxInputDataProcessingTimeMs && KeepMainThreadAlive)
591 DateTime StartTime = DateTime.Now;
593 UpdateRequired |=
true;
598 Log.Exception(
"A unhandled exception occured while processing data for table element {0} {1} with value {2}".Build(D.
TableElementType, D.
Number, D.
Value), E);
604 if (KeepMainThreadAlive)
613 Log.Exception(
"A unhandled exception occured while executing timer events.", E);
620 if (UpdateRequired && KeepMainThreadAlive)
628 Log.Exception(
"A unhandled exception occured while updating the output controllers", E);
633 if (KeepMainThreadAlive)
639 lock (MainThreadLocker)
641 while (
InputQueue.
Count == 0 && NextAlarm > DateTime.Now && !MainThreadDoWork && KeepMainThreadAlive)
643 int TimeOut = ((int)(NextAlarm - DateTime.Now).TotalMilliseconds).Limit(1, 50);
645 Monitor.Wait(MainThreadLocker, TimeOut);
649 MainThreadDoWork =
false;
657 Log.Exception(
"A unexpected exception occured in the DirectOutput MainThread", E);
666 private Dictionary<TableElementTypeEnum, TimeSpanStatisticsItem> TableElementCallStatistics =
new Dictionary<TableElementTypeEnum, TimeSpanStatisticsItem>();
669 private void InitStatistics()
671 Log.Debug(
"Initializing table element statistics");
675 TableElementCallStatistics =
new Dictionary<TableElementTypeEnum, TimeSpanStatisticsItem>();
678 TSI =
new TimeSpanStatisticsItem() { Name =
"{0}".Build(T.ToString()), GroupName =
"Pinball - Table element update calls" };
679 TableElementCallStatistics.Add(T, TSI);
685 Log.Debug(
"Table element statistics initialized");
698 TableElementCallStatistics[TableElementData.
TableElementType].AddDuration(Duration);
702 Log.
Exception(
"Could not update TimeSpanStatistics for Pinball table element type {0} ({1})".Build(TableElementData.ToString(), TableElementData), E);
715 string LastGroupName =
"";
740 public void ReceiveData(
char TableElementTypeChar,
int Number,
int Value)
742 InputQueue.
Enqueue(TableElementTypeChar, Number, Value);
755 InputQueue.
Enqueue(TableElementData);
771 string S = this.GetType().FullName +
" {\n";
772 S +=
" GlobalConfig {\n";
782 S +=
" Table Effects count: " +
Table.
Effects.Count +
"\n";
787 S +=
" Output toys count: " +
Cabinet.
Toys.Count +
"\n";