Skip to content

Commit 0adfb3b

Browse files
committed
Refactor arduino interface to avoid event callback
1 parent 7309adb commit 0adfb3b

File tree

2 files changed

+51
-15
lines changed

2 files changed

+51
-15
lines changed

Bonsai.Arduino/Arduino.cs

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.IO.Ports;
44
using System.Threading;
5+
using System.Threading.Tasks;
56

67
namespace Bonsai.Arduino
78
{
@@ -90,7 +91,6 @@ public Arduino(string portName, int baudRate)
9091
commandBuffer = new byte[MaxDataBytes];
9192
sysexBuffer = new byte[MaxDataBytes];
9293
readBuffer = new byte[serialPort.ReadBufferSize];
93-
serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
9494
}
9595

9696
/// <summary>
@@ -141,28 +141,62 @@ void OnSysexReceived(SysexReceivedEventArgs e)
141141
SysexReceived?.Invoke(this, e);
142142
}
143143

144-
void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
144+
Task RunAsync(CancellationToken cancellationToken)
145145
{
146-
var bytesToRead = serialPort.BytesToRead;
147-
while (serialPort.IsOpen && bytesToRead > 0)
146+
serialPort.Open();
147+
Thread.Sleep(ConnectionDelay);
148+
serialPort.ReadExisting();
149+
return Task.Factory.StartNew(() =>
148150
{
149-
var bytesRead = serialPort.Read(readBuffer, 0, Math.Min(bytesToRead, readBuffer.Length));
150-
for (int i = 0; i < bytesRead; i++)
151+
using var cancellation = cancellationToken.Register(serialPort.Dispose);
152+
while (!cancellationToken.IsCancellationRequested)
151153
{
152-
ProcessInput(readBuffer[i]);
154+
try
155+
{
156+
var bytesToRead = serialPort.BytesToRead;
157+
if (bytesToRead == 0)
158+
{
159+
var nextByte = serialPort.ReadByte();
160+
if (nextByte < 0) break;
161+
ProcessInput((byte)nextByte);
162+
}
163+
else
164+
{
165+
while (bytesToRead > 0)
166+
{
167+
var bytesRead = serialPort.Read(readBuffer, 0, Math.Min(bytesToRead, readBuffer.Length));
168+
for (int i = 0; i < bytesRead; i++)
169+
{
170+
ProcessInput(readBuffer[i]);
171+
}
172+
bytesToRead -= bytesRead;
173+
}
174+
}
175+
}
176+
catch (Exception)
177+
{
178+
if (!cancellationToken.IsCancellationRequested)
179+
{
180+
throw;
181+
}
182+
break;
183+
}
153184
}
154-
bytesToRead -= bytesRead;
155-
}
185+
},
186+
cancellationToken,
187+
TaskCreationOptions.LongRunning,
188+
TaskScheduler.Default);
156189
}
157190

158191
/// <summary>
159192
/// Opens a new serial port connection to the Arduino board.
160193
/// </summary>
161-
public void Open()
194+
/// <param name="cancellationToken">
195+
/// A <see cref="CancellationToken"/> which can be used to cancel the operation.
196+
/// </param>
197+
public void Open(CancellationToken cancellationToken = default)
162198
{
163-
serialPort.Open();
164-
Thread.Sleep(ConnectionDelay);
165-
serialPort.ReadExisting();
199+
RunAsync(cancellationToken);
166200
}
167201

168202
void ReportInput(ref int[] reportInput, byte command, int index, bool state)

Bonsai.Arduino/ArduinoManager.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.IO;
77
using System.Reactive.Disposables;
88
using System.Threading.Tasks;
9+
using System.Threading;
910

1011
namespace Bonsai.Arduino
1112
{
@@ -50,12 +51,13 @@ internal static ArduinoDisposable ReserveConnection(string portName, ArduinoConf
5051
}
5152
#pragma warning restore CS0612 // Type or member is obsolete
5253

54+
var cancellation = new CancellationTokenSource();
5355
var arduino = new Arduino(serialPortName, arduinoConfiguration.BaudRate);
54-
arduino.Open();
56+
arduino.Open(cancellation.Token);
5557
arduino.SamplingInterval(arduinoConfiguration.SamplingInterval);
5658
var dispose = Disposable.Create(() =>
5759
{
58-
arduino.Close();
60+
cancellation.Cancel();
5961
openConnections.Remove(portName);
6062
});
6163

0 commit comments

Comments
 (0)