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