diff --git a/Bonsai.PulsePal/Bonsai.PulsePal.csproj b/Bonsai.PulsePal/Bonsai.PulsePal.csproj index 19c3eed..d3c9811 100644 --- a/Bonsai.PulsePal/Bonsai.PulsePal.csproj +++ b/Bonsai.PulsePal/Bonsai.PulsePal.csproj @@ -5,6 +5,7 @@ Bonsai Library containing modules for interfacing with the PulsePal pulse train generator. Bonsai Rx PulsePal Pulse Stimulator net462 + 9.0 0.2.0 diff --git a/Bonsai.PulsePal/PulsePal.cs b/Bonsai.PulsePal/PulsePal.cs index 68e201e..c9c0d4c 100644 --- a/Bonsai.PulsePal/PulsePal.cs +++ b/Bonsai.PulsePal/PulsePal.cs @@ -1,6 +1,8 @@ using System; using System.IO.Ports; using System.IO; +using System.Threading.Tasks; +using System.Threading; namespace Bonsai.PulsePal { @@ -44,7 +46,6 @@ public PulsePal(string portName) responseBuffer = new byte[4]; commandBuffer = new byte[MaxDataBytes]; readBuffer = new byte[serialPort.ReadBufferSize]; - serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived); } public int MajorVersion { get; private set; } @@ -56,28 +57,79 @@ public bool IsOpen get { return serialPort.IsOpen; } } - void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) + Task RunAsync(CancellationToken cancellationToken) { - var bytesToRead = serialPort.BytesToRead; - if (serialPort.IsOpen && bytesToRead > 0) + serialPort.Open(); + serialPort.ReadExisting(); + Connect(); + + return Task.Factory.StartNew(() => { - bytesToRead = serialPort.Read(readBuffer, 0, bytesToRead); - for (int i = 0; i < bytesToRead; i++) + using var cancellation = cancellationToken.Register(serialPort.Dispose); + while (!cancellationToken.IsCancellationRequested) { - ProcessInput(readBuffer[i]); + try + { + var bytesToRead = serialPort.BytesToRead; + if (bytesToRead == 0) + { + var nextByte = serialPort.ReadByte(); + if (nextByte < 0) break; + ProcessInput((byte)nextByte); + } + else + { + while (bytesToRead > 0) + { + var bytesRead = serialPort.Read(readBuffer, 0, Math.Min(bytesToRead, readBuffer.Length)); + for (int i = 0; i < bytesRead; i++) + { + ProcessInput(readBuffer[i]); + } + bytesToRead -= bytesRead; + } + } + } + catch (Exception) + { + if (!cancellationToken.IsCancellationRequested) + { + throw; + } + break; + } } - } + }, + cancellationToken, + TaskCreationOptions.LongRunning, + TaskScheduler.Default); } - public void Open() + /// + /// Opens a new serial port connection to the Pulse Pal device. + /// + /// + /// A which can be used to cancel the operation. + /// + public void Open(CancellationToken cancellationToken = default) + { + RunAsync(cancellationToken); + } + + void Connect() { - serialPort.Open(); - serialPort.ReadExisting(); commandBuffer[0] = OpMenu; commandBuffer[1] = HandshakeCommand; serialPort.Write(commandBuffer, 0, 2); } + void Disconnect() + { + commandBuffer[0] = OpMenu; + commandBuffer[1] = DisconnectCommand; + serialPort.Write(commandBuffer, 0, 2); + } + void WriteInt(BinaryWriter writer, int value) { writer.Write((byte)value); @@ -270,9 +322,7 @@ private void Dispose(bool disposing) { if (disposing) { - commandBuffer[0] = OpMenu; - commandBuffer[1] = DisconnectCommand; - serialPort.Write(commandBuffer, 0, 2); + Disconnect(); serialPort.Close(); disposed = true; }