public void run() { // debug messages #if (DEBUG_KEEP_SAMPLES) logger.Error("DEBUG_KEEP_SAMPLES is enabled"); #endif // check if there is no application instance if (application == null) { logger.Error("No application instance could be created"); } // log message logger.Debug("Thread started"); // local variables double[] samplePackage = null; #if (DEBUG_SAMPLES_LOG_PERFORMANCE) samplePackagesProcessed = 0; #endif // flag as running running = true; // check if the sytem should be configured and initialized at startup if (startupConfigAndInit) { if (MainThread.configureSystem()) { // successfully configured // initialize MainThread.initializeSystem(); } else { // check if there is no gui if (noGUI) { // message and do not start the process MessageBox.Show("Error during configuration, check log file", "Error during configuration", MessageBoxButtons.OK, MessageBoxIcon.Error); running = false; } } } else { // check if there is no gui if (noGUI) { // message and do not start the process MessageBox.Show("Error during startup, without a GUI and automatic startup arguments there is no way to run the program, check startup arguments", "Error during startup", MessageBoxButtons.OK, MessageBoxIcon.Error); running = false; } } // check if the system should be started at startup (and is ready to start) if (startupStartRun && systemConfigured && systemInitialized) { // start the run MainThread.start(); } // set an initial output time nextOutputTime = Stopwatch.GetTimestamp() + Stopwatch.Frequency; // loop while running while (running) { // lock for thread safety // (very much needed, else it will make calls to other modules and indirectly the data module, which already might have stopped at that point) lock (lockStarted) { // check if we are processing samples if (process) { // processing // see if there samples in the queue, pick the sample for processing samplePackage = null; lock (samplePackagesBuffer.SyncRoot) { // performance watch if (Stopwatch.GetTimestamp() > nextOutputTime) { // check if there were sample discarded the last second if (numSamplePackagesDiscarded > 0) { // message missed logger.Error("Missed " + numSamplePackagesDiscarded + " samples, because the sample buffer was full, the roundtrip of a sample through the filter and application takes longer than the sample frequency of the source"); // reset counter numSamplePackagesDiscarded = 0; } // #if (DEBUG_SAMPLES_LOG_PERFORMANCE) logger.Info("----------"); logger.Info("samples processed: " + samplePackagesProcessed); logger.Info("number of samples left in buffer: " + numSamplePackagesInBuffer); samplePackagesProcessed = 0; #endif // set the next time to output messages nextOutputTime = Stopwatch.GetTimestamp() + Stopwatch.Frequency; } // check if there are samples in the buffer to process if (numSamplePackagesInBuffer > 0) { // retrieve the sample to process (pointer to from array) samplePackage = samplePackagesBuffer[sampleBufferReadIndex]; #if (!DEBUG_KEEP_SAMPLES) // set the read index to the next item sampleBufferReadIndex++; if (sampleBufferReadIndex == sampleBufferSize) { sampleBufferReadIndex = 0; } // decrease the itemcounter as it will be processed (to make space for another item in the samples buffer) numSamplePackagesInBuffer--; #endif } } // check if there is a sample to process if (samplePackage != null) { double[] output = null; // Announce the sample at the beginning of the pipeline Data.pipelineProcessingStart(); // keep? for (int i = 0; i < plugins.Count; i++) { plugins[i].preFiltersProcess(); } // log data (the 'LogPipelineInputStreamValue' function will not log the samples if pipeline input logging is disabled) Data.logPipelineInputStreamValues(samplePackage); // TODO: // log for visualization (the 'LogVisualizationStreamValue' function will discard the sample if visualization is disabled) //Data.logVisualizationStreamValue(sample); // process the sample (filters) for (int i = 0; i < filters.Count; i++) { filters[i].process(samplePackage, out output); samplePackage = output; output = null; } // keep? for (int i = 0; i < plugins.Count; i++) { plugins[i].postFiltersProcess(); } // process the sample (application) if (application != null) { application.process(samplePackage); } // Announce the sample at the end of the pipeline Data.pipelineProcessingEnd(); // flush all plugin buffers to file Data.writePluginData(-1); #if (DEBUG_SAMPLES_LOG_PERFORMANCE) samplePackagesProcessed++; #endif } // sleep (when there are no samples) to allow for other processes if (threadLoopDelayProc != -1 && numSamplePackagesInBuffer == 0) { // reset the manual reset event, so it is sure to block on the next call to WaitOne // // Note: not using AutoResetEvent because it could happen that .Set is called while not in WaitOne yet, when // using AutoResetEvent this will cause it to skip the next WaitOne call loopManualResetEvent.Reset(); // Sleep wait loopManualResetEvent.WaitOne(threadLoopDelayProc); // using WaitOne because this wait is interruptable (in contrast to sleep) } } else { // not processing // reset the manual reset event, so it is sure to block on the next call to WaitOne // // Note: not using AutoResetEvent because it could happen that .Set is called while not in WaitOne yet, when // using AutoResetEvent this will cause it to skip the next WaitOne call loopManualResetEvent.Reset(); // Sleep wait loopManualResetEvent.WaitOne(threadLoopDelayNoProc); // using WaitOne because this wait is interruptable (in contrast to sleep) } } // end lock // check if a stop delegate wants the processing to stop if (stopDataDelegateFlag) { // stop the data Data.stop(); // reset flag stopDataDelegateFlag = false; } } // end loop (running) // stop the source, filter, view and data (if these were running) stop(true); // destroy the source if (source != null) { source.destroy(); source = null; } // destroy the filters for (int i = 0; i < filters.Count; i++) { filters[i].destroy(); } // destroy the view if (application != null) { application.destroy(); } // destroy the plugins for (int i = 0; i < plugins.Count; i++) { plugins[i].destroy(); } // destroy the data class Data.destroy(); // log message logger.Debug("Thread stopped"); }
public static void Run(string[] args, Type applicationType) { // check the endianness if (!BitConverter.IsLittleEndian) { logger.Error("This software assumes a little-endianness OS, your OS uses a big-endian system. Exiting"); return; } // TODO: check if all dependencies exists // TODO: also 32/64 bit (freetype or other dlls) // retrieve the current thread's culture as the initial culture CultureInfo culture = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone(); // startup argument variables bool nogui = false; bool startupConfigAndInit = false; bool startupStartRun = false; string parameterFile = @""; string source = ""; List <string[]> filters = new List <string[]>(); // See if we are providing a graphical user interface (GUI) // // Note: done seperately because it will detemine whether error messages are // also show as message dialogs, instead of only written to the log file for (int i = 0; i < args.Length; i++) { string argument = args[i].ToLower(); if (argument == "-nogui") { nogui = true; } } // process all startup arguments for (int i = 0; i < args.Length; i++) { string argument = args[i].ToLower(); // check if the configuration and initialization should be done automatically at startup if (argument == "-startupconfigandinit") { startupConfigAndInit = true; } // check if the run should be started automatically at startup if (argument == "-startupstartrun") { startupStartRun = true; } // check if the source is given if (argument == "-source") { // the next element should be the source, try to retrieve if (args.Length >= i + 1 && !string.IsNullOrEmpty(args[i + 1])) { // check if valid source int[] sourceIdx = ArrayHelper.jaggedArrayCompare(args[i + 1], availableSources, null, new int[] { 0 }, true); if (sourceIdx == null) { string errMessage = "Could not find the source module '" + args[i + 1] + "' requested as startup argument), choose one of the following: " + ArrayHelper.jaggedArrayJoin(", ", availableSources, 0); logger.Error(errMessage); if (!nogui) { MessageBox.Show(errMessage, "Requested source module not found", MessageBoxButtons.OK, MessageBoxIcon.Error); } return; } else { // store the source-type as a string source = availableSources[sourceIdx[0]][1]; } } } // check if the parameterfile is given if (argument == "-parameterfile") { // the next element should be the parameter file, try to retrieve if (args.Length >= i + 1 && !string.IsNullOrEmpty(args[i + 1])) { parameterFile = args[i + 1]; } } // check if the language is given if (argument == "-language") { // the next element should contain the culture name if (args.Length >= i + 1 && !string.IsNullOrEmpty(args[i + 1])) { try { // overwrite the culture with the given argument, this will cause the respective language // resource file to be used (unless it does not exists, then it will revert to english) culture = new CultureInfo(args[i + 1]); // message logger.Info("Language/culture set to '" + args[i + 1] + "'"); } catch (Exception) { // with an exception the original culture object is ruined // therefore re(clone) the current culture from the thread culture = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone(); // message logger.Error("Language argument given but unknown culture, using the local culture (language)"); } } } } // adjust decimal seperator and group seperator culture.NumberFormat.NumberDecimalSeparator = "."; culture.NumberFormat.NumberGroupSeparator = ""; culture.NumberFormat.NumberGroupSizes = new int[] { 0 }; // set the culture for every future thread and the current thread CultureInfo.DefaultThreadCurrentCulture = culture; CultureInfo.DefaultThreadCurrentUICulture = culture; Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; // try to read the pipeline modules (source and filters) from the <AppName>.Config file try { // if no valid source was parsed from a command-line argument, then try to retrieve a valid source from the <appname>.config file KeyValueConfigurationElement appConfigSource = PipelineConfigurationSection.Pipeline.Source; if (string.IsNullOrEmpty(source) && !string.IsNullOrEmpty(appConfigSource.Value)) { int[] sourceIdx = ArrayHelper.jaggedArrayCompare(appConfigSource.Value, availableSources, null, new int[] { 0 }, true); if (sourceIdx != null) { // store the source-type as a string source = availableSources[sourceIdx[0]][1]; } else { string errMessage = "Could not find the source module '" + appConfigSource.Value + "' requested in the <appname>.config file, choose one of the following: " + ArrayHelper.jaggedArrayJoin(", ", availableSources, 0); logger.Error(errMessage); if (!nogui) { MessageBox.Show(errMessage, "Requested source module not found", MessageBoxButtons.OK, MessageBoxIcon.Error); } return; } } // if no valid filters were parsed from a command-line argument, then try to retrieve valid filters from the <appname>.config file List <FilterConfigurationElement> appConfigFilters = PipelineConfigurationSection.Pipeline.Filters.All; if (filters.Count == 0 && appConfigFilters.Count > 0) { for (int iFilter = 0; iFilter < appConfigFilters.Count; iFilter++) { string filterName = appConfigFilters[iFilter].Name; string filterType = appConfigFilters[iFilter].Type; // check if valid filter int[] filterIdx = ArrayHelper.jaggedArrayCompare(filterType, availableFilters, null, new int[] { 0 }, true); if (filterIdx == null) { string errMessage = "A filter-module of the type '" + filterType + "' was requested in the <appname>.config file, but could not be found. The following filter-types are available: " + ArrayHelper.jaggedArrayJoin(", ", availableFilters, 0); logger.Error(errMessage); if (!nogui) { MessageBox.Show(errMessage, "Requested filter module not found", MessageBoxButtons.OK, MessageBoxIcon.Error); } return; } else { // add the filter as a string array with two values (filter-type and filter-name) filters.Add(new string[] { availableFilters[filterIdx[0]][1], filterName }); } } } } catch (Exception e) { string errMessage = "Error while reading the Pipeline config section in the <appname>.config file: " + e.Message; logger.Error(errMessage); if (!nogui) { MessageBox.Show(errMessage, "Error in the <appname>.config file", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } // if no source passed using command-line or <appname>.config file then allow the user to choose a source by popup if (string.IsNullOrEmpty(source)) { source = ListMessageBox.ShowSingle("Source", availableSources); if (string.IsNullOrEmpty(source)) { return; } } // // Setup and initialize Palmtree // // name this thread if (Thread.CurrentThread.Name == null) { Thread.CurrentThread.Name = "Main Thread"; } // create the main (control) object MainThread mainThread = new MainThread(startupConfigAndInit, startupStartRun, nogui); // variable for the GUI interface object GUIMain gui = null; // check if the GUI should be loaded/shown if (!nogui) { // create the GUI interface object gui = new GUIMain(); // create a GUI (as a separate process) // and pass a reference to the experiment for the GUI to pull information from and push commands to the experiment object Thread thread = new Thread(() => { // name this thread if (Thread.CurrentThread.Name == null) { Thread.CurrentThread.Name = "GUI Thread"; } // setup the GUI Application.EnableVisualStyles(); // start and run the GUI //try { Application.Run(gui); //} catch (Exception e) { //logger.Error("Exception in GUI: " + e.Message); //} // message logger.Info("GUI (thread) stopped"); }); thread.SetApartmentState(ApartmentState.STA); thread.Start(); // wait for the GUI to start or a maximum amount of 5 seconds (5.000 / 50 = 100) int waitCounter = 100; while (!gui.isLoaded() && waitCounter > 0) { Thread.Sleep(50); waitCounter--; } } // message versions logger.Info("MainBoot version " + MainBoot.getClassVersion()); logger.Info("MainThread version " + MainThread.getClassVersion()); // message if (Environment.Is64BitProcess) { logger.Debug("Processes are run in a 64 bit environment"); } else { logger.Debug("Processes are run in a 32 bit environment"); } // setup and initialize the pipeline if (mainThread.initPipeline(source, filters, applicationType)) { // check if a parameter file was given to load at startup if (!String.IsNullOrEmpty(parameterFile)) { // load parameter file to the applications parametersets ParameterManager.loadParameterFile(parameterFile, ParameterManager.getParameterSets()); } // continue to run as the main thread mainThread.run(); } else { // on failure string errMessage = "Error while initializing modules, inspect the log for more information"; logger.Error(errMessage); if (!nogui) { gui.modalMessageDelegate(errMessage, "Initialization error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } // check if there is a gui, and close it by delegate if (gui != null) { gui.closeDelegate(); gui = null; Thread.Sleep(100); // allow GUI threads to terminate, before calling Application.Exit() } // stop all the winforms (Informs all message pumps that they must terminate, and then closes all application windows after the messages have been processed.) Application.Exit(); // exit the environment Environment.Exit(0); }