Add support for Virtual nanoDevice (#756)

This commit is contained in:
José Simões 2022-12-05 14:35:18 +00:00 коммит произвёл GitHub
Родитель e65dc3ad95
Коммит bc304f0a95
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
18 изменённых файлов: 979 добавлений и 15 удалений

Просмотреть файл

@ -109,6 +109,9 @@ namespace nanoFramework.Tools.VisualStudio.Extension
private const string SETTINGS_PORT_BLACK_LIST_KEY = "PortBlackList";
private const string SETTINGS_AUTO_UPDATE_ENABLE_KEY = "AutoUpdateEnable";
private const string SETTINGS_ALLOW_PREVIEW_IMAGES_KEY = "IncludePrereleaseUpdates";
private const string SETTINGS_VIRTUAL_DEVICE_ENABLE_KEY = "VirtualDeviceEnable";
private const string SETTINGS_VIRTUAL_DEVICE_AUTO_UPDATE_NANOCLR_KEY = "VirtualDeviceAutoUpdateNanoCLR";
private const string SETTINGS_VIRTUAL_DEVICE_PORT = "VirtualDevicePort";
private static bool? s_OptionShowInternalErrors;
/// <summary>
@ -336,6 +339,89 @@ namespace nanoFramework.Tools.VisualStudio.Extension
}
}
private static bool? s_SettingVirtualDeviceAutoUpdateNanoClrImage = null;
/// <summary>
/// Setting to enable auto updating nanoCLR image for the virtual device.
/// The value is persisted per user
/// Default is <see langword="false"/>
/// </summary>
public static bool SettingVirtualDeviceAutoUpdateNanoClrImage
{
get
{
if (!s_SettingVirtualDeviceAutoUpdateNanoClrImage.HasValue)
{
s_SettingVirtualDeviceAutoUpdateNanoClrImage = bool.Parse((string)s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY).GetValue(SETTINGS_VIRTUAL_DEVICE_AUTO_UPDATE_NANOCLR_KEY, "True"));
}
return s_SettingVirtualDeviceAutoUpdateNanoClrImage.Value;
}
set
{
s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY, true).SetValue(SETTINGS_VIRTUAL_DEVICE_AUTO_UPDATE_NANOCLR_KEY, value);
s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY, true).Flush();
s_SettingVirtualDeviceAutoUpdateNanoClrImage = value;
}
}
private static bool? s_SettingVirtualDeviceEnable = null;
/// <summary>
/// Setting to enable the use of a virtual device running on the development machine as a command line interface (CLI)
/// The value is persisted per user
/// Default is <see langword="false"/>
/// </summary>
public static bool SettingVirtualDeviceEnable
{
get
{
if (!s_SettingVirtualDeviceEnable.HasValue)
{
s_SettingVirtualDeviceEnable = bool.Parse((string)s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY).GetValue(SETTINGS_VIRTUAL_DEVICE_ENABLE_KEY, "False"));
}
return s_SettingVirtualDeviceEnable.Value;
}
set
{
s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY, true).SetValue(SETTINGS_VIRTUAL_DEVICE_ENABLE_KEY, value);
s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY, true).Flush();
s_SettingVirtualDeviceEnable = value;
}
}
private static string s_SettingVirtualDevicePort = null;
/// <summary>
/// Setting to store COM port for the virtual device
/// The value is persisted per user.
/// Default is empty.
/// </summary>
public static string SettingVirtualDevicePort
{
get
{
if (string.IsNullOrEmpty(s_SettingVirtualDevicePort))
{
s_SettingVirtualDevicePort = (string)s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY).GetValue(SETTINGS_VIRTUAL_DEVICE_PORT, string.Empty);
}
return s_SettingVirtualDevicePort;
}
set
{
s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY, true).SetValue(SETTINGS_VIRTUAL_DEVICE_PORT, value);
s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY, true).Flush();
s_SettingVirtualDevicePort = value;
}
}
#endregion
/// <summary>
@ -344,6 +430,12 @@ namespace nanoFramework.Tools.VisualStudio.Extension
/// </summary>
public static INanoDeviceCommService NanoDeviceCommService { get; private set; }
/// <summary>
/// Provides direct access to <see cref="IVirtualDeviceService"/> service.
/// To be used by providers and other classes in the package.
/// </summary>
internal static IVirtualDeviceService VirtualDeviceService { get; private set; }
private static NanoFrameworkPackage s_instance { get; set; }
// command set Guid
@ -391,6 +483,8 @@ namespace nanoFramework.Tools.VisualStudio.Extension
AddService(typeof(NanoDeviceCommService), CreateNanoDeviceCommServiceAsync);
NanoDeviceCommService = await GetServiceAsync(typeof(NanoDeviceCommService)) as INanoDeviceCommService;
VirtualDeviceService = await GetServiceAsync(typeof(VirtualDeviceService)) as IVirtualDeviceService;
Assumes.Present(VirtualDeviceService);
ViewModelLocator viewModelLocator = null;
@ -417,6 +511,8 @@ namespace nanoFramework.Tools.VisualStudio.Extension
// Enable debugger UI context
UIContext.FromUIContextGuid(CorDebug.EngineGuid).IsActive = true;
VirtualDeviceService.InitVirtualDeviceAsync().FireAndForget();
OutputWelcomeMessage();
}

Просмотреть файл

