/// <summary>
        /// Check if another instance is already running
        /// </summary>
        /// <returns>True if another instance is running</returns>
        private static async Task <bool> CheckForAnotherInstance()
        {
            using DuetAPIClient.CommandConnection connection = new DuetAPIClient.CommandConnection();
            try
            {
                await connection.Connect(Settings.FullSocketPath);
            }
            catch (SocketException)
            {
                return(false);
            }

            if (Settings.UpdateOnly)
            {
                Console.Write("Sending update request to DCS... ");
                try
                {
                    await connection.PerformCode(new DuetAPI.Commands.Code
                    {
                        Type        = DuetAPI.Commands.CodeType.MCode,
                        MajorNumber = 997,
                        Flags       = DuetAPI.Commands.CodeFlags.IsPrioritized
                    });

                    Console.WriteLine("Done!");
                }
                catch
                {
                    Console.WriteLine("Error: Failed to send update request");
                    throw;
                }
                finally
                {
                    CancelSource.Cancel();
                }
            }
            else
            {
                _logger.Fatal("Another instance is already running. Stopping.");
            }
            return(true);
        }
Esempio n. 2
0
        /// <summary>
        /// Entry point of the program
        /// </summary>
        /// <param name="args">Command-line arguments</param>
        /// <returns>Asynchronous task</returns>
        static async Task Main(string[] args)
        {
            // Check if only the firmware is supposed to be updated
            foreach (string arg in args)
            {
                if (arg == "-u" || arg == "--update")
                {
                    UpdateOnly = true;
                    break;
                }
            }

            // Display welcome message
            WriteLine($"Duet Control Server v{Assembly.GetExecutingAssembly().GetName().Version}");
            WriteLine("Written by Christian Hammacher for Duet3D");
            WriteLine("Licensed under the terms of the GNU Public License Version 3");
            WriteLine();

            // Initialize settings
            Write("Loading settings... ");
            try
            {
                Settings.Init(args);
                WriteLine("Done!");
            }
            catch (Exception e)
            {
                Console.WriteLine($"Error: {e.Message}");
                return;
            }

            // Check if another instance is already running
            using (DuetAPIClient.CommandConnection testConnection = new DuetAPIClient.CommandConnection())
            {
                try
                {
                    await testConnection.Connect(Settings.SocketPath);

                    if (UpdateOnly)
                    {
                        Console.Write("Sending update request to DCS... ");
                        try
                        {
                            await testConnection.PerformCode(new DuetAPI.Commands.Code
                            {
                                Type        = DuetAPI.Commands.CodeType.MCode,
                                MajorNumber = 997,
                                Flags       = DuetAPI.Commands.CodeFlags.IsPrioritized
                            });

                            Console.WriteLine("Done!");
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine($"Error: {e.Message}");
                        }
                    }
                    else
                    {
                        Console.WriteLine("Error: Another instance is already running. Stopping.");
                    }
                    return;
                }
                catch
                {
                    // expected
                }
            }

            // Initialise object model
            Write("Initialising variables... ");
            try
            {
                Commands.Code.InitScheduler();
                Model.Provider.Init();
                Model.Observer.Init();
                WriteLine("Done!");
            }
            catch (Exception e)
            {
                Console.WriteLine($"Error: {e.Message}");
                return;
            }

            // Connect to RRF controller
            Write("Connecting to RepRapFirmware... ");
            try
            {
                SPI.Interface.Init();
                if (!SPI.Interface.Connect())
                {
                    Console.WriteLine("Error: Duet is not available");
                    return;
                }
                WriteLine("Done!");
            }
            catch (AggregateException ae)
            {
                Console.WriteLine($"Error: {ae.InnerException.Message}");
                return;
            }

            // Start up IPC server
            Write("Creating IPC socket... ");
            try
            {
                Server.CreateSocket();
                WriteLine("Done!");
            }
            catch (Exception e)
            {
                Console.WriteLine($"Error: {e.Message}");
                return;
            }

            WriteLine();

            // Start main tasks in the background
            Task spiTask            = Task.Run(SPI.Interface.Run, CancelSource.Token);
            Task ipcTask            = Task.Run(Server.AcceptConnections, CancelSource.Token);
            Task updateTask         = Task.Run(Model.Updater.ProcessUpdates, CancelSource.Token);
            Task periodicUpdateTask = Task.Run(Model.UpdateTask.UpdatePeriodically, CancelSource.Token);

            Task[] taskList = { spiTask, ipcTask, updateTask, periodicUpdateTask };

            // Deal with program termination requests (SIGTERM) and wait for program termination
            AppDomain.CurrentDomain.ProcessExit += (sender, eventArgs) =>
            {
                if (!CancelSource.IsCancellationRequested)
                {
                    Console.WriteLine("[info] Received SIGTERM, shutting down...");
                    CancelSource.Cancel();
                }
            };

            await Task.WhenAny(taskList);

            // Tell other tasks to stop in case this is an abnormal program termination
            if (UpdateOnly)
            {
                CancelSource.Cancel();
            }
            else if (!CancelSource.IsCancellationRequested)
            {
                Console.Write("[crit] Abnormal program termination: ");
                if (spiTask.IsCompleted)
                {
                    Console.WriteLine("SPI task terminated");
                }
                if (ipcTask.IsCompleted)
                {
                    Console.WriteLine("IPC task terminated");
                }
                if (updateTask.IsCompleted)
                {
                    Console.WriteLine("Update task terminated");
                }
                if (periodicUpdateTask.IsCompleted)
                {
                    Console.WriteLine("Periodic update task terminated");
                }
                CancelSource.Cancel();
            }

            // Stop logging
            await Utility.Logger.Stop();

            // Stop the IPC subsystem. This has to happen here because Socket.AcceptAsync() does not have a CancellationToken parameter
            Server.Shutdown();

            // Wait for all tasks to finish
            try
            {
                // Do not use Task.WhenAll() here because it does not throw exceptions for already completed tasks
                Task.WaitAll(taskList);
            }
            catch (AggregateException ae)
            {
                foreach (Exception e in ae.InnerExceptions)
                {
                    if (!(e is OperationCanceledException))
                    {
                        Console.Write("[crit] ");
                        Console.WriteLine(e);
                    }
                }
            }
        }
        /// <summary>
        /// Entry point of the program
        /// </summary>
        /// <param name="args">Command-line arguments</param>
        static void Main(string[] args)
        {
            Console.WriteLine($"Duet Control Server v{Assembly.GetExecutingAssembly().GetName().Version}");
            Console.WriteLine("Written by Christian Hammacher for Duet3D");
            Console.WriteLine("Licensed under the terms of the GNU Public License Version 3");
            Console.WriteLine();

            // Deal with program termination requests (SIGTERM)
            AppDomain.CurrentDomain.ProcessExit += (sender, eventArgs) => CancelSource.Cancel();

            // Initialise settings
            Console.Write("Loading settings... ");
            try
            {
                Settings.Load(args);
                Console.WriteLine("Done!");
            }
            catch (Exception e)
            {
                Console.WriteLine($"Error: {e.Message}");
                return;
            }

            // Check if another instance is already running
            using (DuetAPIClient.CommandConnection testConnection = new DuetAPIClient.CommandConnection())
            {
                try
                {
                    testConnection.Connect(Settings.SocketPath, CancelSource.Token).Wait();
                    Console.WriteLine("Error: Another instance is already running. Stopping.");
                    return;
                }
                catch
                {
                    // expected
                }
            }

            // Initialise object model
            Console.Write("Initialising object model... ");
            try
            {
                Model.Provider.Init();
                Model.Updater.Init();
                Console.WriteLine("Done!");
            }
            catch (Exception e)
            {
                Console.WriteLine($"Error: {e.Message}");
                return;
            }

            // Connect to the controller
            Console.Write("Connecting to RepRapFirmware... ");
            try
            {
                SPI.Interface.Init();
                if (!SPI.Interface.Connect())
                {
                    Console.WriteLine("Error: Duet is not available");
                    return;
                }
                Console.WriteLine("Done!");
            }
            catch (AggregateException ae)
            {
                Console.WriteLine($"Error: {ae.InnerException.Message}");
                return;
            }

            // Start up the IPC server
            Console.Write("Creating IPC socket... ");
            try
            {
                Server.CreateSocket();
                Console.WriteLine("Done!");
            }
            catch (Exception e)
            {
                Console.WriteLine($"Error: {e.Message}");
                return;
            }

            Console.WriteLine();

            // Run the main tasks in the background
            Task spiTask         = Task.Run(SPI.Interface.Run);
            Task ipcTask         = Server.AcceptConnections();
            Task modelUpdateTask = Model.UpdateTask.UpdatePeriodically();

            Task[] taskList = { spiTask, ipcTask, modelUpdateTask };

            // Wait for program termination
            Task.WaitAny(taskList);

            // Tell other tasks to stop in case this is an abnormal program termination
            if (!CancelSource.IsCancellationRequested)
            {
                Console.WriteLine("[crit] Abnormal program termination:");
                if (spiTask.IsCompleted)
                {
                    Console.WriteLine("SPI task terminated");
                }
                if (ipcTask.IsCompleted)
                {
                    Console.WriteLine("IPC task terminated");
                }
                if (modelUpdateTask.IsCompleted)
                {
                    Console.WriteLine("Model task terminated");
                }
                CancelSource.Cancel();
            }

            // Stop the IPC subsystem. This has to happen here because Socket.AcceptAsync() does not have a CancellationToken parameter
            Server.Shutdown();

            // Wait for all tasks to finish
            try
            {
                Task.WaitAll(taskList);
            }
            catch (AggregateException ae)
            {
                foreach (Exception e in ae.InnerExceptions)
                {
                    if (!(e is OperationCanceledException) && !(e is SocketException))
                    {
                        Console.Write("[crit] ");
                        Console.WriteLine(e);
                    }
                }
            }
        }