`GlobalExclusiveDeviceAccess` added to Visual Studio extension (#834)
This commit is contained in:
Родитель
f434dac04d
Коммит
639d6d86b9
|
@ -0,0 +1,213 @@
|
|||
# EditorConfig for Visual Studio 2022: https://learn.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options?view=vs-2022
|
||||
|
||||
# This is a top-most .editorconfig file
|
||||
root = true
|
||||
|
||||
#=====================================================
|
||||
#
|
||||
# nanoFramework specific settings
|
||||
#
|
||||
#
|
||||
#=====================================================
|
||||
[*]
|
||||
# Generic EditorConfig settings
|
||||
end_of_line = crlf
|
||||
charset = utf-8-bom
|
||||
|
||||
# Visual Studio spell checker
|
||||
spelling_languages = en-us
|
||||
spelling_checkable_types = strings,identifiers,comments
|
||||
spelling_error_severity = information
|
||||
spelling_exclusion_path = spelling_exclusion.dic
|
||||
|
||||
#=====================================================
|
||||
#
|
||||
# Settings copied from the .NET runtime
|
||||
#
|
||||
# https://github.com/dotnet/runtime
|
||||
#
|
||||
#=====================================================
|
||||
# Default settings:
|
||||
# A newline ending every file
|
||||
# Use 4 spaces as indentation
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Generated code
|
||||
[*{_AssemblyInfo.cs,.notsupported.cs,AsmOffsets.cs}]
|
||||
generated_code = true
|
||||
|
||||
# C# files
|
||||
[*.cs]
|
||||
# New line preferences
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
csharp_new_line_between_query_expression_clauses = true
|
||||
|
||||
# Indentation preferences
|
||||
csharp_indent_block_contents = true
|
||||
csharp_indent_braces = false
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_case_contents_when_block = false
|
||||
csharp_indent_switch_labels = true
|
||||
csharp_indent_labels = one_less_than_current
|
||||
|
||||
# Modifier preferences
|
||||
csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async:suggestion
|
||||
|
||||
# avoid this. unless absolutely necessary
|
||||
dotnet_style_qualification_for_field = false:suggestion
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
dotnet_style_qualification_for_event = false:suggestion
|
||||
|
||||
# Types: use keywords instead of BCL types, and permit var only when the type is clear
|
||||
csharp_style_var_for_built_in_types = false:suggestion
|
||||
csharp_style_var_when_type_is_apparent = false:none
|
||||
csharp_style_var_elsewhere = false:suggestion
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
|
||||
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||
|
||||
# name all constant fields using PascalCase
|
||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
|
||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
|
||||
dotnet_naming_symbols.constant_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.constant_fields.required_modifiers = const
|
||||
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
|
||||
|
||||
# static fields should have s_ prefix
|
||||
dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion
|
||||
dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields
|
||||
dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style
|
||||
dotnet_naming_symbols.static_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.static_fields.required_modifiers = static
|
||||
dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected
|
||||
dotnet_naming_style.static_prefix_style.required_prefix = s_
|
||||
dotnet_naming_style.static_prefix_style.capitalization = camel_case
|
||||
|
||||
# internal and private fields should be _camelCase
|
||||
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
|
||||
dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
|
||||
dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
|
||||
dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
|
||||
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
|
||||
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
|
||||
|
||||
# Code style defaults
|
||||
csharp_using_directive_placement = outside_namespace:suggestion
|
||||
dotnet_sort_system_directives_first = true
|
||||
csharp_prefer_braces = true:silent
|
||||
csharp_preserve_single_line_blocks = true:none
|
||||
csharp_preserve_single_line_statements = false:none
|
||||
csharp_prefer_static_local_function = true:suggestion
|
||||
csharp_prefer_simple_using_statement = false:none
|
||||
csharp_style_prefer_switch_expression = true:suggestion
|
||||
dotnet_style_readonly_field = true:suggestion
|
||||
|
||||
# Expression-level preferences
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_prefer_collection_expression = when_types_exactly_match
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_auto_properties = true:suggestion
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
csharp_prefer_simple_default_expression = true:suggestion
|
||||
|
||||
# Expression-bodied members
|
||||
csharp_style_expression_bodied_methods = true:silent
|
||||
csharp_style_expression_bodied_constructors = true:silent
|
||||
csharp_style_expression_bodied_operators = true:silent
|
||||
csharp_style_expression_bodied_properties = true:silent
|
||||
csharp_style_expression_bodied_indexers = true:silent
|
||||
csharp_style_expression_bodied_accessors = true:silent
|
||||
csharp_style_expression_bodied_lambdas = true:silent
|
||||
csharp_style_expression_bodied_local_functions = true:silent
|
||||
|
||||
# Pattern matching
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
|
||||
# Null checking preferences
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
|
||||
# Other features
|
||||
csharp_style_prefer_index_operator = false:none
|
||||
csharp_style_prefer_range_operator = false:none
|
||||
csharp_style_pattern_local_over_anonymous_function = false:none
|
||||
|
||||
# Space preferences
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_after_comma = true
|
||||
csharp_space_after_dot = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_after_semicolon_in_for_statement = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_around_declaration_statements = do_not_ignore
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_before_comma = false
|
||||
csharp_space_before_dot = false
|
||||
csharp_space_before_open_square_brackets = false
|
||||
csharp_space_before_semicolon_in_for_statement = false
|
||||
csharp_space_between_empty_square_brackets = false
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses = false
|
||||
csharp_space_between_square_brackets = false
|
||||
|
||||
# License header
|
||||
file_header_template = Licensed to the .NET Foundation under one or more agreements.\nThe .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
# C++ Files
|
||||
[*.{cpp,h,in}]
|
||||
curly_bracket_next_line = true
|
||||
indent_brace_style = Allman
|
||||
|
||||
# Xml project files
|
||||
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}]
|
||||
indent_size = 2
|
||||
|
||||
[*.{csproj,vbproj,proj,nativeproj,locproj}]
|
||||
charset = utf-8
|
||||
|
||||
# Xml build files
|
||||
[*.builds]
|
||||
indent_size = 2
|
||||
|
||||
# Xml files
|
||||
[*.{xml,stylecop,resx,ruleset}]
|
||||
indent_size = 2
|
||||
|
||||
# Xml config files
|
||||
[*.{props,targets,config,nuspec}]
|
||||
indent_size = 2
|
||||
|
||||
# YAML config files
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
|
||||
# Shell scripts
|
||||
[*.sh]
|
||||
end_of_line = lf
|
||||
[*.{cmd,bat}]
|
||||
end_of_line = crlf
|
|
@ -1,24 +1,23 @@
|
|||
//
|
||||
// Copyright (c) .NET Foundation and Contributors
|
||||
// See LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using GalaSoft.MvvmLight.Messaging;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
using nanoFramework.Tools.Debugger;
|
||||
using nanoFramework.Tools.VisualStudio.Extension.FirmwareUpdate;
|
||||
using nanoFramework.Tools.VisualStudio.Extension.ToolWindow.ViewModel;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GalaSoft.MvvmLight.Messaging;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
using nanoFramework.Tools.Debugger;
|
||||
using nanoFramework.Tools.Debugger.NFDevice;
|
||||
using nanoFramework.Tools.VisualStudio.Extension.FirmwareUpdate;
|
||||
using nanoFramework.Tools.VisualStudio.Extension.ToolWindow.ViewModel;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
|
||||
namespace nanoFramework.Tools.VisualStudio.Extension.AutomaticUpdates
|
||||
{
|
||||
public class UpdateManager
|
||||
{
|
||||
private const int ExclusiveAccessTimeout = 3000;
|
||||
private static UpdateManager s_instance;
|
||||
private ViewModelLocator ViewModelLocator;
|
||||
private readonly Package _package;
|
||||
|
@ -32,7 +31,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension.AutomaticUpdates
|
|||
}
|
||||
|
||||
public static void Initialize(
|
||||
AsyncPackage package,
|
||||
AsyncPackage package,
|
||||
ViewModelLocator vmLocator)
|
||||
{
|
||||
s_instance = new UpdateManager(package)
|
||||
|
@ -101,257 +100,279 @@ namespace nanoFramework.Tools.VisualStudio.Extension.AutomaticUpdates
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// check if DebugEngine is available
|
||||
if (nanoDevice.DebugEngine == null)
|
||||
{
|
||||
nanoDevice.CreateDebugEngine();
|
||||
}
|
||||
|
||||
if (nanoDevice.DebugEngine == null)
|
||||
{
|
||||
// can't create it, quit update now
|
||||
return;
|
||||
}
|
||||
|
||||
// add this device to the updatING list
|
||||
if (!devicesUpdatING.TryAdd(deviceId, new object()))
|
||||
{
|
||||
// fail to add device to list
|
||||
#if DEBUG
|
||||
Console.WriteLine($"[Automatic Updates] {nanoDevice.TargetName} update already in progress.");
|
||||
#endif
|
||||
|
||||
// quit, never mind, this is not critical whatsoever
|
||||
return;
|
||||
}
|
||||
|
||||
// better wrap this on a try-finally because a lot of things can go wrong in the process
|
||||
GlobalExclusiveDeviceAccess exclusiveAccess = null;
|
||||
try
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
var fwPackage = await GetFirmwarePackageAsync(
|
||||
nanoDevice.TargetName,
|
||||
nanoDevice.Platform);
|
||||
|
||||
await Task.Yield();
|
||||
|
||||
//////////////////////////////
|
||||
// STM32 targets
|
||||
if (fwPackage is Stm32Firmware)
|
||||
// Get exclusive access to the device, but don't wait forever
|
||||
exclusiveAccess = GlobalExclusiveDeviceAccess.TryGet(nanoDevice, ExclusiveAccessTimeout);
|
||||
if (exclusiveAccess is null)
|
||||
{
|
||||
// sanity check
|
||||
if (nanoDevice.DebugEngine == null)
|
||||
{
|
||||
// Can't get access, quit update for now
|
||||
#if DEBUG
|
||||
Console.WriteLine($"[Automatic Updates] {nanoDevice.TargetName} debug engine is not ready.");
|
||||
Console.WriteLine($"[Automatic Updates] Cannot access {nanoDevice.Description}, another application is using the device");
|
||||
#endif
|
||||
// quit
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (nanoDevice.DebugEngine.Connect(
|
||||
1000,
|
||||
true,
|
||||
true))
|
||||
|
||||
// check if DebugEngine is available
|
||||
if (nanoDevice.DebugEngine == null)
|
||||
{
|
||||
nanoDevice.CreateDebugEngine();
|
||||
}
|
||||
|
||||
if (nanoDevice.DebugEngine == null)
|
||||
{
|
||||
// can't create it, quit update now
|
||||
return;
|
||||
}
|
||||
|
||||
// add this device to the updatING list
|
||||
if (!devicesUpdatING.TryAdd(deviceId, new object()))
|
||||
{
|
||||
// fail to add device to list
|
||||
#if DEBUG
|
||||
Console.WriteLine($"[Automatic Updates] {nanoDevice.TargetName} update already in progress.");
|
||||
#endif
|
||||
|
||||
// quit, never mind, this is not critical whatsoever
|
||||
return;
|
||||
}
|
||||
|
||||
// better wrap this on a try-finally because a lot of things can go wrong in the process
|
||||
try
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
var fwPackage = await GetFirmwarePackageAsync(
|
||||
nanoDevice.TargetName,
|
||||
nanoDevice.Platform);
|
||||
|
||||
await Task.Yield();
|
||||
|
||||
//////////////////////////////
|
||||
// STM32 targets
|
||||
if (fwPackage is Stm32Firmware)
|
||||
{
|
||||
Version currentClrVersion = null;
|
||||
|
||||
// try to store CLR version
|
||||
if(nanoDevice.DebugEngine.IsConnectedTonanoCLR)
|
||||
// sanity check
|
||||
if (nanoDevice.DebugEngine == null)
|
||||
{
|
||||
if (nanoDevice.DeviceInfo.Valid)
|
||||
{
|
||||
currentClrVersion = nanoDevice.DeviceInfo.SolutionBuildVersion;
|
||||
}
|
||||
#if DEBUG
|
||||
Console.WriteLine($"[Automatic Updates] {nanoDevice.TargetName} debug engine is not ready.");
|
||||
#endif
|
||||
// quit
|
||||
return;
|
||||
}
|
||||
|
||||
// update conditions:
|
||||
// 1. Running CLR _and_ the new version is higher
|
||||
// 2. Running nanoBooter and there is no version information on the CLR (presumably because there is no CLR installed)
|
||||
if (fwPackage.Version > nanoDevice.CLRVersion)
|
||||
if (nanoDevice.DebugEngine.Connect(
|
||||
1000,
|
||||
true,
|
||||
true))
|
||||
{
|
||||
bool attemptToLaunchBooter = false;
|
||||
Version currentClrVersion = null;
|
||||
|
||||
// try to store CLR version
|
||||
if (nanoDevice.DebugEngine.IsConnectedTonanoCLR)
|
||||
{
|
||||
// any update has to be handled by nanoBooter, so let's have it running
|
||||
try
|
||||
if (nanoDevice.DeviceInfo.Valid)
|
||||
{
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] Launching nanoBooter...");
|
||||
currentClrVersion = nanoDevice.DeviceInfo.SolutionBuildVersion;
|
||||
}
|
||||
}
|
||||
|
||||
attemptToLaunchBooter = nanoDevice.ConnectToNanoBooter();
|
||||
// update conditions:
|
||||
// 1. Running CLR _and_ the new version is higher
|
||||
// 2. Running nanoBooter and there is no version information on the CLR (presumably because there is no CLR installed)
|
||||
if (fwPackage.Version > nanoDevice.CLRVersion)
|
||||
{
|
||||
bool attemptToLaunchBooter = false;
|
||||
|
||||
if (!attemptToLaunchBooter)
|
||||
if (nanoDevice.DebugEngine.IsConnectedTonanoCLR)
|
||||
{
|
||||
// any update has to be handled by nanoBooter, so let's have it running
|
||||
try
|
||||
{
|
||||
// check for version where the software reboot to nanoBooter was made available
|
||||
if (currentClrVersion != null &&
|
||||
nanoDevice.DeviceInfo.SolutionBuildVersion < new Version("1.6.0.54"))
|
||||
{
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] The device is running a version that doesn't support rebooting by software. Please update your device using 'nanoff' tool.");
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] Launching nanoBooter...");
|
||||
|
||||
await Task.Yield();
|
||||
attemptToLaunchBooter = nanoDevice.ConnectToNanoBooter();
|
||||
|
||||
if (!attemptToLaunchBooter)
|
||||
{
|
||||
// check for version where the software reboot to nanoBooter was made available
|
||||
if (currentClrVersion != null &&
|
||||
nanoDevice.DeviceInfo.SolutionBuildVersion < new Version("1.6.0.54"))
|
||||
{
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] The device is running a version that doesn't support rebooting by software. Please update your device using 'nanoff' tool.");
|
||||
|
||||
await Task.Yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// this reboot step can go wrong and there's no big deal with that
|
||||
}
|
||||
}
|
||||
catch
|
||||
else
|
||||
{
|
||||
// this reboot step can go wrong and there's no big deal with that
|
||||
attemptToLaunchBooter = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
attemptToLaunchBooter = true;
|
||||
}
|
||||
|
||||
// check if the device is still there
|
||||
if(ViewModelLocator.DeviceExplorer.AvailableDevices.FirstOrDefault(d => d.DeviceUniqueId == deviceUniqueId) == null)
|
||||
{
|
||||
// check if the device is still there
|
||||
if (ViewModelLocator.DeviceExplorer.AvailableDevices.FirstOrDefault(d => d.DeviceUniqueId == deviceUniqueId) == null)
|
||||
{
|
||||
#if DEBUG
|
||||
Console.WriteLine($"[Automatic Updates] {nanoDevice.TargetName} is not available anymore.");
|
||||
Console.WriteLine($"[Automatic Updates] {nanoDevice.TargetName} is not available anymore.");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (attemptToLaunchBooter &&
|
||||
nanoDevice.Ping() == Debugger.WireProtocol.ConnectionSource.nanoBooter)
|
||||
{
|
||||
// get address for CLR block expected by device
|
||||
var clrAddress = nanoDevice.GetCLRStartAddress();
|
||||
|
||||
// compare with address on the fw packages
|
||||
if (clrAddress !=
|
||||
(fwPackage as Stm32Firmware).ClrStartAddress)
|
||||
{
|
||||
// CLR addresses don't match, can't proceed with update
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Can't update device. CLR addresses are different. Please update nanoBooter manually.");
|
||||
return;
|
||||
}
|
||||
|
||||
await Task.Yield();
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] Starting update to CLR v{fwPackage.Version}.");
|
||||
|
||||
try
|
||||
if (attemptToLaunchBooter &&
|
||||
nanoDevice.Ping() == Debugger.WireProtocol.ConnectionSource.nanoBooter)
|
||||
{
|
||||
// get address for CLR block expected by device
|
||||
var clrAddress = nanoDevice.GetCLRStartAddress();
|
||||
|
||||
// compare with address on the fw packages
|
||||
if (clrAddress !=
|
||||
(fwPackage as Stm32Firmware).ClrStartAddress)
|
||||
{
|
||||
// CLR addresses don't match, can't proceed with update
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Can't update device. CLR addresses are different. Please update nanoBooter manually.");
|
||||
return;
|
||||
}
|
||||
|
||||
await Task.Yield();
|
||||
|
||||
// create a progress indicator to be used by deployment operation to post debug messages
|
||||
var progressIndicator = new Progress<string>(m => MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] {m}"));
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] Starting update to CLR v{fwPackage.Version}.");
|
||||
|
||||
if (nanoDevice.DeployBinaryFile(
|
||||
(fwPackage as Stm32Firmware).nanoClrFileBin,
|
||||
(fwPackage as Stm32Firmware).ClrStartAddress,
|
||||
progressIndicator))
|
||||
try
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] Update successful.");
|
||||
// create a progress indicator to be used by deployment operation to post debug messages
|
||||
var progressIndicator = new Progress<string>(m => MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] {m}"));
|
||||
|
||||
// add it to the list of devices updatED with the update time stamp
|
||||
devicesUpdatED.TryAdd(deviceDescription, DateTime.UtcNow);
|
||||
}
|
||||
|
||||
// if this is the selected device...
|
||||
if (ViewModelLocator.DeviceExplorer.SelectedDevice?.DeviceUniqueId == deviceUniqueId)
|
||||
{
|
||||
// ...reset property to force that device capabilities to be retrieved on next connection
|
||||
ViewModelLocator.DeviceExplorer.LastDeviceConnectedHash = 0;
|
||||
}
|
||||
|
||||
if (attemptToLaunchBooter)
|
||||
{
|
||||
// try to reboot target
|
||||
|
||||
// remove it from updatING list
|
||||
devicesUpdatING.TryRemove(deviceId, out var dummy);
|
||||
|
||||
// check if the device is still there
|
||||
if (ViewModelLocator.DeviceExplorer.AvailableDevices.FirstOrDefault(d => d.DeviceUniqueId == Guid.Parse(deviceId)) == null)
|
||||
if (nanoDevice.DeployBinaryFile(
|
||||
(fwPackage as Stm32Firmware).nanoClrFileBin,
|
||||
(fwPackage as Stm32Firmware).ClrStartAddress,
|
||||
progressIndicator))
|
||||
{
|
||||
return;
|
||||
await Task.Yield();
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] Update successful.");
|
||||
|
||||
// add it to the list of devices updatED with the update time stamp
|
||||
devicesUpdatED.TryAdd(deviceDescription, DateTime.UtcNow);
|
||||
}
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] Rebooting...");
|
||||
// if this is the selected device...
|
||||
if (ViewModelLocator.DeviceExplorer.SelectedDevice?.DeviceUniqueId == deviceUniqueId)
|
||||
{
|
||||
// ...reset property to force that device capabilities to be retrieved on next connection
|
||||
ViewModelLocator.DeviceExplorer.LastDeviceConnectedHash = 0;
|
||||
}
|
||||
|
||||
nanoDevice.DebugEngine.RebootDevice(RebootOptions.NormalReboot);
|
||||
if (attemptToLaunchBooter)
|
||||
{
|
||||
// try to reboot target
|
||||
|
||||
// remove it from updatING list
|
||||
devicesUpdatING.TryRemove(deviceId, out var dummy);
|
||||
|
||||
// check if the device is still there
|
||||
if (ViewModelLocator.DeviceExplorer.AvailableDevices.FirstOrDefault(d => d.DeviceUniqueId == Guid.Parse(deviceId)) == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] Rebooting...");
|
||||
|
||||
nanoDevice.DebugEngine.RebootDevice(RebootOptions.NormalReboot);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Exception occurred when performing update ({ex.Message}).");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
else
|
||||
{
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Exception occurred when performing update ({ex.Message}).");
|
||||
if (attemptToLaunchBooter)
|
||||
{
|
||||
// only report this as an error if the launch was successful
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Failed to launch nanoBooter. Quitting update.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (attemptToLaunchBooter)
|
||||
// just to make sure that the CLR version is the latest, so we don't check it over and over
|
||||
if (nanoDevice.DebugEngine.IsConnectedTonanoCLR &&
|
||||
(fwPackage.Version == nanoDevice.DeviceInfo.ClrBuildVersion))
|
||||
{
|
||||
// only report this as an error if the launch was successful
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Failed to launch nanoBooter. Quitting update.");
|
||||
// add it to the list of devices updatED with the update time stamp
|
||||
devicesUpdatED.TryAdd(deviceDescription, DateTime.UtcNow);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// just to make sure that the CLR version is the latest, so we don't check it over and over
|
||||
if (nanoDevice.DebugEngine.IsConnectedTonanoCLR &&
|
||||
(fwPackage.Version == nanoDevice.DeviceInfo.ClrBuildVersion))
|
||||
{
|
||||
// add it to the list of devices updatED with the update time stamp
|
||||
devicesUpdatED.TryAdd(deviceDescription, DateTime.UtcNow);
|
||||
}
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Can't connect to device. Quitting update.");
|
||||
}
|
||||
}
|
||||
///////////////////////////////////
|
||||
// ESP32 targets
|
||||
else if (fwPackage is Esp32Firmware)
|
||||
{
|
||||
// TODO
|
||||
// not supported yet
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage("The ability to update ESP32 targets is not currently available. Yet...");
|
||||
|
||||
// add it to the list of devices updatED with the update time stamp
|
||||
devicesUpdatED.TryAdd(deviceDescription, DateTime.UtcNow);
|
||||
}
|
||||
///////////////////////////////////////
|
||||
// TI CC13x26x2
|
||||
else if (fwPackage is CC13x26x2Firmware)
|
||||
{
|
||||
// TODO
|
||||
// not supported yet
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage("The ability to update CC13x26x2 targets is not currently available. Yet...");
|
||||
|
||||
// add it to the list of devices updatED with the update time stamp
|
||||
devicesUpdatED.TryAdd(deviceDescription, DateTime.UtcNow);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Can't connect to device. Quitting update.");
|
||||
// shouldn't be here....
|
||||
}
|
||||
}
|
||||
///////////////////////////////////
|
||||
// ESP32 targets
|
||||
else if (fwPackage is Esp32Firmware)
|
||||
catch (Exception ex)
|
||||
{
|
||||
// TODO
|
||||
// not supported yet
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage("The ability to update ESP32 targets is not currently available. Yet...");
|
||||
|
||||
// add it to the list of devices updatED with the update time stamp
|
||||
devicesUpdatED.TryAdd(deviceDescription, DateTime.UtcNow);
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Exception occurred when performing update ({ex.Message}).");
|
||||
}
|
||||
///////////////////////////////////////
|
||||
// TI CC13x26x2
|
||||
else if (fwPackage is CC13x26x2Firmware)
|
||||
finally
|
||||
{
|
||||
// TODO
|
||||
// not supported yet
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage("The ability to update CC13x26x2 targets is not currently available. Yet...");
|
||||
|
||||
// add it to the list of devices updatED with the update time stamp
|
||||
devicesUpdatED.TryAdd(deviceDescription, DateTime.UtcNow);
|
||||
// remove it from updatING list
|
||||
devicesUpdatING.TryRemove(deviceId, out var dummy);
|
||||
}
|
||||
else
|
||||
{
|
||||
// shouldn't be here....
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Exception occurred when performing update ({ex.Message}).");
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
// remove it from updatING list
|
||||
devicesUpdatING.TryRemove(deviceId, out var dummy);
|
||||
nanoDevice.DebugEngine?.Stop();
|
||||
|
||||
exclusiveAccess?.Dispose();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
internal static async Task<FirmwarePackage> GetFirmwarePackageAsync(
|
||||
string targetName,
|
||||
string targetName,
|
||||
string platformName)
|
||||
{
|
||||
if (platformName.StartsWith("STM32"))
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
//
|
||||
// Copyright (c) .NET Foundation and Contributors
|
||||
// See LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using GalaSoft.MvvmLight.Messaging;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
using nanoFramework.Tools.Debugger;
|
||||
using nanoFramework.Tools.VisualStudio.Extension.FirmwareUpdate;
|
||||
using nanoFramework.Tools.VisualStudio.Extension.ToolWindow.ViewModel;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GalaSoft.MvvmLight.Messaging;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
using nanoFramework.Tools.Debugger;
|
||||
using nanoFramework.Tools.Debugger.NFDevice;
|
||||
using nanoFramework.Tools.VisualStudio.Extension.FirmwareUpdate;
|
||||
using nanoFramework.Tools.VisualStudio.Extension.ToolWindow.ViewModel;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
|
||||
namespace nanoFramework.Tools.VisualStudio.Extension.AutomaticUpdates
|
||||
{
|
||||
public class UpdateManager
|
||||
{
|
||||
private const int ExclusiveAccessTimeout = 3000;
|
||||
|
||||
private static UpdateManager s_instance;
|
||||
private ViewModelLocator ViewModelLocator;
|
||||
private readonly Package _package;
|
||||
|
@ -32,7 +32,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension.AutomaticUpdates
|
|||
}
|
||||
|
||||
public static void Initialize(
|
||||
AsyncPackage package,
|
||||
AsyncPackage package,
|
||||
ViewModelLocator vmLocator)
|
||||
{
|
||||
s_instance = new UpdateManager(package)
|
||||
|
@ -102,256 +102,278 @@ namespace nanoFramework.Tools.VisualStudio.Extension.AutomaticUpdates
|
|||
}
|
||||
#endif
|
||||
|
||||
// check if DebugEngine is available
|
||||
if (nanoDevice.DebugEngine == null)
|
||||
{
|
||||
nanoDevice.CreateDebugEngine();
|
||||
}
|
||||
|
||||
if (nanoDevice.DebugEngine == null)
|
||||
{
|
||||
// can't create it, quit update now
|
||||
return;
|
||||
}
|
||||
|
||||
// add this device to the updatING list
|
||||
if (!devicesUpdatING.TryAdd(deviceId, new object()))
|
||||
{
|
||||
// fail to add device to list
|
||||
#if DEBUG
|
||||
Console.WriteLine($"[Automatic Updates] {nanoDevice.TargetName} update already in progress.");
|
||||
#endif
|
||||
|
||||
// quit, never mind, this is not critical whatsoever
|
||||
return;
|
||||
}
|
||||
|
||||
// better wrap this on a try-finally because a lot of things can go wrong in the process
|
||||
GlobalExclusiveDeviceAccess exclusiveAccess = null;
|
||||
try
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
var fwPackage = await GetFirmwarePackageAsync(
|
||||
nanoDevice.TargetName,
|
||||
nanoDevice.Platform);
|
||||
|
||||
await Task.Yield();
|
||||
|
||||
//////////////////////////////
|
||||
// STM32 targets
|
||||
if (fwPackage is Stm32Firmware)
|
||||
// Get exclusive access to the device, but don't wait forever
|
||||
exclusiveAccess = GlobalExclusiveDeviceAccess.TryGet(nanoDevice, ExclusiveAccessTimeout);
|
||||
if (exclusiveAccess is null)
|
||||
{
|
||||
// sanity check
|
||||
if (nanoDevice.DebugEngine == null)
|
||||
{
|
||||
// Can't get access, quit update for now
|
||||
#if DEBUG
|
||||
Console.WriteLine($"[Automatic Updates] {nanoDevice.TargetName} debug engine is not ready.");
|
||||
Console.WriteLine($"[Automatic Updates] Cannot access {nanoDevice.Description}, another application is using the device");
|
||||
#endif
|
||||
// quit
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (nanoDevice.DebugEngine.Connect(
|
||||
1000,
|
||||
true,
|
||||
true))
|
||||
// check if DebugEngine is available
|
||||
if (nanoDevice.DebugEngine == null)
|
||||
{
|
||||
nanoDevice.CreateDebugEngine();
|
||||
}
|
||||
|
||||
if (nanoDevice.DebugEngine == null)
|
||||
{
|
||||
// can't create it, quit update now
|
||||
return;
|
||||
}
|
||||
|
||||
// add this device to the updatING list
|
||||
if (!devicesUpdatING.TryAdd(deviceId, new object()))
|
||||
{
|
||||
// fail to add device to list
|
||||
#if DEBUG
|
||||
Console.WriteLine($"[Automatic Updates] {nanoDevice.TargetName} update already in progress.");
|
||||
#endif
|
||||
|
||||
// quit, never mind, this is not critical whatsoever
|
||||
return;
|
||||
}
|
||||
|
||||
// better wrap this on a try-finally because a lot of things can go wrong in the process
|
||||
try
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
var fwPackage = await GetFirmwarePackageAsync(
|
||||
nanoDevice.TargetName,
|
||||
nanoDevice.Platform);
|
||||
|
||||
await Task.Yield();
|
||||
|
||||
//////////////////////////////
|
||||
// STM32 targets
|
||||
if (fwPackage is Stm32Firmware)
|
||||
{
|
||||
Version currentClrVersion = null;
|
||||
|
||||
// try to store CLR version
|
||||
if(nanoDevice.DebugEngine.IsConnectedTonanoCLR)
|
||||
// sanity check
|
||||
if (nanoDevice.DebugEngine == null)
|
||||
{
|
||||
if (nanoDevice.DeviceInfo.Valid)
|
||||
{
|
||||
currentClrVersion = nanoDevice.DeviceInfo.SolutionBuildVersion;
|
||||
}
|
||||
#if DEBUG
|
||||
Console.WriteLine($"[Automatic Updates] {nanoDevice.TargetName} debug engine is not ready.");
|
||||
#endif
|
||||
// quit
|
||||
return;
|
||||
}
|
||||
|
||||
// update conditions:
|
||||
// 1. Running CLR _and_ the new version is higher
|
||||
// 2. Running nanoBooter and there is no version information on the CLR (presumably because there is no CLR installed)
|
||||
if (fwPackage.Version > nanoDevice.CLRVersion)
|
||||
if (nanoDevice.DebugEngine.Connect(
|
||||
1000,
|
||||
true,
|
||||
true))
|
||||
{
|
||||
bool attemptToLaunchBooter = false;
|
||||
Version currentClrVersion = null;
|
||||
|
||||
// try to store CLR version
|
||||
if (nanoDevice.DebugEngine.IsConnectedTonanoCLR)
|
||||
{
|
||||
// any update has to be handled by nanoBooter, so let's have it running
|
||||
try
|
||||
if (nanoDevice.DeviceInfo.Valid)
|
||||
{
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] Launching nanoBooter...");
|
||||
currentClrVersion = nanoDevice.DeviceInfo.SolutionBuildVersion;
|
||||
}
|
||||
}
|
||||
|
||||
attemptToLaunchBooter = nanoDevice.ConnectToNanoBooter();
|
||||
// update conditions:
|
||||
// 1. Running CLR _and_ the new version is higher
|
||||
// 2. Running nanoBooter and there is no version information on the CLR (presumably because there is no CLR installed)
|
||||
if (fwPackage.Version > nanoDevice.CLRVersion)
|
||||
{
|
||||
bool attemptToLaunchBooter = false;
|
||||
|
||||
if (!attemptToLaunchBooter)
|
||||
if (nanoDevice.DebugEngine.IsConnectedTonanoCLR)
|
||||
{
|
||||
// any update has to be handled by nanoBooter, so let's have it running
|
||||
try
|
||||
{
|
||||
// check for version where the software reboot to nanoBooter was made available
|
||||
if (currentClrVersion != null &&
|
||||
nanoDevice.DeviceInfo.SolutionBuildVersion < new Version("1.6.0.54"))
|
||||
{
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] The device is running a version that doesn't support rebooting by software. Please update your device using 'nanoff' tool.");
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] Launching nanoBooter...");
|
||||
|
||||
await Task.Yield();
|
||||
attemptToLaunchBooter = nanoDevice.ConnectToNanoBooter();
|
||||
|
||||
if (!attemptToLaunchBooter)
|
||||
{
|
||||
// check for version where the software reboot to nanoBooter was made available
|
||||
if (currentClrVersion != null &&
|
||||
nanoDevice.DeviceInfo.SolutionBuildVersion < new Version("1.6.0.54"))
|
||||
{
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] The device is running a version that doesn't support rebooting by software. Please update your device using 'nanoff' tool.");
|
||||
|
||||
await Task.Yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// this reboot step can go wrong and there's no big deal with that
|
||||
}
|
||||
}
|
||||
catch
|
||||
else
|
||||
{
|
||||
// this reboot step can go wrong and there's no big deal with that
|
||||
attemptToLaunchBooter = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
attemptToLaunchBooter = true;
|
||||
}
|
||||
|
||||
// check if the device is still there
|
||||
if(ViewModelLocator.DeviceExplorer.AvailableDevices.FirstOrDefault(d => d.DeviceUniqueId == deviceUniqueId) == null)
|
||||
{
|
||||
// check if the device is still there
|
||||
if (ViewModelLocator.DeviceExplorer.AvailableDevices.FirstOrDefault(d => d.DeviceUniqueId == deviceUniqueId) == null)
|
||||
{
|
||||
#if DEBUG
|
||||
Console.WriteLine($"[Automatic Updates] {nanoDevice.TargetName} is not available anymore.");
|
||||
Console.WriteLine($"[Automatic Updates] {nanoDevice.TargetName} is not available anymore.");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (attemptToLaunchBooter &&
|
||||
nanoDevice.Ping() == Debugger.WireProtocol.ConnectionSource.nanoBooter)
|
||||
{
|
||||
// get address for CLR block expected by device
|
||||
var clrAddress = nanoDevice.GetCLRStartAddress();
|
||||
|
||||
// compare with address on the fw packages
|
||||
if (clrAddress !=
|
||||
(fwPackage as Stm32Firmware).ClrStartAddress)
|
||||
{
|
||||
// CLR addresses don't match, can't proceed with update
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Can't update device. CLR addresses are different. Please update nanoBooter manually.");
|
||||
return;
|
||||
}
|
||||
|
||||
await Task.Yield();
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] Starting update to CLR v{fwPackage.Version}.");
|
||||
|
||||
try
|
||||
if (attemptToLaunchBooter &&
|
||||
nanoDevice.Ping() == Debugger.WireProtocol.ConnectionSource.nanoBooter)
|
||||
{
|
||||
// get address for CLR block expected by device
|
||||
var clrAddress = nanoDevice.GetCLRStartAddress();
|
||||
|
||||
// compare with address on the fw packages
|
||||
if (clrAddress !=
|
||||
(fwPackage as Stm32Firmware).ClrStartAddress)
|
||||
{
|
||||
// CLR addresses don't match, can't proceed with update
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Can't update device. CLR addresses are different. Please update nanoBooter manually.");
|
||||
return;
|
||||
}
|
||||
|
||||
await Task.Yield();
|
||||
|
||||
// create a progress indicator to be used by deployment operation to post debug messages
|
||||
var progressIndicator = new Progress<string>(m => MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] {m}"));
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] Starting update to CLR v{fwPackage.Version}.");
|
||||
|
||||
if (nanoDevice.DeployBinaryFile(
|
||||
(fwPackage as Stm32Firmware).nanoClrFileBin,
|
||||
(fwPackage as Stm32Firmware).ClrStartAddress,
|
||||
progressIndicator))
|
||||
try
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] Update successful.");
|
||||
// create a progress indicator to be used by deployment operation to post debug messages
|
||||
var progressIndicator = new Progress<string>(m => MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] {m}"));
|
||||
|
||||
// add it to the list of devices updatED with the update time stamp
|
||||
devicesUpdatED.TryAdd(deviceDescription, DateTime.UtcNow);
|
||||
}
|
||||
|
||||
// if this is the selected device...
|
||||
if (ViewModelLocator.DeviceExplorer.SelectedDevice?.DeviceUniqueId == deviceUniqueId)
|
||||
{
|
||||
// ...reset property to force that device capabilities to be retrieved on next connection
|
||||
ViewModelLocator.DeviceExplorer.LastDeviceConnectedHash = 0;
|
||||
}
|
||||
|
||||
if (attemptToLaunchBooter)
|
||||
{
|
||||
// try to reboot target
|
||||
|
||||
// remove it from updatING list
|
||||
devicesUpdatING.TryRemove(deviceId, out var dummy);
|
||||
|
||||
// check if the device is still there
|
||||
if (ViewModelLocator.DeviceExplorer.AvailableDevices.FirstOrDefault(d => d.DeviceUniqueId == Guid.Parse(deviceId)) == null)
|
||||
if (nanoDevice.DeployBinaryFile(
|
||||
(fwPackage as Stm32Firmware).nanoClrFileBin,
|
||||
(fwPackage as Stm32Firmware).ClrStartAddress,
|
||||
progressIndicator))
|
||||
{
|
||||
return;
|
||||
await Task.Yield();
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] Update successful.");
|
||||
|
||||
// add it to the list of devices updatED with the update time stamp
|
||||
devicesUpdatED.TryAdd(deviceDescription, DateTime.UtcNow);
|
||||
}
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] Rebooting...");
|
||||
// if this is the selected device...
|
||||
if (ViewModelLocator.DeviceExplorer.SelectedDevice?.DeviceUniqueId == deviceUniqueId)
|
||||
{
|
||||
// ...reset property to force that device capabilities to be retrieved on next connection
|
||||
ViewModelLocator.DeviceExplorer.LastDeviceConnectedHash = 0;
|
||||
}
|
||||
|
||||
nanoDevice.DebugEngine.RebootDevice(RebootOptions.NormalReboot);
|
||||
if (attemptToLaunchBooter)
|
||||
{
|
||||
// try to reboot target
|
||||
|
||||
// remove it from updatING list
|
||||
devicesUpdatING.TryRemove(deviceId, out var dummy);
|
||||
|
||||
// check if the device is still there
|
||||
if (ViewModelLocator.DeviceExplorer.AvailableDevices.FirstOrDefault(d => d.DeviceUniqueId == Guid.Parse(deviceId)) == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] Rebooting...");
|
||||
|
||||
nanoDevice.DebugEngine.RebootDevice(RebootOptions.NormalReboot);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Exception occurred when performing update ({ex.Message}).");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
else
|
||||
{
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Exception occurred when performing update ({ex.Message}).");
|
||||
if (attemptToLaunchBooter)
|
||||
{
|
||||
// only report this as an error if the launch was successful
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Failed to launch nanoBooter. Quitting update.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (attemptToLaunchBooter)
|
||||
// just to make sure that the CLR version is the latest, so we don't check it over and over
|
||||
if (nanoDevice.DebugEngine.IsConnectedTonanoCLR &&
|
||||
(fwPackage.Version == nanoDevice.DeviceInfo.ClrBuildVersion))
|
||||
{
|
||||
// only report this as an error if the launch was successful
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Failed to launch nanoBooter. Quitting update.");
|
||||
// add it to the list of devices updatED with the update time stamp
|
||||
devicesUpdatED.TryAdd(deviceDescription, DateTime.UtcNow);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// just to make sure that the CLR version is the latest, so we don't check it over and over
|
||||
if (nanoDevice.DebugEngine.IsConnectedTonanoCLR &&
|
||||
(fwPackage.Version == nanoDevice.DeviceInfo.ClrBuildVersion))
|
||||
{
|
||||
// add it to the list of devices updatED with the update time stamp
|
||||
devicesUpdatED.TryAdd(deviceDescription, DateTime.UtcNow);
|
||||
}
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Can't connect to device. Quitting update.");
|
||||
}
|
||||
}
|
||||
///////////////////////////////////
|
||||
// ESP32 targets
|
||||
else if (fwPackage is Esp32Firmware)
|
||||
{
|
||||
// TODO
|
||||
// not supported yet
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage("The ability to update ESP32 targets is not currently available. Yet...");
|
||||
|
||||
// add it to the list of devices updatED with the update time stamp
|
||||
devicesUpdatED.TryAdd(deviceDescription, DateTime.UtcNow);
|
||||
}
|
||||
///////////////////////////////////////
|
||||
// TI CC13x26x2
|
||||
else if (fwPackage is CC13x26x2Firmware)
|
||||
{
|
||||
// TODO
|
||||
// not supported yet
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage("The ability to update CC13x26x2 targets is not currently available. Yet...");
|
||||
|
||||
// add it to the list of devices updatED with the update time stamp
|
||||
devicesUpdatED.TryAdd(deviceDescription, DateTime.UtcNow);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Can't connect to device. Quitting update.");
|
||||
// shouldn't be here....
|
||||
}
|
||||
}
|
||||
///////////////////////////////////
|
||||
// ESP32 targets
|
||||
else if (fwPackage is Esp32Firmware)
|
||||
catch (Exception ex)
|
||||
{
|
||||
// TODO
|
||||
// not supported yet
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage("The ability to update ESP32 targets is not currently available. Yet...");
|
||||
|
||||
// add it to the list of devices updatED with the update time stamp
|
||||
devicesUpdatED.TryAdd(deviceDescription, DateTime.UtcNow);
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Exception occurred when performing update ({ex.Message}).");
|
||||
}
|
||||
///////////////////////////////////////
|
||||
// TI CC13x26x2
|
||||
else if (fwPackage is CC13x26x2Firmware)
|
||||
finally
|
||||
{
|
||||
// TODO
|
||||
// not supported yet
|
||||
|
||||
MessageCentre.OutputFirmwareUpdateMessage("The ability to update CC13x26x2 targets is not currently available. Yet...");
|
||||
|
||||
// add it to the list of devices updatED with the update time stamp
|
||||
devicesUpdatED.TryAdd(deviceDescription, DateTime.UtcNow);
|
||||
// remove it from updatING list
|
||||
devicesUpdatING.TryRemove(deviceId, out var dummy);
|
||||
}
|
||||
else
|
||||
{
|
||||
// shouldn't be here....
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageCentre.OutputFirmwareUpdateMessage($"[{deviceDescription}] ERROR: Exception occurred when performing update ({ex.Message}).");
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
// remove it from updatING list
|
||||
devicesUpdatING.TryRemove(deviceId, out var dummy);
|
||||
nanoDevice.DebugEngine?.Stop();
|
||||
|
||||
exclusiveAccess?.Dispose();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
internal static async Task<FirmwarePackage> GetFirmwarePackageAsync(
|
||||
string targetName,
|
||||
string targetName,
|
||||
string platformName)
|
||||
{
|
||||
if (platformName.StartsWith("STM32"))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ImageManifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/VisualStudio/ImageManifestSchema/2014">
|
||||
<Symbols>
|
||||
<String Name="Resources" Value="/nanoFramework.Tools.VS2022.Extension;v2022.3.0.92;C78BE3280FBDE583;Component/Resources" />
|
||||
<String Name="Resources" Value="/nanoFramework.Tools.VS2022.Extension;v2022.3.0.103;C78BE3280FBDE583;Component/Resources" />
|
||||
<Guid Name="NanoFrameworkCatalog" Value="{23cf437f-5e0e-4b0c-8aa4-ceec5b5f8679}" />
|
||||
<ID Name="DeviceConnected" Value="20" />
|
||||
<ID Name="DeviceDisconnected" Value="30" />
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
nano
|
||||
|
|
@ -1,20 +1,17 @@
|
|||
//
|
||||
// Copyright (c) .NET Foundation and Contributors
|
||||
// Portions Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// See LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using CorDebugInterop;
|
||||
using Microsoft.VisualStudio.Debugger.Interop;
|
||||
using nanoFramework.Tools.Debugger;
|
||||
using nanoFramework.Tools.Debugger.Extensions;
|
||||
using nanoFramework.Tools.Debugger.WireProtocol;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using CorDebugInterop;
|
||||
using Microsoft.VisualStudio.Debugger.Interop;
|
||||
using nanoFramework.Tools.Debugger;
|
||||
using nanoFramework.Tools.Debugger.Extensions;
|
||||
using nanoFramework.Tools.Debugger.WireProtocol;
|
||||
using BreakpointDef = nanoFramework.Tools.Debugger.WireProtocol.Commands.Debugging_Execution_BreakpointDef;
|
||||
|
||||
namespace nanoFramework.Tools.VisualStudio.Extension
|
||||
|
@ -79,15 +76,15 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
_syncTerminatingObject = new object();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
bool m_fDisposed = false;
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!m_fDisposed)
|
||||
{
|
||||
|
@ -97,14 +94,14 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
}
|
||||
|
||||
// free "unmanaged" stuff
|
||||
StopDebugging();
|
||||
StopDebugging();
|
||||
m_fDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
~CorDebugProcess()
|
||||
{
|
||||
Dispose (false);
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -126,11 +123,11 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
public bool IsDebugging => _corDebug != null;
|
||||
|
||||
public void SetCurrentAppDomain( CorDebugAppDomain appDomain )
|
||||
public void SetCurrentAppDomain(CorDebugAppDomain appDomain)
|
||||
{
|
||||
if(appDomain != _appDomainCurrent)
|
||||
if (appDomain != _appDomainCurrent)
|
||||
{
|
||||
if(appDomain != null && Engine.Capabilities.AppDomains)
|
||||
if (appDomain != null && Engine.Capabilities.AppDomains)
|
||||
{
|
||||
Engine.SetCurrentAppDomain(appDomain.Id);
|
||||
}
|
||||
|
@ -161,7 +158,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
// catch all as this can throw and we need to continue
|
||||
}
|
||||
|
||||
if(!isProcess)
|
||||
if (!isProcess)
|
||||
{
|
||||
// try sender as Engine
|
||||
try
|
||||
|
@ -355,7 +352,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
}
|
||||
else
|
||||
{
|
||||
MessageCentre.InternalErrorWriteLine($"Device is running nanoCLR, requesting a restart and pause of debugger ({retry + 1}/{ maxOperationRetries }).");
|
||||
MessageCentre.InternalErrorWriteLine($"Device is running nanoCLR, requesting a restart and pause of debugger ({retry + 1}/{maxOperationRetries}).");
|
||||
|
||||
bool rebootSuccessful = _engine.RebootDevice(RebootOptions.ClrOnly | RebootOptions.WaitForDebugger);
|
||||
|
||||
|
@ -373,7 +370,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
}
|
||||
else if (_engine.IsConnectedTonanoBooter)
|
||||
{
|
||||
MessageCentre.InternalErrorWriteLine($"Device is running nanoBooter, requesting to launch nanoCLR ({retry + 1}/{ maxOperationRetries }).");
|
||||
MessageCentre.InternalErrorWriteLine($"Device is running nanoBooter, requesting to launch nanoCLR ({retry + 1}/{maxOperationRetries}).");
|
||||
|
||||
// this is telling nanoBooter to enter CLR
|
||||
_engine.ExecuteMemory(0);
|
||||
|
@ -416,7 +413,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
public Engine AttachToEngine()
|
||||
{
|
||||
|
||||
for(int retry = 0; retry < maxOperationRetries; retry++)
|
||||
for (int retry = 0; retry < maxOperationRetries; retry++)
|
||||
{
|
||||
if (ShuttingDown)
|
||||
{
|
||||
|
@ -425,7 +422,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
break;
|
||||
}
|
||||
|
||||
MessageCentre.InternalErrorWriteLine($"Attempting to connect the debugger engine ({retry + 1}/{ maxOperationRetries })");
|
||||
MessageCentre.InternalErrorWriteLine($"Attempting to connect the debugger engine ({retry + 1}/{maxOperationRetries})");
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -497,7 +494,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
var executionMode = Commands.DebuggingExecutionChangeConditions.State.SourceLevelDebugging;
|
||||
|
||||
// check if we need to disable the stack trace in exceptions
|
||||
if(_engine.ThrowOnCommunicationFailure)
|
||||
if (_engine.ThrowOnCommunicationFailure)
|
||||
{
|
||||
executionMode |= Commands.DebuggingExecutionChangeConditions.State.NoStackTraceInExceptions;
|
||||
}
|
||||
|
@ -517,14 +514,14 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
{
|
||||
DetachFromEngine();
|
||||
|
||||
if(!ShuttingDown)
|
||||
if (!ShuttingDown)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(_engine != null && !_engine.IsConnected)
|
||||
if (_engine != null && !_engine.IsConnected)
|
||||
{
|
||||
DetachFromEngine();
|
||||
|
||||
|
@ -555,21 +552,21 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
bool fContinue = false;
|
||||
ManagedCallbacks.ManagedCallback mc = null;
|
||||
|
||||
lock(this)
|
||||
lock (this)
|
||||
{
|
||||
if(_cStopped == 0 && AnyQueuedEvents)
|
||||
if (_cStopped == 0 && AnyQueuedEvents)
|
||||
{
|
||||
Interlocked.Increment( ref _cStopped );
|
||||
Interlocked.Increment(ref _cStopped);
|
||||
|
||||
mc = (ManagedCallbacks.ManagedCallback)_events.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
if(mc != null)
|
||||
if (mc != null)
|
||||
{
|
||||
DebugAssert(ShuttingDown || IsExecutionPaused || mc is ManagedCallbacks.ManagedCallbackDebugMessage, "Error on FlushEvent");
|
||||
|
||||
mc.Dispatch( _corDebug.ManagedCallback );
|
||||
mc.Dispatch(_corDebug.ManagedCallback);
|
||||
fContinue = true;
|
||||
}
|
||||
|
||||
|
@ -685,7 +682,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
try
|
||||
{
|
||||
EnqueueStartupEventsAndWait();
|
||||
|
||||
|
||||
MessageCentre.DebugMessage(Resources.ResourceStrings.AttachingToDevice);
|
||||
|
||||
if (AttachToEngine() == null)
|
||||
|
@ -699,7 +696,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
if (_fLaunched)
|
||||
{
|
||||
//This will reboot the device if start debugging was done without a deployment
|
||||
|
||||
|
||||
MessageCentre.DebugMessage(Resources.ResourceStrings.WaitingDeviceInitialization);
|
||||
EnsureProcessIsInInitializedState();
|
||||
}
|
||||
|
@ -725,7 +722,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
}
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageCentre.DebugMessage(Resources.ResourceStrings.InitializationFailed);
|
||||
|
||||
|
@ -737,15 +734,15 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
private void UpdateThreadList()
|
||||
{
|
||||
/*
|
||||
This is a bit of a hack (or performance improvement, if you prefer)
|
||||
The nanoCLR creates threads with wild abandon, but ICorDebug specifies that
|
||||
thread creation/destruction events should stop the CLR, and provide callbacks
|
||||
This can slow down debugging anything that makes heavy use of threads
|
||||
For example...managed drivers, timers, etc...
|
||||
So we are faking the events just in time, in a couple of cases --
|
||||
when a real breakpoint gets hit, when execution is stopped via BreakAll, etc..
|
||||
*/
|
||||
/*
|
||||
This is a bit of a hack (or performance improvement, if you prefer)
|
||||
The nanoCLR creates threads with wild abandon, but ICorDebug specifies that
|
||||
thread creation/destruction events should stop the CLR, and provide callbacks
|
||||
This can slow down debugging anything that makes heavy use of threads
|
||||
For example...managed drivers, timers, etc...
|
||||
So we are faking the events just in time, in a couple of cases --
|
||||
when a real breakpoint gets hit, when execution is stopped via BreakAll, etc..
|
||||
*/
|
||||
|
||||
MessageCentre.InternalErrorWriteLine(Resources.ResourceStrings.RunningThreadsInformation);
|
||||
|
||||
|
@ -789,7 +786,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
Init(corDebug, fLaunch);
|
||||
|
||||
_threadDispatch = new Thread(delegate()
|
||||
_threadDispatch = new Thread(delegate ()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -842,7 +839,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
{
|
||||
AD_PROCESS_ID id = new AD_PROCESS_ID();
|
||||
|
||||
id.ProcessIdType = (uint) AD_PROCESS_ID_TYPE.AD_PROCESS_ID_SYSTEM;
|
||||
id.ProcessIdType = (uint)AD_PROCESS_ID_TYPE.AD_PROCESS_ID_SYSTEM;
|
||||
id.dwProcessId = _pid;
|
||||
return id;
|
||||
}
|
||||
|
@ -875,7 +872,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
if (wr != null)
|
||||
{
|
||||
CorDebugValue val = (CorDebugValue) wr.Target;
|
||||
CorDebugValue val = (CorDebugValue)wr.Target;
|
||||
|
||||
if (val != null)
|
||||
{
|
||||
|
@ -945,7 +942,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
m_scratchPad[index] = wr;
|
||||
}
|
||||
|
||||
CorDebugValue val = (CorDebugValue) wr.Target;
|
||||
CorDebugValue val = (CorDebugValue)wr.Target;
|
||||
|
||||
if (val == null)
|
||||
{
|
||||
|
@ -1081,12 +1078,12 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
public CorDebugAssembly AssemblyFromIdx(uint idx)
|
||||
{
|
||||
return CorDebugAssembly.AssemblyFromIdx( idx, _assemblies );
|
||||
return CorDebugAssembly.AssemblyFromIdx(idx, _assemblies);
|
||||
}
|
||||
|
||||
public CorDebugAssembly AssemblyFromIndex(uint index)
|
||||
{
|
||||
return CorDebugAssembly.AssemblyFromIndex( index, _assemblies );
|
||||
return CorDebugAssembly.AssemblyFromIndex(index, _assemblies);
|
||||
}
|
||||
|
||||
public void RegisterBreakpoint(object o, bool fRegister)
|
||||
|
@ -1103,17 +1100,17 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
DirtyBreakpoints();
|
||||
}
|
||||
|
||||
internal ArrayList GetBreakpoints( Type t, CorDebugAppDomain appDomain )
|
||||
internal ArrayList GetBreakpoints(Type t, CorDebugAppDomain appDomain)
|
||||
{
|
||||
ArrayList al = new ArrayList( _breakpoints.Count );
|
||||
ArrayList al = new ArrayList(_breakpoints.Count);
|
||||
|
||||
foreach(CorDebugBreakpointBase breakpoint in _breakpoints)
|
||||
foreach (CorDebugBreakpointBase breakpoint in _breakpoints)
|
||||
{
|
||||
if(t.IsAssignableFrom( breakpoint.GetType() ))
|
||||
if (t.IsAssignableFrom(breakpoint.GetType()))
|
||||
{
|
||||
if(appDomain == null || appDomain == breakpoint.AppDomain)
|
||||
if (appDomain == null || appDomain == breakpoint.AppDomain)
|
||||
{
|
||||
al.Add( breakpoint );
|
||||
al.Add(breakpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1121,22 +1118,22 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
return al;
|
||||
}
|
||||
|
||||
private CorDebugBreakpointBase[] FindBreakpoints( BreakpointDef breakpointDef )
|
||||
private CorDebugBreakpointBase[] FindBreakpoints(BreakpointDef breakpointDef)
|
||||
{
|
||||
//perhaps need to cheat for CorDebugEval.Breakpoint for uncaught exceptions...
|
||||
ArrayList breakpoints = new ArrayList( 1 );
|
||||
if( IsDebugging )
|
||||
ArrayList breakpoints = new ArrayList(1);
|
||||
if (IsDebugging)
|
||||
{
|
||||
foreach( CorDebugBreakpointBase breakpoint in _breakpoints )
|
||||
foreach (CorDebugBreakpointBase breakpoint in _breakpoints)
|
||||
{
|
||||
if( breakpoint.IsMatch( breakpointDef ) )
|
||||
if (breakpoint.IsMatch(breakpointDef))
|
||||
{
|
||||
breakpoints.Add( breakpoint );
|
||||
breakpoints.Add(breakpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (CorDebugBreakpointBase[])breakpoints.ToArray( typeof( CorDebugBreakpointBase ) );
|
||||
return (CorDebugBreakpointBase[])breakpoints.ToArray(typeof(CorDebugBreakpointBase));
|
||||
}
|
||||
|
||||
private bool BreakpointHit(BreakpointDef breakpointDef)
|
||||
|
@ -1147,23 +1144,23 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
CorDebugBreakpointBase[] breakpoints = FindBreakpoints(breakpointDef);
|
||||
bool fStopExecution = false;
|
||||
|
||||
for(int iBreakpoint = 0; iBreakpoint < breakpoints.Length; iBreakpoint++)
|
||||
for (int iBreakpoint = 0; iBreakpoint < breakpoints.Length; iBreakpoint++)
|
||||
{
|
||||
CorDebugBreakpointBase breakpoint = breakpoints[iBreakpoint];
|
||||
|
||||
if(breakpoint.ShouldBreak(breakpointDef))
|
||||
if (breakpoint.ShouldBreak(breakpointDef))
|
||||
{
|
||||
fStopExecution = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(fStopExecution)
|
||||
if (fStopExecution)
|
||||
{
|
||||
for(int iBreakpoint = 0; iBreakpoint < breakpoints.Length; iBreakpoint++)
|
||||
for (int iBreakpoint = 0; iBreakpoint < breakpoints.Length; iBreakpoint++)
|
||||
{
|
||||
CorDebugBreakpointBase breakpoint = breakpoints[iBreakpoint];
|
||||
breakpoint.Hit( breakpointDef );
|
||||
breakpoint.Hit(breakpointDef);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1172,36 +1169,36 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
public void UpdateBreakpoints()
|
||||
{
|
||||
if(!IsAttachedToEngine || !_fUpdateBreakpoints || ShuttingDown)
|
||||
if (!IsAttachedToEngine || !_fUpdateBreakpoints || ShuttingDown)
|
||||
return;
|
||||
|
||||
//Function breakpoints are set for each AppDomain.
|
||||
//No need to send all duplicates to the nanoCLR
|
||||
ArrayList al = new ArrayList( _breakpoints.Count );
|
||||
for(int i = 0; i < _breakpoints.Count; i++)
|
||||
ArrayList al = new ArrayList(_breakpoints.Count);
|
||||
for (int i = 0; i < _breakpoints.Count; i++)
|
||||
{
|
||||
CorDebugBreakpointBase breakpoint1 = ((CorDebugBreakpointBase)_breakpoints[i]);
|
||||
|
||||
bool fDuplicate = false;
|
||||
|
||||
for(int j = 0; j < i; j++)
|
||||
for (int j = 0; j < i; j++)
|
||||
{
|
||||
CorDebugBreakpointBase breakpoint2 = ((CorDebugBreakpointBase)_breakpoints[j]);
|
||||
|
||||
if(breakpoint1.Equals( breakpoint2 ))
|
||||
if (breakpoint1.Equals(breakpoint2))
|
||||
{
|
||||
fDuplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!fDuplicate)
|
||||
if (!fDuplicate)
|
||||
{
|
||||
al.Add( breakpoint1.Debugging_Execution_BreakpointDef );
|
||||
al.Add(breakpoint1.Debugging_Execution_BreakpointDef);
|
||||
}
|
||||
}
|
||||
|
||||
BreakpointDef[] breakpointDefs = (BreakpointDef[])al.ToArray( typeof( BreakpointDef ) );
|
||||
BreakpointDef[] breakpointDefs = (BreakpointDef[])al.ToArray(typeof(BreakpointDef));
|
||||
|
||||
Engine.SetBreakpoints(breakpointDefs);
|
||||
_fUpdateBreakpoints = false;
|
||||
|
@ -1320,7 +1317,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
// Utility.Kernel32.DuplicateHandle(Utility.Kernel32.GetCurrentProcess(), emuProcess.Handle,
|
||||
// Utility.Kernel32.GetCurrentProcess(), out lpProcessInformation.hProcess,
|
||||
// 0, false, DUPLICATE_SAME_ACCESS);
|
||||
|
||||
|
||||
// lpProcessInformation.dwProcessId = (uint)emuProcess.Id;
|
||||
// CreateDummyThread(out lpProcessInformation.hThread, out lpProcessInformation.dwThreadId);
|
||||
// }
|
||||
|
@ -1347,18 +1344,18 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
}
|
||||
|
||||
private void InternalCreateProcess(
|
||||
DebugPort port,
|
||||
string lpApplicationName,
|
||||
string lpCommandLine,
|
||||
IntPtr lpProcessAttributes,
|
||||
IntPtr lpThreadAttributes,
|
||||
int bInheritHandles,
|
||||
uint dwCreationFlags,
|
||||
DebugPort port,
|
||||
string lpApplicationName,
|
||||
string lpCommandLine,
|
||||
IntPtr lpProcessAttributes,
|
||||
IntPtr lpThreadAttributes,
|
||||
int bInheritHandles,
|
||||
uint dwCreationFlags,
|
||||
System.IntPtr lpEnvironment,
|
||||
string lpCurrentDirectory,
|
||||
string lpCurrentDirectory,
|
||||
ref _STARTUPINFO lpStartupInfo,
|
||||
ref _PROCESS_INFORMATION lpProcessInformation,
|
||||
uint debuggingFlags
|
||||
uint debuggingFlags
|
||||
)
|
||||
{
|
||||
//if (port.IsLocalPort)
|
||||
|
@ -1375,7 +1372,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
CommandLineBuilder cb = new CommandLineBuilder(lpCommandLine);
|
||||
string[] args = cb.Arguments;
|
||||
string deployDeviceName = args[args.Length-1];
|
||||
string deployDeviceName = args[args.Length - 1];
|
||||
|
||||
//Extract deployDeviceName
|
||||
if (!deployDeviceName.StartsWith(CorDebugProcess.DeployDeviceName))
|
||||
|
@ -1397,7 +1394,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
return process;
|
||||
}
|
||||
|
||||
internal ulong FakeLoadAssemblyIntoMemory( CorDebugAssembly assembly )
|
||||
internal ulong FakeLoadAssemblyIntoMemory(CorDebugAssembly assembly)
|
||||
{
|
||||
ulong address = _fakeAssemblyAddressNext;
|
||||
|
||||
|
@ -1420,7 +1417,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
DebugAssert(assemblies.Count > 0, "Error loading assemblies. Assemblies count is 0.");
|
||||
|
||||
if(assemblies.Count == 0)
|
||||
if (assemblies.Count == 0)
|
||||
{
|
||||
// if debug was started, presumably after a successful deployment, there have to be assemblies on the device
|
||||
// so, if there are none, probably the command above failed, anyway we can't proceed with debugging
|
||||
|
@ -1480,11 +1477,11 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
}
|
||||
}
|
||||
|
||||
public CorDebugAppDomain GetAppDomainFromId( uint id )
|
||||
public CorDebugAppDomain GetAppDomainFromId(uint id)
|
||||
{
|
||||
foreach(CorDebugAppDomain appDomain in _appDomains)
|
||||
foreach (CorDebugAppDomain appDomain in _appDomains)
|
||||
{
|
||||
if(appDomain.Id == id)
|
||||
if (appDomain.Id == id)
|
||||
{
|
||||
return appDomain;
|
||||
}
|
||||
|
@ -1565,10 +1562,16 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
{
|
||||
_engine.ThrowOnCommunicationFailure = false;
|
||||
|
||||
// need to reboot device to clear memory leaks which are caused by the running app stopping execution and leaving C/C++ vars orphaned in the CRT heap
|
||||
_engine.RebootDevice(RebootOptions.NormalReboot);
|
||||
|
||||
DetachFromEngine();
|
||||
try
|
||||
{
|
||||
// need to reboot device to clear memory leaks which are caused by the running app stopping execution and leaving C/C++ vars orphaned in the CRT heap
|
||||
_engine.RebootDevice(RebootOptions.NormalReboot);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Make sure the engine is detached (disposes the global exclusive access)
|
||||
DetachFromEngine();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -1585,9 +1588,9 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
{
|
||||
if (_threads != null && _threads.Count > 0)
|
||||
{
|
||||
if(_appDomains != null && _appDomains.Count > 0)
|
||||
if (_appDomains != null && _appDomains.Count > 0)
|
||||
{
|
||||
EnqueueEvent( new ManagedCallbacks.ManagedCallbackDebugMessage( (CorDebugThread)_threads[0], (CorDebugAppDomain)_appDomains[0], "nanoCLR_Message", text, LoggingLevelEnum.LStatusLevel0 ) );
|
||||
EnqueueEvent(new ManagedCallbacks.ManagedCallbackDebugMessage((CorDebugThread)_threads[0], (CorDebugAppDomain)_appDomains[0], "nanoCLR_Message", text, LoggingLevelEnum.LStatusLevel0));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1693,9 +1696,9 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
public void OnNoise(byte[] buf, int offset, int count)
|
||||
{
|
||||
if(buf != null && (offset + count) <= buf.Length)
|
||||
if (buf != null && (offset + count) <= buf.Length)
|
||||
{
|
||||
MessageCentre.InternalErrorWriteLine( System.Text.UTF8Encoding.UTF8.GetString(buf, offset, count) );
|
||||
MessageCentre.InternalErrorWriteLine(System.Text.UTF8Encoding.UTF8.GetString(buf, offset, count));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1718,21 +1721,21 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
private uint m_tkCLR;
|
||||
private CorDebugClass m_class;
|
||||
|
||||
public BuiltinType( CorDebugAssembly assembly, uint tkCLR, CorDebugClass cls )
|
||||
public BuiltinType(CorDebugAssembly assembly, uint tkCLR, CorDebugClass cls)
|
||||
{
|
||||
m_assembly = assembly;
|
||||
m_tkCLR = tkCLR;
|
||||
m_class = cls;
|
||||
}
|
||||
|
||||
public CorDebugAssembly GetAssembly( CorDebugAppDomain appDomain )
|
||||
public CorDebugAssembly GetAssembly(CorDebugAppDomain appDomain)
|
||||
{
|
||||
return appDomain.AssemblyFromIdx( m_assembly.Idx );
|
||||
return appDomain.AssemblyFromIdx(m_assembly.Idx);
|
||||
}
|
||||
|
||||
public CorDebugClass GetClass( CorDebugAppDomain appDomain )
|
||||
public CorDebugClass GetClass(CorDebugAppDomain appDomain)
|
||||
{
|
||||
CorDebugAssembly assembly = GetAssembly( appDomain );
|
||||
CorDebugAssembly assembly = GetAssembly(appDomain);
|
||||
|
||||
return assembly.GetClassFromTokenCLR(m_tkCLR);
|
||||
}
|
||||
|
@ -1748,7 +1751,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
uint tkCLR = MetaData.Helper.ClassTokenFromName(assm.MetaDataImport, type);
|
||||
CorDebugClass c = assm.GetClassFromTokenCLR(tkCLR);
|
||||
|
||||
BuiltinType builtInType = new BuiltinType( assm, tkCLR, c );
|
||||
BuiltinType builtInType = new BuiltinType(assm, tkCLR, c);
|
||||
|
||||
_tdBuiltin[o] = builtInType;
|
||||
}
|
||||
|
@ -1775,7 +1778,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
DebugAssert(assmCorLib != null, "Error resolving built-in type. Couldn't find mscorlib");
|
||||
|
||||
AddBuiltInType(CorElementType.ELEMENT_TYPE_BOOLEAN, assmCorLib, "System.Boolean");
|
||||
AddBuiltInType(CorElementType.ELEMENT_TYPE_CHAR, assmCorLib, "System.Char");
|
||||
AddBuiltInType(CorElementType.ELEMENT_TYPE_CHAR, assmCorLib, "System.Char");
|
||||
AddBuiltInType(CorElementType.ELEMENT_TYPE_I1, assmCorLib, "System.SByte");
|
||||
AddBuiltInType(CorElementType.ELEMENT_TYPE_U1, assmCorLib, "System.Byte");
|
||||
AddBuiltInType(CorElementType.ELEMENT_TYPE_I2, assmCorLib, "System.Int16");
|
||||
|
@ -1798,7 +1801,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
AddBuiltInType(ReflectionDefinition.Kind.REFLECTION_METHOD, assmCorLib, "System.Reflection.RuntimeMethodInfo");
|
||||
AddBuiltInType(ReflectionDefinition.Kind.REFLECTION_CONSTRUCTOR, assmCorLib, "System.Reflection.RuntimeConstructorInfo");
|
||||
|
||||
AddBuiltInType(nanoClrDataType.DATATYPE_TRANSPARENT_PROXY, assmCorLib, "System.Runtime.Remoting.Proxies.__TransparentProxy" );
|
||||
AddBuiltInType(nanoClrDataType.DATATYPE_TRANSPARENT_PROXY, assmCorLib, "System.Runtime.Remoting.Proxies.__TransparentProxy");
|
||||
}
|
||||
|
||||
return (BuiltinType)_tdBuiltin[o];
|
||||
|
@ -2177,7 +2180,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
#region ICorDebugProcess2 Members
|
||||
|
||||
int ICorDebugProcess2.GetVersion( out _COR_VERSION version )
|
||||
int ICorDebugProcess2.GetVersion(out _COR_VERSION version)
|
||||
{
|
||||
version = new _COR_VERSION();
|
||||
version.dwMajor = 1; //This is needed to handle v1 exceptions.
|
||||
|
@ -2185,33 +2188,33 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
return COM_HResults.S_OK;
|
||||
}
|
||||
|
||||
int ICorDebugProcess2.GetThreadForTaskID( ulong taskid, out ICorDebugThread2 ppThread )
|
||||
int ICorDebugProcess2.GetThreadForTaskID(ulong taskid, out ICorDebugThread2 ppThread)
|
||||
{
|
||||
ppThread = null;
|
||||
|
||||
return COM_HResults.E_NOTIMPL;
|
||||
}
|
||||
|
||||
int ICorDebugProcess2.SetUnmanagedBreakpoint( ulong address, uint bufsize, byte[] buffer, out uint bufLen )
|
||||
int ICorDebugProcess2.SetUnmanagedBreakpoint(ulong address, uint bufsize, byte[] buffer, out uint bufLen)
|
||||
{
|
||||
bufLen = 0;
|
||||
|
||||
return COM_HResults.E_NOTIMPL;
|
||||
}
|
||||
|
||||
int ICorDebugProcess2.GetDesiredNGENCompilerFlags( out uint pdwFlags )
|
||||
int ICorDebugProcess2.GetDesiredNGENCompilerFlags(out uint pdwFlags)
|
||||
{
|
||||
pdwFlags = 0;
|
||||
|
||||
return COM_HResults.E_NOTIMPL;
|
||||
}
|
||||
|
||||
int ICorDebugProcess2.SetDesiredNGENCompilerFlags( uint pdwFlags )
|
||||
int ICorDebugProcess2.SetDesiredNGENCompilerFlags(uint pdwFlags)
|
||||
{
|
||||
return COM_HResults.E_NOTIMPL;
|
||||
}
|
||||
|
||||
int ICorDebugProcess2.ClearUnmanagedBreakpoint( ulong address )
|
||||
int ICorDebugProcess2.ClearUnmanagedBreakpoint(ulong address)
|
||||
{
|
||||
return COM_HResults.E_NOTIMPL;
|
||||
}
|
||||
|
@ -2277,17 +2280,17 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
{
|
||||
ArrayList appDomains = _appDomains;
|
||||
|
||||
if(!IsAttachedToEngine)
|
||||
if (!IsAttachedToEngine)
|
||||
{
|
||||
//need to fake this in order to get the Attach Dialog to work.
|
||||
DebugAssert( appDomains == null, "Error enumerating programs. AppDomain is null.");
|
||||
DebugAssert(appDomains == null, "Error enumerating programs. AppDomain is null.");
|
||||
appDomains = new ArrayList
|
||||
{
|
||||
new CorDebugAppDomain(this, 1)
|
||||
};
|
||||
}
|
||||
|
||||
ppEnum = new CorDebugEnum( appDomains, typeof( IDebugProgram2 ), typeof( IEnumDebugPrograms2 ) );
|
||||
ppEnum = new CorDebugEnum(appDomains, typeof(IDebugProgram2), typeof(IEnumDebugPrograms2));
|
||||
return COM_HResults.S_OK;
|
||||
}
|
||||
|
||||
|
@ -2330,7 +2333,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
if ((Fields & enum_PROCESS_INFO_FIELDS.PIF_FLAGS) != 0)
|
||||
{
|
||||
if(_executionPaused)
|
||||
if (_executionPaused)
|
||||
pi.Flags = enum_PROCESS_INFO_FLAGS.PIFLAG_PROCESS_STOPPED;
|
||||
else
|
||||
pi.Flags = enum_PROCESS_INFO_FLAGS.PIFLAG_PROCESS_RUNNING;
|
||||
|
@ -2417,23 +2420,23 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
private string GetCommandName(uint cmd)
|
||||
{
|
||||
switch(cmd)
|
||||
switch (cmd)
|
||||
{
|
||||
case Commands.c_Debugging_Execution_BreakpointStatus:
|
||||
return "BreakpointStatus";
|
||||
|
||||
case Commands.c_Debugging_Execution_QueryCLRCapabilities:
|
||||
return "QueryCLRCapabilities";
|
||||
|
||||
|
||||
case Commands.c_Debugging_Execution_Allocate:
|
||||
return "Allocate";
|
||||
|
||||
|
||||
case Commands.c_Debugging_Execution_ChangeConditions:
|
||||
return "ChangeConditions";
|
||||
|
||||
default:
|
||||
return $"0x{cmd:X8}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
//
|
||||
// Copyright (c) .NET Foundation and Contributors
|
||||
// See LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using GalaSoft.MvvmLight.Ioc;
|
||||
using Microsoft.VisualStudio.ProjectSystem;
|
||||
using Microsoft.VisualStudio.ProjectSystem.Debug;
|
||||
using Microsoft.VisualStudio.ProjectSystem.VS.Debug;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
using nanoFramework.Tools.VisualStudio.Extension.ToolWindow.ViewModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using GalaSoft.MvvmLight.Ioc;
|
||||
using Microsoft.VisualStudio.ProjectSystem;
|
||||
using Microsoft.VisualStudio.ProjectSystem.Debug;
|
||||
using Microsoft.VisualStudio.ProjectSystem.VS.Debug;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
using nanoFramework.Tools.Debugger.NFDevice;
|
||||
using nanoFramework.Tools.VisualStudio.Extension.ToolWindow.ViewModel;
|
||||
|
||||
namespace nanoFramework.Tools.VisualStudio.Extension
|
||||
{
|
||||
|
@ -22,6 +21,8 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
[AppliesTo(NanoCSharpProjectUnconfigured.UniqueCapability)]
|
||||
internal partial class NanoDebuggerLaunchProvider : DebugLaunchProviderBase
|
||||
{
|
||||
private const int ExclusiveAccessTimeout = 3000;
|
||||
|
||||
private static AssemblyInformationalVersionAttribute _informationalVersionAttribute;
|
||||
|
||||
[ImportingConstructor]
|
||||
|
@ -50,35 +51,62 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
// get device
|
||||
var device = SimpleIoc.Default.GetInstance<DeviceExplorerViewModel>().SelectedDevice;
|
||||
|
||||
// check for debug engine
|
||||
if (device.DebugEngine == null)
|
||||
var exclusiveAccess = GlobalExclusiveDeviceAccess.TryGet(device, ExclusiveAccessTimeout);
|
||||
if (exclusiveAccess is null)
|
||||
{
|
||||
device.CreateDebugEngine();
|
||||
#pragma warning disable S112 // OK to use Exception here
|
||||
throw new Exception($"Can't get access to {deployDeviceName}, another application is using the device!");
|
||||
#pragma warning restore S112 // General exceptions should never be thrown
|
||||
}
|
||||
|
||||
// update stack trace processing option
|
||||
device.DebugEngine.NoStackTraceInExceptions = !NanoFrameworkPackage.DebuggingOptions.ProcessStackTraceOption;
|
||||
|
||||
// make sure that the device is connected
|
||||
if (device.DebugEngine.Connect(
|
||||
false,
|
||||
true))
|
||||
else
|
||||
{
|
||||
string commandLine = await GetCommandLineForLaunchAsync();
|
||||
commandLine = string.Format("{0} \"{1}{2}\"", commandLine, CorDebugProcess.DeployDeviceName, deployDeviceName);
|
||||
var stopDebugEngine = true;
|
||||
|
||||
var settings = new DebugLaunchSettings(launchOptions)
|
||||
try
|
||||
{
|
||||
Executable = typeof(CorDebugProcess).Assembly.Location,
|
||||
Arguments = commandLine,
|
||||
LaunchOperation = DebugLaunchOperation.CreateProcess,
|
||||
PortSupplierGuid = DebugPortSupplier.PortSupplierGuid,
|
||||
PortName = NanoFrameworkPackage.NanoDeviceCommService.Device.Description,
|
||||
Project = VsHierarchy,
|
||||
LaunchDebugEngineGuid = CorDebug.EngineGuid
|
||||
};
|
||||
// check for debug engine
|
||||
if (device.DebugEngine == null)
|
||||
{
|
||||
device.CreateDebugEngine();
|
||||
}
|
||||
|
||||
return new IDebugLaunchSettings[] { settings };
|
||||
// update stack trace processing option
|
||||
device.DebugEngine.NoStackTraceInExceptions = !NanoFrameworkPackage.DebuggingOptions.ProcessStackTraceOption;
|
||||
|
||||
// make sure that the device is connected
|
||||
if (device.DebugEngine.Connect(
|
||||
false,
|
||||
true))
|
||||
{
|
||||
string commandLine = await GetCommandLineForLaunchAsync();
|
||||
commandLine = string.Format("{0} \"{1}{2}\"", commandLine, CorDebugProcess.DeployDeviceName, deployDeviceName);
|
||||
|
||||
var settings = new DebugLaunchSettings(launchOptions)
|
||||
{
|
||||
Executable = typeof(CorDebugProcess).Assembly.Location,
|
||||
Arguments = commandLine,
|
||||
LaunchOperation = DebugLaunchOperation.CreateProcess,
|
||||
PortSupplierGuid = DebugPortSupplier.PortSupplierGuid,
|
||||
PortName = NanoFrameworkPackage.NanoDeviceCommService.Device.Description,
|
||||
Project = VsHierarchy,
|
||||
LaunchDebugEngineGuid = CorDebug.EngineGuid
|
||||
};
|
||||
|
||||
stopDebugEngine = false;
|
||||
return new IDebugLaunchSettings[] { settings };
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (stopDebugEngine)
|
||||
{
|
||||
// On success, the debug engine does not have to be stopped, it will be stopped in the CorDebugProcess
|
||||
// and the global exclusive access is terminated there.
|
||||
device.DebugEngine?.Stop();
|
||||
}
|
||||
|
||||
exclusiveAccess?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable S112 // OK to use Exception here
|
||||
|
|
|
@ -1,16 +1,6 @@
|
|||
//
|
||||
// Copyright (c) .NET Foundation and Contributors
|
||||
// Portions Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// See LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using ICSharpCode.Decompiler;
|
||||
using ICSharpCode.Decompiler.CSharp;
|
||||
using Microsoft.VisualStudio.ProjectSystem;
|
||||
using Microsoft.VisualStudio.ProjectSystem.Build;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
using nanoFramework.Tools.Debugger;
|
||||
using nanoFramework.Tools.VisualStudio.Extension.ToolWindow.ViewModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
|
@ -19,6 +9,14 @@ using System.Linq;
|
|||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using ICSharpCode.Decompiler;
|
||||
using ICSharpCode.Decompiler.CSharp;
|
||||
using Microsoft.VisualStudio.ProjectSystem;
|
||||
using Microsoft.VisualStudio.ProjectSystem.Build;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
using nanoFramework.Tools.Debugger;
|
||||
using nanoFramework.Tools.Debugger.NFDevice;
|
||||
using nanoFramework.Tools.VisualStudio.Extension.ToolWindow.ViewModel;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
|
||||
namespace nanoFramework.Tools.VisualStudio.Extension
|
||||
|
@ -27,6 +25,8 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
[AppliesTo(NanoCSharpProjectUnconfigured.UniqueCapability)]
|
||||
internal class DeployProvider : IDeployProvider
|
||||
{
|
||||
private const int ExclusiveAccessTimeout = 3000;
|
||||
|
||||
private static ViewModelLocator _viewModelLocator;
|
||||
|
||||
private static Package _package;
|
||||
|
@ -126,6 +126,12 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
bool needsToCloseMessageOutput = false;
|
||||
|
||||
// Get exclusive access to the device, but don't wait forever
|
||||
MessageCentre.InternalErrorWriteLine("Try to get exclusive access to the nanoDevice");
|
||||
|
||||
using var exclusiveAccess = GlobalExclusiveDeviceAccess.TryGet(device, ExclusiveAccessTimeout)
|
||||
?? throw new DeploymentException($"Couldn't access the device {device.Description}, it is used by another application!");
|
||||
|
||||
try
|
||||
{
|
||||
MessageCentre.InternalErrorWriteLine("Starting debug engine on nanoDevice");
|
||||
|
@ -404,6 +410,8 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
}
|
||||
finally
|
||||
{
|
||||
device.DebugEngine?.Stop();
|
||||
|
||||
MessageCentre.StopProgressMessage();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
//
|
||||
// Copyright (c) .NET Foundation and Contributors
|
||||
// See LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using nanoFramework.Tools.Debugger;
|
||||
using nanoFramework.Tools.Debugger.WireProtocol;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using nanoFramework.Tools.Debugger;
|
||||
using nanoFramework.Tools.Debugger.WireProtocol;
|
||||
|
||||
namespace nanoFramework.Tools.VisualStudio.Extension
|
||||
{
|
||||
|
@ -22,7 +20,5 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
bool SelectDevice(string description);
|
||||
|
||||
TaskAwaiter GetAwaiter();
|
||||
|
||||
bool ConnectTo(string description = null, int timeout = 5000);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
//
|
||||
// Copyright (c) .NET Foundation and Contributors
|
||||
// See LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using nanoFramework.Tools.Debugger;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using nanoFramework.Tools.Debugger;
|
||||
|
||||
namespace nanoFramework.Tools.VisualStudio.Extension
|
||||
{
|
||||
|
@ -84,17 +82,5 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool ConnectTo(string deviceId = null, int timeout = 5000)
|
||||
{
|
||||
if (deviceId == null)
|
||||
{
|
||||
return Device.DebugEngine.Connect(timeout, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
return DebugClient.NanoFrameworkDevices.FirstOrDefault(d => d.Description == deviceId).DebugEngine.Connect(timeout, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
//
|
||||
// Copyright (c) .NET Foundation and Contributors
|
||||
// See LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.Design;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using GalaSoft.MvvmLight.Ioc;
|
||||
using GalaSoft.MvvmLight.Messaging;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
using nanoFramework.Tools.Debugger;
|
||||
using nanoFramework.Tools.Debugger.Extensions;
|
||||
using nanoFramework.Tools.Debugger.NFDevice;
|
||||
using nanoFramework.Tools.Debugger.WireProtocol;
|
||||
using nanoFramework.Tools.VisualStudio.Extension.ToolWindow.ViewModel;
|
||||
using System;
|
||||
using System.ComponentModel.Design;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
|
||||
namespace nanoFramework.Tools.VisualStudio.Extension
|
||||
|
@ -83,6 +82,9 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
public const int ShowInternalErrorsCommandID = 0x0300;
|
||||
public const int ShowSettingsCommandID = 0x0420;
|
||||
|
||||
// Timeout for exclusive access
|
||||
private const int ExclusiveAccessTimeout = 3000;
|
||||
|
||||
INanoDeviceCommService NanoDeviceCommService;
|
||||
OleMenuCommandService MenuCommandService;
|
||||
|
||||
|
@ -301,6 +303,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
var descriptionBackup = ViewModelLocator.DeviceExplorer.SelectedDevice.Description;
|
||||
|
||||
MessageCentre.StartProgressMessage($"Pinging {descriptionBackup}...");
|
||||
GlobalExclusiveDeviceAccess exclusiveAccess = null;
|
||||
try
|
||||
{
|
||||
// disable buttons
|
||||
|
@ -309,6 +312,14 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
// make sure this device is showing as selected in Device Explorer tree view
|
||||
ViewModelLocator.DeviceExplorer.ForceNanoDeviceSelection();
|
||||
|
||||
// Get exclusive access to the device, but don't wait forever
|
||||
exclusiveAccess = GlobalExclusiveDeviceAccess.TryGet(ViewModelLocator.DeviceExplorer.SelectedDevice, ExclusiveAccessTimeout);
|
||||
if (exclusiveAccess is null)
|
||||
{
|
||||
MessageCentre.OutputMessage($"Cannot access {descriptionBackup}, another application is using the device.");
|
||||
return;
|
||||
}
|
||||
|
||||
// check if debugger engine exists
|
||||
if (NanoDeviceCommService.Device.DebugEngine == null)
|
||||
{
|
||||
|
@ -348,6 +359,8 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
// disconnect device
|
||||
NanoDeviceCommService.Device?.DebugEngine?.Stop(true);
|
||||
|
||||
exclusiveAccess?.Dispose();
|
||||
|
||||
// enable buttons
|
||||
await UpdateDeviceDependentToolbarButtonsAsync(true);
|
||||
|
||||
|
@ -375,6 +388,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
await Task.Run(async delegate
|
||||
{
|
||||
GlobalExclusiveDeviceAccess exclusiveAccess = null;
|
||||
try
|
||||
{
|
||||
// disable buttons
|
||||
|
@ -386,6 +400,14 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
// only query device if it's different
|
||||
if (descriptionBackup.GetHashCode() != ViewModelLocator.DeviceExplorer.LastDeviceConnectedHash)
|
||||
{
|
||||
// Get exclusive access to the device, but don't wait forever
|
||||
exclusiveAccess = GlobalExclusiveDeviceAccess.TryGet(ViewModelLocator.DeviceExplorer.SelectedDevice, ExclusiveAccessTimeout);
|
||||
if (exclusiveAccess is null)
|
||||
{
|
||||
MessageCentre.OutputMessage($"Cannot access {descriptionBackup}, another application is using the device.");
|
||||
return;
|
||||
}
|
||||
|
||||
// check if debugger engine exists
|
||||
if (NanoDeviceCommService.Device.DebugEngine == null)
|
||||
{
|
||||
|
@ -543,6 +565,8 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
// disconnect device
|
||||
NanoDeviceCommService.Device?.DebugEngine?.Stop(true);
|
||||
|
||||
exclusiveAccess?.Dispose();
|
||||
|
||||
// enable buttons
|
||||
await UpdateDeviceDependentToolbarButtonsAsync(true);
|
||||
|
||||
|
@ -574,6 +598,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
await Task.Run(async delegate
|
||||
{
|
||||
GlobalExclusiveDeviceAccess exclusiveAccess = null;
|
||||
try
|
||||
{
|
||||
// disable buttons
|
||||
|
@ -582,6 +607,14 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
// make sure this device is showing as selected in Device Explorer tree view
|
||||
ViewModelLocator.DeviceExplorer.ForceNanoDeviceSelection();
|
||||
|
||||
// Get exclusive access to the device, but don't wait forever
|
||||
exclusiveAccess = GlobalExclusiveDeviceAccess.TryGet(ViewModelLocator.DeviceExplorer.SelectedDevice, ExclusiveAccessTimeout);
|
||||
if (exclusiveAccess is null)
|
||||
{
|
||||
MessageCentre.OutputMessage($"Cannot access {descriptionBackup}, another application is using the device.");
|
||||
return;
|
||||
}
|
||||
|
||||
// check if debugger engine exists
|
||||
if (NanoDeviceCommService.Device.DebugEngine == null)
|
||||
{
|
||||
|
@ -639,6 +672,8 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
// disconnect device
|
||||
NanoDeviceCommService.Device?.DebugEngine?.Stop(true);
|
||||
|
||||
exclusiveAccess?.Dispose();
|
||||
|
||||
// enable buttons
|
||||
await UpdateDeviceDependentToolbarButtonsAsync(true);
|
||||
|
||||
|
@ -665,6 +700,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
await Task.Run(async delegate
|
||||
{
|
||||
GlobalExclusiveDeviceAccess exclusiveAccess = null;
|
||||
try
|
||||
{
|
||||
// disable buttons
|
||||
|
@ -673,6 +709,17 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
// make sure this device is showing as selected in Device Explorer tree view
|
||||
ViewModelLocator.DeviceExplorer.ForceNanoDeviceSelection();
|
||||
|
||||
// Get exclusive access to the device, but don't wait forever
|
||||
exclusiveAccess = GlobalExclusiveDeviceAccess.TryGet(ViewModelLocator.DeviceExplorer.SelectedDevice, ExclusiveAccessTimeout);
|
||||
if (exclusiveAccess is null)
|
||||
{
|
||||
_ = MessageBox.Show($"Cannot access {ViewModelLocator.DeviceExplorer.SelectedDevice.Description}, another application is using the device.",
|
||||
".NET nanoFramework Device Explorer",
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if debugger engine exists
|
||||
if (NanoDeviceCommService.Device.DebugEngine == null)
|
||||
{
|
||||
|
@ -761,6 +808,8 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
// disconnect device
|
||||
NanoDeviceCommService.Device?.DebugEngine?.Stop(true);
|
||||
|
||||
exclusiveAccess?.Dispose();
|
||||
|
||||
// enable buttons
|
||||
await UpdateDeviceDependentToolbarButtonsAsync(true);
|
||||
|
||||
|
@ -785,6 +834,7 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
|
||||
await Task.Run(async delegate
|
||||
{
|
||||
GlobalExclusiveDeviceAccess exclusiveAccess = null;
|
||||
try
|
||||
{
|
||||
// disable buttons
|
||||
|
@ -793,6 +843,14 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
// make sure this device is showing as selected in Device Explorer tree view
|
||||
ViewModelLocator.DeviceExplorer.ForceNanoDeviceSelection();
|
||||
|
||||
// Get exclusive access to the device, but don't wait forever
|
||||
exclusiveAccess = GlobalExclusiveDeviceAccess.TryGet(ViewModelLocator.DeviceExplorer.SelectedDevice, ExclusiveAccessTimeout);
|
||||
if (exclusiveAccess is null)
|
||||
{
|
||||
MessageCentre.OutputMessage($"Cannot access {ViewModelLocator.DeviceExplorer.SelectedDevice.Description}, another application is using the device.");
|
||||
return;
|
||||
}
|
||||
|
||||
// check if debugger engine exists
|
||||
if (NanoDeviceCommService.Device.DebugEngine == null)
|
||||
{
|
||||
|
@ -881,6 +939,8 @@ namespace nanoFramework.Tools.VisualStudio.Extension
|
|||
// disconnect device
|
||||
NanoDeviceCommService.Device?.DebugEngine?.Stop(true);
|
||||
|
||||
exclusiveAccess?.Dispose();
|
||||
|
||||
// enable buttons
|
||||
await UpdateDeviceDependentToolbarButtonsAsync(true);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче