Add support for Virtual nanoDevice (#756)
This commit is contained in:
Родитель
e65dc3ad95
Коммит
bc304f0a95
|
@ -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>
|
Загрузка…
Ссылка в новой задаче