Exemplo de código de comunicação de porta serial usando a API Async no .net 4.5?
Alguém pode me indicar um exemplo de trabalho que usa a API .net 4.5 Async API (assíncrona, espera, tarefa <>, ReadAsync, etc) para fazer comunicações seriais?
Tentei adaptar uma amostra serial acionada por eventos existente e estou recebendo todo tipo de comportamento horrível - erros de "porta em uso por outro aplicativo", depurador do VS2013 lançando exceções e travando - que geralmente exigem a reinicialização do PC.
editar
Eu escrevi minha própria amostra do zero. É um projeto simples do Winforms que grava na janela Saída. Três botões no formulário - Abrir porta, Fechar porta e Ler dados. O método ReadDataAsync chama SerialPort.BaseStream.ReadAsync.
A partir de agora, ele lerá dados da porta, mas estou tendo problemas para torná-los robustos.
Por exemplo, se eu desconectar o cabo serial, abrir a porta e clicar em Ler Dados duas vezes, receberei uma System.IO.IOException (que eu meio que espero), mas meu aplicativo pára de responder.
Pior ainda, quando tento interromper meu programa, o VS2013 exibe uma caixa de diálogo "Parar a depuração em andamento", que nunca é concluída, e eu não consigo nem matar o VS no Gerenciador de tarefas. Tenho que reiniciar o meu PC toda vez que isso acontece.
Não é bom.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private SerialPort _serialPort;
public Form1()
{
InitializeComponent();
}
private void openPortbutton_Click(object sender, EventArgs e)
{
try
{
if (_serialPort == null )
_serialPort = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);
if (!_serialPort.IsOpen)
_serialPort.Open();
Console.Write("Open...");
}
catch(Exception ex)
{
ClosePort();
MessageBox.Show(ex.ToString());
}
}
private void closePortButton_Click(object sender, EventArgs e)
{
ClosePort();
}
private async void ReadDataButton_Click(object sender, EventArgs e)
{
try
{
await ReadDataAsync();
}
catch (Exception ex)
{
ClosePort();
MessageBox.Show(ex.ToString(), "ReadDataButton_Click");
}
}
private async Task ReadDataAsync()
{
byte[] buffer = new byte[4096];
Task<int> readStringTask = _serialPort.BaseStream.ReadAsync(buffer, 0, 100);
if (!readStringTask.IsCompleted)
Console.WriteLine("Waiting...");
int bytesRead = await readStringTask;
string data = Encoding.ASCII.GetString(buffer, 0, bytesRead);
Console.WriteLine(data);
}
private void ClosePort()
{
if (_serialPort == null) return;
if (_serialPort.IsOpen)
_serialPort.Close();
_serialPort.Dispose();
_serialPort = null;
Console.WriteLine("Close");
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
ClosePort();
}
}
}