[Timeout(2000)] // We abort the test after timeout. This tests the blocking behavior in ReadAsync and the test will fail if ReadAsync blocks. public async Task WriteAsync() { using (var serialPortStreamWrite = new SerialPortStream("COM1", 9600, 8, Parity.None, StopBits.One)) using (var serialPortStreamRead = new SerialPortStream("COM2", 9600, 8, Parity.None, StopBits.One)) { serialPortStreamWrite.Open(); serialPortStreamRead.Open(); var buffer = new byte[1024]; var readTask = Task.Run(async() => await serialPortStreamRead.ReadAsync(buffer, 0, buffer.Length)); var bytes = new byte[] { 0x01, 0x02, 0x03 }; await serialPortStreamWrite.WriteAsync(bytes, 0, bytes.Length); await serialPortStreamWrite.FlushAsync(); // ReadAsync blocks here even if something gets written and flushed to the underlying COM device. // Fails for netcoreapp3.1, works with net472 await readTask; Assert.That(buffer[0], Is.EqualTo(0x01)); Assert.That(buffer[1], Is.EqualTo(0x02)); Assert.That(buffer[2], Is.EqualTo(0x03)); } }
static async Task Main(string[] args) { Console.WriteLine("Start"); using (var serialPortStreamWrite = new SerialPortStream("COM1", 9600, 8, Parity.None, StopBits.One)) using (var serialPortStreamRead = new SerialPortStream("COM2", 9600, 8, Parity.None, StopBits.One)) { serialPortStreamWrite.Open(); serialPortStreamRead.Open(); Console.WriteLine("Serial Port Opened"); var buffer = new byte[1024]; var readTask = Task.Run(async() => await serialPortStreamRead.ReadAsync(buffer, 0, buffer.Length)); Console.WriteLine("Wait for write. Enter any key."); Console.ReadKey(); var bytes = new byte[] { 0x01, 0x02, 0x03 }; Console.WriteLine("Write started"); await serialPortStreamWrite.WriteAsync(bytes, 0, bytes.Length); await serialPortStreamWrite.FlushAsync(); Console.WriteLine("Write finished"); Console.WriteLine("Awaiting read..."); await readTask; Console.WriteLine($"Buffer: {buffer[0]}, {buffer[1]}, {buffer[2]}"); Console.WriteLine("Finished."); } }
protected override async Task RunAsync(CancellationToken cancellationToken) { var options = _options.Value; _logger.LogInformation("Opening {SerialPort}", options.Port); using (var port = new SerialPortStream(options.Port, options.Baud)) { port.Open(); // Clear Status var cls = Encoding.ASCII.GetBytes("*CLS\n"); await port.WriteAsync(cls, 0, cls.Length); // §3.5.10 var formatPacked = Encoding.ASCII.GetBytes("FORMat PACKed\n"); await port.WriteAsync(formatPacked, 0, formatPacked.Length); // §3.5.17 var lterEoi = Encoding.ASCII.GetBytes("SYSTem:COMMunicate:GPIB:LTERminator EOI\n"); await port.WriteAsync(lterEoi, 0, lterEoi.Length); while (!cancellationToken.IsCancellationRequested) { try { await _wait.WaitAsync(cancellationToken); } catch (OperationCanceledException) { } if (_queue.TryDequeue(out var item)) { if (item.CancellationToken.IsCancellationRequested) { continue; } _logger.LogDebug("Sending {Request}", Encoding.ASCII.GetString(item.Request)); await port.WriteAsync(item.Request, 0, item.Request.Length, cancellationToken); await port.FlushAsync(cancellationToken); if (item.ExpectResponse) { var buffer = ArrayPool <byte> .Shared.Rent(1024); var offset = 0; try { var length = -1; while (length == -1 || offset < length) { var oldOffset = offset; var increased = await port.ReadAsync(buffer, offset, buffer.Length - offset, cancellationToken); offset += increased; if (offset > 0 && buffer[offset] == '#' && BlockData.TryDecodeLength(buffer.AsSpan().Slice(0, offset), out var decodedLength)) { length = decodedLength; } else { var relativeIndex = buffer.AsSpan().Slice(oldOffset, increased).IndexOf((byte)'\n'); if (relativeIndex >= 0) { length = oldOffset + relativeIndex + 1; } } } var response = buffer.AsSpan().Slice(0, length).ToArray(); _logger.LogDebug("Received {ResponseBytes} bytes: {Response}", response.Length, Encoding.ASCII.GetString(response)); item.TaskCompletionSource.SetResult(response); } finally { ArrayPool <byte> .Shared.Return(buffer); } } else { item.TaskCompletionSource.SetResult(null); } } } port.Close(); } }
public Task FlushAsync(CancellationToken cancellationToken) => _serialPort?.FlushAsync(cancellationToken);