@ -119,6 +119,53 @@
</Grid>
</TabItem>
<TabItem Header="Virtual Device" IsEnabled="True">
<Grid Margin="10,10,10,10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<GroupBox Grid.Row="0" Margin="0,0,0,69" Header=" " IsEnabled="{Binding IsChecked, ElementName=EnableVirtualDevice}" Grid.RowSpan="4" >
<Grid Margin="8,10,10,10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="111*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<!-- setting to include configuration block in deployment image -->
<Grid Grid.Row="0" Grid.ColumnSpan="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column ="0" Content="Serial Port:" HorizontalAlignment="Left" Name="VirtualSerialPortLabel"/>
<TextBox Grid.Row ="0" Grid.Column="1" Height="23" Margin="2,2,2,2" x:Name="VirtualDeviceSerialPort" Width="50" HorizontalAlignment="Left"/>
</Grid>
<Button x:Name="StartStopDevice" Content="Start virtual device" HorizontalAlignment="Left" Click="StartStopDevice_Click" Grid.Row="1" Margin="55,20,0,0" VerticalAlignment="Top" Width="106" Grid.Column="1" />
<CheckBox x:Name="AutoUpdateNanoClrImage" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left" Margin="4,20,0,0" Content="Auto update nanoCLR image" Grid.ColumnSpan="2" Checked="AutoUpdateNanoClrImage_Checked" Unchecked="AutoUpdateNanoClrImage_Checked" />
</Grid>
</GroupBox>
<CheckBox x:Name="EnableVirtualDevice" Grid.Row="0" Margin="10,2,-10,0" Content="Enable Virtual Device" Height="16" VerticalAlignment="Top" Checked="EnableVirtualSerialDevice_Checked" Unchecked="EnableVirtualSerialDevice_Checked"/>
</Grid>
</TabItem>
</TabControl>
<Button Content="Close" HorizontalAlignment="Right" Margin="0,357,20,0" VerticalAlignment="Top" Width="75" x:Name="CloseButton" Click="CloseButton_Click"/>

Просмотреть файл

@ -5,7 +5,9 @@
namespace nanoFramework.Tools.VisualStudio.Extension
{
using GalaSoft.MvvmLight.Messaging;
using Microsoft.VisualStudio.PlatformUI;
using nanoFramework.Tools.VisualStudio.Extension.ToolWindow.ViewModel;
using System.Collections.Generic;
using System.Net;
using System.Windows.Controls.Primitives;
@ -16,6 +18,8 @@ namespace nanoFramework.Tools.VisualStudio.Extension
/// </summary>
public partial class SettingsDialog : DialogWindow
{
private const string _stopVirtualDeviceLabel = "Stop Virtual Device";
private const string _startVirtualDeviceLabel = "Start Virtual Device";
private static IPAddress _InvalidIPv4 = new IPAddress(0x0);
public SettingsDialog(string helpTopic) : base(helpTopic)
@ -36,11 +40,16 @@ namespace nanoFramework.Tools.VisualStudio.Extension
// init controls
private void InitControls()
{
Messenger.Default.Register<NotificationMessage>(this, DeviceExplorerViewModel.MessagingTokens.VirtualDeviceOperationExecuting, (message) => this.UpdateStartStopAvailability(message.Notification));
// set controls according to stored preferences
GenerateDeploymentImage.IsChecked = NanoFrameworkPackage.SettingGenerateDeploymentImage;
IncludeConfigBlock.IsChecked = NanoFrameworkPackage.SettingIncludeConfigBlockInDeploymentImage;
AutoUpdateEnable.IsChecked = NanoFrameworkPackage.SettingAutoUpdateEnable;
IncludePrereleaseUpdates.IsChecked = NanoFrameworkPackage.SettingIncludePrereleaseUpdates;
EnableVirtualDevice.IsChecked = NanoFrameworkPackage.SettingVirtualDeviceEnable;
VirtualDeviceSerialPort.Text = NanoFrameworkPackage.SettingVirtualDevicePort;
AutoUpdateNanoClrImage.IsChecked = NanoFrameworkPackage.SettingVirtualDeviceAutoUpdateNanoClrImage;
if (string.IsNullOrEmpty(NanoFrameworkPackage.SettingPathOfFlashDumpCache))
{
@ -56,14 +65,34 @@ namespace nanoFramework.Tools.VisualStudio.Extension
PortBlackList.Text = NanoFrameworkPackage.SettingPortBlackList;
// update button content for start/stop device depending if it's running or not
if (EnableVirtualDevice.IsChecked.Value
&& NanoFrameworkPackage.VirtualDeviceService.VirtualDeviceIsRunning)
{
StartStopDevice.Content = _stopVirtualDeviceLabel;
}
if (!string.IsNullOrEmpty(VirtualDeviceSerialPort.Text))
{
// if there is a COM port set, enable the text box only if it's not running
VirtualDeviceSerialPort.IsEnabled = !NanoFrameworkPackage.VirtualDeviceService.VirtualDeviceIsRunning;
}
// OK to add event handlers to controls now
StoreCacheToUserPath.Checked += StoreCacheLocationChanged_Checked;
StoreCacheToUserPath.Unchecked += StoreCacheLocationChanged_Checked;
VirtualDeviceSerialPort.LostFocus += VirtualDeviceSerialPort_LostFocus;
// set focus on close button
CloseButton.Focus();
}
private void UpdateStartStopAvailability(string installCompleted)
{
StartStopDevice.IsEnabled = !bool.Parse(installCompleted);
}
private void CloseButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
Close();
@ -83,7 +112,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
private void StoreCacheLocationChanged_Checked(object sender, System.Windows.RoutedEventArgs e)
{
if(StoreCacheToProjectOutputPath.IsChecked.GetValueOrDefault())
if (StoreCacheToProjectOutputPath.IsChecked.GetValueOrDefault())
{
// cache location is project output
// save setting by clearing the path
@ -162,5 +191,55 @@ namespace nanoFramework.Tools.VisualStudio.Extension
// save new state
NanoFrameworkPackage.SettingIncludePrereleaseUpdates = (sender as ToggleButton).IsChecked ?? false;
}
private void EnableVirtualSerialDevice_Checked(object sender, System.Windows.RoutedEventArgs e)
{
// save new state
NanoFrameworkPackage.SettingVirtualDeviceEnable = (sender as ToggleButton).IsChecked ?? false;
// install/update nanoclr tool
if (NanoFrameworkPackage.SettingVirtualDeviceEnable && !NanoFrameworkPackage.VirtualDeviceService.NanoClrInstalled)
{
NanoFrameworkPackage.VirtualDeviceService.InstallNanoClrTool();
}
}
private void VirtualDeviceSerialPort_LostFocus(object sender, System.Windows.RoutedEventArgs e)
{
// store updated setting
NanoFrameworkPackage.SettingVirtualDevicePort = VirtualDeviceSerialPort.Text;
}
private async void StartStopDevice_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (NanoFrameworkPackage.VirtualDeviceService.VirtualDeviceIsRunning)
{
NanoFrameworkPackage.VirtualDeviceService.StopVirtualDevice();
StartStopDevice.Content = _startVirtualDeviceLabel;
VirtualDeviceSerialPort.IsEnabled = true;
}
else
{
if (await NanoFrameworkPackage.VirtualDeviceService.StartVirtualDeviceAsync(true))
{
StartStopDevice.Content = _stopVirtualDeviceLabel;
VirtualDeviceSerialPort.IsEnabled = false;
// if this is the 1st run, update serial port name, if not already there
if (string.IsNullOrEmpty(VirtualDeviceSerialPort.Text))
{
VirtualDeviceSerialPort.Text = NanoFrameworkPackage.SettingVirtualDevicePort;
}
}
}
}
private void AutoUpdateNanoClrImage_Checked(object sender, System.Windows.RoutedEventArgs e)
{
// save new state
NanoFrameworkPackage.SettingVirtualDeviceAutoUpdateNanoClrImage = (sender as ToggleButton).IsChecked ?? false;
}
}
}

Просмотреть файл

@ -476,6 +476,9 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<PackageReference Include="CliWrap">
<Version>3.5.0</Version>
</PackageReference>
<PackageReference Include="Extended.Wpf.Toolkit">
<Version>4.3.0</Version>
</PackageReference>
@ -638,4 +641,4 @@
<Target Name="BeforeBuild">
</Target>
-->
</Project>
</Project>

Просмотреть файл

@ -2,6 +2,20 @@
"version": 1,
"dependencies": {
".NETFramework,Version=v4.7.2": {
"CliWrap": {
"type": "Direct",
"requested": "[3.5.0, )",
"resolved": "3.5.0",
"contentHash": "JhC8xnY2uVPD8/o/wj8o+5uYQ8jiWJ9rrgTI6i5QqZco++nelZ8RgBjcLmPMJMQMvAXu39obUA/aeEEaYdQUhw==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "6.0.0",
"System.Buffers": "4.5.1",
"System.Memory": "4.5.5",
"System.Runtime.InteropServices.RuntimeInformation": "4.3.0",
"System.Threading.Tasks.Extensions": "4.5.4",
"System.ValueTuple": "4.5.0"
}
},
"Extended.Wpf.Toolkit": {
"type": "Direct",
"requested": "[4.3.0, )",
@ -2109,8 +2123,8 @@
},
"System.Memory": {
"type": "Transitive",
"resolved": "4.5.4",
"contentHash": "1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==",
"resolved": "4.5.5",
"contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==",
"dependencies": {
"System.Buffers": "4.5.1",
"System.Numerics.Vectors": "4.5.0",

Просмотреть файл

@ -1,6 +1,6 @@
{
"$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
"version": "2019.11.0",
"version": "2019.12.0",
"release": {
"branchName" : "release-v{version}",
"versionIncrement" : "minor",

Просмотреть файл

@ -108,6 +108,9 @@ namespace nanoFramework.Tools.VisualStudio.Extension
private const string SETTINGS_PORT_BLACK_LIST_KEY = "PortBlackList";
private const string SETTINGS_AUTO_UPDATE_ENABLE_KEY = "AutoUpdateEnable";
private const string SETTINGS_ALLOW_PREVIEW_IMAGES_KEY = "IncludePrereleaseUpdates";
private const string SETTINGS_VIRTUAL_DEVICE_ENABLE_KEY = "VirtualDeviceEnable";
private const string SETTINGS_VIRTUAL_DEVICE_AUTO_UPDATE_NANOCLR_KEY = "VirtualDeviceAutoUpdateNanoCLR";
private const string SETTINGS_VIRTUAL_DEVICE_PORT = "VirtualDevicePort";
private static bool? s_OptionShowInternalErrors;
/// <summary>
@ -334,6 +337,89 @@ namespace nanoFramework.Tools.VisualStudio.Extension
s_SettingIncludePrereleaseUpdates = value;
}
}
private static bool? s_SettingVirtualDeviceAutoUpdateNanoClrImage = null;
/// <summary>
/// Setting to enable auto updating nanoCLR image for the virtual device.
/// The value is persisted per user
/// Default is <see langword="false"/>
/// </summary>
public static bool SettingVirtualDeviceAutoUpdateNanoClrImage
{
get
{
if (!s_SettingVirtualDeviceAutoUpdateNanoClrImage.HasValue)
{
s_SettingVirtualDeviceAutoUpdateNanoClrImage = bool.Parse((string)s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY).GetValue(SETTINGS_VIRTUAL_DEVICE_AUTO_UPDATE_NANOCLR_KEY, "True"));
}
return s_SettingVirtualDeviceAutoUpdateNanoClrImage.Value;
}
set
{
s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY, true).SetValue(SETTINGS_VIRTUAL_DEVICE_AUTO_UPDATE_NANOCLR_KEY, value);
s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY, true).Flush();
s_SettingVirtualDeviceAutoUpdateNanoClrImage = value;
}
}
private static bool? s_SettingVirtualDeviceEnable = null;
/// <summary>
/// Setting to enable the use of a virtual device running on the development machine as a command line interface (CLI)
/// The value is persisted per user
/// Default is <see langword="false"/>
/// </summary>
public static bool SettingVirtualDeviceEnable
{
get
{
if (!s_SettingVirtualDeviceEnable.HasValue)
{
s_SettingVirtualDeviceEnable = bool.Parse((string)s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY).GetValue(SETTINGS_VIRTUAL_DEVICE_ENABLE_KEY, "False"));
}
return s_SettingVirtualDeviceEnable.Value;
}
set
{
s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY, true).SetValue(SETTINGS_VIRTUAL_DEVICE_ENABLE_KEY, value);
s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY, true).Flush();
s_SettingVirtualDeviceEnable = value;
}
}
private static string s_SettingVirtualDevicePort = null;
/// <summary>
/// Setting to store COM port for the virtual device
/// The value is persisted per user.
/// Default is empty.
/// </summary>
public static string SettingVirtualDevicePort
{
get
{
if (string.IsNullOrEmpty(s_SettingVirtualDevicePort))
{
s_SettingVirtualDevicePort = (string)s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY).GetValue(SETTINGS_VIRTUAL_DEVICE_PORT, string.Empty);
}
return s_SettingVirtualDevicePort;
}
set
{
s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY, true).SetValue(SETTINGS_VIRTUAL_DEVICE_PORT, value);
s_instance.UserRegistryRoot.OpenSubKey(EXTENSION_SUBKEY, true).Flush();
s_SettingVirtualDevicePort = value;
}
}
#endregion
@ -343,6 +429,12 @@ namespace nanoFramework.Tools.VisualStudio.Extension
/// </summary>
public static INanoDeviceCommService NanoDeviceCommService { get; private set; }
/// <summary>
/// Provides direct access to <see cref="IVirtualDeviceService"/> service.
/// To be used by providers and other classes in the package.
/// </summary>
internal static IVirtualDeviceService VirtualDeviceService { get; private set; }
private static NanoFrameworkPackage s_instance { get; set; }
// command set Guid
@ -388,8 +480,11 @@ namespace nanoFramework.Tools.VisualStudio.Extension
await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
AddService(typeof(NanoDeviceCommService), CreateNanoDeviceCommServiceAsync);
AddService(typeof(VirtualDeviceService), CreateVirtualDeviceManagerServiceAsync);
NanoDeviceCommService = await GetServiceAsync(typeof(NanoDeviceCommService)) as INanoDeviceCommService;
VirtualDeviceService = await GetServiceAsync(typeof(VirtualDeviceService)) as IVirtualDeviceService;
Assumes.Present(VirtualDeviceService);
ViewModelLocator viewModelLocator = null;
@ -416,6 +511,8 @@ namespace nanoFramework.Tools.VisualStudio.Extension
// Enable debugger UI context
UIContext.FromUIContextGuid(CorDebug.EngineGuid).IsActive = true;
VirtualDeviceService.InitVirtualDeviceAsync().FireAndForget();
OutputWelcomeMessage();
}
@ -434,6 +531,18 @@ namespace nanoFramework.Tools.VisualStudio.Extension
return service;
}
public async Task<object> CreateVirtualDeviceManagerServiceAsync(IAsyncServiceContainer container, CancellationToken cancellationToken, Type serviceType)
{
VirtualDeviceService service = null;
await System.Threading.Tasks.Task.Run(() =>
{
service = new VirtualDeviceService(this);
});
return service;
}
private void OutputWelcomeMessage()
{
_ = System.Threading.Tasks.Task.Run(async () =>

Просмотреть файл

@ -119,6 +119,53 @@
</Grid>
</TabItem>
<TabItem Header="Virtual Device" IsEnabled="True">
<Grid Margin="10,10,10,10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<GroupBox Grid.Row="0" Margin="0,0,0,69" Header=" " IsEnabled="{Binding IsChecked, ElementName=EnableVirtualDevice}" Grid.RowSpan="4" >
<Grid Margin="8,10,10,10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="111*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<!-- setting to include configuration block in deployment image -->
<Grid Grid.Row="0" Grid.ColumnSpan="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column ="0" Content="Serial Port:" HorizontalAlignment="Left" Name="VirtualSerialPortLabel"/>
<TextBox Grid.Row ="0" Grid.Column="1" Height="23" Margin="2,2,2,2" x:Name="VirtualDeviceSerialPort" Width="50" HorizontalAlignment="Left"/>
</Grid>
<Button x:Name="StartStopDevice" Content="Start virtual device" HorizontalAlignment="Left" Click="StartStopDevice_Click" Grid.Row="1" Margin="55,20,0,0" VerticalAlignment="Top" Width="106" Grid.Column="1" />
<CheckBox x:Name="AutoUpdateNanoClrImage" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left" Margin="4,20,0,0" Content="Auto update nanoCLR image" Grid.ColumnSpan="2" Checked="AutoUpdateNanoClrImage_Checked" Unchecked="AutoUpdateNanoClrImage_Checked" />
</Grid>
</GroupBox>
<CheckBox x:Name="EnableVirtualDevice" Grid.Row="0" Margin="10,2,-10,0" Content="Enable Virtual Device" Height="16" VerticalAlignment="Top" Checked="EnableVirtualSerialDevice_Checked" Unchecked="EnableVirtualSerialDevice_Checked"/>
</Grid>
</TabItem>
</TabControl>
<Button Content="Close" HorizontalAlignment="Right" Margin="0,357,20,0" VerticalAlignment="Top" Width="75" x:Name="CloseButton" Click="CloseButton_Click"/>

Просмотреть файл

@ -5,7 +5,9 @@
namespace nanoFramework.Tools.VisualStudio.Extension
{
using GalaSoft.MvvmLight.Messaging;
using Microsoft.VisualStudio.PlatformUI;
using nanoFramework.Tools.VisualStudio.Extension.ToolWindow.ViewModel;
using System.Collections.Generic;
using System.Net;
using System.Windows.Controls.Primitives;
@ -16,6 +18,8 @@ namespace nanoFramework.Tools.VisualStudio.Extension
/// </summary>
public partial class SettingsDialog : DialogWindow
{
private const string _stopVirtualDeviceLabel = "Stop Virtual Device";
private const string _startVirtualDeviceLabel = "Start Virtual Device";
private static IPAddress _InvalidIPv4 = new IPAddress(0x0);
public SettingsDialog(string helpTopic) : base(helpTopic)
@ -36,11 +40,16 @@ namespace nanoFramework.Tools.VisualStudio.Extension
// init controls
private void InitControls()
{
Messenger.Default.Register<NotificationMessage>(this, DeviceExplorerViewModel.MessagingTokens.VirtualDeviceOperationExecuting, (message) => this.UpdateStartStopAvailability(message.Notification));
// set controls according to stored preferences
GenerateDeploymentImage.IsChecked = NanoFrameworkPackage.SettingGenerateDeploymentImage;
IncludeConfigBlock.IsChecked = NanoFrameworkPackage.SettingIncludeConfigBlockInDeploymentImage;
AutoUpdateEnable.IsChecked = NanoFrameworkPackage.SettingAutoUpdateEnable;
IncludePrereleaseUpdates.IsChecked = NanoFrameworkPackage.SettingIncludePrereleaseUpdates;
EnableVirtualDevice.IsChecked = NanoFrameworkPackage.SettingVirtualDeviceEnable;
VirtualDeviceSerialPort.Text = NanoFrameworkPackage.SettingVirtualDevicePort;
AutoUpdateNanoClrImage.IsChecked = NanoFrameworkPackage.SettingVirtualDeviceAutoUpdateNanoClrImage;
if (string.IsNullOrEmpty(NanoFrameworkPackage.SettingPathOfFlashDumpCache))
{
@ -56,14 +65,34 @@ namespace nanoFramework.Tools.VisualStudio.Extension
PortBlackList.Text = NanoFrameworkPackage.SettingPortBlackList;
// update button content for start/stop device depending if it's running or not
if (EnableVirtualDevice.IsChecked.Value
&& NanoFrameworkPackage.VirtualDeviceService.VirtualDeviceIsRunning)
{
StartStopDevice.Content = _stopVirtualDeviceLabel;
}
if (!string.IsNullOrEmpty(VirtualDeviceSerialPort.Text))
{
// if there is a COM port set, enable the text box only if it's not running
VirtualDeviceSerialPort.IsEnabled = !NanoFrameworkPackage.VirtualDeviceService.VirtualDeviceIsRunning;
}
// OK to add event handlers to controls now
StoreCacheToUserPath.Checked += StoreCacheLocationChanged_Checked;
StoreCacheToUserPath.Unchecked += StoreCacheLocationChanged_Checked;
VirtualDeviceSerialPort.LostFocus += VirtualDeviceSerialPort_LostFocus;
// set focus on close button
CloseButton.Focus();
}
private void UpdateStartStopAvailability(string installCompleted)
{
StartStopDevice.IsEnabled = !bool.Parse(installCompleted);
}
private void CloseButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
Close();
@ -83,7 +112,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
private void StoreCacheLocationChanged_Checked(object sender, System.Windows.RoutedEventArgs e)
{
if(StoreCacheToProjectOutputPath.IsChecked.GetValueOrDefault())
if (StoreCacheToProjectOutputPath.IsChecked.GetValueOrDefault())
{
// cache location is project output
// save setting by clearing the path
@ -162,5 +191,55 @@ namespace nanoFramework.Tools.VisualStudio.Extension
// save new state
NanoFrameworkPackage.SettingIncludePrereleaseUpdates = (sender as ToggleButton).IsChecked ?? false;
}
private void EnableVirtualSerialDevice_Checked(object sender, System.Windows.RoutedEventArgs e)
{
// save new state
NanoFrameworkPackage.SettingVirtualDeviceEnable = (sender as ToggleButton).IsChecked ?? false;
// install/update nanoclr tool
if (NanoFrameworkPackage.SettingVirtualDeviceEnable && !NanoFrameworkPackage.VirtualDeviceService.NanoClrInstalled)
{
NanoFrameworkPackage.VirtualDeviceService.InstallNanoClrTool();
}
}
private void VirtualDeviceSerialPort_LostFocus(object sender, System.Windows.RoutedEventArgs e)
{
// store updated setting
NanoFrameworkPackage.SettingVirtualDevicePort = VirtualDeviceSerialPort.Text;
}
private async void StartStopDevice_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (NanoFrameworkPackage.VirtualDeviceService.VirtualDeviceIsRunning)
{
NanoFrameworkPackage.VirtualDeviceService.StopVirtualDevice();
StartStopDevice.Content = _startVirtualDeviceLabel;
VirtualDeviceSerialPort.IsEnabled = true;
}
else
{
if (await NanoFrameworkPackage.VirtualDeviceService.StartVirtualDeviceAsync(true))
{
StartStopDevice.Content = _stopVirtualDeviceLabel;
VirtualDeviceSerialPort.IsEnabled = false;
// if this is the 1st run, update serial port name, if not already there
if (string.IsNullOrEmpty(VirtualDeviceSerialPort.Text))
{
VirtualDeviceSerialPort.Text = NanoFrameworkPackage.SettingVirtualDevicePort;
}
}
}
}
private void AutoUpdateNanoClrImage_Checked(object sender, System.Windows.RoutedEventArgs e)
{
// save new state
NanoFrameworkPackage.SettingVirtualDeviceAutoUpdateNanoClrImage = (sender as ToggleButton).IsChecked ?? false;
}
}
}

Просмотреть файл

@ -492,6 +492,9 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<PackageReference Include="CliWrap">
<Version>3.5.0</Version>
</PackageReference>
<PackageReference Include="EnvDTE80">
<Version>17.3.32804.24</Version>
</PackageReference>
@ -651,4 +654,4 @@
<Target Name="BeforeBuild">
</Target>
-->
</Project>
</Project>

Просмотреть файл

@ -2,6 +2,20 @@
"version": 1,
"dependencies": {
".NETFramework,Version=v4.7.2": {
"CliWrap": {
"type": "Direct",
"requested": "[3.5.0, )",
"resolved": "3.5.0",
"contentHash": "JhC8xnY2uVPD8/o/wj8o+5uYQ8jiWJ9rrgTI6i5QqZco++nelZ8RgBjcLmPMJMQMvAXu39obUA/aeEEaYdQUhw==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "6.0.0",
"System.Buffers": "4.5.1",
"System.Memory": "4.5.5",
"System.Runtime.InteropServices.RuntimeInformation": "4.3.0",
"System.Threading.Tasks.Extensions": "4.5.4",
"System.ValueTuple": "4.5.0"
}
},
"envdte80": {
"type": "Direct",
"requested": "[17.3.32804.24, )",
@ -304,7 +318,7 @@
"type": "Direct",
"requested": "[1.12.0, )",
"resolved": "1.12.0",
"contentHash": "ls2oi2tgc511yCRrbBOD3KjS9AL4mIWwEs6/g3DuLhGpALhla/g1Dr9qry69M3NwEWEY3rSolxIiwueeqepckQ=="
"contentHash": "qQrFNXmJiStMC4VXk5cVMOJp23/qlT9FW5i9i+igwQVwraQTtvpkam8yK1hj992jqrbjoCIFZP4Hw9E8H0pB7w=="
},
"nanoFramework.TestFramework": {
"type": "Direct",
@ -1830,8 +1844,8 @@
},
"System.Memory": {
"type": "Transitive",
"resolved": "4.5.4",
"contentHash": "1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==",
"resolved": "4.5.5",
"contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==",
"dependencies": {
"System.Buffers": "4.5.1",
"System.Numerics.Vectors": "4.5.0",

Просмотреть файл

@ -1,6 +1,6 @@
{
"$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
"version": "2022.2.0",
"version": "2022.3.0",
"release": {
"branchName" : "release-v{version}",
"versionIncrement" : "minor",

Просмотреть файл

@ -6,6 +6,7 @@
using Microsoft;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using nanoFramework.Tools.Debugger;
@ -20,11 +21,13 @@ namespace nanoFramework.Tools.VisualStudio.Extension
protected static readonly Guid s_InternalErrorsPaneGuid = Guid.NewGuid();
protected static readonly Guid s_DeploymentMessagesPaneGuid = Guid.NewGuid();
protected static readonly Guid s_FirmwareUpdatManagerPane = Guid.NewGuid();
protected static readonly Guid s_VirtualDevicePane = Guid.NewGuid();
private static IVsOutputWindow _outputWindow;
private static IVsOutputWindowPane _debugPane;
private static IVsOutputWindowPane _nanoFrameworkMessagesPane;
private static IVsOutputWindowPane _firmwareUpdatManager;
private static IVsOutputWindowPane _virtualDevice;
private static IVsStatusbar _statusBar;
private static string _paneName;
private static uint progressCookie;
@ -59,6 +62,11 @@ namespace nanoFramework.Tools.VisualStudio.Extension
tempId = s_FirmwareUpdatManagerPane;
_outputWindow.CreatePane(ref tempId, ".NET nanoFramework Firmware Update Manager", 1, 0);
_outputWindow.GetPane(ref tempId, out _firmwareUpdatManager);
// create virtual device manager pane
tempId = s_VirtualDevicePane;
_outputWindow.CreatePane(ref tempId, ".NET nanoFramework Virtual Device", 1, 0);
_outputWindow.GetPane(ref tempId, out _virtualDevice);
});
}
@ -187,6 +195,20 @@ namespace nanoFramework.Tools.VisualStudio.Extension
false);
}
/// <summary>
/// Write a message to the Virtual Device output pane.
/// </summary>
/// <param name="message">Message to be output.</param>
public static void OutputVirtualDeviceMessage(string message)
{
message += Environment.NewLine;
Message(
_virtualDevice,
message,
false);
}
public static void ErrorMessageHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
DebugMessage(outLine.Data);
@ -222,7 +244,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
// stock general animation icon
object icon = (short)Constants.SBAI_General;
object icon = (short)Microsoft.VisualStudio.Shell.Interop.Constants.SBAI_General;
// Make sure the status bar is not frozen
@ -274,7 +296,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
// stock general animation icon
object icon = (short)Constants.SBAI_General;
object icon = (short)Microsoft.VisualStudio.Shell.Interop.Constants.SBAI_General;
// Make sure the status bar is not frozen
_statusBar.IsFrozen(out int frozen);

Просмотреть файл

@ -50,10 +50,10 @@ namespace nanoFramework.Tools.VisualStudio.Extension
PortBase networkDebug = PortBase.CreateInstanceForNetwork(false);
// create composite client with all ports
// start device watcher (or not) according to current user option
// DO NOT start device watcher as this will happen after the virtual device is created (if required)
_debugClient = PortBase.CreateInstanceForComposite(
new[] { serialDebug, networkDebug },
!NanoFrameworkPackage.OptionDisableDeviceWatchers);
false);
}
return _debugClient;

Просмотреть файл

@ -376,6 +376,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension.ToolWindow.ViewModel
public static readonly string ForceSelectionOfNanoDevice = new Guid("{8F012794-BC66-429D-9F9D-A9B0F546D6B5}").ToString();
public static readonly string LaunchFirmwareUpdateForNanoDevice = new Guid("{93822E8C-4A94-4573-AC4F-DEB7FA703933}").ToString();
public static readonly string NanoDeviceHasDeparted = new Guid("{38429FA1-3C16-44C2-937E-227C20AC0342}").ToString();
public static readonly string VirtualDeviceOperationExecuting = new Guid("{B1B40C6E-5EE7-4A69-BB70-9A8663C928C1}").ToString();
}
#endregion

