public static ITransactionProcessor BuildTransactionProcessor(TransactionObserver observer)
        {
            var processor = new ReactiveTransactionProcessor();

            processor.SubscribeTransactionObserver(observer);
            return(processor);
        }
Exemplo n.º 2
0
        static void Main(string[] args)
        {
            var log = LogManager.GetCurrentClassLogger();
            var connectionString = "COM3:9600";
            var factory          = new ChannelFactory();
            var channel          = factory.FromConnectionString(connectionString);

            var observer  = new TransactionObserver(channel);
            var processor = new ReactiveTransactionProcessor();

            processor.SubscribeTransactionObserver(observer);

            channel.Open();                                                                                              // normmaly done in drivers Connected property

            var transaction = new TerminatedStringTransaction("*OPEN_MIRROR_COVER\r", initiator: '*', terminator: '\r'); // ":GR#"

            log.Debug($"Created transaction: {transaction}");
            processor.CommitTransaction(transaction);
            transaction.WaitForCompletionOrTimeout();
            log.Debug($"Finished transaction: {transaction}");

            if (transaction.Successful && transaction.Response.Any())
            {
                var response = transaction.Response.Single();
                log.Info($"received response: {response}");
            }

            Console.WriteLine("Press enter..");
            Console.Read();
        }
Exemplo n.º 3
0
        private static void Main(string[] args)
        {
            #region Setup for Reactive ASCOM

            var connectionString     = Settings.Default.ConnectionString; // Edit in App.config, default is "COM1:"
            var channelFactory       = new ChannelFactory();
            var channel              = channelFactory.FromConnectionString(connectionString);
            var transactionObserver  = new TransactionObserver(channel);
            var transactionProcessor = new ReactiveTransactionProcessor();
            transactionProcessor.SubscribeTransactionObserver(transactionObserver);
            channel.Open();

            #endregion Setup for Reactive ASCOM

            #region Submit some transactions

            // Ready to go. We are going to use tasks to submit the transactions, just to demonstrate thread safety.
            var raTransaction = new TerminatedStringTransaction(":GR#", '#', ':')
            {
                Timeout = TimeSpan.FromSeconds(2)
            };
            // The terminator and initiator are optional parameters and default to values that work for Meade style protocols.
            var decTransaction = new TerminatedStringTransaction(":GD#")
            {
                Timeout = TimeSpan.FromSeconds(2)
            };
            Task.Run(() => transactionProcessor.CommitTransaction(raTransaction));
            Task.Run(() => transactionProcessor.CommitTransaction(decTransaction));

            #endregion Submit some transactions

            #region Wait for the results

            // NOTE we are using the transactions in the reverse order that we committed them, just to prove a point.
            Console.WriteLine("Waiting for declination");
            decTransaction.WaitForCompletionOrTimeout();
            Console.WriteLine("Declination: {0}", decTransaction.Response);
            Console.WriteLine("Waiting for Right Ascensions");
            raTransaction.WaitForCompletionOrTimeout();
            Console.WriteLine("Right Ascension: {0}", raTransaction.Response);

            #endregion Wait for the results

            #region Cleanup

            /*
             * To clean up, we just need to dispose the transaction processor. This terminates the
             * sequence of transactions, which causes the TransactionObserver's OnCompleted method
             * to be called, which unsubscribes the receive sequence, which closes the
             * communications channel
             */
            transactionProcessor.Dispose();

            #endregion Cleanup

            Console.WriteLine("Press ENTER:");
            Console.ReadLine();
        }
Exemplo n.º 4
0
        /// <summary>
        ///     Opens the transaction pipeline for sending and receiving and performs initial state synchronization with the drive
        ///     system.
        /// </summary>
        public void Open()
        {
            var reactiveProcessor = new ReactiveTransactionProcessor();
            var observer          = new TransactionObserver(channel);

            Open(reactiveProcessor, observer);
            var gap = TimeSpan.FromMilliseconds(Settings.Default.MinimumMillisecondsBetweenTransactions);

            reactiveProcessor.SubscribeTransactionObserver(transactionObserver, gap);
            channel.Open();
        }
