diff --git a/Source/v2/Meadow.Cli/Meadow.CLI.csproj b/Source/v2/Meadow.Cli/Meadow.CLI.csproj index af8572bb..7fad0a2f 100644 --- a/Source/v2/Meadow.Cli/Meadow.CLI.csproj +++ b/Source/v2/Meadow.Cli/Meadow.CLI.csproj @@ -10,7 +10,7 @@ Wilderness Labs, Inc Wilderness Labs, Inc true - 2.0.58.0 + 2.0.60.0 AnyCPU http://developer.wildernesslabs.co/Meadow/Meadow.CLI/ https://github.com/WildernessLabs/Meadow.CLI diff --git a/Source/v2/Meadow.Cli/Properties/AssemblyInfo.cs b/Source/v2/Meadow.Cli/Properties/AssemblyInfo.cs index dcd1693f..873026bf 100644 --- a/Source/v2/Meadow.Cli/Properties/AssemblyInfo.cs +++ b/Source/v2/Meadow.Cli/Properties/AssemblyInfo.cs @@ -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"; } \ No newline at end of file diff --git a/Source/v2/Meadow.HCom/Connections/SerialConnection.ListenerProc.cs b/Source/v2/Meadow.HCom/Connections/SerialConnection.ListenerProc.cs index 1b449d9c..e7433e33 100644 --- a/Source/v2/Meadow.HCom/Connections/SerialConnection.ListenerProc.cs +++ b/Source/v2/Meadow.HCom/Connections/SerialConnection.ListenerProc.cs @@ -1,4 +1,4 @@ -namespace Meadow.Hcom +namespace Meadow.Hcom { public partial class SerialConnection { @@ -52,6 +52,34 @@ private async Task ListenerProc() var delimiter = new byte[] { 0x00 }; var receivedLength = 0; + async Task ReOpen() // local function + { + Debug.WriteLine($"Device reset detected"); + + var timeout = 20; + try { _port.Close(); } catch { } // Swallow any exceptions on close - there is nothing we can do about it + + while (!_port.IsOpen) + { + await Task.Delay(500); + + if (timeout-- < 0) + { + return; + } + + try + { + Open(); + Debug.WriteLine($"Port re-opened"); + } + catch + { + Debug.WriteLine($"Failed to re-open port"); + } + } + } + while (!_isDisposed) { if (_port.IsOpen) @@ -64,32 +92,20 @@ private async Task ListenerProc() try { receivedLength = _port.Read(readBuffer, 0, readBuffer.Length); + if (receivedLength == 0) + { + Debug.WriteLine($"Received 0 bytes"); + throw new OperationCanceledException(); + } } catch (OperationCanceledException) { - Debug.WriteLine($"Device reset detected"); - - var timeout = 20; - - while (!_port.IsOpen) - { - await Task.Delay(500); - - if (timeout-- < 0) - { - return; - } - - try - { - Open(); - Debug.WriteLine($"Port re-opened"); - } - catch - { - Debug.WriteLine($"Failed to re-open port"); - } - } + await ReOpen(); + goto read; + } + catch (InvalidOperationException) + { + await ReOpen(); goto read; } diff --git a/Source/v2/Meadow.HCom/Connections/SerialConnection.cs b/Source/v2/Meadow.HCom/Connections/SerialConnection.cs index 452d93eb..ef37f8b5 100755 --- a/Source/v2/Meadow.HCom/Connections/SerialConnection.cs +++ b/Source/v2/Meadow.HCom/Connections/SerialConnection.cs @@ -1,4 +1,4 @@ -using System.Buffers; +using System.Buffers; using System.IO.Ports; using System.Security.Cryptography; @@ -1254,7 +1254,7 @@ public override async Task StartDebuggingSession(int port, ILog var debuggingServer = new DebuggingServer(this, port, logger); logger?.LogDebug("Tell the Debugging Server to Start Listening"); - _ = debuggingServer.StartListening(cancellationToken); + await debuggingServer.StartListening(cancellationToken); logger?.LogDebug($"Start Debugging on port: {port}"); await Device.StartDebugging(port, logger, cancellationToken); diff --git a/Source/v2/Meadow.HCom/Debugging/DebuggingServer.ActiveClient.cs b/Source/v2/Meadow.HCom/Debugging/DebuggingServer.ActiveClient.cs index ce6cb7a2..f25cb25d 100644 --- a/Source/v2/Meadow.HCom/Debugging/DebuggingServer.ActiveClient.cs +++ b/Source/v2/Meadow.HCom/Debugging/DebuggingServer.ActiveClient.cs @@ -1,7 +1,6 @@ -using System.Buffers; +using System.Buffers; using System.Collections.Concurrent; using System.Net.Sockets; -using System.Security.Cryptography; namespace Meadow.Hcom; @@ -10,17 +9,16 @@ public partial class DebuggingServer private class ActiveClient : IDisposable { private readonly IMeadowConnection _connection; - private readonly TcpClient _tcpClient; - private readonly NetworkStream _networkStream; + private TcpClient _tcpClient; + private NetworkStream _networkStream; private readonly CancellationTokenSource _cts; - private readonly Task _receiveVsDebugDataTask; - private readonly Task _receiveMeadowDebugDataTask; + private Task _receiveVsDebugDataTask; + private Task _receiveMeadowDebugDataTask; private readonly ILogger? _logger; private bool _disposed; private readonly BlockingCollection _debuggerMessages = new(); - private readonly AutoResetEvent _vsDebugDataReady = new(false); - internal ActiveClient(IMeadowConnection connection, TcpClient tcpClient, ILogger? logger, CancellationToken? cancellationToken) + internal ActiveClient(IMeadowConnection connection, ILogger? logger, CancellationToken? cancellationToken) { _cts = cancellationToken != null ? CancellationTokenSource.CreateLinkedTokenSource(cancellationToken.Value) @@ -28,13 +26,15 @@ internal ActiveClient(IMeadowConnection connection, TcpClient tcpClient, ILogger _logger = logger; _connection = connection; - _tcpClient = tcpClient; - _networkStream = tcpClient.GetStream(); - - _logger?.LogDebug("Starting receive task"); - _connection.DebuggerMessageReceived += MeadowConnection_DebuggerMessageReceived; + } + public async Task Start(TcpListener tcpListener) + { + _tcpClient = await tcpListener.AcceptTcpClientAsync(); + _networkStream = _tcpClient.GetStream(); + + _logger?.LogDebug("Starting receive task"); _receiveVsDebugDataTask = Task.Factory.StartNew(SendToMeadowAsync, _cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); _receiveMeadowDebugDataTask = Task.Factory.StartNew(SendToVisualStudio, _cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); } @@ -42,7 +42,6 @@ internal ActiveClient(IMeadowConnection connection, TcpClient tcpClient, ILogger private void MeadowConnection_DebuggerMessageReceived(object sender, byte[] e) { _debuggerMessages.Add(e); - _vsDebugDataReady.Set(); } private const int RECEIVE_BUFFER_SIZE = 256; @@ -51,9 +50,7 @@ private async Task SendToMeadowAsync() { try { - using var md5 = MD5.Create(); var receiveBuffer = ArrayPool.Shared.Rent(RECEIVE_BUFFER_SIZE); - var meadowBuffer = Array.Empty(); while (!_cts.Token.IsCancellationRequested) { @@ -69,13 +66,12 @@ private async Task SendToMeadowAsync() continue; } - var destIndex = meadowBuffer.Length; - Array.Resize(ref meadowBuffer, destIndex + bytesRead); - Array.Copy(receiveBuffer, 0, meadowBuffer, destIndex, bytesRead); + var meadowBuffer = new byte[bytesRead]; + Array.Copy(receiveBuffer, 0, meadowBuffer, 0, bytesRead); _logger?.LogTrace("Received {count} bytes from VS, will forward to HCOM/Meadow. {hash}", meadowBuffer.Length, - BitConverter.ToString(md5.ComputeHash(meadowBuffer)) + BitConverter.ToString(meadowBuffer) .Replace("-", string.Empty) .ToLowerInvariant()); @@ -83,7 +79,6 @@ private async Task SendToMeadowAsync() Debug.WriteLine($"ToMeadow: {BitConverter.ToString(meadowBuffer)}"); - meadowBuffer = Array.Empty(); } while (_networkStream.DataAvailable); } else @@ -96,12 +91,10 @@ private async Task SendToMeadowAsync() catch (IOException ioe) { _logger?.LogInformation("Visual Studio has Disconnected"); - _logger?.LogTrace(ioe, "Visual Studio has Disconnected"); } catch (ObjectDisposedException ode) { _logger?.LogInformation("Visual Studio has stopped debugging"); - _logger?.LogTrace(ode, "Visual Studio has stopped debugging"); } catch (Exception ex) { @@ -114,33 +107,23 @@ private async Task SendToVisualStudio() { try { - while (!_cts.Token.IsCancellationRequested) + while (!_cts.IsCancellationRequested) { - if (_networkStream != null && _networkStream.CanWrite) + if (!_debuggerMessages.TryTake(out var byteData, 500, _cts.Token)) { - _vsDebugDataReady.WaitOne(500); - - while (_debuggerMessages.Count > 0) - { - var byteData = _debuggerMessages.Take(_cts.Token); - - _logger?.LogTrace("Received {count} bytes from Meadow, will forward to VS", byteData.Length); - if (!_tcpClient.Connected) - { - _logger?.LogDebug("Cannot forward data, Visual Studio is not connected"); - return; - } - - await _networkStream.WriteAsync(byteData, 0, byteData.Length, _cts.Token); - _logger?.LogTrace("Forwarded {count} bytes to VS", byteData.Length); - - Debug.WriteLine($"ToVisStu: {BitConverter.ToString(byteData)}"); - } + continue; } - else + + _logger?.LogTrace("Received {count} bytes from Meadow, will forward to VS", byteData.Length); + if (!_tcpClient.Connected || _networkStream == null || !_networkStream.CanWrite) { - _logger?.LogInformation("Unable to Write Data from Visual Studio"); + _logger?.LogDebug("Cannot forward data, Visual Studio is not connected"); + break; } + + await _networkStream.WriteAsync(byteData, 0, byteData.Length, _cts.Token); + _logger?.LogTrace("Forwarded {count} bytes to VS", byteData.Length); + Debug.WriteLine($"ToVisStu: {BitConverter.ToString(byteData)}"); } } catch (OperationCanceledException oce) diff --git a/Source/v2/Meadow.HCom/Debugging/DebuggingServer.cs b/Source/v2/Meadow.HCom/Debugging/DebuggingServer.cs index 1b359759..62418990 100644 --- a/Source/v2/Meadow.HCom/Debugging/DebuggingServer.cs +++ b/Source/v2/Meadow.HCom/Debugging/DebuggingServer.cs @@ -1,4 +1,4 @@ -using System.Net; +using System.Net; using System.Net.Sockets; namespace Meadow.Hcom; @@ -50,8 +50,7 @@ public async Task StartListening(CancellationToken cancellationToken) _logger?.LogInformation($"Listening for Visual Studio to connect"); // This call will wait for the client to connect, before continuing. - var tcpClient = await _listener.AcceptTcpClientAsync(); - _activeClient = CreateActiveClient(tcpClient); + _activeClient = await CreateActiveClient(_listener); } /// @@ -70,23 +69,22 @@ public async Task StopListening() } } - private ActiveClient? CreateActiveClient(TcpClient tcpClient) + private async Task CreateActiveClient(TcpListener listener) { try { - lock (_lck) + if (_activeClient != null) { - _logger?.LogInformation("Visual Studio has Connected" + Environment.NewLine); - - if (_activeClient != null) - { - _logger?.LogDebug("Closing active client"); - _activeClient?.Dispose(); - _activeClient = null; - } - - return new ActiveClient(_connection, tcpClient, _logger, _cancellationTokenSource?.Token); + _logger?.LogDebug("Closing active client"); + _activeClient?.Dispose(); + _activeClient = null; } + + + var client = new ActiveClient(_connection, _logger, _cancellationTokenSource?.Token); + await client.Start(listener); + _logger?.LogInformation("Debugger has connected" + Environment.NewLine); + return client; } catch (Exception ex) {