- Update various docs.
- Setup Azure Pipelines.
- Moved source files from nanoframework/nf-tools.

Signed-off-by: José Simões <jose.simoes@eclo.solutions>
This commit is contained in:
José Simões 2019-06-18 18:19:47 +01:00
Родитель f2274130d9
Коммит 6d51981b4a
18 изменённых файлов: 1619 добавлений и 327 удалений

63
.gitattributes поставляемый Normal file
Просмотреть файл

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

339
.gitignore поставляемый
Просмотреть файл

@ -1,330 +1,17 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
# Visual Studio
.vs/
[Bb]in/
[Oo]bj/
[Ll]og/
packages/
*.suo
*.user
NanoFramework-GitHubBot - Web Deploy.pubxml
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# AzureDevOps tasks
ps_modules
7zip
*.vsix
*.zip
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
#SoundCloud
*.sonarqube/

3
CODE_OF_CONDUCT.md Normal file
Просмотреть файл

@ -0,0 +1,3 @@
# Contributor Code of Conduct
Please refer to the contributor Code of Conduct at the Home repository [here](https://github.com/nanoframework/Home/blob/master/CODE_OF_CONDUCT.md).

3
CONTRIBUTING.md Normal file
Просмотреть файл

@ -0,0 +1,3 @@
# Contributing to **nanoFramework**
Please refer to the contribution guidelines at the Home repository [here](https://github.com/nanoframework/Home/blob/master/CONTRIBUTING.md).

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

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2019 nanoFramework
Copyright (c) 2019 nanoFramework contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

29
README.md Normal file
Просмотреть файл

@ -0,0 +1,29 @@
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![#yourfirstpr](https://img.shields.io/badge/first--timers--only-friendly-blue.svg)](https://github.com/nanoframework/Home/blob/master/CONTRIBUTING.md) [![Build Status](https://dev.azure.com/nanoframework/tools/_apis/build/status/nanoframework.nf-tool-hex2dfu)](https://dev.azure.com/nanoframework/tools/_build/latest?definitionId=) [![Discord](https://img.shields.io/discord/478725473862549535.svg)](https://discord.gg/gCyBu8T)
![nanoFramework logo](https://github.com/nanoframework/Home/blob/master/resources/logo/nanoFramework-repo-logo.png)
-----
### Welcome to the **nanoFramework** HEX2DFU tool repository!
This repo contains the Hex2Dfu tool.
It's a console app to convert and/or pack HEX or BIN files in DFU packages (required to update some target boards).
Is part of **nanoFramework** toolbox, along with other various tools that are required in **nanoFramework** development, usage or repository management.
## Feedback and documentation
For documentation, providing feedback, issues and finding out how to contribute please refer to the [Home repo](https://github.com/nanoframework/Home).
Join our Discord community [here](https://discord.gg/gCyBu8T).
## Credits
The list of contributors to this project can be found at [CONTRIBUTORS](https://github.com/nanoframework/Home/blob/master/CONTRIBUTORS.md).
## License
The **nanoFramework** HEX2DFU tool is licensed under the [MIT license](https://opensource.org/licenses/MIT).
## Code of Conduct
This project has adopted the code of conduct defined by the [Contributor Covenant](http://contributor-covenant.org/)
to clarify expected behavior in our community.

132
azure-pipelines.yml Normal file
Просмотреть файл

@ -0,0 +1,132 @@
trigger:
branches:
include:
- master
- develop
- release/*
paths:
exclude:
- /*.md
- .gitignore
pr:
branches:
include:
- master
- develop
- release/*
autoCancel: true
# add nf-tools repo to resources (for Azure Pipelines templates)
resources:
repositories:
- repository: templates
type: github
name: nanoframework/nf-tools
endpoint: nanoframework
jobs:
##############################
- job: Get_Build_Options
pool:
vmImage: 'VS2017-Win2016'
steps:
- checkout: self
# build tools
- job: Build_tools
pool:
vmImage: 'VS2017-Win2016'
variables:
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
solution: 'source\nanoFramework.Tools.Hex2Dfu.sln'
toolName: 'HEX2DFU utility'
steps:
# need this here in order to persist GitHub credentials
- checkout: self
persistCredentials: true
- script: |
git config --global user.email "nanoframework@outlook.com"
git config --global user.name "nfbot"
displayName: Setup git identity
- task: NuGetToolInstaller@0
- task: NuGetCommand@2
inputs:
restoreSolution: '$(solution)'
verbosityRestore: quiet
- task: VSBuild@1
inputs:
solution: '$(solution)'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
- task: CopyFiles@1
inputs:
sourceFolder: $(Build.SourcesDirectory)
Contents: |
**\bin\Release\*.exe
TargetFolder: '$(Build.ArtifactStagingDirectory)'
flattenFolders: true
condition: succeeded()
displayName: Collecting deployable artifacts
# publish artifacts (only possible if this is not a PR originated on a fork)
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: deployables
ArtifactType: Container
condition: and( succeeded(), ne(variables['system.pullrequest.isfork'], true) )
displayName: Publish deployables artifacts
# create or update GitHub release
- task: GitHubReleasePublish@1
inputs:
githubEndpoint: 'nanoFramework'
githubOwner: 'nanoframework'
githubRepositoryName: 'nf-tool-hex2dfu'
githubTag: v$(NBGV_Version)
githubReleaseTitle: 'nanoFramework hex2dfu v$(NBGV_Version)'
githubReleaseNotes: 'add description here'
githubTargetCommitsh: $(Build.SourceVersion)
githubReleaseDraft: true
githubReleasePrerelease: false
githubReuseDraftOnly: true
githubReuseRelease: true
githubEditRelease: true
githubReleaseAsset: '$(Build.ArtifactStagingDirectory)/*.exe'
condition: and( succeeded(), not( startsWith(variables['Build.SourceBranch'], 'refs/pull') ) )
displayName: Create/Update GitHub release
##################################
# report build failure to Discord
- job: Report_Build_Failure
dependsOn:
- Build_tools
condition: failed('Build_tools')
pool:
vmImage: 'VS2017-Win2016'
steps:
- checkout: self
fetchDepth: 1
# step from template @ nf-tools repo
- template: azure-pipelines-templates/discord-webhook.yml@templates
parameters:
status: 'failure'
webhookUrl: '$(DiscordWebhook)'
message: ''

6
source/App.config Normal file
Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
</startup>
</configuration>

671
source/Arguments.cs Normal file
Просмотреть файл

@ -0,0 +1,671 @@
/*
Provides static methods used to retrieve the command line arguments and operands with which the application was started,
as well as a Type to contain them.
The MIT License (MIT)
Copyright (c) 2017 JP Dillingham (jp@dillingham.ws)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass", Justification = "Reviewed.")]
namespace Utility.CommandLine
{
/// <summary>
/// Provides extension method(s) for the Argument namespace.
/// </summary>
public static class Extensions
{
#region Internal Methods
/// <summary>
/// Adds the specified key to the specified dictionary with the specified value, but only if the specified key is not
/// already present in the dictionary. If it is present, a list is created and the new value is added to the list,
/// along with all subsequent values.
/// </summary>
/// <param name="dictionary">The dictionary to which they specified key and value are to be added.</param>
/// <param name="key">The key to add to the dictionary.</param>
/// <param name="value">The value corresponding to the specified key.</param>
internal static void ExclusiveAdd(this Dictionary<string, object> dictionary, string key, object value)
{
if (!dictionary.ContainsKey(key))
{
dictionary.Add(key, value);
}
else
{
var type = dictionary[key].GetType();
if (dictionary[key].GetType() == typeof(List<object>))
{
((List<object>)dictionary[key]).Add(value);
}
else
{
object existingValue = dictionary[key];
dictionary[key] = new List<object>(new object[] { existingValue, value });
}
}
}
#endregion Internal Methods
}
/// <summary>
/// Indicates that the property is to be used as a target for automatic population of values from command line arguments
/// when invoking the <see cref="Arguments.Populate(string)"/> method.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class ArgumentAttribute : Attribute
{
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ArgumentAttribute"/> class.
/// </summary>
/// <param name="shortName">The short name of the argument, represented as a single character.</param>
/// <param name="longName">The long name of the argument.</param>
public ArgumentAttribute(char shortName, string longName)
{
ShortName = shortName;
LongName = longName;
}
#endregion Public Constructors
#region Public Properties
/// <summary>
/// Gets or sets the long name of the argument.
/// </summary>
public string LongName { get; set; }
/// <summary>
/// Gets or sets the short name of the argument.
/// </summary>
public char ShortName { get; set; }
#endregion Public Properties
}
/// <summary>
/// Provides static methods used to retrieve the command line arguments and operands with which the application was
/// started, as well as a Type to contain them.
/// </summary>
public class Arguments
{
#region Private Fields
/// <summary>
/// The regular expression with which to parse the command line string.
/// </summary>
private const string ArgumentRegEx = "(?:[-]{1,2}|\\/)([^=: ]+)[=: ]?(\\w\\S*|\\\"[^\"]*\\\"|\\\'[^']*\\\')?|([^ ([^'\\\"]+|\"[^\\\"]+\"|\\\'[^']+\\\')";
/// <summary>
/// The regular expression with which to parse argument-value groups.
/// </summary>
private const string GroupRegEx = "^-[^-]+";
/// <summary>
/// The regular expression with which to parse strings strictly containing operands.
/// </summary>
private const string OperandRegEx = "([^ ([^'\\\"]+|\\\"[^\\\"]+\\\"|\\\'[^']+\\\')";
/// <summary>
/// The regular expression with which to split the command line string explicitly among argument/value pairs and
/// operands, and strictly operands.
/// </summary>
/// <remarks>
/// This regular expression effectively splits a string into two parts; the part before the first "--", and the part
/// after. Instances of "--" not surrounded by a word boundary and those enclosed in quotes are ignored.
/// </remarks>
private const string StrictOperandSplitRegEx = "(.*?[^\\\"\\\'])?(\\B-{2}\\B)[^\\\"\\\']?(.*)";
#endregion Private Fields
#region Private Constructors
/// <summary>
/// Initializes a new instance of the <see cref="Arguments"/> class with the specified argument dictionary and operand list.
/// </summary>
/// <param name="argumentDictionary">
/// The dictionary containing the arguments and values specified in the command line arguments with which the
/// application was started.
/// </param>
/// <param name="operandList">
/// The list containing the operands specified in the command line arguments with which the application was started.
/// </param>
private Arguments(Dictionary<string, object> argumentDictionary, List<string> operandList)
{
ArgumentDictionary = argumentDictionary;
OperandList = operandList;
}
#endregion Private Constructors
#region Public Properties
/// <summary>
/// Gets a dictionary containing the arguments and values specified in the command line arguments with which the
/// application was started.
/// </summary>
public Dictionary<string, object> ArgumentDictionary { get; private set; }
/// <summary>
/// Gets a list containing the operands specified in the command line arguments with which the application was started.
/// </summary>
public List<string> OperandList { get; private set; }
#endregion Public Properties
#region Public Indexers
/// <summary>
/// Gets the argument value corresponding to the specified key from the <see cref="ArgumentDictionary"/> property.
/// </summary>
/// <param name="index">The key for which the value is to be retrieved.</param>
/// <returns>The argument value corresponding to the specified key.</returns>
public object this[string index]
{
get
{
return ArgumentDictionary[index];
}
}
#endregion Public Indexers
#region Public Methods
/// <summary>
/// Returns a dictionary containing the values specified in the command line arguments with which the application was
/// started, keyed by argument name.
/// </summary>
/// <param name="commandLineString">The command line arguments with which the application was started.</param>
/// <returns>
/// The dictionary containing the arguments and values specified in the command line arguments with which the
/// application was started.
/// </returns>
public static Arguments Parse(string commandLineString = default(string))
{
commandLineString = commandLineString == default(string) || commandLineString == string.Empty ? Environment.CommandLine : commandLineString;
Dictionary<string, object> argumentDictionary;
List<string> operandList;
// use the strict operand regular expression to test for/extract the two halves of the string, if the operator is used.
MatchCollection matches = Regex.Matches(commandLineString, StrictOperandSplitRegEx);
// if there is a match, the string contains the strict operand delimiter. parse the first and second matches accordingly.
if (matches.Count > 0)
{
// the first group of the first match will contain everything in the string prior to the strict operand delimiter,
// so extract the argument key/value pairs and list of operands from that string.
argumentDictionary = GetArgumentDictionary(matches[0].Groups[1].Value);
operandList = GetOperandList(matches[0].Groups[1].Value);
// the first group of the second match will contain everything in the string after the strict operand delimiter, so
// extract the operands from that string using the strict method.
if (matches[0].Groups[3].Value != string.Empty)
{
List<string> operandListStrict = GetOperandListStrict(matches[0].Groups[3].Value);
// join the operand lists.
operandList.AddRange(operandListStrict);
}
}
else
{
argumentDictionary = GetArgumentDictionary(commandLineString);
operandList = GetOperandList(commandLineString);
}
return new Arguments(argumentDictionary, operandList);
}
/// <summary>
/// Populates the properties in the invoking class marked with the
/// <see cref="ArgumentAttribute"/><see cref="Attribute"/> with the values specified in the list of command line
/// arguments, if present.
/// </summary>
/// <param name="commandLineString">The command line arguments with which the application was started.</param>
public static void Populate(string commandLineString = default(string))
{
Populate(new StackFrame(1).GetMethod().DeclaringType, Parse(commandLineString));
}
/// <summary>
/// Populates the properties in the specified Type marked with the
/// <see cref="ArgumentAttribute"/><see cref="Attribute"/> with the values specified in the list of command line
/// arguments, if present.
/// </summary>
/// <param name="type">
/// The Type for which the static properties matching the list of command line arguments are to be populated.
/// </param>
/// <param name="commandLineString">The command line arguments with which the application was started.</param>
public static void Populate(Type type, string commandLineString = default(string))
{
Populate(type, Parse(commandLineString));
}
/// <summary>
/// Populates the properties in the invoking class marked with the
/// <see cref="ArgumentAttribute"/><see cref="Attribute"/> with the values specified in the specified argument
/// dictionary, if present.
/// </summary>
/// <param name="argumentDictionary">
/// The dictionary containing the argument-value pairs with which the destination properties should be populated
/// </param>
public static void Populate(Dictionary<string, object> argumentDictionary)
{
Populate(new StackFrame(1).GetMethod().DeclaringType, new Arguments(argumentDictionary, new List<string>()));
}
/// <summary>
/// Populates the properties in the specified Type marked with the
/// <see cref="ArgumentAttribute"/><see cref="Attribute"/> with the values specified in the specified argument
/// dictionary, if present. All property values are set to null at the start of the routine.
/// </summary>
/// <param name="type">
/// The Type for which the static properties matching the list of command line arguments are to be populated.
/// </param>
/// <param name="arguments">
/// The Arguments object containing the dictionary containing the argument-value pairs with which the destination
/// properties should be populated and the list of operands.
/// </param>
public static void Populate(Type type, Arguments arguments)
{
// fetch any properties in the specified type marked with the ArgumentAttribute attribute and clear them
Dictionary<string, PropertyInfo> properties = GetArgumentProperties(type);
ClearProperties(properties);
foreach (string propertyName in properties.Keys)
{
// if the argument dictionary contains a matching argument
if (arguments.ArgumentDictionary.ContainsKey(propertyName))
{
// retrieve the property and type
PropertyInfo property = properties[propertyName];
Type propertyType = property.PropertyType;
// retrieve the value from the argument dictionary
object value = arguments.ArgumentDictionary[propertyName];
bool valueIsList = value.GetType().IsGenericType && value.GetType().GetGenericTypeDefinition() == typeof(List<>);
object convertedValue;
// if the type of the property is bool and the argument value is empty set the property value to true,
// indicating the argument is present
if (propertyType == typeof(bool) && value.ToString() == string.Empty)
{
convertedValue = true;
}
else if (propertyType.IsArray || (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(List<>)))
{
// if the property is an array or list, convert the value to an array or list of the matching type. start
// by converting atomic values to a list containing a single value, just to simplify processing.
if (valueIsList)
{
convertedValue = value;
}
else
{
convertedValue = new List<object>(new object[] { value });
}
// next, create a list with the same type as the target property
Type valueType;
if (propertyType.IsArray)
{
valueType = propertyType.GetElementType();
}
else
{
valueType = propertyType.GetGenericArguments()[0];
}
// create a list to store converted values
Type valueListType = typeof(List<>).MakeGenericType(valueType);
var valueList = (IList)Activator.CreateInstance(valueListType);
// populate the list
foreach (object v in (List<object>)convertedValue)
{
valueList.Add(ChangeType(v, propertyName, valueType));
}
// if the target property is an array, create one and populate it from the list this is surprisingly
// difficult here because we created the source list with the Activator and ToArray() won't work easily.
if (propertyType.IsArray)
{
var valueArray = Array.CreateInstance(propertyType.GetElementType(), valueList.Count);
for (int i = 0; i < valueArray.Length; i++)
{
valueArray.SetValue(valueList[i], i);
}
convertedValue = valueArray;
}
else
{
convertedValue = valueList;
}
}
else
{
// if the target property Type is an atomic (non-array or list) Type, convert the value and populate it,
// but not if the value is an array or list.
if (valueIsList)
{
throw new InvalidCastException($"Multiple values were specified for argument '{propertyName}', however it is not backed by an array or List<T>. Specify only one value.");
}
convertedValue = ChangeType(value, propertyName, propertyType);
}
// set the target properties' value to the converted value from the argument string
property.SetValue(null, convertedValue);
}
}
PropertyInfo operandsProperty = GetOperandsProperty(type);
// check to ensure the target class has a property marked with the Operands attribute; if not GetOperandsProperty()
// will return null.
if (operandsProperty != default(PropertyInfo))
{
if (operandsProperty.PropertyType.IsAssignableFrom(typeof(List<string>)))
{
operandsProperty.SetValue(null, arguments.OperandList);
}
else
{
operandsProperty.SetValue(null, arguments.OperandList.ToArray());
}
}
}
#endregion Public Methods
#region Private Methods
/// <summary>
/// Converts the specified value for the specified argument to the specified Type.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="argument">The argument for which the value is being converted.</param>
/// <param name="toType">The Type to which the value is being converted.</param>
/// <returns>The converted value.</returns>
private static object ChangeType(object value, string argument, Type toType)
{
try
{
return Convert.ChangeType(value, toType);
}
catch (Exception ex)
{
// if the cast fails, throw an exception
string message = $"Specified value '{value}' for argument '{argument}' (expected type: {toType}). ";
message += "See inner exception for details.";
throw new ArgumentException(message, ex);
}
}
/// <summary>
/// Sets the value of each property in the specified dictionary to null.
/// </summary>
/// <param name="properties">The dictionary containing the properties to clear.</param>
private static void ClearProperties(Dictionary<string, PropertyInfo> properties)
{
foreach (string key in properties.Keys)
{
properties[key].SetValue(null, null);
}
}
/// <summary>
/// Populates and returns a dictionary containing the values specified in the command line arguments with which the
/// application was started, keyed by argument name.
/// </summary>
/// <param name="commandLineString">The command line arguments with which the application was started.</param>
/// <returns>
/// The dictionary containing the arguments and values specified in the command line arguments with which the
/// application was started.
/// </returns>
private static Dictionary<string, object> GetArgumentDictionary(string commandLineString)
{
Dictionary<string, object> argumentDictionary = new Dictionary<string, object>();
foreach (Match match in Regex.Matches(commandLineString, ArgumentRegEx))
{
// the first match of the regular expression used to parse the string will contain the argument name, if one was matched.
if (match.Groups[1].Value == default(string) || match.Groups[1].Value == string.Empty)
{
continue;
}
string fullMatch = match.Groups[0].Value;
string argument = match.Groups[1].Value;
string value = match.Groups[2].Value;
value = TrimOuterQuotes(value);
// check to see if the argument uses a single dash. if so, split the argument name into a char array and add each
// to the dictionary. if a value is specified, it belongs to the final character.
if (Regex.IsMatch(fullMatch, GroupRegEx))
{
char[] charArray = argument.ToCharArray();
// iterate over the characters backwards to more easily assign the value
for (int i = 0; i < charArray.Length; i++)
{
argumentDictionary.ExclusiveAdd(charArray[i].ToString(), i == charArray.Length - 1 ? value : string.Empty);
}
}
else
{
// add the argument and value to the dictionary if it doesn't already exist.
argumentDictionary.ExclusiveAdd(argument, value);
}
}
return argumentDictionary;
}
/// <summary>
/// Retrieves a dictionary containing properties in the target <see cref="Type"/> marked with the
/// <see cref="ArgumentAttribute"/><see cref="Attribute"/>, keyed on the string specified in the 'Name' field of the <see cref="Attribute"/>.
/// </summary>
/// <param name="type">The <see cref="Type"/> for which the matching properties are to be retrieved.</param>
/// <returns>
/// A dictionary containing matching properties, keyed on the 'Name' field of the
/// <see cref="ArgumentAttribute"/><see cref="Attribute"/> used to mark the property.
/// </returns>
private static Dictionary<string, PropertyInfo> GetArgumentProperties(Type type)
{
Dictionary<string, PropertyInfo> properties = new Dictionary<string, PropertyInfo>();
foreach (PropertyInfo property in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static))
{
// attempt to fetch the ArgumentAttribute of the property
CustomAttributeData attribute = property.CustomAttributes.Where(a => a.AttributeType.Name == typeof(ArgumentAttribute).Name).FirstOrDefault();
// if found, extract the Name property and add it to the dictionary
if (attribute != default(CustomAttributeData))
{
char shortName = (char)attribute.ConstructorArguments[0].Value;
string longName = (string)attribute.ConstructorArguments[1].Value;
if (!properties.ContainsKey(shortName.ToString()) && !properties.ContainsKey(longName))
{
properties.Add(shortName.ToString(), property);
properties.Add(longName, property);
}
}
}
return properties;
}
/// <summary>
/// Populates and returns a list containing the operands specified in the command line arguments with which the
/// application was started.
/// </summary>
/// <param name="commandLineString">The command line arguments with which the application was started.</param>
/// <returns>
/// A list containing the operands specified in the command line arguments with which the application was started.
/// </returns>
private static List<string> GetOperandList(string commandLineString)
{
List<string> operands = new List<string>();
foreach (Match match in Regex.Matches(commandLineString, ArgumentRegEx))
{
// the 3rd match of the regular expression used to parse the string will contain the operand, if one was matched.
if (match.Groups[3].Value == default(string) || match.Groups[3].Value == string.Empty)
{
continue;
}
string fullMatch = match.Groups[0].Value;
string operand = match.Groups[3].Value;
operands.Add(TrimOuterQuotes(operand));
}
return operands;
}
/// <summary>
/// Populates and returns a list containing the operands within the specified string grouped by whole words and groups
/// of words contained within single or double quotes, treating strings that would otherwise be treated as argument
/// keys as operands.
/// </summary>
/// <param name="operandListString">The string from which the list of operands is to be parsed.</param>
/// <returns>
/// A list containing the operands within the specified string grouped by whole words and groups of words contained
/// within single or double quotes, treating strings that would otherwise be treated as argument keys as operands.
/// </returns>
private static List<string> GetOperandListStrict(string operandListString)
{
List<string> operands = new List<string>();
foreach (Match match in Regex.Matches(operandListString, OperandRegEx))
{
operands.Add(match.Groups[0].Value);
}
return operands;
}
/// <summary>
/// Retrieves the property in the target <see cref="Type"/> marked with the
/// <see cref="OperandsAttribute"/><see cref="Attribute"/>, if one exists.
/// </summary>
/// <remarks>
/// The target property <see cref="Type"/> of the designated property must be of type string[] or List{string}.
/// </remarks>
/// <param name="type">The Type for which the matching property is to be retrieved.</param>
/// <returns>The matching property, if one exists.</returns>
/// <exception cref="InvalidCastException">
/// Thrown when the Type of the retrieved property is not string[] or List{string}.
/// </exception>
private static PropertyInfo GetOperandsProperty(Type type)
{
PropertyInfo property = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
.Where(p => p.CustomAttributes
.Any(a => a.AttributeType.Name == typeof(OperandsAttribute).Name))
.FirstOrDefault();
if (property != default(PropertyInfo) && property.PropertyType != typeof(string[]) && property.PropertyType != typeof(List<string>))
{
throw new InvalidCastException("The target for the Operands attribute must be of string[] or List<string>.");
}
return property;
}
/// <summary>
/// Returns the specified string with outer single or double quotes trimmed, if the string starts and ends with them.
/// </summary>
/// <param name="value">The string from which to trim outer single or double quotes.</param>
/// <returns>The string with outer single or double quotes trimmed.</returns>
private static string TrimOuterQuotes(string value)
{
if (value.StartsWith("\"") && value.EndsWith("\""))
{
value = value.Trim('"');
}
else if (value.StartsWith("'") && value.EndsWith("'"))
{
value = value.Trim('\'');
}
return value;
}
#endregion Private Methods
}
/// <summary>
/// Indicates that the property is to be used as the target for automatic population of command line operands when invoking
/// the <see cref="Arguments.Populate(string)"/> method.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class OperandsAttribute : Attribute
{
}
}

4
source/FodyWeavers.xml Normal file
Просмотреть файл

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Costura Unmanaged32Assemblies="STDFUFiles.dll" />
</Weavers>

106
source/FodyWeavers.xsd Normal file
Просмотреть файл

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuild. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="Costura" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeDebugSymbols" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCompression" type="xs:boolean">
<xs:annotation>
<xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCleanup" type="xs:boolean">
<xs:annotation>
<xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="LoadAtModuleInit" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification on the target assembly after all weavers have been finished.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

244
source/Hex2Dfu.cs Normal file
Просмотреть файл

@ -0,0 +1,244 @@
//
// Copyright (c) 2017 The nanoFramework project contributors
// Portions Copyright (c) COPYRIGHT 2015 STMicroelectronics
// See LICENSE file in the project root for full license information.
//
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
namespace nanoFramework.Tools
{
public class Hex2Dfu
{
#region constants from STDFUFiles
/// <summary>
/// No error.
/// </summary>
const uint STDFUFILES_NOERROR = 0x12340000;
#endregion
//a block of data to be written
[StructLayout(LayoutKind.Sequential, Pack = 1)]
unsafe public struct STDFUFILES_DfuImageElement
{
public UInt32 dwAddress;
public UInt32 dwDataLength;
public IntPtr Data;
}
#region imports from STDFUFiles.dll
// from dumpbin
// 1 0 00004480 STDFUFILES_AppendImageToDFUFile
// 2 1 000044E0 STDFUFILES_CloseDFUFile
// 3 2 00004550 STDFUFILES_CreateImage
// 4 3 000045B0 STDFUFILES_CreateImageFromMapping
// 5 4 00004610 STDFUFILES_CreateNewDFUFile
// 6 5 00004680 STDFUFILES_DestroyImage
// 7 6 00004700 STDFUFILES_DestroyImageElement
// 8 7 00004770 STDFUFILES_DuplicateImage
// 9 8 00004820 STDFUFILES_FilterImageForOperation
//10 9 000048A0 STDFUFILES_GetImageAlternate
//11 A 00004900 STDFUFILES_GetImageElement
//12 B 00004970 STDFUFILES_GetImageName
//13 C 000049E0 STDFUFILES_GetImageNbElement
//14 D 00004A40 STDFUFILES_GetImageSize
//15 E 00004A90 STDFUFILES_ImageFromFile
//16 F 00004B10 STDFUFILES_ImageToFile
//17 10 00004B80 STDFUFILES_OpenExistingDFUFile
//18 11 00004C20 STDFUFILES_ReadImageFromDFUFile
//19 12 00004CA0 STDFUFILES_SetImageElement
//20 13 00004D20 STDFUFILES_SetImageName
[DllImport("STDFUFiles.DLL", EntryPoint = "STDFUFILES_AppendImageToDFUFile", CharSet = CharSet.Auto)]
public static extern UInt32 STDFUFILES_AppendImageToDFUFile(IntPtr handle, IntPtr image);
[DllImport("STDFUFiles.DLL", EntryPoint = "STDFUFILES_CloseDFUFile", CharSet = CharSet.Auto)]
public static extern UInt32 STDFUFILES_CloseDFUFile(IntPtr handle);
[DllImport("STDFUFiles.DLL", EntryPoint = "STDFUFILES_CreateNewDFUFile", CharSet = CharSet.Auto)]
public static extern UInt32 STDFUFILES_CreateNewDFUFile([MarshalAs(UnmanagedType.LPStr)]String szDevicePath, ref IntPtr handle, UInt16 Vid, UInt16 Pid, UInt16 Bcd);
[DllImport("STDFUFiles.DLL", EntryPoint = "STDFUFILES_CreateImage", CharSet = CharSet.Auto)]
public static extern UInt32 STDFUFILES_CreateImage(ref IntPtr image, byte nAlternate);
[DllImport("STDFUFiles.DLL", EntryPoint = "STDFUFILES_DestroyImage", CharSet = CharSet.Auto)]
public static extern UInt32 STDFUFILES_DestroyImage(ref IntPtr handle);
[DllImport("STDFUFiles.DLL", EntryPoint = "STDFUFILES_ImageFromFile", CharSet = CharSet.Auto)]
public static extern UInt32 STDFUFILES_ImageFromFile([MarshalAs(UnmanagedType.LPStr)]String szDevicePath, ref IntPtr image, byte nAlternate);
[DllImport("STDFUFiles.DLL", EntryPoint = "STDFUFILES_SetImageElement", CharSet = CharSet.Auto)]
public static extern UInt32 STDFUFILES_SetImageElement(IntPtr handle, UInt32 dwRank, bool bInsert, [MarshalAs(UnmanagedType.Struct)]STDFUFILES_DfuImageElement Element);
[DllImport("STDFUFiles.DLL", EntryPoint = "STDFUFILES_SetImageName", CharSet = CharSet.Auto)]
public static extern UInt32 STDFUFILES_SetImageName(IntPtr image, [MarshalAs(UnmanagedType.LPStr)]String pPathFile);
#endregion
const UInt16 defaultSTMVid = 0x0483;
const UInt16 defafultSTMPid = 0xDF11;
const UInt16 defaultFwVersion = 0x2200;
public static bool CreateDfuFile(string hexFile, string dfuName, UInt16 vid = defaultSTMVid, UInt16 pid = defafultSTMPid, UInt16 fwVersion = defaultFwVersion)
{
IntPtr dfuFileHandle = (IntPtr)0;
IntPtr imageFileHandle = (IntPtr)0;
// start creating a new DFU file for output
var retCode = STDFUFILES_CreateNewDFUFile(dfuName, ref dfuFileHandle, vid, pid, fwVersion);
if (retCode == STDFUFILES_NOERROR)
{
// get image from HEX file
retCode = STDFUFILES_ImageFromFile(hexFile, ref imageFileHandle, 0);
if (retCode == STDFUFILES_NOERROR)
{
// add image of HEX file
retCode = STDFUFILES_AppendImageToDFUFile(dfuFileHandle, imageFileHandle);
if (retCode != STDFUFILES_NOERROR)
{
// error adding this file
Console.WriteLine();
Console.WriteLine($"ERROR: adding {hexFile}");
Console.WriteLine();
return false;
}
Console.WriteLine($"Adding image for {hexFile}");
}
}
// image file added, close DFU file
STDFUFILES_CloseDFUFile(dfuFileHandle);
Console.WriteLine();
Console.WriteLine($"DFU generated: {dfuName}");
Console.WriteLine($"Vendor ID: {vid.ToString("X4")}");
Console.WriteLine($"Product ID: {pid.ToString("X4")}");
Console.WriteLine($"Version: {fwVersion.ToString("X4")}");
Console.WriteLine();
// clean-up
if (retCode == STDFUFILES_NOERROR)
{
// destroy image
STDFUFILES_DestroyImage(ref imageFileHandle);
}
return true;
}
public static bool CreateDfuFile(List<BinaryFileInfo> binFiles, string dfuName, UInt16 vid = defaultSTMVid, UInt16 pid = defafultSTMPid, UInt16 fwVersion = defaultFwVersion)
{
IntPtr dfuFileHandle = (IntPtr)0;
IntPtr imageFileHandle = (IntPtr)0;
// start creating a new DFU file for output
var retCode = STDFUFILES_CreateNewDFUFile(dfuName, ref dfuFileHandle, vid, pid, fwVersion);
if (retCode == STDFUFILES_NOERROR)
{
retCode = STDFUFILES_CreateImage(ref imageFileHandle, 0);
retCode = STDFUFILES_SetImageName(imageFileHandle, "nanoFramework");
uint fileCounter = 0;
// loop through collection of bin files and add them
foreach (BinaryFileInfo file in binFiles)
{
byte[] fileData = File.ReadAllBytes(file.FileName);
// get required memory size for byte array
int size = Marshal.SizeOf(fileData[0]) * fileData.Length;
STDFUFILES_DfuImageElement element = new STDFUFILES_DfuImageElement();
element.dwAddress = file.Address;
element.dwDataLength = (uint)fileData.Length;
// allocate memory from the unmanaged memory
element.Data = Marshal.AllocHGlobal(size);
// copy the byte array to the struct
Marshal.Copy(fileData, 0, element.Data, fileData.Length);
// get image from HEX file
retCode = STDFUFILES_SetImageElement(imageFileHandle, fileCounter++, true, element);
// free unmanaged memory
Marshal.FreeHGlobal(element.Data);
if (retCode != STDFUFILES_NOERROR)
{
// error adding this file
Console.WriteLine();
Console.WriteLine($"ERROR: adding {file.FileName}");
Console.WriteLine();
return false;
}
Console.WriteLine($"Adding file to image: {file.FileName}");
}
// add image to DFU file
retCode = STDFUFILES_AppendImageToDFUFile(dfuFileHandle, imageFileHandle);
if (retCode != STDFUFILES_NOERROR)
{
// error adding this file
Console.WriteLine();
Console.WriteLine($"ERROR: adding image to DFU file");
Console.WriteLine();
return false;
}
// image file added, close DFU file
STDFUFILES_CloseDFUFile(dfuFileHandle);
Console.WriteLine();
Console.WriteLine($"DFU generated: {dfuName}");
Console.WriteLine($"Vendor ID: {vid.ToString("X4")}");
Console.WriteLine($"Product ID: {pid.ToString("X4")}");
Console.WriteLine($"Version: {fwVersion.ToString("X4")}");
Console.WriteLine();
// clean-up
if (retCode == STDFUFILES_NOERROR)
{
// destroy image
STDFUFILES_DestroyImage(ref imageFileHandle);
}
}
return true;
}
}
public class BinaryFileInfo
{
public string FileName { get; private set; }
public uint Address { get; private set; }
public BinaryFileInfo(string fileName, uint address)
{
FileName = fileName;
Address = address;
}
}
}

162
source/Program.cs Normal file
Просмотреть файл

@ -0,0 +1,162 @@
//
// Copyright (c) 2017 The nanoFramework project contributors
// See LICENSE file in the project root for full license information.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Utility.CommandLine;
namespace nanoFramework.Tools
{
class Program
{
[Argument('h', "hexfile")]
private static string HexFile { get; set; }
[Argument('b', "binfile")]
private static List<string> BinFiles { get; set; }
[Argument('a', "address")]
private static List<string> Addresses { get; set; }
[Argument('o', "outputdfu")]
private static string OutputDfuFile { get; set; }
[Argument('v', "vid")]
private static string Vid { get; set; }
[Argument('p', "pid")]
private static string Pid { get; set; }
[Argument('f', "fwversion")]
private static string FirmwareVersion { get; set; }
private static ushort _Vid => ushort.Parse(Vid, System.Globalization.NumberStyles.HexNumber);
private static ushort _Pid => ushort.Parse(Pid, System.Globalization.NumberStyles.HexNumber);
private static ushort _FirmwareVersion => ushort.Parse(FirmwareVersion, System.Globalization.NumberStyles.HexNumber);
static void Main(string[] args)
{
Arguments.Populate();
Console.WriteLine();
Console.WriteLine();
Console.WriteLine($"nanoFramework HEX2DFU converter v{Assembly.GetExecutingAssembly().GetName().Version}");
Console.WriteLine($"Copyright (c) 2017 nanoFramework project contributors");
Console.WriteLine();
// output usage help if no arguments are specified
if (args.Count() == 0)
{
Console.WriteLine("Usage:");
Console.WriteLine(" adding a single HEX file: hex2dfu -h=hex_file_name -o=output_DFU_image_file_name");
Console.WriteLine(" adding one or more BIN files: hex2dfu -b=bin_file_name -a=address_to_flash [-b=bin_file_name_N -a=address_to_flash_N] -o=output_DFU_image_file_name");
Console.WriteLine();
Console.WriteLine(" options:");
Console.WriteLine();
Console.WriteLine(@" [-v=""0000""] (VID of target USB device (hexadecimal format), leave empty to use STM default)");
Console.WriteLine(@" [-p=""0000""] (PID of target USB device (hexadecimal format), leave empty to use STM default)");
Console.WriteLine(@" [-f=""0000""] (Firmware version of the target USB device (hexadecimal format), leave empty to use default)");
Console.WriteLine();
}
// args check
// need, at least, one hex file
if (HexFile == null && BinFiles == null)
{
Console.WriteLine();
Console.WriteLine("ERROR: Need at least one HEX or BIN file to create DFU target image.");
Console.WriteLine();
Console.WriteLine(@"Use -h=""path-to-hex-file"" for each HEX file to add to the DFU target.");
Console.WriteLine(@"Use -b=bin_file_name -a=address_to_flash [-b=bin_file_name_N -a=address_to_flash_N] for each BIN file to add to the DFU target.");
Console.WriteLine();
Console.WriteLine();
}
if (BinFiles != null)
{
// need the addresses too
if (Addresses == null)
{
Console.WriteLine();
Console.WriteLine("ERROR: For BIN files the addresses to flash are mandatory.");
Console.WriteLine();
Console.WriteLine(@"Use -b=bin_file_name -a=address_to_flash [-b=bin_file_name_N -a=address_to_flash_N] for each BIN file to add to the DFU target.");
Console.WriteLine();
Console.WriteLine();
}
}
// output DFU file name is mandatory
if (OutputDfuFile == null)
{
Console.WriteLine();
Console.WriteLine("ERROR: Output DFU target file name is required.");
Console.WriteLine();
Console.WriteLine(@"Use -h=""path-to-dfu-file""");
Console.WriteLine();
Console.WriteLine();
}
if (HexFile != null && OutputDfuFile != null)
{
// compose the call to CreateDfuFile according to the requested parameters
if (Vid != null && Pid != null && FirmwareVersion != null)
{
Hex2Dfu.CreateDfuFile(HexFile, OutputDfuFile, _Vid, _Pid, _FirmwareVersion);
}
else if (Vid != null && Pid != null && FirmwareVersion == null)
{
Hex2Dfu.CreateDfuFile(HexFile, OutputDfuFile, _Vid, _Pid);
}
else if (Vid != null && Pid == null && FirmwareVersion == null)
{
Hex2Dfu.CreateDfuFile(HexFile, OutputDfuFile, _Vid);
}
else if (Vid == null && Pid == null && FirmwareVersion == null)
{
Hex2Dfu.CreateDfuFile(HexFile, OutputDfuFile);
}
}
if (BinFiles != null && OutputDfuFile != null)
{
// combine BIN files and addresses
List<BinaryFileInfo> binFiles = new List<BinaryFileInfo>();
var addressEnum = Addresses.GetEnumerator();
foreach (string file in BinFiles)
{
addressEnum.MoveNext();
binFiles.Add(new BinaryFileInfo(file, uint.Parse(addressEnum.Current, System.Globalization.NumberStyles.HexNumber)));
}
// compose the call to CreateDfuFile according to the requested parameters
if (Vid != null && Pid != null && FirmwareVersion != null)
{
Hex2Dfu.CreateDfuFile(binFiles, OutputDfuFile, _Vid, _Pid, _FirmwareVersion);
}
else if (Vid != null && Pid != null && FirmwareVersion == null)
{
Hex2Dfu.CreateDfuFile(binFiles, OutputDfuFile, _Vid, _Pid);
}
else if (Vid != null && Pid == null && FirmwareVersion == null)
{
Hex2Dfu.CreateDfuFile(binFiles, OutputDfuFile, _Vid);
}
else if (Vid == null && Pid == null && FirmwareVersion == null)
{
Hex2Dfu.CreateDfuFile(binFiles, OutputDfuFile);
}
}
}
}
}

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

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
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 Tools Hex2Dfu")]
[assembly: AssemblyDescription("Utility to convert HEX files into DFU target image")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("nanoFramework project contributors")]
[assembly: AssemblyProduct("nanoFramework Tools Hex2Dfu")]
[assembly: AssemblyCopyright("Copyright © 2017 nanoFramework project contributors")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 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)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("378070ef-3572-47f4-a854-3d6c5da3eefa")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]

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

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="packages\Costura.Fody.3.2.0\build\Costura.Fody.props" Condition="Exists('packages\Costura.Fody.3.2.0\build\Costura.Fody.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{378070EF-3572-47F4-A854-3D6C5DA3EEFA}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>nanoFramework.Tools.Hex2Dfu</RootNamespace>
<AssemblyName>hex2dfu</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="Costura, Version=3.2.0.0, Culture=neutral, PublicKeyToken=9919ef960d84173d, processorArchitecture=MSIL">
<HintPath>packages\Costura.Fody.3.2.0\lib\net46\Costura.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="Arguments.cs" />
<Compile Include="Hex2Dfu.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
<None Include="version.json" />
</ItemGroup>
<ItemGroup>
<None Include="FodyWeavers.xml" />
<EmbeddedResource Include="costura32\STDFUFiles.dll" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.6">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.6 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="packages\Fody.3.3.2\build\Fody.targets" Condition="Exists('packages\Fody.3.3.2\build\Fody.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('packages\Fody.3.3.2\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Fody.3.3.2\build\Fody.targets'))" />
<Error Condition="!Exists('packages\Costura.Fody.3.2.0\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Costura.Fody.3.2.0\build\Costura.Fody.props'))" />
<Error Condition="!Exists('packages\Nerdbank.GitVersioning.2.2.33\build\Nerdbank.GitVersioning.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Nerdbank.GitVersioning.2.2.33\build\Nerdbank.GitVersioning.targets'))" />
</Target>
<Import Project="packages\Nerdbank.GitVersioning.2.2.33\build\Nerdbank.GitVersioning.targets" Condition="Exists('packages\Nerdbank.GitVersioning.2.2.33\build\Nerdbank.GitVersioning.targets')" />
</Project>

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

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.15
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "nanoFramework.Tools.Hex2Dfu", "nanoFramework.Tools.Hex2Dfu.csproj", "{378070EF-3572-47F4-A854-3D6C5DA3EEFA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{378070EF-3572-47F4-A854-3D6C5DA3EEFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{378070EF-3572-47F4-A854-3D6C5DA3EEFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{378070EF-3572-47F4-A854-3D6C5DA3EEFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{378070EF-3572-47F4-A854-3D6C5DA3EEFA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0CFE97F1-0501-4C1F-8CC5-11043784ECC5}
EndGlobalSection
EndGlobal

6
source/packages.config Normal file
Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Costura.Fody" version="3.2.0" targetFramework="net46" developmentDependency="true" />
<package id="Fody" version="3.3.2" targetFramework="net46" developmentDependency="true" />
<package id="Nerdbank.GitVersioning" version="2.2.33" targetFramework="net46" developmentDependency="true" />
</packages>

16
source/version.json Normal file
Просмотреть файл

@ -0,0 +1,16 @@
{
"$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
"version": "1.1",
"assemblyVersion": {
"precision": "revision"
},
"semVer1NumericIdentifierPadding": 3,
"publicReleaseRefSpec": [
"^refs/heads/master$",
"^refs/heads/v\\d+(?:\\.\\d+)?$"
],
"cloudBuild": {
"setVersionVariables": true,
"setAllVariables": true
}
}