Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements with communication stability #64

Merged
merged 1 commit into from
Oct 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ For UWP look for the respective Nuget package.</PackageReleaseNotes>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Analyzer Include="..\packages\ConfigureAwaitChecker.Analyzer.1.0.0\analyzers\dotnet\cs\ConfigureAwaitChecker.dll" />
<Analyzer Include="..\packages\UwpDesktop.10.0.14393.3\analyzers\dotnet\UwpDesktopAnalyzer.dll" />
</ItemGroup>
<Import Project="..\nanoFramework.Tools.DebugLibrary.Shared\nanoFramework.Tools.DebugLibrary.Net.projitems" Label="Shared" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="ConfigureAwaitChecker.Analyzer" version="1.0.0" targetFramework="net46" developmentDependency="true" />
<package id="NuGet.Build.Packaging" version="0.2.0" targetFramework="net46" developmentDependency="true" />
<package id="System.Threading.Tasks.Extensions" version="4.4.0" targetFramework="net46" />
<package id="System.ValueTuple" version="4.4.0" targetFramework="net46" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static class DebuggerExtensions
/// <returns></returns>
public static async Task<bool> IsDeviceInInitializeStateAsync(this Engine debugEngine)
{
var result = await debugEngine.SetExecutionModeAsync(0, 0).ConfigureAwait(false);
var result = await debugEngine.SetExecutionModeAsync(0, 0);

if (result.success)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ public async Task<bool> GetDeviceInfo()
if (!Dbg.IsConnectedTonanoCLR) return false;

// get app domains from device
await GetAppDomainsAsync(cancelTSource.Token).ConfigureAwait(false);
await GetAppDomainsAsync(cancelTSource.Token);

// get assemblies from device
await GetAssembliesAsync(cancelTSource.Token).ConfigureAwait(false);
await GetAssembliesAsync(cancelTSource.Token);

Valid = true;

Expand All @@ -50,14 +50,14 @@ private async Task GetAppDomainsAsync(CancellationToken cancellationToken)
{
if (Dbg.Capabilities.AppDomains)
{
Commands.Debugging_TypeSys_AppDomains.Reply domainsReply = await Dbg.GetAppDomainsAsync().ConfigureAwait(false);
Commands.Debugging_TypeSys_AppDomains.Reply domainsReply = await Dbg.GetAppDomainsAsync();
// TODO add cancellation token code

if (domainsReply != null)
{
foreach (uint id in domainsReply.Data)
{
Commands.Debugging_Resolve_AppDomain.Reply reply = await Dbg.ResolveAppDomainAsync(id).ConfigureAwait(false);
Commands.Debugging_Resolve_AppDomain.Reply reply = await Dbg.ResolveAppDomainAsync(id);
// TODO add cancellation token code
if (reply != null)
{
Expand All @@ -70,7 +70,7 @@ private async Task GetAppDomainsAsync(CancellationToken cancellationToken)

private async Task GetAssembliesAsync(CancellationToken cancellationToken)
{
List<Commands.DebuggingResolveAssembly> reply = await Dbg.ResolveAllAssembliesAsync(cancellationToken).ConfigureAwait(false);
List<Commands.DebuggingResolveAssembly> reply = await Dbg.ResolveAllAssembliesAsync(cancellationToken);

if (reply != null)
foreach (Commands.DebuggingResolveAssembly resolvedAssm in reply)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,11 @@ public async Task<bool> ConnectAsync()
{
if (Device is NanoUsbDevice)
{
return await Parent.ConnectDeviceAsync(this as NanoDeviceBase).ConfigureAwait(false);
return await Parent.ConnectDeviceAsync(this as NanoDeviceBase);
}
else if (Device is NanoSerialDevice)
{
return await Parent.ConnectDeviceAsync(this as NanoDeviceBase).ConfigureAwait(false);
return await Parent.ConnectDeviceAsync(this as NanoDeviceBase);
}

return false;
Expand Down

Large diffs are not rendered by default.

178 changes: 73 additions & 105 deletions source/nanoFramework.Tools.DebugLibrary.Shared/PortSerial/SerialPort.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,11 +247,11 @@ private async void AddDeviceToList(DeviceInformation deviceInformation, String d
if (IsDevicesEnumerationComplete)
{
// try opening the device to check for a valid nanoFramework device
if (await ConnectSerialDeviceAsync(newNanoFrameworkDevice.Device.DeviceInformation).ConfigureAwait(false))
if (await ConnectSerialDeviceAsync(newNanoFrameworkDevice.Device.DeviceInformation))
{
Debug.WriteLine("New Serial device: " + deviceInformation.Id);

if(await CheckValidNanoFrameworkSerialDeviceAsync().ConfigureAwait(false))
if (await CheckValidNanoFrameworkSerialDeviceAsync())
{
// done here, close the device
EventHandlerForSerialDevice.Current.CloseDevice();
Expand Down Expand Up @@ -295,44 +295,6 @@ private void RemoveDeviceFromList(string deviceId)
NanoFrameworkDevices.Remove(device);

device = null;

//// start thread to dispose and remove device from collection if it doesn't enumerate again in 2 seconds
//Task.Factory.StartNew(() =>
//{
// // get device
// var device = FindNanoFrameworkDevice(deviceId);

// if (device != null)
// {
// // set device to dispose if it doesn't come back in 2.5 seconds
// device.StartCountdownForDispose();

// // hold here for the same time as the default timer of the dispose timer
// new ManualResetEvent(false).WaitOne(TimeSpan.FromSeconds(4));


// // try to find device
// var newDevice = FindNanoFrameworkDevice(deviceId);


// // check is object was disposed
// if ((newDevice as NanoDevice<NanoSerialDevice>).KillFlag)
// {
// // yes, remove it from collection
// NanoFrameworkDevices.Remove(newDevice);

// Debug.WriteLine("Removing device " + newDevice.Description);

// newDevice = null;
// }
// else
// {
// // add it again to serial devices collection
// deviceEntry = FindDevice(deviceId);
// SerialDevices.Add(deviceEntry);
// }
// }
//});
}

private void ClearDeviceEntries()
Expand Down Expand Up @@ -472,7 +434,7 @@ private async Task<bool> CheckValidNanoFrameworkSerialDeviceAsync()
var device = FindNanoFrameworkDevice(EventHandlerForSerialDevice.Current.DeviceInformation.Id);

// need an extra check on this because this can be 'just' a regular COM port without any nanoFramework device behind
var connectionResult = await device.DebugEngine.ConnectAsync(1, 500, false).ConfigureAwait(false);
var connectionResult = await device.DebugEngine.ConnectAsync(1, 1000, true);

if (connectionResult)
{
Expand Down Expand Up @@ -521,23 +483,23 @@ protected virtual void OnDeviceEnumerationCompleted()
#endregion


public async Task<bool> ConnectDeviceAsync(NanoDeviceBase device)
public Task<bool> ConnectDeviceAsync(NanoDeviceBase device)
{
inputStreamReader = null;
outputStreamWriter = null;

return await ConnectSerialDeviceAsync((device as NanoDevice<NanoSerialDevice>).Device.DeviceInformation as SerialDeviceInformation).ConfigureAwait(false);
return ConnectSerialDeviceAsync((device as NanoDevice<NanoSerialDevice>).Device.DeviceInformation as SerialDeviceInformation);
}

private async Task<bool> ConnectSerialDeviceAsync(SerialDeviceInformation serialDeviceInfo)
private Task<bool> ConnectSerialDeviceAsync(SerialDeviceInformation serialDeviceInfo)
{
// try to determine if we already have this device opened.
if (EventHandlerForSerialDevice.Current != null)
{
// device matches
if (EventHandlerForSerialDevice.Current.DeviceInformation == serialDeviceInfo.DeviceInformation)
{
return true;
return Task.FromResult(true);
}
}

Expand All @@ -547,7 +509,7 @@ private async Task<bool> ConnectSerialDeviceAsync(SerialDeviceInformation serial
// access the Current in EventHandlerForDevice to create a watcher for the device we are connecting to
var isConnected = EventHandlerForSerialDevice.Current.IsDeviceConnected;

return await EventHandlerForSerialDevice.Current.OpenDeviceAsync(serialDeviceInfo.DeviceInformation, serialDeviceInfo.DeviceSelector).ConfigureAwait(false);
return EventHandlerForSerialDevice.Current.OpenDeviceAsync(serialDeviceInfo.DeviceInformation, serialDeviceInfo.DeviceSelector);
}

public void DisconnectDevice(NanoDeviceBase device)
Expand Down Expand Up @@ -589,37 +551,40 @@ public async Task<uint> SendBufferAsync(byte[] buffer, TimeSpan waiTimeout, Canc
}

// serial works as a "single channel" so we can only TX or RX,
// meaning that access to the resource has to be protected with a semephore
await semaphore.WaitAsync().ConfigureAwait(false);
// meaning that access to the resource has to be protected with a semaphore
var semaphoreEntered = await semaphore.WaitAsync(1000, cancellationToken);

try
if (semaphoreEntered)
{
// write buffer to device
outputStreamWriter.WriteBytes(buffer);
try
{
// write buffer to device
outputStreamWriter.WriteBytes(buffer);

// need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
// because we have an external cancellation token and the above timeout cancellation token, need to combine both
Task<uint> storeAsyncTask = outputStreamWriter.StoreAsync().AsTask(cancellationToken.AddTimeout(waiTimeout));
// need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
// because we have an external cancellation token and the above timeout cancellation token, need to combine both
Task<uint> storeAsyncTask = outputStreamWriter.StoreAsync().AsTask(cancellationToken.AddTimeout(waiTimeout));

bytesWritten = await storeAsyncTask.ConfigureAwait(false);
bytesWritten = await storeAsyncTask;

if (bytesWritten > 0)
if (bytesWritten > 0)
{
LastActivity = DateTime.Now;
}
}
catch (TaskCanceledException)
{
LastActivity = DateTime.Now;
// this is expected to happen, don't do anything with this
}
catch (Exception ex)
{
Debug.WriteLine($"SendRawBufferAsync-Serial-Exception occurred: {ex.Message}\r\n {ex.StackTrace}");
}
finally
{
semaphore.Release();
outputStreamWriter?.DetachBuffer();
}
}
catch (TaskCanceledException)
{
// this is expected to happen, don't do anything with this
}
catch (Exception ex)
{
Debug.WriteLine($"SendRawBufferAsync-Serial-Exception occurred: {ex.Message}\r\n {ex.StackTrace}");
}
finally
{
semaphore.Release();
outputStreamWriter.DetachBuffer();
}
}
else
Expand All @@ -637,48 +602,51 @@ public async Task<byte[]> ReadBufferAsync(uint bytesToRead, TimeSpan waiTimeout,
if (EventHandlerForSerialDevice.Current.IsDeviceConnected)
{
// serial works as a "single channel" so we can only TX or RX,
// meaning that access to the resource has to be protected with a semephore
await semaphore.WaitAsync().ConfigureAwait(false);
// meaning that access to the resource has to be protected with a semaphore
var semaphoreEntered = await semaphore.WaitAsync(1000, cancellationToken);

// create a stream reader with serial device InputStream, if there isn't one already
if (inputStreamReader == null)
if (semaphoreEntered)
{
inputStreamReader = new DataReader(EventHandlerForSerialDevice.Current.Device.InputStream);
}
// create a stream reader with serial device InputStream, if there isn't one already
if (inputStreamReader == null)
{
inputStreamReader = new DataReader(EventHandlerForSerialDevice.Current.Device.InputStream);
}

try
{
// need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
// because we have an external cancellation token and the above timeout cancellation token, need to combine both
Task<UInt32> loadAsyncTask = inputStreamReader.LoadAsync(bytesToRead).AsTask(cancellationToken.AddTimeout(waiTimeout));
try
{
// need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
// because we have an external cancellation token and the above timeout cancellation token, need to combine both
Task<UInt32> loadAsyncTask = inputStreamReader.LoadAsync(bytesToRead).AsTask(cancellationToken.AddTimeout(waiTimeout));

// get how many bytes are available to read
uint bytesRead = await loadAsyncTask.ConfigureAwait(false);
// get how many bytes are available to read
uint bytesRead = await loadAsyncTask;

byte[] readBuffer = new byte[bytesToRead];
inputStreamReader.ReadBytes(readBuffer);
byte[] readBuffer = new byte[bytesToRead];
inputStreamReader.ReadBytes(readBuffer);

return readBuffer;
}
catch (TaskCanceledException)
{
// this is expected to happen, don't do anything with it
}
catch (NullReferenceException)
{
// this is expected to happen when there is anything to read, don't do anything with it
}
catch (Exception ex)
{
Debug.WriteLine($"SendRawBufferAsync-Serial-Exception occurred: {ex.Message}\r\n {ex.StackTrace}");
}
finally
{
// relase serial device semaphore
semaphore.Release();
return readBuffer;
}
catch (TaskCanceledException)
{
// this is expected to happen, don't do anything with it
}
catch (NullReferenceException)
{
// this is expected to happen when there is anything to read, don't do anything with it
}
catch (Exception ex)
{
Debug.WriteLine($"SendRawBufferAsync-Serial-Exception occurred: {ex.Message}\r\n {ex.StackTrace}");
}
finally
{
// release serial device semaphore
semaphore.Release();

// detach read buffer
inputStreamReader.DetachBuffer();
// detach read buffer
inputStreamReader.DetachBuffer();
}
}
}
else
Expand Down
Loading