static void Main(string[] args) { // if the app is already running, make the already running app window the foreground window and exit this instance bool singleInstanceOnly = false; bool.TryParse(ConfigurationManager.AppSettings["AllowSingleHulkamaniaInstanceOnly"], out singleInstanceOnly); if (singleInstanceOnly && IsAlreadyRunning()) { System.Environment.Exit(0); return; } MainForm mainForm; try { // Set up logging XmlConfigurator.ConfigureAndWatch(new FileInfo(LOGGING_CONFIG_FILE)); logger.Info("********** Starting Hulkamania **********"); // parse command line mUseDummyMotionController = (Array.IndexOf(args, "UseDummyMotionControl") >= 0); logger.Info("Checking 'UseDummyMotionControl' command line argument: using " + (mUseDummyMotionController ? "Dummy" : "HULK") + " motion controller"); // Disable screensaver SystemParametersInfo(SPI.SPI_SETSCREENSAVEACTIVE, 0, 0, SPIF.None); // Check if required data output folder exists DataLogger.CheckIfRequiredFoldersExist(true); // Start the thread that will control the Hulk MotionController.Instance.CheckModalErrors(); controllerThread = new Thread(Hulk.ControlHulk) { Priority = ThreadPriority.Highest }; controllerThread.Start(); // Set up handlers to deal with any exceptions not caught elsewhere in the application AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; Application.ThreadException += OnUnhandledGuiException; // Find available tasks baseDirectory = Path.GetDirectoryName(Application.ExecutablePath); LoadAvailableTasks(); // Start the network server startServer(); statusTransmitter.initialize(serverHandler); // Start the main form, which will run until it is closed by the user Application.EnableVisualStyles(); mainForm = MainForm.GetMainForm(); Application.Run(mainForm); statusTransmitter.shutdown(); stopServer(); } catch (Exception e) { HandleUnhandledException(e); } try { // Turn the screensaver back on SystemParametersInfo(SPI.SPI_SETSCREENSAVEACTIVE, 1, 0, SPIF.None); // Close the main control loop thread. Hulk.KeepRunning = false; // Stop the network server stopServer(); } catch (Exception e) { HandleUnhandledException(e); } logger.Info("********** Quitting Hulkamania **********"); Application.Exit(); }
/// <summary> /// The main control loop. /// </summary> internal static void ControlHulk() { bool joystickMessageGiven; bool lightMessageGiven; logger.Debug("Enter: ControlHulk()"); logger.Info("Control loop starting."); // Check frames-per-second once every second frameTime = DateTime.Now.AddSeconds(1.0); updateCounter = 0; updateRate = 0; joystickMessageGiven = false; lightMessageGiven = false; // Do the control loop until a signal is sent to stop keepRunning = true; do { // Record the frames-per-second if (DateTime.Now.CompareTo(frameTime) >= 0) { updateRate = updateCounter; frameTime = DateTime.Now.AddSeconds(1.0); updateCounter = 1; } else { updateCounter++; } // Make sure that joystick input is possible if (InputController.IsJoystickConnected) { joystickMessageGiven = false; } else { InputController.AcquireJoystick(); if (!InputController.IsJoystickConnected) { if (!joystickMessageGiven) { // if no joystick connection is detected, the following code needs to be executed just once. Piggyback on the joystickMessageGiven functionality to do this, // since that message is logged once as well // if a task is currently executing, halt execution switch (status) { case Status.Task: case Status.TaskExecuting: case Status.Executing: Hulk.Halt(); // Stop the currently executing task to prevent the task from continuing where it left off once the joystick is plugged back in if (AppMain.CurrentTask != null) { AppMain.CurrentTask.StopTask(); } status = Status.Idling; break; default: break; } // put the HULK in the loading position Hulk.Loading(null); logger.Warn("Joystick must be plugged in to continue."); joystickMessageGiven = true; } continue; } } // See if safety lights show readiness for commands if (DataController.Instance.IsLightGreen) { Hulk.Halt(); if (!lightMessageGiven) { logger.Warn("Light must be red to continue."); lightMessageGiven = true; } Thread.Sleep(250); continue; } else { if (lightMessageGiven) { logger.Info("Red light detected."); lightMessageGiven = false; } } // Is this program ready to send commands? if (!DataController.Instance.PCReady) { Thread.Sleep(250); continue; } // See if PLC is still ready to receive commands if (!DataController.Instance.PLCReady) { Thread.Sleep(250); continue; } // If needed, initiate mayday if (DataController.Instance.IsMaydayPressed) { //Mayday(null); ThreadPool.QueueUserWorkItem(new WaitCallback(Mayday)); } // Check if the motion control board is reporting an error MotionController.Instance.CheckModalErrors(); // Notify programs of current HULK motion MotionController.Instance.ReadCurrentMotion(updateRate); if (AppMain.CurrentTask != null) { AppMain.CurrentTask.LogBasicData(); AppMain.CurrentTask.UpdateNetworkClients(); } switch (status) { case Status.Task: AppMain.CurrentTask.ContinueTask(); break; case Status.TaskExecuting: if (MotionController.Instance.IsMoveComplete()) { status = Status.Task; } break; case Status.Stopping: AppMain.CurrentTask.StopTask(); status = Status.Idling; break; case Status.Homing: ContinueHoming(); break; case Status.Executing: if (MotionController.Instance.IsMoveComplete()) { status = Status.Idling; } break; } } while (keepRunning); // Program is exiting. Perform any necessary cleanup. DataLogger.ReleaseDataLog(); InputController.ReleaseInputDevices(); Halt(); DataController.Instance.PCReady = false; DataController.Instance.StopTasks(); logger.Info("Control loop has exited."); }