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(); }
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(); }
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); }
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(); } }