Exemplo n.º 5
0
 /// <summary>
 ///     Creates the transaction processor ready for use. Also creates and initialises the
 ///     device endpoint and the communications channel and opens the channel.
 /// </summary>
 /// <returns>ITransactionProcessor.</returns>
 public ITransactionProcessor CreateTransactionProcessor()
 {
     Channel   = new ChannelFactory().FromConnectionString(ConnectionString);
     observer  = new TransactionObserver(Channel);
     processor = new ReactiveTransactionProcessor();
     processor.SubscribeTransactionObserver(observer, TimeSpan.FromMilliseconds(100));
     Channel.Open();
     // iOptron ZEQ25 may need a second to initialize after starting the connection
     Task.Delay(TimeSpan.FromSeconds(1)).Wait();
     return(processor);
 }
        /// <inheritdoc />
        /// <summary>
        ///     Creates the transaction processor ready for use. Also creates and initialises the
        ///     device endpoint and the communications channel and opens the channel.
        /// </summary>
        /// <returns>ITransactionProcessor.</returns>
        public ITransactionProcessor CreateTransactionProcessor()
        {
            var factory = new ChannelFactory(); // ToDo - inject the factory in the constructor

            Channel   = factory.FromConnectionString(connectionString);
            observer  = new TransactionObserver(Channel);
            processor = new ReactiveTransactionProcessor();
            processor.SubscribeTransactionObserver(observer);
            Channel.Open();
            return(processor);
        }
 /// <summary>
 ///     Creates the transaction processor ready for use. Also creates and initialises the
 ///     device endpoint and the communications channel and opens the channel.
 /// </summary>
 /// <returns>ITransactionProcessor.</returns>
 public ITransactionProcessor CreateTransactionProcessor()
 {
     Endpoint  = DeviceEndpoint.FromConnectionString(ConnectionString);
     Channel   = CommunicationsStackBuilder.BuildChannel(Endpoint);
     observer  = new TransactionObserver(Channel);
     processor = new ReactiveTransactionProcessor();
     processor.SubscribeTransactionObserver(observer, TimeSpan.FromMilliseconds(100));
     Channel.Open();
     //Task.Delay(TimeSpan.FromSeconds(2)).Wait(); // Arduino needs 2 seconds to initialize
     Thread.Sleep(TimeSpan.FromSeconds(3));
     return(processor);
 }
 /// <summary>
 ///     Destroys the transaction processor and its dependencies. Ensures that the
 ///     <see cref="Channel" /> is closed. Once this method has been called, the
 ///     <see cref="Channel" /> and <see cref="Endpoint" /> properties will be null. A new
 ///     connection to the same endpoint can be created by calling
 ///     <see cref="CreateTransactionProcessor" /> again.
 /// </summary>
 public void DestroyTransactionProcessor()
 {
     processor?.Dispose();
     processor = null; // [Sentinel]
     observer  = null;
     if (Channel?.IsOpen ?? false)
     {
         Channel.Close();
     }
     Channel?.Dispose();
     Channel = null; // [Sentinel]
     GC.Collect(3, GCCollectionMode.Forced, blocking: true);
 }
        public RxAscomContext Build()
        {
            // Build the communications channel
            var channel   = channelFactory.FromConnectionString(connectionString);
            var processor = new ReactiveTransactionProcessor();
            var observer  = new TransactionObserver(channel);

            processor.SubscribeTransactionObserver(observer);
            if (channelShouldBeOpen)
            {
                channel.Open();
            }

            // Assemble the device controller test context
            var context = new RxAscomContext
            {
                Channel   = channel,
                Processor = processor,
                Observer  = observer
            };

            return(context);
        }