Просмотреть файл

@ -0,0 +1,30 @@
////
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
////
using System.Threading.Tasks;
namespace nanoFramework.Tools.VisualStudio.Extension
{
internal interface IVirtualDeviceService
{
bool NanoClrInstalled { get; }
bool VirtualDeviceIsRunning { get; }
Task InitVirtualDeviceAsync();
void InstallNanoClrTool();
void UpdateNanoClr();
string ListVirtualSerialPorts();
bool CreateVirtualSerialPort(string portName, out string executionLog);
void StopVirtualDevice();
Task<bool> StartVirtualDeviceAsync(bool rescanDevices);
}
}

Просмотреть файл

@ -0,0 +1,418 @@
////
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
////
using CliWrap;
using CliWrap.Buffered;
using GalaSoft.MvvmLight.Messaging;
using Humanizer;
using Microsoft;
using Microsoft.VisualStudio.RpcContracts.Commands;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Threading;
using Mono.Cecil.Cil;
using nanoFramework.Tools.VisualStudio.Extension.ToolWindow.ViewModel;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Packaging;
using System.Management.Instrumentation;
using System.Security.Policy;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
namespace nanoFramework.Tools.VisualStudio.Extension
{
internal class VirtualDeviceService : IVirtualDeviceService
{
private readonly Microsoft.VisualStudio.Shell.IAsyncServiceProvider _serviceProvider;
private Process _nanoClrProcess = null;
private INanoDeviceCommService _nanoDeviceCommService;
public bool NanoClrInstalled { get; private set; }
public bool VirtualDeviceIsRunning => _nanoClrProcess != null && !_nanoClrProcess.HasExited;
public VirtualDeviceService(IAsyncServiceProvider provider)
{
_serviceProvider = provider;
}
public async System.Threading.Tasks.Task InitVirtualDeviceAsync()
{
_nanoDeviceCommService = await _serviceProvider.GetServiceAsync(typeof(NanoDeviceCommService)) as INanoDeviceCommService;
Assumes.Present(_nanoDeviceCommService);
if (NanoFrameworkPackage.SettingVirtualDeviceEnable)
{
// take care of installing/updating nanoclr tool
InstallNanoClrTool();
if (NanoFrameworkPackage.SettingVirtualDeviceAutoUpdateNanoClrImage)
{
// update nanoCLR image
UpdateNanoClr();
}
// start virtual device
await StartVirtualDeviceAsync(false);
}
if (!NanoFrameworkPackage.OptionDisableDeviceWatchers)
{
_nanoDeviceCommService.DebugClient.StartDeviceWatchers();
}
}
public void InstallNanoClrTool()
{
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Install/upate nanoclr tool");
var cmd = Cli.Wrap("dotnet")
.WithArguments("tool update -g nanoclr")
.WithValidation(CommandResultValidation.None);
// signal install/update ongoing
Messenger.Default.Send(new NotificationMessage(true.ToString()), DeviceExplorerViewModel.MessagingTokens.VirtualDeviceOperationExecuting);
// setup cancellation token with a timeout of 1 minute
using (var cts = new CancellationTokenSource())
{
cts.CancelAfter(TimeSpan.FromMinutes(1));
ThreadHelper.JoinableTaskFactory.Run(async delegate
{
var cliResult = await cmd.ExecuteBufferedAsync(cts.Token);
if (cliResult.ExitCode == 0)
{
var regexResult = Regex.Match(cliResult.StandardOutput, @"((?>\(version ')(?'version'\d+\.\d+\.\d+)(?>'\)))");
if (regexResult.Success)
{
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Install/update successful v{regexResult.Groups["version"].Value}");
MessageCentre.OutputVirtualDeviceMessage($"Running nanoclr v{regexResult.Groups["version"].Value}");
}
NanoClrInstalled = true;
}
else
{
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Failed to install/update nanoclr. Exit code {cliResult.ExitCode}");
MessageCentre.InternalErrorWriteLine($"VirtualDevice: {cliResult.StandardError}");
MessageCentre.OutputVirtualDeviceMessage($"ERROR: failed to install/update nanoclr. Exit code {cliResult.ExitCode}");
MessageCentre.OutputVirtualDeviceMessage(cliResult.StandardError);
NanoClrInstalled = false;
}
});
// signal install/update completed
Messenger.Default.Send(new NotificationMessage(false.ToString()), DeviceExplorerViewModel.MessagingTokens.VirtualDeviceOperationExecuting);
}
}
public void UpdateNanoClr()
{
var cmd = Cli.Wrap("nanoclr")
.WithArguments("instance --update")
.WithValidation(CommandResultValidation.None);
// setup cancellation token with a timeout of 1 minute
using (var cts = new CancellationTokenSource())
{
cts.CancelAfter(TimeSpan.FromSeconds(20));
ThreadHelper.JoinableTaskFactory.Run(async delegate
{
var cliResult = await cmd.ExecuteBufferedAsync(cts.Token);
if (cliResult.ExitCode == 0)
{
var regexResult = Regex.Match(cliResult.StandardOutput, @"((?>Updated to v)(?'version'\d+\.\d+\.\d+.\d?))");
if (regexResult.Success)
{
MessageCentre.InternalErrorWriteLine($"VirtualDevice: updated nanoCLR image to v{regexResult.Groups["version"].Value}");
MessageCentre.OutputVirtualDeviceMessage($"Updated nanoCLR image to v{regexResult.Groups["version"].Value}");
}
}
else
{
MessageCentre.InternalErrorWriteLine($"VirtualDevice: failed to update the nanoCLR image");
MessageCentre.OutputVirtualDeviceMessage("ERROR: failed to update the nanoCLR image");
}
});
}
}
public string ListVirtualSerialPorts()
{
var cmd = Cli.Wrap("nanoclr")
.WithArguments("virtualserial --list -v q")
.WithValidation(CommandResultValidation.None);
// setup cancellation token with a timeout of 1 minute
using (var cts = new CancellationTokenSource())
{
cts.CancelAfter(TimeSpan.FromSeconds(20));
return ThreadHelper.JoinableTaskFactory.Run(async delegate
{
var cliResult = await cmd.ExecuteBufferedAsync(cts.Token);
if (cliResult.ExitCode == 0)
{
return cliResult.StandardOutput;
}
else
{
return "";
}
});
}
}
public bool CreateVirtualSerialPort(string portName, out string executionLog)
{
var cmd = Cli.Wrap("nanoclr")
.WithArguments($"virtualserial --create {portName} -v q")
.WithValidation(CommandResultValidation.None);
// setup cancellation token with a timeout of 1 minute
using (var cts = new CancellationTokenSource())
{
cts.CancelAfter(TimeSpan.FromSeconds(20));
var cliResult = ThreadHelper.JoinableTaskFactory.Run(async delegate
{
return await cmd.ExecuteBufferedAsync(cts.Token);
});
executionLog = cliResult.StandardOutput;
return (cliResult.ExitCode == 0);
}
}
public void StopVirtualDevice()
{
if (_nanoClrProcess != null)
{
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Attempting to stop virtual device");
try
{
_nanoClrProcess.Exited -= VirtualDeviceProcess_Exited;
// kill process
_nanoClrProcess.Kill();
// output message to pane
MessageCentre.OutputVirtualDeviceMessage("");
MessageCentre.OutputVirtualDeviceMessage("");
MessageCentre.OutputVirtualDeviceMessage("**********************************");
MessageCentre.OutputVirtualDeviceMessage("*** Virtual nanoDevice stopped ***");
MessageCentre.OutputVirtualDeviceMessage("**********************************");
MessageCentre.OutputVirtualDeviceMessage("");
MessageCentre.OutputVirtualDeviceMessage("");
// rescan devices
_nanoDeviceCommService.DebugClient.ReScanDevices();
}
catch
{
// catch all, don't bother
}
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Virtual device stopped");
_nanoClrProcess = null;
}
else
{
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Attempting to stop virtual device without it being started");
}
}
public async System.Threading.Tasks.Task<bool> StartVirtualDeviceAsync(bool rescanDevices)
{
bool tryAgain = true;
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancellationToken.None);
// signal start operation
Messenger.Default.Send(new NotificationMessage(true.ToString()), DeviceExplorerViewModel.MessagingTokens.VirtualDeviceOperationExecuting);
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Attempting to start virtual device");
if (_nanoClrProcess != null)
{
// this shouldn't happen, still...
_nanoClrProcess.Exited -= VirtualDeviceProcess_Exited;
_nanoClrProcess.Kill();
_nanoClrProcess = null;
}
try
{
// check virtual serial ports
var listOfVirtualSerialPorts = ListVirtualSerialPorts();
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Virtual Serial Ports listed");
if (listOfVirtualSerialPorts.Contains("No virtual serial port pairs found.")
|| !listOfVirtualSerialPorts.Contains(NanoFrameworkPackage.SettingVirtualDevicePort))
{
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Creating Virtual Serial Port");
// no virtual ports installed or the specified COM port is not there
var executionResult = CreateVirtualSerialPort(NanoFrameworkPackage.SettingVirtualDevicePort, out string executionLog);
var regexResult = Regex.Match(executionLog, "(?>Creating a new Virtual Bridge )(?'comport'COM\\d{1,3})(?>:COM\\d{1,3})");
if (!executionResult || !regexResult.Success)
{
// failed to create virtual device
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Failed to create Virtual Serial Port");
// report this and suggest an alternative
MessageCentre.OutputVirtualDeviceMessage("**********************************************");
MessageCentre.OutputVirtualDeviceMessage("*** Failed to create Virtual Serial Device ***");
MessageCentre.OutputVirtualDeviceMessage("**********************************************");
MessageCentre.OutputVirtualDeviceMessage("");
MessageCentre.OutputVirtualDeviceMessage($"Please run this at a command prompt: 'nanoclr --virtualserial --create {regexResult.Groups["comport"].Value}'");
MessageCentre.OutputVirtualDeviceMessage($"Then update the Serial Port input in the Virtual Device tab in the Settings dialog with {regexResult.Groups["comport"].Value}");
MessageCentre.OutputVirtualDeviceMessage("");
// done here
return false;
}
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Virtual Serial Port created successfully");
// store serial port name
NanoFrameworkPackage.SettingVirtualDevicePort = regexResult.Groups["comport"].Value;
}
// sanity check for empty port name
if (string.IsNullOrEmpty(NanoFrameworkPackage.SettingVirtualDevicePort))
{
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Storing Virtual Serial Port information in settings");
var regexResult = Regex.Match(listOfVirtualSerialPorts, @"(?'comport'COM\d{1,3})(?><->COM\d{1,3})");
NanoFrameworkPackage.SettingVirtualDevicePort = regexResult.Groups["comport"].Value;
}
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Setting up process to run virtual device");
// OK to launch process with nanoclr
_nanoClrProcess = new Process();
_nanoClrProcess.StartInfo.FileName = "nanoclr";
_nanoClrProcess.StartInfo.Arguments = $"run --serialport {NanoFrameworkPackage.SettingVirtualDevicePort} --monitorparentpid {Process.GetCurrentProcess().Id}";
_nanoClrProcess.StartInfo.UseShellExecute = false;
_nanoClrProcess.StartInfo.CreateNoWindow = true;
_nanoClrProcess.StartInfo.RedirectStandardOutput = true;
_nanoClrProcess.StartInfo.RedirectStandardError = true;
_nanoClrProcess.OutputDataReceived += nanoClrProcess_OutputDataReceived;
_nanoClrProcess.EnableRaisingEvents = true;
// enumeration is completed, OK to start virtual device
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Starting process for virtual device");
startProces:
if (_nanoClrProcess.Start())
{
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Process started");
_nanoClrProcess.BeginOutputReadLine();
if (_nanoClrProcess.WaitForExit(1_000))
{
// something went wrong starting the process
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Process exited prematurely");
if (tryAgain)
{
// lower flag
tryAgain = false;
Thread.Sleep(5_000);
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Retrying to start process");
goto startProces;
}
}
else
{
// all good!
// set handler for process exited
_nanoClrProcess.Exited += VirtualDeviceProcess_Exited;
// done here
return true;
}
}
else
{
// hasn't started
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Failed to start. Exit code was: {_nanoClrProcess.ExitCode}");
MessageCentre.OutputVirtualDeviceMessage("");
MessageCentre.OutputVirtualDeviceMessage("**************************************************");
MessageCentre.OutputVirtualDeviceMessage($"Failed to start virtual device. Exit code was: {_nanoClrProcess.ExitCode}");
MessageCentre.OutputVirtualDeviceMessage("**************************************************");
MessageCentre.OutputVirtualDeviceMessage("");
}
}
catch (Exception ex)
{
MessageCentre.InternalErrorWriteLine($"VirtualDevice: Failed to start. Exception was: {ex.Message}");
MessageCentre.OutputVirtualDeviceMessage("");
MessageCentre.OutputVirtualDeviceMessage("**************************************************");
MessageCentre.OutputVirtualDeviceMessage($"Failed to start virtual device. Exception was: {ex.Message}");
MessageCentre.OutputVirtualDeviceMessage("**************************************************");
MessageCentre.OutputVirtualDeviceMessage("");
}
finally
{
// signal start operation completed
Messenger.Default.Send(new NotificationMessage(false.ToString()), DeviceExplorerViewModel.MessagingTokens.VirtualDeviceOperationExecuting);
// rescan devices, if start was successful and this wasn't requested to skip
if (_nanoClrProcess != null
&& !_nanoClrProcess.HasExited
&& rescanDevices)
{
_nanoDeviceCommService.DebugClient.ReScanDevices();
}
}
// null process
_nanoClrProcess = null;
// done here
return false;
}
private void VirtualDeviceProcess_Exited(object sender, EventArgs e)
{
_nanoClrProcess = null;
}
private void nanoClrProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
{
MessageCentre.OutputVirtualDeviceMessage(e.Data);
}
}
}
}

Просмотреть файл

@ -89,5 +89,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Utilities\DeploymentImageGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\EnumToItemsSource.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\ReferenceCrawler.cs" />
<Compile Include="$(MSBuildThisFileDirectory)VirtualDeviceService\IVirtualDeviceService.cs" />
<Compile Include="$(MSBuildThisFileDirectory)VirtualDeviceService\VirtualDeviceService.cs" />
</ItemGroup>
</Project>