diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..a5a9d5f --- /dev/null +++ b/.editorconfig @@ -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 \ No newline at end of file diff --git a/.github/.changelog-config.json b/.github/.changelog-config.json index 60c9504..d969d52 100644 --- a/.github/.changelog-config.json +++ b/.github/.changelog-config.json @@ -37,7 +37,7 @@ } ], "sort": "ASC", - "template": "${{CHANGELOG}}\n\n**Full Changelog:** ${{RELEASE_DIFF}}\n\nThe following NuGet package is available from this release:\n\n:package: [nanoFramework.Devices.Can](https://www.nuget.org/packages/nanoFramework.Devices.Can/)", + "template": "${{CHANGELOG}}\n\n**Full Changelog:** ${{RELEASE_DIFF}}\n\nThe following NuGet packages are available from this release:\n\n:package: [nanoFramework.Devices.Can.Core](https://www.nuget.org/packages/nanoFramework.Devices.Can.Core/)\n:package: [nanoFramework.Device.Can.Stm32](https://www.nuget.org/packages/nanoFramework.Devices.Can.Stm32/)", "pr_template": "* ${{TITLE}} by @${{AUTHOR}} in #${{NUMBER}}", "empty_template": "- no changes", "max_tags_to_fetch": 200, diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 04974da..644b2ae 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -10,6 +10,8 @@ jobs: check_package_lock: name: nanoFramework uses: nanoframework/nf-tools/.github/workflows/check-package-lock.yml@main + with: + solution: 'nanoFramework.Device.Can.sln' check_nuget_latest: name: nanoFramework uses: nanoframework/nf-tools/.github/workflows/check-packages-updated.yml@main diff --git a/.github/workflows/update-dependencies.yml b/.github/workflows/update-dependencies.yml index 572a883..654dc41 100644 --- a/.github/workflows/update-dependencies.yml +++ b/.github/workflows/update-dependencies.yml @@ -7,7 +7,7 @@ name: Daily update dependencies on: schedule: - # At 00:10 UTC. + # At 00:10 UTC. - cron: '10 00 * * Wed,Fri' repository_dispatch: types: update-dependencies @@ -18,4 +18,5 @@ jobs: uses: nanoframework/nf-tools/.github/workflows/update-dependencies.yml@main secrets: inherit with: - solutionsToCheck: 'nanoFramework.Device.Can.sln' + solutionsToCheck: | + nanoFramework.Device.Can.sln diff --git a/README.md b/README.md index f177bdb..ae706a6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=nanoframework_lib-nanoFramework.Devices.Can&metric=alert_status)](https://sonarcloud.io/dashboard?id=nanoframework_lib-nanoFramework.Devices.Can) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=nanoframework_lib-nanoFramework.Devices.Can&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=nanoframework_lib-nanoFramework.Devices.Can) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![NuGet](https://img.shields.io/nuget/dt/nanoFramework.Device.Can.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.Device.Can/) [![#yourfirstpr](https://img.shields.io/badge/first--timers--only-friendly-blue.svg)](https://github.com/nanoframework/Home/blob/main/CONTRIBUTING.md) [![Discord](https://img.shields.io/discord/478725473862549535.svg?logo=discord&logoColor=white&label=Discord&color=7289DA)](https://discord.gg/gCyBu8T) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=nanoframework_lib-nanoFramework.Devices.Can&metric=alert_status)](https://sonarcloud.io/dashboard?id=nanoframework_lib-nanoFramework.Devices.Can) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=nanoframework_lib-nanoFramework.Devices.Can&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=nanoframework_lib-nanoFramework.Devices.Can) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![NuGet](https://img.shields.io/nuget/dt/nanoFramework.Device.Can.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.Device.Can/) [![#yourfirstpr](https://img.shields.io/badge/first--timers--only-friendly-blue.svg)](https://github.com/nanoframework/Home/blob/main/CONTRIBUTING.md) [![Discord](https://img.shields.io/discord/478725473862549535.svg?logo=discord&logoColor=white&label=Discord&color=7289DA)](https://discord.gg/gCyBu8T) ![nanoFramework logo](https://raw.githubusercontent.com/nanoframework/Home/main/resources/logo/nanoFramework-repo-logo.png) @@ -6,11 +6,28 @@ ### Welcome to the .NET **nanoFramework** CAN Class Library repository +These libraries are the successor of the `nanoFramework.Device.Can` class library that required a native component and was available for two STM32-based boards. The direct replacement of that library is `nanoFramework.Device.Can.Stm32`. + ## Build status | Component | Build Status | NuGet Package | |:-|---|---| -| nanoFramework.Device.Can | [![Build Status](https://dev.azure.com/nanoframework/nanoFramework.Device.Can/_apis/build/status/nanoFramework.Device.Can?repoName=nanoframework%2FnanoFramework.Device.Can&branchName=main)](https://dev.azure.com/nanoframework/nanoFramework.Device.Can/_build/latest?definitionId=25&repoName=nanoframework%2FnanoFramework.Device.Can&branchName=main) | [![NuGet](https://img.shields.io/nuget/v/nanoFramework.Device.Can.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.Device.Can/) | +| nanoFramework.Device.Can.Core | [![Build Status](https://dev.azure.com/nanoframework/nanoFramework.Device.Can/_apis/build/status/nanoFramework.Device.Can?repoName=nanoframework%2FnanoFramework.Device.Can&branchName=main)](https://dev.azure.com/nanoframework/nanoFramework.Device.Can/_build/latest?definitionId=25&repoName=nanoframework%2FnanoFramework.Device.Can&branchName=main) | [![NuGet](https://img.shields.io/nuget/v/nanoFramework.Device.Can.Core.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.Device.Can.Core/) | +| nanoFramework.Device.Can.Esp32 | [![Build Status](https://dev.azure.com/nanoframework/nanoFramework.Device.Can/_apis/build/status/nanoFramework.Device.Can?repoName=nanoframework%2FnanoFramework.Device.Can&branchName=main)](https://dev.azure.com/nanoframework/nanoFramework.Device.Can/_build/latest?definitionId=25&repoName=nanoframework%2FnanoFramework.Device.Can&branchName=main) | [![NuGet](https://img.shields.io/nuget/v/nanoFramework.Device.Can.Esp32.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.Device.Can.Esp32/) | +| nanoFramework.Device.Can.Mcp2515 | [![Build Status](https://dev.azure.com/nanoframework/nanoFramework.Device.Can/_apis/build/status/nanoFramework.Device.Can?repoName=nanoframework%2FnanoFramework.Device.Can&branchName=main)](https://dev.azure.com/nanoframework/nanoFramework.Device.Can/_build/latest?definitionId=25&repoName=nanoframework%2FnanoFramework.Device.Can&branchName=main) | [![NuGet](https://img.shields.io/nuget/v/nanoFramework.Device.Can.Mc2515.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.Device.Can.Mcp2515/) | +| nanoFramework.Device.Can.Stm32 | [![Build Status](https://dev.azure.com/nanoframework/nanoFramework.Device.Can/_apis/build/status/nanoFramework.Device.Can?repoName=nanoframework%2FnanoFramework.Device.Can&branchName=main)](https://dev.azure.com/nanoframework/nanoFramework.Device.Can/_build/latest?definitionId=25&repoName=nanoframework%2FnanoFramework.Device.Can&branchName=main) | [![NuGet](https://img.shields.io/nuget/v/nanoFramework.Device.Can.Stm32.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.Device.Can.Stm32/) | + +## The .NET **nanoFramework** CAN Class Libraries + +To exchange CAN messages by a .NET **nanoFramework** application, at least one device dependent class library is required: + +- `nanoFramework.Device.Can.Esp32` uses the CAN/TWAI implementation of an ESP32 microcontroller. This requires a matching firmware/target version for the microcontroller that provides the native part of the implementation. In general an external CAN transceiver is also required. +- `nanoFramework.Device.Can.Stm` uses the CAN implementation of a STM32 microcontroller. This requires a matching firmware/target version for the microcontroller that provides the native part of the implementation. In general an external CAN transceiver is also required. +- `nanoFramework.Device.Can.Mcp2515` uses an external CAN device based on the MCP2515 chip. It is a 100% .NET implementation that works with every microcontroller, and can be used in combination with the ESP32 or STM32 library. MCP2515 boards typically include a CAN transceiver. + +All device dependent libraries are based on: + +- `nanoFramework.Device.Can.Core` contains the common classes and interfaces. As the `nanoFramework.Device.Can` namespace implements the basic ISO 11898 CAN message transfer, this library can be used to implement higher-level protocols (e.g., CAN-TP or ISO-TP as used in ODB II) in device independent libraries. ## Feedback and documentation diff --git a/Stub-generation.md b/Stub-generation.md new file mode 100644 index 0000000..9ff5d27 --- /dev/null +++ b/Stub-generation.md @@ -0,0 +1,5 @@ +# Stub generation + +The libraries that require a native components generate a stub for the native part on each build. The stub is placed in, e.g., the `nanoFramework.Device.Can.Stm32\bin\Release\Stubs` directory. + +The native component will probably require access to the common classes in `nanoFramework.Device.Can.Core`. As that library is pure .NET, no stub is required. To generate the stub, select the **GenerateStub** configuration (instead of *Debug* or *Release*) in the *nanoFramework.Device.Can.sln* solution and build the solution. The stub will be placed in the `nanoFramework.Device.Can.Core\bin'\GenerateStubs\Stubs` directory. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1acb88a..89d195f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -17,6 +17,10 @@ trigger: - assets/* - .github/* + tags: + include: + - v* + # PR always trigger build pr: autoCancel: true @@ -29,34 +33,137 @@ resources: name: nanoframework/nf-tools endpoint: nanoframework -pool: - vmImage: 'windows-latest' - variables: - - group: sign-client-credentials - name: DOTNET_NOLOGO - value: true - - name: buildPlatform - value: 'Any CPU' - - name: buildConfiguration - value: 'Release' - - name: solution - value: 'nanoFramework.Device.Can.sln' - - name: nugetPackageName - value: 'nanoFramework.Device.Can' - -steps: - -# step from template @ nf-tools repo -# all build, update and publish steps -- template: azure-pipelines-templates/class-lib-build.yml@templates - parameters: - sonarCloudProject: 'nanoframework_lib-nanoFramework.Devices.Can' - -# step from template @ nf-tools repo -# report error -- template: azure-pipelines-templates/discord-webhook-task.yml@templates - parameters: - status: 'failure' - webhookUrl: '$(DiscordWebhook)' - message: '' + value: true + +jobs: + +############################## +- job: Build_Library + condition: >- + and( + not(startsWith(variables['Build.SourceBranch'], 'refs/tags/v')), + or( + eq(variables['UPDATE_DEPENDENTS'], 'false'), + eq(variables['StartReleaseCandidate'], 'true') + ) + ) + pool: + vmImage: 'windows-latest' + + variables: + - group: sign-client-credentials + - name: buildPlatform + value: 'Any CPU' + - name: buildConfiguration + value: 'Release' + - name: solution + value: 'nanoFramework.Device.Can.sln' + + steps: + + # build step only + - template: azure-pipelines-templates/class-lib-build-only.yml@templates + parameters: + sonarCloudProject: 'nanoframework_lib-nanoFramework.Devices.Can' + runUnitTests: false + unitTestRunsettings: '$(System.DefaultWorkingDirectory)\.runsettings' + + # build the 4 libs step + - template: azure-pipelines-templates/class-lib-package.yml@templates + parameters: + nugetPackageName: 'nanoFramework.Device.Can.Core' + + #- template: azure-pipelines-templates/class-lib-package.yml@templates + # parameters: + # nugetPackageName: 'nanoFramework.Device.Can.Esp32' + + #- template: azure-pipelines-templates/class-lib-package.yml@templates + # parameters: + # nugetPackageName: 'nanoFramework.Device.Can.Mcp2515' + + - template: azure-pipelines-templates/class-lib-package.yml@templates + parameters: + nugetPackageName: 'nanoFramework.Device.Can.Stm32' + + # publish the libs + - template: azure-pipelines-templates/class-lib-publish.yml@templates + + # create GitHub release build from main branch + - task: GithubRelease@1 + condition: >- + and( + succeeded(), + eq(variables['System.PullRequest.PullRequestId'], ''), + startsWith(variables['Build.SourceBranch'], 'refs/heads/main'), + not(contains(variables['Build.SourceBranch'], 'preview')), + eq(variables['StartReleaseCandidate'], false) + ) + displayName: Create/Update GitHub release + inputs: + action: edit + gitHubConnection: 'github.com_nano-$(System.TeamProject)' + tagSource: userSpecifiedTag + tag: v$(MY_NUGET_VERSION) + title: 'nanoFramework.Device.Can Library v$(MY_NUGET_VERSION)' + releaseNotesSource: inline + releaseNotesInline: 'Check the [changelog]($(Build.Repository.Uri)/blob/$(Build.SourceBranchName)/CHANGELOG.md).

