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

Re-order Debugging Start-up to be like v1. Refactor MeadowConnectionManager so it can be shared amongst extensions #590

Closed
wants to merge 12 commits into from
Closed
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
8 changes: 4 additions & 4 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Meadow.CLI Packaging
env:
CLI_RELEASE_VERSION_1: 1.9.4.0
CLI_RELEASE_VERSION_2: 2.0.17.0
CLI_RELEASE_VERSION_2: 2.0.60.0
IDE_TOOLS_RELEASE_VERSION: 1.9.4
MEADOW_OS_VERSION: 1.9.0.0
VS_MAC_2019_VERSION: 8.10
Expand Down Expand Up @@ -532,10 +532,10 @@ jobs:
- name: Setup Nuget
uses: Nuget/[email protected]

- name: Setup Node.js 16
uses: actions/setup-node@v2
- name: Setup Node.js 20
uses: actions/setup-node@v4
with:
node-version: '16'
node-version: '20'

- name: Install NPM
run: |
Expand Down
4 changes: 2 additions & 2 deletions Source/v2/Meadow.Cli/Commands/Current/BaseDeviceCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ private async Task<IMeadowConnection> GetConnection(string? route, bool forceRec

if (route != null)
{
connection = ConnectionManager.GetConnectionForRoute(route, forceReconnect);
connection = await MeadowConnectionManager.GetConnectionForRoute(route, forceReconnect);
}
else
{
connection = ConnectionManager.GetCurrentConnection(forceReconnect);
connection = await ConnectionManager.GetCurrentConnection(forceReconnect);
}

if (connection != null)
Expand Down
2 changes: 1 addition & 1 deletion Source/v2/Meadow.Cli/Meadow.CLI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<Authors>Wilderness Labs, Inc</Authors>
<Company>Wilderness Labs, Inc</Company>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageVersion>2.0.58.0</PackageVersion>
<PackageVersion>2.0.60.0</PackageVersion>
<Platforms>AnyCPU</Platforms>
<PackageProjectUrl>http://developer.wildernesslabs.co/Meadow/Meadow.CLI/</PackageProjectUrl>
<RepositoryUrl>https://github.com/WildernessLabs/Meadow.CLI</RepositoryUrl>
Expand Down
2 changes: 1 addition & 1 deletion Source/v2/Meadow.Cli/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ namespace Meadow.CLI;

public static class Constants
{
public const string CLI_VERSION = "2.0.58.0";
public const string CLI_VERSION = "2.0.60.0";
}
11 changes: 10 additions & 1 deletion Source/v2/Meadow.HCom/Connections/ConnectionBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,17 @@ protected void RaiseConnectionMessage(string message)
ConnectionMessage?.Invoke(this, message);
}

protected void RaiseDebuggerMessage(byte[] data)
bool firstRun = true;

protected async Task RaiseDebuggerMessage(byte[] data)
{
if (firstRun)
{
await Task.Delay(2000);
CartBlanche marked this conversation as resolved.
Show resolved Hide resolved
firstRun = false;
}

Debug.WriteLine($"*************************** RaiseDebuggerMessage: {data.Length}");
DebuggerMessageReceived?.Invoke(this, data);
}

Expand Down
327 changes: 170 additions & 157 deletions Source/v2/Meadow.HCom/Connections/SerialConnection.ListenerProc.cs

Large diffs are not rendered by default.

30 changes: 14 additions & 16 deletions Source/v2/Meadow.HCom/Connections/SerialConnection.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Buffers;
using System.Collections.Concurrent;
using System.IO.Ports;
using System.Security.Cryptography;

Expand All @@ -21,8 +22,7 @@ public partial class SerialConnection : ConnectionBase, IDisposable
private bool _isDisposed;
private ConnectionState _state;
private readonly List<IConnectionListener> _listeners = new List<IConnectionListener>();
private readonly Queue<IRequest> _pendingCommands = new Queue<IRequest>();
private readonly AutoResetEvent _commandEvent = new AutoResetEvent(false);
private readonly ConcurrentQueue<IRequest> _pendingCommands = new ConcurrentQueue<IRequest>();
private bool _maintainConnection;
private Thread? _connectionManager = null;
private readonly List<string> _textList = new List<string>();
Expand Down Expand Up @@ -208,8 +208,7 @@ public override void Detach()
// local function so we can unsubscribe
var count = _messageCount;