Exemplo n.º 10
0
        private string TalkWithAxis(AXISID axis, char cmd, string cmdDataStr)
        {
            string         response = string.Empty;
            DeviceEndpoint endPoint = SerialDeviceEndpoint.FromConnectionString(ConnectionString);

            const int     BufferSize = 20;
            StringBuilder sb         = new StringBuilder(BufferSize);

            sb.Append(cStartChar_Out);           // 0: Leading char
            sb.Append(cmd);                      // 1: Length of command( Source, distination, command char, data )

            // Target Device
            sb.Append(((int)axis + 1).ToString()); // 2: Target Axis
                                                   // Copy command data to buffer
            sb.Append(cmdDataStr);

            sb.Append(cEndChar); // CR Character

            string cmdString = sb.ToString();


            var cmdTransaction = new EQTransaction(cmdString)
            {
                Timeout = TimeSpan.FromSeconds(TimeOut)
            };


            using (ICommunicationChannel channel = new SerialCommunicationChannel(endPoint))
                using (var processor = new ReactiveTransactionProcessor())
                {
                    var transactionObserver = new TransactionObserver(channel);
                    processor.SubscribeTransactionObserver(transactionObserver);
                    try
                    {
                        channel.Open();

                        // prepare to communicate
                        for (int i = 0; i < Retry; i++)
                        {
                            Task.Run(() => processor.CommitTransaction(cmdTransaction));
                            cmdTransaction.WaitForCompletionOrTimeout();
                            if (!cmdTransaction.Failed)
                            {
                                response = cmdTransaction.Value;
                                break;
                            }
                            else
                            {
                                Trace.TraceError(cmdTransaction.ErrorMessage.Single());
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Trace.TraceError("Connnection Lost");
                        throw new Exception("AstroEQ not responding", ex);
                    }
                    finally
                    {
                        // To clean up, we just need to dispose the TransactionObserver and the channel is closed automatically.
                        // Not strictly necessary, but good practice.
                        transactionObserver.OnCompleted(); // There will be no more transactions.
                        transactionObserver = null;        // not necessary, but good practice.
                        endPoint            = null;
                    }
                }
            return(response);
        }
Exemplo n.º 11
0
        private static void Main(string[] args)
        {
            #region Setup for Reactive ASCOM

            /*
             * First create our channel factory.
             * This is also the place where we can inject a logging service.
             * If you don't provide a logging service here, there will be no logging!
             * Note that logging is configured in NLog.config.
             * See also: TA.Utils.Core.Diagnostics
             *
             * The channel factory knows about serial ports by default, but we are going to
             * register a custom channel implementation that contains a hardware simulator.
             * (the simulator is abstracted from the Digital Domeworks dome driver).
             * If you make your own custom channels, you can register them the same way.
             */
            var log = new LoggingService(); // TA.Utils.Logging.NLog
            log.Info()
            .Message("Program start. Version {gitversion}", GitVersion.GitInformationalVersion)
            .Property("CommitSha", GitVersion.GitCommitSha)
            .Property("CommitDate", GitVersion.GitCommitDate)
            .Write();

            var channelFactory = new ChannelFactory(log);
            channelFactory.RegisterChannelType(
                SimulatorEndpoint.IsConnectionStringValid,
                SimulatorEndpoint.FromConnectionString,
                endpoint => new SimulatorCommunicationsChannel((SimulatorEndpoint)endpoint, log));

            /*
             * Now get our connection string from the AppSettings.json file.
             */

            var connectionString = Configuration["ConnectionString"];

            /*
             * Create the communications channel and connect it to the transaction observer.
             * The TransactionObserver is the beating heart of Rx Comms and is where everything is synchronized.
             */
            var channel             = channelFactory.FromConnectionString(connectionString);
            var transactionObserver = new TransactionObserver(channel);

            /*
             * TransactionObsever is an IObservable<DeviceTransaction>, so we need a sequence for it to observe.
             * The transaction sequence can be created by any convenient means, and Rx Comms provides
             * a handy helper class for doing this, called ReactiveTransactionProcessor.
             *
             * However the sequence is created, it must be fed into the transaction observer
             * by creating a subscription. ReactiveTransactionProcessor has a helper method for that.
             * The helper method also gives us a way to rate-limit commands to the hardware, if needed.
             */
            var transactionProcessor = new ReactiveTransactionProcessor();
            transactionProcessor.SubscribeTransactionObserver(transactionObserver, TimeSpan.FromSeconds(1));
            channel.Open();
            #endregion Setup for Reactive ASCOM

            // All set up and ready to go.
            try
            {
                // First we'll create a StatusTransaction and get the device's status.
                var statusTransaction = new StatusTransaction();
                transactionProcessor.CommitTransaction(statusTransaction);
                statusTransaction.WaitForCompletionOrTimeout(); // There is also an async version

                // If the transaction failed, log and throw TransactionException.
                TransactionExtensions.ThrowIfFailed(statusTransaction, log);

                // Now we can retrieve the results and use them.
                // If the transaction succeeded, we should be assured of a valid result.
                // When you write your own transactions, make sure this is so!
                var status = statusTransaction.HardwareStatus;
                log.Debug().Message("Got status: {deviceStatus}", status).Write();

                // Get the user GPIO pins and flip the value of pin 0.
                var gpioPins        = status.UserPins;
                var gpioPinsToWrite = gpioPins.WithBitSetTo(0, !gpioPins[0]);

                // Now we'll use another transaction to set the new GPIO pin state.
                var gpioTransaction = new SetUserPinTransaction(gpioPinsToWrite);
                transactionProcessor.CommitTransaction(gpioTransaction);
                gpioTransaction.WaitForCompletionOrTimeout();

                TransactionExtensions.ThrowIfFailed(gpioTransaction, log);
                var newPinState = gpioTransaction.UserPins;
                if (newPinState != gpioPinsToWrite)
                {
                    throw new ApplicationException("Failed to write GPIO pins");
                }
                log.Info()
                .Message("Successfully changed GPIO pins {oldState} => {newState}", gpioPins, newPinState)
                .Write();
            }
            catch (TransactionException exception)
            {
                log.Error().Exception(exception)
                .Message("Transaction failed {transaction}", exception.Transaction)
                .Write();
                Console.WriteLine(exception);
            }
            catch (ApplicationException exception)
            {
                log.Error().Message("Failed to set teh GPIO pins.").Exception(exception).Write();
            }
            finally
            {
                /*
                 * We just need to dispose the transaction processor. This terminates the
                 * sequence of transactions, which causes the TransactionObserver's OnCompleted method
                 * to be called, which unsubscribes the receive sequence, which closes the
                 * communications channel.
                 */
                transactionProcessor.Dispose();
                log.Info().Message("Cleanup complete").Write();

                /*
                 * It is best practice to explicitly shut down the logging service,
                 * otherwise any buffered log entries might not be written to the log.
                 * This may take a few seconds if you are using a slow log target.
                 */
                log.Shutdown();
            }
        }