Install from NuGet


The following NuGet packages are available for download from this release:
:package: [nanoFramework.Device.Can.Core](https://www.nuget.org/packages/nanoFramework.Device.Can.Core/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION).
:package: [nanoFramework.Device.Can.Esp32](https://www.nuget.org/packages/nanoFramework.Device.Can.Esp32/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION).
:package: [nanoFramework.Device.Can.Mcp2515](https://www.nuget.org/packages/nanoFramework.Device.Can.Mcp2515/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION).
:package: [nanoFramework.Device.Can.Stm32](https://www.nuget.org/packages/nanoFramework.Device.Can.Stm32/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION).' + assets: '$(Build.ArtifactStagingDirectory)/*.nupkg' + assetUploadMode: replace + isPreRelease: false + addChangeLog: false + +############################## +- job: Update_Dependents + condition: >- + or( + and( + startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), + eq(variables['StartReleaseCandidate'], 'false') + ), + and( + contains(variables['getCommitMessage.COMMIT_MESSAGE'], '***UPDATE_DEPENDENTS***'), + eq(variables['StartReleaseCandidate'], 'false') + ), + eq(variables['UPDATE_DEPENDENTS'], 'true') + ) + + pool: + vmImage: 'windows-latest' + + variables: + DOTNET_NOLOGO: true + + steps: + # need this here in order to persist GitHub credentials + - checkout: self + fetchDepth: 1 + +################################## +# report build failure to Discord +- job: Report_Build_Failure + + dependsOn: + - Build_Library + - Update_Dependents + condition: >- + or( + failed('Build_Library'), + failed('Update_Dependents') + ) + + pool: + vmImage: 'windows-latest' + + steps: + + - checkout: self + + # step from template @ nf-tools repo + # report error + - template: azure-pipelines-templates/discord-webhook-task.yml@templates + parameters: + status: 'failure' + webhookUrl: '$(DiscordWebhook)' + message: '' diff --git a/nanoFramework.Device.Can.nuspec b/nanoFramework.Device.Can.Core.nuspec similarity index 55% rename from nanoFramework.Device.Can.nuspec rename to nanoFramework.Device.Can.Core.nuspec index 1c078c4..ba6a94e 100644 --- a/nanoFramework.Device.Can.nuspec +++ b/nanoFramework.Device.Can.Core.nuspec @@ -1,9 +1,9 @@ - nanoFramework.Device.Can + nanoFramework.Device.Can.Core $version$ - nanoFramework.Device.Can + nanoFramework.Device.Can.Core nanoframework false LICENSE.md @@ -15,20 +15,19 @@ images\nf-logo.png Copyright (c) .NET Foundation and Contributors - This package includes the nanoFramework.Device.Can assembly for .NET nanoFramework C# projects. -This package requires a target with nanoFramework.Device.Can v$nativeVersion$ (checksum $checksum$). + This package includes the nanoFramework.Device.Can.Core assembly for .NET nanoFramework C# projects. +It contains the device-independent part of the implementation of the nanoFramework.Device.Can namespace. nanoFramework C# csharp netmf netnf canbus can - - - - - - + + + + + diff --git a/nanoFramework.Device.Can/CanController.cs b/nanoFramework.Device.Can.Core/CanController.cs similarity index 100% rename from nanoFramework.Device.Can/CanController.cs rename to nanoFramework.Device.Can.Core/CanController.cs diff --git a/nanoFramework.Device.Can/CanControllerEventListener.cs b/nanoFramework.Device.Can.Core/CanControllerEventListener.cs similarity index 100% rename from nanoFramework.Device.Can/CanControllerEventListener.cs rename to nanoFramework.Device.Can.Core/CanControllerEventListener.cs diff --git a/nanoFramework.Device.Can/CanControllerManager.cs b/nanoFramework.Device.Can.Core/CanControllerManager.cs similarity index 100% rename from nanoFramework.Device.Can/CanControllerManager.cs rename to nanoFramework.Device.Can.Core/CanControllerManager.cs diff --git a/nanoFramework.Device.Can/CanEvent.cs b/nanoFramework.Device.Can.Core/CanEvent.cs similarity index 100% rename from nanoFramework.Device.Can/CanEvent.cs rename to nanoFramework.Device.Can.Core/CanEvent.cs diff --git a/nanoFramework.Device.Can/CanMessage.cs b/nanoFramework.Device.Can.Core/CanMessage.cs similarity index 100% rename from nanoFramework.Device.Can/CanMessage.cs rename to nanoFramework.Device.Can.Core/CanMessage.cs diff --git a/nanoFramework.Device.Can/CanMessageEvent.cs b/nanoFramework.Device.Can.Core/CanMessageEvent.cs similarity index 100% rename from nanoFramework.Device.Can/CanMessageEvent.cs rename to nanoFramework.Device.Can.Core/CanMessageEvent.cs diff --git a/nanoFramework.Device.Can/CanMessageFrameType.cs b/nanoFramework.Device.Can.Core/CanMessageFrameType.cs similarity index 100% rename from nanoFramework.Device.Can/CanMessageFrameType.cs rename to nanoFramework.Device.Can.Core/CanMessageFrameType.cs diff --git a/nanoFramework.Device.Can/CanMessageIdType.cs b/nanoFramework.Device.Can.Core/CanMessageIdType.cs similarity index 100% rename from nanoFramework.Device.Can/CanMessageIdType.cs rename to nanoFramework.Device.Can.Core/CanMessageIdType.cs diff --git a/nanoFramework.Device.Can/CanMessageReceivedEventArgs.cs b/nanoFramework.Device.Can.Core/CanMessageReceivedEventArgs.cs similarity index 100% rename from nanoFramework.Device.Can/CanMessageReceivedEventArgs.cs rename to nanoFramework.Device.Can.Core/CanMessageReceivedEventArgs.cs diff --git a/nanoFramework.Device.Can/CanSettings.cs b/nanoFramework.Device.Can.Core/CanSettings.cs similarity index 100% rename from nanoFramework.Device.Can/CanSettings.cs rename to nanoFramework.Device.Can.Core/CanSettings.cs diff --git a/nanoFramework.Device.Can.Core/Properties/AssemblyInfo.cs b/nanoFramework.Device.Can.Core/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b4e7a5c --- /dev/null +++ b/nanoFramework.Device.Can.Core/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("nanoFramework.Device.Can.Core")] +[assembly: AssemblyCompany("nanoFramework Contributors")] +[assembly: AssemblyProduct("nanoFramework.Device.Can.Core")] +[assembly: AssemblyCopyright("Copyright (c) .NET Foundation and Contributors")] + +#if STUBGENERATION +//////////////////////////////////////////////////////////////// +// update this whenever the native assembly signature changes // +[assembly: AssemblyNativeVersion("100.1.0.0")] +//////////////////////////////////////////////////////////////// +#endif + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] diff --git a/nanoFramework.Device.Can/key.snk b/nanoFramework.Device.Can.Core/key.snk similarity index 100% rename from nanoFramework.Device.Can/key.snk rename to nanoFramework.Device.Can.Core/key.snk diff --git a/nanoFramework.Device.Can.Core/nanoFramework.Device.Can.Core.nfproj b/nanoFramework.Device.Can.Core/nanoFramework.Device.Can.Core.nfproj new file mode 100644 index 0000000..0595177 --- /dev/null +++ b/nanoFramework.Device.Can.Core/nanoFramework.Device.Can.Core.nfproj @@ -0,0 +1,102 @@ + + + + + + Debug + AnyCPU + + + GenerateStubs + AnyCPU + + + Release + AnyCPU + + + StubGeneration + AnyCPU + + + + $(MSBuildExtensionsPath)\nanoFramework\v1.0\ + + + + Debug + AnyCPU + {11A8DD76-328B-46DF-9F39-F559912D0360};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 99ca76e4-d76f-42c9-9e62-49c2f499aa02 + Library + Properties + 512 + nanoFramework.Device.Can + nanoFramework.Device.Can.Core + v1.0 + bin\$(Configuration)\nanoFramework.Device.Can.Core.xml + true + true + + + true + + + key.snk + + + false + + + True + $(DefineConstants);STUBGENERATION + + + bin\$(Configuration)\Stubs + nf_device_can_core_native + nanoFramework.Device.Can.Core + + + + false + + + + + + + + + + + + + + + + + + + + + + + + ..\packages\nanoFramework.CoreLibrary.1.16.11\lib\mscorlib.dll + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/nanoFramework.Device.Can/packages.config b/nanoFramework.Device.Can.Core/packages.config similarity index 100% rename from nanoFramework.Device.Can/packages.config rename to nanoFramework.Device.Can.Core/packages.config diff --git a/nanoFramework.Device.Can/packages.lock.json b/nanoFramework.Device.Can.Core/packages.lock.json similarity index 100% rename from nanoFramework.Device.Can/packages.lock.json rename to nanoFramework.Device.Can.Core/packages.lock.json diff --git a/nanoFramework.Device.Can.Esp32.nuspec b/nanoFramework.Device.Can.Esp32.nuspec new file mode 100644 index 0000000..b384dbf --- /dev/null +++ b/nanoFramework.Device.Can.Esp32.nuspec @@ -0,0 +1,39 @@ + + + + nanoFramework.Device.Can.Esp32 + $version$ + nanoFramework.Device.Can.Esp32 + nanoframework + false + LICENSE.md + + + docs\README.md + false + https://github.com/nanoframework/nanoFramework.Device.Can + images\nf-logo.png + + Copyright (c) .NET Foundation and Contributors + This package includes the nanoFramework.Device.Can.Esp32 assembly for .NET nanoFramework C# projects. +It contains the device-dependent part of the implementation of the nanoFramework.Device.Can namespace for ESP32-based devices. +This package requires a target with nanoFramework.Device.Can.Esp32 v$nativeVersion$ (checksum $checksum$). + nanoFramework C# csharp netmf netnf canbus can + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nanoFramework.Device.Can/Properties/AssemblyInfo.cs b/nanoFramework.Device.Can.Esp32/Properties/AssemblyInfo.cs similarity index 83% rename from nanoFramework.Device.Can/Properties/AssemblyInfo.cs rename to nanoFramework.Device.Can.Esp32/Properties/AssemblyInfo.cs index 0a2eb3f..c85aca7 100644 --- a/nanoFramework.Device.Can/Properties/AssemblyInfo.cs +++ b/nanoFramework.Device.Can.Esp32/Properties/AssemblyInfo.cs @@ -4,14 +4,14 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("nanoFramework.Device.Can")] +[assembly: AssemblyTitle("nanoFramework.Device.Can.Esp32")] [assembly: AssemblyCompany("nanoFramework Contributors")] -[assembly: AssemblyProduct("nanoFramework.Device.Can")] +[assembly: AssemblyProduct("nanoFramework.Device.Can.Esp32")] [assembly: AssemblyCopyright("Copyright (c) .NET Foundation and Contributors")] //////////////////////////////////////////////////////////////// // update this whenever the native assembly signature changes // -[assembly: AssemblyNativeVersion("100.0.5.1")] +[assembly: AssemblyNativeVersion("100.1.0.0")] //////////////////////////////////////////////////////////////// // Setting ComVisible to false makes the types in this assembly not visible diff --git a/nanoFramework.Device.Can.Esp32/key.snk b/nanoFramework.Device.Can.Esp32/key.snk new file mode 100644 index 0000000..67c9bb0 Binary files /dev/null and b/nanoFramework.Device.Can.Esp32/key.snk differ diff --git a/nanoFramework.Device.Can.Esp32/nanoFramework.Device.Can.Esp32.nfproj b/nanoFramework.Device.Can.Esp32/nanoFramework.Device.Can.Esp32.nfproj new file mode 100644 index 0000000..e106016 --- /dev/null +++ b/nanoFramework.Device.Can.Esp32/nanoFramework.Device.Can.Esp32.nfproj @@ -0,0 +1,73 @@ + + + + + $(MSBuildExtensionsPath)\nanoFramework\v1.0\ + + + + Debug + AnyCPU + {11A8DD76-328B-46DF-9F39-F559912D0360};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + {7CE9A616-F4A4-43EA-B067-526155C823AC} + Library + Properties + 512 + nanoFramework.Device.Can + nanoFramework.Device.Can.Esp32 + v1.0 + True + bin\$(Configuration)\nanoFramework.Device.Can.Esp32.xml + true + true + + + true + + + key.snk + + + false + + + bin\$(Configuration)\Stubs + nf_device_can_esp32_native + nanoFramework.Device.Can.Esp32 + + + + false + + + + + + + + + + + + + ..\packages\nanoFramework.CoreLibrary.1.16.11\lib\mscorlib.dll + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/nanoFramework.Device.Can.Esp32/packages.config b/nanoFramework.Device.Can.Esp32/packages.config new file mode 100644 index 0000000..2db295a --- /dev/null +++ b/nanoFramework.Device.Can.Esp32/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/nanoFramework.Device.Can.Esp32/packages.lock.json b/nanoFramework.Device.Can.Esp32/packages.lock.json new file mode 100644 index 0000000..0ab0f5c --- /dev/null +++ b/nanoFramework.Device.Can.Esp32/packages.lock.json @@ -0,0 +1,25 @@ +{ + "version": 1, + "dependencies": { + ".NETnanoFramework,Version=v1.0": { + "nanoFramework.CoreLibrary": { + "type": "Direct", + "requested": "[1.16.11, 1.16.11]", + "resolved": "1.16.11", + "contentHash": "2XW+Zn0lQ+lOcxDbB1l2ga2rNoj9Jv2IeJwXE4ka1r+swmxn5N/otlMJVEXJgK8trUeD/E8T7+J7dXjU8UReHw==" + }, + "nanoFramework.Runtime.Events": { + "type": "Direct", + "requested": "[1.11.29, 1.11.29]", + "resolved": "1.11.29", + "contentHash": "y3Y0SNfr1afMor4xrsiB1ETldjKvmnzBTcEH5gizFFXw3RNBB/N8npWqkCJn4HZS0TEENlH2vVrib3bWYMx5+Q==" + }, + "Nerdbank.GitVersioning": { + "type": "Direct", + "requested": "[3.7.115, 3.7.115]", + "resolved": "3.7.115", + "contentHash": "EpXamaAdRfG/BMxGgvZlTM0npRnkmXUjAj8OdNKd17t4oN+2nvjdv/KnFmzOOMDqvlwB49UCwtOHJrAQTfUBtQ==" + } + } + } +} \ No newline at end of file diff --git a/nanoFramework.Device.Can.Mcp2515.nuspec b/nanoFramework.Device.Can.Mcp2515.nuspec new file mode 100644 index 0000000..0bde20b --- /dev/null +++ b/nanoFramework.Device.Can.Mcp2515.nuspec @@ -0,0 +1,38 @@ + + + + nanoFramework.Device.Can.Mcp2515 + $version$ + nanoFramework.Device.Can.Mcp2515 + nanoframework + false + LICENSE.md + + + docs\README.md + false + https://github.com/nanoframework/nanoFramework.Device.Can + images\nf-logo.png + + Copyright (c) .NET Foundation and Contributors + This package includes the nanoFramework.Device.Can.Mcp2515 assembly for .NET nanoFramework C# projects. +It contains the device-dependent part of the implementation of the nanoFramework.Device.Can namespace for a CAN-bus that is accessed using a MCP2515. + nanoFramework C# csharp netmf netnf canbus can + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nanoFramework.Device.Can.Mcp2515/Properties/AssemblyInfo.cs b/nanoFramework.Device.Can.Mcp2515/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..82075e5 --- /dev/null +++ b/nanoFramework.Device.Can.Mcp2515/Properties/AssemblyInfo.cs @@ -0,0 +1,15 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("nanoFramework.Device.Can.Mcp2515")] +[assembly: AssemblyCompany("nanoFramework Contributors")] +[assembly: AssemblyProduct("nanoFramework.Device.Can.Mcp2515")] +[assembly: AssemblyCopyright("Copyright (c) .NET Foundation and Contributors")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] diff --git a/nanoFramework.Device.Can.Mcp2515/key.snk b/nanoFramework.Device.Can.Mcp2515/key.snk new file mode 100644 index 0000000..67c9bb0 Binary files /dev/null and b/nanoFramework.Device.Can.Mcp2515/key.snk differ diff --git a/nanoFramework.Device.Can.Mcp2515/nanoFramework.Device.Can.Mcp2515.nfproj b/nanoFramework.Device.Can.Mcp2515/nanoFramework.Device.Can.Mcp2515.nfproj new file mode 100644 index 0000000..c7fd1f9 --- /dev/null +++ b/nanoFramework.Device.Can.Mcp2515/nanoFramework.Device.Can.Mcp2515.nfproj @@ -0,0 +1,67 @@ + + + + + $(MSBuildExtensionsPath)\nanoFramework\v1.0\ + + + + Debug + AnyCPU + {11A8DD76-328B-46DF-9F39-F559912D0360};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + {9263BAA1-79C2-4A5F-9B36-EF2B24D6DF26} + Library + Properties + 512 + nanoFramework.Device.Can + nanoFramework.Device.Can.Mcp2515 + v1.0 + bin\$(Configuration)\nanoFramework.Device.Can.Mcp2515.xml + true + true + + + true + + + key.snk + + + false + + + + false + + + + + + + + + + + + + ..\packages\nanoFramework.CoreLibrary.1.16.11\lib\mscorlib.dll + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/nanoFramework.Device.Can.Mcp2515/packages.config b/nanoFramework.Device.Can.Mcp2515/packages.config new file mode 100644 index 0000000..2db295a --- /dev/null +++ b/nanoFramework.Device.Can.Mcp2515/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/nanoFramework.Device.Can.Mcp2515/packages.lock.json b/nanoFramework.Device.Can.Mcp2515/packages.lock.json new file mode 100644 index 0000000..0ab0f5c --- /dev/null +++ b/nanoFramework.Device.Can.Mcp2515/packages.lock.json @@ -0,0 +1,25 @@ +{ + "version": 1, + "dependencies": { + ".NETnanoFramework,Version=v1.0": { + "nanoFramework.CoreLibrary": { + "type": "Direct", + "requested": "[1.16.11, 1.16.11]", + "resolved": "1.16.11", + "contentHash": "2XW+Zn0lQ+lOcxDbB1l2ga2rNoj9Jv2IeJwXE4ka1r+swmxn5N/otlMJVEXJgK8trUeD/E8T7+J7dXjU8UReHw==" + }, + "nanoFramework.Runtime.Events": { + "type": "Direct", + "requested": "[1.11.29, 1.11.29]", + "resolved": "1.11.29", + "contentHash": "y3Y0SNfr1afMor4xrsiB1ETldjKvmnzBTcEH5gizFFXw3RNBB/N8npWqkCJn4HZS0TEENlH2vVrib3bWYMx5+Q==" + }, + "Nerdbank.GitVersioning": { + "type": "Direct", + "requested": "[3.7.115, 3.7.115]", + "resolved": "3.7.115", + "contentHash": "EpXamaAdRfG/BMxGgvZlTM0npRnkmXUjAj8OdNKd17t4oN+2nvjdv/KnFmzOOMDqvlwB49UCwtOHJrAQTfUBtQ==" + } + } + } +} \ No newline at end of file diff --git a/nanoFramework.Device.Can.Stm32.nuspec b/nanoFramework.Device.Can.Stm32.nuspec new file mode 100644 index 0000000..d81b17e --- /dev/null +++ b/nanoFramework.Device.Can.Stm32.nuspec @@ -0,0 +1,40 @@ + + + + nanoFramework.Device.Can.Stm32 + $version$ + nanoFramework.Device.Can.Stm32 + nanoframework + false + LICENSE.md + + + docs\README.md + false + https://github.com/nanoframework/nanoFramework.Device.Can + images\nf-logo.png + + Copyright (c) .NET Foundation and Contributors + This package includes the nanoFramework.Device.Can.Stm32 assembly for .NET nanoFramework C# projects. +It contains the device-dependent part of the implementation of the nanoFramework.Device.Can namespace for STM32-based devices. +This package requires a target with nanoFramework.Device.Can.Stm32 v$nativeVersion$ (checksum $checksum$). + nanoFramework C# csharp netmf netnf canbus can + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nanoFramework.Device.Can.Stm32/CanController.cs b/nanoFramework.Device.Can.Stm32/CanController.cs new file mode 100644 index 0000000..9706f93 --- /dev/null +++ b/nanoFramework.Device.Can.Stm32/CanController.cs @@ -0,0 +1,271 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +using System; +using System.Runtime.CompilerServices; + +namespace nanoFramework.Device.Can +{ + // This should be a TypedEventHandler "EventHandler" +#pragma warning disable 1591 + public delegate void CanMessageReceivedEventHandler( + Object sender, + CanMessageReceivedEventArgs e); + +#pragma warning restore 1591 + + /// + /// Represents a CAN controller on the system. + /// + public sealed class CanController : IDisposable + { + [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] + private static CanControllerEventListener s_eventListener = new CanControllerEventListener(); + + [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] + private bool _disposed; + + [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] + private CanMessageReceivedEventHandler _callbacks = null; + + // this is used as the lock object + // a lock is required because multiple threads can access the CanController + [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] + private readonly object _syncLock = new object(); + + [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] + internal readonly int _controllerId; + + [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] + private readonly CanSettings _settings; + + [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] + private readonly CanMessage _message; + + /// + /// Controller ID for this . + /// + public readonly string ControllerId; + + internal CanController(string controller, Can​Settings settings) + { + // the CAN id is an ASCII string with the format 'CANn' + // need to grab 'n' from the string and convert that to the integer value from the ASCII code (do this by subtracting 48 from the char value) + _controllerId = controller[3] - '0'; + + ControllerId = controller; + + // check if this controller is already opened + var myController = FindController(_controllerId); + + if (myController == null) + { + _settings = new CanSettings(settings); + + // call native init to allow HAL/PAL inits related with Can hardware + NativeInit(); + + // add controller to collection, with the ID as key + // ** just the index number *** + CanControllerManager.ControllersCollection.Add(this); + + // add the controller to the event listener in order to receive the callbacks from the native interrupts + s_eventListener.AddCanController(this); + } + else + { + // this controller already exists: throw an exception + throw new ArgumentException(); + } + } + + /// + /// Opens a CAN bus with the settings provided. + /// + /// The id of the bus. + /// The bus settings. + /// The CAN controller requested. + public static CanController FromId(string controllerId, Can​Settings settings) + { + //TODO: some sanity checks on controllerId + return new CanController(controllerId, settings); + } + + /// + /// Write message to CAN Bus. + /// + /// CAN mesage to write in CAN Bus. + [MethodImpl(MethodImplOptions.InternalCall)] + public extern void WriteMessage(CanMessage message); + + internal static CanController FindController(int index) + { + for (int i = 0; i < CanControllerManager.ControllersCollection.Count; i++) + { + if (((CanController)CanControllerManager.ControllersCollection[i])._controllerId == index) + { + return (CanController)CanControllerManager.ControllersCollection[i]; + } + } + + return null; + } + + #region IDisposable Support + + private void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + // remove controller from controller collection + CanControllerManager.ControllersCollection.Remove(this); + + // remove the controller from the event listener + s_eventListener.RemoveCanController(_controllerId); + } + + DisposeNative(); + + _disposed = true; + } + } + +#pragma warning disable 1591 + ~CanController() + { + Dispose(false); + } + + public void Dispose() + { + lock (_syncLock) + { + if (!_disposed) + { + Dispose(true); + + GC.SuppressFinalize(this); + } + } + } + +#pragma warning restore 1591 + + #endregion + + #region Events + + /// + /// Indicates that a message has been received through a object. + /// + public event CanMessageReceivedEventHandler MessageReceived + { + add + { + lock (_syncLock) + { + if (_disposed) + { + throw new ObjectDisposedException(); + } + + CanMessageReceivedEventHandler callbacksOld = _callbacks; + CanMessageReceivedEventHandler callbacksNew = (CanMessageReceivedEventHandler)Delegate.Combine(callbacksOld, value); + + try + { + _callbacks = callbacksNew; + } + catch + { + _callbacks = callbacksOld; + + throw; + } + + NativeUpdateCallbacks(); + } + } + + remove + { + lock (_syncLock) + { + if (_disposed) + { + throw new ObjectDisposedException(); + } + + CanMessageReceivedEventHandler callbacksOld = _callbacks; + CanMessageReceivedEventHandler callbacksNew = (CanMessageReceivedEventHandler)Delegate.Remove(callbacksOld, value); + + try + { + _callbacks = callbacksNew; + } + catch + { + _callbacks = callbacksOld; + + throw; + } + + NativeUpdateCallbacks(); + } + } + } + + + /// + /// Handles internal events and re-dispatches them to the publicly subscribed delegates. + /// + /// The Event type. + + internal void OnCanMessageReceivedInternal(CanEvent eventType) + { + CanMessageReceivedEventHandler callbacks = null; + + lock (_syncLock) + { + if (!_disposed) + { + callbacks = _callbacks; + } + } + + callbacks?.Invoke(this, new CanMessageReceivedEventArgs(eventType)); + } + + #endregion + + #region Native Calls + + /// + /// Get next available in the _ internal buffer. + /// If there are no more messages available null will be returned. + /// + /// + /// A or null if there are no more messages available. + /// + [MethodImpl(MethodImplOptions.InternalCall)] + public extern CanMessage GetMessage(); + + [MethodImpl(MethodImplOptions.InternalCall)] + private extern void DisposeNative(); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern string GetDeviceSelector(); + + [MethodImpl(MethodImplOptions.InternalCall)] + private extern void NativeInit(); + + [MethodImpl(MethodImplOptions.InternalCall)] + private extern void NativeUpdateCallbacks(); + + #endregion + } +} diff --git a/nanoFramework.Device.Can.Stm32/CanControllerEventListener.cs b/nanoFramework.Device.Can.Stm32/CanControllerEventListener.cs new file mode 100644 index 0000000..f0278d2 --- /dev/null +++ b/nanoFramework.Device.Can.Stm32/CanControllerEventListener.cs @@ -0,0 +1,93 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +using nanoFramework.Runtime.Events; +using System; +using System.Collections; + +namespace nanoFramework.Device.Can +{ + internal class CanControllerEventListener : IEventProcessor, IEventListener + { + // Map of serial device numbers to CanController objects. + private ArrayList _canControllersMap = new ArrayList(); + + public CanControllerEventListener() + { + EventSink.AddEventProcessor(EventCategory.Can, this); + EventSink.AddEventListener(EventCategory.Can, this); + } + + public BaseEvent ProcessEvent(uint data1, uint data2, DateTime time) + { + return new CanMessageEvent + { + // Data1 is packed by PostManagedEvent, so we need to unpack the high word. + ControllerIndex = (int)(data1 >> 16), + Event = (CanEvent)data2 + }; + } + + public void InitializeForEventSource() + { + } + + public bool OnEvent(BaseEvent ev) + { + var canMessageEvent = (CanMessageEvent)ev; + CanController device = null; + + lock (_canControllersMap) + { + device = FindCanController(canMessageEvent.ControllerIndex); + } + + // Avoid calling this under a lock to prevent a potential lock inversion. + if (device != null) + { + device.OnCanMessageReceivedInternal(canMessageEvent.Event); + } + else + { + return false; + } + + return true; + } + + public void AddCanController(CanController controller) + { + lock (_canControllersMap) + { + _canControllersMap.Add(controller); + } + } + + public void RemoveCanController(int index) + { + lock (_canControllersMap) + { + var controller = FindCanController(index); + + if (controller != null) + { + _canControllersMap.Remove(controller); + } + } + } + private CanController FindCanController(int controllerId) + { + for (int i = 0; i < _canControllersMap.Count; i++) + { + if (((CanController)_canControllersMap[i])._controllerId == controllerId) + { + return (CanController)_canControllersMap[i]; + } + } + + return null; + } + } +} diff --git a/nanoFramework.Device.Can.Stm32/CanControllerManager.cs b/nanoFramework.Device.Can.Stm32/CanControllerManager.cs new file mode 100644 index 0000000..6c0ee2d --- /dev/null +++ b/nanoFramework.Device.Can.Stm32/CanControllerManager.cs @@ -0,0 +1,48 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +using System.Collections; + +namespace nanoFramework.Device.Can +{ + internal sealed class CanControllerManager + { + private static readonly object _syncLock = new object(); + + // backing field for ControllersCollection + // to store the controllers that are open + private static ArrayList s_controllersCollection; + + /// + /// collection. + /// + /// + /// This collection is for internal use only. + /// + internal static ArrayList ControllersCollection + { + get + { + if (s_controllersCollection == null) + { + lock (_syncLock) + { + if (s_controllersCollection == null) + { + s_controllersCollection = new ArrayList(); + } + } + } + + return s_controllersCollection; + } + + set + { + s_controllersCollection = value; + } + } + } +} diff --git a/nanoFramework.Device.Can.Stm32/CanEvent.cs b/nanoFramework.Device.Can.Stm32/CanEvent.cs new file mode 100644 index 0000000..cca6405 --- /dev/null +++ b/nanoFramework.Device.Can.Stm32/CanEvent.cs @@ -0,0 +1,23 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +namespace nanoFramework.Device.Can +{ + /// + /// Describes the possible types of events for the CAN controller. + /// + public enum CanEvent + { + /// + /// A CAN message was received. + /// + MessageReceived = 0, + + /// + /// An error has occurred. + /// + ErrorOccurred + } +} diff --git a/nanoFramework.Device.Can.Stm32/CanMessage.cs b/nanoFramework.Device.Can.Stm32/CanMessage.cs new file mode 100644 index 0000000..e7b5291 --- /dev/null +++ b/nanoFramework.Device.Can.Stm32/CanMessage.cs @@ -0,0 +1,79 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +using System; +using System.Runtime.CompilerServices; + +namespace nanoFramework.Device.Can +{ + /// + /// CAN message. + /// + public class CanMessage + { + [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] + private uint _id; + + [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] + private CanMessageIdType _identifierType; + + [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] + private CanMessageFrameType _frameType; + + [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] + private byte[] _message; + + /// + /// Message ID (SID or EID format, depending on ). + /// + public uint Id + { + get { return _id; } + set { _id = value; } + } + + /// + /// Message identifier type. + /// + public CanMessageIdType IdentifierType + { + get { return _identifierType; } + set { _identifierType = value; } + } + + /// + /// Message frame type. + /// + public CanMessageFrameType FrameType + { + get { return _frameType; } + set { _frameType = value; } + } + + /// + /// Message data. + /// + /// + /// Maximum lenght of data buffer is 8. + /// + /// If the message buffer exceeds the maximum allowed lenght. + public byte[] Message + { + get { return _message; } + set { _message = value; } + } + + /// + /// Creates a CAN message. + /// + public CanMessage(uint id, CanMessageIdType identifierType, CanMessageFrameType frameType, byte[] message) + { + _id = id; + _identifierType = identifierType; + _frameType = frameType; + _message = message; + } + } +} diff --git a/nanoFramework.Device.Can.Stm32/CanMessageEvent.cs b/nanoFramework.Device.Can.Stm32/CanMessageEvent.cs new file mode 100644 index 0000000..c511e6a --- /dev/null +++ b/nanoFramework.Device.Can.Stm32/CanMessageEvent.cs @@ -0,0 +1,15 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +using nanoFramework.Runtime.Events; + +namespace nanoFramework.Device.Can +{ + internal class CanMessageEvent : BaseEvent + { + public int ControllerIndex; + public CanEvent Event; + } +} diff --git a/nanoFramework.Device.Can.Stm32/CanMessageFrameType.cs b/nanoFramework.Device.Can.Stm32/CanMessageFrameType.cs new file mode 100644 index 0000000..a00690b --- /dev/null +++ b/nanoFramework.Device.Can.Stm32/CanMessageFrameType.cs @@ -0,0 +1,23 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +namespace nanoFramework.Device.Can +{ + /// + /// CAN message frame type. + /// + public enum CanMessageFrameType + { + /// + /// Data frame. + /// + Data = 0, + + /// + /// Remote request frame. + /// + RemoteRequest + } +} diff --git a/nanoFramework.Device.Can.Stm32/CanMessageIdType.cs b/nanoFramework.Device.Can.Stm32/CanMessageIdType.cs new file mode 100644 index 0000000..283b05c --- /dev/null +++ b/nanoFramework.Device.Can.Stm32/CanMessageIdType.cs @@ -0,0 +1,23 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +namespace nanoFramework.Device.Can +{ + /// + /// CAN message identifier type. + /// + public enum CanMessageIdType + { + /// + /// Standard Identifier. + /// + SID, + + /// + /// Extended Identifier. + /// + EID + } +} diff --git a/nanoFramework.Device.Can.Stm32/CanMessageReceivedEventArgs.cs b/nanoFramework.Device.Can.Stm32/CanMessageReceivedEventArgs.cs new file mode 100644 index 0000000..fa6ee7a --- /dev/null +++ b/nanoFramework.Device.Can.Stm32/CanMessageReceivedEventArgs.cs @@ -0,0 +1,18 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +namespace nanoFramework.Device.Can +{ + /// + /// Provides data for the event. + /// + public class CanMessageReceivedEventArgs + { + internal CanMessageReceivedEventArgs(CanEvent msgValue) + { + + } + } +} diff --git a/nanoFramework.Device.Can.Stm32/CanSettings.cs b/nanoFramework.Device.Can.Stm32/CanSettings.cs new file mode 100644 index 0000000..a7ac738 --- /dev/null +++ b/nanoFramework.Device.Can.Stm32/CanSettings.cs @@ -0,0 +1,88 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +namespace nanoFramework.Device.Can +{ + /// + /// Represents the settings for CAN bus. + /// + public sealed class CanSettings + { + [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] + private byte _baudRatePrescaler; + + [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] + private byte _phaseSegment1; + + [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] + private byte _phaseSegment2; + + [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] + private byte _syncJumpWidth; + + /// + /// Initializes a new instance of . + /// + /// Bus baud rate prescaler. + /// Phase segment 1. + /// Phase segment 2. + /// Synchronization jump width. + public Can​Settings(byte baudRatePrescaler, byte phaseSegment1, byte phaseSegment2, byte syncJumpWidth) + { + _baudRatePrescaler = baudRatePrescaler; + _phaseSegment1 = phaseSegment1; + _phaseSegment2 = phaseSegment2; + _syncJumpWidth = syncJumpWidth; + } + + /// + /// Initializes a copy of a object. + /// + /// Object to copy from. + internal CanSettings(Can​Settings value) + { + _baudRatePrescaler = value._baudRatePrescaler; + _phaseSegment1 = value._phaseSegment1; + _phaseSegment2 = value._phaseSegment2; + _syncJumpWidth = value._syncJumpWidth; + } + + /// + /// Gets or sets the baud rate prescaler. + /// + public byte BaudRatePrescaler + { + get { return _baudRatePrescaler; } + set { _baudRatePrescaler = value; } + } + + /// + /// Gets or sets the value for phase segment 1. + /// + public byte PhaseSegment1 + { + get { return _phaseSegment1; } + set { _phaseSegment1 = value; } + } + + /// + /// Gets or sets the value for phase segment 2. + /// + public byte PhaseSegment2 + { + get { return _phaseSegment2; } + set { _phaseSegment2 = value; } + } + + /// + /// Gets or sets the value for the synchronization jump width. + /// + public byte SyncJumpWidth + { + get { return _syncJumpWidth; } + set { _syncJumpWidth = value; } + } + } +} diff --git a/nanoFramework.Device.Can.Stm32/Properties/AssemblyInfo.cs b/nanoFramework.Device.Can.Stm32/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d2dc91f --- /dev/null +++ b/nanoFramework.Device.Can.Stm32/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("nanoFramework.Device.Can.Stm32")] +[assembly: AssemblyCompany("nanoFramework Contributors")] +[assembly: AssemblyProduct("nanoFramework.Device.Can.Stm32")] +[assembly: AssemblyCopyright("Copyright (c) .NET Foundation and Contributors")] + +//////////////////////////////////////////////////////////////// +// update this whenever the native assembly signature changes // +[assembly: AssemblyNativeVersion("100.1.0.0")] +//////////////////////////////////////////////////////////////// + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] diff --git a/nanoFramework.Device.Can.Stm32/key.snk b/nanoFramework.Device.Can.Stm32/key.snk new file mode 100644 index 0000000..67c9bb0 Binary files /dev/null and b/nanoFramework.Device.Can.Stm32/key.snk differ diff --git a/nanoFramework.Device.Can/nanoFramework.Device.Can.nfproj b/nanoFramework.Device.Can.Stm32/nanoFramework.Device.Can.Stm32.nfproj similarity index 91% rename from nanoFramework.Device.Can/nanoFramework.Device.Can.nfproj rename to nanoFramework.Device.Can.Stm32/nanoFramework.Device.Can.Stm32.nfproj index 6342a57..75cd363 100644 --- a/nanoFramework.Device.Can/nanoFramework.Device.Can.nfproj +++ b/nanoFramework.Device.Can.Stm32/nanoFramework.Device.Can.Stm32.nfproj @@ -9,15 +9,15 @@ Debug AnyCPU {11A8DD76-328B-46DF-9F39-F559912D0360};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 99ca76e4-d76f-42c9-9e62-49c2f499aa02 + {695177A1-93CE-4AC4-88A2-EEFDDF327D0F} Library Properties 512 nanoFramework.Device.Can - nanoFramework.Device.Can + nanoFramework.Device.Can.Stm32 v1.0 True - bin\$(Configuration)\nanoFramework.Device.Can.xml + bin\$(Configuration)\nanoFramework.Device.Can.Stm32.xml true true @@ -32,8 +32,8 @@ bin\$(Configuration)\Stubs - nf_device_can_native - nanoFramework.Device.Can + nf_device_can_stm32_native + nanoFramework.Device.Can.Stm32 @@ -67,6 +67,9 @@ ..\packages\nanoFramework.Runtime.Events.1.11.29\lib\nanoFramework.Runtime.Events.dll + + + diff --git a/nanoFramework.Device.Can.Stm32/packages.config b/nanoFramework.Device.Can.Stm32/packages.config new file mode 100644 index 0000000..2db295a --- /dev/null +++ b/nanoFramework.Device.Can.Stm32/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/nanoFramework.Device.Can.Stm32/packages.lock.json b/nanoFramework.Device.Can.Stm32/packages.lock.json new file mode 100644 index 0000000..0ab0f5c --- /dev/null +++ b/nanoFramework.Device.Can.Stm32/packages.lock.json @@ -0,0 +1,25 @@ +{ + "version": 1, + "dependencies": { + ".NETnanoFramework,Version=v1.0": { + "nanoFramework.CoreLibrary": { + "type": "Direct", + "requested": "[1.16.11, 1.16.11]", + "resolved": "1.16.11", + "contentHash": "2XW+Zn0lQ+lOcxDbB1l2ga2rNoj9Jv2IeJwXE4ka1r+swmxn5N/otlMJVEXJgK8trUeD/E8T7+J7dXjU8UReHw==" + }, + "nanoFramework.Runtime.Events": { + "type": "Direct", + "requested": "[1.11.29, 1.11.29]", + "resolved": "1.11.29", + "contentHash": "y3Y0SNfr1afMor4xrsiB1ETldjKvmnzBTcEH5gizFFXw3RNBB/N8npWqkCJn4HZS0TEENlH2vVrib3bWYMx5+Q==" + }, + "Nerdbank.GitVersioning": { + "type": "Direct", + "requested": "[3.7.115, 3.7.115]", + "resolved": "3.7.115", + "contentHash": "EpXamaAdRfG/BMxGgvZlTM0npRnkmXUjAj8OdNKd17t4oN+2nvjdv/KnFmzOOMDqvlwB49UCwtOHJrAQTfUBtQ==" + } + } + } +} \ No newline at end of file diff --git a/nanoFramework.Device.Can.sln b/nanoFramework.Device.Can.sln index 5124105..902148c 100644 --- a/nanoFramework.Device.Can.sln +++ b/nanoFramework.Device.Can.sln @@ -2,28 +2,64 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.2.32505.173 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{11A8DD76-328B-46DF-9F39-F559912D0360}") = "nanoFramework.Device.Can", "nanoFramework.Device.Can\nanoFramework.Device.Can.nfproj", "{99CA76E4-D76F-42C9-9E62-49C2F499AA02}" +Project("{11A8DD76-328B-46DF-9F39-F559912D0360}") = "nanoFramework.Device.Can.Core", "nanoFramework.Device.Can.Core\nanoFramework.Device.Can.Core.nfproj", "{99CA76E4-D76F-42C9-9E62-49C2F499AA02}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B46D657A-F9AC-427C-A131-5323F92F211C}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Packages and stubs", "Packages and stubs", "{B46D657A-F9AC-427C-A131-5323F92F211C}" ProjectSection(SolutionItems) = preProject - nanoFramework.Device.Can.DELIVERABLES.nuspec = nanoFramework.Device.Can.DELIVERABLES.nuspec - nanoFramework.Device.Can.nuspec = nanoFramework.Device.Can.nuspec + nanoFramework.Device.Can.Core.nuspec = nanoFramework.Device.Can.Core.nuspec + nanoFramework.Device.Can.Esp32.nuspec = nanoFramework.Device.Can.Esp32.nuspec + nanoFramework.Device.Can.Mcp2515.nuspec = nanoFramework.Device.Can.Mcp2515.nuspec + nanoFramework.Device.Can.Stm32.nuspec = nanoFramework.Device.Can.Stm32.nuspec NuGet.Config = NuGet.Config + README.md = README.md + Stub-generation.md = Stub-generation.md version.json = version.json EndProjectSection EndProject +Project("{11A8DD76-328B-46DF-9F39-F559912D0360}") = "nanoFramework.Device.Can.Esp32", "nanoFramework.Device.Can.Esp32\nanoFramework.Device.Can.Esp32.nfproj", "{7CE9A616-F4A4-43EA-B067-526155C823AC}" +EndProject +Project("{11A8DD76-328B-46DF-9F39-F559912D0360}") = "nanoFramework.Device.Can.Stm32", "nanoFramework.Device.Can.Stm32\nanoFramework.Device.Can.Stm32.nfproj", "{695177A1-93CE-4AC4-88A2-EEFDDF327D0F}" +EndProject +Project("{11A8DD76-328B-46DF-9F39-F559912D0360}") = "nanoFramework.Device.Can.Mcp2515", "nanoFramework.Device.Can.Mcp2515\nanoFramework.Device.Can.Mcp2515.nfproj", "{9263BAA1-79C2-4A5F-9B36-EF2B24D6DF26}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + GenerateStubs|Any CPU = GenerateStubs|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {99CA76E4-D76F-42C9-9E62-49C2F499AA02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {99CA76E4-D76F-42C9-9E62-49C2F499AA02}.Debug|Any CPU.Build.0 = Debug|Any CPU {99CA76E4-D76F-42C9-9E62-49C2F499AA02}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {99CA76E4-D76F-42C9-9E62-49C2F499AA02}.GenerateStubs|Any CPU.ActiveCfg = GenerateStubs|Any CPU + {99CA76E4-D76F-42C9-9E62-49C2F499AA02}.GenerateStubs|Any CPU.Build.0 = GenerateStubs|Any CPU {99CA76E4-D76F-42C9-9E62-49C2F499AA02}.Release|Any CPU.ActiveCfg = Release|Any CPU {99CA76E4-D76F-42C9-9E62-49C2F499AA02}.Release|Any CPU.Build.0 = Release|Any CPU {99CA76E4-D76F-42C9-9E62-49C2F499AA02}.Release|Any CPU.Deploy.0 = Release|Any CPU + {7CE9A616-F4A4-43EA-B067-526155C823AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7CE9A616-F4A4-43EA-B067-526155C823AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7CE9A616-F4A4-43EA-B067-526155C823AC}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {7CE9A616-F4A4-43EA-B067-526155C823AC}.GenerateStubs|Any CPU.ActiveCfg = Debug|Any CPU + {7CE9A616-F4A4-43EA-B067-526155C823AC}.GenerateStubs|Any CPU.Build.0 = Debug|Any CPU + {7CE9A616-F4A4-43EA-B067-526155C823AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7CE9A616-F4A4-43EA-B067-526155C823AC}.Release|Any CPU.Build.0 = Release|Any CPU + {7CE9A616-F4A4-43EA-B067-526155C823AC}.Release|Any CPU.Deploy.0 = Release|Any CPU + {695177A1-93CE-4AC4-88A2-EEFDDF327D0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {695177A1-93CE-4AC4-88A2-EEFDDF327D0F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {695177A1-93CE-4AC4-88A2-EEFDDF327D0F}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {695177A1-93CE-4AC4-88A2-EEFDDF327D0F}.GenerateStubs|Any CPU.ActiveCfg = Debug|Any CPU + {695177A1-93CE-4AC4-88A2-EEFDDF327D0F}.GenerateStubs|Any CPU.Build.0 = Debug|Any CPU + {695177A1-93CE-4AC4-88A2-EEFDDF327D0F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {695177A1-93CE-4AC4-88A2-EEFDDF327D0F}.Release|Any CPU.Build.0 = Release|Any CPU + {695177A1-93CE-4AC4-88A2-EEFDDF327D0F}.Release|Any CPU.Deploy.0 = Release|Any CPU + {9263BAA1-79C2-4A5F-9B36-EF2B24D6DF26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9263BAA1-79C2-4A5F-9B36-EF2B24D6DF26}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9263BAA1-79C2-4A5F-9B36-EF2B24D6DF26}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {9263BAA1-79C2-4A5F-9B36-EF2B24D6DF26}.GenerateStubs|Any CPU.ActiveCfg = Debug|Any CPU + {9263BAA1-79C2-4A5F-9B36-EF2B24D6DF26}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9263BAA1-79C2-4A5F-9B36-EF2B24D6DF26}.Release|Any CPU.Build.0 = Release|Any CPU + {9263BAA1-79C2-4A5F-9B36-EF2B24D6DF26}.Release|Any CPU.Deploy.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/spelling_exclusion.dic b/spelling_exclusion.dic new file mode 100644 index 0000000..8c0e1f8 --- /dev/null +++ b/spelling_exclusion.dic @@ -0,0 +1 @@ +nano