_pendingCommands.Enqueue(command);
_commandEvent.Set();
EnqueueRequest(command);

while (timeout-- > 0)
{
Expand Down Expand Up @@ -242,18 +241,13 @@ public override void Detach()
}
}

private void CommandManager()
private async void CommandManager()
{
while (!_isDisposed)
{
_commandEvent.WaitOne(1000);

while (_pendingCommands.Count > 0)
if (_pendingCommands.TryDequeue(out var pendingCommand))
{
Debug.WriteLine($"There are {_pendingCommands.Count} pending commands");

var command = _pendingCommands.Dequeue() as Request;
if (command != null)
if (pendingCommand is Request command)
{
// if this is a file write, we need to packetize for progress

Expand All @@ -263,6 +257,11 @@ private void CommandManager()
// TODO: re-queue on fail?
}
}
else
{
// If no commands to dequeue, delay a bit to avoid busy waiting
await Task.Delay(100);
}
}
}

Expand Down Expand Up @@ -298,7 +297,6 @@ public void EnqueueRequest(IRequest command)
}

_pendingCommands.Enqueue(command);
_commandEvent.Set();
}

private void EncodeAndSendPacket(byte[] messageBytes, CancellationToken? cancellationToken = null)
Expand Down Expand Up @@ -1251,14 +1249,14 @@ public override async Task<DebuggingServer> StartDebuggingSession(int port, ILog
throw new DeviceNotFoundException();
}

logger?.LogDebug($"Start Debugging on port: {port}");
await Device.StartDebugging(port, logger, cancellationToken);

var debuggingServer = new DebuggingServer(this, port, logger);

logger?.LogDebug("Tell the Debugging Server to Start Listening");
_ = debuggingServer.StartListening(cancellationToken);

logger?.LogDebug($"Start Debugging on port: {port}");
await Device.StartDebugging(port, logger, cancellationToken);

return debuggingServer;
}

Expand Down
100 changes: 60 additions & 40 deletions Source/v2/Meadow.HCom/Debugging/DebuggingServer.ActiveClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ private class ActiveClient : IDisposable
private readonly ILogger? _logger;
private bool _disposed;
private readonly BlockingCollection<byte[]> _debuggerMessages = new();
private readonly AutoResetEvent _vsDebugDataReady = new(false);
private readonly object _disposeLock = new();

internal ActiveClient(IMeadowConnection connection, TcpClient tcpClient, ILogger? logger, CancellationToken? cancellationToken)
{
Expand All @@ -35,24 +35,33 @@ internal ActiveClient(IMeadowConnection connection, TcpClient tcpClient, ILogger

_connection.DebuggerMessageReceived += MeadowConnection_DebuggerMessageReceived;

_receiveVsDebugDataTask = Task.Factory.StartNew(SendToMeadowAsync, _cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
/*_receiveVsDebugDataTask = Task.Run(SendToMeadow, _cts.Token);
_receiveMeadowDebugDataTask = Task.Run(SendToVisualStudio, _cts.Token);*/
_receiveVsDebugDataTask = Task.Factory.StartNew(SendToMeadow, _cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
_receiveMeadowDebugDataTask = Task.Factory.StartNew(SendToVisualStudio, _cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}

private void MeadowConnection_DebuggerMessageReceived(object sender, byte[] e)
{
_debuggerMessages.Add(e);
_vsDebugDataReady.Set();
lock (_disposeLock)
{
if (!_disposed)
{
_debuggerMessages.Add(e);
}
}
}

private const int RECEIVE_BUFFER_SIZE = 256;

private async Task SendToMeadowAsync()
private async Task SendToMeadow()
{
byte[]? receiveBuffer = null;

try
{
using var md5 = MD5.Create();
var receiveBuffer = ArrayPool<byte>.Shared.Rent(RECEIVE_BUFFER_SIZE);
receiveBuffer = ArrayPool<byte>.Shared.Rent(RECEIVE_BUFFER_SIZE);
var meadowBuffer = Array.Empty<byte>();

while (!_cts.Token.IsCancellationRequested)
Expand All @@ -74,10 +83,10 @@ private async Task SendToMeadowAsync()
Array.Copy(receiveBuffer, 0, meadowBuffer, destIndex, bytesRead);

_logger?.LogTrace("Received {count} bytes from VS, will forward to HCOM/Meadow. {hash}",
meadowBuffer.Length,
BitConverter.ToString(md5.ComputeHash(meadowBuffer))
.Replace("-", string.Empty)
.ToLowerInvariant());
meadowBuffer.Length,
BitConverter.ToString(md5.ComputeHash(meadowBuffer))
.Replace("-", string.Empty)
.ToLowerInvariant());

await _connection.SendDebuggerData(meadowBuffer, 0, _cts.Token);

Expand Down Expand Up @@ -105,9 +114,16 @@ private async Task SendToMeadowAsync()
}
catch (Exception ex)
{
_logger?.LogError($"Error receiving data from Visual Studio.\nError: {ex.Message}\nStackTrace:\n{ex.StackTrace}");
_logger?.LogError($"Error receiving data from Visual Studio.{Environment.NewLine}Error: {ex.Message}{Environment.NewLine}StackTrace:{Environment.NewLine}{ex.StackTrace}");
throw;
}
finally
{
if (receiveBuffer != null)
{
ArrayPool<byte>.Shared.Return(receiveBuffer);
}
}
}

private async Task SendToVisualStudio()
Expand All @@ -118,12 +134,8 @@ private async Task SendToVisualStudio()
{
if (_networkStream != null && _networkStream.CanWrite)
{
_vsDebugDataReady.WaitOne(500);

while (_debuggerMessages.Count > 0)
if (_debuggerMessages.TryTake(out var byteData, Timeout.Infinite, _cts.Token))
{
var byteData = _debuggerMessages.Take(_cts.Token);

_logger?.LogTrace("Received {count} bytes from Meadow, will forward to VS", byteData.Length);
if (!_tcpClient.Connected)
{
Expand All @@ -136,21 +148,25 @@ private async Task SendToVisualStudio()

Debug.WriteLine($"ToVisStu: {BitConverter.ToString(byteData)}");
}
else
{
// If no _debuggerMessages to Take, delay a bit to avoid busy waiting
await Task.Delay(100);
}
}
else
{
_logger?.LogInformation("Unable to Write Data from Visual Studio");
}
}
}
catch (OperationCanceledException oce)
catch (OperationCanceledException)
{
_logger?.LogInformation("Operation Cancelled");
_logger?.LogTrace(oce, "Operation Cancelled");
}
catch (Exception ex)
{
_logger?.LogError($"Error sending data to Visual Studio.\nError: {ex.Message}\nStackTrace:\n{ex.StackTrace}");
_logger?.LogError($"Error sending data to Visual Studio.{Environment.NewLine}Error: {ex.Message}{Environment.NewLine}StackTrace:{Environment.NewLine}{ex.StackTrace}");

if (!_cts.Token.IsCancellationRequested)
{
Expand All @@ -161,30 +177,34 @@ private async Task SendToVisualStudio()

public void Dispose()
{
if (_disposed)
lock (_disposeLock)
{
return;
}
if (_disposed) return;

_logger?.LogTrace("Disposing ActiveClient");
_cts.Cancel();
try
{
Task.WhenAll(_receiveVsDebugDataTask, _receiveMeadowDebugDataTask).Wait(TimeSpan.FromSeconds(10));
}
catch (AggregateException ex)
{
_logger?.LogError("Error waiting for tasks to complete during dispose", ex);
}
_tcpClient.Dispose();
_networkStream.Dispose();
_cts.Dispose();
_logger?.LogTrace("Disposing ActiveClient");

if (_connection != null)
{
_connection.DebuggerMessageReceived -= MeadowConnection_DebuggerMessageReceived;
_cts.Cancel();

try
{
Task.WhenAll(_receiveVsDebugDataTask, _receiveMeadowDebugDataTask).Wait(TimeSpan.FromSeconds(10));
}
catch (AggregateException ex)
{
_logger?.LogError("Error waiting for tasks to complete during dispose", ex);
}

_tcpClient.Dispose();
_networkStream.Dispose();
_cts.Dispose();

if (_connection != null)
{
_connection.DebuggerMessageReceived -= MeadowConnection_DebuggerMessageReceived;
}

_disposed = true;
}
_disposed = true;
}
}
}
}
Loading
Loading