static Task KeyHandlingAsync(Configuration config, CancellationTokenSource cancelSource, SerialWrapper serial) => Task.Run(() => { Console.WriteLine("Ctrl-C to quit"); Console.WriteLine("Ctrl-X to clear screen"); if (config.IsLogging) { Console.WriteLine("Ctrl-Space to start logging to a new log file"); } Console.WriteLine(); while (!cancelSource.IsCancellationRequested) { var keyInfo = Console.ReadKey(true); // Application control if (keyInfo.Modifiers == ConsoleModifiers.Control) { switch (keyInfo.Key) { case ConsoleKey.C: cancelSource.Cancel(); break; case ConsoleKey.X: Console.Clear(); Console.WriteLine(GenerateHeader(config)); Console.WriteLine("Ctrl-C to quit"); Console.WriteLine("Ctrl-X to clear screen"); if (config.IsLogging) { Console.WriteLine("Ctrl-Space to start logging to a new log file"); } Console.WriteLine(); break; case ConsoleKey.Spacebar: if (config.IsLogging) { config.Logger.RollLog(); } break; } } // Text input else if (config.AllowKeyEntry) { var data = Encoding.ASCII.GetBytes(new[] { keyInfo.KeyChar }); serial.WriteAsync(data, 0, data.Length); } } });
static Task SerialReadAsync(Configuration config, DataBuffer dataQueue, CancellationToken cancelToken, SerialWrapper serial) { return(Task.Run(async() => { try { // Try open the port. Only one try is necessary if (!serial.Open()) { return; } var isReadValid = true; while (isReadValid && !cancelToken.IsCancellationRequested) { var retries = 10; do { var bytesRead = await serial.ReadAsync(cancelToken); if (bytesRead == 0) { // ReadAsync terminated because we cancelled a task. // Just jump out if (cancelToken.IsCancellationRequested) { break; } Console.WriteLine($"{Environment.NewLine}WARNING: Cannot read from port {config.COMPort}. Retrying..."); serial.Close(); await Task.Delay(5000, cancelToken); // Try re-open the serial port, as many times as we can while (!serial.Open() && --retries > 0) { await Task.Delay(2000, cancelToken); } } } while (retries > 0 && !isReadValid); } } catch (OperationCanceledException) { // Ignore cancellations } catch (Exception ex) { Console.WriteLine($"{Environment.NewLine}{Environment.NewLine}ERROR: {ex.Message}{Environment.NewLine}{Environment.NewLine}{ex}"); } })); }
static void Main(string[] args) { Console.TreatControlCAsInput = true; if (ParseCommandLine(args, out var config)) { string exitMsg = string.Empty; using (config.Logger = new LineLogger(config)) { var header = GenerateHeader(config); if (config.IsLogging) { config.Logger.Header = header; } Console.WriteLine(header); var dataQueue = new DataBuffer(BUFFER_SIZE * 10); var cancelSource = new CancellationTokenSource(); using (var serial = new SerialWrapper(config, dataQueue, BUFFER_SIZE / 2)) { try { var taskList = new List <Tuple <string, Task> >() { new Tuple <string, Task>("Serial read", SerialReadAsync(config, dataQueue, cancelSource.Token, serial)), new Tuple <string, Task>("Key handling", KeyHandlingAsync(config, cancelSource, serial)), new Tuple <string, Task>("Log write", LogWriteAsync(config, dataQueue, cancelSource.Token)) }; // Wait for any of the tasks to end var index = Task.WaitAny(taskList.Select(t => t.Item2).ToArray()); // Cancel the other tasks cancelSource.Cancel(); // Wait for the logger to complete (it must be the last task!) Task.WaitAll(taskList.Select(t => t.Item2).Last()); exitMsg = $"{Environment.NewLine}Exit: {taskList[index].Item1}"; } catch (OperationCanceledException) { // Ignore cancellations } catch (Exception ex) { Console.WriteLine($"{Environment.NewLine}{Environment.NewLine}ERROR: {ex.Message}{Environment.NewLine}{Environment.NewLine}{ex}"); } } } if (!string.IsNullOrEmpty(exitMsg)) { Console.WriteLine(exitMsg); } } else { Environment.ExitCode = 1; } }